@axa-fr/oidc-client-service-worker 6.25.2-alpha949

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.
Files changed (54) hide show
  1. package/dist/OidcServiceWorker.d.ts +1 -0
  2. package/dist/OidcServiceWorker.js +559 -0
  3. package/dist/OidcServiceWorker.js.map +1 -0
  4. package/dist/OidcTrustedDomains.js +26 -0
  5. package/dist/src/OidcServiceWorker.d.ts +2 -0
  6. package/dist/src/OidcServiceWorker.d.ts.map +1 -0
  7. package/dist/src/constants.d.ts +18 -0
  8. package/dist/src/constants.d.ts.map +1 -0
  9. package/dist/src/types.d.ts +87 -0
  10. package/dist/src/types.d.ts.map +1 -0
  11. package/dist/src/utils/__tests__/codeVerifier.spec.d.ts +2 -0
  12. package/dist/src/utils/__tests__/codeVerifier.spec.d.ts.map +1 -0
  13. package/dist/src/utils/__tests__/domains.spec.d.ts +2 -0
  14. package/dist/src/utils/__tests__/domains.spec.d.ts.map +1 -0
  15. package/dist/src/utils/__tests__/serializeHeaders.spec.d.ts +2 -0
  16. package/dist/src/utils/__tests__/serializeHeaders.spec.d.ts.map +1 -0
  17. package/dist/src/utils/__tests__/strings.spec.d.ts +2 -0
  18. package/dist/src/utils/__tests__/strings.spec.d.ts.map +1 -0
  19. package/dist/src/utils/__tests__/testHelper.d.ts +57 -0
  20. package/dist/src/utils/__tests__/testHelper.d.ts.map +1 -0
  21. package/dist/src/utils/__tests__/tokens.spec.d.ts +2 -0
  22. package/dist/src/utils/__tests__/tokens.spec.d.ts.map +1 -0
  23. package/dist/src/utils/codeVerifier.d.ts +2 -0
  24. package/dist/src/utils/codeVerifier.d.ts.map +1 -0
  25. package/dist/src/utils/domains.d.ts +6 -0
  26. package/dist/src/utils/domains.d.ts.map +1 -0
  27. package/dist/src/utils/index.d.ts +6 -0
  28. package/dist/src/utils/index.d.ts.map +1 -0
  29. package/dist/src/utils/serializeHeaders.d.ts +3 -0
  30. package/dist/src/utils/serializeHeaders.d.ts.map +1 -0
  31. package/dist/src/utils/sleep.d.ts +3 -0
  32. package/dist/src/utils/sleep.d.ts.map +1 -0
  33. package/dist/src/utils/strings.d.ts +8 -0
  34. package/dist/src/utils/strings.d.ts.map +1 -0
  35. package/dist/src/utils/tokens.d.ts +22 -0
  36. package/dist/src/utils/tokens.d.ts.map +1 -0
  37. package/package.json +72 -0
  38. package/src/OidcServiceWorker.ts +423 -0
  39. package/src/OidcTrustedDomains.js +26 -0
  40. package/src/constants.ts +32 -0
  41. package/src/types.ts +101 -0
  42. package/src/utils/__tests__/codeVerifier.spec.ts +13 -0
  43. package/src/utils/__tests__/domains.spec.ts +90 -0
  44. package/src/utils/__tests__/serializeHeaders.spec.ts +12 -0
  45. package/src/utils/__tests__/strings.spec.ts +10 -0
  46. package/src/utils/__tests__/testHelper.ts +346 -0
  47. package/src/utils/__tests__/tokens.spec.ts +90 -0
  48. package/src/utils/codeVerifier.ts +4 -0
  49. package/src/utils/domains.ts +104 -0
  50. package/src/utils/index.ts +5 -0
  51. package/src/utils/serializeHeaders.ts +12 -0
  52. package/src/utils/sleep.ts +2 -0
  53. package/src/utils/strings.ts +9 -0
  54. package/src/utils/tokens.ts +207 -0
