@mapcreator/api 0.0.0-wms.0 → 0.0.0-wms.1

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 (70) hide show
  1. package/cjs/api/insetMap.js +1 -1
  2. package/cjs/api/insetMap.js.map +1 -1
  3. package/cjs/api/job.d.ts +1 -0
  4. package/cjs/api/job.d.ts.map +1 -1
  5. package/cjs/api/job.js.map +1 -1
  6. package/cjs/api/jobResult.d.ts +1 -1
  7. package/cjs/api/jobResult.d.ts.map +1 -1
  8. package/cjs/api/jobResult.js +1 -1
  9. package/cjs/api/jobResult.js.map +1 -1
  10. package/cjs/api/jobRevision.d.ts +2 -2
  11. package/cjs/api/jobRevision.d.ts.map +1 -1
  12. package/cjs/api/jobRevision.js +1 -1
  13. package/cjs/api/jobRevision.js.map +1 -1
  14. package/cjs/api/organisation.d.ts +2 -1
  15. package/cjs/api/organisation.d.ts.map +1 -1
  16. package/cjs/api/organisation.js +1 -2
  17. package/cjs/api/organisation.js.map +1 -1
  18. package/cjs/api/resources.d.ts +1 -1
  19. package/cjs/api/resources.d.ts.map +1 -1
  20. package/cjs/api/resources.js.map +1 -1
  21. package/esm/api/insetMap.js +1 -1
  22. package/esm/api/insetMap.js.map +1 -1
  23. package/esm/api/job.d.ts +1 -0
  24. package/esm/api/job.d.ts.map +1 -1
  25. package/esm/api/job.js.map +1 -1
  26. package/esm/api/jobResult.d.ts +1 -1
  27. package/esm/api/jobResult.d.ts.map +1 -1
  28. package/esm/api/jobResult.js +1 -1
  29. package/esm/api/jobResult.js.map +1 -1
  30. package/esm/api/jobRevision.d.ts +2 -2
  31. package/esm/api/jobRevision.d.ts.map +1 -1
  32. package/esm/api/jobRevision.js +1 -1
  33. package/esm/api/jobRevision.js.map +1 -1
  34. package/esm/api/organisation.d.ts +2 -1
  35. package/esm/api/organisation.d.ts.map +1 -1
  36. package/esm/api/organisation.js +1 -2
  37. package/esm/api/organisation.js.map +1 -1
  38. package/esm/api/resources.d.ts +1 -1
  39. package/esm/api/resources.d.ts.map +1 -1
  40. package/esm/api/resources.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/api/apiCommon.ts +70 -70
  43. package/src/api/choropleth.ts +359 -359
  44. package/src/api/color.ts +22 -22
  45. package/src/api/dimension.ts +44 -44
  46. package/src/api/dimensionSet.ts +20 -20
  47. package/src/api/feature.ts +22 -22
  48. package/src/api/font.ts +49 -49
  49. package/src/api/fontFamily.ts +43 -43
  50. package/src/api/highlight.ts +87 -87
  51. package/src/api/insetMap.ts +96 -96
  52. package/src/api/job.ts +130 -129
  53. package/src/api/jobResult.ts +95 -95
  54. package/src/api/jobRevision.ts +279 -278
  55. package/src/api/jobShare.ts +35 -35
  56. package/src/api/jobType.ts +26 -26
  57. package/src/api/language.ts +19 -19
  58. package/src/api/layer.ts +38 -38
  59. package/src/api/layerFaq.ts +53 -53
  60. package/src/api/layerGroup.ts +69 -69
  61. package/src/api/mapstyleSet.ts +48 -48
  62. package/src/api/message.ts +80 -80
  63. package/src/api/organisation.ts +95 -95
  64. package/src/api/resources.ts +146 -144
  65. package/src/api/svg.ts +33 -33
  66. package/src/api/svgSet.ts +56 -56
  67. package/src/api/user.ts +327 -327
  68. package/src/index.ts +43 -43
  69. package/src/oauth.ts +314 -314
  70. package/src/utils.ts +342 -342
