UNPKG

@bitblit/epsilon

Version:

Tiny adapter to simplify building API gateway Lambda APIS

255 lines (251 loc) 14.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SampleServerComponents = void 0; /** * This is an example of how to setup a local server for testing. Replace the createRouterConfig function * with your own. */ const common_1 = require("@bitblit/ratchet/common"); const server_1 = require("@apollo/server"); const graphql_tag_1 = require("graphql-tag"); const default_1 = require("@apollo/server/plugin/landingPage/default"); const epsilon_global_handler_1 = require("../epsilon-global-handler"); const built_in_handlers_1 = require("../built-in/http/built-in-handlers"); const local_web_token_manipulator_1 = require("../http/auth/local-web-token-manipulator"); const echo_processor_1 = require("../built-in/background/echo-processor"); const no_op_processor_1 = require("../built-in/background/no-op-processor"); const sample_delay_processor_1 = require("../built-in/background/sample-delay-processor"); const log_and_enqueue_echo_processor_1 = require("../built-in/background/log-and-enqueue-echo-processor"); const epsilon_config_parser_1 = require("../util/epsilon-config-parser"); const router_util_1 = require("../http/route/router-util"); const sample_input_validated_processor_1 = require("../built-in/background/sample-input-validated-processor"); const built_in_authorizers_1 = require("../built-in/http/built-in-authorizers"); const apollo_filter_1 = require("../apollo/http/apollo-filter"); const built_in_filters_1 = require("../built-in/http/built-in-filters"); const log_message_background_error_processor_1 = require("../built-in/background/log-message-background-error-processor"); const single_thread_local_background_manager_1 = require("../background/manager/single-thread-local-background-manager"); const sample_server_static_files_1 = require("./sample-server-static-files"); const apollo_util_1 = require("../apollo/http/apollo-util"); const epsilon_apollo_cors_method_1 = require("../apollo/http/epsilon-apollo-cors-method"); const local_server_1 = require("../local-server"); class SampleServerComponents { // Prevent instantiation // eslint-disable-next-line @typescript-eslint/no-empty-function constructor() { } static createSampleApollo() { return __awaiter(this, void 0, void 0, function* () { const gqlString = sample_server_static_files_1.SampleServerStaticFiles.SAMPLE_SERVER_GRAPHQL; common_1.Logger.silly('Creating apollo from : %s', gqlString); const typeDefs = (0, graphql_tag_1.gql)(gqlString); // Provide resolver functions for your schema fields const resolvers = { RootQueryType: { serverMeta: (root) => __awaiter(this, void 0, void 0, function* () { return { version: 'A1', serverTime: new Date().toISOString() }; }), forceTimeout: (root) => __awaiter(this, void 0, void 0, function* () { // This will be longer than the max timeout yield common_1.PromiseRatchet.wait(1000 * 60 * 30); return { placeholder: 'A1' }; }), }, }; const server = new server_1.ApolloServer({ introspection: true, typeDefs, resolvers, plugins: [ /* // Install a landing page plugin based on NODE_ENV process.env.NODE_ENV === 'production' ? ApolloServerPluginLandingPageProductionDefault({ graphRef: 'my-graph-id@my-graph-variant', footer: false, }) : ApolloServerPluginLandingPageLocalDefault({ footer: false }), */ (0, default_1.ApolloServerPluginLandingPageLocalDefault)({ footer: false }), ], }); // Need the server started before we start processing... yield server.start(); return server; }); } // Functions below here are for using as samples static createSampleEpsilonConfig(label) { return __awaiter(this, void 0, void 0, function* () { const yamlString = sample_server_static_files_1.SampleServerStaticFiles.SAMPLE_OPEN_API_DOC; const authorizers = new Map(); authorizers.set('SampleAuthorizer', (token, evt) => built_in_authorizers_1.BuiltInAuthorizers.simpleLoggedInAuth(token, evt)); authorizers.set('LogAuthorizer', (token, evt) => built_in_authorizers_1.BuiltInAuthorizers.simpleNoAuthenticationLogAccess(token, evt)); const handlers = new Map(); handlers.set('get /', (event, context) => built_in_handlers_1.BuiltInHandlers.sample(event, null, context)); handlers.set('get /meta/server', (event) => built_in_handlers_1.BuiltInHandlers.sample(event)); handlers.set('get /meta/user', (event) => built_in_handlers_1.BuiltInHandlers.sample(event)); handlers.set('get /meta/item/{itemId}', (event) => built_in_handlers_1.BuiltInHandlers.sample(event)); handlers.set('post /secure/access-token', (event) => built_in_handlers_1.BuiltInHandlers.sample(event)); handlers.set('get /multi/fixed', (event) => built_in_handlers_1.BuiltInHandlers.sample(event, 'fixed')); handlers.set('get /multi/{v}', (event) => built_in_handlers_1.BuiltInHandlers.sample(event, 'variable')); handlers.set('get /event', (event) => { return Promise.resolve({ statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(event, null, 2), }); }); handlers.set('get /err/{code}', (event) => { const err = common_1.ErrorRatchet.fErr('Fake Err : %j', event); err['statusCode'] = common_1.NumberRatchet.safeNumber(event.pathParameters['code']); throw err; }); handlers.set('get /meta/sample-item', (event) => __awaiter(this, void 0, void 0, function* () { const numberToUse = common_1.NumberRatchet.safeNumber(event.queryStringParameters['num']) || 5; const rval = { numberParam: numberToUse, nameParam: 'Test-String', }; return rval; })); handlers.set('post /meta/sample-item', (event) => __awaiter(this, void 0, void 0, function* () { const parsed = event.parsedBody; const forceFail = common_1.BooleanRatchet.parseBool(common_1.StringRatchet.trimToNull(event.queryStringParameters['forceFail'])) === true; if (forceFail) { parsed['numberParam'] = 'test'; // Should cause a failure outbound } return parsed; })); // GraphQL endpoints are handled by filter and aren't in the OpenAPI spec so no need to wire them here const tokenManipulator = new local_web_token_manipulator_1.LocalWebTokenManipulator(['abcd1234'], 'sample.erigir.com') .withParseFailureLogLevel(common_1.LoggerLevelName.debug) .withExtraDecryptionKeys(['abcdefabcdef']) .withOldKeyUseLogLevel(common_1.LoggerLevelName.info); const meta = router_util_1.RouterUtil.defaultHttpMetaProcessingConfigWithAuthenticationHeaderParsing(tokenManipulator); meta.timeoutMS = 10000; apollo_filter_1.ApolloFilter.addApolloFilterToList(meta.preFilters, new RegExp('.*graphql.*'), yield SampleServerComponents.createSampleApollo(), { context: (arg) => apollo_util_1.ApolloUtil.defaultEpsilonApolloContext(arg, tokenManipulator.jwtRatchet), timeoutMS: 5000, corsMethod: epsilon_apollo_cors_method_1.EpsilonApolloCorsMethod.All, }); /* { cors: { origin: '*', credentials: true, }, } as CreateHandlerOptions); */ meta.errorFilters.push((fCtx) => built_in_filters_1.BuiltInFilters.secureOutboundServerErrorForProduction(fCtx, 'Clean Internal Server Error', 500)); const preFiltersAllowingNull = Object.assign({}, meta); // TODO: This approach is pretty fragile... preFiltersAllowingNull.preFilters = Object.assign([], preFiltersAllowingNull.preFilters); preFiltersAllowingNull.preFilters.splice(8, 1); const cfg = { defaultMetaHandling: meta, handlers: handlers, authorizers: authorizers, overrideMetaHandling: [ { pathRegex: '/background', methods: null, config: Object.assign({}, meta, { overrideAuthorizerName: 'LogAuthorizer' }), }, { pathRegex: '/meta/server', methods: ['GET'], config: preFiltersAllowingNull, }, ], prefixesToStripBeforeRouteMatch: ['v0'], filterHandledRouteMatches: ['options .*'], }; const background = { //aws: { // queueUrl: 'FAKE-LOCAL', // notificationArn: 'FAKE-LOCAL', //}, httpMetaEndpoint: '/background/meta', httpSubmissionPath: '/background', implyTypeFromPathSuffix: false, processors: [ new echo_processor_1.EchoProcessor(), new no_op_processor_1.NoOpProcessor(), new sample_delay_processor_1.SampleDelayProcessor(), new sample_input_validated_processor_1.SampleInputValidatedProcessor(), new log_and_enqueue_echo_processor_1.LogAndEnqueueEchoProcessor(), ], errorProcessor: new log_message_background_error_processor_1.LogMessageBackgroundErrorProcessor(), }; const epsilonConfig = { label: label, openApiYamlString: yamlString, httpConfig: cfg, backgroundConfig: background, }; return epsilonConfig; }); } static createSampleEpsilonGlobalHandler(label) { return __awaiter(this, void 0, void 0, function* () { const epsilonConfig = yield SampleServerComponents.createSampleEpsilonConfig(label); const backgroundManager = new single_thread_local_background_manager_1.SingleThreadLocalBackgroundManager(); const epsilonInstance = epsilon_config_parser_1.EpsilonConfigParser.epsilonConfigToEpsilonInstance(epsilonConfig, backgroundManager); const rval = new epsilon_global_handler_1.EpsilonGlobalHandler(epsilonInstance); return rval; }); } static createSampleBatchOnlyEpsilonGlobalHandler(label) { return __awaiter(this, void 0, void 0, function* () { const epsilonConfig = yield SampleServerComponents.createSampleEpsilonConfig(label); epsilonConfig.httpConfig.handlers = new Map(); // Unused const byPassCfg = Object.assign({}, epsilonConfig.httpConfig.defaultMetaHandling); byPassCfg.preFilters = byPassCfg.preFilters.concat([ (fCtx) => built_in_filters_1.BuiltInFilters.autoRespond(fCtx, { message: 'Background Processing Only' }), ]); epsilonConfig.httpConfig.overrideMetaHandling = [ { pathRegex: '.*background.*', invertPathMatching: true, config: byPassCfg, }, ]; epsilonConfig.httpConfig.filterHandledRouteMatches = ['.*']; // Only want the batch handling const backgroundManager = new single_thread_local_background_manager_1.SingleThreadLocalBackgroundManager(); const epsilonInstance = epsilon_config_parser_1.EpsilonConfigParser.epsilonConfigToEpsilonInstance(epsilonConfig, backgroundManager); const rval = new epsilon_global_handler_1.EpsilonGlobalHandler(epsilonInstance); return rval; }); } static runSampleBatchOnlyServerFromCliArgs(args) { return __awaiter(this, void 0, void 0, function* () { common_1.Logger.setLevel(common_1.LoggerLevelName.debug); const handler = yield SampleServerComponents.createSampleBatchOnlyEpsilonGlobalHandler('SampleBatchOnlyLocalServer-' + Date.now()); const testServer = new local_server_1.LocalServer(handler); const res = yield testServer.runServer(); common_1.Logger.info('Res was : %s', res); }); } static runSampleLocalServerFromCliArgs(args) { return __awaiter(this, void 0, void 0, function* () { common_1.Logger.setLevel(common_1.LoggerLevelName.debug); const localTokenHandler = new local_web_token_manipulator_1.LocalWebTokenManipulator(['abcd1234'], 'sample-server'); const token = yield localTokenHandler.createJWTStringAsync('asdf', {}, ['USER'], 3600); common_1.Logger.info('Use token: %s', token); const handler = yield SampleServerComponents.createSampleEpsilonGlobalHandler('SampleLocalServer-' + Date.now()); const testServer = new local_server_1.LocalServer(handler, 8888, true); const res = yield testServer.runServer(); common_1.Logger.info('Res was : %s', res); }); } } exports.SampleServerComponents = SampleServerComponents; //# sourceMappingURL=sample-server-components.js.map