@@ -0,0 +1,12 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { serializeHeaders } from '..';
4
+
5
+ describe('serializeHeaders', () => {
6
+ it('can serialize basic header', () => {
7
+ const result = serializeHeaders(
8
+ new Headers({ 'Content-Type': 'application/json' }),
9
+ ); // Error: Argument of type 'Headers' is not assignable to parameter of type 'Headers'.(2345
10
+ expect(result).toEqual({ 'content-type': 'application/json' });
11
+ });
12
+ });
@@ -0,0 +1,10 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { countLetter } from '..';
4
+
5
+ describe('strings', () => {
6
+ it('can count instance of char', () => {
7
+ const result = countLetter('token.type.z', '.');
8
+ expect(result).toBe(2);
9
+ });
10
+ });
@@ -0,0 +1,346 @@
1
+ import { vi } from 'vitest';
2
+
3
+ import {
4
+ AccessTokenPayload,
5
+ IdTokenPayload,
6
+ Nonce,
7
+ OidcConfig,
8
+ OidcConfiguration,
9
+ OidcServerConfiguration,
10
+ Status,
11
+ Tokens,
12
+ } from '../../types';
13
+
14
+ const currentTimeUnixSeconds = (): number => {
15
+ return new Date().getTime() / 1000;
16
+ };
17
+
18
+ const createToken = (expires: number, issued_at: number): Tokens => {
19
+ return {
20
+ expiresAt: expires,
21
+ issued_at,
22
+ expires_in: 60,
23
+ id_token: null,
24
+ accessTokenPayload: null,
25
+ access_token: '',
26
+ idTokenPayload: { iss: '', exp: 0, iat: 0, nonce: null },
27
+ };
28
+ };
29
+
30
+ class TokenBuilder {
31
+ private tokens: Tokens = {
32
+ expiresAt: 0,
33
+ issued_at: 0,
34
+ expires_in: 0,
35
+ id_token: null,
36
+ accessTokenPayload: null,
37
+ access_token: '',
38
+ idTokenPayload: { iss: '', exp: 0, iat: 0, nonce: null },
39
+ };
40
+
41
+ public withExpiredToken(): TokenBuilder {
42
+ this.withExpiresIn(currentTimeUnixSeconds() - 10);
43
+ this.withIssuedAt(currentTimeUnixSeconds() - 60);
44
+ return this;
45
+ }
46
+
47
+ public WithNonExpiredToken(): TokenBuilder {
48
+ this.withExpiresAt(currentTimeUnixSeconds() + 60);
49
+ this.withExpiresIn(currentTimeUnixSeconds() + 60);
50
+ this.withIssuedAt(currentTimeUnixSeconds() - 60);
51
+ return this;
52
+ }
53
+
54
+ public withExpiresAt(expiresAt: number): TokenBuilder {
55
+ this.tokens.expiresAt = expiresAt;
56
+ return this;
57
+ }
58
+
59
+ public withIssuedAt(issued_at: number): TokenBuilder {
60
+ this.tokens.issued_at = issued_at;
61
+ return this;
62
+ }
63
+
64
+ public withExpiresIn(expires_in: number): TokenBuilder {
65
+ this.tokens.expires_in = expires_in;
66
+ return this;
67
+ }
68
+
69
+ public withIdToken(id_token: string): TokenBuilder {
70
+ this.tokens.id_token = id_token;
71
+ return this;
72
+ }
73
+
74
+ public withAccessTokenPayload(
75
+ accessTokenPayload: AccessTokenPayload,
76
+ ): TokenBuilder {
77
+ this.tokens.accessTokenPayload = accessTokenPayload;
78
+ return this;
79
+ }
80
+
81
+ public withAccessToken(access_token: string): TokenBuilder {
82
+ this.tokens.access_token = access_token;
83
+ return this;
84
+ }
85
+
86
+ public withIdTokenPayload(idTokenPayload: IdTokenPayload): TokenBuilder {
87
+ this.tokens.idTokenPayload = idTokenPayload;
88
+ return this;
89
+ }
90
+
91
+ public build(): Tokens {
92
+ return this.tokens;
93
+ }
94
+ }
95
+
96
+ class OidcConfigurationBuilder {
97
+ private oidcConfiguration: OidcConfiguration = {
98
+ token_renew_mode: 'offline',
99
+ service_worker_convert_all_requests_to_cors: true,
100
+ };
101
+
102
+ public withTokenRenewMode(
103
+ token_renew_mode: string,
104
+ ): OidcConfigurationBuilder {
105
+ this.oidcConfiguration.token_renew_mode = token_renew_mode;
106
+ return this;
107
+ }
108
+
109
+ public withServiceWorkerConvertAllRequestsToCors(
110
+ service_worker_convert_all_requests_to_cors: boolean,
111
+ ): OidcConfigurationBuilder {
112
+ this.oidcConfiguration.service_worker_convert_all_requests_to_cors =
113
+ service_worker_convert_all_requests_to_cors;
114
+ return this;
115
+ }
116
+
117
+ public build(): OidcConfiguration {
118
+ return this.oidcConfiguration;
119
+ }
120
+ }
121
+
122
+ class OidcConfigBuilder {
123
+ private oidcConfig: OidcConfig = {
124
+ configurationName: '',
125
+ tokens: null,
126
+ status: 'NOT_CONNECTED',
127
+ state: '',
128
+ codeVerifier: '',
129
+ nonce: null,
130
+ oidcServerConfiguration: null,
131
+ oidcConfiguration: undefined,
132
+ sessionState: null,
133
+ items: undefined,
134
+ hideAccessToken: true,
135
+ };
136
+
137
+ public withTestingDefault(): OidcConfigBuilder {
138
+ this.oidcConfig.configurationName = 'test';
139
+ this.oidcConfig.tokens = new TokenBuilder().WithNonExpiredToken().build();
140
+ this.oidcConfig.status = 'NOT_CONNECTED';
141
+ this.oidcConfig.state = 'state';
142
+ this.oidcConfig.codeVerifier = 'codeVerifier';
143
+ this.oidcConfig.nonce = null;
144
+ this.oidcConfig.oidcConfiguration = new OidcConfigurationBuilder().build();
145
+ this.oidcConfig.oidcServerConfiguration = new OidcServerConfigBuilder()
146
+ .withTestingDefault()
147
+ .build();
148
+ this.oidcConfig.sessionState = null;
149
+ this.oidcConfig.items = undefined;
150
+ this.oidcConfig.hideAccessToken = true;
151
+ return this;
152
+ }
153
+
154
+ public withHideAccessToken(hideAccessToken: boolean): OidcConfigBuilder {
155
+ this.oidcConfig.hideAccessToken = hideAccessToken;
156
+ return this;
157
+ }
158
+
159
+ public withConfigurationName(configurationName: string): OidcConfigBuilder {
160
+ this.oidcConfig.configurationName = configurationName;
161
+ return this;
162
+ }
163
+
164
+ public withTokens(tokens: Tokens): OidcConfigBuilder {
165
+ this.oidcConfig.tokens = tokens;
166
+ return this;
167
+ }
168
+
169
+ public withStatus(status: Status): OidcConfigBuilder {
170
+ this.oidcConfig.status = status;
171
+ return this;
172
+ }
173
+
174
+ public withState(state: string): OidcConfigBuilder {
175
+ this.oidcConfig.state = state;
176
+ return this;
177
+ }
178
+
179
+ public withCodeVerifier(codeVerifier: string): OidcConfigBuilder {
180
+ this.oidcConfig.codeVerifier = codeVerifier;
181
+ return this;
182
+ }
183
+
184
+ public withNonce(nonce: Nonce): OidcConfigBuilder {
185
+ this.oidcConfig.nonce = nonce;
186
+ return this;
187
+ }
188
+
189
+ public withOidcServerConfiguration(
190
+ oidcServerConfiguration: OidcServerConfiguration,
191
+ ): OidcConfigBuilder {
192
+ this.oidcConfig.oidcServerConfiguration = oidcServerConfiguration;
193
+ return this;
194
+ }
195
+
196
+ public build() {
197
+ return this.oidcConfig;
198
+ }
199
+ }
200
+
201
+ class OidcServerConfigBuilder {
202
+ private oidcServerConfig: OidcServerConfiguration = {
203
+ revocationEndpoint: '',
204
+ issuer: '',
205
+ authorizationEndpoint: '',
206
+ tokenEndpoint: '',
207
+ userInfoEndpoint: '',
208
+ };
209
+
210
+ public withTestingDefault(): OidcServerConfigBuilder {
211
+ this.oidcServerConfig.revocationEndpoint =
212
+ 'http://localhost:3000/revocation';
213
+ this.oidcServerConfig.issuer = 'http://localhost:3000';
214
+ this.oidcServerConfig.authorizationEndpoint =
215
+ 'http://localhost:3000/authorization';
216
+ this.oidcServerConfig.tokenEndpoint = 'http://localhost:3000/token';
217
+ this.oidcServerConfig.userInfoEndpoint = 'http://localhost:3000/userinfo';
218
+ return this;
219
+ }
220
+
221
+ public withRevocationEndpoint(
222
+ revocationEndpoint: string,
223
+ ): OidcServerConfigBuilder {
224
+ this.oidcServerConfig.revocationEndpoint = revocationEndpoint;
225
+ return this;
226
+ }
227
+
228
+ public withIssuer(issuer: string): OidcServerConfigBuilder {
229
+ this.oidcServerConfig.issuer = issuer;
230
+ return this;
231
+ }
232
+
233
+ public withAuthorizationEndpoint(
234
+ authorizationEndpoint: string,
235
+ ): OidcServerConfigBuilder {
236
+ this.oidcServerConfig.authorizationEndpoint = authorizationEndpoint;
237
+ return this;
238
+ }
239
+
240
+ public withTokenEndpoint(tokenEndpoint: string): OidcServerConfigBuilder {
241
+ this.oidcServerConfig.tokenEndpoint = tokenEndpoint;
242
+ return this;
243
+ }
244
+
245
+ public withUserInfoEndpoint(
246
+ userInfoEndpoint: string,
247
+ ): OidcServerConfigBuilder {
248
+ this.oidcServerConfig.userInfoEndpoint = userInfoEndpoint;
249
+ return this;
250
+ }
251
+
252
+ public build(): OidcServerConfiguration {
253
+ return this.oidcServerConfig;
254
+ }
255
+ }
256
+
257
+ interface TestingResponse extends Response {
258
+ bodyContent?: any;
259
+ }
260
+
261
+ class ResponseBuilder {
262
+ private response: any = {
263
+ status: 200,
264
+ body: '',
265
+ headers: {},
266
+ bodyContent: { issued_at: 343434 },
267
+ };
268
+
269
+ public withStatus(status: number): ResponseBuilder {
270
+ this.response.status = status;
271
+ return this;
272
+ }
273
+
274
+ public withBody(body: string): ResponseBuilder {
275
+ this.response.body = body;
276
+ return this;
277
+ }
278
+
279
+ public withHeaders(headers: Headers): ResponseBuilder {
280
+ this.response.headers = headers;
281
+ return this;
282
+ }
283
+
284
+ /**
285
+ * Custom property for Testing setup
286
+ * @param body
287
+ * @returns
288
+ */
289
+ public withBodyContent(body: any): ResponseBuilder {
290
+ this.response.bodyContent = body;
291
+ return this;
292
+ }
293
+
294
+ public build(): TestingResponse {
295
+ return {
296
+ ...{
297
+ status: 200,
298
+ headers: {
299
+ append: vi.fn(),
300
+ delete: vi.fn(),
301
+ forEach: vi.fn(),
302
+ get: vi.fn(),
303
+ has: vi.fn(),
304
+ set: vi.fn(),
305
+ },
306
+ ok: true,
307
+ redirected: false,
308
+ statusText: '',
309
+ type: 'basic',
310
+ url: '',
311
+ clone: function (): Response {
312
+ throw new Error('Function not implemented.');
313
+ },
314
+ body: null,
315
+ bodyUsed: false,
316
+ arrayBuffer: function (): Promise<ArrayBuffer> {
317
+ throw new Error('Function not implemented.');
318
+ },
319
+ blob: function (): Promise<Blob> {
320
+ throw new Error('Function not implemented.');
321
+ },
322
+ formData: function (): Promise<FormData> {
323
+ throw new Error('Function not implemented.');
324
+ },
325
+ json: function (): Promise<any> {
326
+ return new Promise<any>((resolve) => {
327
+ resolve(this.bodyContent);
328
+ });
329
+ },
330
+ text: function (): Promise<string> {
331
+ throw new Error('Function not implemented.');
332
+ },
333
+ },
334
+ ...this.response,
335
+ } as TestingResponse;
336
+ }
337
+ }
338
+
339
+ export {
340
+ createToken,
341
+ currentTimeUnixSeconds,
342
+ OidcConfigBuilder,
343
+ OidcServerConfigBuilder,
344
+ ResponseBuilder,
345
+ TokenBuilder,
346
+ };
@@ -0,0 +1,90 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+
3
+ import { OidcServerConfiguration } from '../../types';
4
+ import { _hideTokens, extractTokenPayload, isTokensOidcValid, isTokensValid } from '..';
5
+ import { OidcConfigBuilder, OidcServerConfigBuilder, TokenBuilder } from './testHelper';
6
+
7
+ describe('tokens', () => {
8
+ let oidcServerConfig: OidcServerConfiguration;
9
+
10
+ beforeEach(() => {
11
+ oidcServerConfig = new OidcServerConfigBuilder()
12
+ .withTestingDefault()
13
+ .build();
14
+ });
15
+
16
+ describe('isTokensValid', () => {
17
+ it('can check expired token', () => {
18
+ expect(
19
+ isTokensValid(new TokenBuilder().withExpiredToken().build()),
20
+ ).toBeFalsy();
21
+ });
22
+
23
+ it('can check non-expired token', () => {
24
+ const token = new TokenBuilder().WithNonExpiredToken().build();
25
+ expect(isTokensValid(token)).toBeTruthy();
26
+ });
27
+
28
+ it('can check null token', () => {
29
+ expect(isTokensValid(null)).toBeFalsy();
30
+ });
31
+ });
32
+
33
+ describe('extractTokenPayload', () => {
34
+ it('can extract token payload', () => {
35
+ const result = extractTokenPayload(
36
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
37
+ );
38
+ expect(result).toEqual({
39
+ sub: '1234567890',
40
+ name: 'John Doe',
41
+ iat: 1516239022,
42
+ });
43
+ });
44
+ it('returns null if undefined', () => {
45
+ expect(extractTokenPayload(undefined)).toBeNull();
46
+ });
47
+
48
+ it('returns null if invalid token', () => {
49
+ expect(extractTokenPayload('invalid token')).toBeNull();
50
+ });
51
+ });
52
+
53
+ describe('isTokensOidcValid', () => {
54
+ it('can validate valid token', () => {
55
+ const token = new TokenBuilder()
56
+ .WithNonExpiredToken()
57
+ .withIdTokenPayload({
58
+ iss: oidcServerConfig.issuer,
59
+ exp: 0,
60
+ iat: 0,
61
+ nonce: null,
62
+ })
63
+ .build();
64
+ const result = isTokensOidcValid(token, null, oidcServerConfig);
65
+ expect(result.isValid).toBeTruthy();
66
+ expect(result.reason).toBe('');
67
+ });
68
+ });
69
+
70
+ describe('_hideTokens', () => {
71
+ it.each([
72
+ { hideAccessToken: true, expectedAccessToken: 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_test' },
73
+ { hideAccessToken: false, expectedAccessToken: 'test_access_token' },
74
+ ])('accesstoken will be hide $hideAccessToken result should be $expectedAccessToken', ({ hideAccessToken, expectedAccessToken }) => {
75
+ const token = new TokenBuilder()
76
+ .withIdTokenPayload({
77
+ iss: oidcServerConfig.issuer,
78
+ exp: 0,
79
+ iat: 0,
80
+ nonce: null,
81
+ })
82
+ .WithNonExpiredToken()
83
+ .withAccessToken('test_access_token')
84
+ .build();
85
+ const oidcConfiguration = new OidcConfigBuilder().withTestingDefault().withHideAccessToken(hideAccessToken).build();
86
+ const secureTokens = _hideTokens(token, oidcConfiguration, 'test');
87
+ expect(secureTokens.access_token).toBe(expectedAccessToken);
88
+ });
89
+ });
90
+ });
@@ -0,0 +1,4 @@
1
+ export function replaceCodeVerifier(codeVerifier:string, newCodeVerifier:string):string {
2
+ const regex = /code_verifier=[A-Za-z0-9_-]+/i;
3
+ return codeVerifier.replace(regex, `code_verifier=${newCodeVerifier}`);
4
+ }
@@ -0,0 +1,104 @@
1
+ import {
2
+ acceptAnyDomainToken,
3
+ openidWellknownUrlEndWith,
4
+ scriptFilename,
5
+ } from '../constants';
6
+ import { Database, Domain, DomainDetails, OidcConfig, TrustedDomains } from '../types';
7
+
8
+ function checkDomain(domains: Domain[], endpoint: string) {
9
+ if (!endpoint) {
10
+ return;
11
+ }
12
+
13
+ const domain = domains.find((domain) => {
14
+ let testable: RegExp;
15
+
16
+ if (typeof domain === 'string') {
17
+ testable = new RegExp(`^${domain}`);
18
+ } else {
19
+ testable = domain;
20
+ }
21
+
22
+ return testable.test?.(endpoint);
23
+ });
24
+ if (!domain) {
25
+ throw new Error(
26
+ 'Domain ' +
27
+ endpoint +
28
+ ' is not trusted, please add domain in ' +
29
+ scriptFilename,
30
+ );
31
+ }
32
+ }
33
+
34
+ export const getDomains = (trustedDomain: Domain[] | DomainDetails, type: 'oidc' | 'accessToken') => {
35
+ if (Array.isArray(trustedDomain)) {
36
+ return trustedDomain;
37
+ }
38
+
39
+ return trustedDomain[`${type}Domains`] ?? trustedDomain.domains ?? [];
40
+ };
41
+
42
+ const getCurrentDatabaseDomain = (
43
+ database: Database,
44
+ url: string,
45
+ trustedDomains: TrustedDomains,
46
+ ) => {
47
+ if (url.endsWith(openidWellknownUrlEndWith)) {
48
+ return null;
49
+ }
50
+ for (const [key, currentDatabase] of Object.entries<OidcConfig>(database)) {
51
+ const oidcServerConfiguration = currentDatabase.oidcServerConfiguration;
52
+
53
+ if (!oidcServerConfiguration) {
54
+ continue;
55
+ }
56
+
57
+ if (
58
+ oidcServerConfiguration.tokenEndpoint &&
59
+ url === oidcServerConfiguration.tokenEndpoint
60
+ ) {
61
+ continue;
62
+ }
63
+ if (
64
+ oidcServerConfiguration.revocationEndpoint &&
65
+ url === oidcServerConfiguration.revocationEndpoint
66
+ ) {
67
+ continue;
68
+ }
69
+ const trustedDomain = trustedDomains == null ? [] : trustedDomains[key];
70
+
71
+ const domains = getDomains(trustedDomain, 'accessToken');
72
+ const domainsToSendTokens = oidcServerConfiguration.userInfoEndpoint
73
+ ? [oidcServerConfiguration.userInfoEndpoint, ...domains]
74
+ : [...domains];
75
+
76
+ let hasToSendToken = false;
77
+ if (domainsToSendTokens.find((f) => f === acceptAnyDomainToken)) {
78
+ hasToSendToken = true;
79
+ } else {
80
+ for (let i = 0; i < domainsToSendTokens.length; i++) {
81
+ let domain = domainsToSendTokens[i];
82
+
83
+ if (typeof domain === 'string') {
84
+ domain = new RegExp(`^${domain}`);
85
+ }
86
+
87
+ if (domain.test?.(url)) {
88
+ hasToSendToken = true;
89
+ break;
90
+ }
91
+ }
92
+ }
93
+
94
+ if (hasToSendToken) {
95
+ if (!currentDatabase.tokens) {
96
+ return null;
97
+ }
98
+ return currentDatabase;
99
+ }
100
+ }
101
+ return null;
102
+ };
103
+
104
+ export { checkDomain, getCurrentDatabaseDomain };
@@ -0,0 +1,5 @@
1
+ export * from './domains';
2
+ export * from './serializeHeaders';
3
+ export * from './sleep';
4
+ export * from './strings';
5
+ export * from './tokens';
@@ -0,0 +1,12 @@
1
+ import { FetchHeaders } from '../types';
2
+
3
+ function serializeHeaders(headers: Headers) {
4
+ const headersObj: Record<string, string> = {};
5
+ for (const key of (headers as FetchHeaders).keys()) {
6
+ if (headers.has(key)) {
7
+ headersObj[key] = headers.get(key) as string;
8
+ }
9
+ }
10
+ return headersObj;
11
+ }
12
+ export { serializeHeaders };
@@ -0,0 +1,2 @@
1
+ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
2
+ export { sleep };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Count occurances of letter in string
3
+ * @param str
4
+ * @param find
5
+ * @returns
6
+ */
7
+ export function countLetter(str: string, find: string) {
8
+ return str.split(find).length - 1;
9
+ }