@openstax/ts-utils 1.12.3 → 1.14.0

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.
@@ -1,3 +1,4 @@
1
+ import type { JsonCompatibleStruct } from '../routing';
1
2
  /**
2
3
  * Returns true if the error is defined in this library
3
4
  */
@@ -17,6 +18,19 @@ export declare class InvalidRequestError extends Error {
17
18
  static matches: (e: any) => e is typeof InvalidRequestError;
18
19
  constructor(message?: string);
19
20
  }
21
+ /**
22
+ * Validation Error
23
+ *
24
+ * `ValidationError.matches(error)` is a reliable way to check if an error is an
25
+ * `ValidationError`; `instanceof` checks may not work if code is split into multiple bundles
26
+ */
27
+ export declare class ValidationError extends Error {
28
+ static readonly TYPE = "ValidationError";
29
+ static matches: (e: any) => e is typeof ValidationError;
30
+ private data;
31
+ constructor(data: JsonCompatibleStruct);
32
+ getData(): JsonCompatibleStruct;
33
+ }
20
34
  /**
21
35
  * Unauthorized error
22
36
  *
@@ -30,6 +30,21 @@ export class InvalidRequestError extends Error {
30
30
  }
31
31
  InvalidRequestError.TYPE = 'InvalidRequestError';
32
32
  InvalidRequestError.matches = errorIsType(InvalidRequestError);
33
+ /**
34
+ * Validation Error
35
+ *
36
+ * `ValidationError.matches(error)` is a reliable way to check if an error is an
37
+ * `ValidationError`; `instanceof` checks may not work if code is split into multiple bundles
38
+ */
39
+ export class ValidationError extends Error {
40
+ constructor(data) {
41
+ super(InvalidRequestError.TYPE);
42
+ this.data = data;
43
+ }
44
+ getData() { return this.data; }
45
+ }
46
+ ValidationError.TYPE = 'ValidationError';
47
+ ValidationError.matches = errorIsType(ValidationError);
33
48
  /**
34
49
  * Unauthorized error
35
50
  *
@@ -1,8 +1,17 @@
1
+ import { InvalidRequestError, NotFoundError, SessionExpiredError, UnauthorizedError, ValidationError } from '../errors';
1
2
  import type { ApiResponse } from '../routing';
2
3
  import type { Logger } from '../services/logger';
3
- declare type Handlers = {
4
- [key: string]: (e: Error, logger: Logger) => ApiResponse<number, any>;
4
+ export declare type DefaultErrors = {
5
+ UnauthorizedError: UnauthorizedError;
6
+ SessionExpiredError: SessionExpiredError;
7
+ NotFoundError: NotFoundError;
8
+ InvalidRequestError: InvalidRequestError;
9
+ ValidationError: ValidationError;
5
10
  };
11
+ export declare type Handlers<E> = {
12
+ [T in keyof E]: (e: E[T], logger: Logger) => ApiResponse<number, any>;
13
+ };
14
+ export declare const defaultHandlers: Handlers<DefaultErrors>;
6
15
  /**
7
16
  * Creates an error handler. Provides default handlers for `UnauthorizedError`,
8
17
  * `SessionExpiredError`, `NotFoundError`, and `InvalidRequestError`. User-specified
@@ -11,5 +20,4 @@ declare type Handlers = {
11
20
  *
12
21
  * @param inputHandlers a map of errors to handler functions
13
22
  */
14
- export declare const createErrorHandler: (inputHandlers?: Handlers | undefined) => (e: Error, logger: Logger) => Promise<ApiResponse<number, any>>;
15
- export {};
23
+ export declare const createErrorHandler: <Errors = DefaultErrors>(inputHandlers?: Handlers<Errors> | undefined) => (e: Error, logger: Logger) => Promise<ApiResponse<number, any>>;
@@ -1,11 +1,12 @@
1
1
  import { isAppError } from '../errors';
2
- import { apiTextResponse } from '../routing';
2
+ import { apiJsonResponse, apiTextResponse } from '../routing';
3
3
  import { Level } from '../services/logger';
