@mapcreator/api 0.0.0-saga.6 → 0.0.0-saga.8

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.

Potentially problematic release.


This version of @mapcreator/api might be problematic. Click here for more details.

Files changed (93) hide show
  1. package/cjs/api/choropleth.d.ts +97 -8
  2. package/cjs/api/choropleth.d.ts.map +1 -1
  3. package/cjs/api/choropleth.js +33 -15
  4. package/cjs/api/choropleth.js.map +1 -1
  5. package/cjs/api/font.d.ts.map +1 -1
  6. package/cjs/api/font.js.map +1 -1
  7. package/cjs/api/geocode.d.ts +10 -0
  8. package/cjs/api/geocode.d.ts.map +1 -0
  9. package/cjs/api/geocode.js +9 -0
  10. package/cjs/api/geocode.js.map +1 -0
  11. package/cjs/api/insetMap.d.ts.map +1 -1
  12. package/cjs/api/insetMap.js +3 -5
  13. package/cjs/api/insetMap.js.map +1 -1
  14. package/cjs/api/jobRevision.d.ts +1 -1
  15. package/cjs/api/jobRevision.d.ts.map +1 -1
  16. package/cjs/api/jobRevision.js +10 -16
  17. package/cjs/api/jobRevision.js.map +1 -1
  18. package/cjs/api/mapstyleSet.d.ts +2 -1
  19. package/cjs/api/mapstyleSet.d.ts.map +1 -1
  20. package/cjs/api/mapstyleSet.js +9 -0
  21. package/cjs/api/mapstyleSet.js.map +1 -1
  22. package/cjs/api/organisation.d.ts +2 -2
  23. package/cjs/api/organisation.d.ts.map +1 -1
  24. package/cjs/api/organisation.js +4 -4
  25. package/cjs/api/organisation.js.map +1 -1
  26. package/cjs/api/user.d.ts +2 -1
  27. package/cjs/api/user.d.ts.map +1 -1
  28. package/cjs/api/user.js +2 -3
  29. package/cjs/api/user.js.map +1 -1
  30. package/cjs/index.d.ts +1 -0
  31. package/cjs/index.d.ts.map +1 -1
  32. package/cjs/index.js +1 -0
  33. package/cjs/index.js.map +1 -1
  34. package/cjs/oauth.d.ts +10 -6
  35. package/cjs/oauth.d.ts.map +1 -1
  36. package/cjs/oauth.js +30 -199
  37. package/cjs/oauth.js.map +1 -1
  38. package/cjs/utils.d.ts.map +1 -1
  39. package/cjs/utils.js +3 -3
  40. package/cjs/utils.js.map +1 -1
  41. package/esm/api/choropleth.d.ts +97 -8
  42. package/esm/api/choropleth.d.ts.map +1 -1
  43. package/esm/api/choropleth.js +28 -13
  44. package/esm/api/choropleth.js.map +1 -1
  45. package/esm/api/font.d.ts.map +1 -1
  46. package/esm/api/font.js +1 -1
  47. package/esm/api/font.js.map +1 -1
  48. package/esm/api/geocode.d.ts +10 -0
  49. package/esm/api/geocode.d.ts.map +1 -0
  50. package/esm/api/geocode.js +6 -0
  51. package/esm/api/geocode.js.map +1 -0
  52. package/esm/api/insetMap.d.ts.map +1 -1
  53. package/esm/api/insetMap.js +4 -6
  54. package/esm/api/insetMap.js.map +1 -1
  55. package/esm/api/jobRevision.d.ts +1 -1
  56. package/esm/api/jobRevision.d.ts.map +1 -1
  57. package/esm/api/jobRevision.js +10 -16
  58. package/esm/api/jobRevision.js.map +1 -1
  59. package/esm/api/mapstyleSet.d.ts +2 -1
  60. package/esm/api/mapstyleSet.d.ts.map +1 -1
  61. package/esm/api/mapstyleSet.js +8 -0
  62. package/esm/api/mapstyleSet.js.map +1 -1
  63. package/esm/api/organisation.d.ts +2 -2
  64. package/esm/api/organisation.d.ts.map +1 -1
  65. package/esm/api/organisation.js +4 -4
  66. package/esm/api/organisation.js.map +1 -1
  67. package/esm/api/user.d.ts +2 -1
  68. package/esm/api/user.d.ts.map +1 -1
  69. package/esm/api/user.js +2 -3
  70. package/esm/api/user.js.map +1 -1
  71. package/esm/index.d.ts +1 -0
  72. package/esm/index.d.ts.map +1 -1
  73. package/esm/index.js +1 -0
  74. package/esm/index.js.map +1 -1
  75. package/esm/oauth.d.ts +10 -6
  76. package/esm/oauth.d.ts.map +1 -1
  77. package/esm/oauth.js +29 -198
  78. package/esm/oauth.js.map +1 -1
  79. package/esm/utils.d.ts.map +1 -1
  80. package/esm/utils.js +4 -4
  81. package/esm/utils.js.map +1 -1
  82. package/package.json +1 -1
  83. package/src/api/choropleth.ts +177 -46
  84. package/src/api/font.ts +9 -1
  85. package/src/api/geocode.ts +17 -0
  86. package/src/api/insetMap.ts +4 -5
  87. package/src/api/jobRevision.ts +9 -7
  88. package/src/api/mapstyleSet.ts +23 -1
  89. package/src/api/organisation.ts +5 -4
  90. package/src/api/user.ts +3 -3
  91. package/src/index.ts +1 -0
  92. package/src/oauth.ts +31 -255
  93. package/src/utils.ts +4 -4
