@bitblit/epsilon
Version:
Tiny adapter to simplify building API gateway Lambda APIS
255 lines (251 loc) • 14.8 kB
JavaScript
;
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