@whook/gcp-functions 8.5.1 → 9.0.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.
@@ -16,6 +16,7 @@ import type {
16
16
  Initializer,
17
17
  Dependencies,
18
18
  Service,
19
+ ServiceInitializerWrapper,
19
20
  } from 'knifecycle';
20
21
  import type { WhookBuildConstantsService } from '@whook/whook';
21
22
  import type { WhookRawOperation } from '@whook/http-router';
@@ -23,6 +24,127 @@ import type { LogService } from 'common-services';
23
24
  import type { OpenAPIV3 } from 'openapi-types';
24
25
  import type { WhookAPIOperationGCPFunctionConfig } from '..';
25
26
 
27
+ const initializerWrapper: ServiceInitializerWrapper<
28
+ Autoloader<Initializer<Dependencies, Service>>,
29
+ Dependencies
30
+ > = (async (
31
+ {
32
+ BUILD_CONSTANTS = {},
33
+ $injector,
34
+ $instance,
35
+ log = noop,
36
+ }: {
37
+ BUILD_CONSTANTS?: WhookBuildConstantsService;
38
+ $injector: Injector<Service>;
39
+ $instance: Knifecycle;
40
+ log: LogService;
41
+ },
42
+ $autoload: Autoloader<Initializer<Dependencies, Service>>,
43
+ ): Promise<
44
+ (serviceName: string) => Promise<{
45
+ initializer: Initializer<Dependencies, Service>;
46
+ path: string;
47
+ }>
48
+ > => {
49
+ let API: OpenAPIV3.Document;
50
+ let OPERATION_APIS: WhookRawOperation<WhookAPIOperationGCPFunctionConfig>[];
51
+ const getAPIOperation = (() => {
52
+ return async (serviceName) => {
53
+ // eslint-disable-next-line
54
+ API = API || (await $injector(['API'])).API;
55
+ // eslint-disable-next-line
56
+ OPERATION_APIS =
57
+ OPERATION_APIS ||
58
+ getOpenAPIOperations<WhookAPIOperationGCPFunctionConfig>(API);
59
+
60
+ const OPERATION = OPERATION_APIS.find(
61
+ (operation) =>
62
+ serviceName ===
63
+ (((operation['x-whook'] || {}).sourceOperationId &&
64
+ 'OPERATION_API_' +
65
+ (operation['x-whook'] || {}).sourceOperationId) ||
66
+ 'OPERATION_API_' + operation.operationId) +
67
+ ((operation['x-whook'] || {}).suffix || ''),
68
+ );
69
+
70
+ if (!OPERATION) {
71
+ log('error', '💥 - Unable to find a lambda operation definition!');
72
+ throw new YError('E_OPERATION_NOT_FOUND', serviceName);
73
+ }
74
+
75
+ // eslint-disable-next-line
76
+ const OPERATION_API = cleanupOpenAPI({
77
+ ...API,
78
+ paths: {
79
+ [OPERATION.path]: {
80
+ [OPERATION.method]: API.paths[OPERATION.path]?.[OPERATION.method],
81
+ },
82
+ },
83
+ });
84
+
85
+ return {
86
+ ...OPERATION_API,
87
+ paths: {
88
+ [OPERATION.path]: {
89
+ [OPERATION.method]: (
90
+ await dereferenceOpenAPIOperations(OPERATION_API, [
91
+ {
92
+ path: OPERATION.path,
93
+ method: OPERATION.method,
94
+ ...OPERATION_API.paths[OPERATION.path]?.[OPERATION.method],
95
+ parameters: OPERATION.parameters,
96
+ },
97
+ ])
98
+ )[0],
99
+ },
100
+ },
101
+ };
102
+ };
103
+ })();
104
+
105
+ log('debug', '🤖 - Initializing the `$autoload` build wrapper.');
106
+
107
+ return async (serviceName) => {
108
+ try {
109
+ // TODO: add initializer map to knifecycle public API
110
+ const initializer = ($instance as any)._initializers.get(serviceName);
111
+
112
+ if (initializer && initializer[SPECIAL_PROPS.TYPE] === 'constant') {
113
+ log(
114
+ 'debug',
115
+ `🤖 - Reusing a constant initializer directly from the Knifecycle instance: "${serviceName}".`,
116
+ );
117
+ return {
118
+ initializer,
119
+ path: `instance://${serviceName}`,
120
+ };
121
+ }
122
+
123
+ if (serviceName.startsWith('OPERATION_API_')) {
124
+ const OPERATION_API = await getAPIOperation(serviceName);
125
+
126
+ return {
127
+ initializer: constant(serviceName, OPERATION_API),
128
+ path: `api://${serviceName}`,
129
+ };
130
+ }
131
+
132
+ if (BUILD_CONSTANTS[serviceName]) {
133
+ return {
134
+ initializer: constant(serviceName, BUILD_CONSTANTS[serviceName]),
135
+ path: `constant://${serviceName}`,
136
+ };
137
+ }
138
+
139
+ return $autoload(serviceName);
140
+ } catch (err) {
141
+ log('error', `Build error while loading "${serviceName}".`);
142
+ log('error-stack', (err as Error).stack || 'no_stack_trace');
143
+ throw err;
144
+ }
145
+ };
146
+ }) as any;
147
+
26
148
  /**
27
149
  * Wrap the _autoload service in order to build AWS
28
150
  * Lambda compatible code.
@@ -39,123 +161,5 @@ import type { WhookAPIOperationGCPFunctionConfig } from '..';
39
161
  */
