@placeos/ts-client 4.2.2 → 4.2.4

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.
@@ -17,6 +17,8 @@ export declare class PlaceRepository extends PlaceResource {
17
17
  readonly username: string;
18
18
  /** Password to connect to repository with */
19
19
  readonly password: string;
20
+ /** Root path of the repository to serve at the `folder_name` path */
21
+ readonly root_path: string;
20
22
  /** Repository type */
21
23
  get type(): PlaceRepositoryType;
22
24
  constructor(raw_data?: Partial<PlaceRepository>);
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.2.2",
2
+ "version": "4.2.4",
3
3
  "license": "MIT",
4
4
  "name": "@placeos/ts-client",
5
5
  "author": "Alex Sorafumo <alex@place.tech>",
@@ -1,6 +1,6 @@
1
- import { Observable, of, throwError } from 'rxjs';
1
+ import { Observable, throwError } from 'rxjs';
2
2
  import { fromFetch } from 'rxjs/fetch';
3
- import { filter, mergeMap, retryWhen, switchMap, take } from 'rxjs/operators';
3
+ import { filter, retry, switchMap, take } from 'rxjs/operators';
4
4
 
5
5
  import {
6
6
  apiKey,
@@ -225,17 +225,26 @@ export async function transform(
225
225
  return await resp.json().catch(() => ({}));
226
226
  case 'text':
227
227
  return await resp.text();
228
+ case 'void':
229
+ return;
230
+ default:
231
+ return await resp.json().catch(() => ({}));
228
232
  }
229
233
  }
230
234
 
231
235
  /**
232
236
  * @private
233
237
  */
234
- const reloadAuth = () => {
238
+ const reloadAuth = (): Promise<void> => {
235
239
  invalidateToken();
236
- refreshAuthority().then(
237
- () => null,
238
- () => setTimeout(() => reloadAuth(), 1000),
240
+ return refreshAuthority().then(
241
+ () => Promise.resolve(),
242
+ () =>
243
+ new Promise<void>((resolve) => {
244
+ setTimeout(() => {
245
+ reloadAuth().then(() => resolve());
246
+ }, 1000);
247
+ }),
239
248
  );
240
249
  };
241
250
 
@@ -255,7 +264,7 @@ export function request(
255
264
  m: HttpVerb,
256
265
  url: string,
257
266
  body?: any,
258
- ) => Observable<HttpResponse> | null = mockRequest,
267
+ ) => Observable<HashMap | string | void> | null = mockRequest,
259
268
  success: (
260
269
  e: Response,
261
270
  t: HttpResponseType,
@@ -268,7 +277,9 @@ export function request(
268
277
  }
269
278
  }
270
279
  options.headers = options.headers || {};
271
- options.headers['Content-Type'] = `application/json`;
280
+ if (!options.headers['Content-Type'] && !options.headers['content-type']) {
281
+ options.headers['Content-Type'] = `application/json`;
282
+ }
272
283
  return listenForToken().pipe(
273
284
  filter((_) => _),
274
285
  take(1),
@@ -278,34 +289,57 @@ export function request(
278
289
  } else {
279
290
  options.headers!.Authorization = `Bearer ${token()}`;
280
291
  }
281
- return fromFetch(url, {
292
+ const fetchOptions: any = {
282
293
  ...options,
283
- body: JSON.stringify(options.body),
284
294
  method,
285
295
  credentials: 'same-origin',
286
- });
296
+ };
297
+
298
+ // Only add body for methods that support it and when body exists
299
+ if (
300
+ ['POST', 'PUT', 'PATCH'].includes(method) &&
301
+ options.body !== undefined
302
+ ) {
303
+ fetchOptions.body =
304
+ typeof options.body === 'string'
305
+ ? options.body
306
+ : JSON.stringify(options.body);
307
+ }
308
+
309
+ return fromFetch(url, fetchOptions) as Observable<Response>;
287
310
  }),
288
- switchMap((resp) => {
311
+ switchMap((resp: Response) => {
289
312
  if (resp.ok) {
290
313
  return success(resp, options.response_type as any);
291
314
  }
292
315
  return throwError(resp);
293
316
  }),
294
- retryWhen((attempts: Observable<any>) =>
295
- attempts.pipe(
296
- mergeMap((error, i) => {
317
+ retry({
318
+ count: 4,
319
+ delay: (error, retry_count) => {
320
+ return new Observable<number>((subscriber) => {
297
321
  if (error.status === 511) {
298
322
  sendToLogin(authority()!);
299
- return of(error);
323
+ subscriber.error(error);
324
+ return;
300
325
  }
301
- if (i + 1 > 4 || error.status !== 401) {
302
- return throwError(error || {});
326
+ if (error.status !== 401) {
327
+ subscriber.error(error || {});
328
+ return;
303
329
  }
304
330
  log('HTTP', 'Auth error', error);
305
- reloadAuth();
306
- return of(error);
307
- }),
308
- ),
309
- ),
331
+ // Wait for auth refresh before retrying with exponential backoff
332
+ const delay_ms = Math.pow(2, retry_count - 1) * 1000; // Exponential backoff: 1s, 2s, 4s, 8s
333
+ reloadAuth()
334
+ .then(() => {
335
+ subscriber.next(delay_ms);
336
+ subscriber.complete();
337
+ })
338
+ .catch(() => {
339
+ subscriber.error(error);
340
+ });
341
+ });
342
+ },
343
+ }),
310
344
  );
311
345
  }
package/src/http/mock.ts CHANGED
@@ -86,12 +86,12 @@ export function clearMockEndpoints(
86
86
  * @param handler_map Handler map to query for the request handler.
87
87
  * Defaults to the global handler map
88
88
  */
89
- export function mockRequest<T>(
89
+ export function mockRequest(
90
90
  method: HttpVerb,
91
91
  url: string,
92
92
  body?: any,
93
93
  handler_map: HashMap<MockHttpRequestHandler> = _handlers,
94
- ): Observable<T> | null {
94
+ ): Observable<HashMap | string | void> | null {
95
95
  const handler = findRequestHandler(method, url, handler_map);
96
96
  if (handler) {
97
97
  const request = processRequest(url, handler, body);
@@ -113,7 +113,7 @@ export function findRequestHandler(
113
113
  handler_map: HashMap<MockHttpRequestHandler> = _handlers,
114
114
  ): MockHttpRequestHandler | null {
115
115
  const path = url
116
- .replace(/(http|https)?:\/\/[a-zA-Z0-9.]*:?([0-9]*)?/g, '')
116
+ .replace(/(http|https):\/\/[a-zA-Z0-9.]*:?([0-9]*)?/g, '')
117
117
  .replace(/^\//, '')
118
118
  .split('?')[0];
119
119
  const route_parts = path.split('/');
@@ -161,16 +161,16 @@ export function processRequest<T = any>(
161
161
  const parts = url
162
162
  .replace(/(http|https):\/\/[a-zA-Z0-9.]*:?([0-9]*)?/g, '')
163
163
  .split('?');
164
- const path = parts[0].replace(/^\//g, '');
164
+ const path = parts[0].replace(/^\//, '');
165
165
  const query = parts[1] || '';
166
166
  const query_params = convertPairStringToMap(query);
167
167
  // Grab route parameters from URL
168
168
  const route_parts = path.split('/');
169
169
  const route_params: HashMap = {};
170
- for (const part of handler.path_structure) {
171
- if (part) {
172
- route_params[part] =
173
- route_parts[handler.path_structure.indexOf(part)];
170
+ for (let i = 0; i < handler.path_structure.length; i++) {
171
+ const paramName = handler.path_structure[i];
172
+ if (paramName) {
173
+ route_params[paramName] = route_parts[i];
174
174
  }
175
175
  }
176
176
  const request = {
@@ -196,9 +196,15 @@ export function onMockRequest(
196
196
  handler: MockHttpRequestHandler,
197
197
  request: MockHttpRequest,
198
198
  ) {
199
- const result = handler.callback
200
- ? handler.callback(request)
201
- : handler.metadata;
199
+ let result;
200
+ try {
201
+ result = handler.callback
202
+ ? handler.callback(request)
203
+ : handler.metadata;
204
+ } catch (error) {
205
+ log('HTTP(M)', `ERROR ${request.method}:`, [request.url, error]);
206
+ throw error;
207
+ }
202
208
  const variance = handler.delay_variance || 100;
203
209
  const delay_value = handler.delay || 300;
204
210
  const delay_time =
@@ -206,3 +212,11 @@ export function onMockRequest(
206
212
  log('HTTP(M)', `RESP ${request.method}:`, [request.url, result]);
207
213
  return from([result]).pipe(delay(Math.max(200, delay_time)));
208
214
  }
215
+
216
+ /**
217
+ * Get a list of the method + endpoints that have been mocked
218
+ * @returns List of the method + endpoint that have been mocked
219
+ */
220
+ export function listMockedEndpoints(): string[] {
221
+ return Object.keys(_handlers);
222
+ }
@@ -18,6 +18,8 @@ export class PlaceRepository extends PlaceResource {
18
18
  public readonly username: string;
19
19
  /** Password to connect to repository with */
20
20
  public readonly password: string;
21
+ /** Root path of the repository to serve at the `folder_name` path */
22
+ public readonly root_path: string;
21
23
  /** Repository type */
22
24
  public get type() {
23
25
  return this.repo_type;
@@ -33,5 +35,6 @@ export class PlaceRepository extends PlaceResource {
33
35
  this.repo_type = raw_data.repo_type || PlaceRepositoryType.Driver;
34
36
  this.username = raw_data.username || '';
35
37
  this.password = raw_data.password || '';
38
+ this.root_path = raw_data.root_path || '';
36
39
  }
37
40
  }