ketting 8.4.1 → 8.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
+ import { EventEmitter } from "events";
1
2
  import { LinkHints } from "hal-types";
2
- import { EventEmitter } from "node:events";
3
3
 
4
4
  //#region src/http/fetcher.d.ts
5
5
  type FetchMiddleware = (request: Request, next: (request: Request) => Promise<Response>) => Promise<Response>;
@@ -1,2 +1,2 @@
1
- import e from"query-string";import*as t from"uri-template";import*as n from"http-link-header";import*as r from"sax";import{OAuth2Client as i,OAuth2Fetch as a}from"@badgateway/oauth2-client";var o=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),s=class extends Error{constructor(e){super(`HTTP error `+e.status),this.response=e,this.status=e.status}},c=class extends s{constructor(e,t){super(e),this.body={type:t.type??`about:blank`,status:t.status??this.status,...t},this.body.title&&(this.message=`HTTP Error `+this.status+`: `+this.body.title)}};async function l(e){let t=e.headers.get(`Content-Type`);return t!=null&&t.match(/^application\/problem\+json/i)?new c(e,await e.json()):new s(e)}var u=o(((e,t)=>{t.exports={name:`ketting`,version:`8.4.1`,description:`Opiniated HATEAOS / Rest client.`,main:`dist/main/index.js`,types:`dist/main/index.d.ts`,files:[`src/`,`dist/`,`LICENSE`],scripts:{test:`make test`,prepublishOnly:`make build`,build:`make build`},repository:{type:`git`,url:`git+https://github.com/badgateway/ketting.git`},keywords:[`rest`,`hypermedia`,`client`,`http`,`hateoas`,`hal`],author:`Evert Pot`,license:`MIT`,bugs:{url:`https://github.com/badgateway/ketting/issues`},homepage:`https://github.com/badgateway/ketting#readme`,engines:{node:`>=16`},dependencies:{"@badgateway/oauth2-client":`^2.0.17`,events:`^3.3.0`,"hal-types":`^3.0.0`,"http-link-header":`^1.0.3`,"query-string":`^9.3.1`,sax:`^1.2.4`,"uri-template":`^2.0.0`},devDependencies:{"@eslint/js":`^9.14.0`,"@types/chai":`^5.0.1`,"@types/http-link-header":`^1.0.2`,"@types/koa-bodyparser":`^4.3.0`,"@types/koa-logger":`^3.1.1`,"@types/koa-static":`^4.0.1`,"@types/mocha":`^10.0.0`,"@types/node":`^18.7.14`,"@types/sax":`^1.2.1`,chai:`^5.2.0`,koa:`^3.1.2`,"koa-bodyparser":`^4.3.0`,"koa-logger":`^3.2.1`,"koa-path-match":`^3.0.0`,"koa-static":`^5.0.0`,mocha:`^11.1.0`,tsdown:`^0.21.6`,tsx:`^4.19.3`,typescript:`^5.7.3`,"typescript-eslint":`^8.13.0`}}})),d=class{constructor(){this.middlewares=[],this.advertiseKetting=!0}fetch(e,t){let n=new Request(e,t),r=new URL(n.url).origin,i=this.getMiddlewaresByOrigin(r);return i.push(e=>(!e.headers.has(`User-Agent`)&&this.advertiseKetting&&e.headers.set(`User-Agent`,`Ketting/`+u().version),fetch(e))),f(i,n)}getMiddlewaresByOrigin(e){return this.middlewares.filter(([t])=>t.test(e)).map(([,e])=>e)}use(e,t=`*`){let n=t.split(`*`).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(`(.*)`),r=RegExp(`^`+n+`$`);this.middlewares.push([r,e])}async fetchOrThrow(e,t){let n=await this.fetch(e,t);if(n.ok)return n;throw await l(n)}};function f(e,t){return e[0](t,t=>f(e.slice(1),t))}function p(e,t){let n,r;typeof e==`string`?(n=e,r=t):(n=e.context,r=e.href);let i=new URL(r,new URL(n,`http://ketting.invalid`));return i.hostname===`ketting.invalid`?i.pathname+i.search+i.hash:n.startsWith(`//`)?`//`+i.host+i.pathname+i.search+i.hash:i.toString()}var m=class e{constructor(t,n){if(this.defaultContext=t,this.store=new Map,n)if(n instanceof e)this.add(...n.getAll());else for(let e of n)this.add(e)}add(...e){let t;t=typeof e[0]==`string`?[{rel:e[0],href:e[1],context:this.defaultContext}]:e.map(e=>({context:this.defaultContext,...e}));for(let e of t)this.store.has(e.rel)?this.store.get(e.rel).push(e):this.store.set(e.rel,[e])}set(e,t){let n;n=typeof e==`string`?{rel:e,href:t,context:this.defaultContext}:{context:this.defaultContext,...e},this.store.set(n.rel,[n])}get(e){let t=this.store.get(e);if(!(!t||t.length<0))return t[0]}delete(e,t){if(t===void 0){this.store.delete(e);return}let n=this.store.get(e);if(!n)return;this.store.delete(e);let r=p(this.defaultContext,t);this.store.set(e,n.filter(e=>p(e)!==r))}getMany(e){return this.store.get(e)||[]}getAll(){let e=[];for(let t of this.store.values())e.push(...t);return e}has(e){return this.store.has(e)}},h=class extends Error{};function g(e){return typeof e.uri==`string`&&e.links instanceof m&&e.headers instanceof Headers}var _=class{constructor(e,t){this.client=e;for(let[e,n]of Object.entries(t))this[e]=n}async submit(t){let n=new URL(this.uri),r=this.validateForm(t);if(this.method===`GET`)return n.search=e.stringify(r),this.client.go(n.toString()).get();let i=await this.fetchOrThrowWithBody(n,r);return this.client.getStateForResponse(n.toString(),i)}async submitFollow(t){let n=new URL(this.uri),r=this.validateForm(t);if(this.method===`GET`)return n.search=e.stringify(r),this.client.go(n.toString());let i=await this.fetchOrThrowWithBody(n,r);switch(i.status){case 201:if(i.headers.has(`location`))return this.client.go(i.headers.get(`location`));throw Error(`Could not follow after a 201 request, because the server did not reply with a Location header. If you sent a Location header, check if your service is returning "Access-Control-Expose-Headers: Location".`);case 204:case 205:return this.client.go(n.toString());default:throw Error(`Did not receive a 201, 204 or 205 status code so we could not follow to the next resource`)}}validateForm(e){let t={...e};for(let n of this.fields)if(!(n.name in e)){if(n.value)t[n.name]=n.value;else if(n.required)throw Error(`The ${n.name} field is required in this form`)}return t}fetchOrThrowWithBody(t,n){let r;switch(this.contentType){case`application/x-www-form-urlencoded`:r=e.stringify(n);break;case`application/json`:r=JSON.stringify(n);break;default:throw Error(`Serializing mimetype ${this.contentType} is not yet supported in actions`)}return this.client.fetcher.fetchOrThrow(t.toString(),{method:this.method,body:r,headers:{"Content-Type":this.contentType}})}field(e){return this.fields.find(t=>t.name===e)}},v=class extends Error{};function y(e,n,r){let i,a,o;typeof e==`string`?(i=e,a=n,o=r):(i=e.context,a=e.href,o=n);let s=t.parse(a).expand(o);return p(i,s)}function b(e){return e?(e.includes(`;`)&&(e=e.split(`;`)[0]),e.trim()):null}function x(e,t){let r=new m(e);if(!t)return r;for(let i of n.parse(t).refs)for(let t of i.rel.split(` `)){let n={rel:t,href:i.uri,context:e,title:i.title,hreflang:i.hreflang,type:i.type};r.add(n)}return r}const ee=[`GET`,`HEAD`,`OPTIONS`,`PRI`,`PROPFIND`,`REPORT`,`SEARCH`,`TRACE`];function te(e){return ee.includes(e)}const ne=[`Content-Type`,`Content-Language`,`Content-Location`,`Deprecation`,`ETag`,`Expires`,`Last-Modified`,`Sunset`,`Title`,`Warning`];var S=class{constructor(e){this.client=e.client,this.uri=e.uri,this.headers=e.headers,this.timestamp=Date.now(),this.links=e.links}follow(e,t){var n;let r=this.links.get(e);if(!r)throw new h(`Link with rel ${e} on ${this.uri} not found`);let i;return i=r.templated?y(r,t||{}):p(r),((n=r.hints)==null?void 0:n.status)===`deprecated`&&console.warn(`[ketting] The ${r.rel} link on ${this.uri} is marked deprecated.`,r),this.client.go(i)}followAll(e){return this.links.getMany(e).map(e=>{var t;((t=e.hints)==null?void 0:t.status)===`deprecated`&&console.warn(`[ketting] The ${e.rel} link on ${this.uri} is marked deprecated.`,e);let n=p(e);return this.client.go(n)})}contentHeaders(){let e={};for(let t of ne)this.headers.has(t)&&(e[t]=this.headers.get(t));return new Headers(e)}},C=class e extends S{constructor(e){super(e),this.data=e.data,this.actionInfo=e.actions||[],this.embedded=e.embedded||[]}action(e){let t=this.doFindAction(e);if(t===`NO_ACTION_DEFINED`)throw new v(`This State does not define any actions`);if(t===`NO_ACTION_FOR_THE_PROVIDED_NAME`)throw new v(`This State defines no action`);return t}findAction(e){let t=this.doFindAction(e);if(typeof t==`object`)return t}doFindAction(e){if(!this.actionInfo.length)return`NO_ACTION_DEFINED`;if(e===void 0)return new _(this.client,this.actionInfo[0]);for(let t of this.actionInfo)if(t.name===e)return new _(this.client,t);return`NO_ACTION_FOR_THE_PROVIDED_NAME`}actions(){return this.actionInfo.map(e=>new _(this.client,e))}hasAction(e){if(e===void 0)return this.actionInfo.length>0;for(let t of this.actionInfo)if(e===t.name)return!0;return!1}serializeBody(){return globalThis.Buffer&&this.data instanceof Buffer||globalThis.Blob&&this.data instanceof Blob||typeof this.data==`string`?this.data:JSON.stringify(this.data)}getEmbedded(){return this.embedded}clone(){return new e({client:this.client,uri:this.uri,data:this.data,headers:new Headers(this.headers),links:new m(this.links.defaultContext,this.links.getAll()),actions:this.actionInfo})}},w=class e extends C{serializeBody(){return JSON.stringify({_links:this.serializeLinks(),...this.data})}serializeLinks(){let e={self:{href:this.uri}};for(let t of this.links.getAll()){let{rel:n,context:r,...i}=t;n!==`self`&&(e[n]===void 0?e[n]=i:Array.isArray(e[n])?e[n].push(i):e[n]=[e[n],i])}return e}clone(){return new e({client:this.client,uri:this.uri,data:this.data,headers:new Headers(this.headers),links:new m(this.links.defaultContext,this.links.getAll()),actions:this.actionInfo})}};const T=async(e,t,n)=>{let r=await n.json(),i=x(t,n.headers.get(`Link`));if(Array.isArray(r))return new w({client:e,uri:t,data:r,headers:n.headers,links:i});i.add(...E(t,r));let{_embedded:a,_links:o,_templates:s,...c}=r;return new w({client:e,uri:t,data:c,headers:n.headers,links:i,embedded:D(e,t,r,n.headers),actions:O(t,r)})};function E(e,t){if(t._links===void 0)return[];let n=[],r=new Set;for(let[i,a]of Object.entries(t._links)){let t=Array.isArray(a)?a:[a];for(let e of t)r.add(i+`;`+e.href);n.push(...re(e,i,t))}if(t._embedded)for(let[a,o]of Object.entries(t._embedded))for(let t of Array.isArray(o)?o:[o]){var i;let o=t==null||(i=t._links)==null||(i=i.self)==null?void 0:i.href;o&&(r.has(a+`;`+o)||n.push({rel:a,href:o,context:e}))}return n}function re(e,t,n){let r=[];for(let i of n)r.push({rel:t,context:e,...i});return r}function D(e,t,n,r){if(n._embedded===void 0||!n._embedded)return[];let i=[];for(let s of Object.values(n._embedded)){let n;n=Array.isArray(s)?s:[s];for(let s of n){var a,o;if(((a=s._links)==null||(a=a.self)==null?void 0:a.href)===void 0){console.warn(`An item in _embedded was ignored. Each item must have a single "self" link`);continue}let n=p(t,(o=s._links)==null||(o=o.self)==null?void 0:o.href),{_embedded:c,_links:l,...u}=s;i.push(new w({client:e,uri:n,data:u,headers:new Headers({"Content-Type":r.get(`Content-Type`)}),links:new m(n,E(t,s)),embedded:D(e,n,s,r),actions:O(n,s)}))}}return i}function O(e,t){return t._templates?Object.entries(t._templates).map(([t,n])=>({uri:p(e,n.target||``),name:t,title:n.title,method:n.method,contentType:n.contentType||`application/json`,fields:n.properties?n.properties.map(e=>ie(e)).filter(e=>!!e):[]})):[]}function ie(e){switch(e.type){case void 0:case`text`:case`search`:case`tel`:case`url`:case`email`:if(e.options){let t=!(`maxItems`in e.options)||!e.options.maxItems||e.options.maxItems>1,n={name:e.name,type:`select`,label:e.prompt,required:e.required||!1,readOnly:e.readOnly||!1,value:e.options.selectedValues||e.value},r=ae(e.options);if(t)return{multiple:!0,selectedValues:e.options.selectedValues,...n,...r};{let i=e.options.selectedValues,a;return i&&(i.length===1?a=i[0]:i.length>1&&console.warn(`More than 1 selected value received for single select field ${n.name}. Ignoring all selected values for this field.`)),{multiple:t,selectedValue:a,...n,...r}}}else return{name:e.name,type:e.type??`text`,required:e.required||!1,readOnly:e.readOnly||!1,value:e.value,pattern:e.regex?new RegExp(e.regex):void 0,label:e.prompt,placeholder:e.placeholder,minLength:e.minLength,maxLength:e.maxLength};case`hidden`:return{name:e.name,type:`hidden`,required:e.required||!1,readOnly:e.readOnly||!1,value:e.value,label:e.prompt,placeholder:e.placeholder};case`textarea`:return{name:e.name,type:e.type,required:e.required||!1,readOnly:e.readOnly||!1,value:e.value,label:e.prompt,placeholder:e.placeholder,cols:e.cols,rows:e.rows,minLength:e.minLength,maxLength:e.maxLength};case`password`:return{name:e.name,type:e.type,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,placeholder:e.placeholder,minLength:e.minLength,maxLength:e.maxLength};case`date`:case`month`:case`week`:case`time`:return{name:e.name,type:e.type,value:e.value,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,min:e.min,max:e.max,step:e.step};case`number`:case`range`:return{name:e.name,type:e.type,value:e.value?+e.value:void 0,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,min:e.min,max:e.max,step:e.step};case`datetime-local`:return{name:e.name,type:e.type,value:e.value?new Date(e.value):void 0,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,min:e.min,max:e.max,step:e.step};case`color`:return{name:e.name,type:e.type,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,value:e.value};case`radio`:case`checkbox`:return{name:e.name,type:e.type,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,value:!!e.value};default:return}}function ae(e){let t=e.promptField||`prompt`,n=e.valueField||`value`;if(oe(e)){let r={};for(let i of e.inline)typeof i==`string`?r[i]=i:r[i[n]]=i[t];return{options:r}}else return{dataSource:{href:e.link.href,type:e.link.type,labelField:t,valueField:n}}}function oe(e){return e.inline!==void 0}const k=async(e,t,n)=>new C({client:e,uri:t,data:await n.blob(),headers:n.headers,links:x(t,n.headers.get(`Link`))}),A=async(e,t,n)=>{let r=await n.json(),i=x(t,n.headers.get(`Link`));return i.add(...se(t,r),...ce(t,r)),new C({client:e,uri:t,data:r,headers:n.headers,links:i})};function se(e,t){let n=[];if(t.links===void 0)return n;for(let[r,i]of Object.entries(t.links))Array.isArray(i)?n.push(...i.map(t=>j(e,r,t))):n.push(j(e,r,i));return n}function ce(e,t){if(!Array.isArray(t.data))return[];let n=[];for(let r of t.data)if(`links`in r&&`self`in r.links){let t=j(e,`self`,r.links.self);n.push({context:e,href:t.href,rel:`item`})}return n}function j(e,t,n){return{context:e,rel:t,href:typeof n==`string`?n:n.href}}var M=class e extends C{serializeBody(){throw Error(`Reserializing Siren states is not yet supported. Please log an issue in the Ketting project to help figure out how this should be done`)}clone(){return new e({client:this.client,uri:this.uri,data:this.data,headers:new Headers(this.headers),links:new m(this.uri,this.links),actions:this.actionInfo})}};const le=async(e,t,n)=>{let r=await n.json(),i=x(t,n.headers.get(`Link`));return i.add(...N(t,r)),new M({client:e,uri:t,data:r.properties,headers:n.headers,links:i,embedded:ue(e,t,r,n.headers),actions:r.actions?r.actions.map(e=>L(t,e)):[]})};function N(e,t){let n=[];if(t.links!==void 0)for(let r of t.links)n.push(...P(e,r));if(t.entities!==void 0)for(let r of t.entities)r.href===void 0?n.push(...de(e,r)):n.push(...P(e,r));return n}function P(e,t){let n=[],{rel:r,...i}=t;for(let t of r){let r={rel:t,context:e,...i};n.push(r)}return n}function ue(e,t,n,r){if(n.entities===void 0)return[];let i=[];for(let a of n.entities)if(I(a)){let n=F(e,t,a,r);n!==null&&i.push(n)}return i}function de(e,t){if(t.links===void 0)return[];let n=null;for(let e of t.links)e.rel.includes(`self`)&&(n=e.href);return n===null?[]:t.rel.map(r=>{let i=t.title,a={href:n,rel:r,context:e};return i&&(a.title=i),a})}function F(e,t,n,r){if(n.links===void 0)return null;let i=null;for(let e of n.links)e.rel.includes(`self`)&&(i=e.href);return i?new M({client:e,uri:p(t,i),data:n.properties,headers:r,links:new m(i,N(i,n))}):null}function I(e){return e.href===void 0}function L(e,t){return{uri:p(e,t.href),name:t.name,title:t.title,method:t.method||`GET`,contentType:t.type||`application/x-www-form-urlencoded`,fields:t.fields?t.fields.map(e=>R(e)):[]}}function R(e){let t={name:e.name,type:e.type||`text`,required:!1,readOnly:!1};return e.value&&(t.value=e.value),e.title&&(t.label=e.title),t}const z=async(e,t,n)=>new C({client:e,uri:t,data:await n.text(),headers:n.headers,links:x(t,n.headers.get(`Link`))});var B=class extends C{serializeBody(){throw Error(`Reserializing Collection+JSON states is not yet supported. Please log an issue in the Ketting project to help figure out how this should be done`)}};const V=async(e,t,n)=>{let r=await n.json(),i=x(t,n.headers.get(`Link`));i.add(...H(t,r));let{_embedded:a,_links:o,...s}=r;return new B({client:e,uri:t,data:s,headers:n.headers,links:i})};function H(e,t){let n=[];if(t.collection.links!==void 0)for(let r of t.collection.links)n.push({context:e,href:r.href,rel:r.rel,title:r.name});if(t.collection.items!==void 0)for(let r of t.collection.items)r.href&&n.push({context:e,href:r.href,rel:`item`});if(t.collection.queries!==void 0)for(let r of t.collection.queries)r.data?n.push({context:e,href:r.href+r.data.map(e=>`{?`+e.name+`}`).join(``),templated:!0,rel:r.rel,title:r.name}):n.push({context:e,href:r.href,rel:r.rel,title:r.name});return n}function fe(e,t){let n=r.parser(!1,{}),i=[],a=[];return n.onopentag=t=>{switch(t.name){case`LINK`:case`A`:i.push(...pe(e,t));break;case`FORM`:a.push(...me(e,t));break}},n.write(t).close(),{forms:a,links:i}}function pe(e,t){if(!t.attributes.REL||!t.attributes.HREF)return[];let n=t.attributes.REL,r=[];for(let i of n.split(` `)){let n=t.attributes.TYPE,a={rel:i,context:e,href:t.attributes.HREF};n&&(a.type=n),r.push(a)}return r}function me(e,t){let n=t.attributes.REL||null,r=t.attributes.ID||null,i=t.attributes.ACTION||``,a=t.attributes.METHOD||`GET`,o=t.attributes.ENCTYPE||`application/x-www-form-urlencoded`;if(!n)return[{rel:null,id:r,action:p(e,i),method:a,enctype:o}];let s=[];for(let t of n.split(` `))s.push({rel:t,id:r,action:p(e,i),method:a,enctype:o});return s}const he=async(e,t,n)=>{let r=await n.text(),i=x(t,n.headers.get(`Link`)),a=fe(t,r);return i.add(...a.links),new C({client:e,uri:t,data:r,headers:n.headers,links:i,actions:a.forms.map(e=>ge(t,e))})};function ge(e,t){return{uri:p(e,t.action),name:t.rel||t.id||``,method:t.method||`GET`,contentType:t.enctype||`application/x-www-form-urlencoded`,fields:[]}}const _e=async(e,t,n)=>{let r=x(t,n.headers.get(`Link`));return new S({client:e,uri:t,headers:n.headers,links:r})};var U=class{constructor(){this.prefetchEnabled=!1,this.preferTranscludeEnabled=!1,this.useHeadEnabled=!1}preFetch(){return this.prefetchEnabled=!0,this}preferTransclude(){return this.preferTranscludeEnabled=!0,this}useHead(){return this.useHeadEnabled=!0,this}},W=class e extends U{constructor(e,t,n){super(),this.resource=e,this.rel=t,this.variables=n}then(e,t){return this.fetchLinkedResource().then(e,t)}catch(e){return this.fetchLinkedResource().then(void 0,e)}finally(e){return this.then(()=>e(),()=>e())}follow(t,n){return new e(this.fetchLinkedResource(),t,n)}async get(e){return(await this).get(e)}followAll(e){return new G(this.fetchLinkedResource(),e)}async fetchLinkedResource(){let e=await this.resource,t={};!this.useHeadEnabled&&this.preferTranscludeEnabled&&(t.Prefer=`transclude=`+this.rel);let n;n=this.useHeadEnabled?await e.head({headers:t}):await e.get({headers:t});let r=n.follow(this.rel,this.variables);return this.prefetchEnabled&&r.get().catch(e=>{console.warn(`Error while prefetching linked resource`,e)}),r}},G=class extends U{constructor(e,t){super(),this.resource=e,this.rel=t}then(e,t){return this.fetchLinkedResources().then(e,t)}catch(e){return this.fetchLinkedResources().then(void 0,e)}finally(e){return this.then(()=>e(),()=>e())}async get(e){return Promise.all((await this).map(t=>t.get(e)))}async fetchLinkedResources(){let e=await this.resource,t={};!this.useHeadEnabled&&this.preferTranscludeEnabled&&(t.Prefer=`transclude=`+this.rel);let n;n=this.useHeadEnabled?await e.head({headers:t}):await e.get({headers:t});let r=n.followAll(this.rel);return this.prefetchEnabled&&r.map(e=>{e.get().catch(e=>{console.warn(`Error while prefetching linked resource`,e)})}),r}},ve=o(((e,t)=>{var n=typeof Reflect==`object`?Reflect:null,r=n&&typeof n.apply==`function`?n.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)},i=n&&typeof n.ownKeys==`function`?n.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};function a(e){console&&console.warn&&console.warn(e)}var o=Number.isNaN||function(e){return e!==e};function s(){s.init.call(this)}t.exports=s,t.exports.once=y,s.EventEmitter=s,s.prototype._events=void 0,s.prototype._eventsCount=0,s.prototype._maxListeners=void 0;var c=10;function l(e){if(typeof e!=`function`)throw TypeError(`The "listener" argument must be of type Function. Received type `+typeof e)}Object.defineProperty(s,`defaultMaxListeners`,{enumerable:!0,get:function(){return c},set:function(e){if(typeof e!=`number`||e<0||o(e))throw RangeError(`The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received `+e+`.`);c=e}}),s.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},s.prototype.setMaxListeners=function(e){if(typeof e!=`number`||e<0||o(e))throw RangeError(`The value of "n" is out of range. It must be a non-negative number. Received `+e+`.`);return this._maxListeners=e,this};function u(e){return e._maxListeners===void 0?s.defaultMaxListeners:e._maxListeners}s.prototype.getMaxListeners=function(){return u(this)},s.prototype.emit=function(e){for(var t=[],n=1;n<arguments.length;n++)t.push(arguments[n]);var i=e===`error`,a=this._events;if(a!==void 0)i&&=a.error===void 0;else if(!i)return!1;if(i){var o;if(t.length>0&&(o=t[0]),o instanceof Error)throw o;var s=Error(`Unhandled error.`+(o?` (`+o.message+`)`:``));throw s.context=o,s}var c=a[e];if(c===void 0)return!1;if(typeof c==`function`)r(c,this,t);else for(var l=c.length,u=g(c,l),n=0;n<l;++n)r(u[n],this,t);return!0};function d(e,t,n,r){var i,o,s;if(l(n),o=e._events,o===void 0?(o=e._events=Object.create(null),e._eventsCount=0):(o.newListener!==void 0&&(e.emit(`newListener`,t,n.listener?n.listener:n),o=e._events),s=o[t]),s===void 0)s=o[t]=n,++e._eventsCount;else if(typeof s==`function`?s=o[t]=r?[n,s]:[s,n]:r?s.unshift(n):s.push(n),i=u(e),i>0&&s.length>i&&!s.warned){s.warned=!0;var c=Error(`Possible EventEmitter memory leak detected. `+s.length+` `+String(t)+` listeners added. Use emitter.setMaxListeners() to increase limit`);c.name=`MaxListenersExceededWarning`,c.emitter=e,c.type=t,c.count=s.length,a(c)}return e}s.prototype.addListener=function(e,t){return d(this,e,t,!1)},s.prototype.on=s.prototype.addListener,s.prototype.prependListener=function(e,t){return d(this,e,t,!0)};function f(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length===0?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function p(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=f.bind(r);return i.listener=n,r.wrapFn=i,i}s.prototype.once=function(e,t){return l(t),this.on(e,p(this,e,t)),this},s.prototype.prependOnceListener=function(e,t){return l(t),this.prependListener(e,p(this,e,t)),this},s.prototype.removeListener=function(e,t){var n,r,i,a,o;if(l(t),r=this._events,r===void 0||(n=r[e],n===void 0))return this;if(n===t||n.listener===t)--this._eventsCount===0?this._events=Object.create(null):(delete r[e],r.removeListener&&this.emit(`removeListener`,e,n.listener||t));else if(typeof n!=`function`){for(i=-1,a=n.length-1;a>=0;a--)if(n[a]===t||n[a].listener===t){o=n[a].listener,i=a;break}if(i<0)return this;i===0?n.shift():_(n,i),n.length===1&&(r[e]=n[0]),r.removeListener!==void 0&&this.emit(`removeListener`,e,o||t)}return this},s.prototype.off=s.prototype.removeListener,s.prototype.removeAllListeners=function(e){var t,n=this._events,r;if(n===void 0)return this;if(n.removeListener===void 0)return arguments.length===0?(this._events=Object.create(null),this._eventsCount=0):n[e]!==void 0&&(--this._eventsCount===0?this._events=Object.create(null):delete n[e]),this;if(arguments.length===0){var i=Object.keys(n),a;for(r=0;r<i.length;++r)a=i[r],a!==`removeListener`&&this.removeAllListeners(a);return this.removeAllListeners(`removeListener`),this._events=Object.create(null),this._eventsCount=0,this}if(t=n[e],typeof t==`function`)this.removeListener(e,t);else if(t!==void 0)for(r=t.length-1;r>=0;r--)this.removeListener(e,t[r]);return this};function m(e,t,n){var r=e._events;if(r===void 0)return[];var i=r[t];return i===void 0?[]:typeof i==`function`?n?[i.listener||i]:[i]:n?v(i):g(i,i.length)}s.prototype.listeners=function(e){return m(this,e,!0)},s.prototype.rawListeners=function(e){return m(this,e,!1)},s.listenerCount=function(e,t){return typeof e.listenerCount==`function`?e.listenerCount(t):h.call(e,t)},s.prototype.listenerCount=h;function h(e){var t=this._events;if(t!==void 0){var n=t[e];if(typeof n==`function`)return 1;if(n!==void 0)return n.length}return 0}s.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]};function g(e,t){for(var n=Array(t),r=0;r<t;++r)n[r]=e[r];return n}function _(e,t){for(;t+1<e.length;t++)e[t]=e[t+1];e.pop()}function v(e){for(var t=Array(e.length),n=0;n<t.length;++n)t[n]=e[n].listener||e[n];return t}function y(e,t){return new Promise(function(n,r){function i(n){e.removeListener(t,a),r(n)}function a(){typeof e.removeListener==`function`&&e.removeListener(`error`,i),n([].slice.call(arguments))}x(e,t,a,{once:!0}),t!==`error`&&b(e,i,{once:!0})})}function b(e,t,n){typeof e.on==`function`&&x(e,`error`,t,n)}function x(e,t,n,r){if(typeof e.on==`function`)r.once?e.once(t,n):e.on(t,n);else if(typeof e.addEventListener==`function`)e.addEventListener(t,function i(a){r.once&&e.removeEventListener(t,i),n(a)});else throw TypeError(`The "emitter" argument must be of type EventEmitter. Received type `+typeof e)}}))();function ye(e){return!(typeof e==`string`||globalThis.Buffer&&e instanceof Buffer)}var K=class extends ve.EventEmitter{constructor(e,t){super(),this.activeRefresh=new Map,this.client=e,this.uri=t,this.setMaxListeners(500)}get(e){let t=this.getCache();if(t)return Promise.resolve(t);let n=q(`GET`,e),r=this.uri,i=J(this.uri,e);return this.activeRefresh.has(i)||this.activeRefresh.set(i,(async()=>{try{let e=await this.fetchOrThrow(n),t=await this.client.getStateForResponse(r,e);return this.updateCache(t),t}finally{this.activeRefresh.delete(i)}})()),this.activeRefresh.get(i)}async head(e){let t=this.client.cache.get(this.uri);if(t)return t;let n=await this.fetchOrThrow(q(`HEAD`,e));return t=await _e(this.client,this.uri,n),t}refresh(e){let t=q(`GET`,e);t.cache=`no-cache`;let n=this.uri,r=J(this.uri,e);return this.activeRefresh.has(r)||this.activeRefresh.set(r,(async()=>{try{let e=await this.fetchOrThrow(t),r=await this.client.getStateForResponse(n,e);return this.updateCache(r),r}finally{this.activeRefresh.delete(r)}})()),this.activeRefresh.get(r)}async put(e){let t=q(`PUT`,e);g(e)&&t.headers.set(`X-KETTING-NO-STALE`,`1`),await this.fetchOrThrow(t),g(e)&&this.updateCache(e)}async delete(){await this.fetchOrThrow({method:`DELETE`})}async post(e){let t=await this.fetchOrThrow(q(`POST`,e));return this.client.getStateForResponse(this.uri,t)}async postFollow(e){let t=await this.fetchOrThrow(q(`POST`,e));switch(t.status){case 201:if(t.headers.has(`location`))return this.go(t.headers.get(`location`));throw Error(`Could not follow after a 201 request, because the server did not reply with a Location header. If you sent a Location header, check if your service is returning "Access-Control-Expose-Headers: Location".`);case 204:case 205:return this;default:throw Error(`Did not receive a 201, 204 or 205 status code so we could not follow to the next resource`)}}async patch(e){let t=await this.fetchOrThrow(q(`PATCH`,e));if(t.status===200)return await this.client.getStateForResponse(this.uri,t)}follow(e,t){return new W(this,e,t)}followAll(e){return new G(this,e)}go(e){return typeof e==`string`?this.client.go(p(this.uri,e)):this.client.go(e)}fetch(e){return this.client.fetcher.fetch(this.uri,e)}fetchOrThrow(e){return this.client.fetcher.fetchOrThrow(this.uri,e)}updateCache(e){if(e.uri!==this.uri)throw Error(`When calling updateCache on a resource, the uri of the State object must match the uri of the Resource`);this.client.cacheState(e)}clearCache(){this.client.clearResourceCache([this.uri],[])}getCache(){return this.client.cache.get(this.uri)}async link(e){let t=(await this.get()).links.get(e);if(!t)throw new h(`Link with rel: ${e} not found on ${this.uri}`);return t}async links(e){let t=await this.get();return e?t.links.getMany(e):t.links.getAll()}async hasLink(e){return(await this.get()).links.has(e)}};function q(e,t){if(!t)return{method:e,headers:new Headers};let n;n=t.getContentHeaders?new Headers(t.getContentHeaders()):t.headers?new Headers(t.headers):new Headers,n.has(`Content-Type`)||n.set(`Content-Type`,`application/json`);let r;return t.serializeBody===void 0?t.data?(r=t.data,ye(r)&&(r=JSON.stringify(r))):r=null:r=t.serializeBody(),{method:e,body:r,headers:n}}function J(e,t){let n={};if(t){var r;new Headers(((r=t.getContentHeaders)==null?void 0:r.call(t))||t.headers).forEach((e,t)=>{n[t]=e})}let i=Object.entries(n).map(([e,t])=>e.toLowerCase()+`:`+t).join(`,`);return e+`|`+i}var Y=class{constructor(){this.cache=new Map}store(e){this.cache.set(e.uri,e.clone())}get(e){let t=this.cache.get(e);return t?t.clone():null}has(e){return this.cache.has(e)}delete(e){this.cache.delete(e)}clear(){this.cache.clear()}destroy(){}},be=class extends Y{constructor(e=3e4){super(),this.cacheTimeout=e,this.activeTimers=new Map}store(e){super.store(e),this.setTimer(e.uri)}setTimer(e){this.activeTimers.has(e)&&clearTimeout(this.activeTimers.get(e)),this.activeTimers.set(e,setTimeout(()=>{this.delete(e),this.activeTimers.delete(e)},this.cacheTimeout))}destroy(){for(let e of this.activeTimers.values())clearTimeout(e)}},xe=class{store(e){}get(e){return null}has(e){return!1}delete(e){}clear(){}};function Se(e){return async(t,r)=>{let i=!1;t.headers.has(`X-KETTING-NO-STALE`)&&(i=!0,t.headers.delete(`X-KETTING-NO-STALE`));let a=await r(t);if(te(t.method)||!a.ok)return a;let o=[],s=[];if(t.method===`DELETE`?s.push(t.url):i||o.push(t.url),a.headers.has(`Link`))for(let e of n.parse(a.headers.get(`Link`)).rel(`invalidates`)){let n=p(t.url,e.uri);o.push(n)}if(a.headers.has(`Location`)&&o.push(p(t.url,a.headers.get(`Location`))),e.clearResourceCache(o,s),t.cache!==`no-store`&&a.headers.has(`Content-Location`)){let n=p(t.url,a.headers.get(`Content-Location`)),r=await e.getStateForResponse(n,a.clone());e.cacheState(r)}return a}}function Ce(e){return async(t,n)=>{if(!t.headers.has(`Accept`)){let n=Object.entries(e.contentTypeMap).map(([e,[,t]])=>e+`;q=`+t).join(`, `);t.headers.set(`Accept`,n)}return n(t)}}function X(){return async(e,t)=>{let r=await t(e);if(r.headers.get(`Deprecation`)){let t=r.headers.get(`Sunset`),i=`[Ketting] The resource ${e.url} is deprecated.`;if(t&&(i+=` It will no longer respond `+t),r.headers.has(`Link`))for(let t of n.parse(r.headers.get(`Link`)).rel(`deprecation`)){let n=p(e.url,t.uri);i+=`See ${n} for more information.`}console.warn(i)}return r}}var Z=class{constructor(e){this.contentTypeMap={"application/prs.hal-forms+json":[T,`1.0`],"application/hal+json":[T,`0.9`],"application/vnd.api+json":[A,`0.8`],"application/vnd.siren+json":[le,`0.8`],"application/vnd.collection+json":[V,`0.8`],"application/json":[T,`0.7`],"text/html":[he,`0.6`]},this.cacheDependencies=new Map,this.bookmarkUri=e,this.fetcher=new d,this.fetcher.use(Se(this)),this.fetcher.use(Ce(this)),this.fetcher.use(X()),this.cache=new Y,this.resources=new Map}follow(e,t){return this.go().follow(e,t)}go(e){let t;if(t=e===void 0?this.bookmarkUri:typeof e==`string`?p(this.bookmarkUri,e):p(e),!this.resources.has(t)){let e=new K(this,t);return this.resources.set(t,e),e}return this.resources.get(t)}use(e,t=`*`){this.fetcher.use(e,t)}clearCache(){this.cache.clear(),this.cacheDependencies=new Map}cacheState(e){let t=$(e);for(let e of t)for(let t of e.links.getMany(`inv-by`))this.addCacheDependency(p(t),e.uri);for(let e of t)this.cache.store(e);for(let e of t){let t=this.resources.get(e.uri);t&&t.emit(`update`,e)}}addCacheDependency(e,t){this.cacheDependencies.has(e)?this.cacheDependencies.get(e).add(t):this.cacheDependencies.set(e,new Set([t]))}clearResourceCache(e,t){let n=new Set,r=new Set;for(let t of e)n.add(p(this.bookmarkUri,t));for(let e of t)n.add(p(this.bookmarkUri,e)),r.add(p(this.bookmarkUri,e));n=Q(new Set([...n,...r]),this.cacheDependencies);for(let e of n){this.cache.delete(e);let t=this.resources.get(e);t&&(r.has(e)?t.emit(`delete`):t.emit(`stale`))}}async getStateForResponse(e,t){let n=b(t.headers.get(`Content-Type`));return!n||t.status===204?k(this,e,t):n in this.contentTypeMap?this.contentTypeMap[n][0](this,e,t):n.startsWith(`text/`)?z(this,e,t):n.match(/^application\/[A-Za-z-.]+\+json/)?T(this,e,t):k(this,e,t)}};function Q(e,t,n){n||=new Set;for(let r of e)n.has(r)||(n.add(r),t.has(r)&&Q(t.get(r),t,n));return n}function $(e,t=new Set){t.add(e);for(let n of e.getEmbedded())$(n,t);return t}var we=(e,t)=>{let n=`Basic `+btoa(e+`:`+t);return(e,t)=>(e.headers.set(`Authorization`,n),t(e))},Te=e=>{let t=`Bearer `+e;return(e,n)=>(e.headers.set(`Authorization`,t),n(e))};function Ee(e,t){console.warn(`The OAuth2 middleware in Ketting is deprecated, and will be removed in the next major version of Ketting. You should upgrade to the OAuth2Fetch from the @badgateway/oauth2-client project`);let n=new i({clientId:e.clientId,clientSecret:`clientSecret`in e?e.clientSecret:void 0,tokenEndpoint:e.tokenEndpoint});return new a({client:n,getNewToken:async()=>{switch(e.grantType){case`password`:return n.password({username:e.userName,password:e.password,scope:e.scope});case`client_credentials`:return n.clientCredentials({scope:e.scope});case`authorization_code`:return n.authorizationCode.getToken({code:e.code,codeVerifier:e.codeVerifier,redirectUri:e.redirectUri});case void 0:return null}},getStoredToken:()=>t??null,storeToken:t=>{e.onTokenUpdate&&e.onTokenUpdate(t)},onError:t=>{e.onAuthError&&e.onAuthError(t)}}).mw()}export{S as BaseHeadState,C as BaseState,B as CjState,Z as Client,Z as Ketting,Z as default,G as FollowPromiseMany,W as FollowPromiseOne,Y as ForeverCache,w as HalState,h as LinkNotFound,m as Links,xe as NeverCache,c as Problem,K as Resource,be as ShortCache,M as SirenState,we as basicAuth,Te as bearerAuth,y as expand,g as isState,Ee as oauth2,p as resolve};
1
+ import e from"query-string";import*as t from"uri-template";import*as n from"http-link-header";import*as r from"sax";import{EventEmitter as i}from"events";import{OAuth2Client as a,OAuth2Fetch as o}from"@badgateway/oauth2-client";var s=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),c=class extends Error{constructor(e){super(`HTTP error `+e.status),this.response=e,this.status=e.status}},l=class extends c{constructor(e,t){super(e),this.body={type:t.type??`about:blank`,status:t.status??this.status,...t},this.body.title&&(this.message=`HTTP Error `+this.status+`: `+this.body.title)}};async function u(e){let t=e.headers.get(`Content-Type`);return t!=null&&t.match(/^application\/problem\+json/i)?new l(e,await e.json()):new c(e)}var ee=s(((e,t)=>{t.exports={name:`ketting`,version:`8.4.2`,description:`Opiniated HATEAOS / Rest client.`,main:`dist/main/index.js`,types:`dist/main/index.d.ts`,files:[`src/`,`dist/`,`LICENSE`],scripts:{test:`make test`,prepublishOnly:`make build`,build:`make build`},repository:{type:`git`,url:`git+https://github.com/badgateway/ketting.git`},keywords:[`rest`,`hypermedia`,`client`,`http`,`hateoas`,`hal`],author:`Evert Pot`,license:`MIT`,bugs:{url:`https://github.com/badgateway/ketting/issues`},homepage:`https://github.com/badgateway/ketting#readme`,engines:{node:`>=16`},dependencies:{"@badgateway/oauth2-client":`^2.0.17`,events:`^3.3.0`,"hal-types":`^3.0.0`,"http-link-header":`^1.0.3`,"query-string":`^9.3.1`,sax:`^1.2.4`,"uri-template":`^2.0.0`},devDependencies:{"@eslint/js":`^9.14.0`,"@types/chai":`^5.0.1`,"@types/http-link-header":`^1.0.2`,"@types/koa-bodyparser":`^4.3.0`,"@types/koa-logger":`^3.1.1`,"@types/koa-static":`^4.0.1`,"@types/mocha":`^10.0.0`,"@types/node":`^18.7.14`,"@types/sax":`^1.2.1`,chai:`^5.2.0`,koa:`^3.1.2`,"koa-bodyparser":`^4.3.0`,"koa-logger":`^3.2.1`,"koa-path-match":`^3.0.0`,"koa-static":`^5.0.0`,mocha:`^11.1.0`,tsdown:`^0.21.6`,tsx:`^4.19.3`,typescript:`^5.7.3`,"typescript-eslint":`^8.13.0`}}})),te=class{constructor(){this.middlewares=[],this.advertiseKetting=!0}fetch(e,t){let n=new Request(e,t),r=new URL(n.url).origin,i=this.getMiddlewaresByOrigin(r);return i.push(e=>(!e.headers.has(`User-Agent`)&&this.advertiseKetting&&e.headers.set(`User-Agent`,`Ketting/`+ee().version),fetch(e))),d(i,n)}getMiddlewaresByOrigin(e){return this.middlewares.filter(([t])=>t.test(e)).map(([,e])=>e)}use(e,t=`*`){let n=t.split(`*`).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(`(.*)`),r=RegExp(`^`+n+`$`);this.middlewares.push([r,e])}async fetchOrThrow(e,t){let n=await this.fetch(e,t);if(n.ok)return n;throw await u(n)}};function d(e,t){return e[0](t,t=>d(e.slice(1),t))}function f(e,t){let n,r;typeof e==`string`?(n=e,r=t):(n=e.context,r=e.href);let i=new URL(r,new URL(n,`http://ketting.invalid`));return i.hostname===`ketting.invalid`?i.pathname+i.search+i.hash:n.startsWith(`//`)?`//`+i.host+i.pathname+i.search+i.hash:i.toString()}var p=class e{constructor(t,n){if(this.defaultContext=t,this.store=new Map,n)if(n instanceof e)this.add(...n.getAll());else for(let e of n)this.add(e)}add(...e){let t;t=typeof e[0]==`string`?[{rel:e[0],href:e[1],context:this.defaultContext}]:e.map(e=>({context:this.defaultContext,...e}));for(let e of t)this.store.has(e.rel)?this.store.get(e.rel).push(e):this.store.set(e.rel,[e])}set(e,t){let n;n=typeof e==`string`?{rel:e,href:t,context:this.defaultContext}:{context:this.defaultContext,...e},this.store.set(n.rel,[n])}get(e){let t=this.store.get(e);if(!(!t||t.length<0))return t[0]}delete(e,t){if(t===void 0){this.store.delete(e);return}let n=this.store.get(e);if(!n)return;this.store.delete(e);let r=f(this.defaultContext,t);this.store.set(e,n.filter(e=>f(e)!==r))}getMany(e){return this.store.get(e)||[]}getAll(){let e=[];for(let t of this.store.values())e.push(...t);return e}has(e){return this.store.has(e)}},m=class extends Error{};function h(e){return typeof e.uri==`string`&&e.links instanceof p&&e.headers instanceof Headers}var g=class{constructor(e,t){this.client=e;for(let[e,n]of Object.entries(t))this[e]=n}async submit(t){let n=new URL(this.uri),r=this.validateForm(t);if(this.method===`GET`)return n.search=e.stringify(r),this.client.go(n.toString()).get();let i=await this.fetchOrThrowWithBody(n,r);return this.client.getStateForResponse(n.toString(),i)}async submitFollow(t){let n=new URL(this.uri),r=this.validateForm(t);if(this.method===`GET`)return n.search=e.stringify(r),this.client.go(n.toString());let i=await this.fetchOrThrowWithBody(n,r);switch(i.status){case 201:if(i.headers.has(`location`))return this.client.go(i.headers.get(`location`));throw Error(`Could not follow after a 201 request, because the server did not reply with a Location header. If you sent a Location header, check if your service is returning "Access-Control-Expose-Headers: Location".`);case 204:case 205:return this.client.go(n.toString());default:throw Error(`Did not receive a 201, 204 or 205 status code so we could not follow to the next resource`)}}validateForm(e){let t={...e};for(let n of this.fields)if(!(n.name in e)){if(n.value)t[n.name]=n.value;else if(n.required)throw Error(`The ${n.name} field is required in this form`)}return t}fetchOrThrowWithBody(t,n){let r;switch(this.contentType){case`application/x-www-form-urlencoded`:r=e.stringify(n);break;case`application/json`:r=JSON.stringify(n);break;default:throw Error(`Serializing mimetype ${this.contentType} is not yet supported in actions`)}return this.client.fetcher.fetchOrThrow(t.toString(),{method:this.method,body:r,headers:{"Content-Type":this.contentType}})}field(e){return this.fields.find(t=>t.name===e)}},_=class extends Error{};function v(e,n,r){let i,a,o;typeof e==`string`?(i=e,a=n,o=r):(i=e.context,a=e.href,o=n);let s=t.parse(a).expand(o);return f(i,s)}function ne(e){return e?(e.includes(`;`)&&(e=e.split(`;`)[0]),e.trim()):null}function y(e,t){let r=new p(e);if(!t)return r;for(let i of n.parse(t).refs)for(let t of i.rel.split(` `)){let n={rel:t,href:i.uri,context:e,title:i.title,hreflang:i.hreflang,type:i.type};r.add(n)}return r}const re=[`GET`,`HEAD`,`OPTIONS`,`PRI`,`PROPFIND`,`REPORT`,`SEARCH`,`TRACE`];function ie(e){return re.includes(e)}const b=[`Content-Type`,`Content-Language`,`Content-Location`,`Deprecation`,`ETag`,`Expires`,`Last-Modified`,`Sunset`,`Title`,`Warning`];var x=class{constructor(e){this.client=e.client,this.uri=e.uri,this.headers=e.headers,this.timestamp=Date.now(),this.links=e.links}follow(e,t){var n;let r=this.links.get(e);if(!r)throw new m(`Link with rel ${e} on ${this.uri} not found`);let i;return i=r.templated?v(r,t||{}):f(r),((n=r.hints)==null?void 0:n.status)===`deprecated`&&console.warn(`[ketting] The ${r.rel} link on ${this.uri} is marked deprecated.`,r),this.client.go(i)}followAll(e){return this.links.getMany(e).map(e=>{var t;((t=e.hints)==null?void 0:t.status)===`deprecated`&&console.warn(`[ketting] The ${e.rel} link on ${this.uri} is marked deprecated.`,e);let n=f(e);return this.client.go(n)})}contentHeaders(){let e={};for(let t of b)this.headers.has(t)&&(e[t]=this.headers.get(t));return new Headers(e)}},S=class e extends x{constructor(e){super(e),this.data=e.data,this.actionInfo=e.actions||[],this.embedded=e.embedded||[]}action(e){let t=this.doFindAction(e);if(t===`NO_ACTION_DEFINED`)throw new _(`This State does not define any actions`);if(t===`NO_ACTION_FOR_THE_PROVIDED_NAME`)throw new _(`This State defines no action`);return t}findAction(e){let t=this.doFindAction(e);if(typeof t==`object`)return t}doFindAction(e){if(!this.actionInfo.length)return`NO_ACTION_DEFINED`;if(e===void 0)return new g(this.client,this.actionInfo[0]);for(let t of this.actionInfo)if(t.name===e)return new g(this.client,t);return`NO_ACTION_FOR_THE_PROVIDED_NAME`}actions(){return this.actionInfo.map(e=>new g(this.client,e))}hasAction(e){if(e===void 0)return this.actionInfo.length>0;for(let t of this.actionInfo)if(e===t.name)return!0;return!1}serializeBody(){return globalThis.Buffer&&this.data instanceof Buffer||globalThis.Blob&&this.data instanceof Blob||typeof this.data==`string`?this.data:JSON.stringify(this.data)}getEmbedded(){return this.embedded}clone(){return new e({client:this.client,uri:this.uri,data:this.data,headers:new Headers(this.headers),links:new p(this.links.defaultContext,this.links.getAll()),actions:this.actionInfo})}},C=class e extends S{serializeBody(){return JSON.stringify({_links:this.serializeLinks(),...this.data})}serializeLinks(){let e={self:{href:this.uri}};for(let t of this.links.getAll()){let{rel:n,context:r,...i}=t;n!==`self`&&(e[n]===void 0?e[n]=i:Array.isArray(e[n])?e[n].push(i):e[n]=[e[n],i])}return e}clone(){return new e({client:this.client,uri:this.uri,data:this.data,headers:new Headers(this.headers),links:new p(this.links.defaultContext,this.links.getAll()),actions:this.actionInfo})}};const w=async(e,t,n)=>{let r=await n.json(),i=y(t,n.headers.get(`Link`));if(Array.isArray(r))return new C({client:e,uri:t,data:r,headers:n.headers,links:i});i.add(...T(t,r));let{_embedded:a,_links:o,_templates:s,...c}=r;return new C({client:e,uri:t,data:c,headers:n.headers,links:i,embedded:D(e,t,r,n.headers),actions:O(t,r)})};function T(e,t){if(t._links===void 0)return[];let n=[],r=new Set;for(let[i,a]of Object.entries(t._links)){let t=Array.isArray(a)?a:[a];for(let e of t)r.add(i+`;`+e.href);n.push(...E(e,i,t))}if(t._embedded)for(let[a,o]of Object.entries(t._embedded))for(let t of Array.isArray(o)?o:[o]){var i;let o=t==null||(i=t._links)==null||(i=i.self)==null?void 0:i.href;o&&(r.has(a+`;`+o)||n.push({rel:a,href:o,context:e}))}return n}function E(e,t,n){let r=[];for(let i of n)r.push({rel:t,context:e,...i});return r}function D(e,t,n,r){if(n._embedded===void 0||!n._embedded)return[];let i=[];for(let s of Object.values(n._embedded)){let n;n=Array.isArray(s)?s:[s];for(let s of n){var a,o;if(((a=s._links)==null||(a=a.self)==null?void 0:a.href)===void 0){console.warn(`An item in _embedded was ignored. Each item must have a single "self" link`);continue}let n=f(t,(o=s._links)==null||(o=o.self)==null?void 0:o.href),{_embedded:c,_links:l,...u}=s;i.push(new C({client:e,uri:n,data:u,headers:new Headers({"Content-Type":r.get(`Content-Type`)}),links:new p(n,T(t,s)),embedded:D(e,n,s,r),actions:O(n,s)}))}}return i}function O(e,t){return t._templates?Object.entries(t._templates).map(([t,n])=>({uri:f(e,n.target||``),name:t,title:n.title,method:n.method,contentType:n.contentType||`application/json`,fields:n.properties?n.properties.map(e=>ae(e)).filter(e=>!!e):[]})):[]}function ae(e){switch(e.type){case void 0:case`text`:case`search`:case`tel`:case`url`:case`email`:if(e.options){let t=!(`maxItems`in e.options)||!e.options.maxItems||e.options.maxItems>1,n={name:e.name,type:`select`,label:e.prompt,required:e.required||!1,readOnly:e.readOnly||!1,value:e.options.selectedValues||e.value},r=oe(e.options);if(t)return{multiple:!0,selectedValues:e.options.selectedValues,...n,...r};{let i=e.options.selectedValues,a;return i&&(i.length===1?a=i[0]:i.length>1&&console.warn(`More than 1 selected value received for single select field ${n.name}. Ignoring all selected values for this field.`)),{multiple:t,selectedValue:a,...n,...r}}}else return{name:e.name,type:e.type??`text`,required:e.required||!1,readOnly:e.readOnly||!1,value:e.value,pattern:e.regex?new RegExp(e.regex):void 0,label:e.prompt,placeholder:e.placeholder,minLength:e.minLength,maxLength:e.maxLength};case`hidden`:return{name:e.name,type:`hidden`,required:e.required||!1,readOnly:e.readOnly||!1,value:e.value,label:e.prompt,placeholder:e.placeholder};case`textarea`:return{name:e.name,type:e.type,required:e.required||!1,readOnly:e.readOnly||!1,value:e.value,label:e.prompt,placeholder:e.placeholder,cols:e.cols,rows:e.rows,minLength:e.minLength,maxLength:e.maxLength};case`password`:return{name:e.name,type:e.type,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,placeholder:e.placeholder,minLength:e.minLength,maxLength:e.maxLength};case`date`:case`month`:case`week`:case`time`:return{name:e.name,type:e.type,value:e.value,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,min:e.min,max:e.max,step:e.step};case`number`:case`range`:return{name:e.name,type:e.type,value:e.value?+e.value:void 0,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,min:e.min,max:e.max,step:e.step};case`datetime-local`:return{name:e.name,type:e.type,value:e.value?new Date(e.value):void 0,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,min:e.min,max:e.max,step:e.step};case`color`:return{name:e.name,type:e.type,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,value:e.value};case`radio`:case`checkbox`:return{name:e.name,type:e.type,required:e.required||!1,readOnly:e.readOnly||!1,label:e.prompt,value:!!e.value};default:return}}function oe(e){let t=e.promptField||`prompt`,n=e.valueField||`value`;if(se(e)){let r={};for(let i of e.inline)typeof i==`string`?r[i]=i:r[i[n]]=i[t];return{options:r}}else return{dataSource:{href:e.link.href,type:e.link.type,labelField:t,valueField:n}}}function se(e){return e.inline!==void 0}const k=async(e,t,n)=>new S({client:e,uri:t,data:await n.blob(),headers:n.headers,links:y(t,n.headers.get(`Link`))}),ce=async(e,t,n)=>{let r=await n.json(),i=y(t,n.headers.get(`Link`));return i.add(...le(t,r),...ue(t,r)),new S({client:e,uri:t,data:r,headers:n.headers,links:i})};function le(e,t){let n=[];if(t.links===void 0)return n;for(let[r,i]of Object.entries(t.links))Array.isArray(i)?n.push(...i.map(t=>A(e,r,t))):n.push(A(e,r,i));return n}function ue(e,t){if(!Array.isArray(t.data))return[];let n=[];for(let r of t.data)if(`links`in r&&`self`in r.links){let t=A(e,`self`,r.links.self);n.push({context:e,href:t.href,rel:`item`})}return n}function A(e,t,n){return{context:e,rel:t,href:typeof n==`string`?n:n.href}}var j=class e extends S{serializeBody(){throw Error(`Reserializing Siren states is not yet supported. Please log an issue in the Ketting project to help figure out how this should be done`)}clone(){return new e({client:this.client,uri:this.uri,data:this.data,headers:new Headers(this.headers),links:new p(this.uri,this.links),actions:this.actionInfo})}};const de=async(e,t,n)=>{let r=await n.json(),i=y(t,n.headers.get(`Link`));return i.add(...M(t,r)),new j({client:e,uri:t,data:r.properties,headers:n.headers,links:i,embedded:P(e,t,r,n.headers),actions:r.actions?r.actions.map(e=>R(t,e)):[]})};function M(e,t){let n=[];if(t.links!==void 0)for(let r of t.links)n.push(...N(e,r));if(t.entities!==void 0)for(let r of t.entities)r.href===void 0?n.push(...F(e,r)):n.push(...N(e,r));return n}function N(e,t){let n=[],{rel:r,...i}=t;for(let t of r){let r={rel:t,context:e,...i};n.push(r)}return n}function P(e,t,n,r){if(n.entities===void 0)return[];let i=[];for(let a of n.entities)if(L(a)){let n=I(e,t,a,r);n!==null&&i.push(n)}return i}function F(e,t){if(t.links===void 0)return[];let n=null;for(let e of t.links)e.rel.includes(`self`)&&(n=e.href);return n===null?[]:t.rel.map(r=>{let i=t.title,a={href:n,rel:r,context:e};return i&&(a.title=i),a})}function I(e,t,n,r){if(n.links===void 0)return null;let i=null;for(let e of n.links)e.rel.includes(`self`)&&(i=e.href);return i?new j({client:e,uri:f(t,i),data:n.properties,headers:r,links:new p(i,M(i,n))}):null}function L(e){return e.href===void 0}function R(e,t){return{uri:f(e,t.href),name:t.name,title:t.title,method:t.method||`GET`,contentType:t.type||`application/x-www-form-urlencoded`,fields:t.fields?t.fields.map(e=>z(e)):[]}}function z(e){let t={name:e.name,type:e.type||`text`,required:!1,readOnly:!1};return e.value&&(t.value=e.value),e.title&&(t.label=e.title),t}const B=async(e,t,n)=>new S({client:e,uri:t,data:await n.text(),headers:n.headers,links:y(t,n.headers.get(`Link`))});var V=class extends S{serializeBody(){throw Error(`Reserializing Collection+JSON states is not yet supported. Please log an issue in the Ketting project to help figure out how this should be done`)}};const H=async(e,t,n)=>{let r=await n.json(),i=y(t,n.headers.get(`Link`));i.add(...fe(t,r));let{_embedded:a,_links:o,...s}=r;return new V({client:e,uri:t,data:s,headers:n.headers,links:i})};function fe(e,t){let n=[];if(t.collection.links!==void 0)for(let r of t.collection.links)n.push({context:e,href:r.href,rel:r.rel,title:r.name});if(t.collection.items!==void 0)for(let r of t.collection.items)r.href&&n.push({context:e,href:r.href,rel:`item`});if(t.collection.queries!==void 0)for(let r of t.collection.queries)r.data?n.push({context:e,href:r.href+r.data.map(e=>`{?`+e.name+`}`).join(``),templated:!0,rel:r.rel,title:r.name}):n.push({context:e,href:r.href,rel:r.rel,title:r.name});return n}function pe(e,t){let n=r.parser(!1,{}),i=[],a=[];return n.onopentag=t=>{switch(t.name){case`LINK`:case`A`:i.push(...me(e,t));break;case`FORM`:a.push(...he(e,t));break}},n.write(t).close(),{forms:a,links:i}}function me(e,t){if(!t.attributes.REL||!t.attributes.HREF)return[];let n=t.attributes.REL,r=[];for(let i of n.split(` `)){let n=t.attributes.TYPE,a={rel:i,context:e,href:t.attributes.HREF};n&&(a.type=n),r.push(a)}return r}function he(e,t){let n=t.attributes.REL||null,r=t.attributes.ID||null,i=t.attributes.ACTION||``,a=t.attributes.METHOD||`GET`,o=t.attributes.ENCTYPE||`application/x-www-form-urlencoded`;if(!n)return[{rel:null,id:r,action:f(e,i),method:a,enctype:o}];let s=[];for(let t of n.split(` `))s.push({rel:t,id:r,action:f(e,i),method:a,enctype:o});return s}const ge=async(e,t,n)=>{let r=await n.text(),i=y(t,n.headers.get(`Link`)),a=pe(t,r);return i.add(...a.links),new S({client:e,uri:t,data:r,headers:n.headers,links:i,actions:a.forms.map(e=>_e(t,e))})};function _e(e,t){return{uri:f(e,t.action),name:t.rel||t.id||``,method:t.method||`GET`,contentType:t.enctype||`application/x-www-form-urlencoded`,fields:[]}}const ve=async(e,t,n)=>{let r=y(t,n.headers.get(`Link`));return new x({client:e,uri:t,headers:n.headers,links:r})};var U=class{constructor(){this.prefetchEnabled=!1,this.preferTranscludeEnabled=!1,this.useHeadEnabled=!1}preFetch(){return this.prefetchEnabled=!0,this}preferTransclude(){return this.preferTranscludeEnabled=!0,this}useHead(){return this.useHeadEnabled=!0,this}},W=class e extends U{constructor(e,t,n){super(),this.resource=e,this.rel=t,this.variables=n}then(e,t){return this.fetchLinkedResource().then(e,t)}catch(e){return this.fetchLinkedResource().then(void 0,e)}finally(e){return this.then(()=>e(),()=>e())}follow(t,n){return new e(this.fetchLinkedResource(),t,n)}async get(e){return(await this).get(e)}followAll(e){return new G(this.fetchLinkedResource(),e)}async fetchLinkedResource(){let e=await this.resource,t={};!this.useHeadEnabled&&this.preferTranscludeEnabled&&(t.Prefer=`transclude=`+this.rel);let n;n=this.useHeadEnabled?await e.head({headers:t}):await e.get({headers:t});let r=n.follow(this.rel,this.variables);return this.prefetchEnabled&&r.get().catch(e=>{console.warn(`Error while prefetching linked resource`,e)}),r}},G=class extends U{constructor(e,t){super(),this.resource=e,this.rel=t}then(e,t){return this.fetchLinkedResources().then(e,t)}catch(e){return this.fetchLinkedResources().then(void 0,e)}finally(e){return this.then(()=>e(),()=>e())}async get(e){return Promise.all((await this).map(t=>t.get(e)))}async fetchLinkedResources(){let e=await this.resource,t={};!this.useHeadEnabled&&this.preferTranscludeEnabled&&(t.Prefer=`transclude=`+this.rel);let n;n=this.useHeadEnabled?await e.head({headers:t}):await e.get({headers:t});let r=n.followAll(this.rel);return this.prefetchEnabled&&r.map(e=>{e.get().catch(e=>{console.warn(`Error while prefetching linked resource`,e)})}),r}};function ye(e){return!(typeof e==`string`||globalThis.Buffer&&e instanceof Buffer)}var K=class extends i{constructor(e,t){super(),this.activeRefresh=new Map,this.client=e,this.uri=t,this.setMaxListeners(500)}get(e){let t=this.getCache();if(t)return Promise.resolve(t);let n=q(`GET`,e),r=this.uri,i=J(this.uri,e);return this.activeRefresh.has(i)||this.activeRefresh.set(i,(async()=>{try{let e=await this.fetchOrThrow(n),t=await this.client.getStateForResponse(r,e);return this.updateCache(t),t}finally{this.activeRefresh.delete(i)}})()),this.activeRefresh.get(i)}async head(e){let t=this.client.cache.get(this.uri);if(t)return t;let n=await this.fetchOrThrow(q(`HEAD`,e));return t=await ve(this.client,this.uri,n),t}refresh(e){let t=q(`GET`,e);t.cache=`no-cache`;let n=this.uri,r=J(this.uri,e);return this.activeRefresh.has(r)||this.activeRefresh.set(r,(async()=>{try{let e=await this.fetchOrThrow(t),r=await this.client.getStateForResponse(n,e);return this.updateCache(r),r}finally{this.activeRefresh.delete(r)}})()),this.activeRefresh.get(r)}async put(e){let t=q(`PUT`,e);h(e)&&t.headers.set(`X-KETTING-NO-STALE`,`1`),await this.fetchOrThrow(t),h(e)&&this.updateCache(e)}async delete(){await this.fetchOrThrow({method:`DELETE`})}async post(e){let t=await this.fetchOrThrow(q(`POST`,e));return this.client.getStateForResponse(this.uri,t)}async postFollow(e){let t=await this.fetchOrThrow(q(`POST`,e));switch(t.status){case 201:if(t.headers.has(`location`))return this.go(t.headers.get(`location`));throw Error(`Could not follow after a 201 request, because the server did not reply with a Location header. If you sent a Location header, check if your service is returning "Access-Control-Expose-Headers: Location".`);case 204:case 205:return this;default:throw Error(`Did not receive a 201, 204 or 205 status code so we could not follow to the next resource`)}}async patch(e){let t=await this.fetchOrThrow(q(`PATCH`,e));if(t.status===200)return await this.client.getStateForResponse(this.uri,t)}follow(e,t){return new W(this,e,t)}followAll(e){return new G(this,e)}go(e){return typeof e==`string`?this.client.go(f(this.uri,e)):this.client.go(e)}fetch(e){return this.client.fetcher.fetch(this.uri,e)}fetchOrThrow(e){return this.client.fetcher.fetchOrThrow(this.uri,e)}updateCache(e){if(e.uri!==this.uri)throw Error(`When calling updateCache on a resource, the uri of the State object must match the uri of the Resource`);this.client.cacheState(e)}clearCache(){this.client.clearResourceCache([this.uri],[])}getCache(){return this.client.cache.get(this.uri)}async link(e){let t=(await this.get()).links.get(e);if(!t)throw new m(`Link with rel: ${e} not found on ${this.uri}`);return t}async links(e){let t=await this.get();return e?t.links.getMany(e):t.links.getAll()}async hasLink(e){return(await this.get()).links.has(e)}};function q(e,t){if(!t)return{method:e,headers:new Headers};let n;n=t.getContentHeaders?new Headers(t.getContentHeaders()):t.headers?new Headers(t.headers):new Headers,n.has(`Content-Type`)||n.set(`Content-Type`,`application/json`);let r;return t.serializeBody===void 0?t.data?(r=t.data,ye(r)&&(r=JSON.stringify(r))):r=null:r=t.serializeBody(),{method:e,body:r,headers:n}}function J(e,t){let n={};if(t){var r;new Headers(((r=t.getContentHeaders)==null?void 0:r.call(t))||t.headers).forEach((e,t)=>{n[t]=e})}let i=Object.entries(n).map(([e,t])=>e.toLowerCase()+`:`+t).join(`,`);return e+`|`+i}var Y=class{constructor(){this.cache=new Map}store(e){this.cache.set(e.uri,e.clone())}get(e){let t=this.cache.get(e);return t?t.clone():null}has(e){return this.cache.has(e)}delete(e){this.cache.delete(e)}clear(){this.cache.clear()}destroy(){}},be=class extends Y{constructor(e=3e4){super(),this.cacheTimeout=e,this.activeTimers=new Map}store(e){super.store(e),this.setTimer(e.uri)}setTimer(e){this.activeTimers.has(e)&&clearTimeout(this.activeTimers.get(e)),this.activeTimers.set(e,setTimeout(()=>{this.delete(e),this.activeTimers.delete(e)},this.cacheTimeout))}destroy(){for(let e of this.activeTimers.values())clearTimeout(e)}},xe=class{store(e){}get(e){return null}has(e){return!1}delete(e){}clear(){}};function Se(e){return async(t,r)=>{let i=!1;t.headers.has(`X-KETTING-NO-STALE`)&&(i=!0,t.headers.delete(`X-KETTING-NO-STALE`));let a=await r(t);if(ie(t.method)||!a.ok)return a;let o=[],s=[];if(t.method===`DELETE`?s.push(t.url):i||o.push(t.url),a.headers.has(`Link`))for(let e of n.parse(a.headers.get(`Link`)).rel(`invalidates`)){let n=f(t.url,e.uri);o.push(n)}if(a.headers.has(`Location`)&&o.push(f(t.url,a.headers.get(`Location`))),e.clearResourceCache(o,s),t.cache!==`no-store`&&a.headers.has(`Content-Location`)){let n=f(t.url,a.headers.get(`Content-Location`)),r=await e.getStateForResponse(n,a.clone());e.cacheState(r)}return a}}function Ce(e){return async(t,n)=>{if(!t.headers.has(`Accept`)){let n=Object.entries(e.contentTypeMap).map(([e,[,t]])=>e+`;q=`+t).join(`, `);t.headers.set(`Accept`,n)}return n(t)}}function X(){return async(e,t)=>{let r=await t(e);if(r.headers.get(`Deprecation`)){let t=r.headers.get(`Sunset`),i=`[Ketting] The resource ${e.url} is deprecated.`;if(t&&(i+=` It will no longer respond `+t),r.headers.has(`Link`))for(let t of n.parse(r.headers.get(`Link`)).rel(`deprecation`)){let n=f(e.url,t.uri);i+=`See ${n} for more information.`}console.warn(i)}return r}}var Z=class{constructor(e){this.contentTypeMap={"application/prs.hal-forms+json":[w,`1.0`],"application/hal+json":[w,`0.9`],"application/vnd.api+json":[ce,`0.8`],"application/vnd.siren+json":[de,`0.8`],"application/vnd.collection+json":[H,`0.8`],"application/json":[w,`0.7`],"text/html":[ge,`0.6`]},this.cacheDependencies=new Map,this.bookmarkUri=e,this.fetcher=new te,this.fetcher.use(Se(this)),this.fetcher.use(Ce(this)),this.fetcher.use(X()),this.cache=new Y,this.resources=new Map}follow(e,t){return this.go().follow(e,t)}go(e){let t;if(t=e===void 0?this.bookmarkUri:typeof e==`string`?f(this.bookmarkUri,e):f(e),!this.resources.has(t)){let e=new K(this,t);return this.resources.set(t,e),e}return this.resources.get(t)}use(e,t=`*`){this.fetcher.use(e,t)}clearCache(){this.cache.clear(),this.cacheDependencies=new Map}cacheState(e){let t=$(e);for(let e of t)for(let t of e.links.getMany(`inv-by`))this.addCacheDependency(f(t),e.uri);for(let e of t)this.cache.store(e);for(let e of t){let t=this.resources.get(e.uri);t&&t.emit(`update`,e)}}addCacheDependency(e,t){this.cacheDependencies.has(e)?this.cacheDependencies.get(e).add(t):this.cacheDependencies.set(e,new Set([t]))}clearResourceCache(e,t){let n=new Set,r=new Set;for(let t of e)n.add(f(this.bookmarkUri,t));for(let e of t)n.add(f(this.bookmarkUri,e)),r.add(f(this.bookmarkUri,e));n=Q(new Set([...n,...r]),this.cacheDependencies);for(let e of n){this.cache.delete(e);let t=this.resources.get(e);t&&(r.has(e)?t.emit(`delete`):t.emit(`stale`))}}async getStateForResponse(e,t){let n=ne(t.headers.get(`Content-Type`));return!n||t.status===204?k(this,e,t):n in this.contentTypeMap?this.contentTypeMap[n][0](this,e,t):n.startsWith(`text/`)?B(this,e,t):n.match(/^application\/[A-Za-z-.]+\+json/)?w(this,e,t):k(this,e,t)}};function Q(e,t,n){n||=new Set;for(let r of e)n.has(r)||(n.add(r),t.has(r)&&Q(t.get(r),t,n));return n}function $(e,t=new Set){t.add(e);for(let n of e.getEmbedded())$(n,t);return t}var we=(e,t)=>{let n=`Basic `+btoa(e+`:`+t);return(e,t)=>(e.headers.set(`Authorization`,n),t(e))},Te=e=>{let t=`Bearer `+e;return(e,n)=>(e.headers.set(`Authorization`,t),n(e))};function Ee(e,t){console.warn(`The OAuth2 middleware in Ketting is deprecated, and will be removed in the next major version of Ketting. You should upgrade to the OAuth2Fetch from the @badgateway/oauth2-client project`);let n=new a({clientId:e.clientId,clientSecret:`clientSecret`in e?e.clientSecret:void 0,tokenEndpoint:e.tokenEndpoint});return new o({client:n,getNewToken:async()=>{switch(e.grantType){case`password`:return n.password({username:e.userName,password:e.password,scope:e.scope});case`client_credentials`:return n.clientCredentials({scope:e.scope});case`authorization_code`:return n.authorizationCode.getToken({code:e.code,codeVerifier:e.codeVerifier,redirectUri:e.redirectUri});case void 0:return null}},getStoredToken:()=>t??null,storeToken:t=>{e.onTokenUpdate&&e.onTokenUpdate(t)},onError:t=>{e.onAuthError&&e.onAuthError(t)}}).mw()}export{x as BaseHeadState,S as BaseState,V as CjState,Z as Client,Z as Ketting,Z as default,G as FollowPromiseMany,W as FollowPromiseOne,Y as ForeverCache,C as HalState,m as LinkNotFound,p as Links,xe as NeverCache,l as Problem,K as Resource,be as ShortCache,j as SirenState,we as basicAuth,Te as bearerAuth,v as expand,h as isState,Ee as oauth2,f as resolve};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["parseLink","factory","parseLink","factory","parseLink","factory","parseLink","factory","parseLink","factory","parseLink","factory","parseLink","factory","parseLink","parseLink","EventEmitter","headStateFactory","halStateFactory","jsonApiStateFactory","sirenStateFactory","cjStateFactory","htmlStateFactory","cacheExpireMiddleware","acceptMiddleware","warningMiddleware","binaryStateFactory","textStateFactory"],"sources":["../../src/http/error.ts","../../package.json","../../src/http/fetcher.ts","../../src/util/uri.ts","../../src/link.ts","../../src/state/interface.ts","../../src/action.ts","../../src/util/uri-template.ts","../../src/http/util.ts","../../src/state/base-state.ts","../../src/state/hal.ts","../../src/state/binary.ts","../../src/state/jsonapi.ts","../../src/state/siren.ts","../../src/state/text.ts","../../src/state/collection-json.ts","../../src/util/html.ts","../../src/state/html.ts","../../src/state/head.ts","../../src/follow-promise.ts","../../node_modules/events/events.js","../../src/util/fetch-body-helper.ts","../../src/resource.ts","../../src/cache/forever.ts","../../src/cache/short.ts","../../src/cache/never.ts","../../src/middlewares/cache.ts","../../src/middlewares/accept-header.ts","../../src/middlewares/warning.ts","../../src/client.ts","../../src/http/basic-auth.ts","../../src/http/bearer-auth.ts","../../src/http/oauth2.ts"],"sourcesContent":["/**\n * HttpError extends the Error object, and is thrown wheenever servers emit\n * HTTP errors.\n *\n * It has a response property, allowing users to find out more about the\n * nature of the error.\n */\nexport class HttpError extends Error {\n\n response: Response;\n status: number;\n\n constructor(response: Response) {\n super('HTTP error ' + response.status);\n this.response = response;\n this.status = response.status;\n }\n\n}\n\n/**\n * Problem extends the HttpError object. If a server emits a HTTP error, and\n * the response body's content-type is application/problem+json.\n *\n * application/problem+json is defined in RFC7807 and provides a standardized\n * way to describe error conditions by a HTTP server.\n */\nexport class Problem extends HttpError {\n\n body: {\n type: string;\n title?: string;\n status: number;\n detail?: string;\n instance?: string;\n [x: string]: any;\n };\n\n constructor(response: Response, problemBody: Record<string, any>) {\n super(response);\n\n this.body = {\n type: problemBody.type ?? 'about:blank',\n status: problemBody.status ?? this.status,\n ...problemBody\n };\n\n if (this.body.title) {\n this.message = 'HTTP Error ' + this.status + ': ' + this.body.title;\n }\n }\n\n}\n\n/**\n * This function creates problems, not unlike the the author of this file.\n *\n * It takes a Fetch Response object, and returns a HttpError. If the HTTP\n * response has a type of application/problem+json it will return a Problem\n * object.\n *\n * Because parsing the response might be asynchronous, the function returns\n * a Promise resolving in either object.\n */\nexport default async function problemFactory(response: Response): Promise<HttpError | Problem> {\n\n const contentType = response.headers.get('Content-Type');\n if (contentType?.match(/^application\\/problem\\+json/i)) {\n const problemBody = await response.json();\n return new Problem(response, problemBody);\n } else {\n return new HttpError(response);\n }\n\n}\n\n","","import problemFactory from './error';\n\nexport type FetchMiddleware =\n (request: Request, next: (request: Request) => Promise<Response>) => Promise<Response>;\n\n/**\n * The fetcher object is responsible for calling fetch()\n *\n * This is wrapped in an object because we want to support\n * 'fetch middlewares'. These middlewares are similar to server-side\n * middlewares and can intercept requests and alter requests/responses.\n */\nexport class Fetcher {\n\n middlewares: [RegExp, FetchMiddleware][] = [];\n\n advertiseKetting: boolean = true;\n\n /**\n * A wrapper for MDN fetch()\n *\n * This wrapper supports 'fetch middlewares'. It will call them\n * in sequence.\n */\n fetch(resource: string|Request, init?: RequestInit): Promise<Response> {\n\n const request = new Request(resource, init);\n\n const origin = new URL(request.url).origin;\n const mws = this.getMiddlewaresByOrigin(origin);\n mws.push((innerRequest: Request) => {\n\n if (!innerRequest.headers.has('User-Agent') && this.advertiseKetting) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n innerRequest.headers.set('User-Agent', 'Ketting/' + require('../../package.json').version);\n }\n\n return fetch(innerRequest);\n });\n\n return invokeMiddlewares(mws, request);\n\n }\n\n /**\n * Returns the list of middlewares that are applicable to\n * a specific origin\n */\n getMiddlewaresByOrigin(origin: string): FetchMiddleware[] {\n\n return this.middlewares.filter( ([regex]) => {\n return regex.test(origin);\n\n }).map( ([, middleware]) => {\n return middleware;\n });\n\n }\n\n /**\n * Add a middleware\n */\n use(mw: FetchMiddleware, origin: string = '*'): void {\n\n const matchSplit = origin.split('*');\n const matchRegex = matchSplit.map(\n part =>\n part.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n ).join('(.*)');\n\n const regex = new RegExp('^' + matchRegex + '$');\n this.middlewares.push([regex, mw]);\n\n }\n\n /**\n * Does a HTTP request and throws an exception if the server emitted\n * a HTTP error.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Request/Request\n */\n async fetchOrThrow(resource: string|Request, init?: RequestInit): Promise<Response> {\n\n const response = await this.fetch(resource, init);\n\n if (response.ok) {\n return response;\n } else {\n throw await problemFactory(response);\n }\n\n }\n\n}\nexport default Fetcher;\n\nfunction invokeMiddlewares(mws: FetchMiddleware[], request: Request): Promise<Response> {\n\n return mws[0](\n request,\n (nextRequest: Request) => {\n return invokeMiddlewares(mws.slice(1), nextRequest);\n }\n );\n\n}\n","import { Link } from '../link';\n\ntype UrlParts = {\n host?: string|null;\n};\n\n/**\n * Resolves a relative url using another url.\n *\n * This is the node.js version.\n */\nexport function resolve(base: string, relative: string): string;\nexport function resolve(link: Link): string;\nexport function resolve(arg1: string|Link, arg2?: string): string {\n\n\n // Normalize the 2 calling conventions\n let base, relative;\n if (typeof arg1==='string') {\n base = arg1;\n relative = arg2 as string;\n } else {\n base = arg1.context;\n relative = arg1.href;\n }\n\n // Our resolve function allows both parts to be relative, and new URL\n // requires the second argument to be absolute, so we wil use the RFC6761\n // 'invalid' domain as a base, so we can later strip it out.\n const newUrl = new URL(relative, new URL(base, 'http://ketting.invalid'));\n\n if (newUrl.hostname === 'ketting.invalid') {\n // Make the URL relative again if it contained 'ketting.invalid'\n return newUrl.pathname + newUrl.search + newUrl.hash;\n } else if (base.startsWith('//')) {\n // if the 'base' started with `//` it means it's a protocol-relative URL.\n // We want to make sure we retain that and don't accidentally add the `http`\n // from ketting.invalid\n return '//' + newUrl.host + newUrl.pathname + newUrl.search + newUrl.hash;\n } else {\n return newUrl.toString();\n }\n\n}\n\n/**\n * Parses a url in multiple components.\n *\n * This is the node.js version.\n */\nexport function parse(url: string): UrlParts {\n\n const parsed = new URL(url, 'http://ketting.invalid');\n if (parsed.hostname === 'ketting.invalid') {\n return {\n host: null\n };\n } else {\n return {\n host: parsed.host\n };\n }\n\n}\n","import { LinkHints } from 'hal-types';\nimport { resolve } from './util/uri';\n\nexport type Link = {\n /**\n * Target URI\n */\n href: string;\n\n /**\n * Context URI.\n *\n * Used to resolve relative URIs\n */\n context: string;\n\n /**\n * Relation type\n */\n rel: string;\n\n /**\n * Link title\n */\n title?: string;\n\n /**\n * Content type hint of the target resource\n */\n type?: string;\n\n /**\n * Anchor.\n *\n * This describes where the link is linked from, from for example\n * a fragment in the current document\n */\n anchor?: string;\n\n /**\n * Language of the target resource\n */\n hreflang?: string;\n\n /**\n * HTML5 media attribute\n */\n media?: string;\n\n /**\n * If templated is set to true, the href is a templated URI.\n */\n templated?: boolean;\n\n /**\n * Link hints, as defined in draft-nottingham-link-hint\n */\n hints?: LinkHints;\n\n /**\n * Link name\n *\n * This is sometimes used as a machine-readable secondary key for links.\n *\n * This is at least used in HAL, but there may be other formats:\n *\n * @see https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-06#section-5.5\n */\n name?: string;\n\n}\n\ntype NewLink = Omit<Link, 'context'>;\n\n\n/**\n * Links container, providing an easy way to manage a set of links.\n */\nexport class Links {\n\n private store: Map<string, Link[]>;\n\n constructor(public defaultContext: string, links?: Link[] | Links) {\n\n this.store = new Map();\n\n if (links) {\n if (links instanceof Links) {\n this.add(...links.getAll());\n } else {\n for (const link of links) {\n this.add(link);\n }\n }\n }\n\n }\n\n /**\n * Adds a link to the list\n */\n add(...links: (Link | NewLink)[]): void\n add(rel: string, href: string): void\n add(...args: any[]): void {\n\n let links: Link[];\n\n if (typeof args[0] === 'string') {\n links = [{\n rel: args[0],\n href: args[1],\n context: this.defaultContext,\n }];\n } else {\n links = args.map( link => { return { context: this.defaultContext, ...link };} );\n }\n\n for(const link of links) {\n if (this.store.has(link.rel)) {\n this.store.get(link.rel)!.push(link);\n } else {\n this.store.set(link.rel, [link]);\n }\n }\n\n }\n\n /**\n * Set a link\n *\n * If a link with the provided 'rel' already existed, it will be overwritten.\n */\n set(link: Link | NewLink): void\n set(rel: string, href: string): void\n set(arg1: any, arg2?: any): void {\n\n let link: Link;\n if (typeof arg1 === 'string') {\n link = {\n rel: arg1,\n href: arg2,\n context: this.defaultContext,\n };\n } else {\n link = {\n context: this.defaultContext,\n ...arg1,\n };\n }\n this.store.set(link.rel, [link]);\n\n }\n\n /**\n * Return a single link by its 'rel'.\n *\n * If the link does not exist, undefined is returned.\n */\n get(rel: string): Link|undefined {\n\n const links = this.store.get(rel);\n if (!links || links.length < 0) {\n return undefined;\n }\n return links[0];\n\n }\n\n /**\n * Delete all links with the given 'rel'.\n *\n * If the second argument is provided, only links that match the href will\n * be removed.\n */\n delete(rel: string, href?: string): void {\n\n if (href===undefined) {\n this.store.delete(rel);\n return;\n }\n\n const uris = this.store.get(rel);\n if (!uris) return;\n\n this.store.delete(rel);\n const absHref = resolve(this.defaultContext, href);\n this.store.set(rel,\n uris.filter(uri => resolve(uri) !== absHref)\n );\n }\n\n /**\n * Return all links that have a given rel.\n *\n * If no links with the rel were found, an empty array is returned.\n */\n getMany(rel: string): Link[] {\n\n return this.store.get(rel) || [];\n\n }\n\n /**\n * Return all links.\n */\n getAll(): Link[] {\n const result = [];\n for(const links of this.store.values()) {\n result.push(...links);\n }\n return result;\n }\n\n /**\n * Returns true if at least 1 link with the given rel exists.\n */\n has(rel: string): boolean {\n\n return this.store.has(rel);\n\n }\n\n}\n\n/**\n * The LinkNotFound error gets thrown whenever something tries to follow a\n * link by its rel, that doesn't exist\n */\nexport class LinkNotFound extends Error {}\n\n/**\n * A key->value map of variables to place in a templated link\n */\nexport type LinkVariables = {\n [key: string]: string | number | string[] | number[];\n};\n","import { Action } from '../action';\nimport { Links, LinkVariables } from '../link';\nimport Client from '../client';\nimport { Resource } from '../resource';\n\nexport type State<T = any> = {\n\n /**\n * The URI associated with this state\n */\n uri: string;\n\n /**\n * Represents the body of the HTTP response.\n *\n * In the case of a JSON response, this will be deserialized\n */\n data: T;\n\n /**\n * All links associated with the resource.\n */\n links: Links;\n\n /**\n * The full list of HTTP headers that were sent with the response.\n */\n headers: Headers;\n\n /**\n * Reference to main client that created this state\n */\n client: Client;\n\n /**\n * Follows a relationship, based on its reltype. For example, this might be\n * 'alternate', 'item', 'edit' or a custom url-based one.\n *\n * This function can also follow templated uris. You can specify uri\n * variables in the optional variables argument.\n */\n follow<TFollowedResource = any>(rel: string, variables?: LinkVariables): Resource<TFollowedResource>;\n\n /**\n * Follows a relationship based on its reltype. This function returns a\n * Promise that resolves to an array of Resource objects.\n *\n * If no resources were found, the array will be empty.\n */\n followAll<TFollowedResource = any>(rel: string): Resource<TFollowedResource>[];\n\n /**\n * Return an action by name.\n *\n * If the format provides a default action, the name may be omitted.\n */\n action<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData>;\n\n /**\n * Find an action by name.\n *\n * If the format provides a default action, the name may be omitted.\n */\n findAction<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData> | undefined;\n\n /**\n * Returns all actions\n */\n actions(): Action[];\n\n /**\n * Checks if the specified action exists.\n *\n * If no name is given, checks if _any_ action exists.\n */\n hasAction(name?: string): boolean;\n\n /**\n * Returns a serialization of the state that can be used in a HTTP\n * response.\n *\n * For example, a JSON object might simply serialize using\n * JSON.serialize().\n */\n serializeBody(): Buffer|Blob|string;\n\n /**\n * Content-headers are a subset of HTTP headers that related directly\n * to the content. The obvious ones are Content-Type.\n *\n * This set of headers will be sent by the server along with a GET\n * response, but will also be sent back to the server in a PUT\n * request.\n */\n contentHeaders(): Headers;\n\n /**\n * Some formats support embedding resources inside other resources.\n *\n * Please note: generally you should always use the .follow() and\n * .followAll() functions to get access to linked embedded resources.\n *\n * There's several operations that change the State in the Ketting Cache,\n * and usually this erases any associated embedded resources.\n *\n * .follow() and .followAll() will return the embedded resources, and also\n * keeps their respective states fresh when changes are made.\n */\n getEmbedded(): State[];\n\n /**\n * Timestamp of when the State was first generated\n */\n timestamp: number;\n\n clone(): State<T>;\n\n}\n\n/**\n * HeadState represents the response to a HEAD request.\n *\n * Some information in HEAD responses might be available, but many aren't.\n * Notably, the body.\n */\nexport type HeadState = Omit<State, 'data' | 'action' | 'findAction' | 'actions' | 'hasAction' | 'serializeBody' | 'getEmbedded' | 'client' | 'clone'>;\n\n/**\n * A 'StateFactory' is responsible for taking a Fetch Response, and returning\n * an object that impements the State interface\n */\nexport type StateFactory<T = any> = (client: Client, uri: string, request: Response) => Promise<State<T>>;\n\nexport function isState(input: Record<string, any>): input is State {\n\n return (\n typeof (input as any).uri === 'string' &&\n (input as any).links instanceof Links &&\n (input as any).headers instanceof Headers\n );\n\n}\n","import { State } from './state';\nimport qs from 'query-string';\nimport Client from './client';\nimport { Field } from './field';\nimport Resource from './resource';\n\nexport interface ActionInfo {\n\n /**\n * What url to post the form to.\n */\n uri: string;\n\n /**\n * Action name.\n *\n * Some formats call this the 'rel'\n */\n name: string | null;\n\n /**\n * Form title.\n *\n * Should be human-friendly.\n */\n title?: string;\n\n /**\n * The HTTP method to use\n */\n method: string;\n\n /**\n * The contentType to use for the form submission\n */\n contentType: string;\n\n /**\n * Returns the list of fields associated to an action\n */\n fields: Field[];\n}\n\n/**\n * An action represents a hypermedia form submission or action.\n */\nexport interface Action<T extends Record<string, any> = Record<string, any>> extends ActionInfo {\n\n /**\n * Execute the action or submit the form.\n */\n submit(formData: T): Promise<State>;\n\n /**\n * Return a field by name.\n */\n field(name: string): Field | undefined;\n\n /**\n * Execute the action or submit the form, then return the next resource.\n *\n * If a server responds with a 201 Status code and a Location header,\n * it will automatically return the newly created resource.\n *\n * If the server responded with a 204 or 205, this function will return\n * `this`.\n */\n submitFollow(formData: T): Promise<Resource>;\n}\n\nexport class SimpleAction<TFormData extends Record<string, any>> implements Action {\n\n /**\n * What url to post the form to.\n */\n uri!: string;\n\n /**\n * Action name.\n *\n * Some formats call this the 'rel'\n */\n name!: string | null;\n\n /**\n * Form title.\n *\n * Should be human-friendly.\n */\n title!: string;\n\n /**\n * The HTTP method to use\n */\n method!: string;\n\n /**\n * The contentType to use for the form submission\n */\n contentType!: string;\n\n /**\n * Returns the list of fields associated to an action\n */\n fields!: Field[];\n\n /**\n * Reference to client\n */\n client: Client;\n\n constructor(client: Client, formInfo: ActionInfo) {\n this.client = client;\n\n for(const [k, v] of Object.entries(formInfo)) {\n this[k as keyof ActionInfo] = v;\n }\n\n }\n\n /**\n * Execute the action or submit the form.\n */\n async submit(formData: TFormData): Promise<State<any>> {\n\n const uri = new URL(this.uri);\n\n const newFormData = this.validateForm(formData);\n\n if (this.method === 'GET') {\n uri.search = qs.stringify(newFormData);\n const resource = this.client.go(uri.toString());\n return resource.get();\n }\n const response = await this.fetchOrThrowWithBody(uri, newFormData);\n const state = this.client.getStateForResponse(uri.toString(), response);\n return state;\n }\n\n async submitFollow(formData: TFormData): Promise<Resource> {\n const uri = new URL(this.uri);\n\n const newFormData = this.validateForm(formData);\n\n if (this.method === 'GET') {\n uri.search = qs.stringify(newFormData);\n return this.client.go(uri.toString());\n }\n\n const response = await this.fetchOrThrowWithBody(uri, newFormData);\n switch (response.status) {\n case 201:\n if (response.headers.has('location')) {\n return this.client.go(response.headers.get('location')!);\n }\n throw new Error('Could not follow after a 201 request, because the server did not reply with a Location header. If you sent a Location header, check if your service is returning \"Access-Control-Expose-Headers: Location\".');\n case 204 :\n case 205 :\n return this.client.go(uri.toString());\n default:\n throw new Error('Did not receive a 201, 204 or 205 status code so we could not follow to the next resource');\n }\n }\n\n private validateForm(formData: TFormData): TFormData {\n const newFormData: TFormData = {\n ...formData\n };\n\n for (const field of this.fields) {\n\n if (!(field.name in formData)) {\n\n if (field.value) {\n // We don't have perfect types for fields vs. FormData and how they\n // related, so 'any' is needed here.\n (newFormData as any)[field.name] = field.value;\n } else if (field.required) {\n throw new Error(`The ${field.name} field is required in this form`);\n }\n\n }\n\n }\n return newFormData;\n }\n\n private fetchOrThrowWithBody(uri: URL, formData: TFormData): Promise<Response> {\n let body;\n switch (this.contentType) {\n case 'application/x-www-form-urlencoded' :\n body = qs.stringify(formData);\n break;\n case 'application/json':\n body = JSON.stringify(formData);\n break;\n default :\n throw new Error(`Serializing mimetype ${this.contentType} is not yet supported in actions`);\n }\n return this.client.fetcher.fetchOrThrow(uri.toString(), {\n method: this.method,\n body,\n headers: {\n 'Content-Type': this.contentType\n }\n });\n }\n\n field(name: string): Field | undefined {\n return this.fields.find(field => field.name === name);\n }\n}\n\nexport class ActionNotFound extends Error {}\n","import * as uriTemplate from 'uri-template';\nimport { resolve } from './uri';\nimport { LinkVariables, Link } from '../link';\n\nexport function expand(context: string, template: string, vars: LinkVariables): string;\nexport function expand(link: Link, vars: LinkVariables): string;\nexport function expand(arg1: string|Link, arg2: string|LinkVariables, arg3?: LinkVariables): string {\n\n let context:string;\n let template:string;\n let vars:LinkVariables;\n\n if (typeof arg1 === 'string') {\n context = arg1;\n template = arg2 as string;\n vars = arg3 as LinkVariables;\n } else {\n context = arg1.context;\n template = arg1.href;\n vars = arg2 as LinkVariables;\n }\n const templ = uriTemplate.parse(template);\n const expanded = templ.expand(vars);\n return resolve(context, expanded);\n}\n","import * as LinkHeader from 'http-link-header';\nimport { Links } from '../link';\n\n/**\n * Takes a Content-Type header, and only returns the mime-type part.\n */\nexport function parseContentType(contentType: string | null): string | null {\n\n if (!contentType) {\n return null;\n }\n if (contentType.includes(';')) {\n contentType = contentType.split(';')[0];\n }\n return contentType.trim();\n\n}\n\n\nexport function parseLink(context: string, header: string|null): Links {\n\n const result = new Links(context);\n if (!header) {\n return result;\n }\n\n for (const httpLink of LinkHeader.parse(header).refs) {\n // Looping through individual links\n for (const rel of httpLink.rel.split(' ')) {\n // Looping through space separated rel values.\n const link = {\n rel: rel,\n href: httpLink.uri,\n context,\n title: httpLink.title,\n hreflang: httpLink.hreflang,\n type: httpLink.type,\n };\n result.add(link);\n }\n }\n return result;\n}\n\nconst safeMethods = ['GET', 'HEAD', 'OPTIONS', 'PRI', 'PROPFIND', 'REPORT', 'SEARCH', 'TRACE'];\n\nexport function isSafeMethod(method: string): boolean {\n return safeMethods.includes(method);\n}\n\n/**\n * Older HTTP versions calls these 'entity headers'.\n *\n * Never HTTP/1.1 specs calls some of these 'representation headers'.\n *\n * What they have in common is that these headers can exist on request and\n * response and say something *about* the content.\n */\nexport const entityHeaderNames = [\n 'Content-Type',\n 'Content-Language',\n 'Content-Location',\n 'Deprecation',\n 'ETag',\n 'Expires',\n 'Last-Modified',\n 'Sunset',\n 'Title',\n 'Warning',\n];\n","import { State, HeadState } from './interface';\nimport { Links, LinkVariables, LinkNotFound } from '../link';\nimport Client from '../client';\nimport { Action, ActionNotFound, ActionInfo, SimpleAction } from '../action';\nimport { Resource } from '../resource';\nimport { resolve } from '../util/uri';\nimport { expand } from '../util/uri-template';\nimport { entityHeaderNames } from '../http/util';\n\ntype HeadStateInit = {\n\n client: Client;\n uri: string;\n links: Links;\n\n /**\n * The full list of HTTP headers that were sent with the response.\n */\n headers: Headers;\n}\n\ntype StateInit<T> = {\n client: Client;\n uri: string;\n data: T;\n headers: Headers;\n links: Links;\n embedded?: State[];\n actions?: ActionInfo[];\n}\n\n/**\n * Implements a State object for HEAD responses\n */\nexport class BaseHeadState implements HeadState {\n\n uri: string;\n\n /**\n * Timestamp of when the State was first generated\n */\n timestamp: number;\n\n /**\n * The full list of HTTP headers that were sent with the response.\n */\n headers: Headers;\n\n /**\n * All links associated with the resource.\n */\n links: Links;\n\n /**\n * Reference to main client that created this state\n */\n client: Client;\n\n constructor(init: HeadStateInit) {\n this.client = init.client;\n this.uri = init.uri;\n this.headers = init.headers;\n this.timestamp = Date.now();\n this.links = init.links;\n }\n\n /**\n * Follows a relationship, based on its reltype. For example, this might be\n * 'alternate', 'item', 'edit' or a custom url-based one.\n *\n * This function can also follow templated uris. You can specify uri\n * variables in the optional variables argument.\n */\n follow<TFollowedResource = any>(rel: string, variables?: LinkVariables): Resource<TFollowedResource> {\n\n const link = this.links.get(rel);\n if (!link) throw new LinkNotFound(`Link with rel ${rel} on ${this.uri} not found`);\n\n let href;\n\n if (link.templated) {\n href = expand(link, variables || {});\n } else {\n href = resolve(link);\n }\n if (link.hints?.status === 'deprecated') {\n /* eslint-disable-next-line no-console */\n console.warn(`[ketting] The ${link.rel} link on ${this.uri} is marked deprecated.`, link);\n }\n\n return this.client.go(href);\n\n }\n\n /**\n * Follows a relationship based on its reltype. This function returns a\n * Promise that resolves to an array of Resource objects.\n *\n * If no resources were found, the array will be empty.\n */\n followAll<TFollowedResource = any>(rel: string): Resource<TFollowedResource>[] {\n\n return this.links.getMany(rel).map( link => {\n\n if (link.hints?.status === 'deprecated') {\n /* eslint-disable-next-line no-console */\n console.warn(`[ketting] The ${link.rel} link on ${this.uri} is marked deprecated.`, link);\n }\n const href = resolve(link);\n return this.client.go(href);\n\n });\n\n }\n\n\n /**\n * Content-headers are a subset of HTTP headers that related directly\n * to the content. The obvious ones are Content-Type.\n *\n * This set of headers will be sent by the server along with a GET\n * response, but will also be sent back to the server in a PUT\n * request.\n */\n contentHeaders(): Headers {\n\n const result: {[name: string]: string} = {};\n\n for(const contentHeader of entityHeaderNames) {\n if (this.headers.has(contentHeader)) {\n result[contentHeader] = this.headers.get(contentHeader)!;\n }\n }\n return new Headers(result);\n\n }\n\n}\n\n/**\n * The Base State provides a convenient way to implement a new State type.\n */\nexport class BaseState<T> extends BaseHeadState implements State<T> {\n\n\n data: T;\n\n protected embedded: State[];\n protected actionInfo: ActionInfo[];\n\n constructor(init: StateInit<T>) {\n\n super(init);\n this.data = init.data;\n this.actionInfo = init.actions || [];\n this.embedded = init.embedded || [];\n\n }\n\n /**\n * Return an action by name.\n *\n * If no name is given, the first action is returned. This is useful for\n * formats that only supply 1 action, and no name.\n */\n action<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData> {\n\n const actionSearchResult = this.doFindAction(name);\n if (actionSearchResult === 'NO_ACTION_DEFINED') {\n throw new ActionNotFound('This State does not define any actions');\n }\n if (actionSearchResult === 'NO_ACTION_FOR_THE_PROVIDED_NAME') {\n throw new ActionNotFound('This State defines no action');\n }\n return actionSearchResult;\n\n }\n\n findAction<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData> | undefined {\n\n const actionSearchResult = this.doFindAction(name);\n if (typeof actionSearchResult !== 'object') {\n return undefined;\n }\n return actionSearchResult;\n }\n\n private doFindAction<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData> | ActionNotFoundReason {\n\n if (!this.actionInfo.length) {\n return 'NO_ACTION_DEFINED';\n }\n if (name === undefined) {\n return new SimpleAction(this.client, this.actionInfo[0]);\n }\n for(const action of this.actionInfo) {\n if (action.name === name) {\n return new SimpleAction(this.client, action);\n }\n }\n return 'NO_ACTION_FOR_THE_PROVIDED_NAME';\n }\n\n /**\n * Returns all actions\n */\n actions(): Action[] {\n\n return this.actionInfo.map(action => new SimpleAction(this.client, action));\n\n }\n\n /**\n * Checks if the specified action exists.\n *\n * If no name is given, checks if _any_ action exists.\n */\n hasAction(name?: string): boolean {\n\n if (name===undefined) return this.actionInfo.length>0;\n for(const action of this.actionInfo) {\n if (name === action.name) {\n return true;\n }\n }\n return false;\n\n }\n\n /**\n * Returns a serialization of the state that can be used in a HTTP\n * response.\n *\n * For example, a JSON object might simply serialize using\n * JSON.serialize().\n */\n serializeBody(): Buffer|Blob|string {\n\n if (\n (globalThis.Buffer && this.data instanceof Buffer) ||\n (globalThis.Blob && this.data instanceof Blob) ||\n typeof this.data === 'string')\n {\n return this.data;\n }\n return JSON.stringify(this.data);\n\n }\n\n /**\n * Certain formats can embed other resources, identified by their\n * own URI.\n *\n * When a format has embedded resources, we will use these to warm\n * the cache.\n *\n * This method returns every embedded resource.\n */\n getEmbedded(): State[] {\n\n return this.embedded;\n\n }\n\n clone(): State<T> {\n\n return new BaseState({\n client: this.client,\n uri: this.uri,\n data: this.data,\n headers: new Headers(this.headers),\n links: new Links(this.links.defaultContext, this.links.getAll()),\n actions: this.actionInfo,\n });\n\n }\n\n}\n\ntype ActionNotFoundReason = 'NO_ACTION_DEFINED' | 'NO_ACTION_FOR_THE_PROVIDED_NAME';\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { Link, Links } from '../link';\nimport { resolve } from '../util/uri';\nimport { ActionInfo } from '../action';\nimport {Field, OptionsDataSource} from '../field';\nimport { StateFactory } from './interface';\nimport Client from '../client';\nimport * as hal from 'hal-types';\n\n/**\n * Represents a resource state in the HAL format\n */\nexport class HalState<T = any> extends BaseState<T> {\n\n serializeBody(): string {\n\n return JSON.stringify({\n _links: this.serializeLinks(),\n ...this.data\n });\n\n }\n\n private serializeLinks(): hal.HalResource['_links'] {\n\n const links: hal.HalResource['_links'] = {\n self: { href: this.uri },\n };\n for(const link of this.links.getAll()) {\n\n const { rel, context, ...attributes } = link;\n\n if (rel === 'self') {\n // skip\n continue;\n }\n\n if (links[rel] === undefined) {\n // First link of its kind\n links[rel] = attributes;\n } else if (Array.isArray(links[rel])) {\n // Add link to link array.\n (links[rel] as hal.HalLink[]).push(attributes);\n } else {\n // 1 link with this rel existed, so we will transform it to an array.\n links[rel] = [links[rel] as hal.HalLink, attributes];\n }\n\n }\n\n return links;\n\n }\n\n clone(): HalState<T> {\n\n return new HalState({\n client: this.client,\n uri: this.uri,\n data: this.data,\n headers: new Headers(this.headers),\n links: new Links(this.links.defaultContext, this.links.getAll()),\n actions: this.actionInfo,\n });\n\n }\n\n}\n\n/**\n * Turns a HTTP response into a HalState\n */\nexport const factory:StateFactory = async (client, uri, response): Promise<HalState> => {\n\n const body = await response.json();\n const links = parseLink(uri, response.headers.get('Link'));\n\n // The HAL factory is also respondible for plain JSON, which might be an\n // array.\n if (Array.isArray(body)) {\n return new HalState({\n client,\n uri,\n data: body,\n headers: response.headers,\n links,\n });\n }\n\n links.add(...parseHalLinks(uri, body));\n\n // Remove _links and _embedded from body\n const {\n _embedded,\n _links,\n _templates,\n ...newBody\n } = body;\n\n return new HalState({\n client,\n uri: uri,\n data: newBody,\n headers: response.headers,\n links: links,\n embedded: parseHalEmbedded(client, uri, body, response.headers),\n actions: parseHalForms(uri, body),\n });\n\n};\n\n/**\n * Parse the Hal _links object and populate the 'links' property.\n */\nfunction parseHalLinks(context: string, body: hal.HalResource): Link[] {\n\n if (body._links === undefined) {\n return [];\n }\n\n const result: Link[] = [];\n\n /**\n * We're capturing all rel-link pairs so we don't duplicate them if they\n * re-appear in _embedded.\n *\n * Links that are embedded _should_ appear in both lists, but not everyone\n * does this.\n */\n const foundLinks = new Set();\n\n for (const [relType, links] of Object.entries(body._links)) {\n\n const linkList = Array.isArray(links) ? links : [links];\n\n for (const link of linkList) {\n foundLinks.add(relType + ';' + link.href);\n }\n\n result.push(\n ...parseHalLink(context, relType, linkList)\n );\n\n\n }\n\n if (body._embedded) {\n // eslint-disable-next-line prefer-const\n for (let [rel, innerBodies] of Object.entries(body._embedded)) {\n\n for(const innerBody of Array.isArray(innerBodies) ? innerBodies : [innerBodies]) {\n\n const href:string = (innerBody?._links?.self as hal.HalLink)?.href;\n if (!href) {\n continue;\n }\n\n if (foundLinks.has(rel + ';' + href)) {\n continue;\n }\n result.push({\n rel: rel,\n href: href,\n context: context,\n });\n\n }\n\n }\n\n }\n\n return result;\n\n}\n\n/**\n * Parses a single HAL link from a _links object\n */\nfunction parseHalLink(context: string, rel: string, links: hal.HalLink[]): Link[] {\n\n const result: Link[] = [];\n\n for (const link of links) {\n result.push({\n rel,\n context,\n ...link,\n });\n }\n\n return result;\n\n}\n\n/**\n * Parse the HAL _embedded object. Right now we're just grabbing the\n * information from _embedded and turn it into links.\n */\nfunction parseHalEmbedded(client: Client, context: string, body: hal.HalResource, headers: Headers): HalState<any>[] {\n\n if (body._embedded === undefined || !body._embedded) {\n return [];\n }\n\n const result: HalState<any>[] = [];\n\n for (const embedded of Object.values(body._embedded)) {\n\n let embeddedList: hal.HalResource[];\n\n if (!Array.isArray(embedded)) {\n embeddedList = [embedded];\n } else {\n embeddedList = embedded;\n\n }\n for (const embeddedItem of embeddedList) {\n\n if ((embeddedItem._links?.self as hal.HalLink)?.href === undefined) {\n\n console.warn('An item in _embedded was ignored. Each item must have a single \"self\" link');\n continue;\n }\n\n const embeddedSelf = resolve(context, (embeddedItem._links?.self as hal.HalLink)?.href);\n\n // Remove _links and _embedded from body\n const {\n _embedded,\n _links,\n ...newBody\n } = embeddedItem;\n\n result.push(new HalState({\n client,\n uri: embeddedSelf,\n data: newBody,\n headers: new Headers({\n 'Content-Type': headers.get('Content-Type')!,\n }),\n links: new Links(embeddedSelf, parseHalLinks(context, embeddedItem)),\n // Parsing nested embedded items. Note that we assume that the base url is relative to\n // the outermost parent, not relative to the embedded item. HAL is not clear on this.\n embedded: parseHalEmbedded(client, embeddedSelf, embeddedItem, headers),\n actions: parseHalForms(embeddedSelf, embeddedItem)\n }));\n }\n }\n\n return result;\n\n}\n\nfunction parseHalForms(context: string, body: hal.HalResource): ActionInfo[] {\n\n if (!body._templates) return [];\n\n return Object.entries(body._templates).map( ([key, hf]) => {\n return {\n uri: resolve(context, hf.target || ''),\n name: key,\n title: hf.title,\n method: hf.method,\n contentType: hf.contentType || 'application/json',\n fields: hf.properties ? hf.properties.map(prop => parseHalField(prop)).filter(prop => !!prop) : [],\n };\n });\n\n}\n\nfunction parseHalField(halField: hal.HalFormsProperty): Field | undefined {\n\n switch(halField.type) {\n case undefined:\n case 'text' :\n case 'search' :\n case 'tel' :\n case 'url' :\n case 'email' :\n\n if (halField.options) {\n const multiple: boolean | undefined = !('maxItems' in halField.options) || !halField.options.maxItems || halField.options.maxItems > 1;\n\n const baseField = {\n name: halField.name,\n type: 'select' as const,\n label: halField.prompt,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n value: (halField.options.selectedValues || halField.value) as any,\n };\n\n const optionsDataSource = toOptionsDataSource(halField.options);\n\n if (multiple) {\n return {\n multiple: true,\n selectedValues: halField.options.selectedValues,\n ...baseField,\n ...optionsDataSource\n };\n } else {\n const selectedValues = halField.options.selectedValues;\n let selectedValue: string | undefined;\n if (selectedValues) {\n if (selectedValues.length === 1) {\n selectedValue = selectedValues[0];\n } else if (selectedValues.length > 1) {\n console.warn(`More than 1 selected value received for single select field ${baseField.name}. Ignoring all selected values for this field.`);\n }\n }\n return {\n multiple,\n selectedValue,\n ...baseField,\n ...optionsDataSource\n };\n }\n } else {\n return {\n name: halField.name,\n type: halField.type ?? 'text',\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n value: halField.value,\n pattern: halField.regex ? new RegExp(halField.regex) : undefined,\n label: halField.prompt,\n placeholder: halField.placeholder,\n minLength: halField.minLength,\n maxLength: halField.maxLength,\n };\n }\n case 'hidden' :\n return {\n name: halField.name,\n type: 'hidden',\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n value: halField.value,\n label: halField.prompt,\n placeholder: halField.placeholder,\n };\n case 'textarea' :\n return {\n name: halField.name,\n type: halField.type,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n value: halField.value,\n label: halField.prompt,\n placeholder: halField.placeholder,\n cols: halField.cols,\n rows: halField.rows,\n minLength: halField.minLength,\n maxLength: halField.maxLength,\n };\n case 'password' :\n return {\n name: halField.name,\n type: halField.type,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n placeholder: halField.placeholder,\n minLength: halField.minLength,\n maxLength: halField.maxLength,\n };\n case 'date' :\n case 'month' :\n case 'week' :\n case 'time' :\n return {\n name: halField.name,\n type: halField.type,\n value: halField.value,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n min: halField.min,\n max: halField.max,\n step: halField.step,\n };\n case 'number' :\n case 'range' :\n return {\n name: halField.name,\n type: halField.type,\n value: halField.value ? +halField.value : undefined,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n min: halField.min,\n max: halField.max,\n step: halField.step,\n };\n case 'datetime-local' :\n return {\n name: halField.name,\n type: halField.type,\n value: halField.value ? new Date(halField.value) : undefined,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n min: halField.min,\n max: halField.max,\n step: halField.step,\n };\n case 'color' :\n return {\n name: halField.name,\n type: halField.type,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n value: halField.value,\n };\n case 'radio' :\n case 'checkbox' :\n return {\n name: halField.name,\n type: halField.type,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n value: !!halField.value,\n };\n default:\n return undefined;\n }\n\n}\n\nfunction toOptionsDataSource(halFieldOptions: NonNullable<hal.HalFormsSimpleProperty['options']>): OptionsDataSource {\n const labelField = halFieldOptions.promptField || 'prompt';\n const valueField = halFieldOptions.valueField || 'value';\n if (isInlineOptions(halFieldOptions)) {\n\n const options: Record<string, string> = {};\n\n for (const entry of halFieldOptions.inline) {\n\n if (typeof entry === 'string') {\n options[entry] = entry;\n } else {\n options[entry[valueField]] = entry[labelField];\n }\n }\n\n return {options};\n } else {\n return {\n dataSource: {\n href: halFieldOptions.link.href,\n type: halFieldOptions.link.type,\n labelField,\n valueField,\n }\n };\n }\n}\n\nfunction isInlineOptions(options: hal.HalFormsSimpleProperty['options']): options is hal.HalFormsOptionsInline {\n\n return (options as any).inline !== undefined;\n\n}\n","import { BaseState } from './base-state';\nimport { StateFactory } from './interface';\nimport { parseLink } from '../http/util';\n\n/**\n * Turns a HTTP response into a BinaryState\n */\nexport const factory: StateFactory<Blob> = async (client, uri, response): Promise<BaseState<Blob>> => {\n\n return new BaseState({\n client,\n uri,\n data: await response.blob(),\n headers: response.headers,\n links: parseLink(uri, response.headers.get('Link')),\n });\n\n};\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { Link } from '../link';\nimport Client from '../client';\n\n/**\n * Turns a HTTP response into a JsonApiState\n */\nexport const factory = async (client: Client, uri: string, response: Response): Promise<BaseState<JsonApiTopLevelObject>> => {\n\n const body = await response.json();\n\n const links = parseLink(uri, response.headers.get('Link'));\n links.add(\n ...parseJsonApiLinks(uri, body),\n ...parseJsonApiCollection(uri, body),\n );\n\n return new BaseState({\n client,\n uri,\n data: body,\n headers: response.headers,\n links: links,\n });\n\n};\n/**\n * A JSON:API link can either be a string, or an object with at least a href\n * property.\n */\ntype JsonApiLink = string | { href: string };\n\n/**\n * This type is a full 'links' object, which might appear on the top level\n * or on resource objects.\n */\ntype JsonApiLinksObject = {\n self?: JsonApiLink;\n profile?: JsonApiLink;\n [rel: string]: JsonApiLink | JsonApiLink[] | undefined;\n};\n\n/**\n * This is a single JSON:API resource. Its type contains just the properties\n * we care about.\n */\ntype JsonApiResource = {\n type: string;\n id: string;\n links?: JsonApiLinksObject;\n};\n\n\n/**\n * This type represents a valid JSON:API response. We're only interested\n * in the links object at the moment, so everything else is (for now)\n * untyped.\n */\ntype JsonApiTopLevelObject = {\n links?: JsonApiLinksObject;\n data: JsonApiResource | JsonApiResource[] | null;\n [s: string]: any;\n};\n\n/**\n * This function takes a JSON:API object, and extracts the links property.\n */\nfunction parseJsonApiLinks(contextUri: string, body: JsonApiTopLevelObject): Link[] {\n\n const result: Link[] = [];\n\n if (body.links === undefined) {\n return result;\n }\n\n for (const [rel, linkValue] of Object.entries(body.links)) {\n\n if (Array.isArray(linkValue)) {\n result.push(...linkValue.map( link => parseJsonApiLink(contextUri, rel, link)));\n } else {\n result.push(parseJsonApiLink(contextUri, rel, linkValue!));\n }\n\n }\n\n return result;\n\n}\n\n/**\n * Find collection members in JSON:API objects.\n *\n * A JSON:API top-level object might represent a collection that has 0 or more\n * members.\n *\n * Members of this collection should appear as an 'item' link to the parent.\n */\nfunction parseJsonApiCollection(contextUri: string, body: JsonApiTopLevelObject): Link[] {\n\n if (!Array.isArray(body.data)) {\n // Not a collection\n return [];\n }\n\n const result: Link[] = [];\n for (const member of body.data) {\n\n if ('links' in member && 'self' in member.links!) {\n\n const selfLink = parseJsonApiLink(contextUri, 'self', member.links!.self!);\n result.push({\n context: contextUri,\n href: selfLink.href,\n rel: 'item'\n });\n\n }\n }\n\n return result;\n\n}\n\n/**\n * This function takes a single link value from a JSON:API link object, and\n * returns a object of type Link\n */\nfunction parseJsonApiLink(contextUri: string, rel: string, link: JsonApiLink): Link {\n\n return ({\n context: contextUri,\n rel,\n href: typeof link === 'string' ? link : link.href,\n });\n\n}\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { Link, Links } from '../link';\nimport { resolve } from '../util/uri';\nimport { ActionInfo } from '../action';\nimport { Field } from '../field';\nimport Client from '../client';\n\n/**\n * Represents a resource state in the Siren format\n */\nexport class SirenState<T> extends BaseState<T> {\n\n /**\n * Returns a serialization of the state that can be used in a HTTP\n * response.\n *\n * For example, a JSON object might simply serialize using\n * JSON.serialize().\n */\n serializeBody(): string {\n\n throw new Error('Reserializing Siren states is not yet supported. Please log an issue in the Ketting project to help figure out how this should be done');\n\n }\n\n clone(): SirenState<T> {\n\n return new SirenState({\n client: this.client,\n uri: this.uri,\n data: this.data,\n headers: new Headers(this.headers),\n links: new Links(this.uri, this.links),\n actions: this.actionInfo,\n });\n\n }\n\n}\n\n\n/**\n * Turns a HTTP response into a SirenState\n */\nexport const factory = async (client: Client, uri: string, response: Response): Promise<SirenState<any>> => {\n\n const body:SirenEntity<any> = await response.json();\n\n const links = parseLink(uri, response.headers.get('Link'));\n links.add(...parseSirenLinks(uri, body));\n\n return new SirenState({\n client,\n uri,\n data: body.properties,\n headers: response.headers,\n links: links,\n embedded: parseSirenEmbedded(client, uri, body, response.headers),\n actions: body.actions ? body.actions.map( action => parseSirenAction(uri, action) ) : [],\n });\n\n};\n\ntype SirenProperties = Record<string, any> | undefined;\n\ntype SirenEntity<T extends SirenProperties> = {\n\n class?: string[];\n\n properties: T;\n entities?: (SirenLink | SirenSubEntity)[];\n\n links?: SirenLink[];\n actions?: SirenAction[];\n title?: string;\n\n};\n\ntype SirenSubEntity = SirenEntity<any> & { rel: string[] };\n\ntype SirenLink = {\n\n class?: string[];\n rel: string[];\n href: string;\n type?: string;\n title?: string;\n\n};\n\ntype SirenAction = {\n name: string;\n class?: string[];\n method?: string;\n href: string;\n title?: string;\n type?: string;\n fields?: SirenField[];\n};\n\ntype SirenField = {\n name: string;\n class?: string[];\n type?: 'hidden' | 'text' | 'search' | 'tel' | 'url' | 'email' | 'password' | 'datetime' | 'date' | 'month' | 'week' | 'time' | 'datetime-local' | 'number' | 'range' | 'color' | 'checkbox' | 'radio' | 'file';\n value?: string;\n title?: string;\n};\n\nfunction parseSirenLinks(contextUri: string, body: SirenEntity<any>): Link[] {\n\n const result: Link[] = [];\n\n if (body.links !== undefined) {\n for (const link of body.links) {\n result.push(...parseSirenLink(contextUri, link));\n }\n }\n\n if (body.entities !== undefined) {\n for (const subEntity of body.entities) {\n if ((subEntity as SirenLink).href !== undefined) {\n result.push(...parseSirenLink(contextUri, subEntity as SirenLink));\n } else {\n result.push(...parseSirenSubEntityAsLink(contextUri, subEntity as SirenSubEntity));\n }\n }\n }\n\n return result;\n\n}\n\nfunction parseSirenLink(contextUri: string, link: SirenLink): Link[] {\n\n const result: Link[] = [];\n\n const {\n rel: rels,\n ...attributes\n } = link;\n for (const rel of rels) {\n\n const newLink: Link = {\n rel,\n context: contextUri,\n ...attributes,\n };\n result.push(newLink);\n\n }\n\n return result;\n\n}\n\nfunction parseSirenEmbedded(client: Client, contextUri: string, body: SirenEntity<any>, headers: Headers): SirenState<SirenEntity<any>>[] {\n\n if (body.entities === undefined) {\n return [];\n }\n\n const result: SirenState<SirenEntity<any>>[] = [];\n\n for (const entity of body.entities) {\n if (isSubEntity(entity)) {\n const subState = parseSirenSubEntityAsEmbedded(client, contextUri, entity, headers);\n if (subState !== null) {\n result.push(subState);\n }\n }\n }\n\n return result;\n\n}\n\nfunction parseSirenSubEntityAsLink(contextUri: string, subEntity: SirenSubEntity): Link[] {\n\n if (subEntity.links === undefined) {\n // We don't yet support subentities that don't have a URI.\n return [];\n }\n let selfHref: string | null = null;\n for (const link of subEntity.links) {\n if (link.rel.includes('self')) {\n selfHref = link.href;\n }\n }\n if (selfHref === null) {\n // We don't yet support subentities that don't have a URI.\n return [];\n }\n\n return subEntity.rel.map(rel => {\n const title = subEntity.title;\n const link: Link = {\n href: selfHref!,\n rel,\n context: contextUri,\n };\n if (title) {\n link.title = title;\n }\n return link;\n });\n\n}\n\nfunction parseSirenSubEntityAsEmbedded(client: Client, contextUri: string, subEntity: SirenSubEntity, headers: Headers): SirenState<SirenEntity<any>> | null {\n\n if (subEntity.links === undefined) {\n // We don't yet support subentities that don't have a URI.\n return null;\n }\n let selfHref = null;\n for (const link of subEntity.links) {\n if (link.rel.includes('self')) {\n selfHref = link.href;\n }\n }\n if (!selfHref) {\n // We don't yet support subentities that don't have a URI.\n return null;\n }\n\n const subEntityUrl = resolve(contextUri, selfHref);\n\n return new SirenState({\n client,\n uri: subEntityUrl,\n data: subEntity.properties,\n headers,\n links: new Links(selfHref, parseSirenLinks(selfHref, subEntity)),\n });\n\n}\n\nfunction isSubEntity(input: SirenLink | SirenSubEntity): input is SirenSubEntity {\n\n return (input as any).href === undefined;\n\n}\n\nfunction parseSirenAction(uri: string, action: SirenAction): ActionInfo {\n return {\n uri: resolve(uri, action.href),\n name: action.name,\n title: action.title,\n method: action.method || 'GET',\n contentType: action.type || 'application/x-www-form-urlencoded',\n fields: action.fields ? action.fields.map( field => sirenFieldToField(field)) : [],\n };\n}\n\nfunction sirenFieldToField(input: SirenField): Field {\n\n const result: Field = {\n name: input.name,\n type: input.type || 'text',\n required: false,\n readOnly: false,\n };\n\n if (input.value) {\n result.value = input.value;\n }\n if (input.title) {\n result.label = input.title;\n }\n\n return result;\n}\n","import { BaseState } from './base-state';\nimport { StateFactory } from './interface';\nimport { parseLink } from '../http/util';\nimport Client from '../client';\n\n/**\n * Turns a HTTP response into a TextState\n */\nexport const factory: StateFactory<string> = async (client: Client, uri: string, response: Response): Promise<BaseState<string>> => {\n\n return new BaseState({\n client,\n uri,\n data: await response.text(),\n headers: response.headers,\n links: parseLink(uri, response.headers.get('Link')),\n });\n\n};\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { Link } from '../link';\nimport { StateFactory } from './interface';\n\n/**\n * Represents a resource state in the HAL format\n */\nexport class CjState<T = any> extends BaseState<T> {\n\n serializeBody(): string {\n\n throw new Error('Reserializing Collection+JSON states is not yet supported. Please log an issue in the Ketting project to help figure out how this should be done');\n }\n\n}\n\n/**\n * Turns a HTTP response into a CjState\n */\nexport const factory: StateFactory = async (client, uri, response): Promise<CjState<CjCollection>> => {\n\n const body = await response.json();\n\n const links = parseLink(uri, response.headers.get('Link'));\n links.add(\n ...parseCjLinks(uri, body),\n );\n\n // Remove _links and _embedded from body\n const {\n _embedded,\n _links,\n ...newBody\n } = body;\n\n return new CjState({\n client,\n uri,\n data: newBody,\n headers: response.headers,\n links,\n });\n\n};\n\ntype CjDocument = {\n collection: CjCollection;\n};\n\ntype CjCollection = {\n version?: string;\n href?: string;\n links?: CjLink[];\n items?: CjItem[];\n queries?: CjQuery[];\n template?: CjTemplate;\n error?: CjError;\n};\n\ntype CjError = {\n title?: string;\n code?: string;\n message?: string;\n};\n\ntype CjTemplate = {\n data?: CjProperty[];\n};\n\ntype CjItem = {\n href?: string;\n data?: CjProperty[];\n links?: CjLink[];\n};\n\ntype CjProperty = {\n name: string;\n value?: string;\n prompt?: string;\n};\n\ntype CjQuery = {\n href: string;\n rel: string;\n name?: string;\n prompt?: string;\n data?: CjProperty[];\n};\n\ntype CjLink = {\n href: string;\n rel: string;\n name?: string;\n render?: 'image' | 'link';\n prompt?: string;\n};\n\n\nfunction parseCjLinks(contextUri: string, body: CjDocument) {\n\n const result: Link[] = [];\n if (body.collection.links !== undefined) {\n\n // Lets start with all links from the links property.\n for (const link of body.collection.links) {\n result.push({\n context: contextUri,\n href: link.href,\n rel: link.rel,\n title: link.name,\n });\n }\n }\n\n if (body.collection.items !== undefined) {\n\n // Things that are in the 'items' array should also be considered links\n // with the 'item' link relationship.\n for (const item of body.collection.items) {\n\n if (!item.href) {\n continue;\n }\n\n result.push({\n context: contextUri,\n href: item.href,\n rel: 'item',\n });\n }\n\n }\n\n\n if (body.collection.queries !== undefined) {\n\n // Things that are in the 'queries' array can be considered links too.\n for (const query of body.collection.queries) {\n\n if (!query.data) {\n // Non-templated\n result.push({\n context: contextUri,\n href: query.href,\n rel: query.rel,\n title: query.name,\n });\n } else {\n // This query has a data property so we need 50% more magic\n result.push({\n context: contextUri,\n href: query.href + query.data.map(\n property => '{?' + property.name + '}'\n ).join(''),\n templated: true,\n rel: query.rel,\n title: query.name,\n });\n }\n }\n\n }\n\n return result;\n\n}\n","import * as sax from 'sax';\nimport { Link } from '../link';\nimport { resolve } from './uri';\n\nexport type HtmlForm = {\n action: string;\n method: string | null;\n enctype: string | null;\n rel: string | null;\n id: string | null;\n}\n\ntype ParseHtmlResult = {\n\n links: Link[];\n forms: HtmlForm[];\n\n}\n\nexport function parseHtml(contextUri: string, body: string): ParseHtmlResult {\n\n const parser = sax.parser(false, {});\n const links: Link[] = [];\n const forms: ParseHtmlResult['forms'] = [];\n\n parser.onopentag = node => {\n\n switch(node.name) {\n case 'LINK' :\n case 'A' :\n links.push(...parseLink(contextUri, node as sax.Tag));\n break;\n case 'FORM' :\n forms.push(...parseForm(contextUri, node as sax.Tag));\n break;\n\n }\n\n };\n\n parser.write(body).close();\n\n return {\n forms,\n links,\n };\n\n}\n\nfunction parseLink(contextUri: string, node: sax.Tag): Link[] {\n\n if (!node.attributes.REL) {\n return [];\n }\n if (!node.attributes.HREF) {\n return [];\n }\n\n const rels = node.attributes.REL as string;\n\n const links: Link[] = [];\n for (const rel of rels.split(' ')) {\n\n const type = node.attributes.TYPE as string;\n const link: Link = {\n rel,\n context: contextUri,\n href: node.attributes.HREF as string,\n };\n if (type) link.type = type;\n links.push(link);\n }\n\n return links;\n\n}\n\nfunction parseForm(contextUri: string, node: sax.Tag): HtmlForm[] {\n\n const rels = node.attributes.REL || null;\n const id = node.attributes.ID || null;\n const action = node.attributes.ACTION || '';\n const method = node.attributes.METHOD || 'GET';\n const enctype = node.attributes.ENCTYPE || 'application/x-www-form-urlencoded';\n\n if (!rels) {\n return [{\n rel: null,\n id,\n action: resolve(contextUri, action),\n method,\n enctype,\n }];\n }\n\n const result = [];\n\n for(const rel of rels.split(' ')) {\n\n result.push({\n rel,\n id,\n action: resolve(contextUri, action),\n method,\n enctype,\n });\n\n }\n return result;\n\n}\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { parseHtml, HtmlForm } from '../util/html';\nimport { ActionInfo } from '../action';\nimport { resolve } from '../util/uri';\nimport { StateFactory } from './interface';\n\n/**\n * Turns a HTTP response into a HtmlState\n */\nexport const factory:StateFactory = async (client, uri, response): Promise<BaseState<string>> => {\n\n const body = await response.text();\n\n const links = parseLink(uri, response.headers.get('Link'));\n const htmlResult = parseHtml(uri, body);\n links.add(...htmlResult.links);\n\n return new BaseState({\n client,\n uri,\n data: body,\n headers: response.headers,\n links,\n actions: htmlResult.forms.map(form => formToAction(uri, form)),\n });\n\n};\n\nfunction formToAction(context: string, form: HtmlForm): ActionInfo {\n\n return {\n uri: resolve(context, form.action),\n name: form.rel || form.id || '',\n method: form.method || 'GET',\n contentType: form.enctype || 'application/x-www-form-urlencoded',\n // Fields are not yet supported :(\n fields: [],\n };\n}\n","import { BaseHeadState } from './base-state';\nimport { parseLink } from '../http/util';\nimport Client from '../client';\n\n/**\n * Turns the response to a HTTP Head request into a HeadState object.\n *\n * HeadState is a bit different from normal State objects, because it's\n * missing a bunch of information.\n */\nexport const factory = async (client: Client, uri: string, response: Response): Promise<BaseHeadState> => {\n\n const links = parseLink(uri, response.headers.get('Link'));\n\n return new BaseHeadState({\n client,\n uri,\n headers: response.headers,\n links,\n });\n\n};\n","import Resource from './resource';\nimport { LinkVariables } from './link';\nimport {State} from './state';\nimport {GetRequestOptions} from './types';\n\n/**\n * Base interface for both FollowOne and FollowAll\n */\nabstract class FollowPromise<T> implements PromiseLike<T> {\n\n protected prefetchEnabled: boolean;\n protected preferTranscludeEnabled: boolean;\n protected useHeadEnabled: boolean;\n\n constructor() {\n this.prefetchEnabled = false;\n this.preferTranscludeEnabled = false;\n this.useHeadEnabled = false;\n }\n\n preFetch(): this {\n this.prefetchEnabled = true;\n return this;\n }\n\n preferTransclude(): this {\n this.preferTranscludeEnabled = true;\n return this;\n }\n\n /**\n * Use a HTTP HEAD request to fetch the links.\n *\n * This is useful when interacting with servers that embed links in Link\n * Headers.\n */\n useHead(): this {\n\n this.useHeadEnabled = true;\n return this;\n\n }\n\n abstract then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;\n abstract catch<TResult1 = T, TResult2 = never>(onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;\n\n}\n\n/**\n * The FollowPromise class is what's being returned from follow() functions.\n *\n * It's 'PromiseLike', which means you can treat it like a Promise, and it\n * can be awaited. When used as a Promise, it resolves to the Resource object\n * that was followed.\n *\n * In addition to being a Promise<Resource> stand-in, it also exposes other\n * functions, namely:\n *\n * * `follow()` to allow a user to chain several follow() functions to do\n * several 'hops' all at once.\n * * `followAll()`, allowing a user to call `followAll()` at the end of a\n * chain.\n */\nexport class FollowPromiseOne<T = any> extends FollowPromise<Resource<T>> {\n\n private resource: Resource | Promise<Resource>;\n private rel: string;\n private variables?: LinkVariables;\n\n constructor(resource: Resource | Promise<Resource>, rel: string, variables?: LinkVariables) {\n\n super();\n this.resource = resource;\n this.rel = rel;\n this.variables = variables;\n\n }\n\n /**\n * This 'then' function behaves like a Promise then() function.\n *\n * This method signature is pretty crazy, but trust that it's pretty much\n * like any then() method on a promise.\n */\n then<TResult1 = Resource<T>, TResult2 = never>(\n onfulfilled?: ((value: Resource<T>) => TResult1 | PromiseLike<TResult1>) | null | undefined,\n onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | null | undefined\n ): Promise<TResult1 | TResult2> {\n\n return this.fetchLinkedResource().then(onfulfilled, onrejected);\n\n }\n\n /**\n * This 'catch' function behaves like a Promise catch() function.\n */\n catch<TResult1 = any, TResult2 = never>(onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | null | undefined): Promise<TResult1 | TResult2> {\n\n return this.fetchLinkedResource().then(undefined, onrejected);\n\n }\n\n /**\n * Implementation of a Promise.finally function\n */\n finally<TResult1 = any>(onfinally: () => TResult1 | PromiseLike<TResult1>): Promise<TResult1> {\n\n return this.then(\n () => onfinally(),\n () => onfinally()\n );\n\n }\n\n /**\n * Follow another link immediately after following this link.\n *\n * This allows you to follow several hops of links in one go.\n *\n * For example: resource.follow('foo').follow('bar');\n */\n follow<TNested = any>(rel: string, variables?: LinkVariables): FollowPromiseOne<TNested> {\n\n return new FollowPromiseOne(this.fetchLinkedResource(), rel, variables);\n\n }\n\n /**\n * Gets the current state of the resource.\n *\n * This function will return a State object.\n */\n async get(getOptions?: GetRequestOptions): Promise<State<T>> {\n return (await this).get(getOptions);\n }\n\n /**\n * Follows a set of links immediately after following this link.\n *\n * For example: resource.follow('foo').followAll('item');\n */\n followAll<TNested = any>(rel: string): FollowPromiseMany<TNested> {\n\n return new FollowPromiseMany(this.fetchLinkedResource(), rel);\n\n }\n\n /**\n * This function does the actual fetching of the linked\n * resource.\n */\n private async fetchLinkedResource(): Promise<Resource<T>> {\n\n const resource = await this.resource;\n\n const headers: { [name: string]: string } = {};\n if (!this.useHeadEnabled && this.preferTranscludeEnabled) {\n headers.Prefer = 'transclude=' + this.rel;\n }\n\n let state;\n if (this.useHeadEnabled) {\n state = await resource.head({headers});\n } else {\n state = await resource.get({\n headers\n });\n }\n\n const newResource = state.follow(this.rel, this.variables);\n\n if (this.prefetchEnabled) {\n newResource.get().catch( (err: Error) => {\n // eslint-disable-next-line no-console\n console.warn('Error while prefetching linked resource', err);\n });\n }\n\n return newResource;\n\n }\n\n}\n\n/**\n */\nexport class FollowPromiseMany<T = any> extends FollowPromise<Resource<T>[]> {\n\n private resource: Resource | Promise<Resource>;\n private rel: string;\n\n constructor(resource: Resource | Promise<Resource>, rel: string) {\n\n super();\n this.resource = resource;\n this.rel = rel;\n\n }\n\n /**\n * This 'then' function behaves like a Promise then() function.\n */\n then<TResult1 = Resource<T>[], TResult2 = never>(\n onfulfilled?: ((value: Resource<T>[]) => TResult1 | PromiseLike<TResult1>) | null | undefined,\n onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | null | undefined\n ): Promise<TResult1 | TResult2> {\n\n return this.fetchLinkedResources().then(onfulfilled, onrejected);\n\n }\n\n /**\n * This 'catch' function behaves like a Promise catch() function.\n */\n catch<TResult1 = any, TResult2 = never>(onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | null | undefined): Promise<TResult1 | TResult2> {\n\n return this.fetchLinkedResources().then(undefined, onrejected);\n\n }\n\n /**\n * Implementation of a Promise.finally function\n */\n finally<TResult1 = any>(onfinally: () => TResult1 | PromiseLike<TResult1>): Promise<TResult1> {\n\n return this.then(\n () => onfinally(),\n () => onfinally()\n );\n\n }\n\n /**\n * Gets the current states of the resources.\n *\n * This function will return an array of State object.\n */\n async get(getOptions?: GetRequestOptions): Promise<State<T>[]> {\n return Promise.all((await this).map(resource => resource.get(getOptions)));\n }\n\n /**\n * This function does the actual fetching, to obtained the url\n * of the linked resource. It returns the Resource object.\n */\n private async fetchLinkedResources(): Promise<Resource<T>[]> {\n\n const resource = await this.resource;\n const headers: { [name: string]: string } = {};\n if (!this.useHeadEnabled && this.preferTranscludeEnabled) {\n headers.Prefer = 'transclude=' + this.rel;\n }\n\n let state;\n if (this.useHeadEnabled) {\n state = await resource.head({headers});\n } else {\n state = await resource.get({\n headers\n });\n }\n\n const result: Resource<T>[] = state.followAll(this.rel);\n\n if (this.prefetchEnabled) {\n result.map( resource => {\n resource.get().catch( err => {\n // eslint-disable-next-line no-console\n console.warn('Error while prefetching linked resource', err);\n });\n });\n }\n\n return result;\n\n }\n\n}\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n}\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\nmodule.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction _getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n checkListener(listener);\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = _getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n if (arguments.length === 0)\n return this.listener.call(this.target);\n return this.listener.apply(this.target, arguments);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n checkListener(listener);\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n checkListener(listener);\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n checkListener(listener);\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n\nfunction once(emitter, name) {\n return new Promise(function (resolve, reject) {\n function errorListener(err) {\n emitter.removeListener(name, resolver);\n reject(err);\n }\n\n function resolver() {\n if (typeof emitter.removeListener === 'function') {\n emitter.removeListener('error', errorListener);\n }\n resolve([].slice.call(arguments));\n };\n\n eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n if (name !== 'error') {\n addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n }\n });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n if (typeof emitter.on === 'function') {\n eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n if (typeof emitter.on === 'function') {\n if (flags.once) {\n emitter.once(name, listener);\n } else {\n emitter.on(name, listener);\n }\n } else if (typeof emitter.addEventListener === 'function') {\n // EventTarget does not have `error` event semantics like Node\n // EventEmitters, we do not listen for `error` events here.\n emitter.addEventListener(name, function wrapListener(arg) {\n // IE does not have builtin `{ once: true }` support so we\n // have to do it manually.\n if (flags.once) {\n emitter.removeEventListener(name, wrapListener);\n }\n listener(arg);\n });\n } else {\n throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n }\n}\n","export function needsJsonStringify(input: any): boolean {\n\n if (typeof input ==='string') {\n return false;\n }\n\n if (globalThis.Buffer && input instanceof Buffer) {\n return false;\n }\n\n return true;\n\n}\n","import Client from './client';\nimport { State, headStateFactory, HeadState, isState } from './state';\nimport { resolve } from './util/uri';\nimport { FollowPromiseOne, FollowPromiseMany } from './follow-promise';\nimport { Link, LinkNotFound, LinkVariables } from './link';\nimport { EventEmitter } from 'node:events';\nimport { GetRequestOptions, PostRequestOptions, PatchRequestOptions, PutRequestOptions, HeadRequestOptions } from './types';\nimport { needsJsonStringify } from './util/fetch-body-helper';\n\n/**\n * A 'resource' represents an endpoint on a server.\n *\n * A resource has a uri, methods that correspond to HTTP methods,\n * and events to subscribe to state changes.\n */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\nexport class Resource<T = any> extends EventEmitter {\n\n /**\n * URI of the current resource\n */\n uri: string;\n\n /**\n * Reference to the Client that created the resource\n */\n client: Client;\n\n /**\n * This object tracks all in-flight requests.\n *\n * When 2 identical requests are made in quick succession, this object is\n * used to de-duplicate the requests.\n */\n private readonly activeRefresh: Map<string, Promise<State<T>>> = new Map<string, Promise<State<T>>>();\n\n /**\n * Create the resource.\n *\n * This is usually done by the Client.\n */\n constructor(client: Client, uri: string) {\n super();\n this.client = client;\n this.uri = uri;\n this.setMaxListeners(500);\n\n }\n\n /**\n * Gets the current state of the resource.\n *\n * This function will return a State object.\n */\n get(getOptions?: GetRequestOptions): Promise<State<T>> {\n\n const state = this.getCache();\n if (state) {\n return Promise.resolve(state);\n }\n\n const params = optionsToRequestInit('GET', getOptions);\n const uri = this.uri;\n\n const hash = requestHash(this.uri, getOptions);\n\n if (!this.activeRefresh.has(hash)) {\n this.activeRefresh.set(hash, (async (): Promise<State<T>> => {\n try {\n const response = await this.fetchOrThrow(params);\n const state = await this.client.getStateForResponse(uri, response);\n this.updateCache(state);\n return state;\n } finally {\n this.activeRefresh.delete(hash);\n }\n })());\n }\n\n return this.activeRefresh.get(hash)!;\n }\n\n /**\n * Does a HEAD request and returns a HeadState object.\n *\n * If there was a valid existing cache for a GET request, it will\n * still return that.\n */\n async head(headOptions?: HeadRequestOptions): Promise<HeadState> {\n\n let state: State|HeadState|null = this.client.cache.get(this.uri);\n if (state) {\n return state;\n }\n\n const response = await this.fetchOrThrow(\n optionsToRequestInit('HEAD', headOptions)\n );\n\n state = await headStateFactory(this.client, this.uri, response);\n return state;\n\n }\n\n\n /**\n * Gets the current state of the resource, skipping\n * the cache.\n *\n * This function will return a State object.\n */\n refresh(getOptions?: GetRequestOptions): Promise<State<T>> {\n\n const params = optionsToRequestInit('GET', getOptions);\n params.cache = 'no-cache';\n const uri = this.uri;\n\n const hash = requestHash(this.uri, getOptions);\n\n if (!this.activeRefresh.has(hash)) {\n this.activeRefresh.set(hash, (async (): Promise<State<T>> => {\n try {\n const response = await this.fetchOrThrow(params);\n const state = await this.client.getStateForResponse(uri, response);\n this.updateCache(state);\n return state;\n } finally {\n this.activeRefresh.delete(hash);\n }\n })());\n }\n\n return this.activeRefresh.get(hash)!;\n }\n\n /**\n * Updates the server state with a PUT request\n */\n async put(options: PutRequestOptions<T> | State): Promise<void> {\n\n const requestInit = optionsToRequestInit('PUT', options);\n\n /**\n * If we got a 'State' object passed, it means we don't need to emit a\n * stale event, as the passed object is the new\n * state.\n *\n * We're gonna track that with a custom header that will be removed\n * later in the fetch pipeline.\n */\n if (isState(options)) {\n requestInit.headers.set('X-KETTING-NO-STALE', '1');\n }\n\n await this.fetchOrThrow(requestInit);\n\n if (isState(options)) {\n this.updateCache(options);\n\n }\n\n }\n\n /**\n * Deletes the resource\n */\n async delete(): Promise<void> {\n\n await this.fetchOrThrow(\n { method: 'DELETE' }\n );\n\n }\n\n /**\n * Sends a POST request to the resource.\n *\n * See the documentation for PostRequestOptions for more details.\n * This function is used for RPC-like endpoints and form submissions.\n *\n * This function will return the response as a State object.\n */\n async post(options: PostRequestOptions): Promise<State> {\n\n const response = await this.fetchOrThrow(\n optionsToRequestInit('POST', options)\n );\n\n return this.client.getStateForResponse(this.uri, response);\n\n }\n\n /**\n * Sends a POST request, and follows to the next resource.\n *\n * If a server responds with a 201 Status code and a Location header,\n * it will automatically return the newly created resource.\n *\n * If the server responded with a 204 or 205, this function will return\n * `this`.\n */\n async postFollow(options: PostRequestOptions): Promise<Resource> {\n\n const response = await this.fetchOrThrow(\n optionsToRequestInit('POST', options)\n );\n\n switch (response.status) {\n case 201:\n if (response.headers.has('location')) {\n return this.go(response.headers.get('location')!);\n }\n throw new Error('Could not follow after a 201 request, because the server did not reply with a Location header. If you sent a Location header, check if your service is returning \"Access-Control-Expose-Headers: Location\".');\n case 204 :\n case 205 :\n return this;\n default:\n throw new Error('Did not receive a 201, 204 or 205 status code so we could not follow to the next resource');\n }\n\n }\n\n /**\n * Sends a PATCH request to the resource.\n *\n * This function defaults to a application/json content-type header.\n *\n * If the server responds with 200 Status code this will return a State object\n */\n async patch(options: PatchRequestOptions): Promise<undefined | State<T>> {\n\n const response = await this.fetchOrThrow(\n optionsToRequestInit('PATCH', options)\n );\n\n if (response.status === 200) {\n return await this.client.getStateForResponse(this.uri, response);\n }\n }\n\n /**\n * Follows a relationship, based on its reltype. For example, this might be\n * 'alternate', 'item', 'edit' or a custom url-based one.\n *\n * This function can also follow templated uris. You can specify uri\n * variables in the optional variables argument.\n */\n follow<TFollowedResource = any>(rel: string, variables?: LinkVariables): FollowPromiseOne<TFollowedResource> {\n\n return new FollowPromiseOne(this, rel, variables);\n\n }\n\n /**\n * Follows a relationship based on its reltype. This function returns a\n * Promise that resolves to an array of Resource objects.\n *\n * If no resources were found, the array will be empty.\n */\n followAll<TFollowedResource = any>(rel: string): FollowPromiseMany<TFollowedResource> {\n\n return new FollowPromiseMany(this, rel);\n\n }\n\n /**\n * Resolves a new resource based on a relative uri.\n *\n * Use this function to manually get a Resource object via a uri. The uri\n * will be resolved based on the uri of the current resource.\n *\n * This function doesn't do any HTTP requests.\n */\n go<TGoResource = any>(uri: string|Link): Resource<TGoResource> {\n\n if (typeof uri === 'string') {\n return this.client.go(resolve(this.uri, uri));\n } else {\n return this.client.go(uri);\n }\n\n }\n\n /**\n * Does a HTTP request on the current resource URI\n */\n fetch(init?: RequestInit): Promise<Response> {\n\n return this.client.fetcher.fetch(this.uri, init);\n\n }\n\n /**\n * Does a HTTP request on the current resource URI.\n *\n * If the response was a 4XX or 5XX, this function will throw\n * an exception.\n */\n fetchOrThrow(init?: RequestInit): Promise<Response> {\n\n return this.client.fetcher.fetchOrThrow(this.uri, init);\n\n }\n\n /**\n * Updates the state cache, and emits events.\n *\n * This will update the local state but *not* update the server\n */\n updateCache(state: State<T>) {\n\n if (state.uri !== this.uri) {\n throw new Error('When calling updateCache on a resource, the uri of the State object must match the uri of the Resource');\n }\n this.client.cacheState(state);\n\n }\n\n /**\n * Clears the state cache for this resource.\n */\n clearCache(): void {\n\n this.client.clearResourceCache([this.uri],[]);\n\n }\n\n /**\n * Retrieves the current cached resource state, and return `null` if it's\n * not available.\n */\n getCache(): State<T>|null {\n\n return this.client.cache.get(this.uri);\n\n }\n\n /**\n * Returns a Link object, by its REL.\n *\n * If the link does not exist, a LinkNotFound error will be thrown.\n *\n * @deprecated\n */\n async link(rel: string): Promise<Link> {\n\n const state = await this.get();\n const link = state.links.get(rel);\n\n if (!link) {\n throw new LinkNotFound(`Link with rel: ${rel} not found on ${this.uri}`);\n }\n return link;\n\n }\n\n /**\n * Returns all links defined on this object.\n *\n * @deprecated\n */\n async links(rel?: string): Promise<Link[]> {\n\n const state = await this.get();\n if (!rel) {\n return state.links.getAll();\n } else {\n return state.links.getMany(rel);\n }\n\n }\n\n /**\n *\n * Returns true or false depending on if a link with the specified relation\n * type exists.\n *\n * @deprecated\n */\n async hasLink(rel: string): Promise<boolean> {\n\n const state = await this.get();\n return state.links.has(rel);\n\n }\n}\n\n// eslint doesn't like that we have a generic T but not using it.\n// eslint-disable-next-line\nexport declare interface Resource<T = any> {\n\n /**\n * Subscribe to the 'update' event.\n *\n * This event will get triggered whenever a new State is received\n * from the server, either through a GET request or if it was\n * transcluded.\n *\n * It will also trigger when calling 'PUT' with a full state object,\n * and when updateCache() was used.\n */\n on(event: 'update', listener: (state: State) => void) : this;\n\n /**\n * Subscribe to the 'stale' event.\n *\n * This event will get triggered whenever an unsafe method was\n * used, such as POST, PUT, PATCH, etc.\n *\n * When any of these methods are used, the local cache is stale.\n */\n on(event: 'stale', listener: () => void) : this;\n\n /**\n * Subscribe to the 'delete' event.\n *\n * This event gets triggered when the `DELETE` http method is used.\n */\n on(event: 'delete', listener: () => void) : this;\n\n /**\n * Subscribe to the 'update' event and unsubscribe after it was\n * emitted the first time.\n */\n once(event: 'update', listener: (state: State) => void) : this;\n\n /**\n * Subscribe to the 'stale' event and unsubscribe after it was\n * emitted the first time.\n */\n once(event: 'stale', listener: () => void) : this;\n\n /**\n * Subscribe to the 'delete' event and unsubscribe after it was\n * emitted the first time.\n */\n once(event: 'delete', listener: () => void) : this;\n\n /**\n * Unsubscribe from the 'update' event\n */\n off(event: 'update', listener: (state: State) => void) : this;\n\n /**\n * Unsubscribe from the 'stale' event\n */\n off(event: 'stale', listener: () => void) : this;\n\n /**\n * Unsubscribe from the 'delete' event\n */\n off(event: 'delete', listener: () => void) : this;\n\n /**\n * Emit an 'update' event.\n */\n emit(event: 'update', state: State) : boolean;\n\n /**\n * Emit a 'stale' event.\n */\n emit(event: 'stale') : boolean;\n\n /**\n * Emit a 'delete' event.\n */\n emit(event: 'delete') : boolean;\n\n}\n\nexport default Resource;\n\ntype StrictRequestInit = RequestInit & {\n headers: Headers;\n};\n\n/**\n * Convert request options to RequestInit\n *\n * RequestInit is passed to the constructor of fetch(). We have our own 'options' format\n */\nfunction optionsToRequestInit(method: 'GET', options?: GetRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: 'HEAD', options?: HeadRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: 'PATCH', options?: PatchRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: 'POST', options?: PostRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: 'PUT', options?: PutRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: string, options?: GetRequestOptions | PostRequestOptions | PatchRequestOptions | PutRequestOptions): StrictRequestInit {\n\n if (!options) {\n return {\n method,\n headers: new Headers(),\n };\n }\n let headers;\n if (options.getContentHeaders) {\n headers = new Headers(options.getContentHeaders());\n } else if (options.headers) {\n headers = new Headers(options.headers);\n } else {\n headers = new Headers();\n }\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json');\n }\n let body;\n if ((options as any).serializeBody !== undefined) {\n body = (options as any).serializeBody();\n } else if ((options as any).data) {\n body = (options as any).data;\n if (needsJsonStringify(body)) {\n body = JSON.stringify(body);\n }\n } else {\n body = null;\n }\n return {\n method,\n body,\n headers,\n };\n\n}\n\nfunction requestHash(uri: string, options: GetRequestOptions | undefined): string {\n\n const headers: Record<string, string> = {};\n if (options) {\n new Headers(options.getContentHeaders?.() || options.headers)\n .forEach((value, key) => {\n headers[key] = value;\n });\n }\n\n const headerStr = Object.entries(headers).map( ([name, value]) => {\n return name.toLowerCase() + ':' + value;\n }).join(',');\n\n return uri + '|' + headerStr;\n}\n","import { StateCache } from './';\nimport { State } from '../state';\n\n/**\n * The 'Forever' cache stores any State for as long as the application\n * lives.\n *\n * It is a good default for most applications, but it means that if\n * a resource was changed server-side, Ketting will not pick up that change\n * until something was done to expire caches.\n *\n * Executing an unsafe method, calling clearCache() on a resource, or\n * when a resource appears in Location, Content-Location, or \"invalidates\"\n * link relationships.\n */\nexport class ForeverCache implements StateCache {\n\n private cache: Map<string, State>;\n\n constructor() {\n this.cache = new Map();\n }\n\n /**\n * Store a State object.\n *\n * This function will clone the state object before storing\n */\n store(state: State) {\n this.cache.set(\n state.uri,\n state.clone()\n );\n }\n\n /**\n * Retrieve a State object from the cache by its absolute uri\n */\n get(uri: string): State | null {\n\n const state = this.cache.get(uri);\n if (!state) {\n return null;\n }\n return state.clone();\n\n }\n\n /**\n * Return true if a State object with the specified uri exists in the cache\n */\n has(uri: string): boolean {\n\n return this.cache.has(uri);\n\n }\n\n /**\n * Delete a State object from the cache, by its uri\n */\n delete(uri: string) {\n this.cache.delete(uri);\n }\n\n /**\n * Purge the entire cache\n */\n clear() {\n this.cache.clear();\n }\n\n /**\n * Clean up any dangling references to avoid memory leaks.\n */\n destroy() {\n\n }\n\n}\n","import { State } from '../state';\nimport { ForeverCache } from './forever';\n\n/**\n * ShortCache stores items in the cache for a short time.\n *\n * This cache can be a good choice if your server heavily relies\n * on HTTP cache headers and Ketting runs in your browser, or if in general\n * you want very up-to-date data.\n *\n * The reason in this scenarios it's useful to still have a 'very temporary'\n * cache, is because during many operations `get()` may be called in rapid\n * succession, and it also allows for enough time for 'embedded items' to\n * pe placed in the cache and extracted again.\n */\nexport class ShortCache extends ForeverCache {\n\n private cacheTimeout: number;\n private activeTimers: Map<string, ReturnType<typeof setInterval>>;\n\n /**\n * Create the short cache.\n *\n * cacheTimeout is specified in ms.\n */\n constructor(cacheTimeout: number = 30000) {\n super();\n this.cacheTimeout = cacheTimeout;\n this.activeTimers = new Map();\n }\n\n /**\n * Store a State object.\n *\n * This function will clone the state object before storing\n */\n store(state: State) {\n super.store(state);\n this.setTimer(state.uri);\n }\n\n private setTimer(uri: string) {\n\n if (this.activeTimers.has(uri)) {\n clearTimeout(this.activeTimers.get(uri)!);\n }\n // If there is a TON in the cache, this algorithm might\n // be optimized by using a linked list and a single timeout\n // for the 'next scheduled' expiry.\n //\n // The expectation is that this is not the case though, so this is the\n // lazy/easy way.\n this.activeTimers.set(\n uri,\n setTimeout( () => {\n this.delete(uri);\n this.activeTimers.delete(uri);\n }, this.cacheTimeout)\n );\n\n }\n\n /**\n * Clean up any dangling references to avoid memory leaks.\n */\n destroy() {\n\n for (const timer of this.activeTimers.values()) {\n clearTimeout(timer);\n }\n\n }\n}\n","import { StateCache } from './';\nimport { State } from '../state';\n\n/**\n * The NeverCache caches absolutely nothing.\n *\n * This should usually only be used in testing scenarios or if you really\n * know what you're doing.\n *\n * Using it could cause excessive requests, and will cause embedded items\n * to be ignored.\n */\nexport class NeverCache implements StateCache {\n\n /**\n * Store a State object.\n *\n * This function will clone the state object before storing\n */\n store(state: State) {\n // Nothing to do\n }\n\n /**\n * Retrieve a State object from the cache by its absolute uri\n */\n get(uri: string): null {\n return null;\n }\n\n /**\n * Return true if a State object with the specified uri exists in the cache\n */\n has(uri: string): boolean {\n\n return false;\n\n }\n\n /**\n * Delete a State object from the cache, by its uri\n */\n delete(uri: string) {\n // Nothing to do\n }\n\n /**\n * Purge the entire cache\n */\n clear() {\n // Nothing to do\n }\n\n}\n","import { FetchMiddleware } from '../http/fetcher';\nimport { isSafeMethod } from '../http/util';\nimport * as LinkHeader from 'http-link-header';\nimport { resolve } from '../util/uri';\nimport Client from '../client';\n\n/**\n * This middleware manages the cache based on information in requests\n * and responses.\n *\n * It expires items from the cache and updates the cache if `Content-Location`\n * appeared in the response.\n *\n * It's also responsible for emitting 'stale' events.\n */\nexport default function(client: Client): FetchMiddleware {\n\n return async(request, next) => {\n\n /**\n * Prevent a 'stale' event from being emitted, but only for the main\n * uri\n */\n let noStaleEvent = false;\n\n if (request.headers.has('X-KETTING-NO-STALE')) {\n noStaleEvent = true;\n request.headers.delete('X-KETTING-NO-STALE');\n }\n\n const response = await next(request);\n\n if (isSafeMethod(request.method)) {\n return response;\n }\n\n if (!response.ok) {\n // There was an error, no cache changes\n return response;\n }\n\n // We just processed an unsafe method, lets notify all subsystems.\n const stale = [];\n const deleted = [];\n\n if (request.method === 'DELETE') {\n deleted.push(request.url);\n } else if (!noStaleEvent) {\n stale.push(request.url);\n }\n\n // If the response had a Link: rel=invalidate header, we want to\n // expire those too.\n if (response.headers.has('Link')) {\n for (const httpLink of LinkHeader.parse(response.headers.get('Link')!).rel('invalidates')) {\n const uri = resolve(request.url, httpLink.uri);\n stale.push(uri);\n }\n }\n\n // Location headers should also expire\n if (response.headers.has('Location')) {\n stale.push(\n resolve(request.url, response.headers.get('Location')!)\n );\n }\n\n client.clearResourceCache(stale, deleted);\n\n // If the response had a 'Content-Location' header, it means that the\n // response body is the _new_ state for the url in the content-location\n // header, so we store it!\n if (request.cache !== 'no-store' && response.headers.has('Content-Location')) {\n const cl = resolve(request.url, response.headers.get('Content-Location')!);\n const clState = await client.getStateForResponse(\n cl,\n response.clone()\n );\n client.cacheState(clState);\n }\n\n return response;\n\n };\n\n}\n","import { FetchMiddleware } from '../http/fetcher';\nimport Client from '../client';\n\n/**\n * This middleware injects a default Accept header.\n *\n * The list of content-types is generated from the Client's\n * 'contentTypeMap'.\n */\nexport default function(client: Client): FetchMiddleware {\n\n return async(request, next) => {\n\n if (!request.headers.has('Accept')) {\n const acceptHeader = Object.entries(client.contentTypeMap).map(\n ([contentType, [, q]]) => contentType + ';q=' + q\n ).join(', ');\n request.headers.set('Accept', acceptHeader);\n }\n return next(request);\n\n };\n\n}\n","import { FetchMiddleware } from '../http/fetcher';\nimport * as LinkHeader from 'http-link-header';\nimport { resolve } from '../util/uri';\n\n/**\n * This middleware will emit warnings based on HTTP responses.\n *\n * Currently it just inspects the 'Deprecation' HTTP header from\n * draft-dalal-deprecation-header\n */\nexport default function(): FetchMiddleware {\n\n return async(request, next) => {\n\n const response = await next(request);\n const deprecation = response.headers.get('Deprecation');\n if (deprecation) {\n const sunset = response.headers.get('Sunset');\n let msg = `[Ketting] The resource ${request.url} is deprecated.`;\n if (sunset) {\n msg += ' It will no longer respond ' + sunset;\n }\n if (response.headers.has('Link')) {\n for (const httpLink of LinkHeader.parse(response.headers.get('Link')!).rel('deprecation')) {\n const uri = resolve(request.url, httpLink.uri);\n msg += `See ${uri} for more information.`;\n }\n }\n\n /* eslint-disable-next-line no-console */\n console.warn(msg);\n\n }\n return response;\n\n };\n\n}\n","import { Fetcher, FetchMiddleware } from './http/fetcher';\nimport Resource from './resource';\nimport { State, StateFactory } from './state';\nimport {\n halStateFactory,\n binaryStateFactory,\n jsonApiStateFactory,\n sirenStateFactory,\n textStateFactory,\n cjStateFactory,\n htmlStateFactory\n} from './state';\nimport { parseContentType } from './http/util';\nimport { resolve } from './util/uri';\nimport { Link, LinkVariables } from './link';\nimport { FollowPromiseOne } from './follow-promise';\nimport { StateCache, ForeverCache } from './cache';\nimport cacheExpireMiddleware from './middlewares/cache';\nimport acceptMiddleware from './middlewares/accept-header';\nimport warningMiddleware from './middlewares/warning';\n\nexport default class Client {\n\n /**\n * All relative urls will by default use the bookmarkUri to\n * expand. It should usually be the starting point of your\n * API\n */\n bookmarkUri: string;\n\n /**\n * Supported content types\n *\n * Each content-type has a 'factory' that turns a HTTP response\n * into a State object.\n *\n * The last value in the array is the 'q=' value, used in Accept\n * headers. Higher means higher priority.\n */\n contentTypeMap: {\n [mimeType: string]: [StateFactory<any>, string];\n } = {\n 'application/prs.hal-forms+json': [halStateFactory, '1.0'],\n 'application/hal+json': [halStateFactory, '0.9'],\n 'application/vnd.api+json': [jsonApiStateFactory, '0.8'],\n 'application/vnd.siren+json': [sirenStateFactory, '0.8'],\n 'application/vnd.collection+json': [cjStateFactory, '0.8'],\n 'application/json': [halStateFactory, '0.7'],\n 'text/html': [htmlStateFactory, '0.6'],\n };\n\n /**\n * The cache for 'State' objects\n */\n cache: StateCache;\n\n /**\n * The cache for 'Resource' objects. Each unique uri should\n * only ever get 1 associated resource.\n */\n resources: Map<string, Resource>;\n\n /**\n * Fetcher is a utility object that handles fetch() requests\n * and middlewares.\n */\n fetcher: Fetcher;\n\n constructor(bookmarkUri: string) {\n this.bookmarkUri = bookmarkUri;\n this.fetcher = new Fetcher();\n this.fetcher.use(cacheExpireMiddleware(this));\n this.fetcher.use(acceptMiddleware(this));\n this.fetcher.use(warningMiddleware());\n this.cache = new ForeverCache();\n this.resources = new Map();\n }\n\n /**\n * Follows a relationship, based on its reltype. For example, this might be\n * 'alternate', 'item', 'edit' or a custom url-based one.\n *\n * This function can also follow templated uris. You can specify uri\n * variables in the optional variables argument.\n */\n follow<TFollowedResource = any>(rel: string, variables?: LinkVariables): FollowPromiseOne<TFollowedResource> {\n\n return this.go().follow(rel, variables);\n\n }\n\n /**\n * Returns a resource by its uri.\n *\n * This function doesn't do any HTTP requests. The uri is optional. If it's\n * not specified, it will return the bookmark resource.\n *\n * If a relative uri is passed, it will be resolved based on the bookmark\n * uri.\n *\n * @example\n * const res = ketting.go('https://example.org/);\n * @example\n * const res = ketting.go<Author>('/users/1');\n * @example\n * const res = ketting.go(); // bookmark\n */\n go<TResource = any>(uri?: string|Link): Resource<TResource> {\n\n let absoluteUri;\n if (uri === undefined) {\n absoluteUri = this.bookmarkUri;\n } else if (typeof uri === 'string') {\n absoluteUri = resolve(this.bookmarkUri, uri);\n } else {\n absoluteUri = resolve(uri);\n }\n if (!this.resources.has(absoluteUri)) {\n const resource = new Resource(this, absoluteUri);\n this.resources.set(absoluteUri, resource);\n return resource;\n }\n return this.resources.get(absoluteUri)!;\n\n }\n\n /**\n * Adds a fetch middleware, which will be executed for\n * each fetch() call.\n *\n * If 'origin' is specified, fetch middlewares can be executed\n * only if the host/origin matches.\n */\n use(middleware: FetchMiddleware, origin: string = '*') {\n\n this.fetcher.use(middleware, origin);\n\n }\n\n /**\n * Clears the entire state cache\n */\n clearCache() {\n\n this.cache.clear();\n this.cacheDependencies = new Map();\n\n }\n\n /**\n * Caches a State object\n *\n * This function will also emit 'update' events to resources, and store all\n * embedded states.\n */\n cacheState(state: State) {\n\n // Flatten the list of state objects.\n const newStates = flattenState(state);\n\n // Register all cache dependencies.\n for(const nState of newStates) {\n for(const invByLink of nState.links.getMany('inv-by')) {\n this.addCacheDependency(resolve(invByLink), nState.uri);\n }\n }\n\n // Store all new caches\n for(const nState of newStates) {\n this.cache.store(nState);\n }\n\n // Emit 'update' events\n for(const nState of newStates) {\n const resource = this.resources.get(nState.uri);\n if (resource) {\n // We have a resource for this object, notify it as well.\n resource.emit('update', nState);\n }\n }\n\n }\n\n /**\n * cacheDependencies contains all cache relationships between\n * resources.\n *\n * This lets a user (for example) let a resource automatically\n * expire, if another one expires.\n *\n * A server can populate this list using the `inv-by' link.\n *\n * @deprecated This property will go private in a future release.\n */\n public cacheDependencies: Map<string, Set<string>> = new Map();\n\n /**\n * Adds a cache dependency between two resources.\n *\n * If the 'target' resource ever expires, it will cause 'dependentUri' to\n * also expire.\n *\n * Both argument MUST be absolute urls.\n */\n addCacheDependency(targetUri: string, dependentUri: string): void {\n\n if (this.cacheDependencies.has(targetUri)) {\n this.cacheDependencies.get(targetUri)!.add(dependentUri);\n } else {\n this.cacheDependencies.set(targetUri, new Set([dependentUri]));\n }\n\n }\n\n /**\n * Helper function for clearing the cache for a resource.\n *\n * This function will also emit the 'stale' event for resources that have\n * subscribers, and handle any dependent resource caches.\n *\n * If any resources are specified in deletedUris, those will not\n * receive 'stale' events, but 'delete' events instead.\n */\n clearResourceCache(staleUris: string[], deletedUris: string[]) {\n\n let stale = new Set<string>();\n const deleted = new Set<string>();\n for(const uri of staleUris) {\n stale.add(resolve(this.bookmarkUri, uri));\n }\n for(const uri of deletedUris) {\n stale.add(resolve(this.bookmarkUri, uri));\n deleted.add(resolve(this.bookmarkUri, uri));\n }\n\n stale = expandCacheDependencies(\n new Set([...stale, ...deleted]),\n this.cacheDependencies\n );\n\n for(const uri of stale) {\n this.cache.delete(uri);\n\n const resource = this.resources.get(uri);\n if (resource) {\n if (deleted.has(uri)) {\n resource.emit('delete');\n } else {\n resource.emit('stale');\n }\n\n }\n\n }\n\n }\n\n /**\n * Transforms a fetch Response to a State object.\n */\n async getStateForResponse(uri: string, response: Response): Promise<State> {\n\n const contentType = parseContentType(response.headers.get('Content-Type')!);\n\n if (!contentType || response.status === 204) {\n return binaryStateFactory(this, uri, response);\n }\n\n if (contentType in this.contentTypeMap) {\n return this.contentTypeMap[contentType][0](this, uri, response);\n } else if (contentType.startsWith('text/')) {\n // Default to TextState for any format starting with text/\n return textStateFactory(this, uri, response);\n } else if (contentType.match(/^application\\/[A-Za-z-.]+\\+json/)) {\n // Default to HalState for any format containing a pattern like application/*+json\n return halStateFactory(this, uri, response);\n } else {\n return binaryStateFactory(this, uri, response);\n }\n\n }\n\n\n}\n\n\n\n/**\n * Find all dependencies for a given resource.\n *\n * For example, if\n * * if resourceA depends on resourceB\n * * and resourceB depends on resourceC\n *\n * Then if 'resourceC' expires, so should 'resourceA' and 'resourceB'.\n *\n * This function helps us find these dependencies recursively and guarding\n * against recursive loops.\n */\nfunction expandCacheDependencies(uris: Set<string>, dependencies: Map<string, Set<string>>, output?: Set<string>): Set<string> {\n\n if (!output) output = new Set();\n\n for(const uri of uris) {\n\n if (!output.has(uri)) {\n output.add(uri);\n if (dependencies.has(uri)) {\n expandCacheDependencies(dependencies.get(uri)!, dependencies, output);\n }\n }\n\n }\n\n return output;\n\n}\n\n/**\n * Take a State object, find all it's embedded resources and return a flat\n * array of all resources at any depth.\n */\nfunction flattenState(state: State, result: Set<State> = new Set<State>()): Set<State> {\n\n result.add(state);\n for(const embedded of state.getEmbedded()) {\n flattenState(embedded, result);\n }\n return result;\n\n}\n","import { FetchMiddleware } from './fetcher';\n\nexport default (userName: string, password: string): FetchMiddleware => {\n\n const basicAuthHeader = 'Basic ' + btoa(userName + ':' + password);\n\n return (request, next) => {\n\n request.headers.set('Authorization', basicAuthHeader);\n return next(request);\n\n };\n\n};\n","import { FetchMiddleware } from './fetcher';\n\nexport default (token: string): FetchMiddleware => {\n\n const bearerAuthHeader = 'Bearer ' + token;\n\n return (request, next) => {\n\n request.headers.set('Authorization', bearerAuthHeader);\n return next(request);\n\n };\n\n};\n","import { FetchMiddleware } from './fetcher';\nimport { OAuth2Client, OAuth2Fetch } from '@badgateway/oauth2-client';\n\nfunction oauth2mw(oauth2Options: OAuth2Options, token?: OAuth2Token): FetchMiddleware {\n\n console.warn('The OAuth2 middleware in Ketting is deprecated, and will be removed in the next major version of Ketting. You should upgrade to the OAuth2Fetch from the @badgateway/oauth2-client project');\n\n // This code converts the old 'fetch-mw-oauth2' options format to the new\n // oauth2 client we use now, which is why it's a bit clunky.\n const newOptions: ConstructorParameters<typeof OAuth2Client>[0] = {\n clientId: oauth2Options.clientId,\n clientSecret: 'clientSecret' in oauth2Options ? oauth2Options.clientSecret : undefined,\n tokenEndpoint: oauth2Options.tokenEndpoint,\n };\n\n\n const oauth2Client = new OAuth2Client(newOptions);\n const oauth2Fetch = new OAuth2Fetch({\n client: oauth2Client,\n getNewToken: async() => {\n\n switch(oauth2Options.grantType) {\n case 'password' :\n return oauth2Client.password({\n username: oauth2Options.userName,\n password: oauth2Options.password,\n scope: oauth2Options.scope,\n });\n case 'client_credentials' :\n return oauth2Client.clientCredentials({\n scope: oauth2Options.scope\n });\n case 'authorization_code' :\n return oauth2Client.authorizationCode.getToken({\n code: oauth2Options.code,\n codeVerifier: oauth2Options.codeVerifier,\n redirectUri: oauth2Options.redirectUri,\n });\n case undefined:\n return null;\n }\n\n },\n\n getStoredToken: (): OAuth2Token|null => {\n return token ?? null;\n },\n\n storeToken: (token: OAuth2Token) => {\n if (oauth2Options.onTokenUpdate) {\n oauth2Options.onTokenUpdate(token);\n }\n },\n\n onError: (err: Error) => {\n if (oauth2Options.onAuthError) {\n oauth2Options.onAuthError(err);\n }\n }\n });\n\n\n\n return oauth2Fetch.mw();\n}\n\n\nexport default oauth2mw;\n\n/**\n * Token information\n */\nexport type OAuth2Token = {\n\n /**\n * OAuth2 Access Token\n */\n accessToken: string;\n\n /**\n * When the Access Token expires.\n *\n * This is expressed as a unix timestamp in milliseconds.\n */\n expiresAt: number | null;\n\n /**\n * OAuth2 refresh token\n */\n refreshToken: string | null;\n};\n\n/**\n * grant_type=password\n */\ntype PasswordGrantOptions = {\n grantType: 'password';\n\n /**\n * OAuth2 client id\n */\n clientId: string;\n\n /**\n * OAuth2 Client Secret\n */\n clientSecret: string;\n\n /**\n * OAuth2 token endpoint\n */\n tokenEndpoint: string;\n\n /**\n * List of OAuth2 scopes\n */\n scope?: string[];\n\n /**\n * Username to log in as\n */\n userName: string;\n\n /**\n * Password\n */\n password: string;\n\n /**\n * Callback to trigger when a new access/refresh token pair was obtained.\n */\n onTokenUpdate?: (token: OAuth2Token) => void;\n\n /**\n * If authentication fails without a chance of recovery, this gets triggered.\n *\n * This is used for example when your resource server returns a 401, but only after\n * other attempts have been made to reauthenticate (such as a token refresh).\n */\n onAuthError?: (error: Error) => void;\n};\n\n/**\n * grant_type=client_credentials\n */\ntype ClientCredentialsGrantOptions = {\n grantType: 'client_credentials';\n\n /**\n * OAuth2 client id\n */\n clientId: string;\n\n /**\n * OAuth2 Client Secret\n */\n clientSecret: string;\n\n /**\n * OAuth2 token endpoint\n */\n tokenEndpoint: string;\n\n /**\n * List of OAuth2 scopes\n */\n scope?: string[];\n\n /**\n * Callback to trigger when a new access/refresh token pair was obtained.\n */\n onTokenUpdate?: (token: OAuth2Token) => void;\n\n /**\n * If authentication fails without a chance of recovery, this gets triggered.\n *\n * This is used for example when your resource server returns a 401, but only after\n * other attempts have been made to reauthenticate (such as a token refresh).\n */\n onAuthError?: (error: Error) => void;\n};\n\n/**\n * grant_type=authorization_code\n */\ntype AuthorizationCodeGrantOptions = {\n grantType: 'authorization_code';\n\n /**\n * OAuth2 client id\n */\n clientId: string;\n\n /**\n * OAuth2 token endpoint\n */\n tokenEndpoint: string;\n\n /**\n * The redirect_uri that was passed originally to the 'authorization' endpoint.\n *\n * This must be identical to the original string, as conforming OAuth2 servers\n * will validate this.\n */\n redirectUri: string;\n\n /**\n * Code that was obtained from the authorization endpoint\n */\n code: string;\n\n /**\n * Callback to trigger when a new access/refresh token pair was obtained.\n */\n onTokenUpdate?: (token: OAuth2Token) => void;\n\n /**\n * If authentication fails without a chance of recovery, this gets triggered.\n *\n * This is used for example when your resource server returns a 401, but only after\n * other attempts have been made to reauthenticate (such as a token refresh).\n */\n onAuthError?: (error: Error) => void;\n\n /**\n * When using PKCE, specify the previously generated code verifier here.\n */\n codeVerifier?: string;\n};\n\n/**\n * In case you obtained an access token and/or refresh token through different\n * means, you can not specify a grant_type and simply only specify an access\n * and refresh token.\n *\n * If a refresh or tokenEndpoint are not supplied, the token will never get refreshed.\n */\ntype RefreshOnlyGrantOptions = {\n grantType: undefined;\n\n /**\n * OAuth2 client id\n */\n clientId: string;\n tokenEndpoint: string;\n\n /**\n * Callback to trigger when a new access/refresh token pair was obtained.\n */\n onTokenUpdate?: (token: OAuth2Token) => void;\n\n /**\n * If authentication fails without a chance of recovery, this gets triggered.\n *\n * This is used for example when your resource server returns a 401, but only after\n * other attempts have been made to reauthenticate (such as a token refresh).\n */\n onAuthError?: (error: Error) => void;\n};\n\nexport type OAuth2Options =\n PasswordGrantOptions | ClientCredentialsGrantOptions | AuthorizationCodeGrantOptions | RefreshOnlyGrantOptions;\n"],"x_google_ignoreList":[20],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["parseLink","factory","parseLink","factory","parseLink","factory","parseLink","factory","parseLink","factory","parseLink","factory","parseLink","factory","parseLink","parseLink","headStateFactory","halStateFactory","jsonApiStateFactory","sirenStateFactory","cjStateFactory","htmlStateFactory","cacheExpireMiddleware","acceptMiddleware","warningMiddleware","binaryStateFactory","textStateFactory"],"sources":["../../src/http/error.ts","../../package.json","../../src/http/fetcher.ts","../../src/util/uri.ts","../../src/link.ts","../../src/state/interface.ts","../../src/action.ts","../../src/util/uri-template.ts","../../src/http/util.ts","../../src/state/base-state.ts","../../src/state/hal.ts","../../src/state/binary.ts","../../src/state/jsonapi.ts","../../src/state/siren.ts","../../src/state/text.ts","../../src/state/collection-json.ts","../../src/util/html.ts","../../src/state/html.ts","../../src/state/head.ts","../../src/follow-promise.ts","../../src/util/fetch-body-helper.ts","../../src/resource.ts","../../src/cache/forever.ts","../../src/cache/short.ts","../../src/cache/never.ts","../../src/middlewares/cache.ts","../../src/middlewares/accept-header.ts","../../src/middlewares/warning.ts","../../src/client.ts","../../src/http/basic-auth.ts","../../src/http/bearer-auth.ts","../../src/http/oauth2.ts"],"sourcesContent":["/**\n * HttpError extends the Error object, and is thrown wheenever servers emit\n * HTTP errors.\n *\n * It has a response property, allowing users to find out more about the\n * nature of the error.\n */\nexport class HttpError extends Error {\n\n response: Response;\n status: number;\n\n constructor(response: Response) {\n super('HTTP error ' + response.status);\n this.response = response;\n this.status = response.status;\n }\n\n}\n\n/**\n * Problem extends the HttpError object. If a server emits a HTTP error, and\n * the response body's content-type is application/problem+json.\n *\n * application/problem+json is defined in RFC7807 and provides a standardized\n * way to describe error conditions by a HTTP server.\n */\nexport class Problem extends HttpError {\n\n body: {\n type: string;\n title?: string;\n status: number;\n detail?: string;\n instance?: string;\n [x: string]: any;\n };\n\n constructor(response: Response, problemBody: Record<string, any>) {\n super(response);\n\n this.body = {\n type: problemBody.type ?? 'about:blank',\n status: problemBody.status ?? this.status,\n ...problemBody\n };\n\n if (this.body.title) {\n this.message = 'HTTP Error ' + this.status + ': ' + this.body.title;\n }\n }\n\n}\n\n/**\n * This function creates problems, not unlike the the author of this file.\n *\n * It takes a Fetch Response object, and returns a HttpError. If the HTTP\n * response has a type of application/problem+json it will return a Problem\n * object.\n *\n * Because parsing the response might be asynchronous, the function returns\n * a Promise resolving in either object.\n */\nexport default async function problemFactory(response: Response): Promise<HttpError | Problem> {\n\n const contentType = response.headers.get('Content-Type');\n if (contentType?.match(/^application\\/problem\\+json/i)) {\n const problemBody = await response.json();\n return new Problem(response, problemBody);\n } else {\n return new HttpError(response);\n }\n\n}\n\n","","import problemFactory from './error';\n\nexport type FetchMiddleware =\n (request: Request, next: (request: Request) => Promise<Response>) => Promise<Response>;\n\n/**\n * The fetcher object is responsible for calling fetch()\n *\n * This is wrapped in an object because we want to support\n * 'fetch middlewares'. These middlewares are similar to server-side\n * middlewares and can intercept requests and alter requests/responses.\n */\nexport class Fetcher {\n\n middlewares: [RegExp, FetchMiddleware][] = [];\n\n advertiseKetting: boolean = true;\n\n /**\n * A wrapper for MDN fetch()\n *\n * This wrapper supports 'fetch middlewares'. It will call them\n * in sequence.\n */\n fetch(resource: string|Request, init?: RequestInit): Promise<Response> {\n\n const request = new Request(resource, init);\n\n const origin = new URL(request.url).origin;\n const mws = this.getMiddlewaresByOrigin(origin);\n mws.push((innerRequest: Request) => {\n\n if (!innerRequest.headers.has('User-Agent') && this.advertiseKetting) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n innerRequest.headers.set('User-Agent', 'Ketting/' + require('../../package.json').version);\n }\n\n return fetch(innerRequest);\n });\n\n return invokeMiddlewares(mws, request);\n\n }\n\n /**\n * Returns the list of middlewares that are applicable to\n * a specific origin\n */\n getMiddlewaresByOrigin(origin: string): FetchMiddleware[] {\n\n return this.middlewares.filter( ([regex]) => {\n return regex.test(origin);\n\n }).map( ([, middleware]) => {\n return middleware;\n });\n\n }\n\n /**\n * Add a middleware\n */\n use(mw: FetchMiddleware, origin: string = '*'): void {\n\n const matchSplit = origin.split('*');\n const matchRegex = matchSplit.map(\n part =>\n part.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n ).join('(.*)');\n\n const regex = new RegExp('^' + matchRegex + '$');\n this.middlewares.push([regex, mw]);\n\n }\n\n /**\n * Does a HTTP request and throws an exception if the server emitted\n * a HTTP error.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Request/Request\n */\n async fetchOrThrow(resource: string|Request, init?: RequestInit): Promise<Response> {\n\n const response = await this.fetch(resource, init);\n\n if (response.ok) {\n return response;\n } else {\n throw await problemFactory(response);\n }\n\n }\n\n}\nexport default Fetcher;\n\nfunction invokeMiddlewares(mws: FetchMiddleware[], request: Request): Promise<Response> {\n\n return mws[0](\n request,\n (nextRequest: Request) => {\n return invokeMiddlewares(mws.slice(1), nextRequest);\n }\n );\n\n}\n","import { Link } from '../link';\n\ntype UrlParts = {\n host?: string|null;\n};\n\n/**\n * Resolves a relative url using another url.\n *\n * This is the node.js version.\n */\nexport function resolve(base: string, relative: string): string;\nexport function resolve(link: Link): string;\nexport function resolve(arg1: string|Link, arg2?: string): string {\n\n\n // Normalize the 2 calling conventions\n let base, relative;\n if (typeof arg1==='string') {\n base = arg1;\n relative = arg2 as string;\n } else {\n base = arg1.context;\n relative = arg1.href;\n }\n\n // Our resolve function allows both parts to be relative, and new URL\n // requires the second argument to be absolute, so we wil use the RFC6761\n // 'invalid' domain as a base, so we can later strip it out.\n const newUrl = new URL(relative, new URL(base, 'http://ketting.invalid'));\n\n if (newUrl.hostname === 'ketting.invalid') {\n // Make the URL relative again if it contained 'ketting.invalid'\n return newUrl.pathname + newUrl.search + newUrl.hash;\n } else if (base.startsWith('//')) {\n // if the 'base' started with `//` it means it's a protocol-relative URL.\n // We want to make sure we retain that and don't accidentally add the `http`\n // from ketting.invalid\n return '//' + newUrl.host + newUrl.pathname + newUrl.search + newUrl.hash;\n } else {\n return newUrl.toString();\n }\n\n}\n\n/**\n * Parses a url in multiple components.\n *\n * This is the node.js version.\n */\nexport function parse(url: string): UrlParts {\n\n const parsed = new URL(url, 'http://ketting.invalid');\n if (parsed.hostname === 'ketting.invalid') {\n return {\n host: null\n };\n } else {\n return {\n host: parsed.host\n };\n }\n\n}\n","import { LinkHints } from 'hal-types';\nimport { resolve } from './util/uri';\n\nexport type Link = {\n /**\n * Target URI\n */\n href: string;\n\n /**\n * Context URI.\n *\n * Used to resolve relative URIs\n */\n context: string;\n\n /**\n * Relation type\n */\n rel: string;\n\n /**\n * Link title\n */\n title?: string;\n\n /**\n * Content type hint of the target resource\n */\n type?: string;\n\n /**\n * Anchor.\n *\n * This describes where the link is linked from, from for example\n * a fragment in the current document\n */\n anchor?: string;\n\n /**\n * Language of the target resource\n */\n hreflang?: string;\n\n /**\n * HTML5 media attribute\n */\n media?: string;\n\n /**\n * If templated is set to true, the href is a templated URI.\n */\n templated?: boolean;\n\n /**\n * Link hints, as defined in draft-nottingham-link-hint\n */\n hints?: LinkHints;\n\n /**\n * Link name\n *\n * This is sometimes used as a machine-readable secondary key for links.\n *\n * This is at least used in HAL, but there may be other formats:\n *\n * @see https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-06#section-5.5\n */\n name?: string;\n\n}\n\ntype NewLink = Omit<Link, 'context'>;\n\n\n/**\n * Links container, providing an easy way to manage a set of links.\n */\nexport class Links {\n\n private store: Map<string, Link[]>;\n\n constructor(public defaultContext: string, links?: Link[] | Links) {\n\n this.store = new Map();\n\n if (links) {\n if (links instanceof Links) {\n this.add(...links.getAll());\n } else {\n for (const link of links) {\n this.add(link);\n }\n }\n }\n\n }\n\n /**\n * Adds a link to the list\n */\n add(...links: (Link | NewLink)[]): void\n add(rel: string, href: string): void\n add(...args: any[]): void {\n\n let links: Link[];\n\n if (typeof args[0] === 'string') {\n links = [{\n rel: args[0],\n href: args[1],\n context: this.defaultContext,\n }];\n } else {\n links = args.map( link => { return { context: this.defaultContext, ...link };} );\n }\n\n for(const link of links) {\n if (this.store.has(link.rel)) {\n this.store.get(link.rel)!.push(link);\n } else {\n this.store.set(link.rel, [link]);\n }\n }\n\n }\n\n /**\n * Set a link\n *\n * If a link with the provided 'rel' already existed, it will be overwritten.\n */\n set(link: Link | NewLink): void\n set(rel: string, href: string): void\n set(arg1: any, arg2?: any): void {\n\n let link: Link;\n if (typeof arg1 === 'string') {\n link = {\n rel: arg1,\n href: arg2,\n context: this.defaultContext,\n };\n } else {\n link = {\n context: this.defaultContext,\n ...arg1,\n };\n }\n this.store.set(link.rel, [link]);\n\n }\n\n /**\n * Return a single link by its 'rel'.\n *\n * If the link does not exist, undefined is returned.\n */\n get(rel: string): Link|undefined {\n\n const links = this.store.get(rel);\n if (!links || links.length < 0) {\n return undefined;\n }\n return links[0];\n\n }\n\n /**\n * Delete all links with the given 'rel'.\n *\n * If the second argument is provided, only links that match the href will\n * be removed.\n */\n delete(rel: string, href?: string): void {\n\n if (href===undefined) {\n this.store.delete(rel);\n return;\n }\n\n const uris = this.store.get(rel);\n if (!uris) return;\n\n this.store.delete(rel);\n const absHref = resolve(this.defaultContext, href);\n this.store.set(rel,\n uris.filter(uri => resolve(uri) !== absHref)\n );\n }\n\n /**\n * Return all links that have a given rel.\n *\n * If no links with the rel were found, an empty array is returned.\n */\n getMany(rel: string): Link[] {\n\n return this.store.get(rel) || [];\n\n }\n\n /**\n * Return all links.\n */\n getAll(): Link[] {\n const result = [];\n for(const links of this.store.values()) {\n result.push(...links);\n }\n return result;\n }\n\n /**\n * Returns true if at least 1 link with the given rel exists.\n */\n has(rel: string): boolean {\n\n return this.store.has(rel);\n\n }\n\n}\n\n/**\n * The LinkNotFound error gets thrown whenever something tries to follow a\n * link by its rel, that doesn't exist\n */\nexport class LinkNotFound extends Error {}\n\n/**\n * A key->value map of variables to place in a templated link\n */\nexport type LinkVariables = {\n [key: string]: string | number | string[] | number[];\n};\n","import { Action } from '../action';\nimport { Links, LinkVariables } from '../link';\nimport Client from '../client';\nimport { Resource } from '../resource';\n\nexport type State<T = any> = {\n\n /**\n * The URI associated with this state\n */\n uri: string;\n\n /**\n * Represents the body of the HTTP response.\n *\n * In the case of a JSON response, this will be deserialized\n */\n data: T;\n\n /**\n * All links associated with the resource.\n */\n links: Links;\n\n /**\n * The full list of HTTP headers that were sent with the response.\n */\n headers: Headers;\n\n /**\n * Reference to main client that created this state\n */\n client: Client;\n\n /**\n * Follows a relationship, based on its reltype. For example, this might be\n * 'alternate', 'item', 'edit' or a custom url-based one.\n *\n * This function can also follow templated uris. You can specify uri\n * variables in the optional variables argument.\n */\n follow<TFollowedResource = any>(rel: string, variables?: LinkVariables): Resource<TFollowedResource>;\n\n /**\n * Follows a relationship based on its reltype. This function returns a\n * Promise that resolves to an array of Resource objects.\n *\n * If no resources were found, the array will be empty.\n */\n followAll<TFollowedResource = any>(rel: string): Resource<TFollowedResource>[];\n\n /**\n * Return an action by name.\n *\n * If the format provides a default action, the name may be omitted.\n */\n action<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData>;\n\n /**\n * Find an action by name.\n *\n * If the format provides a default action, the name may be omitted.\n */\n findAction<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData> | undefined;\n\n /**\n * Returns all actions\n */\n actions(): Action[];\n\n /**\n * Checks if the specified action exists.\n *\n * If no name is given, checks if _any_ action exists.\n */\n hasAction(name?: string): boolean;\n\n /**\n * Returns a serialization of the state that can be used in a HTTP\n * response.\n *\n * For example, a JSON object might simply serialize using\n * JSON.serialize().\n */\n serializeBody(): Buffer|Blob|string;\n\n /**\n * Content-headers are a subset of HTTP headers that related directly\n * to the content. The obvious ones are Content-Type.\n *\n * This set of headers will be sent by the server along with a GET\n * response, but will also be sent back to the server in a PUT\n * request.\n */\n contentHeaders(): Headers;\n\n /**\n * Some formats support embedding resources inside other resources.\n *\n * Please note: generally you should always use the .follow() and\n * .followAll() functions to get access to linked embedded resources.\n *\n * There's several operations that change the State in the Ketting Cache,\n * and usually this erases any associated embedded resources.\n *\n * .follow() and .followAll() will return the embedded resources, and also\n * keeps their respective states fresh when changes are made.\n */\n getEmbedded(): State[];\n\n /**\n * Timestamp of when the State was first generated\n */\n timestamp: number;\n\n clone(): State<T>;\n\n}\n\n/**\n * HeadState represents the response to a HEAD request.\n *\n * Some information in HEAD responses might be available, but many aren't.\n * Notably, the body.\n */\nexport type HeadState = Omit<State, 'data' | 'action' | 'findAction' | 'actions' | 'hasAction' | 'serializeBody' | 'getEmbedded' | 'client' | 'clone'>;\n\n/**\n * A 'StateFactory' is responsible for taking a Fetch Response, and returning\n * an object that impements the State interface\n */\nexport type StateFactory<T = any> = (client: Client, uri: string, request: Response) => Promise<State<T>>;\n\nexport function isState(input: Record<string, any>): input is State {\n\n return (\n typeof (input as any).uri === 'string' &&\n (input as any).links instanceof Links &&\n (input as any).headers instanceof Headers\n );\n\n}\n","import { State } from './state';\nimport qs from 'query-string';\nimport Client from './client';\nimport { Field } from './field';\nimport Resource from './resource';\n\nexport interface ActionInfo {\n\n /**\n * What url to post the form to.\n */\n uri: string;\n\n /**\n * Action name.\n *\n * Some formats call this the 'rel'\n */\n name: string | null;\n\n /**\n * Form title.\n *\n * Should be human-friendly.\n */\n title?: string;\n\n /**\n * The HTTP method to use\n */\n method: string;\n\n /**\n * The contentType to use for the form submission\n */\n contentType: string;\n\n /**\n * Returns the list of fields associated to an action\n */\n fields: Field[];\n}\n\n/**\n * An action represents a hypermedia form submission or action.\n */\nexport interface Action<T extends Record<string, any> = Record<string, any>> extends ActionInfo {\n\n /**\n * Execute the action or submit the form.\n */\n submit(formData: T): Promise<State>;\n\n /**\n * Return a field by name.\n */\n field(name: string): Field | undefined;\n\n /**\n * Execute the action or submit the form, then return the next resource.\n *\n * If a server responds with a 201 Status code and a Location header,\n * it will automatically return the newly created resource.\n *\n * If the server responded with a 204 or 205, this function will return\n * `this`.\n */\n submitFollow(formData: T): Promise<Resource>;\n}\n\nexport class SimpleAction<TFormData extends Record<string, any>> implements Action {\n\n /**\n * What url to post the form to.\n */\n uri!: string;\n\n /**\n * Action name.\n *\n * Some formats call this the 'rel'\n */\n name!: string | null;\n\n /**\n * Form title.\n *\n * Should be human-friendly.\n */\n title!: string;\n\n /**\n * The HTTP method to use\n */\n method!: string;\n\n /**\n * The contentType to use for the form submission\n */\n contentType!: string;\n\n /**\n * Returns the list of fields associated to an action\n */\n fields!: Field[];\n\n /**\n * Reference to client\n */\n client: Client;\n\n constructor(client: Client, formInfo: ActionInfo) {\n this.client = client;\n\n for(const [k, v] of Object.entries(formInfo)) {\n this[k as keyof ActionInfo] = v;\n }\n\n }\n\n /**\n * Execute the action or submit the form.\n */\n async submit(formData: TFormData): Promise<State<any>> {\n\n const uri = new URL(this.uri);\n\n const newFormData = this.validateForm(formData);\n\n if (this.method === 'GET') {\n uri.search = qs.stringify(newFormData);\n const resource = this.client.go(uri.toString());\n return resource.get();\n }\n const response = await this.fetchOrThrowWithBody(uri, newFormData);\n const state = this.client.getStateForResponse(uri.toString(), response);\n return state;\n }\n\n async submitFollow(formData: TFormData): Promise<Resource> {\n const uri = new URL(this.uri);\n\n const newFormData = this.validateForm(formData);\n\n if (this.method === 'GET') {\n uri.search = qs.stringify(newFormData);\n return this.client.go(uri.toString());\n }\n\n const response = await this.fetchOrThrowWithBody(uri, newFormData);\n switch (response.status) {\n case 201:\n if (response.headers.has('location')) {\n return this.client.go(response.headers.get('location')!);\n }\n throw new Error('Could not follow after a 201 request, because the server did not reply with a Location header. If you sent a Location header, check if your service is returning \"Access-Control-Expose-Headers: Location\".');\n case 204 :\n case 205 :\n return this.client.go(uri.toString());\n default:\n throw new Error('Did not receive a 201, 204 or 205 status code so we could not follow to the next resource');\n }\n }\n\n private validateForm(formData: TFormData): TFormData {\n const newFormData: TFormData = {\n ...formData\n };\n\n for (const field of this.fields) {\n\n if (!(field.name in formData)) {\n\n if (field.value) {\n // We don't have perfect types for fields vs. FormData and how they\n // related, so 'any' is needed here.\n (newFormData as any)[field.name] = field.value;\n } else if (field.required) {\n throw new Error(`The ${field.name} field is required in this form`);\n }\n\n }\n\n }\n return newFormData;\n }\n\n private fetchOrThrowWithBody(uri: URL, formData: TFormData): Promise<Response> {\n let body;\n switch (this.contentType) {\n case 'application/x-www-form-urlencoded' :\n body = qs.stringify(formData);\n break;\n case 'application/json':\n body = JSON.stringify(formData);\n break;\n default :\n throw new Error(`Serializing mimetype ${this.contentType} is not yet supported in actions`);\n }\n return this.client.fetcher.fetchOrThrow(uri.toString(), {\n method: this.method,\n body,\n headers: {\n 'Content-Type': this.contentType\n }\n });\n }\n\n field(name: string): Field | undefined {\n return this.fields.find(field => field.name === name);\n }\n}\n\nexport class ActionNotFound extends Error {}\n","import * as uriTemplate from 'uri-template';\nimport { resolve } from './uri';\nimport { LinkVariables, Link } from '../link';\n\nexport function expand(context: string, template: string, vars: LinkVariables): string;\nexport function expand(link: Link, vars: LinkVariables): string;\nexport function expand(arg1: string|Link, arg2: string|LinkVariables, arg3?: LinkVariables): string {\n\n let context:string;\n let template:string;\n let vars:LinkVariables;\n\n if (typeof arg1 === 'string') {\n context = arg1;\n template = arg2 as string;\n vars = arg3 as LinkVariables;\n } else {\n context = arg1.context;\n template = arg1.href;\n vars = arg2 as LinkVariables;\n }\n const templ = uriTemplate.parse(template);\n const expanded = templ.expand(vars);\n return resolve(context, expanded);\n}\n","import * as LinkHeader from 'http-link-header';\nimport { Links } from '../link';\n\n/**\n * Takes a Content-Type header, and only returns the mime-type part.\n */\nexport function parseContentType(contentType: string | null): string | null {\n\n if (!contentType) {\n return null;\n }\n if (contentType.includes(';')) {\n contentType = contentType.split(';')[0];\n }\n return contentType.trim();\n\n}\n\n\nexport function parseLink(context: string, header: string|null): Links {\n\n const result = new Links(context);\n if (!header) {\n return result;\n }\n\n for (const httpLink of LinkHeader.parse(header).refs) {\n // Looping through individual links\n for (const rel of httpLink.rel.split(' ')) {\n // Looping through space separated rel values.\n const link = {\n rel: rel,\n href: httpLink.uri,\n context,\n title: httpLink.title,\n hreflang: httpLink.hreflang,\n type: httpLink.type,\n };\n result.add(link);\n }\n }\n return result;\n}\n\nconst safeMethods = ['GET', 'HEAD', 'OPTIONS', 'PRI', 'PROPFIND', 'REPORT', 'SEARCH', 'TRACE'];\n\nexport function isSafeMethod(method: string): boolean {\n return safeMethods.includes(method);\n}\n\n/**\n * Older HTTP versions calls these 'entity headers'.\n *\n * Never HTTP/1.1 specs calls some of these 'representation headers'.\n *\n * What they have in common is that these headers can exist on request and\n * response and say something *about* the content.\n */\nexport const entityHeaderNames = [\n 'Content-Type',\n 'Content-Language',\n 'Content-Location',\n 'Deprecation',\n 'ETag',\n 'Expires',\n 'Last-Modified',\n 'Sunset',\n 'Title',\n 'Warning',\n];\n","import { State, HeadState } from './interface';\nimport { Links, LinkVariables, LinkNotFound } from '../link';\nimport Client from '../client';\nimport { Action, ActionNotFound, ActionInfo, SimpleAction } from '../action';\nimport { Resource } from '../resource';\nimport { resolve } from '../util/uri';\nimport { expand } from '../util/uri-template';\nimport { entityHeaderNames } from '../http/util';\n\ntype HeadStateInit = {\n\n client: Client;\n uri: string;\n links: Links;\n\n /**\n * The full list of HTTP headers that were sent with the response.\n */\n headers: Headers;\n}\n\ntype StateInit<T> = {\n client: Client;\n uri: string;\n data: T;\n headers: Headers;\n links: Links;\n embedded?: State[];\n actions?: ActionInfo[];\n}\n\n/**\n * Implements a State object for HEAD responses\n */\nexport class BaseHeadState implements HeadState {\n\n uri: string;\n\n /**\n * Timestamp of when the State was first generated\n */\n timestamp: number;\n\n /**\n * The full list of HTTP headers that were sent with the response.\n */\n headers: Headers;\n\n /**\n * All links associated with the resource.\n */\n links: Links;\n\n /**\n * Reference to main client that created this state\n */\n client: Client;\n\n constructor(init: HeadStateInit) {\n this.client = init.client;\n this.uri = init.uri;\n this.headers = init.headers;\n this.timestamp = Date.now();\n this.links = init.links;\n }\n\n /**\n * Follows a relationship, based on its reltype. For example, this might be\n * 'alternate', 'item', 'edit' or a custom url-based one.\n *\n * This function can also follow templated uris. You can specify uri\n * variables in the optional variables argument.\n */\n follow<TFollowedResource = any>(rel: string, variables?: LinkVariables): Resource<TFollowedResource> {\n\n const link = this.links.get(rel);\n if (!link) throw new LinkNotFound(`Link with rel ${rel} on ${this.uri} not found`);\n\n let href;\n\n if (link.templated) {\n href = expand(link, variables || {});\n } else {\n href = resolve(link);\n }\n if (link.hints?.status === 'deprecated') {\n /* eslint-disable-next-line no-console */\n console.warn(`[ketting] The ${link.rel} link on ${this.uri} is marked deprecated.`, link);\n }\n\n return this.client.go(href);\n\n }\n\n /**\n * Follows a relationship based on its reltype. This function returns a\n * Promise that resolves to an array of Resource objects.\n *\n * If no resources were found, the array will be empty.\n */\n followAll<TFollowedResource = any>(rel: string): Resource<TFollowedResource>[] {\n\n return this.links.getMany(rel).map( link => {\n\n if (link.hints?.status === 'deprecated') {\n /* eslint-disable-next-line no-console */\n console.warn(`[ketting] The ${link.rel} link on ${this.uri} is marked deprecated.`, link);\n }\n const href = resolve(link);\n return this.client.go(href);\n\n });\n\n }\n\n\n /**\n * Content-headers are a subset of HTTP headers that related directly\n * to the content. The obvious ones are Content-Type.\n *\n * This set of headers will be sent by the server along with a GET\n * response, but will also be sent back to the server in a PUT\n * request.\n */\n contentHeaders(): Headers {\n\n const result: {[name: string]: string} = {};\n\n for(const contentHeader of entityHeaderNames) {\n if (this.headers.has(contentHeader)) {\n result[contentHeader] = this.headers.get(contentHeader)!;\n }\n }\n return new Headers(result);\n\n }\n\n}\n\n/**\n * The Base State provides a convenient way to implement a new State type.\n */\nexport class BaseState<T> extends BaseHeadState implements State<T> {\n\n\n data: T;\n\n protected embedded: State[];\n protected actionInfo: ActionInfo[];\n\n constructor(init: StateInit<T>) {\n\n super(init);\n this.data = init.data;\n this.actionInfo = init.actions || [];\n this.embedded = init.embedded || [];\n\n }\n\n /**\n * Return an action by name.\n *\n * If no name is given, the first action is returned. This is useful for\n * formats that only supply 1 action, and no name.\n */\n action<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData> {\n\n const actionSearchResult = this.doFindAction(name);\n if (actionSearchResult === 'NO_ACTION_DEFINED') {\n throw new ActionNotFound('This State does not define any actions');\n }\n if (actionSearchResult === 'NO_ACTION_FOR_THE_PROVIDED_NAME') {\n throw new ActionNotFound('This State defines no action');\n }\n return actionSearchResult;\n\n }\n\n findAction<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData> | undefined {\n\n const actionSearchResult = this.doFindAction(name);\n if (typeof actionSearchResult !== 'object') {\n return undefined;\n }\n return actionSearchResult;\n }\n\n private doFindAction<TFormData extends Record<string, any> = any>(name?: string): Action<TFormData> | ActionNotFoundReason {\n\n if (!this.actionInfo.length) {\n return 'NO_ACTION_DEFINED';\n }\n if (name === undefined) {\n return new SimpleAction(this.client, this.actionInfo[0]);\n }\n for(const action of this.actionInfo) {\n if (action.name === name) {\n return new SimpleAction(this.client, action);\n }\n }\n return 'NO_ACTION_FOR_THE_PROVIDED_NAME';\n }\n\n /**\n * Returns all actions\n */\n actions(): Action[] {\n\n return this.actionInfo.map(action => new SimpleAction(this.client, action));\n\n }\n\n /**\n * Checks if the specified action exists.\n *\n * If no name is given, checks if _any_ action exists.\n */\n hasAction(name?: string): boolean {\n\n if (name===undefined) return this.actionInfo.length>0;\n for(const action of this.actionInfo) {\n if (name === action.name) {\n return true;\n }\n }\n return false;\n\n }\n\n /**\n * Returns a serialization of the state that can be used in a HTTP\n * response.\n *\n * For example, a JSON object might simply serialize using\n * JSON.serialize().\n */\n serializeBody(): Buffer|Blob|string {\n\n if (\n (globalThis.Buffer && this.data instanceof Buffer) ||\n (globalThis.Blob && this.data instanceof Blob) ||\n typeof this.data === 'string')\n {\n return this.data;\n }\n return JSON.stringify(this.data);\n\n }\n\n /**\n * Certain formats can embed other resources, identified by their\n * own URI.\n *\n * When a format has embedded resources, we will use these to warm\n * the cache.\n *\n * This method returns every embedded resource.\n */\n getEmbedded(): State[] {\n\n return this.embedded;\n\n }\n\n clone(): State<T> {\n\n return new BaseState({\n client: this.client,\n uri: this.uri,\n data: this.data,\n headers: new Headers(this.headers),\n links: new Links(this.links.defaultContext, this.links.getAll()),\n actions: this.actionInfo,\n });\n\n }\n\n}\n\ntype ActionNotFoundReason = 'NO_ACTION_DEFINED' | 'NO_ACTION_FOR_THE_PROVIDED_NAME';\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { Link, Links } from '../link';\nimport { resolve } from '../util/uri';\nimport { ActionInfo } from '../action';\nimport {Field, OptionsDataSource} from '../field';\nimport { StateFactory } from './interface';\nimport Client from '../client';\nimport * as hal from 'hal-types';\n\n/**\n * Represents a resource state in the HAL format\n */\nexport class HalState<T = any> extends BaseState<T> {\n\n serializeBody(): string {\n\n return JSON.stringify({\n _links: this.serializeLinks(),\n ...this.data\n });\n\n }\n\n private serializeLinks(): hal.HalResource['_links'] {\n\n const links: hal.HalResource['_links'] = {\n self: { href: this.uri },\n };\n for(const link of this.links.getAll()) {\n\n const { rel, context, ...attributes } = link;\n\n if (rel === 'self') {\n // skip\n continue;\n }\n\n if (links[rel] === undefined) {\n // First link of its kind\n links[rel] = attributes;\n } else if (Array.isArray(links[rel])) {\n // Add link to link array.\n (links[rel] as hal.HalLink[]).push(attributes);\n } else {\n // 1 link with this rel existed, so we will transform it to an array.\n links[rel] = [links[rel] as hal.HalLink, attributes];\n }\n\n }\n\n return links;\n\n }\n\n clone(): HalState<T> {\n\n return new HalState({\n client: this.client,\n uri: this.uri,\n data: this.data,\n headers: new Headers(this.headers),\n links: new Links(this.links.defaultContext, this.links.getAll()),\n actions: this.actionInfo,\n });\n\n }\n\n}\n\n/**\n * Turns a HTTP response into a HalState\n */\nexport const factory:StateFactory = async (client, uri, response): Promise<HalState> => {\n\n const body = await response.json();\n const links = parseLink(uri, response.headers.get('Link'));\n\n // The HAL factory is also respondible for plain JSON, which might be an\n // array.\n if (Array.isArray(body)) {\n return new HalState({\n client,\n uri,\n data: body,\n headers: response.headers,\n links,\n });\n }\n\n links.add(...parseHalLinks(uri, body));\n\n // Remove _links and _embedded from body\n const {\n _embedded,\n _links,\n _templates,\n ...newBody\n } = body;\n\n return new HalState({\n client,\n uri: uri,\n data: newBody,\n headers: response.headers,\n links: links,\n embedded: parseHalEmbedded(client, uri, body, response.headers),\n actions: parseHalForms(uri, body),\n });\n\n};\n\n/**\n * Parse the Hal _links object and populate the 'links' property.\n */\nfunction parseHalLinks(context: string, body: hal.HalResource): Link[] {\n\n if (body._links === undefined) {\n return [];\n }\n\n const result: Link[] = [];\n\n /**\n * We're capturing all rel-link pairs so we don't duplicate them if they\n * re-appear in _embedded.\n *\n * Links that are embedded _should_ appear in both lists, but not everyone\n * does this.\n */\n const foundLinks = new Set();\n\n for (const [relType, links] of Object.entries(body._links)) {\n\n const linkList = Array.isArray(links) ? links : [links];\n\n for (const link of linkList) {\n foundLinks.add(relType + ';' + link.href);\n }\n\n result.push(\n ...parseHalLink(context, relType, linkList)\n );\n\n\n }\n\n if (body._embedded) {\n // eslint-disable-next-line prefer-const\n for (let [rel, innerBodies] of Object.entries(body._embedded)) {\n\n for(const innerBody of Array.isArray(innerBodies) ? innerBodies : [innerBodies]) {\n\n const href:string = (innerBody?._links?.self as hal.HalLink)?.href;\n if (!href) {\n continue;\n }\n\n if (foundLinks.has(rel + ';' + href)) {\n continue;\n }\n result.push({\n rel: rel,\n href: href,\n context: context,\n });\n\n }\n\n }\n\n }\n\n return result;\n\n}\n\n/**\n * Parses a single HAL link from a _links object\n */\nfunction parseHalLink(context: string, rel: string, links: hal.HalLink[]): Link[] {\n\n const result: Link[] = [];\n\n for (const link of links) {\n result.push({\n rel,\n context,\n ...link,\n });\n }\n\n return result;\n\n}\n\n/**\n * Parse the HAL _embedded object. Right now we're just grabbing the\n * information from _embedded and turn it into links.\n */\nfunction parseHalEmbedded(client: Client, context: string, body: hal.HalResource, headers: Headers): HalState<any>[] {\n\n if (body._embedded === undefined || !body._embedded) {\n return [];\n }\n\n const result: HalState<any>[] = [];\n\n for (const embedded of Object.values(body._embedded)) {\n\n let embeddedList: hal.HalResource[];\n\n if (!Array.isArray(embedded)) {\n embeddedList = [embedded];\n } else {\n embeddedList = embedded;\n\n }\n for (const embeddedItem of embeddedList) {\n\n if ((embeddedItem._links?.self as hal.HalLink)?.href === undefined) {\n\n console.warn('An item in _embedded was ignored. Each item must have a single \"self\" link');\n continue;\n }\n\n const embeddedSelf = resolve(context, (embeddedItem._links?.self as hal.HalLink)?.href);\n\n // Remove _links and _embedded from body\n const {\n _embedded,\n _links,\n ...newBody\n } = embeddedItem;\n\n result.push(new HalState({\n client,\n uri: embeddedSelf,\n data: newBody,\n headers: new Headers({\n 'Content-Type': headers.get('Content-Type')!,\n }),\n links: new Links(embeddedSelf, parseHalLinks(context, embeddedItem)),\n // Parsing nested embedded items. Note that we assume that the base url is relative to\n // the outermost parent, not relative to the embedded item. HAL is not clear on this.\n embedded: parseHalEmbedded(client, embeddedSelf, embeddedItem, headers),\n actions: parseHalForms(embeddedSelf, embeddedItem)\n }));\n }\n }\n\n return result;\n\n}\n\nfunction parseHalForms(context: string, body: hal.HalResource): ActionInfo[] {\n\n if (!body._templates) return [];\n\n return Object.entries(body._templates).map( ([key, hf]) => {\n return {\n uri: resolve(context, hf.target || ''),\n name: key,\n title: hf.title,\n method: hf.method,\n contentType: hf.contentType || 'application/json',\n fields: hf.properties ? hf.properties.map(prop => parseHalField(prop)).filter(prop => !!prop) : [],\n };\n });\n\n}\n\nfunction parseHalField(halField: hal.HalFormsProperty): Field | undefined {\n\n switch(halField.type) {\n case undefined:\n case 'text' :\n case 'search' :\n case 'tel' :\n case 'url' :\n case 'email' :\n\n if (halField.options) {\n const multiple: boolean | undefined = !('maxItems' in halField.options) || !halField.options.maxItems || halField.options.maxItems > 1;\n\n const baseField = {\n name: halField.name,\n type: 'select' as const,\n label: halField.prompt,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n value: (halField.options.selectedValues || halField.value) as any,\n };\n\n const optionsDataSource = toOptionsDataSource(halField.options);\n\n if (multiple) {\n return {\n multiple: true,\n selectedValues: halField.options.selectedValues,\n ...baseField,\n ...optionsDataSource\n };\n } else {\n const selectedValues = halField.options.selectedValues;\n let selectedValue: string | undefined;\n if (selectedValues) {\n if (selectedValues.length === 1) {\n selectedValue = selectedValues[0];\n } else if (selectedValues.length > 1) {\n console.warn(`More than 1 selected value received for single select field ${baseField.name}. Ignoring all selected values for this field.`);\n }\n }\n return {\n multiple,\n selectedValue,\n ...baseField,\n ...optionsDataSource\n };\n }\n } else {\n return {\n name: halField.name,\n type: halField.type ?? 'text',\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n value: halField.value,\n pattern: halField.regex ? new RegExp(halField.regex) : undefined,\n label: halField.prompt,\n placeholder: halField.placeholder,\n minLength: halField.minLength,\n maxLength: halField.maxLength,\n };\n }\n case 'hidden' :\n return {\n name: halField.name,\n type: 'hidden',\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n value: halField.value,\n label: halField.prompt,\n placeholder: halField.placeholder,\n };\n case 'textarea' :\n return {\n name: halField.name,\n type: halField.type,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n value: halField.value,\n label: halField.prompt,\n placeholder: halField.placeholder,\n cols: halField.cols,\n rows: halField.rows,\n minLength: halField.minLength,\n maxLength: halField.maxLength,\n };\n case 'password' :\n return {\n name: halField.name,\n type: halField.type,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n placeholder: halField.placeholder,\n minLength: halField.minLength,\n maxLength: halField.maxLength,\n };\n case 'date' :\n case 'month' :\n case 'week' :\n case 'time' :\n return {\n name: halField.name,\n type: halField.type,\n value: halField.value,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n min: halField.min,\n max: halField.max,\n step: halField.step,\n };\n case 'number' :\n case 'range' :\n return {\n name: halField.name,\n type: halField.type,\n value: halField.value ? +halField.value : undefined,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n min: halField.min,\n max: halField.max,\n step: halField.step,\n };\n case 'datetime-local' :\n return {\n name: halField.name,\n type: halField.type,\n value: halField.value ? new Date(halField.value) : undefined,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n min: halField.min,\n max: halField.max,\n step: halField.step,\n };\n case 'color' :\n return {\n name: halField.name,\n type: halField.type,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n value: halField.value,\n };\n case 'radio' :\n case 'checkbox' :\n return {\n name: halField.name,\n type: halField.type,\n required: halField.required || false,\n readOnly: halField.readOnly || false,\n label: halField.prompt,\n value: !!halField.value,\n };\n default:\n return undefined;\n }\n\n}\n\nfunction toOptionsDataSource(halFieldOptions: NonNullable<hal.HalFormsSimpleProperty['options']>): OptionsDataSource {\n const labelField = halFieldOptions.promptField || 'prompt';\n const valueField = halFieldOptions.valueField || 'value';\n if (isInlineOptions(halFieldOptions)) {\n\n const options: Record<string, string> = {};\n\n for (const entry of halFieldOptions.inline) {\n\n if (typeof entry === 'string') {\n options[entry] = entry;\n } else {\n options[entry[valueField]] = entry[labelField];\n }\n }\n\n return {options};\n } else {\n return {\n dataSource: {\n href: halFieldOptions.link.href,\n type: halFieldOptions.link.type,\n labelField,\n valueField,\n }\n };\n }\n}\n\nfunction isInlineOptions(options: hal.HalFormsSimpleProperty['options']): options is hal.HalFormsOptionsInline {\n\n return (options as any).inline !== undefined;\n\n}\n","import { BaseState } from './base-state';\nimport { StateFactory } from './interface';\nimport { parseLink } from '../http/util';\n\n/**\n * Turns a HTTP response into a BinaryState\n */\nexport const factory: StateFactory<Blob> = async (client, uri, response): Promise<BaseState<Blob>> => {\n\n return new BaseState({\n client,\n uri,\n data: await response.blob(),\n headers: response.headers,\n links: parseLink(uri, response.headers.get('Link')),\n });\n\n};\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { Link } from '../link';\nimport Client from '../client';\n\n/**\n * Turns a HTTP response into a JsonApiState\n */\nexport const factory = async (client: Client, uri: string, response: Response): Promise<BaseState<JsonApiTopLevelObject>> => {\n\n const body = await response.json();\n\n const links = parseLink(uri, response.headers.get('Link'));\n links.add(\n ...parseJsonApiLinks(uri, body),\n ...parseJsonApiCollection(uri, body),\n );\n\n return new BaseState({\n client,\n uri,\n data: body,\n headers: response.headers,\n links: links,\n });\n\n};\n/**\n * A JSON:API link can either be a string, or an object with at least a href\n * property.\n */\ntype JsonApiLink = string | { href: string };\n\n/**\n * This type is a full 'links' object, which might appear on the top level\n * or on resource objects.\n */\ntype JsonApiLinksObject = {\n self?: JsonApiLink;\n profile?: JsonApiLink;\n [rel: string]: JsonApiLink | JsonApiLink[] | undefined;\n};\n\n/**\n * This is a single JSON:API resource. Its type contains just the properties\n * we care about.\n */\ntype JsonApiResource = {\n type: string;\n id: string;\n links?: JsonApiLinksObject;\n};\n\n\n/**\n * This type represents a valid JSON:API response. We're only interested\n * in the links object at the moment, so everything else is (for now)\n * untyped.\n */\ntype JsonApiTopLevelObject = {\n links?: JsonApiLinksObject;\n data: JsonApiResource | JsonApiResource[] | null;\n [s: string]: any;\n};\n\n/**\n * This function takes a JSON:API object, and extracts the links property.\n */\nfunction parseJsonApiLinks(contextUri: string, body: JsonApiTopLevelObject): Link[] {\n\n const result: Link[] = [];\n\n if (body.links === undefined) {\n return result;\n }\n\n for (const [rel, linkValue] of Object.entries(body.links)) {\n\n if (Array.isArray(linkValue)) {\n result.push(...linkValue.map( link => parseJsonApiLink(contextUri, rel, link)));\n } else {\n result.push(parseJsonApiLink(contextUri, rel, linkValue!));\n }\n\n }\n\n return result;\n\n}\n\n/**\n * Find collection members in JSON:API objects.\n *\n * A JSON:API top-level object might represent a collection that has 0 or more\n * members.\n *\n * Members of this collection should appear as an 'item' link to the parent.\n */\nfunction parseJsonApiCollection(contextUri: string, body: JsonApiTopLevelObject): Link[] {\n\n if (!Array.isArray(body.data)) {\n // Not a collection\n return [];\n }\n\n const result: Link[] = [];\n for (const member of body.data) {\n\n if ('links' in member && 'self' in member.links!) {\n\n const selfLink = parseJsonApiLink(contextUri, 'self', member.links!.self!);\n result.push({\n context: contextUri,\n href: selfLink.href,\n rel: 'item'\n });\n\n }\n }\n\n return result;\n\n}\n\n/**\n * This function takes a single link value from a JSON:API link object, and\n * returns a object of type Link\n */\nfunction parseJsonApiLink(contextUri: string, rel: string, link: JsonApiLink): Link {\n\n return ({\n context: contextUri,\n rel,\n href: typeof link === 'string' ? link : link.href,\n });\n\n}\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { Link, Links } from '../link';\nimport { resolve } from '../util/uri';\nimport { ActionInfo } from '../action';\nimport { Field } from '../field';\nimport Client from '../client';\n\n/**\n * Represents a resource state in the Siren format\n */\nexport class SirenState<T> extends BaseState<T> {\n\n /**\n * Returns a serialization of the state that can be used in a HTTP\n * response.\n *\n * For example, a JSON object might simply serialize using\n * JSON.serialize().\n */\n serializeBody(): string {\n\n throw new Error('Reserializing Siren states is not yet supported. Please log an issue in the Ketting project to help figure out how this should be done');\n\n }\n\n clone(): SirenState<T> {\n\n return new SirenState({\n client: this.client,\n uri: this.uri,\n data: this.data,\n headers: new Headers(this.headers),\n links: new Links(this.uri, this.links),\n actions: this.actionInfo,\n });\n\n }\n\n}\n\n\n/**\n * Turns a HTTP response into a SirenState\n */\nexport const factory = async (client: Client, uri: string, response: Response): Promise<SirenState<any>> => {\n\n const body:SirenEntity<any> = await response.json();\n\n const links = parseLink(uri, response.headers.get('Link'));\n links.add(...parseSirenLinks(uri, body));\n\n return new SirenState({\n client,\n uri,\n data: body.properties,\n headers: response.headers,\n links: links,\n embedded: parseSirenEmbedded(client, uri, body, response.headers),\n actions: body.actions ? body.actions.map( action => parseSirenAction(uri, action) ) : [],\n });\n\n};\n\ntype SirenProperties = Record<string, any> | undefined;\n\ntype SirenEntity<T extends SirenProperties> = {\n\n class?: string[];\n\n properties: T;\n entities?: (SirenLink | SirenSubEntity)[];\n\n links?: SirenLink[];\n actions?: SirenAction[];\n title?: string;\n\n};\n\ntype SirenSubEntity = SirenEntity<any> & { rel: string[] };\n\ntype SirenLink = {\n\n class?: string[];\n rel: string[];\n href: string;\n type?: string;\n title?: string;\n\n};\n\ntype SirenAction = {\n name: string;\n class?: string[];\n method?: string;\n href: string;\n title?: string;\n type?: string;\n fields?: SirenField[];\n};\n\ntype SirenField = {\n name: string;\n class?: string[];\n type?: 'hidden' | 'text' | 'search' | 'tel' | 'url' | 'email' | 'password' | 'datetime' | 'date' | 'month' | 'week' | 'time' | 'datetime-local' | 'number' | 'range' | 'color' | 'checkbox' | 'radio' | 'file';\n value?: string;\n title?: string;\n};\n\nfunction parseSirenLinks(contextUri: string, body: SirenEntity<any>): Link[] {\n\n const result: Link[] = [];\n\n if (body.links !== undefined) {\n for (const link of body.links) {\n result.push(...parseSirenLink(contextUri, link));\n }\n }\n\n if (body.entities !== undefined) {\n for (const subEntity of body.entities) {\n if ((subEntity as SirenLink).href !== undefined) {\n result.push(...parseSirenLink(contextUri, subEntity as SirenLink));\n } else {\n result.push(...parseSirenSubEntityAsLink(contextUri, subEntity as SirenSubEntity));\n }\n }\n }\n\n return result;\n\n}\n\nfunction parseSirenLink(contextUri: string, link: SirenLink): Link[] {\n\n const result: Link[] = [];\n\n const {\n rel: rels,\n ...attributes\n } = link;\n for (const rel of rels) {\n\n const newLink: Link = {\n rel,\n context: contextUri,\n ...attributes,\n };\n result.push(newLink);\n\n }\n\n return result;\n\n}\n\nfunction parseSirenEmbedded(client: Client, contextUri: string, body: SirenEntity<any>, headers: Headers): SirenState<SirenEntity<any>>[] {\n\n if (body.entities === undefined) {\n return [];\n }\n\n const result: SirenState<SirenEntity<any>>[] = [];\n\n for (const entity of body.entities) {\n if (isSubEntity(entity)) {\n const subState = parseSirenSubEntityAsEmbedded(client, contextUri, entity, headers);\n if (subState !== null) {\n result.push(subState);\n }\n }\n }\n\n return result;\n\n}\n\nfunction parseSirenSubEntityAsLink(contextUri: string, subEntity: SirenSubEntity): Link[] {\n\n if (subEntity.links === undefined) {\n // We don't yet support subentities that don't have a URI.\n return [];\n }\n let selfHref: string | null = null;\n for (const link of subEntity.links) {\n if (link.rel.includes('self')) {\n selfHref = link.href;\n }\n }\n if (selfHref === null) {\n // We don't yet support subentities that don't have a URI.\n return [];\n }\n\n return subEntity.rel.map(rel => {\n const title = subEntity.title;\n const link: Link = {\n href: selfHref!,\n rel,\n context: contextUri,\n };\n if (title) {\n link.title = title;\n }\n return link;\n });\n\n}\n\nfunction parseSirenSubEntityAsEmbedded(client: Client, contextUri: string, subEntity: SirenSubEntity, headers: Headers): SirenState<SirenEntity<any>> | null {\n\n if (subEntity.links === undefined) {\n // We don't yet support subentities that don't have a URI.\n return null;\n }\n let selfHref = null;\n for (const link of subEntity.links) {\n if (link.rel.includes('self')) {\n selfHref = link.href;\n }\n }\n if (!selfHref) {\n // We don't yet support subentities that don't have a URI.\n return null;\n }\n\n const subEntityUrl = resolve(contextUri, selfHref);\n\n return new SirenState({\n client,\n uri: subEntityUrl,\n data: subEntity.properties,\n headers,\n links: new Links(selfHref, parseSirenLinks(selfHref, subEntity)),\n });\n\n}\n\nfunction isSubEntity(input: SirenLink | SirenSubEntity): input is SirenSubEntity {\n\n return (input as any).href === undefined;\n\n}\n\nfunction parseSirenAction(uri: string, action: SirenAction): ActionInfo {\n return {\n uri: resolve(uri, action.href),\n name: action.name,\n title: action.title,\n method: action.method || 'GET',\n contentType: action.type || 'application/x-www-form-urlencoded',\n fields: action.fields ? action.fields.map( field => sirenFieldToField(field)) : [],\n };\n}\n\nfunction sirenFieldToField(input: SirenField): Field {\n\n const result: Field = {\n name: input.name,\n type: input.type || 'text',\n required: false,\n readOnly: false,\n };\n\n if (input.value) {\n result.value = input.value;\n }\n if (input.title) {\n result.label = input.title;\n }\n\n return result;\n}\n","import { BaseState } from './base-state';\nimport { StateFactory } from './interface';\nimport { parseLink } from '../http/util';\nimport Client from '../client';\n\n/**\n * Turns a HTTP response into a TextState\n */\nexport const factory: StateFactory<string> = async (client: Client, uri: string, response: Response): Promise<BaseState<string>> => {\n\n return new BaseState({\n client,\n uri,\n data: await response.text(),\n headers: response.headers,\n links: parseLink(uri, response.headers.get('Link')),\n });\n\n};\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { Link } from '../link';\nimport { StateFactory } from './interface';\n\n/**\n * Represents a resource state in the HAL format\n */\nexport class CjState<T = any> extends BaseState<T> {\n\n serializeBody(): string {\n\n throw new Error('Reserializing Collection+JSON states is not yet supported. Please log an issue in the Ketting project to help figure out how this should be done');\n }\n\n}\n\n/**\n * Turns a HTTP response into a CjState\n */\nexport const factory: StateFactory = async (client, uri, response): Promise<CjState<CjCollection>> => {\n\n const body = await response.json();\n\n const links = parseLink(uri, response.headers.get('Link'));\n links.add(\n ...parseCjLinks(uri, body),\n );\n\n // Remove _links and _embedded from body\n const {\n _embedded,\n _links,\n ...newBody\n } = body;\n\n return new CjState({\n client,\n uri,\n data: newBody,\n headers: response.headers,\n links,\n });\n\n};\n\ntype CjDocument = {\n collection: CjCollection;\n};\n\ntype CjCollection = {\n version?: string;\n href?: string;\n links?: CjLink[];\n items?: CjItem[];\n queries?: CjQuery[];\n template?: CjTemplate;\n error?: CjError;\n};\n\ntype CjError = {\n title?: string;\n code?: string;\n message?: string;\n};\n\ntype CjTemplate = {\n data?: CjProperty[];\n};\n\ntype CjItem = {\n href?: string;\n data?: CjProperty[];\n links?: CjLink[];\n};\n\ntype CjProperty = {\n name: string;\n value?: string;\n prompt?: string;\n};\n\ntype CjQuery = {\n href: string;\n rel: string;\n name?: string;\n prompt?: string;\n data?: CjProperty[];\n};\n\ntype CjLink = {\n href: string;\n rel: string;\n name?: string;\n render?: 'image' | 'link';\n prompt?: string;\n};\n\n\nfunction parseCjLinks(contextUri: string, body: CjDocument) {\n\n const result: Link[] = [];\n if (body.collection.links !== undefined) {\n\n // Lets start with all links from the links property.\n for (const link of body.collection.links) {\n result.push({\n context: contextUri,\n href: link.href,\n rel: link.rel,\n title: link.name,\n });\n }\n }\n\n if (body.collection.items !== undefined) {\n\n // Things that are in the 'items' array should also be considered links\n // with the 'item' link relationship.\n for (const item of body.collection.items) {\n\n if (!item.href) {\n continue;\n }\n\n result.push({\n context: contextUri,\n href: item.href,\n rel: 'item',\n });\n }\n\n }\n\n\n if (body.collection.queries !== undefined) {\n\n // Things that are in the 'queries' array can be considered links too.\n for (const query of body.collection.queries) {\n\n if (!query.data) {\n // Non-templated\n result.push({\n context: contextUri,\n href: query.href,\n rel: query.rel,\n title: query.name,\n });\n } else {\n // This query has a data property so we need 50% more magic\n result.push({\n context: contextUri,\n href: query.href + query.data.map(\n property => '{?' + property.name + '}'\n ).join(''),\n templated: true,\n rel: query.rel,\n title: query.name,\n });\n }\n }\n\n }\n\n return result;\n\n}\n","import * as sax from 'sax';\nimport { Link } from '../link';\nimport { resolve } from './uri';\n\nexport type HtmlForm = {\n action: string;\n method: string | null;\n enctype: string | null;\n rel: string | null;\n id: string | null;\n}\n\ntype ParseHtmlResult = {\n\n links: Link[];\n forms: HtmlForm[];\n\n}\n\nexport function parseHtml(contextUri: string, body: string): ParseHtmlResult {\n\n const parser = sax.parser(false, {});\n const links: Link[] = [];\n const forms: ParseHtmlResult['forms'] = [];\n\n parser.onopentag = node => {\n\n switch(node.name) {\n case 'LINK' :\n case 'A' :\n links.push(...parseLink(contextUri, node as sax.Tag));\n break;\n case 'FORM' :\n forms.push(...parseForm(contextUri, node as sax.Tag));\n break;\n\n }\n\n };\n\n parser.write(body).close();\n\n return {\n forms,\n links,\n };\n\n}\n\nfunction parseLink(contextUri: string, node: sax.Tag): Link[] {\n\n if (!node.attributes.REL) {\n return [];\n }\n if (!node.attributes.HREF) {\n return [];\n }\n\n const rels = node.attributes.REL as string;\n\n const links: Link[] = [];\n for (const rel of rels.split(' ')) {\n\n const type = node.attributes.TYPE as string;\n const link: Link = {\n rel,\n context: contextUri,\n href: node.attributes.HREF as string,\n };\n if (type) link.type = type;\n links.push(link);\n }\n\n return links;\n\n}\n\nfunction parseForm(contextUri: string, node: sax.Tag): HtmlForm[] {\n\n const rels = node.attributes.REL || null;\n const id = node.attributes.ID || null;\n const action = node.attributes.ACTION || '';\n const method = node.attributes.METHOD || 'GET';\n const enctype = node.attributes.ENCTYPE || 'application/x-www-form-urlencoded';\n\n if (!rels) {\n return [{\n rel: null,\n id,\n action: resolve(contextUri, action),\n method,\n enctype,\n }];\n }\n\n const result = [];\n\n for(const rel of rels.split(' ')) {\n\n result.push({\n rel,\n id,\n action: resolve(contextUri, action),\n method,\n enctype,\n });\n\n }\n return result;\n\n}\n","import { BaseState } from './base-state';\nimport { parseLink } from '../http/util';\nimport { parseHtml, HtmlForm } from '../util/html';\nimport { ActionInfo } from '../action';\nimport { resolve } from '../util/uri';\nimport { StateFactory } from './interface';\n\n/**\n * Turns a HTTP response into a HtmlState\n */\nexport const factory:StateFactory = async (client, uri, response): Promise<BaseState<string>> => {\n\n const body = await response.text();\n\n const links = parseLink(uri, response.headers.get('Link'));\n const htmlResult = parseHtml(uri, body);\n links.add(...htmlResult.links);\n\n return new BaseState({\n client,\n uri,\n data: body,\n headers: response.headers,\n links,\n actions: htmlResult.forms.map(form => formToAction(uri, form)),\n });\n\n};\n\nfunction formToAction(context: string, form: HtmlForm): ActionInfo {\n\n return {\n uri: resolve(context, form.action),\n name: form.rel || form.id || '',\n method: form.method || 'GET',\n contentType: form.enctype || 'application/x-www-form-urlencoded',\n // Fields are not yet supported :(\n fields: [],\n };\n}\n","import { BaseHeadState } from './base-state';\nimport { parseLink } from '../http/util';\nimport Client from '../client';\n\n/**\n * Turns the response to a HTTP Head request into a HeadState object.\n *\n * HeadState is a bit different from normal State objects, because it's\n * missing a bunch of information.\n */\nexport const factory = async (client: Client, uri: string, response: Response): Promise<BaseHeadState> => {\n\n const links = parseLink(uri, response.headers.get('Link'));\n\n return new BaseHeadState({\n client,\n uri,\n headers: response.headers,\n links,\n });\n\n};\n","import Resource from './resource';\nimport { LinkVariables } from './link';\nimport {State} from './state';\nimport {GetRequestOptions} from './types';\n\n/**\n * Base interface for both FollowOne and FollowAll\n */\nabstract class FollowPromise<T> implements PromiseLike<T> {\n\n protected prefetchEnabled: boolean;\n protected preferTranscludeEnabled: boolean;\n protected useHeadEnabled: boolean;\n\n constructor() {\n this.prefetchEnabled = false;\n this.preferTranscludeEnabled = false;\n this.useHeadEnabled = false;\n }\n\n preFetch(): this {\n this.prefetchEnabled = true;\n return this;\n }\n\n preferTransclude(): this {\n this.preferTranscludeEnabled = true;\n return this;\n }\n\n /**\n * Use a HTTP HEAD request to fetch the links.\n *\n * This is useful when interacting with servers that embed links in Link\n * Headers.\n */\n useHead(): this {\n\n this.useHeadEnabled = true;\n return this;\n\n }\n\n abstract then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;\n abstract catch<TResult1 = T, TResult2 = never>(onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;\n\n}\n\n/**\n * The FollowPromise class is what's being returned from follow() functions.\n *\n * It's 'PromiseLike', which means you can treat it like a Promise, and it\n * can be awaited. When used as a Promise, it resolves to the Resource object\n * that was followed.\n *\n * In addition to being a Promise<Resource> stand-in, it also exposes other\n * functions, namely:\n *\n * * `follow()` to allow a user to chain several follow() functions to do\n * several 'hops' all at once.\n * * `followAll()`, allowing a user to call `followAll()` at the end of a\n * chain.\n */\nexport class FollowPromiseOne<T = any> extends FollowPromise<Resource<T>> {\n\n private resource: Resource | Promise<Resource>;\n private rel: string;\n private variables?: LinkVariables;\n\n constructor(resource: Resource | Promise<Resource>, rel: string, variables?: LinkVariables) {\n\n super();\n this.resource = resource;\n this.rel = rel;\n this.variables = variables;\n\n }\n\n /**\n * This 'then' function behaves like a Promise then() function.\n *\n * This method signature is pretty crazy, but trust that it's pretty much\n * like any then() method on a promise.\n */\n then<TResult1 = Resource<T>, TResult2 = never>(\n onfulfilled?: ((value: Resource<T>) => TResult1 | PromiseLike<TResult1>) | null | undefined,\n onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | null | undefined\n ): Promise<TResult1 | TResult2> {\n\n return this.fetchLinkedResource().then(onfulfilled, onrejected);\n\n }\n\n /**\n * This 'catch' function behaves like a Promise catch() function.\n */\n catch<TResult1 = any, TResult2 = never>(onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | null | undefined): Promise<TResult1 | TResult2> {\n\n return this.fetchLinkedResource().then(undefined, onrejected);\n\n }\n\n /**\n * Implementation of a Promise.finally function\n */\n finally<TResult1 = any>(onfinally: () => TResult1 | PromiseLike<TResult1>): Promise<TResult1> {\n\n return this.then(\n () => onfinally(),\n () => onfinally()\n );\n\n }\n\n /**\n * Follow another link immediately after following this link.\n *\n * This allows you to follow several hops of links in one go.\n *\n * For example: resource.follow('foo').follow('bar');\n */\n follow<TNested = any>(rel: string, variables?: LinkVariables): FollowPromiseOne<TNested> {\n\n return new FollowPromiseOne(this.fetchLinkedResource(), rel, variables);\n\n }\n\n /**\n * Gets the current state of the resource.\n *\n * This function will return a State object.\n */\n async get(getOptions?: GetRequestOptions): Promise<State<T>> {\n return (await this).get(getOptions);\n }\n\n /**\n * Follows a set of links immediately after following this link.\n *\n * For example: resource.follow('foo').followAll('item');\n */\n followAll<TNested = any>(rel: string): FollowPromiseMany<TNested> {\n\n return new FollowPromiseMany(this.fetchLinkedResource(), rel);\n\n }\n\n /**\n * This function does the actual fetching of the linked\n * resource.\n */\n private async fetchLinkedResource(): Promise<Resource<T>> {\n\n const resource = await this.resource;\n\n const headers: { [name: string]: string } = {};\n if (!this.useHeadEnabled && this.preferTranscludeEnabled) {\n headers.Prefer = 'transclude=' + this.rel;\n }\n\n let state;\n if (this.useHeadEnabled) {\n state = await resource.head({headers});\n } else {\n state = await resource.get({\n headers\n });\n }\n\n const newResource = state.follow(this.rel, this.variables);\n\n if (this.prefetchEnabled) {\n newResource.get().catch( (err: Error) => {\n // eslint-disable-next-line no-console\n console.warn('Error while prefetching linked resource', err);\n });\n }\n\n return newResource;\n\n }\n\n}\n\n/**\n */\nexport class FollowPromiseMany<T = any> extends FollowPromise<Resource<T>[]> {\n\n private resource: Resource | Promise<Resource>;\n private rel: string;\n\n constructor(resource: Resource | Promise<Resource>, rel: string) {\n\n super();\n this.resource = resource;\n this.rel = rel;\n\n }\n\n /**\n * This 'then' function behaves like a Promise then() function.\n */\n then<TResult1 = Resource<T>[], TResult2 = never>(\n onfulfilled?: ((value: Resource<T>[]) => TResult1 | PromiseLike<TResult1>) | null | undefined,\n onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | null | undefined\n ): Promise<TResult1 | TResult2> {\n\n return this.fetchLinkedResources().then(onfulfilled, onrejected);\n\n }\n\n /**\n * This 'catch' function behaves like a Promise catch() function.\n */\n catch<TResult1 = any, TResult2 = never>(onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | null | undefined): Promise<TResult1 | TResult2> {\n\n return this.fetchLinkedResources().then(undefined, onrejected);\n\n }\n\n /**\n * Implementation of a Promise.finally function\n */\n finally<TResult1 = any>(onfinally: () => TResult1 | PromiseLike<TResult1>): Promise<TResult1> {\n\n return this.then(\n () => onfinally(),\n () => onfinally()\n );\n\n }\n\n /**\n * Gets the current states of the resources.\n *\n * This function will return an array of State object.\n */\n async get(getOptions?: GetRequestOptions): Promise<State<T>[]> {\n return Promise.all((await this).map(resource => resource.get(getOptions)));\n }\n\n /**\n * This function does the actual fetching, to obtained the url\n * of the linked resource. It returns the Resource object.\n */\n private async fetchLinkedResources(): Promise<Resource<T>[]> {\n\n const resource = await this.resource;\n const headers: { [name: string]: string } = {};\n if (!this.useHeadEnabled && this.preferTranscludeEnabled) {\n headers.Prefer = 'transclude=' + this.rel;\n }\n\n let state;\n if (this.useHeadEnabled) {\n state = await resource.head({headers});\n } else {\n state = await resource.get({\n headers\n });\n }\n\n const result: Resource<T>[] = state.followAll(this.rel);\n\n if (this.prefetchEnabled) {\n result.map( resource => {\n resource.get().catch( err => {\n // eslint-disable-next-line no-console\n console.warn('Error while prefetching linked resource', err);\n });\n });\n }\n\n return result;\n\n }\n\n}\n","export function needsJsonStringify(input: any): boolean {\n\n if (typeof input ==='string') {\n return false;\n }\n\n if (globalThis.Buffer && input instanceof Buffer) {\n return false;\n }\n\n return true;\n\n}\n","import Client from './client';\nimport { State, headStateFactory, HeadState, isState } from './state';\nimport { resolve } from './util/uri';\nimport { FollowPromiseOne, FollowPromiseMany } from './follow-promise';\nimport { Link, LinkNotFound, LinkVariables } from './link';\nimport { EventEmitter } from 'events';\nimport { GetRequestOptions, PostRequestOptions, PatchRequestOptions, PutRequestOptions, HeadRequestOptions } from './types';\nimport { needsJsonStringify } from './util/fetch-body-helper';\n\n/**\n * A 'resource' represents an endpoint on a server.\n *\n * A resource has a uri, methods that correspond to HTTP methods,\n * and events to subscribe to state changes.\n */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\nexport class Resource<T = any> extends EventEmitter {\n\n /**\n * URI of the current resource\n */\n uri: string;\n\n /**\n * Reference to the Client that created the resource\n */\n client: Client;\n\n /**\n * This object tracks all in-flight requests.\n *\n * When 2 identical requests are made in quick succession, this object is\n * used to de-duplicate the requests.\n */\n private readonly activeRefresh: Map<string, Promise<State<T>>> = new Map<string, Promise<State<T>>>();\n\n /**\n * Create the resource.\n *\n * This is usually done by the Client.\n */\n constructor(client: Client, uri: string) {\n super();\n this.client = client;\n this.uri = uri;\n this.setMaxListeners(500);\n\n }\n\n /**\n * Gets the current state of the resource.\n *\n * This function will return a State object.\n */\n get(getOptions?: GetRequestOptions): Promise<State<T>> {\n\n const state = this.getCache();\n if (state) {\n return Promise.resolve(state);\n }\n\n const params = optionsToRequestInit('GET', getOptions);\n const uri = this.uri;\n\n const hash = requestHash(this.uri, getOptions);\n\n if (!this.activeRefresh.has(hash)) {\n this.activeRefresh.set(hash, (async (): Promise<State<T>> => {\n try {\n const response = await this.fetchOrThrow(params);\n const state = await this.client.getStateForResponse(uri, response);\n this.updateCache(state);\n return state;\n } finally {\n this.activeRefresh.delete(hash);\n }\n })());\n }\n\n return this.activeRefresh.get(hash)!;\n }\n\n /**\n * Does a HEAD request and returns a HeadState object.\n *\n * If there was a valid existing cache for a GET request, it will\n * still return that.\n */\n async head(headOptions?: HeadRequestOptions): Promise<HeadState> {\n\n let state: State|HeadState|null = this.client.cache.get(this.uri);\n if (state) {\n return state;\n }\n\n const response = await this.fetchOrThrow(\n optionsToRequestInit('HEAD', headOptions)\n );\n\n state = await headStateFactory(this.client, this.uri, response);\n return state;\n\n }\n\n\n /**\n * Gets the current state of the resource, skipping\n * the cache.\n *\n * This function will return a State object.\n */\n refresh(getOptions?: GetRequestOptions): Promise<State<T>> {\n\n const params = optionsToRequestInit('GET', getOptions);\n params.cache = 'no-cache';\n const uri = this.uri;\n\n const hash = requestHash(this.uri, getOptions);\n\n if (!this.activeRefresh.has(hash)) {\n this.activeRefresh.set(hash, (async (): Promise<State<T>> => {\n try {\n const response = await this.fetchOrThrow(params);\n const state = await this.client.getStateForResponse(uri, response);\n this.updateCache(state);\n return state;\n } finally {\n this.activeRefresh.delete(hash);\n }\n })());\n }\n\n return this.activeRefresh.get(hash)!;\n }\n\n /**\n * Updates the server state with a PUT request\n */\n async put(options: PutRequestOptions<T> | State): Promise<void> {\n\n const requestInit = optionsToRequestInit('PUT', options);\n\n /**\n * If we got a 'State' object passed, it means we don't need to emit a\n * stale event, as the passed object is the new\n * state.\n *\n * We're gonna track that with a custom header that will be removed\n * later in the fetch pipeline.\n */\n if (isState(options)) {\n requestInit.headers.set('X-KETTING-NO-STALE', '1');\n }\n\n await this.fetchOrThrow(requestInit);\n\n if (isState(options)) {\n this.updateCache(options);\n\n }\n\n }\n\n /**\n * Deletes the resource\n */\n async delete(): Promise<void> {\n\n await this.fetchOrThrow(\n { method: 'DELETE' }\n );\n\n }\n\n /**\n * Sends a POST request to the resource.\n *\n * See the documentation for PostRequestOptions for more details.\n * This function is used for RPC-like endpoints and form submissions.\n *\n * This function will return the response as a State object.\n */\n async post(options: PostRequestOptions): Promise<State> {\n\n const response = await this.fetchOrThrow(\n optionsToRequestInit('POST', options)\n );\n\n return this.client.getStateForResponse(this.uri, response);\n\n }\n\n /**\n * Sends a POST request, and follows to the next resource.\n *\n * If a server responds with a 201 Status code and a Location header,\n * it will automatically return the newly created resource.\n *\n * If the server responded with a 204 or 205, this function will return\n * `this`.\n */\n async postFollow(options: PostRequestOptions): Promise<Resource> {\n\n const response = await this.fetchOrThrow(\n optionsToRequestInit('POST', options)\n );\n\n switch (response.status) {\n case 201:\n if (response.headers.has('location')) {\n return this.go(response.headers.get('location')!);\n }\n throw new Error('Could not follow after a 201 request, because the server did not reply with a Location header. If you sent a Location header, check if your service is returning \"Access-Control-Expose-Headers: Location\".');\n case 204 :\n case 205 :\n return this;\n default:\n throw new Error('Did not receive a 201, 204 or 205 status code so we could not follow to the next resource');\n }\n\n }\n\n /**\n * Sends a PATCH request to the resource.\n *\n * This function defaults to a application/json content-type header.\n *\n * If the server responds with 200 Status code this will return a State object\n */\n async patch(options: PatchRequestOptions): Promise<undefined | State<T>> {\n\n const response = await this.fetchOrThrow(\n optionsToRequestInit('PATCH', options)\n );\n\n if (response.status === 200) {\n return await this.client.getStateForResponse(this.uri, response);\n }\n }\n\n /**\n * Follows a relationship, based on its reltype. For example, this might be\n * 'alternate', 'item', 'edit' or a custom url-based one.\n *\n * This function can also follow templated uris. You can specify uri\n * variables in the optional variables argument.\n */\n follow<TFollowedResource = any>(rel: string, variables?: LinkVariables): FollowPromiseOne<TFollowedResource> {\n\n return new FollowPromiseOne(this, rel, variables);\n\n }\n\n /**\n * Follows a relationship based on its reltype. This function returns a\n * Promise that resolves to an array of Resource objects.\n *\n * If no resources were found, the array will be empty.\n */\n followAll<TFollowedResource = any>(rel: string): FollowPromiseMany<TFollowedResource> {\n\n return new FollowPromiseMany(this, rel);\n\n }\n\n /**\n * Resolves a new resource based on a relative uri.\n *\n * Use this function to manually get a Resource object via a uri. The uri\n * will be resolved based on the uri of the current resource.\n *\n * This function doesn't do any HTTP requests.\n */\n go<TGoResource = any>(uri: string|Link): Resource<TGoResource> {\n\n if (typeof uri === 'string') {\n return this.client.go(resolve(this.uri, uri));\n } else {\n return this.client.go(uri);\n }\n\n }\n\n /**\n * Does a HTTP request on the current resource URI\n */\n fetch(init?: RequestInit): Promise<Response> {\n\n return this.client.fetcher.fetch(this.uri, init);\n\n }\n\n /**\n * Does a HTTP request on the current resource URI.\n *\n * If the response was a 4XX or 5XX, this function will throw\n * an exception.\n */\n fetchOrThrow(init?: RequestInit): Promise<Response> {\n\n return this.client.fetcher.fetchOrThrow(this.uri, init);\n\n }\n\n /**\n * Updates the state cache, and emits events.\n *\n * This will update the local state but *not* update the server\n */\n updateCache(state: State<T>) {\n\n if (state.uri !== this.uri) {\n throw new Error('When calling updateCache on a resource, the uri of the State object must match the uri of the Resource');\n }\n this.client.cacheState(state);\n\n }\n\n /**\n * Clears the state cache for this resource.\n */\n clearCache(): void {\n\n this.client.clearResourceCache([this.uri],[]);\n\n }\n\n /**\n * Retrieves the current cached resource state, and return `null` if it's\n * not available.\n */\n getCache(): State<T>|null {\n\n return this.client.cache.get(this.uri);\n\n }\n\n /**\n * Returns a Link object, by its REL.\n *\n * If the link does not exist, a LinkNotFound error will be thrown.\n *\n * @deprecated\n */\n async link(rel: string): Promise<Link> {\n\n const state = await this.get();\n const link = state.links.get(rel);\n\n if (!link) {\n throw new LinkNotFound(`Link with rel: ${rel} not found on ${this.uri}`);\n }\n return link;\n\n }\n\n /**\n * Returns all links defined on this object.\n *\n * @deprecated\n */\n async links(rel?: string): Promise<Link[]> {\n\n const state = await this.get();\n if (!rel) {\n return state.links.getAll();\n } else {\n return state.links.getMany(rel);\n }\n\n }\n\n /**\n *\n * Returns true or false depending on if a link with the specified relation\n * type exists.\n *\n * @deprecated\n */\n async hasLink(rel: string): Promise<boolean> {\n\n const state = await this.get();\n return state.links.has(rel);\n\n }\n}\n\n// eslint doesn't like that we have a generic T but not using it.\n// eslint-disable-next-line\nexport declare interface Resource<T = any> {\n\n /**\n * Subscribe to the 'update' event.\n *\n * This event will get triggered whenever a new State is received\n * from the server, either through a GET request or if it was\n * transcluded.\n *\n * It will also trigger when calling 'PUT' with a full state object,\n * and when updateCache() was used.\n */\n on(event: 'update', listener: (state: State) => void) : this;\n\n /**\n * Subscribe to the 'stale' event.\n *\n * This event will get triggered whenever an unsafe method was\n * used, such as POST, PUT, PATCH, etc.\n *\n * When any of these methods are used, the local cache is stale.\n */\n on(event: 'stale', listener: () => void) : this;\n\n /**\n * Subscribe to the 'delete' event.\n *\n * This event gets triggered when the `DELETE` http method is used.\n */\n on(event: 'delete', listener: () => void) : this;\n\n /**\n * Subscribe to the 'update' event and unsubscribe after it was\n * emitted the first time.\n */\n once(event: 'update', listener: (state: State) => void) : this;\n\n /**\n * Subscribe to the 'stale' event and unsubscribe after it was\n * emitted the first time.\n */\n once(event: 'stale', listener: () => void) : this;\n\n /**\n * Subscribe to the 'delete' event and unsubscribe after it was\n * emitted the first time.\n */\n once(event: 'delete', listener: () => void) : this;\n\n /**\n * Unsubscribe from the 'update' event\n */\n off(event: 'update', listener: (state: State) => void) : this;\n\n /**\n * Unsubscribe from the 'stale' event\n */\n off(event: 'stale', listener: () => void) : this;\n\n /**\n * Unsubscribe from the 'delete' event\n */\n off(event: 'delete', listener: () => void) : this;\n\n /**\n * Emit an 'update' event.\n */\n emit(event: 'update', state: State) : boolean;\n\n /**\n * Emit a 'stale' event.\n */\n emit(event: 'stale') : boolean;\n\n /**\n * Emit a 'delete' event.\n */\n emit(event: 'delete') : boolean;\n\n}\n\nexport default Resource;\n\ntype StrictRequestInit = RequestInit & {\n headers: Headers;\n};\n\n/**\n * Convert request options to RequestInit\n *\n * RequestInit is passed to the constructor of fetch(). We have our own 'options' format\n */\nfunction optionsToRequestInit(method: 'GET', options?: GetRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: 'HEAD', options?: HeadRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: 'PATCH', options?: PatchRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: 'POST', options?: PostRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: 'PUT', options?: PutRequestOptions): StrictRequestInit;\nfunction optionsToRequestInit(method: string, options?: GetRequestOptions | PostRequestOptions | PatchRequestOptions | PutRequestOptions): StrictRequestInit {\n\n if (!options) {\n return {\n method,\n headers: new Headers(),\n };\n }\n let headers;\n if (options.getContentHeaders) {\n headers = new Headers(options.getContentHeaders());\n } else if (options.headers) {\n headers = new Headers(options.headers);\n } else {\n headers = new Headers();\n }\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json');\n }\n let body;\n if ((options as any).serializeBody !== undefined) {\n body = (options as any).serializeBody();\n } else if ((options as any).data) {\n body = (options as any).data;\n if (needsJsonStringify(body)) {\n body = JSON.stringify(body);\n }\n } else {\n body = null;\n }\n return {\n method,\n body,\n headers,\n };\n\n}\n\nfunction requestHash(uri: string, options: GetRequestOptions | undefined): string {\n\n const headers: Record<string, string> = {};\n if (options) {\n new Headers(options.getContentHeaders?.() || options.headers)\n .forEach((value, key) => {\n headers[key] = value;\n });\n }\n\n const headerStr = Object.entries(headers).map( ([name, value]) => {\n return name.toLowerCase() + ':' + value;\n }).join(',');\n\n return uri + '|' + headerStr;\n}\n","import { StateCache } from './';\nimport { State } from '../state';\n\n/**\n * The 'Forever' cache stores any State for as long as the application\n * lives.\n *\n * It is a good default for most applications, but it means that if\n * a resource was changed server-side, Ketting will not pick up that change\n * until something was done to expire caches.\n *\n * Executing an unsafe method, calling clearCache() on a resource, or\n * when a resource appears in Location, Content-Location, or \"invalidates\"\n * link relationships.\n */\nexport class ForeverCache implements StateCache {\n\n private cache: Map<string, State>;\n\n constructor() {\n this.cache = new Map();\n }\n\n /**\n * Store a State object.\n *\n * This function will clone the state object before storing\n */\n store(state: State) {\n this.cache.set(\n state.uri,\n state.clone()\n );\n }\n\n /**\n * Retrieve a State object from the cache by its absolute uri\n */\n get(uri: string): State | null {\n\n const state = this.cache.get(uri);\n if (!state) {\n return null;\n }\n return state.clone();\n\n }\n\n /**\n * Return true if a State object with the specified uri exists in the cache\n */\n has(uri: string): boolean {\n\n return this.cache.has(uri);\n\n }\n\n /**\n * Delete a State object from the cache, by its uri\n */\n delete(uri: string) {\n this.cache.delete(uri);\n }\n\n /**\n * Purge the entire cache\n */\n clear() {\n this.cache.clear();\n }\n\n /**\n * Clean up any dangling references to avoid memory leaks.\n */\n destroy() {\n\n }\n\n}\n","import { State } from '../state';\nimport { ForeverCache } from './forever';\n\n/**\n * ShortCache stores items in the cache for a short time.\n *\n * This cache can be a good choice if your server heavily relies\n * on HTTP cache headers and Ketting runs in your browser, or if in general\n * you want very up-to-date data.\n *\n * The reason in this scenarios it's useful to still have a 'very temporary'\n * cache, is because during many operations `get()` may be called in rapid\n * succession, and it also allows for enough time for 'embedded items' to\n * pe placed in the cache and extracted again.\n */\nexport class ShortCache extends ForeverCache {\n\n private cacheTimeout: number;\n private activeTimers: Map<string, ReturnType<typeof setInterval>>;\n\n /**\n * Create the short cache.\n *\n * cacheTimeout is specified in ms.\n */\n constructor(cacheTimeout: number = 30000) {\n super();\n this.cacheTimeout = cacheTimeout;\n this.activeTimers = new Map();\n }\n\n /**\n * Store a State object.\n *\n * This function will clone the state object before storing\n */\n store(state: State) {\n super.store(state);\n this.setTimer(state.uri);\n }\n\n private setTimer(uri: string) {\n\n if (this.activeTimers.has(uri)) {\n clearTimeout(this.activeTimers.get(uri)!);\n }\n // If there is a TON in the cache, this algorithm might\n // be optimized by using a linked list and a single timeout\n // for the 'next scheduled' expiry.\n //\n // The expectation is that this is not the case though, so this is the\n // lazy/easy way.\n this.activeTimers.set(\n uri,\n setTimeout( () => {\n this.delete(uri);\n this.activeTimers.delete(uri);\n }, this.cacheTimeout)\n );\n\n }\n\n /**\n * Clean up any dangling references to avoid memory leaks.\n */\n destroy() {\n\n for (const timer of this.activeTimers.values()) {\n clearTimeout(timer);\n }\n\n }\n}\n","import { StateCache } from './';\nimport { State } from '../state';\n\n/**\n * The NeverCache caches absolutely nothing.\n *\n * This should usually only be used in testing scenarios or if you really\n * know what you're doing.\n *\n * Using it could cause excessive requests, and will cause embedded items\n * to be ignored.\n */\nexport class NeverCache implements StateCache {\n\n /**\n * Store a State object.\n *\n * This function will clone the state object before storing\n */\n store(state: State) {\n // Nothing to do\n }\n\n /**\n * Retrieve a State object from the cache by its absolute uri\n */\n get(uri: string): null {\n return null;\n }\n\n /**\n * Return true if a State object with the specified uri exists in the cache\n */\n has(uri: string): boolean {\n\n return false;\n\n }\n\n /**\n * Delete a State object from the cache, by its uri\n */\n delete(uri: string) {\n // Nothing to do\n }\n\n /**\n * Purge the entire cache\n */\n clear() {\n // Nothing to do\n }\n\n}\n","import { FetchMiddleware } from '../http/fetcher';\nimport { isSafeMethod } from '../http/util';\nimport * as LinkHeader from 'http-link-header';\nimport { resolve } from '../util/uri';\nimport Client from '../client';\n\n/**\n * This middleware manages the cache based on information in requests\n * and responses.\n *\n * It expires items from the cache and updates the cache if `Content-Location`\n * appeared in the response.\n *\n * It's also responsible for emitting 'stale' events.\n */\nexport default function(client: Client): FetchMiddleware {\n\n return async(request, next) => {\n\n /**\n * Prevent a 'stale' event from being emitted, but only for the main\n * uri\n */\n let noStaleEvent = false;\n\n if (request.headers.has('X-KETTING-NO-STALE')) {\n noStaleEvent = true;\n request.headers.delete('X-KETTING-NO-STALE');\n }\n\n const response = await next(request);\n\n if (isSafeMethod(request.method)) {\n return response;\n }\n\n if (!response.ok) {\n // There was an error, no cache changes\n return response;\n }\n\n // We just processed an unsafe method, lets notify all subsystems.\n const stale = [];\n const deleted = [];\n\n if (request.method === 'DELETE') {\n deleted.push(request.url);\n } else if (!noStaleEvent) {\n stale.push(request.url);\n }\n\n // If the response had a Link: rel=invalidate header, we want to\n // expire those too.\n if (response.headers.has('Link')) {\n for (const httpLink of LinkHeader.parse(response.headers.get('Link')!).rel('invalidates')) {\n const uri = resolve(request.url, httpLink.uri);\n stale.push(uri);\n }\n }\n\n // Location headers should also expire\n if (response.headers.has('Location')) {\n stale.push(\n resolve(request.url, response.headers.get('Location')!)\n );\n }\n\n client.clearResourceCache(stale, deleted);\n\n // If the response had a 'Content-Location' header, it means that the\n // response body is the _new_ state for the url in the content-location\n // header, so we store it!\n if (request.cache !== 'no-store' && response.headers.has('Content-Location')) {\n const cl = resolve(request.url, response.headers.get('Content-Location')!);\n const clState = await client.getStateForResponse(\n cl,\n response.clone()\n );\n client.cacheState(clState);\n }\n\n return response;\n\n };\n\n}\n","import { FetchMiddleware } from '../http/fetcher';\nimport Client from '../client';\n\n/**\n * This middleware injects a default Accept header.\n *\n * The list of content-types is generated from the Client's\n * 'contentTypeMap'.\n */\nexport default function(client: Client): FetchMiddleware {\n\n return async(request, next) => {\n\n if (!request.headers.has('Accept')) {\n const acceptHeader = Object.entries(client.contentTypeMap).map(\n ([contentType, [, q]]) => contentType + ';q=' + q\n ).join(', ');\n request.headers.set('Accept', acceptHeader);\n }\n return next(request);\n\n };\n\n}\n","import { FetchMiddleware } from '../http/fetcher';\nimport * as LinkHeader from 'http-link-header';\nimport { resolve } from '../util/uri';\n\n/**\n * This middleware will emit warnings based on HTTP responses.\n *\n * Currently it just inspects the 'Deprecation' HTTP header from\n * draft-dalal-deprecation-header\n */\nexport default function(): FetchMiddleware {\n\n return async(request, next) => {\n\n const response = await next(request);\n const deprecation = response.headers.get('Deprecation');\n if (deprecation) {\n const sunset = response.headers.get('Sunset');\n let msg = `[Ketting] The resource ${request.url} is deprecated.`;\n if (sunset) {\n msg += ' It will no longer respond ' + sunset;\n }\n if (response.headers.has('Link')) {\n for (const httpLink of LinkHeader.parse(response.headers.get('Link')!).rel('deprecation')) {\n const uri = resolve(request.url, httpLink.uri);\n msg += `See ${uri} for more information.`;\n }\n }\n\n /* eslint-disable-next-line no-console */\n console.warn(msg);\n\n }\n return response;\n\n };\n\n}\n","import { Fetcher, FetchMiddleware } from './http/fetcher';\nimport Resource from './resource';\nimport { State, StateFactory } from './state';\nimport {\n halStateFactory,\n binaryStateFactory,\n jsonApiStateFactory,\n sirenStateFactory,\n textStateFactory,\n cjStateFactory,\n htmlStateFactory\n} from './state';\nimport { parseContentType } from './http/util';\nimport { resolve } from './util/uri';\nimport { Link, LinkVariables } from './link';\nimport { FollowPromiseOne } from './follow-promise';\nimport { StateCache, ForeverCache } from './cache';\nimport cacheExpireMiddleware from './middlewares/cache';\nimport acceptMiddleware from './middlewares/accept-header';\nimport warningMiddleware from './middlewares/warning';\n\nexport default class Client {\n\n /**\n * All relative urls will by default use the bookmarkUri to\n * expand. It should usually be the starting point of your\n * API\n */\n bookmarkUri: string;\n\n /**\n * Supported content types\n *\n * Each content-type has a 'factory' that turns a HTTP response\n * into a State object.\n *\n * The last value in the array is the 'q=' value, used in Accept\n * headers. Higher means higher priority.\n */\n contentTypeMap: {\n [mimeType: string]: [StateFactory<any>, string];\n } = {\n 'application/prs.hal-forms+json': [halStateFactory, '1.0'],\n 'application/hal+json': [halStateFactory, '0.9'],\n 'application/vnd.api+json': [jsonApiStateFactory, '0.8'],\n 'application/vnd.siren+json': [sirenStateFactory, '0.8'],\n 'application/vnd.collection+json': [cjStateFactory, '0.8'],\n 'application/json': [halStateFactory, '0.7'],\n 'text/html': [htmlStateFactory, '0.6'],\n };\n\n /**\n * The cache for 'State' objects\n */\n cache: StateCache;\n\n /**\n * The cache for 'Resource' objects. Each unique uri should\n * only ever get 1 associated resource.\n */\n resources: Map<string, Resource>;\n\n /**\n * Fetcher is a utility object that handles fetch() requests\n * and middlewares.\n */\n fetcher: Fetcher;\n\n constructor(bookmarkUri: string) {\n this.bookmarkUri = bookmarkUri;\n this.fetcher = new Fetcher();\n this.fetcher.use(cacheExpireMiddleware(this));\n this.fetcher.use(acceptMiddleware(this));\n this.fetcher.use(warningMiddleware());\n this.cache = new ForeverCache();\n this.resources = new Map();\n }\n\n /**\n * Follows a relationship, based on its reltype. For example, this might be\n * 'alternate', 'item', 'edit' or a custom url-based one.\n *\n * This function can also follow templated uris. You can specify uri\n * variables in the optional variables argument.\n */\n follow<TFollowedResource = any>(rel: string, variables?: LinkVariables): FollowPromiseOne<TFollowedResource> {\n\n return this.go().follow(rel, variables);\n\n }\n\n /**\n * Returns a resource by its uri.\n *\n * This function doesn't do any HTTP requests. The uri is optional. If it's\n * not specified, it will return the bookmark resource.\n *\n * If a relative uri is passed, it will be resolved based on the bookmark\n * uri.\n *\n * @example\n * const res = ketting.go('https://example.org/);\n * @example\n * const res = ketting.go<Author>('/users/1');\n * @example\n * const res = ketting.go(); // bookmark\n */\n go<TResource = any>(uri?: string|Link): Resource<TResource> {\n\n let absoluteUri;\n if (uri === undefined) {\n absoluteUri = this.bookmarkUri;\n } else if (typeof uri === 'string') {\n absoluteUri = resolve(this.bookmarkUri, uri);\n } else {\n absoluteUri = resolve(uri);\n }\n if (!this.resources.has(absoluteUri)) {\n const resource = new Resource(this, absoluteUri);\n this.resources.set(absoluteUri, resource);\n return resource;\n }\n return this.resources.get(absoluteUri)!;\n\n }\n\n /**\n * Adds a fetch middleware, which will be executed for\n * each fetch() call.\n *\n * If 'origin' is specified, fetch middlewares can be executed\n * only if the host/origin matches.\n */\n use(middleware: FetchMiddleware, origin: string = '*') {\n\n this.fetcher.use(middleware, origin);\n\n }\n\n /**\n * Clears the entire state cache\n */\n clearCache() {\n\n this.cache.clear();\n this.cacheDependencies = new Map();\n\n }\n\n /**\n * Caches a State object\n *\n * This function will also emit 'update' events to resources, and store all\n * embedded states.\n */\n cacheState(state: State) {\n\n // Flatten the list of state objects.\n const newStates = flattenState(state);\n\n // Register all cache dependencies.\n for(const nState of newStates) {\n for(const invByLink of nState.links.getMany('inv-by')) {\n this.addCacheDependency(resolve(invByLink), nState.uri);\n }\n }\n\n // Store all new caches\n for(const nState of newStates) {\n this.cache.store(nState);\n }\n\n // Emit 'update' events\n for(const nState of newStates) {\n const resource = this.resources.get(nState.uri);\n if (resource) {\n // We have a resource for this object, notify it as well.\n resource.emit('update', nState);\n }\n }\n\n }\n\n /**\n * cacheDependencies contains all cache relationships between\n * resources.\n *\n * This lets a user (for example) let a resource automatically\n * expire, if another one expires.\n *\n * A server can populate this list using the `inv-by' link.\n *\n * @deprecated This property will go private in a future release.\n */\n public cacheDependencies: Map<string, Set<string>> = new Map();\n\n /**\n * Adds a cache dependency between two resources.\n *\n * If the 'target' resource ever expires, it will cause 'dependentUri' to\n * also expire.\n *\n * Both argument MUST be absolute urls.\n */\n addCacheDependency(targetUri: string, dependentUri: string): void {\n\n if (this.cacheDependencies.has(targetUri)) {\n this.cacheDependencies.get(targetUri)!.add(dependentUri);\n } else {\n this.cacheDependencies.set(targetUri, new Set([dependentUri]));\n }\n\n }\n\n /**\n * Helper function for clearing the cache for a resource.\n *\n * This function will also emit the 'stale' event for resources that have\n * subscribers, and handle any dependent resource caches.\n *\n * If any resources are specified in deletedUris, those will not\n * receive 'stale' events, but 'delete' events instead.\n */\n clearResourceCache(staleUris: string[], deletedUris: string[]) {\n\n let stale = new Set<string>();\n const deleted = new Set<string>();\n for(const uri of staleUris) {\n stale.add(resolve(this.bookmarkUri, uri));\n }\n for(const uri of deletedUris) {\n stale.add(resolve(this.bookmarkUri, uri));\n deleted.add(resolve(this.bookmarkUri, uri));\n }\n\n stale = expandCacheDependencies(\n new Set([...stale, ...deleted]),\n this.cacheDependencies\n );\n\n for(const uri of stale) {\n this.cache.delete(uri);\n\n const resource = this.resources.get(uri);\n if (resource) {\n if (deleted.has(uri)) {\n resource.emit('delete');\n } else {\n resource.emit('stale');\n }\n\n }\n\n }\n\n }\n\n /**\n * Transforms a fetch Response to a State object.\n */\n async getStateForResponse(uri: string, response: Response): Promise<State> {\n\n const contentType = parseContentType(response.headers.get('Content-Type')!);\n\n if (!contentType || response.status === 204) {\n return binaryStateFactory(this, uri, response);\n }\n\n if (contentType in this.contentTypeMap) {\n return this.contentTypeMap[contentType][0](this, uri, response);\n } else if (contentType.startsWith('text/')) {\n // Default to TextState for any format starting with text/\n return textStateFactory(this, uri, response);\n } else if (contentType.match(/^application\\/[A-Za-z-.]+\\+json/)) {\n // Default to HalState for any format containing a pattern like application/*+json\n return halStateFactory(this, uri, response);\n } else {\n return binaryStateFactory(this, uri, response);\n }\n\n }\n\n\n}\n\n\n\n/**\n * Find all dependencies for a given resource.\n *\n * For example, if\n * * if resourceA depends on resourceB\n * * and resourceB depends on resourceC\n *\n * Then if 'resourceC' expires, so should 'resourceA' and 'resourceB'.\n *\n * This function helps us find these dependencies recursively and guarding\n * against recursive loops.\n */\nfunction expandCacheDependencies(uris: Set<string>, dependencies: Map<string, Set<string>>, output?: Set<string>): Set<string> {\n\n if (!output) output = new Set();\n\n for(const uri of uris) {\n\n if (!output.has(uri)) {\n output.add(uri);\n if (dependencies.has(uri)) {\n expandCacheDependencies(dependencies.get(uri)!, dependencies, output);\n }\n }\n\n }\n\n return output;\n\n}\n\n/**\n * Take a State object, find all it's embedded resources and return a flat\n * array of all resources at any depth.\n */\nfunction flattenState(state: State, result: Set<State> = new Set<State>()): Set<State> {\n\n result.add(state);\n for(const embedded of state.getEmbedded()) {\n flattenState(embedded, result);\n }\n return result;\n\n}\n","import { FetchMiddleware } from './fetcher';\n\nexport default (userName: string, password: string): FetchMiddleware => {\n\n const basicAuthHeader = 'Basic ' + btoa(userName + ':' + password);\n\n return (request, next) => {\n\n request.headers.set('Authorization', basicAuthHeader);\n return next(request);\n\n };\n\n};\n","import { FetchMiddleware } from './fetcher';\n\nexport default (token: string): FetchMiddleware => {\n\n const bearerAuthHeader = 'Bearer ' + token;\n\n return (request, next) => {\n\n request.headers.set('Authorization', bearerAuthHeader);\n return next(request);\n\n };\n\n};\n","import { FetchMiddleware } from './fetcher';\nimport { OAuth2Client, OAuth2Fetch } from '@badgateway/oauth2-client';\n\nfunction oauth2mw(oauth2Options: OAuth2Options, token?: OAuth2Token): FetchMiddleware {\n\n console.warn('The OAuth2 middleware in Ketting is deprecated, and will be removed in the next major version of Ketting. You should upgrade to the OAuth2Fetch from the @badgateway/oauth2-client project');\n\n // This code converts the old 'fetch-mw-oauth2' options format to the new\n // oauth2 client we use now, which is why it's a bit clunky.\n const newOptions: ConstructorParameters<typeof OAuth2Client>[0] = {\n clientId: oauth2Options.clientId,\n clientSecret: 'clientSecret' in oauth2Options ? oauth2Options.clientSecret : undefined,\n tokenEndpoint: oauth2Options.tokenEndpoint,\n };\n\n\n const oauth2Client = new OAuth2Client(newOptions);\n const oauth2Fetch = new OAuth2Fetch({\n client: oauth2Client,\n getNewToken: async() => {\n\n switch(oauth2Options.grantType) {\n case 'password' :\n return oauth2Client.password({\n username: oauth2Options.userName,\n password: oauth2Options.password,\n scope: oauth2Options.scope,\n });\n case 'client_credentials' :\n return oauth2Client.clientCredentials({\n scope: oauth2Options.scope\n });\n case 'authorization_code' :\n return oauth2Client.authorizationCode.getToken({\n code: oauth2Options.code,\n codeVerifier: oauth2Options.codeVerifier,\n redirectUri: oauth2Options.redirectUri,\n });\n case undefined:\n return null;\n }\n\n },\n\n getStoredToken: (): OAuth2Token|null => {\n return token ?? null;\n },\n\n storeToken: (token: OAuth2Token) => {\n if (oauth2Options.onTokenUpdate) {\n oauth2Options.onTokenUpdate(token);\n }\n },\n\n onError: (err: Error) => {\n if (oauth2Options.onAuthError) {\n oauth2Options.onAuthError(err);\n }\n }\n });\n\n\n\n return oauth2Fetch.mw();\n}\n\n\nexport default oauth2mw;\n\n/**\n * Token information\n */\nexport type OAuth2Token = {\n\n /**\n * OAuth2 Access Token\n */\n accessToken: string;\n\n /**\n * When the Access Token expires.\n *\n * This is expressed as a unix timestamp in milliseconds.\n */\n expiresAt: number | null;\n\n /**\n * OAuth2 refresh token\n */\n refreshToken: string | null;\n};\n\n/**\n * grant_type=password\n */\ntype PasswordGrantOptions = {\n grantType: 'password';\n\n /**\n * OAuth2 client id\n */\n clientId: string;\n\n /**\n * OAuth2 Client Secret\n */\n clientSecret: string;\n\n /**\n * OAuth2 token endpoint\n */\n tokenEndpoint: string;\n\n /**\n * List of OAuth2 scopes\n */\n scope?: string[];\n\n /**\n * Username to log in as\n */\n userName: string;\n\n /**\n * Password\n */\n password: string;\n\n /**\n * Callback to trigger when a new access/refresh token pair was obtained.\n */\n onTokenUpdate?: (token: OAuth2Token) => void;\n\n /**\n * If authentication fails without a chance of recovery, this gets triggered.\n *\n * This is used for example when your resource server returns a 401, but only after\n * other attempts have been made to reauthenticate (such as a token refresh).\n */\n onAuthError?: (error: Error) => void;\n};\n\n/**\n * grant_type=client_credentials\n */\ntype ClientCredentialsGrantOptions = {\n grantType: 'client_credentials';\n\n /**\n * OAuth2 client id\n */\n clientId: string;\n\n /**\n * OAuth2 Client Secret\n */\n clientSecret: string;\n\n /**\n * OAuth2 token endpoint\n */\n tokenEndpoint: string;\n\n /**\n * List of OAuth2 scopes\n */\n scope?: string[];\n\n /**\n * Callback to trigger when a new access/refresh token pair was obtained.\n */\n onTokenUpdate?: (token: OAuth2Token) => void;\n\n /**\n * If authentication fails without a chance of recovery, this gets triggered.\n *\n * This is used for example when your resource server returns a 401, but only after\n * other attempts have been made to reauthenticate (such as a token refresh).\n */\n onAuthError?: (error: Error) => void;\n};\n\n/**\n * grant_type=authorization_code\n */\ntype AuthorizationCodeGrantOptions = {\n grantType: 'authorization_code';\n\n /**\n * OAuth2 client id\n */\n clientId: string;\n\n /**\n * OAuth2 token endpoint\n */\n tokenEndpoint: string;\n\n /**\n * The redirect_uri that was passed originally to the 'authorization' endpoint.\n *\n * This must be identical to the original string, as conforming OAuth2 servers\n * will validate this.\n */\n redirectUri: string;\n\n /**\n * Code that was obtained from the authorization endpoint\n */\n code: string;\n\n /**\n * Callback to trigger when a new access/refresh token pair was obtained.\n */\n onTokenUpdate?: (token: OAuth2Token) => void;\n\n /**\n * If authentication fails without a chance of recovery, this gets triggered.\n *\n * This is used for example when your resource server returns a 401, but only after\n * other attempts have been made to reauthenticate (such as a token refresh).\n */\n onAuthError?: (error: Error) => void;\n\n /**\n * When using PKCE, specify the previously generated code verifier here.\n */\n codeVerifier?: string;\n};\n\n/**\n * In case you obtained an access token and/or refresh token through different\n * means, you can not specify a grant_type and simply only specify an access\n * and refresh token.\n *\n * If a refresh or tokenEndpoint are not supplied, the token will never get refreshed.\n */\ntype RefreshOnlyGrantOptions = {\n grantType: undefined;\n\n /**\n * OAuth2 client id\n */\n clientId: string;\n tokenEndpoint: string;\n\n /**\n * Callback to trigger when a new access/refresh token pair was obtained.\n */\n onTokenUpdate?: (token: OAuth2Token) => void;\n\n /**\n * If authentication fails without a chance of recovery, this gets triggered.\n *\n * This is used for example when your resource server returns a 401, but only after\n * other attempts have been made to reauthenticate (such as a token refresh).\n */\n onAuthError?: (error: Error) => void;\n};\n\nexport type OAuth2Options =\n PasswordGrantOptions | ClientCredentialsGrantOptions | AuthorizationCodeGrantOptions | RefreshOnlyGrantOptions;\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import Client from './client';
2
2
  import { State, HeadState } from './state';
3
3
  import { FollowPromiseOne, FollowPromiseMany } from './follow-promise';
4
4
  import { Link, LinkVariables } from './link';
5
- import { EventEmitter } from 'node:events';
5
+ import { EventEmitter } from 'events';
6
6
  import { GetRequestOptions, PostRequestOptions, PatchRequestOptions, PutRequestOptions, HeadRequestOptions } from './types';
7
7
  /**
8
8
  * A 'resource' represents an endpoint on a server.
@@ -5,7 +5,7 @@ const state_1 = require("./state");
5
5
  const uri_1 = require("./util/uri");
6
6
  const follow_promise_1 = require("./follow-promise");
7
7
  const link_1 = require("./link");
8
- const node_events_1 = require("node:events");
8
+ const events_1 = require("events");
9
9
  const fetch_body_helper_1 = require("./util/fetch-body-helper");
10
10
  /**
11
11
  * A 'resource' represents an endpoint on a server.
@@ -14,7 +14,7 @@ const fetch_body_helper_1 = require("./util/fetch-body-helper");
14
14
  * and events to subscribe to state changes.
15
15
  */
16
16
  // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
17
- class Resource extends node_events_1.EventEmitter {
17
+ class Resource extends events_1.EventEmitter {
18
18
  /**
19
19
  * Create the resource.
20
20
  *
@@ -1 +1 @@
1
- {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/resource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/resource.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ketting",
3
- "version": "8.4.1",
3
+ "version": "8.4.2",
4
4
  "description": "Opiniated HATEAOS / Rest client.",
5
5
  "main": "dist/main/index.js",
6
6
  "types": "dist/main/index.d.ts",
package/src/resource.ts CHANGED
@@ -3,7 +3,7 @@ import { State, headStateFactory, HeadState, isState } from './state';
3
3
  import { resolve } from './util/uri';
4
4
  import { FollowPromiseOne, FollowPromiseMany } from './follow-promise';
5
5
  import { Link, LinkNotFound, LinkVariables } from './link';
6
- import { EventEmitter } from 'node:events';
6
+ import { EventEmitter } from 'events';
7
7
  import { GetRequestOptions, PostRequestOptions, PatchRequestOptions, PutRequestOptions, HeadRequestOptions } from './types';
8
8
  import { needsJsonStringify } from './util/fetch-body-helper';
9
9