@yopdev/dev-server 3.0.1 → 3.0.2-RC1

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 (92) hide show
  1. package/.github/workflows/npm-publish.yml +33 -0
  2. package/__tests__/bootstrap.test.ts +89 -0
  3. package/__tests__/deferred.test.ts +86 -0
  4. package/__tests__/event-proxy.test.ts +42 -0
  5. package/__tests__/lambda-http-proxy.test.ts +179 -0
  6. package/jest.config.js +7 -0
  7. package/package.json +2 -5
  8. package/src/assert.ts +4 -0
  9. package/src/cloudformation-dynamodb-table.ts +97 -0
  10. package/src/cloudformation-event-proxy.ts +61 -0
  11. package/src/cloudformation-lambda-http-proxy.ts +125 -0
  12. package/src/cloudformation.ts +95 -0
  13. package/src/config.ts +34 -0
  14. package/src/container.ts +82 -0
  15. package/src/deferred.ts +60 -0
  16. package/src/dev-server.ts +78 -0
  17. package/src/dynamodb.ts +62 -0
  18. package/src/event-proxy.ts +101 -0
  19. package/src/factories.ts +19 -0
  20. package/src/http-server.ts +59 -0
  21. package/src/index.ts +32 -0
  22. package/src/internal-queue.ts +89 -0
  23. package/src/lambda-http-proxy.ts +111 -0
  24. package/src/localstack.ts +74 -0
  25. package/src/mappers.ts +231 -0
  26. package/src/pre-traffic-hooks.ts +24 -0
  27. package/src/responses.ts +28 -0
  28. package/src/s3.ts +24 -0
  29. package/src/scheduled-tasks.ts +31 -0
  30. package/src/services.ts +46 -0
  31. package/src/sns-http-proxy.ts +109 -0
  32. package/src/sns.ts +49 -0
  33. package/src/sqs.ts +46 -0
  34. package/src/stoppable.ts +10 -0
  35. package/src/tunnel.ts +32 -0
  36. package/tsconfig.json +9 -0
  37. package/dist/src/assert.d.ts +0 -1
  38. package/dist/src/assert.js +0 -9
  39. package/dist/src/cloudformation-dynamodb-table.d.ts +0 -13
  40. package/dist/src/cloudformation-dynamodb-table.js +0 -45
  41. package/dist/src/cloudformation-event-proxy.d.ts +0 -13
  42. package/dist/src/cloudformation-event-proxy.js +0 -25
  43. package/dist/src/cloudformation-lambda-http-proxy.d.ts +0 -14
  44. package/dist/src/cloudformation-lambda-http-proxy.js +0 -62
  45. package/dist/src/cloudformation.d.ts +0 -28
  46. package/dist/src/cloudformation.js +0 -50
  47. package/dist/src/config.d.ts +0 -31
  48. package/dist/src/config.js +0 -2
  49. package/dist/src/container.d.ts +0 -18
  50. package/dist/src/container.js +0 -33
  51. package/dist/src/deferred.d.ts +0 -4
  52. package/dist/src/deferred.js +0 -45
  53. package/dist/src/dev-server.d.ts +0 -19
  54. package/dist/src/dev-server.js +0 -63
  55. package/dist/src/dynamodb.d.ts +0 -16
  56. package/dist/src/dynamodb.js +0 -48
  57. package/dist/src/event-proxy.d.ts +0 -13
  58. package/dist/src/event-proxy.js +0 -68
  59. package/dist/src/factories.d.ts +0 -3
  60. package/dist/src/factories.js +0 -16
  61. package/dist/src/http-server.d.ts +0 -25
  62. package/dist/src/http-server.js +0 -37
  63. package/dist/src/index.d.ts +0 -24
  64. package/dist/src/index.js +0 -46
  65. package/dist/src/internal-queue.d.ts +0 -11
  66. package/dist/src/internal-queue.js +0 -53
  67. package/dist/src/lambda-http-proxy.d.ts +0 -27
  68. package/dist/src/lambda-http-proxy.js +0 -49
  69. package/dist/src/localstack.d.ts +0 -11
  70. package/dist/src/localstack.js +0 -62
  71. package/dist/src/mappers.d.ts +0 -25
  72. package/dist/src/mappers.js +0 -158
  73. package/dist/src/pre-traffic-hooks.d.ts +0 -2
  74. package/dist/src/pre-traffic-hooks.js +0 -19
  75. package/dist/src/responses.d.ts +0 -5
  76. package/dist/src/responses.js +0 -22
  77. package/dist/src/s3.d.ts +0 -7
  78. package/dist/src/s3.js +0 -20
  79. package/dist/src/scheduled-tasks.d.ts +0 -6
  80. package/dist/src/scheduled-tasks.js +0 -20
  81. package/dist/src/services.d.ts +0 -22
  82. package/dist/src/services.js +0 -26
  83. package/dist/src/sns-http-proxy.d.ts +0 -28
  84. package/dist/src/sns-http-proxy.js +0 -66
  85. package/dist/src/sns.d.ts +0 -15
  86. package/dist/src/sns.js +0 -35
  87. package/dist/src/sqs.d.ts +0 -13
  88. package/dist/src/sqs.js +0 -33
  89. package/dist/src/stoppable.d.ts +0 -2
  90. package/dist/src/stoppable.js +0 -15
  91. package/dist/src/tunnel.d.ts +0 -10
  92. package/dist/src/tunnel.js +0 -52