40
162
  export default alsoInject(
41
163
  ['?BUILD_CONSTANTS', '$instance', '$injector', '?log'],
42
- wrapInitializer(
43
- async (
44
- {
45
- BUILD_CONSTANTS = {},
46
- $injector,
47
- $instance,
48
- log = noop,
49
- }: {
50
- BUILD_CONSTANTS?: WhookBuildConstantsService;
51
- $injector: Injector<Service>;
52
- $instance: Knifecycle<Dependencies>;
53
- log: LogService;
54
- },
55
- $autoload: Autoloader,
56
- ): Promise<
57
- (serviceName: string) => Promise<{
58
- initializer: Initializer<Dependencies, Service>;
59
- path: string;
60
- }>
61
- > => {
62
- let API: OpenAPIV3.Document;
63
- let OPERATION_APIS: WhookRawOperation<WhookAPIOperationGCPFunctionConfig>[];
64
- const getAPIOperation = (() => {
65
- return async (serviceName) => {
66
- // eslint-disable-next-line
67
- API = API || (await $injector(['API'])).API;
68
- // eslint-disable-next-line
69
- OPERATION_APIS =
70
- OPERATION_APIS ||
71
- getOpenAPIOperations<WhookAPIOperationGCPFunctionConfig>(API);
72
-
73
- const OPERATION = OPERATION_APIS.find(
74
- (operation) =>
75
- serviceName ===
76
- (((operation['x-whook'] || {}).sourceOperationId &&
77
- 'OPERATION_API_' +
78
- (operation['x-whook'] || {}).sourceOperationId) ||
79
- 'OPERATION_API_' + operation.operationId) +
80
- ((operation['x-whook'] || {}).suffix || ''),
81
- );
82
-
83
- if (!OPERATION) {
84
- log('error', '💥 - Unable to find a lambda operation definition!');
85
- throw new YError('E_OPERATION_NOT_FOUND', serviceName);
86
- }
87
-
88
- // eslint-disable-next-line
89
- const OPERATION_API = cleanupOpenAPI({
90
- ...API,
91
- paths: {
92
- [OPERATION.path]: {
93
- [OPERATION.method]: API.paths[OPERATION.path][OPERATION.method],
94
- },
95
- },
96
- });
97
-
98
- return {
99
- ...OPERATION_API,
100
- paths: {
101
- [OPERATION.path]: {
102
- [OPERATION.method]: (
103
- await dereferenceOpenAPIOperations(OPERATION_API, [
104
- {
105
- path: OPERATION.path,
106
- method: OPERATION.method,
107
- ...OPERATION_API.paths[OPERATION.path][OPERATION.method],
108
- parameters: OPERATION.parameters,
109
- },
110
- ])
111
- )[0],
112
- },
113
- },
114
- };
115
- };
116
- })();
117
-
118
- log('debug', '🤖 - Initializing the `$autoload` build wrapper.');
119
-
120
- return async (serviceName) => {
121
- try {
122
- // TODO: add initializer map to knifecycle public API
123
- const initializer = ($instance as any)._initializers.get(serviceName);
124
-
125
- if (initializer && initializer[SPECIAL_PROPS.TYPE] === 'constant') {
126
- log(
127
- 'debug',
128
- `🤖 - Reusing a constant initializer directly from the Knifecycle instance: "${serviceName}".`,
129
- );
130
- return {
131
- initializer,
132
- path: `instance://${serviceName}`,
133
- };
134
- }
135
-
136
- if (serviceName.startsWith('OPERATION_API_')) {
137
- const OPERATION_API = await getAPIOperation(serviceName);
138
-
139
- return {
140
- initializer: constant(serviceName, OPERATION_API),
141
- path: `api://${serviceName}`,
142
- };
143
- }
144
-
145
- if (BUILD_CONSTANTS[serviceName]) {
146
- return {
147
- initializer: constant(serviceName, BUILD_CONSTANTS[serviceName]),
148
- path: `constant://${serviceName}`,
149
- };
150
- }
151
-
152
- return $autoload(serviceName);
153
- } catch (err) {
154
- log('error', `Build error while loading "${serviceName}".`);
155
- log('stack', err.stack);
156
- }
157
- };
158
- },
159
- initAutoload,
160
- ),
164
+ wrapInitializer(initializerWrapper as any, initAutoload),
161
165
  );