package/src/oauth.ts CHANGED
@@ -1,314 +1,314 @@
1
- export let apiHost = '';
2
-
3
- export let token: {
4
- type: string;
5
- token: string;
6
- expires: Date;
7
-
8
- toString: () => string;
9
- } | null = null;
10
-
11
- let apiClientId = '';
12
- let callbackUrl = '';
13
- let oauthScopes = ['*'];
14
-
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');
22
-
23
- interface AnchorToken {
24
- access_token: string;
25
- token_type: string;
26
- expires_in: string;
27
- state: string;
28
- }
29
-
30
- const titleCase = (str: unknown): string => String(str).toLowerCase().replace(/\b\w/g, c => c.toUpperCase());
31
-
32
- /**
33
- * Setup internal structures to use dummy authentication flow
34
- *
35
- * @param {string} apiUrl - Full API URL
36
- * @param {string} oauthToken - OAuth Token
37
- */
38
- export function initDummyFlow(apiUrl: string, oauthToken: string): void {
39
- const parts = oauthToken.includes(' ') ? oauthToken.split(' ', 2) : ['Bearer', oauthToken];
40
-
41
- apiHost = apiUrl.replace(/\/+$/, '');
42
- token = {
43
- type: titleCase(parts[0]),
44
- token: parts[1],
45
- expires: dummyTokenExpires,
46
-
47
- toString(): string {
48
- return `${this.type} ${this.token}`;
49
- },
50
- };
51
- }
52
-
53
- /**
54
- * Setup internal structures to use implicit authentication flow
55
- *
56
- * @param {string} apiUrl - Full API URL
57
- * @param {string} clientId - OAuth client id
58
- * @param {string} [redirectUrl] - Callback URL
59
- * @param {string[]} [scopes] - A list of required scopes
60
- */
61
- export function initImplicitFlow(apiUrl: string, clientId: string, redirectUrl = '', scopes = ['*']): void {
62
- apiHost = apiUrl.replace(/\/+$/, '');
63
-
64
- apiClientId = String(clientId);
65
- 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
-
132
- if (authenticated()) {
133
- const href = sessionStorage.getItem('redirect-url');
134
-
135
- if (href) {
136
- sessionStorage.removeItem('redirect-url');
137
- window.history.replaceState(null, document.title, href);
138
- }
139
- }
140
- }
141
-
142
- export async function authenticate(): Promise<string> | never {
143
- return new Promise(() => {
144
- if (anchorContainsError()) {
145
- console.error(getError());
146
- cleanAnchorParams();
147
- }
148
-
149
- forget();
150
-
151
- sessionStorage.setItem('redirect-url', window.location.href);
152
- window.location.assign(buildRedirectUrl());
153
- });
154
- }
155
-
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
- }
176
-
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
- }
185
-
186
- token = null;
187
- }
188
-
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(),
196
- });
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
- }
1
+ export let apiHost = '';
2
+
3
+ export let token: {
4
+ type: string;
5
+ token: string;
6
+ expires: Date;
7
+
8
+ toString: () => string;
9
+ } | null = null;
10
+
11
+ let apiClientId = '';
12
+ let callbackUrl = '';
13
+ let oauthScopes = ['*'];
14
+
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');
22
+
23
+ interface AnchorToken {
24
+ access_token: string;
25
+ token_type: string;
26
+ expires_in: string;
27
+ state: string;
28
+ }
29
+
30
+ const titleCase = (str: unknown): string => String(str).toLowerCase().replace(/\b\w/g, c => c.toUpperCase());
31
+
32
+ /**
33
+ * Setup internal structures to use dummy authentication flow
34
+ *
35
+ * @param {string} apiUrl - Full API URL
36
+ * @param {string} oauthToken - OAuth Token
37
+ */
38
+ export function initDummyFlow(apiUrl: string, oauthToken: string): void {
39
+ const parts = oauthToken.includes(' ') ? oauthToken.split(' ', 2) : ['Bearer', oauthToken];
40
+
41
+ apiHost = apiUrl.replace(/\/+$/, '');
42
+ token = {
43
+ type: titleCase(parts[0]),
44
+ token: parts[1],
45
+ expires: dummyTokenExpires,
46
+
47
+ toString(): string {
48
+ return `${this.type} ${this.token}`;
49
+ },
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Setup internal structures to use implicit authentication flow
55
+ *
56
+ * @param {string} apiUrl - Full API URL
57
+ * @param {string} clientId - OAuth client id
58
+ * @param {string} [redirectUrl] - Callback URL
59
+ * @param {string[]} [scopes] - A list of required scopes
60
+ */
61
+ export function initImplicitFlow(apiUrl: string, clientId: string, redirectUrl = '', scopes = ['*']): void {
62
+ apiHost = apiUrl.replace(/\/+$/, '');
63
+
64
+ apiClientId = String(clientId);
65
+ 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
+
132
+ if (authenticated()) {
133
+ const href = sessionStorage.getItem('redirect-url');
134
+
135
+ if (href) {
136
+ sessionStorage.removeItem('redirect-url');
137
+ window.history.replaceState(null, document.title, href);
138
+ }
139
+ }
140
+ }
141
+
142
+ export async function authenticate(): Promise<string> | never {
143
+ return new Promise(() => {
144
+ if (anchorContainsError()) {
145
+ console.error(getError());
146
+ cleanAnchorParams();
147
+ }
148
+
149
+ forget();
150
+
151
+ sessionStorage.setItem('redirect-url', window.location.href);
152
+ window.location.assign(buildRedirectUrl());
153
+ });
154
+ }
155
+
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
+ }
176
+
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
+ }
185
+
186
+ token = null;
187
+ }
188
+
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(),
196
+ });
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
+ }