package/src/api/font.ts CHANGED
@@ -1,4 +1,12 @@
1
- import { type ApiCommonData, type ApiError, type ApiSuccess, type Flatten, type Revivers, getSearchParams, request } from '../utils.js';
1
+ import {
2
+ type ApiCommonData,
3
+ type ApiError,
4
+ type ApiSuccess,
5
+ type Flatten,
6
+ type Revivers,
7
+ getSearchParams,
8
+ request,
9
+ } from '../utils.js';
2
10
 
3
11
  export type Font = {
4
12
  id: number;
@@ -0,0 +1,17 @@
1
+ import { type ApiError, type ApiSuccess, request } from '../utils.js';
2
+
3
+ export type GeocodeResult = {
4
+ index: number;
5
+ lat: number | undefined;
6
+ lng: number | undefined;
7
+ };
8
+
9
+ export async function bulkGeocode(addresses: Array<{ index: number; address: string }>): Promise<GeocodeResult[]> {
10
+ const pathname = `/v1/geocode`;
11
+
12
+ type GeocodeResultArray = {
13
+ data: GeocodeResult[];
14
+ } & Omit<ApiSuccess, 'data'> | ApiError;
15
+
16
+ return request<GeocodeResultArray, GeocodeResult>(pathname, { items: addresses });
17
+ }
@@ -1,4 +1,4 @@
1
- import { apiHost, authenticate, token } from '../oauth.js';
1
+ import { apiHost, authenticate, getAuthorizationHeaders, token } from '../oauth.js';
2
2
  import {
3
3
  APIError,
4
4
  type ApiCommonData,
@@ -63,10 +63,9 @@ export async function getInsetMap(insetMapId: number): Promise<InsetMap> {
63
63
 
64
64
  export async function getInsetMapTopoJson<TopoJSON>(insetMapId: number): Promise<TopoJSON> {
65
65
  const href = `${apiHost}/v1/inset-maps/${insetMapId}/json`;
66
- const headers = { Accept: 'application/json', ...(token ? { Authorization: token.toString() } : null) };
67
- const response = await fetch(href, { headers }).catch((error: Error) => {
68
- throw new NetworkError(error?.message ?? error);
69
- });
66
+ const headers = getAuthorizationHeaders('GET');
67
+ const response = await fetch(href, { headers, ...!token && { credentials: 'include' } })
68
+ .catch((error: Error) => { throw new NetworkError(error?.message ?? error) });
70
69
 
71
70
  if (response.ok) {
72
71
  return response.json().catch(() => {
@@ -1,5 +1,5 @@
1
+ import { apiHost, authenticate, getAuthorizationHeaders, token } from '../oauth.js';
1
2
  import { type ApiLayerData, type Layer, layerRevivers } from './layer.js';
2
- import { apiHost, authenticate, token } from '../oauth.js';
3
3
  import type { ApiMapstyleSetData } from './mapstyleSet.js';
4
4
  import type { ApiLanguageData } from './language.js';
5
5
  import {
@@ -70,6 +70,7 @@ export async function createJobRevision(
70
70
  layers: number[],
71
71
  output: FileFormat,
72
72
  jobObject: Record<string, unknown>,
73
+ skipValidation?: boolean
73
74
  ): Promise<JobRevision> {
74
75
  const pathname = `/v1/jobs/${jobId}/revisions`;
75
76
  const path = `${pathname}?${deletedNoneParam}`;
@@ -79,6 +80,7 @@ export async function createJobRevision(
79
80
  object: JSON.stringify(jobObject),
80
81
  output,
81
82
  layers,
83
+ ...skipValidation && { skip_validation: skipValidation },
82
84
  };
83
85
  const options = { revivers: jobRevisionRevivers };
84
86
 
@@ -221,10 +223,9 @@ export async function getJobRevisionOutput(jobId: number): Promise<JobRevisionOu
221
223
  await createJobRevisionBuild(jobId);
222
224
 
223
225
  const href = `${apiHost}/v1/jobs/${jobId}/revisions/${lastJobRevision}/result/output`;
224
- const headers = { ...(token ? { Authorization: token.toString() } : null) };
225
- const response = await fetch(href, { headers }).catch((error: Error) => {
226
- throw new NetworkError(error?.message ?? error);
227
- });
226
+ const headers = getAuthorizationHeaders('GET');
227
+ const response = await fetch(href, { headers, ...!token && { credentials: 'include' } })
228
+ .catch((error: Error) => { throw new NetworkError(error?.message ?? error) });
228
229
 
229
230
  if (response.ok) {
230
231
  const blob = await response.blob().catch(() => {
@@ -271,9 +272,10 @@ export async function getJobRevisionOutput(jobId: number): Promise<JobRevisionOu
271
272
  }
272
273
  }
273
274
 
274
- async function createJobRevisionBuild(jobId: number): Promise<string> {
275
+ async function createJobRevisionBuild(jobId: number, skipValidation?: boolean): Promise<string> {
275
276
  const pathname = `/v1/jobs/${jobId}/revisions/${lastJobRevision}/build`;
276
277
  const path = `${pathname}?${deletedNoneParam}`;
278
+ const body = skipValidation ? { skip_validation: skipValidation } : null;
277
279
 
278
- return request<ApiCommon, string>(path, null, null, { method: 'POST' });
280
+ return request<ApiCommon, string>(path, body, null, { method: 'POST' });
279
281
  }
@@ -1,4 +1,13 @@
1
- import type { ApiCommonData, ApiError, ApiSuccess, Flatten, Revivers } from '../utils.js';
1
+ import {
2
+ type ApiCommonData,
3
+ type ApiError,
4
+ type ApiSuccess,
5
+ type Flatten,
6
+ type Revivers,
7
+ defaultListHeader,
8
+ getSearchParams,
9
+ request,
10
+ } from '../utils.js';
2
11
 
3
12
  export type MapstyleSet = {
4
13
  id: number;
@@ -46,3 +55,16 @@ export const mapstyleSetRevivers: Revivers<ApiMapstyleSet, MapstyleSet> = {
46
55
  order: undefined,
47
56
  custom_settings: undefined,
48
57
  };
58
+
59
+ export async function listMapstyleSets(jobTypeId?: number): Promise<MapstyleSet[]> {
60
+ const pathname = `/v1/mapstyles/sets`;
61
+ const query = jobTypeId !== undefined ? getSearchParams({ search: { job_type_id: jobTypeId } }) : null;
62
+ const path = query ? `${pathname}?${query}` : pathname;
63
+ const options = { revivers: mapstyleSetRevivers };
64
+
65
+ type ApiMapstyleSetArray = {
66
+ data: ApiMapstyleSetData[];
67
+ } & Omit<ApiSuccess, 'data'> | ApiError;
68
+
69
+ return request<ApiMapstyleSetArray, MapstyleSet>(path, null, defaultListHeader, options);
70
+ }
@@ -63,8 +63,10 @@ export const organisationRevivers: Revivers<ApiOrganisation, Organisation> = {
63
63
  exportTemplates: (data: ApiOrganisationData) => data.template_settings ?? '{}',
64
64
  };
65
65
 
66
- export async function getOrganisation(): Promise<Organisation> {
67
- const path = `/v1/organisations/${myOrganisations}`;
66
+ export async function getOrganisation(
67
+ organisationId: number | typeof myOrganisations = myOrganisations,
68
+ ): Promise<Organisation> {
69
+ const path = `/v1/organisations/${organisationId}`;
68
70
  const options = { revivers: organisationRevivers };
69
71
 
70
72
  return request<ApiOrganisation, Organisation>(path, null, null, options);
@@ -73,11 +75,10 @@ export async function getOrganisation(): Promise<Organisation> {
73
75
  export async function listOrganisationJobs(
74
76
  organisationId: number | typeof myOrganisations,
75
77
  title: string,
76
- shared: boolean,
77
78
  page: number,
78
79
  options?: Record<string, unknown>,
79
80
  ): Promise<JobSearchResult> {
80
- const search = { ...options, ...{ hidePrivate: true, shared } };
81
+ const search = { ...options };
81
82
 
82
83
  return listJobs(`/v1/organisations/${organisationId}/jobs`, title, page, search);
83
84
  }
package/src/api/user.ts CHANGED
@@ -40,6 +40,7 @@ type UnitType = 'metric' | 'imperial' | null;
40
40
 
41
41
  export type User = {
42
42
  id: number;
43
+ organisationId: number;
43
44
  languageCode: string;
44
45
  interfaceLanguage: string;
45
46
  videoNotifications: boolean;
@@ -121,7 +122,6 @@ export type ApiJobFolder = {
121
122
  export type ApiJobFolderData = Flatten<Exclude<ApiJobFolder, ApiError>['data']>;
122
123
 
123
124
  export const userRevivers: Revivers<ApiUser, User> = {
124
- organisation_id: undefined,
125
125
  hide_messages: undefined,
126
126
  phone: undefined,
127
127
  profession: undefined,
@@ -159,8 +159,8 @@ type UpdateUserParams = {
159
159
  email?: string;
160
160
  };
161
161
 
162
- export async function getUser(): Promise<User> {
163
- const path = `/v1/users/${myUser}`;
162
+ export async function getUser(userId: number | typeof myUser = myUser): Promise<User> {
163
+ const path = `/v1/users/${userId}`;
164
164
  const options = { revivers: userRevivers };
165
165
 
166
166
  return request<ApiUser, User>(path, null, null, options);
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ export * from './api/dimensionSet.js';
5
5
  export * from './api/feature.js';
6
6
  export * from './api/font.js';
7
7
  export * from './api/fontFamily.js';
8
+ export * from './api/geocode.js';
8
9
  export * from './api/highlight.js';
9
10
  export * from './api/insetMap.js';
10
11
  export * from './api/job.js';
package/src/oauth.ts CHANGED
@@ -8,27 +8,19 @@ export let token: {
8
8
  toString: () => string;
9
9
  } | null = null;
10
10
 
11
- let apiClientId = '';
12
11
  let callbackUrl = '';
13
- let oauthScopes = ['*'];
14
12
 
15
- const anchorParams = ['access_token', 'token_type', 'expires_in', 'state'];
16
-
17
- const storagePrefix = '_m4n_';
18
- const statePrefix = 'oauth_state_';
19
- const storageName = 'api_token';
20
-
21
- const dummyTokenExpires = new Date('2100-01-01T01:00:00');
13
+ /**
14
+ * Cleanup of previously used data. The code part can be removed in a while.
15
+ */
16
+ for (let i = 0; i < window.localStorage.length; ++i) {
17
+ const key = window.localStorage.key(i);
22
18
 
23
- interface AnchorToken {
24
- access_token: string;
25
- token_type: string;
26
- expires_in: string;
27
- state: string;
19
+ if (key?.startsWith('_m4n_')) {
20
+ window.localStorage.removeItem(key);
21
+ }
28
22
  }
29
23
 
30
- const titleCase = (str: unknown): string => String(str).toLowerCase().replace(/\b\w/g, c => c.toUpperCase());
31
-
32
24
  /**
33
25
  * Setup internal structures to use dummy authentication flow
34
26
  *
@@ -40,9 +32,9 @@ export function initDummyFlow(apiUrl: string, oauthToken: string): void {
40
32
 
41
33
  apiHost = apiUrl.replace(/\/+$/, '');
42
34
  token = {
43
- type: titleCase(parts[0]),
35
+ type: parts[0].toLowerCase().replace(/\b\w/g, c => c.toUpperCase()),
44
36
  token: parts[1],
45
- expires: dummyTokenExpires,
37
+ expires: new Date('2100-01-01T01:00:00'),
46
38
 
47
39
  toString(): string {
48
40
  return `${this.type} ${this.token}`;
@@ -54,261 +46,45 @@ export function initDummyFlow(apiUrl: string, oauthToken: string): void {
54
46
  * Setup internal structures to use implicit authentication flow
55
47
  *
56
48
  * @param {string} apiUrl - Full API URL
57
- * @param {string} clientId - OAuth client id
58
49
  * @param {string} [redirectUrl] - Callback URL
59
- * @param {string[]} [scopes] - A list of required scopes
60
50
  */
61
- export function initImplicitFlow(apiUrl: string, clientId: string, redirectUrl = '', scopes = ['*']): void {
51
+ export function initImplicitFlow(apiUrl: string, redirectUrl = ''): void {
62
52
  apiHost = apiUrl.replace(/\/+$/, '');
63
53
 
64
- apiClientId = String(clientId);
65
54
  callbackUrl = String(redirectUrl || window.location.href.split('#')[0]);
66
- oauthScopes = scopes;
67
-
68
- {
69
- const key = `${storagePrefix}${storageName}`;
70
- const data = window.localStorage.getItem(key);
71
-
72
- if (data) {
73
- try {
74
- const obj = JSON.parse(data) as { type?: unknown; token?: unknown; expires?: unknown };
75
-
76
- if (
77
- typeof obj.type === 'string' &&
78
- typeof obj.token === 'string' &&
79
- typeof obj.expires === 'string' &&
80
- new Date(obj.expires) > new Date()
81
- ) {
82
- token = {
83
- type: titleCase(obj.type),
84
- token: obj.token,
85
- expires: new Date(obj.expires),
86
-
87
- toString(): string {
88
- return `${this.type} ${this.token}`;
89
- },
90
- };
91
- } else {
92
- window.localStorage.removeItem(key);
93
- }
94
- } catch (e) {
95
- /* */
96
- }
97
- }
98
- }
99
-
100
- {
101
- const obj = getAnchorToken();
102
-
103
- if (isAnchorToken(obj)) {
104
- // We'll not go there if anchor contains error and/or message
105
- // This means that anchor parameters will be preserved for the next processing
106
- cleanAnchorParams();
107
-
108
- const expires = new Date(Date.now() + Number(obj.expires_in) * 1000);
109
-
110
- if (isValidState(obj.state) && expires > new Date()) {
111
- token = {
112
- type: titleCase(obj.token_type),
113
- token: obj.access_token,
114
- expires,
115
-
116
- toString(): string {
117
- return `${this.type} ${this.token}`;
118
- },
119
- };
120
-
121
- const key = `${storagePrefix}${storageName}`;
122
- const data = { type: token.type, token: token.token, expires: expires.toUTCString() };
123
-
124
- window.localStorage.setItem(key, JSON.stringify(data));
125
- } else {
126
- // TODO: add some logic to handle this
127
- // throw Error('Invalid state in url');
128
- }
129
- }
130
- }
131
55
 
132
- if (authenticated()) {
133
- const href = sessionStorage.getItem('redirect-url');
56
+ const href = sessionStorage.getItem('redirect-url');
134
57
 
135
- if (href) {
136
- sessionStorage.removeItem('redirect-url');
137
- window.history.replaceState(null, document.title, href);
138
- }
58
+ if (href) {
59
+ sessionStorage.removeItem('redirect-url');
60
+ window.history.replaceState(null, document.title, href);
139
61
  }
140
62
  }
141
63
 
142
- export async function authenticate(): Promise<string> | never {
64
+ export async function authenticate(): Promise<never> {
143
65
  return new Promise(() => {
144
- if (anchorContainsError()) {
145
- console.error(getError());
146
- cleanAnchorParams();
147
- }
148
-
149
- forget();
150
-
151
66
  sessionStorage.setItem('redirect-url', window.location.href);
152
- window.location.assign(buildRedirectUrl());
67
+ window.location.assign(`${apiHost}/login?${new URLSearchParams({ redirect_uri: callbackUrl })}`);
153
68
  });
154
69
  }
155
70
 
156
- export function authenticated(): boolean {
157
- return token != null && token.expires > new Date() && (
158
- token.expires.valueOf() === dummyTokenExpires.valueOf() ||
159
- !!window.localStorage.getItem(`${storagePrefix}${storageName}`)
160
- );
161
- }
162
-
163
- export async function logout(): Promise<void> {
164
- if (token) {
165
- await fetch(`${apiHost}/oauth/logout`, {
166
- method: 'POST',
167
- headers: {
168
- Accept: 'application/json',
169
- Authorization: token.toString(),
170
- },
171
- });
172
- }
173
-
174
- forget();
175
- }
71
+ // eslint-disable-next-line @typescript-eslint/naming-convention
72
+ type AuthHeaders = { Authorization: string } | { 'X-XSRF-Token': string } | undefined;
176
73
 
177
- function forget(): void {
178
- for (let i = 0; i < window.localStorage.length; ++i) {
179
- const key = window.localStorage.key(i);
180
-
181
- if (key?.startsWith(storagePrefix)) {
182
- window.localStorage.removeItem(key);
183
- }
184
- }
74
+ export function getAuthorizationHeaders(method: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'): AuthHeaders {
75
+ const cookie = !token && method !== 'GET' && method !== 'HEAD'
76
+ ? document.cookie.split(/ *; */).find(pair => pair.startsWith('XSRF-TOKEN'))?.split('=')[1]
77
+ : undefined;
185
78
 
186
- token = null;
79
+ return token
80
+ ? { Authorization: token.toString() }
81
+ : cookie
82
+ ? { 'X-XSRF-Token': decodeURIComponent(cookie) }
83
+ : undefined;
187
84
  }
188
85
 
189
- function buildRedirectUrl(): string {
190
- const queryParams = new URLSearchParams({
191
- client_id: apiClientId,
192
- redirect_uri: callbackUrl,
193
- response_type: 'token',
194
- scope: oauthScopes.join(' '),
195
- state: generateState(),
86
+ export async function logout(): Promise<never> {
87
+ return new Promise(() => {
88
+ window.location.assign(`${apiHost}/logout?${new URLSearchParams({ redirect_uri: callbackUrl })}`);
196
89
  });
197
-
198
- return `${apiHost}/oauth/authorize?${queryParams}`;
199
- }
200
-
201
- function getAnchorQuery(): string {
202
- return window.location.hash.replace(/^#\/?/, '');
203
- }
204
-
205
- function getAnchorParams(): Record<string, unknown> {
206
- const query = getAnchorQuery();
207
- // eslint-disable-next-line @stylistic/padding-line-between-statements,@typescript-eslint/no-unsafe-return
208
- return Object.fromEntries(query.split('&').map(pair => pair.split('=').map(decodeURIComponent)));
209
- }
210
-
211
- function getAnchorToken(): Partial<AnchorToken> {
212
- const params = getAnchorParams();
213
-
214
- return Object.fromEntries(Object.entries(params).filter(([key]) => anchorParams.includes(key)));
215
- }
216
-
217
- function isAnchorToken(anchorToken: Partial<AnchorToken>): anchorToken is AnchorToken {
218
- const queryKeys = Object.keys(anchorToken);
219
-
220
- return anchorParams.every(key => queryKeys.includes(key));
221
- }
222
-
223
- function cleanAnchorParams(): void {
224
- const query = window.location.hash.replace(/^#\/?/, '');
225
- const targets = [...anchorParams, 'error', 'message'];
226
- const newHash = query
227
- .split('&')
228
- .filter(pair => !targets.includes(decodeURIComponent(pair.split('=')[0])))
229
- .join('&');
230
-
231
- if (newHash) {
232
- window.location.hash = newHash;
233
- } else {
234
- const { origin, pathname, search } = window.location;
235
-
236
- window.history.replaceState(null, document.title, `${origin}${pathname}${search}`);
237
- }
238
- }
239
-
240
- function isValidState(state: string): boolean {
241
- const key = `${storagePrefix}${statePrefix}${state}`;
242
- const found = window.localStorage.getItem(key) != null;
243
-
244
- if (found) {
245
- window.localStorage.removeItem(key);
246
- }
247
-
248
- return found;
249
- }
250
-
251
- function anchorContainsError(): boolean {
252
- return 'error' in getAnchorParams();
253
- }
254
-
255
- function generateState(): string {
256
- // @ts-expect-error TS2365
257
- // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
258
- const state = (([1e7] + -1e3 + -4e3 + -8e3 + -1e11) as string).replace(
259
- /[018]/g, // @ts-expect-error TS2362
260
- c => (c ^ ((Math.random() * 256) & (0x0f >>> (c >>> 2)))).toString(16),
261
- );
262
- const key = `${storagePrefix}${statePrefix}${state}`;
263
-
264
- window.localStorage.setItem(key, `${Date.now()}`);
265
-
266
- return state;
267
- }
268
-
269
- class OAuthError extends Error {
270
- error: string;
271
-
272
- constructor(message: string, error: unknown) {
273
- super(message);
274
-
275
- this.error = String(error);
276
- }
277
-
278
- toString(): string {
279
- let error = this.error;
280
-
281
- if (error.includes('_')) {
282
- error = error.replace('_', ' ').replace(/^./, c => c.toUpperCase());
283
- }
284
-
285
- return this.message ? `${error}: ${this.message}` : error;
286
- }
287
- }
288
-
289
- function getError(): OAuthError {
290
- const params = getAnchorParams();
291
-
292
- return params.message
293
- ? new OAuthError(params.message as string, params.error)
294
- : new OAuthError(titleCase(params.error), params.error);
295
- }
296
-
297
- /**
298
- * Our goal is to support even obsolete platforms (ES2017+ / Node.js 8.10+).
299
- * This is a small polyfill for possibly missing method used in our codebase.
300
- */
301
- if (!Object.fromEntries) { // eslint-disable-next-line arrow-body-style
302
- Object.fromEntries = <T = never>(entries: Iterable<readonly [string | number, T]>): { [k: string]: T } => {
303
- return Array.from(entries).reduce<{ [k: string]: T }>(
304
- (object, entry) => {
305
- if (!Array.isArray(entry)) {
306
- throw new TypeError(`Iterator value ${entry as unknown as string} is not an entry object.`);
307
- }
308
- object[`${entry[0]}`] = entry[1];
309
-
310
- return object;
311
- }, {}
312
- );
313
- };
314
90
  }
package/src/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import { apiHost, authenticate, getAuthorizationHeaders, token } from './oauth.js';
1
2
  import type { CamelCasedProperties, SnakeCasedProperties } from 'type-fest';
2
- import { apiHost, authenticate, token } from './oauth.js';
3
3
 
4
4
  export type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;
5
5
 
@@ -233,7 +233,6 @@ function getRequestInit<I extends ApiCommon, O extends Record<string, unknown>>(
233
233
  extraHeaders?: Record<string, string> | null,
234
234
  extraOptions?: ExtraOptions<I, O>,
235
235
  ): RequestInit {
236
- const authorization = token ? { Authorization: token.toString() } : null;
237
236
  let contentType = null as { 'Content-Type': string } | null;
238
237
 
239
238
  if (body !== undefined) {
@@ -259,10 +258,11 @@ function getRequestInit<I extends ApiCommon, O extends Record<string, unknown>>(
259
258
  }
260
259
  }
261
260
 
262
- const headers = { Accept: 'application/json', ...authorization, ...contentType, ...extraHeaders };
263
261
  const method = extraOptions?.method ?? (body != null ? 'POST' : 'GET'); // don't touch `!=` please
262
+ const authorization = getAuthorizationHeaders(method);
263
+ const headers = { Accept: 'application/json', ...authorization, ...contentType, ...extraHeaders };
264
264
 
265
- return { body, headers, method } as RequestInit;
265
+ return { body, headers, method, ...!token && { credentials: 'include' } } as RequestInit;
266
266
  }
267
267
 
268
268
  interface Context<I extends ApiCommon, O extends Record<string, unknown>> {