@bitblit/ratchet-epsilon-common 6.0.146-alpha → 6.0.147-alpha

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 (164) hide show
  1. package/package.json +10 -9
  2. package/src/background/background-dynamo-log-table-handler.ts +44 -0
  3. package/src/background/background-entry.ts +4 -0
  4. package/src/background/background-execution-event-type.ts +9 -0
  5. package/src/background/background-execution-event.ts +9 -0
  6. package/src/background/background-execution-listener.ts +6 -0
  7. package/src/background/background-handler.ts +352 -0
  8. package/src/background/background-http-adapter-handler.ts +166 -0
  9. package/src/background/background-meta-response-internal.ts +5 -0
  10. package/src/background/background-process-handling.ts +6 -0
  11. package/src/background/background-process-log-table-entry.ts +11 -0
  12. package/src/background/background-queue-response-internal.ts +9 -0
  13. package/src/background/background-validator.ts +105 -0
  14. package/src/background/epsilon-background-process-error.ts +110 -0
  15. package/src/background/internal-background-entry.ts +10 -0
  16. package/src/background/manager/abstract-background-manager.ts +120 -0
  17. package/src/background/manager/aws-large-payload-s3-sqs-sns-background-manager.ts +87 -0
  18. package/src/background/manager/aws-sqs-sns-background-manager.ts +201 -0
  19. package/src/background/manager/background-manager-like.ts +44 -0
  20. package/src/background/manager/background-manager.spec.ts +89 -0
  21. package/src/background/manager/single-thread-local-background-manager.ts +58 -0
  22. package/src/background/s3-background-transaction-logger.ts +65 -0
  23. package/src/build/ratchet-epsilon-common-info.ts +19 -0
  24. package/src/built-in/background/echo-processor.ts +17 -0
  25. package/src/built-in/background/log-and-enqueue-echo-processor.ts +14 -0
  26. package/src/built-in/background/log-message-background-error-processor.ts +10 -0
  27. package/src/built-in/background/no-op-processor.ts +12 -0
  28. package/src/built-in/background/retry-processor.ts +51 -0
  29. package/src/built-in/background/sample-delay-processor.ts +15 -0
  30. package/src/built-in/background/sample-input-validated-processor-data.ts +4 -0
  31. package/src/built-in/background/sample-input-validated-processor.ts +14 -0
  32. package/src/built-in/built-in-trace-id-generators.ts +22 -0
  33. package/src/built-in/daemon/daemon-authorizer-function.ts +4 -0
  34. package/src/built-in/daemon/daemon-config.ts +9 -0
  35. package/src/built-in/daemon/daemon-group-selection-function.ts +3 -0
  36. package/src/built-in/daemon/daemon-handler.ts +87 -0
  37. package/src/built-in/daemon/daemon-process-state-list.ts +9 -0
  38. package/src/built-in/http/apollo/apollo-util.ts +43 -0
  39. package/src/built-in/http/apollo/default-epsilon-apollo-context.ts +11 -0
  40. package/src/built-in/http/apollo/epsilon-apollo-context-builder-options.ts +5 -0
  41. package/src/built-in/http/apollo/epsilon-lambda-apollo-context-function-argument.ts +6 -0
  42. package/src/built-in/http/apollo/epsilon-lambda-apollo-options.ts +11 -0
  43. package/src/built-in/http/apollo-filter.ts +151 -0
  44. package/src/built-in/http/built-in-auth-filters.ts +73 -0
  45. package/src/built-in/http/built-in-authorizers.ts +22 -0
  46. package/src/built-in/http/built-in-filters.spec.ts +26 -0
  47. package/src/built-in/http/built-in-filters.ts +300 -0
  48. package/src/built-in/http/built-in-handlers.ts +85 -0
  49. package/src/built-in/http/log-level-manipulation-filter.ts +26 -0
  50. package/src/built-in/http/run-handler-as-filter.spec.ts +67 -0
  51. package/src/built-in/http/run-handler-as-filter.ts +102 -0
  52. package/src/cli/ratchet-cli-handler.ts +23 -0
  53. package/src/cli/run-background-process-from-command-line.ts +32 -0
  54. package/src/config/background/background-aws-config.ts +8 -0
  55. package/src/config/background/background-config.ts +15 -0
  56. package/src/config/background/background-error-processor.ts +5 -0
  57. package/src/config/background/background-processor.ts +14 -0
  58. package/src/config/background/background-transaction-log.ts +9 -0
  59. package/src/config/background/background-transaction-logger.ts +6 -0
  60. package/src/config/cron/abstract-cron-entry.ts +17 -0
  61. package/src/config/cron/cron-background-entry.ts +17 -0
  62. package/src/config/cron/cron-config.ts +10 -0
  63. package/src/config/dynamo-db-config.ts +6 -0
  64. package/src/config/epsilon-config.ts +30 -0
  65. package/src/config/epsilon-lambda-event-handler.ts +12 -0
  66. package/src/config/epsilon-logger-config.ts +23 -0
  67. package/src/config/espilon-server-mode.ts +10 -0
  68. package/src/config/generic-aws-event-handler-function.ts +1 -0
  69. package/src/config/http/authorizer-function.ts +9 -0
  70. package/src/config/http/epsilon-authorization-context.ts +5 -0
  71. package/src/config/http/epsilon-cors-approach.ts +7 -0
  72. package/src/config/http/extended-api-gateway-event.ts +8 -0
  73. package/src/config/http/filter-chain-context.ts +15 -0
  74. package/src/config/http/filter-function.ts +3 -0
  75. package/src/config/http/handler-function.ts +4 -0
  76. package/src/config/http/http-config.ts +27 -0
  77. package/src/config/http/http-processing-config.ts +23 -0
  78. package/src/config/http/mapped-http-processing-config.ts +12 -0
  79. package/src/config/http/null-returned-object-handling.ts +7 -0
  80. package/src/config/inter-api/inter-api-aws-config.ts +5 -0
  81. package/src/config/inter-api/inter-api-config.ts +7 -0
  82. package/src/config/inter-api/inter-api-process-mapping.ts +11 -0
  83. package/src/config/local-server/local-server-event-logging-style.ts +8 -0
  84. package/src/config/local-server/local-server-http-method-handling.ts +7 -0
  85. package/src/config/local-server/local-server-options.ts +12 -0
  86. package/src/config/logging-trace-id-generator.ts +3 -0
  87. package/src/config/no-handlers-found-error.ts +6 -0
  88. package/src/config/open-api/open-api-document-components.ts +4 -0
  89. package/src/config/open-api/open-api-document.ts +7 -0
  90. package/src/config/s3-config.ts +8 -0
  91. package/src/config/sns-config.ts +7 -0
  92. package/src/config/sqs-config.ts +7 -0
  93. package/src/epsilon-build-properties.ts +21 -0
  94. package/src/epsilon-constants.ts +62 -0
  95. package/src/epsilon-global-handler.ts +238 -0
  96. package/src/epsilon-instance.ts +20 -0
  97. package/src/epsilon-logging-extension-processor.ts +19 -0
  98. package/src/http/auth/api-gateway-adapter-authentication-handler.ts +95 -0
  99. package/src/http/auth/auth0-web-token-manipulator.ts +69 -0
  100. package/src/http/auth/basic-auth-token.ts +7 -0
  101. package/src/http/auth/google-web-token-manipulator.spec.ts +15 -0
  102. package/src/http/auth/google-web-token-manipulator.ts +80 -0
  103. package/src/http/auth/jwt-ratchet-local-web-token-manipulator.ts +37 -0
  104. package/src/http/auth/local-web-token-manipulator.spec.ts +34 -0
  105. package/src/http/auth/local-web-token-manipulator.ts +114 -0
  106. package/src/http/auth/web-token-manipulator.ts +9 -0
  107. package/src/http/error/bad-gateway.ts +11 -0
  108. package/src/http/error/bad-request-error.ts +11 -0
  109. package/src/http/error/conflict-error.ts +12 -0
  110. package/src/http/error/forbidden-error.ts +12 -0
  111. package/src/http/error/gateway-timeout.ts +12 -0
  112. package/src/http/error/method-not-allowed-error.ts +12 -0
  113. package/src/http/error/misconfigured-error.ts +12 -0
  114. package/src/http/error/not-found-error.ts +12 -0
  115. package/src/http/error/not-implemented.ts +12 -0
  116. package/src/http/error/request-timeout-error.ts +12 -0
  117. package/src/http/error/service-unavailable.ts +12 -0
  118. package/src/http/error/too-many-requests-error.ts +12 -0
  119. package/src/http/error/unauthorized-error.ts +12 -0
  120. package/src/http/event-util.spec.ts +190 -0
  121. package/src/http/event-util.ts +272 -0
  122. package/src/http/response-util.spec.ts +117 -0
  123. package/src/http/response-util.ts +164 -0
  124. package/src/http/route/epsilon-router.ts +9 -0
  125. package/src/http/route/extended-auth-response-context.ts +7 -0
  126. package/src/http/route/route-and-parse.ts +8 -0
  127. package/src/http/route/route-mapping.ts +21 -0
  128. package/src/http/route/route-validator-config.ts +5 -0
  129. package/src/http/route/router-util.spec.ts +33 -0
  130. package/src/http/route/router-util.ts +314 -0
  131. package/src/http/web-handler.spec.ts +99 -0
  132. package/src/http/web-handler.ts +157 -0
  133. package/src/http/web-v2-handler.ts +34 -0
  134. package/src/inter-api/inter-api-entry.ts +8 -0
  135. package/src/inter-api/inter-api-util.spec.ts +77 -0
  136. package/src/inter-api/inter-api-util.ts +71 -0
  137. package/src/inter-api-manager.ts +75 -0
  138. package/src/lambda-event-handler/cron-epsilon-lambda-event-handler.spec.ts +130 -0
  139. package/src/lambda-event-handler/cron-epsilon-lambda-event-handler.ts +132 -0
  140. package/src/lambda-event-handler/dynamo-epsilon-lambda-event-handler.ts +42 -0
  141. package/src/lambda-event-handler/generic-sns-epsilon-lambda-event-handler.ts +38 -0
  142. package/src/lambda-event-handler/generic-sqs-epsilon-lambda-event-handler.ts +43 -0
  143. package/src/lambda-event-handler/inter-api-epsilon-lambda-event-handler.ts +33 -0
  144. package/src/lambda-event-handler/s3-epsilon-lambda-event-handler.ts +50 -0
  145. package/src/local-container-server.ts +128 -0
  146. package/src/local-server.spec.ts +16 -0
  147. package/src/local-server.ts +426 -0
  148. package/src/open-api-util/open-api-doc-modifications.ts +9 -0
  149. package/src/open-api-util/open-api-doc-modifier.spec.ts +22 -0
  150. package/src/open-api-util/open-api-doc-modifier.ts +90 -0
  151. package/src/open-api-util/yaml-combiner.spec.ts +26 -0
  152. package/src/open-api-util/yaml-combiner.ts +35 -0
  153. package/src/sample/sample-server-components-with-apollo.ts +87 -0
  154. package/src/sample/sample-server-components.ts +183 -0
  155. package/src/sample/sample-server-static-files.ts +614 -0
  156. package/src/sample/test-error-server.ts +140 -0
  157. package/src/util/aws-util.ts +89 -0
  158. package/src/util/context-global-data.ts +13 -0
  159. package/src/util/context-util.ts +156 -0
  160. package/src/util/cron-util.spec.ts +190 -0
  161. package/src/util/cron-util.ts +86 -0
  162. package/src/util/epsilon-config-parser.ts +90 -0
  163. package/src/util/epsilon-server-util.spec.ts +18 -0
  164. package/src/util/epsilon-server-util.ts +16 -0
