From f834261a401dff9a8c2043aa3a81c38176c4f8dd Mon Sep 17 00:00:00 2001 From: Evert Pot Date: Wed, 6 Nov 2019 16:09:04 -0500 Subject: [PATCH] Add an options hydrator --- package-lock.json | 6 ++-- package.json | 2 +- src/ketting.ts | 18 ++++++++++++ src/utils/fetch-helper.ts | 62 +++++++++++++++++++++++++++++++++------ 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 940b80d8..0a0076d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2103,9 +2103,9 @@ "dev": true }, "fetch-mw-oauth2": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/fetch-mw-oauth2/-/fetch-mw-oauth2-0.3.5.tgz", - "integrity": "sha512-ctlGARDDUY6fsUQFjAfGIRgTRtZGKmFSmnUQAK4xYdwWgXzKe6iQmBAUng0vE3pe8pu+Es84Li5oc1TRwpXdOg==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/fetch-mw-oauth2/-/fetch-mw-oauth2-0.4.0.tgz", + "integrity": "sha512-qn38slnWrMueICoad3i88S4SADDhSEZdsnT3E79wlPYnZqbmXf8bEGOwi3Jya1eR8d9r567JU1DSAQyLx7v/jQ==" }, "figgy-pudding": { "version": "3.5.1", diff --git a/package.json b/package.json index 0268e101..d2d68ab0 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ ], "types": "dist/index.d.ts", "dependencies": { - "fetch-mw-oauth2": "^0.3.5", + "fetch-mw-oauth2": "^0.4.0", "http-link-header": "^1.0.2", "node-fetch": "^2.6.0", "querystring-browser": "^1.0.4", diff --git a/src/ketting.ts b/src/ketting.ts index 729c1020..5f39d45c 100644 --- a/src/ketting.ts +++ b/src/ketting.ts @@ -105,6 +105,24 @@ export default class Ketting { } + /** + * Returns a list of all Ketting options. + * + * The primary purpose of this is for hydrating all options in for example LocalStorage. + * + * The options will not be an exact copy of what was passed, but instead will + * contain properties like refreshToken and accessToken, allowing authentication information + * to be cached. + * + * NOTE that this function is experimental and only handles top-level settings, and not for + * specific domains. + */ + getOptions(): Promise { + + return this.fetchHelper.getOptions(); + + } + /** * This function does an arbitrary request using the fetch API. * diff --git a/src/utils/fetch-helper.ts b/src/utils/fetch-helper.ts index 2fe34f39..31c4c9e4 100644 --- a/src/utils/fetch-helper.ts +++ b/src/utils/fetch-helper.ts @@ -27,7 +27,7 @@ export default class FetchHelper { private onBeforeRequest: beforeRequestCallback | null; private onAfterRequest: afterRequestCallback | null; - constructor(options: Partial, onBeforeRequest: beforeRequestCallback | null = null, onAfterRequest: afterRequestCallback | null = null) { + constructor(options: KettingInit, onBeforeRequest: beforeRequestCallback | null = null, onAfterRequest: afterRequestCallback | null = null) { this.options = { fetchInit: options.fetchInit || {}, auth: options.auth, @@ -69,6 +69,40 @@ export default class FetchHelper { } + /** + * Returns a list of all Ketting options. + * + * The primary purpose of this is for hydrating all options in for example LocalStorage. + * + * The options will not be an exact copy of what was passed, but instead will + * contain properties like refreshToken and accessToken, allowing authentication information + * to be cached. + * + * NOTE that this function is experimental and only handles top-level settings, and not for + * specific domains. + */ + async getOptions(): Promise { + + const options = this.getDomainOptions('*'); + let auth; + + if (options.auth && options.auth.type === 'oauth2') { + const oauth2 = this.getOAuth2Bucket(options); + auth = { + type: 'oauth2' as 'oauth2', + ...await oauth2.getOptions(), + }; + } else { + auth = options.auth; + } + + return { + fetchInit: options.fetchInit, + auth, + }; + + } + getDomainOptions(uri: string): DomainOptions { if (!this.options.match) { @@ -117,7 +151,6 @@ export default class FetchHelper { const options = this.getDomainOptions(request.url); const authOptions = options.auth; - const authBucket = options.authBucket; if (!authOptions) { return this.doFetch(request); @@ -131,14 +164,8 @@ export default class FetchHelper { request.headers.set('Authorization', 'Bearer ' + authOptions.token); return this.doFetch(request); case 'oauth2' : - if (!this.oAuth2Buckets.has(authBucket)) { - this.oAuth2Buckets.set( - authBucket, - new OAuth2(authOptions) - ); - } if (this.onBeforeRequest) { this.onBeforeRequest(request); } - const response = await this.oAuth2Buckets.get(authBucket)!.fetch(request); + const response = await this.getOAuth2Bucket(options).fetch(request); if (this.onAfterRequest) { this.onAfterRequest(request, response); } return response; } @@ -146,6 +173,23 @@ export default class FetchHelper { } + private getOAuth2Bucket(options: DomainOptions): OAuth2 { + + const authOptions = options.auth; + if (!authOptions || authOptions.type !== 'oauth2') { + throw new Error('getOAuth2Bucket can only be called for oauth2 credentials'); + } + + if (!this.oAuth2Buckets.has(options.authBucket)) { + this.oAuth2Buckets.set( + options.authBucket, + new OAuth2(authOptions) + ); + } + return this.oAuth2Buckets.get(options.authBucket)!; + + } + /** * This function is the last mile before the actual fetch request is ran */