4
- const defaultHandlers = {
4
+ export const defaultHandlers = {
5
5
  UnauthorizedError: () => apiTextResponse(401, '401 UnauthorizedError'),
6
6
  SessionExpiredError: () => apiTextResponse(440, '440 SessionExpiredError'),
7
7
  NotFoundError: (e) => apiTextResponse(404, `404 ${e.message}`),
8
8
  InvalidRequestError: (e) => apiTextResponse(400, `400 ${e.message}`),
9
+ ValidationError: (e) => apiJsonResponse(422, e.getData()),
9
10
  };
10
11
  /**
11
12
  * Creates an error handler. Provides default handlers for `UnauthorizedError`,
@@ -21,6 +22,8 @@ export const createErrorHandler = (inputHandlers) => {
21
22
  const name = isAppError(e) ? e.constructor.TYPE : e.constructor.name;
22
23
  const handler = handlers[name];
23
24
  if (handler) {
25
+ // convincing typescript that this error is the right kind for the handler
26
+ // we looked up based on the errors name is very annoying
24
27
  return handler(e, logger);
25
28
  }
26
29
  logger.logEvent(Level.Error, {
@@ -0,0 +1,4 @@
1
+ import type { z } from 'zod';
2
+ export declare const zodPayloadValidator: <T>(validator: z.ZodType<T, z.ZodTypeDef, T>) => (input: {
3
+ [key: string]: any;
4
+ }) => input is T;
@@ -0,0 +1,8 @@
1
+ import { ValidationError } from '../../errors';
2
+ export const zodPayloadValidator = (validator) => (input) => {
3
+ const result = validator.safeParse(input);
4
+ if (result.success) {
5
+ return true;
6
+ }
7
+ throw new ValidationError(result.error.format());
8
+ };
@@ -1,7 +1,7 @@
1
1
  import { ConfigProviderForConfig } from '../../config';
2
2
  import { GenericFetch } from '../../fetch';
3
3
  import { JsonCompatibleStruct } from '../../routing';
4
- import { ApiUser } from '../authProvider';
4
+ import { ApiUser, ConsentPreferences } from '../authProvider';
5
5
  import { Logger } from '../logger';
6
6
  export declare type Config = {
7
7
  accountsBase: string;
@@ -60,6 +60,7 @@ export declare type SearchUsersResponse = {
60
60
  } & JsonCompatibleStruct>;
61
61
  total_count: number;
62
62
  };
63
+ export declare type UpdateUserPayload = ConsentPreferences;
63
64
  export declare type MappedUserInfo<T> = {
64
65
  data: T;
65
66
  fullName: string;
@@ -78,6 +79,7 @@ export declare const accountsGateway: <C extends string = "accounts">(initialize
78
79
  [uuid: string]: T;
79
80
  }, logger: Logger, platformId?: string | undefined) => Promise<MappedUserInfo<T>[]>;
80
81
  searchUsers: (payload: SearchUsersPayload) => Promise<SearchUsersResponse>;
82
+ updateUser: (token: string, body: UpdateUserPayload) => Promise<ApiUser & JsonCompatibleStruct>;
81
83
  };
82
84
  export declare type AccountsGateway = ReturnType<ReturnType<typeof accountsGateway>>;
83
85
  export {};
@@ -54,6 +54,7 @@ export const accountsGateway = (initializer) => (configProvider) => {
54
54
  }
55
55
  });
56
56
  const searchUsers = async (payload) => request(METHOD.GET, `users?${queryString.stringify(payload)}`, {});
57
+ const updateUser = async (token, body) => request(METHOD.PUT, 'user', { body, token });
57
58
  const getPlatformUserId = (externalIds, platformId) => {
58
59
  for (const externalId of externalIds) {
59
60
  const [userPlatformId, userId] = externalId.split('/', 2);
@@ -106,5 +107,5 @@ export const accountsGateway = (initializer) => (configProvider) => {
106
107
  }));
107
108
  return results;
108
109
  };
109
- return { findOrCreateUser, findUser, getUser, linkUser, mapUserUuids, searchUsers };
110
+ return { findOrCreateUser, findUser, getUser, linkUser, mapUserUuids, searchUsers, updateUser };
110
111
  };
@@ -1,6 +1,12 @@
1
1
  import type { FetchConfig } from '../../fetch';
2
2
  import type { HttpHeaders, QueryParams } from '../../routing';
3
- export interface TokenUser {
3
+ export declare type ConsentPreferences = {
4
+ consent_preferences: {
5
+ accepted: string[];
6
+ rejected: string[];
7
+ };
8
+ };
9
+ export declare type TokenUser = {
4
10
  id: number;
5
11
  name: string;
6
12
  first_name: string;
@@ -9,7 +15,7 @@ export interface TokenUser {
9
15
  uuid: string;
10
16
  faculty_status: string;
11
17
  is_administrator: boolean;
12
- }
18
+ } & Partial<ConsentPreferences>;
13
19
  export interface ApiUser extends TokenUser {
14
20
  contact_infos: Array<{
15
21
  type: string;
@@ -24,7 +24,8 @@ export const embeddedAuthProvider = (getUserData, { authQuery, window }) => {
24
24
  ...params,
25
25
  ...extraParams,
26
26
  ...(authQuery && authQuery.value ? { [authQuery.key]: authQuery.value } : { auth: 'embedded' }),
27
- [embeddedQueryKey]: embeddedQueryValue
27
+ [embeddedQueryKey]: embeddedQueryValue,
28
+ subcontent: 'true',
28
29
  });
29
30
  return url.href;
30
31
  };