@@ -0,0 +1,7 @@
1
+ // NOTE: This is a psuedo-enum to fix some issues with Typescript enums. See: https://exploringjs.com/tackling-ts/ch_enum-alternatives.html for details
2
+ export const LocalServerHttpMethodHandling = {
3
+ Uppercase: 'Uppercase',
4
+ Lowercase: 'Lowercase',
5
+ PassThru: 'PassThru',
6
+ };
7
+ export type LocalServerHttpMethodHandling = (typeof LocalServerHttpMethodHandling)[keyof typeof LocalServerHttpMethodHandling];
@@ -0,0 +1,12 @@
1
+ import { LocalServerHttpMethodHandling } from './local-server-http-method-handling.js';
2
+ import { LocalServerEventLoggingStyle } from "./local-server-event-logging-style.ts";
3
+ import { LoggerLevelName } from "@bitblit/ratchet-common/logger/logger-level-name";
4
+
5
+ export interface LocalServerOptions {
6
+ port?: number;
7
+ https?: boolean;
8
+ methodHandling?: LocalServerHttpMethodHandling;
9
+ eventLoggingStyle?: LocalServerEventLoggingStyle;
10
+ eventLoggingLevel?: LoggerLevelName;
11
+ graphQLIntrospectionEventLogLevel?: LoggerLevelName;
12
+ }
@@ -0,0 +1,3 @@
1
+ import { Context } from 'aws-lambda';
2
+
3
+ export type LoggingTraceIdGenerator = (event?: any, context?: Context) => string;
@@ -0,0 +1,6 @@
1
+ export class NoHandlersFoundError extends Error {
2
+ constructor(msg?: string) {
3
+ super(msg ?? 'No handlers found');
4
+ Object.setPrototypeOf(this, NoHandlersFoundError.prototype);
5
+ }
6
+ }
@@ -0,0 +1,4 @@
1
+ export interface OpenApiDocumentComponents {
2
+ securitySchemes: any[];
3
+ schemas: any[];
4
+ }
@@ -0,0 +1,7 @@
1
+ import { OpenApiDocumentComponents } from './open-api-document-components.js';
2
+ //import { OpenApiDocumentPath } from './open-api-document-path.js';
3
+
4
+ export interface OpenApiDocument {
5
+ components: OpenApiDocumentComponents;
6
+ paths: Record<string, any>[]; //OpenApiDocumentPath[];
7
+ }
@@ -0,0 +1,8 @@
1
+ import { GenericAwsEventHandlerFunction } from './generic-aws-event-handler-function.js';
2
+ import { S3Event } from 'aws-lambda';
3
+
4
+ export interface S3Config {
5
+ // S3 events mapped by bucket name
6
+ createHandlers: Map<string, GenericAwsEventHandlerFunction<S3Event>>;
7
+ removeHandlers: Map<string, GenericAwsEventHandlerFunction<S3Event>>;
8
+ }
@@ -0,0 +1,7 @@
1
+ import { GenericAwsEventHandlerFunction } from './generic-aws-event-handler-function.js';
2
+ import { SNSEvent } from 'aws-lambda';
3
+
4
+ export interface SnsConfig {
5
+ // Map of TopicARN to handler
6
+ handlers: Map<string, GenericAwsEventHandlerFunction<SNSEvent>>;
7
+ }
@@ -0,0 +1,7 @@
1
+ import { GenericAwsEventHandlerFunction } from './generic-aws-event-handler-function.js';
2
+ import { SQSEvent } from 'aws-lambda';
3
+
4
+ export interface SqsConfig {
5
+ // Map of TopicARN to handler
6
+ handlers: Map<string, GenericAwsEventHandlerFunction<SQSEvent>>;
7
+ }
@@ -0,0 +1,21 @@
1
+ import { StringRatchet } from '@bitblit/ratchet-common/lang/string-ratchet';
2
+
3
+ export class EpsilonBuildProperties {
4
+ // Prevent instantiation
5
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
6
+ private constructor() {}
7
+
8
+ public readonly buildVersion: string = 'LOCAL-SNAPSHOT';
9
+
10
+ public readonly buildHash: string = 'LOCAL-HASH';
11
+
12
+ public readonly buildBranch: string = 'LOCAL-BRANCH';
13
+
14
+ public readonly buildTag: string = 'LOCAL-TAG';
15
+
16
+ public get buildBranchOrTag(): string {
17
+ return StringRatchet.trimToNull(this.buildBranch) ? 'BRANCH:' + this.buildBranch : 'TAG:' + this.buildTag;
18
+ }
19
+
20
+ public readonly buildTime: string = 'LOCAL-TIME';
21
+ }
@@ -0,0 +1,62 @@
1
+ import { EpsilonGlobalHandler } from './epsilon-global-handler.js';
2
+ import { Logger } from '@bitblit/ratchet-common/logger/logger';
3
+ import { EsmRatchet } from '@bitblit/ratchet-common/lang/esm-ratchet';
4
+
5
+ export class EpsilonConstants {
6
+ public static readonly EPSILON_FINDER_DYNAMIC_IMPORT_PATH_ENV_NAME = 'EPSILON_FINDER_DYNAMIC_IMPORT_PATH';
7
+ public static readonly EPSILON_FINDER_FUNCTION_NAME_ENV_NAME = 'EPSILON_FINDER_FUNCTION_NAME';
8
+ public static readonly DEFAULT_EPSILON_FINDER_DYNAMIC_IMPORT_PATH = 'epsilon-global-handler-provider.js';
9
+ public static readonly DEFAULT_EPSILON_FINDER_FUNCTION_NAME = 'findEpsilonGlobalHandler';
10
+
11
+ public static readonly AUTH_HEADER_PREFIX: string = 'Bearer ';
12
+ public static readonly AUTH_HEADER_NAME: string = 'Authorization';
13
+
14
+ public static readonly BACKGROUND_SQS_TYPE_FIELD = 'BACKGROUND_TYPE';
15
+ public static readonly BACKGROUND_SNS_START_MARKER = 'BACKGROUND_START_MARKER';
16
+ public static readonly BACKGROUND_SNS_IMMEDIATE_RUN_FLAG = 'BACKGROUND_IMMEDIATE_RUN_FLAG';
17
+
18
+ public static readonly INTER_API_SNS_EVENT = 'EPSILON_INTER_API_EVENT';
19
+
20
+ private static load<T>(filePath: string, className: string): T {
21
+ Logger.info('Searching for %s : %s : %s', filePath, className, EsmRatchet.fetchDirName(import.meta.url));
22
+ let rval: T = null;
23
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
24
+ const val = require(filePath);
25
+ if (val) {
26
+ Logger.debug('Found %s - pulling object : %j : %s', filePath, Object.keys(val), className);
27
+ rval = val[className];
28
+ }
29
+ return rval;
30
+ }
31
+
32
+ public static async findDynamicImportEpsilonGlobalHandlerProvider(): Promise<EpsilonGlobalHandler> {
33
+ const importPath: string =
34
+ process.env[EpsilonConstants.EPSILON_FINDER_DYNAMIC_IMPORT_PATH_ENV_NAME] ||
35
+ EpsilonConstants.DEFAULT_EPSILON_FINDER_DYNAMIC_IMPORT_PATH;
36
+ const fnName: string =
37
+ process.env[EpsilonConstants.EPSILON_FINDER_FUNCTION_NAME_ENV_NAME] || EpsilonConstants.DEFAULT_EPSILON_FINDER_FUNCTION_NAME;
38
+ Logger.debug('Using epsilon finder dynamic import path : %s / %s', importPath, fnName);
39
+
40
+ let provider: any = null;
41
+ try {
42
+ provider = this.load(importPath, fnName);
43
+ } catch (err) {
44
+ Logger.error('Error loading provider : %s / %s : %s', importPath, fnName, err, err);
45
+ }
46
+
47
+ let rval: Promise<EpsilonGlobalHandler> = null;
48
+ if (provider) {
49
+ Logger.debug('Type2 is : %s', typeof provider);
50
+ //const fn = provider.fetchEpsilonGlobalHandler();
51
+ Logger.info('Got3 : %s : %s', provider, typeof provider);
52
+ rval = provider();
53
+ Logger.info('Rval3 is %s', rval);
54
+ }
55
+ return rval;
56
+ }
57
+ //producer: () => Promise<EpsilonGlobalHandler>
58
+
59
+ // Prevent instantiation
60
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
61
+ private constructor() {}
62
+ }
@@ -0,0 +1,238 @@
1
+ import { Context, ProxyResult } from 'aws-lambda';
2
+ import { Logger } from '@bitblit/ratchet-common/logger/logger';
3
+ import { ErrorRatchet } from '@bitblit/ratchet-common/lang/error-ratchet';
4
+ import { PromiseRatchet } from '@bitblit/ratchet-common/lang/promise-ratchet';
5
+ import { LoggerLevelName } from '@bitblit/ratchet-common/logger/logger-level-name';
6
+ import { LoggerOptions } from '@bitblit/ratchet-common/logger/logger-options';
7
+ import { LogMessageFormatType } from '@bitblit/ratchet-common/logger/log-message-format-type';
8
+ import { LogMessageProcessor } from '@bitblit/ratchet-common/logger/log-message-processor';
9
+ import { LoggerOutputFunction } from '@bitblit/ratchet-common/logger/logger-output-function';
10
+ import { TimeoutToken } from '@bitblit/ratchet-common/lang/timeout-token';
11
+ import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error';
12
+ import { EventUtil } from './http/event-util.js';
13
+ import { BackgroundEntry } from './background/background-entry.js';
14
+ import { EpsilonInstance } from './epsilon-instance.js';
15
+ import { ResponseUtil } from './http/response-util.js';
16
+ import { RequestTimeoutError } from './http/error/request-timeout-error.js';
17
+ import { InternalBackgroundEntry } from './background/internal-background-entry.js';
18
+ import { ContextUtil } from './util/context-util.js';
19
+ import { EpsilonLambdaEventHandler } from './config/epsilon-lambda-event-handler.js';
20
+ import { WebV2Handler } from './http/web-v2-handler.js';
21
+ import { InterApiEpsilonLambdaEventHandler } from './lambda-event-handler/inter-api-epsilon-lambda-event-handler.js';
22
+ import { GenericSnsEpsilonLambdaEventHandler } from './lambda-event-handler/generic-sns-epsilon-lambda-event-handler.js';
23
+ import { CronEpsilonLambdaEventHandler } from './lambda-event-handler/cron-epsilon-lambda-event-handler.js';
24
+ import { S3EpsilonLambdaEventHandler } from './lambda-event-handler/s3-epsilon-lambda-event-handler.js';
25
+ import { DynamoEpsilonLambdaEventHandler } from './lambda-event-handler/dynamo-epsilon-lambda-event-handler.js';
26
+ import { EpsilonLoggingExtensionProcessor } from './epsilon-logging-extension-processor.js';
27
+ import { GenericSqsEpsilonLambdaEventHandler } from './lambda-event-handler/generic-sqs-epsilon-lambda-event-handler.js';
28
+ import { NoHandlersFoundError } from './config/no-handlers-found-error.js';
29
+
30
+ /**
31
+ * This class functions as the adapter from a default Lambda function to the handlers exposed via Epsilon
32
+ */
33
+ export class EpsilonGlobalHandler {
34
+ private static LOGGER_CONFIGURED: boolean = false;
35
+ private static GLOBAL_INSTANCE_PROVIDER: () => Promise<EpsilonGlobalHandler>;
36
+
37
+ public static set globalInstanceProvider(input: () => Promise<EpsilonGlobalHandler>) {
38
+ EpsilonGlobalHandler.GLOBAL_INSTANCE_PROVIDER = input;
39
+ }
40
+
41
+ public static get globalInstanceProvider(): () => Promise<EpsilonGlobalHandler> {
42
+ return EpsilonGlobalHandler.GLOBAL_INSTANCE_PROVIDER;
43
+ }
44
+ private handlers: EpsilonLambdaEventHandler<any>[] = null;
45
+
46
+ constructor(private _epsilon: EpsilonInstance) {
47
+ // We only want to do this if it wasn't explicitly configured earlier
48
+ if (!EpsilonGlobalHandler.LOGGER_CONFIGURED) {
49
+ EpsilonGlobalHandler.configureDefaultLogger();
50
+ Logger.info('EpsilonLoggingConfiguration:Default logger configured');
51
+ } else {
52
+ Logger.info('EpsilonLoggingConfiguration:Skipping default logger config - already configured');
53
+ }
54
+
55
+ this.handlers = [
56
+ this._epsilon.webHandler,
57
+ new WebV2Handler(this._epsilon.webHandler),
58
+ this._epsilon.backgroundHandler,
59
+ new InterApiEpsilonLambdaEventHandler(this._epsilon),
60
+ new GenericSnsEpsilonLambdaEventHandler(this._epsilon),
61
+ new GenericSqsEpsilonLambdaEventHandler(this._epsilon),
62
+ new CronEpsilonLambdaEventHandler(this._epsilon),
63
+ new S3EpsilonLambdaEventHandler(this._epsilon),
64
+ new DynamoEpsilonLambdaEventHandler(this._epsilon),
65
+ ];
66
+ }
67
+
68
+ public static configureDefaultLogger(overrides?: LoggerOptions): void {
69
+ const output: LoggerOptions = overrides ? Object.assign({}, overrides) : {};
70
+ output.initialLevel = output.initialLevel ?? LoggerLevelName.info;
71
+ output.formatType = output.formatType ?? LogMessageFormatType.StructuredJson;
72
+ //output.trace;
73
+ output.globalVars = output.globalVars ?? {}; // No extra defaults for now
74
+ output.outputFunction = output.outputFunction ?? LoggerOutputFunction.StdOut;
75
+ output.ringBufferSize = output.ringBufferSize ?? 0;
76
+ const src: LogMessageProcessor[] = output.preProcessors || [];
77
+ output.preProcessors = src.concat([new EpsilonLoggingExtensionProcessor()]);
78
+ //output.preProcessors.push();
79
+
80
+ const _pre: LoggerOptions = Logger.getOptions();
81
+ Logger.changeDefaultOptions(output, true);
82
+ const _post: LoggerOptions = Logger.getOptions();
83
+ EpsilonGlobalHandler.LOGGER_CONFIGURED = true;
84
+ Logger.info('EpsilonLoggingConfiguration: Updated');
85
+ Logger.dumpOptionsIntoLog();
86
+ }
87
+
88
+ public get epsilon(): EpsilonInstance {
89
+ return this._epsilon;
90
+ }
91
+
92
+ public async processSingleBackgroundByParts<T>(
93
+ type: string,
94
+ data?: T,
95
+ overrideTraceId?: string,
96
+ overrideTraceDepth?: number,
97
+ ): Promise<boolean> {
98
+ return this.processSingleBackgroundEntry(this._epsilon.backgroundManager.createEntry(type, data), overrideTraceId, overrideTraceDepth);
99
+ }
100
+
101
+ public async processSingleBackgroundEntry(
102
+ e: BackgroundEntry<any>,
103
+ overrideTraceId?: string,
104
+ overrideTraceDepth?: number,
105
+ ): Promise<boolean> {
106
+ let rval: boolean = false;
107
+ if (e?.type) {
108
+ const internal: InternalBackgroundEntry<any> = await this._epsilon.backgroundManager.wrapEntryForInternal(
109
+ e,
110
+ overrideTraceId,
111
+ overrideTraceDepth,
112
+ );
113
+ rval = await this._epsilon.backgroundHandler.processSingleBackgroundEntry(internal);
114
+ Logger.info('Direct processed request %j to %s', e, rval);
115
+ } else {
116
+ Logger.error('Cannot process null/unnamed background entry');
117
+ }
118
+ return rval;
119
+ }
120
+
121
+ public async lambdaHandler(event: any, context: Context): Promise<any> {
122
+ let rval: any = null;
123
+ try {
124
+ if (this.epsilon.config.disableLastResortTimeout || !context || !context.getRemainingTimeInMillis()) {
125
+ rval = await this.innerLambdaHandler(event, context);
126
+ } else {
127
+ // Outer wrap timeout makes sure that we timeout even if the slow part is a filter instead of the controller
128
+ const tmp: any = await PromiseRatchet.timeout<ProxyResult>(
129
+ this.innerLambdaHandler(event, context),
130
+ 'EpsilonLastResortTimeout',
131
+ context.getRemainingTimeInMillis() - 1000,
132
+ ); // Reserve 1 second for cleanup
133
+ if (TimeoutToken.isTimeoutToken(tmp)) {
134
+ (tmp as TimeoutToken).writeToLog();
135
+ // Using the HTTP version since it can use it, and the background ones dont care about the response format
136
+ rval = ResponseUtil.errorResponse(RestfulApiHttpError.wrapError(new RequestTimeoutError('Timed out')));
137
+ } else {
138
+ rval = tmp;
139
+ }
140
+ }
141
+ } finally {
142
+ ContextUtil.clearContext();
143
+ }
144
+ return rval;
145
+ }
146
+
147
+ public async innerLambdaHandler(event: any, context: Context): Promise<any> {
148
+ ContextUtil.initContext(this._epsilon, event, context, 'TBD');
149
+ let rval: ProxyResult = null;
150
+ let errorHandler: (evt: any, context: Context, err: any) => Promise<ProxyResult> = EpsilonGlobalHandler.defaultProcessUncaughtError;
151
+ let noMatchingHandler: boolean = false;
152
+
153
+ try {
154
+ if (!this._epsilon) {
155
+ Logger.error('Config not found, abandoning');
156
+ return false;
157
+ }
158
+
159
+ // Setup logging
160
+ const logLevel: LoggerLevelName = EventUtil.calcLogLevelViaEventOrEnvParam(
161
+ Logger.getLevel(),
162
+ event,
163
+ this._epsilon.config.loggerConfig,
164
+ );
165
+ Logger.setLevel(logLevel);
166
+
167
+ if (
168
+ this._epsilon.config.loggerConfig &&
169
+ this._epsilon.config.loggerConfig.queryParamTracePrefixName &&
170
+ event.queryStringParameters &&
171
+ event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]
172
+ ) {
173
+ Logger.info('Setting trace prefix to %s', event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]);
174
+ Logger.updateTracePrefix(event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]);
175
+ }
176
+
177
+ let found: boolean = false;
178
+ for (let i = 0; i < this.handlers.length && !found; i++) {
179
+ const handler: EpsilonLambdaEventHandler<any> = this.handlers[i];
180
+ if (handler.handlesEvent(event)) {
181
+ found = true;
182
+ errorHandler = handler.processUncaughtError || errorHandler; // Override it, if the handler supports that
183
+ const label: string = handler.extractLabel(event, context);
184
+ ContextUtil.setProcessLabel(label);
185
+ Logger.logByLevel(
186
+ this._epsilon?.config?.loggerConfig?.epsilonStartEndMessageLogLevel || LoggerLevelName.info,
187
+ 'EvtStart: %s',
188
+ label,
189
+ );
190
+ try {
191
+ rval = await handler.processEvent(event, context);
192
+ } catch (err) {
193
+ if (err instanceof NoHandlersFoundError) {
194
+ // We found a generic handler to handle this event, but it didn't have any handlers for
195
+ // this specific message.
196
+ // Reset "found" flag to false, but still break the loop.
197
+ found = false;
198
+ break;
199
+ } else {
200
+ throw err;
201
+ }
202
+ }
203
+ Logger.logByLevel(
204
+ this._epsilon?.config?.loggerConfig?.epsilonStartEndMessageLogLevel || LoggerLevelName.info,
205
+ 'EvtEnd: %s',
206
+ label,
207
+ );
208
+ Logger.silly('EvtEnd:Value: %s Value: %j', label, rval);
209
+ }
210
+ }
211
+
212
+ if (!found) {
213
+ noMatchingHandler = true;
214
+ }
215
+ } catch (err) {
216
+ // Note: If your errorHandler throws an error its just gonna get thrown up, which is what we want
217
+ // since some of them actually NEED to rethrow errors to get auto-retries (eg, Dynamo)
218
+ rval = await errorHandler(event, context, err);
219
+ }
220
+
221
+ if (this.epsilon.config.throwErrorIfNoSuitableEventHandlers && noMatchingHandler) {
222
+ Logger.error('No matching handler found for event: %j', event);
223
+ throw new Error('No matching handler found for event');
224
+ }
225
+
226
+ return rval;
227
+ }
228
+
229
+ public static async defaultProcessUncaughtError(event: any, context: Context, err: any): Promise<ProxyResult> {
230
+ Logger.error('Error slipped out to outer edge (Default). Logging and returning log : %s', err, err);
231
+ const rval: ProxyResult = {
232
+ statusCode: 500,
233
+ body: JSON.stringify({ error: ErrorRatchet.safeStringifyErr(err) }),
234
+ isBase64Encoded: false,
235
+ };
236
+ return rval;
237
+ }
238
+ }
@@ -0,0 +1,20 @@
1
+ import { EpsilonConfig } from './config/epsilon-config.js';
2
+ import { WebHandler } from './http/web-handler.js';
3
+ import { BackgroundHandler } from './background/background-handler.js';
4
+ import { OpenApiDocument } from './config/open-api/open-api-document.js';
5
+ import { ModelValidator } from '@bitblit/ratchet-misc/model-validator/model-validator';
6
+ import { BackgroundManagerLike } from './background/manager/background-manager-like.js';
7
+
8
+ /**
9
+ * This interface just wraps up everything that gets created by the config parsing process so that
10
+ * I can hand it in a neat package to EpsilonGlobalHandler, rather than passing in a bunch of
11
+ * params on the constructor
12
+ */
13
+ export interface EpsilonInstance {
14
+ config: EpsilonConfig;
15
+ parsedOpenApiDoc: OpenApiDocument;
16
+ modelValidator: ModelValidator;
17
+ webHandler: WebHandler;
18
+ backgroundHandler: BackgroundHandler;
19
+ backgroundManager: BackgroundManagerLike;
20
+ }
@@ -0,0 +1,19 @@
1
+ import { LogMessageProcessor } from '@bitblit/ratchet-common/logger/log-message-processor';
2
+ import { LogMessage } from '@bitblit/ratchet-common/logger/log-message';
3
+ import { ContextUtil } from './util/context-util.js';
4
+
5
+ export class EpsilonLoggingExtensionProcessor implements LogMessageProcessor {
6
+ public process(msg: LogMessage): LogMessage {
7
+ msg.params = Object.assign({}, msg.params || {}, ContextUtil.fetchLogVariables());
8
+ msg.params['tester'] = Date.now();
9
+ msg.params['awsRequestId'] = ContextUtil.currentRequestId();
10
+ //msg.params['epoch'] = msg.timestamp;
11
+ msg.params['traceId'] = ContextUtil.currentTraceId();
12
+ msg.params['traceDepth'] = ContextUtil.currentTraceDepth();
13
+ msg.params['procLabel'] = ContextUtil.currentProcessLabel();
14
+ return msg;
15
+ }
16
+ public label(): string {
17
+ return 'EpsilonLoggingExtensionProcessor';
18
+ }
19
+ }
@@ -0,0 +1,95 @@
1
+ import { AuthResponse, AuthResponseContext, Callback, Context, CustomAuthorizerEvent, PolicyDocument } from 'aws-lambda';
2
+ import { Logger } from '@bitblit/ratchet-common/logger/logger';
3
+ import { LocalWebTokenManipulator } from './local-web-token-manipulator.js';
4
+ import { EpsilonConstants } from '../../epsilon-constants.js';
5
+ import { JwtTokenBase } from '@bitblit/ratchet-common/jwt/jwt-token-base';
6
+
7
+ /**
8
+ * This class is to simplify if the user wants to use a AWS Gateway authorizer in conjunction with Epsilon
9
+ */
10
+ export class ApiGatewayAdapterAuthenticationHandler {
11
+ private webTokenManipulator: LocalWebTokenManipulator<JwtTokenBase>;
12
+
13
+ constructor(issuer: string, encryptionKeys: string) {
14
+ this.webTokenManipulator = new LocalWebTokenManipulator<JwtTokenBase>([encryptionKeys], issuer);
15
+ }
16
+
17
+ /**
18
+ * This is the default authorizer - parses the incoming JWT token and sticks it
19
+ * into context (or blocks if none/invalid found)
20
+ * @param event
21
+ * @param {Context} context
22
+ * @param {Callback} callback
23
+ */
24
+ public lambdaHandler(event: CustomAuthorizerEvent, context: Context, callback: Callback): void {
25
+ Logger.info('Got event : %j', event);
26
+
27
+ const srcString = ApiGatewayAdapterAuthenticationHandler.extractTokenStringFromAuthorizerEvent(event);
28
+
29
+ if (srcString) {
30
+ const methodArn = event.methodArn;
31
+
32
+ this.webTokenManipulator
33
+ .parseAndValidateJWTStringAsync(srcString)
34
+ .then((parsed) => {
35
+ if (parsed) {
36
+ callback(null, this.createPolicy(methodArn, srcString, parsed));
37
+ } else {
38
+ Logger.info('Invalid bearer token');
39
+ callback(new Error('Unauthorized')); // Required by Lambda
40
+ }
41
+ })
42
+ .catch((err) => {
43
+ Logger.error('Exception parsing token : %s', err);
44
+ callback(new Error('Unauthorized')); // Required by Lambda
45
+ });
46
+ } else {
47
+ Logger.info('Token not supplied');
48
+ callback(new Error('Unauthorized')); // Required by Lambda
49
+ }
50
+ }
51
+
52
+ private createPolicy(methodArn: string, srcString: string, userOb: any): AuthResponse {
53
+ // If we reached here, create a policy document
54
+ // parse the ARN from the incoming event
55
+ const tmp = methodArn.split(':'); // event.methodArn;
56
+ const apiGatewayArnTmp = tmp[5].split('/');
57
+ const awsAccountId = tmp[4];
58
+ const region = tmp[3];
59
+ const stage = apiGatewayArnTmp[1];
60
+ const restApiId = apiGatewayArnTmp[0];
61
+
62
+ const response: AuthResponse = {
63
+ principalId: 'user',
64
+ policyDocument: {
65
+ Version: '2012-10-17',
66
+ Statement: [
67
+ {
68
+ Action: 'execute-api:Invoke',
69
+ Effect: 'Allow',
70
+ Resource: ['arn:aws:execute-api:' + region + ':' + awsAccountId + ':' + restApiId + '/' + stage + '/*/*'],
71
+ },
72
+ ],
73
+ } as PolicyDocument,
74
+ // Context matches what would come in ExtendedAuthResponseContext if using epsilon auth
75
+ context: {
76
+ userJSON: JSON.stringify(userOb),
77
+ srcData: srcString, // Put this in in-case we are doing a token update
78
+ } as AuthResponseContext,
79
+ } as AuthResponse;
80
+
81
+ return response;
82
+ }
83
+
84
+ public static extractTokenStringFromAuthorizerEvent(event: CustomAuthorizerEvent): string {
85
+ Logger.silly('Extracting token from event : %j', event);
86
+ let rval: string = null;
87
+ if (event && event.authorizationToken) {
88
+ const token: string = event.authorizationToken;
89
+ if (token && token.startsWith(EpsilonConstants.AUTH_HEADER_PREFIX)) {
90
+ rval = token.substring(EpsilonConstants.AUTH_HEADER_PREFIX.length); // Strip "Bearer "
91
+ }
92
+ }
93
+ return rval;
94
+ }
95
+ }
@@ -0,0 +1,69 @@
1
+ import { Logger } from '@bitblit/ratchet-common/logger/logger';
2
+ import { StringRatchet } from '@bitblit/ratchet-common/lang/string-ratchet';
3
+ import { JwtTokenBase } from '@bitblit/ratchet-common/jwt/jwt-token-base';
4
+ import jwt from 'jsonwebtoken';
5
+ import jwks from 'jwks-rsa';
6
+ import { WebTokenManipulator } from './web-token-manipulator.js';
7
+
8
+ export class Auth0WebTokenManipulator implements WebTokenManipulator<JwtTokenBase> {
9
+ private jwksClient: any;
10
+
11
+ constructor(
12
+ private clientId: string,
13
+ private jwksUri: string,
14
+ private issuer: string,
15
+ ) {}
16
+
17
+ public async extractTokenFromAuthorizationHeader(authHeader: string): Promise<JwtTokenBase> {
18
+ let tokenString: string = StringRatchet.trimToEmpty(authHeader);
19
+ if (tokenString.toLowerCase().startsWith('bearer ')) {
20
+ tokenString = tokenString.substring(7);
21
+ }
22
+ const validated: JwtTokenBase = tokenString ? await this.parseAndValidateAuth0Token(tokenString, false) : null;
23
+ return validated;
24
+ }
25
+
26
+ public async parseAndValidateAuth0Token(auth0Token: string, allowExpired: boolean = false): Promise<JwtTokenBase> {
27
+ Logger.debug('Validating Auth0 token : %s', StringRatchet.obscure(auth0Token, 4));
28
+
29
+ const fullToken: any = jwt.decode(auth0Token, { complete: true });
30
+ const kid: string = fullToken?.header?.kid;
31
+ const nowEpochSeconds: number = Math.floor(new Date().getTime() / 1000);
32
+
33
+ const pubKey: string = await this.fetchSigningKey(kid as string);
34
+ const validated: any = jwt.verify(auth0Token, pubKey, {
35
+ audience: this.clientId,
36
+ issuer: this.issuer,
37
+ ignoreExpiration: allowExpired,
38
+ clockTimestamp: nowEpochSeconds,
39
+ });
40
+
41
+ return validated;
42
+ }
43
+
44
+ private async fetchSigningKey(kid: string): Promise<string> {
45
+ const jClient: any = await this.fetchJwksClient();
46
+
47
+ return new Promise<string>((res, rej) => {
48
+ jClient.getSigningKey(kid, (err, key) => {
49
+ if (err) {
50
+ rej(err);
51
+ } else {
52
+ res(key.publicKey || key.rsaPublicKey);
53
+ }
54
+ });
55
+ });
56
+ }
57
+
58
+ private async fetchJwksClient(): Promise<any> {
59
+ if (!this.jwksClient) {
60
+ this.jwksClient = jwks({
61
+ cache: true,
62
+ cacheMaxEntries: 5,
63
+ cacheMaxAge: 1000 * 60 * 60 * 10,
64
+ jwksUri: this.jwksUri,
65
+ });
66
+ }
67
+ return this.jwksClient;
68
+ }
69
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Simple decoding of a Basic Authorization header
3
+ */
4
+ export interface BasicAuthToken {
5
+ username: string;
6
+ password: string;
7
+ }
@@ -0,0 +1,15 @@
1
+ import { GoogleWebTokenManipulator } from './google-web-token-manipulator.js';
2
+ import { JwtTokenBase } from '@bitblit/ratchet-common/jwt/jwt-token-base';
3
+ import { describe, expect, test } from 'vitest';
4
+
5
+ describe('#googleWebTokenManipulator', function () {
6
+ test.skip('should extract a token', async () => {
7
+ const token: string = 'TOKEN_HERE';
8
+ const clientId: string = 'CLIENT_HERE';
9
+
10
+ const svc: GoogleWebTokenManipulator = new GoogleWebTokenManipulator(clientId);
11
+ const res: JwtTokenBase = await svc.parseAndValidateGoogleToken<any>(token, false);
12
+
13
+ expect(res).toBeTruthy();
14
+ });
15
+ });