@@ -1,18 +0,0 @@
1
- import { BindMount, Environment } from 'testcontainers/build/types';
2
- import { Callback, Service } from './services';
3
- import { PortWithOptionalBinding } from 'testcontainers/build/utils/port';
4
- import { Readable } from 'stream';
5
- import { WaitStrategy } from 'testcontainers/build/wait-strategies/wait-strategy';
6
- export declare const newContainer: (name: string, config: {
7
- image: string;
8
- networkAlias: string;
9
- environment?: Environment;
10
- bindMounts?: BindMount[];
11
- exposedPorts?: PortWithOptionalBinding[];
12
- logConsumer?: (stream: Readable) => unknown;
13
- startup?: {
14
- waitStrategy: WaitStrategy;
15
- timeout: number;
16
- };
17
- endpointBuilder?: (port: number) => string;
18
- }, callback?: Callback<string>) => Service<string>;
@@ -1,33 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.newContainer = void 0;
4
- const logging_1 = require("@yopdev/logging");
5
- const testcontainers_1 = require("testcontainers");
6
- const services_1 = require("./services");
7
- const newContainer = (name, config, callback) => new services_1.Service(new Container(name, config.image, config.networkAlias, config.environment, config.bindMounts, config.exposedPorts, config.logConsumer, config.startup, config.endpointBuilder), callback);
8
- exports.newContainer = newContainer;
9
- class Container {
10
- constructor(name, image, networkAlias, environment, bindMounts, exposedPorts, logConsumer, startup, endpointBuilder) {
11
- this.name = name;
12
- this.networkAlias = networkAlias;
13
- this.start = async (config) => Promise.resolve(this.LOGGER.info('start'))
14
- .then(() => this.container
15
- .withNetwork(config.network)
16
- .withNetworkAliases(this.networkAlias)
17
- .start())
18
- .then((started) => this.started = started)
19
- .then(() => this.endpointBuilder(this.started.getFirstMappedPort()))
20
- .tap((url) => this.LOGGER.debug(url));
21
- this.stop = async () => (this.started ?? { stop: async () => { this.LOGGER.warn('no container'); } }).stop().then(() => undefined);
22
- this.LOGGER = logging_1.LoggerFactory.create(`CONTAINER[${name}]`);
23
- const generic = new testcontainers_1.GenericContainer(image);
24
- const withEnvironment = environment ? generic.withEnvironment(environment) : generic;
25
- const withBindMounts = bindMounts ? withEnvironment.withBindMounts(bindMounts) : withEnvironment;
26
- const withExposedPorts = exposedPorts ? withBindMounts.withExposedPorts(...exposedPorts) : withBindMounts;
27
- const withLogConsumer = logConsumer ? withExposedPorts.withLogConsumer(logConsumer) : withExposedPorts;
28
- this.container = startup ? withLogConsumer.withWaitStrategy(startup.waitStrategy).withStartupTimeout(startup.timeout) : withLogConsumer;
29
- this.networkAlias = networkAlias;
30
- this.endpointBuilder = endpointBuilder ?? ((port) => `http://localhost:${port}`);
31
- }
32
- }
33
- ;
@@ -1,4 +0,0 @@
1
- import { DevServerConfig } from "./config";
2
- import { Service } from "./services";
3
- export declare const lazy: <I>(lifecycle: (config: DevServerConfig) => Service<I>) => Service<I>;
4
- export declare const promised: <I>(lifecycle: (config: DevServerConfig) => Promise<Service<I>>) => Service<I>;
@@ -1,45 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.promised = exports.lazy = void 0;
4
- const crypto_1 = require("crypto");
5
- const services_1 = require("./services");
6
- const logging_1 = require("@yopdev/logging");
7
- const lazy = (lifecycle) => new services_1.Service(new Lazy(lifecycle));
8
- exports.lazy = lazy;
9
- const promised = (lifecycle) => new services_1.Service(new Promised(lifecycle));
10
- exports.promised = promised;
11
- class Lazy {
12
- constructor(configurable) {
13
- this.configurable = configurable;
14
- this.stop = async () => this.withStartedOr(async (s) => s.stop(), async () => Promise.reject(new Error('not started')));
15
- this.started = undefined;
16
- this.name = (0, crypto_1.randomUUID)();
17
- this.LOGGER = logging_1.LoggerFactory.create(`LAZY[${this.name}]`);
18
- }
19
- async start(config) {
20
- const local = this.configurable(config);
21
- this.started = local;
22
- this.LOGGER.info('DISCOVERY:%s', local.name);
23
- return local.start(config);
24
- }
25
- withStartedOr(task, fallback) {
26
- const local = this.started;
27
- if (local !== undefined)
28
- task(local);
29
- else
30
- fallback();
31
- }
32
- }
33
- class Promised {
34
- constructor(configurable) {
35
- this.name = (0, crypto_1.randomUUID)();
36
- this.LOGGER = logging_1.LoggerFactory.create(`PROMISED[${this.name}]`);
37
- let initialized;
38
- this.start = async (config) => configurable(config)
39
- .catch((e) => e?.cleanup?.() ?? Promise.reject(e))
40
- .then((service) => initialized = service)
41
- .tap((service) => this.LOGGER.info('DISCOVERY:%s', service.name))
42
- .then((service) => service.start(config));
43
- this.stop = async () => (initialized ?? { stop: async () => this.LOGGER.info('not started') }).stop();
44
- }
45
- }
@@ -1,19 +0,0 @@
1
- import { Config } from "./config";
2
- import { Service } from "./services";
3
- export declare class DevServer {
4
- readonly name: string;
5
- private readonly service;
6
- private readonly config?;
7
- private readonly eventProxyTopic;
8
- private LOGGER;
9
- private localStack;
10
- private network;
11
- constructor(name: string, service: Service<any>, config?: Config);
12
- start: () => Promise<StartedDevServer>;
13
- private shutdown;
14
- }
15
- type StartedDevServer = {
16
- name: string;
17
- stop: () => Promise<void>;
18
- };
19
- export {};
@@ -1,63 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DevServer = void 0;
4
- const testcontainers_1 = require("testcontainers");
5
- const localstack_1 = require("./localstack");
6
- const sqs_1 = require("./sqs");
7
- const dynamodb_1 = require("./dynamodb");
8
- const logging_1 = require("@yopdev/logging");
9
- const sns_1 = require("./sns");
10
- const tunnel_1 = require("./tunnel");
11
- const s3_1 = require("./s3");
12
- class DevServer {
13
- constructor(name, service, config) {
14
- this.name = name;
15
- this.service = service;
16
- this.config = config;
17
- this.start = async () => Promise.resolve(new testcontainers_1.Network(new testcontainers_1.RandomUuid()).start())
18
- .tap((network) => this.network = network)
19
- .then((network) => ({
20
- localStack: this.localStack = new localstack_1.LocalStack(network, this.config),
21
- network: network
22
- }))
23
- .then((infra) => infra.localStack.start().then((config) => ({
24
- aws: config,
25
- network: infra.network
26
- })))
27
- .then((infra) => Promise
28
- .resolve(new sns_1.Sns(infra.aws))
29
- .then((sns) => sns
30
- .createTopic(this.eventProxyTopic)
31
- .then((eventProxyTopicArn) => ({
32
- raw: infra.aws,
33
- network: infra.network,
34
- sqs: new sqs_1.Sqs(infra.aws),
35
- sns: new sns_1.Sns(infra.aws),
36
- s3: new s3_1.S3(infra.aws),
37
- dynamo: new dynamodb_1.DynamoDb(infra.aws),
38
- eventsProxy: {
39
- topic: {
40
- arn: eventProxyTopicArn
41
- }
42
- },
43
- }))))
44
- .tap((config) => this.LOGGER.debug('config is %o', config))
45
- .then((aws) => this.service.start(aws))
46
- .catch((e) => this.shutdown()
47
- .then(() => this.LOGGER.error('error starting service'))
48
- .then(() => Promise.reject(e)))
49
- .then(() => this.LOGGER.info('started'))
50
- .then(() => ({
51
- name: this.name,
52
- stop: async () => this.shutdown().then(() => this.LOGGER.info('stopped')),
53
- }));
54
- this.shutdown = async () => this.service.stop()
55
- .finally(tunnel_1.terminate)
56
- .then(() => this.localStack?.stop())
57
- .then(() => this.network?.stop().catch((e) => this.LOGGER.warn(e, 'failed to stop network')));
58
- this.LOGGER = logging_1.LoggerFactory.create(`DEVSERVER[${name}]`);
59
- const encodedName = Buffer.from(name).toString('hex').substring(0, 64);
60
- this.eventProxyTopic = `EventProxyTopic${encodedName}`;
61
- }
62
- }
63
- exports.DevServer = DevServer;
@@ -1,16 +0,0 @@
1
- import { CreateTableCommand, DynamoDBClient } from "@aws-sdk/client-dynamodb";
2
- import { AwsConfig } from "./config";
3
- import { Service, Callback } from "./services";
4
- export declare const newDynamoDbTable: (name: string, config: {
5
- command: CreateTableCommand;
6
- ttlAttribute?: string;
7
- }, callback?: Callback<string>) => Service<string>;
8
- export declare class DynamoDb {
9
- readonly client: DynamoDBClient;
10
- constructor(config: AwsConfig);
11
- createTable: (factory: CreateTableCommand) => Promise<import("@aws-sdk/client-dynamodb").CreateTableCommandOutput | {
12
- TableDescription: {
13
- TableName: string;
14
- };
15
- }>;
16
- }
@@ -1,48 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DynamoDb = exports.newDynamoDbTable = void 0;
4
- const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
5
- const logging_1 = require("@yopdev/logging");
6
- const services_1 = require("./services");
7
- const assert_1 = require("./assert");
8
- const newDynamoDbTable = (name, config, callback) => new services_1.Service(new DynamoDbTableCreator(name, config.command, config.ttlAttribute), callback);
9
- exports.newDynamoDbTable = newDynamoDbTable;
10
- class DynamoDbTableCreator {
11
- constructor(name, command, ttlAttribute) {
12
- this.name = name;
13
- this.command = command;
14
- this.ttlAttribute = ttlAttribute;
15
- this.start = async (config) => config.dynamo.createTable(this.command)
16
- .tap((output) => this.LOGGER.debug(output))
17
- .then(() => this.ttlAttribute)
18
- .then((ttl) => ttl !== undefined ? this.setupTimeToLive(config.dynamo, ttl) : Promise.resolve())
19
- .then(() => this.name);
20
- this.setupTimeToLive = async (dynamodb, attributeName) => dynamodb.client.send(new client_dynamodb_1.UpdateTimeToLiveCommand({
21
- TableName: this.command.input.TableName,
22
- TimeToLiveSpecification: {
23
- Enabled: true,
24
- AttributeName: attributeName,
25
- }
26
- }))
27
- .tap((out) => this.LOGGER.info('set ttl attribute %s? %s', attributeName, out.$metadata.httpStatusCode === 200))
28
- .then(() => undefined);
29
- this.stop = () => Promise.resolve();
30
- this.LOGGER = logging_1.LoggerFactory.create(`TABLE[${name}]`);
31
- }
32
- }
33
- const LOGGER = logging_1.LoggerFactory.create('DYNAMODB');
34
- class DynamoDb {
35
- constructor(config) {
36
- this.createTable = async (factory) => this.client
37
- .send(factory) //
38
- .tap((table) => LOGGER.debug('created %s', (0, assert_1.assertNotUndefined)(table.TableDescription).TableName))
39
- .catch((reason) => {
40
- LOGGER.error('failed to create table');
41
- if (reason.name !== 'ResourceInUseException')
42
- return Promise.reject(reason);
43
- return { TableDescription: { TableName: factory.input.TableName } };
44
- });
45
- this.client = new client_dynamodb_1.DynamoDBClient(config);
46
- }
47
- }
48
- exports.DynamoDb = DynamoDb;
@@ -1,13 +0,0 @@
1
- import { SNSMessageAttributes, SQSEvent, SQSRecord } from 'aws-lambda';
2
- import { Message } from '@aws-sdk/client-sqs';
3
- import { Service } from './services';
4
- export declare const newEventsProxy: (name: string, config: {
5
- handlers: EventHandler[];
6
- topic?: string;
7
- mapper?: (message: Message) => SQSRecord;
8
- }) => Service<void>;
9
- export type EventHandler = {
10
- name: string;
11
- handler: (event: SQSEvent) => Promise<unknown>;
12
- matcher: (subject: string, attributes: SNSMessageAttributes) => boolean;
13
- };
@@ -1,68 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.newEventsProxy = void 0;
4
- const sqs_consumer_1 = require("sqs-consumer");
5
- const mappers_1 = require("./mappers");
6
- const logging_1 = require("@yopdev/logging");
7
- const stoppable_1 = require("./stoppable");
8
- const assert_1 = require("./assert");
9
- const services_1 = require("./services");
10
- const newEventsProxy = (name, config) => new services_1.Service(new EventsProxy(name, config.handlers, config.mapper ?? mappers_1.mapToLambdaSqsRecord, config.topic));
11
- exports.newEventsProxy = newEventsProxy;
12
- class EventsProxy {
13
- constructor(name, handlers, mapper, topic) {
14
- this.name = name;
15
- this.handlers = handlers;
16
- this.mapper = mapper;
17
- this.topic = topic;
18
- this.pollingFrequency = 1;
19
- this.stopped = true;
20
- this.queueName = () => `EventProxyQueue${Buffer.from(this.name).toString('hex').substring(0, 64)}`;
21
- this.start = async (config) => this.queueConnectedToTopic(config.sns, this.topic ?? config.eventsProxy.topic.arn, config.sqs, this.queueName())
22
- .then((url) => this.startEventsConsumer(config.sqs.client, url))
23
- .tap(() => this.stopped = false)
24
- .then((consumer) => this.LOGGER.debug(consumer));
25
- this.queueConnectedToTopic = async (sns, topic, sqs, queue) => sqs.createStandardQueue(queue)
26
- .then((queue) => sns
27
- .createSubscription({ arn: topic }, { arn: queue.arn })
28
- .then(() => queue.url));
29
- this.startEventsConsumer = async (sqs, url) => {
30
- this.consumer = sqs_consumer_1.Consumer.create({
31
- waitTimeSeconds: this.pollingFrequency,
32
- queueUrl: url,
33
- sqs: sqs,
34
- handleMessage: async (message) => this.onEachMessage(message),
35
- });
36
- this.consumer.start();
37
- return url;
38
- };
39
- this.extractErrorMessage = (e) => typeof e === 'string' ? e : e.message !== undefined && typeof e.message === 'string' ? e.message : '';
40
- this.onEachMessage = async (message) => {
41
- if (this.stopped) {
42
- this.LOGGER.warn('stopped events proxy received message %o', message);
43
- return;
44
- }
45
- const body = (0, assert_1.assertNotUndefined)(message.Body, 'body is not present');
46
- const json = JSON.parse(body);
47
- const attributes = json.MessageAttributes;
48
- const subject = json.Subject;
49
- const handlers = this.handlers.filter((handler) => handler.matcher(subject, attributes));
50
- if (handlers.length === 0) {
51
- this.LOGGER.warn('no handlers found for message %o', message);
52
- }
53
- const record = this.mapper(message);
54
- return Promise.all(handlers.map((handler) => handler
55
- .handler({ Records: [record] })
56
- .then(() => {
57
- this.LOGGER.debug('handler %s accepted message', handler.name);
58
- })
59
- .catch((e) => {
60
- const error = this.extractErrorMessage(e);
61
- this.LOGGER.error(e, 'handler %s failed with %s', handler.name, error);
62
- }))).then(() => undefined);
63
- };
64
- this.stop = async () => (0, stoppable_1.stopConsumer)(this.pollingFrequency, this.consumer);
65
- this.LOGGER = logging_1.LoggerFactory.create(`SNS->SQS[${name}]`);
66
- this.LOGGER.debug('handling events from %s', topic ?? 'the event bus');
67
- }
68
- }
@@ -1,3 +0,0 @@
1
- import { Service } from "./services";
2
- export declare const all: (services: Service<any>[]) => Service<any>;
3
- export declare const oneThenOther: (one: Service<unknown>, other: Service<unknown>) => Service<unknown>;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.oneThenOther = exports.all = void 0;
4
- const services_1 = require("./services");
5
- const all = (services) => new services_1.Service({
6
- name: `ALLOF[${services.map((each) => each.name).join(',')}]`,
7
- start: async (config) => Promise.all(services.map((each) => each.start(config))).then(() => this),
8
- stop: async () => Promise.all(services.map((each) => each.stop())).then()
9
- });
10
- exports.all = all;
11
- const oneThenOther = (one, other) => new services_1.Service({
12
- name: `[${one.name}]->[${other.name}]`,
13
- start: async (config) => one.start(config).then(async () => other.start(config)),
14
- stop: async () => other.stop().then(async () => one.stop()),
15
- });
16
- exports.oneThenOther = oneThenOther;
@@ -1,25 +0,0 @@
1
- /// <reference types="node" />
2
- import { IncomingMessage, ServerResponse } from "http";
3
- import { Lifecycle, Service, Callback } from "./services";
4
- export declare const newHttpServer: (name: string, config: {
5
- settings: HttpSettings;
6
- handler: (request: IncomingMessage, requestBody: string, response: ServerResponse) => void;
7
- }, callback?: Callback<string>) => Service<string>;
8
- export declare class HttpServer implements Lifecycle<string> {
9
- readonly name: string;
10
- readonly settings: HttpSettings;
11
- readonly handler: (request: IncomingMessage, requestBody: string, response: ServerResponse) => void;
12
- private LOGGER;
13
- private readonly protocol;
14
- private address;
15
- private readonly server;
16
- constructor(name: string, settings: HttpSettings, handler: (request: IncomingMessage, requestBody: string, response: ServerResponse) => void);
17
- start: () => Promise<string>;
18
- private endpointUrl;
19
- stop: () => Promise<any>;
20
- }
21
- export type HttpSettings = {
22
- protocol: string;
23
- host: string;
24
- port: number | undefined;
25
- };
@@ -1,37 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpServer = exports.newHttpServer = void 0;
4
- const http_1 = require("http");
5
- const events_1 = require("events");
6
- const logging_1 = require("@yopdev/logging");
7
- const assert_1 = require("./assert");
8
- const services_1 = require("./services");
9
- const newHttpServer = (name, config, callback) => new services_1.Service(new HttpServer(name, config.settings, config.handler), callback);
10
- exports.newHttpServer = newHttpServer;
11
- class HttpServer {
12
- constructor(name, settings, handler) {
13
- this.name = name;
14
- this.settings = settings;
15
- this.handler = handler;
16
- this.start = () => this.server
17
- .then(() => this.LOGGER.debug('listening [%s]', (0, assert_1.assertNotUndefined)(this.address).port))
18
- .then(() => this.endpointUrl());
19
- this.endpointUrl = () => {
20
- const address = (0, assert_1.assertNotUndefined)(this.address, 'server not started');
21
- return `${this.protocol}//${address.address}:${address.port}/`;
22
- };
23
- this.stop = () => this.server.then((server) => server.close()).then(() => undefined);
24
- const server = (0, http_1.createServer)((req, res) => {
25
- req.setEncoding('utf-8');
26
- let body = '';
27
- req.on('data', (chunks) => body = body.concat(chunks));
28
- req.on('end', () => handler(req, body, res));
29
- })
30
- .listen(settings.port, settings.host, () => this.address = server.address());
31
- this.server = (0, events_1.once)(server, 'listening')
32
- .then(() => server);
33
- this.protocol = settings.protocol;
34
- this.LOGGER = logging_1.LoggerFactory.create(`HTTPSERVER[${name}]`);
35
- }
36
- }
37
- exports.HttpServer = HttpServer;
@@ -1,24 +0,0 @@
1
- export { DevServer } from './dev-server';
2
- export { newHttpServer as httpServer, HttpSettings } from './http-server';
3
- export { newLambdaHttpProxy as lambdaHttpProxy, UNAUTHORIZED } from './lambda-http-proxy';
4
- export { v1 as v1LambdaProxyPayload, v2 as v2LambdaProxyPayload } from './mappers';
5
- export { newLambdaProxyFromCloudFormationTemplate as cloudFormationLambdaProxy } from './cloudformation-lambda-http-proxy';
6
- export { newDynamoDbTableFromCloudFormationTemplate as cloudFormationDynamoDbTable } from './cloudformation-dynamodb-table';
7
- export { newSnsHttpProxy as snsHttpProxy } from './sns-http-proxy';
8
- export { newInternalQueue as internalQueue } from './internal-queue';
9
- export { newEventsProxy as eventsProxy } from './event-proxy';
10
- export { snsEventsFromCloudFormationTemplate as cloudFormationSnsEventHandlers } from './cloudformation-event-proxy';
11
- export { newScheduledTasks as scheduledTasks } from './scheduled-tasks';
12
- export { newPreTrafficHooks as preTrafficHooks } from './pre-traffic-hooks';
13
- export { newDynamoDbTable as dynamoDbTable } from './dynamodb';
14
- export { newContainer as container } from './container';
15
- export { newTunnel as tunnel } from './tunnel';
16
- export { all as allOf, oneThenOther } from './factories';
17
- export { lazy, promised } from './deferred';
18
- export { Lifecycle, Service, Startable } from './services';
19
- export { DevServerConfig } from './config';
20
- declare global {
21
- interface Promise<T> {
22
- tap(onfulfilled?: (value: T) => void, onrejected?: (reason: unknown) => void): Promise<T>;
23
- }
24
- }
package/dist/src/index.js DELETED
@@ -1,46 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Service = exports.promised = exports.lazy = exports.oneThenOther = exports.allOf = exports.tunnel = exports.container = exports.dynamoDbTable = exports.preTrafficHooks = exports.scheduledTasks = exports.cloudFormationSnsEventHandlers = exports.eventsProxy = exports.internalQueue = exports.snsHttpProxy = exports.cloudFormationDynamoDbTable = exports.cloudFormationLambdaProxy = exports.v2LambdaProxyPayload = exports.v1LambdaProxyPayload = exports.UNAUTHORIZED = exports.lambdaHttpProxy = exports.httpServer = exports.DevServer = void 0;
4
- var dev_server_1 = require("./dev-server");
5
- Object.defineProperty(exports, "DevServer", { enumerable: true, get: function () { return dev_server_1.DevServer; } });
6
- var http_server_1 = require("./http-server");
7
- Object.defineProperty(exports, "httpServer", { enumerable: true, get: function () { return http_server_1.newHttpServer; } });
8
- var lambda_http_proxy_1 = require("./lambda-http-proxy");
9
- Object.defineProperty(exports, "lambdaHttpProxy", { enumerable: true, get: function () { return lambda_http_proxy_1.newLambdaHttpProxy; } });
10
- Object.defineProperty(exports, "UNAUTHORIZED", { enumerable: true, get: function () { return lambda_http_proxy_1.UNAUTHORIZED; } });
11
- var mappers_1 = require("./mappers");
12
- Object.defineProperty(exports, "v1LambdaProxyPayload", { enumerable: true, get: function () { return mappers_1.v1; } });
13
- Object.defineProperty(exports, "v2LambdaProxyPayload", { enumerable: true, get: function () { return mappers_1.v2; } });
14
- var cloudformation_lambda_http_proxy_1 = require("./cloudformation-lambda-http-proxy");
15
- Object.defineProperty(exports, "cloudFormationLambdaProxy", { enumerable: true, get: function () { return cloudformation_lambda_http_proxy_1.newLambdaProxyFromCloudFormationTemplate; } });
16
- var cloudformation_dynamodb_table_1 = require("./cloudformation-dynamodb-table");
17
- Object.defineProperty(exports, "cloudFormationDynamoDbTable", { enumerable: true, get: function () { return cloudformation_dynamodb_table_1.newDynamoDbTableFromCloudFormationTemplate; } });
18
- var sns_http_proxy_1 = require("./sns-http-proxy");
19
- Object.defineProperty(exports, "snsHttpProxy", { enumerable: true, get: function () { return sns_http_proxy_1.newSnsHttpProxy; } });
20
- var internal_queue_1 = require("./internal-queue");
21
- Object.defineProperty(exports, "internalQueue", { enumerable: true, get: function () { return internal_queue_1.newInternalQueue; } });
22
- var event_proxy_1 = require("./event-proxy");
23
- Object.defineProperty(exports, "eventsProxy", { enumerable: true, get: function () { return event_proxy_1.newEventsProxy; } });
24
- var cloudformation_event_proxy_1 = require("./cloudformation-event-proxy");
25
- Object.defineProperty(exports, "cloudFormationSnsEventHandlers", { enumerable: true, get: function () { return cloudformation_event_proxy_1.snsEventsFromCloudFormationTemplate; } });
26
- var scheduled_tasks_1 = require("./scheduled-tasks");
27
- Object.defineProperty(exports, "scheduledTasks", { enumerable: true, get: function () { return scheduled_tasks_1.newScheduledTasks; } });
28
- var pre_traffic_hooks_1 = require("./pre-traffic-hooks");
29
- Object.defineProperty(exports, "preTrafficHooks", { enumerable: true, get: function () { return pre_traffic_hooks_1.newPreTrafficHooks; } });
30
- var dynamodb_1 = require("./dynamodb");
31
- Object.defineProperty(exports, "dynamoDbTable", { enumerable: true, get: function () { return dynamodb_1.newDynamoDbTable; } });
32
- var container_1 = require("./container");
33
- Object.defineProperty(exports, "container", { enumerable: true, get: function () { return container_1.newContainer; } });
34
- var tunnel_1 = require("./tunnel");
35
- Object.defineProperty(exports, "tunnel", { enumerable: true, get: function () { return tunnel_1.newTunnel; } });
36
- var factories_1 = require("./factories");
37
- Object.defineProperty(exports, "allOf", { enumerable: true, get: function () { return factories_1.all; } });
38
- Object.defineProperty(exports, "oneThenOther", { enumerable: true, get: function () { return factories_1.oneThenOther; } });
39
- var deferred_1 = require("./deferred");
40
- Object.defineProperty(exports, "lazy", { enumerable: true, get: function () { return deferred_1.lazy; } });
41
- Object.defineProperty(exports, "promised", { enumerable: true, get: function () { return deferred_1.promised; } });
42
- var services_1 = require("./services");
43
- Object.defineProperty(exports, "Service", { enumerable: true, get: function () { return services_1.Service; } });
44
- Promise.prototype.tap = async function (onfulfilled, onrejected) {
45
- return this.then(onfulfilled, onrejected).then(async () => this);
46
- };
@@ -1,11 +0,0 @@
1
- import { Queue } from "./sqs";
2
- import { SQSEvent, SQSRecord } from "aws-lambda";
3
- import { Service, Callback } from "./services";
4
- import { Message } from "@aws-sdk/client-sqs";
5
- export declare const newInternalQueue: (name: string, config: {
6
- name: string;
7
- visibility: number;
8
- handler: (queue: Queue) => (e: SQSEvent) => Promise<void>;
9
- fifo: boolean;
10
- mapper?: (message: Message) => SQSRecord;
11
- }, callback?: Callback<string>) => Service<string>;
@@ -1,53 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.newInternalQueue = void 0;
4
- const logging_1 = require("@yopdev/logging");
5
- const sqs_consumer_1 = require("sqs-consumer");
6
- const stoppable_1 = require("./stoppable");
7
- const mappers_1 = require("./mappers");
8
- const services_1 = require("./services");
9
- const newInternalQueue = (name, config, callback) => new services_1.Service(new InternalQueue(name, config.visibility, config.handler, (sqs) => config.fifo ? sqs.createFifoQueue : sqs.createStandardQueue, config.mapper ?? mappers_1.mapToLambdaSqsRecord), callback);
10
- exports.newInternalQueue = newInternalQueue;
11
- class InternalQueue {
12
- constructor(name, visibility, handler, creator, mapper) {
13
- this.name = name;
14
- this.visibility = visibility;
15
- this.handler = handler;
16
- this.creator = creator;
17
- this.mapper = mapper;
18
- this.start = (config) => this.create(config.sqs);
19
- this.create = async (sqs) => this.createQueue(sqs, this.name)
20
- .then((queue) => this
21
- .createConsumer(sqs.client, this.name, queue.url, this.handler(queue), this.visibility)
22
- .then(() => queue.url));
23
- this.createConsumer = async (sqs, name, url, handler, visibility) => Promise.resolve(() => this.consumer = sqs_consumer_1.Consumer.create({
24
- queueUrl: url,
25
- waitTimeSeconds: visibility,
26
- sqs: sqs,
27
- handleMessage: async (message) => handler({ Records: [this.mapper(message)] }),
28
- }))
29
- .then((factory) => factory())
30
- .then((consumer) => {
31
- consumer.on('error', (err) => {
32
- this.LOGGER.error(err, 'failed to handle message');
33
- });
34
- consumer.on('processing_error', (err) => {
35
- this.LOGGER.error(err, 'failed to process message');
36
- });
37
- this.LOGGER.info('consumer for %s initialized', name);
38
- return consumer;
39
- })
40
- .then(async (consumer) => consumer.start())
41
- .then(() => this.LOGGER.info('started'))
42
- .then(() => this);
43
- this.stop = async () => this.consumer !== undefined ? (0, stoppable_1.stopConsumer)(this.visibility, this.consumer) : this.LOGGER.warn('no consumer');
44
- this.LOGGER = logging_1.LoggerFactory.create(`INTERNALQUEUE[${name}]`);
45
- }
46
- async createQueue(sqs, name) {
47
- return this.creator(sqs)(name) //
48
- .then((queue) => {
49
- this.LOGGER.info('created: %s', queue.url);
50
- return queue;
51
- });
52
- }
53
- }
@@ -1,27 +0,0 @@
1
- /// <reference types="node" />
2
- import { HttpSettings } from "./http-server";
3
- import { LambdaMapperFactory } from "./mappers";
4
- import { Service, Callback } from "./services";
5
- export declare const UNAUTHORIZED: Error;
6
- export declare const newLambdaHttpProxy: <Context, AuthorizerContext, Event_1, HandlerResponse>(name: string, config: {
7
- settings: HttpSettings;
8
- routes: Route<Context, AuthorizerContext, Event_1, HandlerResponse>[];
9
- mapper: LambdaMapperFactory<AuthorizerContext, Event_1, HandlerResponse>;
10
- authorizer?: Authorizer<AuthorizerContext>;
11
- context?: () => Context;
12
- }, callback?: Callback<string>) => Service<string>;
13
- export declare abstract class Response {
14
- readonly statusCode: number;
15
- readonly contentType: string | undefined;
16
- readonly location: string | undefined;
17
- constructor(statusCode: number, contentType: string | undefined, location: string | undefined);
18
- body: () => string | Buffer | undefined;
19
- }
20
- export type Route<Context, AuthorizerContext, Event, HandlerResponse> = {
21
- method: RegExp;
22
- path: RegExp;
23
- weight: number;
24
- authorizer?: Authorizer<AuthorizerContext>;
25
- handler: (event: Event, context: Context) => Promise<HandlerResponse>;
26
- };
27
- export type Authorizer<Context> = (authorization: string) => Promise<Context | undefined>;
@@ -1,49 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Response = exports.newLambdaHttpProxy = exports.UNAUTHORIZED = void 0;
4
- const logging_1 = require("@yopdev/logging");
5
- const http_server_1 = require("./http-server");
6
- const responses_1 = require("./responses");
7
- const services_1 = require("./services");
8
- exports.UNAUTHORIZED = new Error('UNAUTHORIZED');
9
- const newLambdaHttpProxy = (name, config, callback) => new services_1.Service(new LambdaHttpProxy(name, config.settings, config.routes, config.mapper, config.authorizer ?? (() => Promise.resolve(undefined)), config.context), callback);
10
- exports.newLambdaHttpProxy = newLambdaHttpProxy;
11
- class LambdaHttpProxy {
12
- constructor(name, settings, routes, mapper, defaultAuthorizer, context = () => undefined) {
13
- this.name = name;
14
- this.routes = routes;
15
- this.mapper = mapper;
16
- this.defaultAuthorizer = defaultAuthorizer;
17
- this.context = context;
18
- this.start = () => this.server.start();
19
- this.stop = () => this.server.stop();
20
- this.handler = (authorizer, lambdaHandler) => (request, body, response) => this.mapper.newInstance(request, body)
21
- .then(async (mapper) => authorizer(mapper.authorization())
22
- .then(async (context) => lambdaHandler(mapper.event(context), this.context())
23
- .then((lambda) => {
24
- const result = mapper.toResponse(lambda);
25
- return (0, responses_1.writeResponse)(response, result.statusCode, result.body(), result.contentType, result.location);
26
- })
27
- .catch((e) => {
28
- this.LOGGER.error(e, 'request failed to execute');
29
- (0, responses_1.internalServerError)(response, e.body);
30
- }), (e) => e === exports.UNAUTHORIZED ? (0, responses_1.writeResponse)(response, 401, '') : (0, responses_1.internalServerError)(response, e)));
31
- this.fallback = async (request, _, response) => Promise.resolve(this.LOGGER.warn(`FALLBACK: ${request.method} to ${request.url}`)).then(() => (0, responses_1.writeResponse)(response, 404, `no route found to handle ${request.method} to ${request.url}`));
32
- this.resolveRoute = (request, body, response) => (this.routes.filter((r) => r.method.test(request.method))
33
- .filter((r) => r.path.test(request.url))
34
- .sort((r1, r2) => r2.weight - r1.weight)
35
- .map((r) => this.handler(r.authorizer ?? this.defaultAuthorizer, r.handler))
36
- .find(() => true) ?? this.fallback)(request, body, response);
37
- this.server = new http_server_1.HttpServer(name, settings, this.resolveRoute);
38
- this.LOGGER = logging_1.LoggerFactory.create(`HTTP->LAMBDA[${this.name}]`);
39
- this.LOGGER.info('registered %i routes', routes.length);
40
- }
41
- }
42
- class Response {
43
- constructor(statusCode, contentType, location) {
44
- this.statusCode = statusCode;
45
- this.contentType = contentType;
46
- this.location = location;
47
- }
48
- }
49
- exports.Response = Response;