@openstax/ts-utils 1.2.1 → 1.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.
Files changed (47) hide show
  1. package/dist/cjs/errors.d.ts +5 -0
  2. package/dist/cjs/errors.js +4 -1
  3. package/dist/cjs/middleware/apiErrorHandler.d.ts +7 -0
  4. package/dist/cjs/middleware/apiErrorHandler.js +29 -0
  5. package/dist/cjs/middleware/apiSlowResponseMiddleware.d.ts +11 -0
  6. package/dist/cjs/middleware/apiSlowResponseMiddleware.js +43 -0
  7. package/dist/cjs/middleware/lambdaCorsResponseMiddleware.d.ts +10 -0
  8. package/dist/cjs/middleware/lambdaCorsResponseMiddleware.js +32 -0
  9. package/dist/cjs/middleware/throwNotFoundMiddleware.d.ts +1 -0
  10. package/dist/cjs/middleware/throwNotFoundMiddleware.js +11 -0
  11. package/dist/cjs/profile.d.ts +2 -0
  12. package/dist/cjs/routing/index.d.ts +14 -4
  13. package/dist/cjs/routing/index.js +16 -8
  14. package/dist/cjs/services/apiGateway/index.js +2 -1
  15. package/dist/cjs/services/authProvider/browser.d.ts +3 -1
  16. package/dist/cjs/services/authProvider/browser.js +1 -1
  17. package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.d.ts +3 -1
  18. package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.js +7 -2
  19. package/dist/cjs/services/logger/console.d.ts +1 -0
  20. package/dist/cjs/services/logger/console.js +9 -0
  21. package/dist/cjs/services/logger/index.d.ts +14 -0
  22. package/dist/cjs/services/logger/index.js +20 -0
  23. package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
  24. package/dist/esm/errors.d.ts +5 -0
  25. package/dist/esm/errors.js +2 -0
  26. package/dist/esm/middleware/apiErrorHandler.d.ts +7 -0
  27. package/dist/esm/middleware/apiErrorHandler.js +25 -0
  28. package/dist/esm/middleware/apiSlowResponseMiddleware.d.ts +11 -0
  29. package/dist/esm/middleware/apiSlowResponseMiddleware.js +39 -0
  30. package/dist/esm/middleware/lambdaCorsResponseMiddleware.d.ts +10 -0
  31. package/dist/esm/middleware/lambdaCorsResponseMiddleware.js +28 -0
  32. package/dist/esm/middleware/throwNotFoundMiddleware.d.ts +1 -0
  33. package/dist/esm/middleware/throwNotFoundMiddleware.js +7 -0
  34. package/dist/esm/profile.d.ts +2 -0
  35. package/dist/esm/routing/index.d.ts +14 -4
  36. package/dist/esm/routing/index.js +16 -8
  37. package/dist/esm/services/apiGateway/index.js +2 -1
  38. package/dist/esm/services/authProvider/browser.d.ts +3 -1
  39. package/dist/esm/services/authProvider/browser.js +1 -1
  40. package/dist/esm/services/authProvider/utils/embeddedAuthProvider.d.ts +3 -1
  41. package/dist/esm/services/authProvider/utils/embeddedAuthProvider.js +4 -2
  42. package/dist/esm/services/logger/console.d.ts +1 -0
  43. package/dist/esm/services/logger/console.js +5 -0
  44. package/dist/esm/services/logger/index.d.ts +14 -0
  45. package/dist/esm/services/logger/index.js +16 -0
  46. package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -1
  47. package/package.json +1 -1