@@ -2,6 +2,6 @@ import initLogService from './log';
2
2
 
3
3
  describe('initLogService', () => {
4
4
  it('should work', async () => {
5
- await initLogService();
5
+ await initLogService({});
6
6
  });
7
7
  });
@@ -88,7 +88,7 @@ export default function wrapHandlerForAWSHTTPFunction<
88
88
  ],
89
89
  reuseSpecialProps(
90
90
  initHandler,
91
- initHandlerForAWSHTTPFunction.bind(
91
+ (initHandlerForAWSHTTPFunction as any).bind(
92
92
  null,
93
93
  initHandler,
94
94
  ) as ServiceInitializer<D, S>,
@@ -97,7 +97,7 @@ export default function wrapHandlerForAWSHTTPFunction<
97
97
  }
98
98
 
99
99
  async function initHandlerForAWSHTTPFunction(
100
- initHandler: ServiceInitializer<unknown, WhookHandler>,
100
+ initHandler: ServiceInitializer<Dependencies<any>, WhookHandler>,
101
101
  {
102
102
  OPERATION_API,
103
103
  WRAPPERS,
@@ -125,9 +125,9 @@ async function initHandlerForAWSHTTPFunction(
125
125
  verbose: DEBUG_NODE_ENVS.includes(NODE_ENV),
126
126
  strict: true,
127
127
  logger: {
128
- log: (...args) => log('debug', ...args),
129
- warn: (...args) => log('warning', ...args),
130
- error: (...args) => log('error', ...args),
128
+ log: (...args) => log?.('debug', ...args),
129
+ warn: (...args) => log?.('warning', ...args),
130
+ error: (...args) => log?.('error', ...args),
131
131
  },
132
132
  useDefaults: true,
133
133
  coerceTypes: true,
@@ -213,10 +213,10 @@ async function handleForAWSHTTPFunction(
213
213
  req,
214
214
  res,
215
215
  ) {
216
- const debugging = DEBUG_NODE_ENVS.includes(NODE_ENV);
216
+ const debugging = (DEBUG_NODE_ENVS || []).includes(NODE_ENV);
217
217
  const bufferLimit = bytes.parse(BUFFER_LIMIT);
218
218
 
219
- log(
219
+ log?.(
220
220
  'info',
221
221
  'GCP_FUNCTIONS_REQUEST',
222
222
  JSON.stringify({
@@ -234,7 +234,7 @@ async function handleForAWSHTTPFunction(
234
234
  let responseLog;
235
235
  let responseSpec;
236
236
 
237
- log(
237
+ log?.(
238
238
  'debug',
239
239
  'REQUEST',
240
240
  JSON.stringify({
@@ -276,19 +276,21 @@ async function handleForAWSHTTPFunction(
276
276
  request.url.split(SEARCH_SEPARATOR)[0].length,
277
277
  );
278
278
 
279
- const pathParameters = OPERATION.path
280
- .split(PATH_SEPARATOR)
281
- .filter(identity)
282
- .map((part, index) => {
283
- const matches = /^\{([\d\w]+)\}$/i.exec(part);
284
-
285
- if (matches) {
286
- return {
287
- name: matches[1],
288
- value: parts[index],
289
- };
290
- }
291
- })
279
+ const pathParameters = (
280
+ OPERATION.path
281
+ .split(PATH_SEPARATOR)
282
+ .filter(identity)
283
+ .map((part, index) => {
284
+ const matches = /^\{([\d\w]+)\}$/i.exec(part);
285
+
286
+ if (matches) {
287
+ return {
288
+ name: matches[1],
289
+ value: parts[index],
290
+ };
291
+ }
292
+ }) as Array<{ name: string; value: string }>
293
+ )
292
294
  .filter(identity)
293
295
  .reduce(
294
296
  (accParameters, { name, value }) => ({
@@ -326,7 +328,7 @@ async function handleForAWSHTTPFunction(
326
328
  ...('undefined' !== typeof body ? { body } : {}),
327
329
  };
328
330
  } catch (err) {
329
- throw HTTPError.cast(err, 400);
331
+ throw HTTPError.cast(err as Error, 400);
330
332
  }
331
333
 
332
334
  response = await executeHandler(operation, handler, parameters);
@@ -366,9 +368,9 @@ async function handleForAWSHTTPFunction(
366
368
  type: 'success',
367
369
  status: response.status,
368
370
  };
369
- log('debug', JSON.stringify(responseLog));
371
+ log?.('debug', JSON.stringify(responseLog));
370
372
  } catch (err) {
371
- const castedError = HTTPError.cast(err);
373
+ const castedError = HTTPError.cast(err as Error);
372
374
 
373
375
  responseLog = {
374
376
  type: 'error',
@@ -378,7 +380,7 @@ async function handleForAWSHTTPFunction(
378
380
  stack: castedError.stack,
379
381
  };
380
382
 
381
- log('error', JSON.stringify(responseLog));
383
+ log?.('error', JSON.stringify(responseLog));
382
384
  response = {
383
385
  status: castedError.httpCode,
384
386
  headers: {
@@ -396,7 +398,7 @@ async function handleForAWSHTTPFunction(
396
398
  };
397
399
  }
398
400
 
399
- log(
401
+ log?.(
400
402
  'debug',
401
403
  'RESPONSE',
402
404
  JSON.stringify({
@@ -441,8 +443,8 @@ async function pipeResponseInGCPFResponse(
441
443
  response: WhookResponse,
442
444
  res,
443
445
  ): Promise<void> {
444
- Object.keys(response.headers).forEach((headerName) => {
445
- res.set(headerName, response.headers[headerName]);
446
+ Object.keys(response.headers || {}).forEach((headerName) => {
447
+ res.set(headerName, response.headers?.[headerName]);
446
448
  });
447
449
  res.status(response.status);
448
450