@@ -1,3 +1,8 @@
1
+ export declare const isAppError: (e: any) => e is Error & {
2
+ constructor: {
3
+ TYPE: string;
4
+ };
5
+ };
1
6
  export declare class InvalidRequestError extends Error {
2
7
  static readonly TYPE = "InvalidRequestError";
3
8
  static matches: (e: any) => e is typeof InvalidRequestError;
@@ -12,6 +12,8 @@
12
12
  */
13
13
  const errorIsType = ({ TYPE }) => (e) => e instanceof Error
14
14
  && e.constructor.TYPE === TYPE;
15
+ export const isAppError = (e) => e instanceof Error
16
+ && typeof e.constructor.TYPE === 'string';
15
17
  export class InvalidRequestError extends Error {
16
18
  }
17
19
  InvalidRequestError.TYPE = 'InvalidRequestError';
@@ -0,0 +1,7 @@
1
+ import type { ApiResponse } from '../routing';
2
+ import type { Logger } from '../services/logger';
3
+ declare type Handlers = {
4
+ [key: string]: (e: Error, logger: Logger) => ApiResponse<number, any>;
5
+ };
6
+ export declare const createErrorHandler: (inputHandlers?: Handlers | undefined) => (e: Error, logger: Logger) => Promise<ApiResponse<number, any>>;
7
+ export {};
@@ -0,0 +1,25 @@
1
+ import { isAppError } from '../errors';
2
+ import { apiTextResponse } from '../routing';
3
+ import { Level } from '../services/logger';
4
+ const defaultHandlers = {
5
+ UnauthorizedError: () => apiTextResponse(401, '401 UnauthorizedError'),
6
+ SessionExpiredError: () => apiTextResponse(440, '440 SessionExpiredError'),
7
+ NotFoundError: (e) => apiTextResponse(404, e.message || '404 NotFoundError'),
8
+ InvalidRequestError: (e) => apiTextResponse(400, e.message || '400 InvalidRequestError'),
9
+ };
10
+ export const createErrorHandler = (inputHandlers) => {
11
+ const handlers = { ...defaultHandlers, ...inputHandlers };
12
+ return async (e, logger) => {
13
+ const name = isAppError(e) ? e.constructor.TYPE : e.constructor.name;
14
+ const handler = handlers[name];
15
+ if (handler) {
16
+ return handler(e, logger);
17
+ }
18
+ logger.logEvent(Level.Error, {
19
+ name: e.name,
20
+ message: e.message,
21
+ stack: e.stack,
22
+ });
23
+ return apiTextResponse(500, '500 Error');
24
+ };
25
+ };
@@ -0,0 +1,11 @@
1
+ import type { ConfigProviderForConfig } from '../config';
2
+ import type { ApiResponse } from '../routing';
3
+ import type { Logger } from '../services/logger';
4
+ declare type Config = {
5
+ logResponseSlowerThan: string;
6
+ timeoutResponseAfter: string;
7
+ };
8
+ export declare const createSlowResponseMiddleware: (config: ConfigProviderForConfig<Config>) => () => (response: Promise<ApiResponse<number, any>> | undefined, { logger }: {
9
+ logger: Logger;
10
+ }) => Promise<ApiResponse<number, string>> | undefined;
11
+ export {};
@@ -0,0 +1,39 @@
1
+ import { resolveConfigValue } from '../config/resolveConfigValue';
2
+ import { once } from '../misc/helpers';
3
+ import { apiTextResponse } from '../routing';
4
+ import { Level } from '../services/logger';
5
+ export const createSlowResponseMiddleware = (config) => {
6
+ const getSlowThreshold = once(() => resolveConfigValue(config.logResponseSlowerThan).then(result => parseInt(result, 10)));
7
+ const getTimeoutAfter = once(() => resolveConfigValue(config.timeoutResponseAfter).then(result => parseInt(result, 10)));
8
+ return () => (response, { logger }) => {
9
+ const start = Date.now();
10
+ if (!response) {
11
+ return response;
12
+ }
13
+ return Promise.all([getSlowThreshold(), getTimeoutAfter()]).then(([slowThreshold, timeoutAfter]) => {
14
+ let timeout = undefined;
15
+ const timeoutPromise = isNaN(timeoutAfter)
16
+ ? undefined
17
+ : new Promise(resolve => timeout = setTimeout(() => {
18
+ logger.logEvent(Level.Error, {
19
+ message: 'request processing timed out',
20
+ });
21
+ resolve(apiTextResponse(504, '504 Gateway Timeout'));
22
+ }, timeoutAfter));
23
+ const requestPromise = response.then(response => {
24
+ const time = Date.now() - start;
25
+ if (timeout !== undefined) {
26
+ clearTimeout(timeout);
27
+ }
28
+ if (time > slowThreshold) {
29
+ logger.logEvent(Level.Warn, {
30
+ message: 'slow response',
31
+ time,
32
+ });
33
+ }
34
+ return response;
35
+ });
36
+ return timeoutPromise ? Promise.race([timeoutPromise, requestPromise]) : requestPromise;
37
+ });
38
+ };
39
+ };
@@ -0,0 +1,10 @@
1
+ import { APIGatewayProxyEventV2 } from 'aws-lambda';
2
+ import { ConfigProviderForConfig } from '../config';
3
+ import { ApiResponse } from '../routing';
4
+ declare type Config = {
5
+ corsAllowedHostRegex: string;
6
+ };
7
+ export declare const createLambdaCorsResponseMiddleware: (config: ConfigProviderForConfig<Config>) => (responsePromise: Promise<ApiResponse<number, any>> | undefined, { request }: {
8
+ request: APIGatewayProxyEventV2;
9
+ }) => Promise<ApiResponse<number, any>> | undefined;
10
+ export {};
@@ -0,0 +1,28 @@
1
+ import { resolveConfigValue } from '../config/resolveConfigValue';
2
+ import { apiTextResponse } from '../routing';
3
+ export const createLambdaCorsResponseMiddleware = (config) => (responsePromise, { request }) => {
4
+ const cors = async () => {
5
+ const allowedHost = await resolveConfigValue(config.corsAllowedHostRegex);
6
+ if (request.headers.origin && request.headers.origin !== 'null' && new URL(request.headers.origin).hostname.match(new RegExp(allowedHost))) {
7
+ return {
8
+ 'Access-Control-Allow-Origin': request.headers.origin,
9
+ 'Access-Control-Allow-Credentials': 'true',
10
+ 'Access-Control-Allow-Headers': 'content-type',
11
+ 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
12
+ };
13
+ }
14
+ };
15
+ if (responsePromise) {
16
+ return responsePromise.then(async (response) => {
17
+ response.headers = {
18
+ ...await cors(),
19
+ ...response.headers
20
+ };
21
+ return response;
22
+ });
23
+ }
24
+ if (request.requestContext.http.method === 'OPTIONS') {
25
+ return cors().then(headers => apiTextResponse(200, '', headers));
26
+ }
27
+ return responsePromise;
28
+ };
@@ -0,0 +1 @@
1
+ export declare const createThrowNotFoundMiddleware: <Ro>() => () => (response: Promise<Ro> | undefined) => Promise<Ro>;
@@ -0,0 +1,7 @@
1
+ import { NotFoundError } from '../errors';
2
+ export const createThrowNotFoundMiddleware = () => () => (response) => {
3
+ if (!response) {
4
+ throw new NotFoundError('not found');
5
+ }
6
+ return response;
7
+ };
@@ -1,5 +1,6 @@
1
1
  import { GenericFetch } from './fetch';
2
2
  import { ApiResponse, HttpHeaders } from './routing';
3
+ import { Logger } from './services/logger';
3
4
  export interface Call {
4
5
  start: number;
5
6
  end?: number;
@@ -52,6 +53,7 @@ export declare const makeProfileApiResponseMiddleware: <Ri extends {
52
53
  }>(showReport: (request: Ri) => string | boolean) => () => (responsePromise: Promise<ApiResponse<number, any>> | undefined, { request, profile }: {
53
54
  request: Ri;
54
55
  profile: Track;
56
+ logger: Logger;
55
57
  }) => Promise<ApiResponse<number, any>> | undefined;
56
58
  export declare const makeHtmlReport: (report: CallReport) => string;
57
59
  export declare const makeHtmlProfileReport: (report: ProfileReport) => string;
@@ -1,4 +1,5 @@
1
1
  import { Track } from '../profile';
2
+ import { Logger } from '../services/logger';
2
3
  export declare type QueryParams = Record<string, string | undefined | string[] | null>;
3
4
  export declare type RouteParams = {
4
5
  [key: string]: string;
@@ -19,6 +20,7 @@ export declare type PayloadForRoute<R> = RequestServicesForRoute<R> extends {
19
20
  declare type RequestServiceProvider<Sa, Sr, Ri> = (app: Sa) => <R>(middleware: {
20
21
  request: Ri;
21
22
  profile: Track;
23
+ logger: Logger;
22
24
  }, match: RouteMatchRecord<R>) => Sr;
23
25
  declare type RouteHandler<P, Sr, Ro> = (params: P, request: Sr) => Ro;
24
26
  declare type Route<N extends string, P extends RouteParams | undefined, Sa, Sr, Ri, Ro> = (Sr extends undefined ? {
@@ -50,19 +52,27 @@ export declare const makeRenderRouteUrl: <Ru extends {
50
52
  }>() => <R extends Ru>(route: R, params: ParamsForRoute<R>, query?: QueryParams) => string;
51
53
  export declare const renderAnyRouteUrl: <R extends any>(route: R, params: ParamsForRoute<R>, query?: QueryParams) => string;
52
54
  declare type RequestPathExtractor<Ri> = (request: Ri) => string;
55
+ declare type RequestLogExtractor<Ri> = (request: Ri) => JsonCompatibleStruct;
53
56
  declare type RequestRouteMatcher<Ri, R> = (request: Ri, route: R) => boolean;
57
+ declare type CompatibleServices<T1> = keyof T1 extends 'logger' ? T1 extends {
58
+ logger: Logger;
59
+ } ? T1 : never : T1 & {
60
+ logger?: Logger;
61
+ };
54
62
  declare type RequestResponder<Sa, Ri, Ro> = {
55
- (services: Sa): (request: Ri) => Ro | undefined;
56
- <RoF>(services: Sa, responseMiddleware: (app: Sa) => (response: Ro | undefined, request: {
63
+ (services: CompatibleServices<Sa>): (request: Ri) => Ro | undefined;
64
+ <RoF>(services: CompatibleServices<Sa>, responseMiddleware: (app: Sa) => (response: Ro | undefined, request: {
57
65
  request: Ri;
58
66
  profile: Track;
67
+ logger: Logger;
59
68
  }) => RoF): (request: Ri) => RoF;
60
69
  };
61
- export declare const makeGetRequestResponder: <Sa, Ru, Ri, Ro>() => ({ routes, pathExtractor, routeMatcher, errorHandler }: {
70
+ export declare const makeGetRequestResponder: <Sa, Ru, Ri, Ro>() => ({ routes, pathExtractor, routeMatcher, errorHandler, logExtractor }: {
62
71
  routes: () => AnySpecificRoute<Ru, Sa, Ri, Ro>[];
63
72
  pathExtractor: RequestPathExtractor<Ri>;
73
+ logExtractor?: RequestLogExtractor<Ri> | undefined;
64
74
  routeMatcher?: RequestRouteMatcher<Ri, AnySpecificRoute<Ru, Sa, Ri, Ro>> | undefined;
65
- errorHandler?: ((e: Error) => Ro) | undefined;
75
+ errorHandler?: ((e: Error, logger: Logger) => Ro) | undefined;
66
76
  }) => RequestResponder<Sa, Ri, Ro>;
67
77
  export declare type HttpHeaders = {
68
78
  [key: string]: string | undefined | string[];
@@ -2,6 +2,7 @@ import * as pathToRegexp from 'path-to-regexp';
2
2
  import queryString from 'query-string';
3
3
  import { mapFind, memoize } from '../misc/helpers';
4
4
  import { createProfile } from '../profile';
5
+ import { createConsoleLogger } from '../services/logger/console';
5
6
  /*
6
7
  * route definition helper. the only required params of the route are the name, path, and handler. other params
7
8
  * can be added to the type and then later used in the routeMatcher. when defining the `createRoute` method, only
@@ -59,11 +60,11 @@ export const renderAnyRouteUrl = makeRenderRouteUrl();
59
60
  const bindRoute = (services, appBinder, pathExtractor, matcher) => (route) => {
60
61
  const getParamsFromPath = pathToRegexp.match(route.path, { decode: decodeURIComponent });
61
62
  const boundServiceProvider = route.requestServiceProvider && appBinder(services, route.requestServiceProvider);
62
- return (request, profile) => {
63
+ return (request, profile, logger) => {
63
64
  const path = pathExtractor(request);
64
65
  const match = getParamsFromPath(path);
65
66
  if ((!matcher || matcher(request, route)) && match) {
66
- return profile.track(route.name, routeProfile => () => route.handler(match.params, boundServiceProvider ? boundServiceProvider({ request, profile: routeProfile }, { route, params: match.params }) : undefined));
67
+ return profile.track(route.name, routeProfile => () => route.handler(match.params, boundServiceProvider ? boundServiceProvider({ request, profile: routeProfile, logger }, { route, params: match.params }) : undefined));
67
68
  }
68
69
  };
69
70
  };
@@ -86,11 +87,12 @@ const bindRoute = (services, appBinder, pathExtractor, matcher) => (route) => {
86
87
  * lambdaMiddleware // environment specific response middleware (like cors)
87
88
  * );
88
89
  */
89
- export const makeGetRequestResponder = () => ({ routes, pathExtractor, routeMatcher, errorHandler }) => (services, responseMiddleware) => {
90
+ export const makeGetRequestResponder = () => ({ routes, pathExtractor, routeMatcher, errorHandler, logExtractor }) => (services, responseMiddleware) => {
90
91
  const appBinderImpl = (app, middleware) => middleware(app, appBinder);
91
92
  const appBinder = memoize(appBinderImpl);
92
93
  const boundRoutes = routes().map(bindRoute(services, appBinder, pathExtractor, routeMatcher));
93
94
  const boundResponseMiddleware = responseMiddleware ? responseMiddleware(services) : undefined;
95
+ const appLogger = services.logger || createConsoleLogger();
94
96
  // *note* this opaque promise guard is less generic than i hoped so
95
97
  // i'm leaving it here instead of the guards file.
96
98
  //
@@ -101,14 +103,18 @@ export const makeGetRequestResponder = () => ({ routes, pathExtractor, routeMatc
101
103
  const isPromise = (thing) => thing instanceof Promise;
102
104
  return (request) => {
103
105
  const { end, ...profile } = createProfile(new Date().toISOString()).start();
106
+ const logger = appLogger.createSubContext();
107
+ if (logExtractor) {
108
+ logger.setContext(logExtractor(request));
109
+ }
104
110
  try {
105
- const executor = mapFind(boundRoutes, (route) => route(request, profile));
111
+ const executor = mapFind(boundRoutes, (route) => route(request, profile, logger));
106
112
  if (executor) {
107
113
  const result = boundResponseMiddleware ?
108
- boundResponseMiddleware(executor(), { request, profile }) : executor();
114
+ boundResponseMiddleware(executor(), { request, profile, logger }) : executor();
109
115
  if (isPromise(result) && errorHandler) {
110
116
  const errorHandlerWithMiddleware = (e) => boundResponseMiddleware ?
111
- boundResponseMiddleware(errorHandler(e), { request, profile }) : errorHandler(e);
117
+ boundResponseMiddleware(errorHandler(e, logger), { request, profile, logger }) : errorHandler(e, logger);
112
118
  return result.catch(errorHandlerWithMiddleware);
113
119
  }
114
120
  else {
@@ -116,12 +122,14 @@ export const makeGetRequestResponder = () => ({ routes, pathExtractor, routeMatc
116
122
  }
117
123
  }
118
124
  else if (boundResponseMiddleware) {
119
- return boundResponseMiddleware(undefined, { request, profile });
125
+ return boundResponseMiddleware(undefined, { request, profile, logger });
120
126
  }
121
127
  }
122
128
  catch (e) {
123
129
  if (errorHandler && e instanceof Error) {
124
- return boundResponseMiddleware ? boundResponseMiddleware(errorHandler(e), { request, profile }) : errorHandler(e);
130
+ return boundResponseMiddleware
131
+ ? boundResponseMiddleware(errorHandler(e, logger), { request, profile, logger })
132
+ : errorHandler(e, logger);
125
133
  }
126
134
  throw e;
127
135
  }
@@ -45,8 +45,9 @@ const makeRouteClient = (initializer, config, route, authProvider) => {
45
45
  if (!status.includes(response.status)) {
46
46
  throw new Error('unexpected response from api');
47
47
  }
48
- return { status: response.status, load: loadResponse(response) };
48
+ return { status: response.status, headers: response.headers, load: loadResponse(response) };
49
49
  },
50
+ headers: response.headers,
50
51
  load: loadResponse(response),
51
52
  };
52
53
  });
@@ -48,7 +48,9 @@ export declare const browserAuthProvider: <C extends string = "auth">({ window,
48
48
  * gets an authorized url for an iframe src. sets params on the url and saves its
49
49
  * origin to trust releasing user identity to it
50
50
  */
51
- getAuthorizedEmbedUrl: (urlString: string) => string;
51
+ getAuthorizedEmbedUrl: (urlString: string, extraParams?: {
52
+ [key: string]: string;
53
+ } | undefined) => string;
52
54
  /**
53
55
  * gets second argument for `fetch` that has authentication token or cookie
54
56
  */
@@ -62,7 +62,7 @@ export const browserAuthProvider = ({ window, configSpace }) => (configProvider)
62
62
  const timeout = setTimeout(() => {
63
63
  window.removeEventListener('message', handler);
64
64
  reject(new Error('loading user identity timed out'));
65
- }, 100);
65
+ }, 5000);
66
66
  });
67
67
  /*
68
68
  * requests user identity from accounts api using given token or cookie
@@ -14,7 +14,9 @@ export declare const embeddedAuthProvider: (getUserData: UserDataLoader, { query
14
14
  window: Window;
15
15
  }) => {
16
16
  embeddedQueryValue: string;
17
- getAuthorizedEmbedUrl: (urlString: string) => string;
17
+ getAuthorizedEmbedUrl: (urlString: string, extraParams?: {
18
+ [key: string]: string;
19
+ } | undefined) => string;
18
20
  unmount: () => void;
19
21
  };
20
22
  export {};
@@ -1,3 +1,4 @@
1
+ import queryString from 'query-string';
1
2
  export var PostMessageTypes;
2
3
  (function (PostMessageTypes) {
3
4
  PostMessageTypes["ReceiveUser"] = "receive-user";
@@ -14,10 +15,11 @@ export const embeddedAuthProvider = (getUserData, { queryKey = 'auth', window })
14
15
  }
15
16
  };
16
17
  window.addEventListener('message', messageHandler);
17
- const getAuthorizedEmbedUrl = (urlString) => {
18
+ const getAuthorizedEmbedUrl = (urlString, extraParams) => {
18
19
  const url = new URL(urlString);
19
20
  trustedEmbeds.add(url.origin);
20
- url.searchParams.set(queryKey, embeddedQueryValue);
21
+ const params = queryString.parse(url.search);
22
+ url.search = queryString.stringify({ ...params, ...extraParams, [queryKey]: embeddedQueryValue });
21
23
  return url.href;
22
24
  };
23
25
  return {
@@ -0,0 +1 @@
1
+ export declare const createConsoleLogger: () => import(".").Logger;
@@ -0,0 +1,5 @@
1
+ import { createCoreLogger } from '.';
2
+ export const createConsoleLogger = () => createCoreLogger((level, event) => console[level](JSON.stringify({
3
+ eventType: level.toUpperCase(),
4
+ ...event,
5
+ })));
@@ -0,0 +1,14 @@
1
+ import { JsonCompatibleStruct } from '../../routing';
2
+ export declare enum Level {
3
+ Info = "info",
4
+ Warn = "warn",
5
+ Error = "error"
6
+ }
7
+ export declare type LogEvent = (level: Level, event: JsonCompatibleStruct) => void;
8
+ export interface Logger {
9
+ setContext: (obj: JsonCompatibleStruct) => void;
10
+ logEvent: LogEvent;
11
+ log: (message: string, level?: Level) => void;
12
+ createSubContext: () => Logger;
13
+ }
14
+ export declare const createCoreLogger: (driver: LogEvent, getParentContext?: (() => JsonCompatibleStruct) | undefined) => Logger;
@@ -0,0 +1,16 @@
1
+ export var Level;
2
+ (function (Level) {
3
+ Level["Info"] = "info";
4
+ Level["Warn"] = "warn";
5
+ Level["Error"] = "error";
6
+ })(Level || (Level = {}));
7
+ export const createCoreLogger = (driver, getParentContext) => {
8
+ const context = {};
9
+ const getContext = () => ({ ...getParentContext === null || getParentContext === void 0 ? void 0 : getParentContext(), ...context });
10
+ return {
11
+ logEvent: (level, event) => driver(level, { ...event, context: getContext() }),
12
+ log: (message, level = Level.Info) => driver(level, { message, context: getContext() }),
13
+ setContext: (obj) => { Object.assign(context, obj); },
14
+ createSubContext: () => createCoreLogger(driver, getContext),
15
+ };
16
+ };