@lafken/queue 0.11.20 → 0.12.1

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.
@@ -92,6 +92,7 @@ exports.Standard = (0, common_1.createLambdaDecorator)({
92
92
  getLambdaMetadata: (props, methodName) => ({
93
93
  ...props,
94
94
  queueName: props.queueName || methodName,
95
+ isExternal: props.isExternal ?? false,
95
96
  name: methodName,
96
97
  isFifo: false,
97
98
  }),
@@ -122,6 +123,7 @@ exports.Fifo = (0, common_1.createLambdaDecorator)({
122
123
  getLambdaMetadata: (props, methodName) => ({
123
124
  ...props,
124
125
  queueName: props.queueName || methodName,
126
+ isExternal: props.isExternal ?? false,
125
127
  name: methodName,
126
128
  isFifo: true,
127
129
  }),
@@ -1,4 +1,4 @@
1
- import type { LambdaMetadata, LambdaProps, QueueNames, QueueReferenceNames, ResourceOutputType } from '@lafken/common';
1
+ import type { GetResourceProps, LambdaMetadata, LambdaProps, QueueNames, QueueReferenceNames, ResourceOutputType } from '@lafken/common';
2
2
  /**
3
3
  * Attributes that can be exported from an SQS queue resource.
4
4
  *
@@ -18,7 +18,15 @@ export interface DlqProps {
18
18
  */
19
19
  retentionPeriod?: number;
20
20
  }
21
- export interface StandardProps {
21
+ export interface InternalStandardProps {
22
+ /**
23
+ * Marks the queue as an external resource.
24
+ *
25
+ * When set to `true`, the SQS queue is not created by the framework.
26
+ * Instead, it references an existing queue by `queueName`. The Lambda
27
+ * handler and event source mapping are still created.
28
+ */
29
+ isExternal?: false;
22
30
  /**
23
31
  * Delivery delay in seconds.
24
32
  *
@@ -115,7 +123,21 @@ export interface StandardProps {
115
123
  */
116
124
  dlq?: DlqProps;
117
125
  }
118
- export interface FifoProps extends StandardProps {
126
+ export interface ExternalQueueProps {
127
+ /**
128
+ * Marks the queue as an external resource.
129
+ *
130
+ * When set to `true`, the SQS queue is not created by the framework.
131
+ * Instead, it references an existing queue by `queueName`. The Lambda
132
+ * handler and event source mapping are still created.
133
+ */
134
+ isExternal: true;
135
+ /**
136
+ *
137
+ */
138
+ queueName: string | ((props: GetResourceProps) => string);
139
+ }
140
+ export interface InternalFifoProps extends InternalStandardProps {
119
141
  /**
120
142
  * Enable content-based deduplication.
121
143
  *
@@ -126,7 +148,10 @@ export interface FifoProps extends StandardProps {
126
148
  */
127
149
  contentBasedDeduplication?: boolean;
128
150
  }
129
- export interface QueueLambdaMetadata extends LambdaMetadata, Omit<FifoProps, 'queueName'> {
130
- queueName: string;
151
+ export type StandardProps = InternalStandardProps | ExternalQueueProps;
152
+ export type FifoProps = InternalFifoProps | ExternalQueueProps;
153
+ export interface QueueLambdaMetadata extends LambdaMetadata, Omit<InternalFifoProps, 'queueName' | 'isExternal'> {
154
+ queueName: ExternalQueueProps['queueName'];
131
155
  isFifo: boolean;
156
+ isExternal: boolean;
132
157
  }
@@ -0,0 +1,16 @@
1
+ import type { Construct } from 'constructs';
2
+ import type { QueueProps } from '../queue.types';
3
+ type Constructor = new (...args: any[]) => Construct & {
4
+ arn: string;
5
+ };
6
+ export declare function QueueBase<TBase extends Constructor>(Base: TBase): {
7
+ new (...args: any[]): {
8
+ addEventSource(id: string, props: QueueProps): void;
9
+ validateEventParams(props: QueueProps): void;
10
+ readonly node: import("constructs").Node;
11
+ with(...mixins: import("constructs").IMixin[]): import("constructs").IConstruct;
12
+ toString(): string;
13
+ arn: string;
14
+ };
15
+ } & TBase;
16
+ export {};
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QueueBase = QueueBase;
4
+ const lambda_event_source_mapping_1 = require("@cdktn/provider-aws/lib/lambda-event-source-mapping");
5
+ const common_1 = require("@lafken/common");
6
+ const resolver_1 = require("@lafken/resolver");
7
+ const attributeAllowedTypes = new Set(['String', 'Number']);
8
+ const bodyUnparsedTypes = new Set(['String']);
9
+ function getParams(props) {
10
+ const { classResource, handler } = props;
11
+ const params = (0, common_1.getMetadataPrototypeByKey)(classResource, common_1.LambdaReflectKeys.event_param) || {};
12
+ return params[handler.name];
13
+ }
14
+ function validateParamType(param) {
15
+ if (param.source === 'attribute' && !attributeAllowedTypes.has(param.type)) {
16
+ throw new Error(`Attribute params only support ${[...attributeAllowedTypes].join(', ')} values`);
17
+ }
18
+ if (param?.source === 'body' && !param.parse && !bodyUnparsedTypes.has(param.type)) {
19
+ throw new Error(`Body params only support ${[...bodyUnparsedTypes].join(', ')} values`);
20
+ }
21
+ }
22
+ function QueueBase(Base) {
23
+ class QueueWithBase extends Base {
24
+ addEventSource(id, props) {
25
+ const { handler, resourceMetadata } = props;
26
+ const lambdaHandler = new resolver_1.LambdaHandler(this, `${id}-handler`, {
27
+ ...handler,
28
+ originalName: resourceMetadata.originalName,
29
+ filename: resourceMetadata.filename,
30
+ foldername: resourceMetadata.foldername,
31
+ suffix: 'queue',
32
+ });
33
+ new lambda_event_source_mapping_1.LambdaEventSourceMapping(this, 'event-mapping', {
34
+ batchSize: handler.batchSize,
35
+ eventSourceArn: this.arn,
36
+ functionName: lambdaHandler.arn,
37
+ maximumBatchingWindowInSeconds: handler.maxBatchingWindow,
38
+ functionResponseTypes: handler.isFifo ? ['ReportBatchItemFailures'] : undefined,
39
+ scalingConfig: handler.maxConcurrency
40
+ ? { maximumConcurrency: handler.maxConcurrency }
41
+ : undefined,
42
+ dependsOn: [lambdaHandler],
43
+ });
44
+ }
45
+ validateEventParams(props) {
46
+ const param = getParams(props);
47
+ if (!param)
48
+ return;
49
+ let bodyCount = 0;
50
+ for (const property of param.properties) {
51
+ validateParamType(property);
52
+ if (property.source === 'body')
53
+ bodyCount++;
54
+ if (bodyCount >= 2)
55
+ throw new Error('Queue event only support one body param');
56
+ }
57
+ }
58
+ }
59
+ return QueueWithBase;
60
+ }
@@ -0,0 +1,25 @@
1
+ import { DataAwsSqsQueue } from '@cdktn/provider-aws/lib/data-aws-sqs-queue';
2
+ import { type AppModule } from '@lafken/resolver';
3
+ import type { QueueProps } from '../queue.types';
4
+ declare const ExternalQueue_base: {
5
+ new (...args: any[]): {
6
+ addEventSource(id: string, props: QueueProps): void;
7
+ validateEventParams(props: QueueProps): void;
8
+ readonly node: import("constructs").Node;
9
+ with(...mixins: import("constructs").IMixin[]): import("constructs").IConstruct;
10
+ toString(): string;
11
+ arn: string;
12
+ };
13
+ } & (new (...args: any[]) => {
14
+ register(namespaces: import("@lafken/common").RegisterNamespaces | (string & {}), id: string): void;
15
+ onResolve(callback: () => void): void;
16
+ readonly node: import("constructs").Node;
17
+ with(...mixins: import("constructs").IMixin[]): import("constructs").IConstruct;
18
+ toString(): string;
19
+ }) & typeof DataAwsSqsQueue;
20
+ export declare class ExternalQueue extends ExternalQueue_base {
21
+ private props;
22
+ constructor(scope: AppModule, id: string, props: QueueProps);
23
+ private setName;
24
+ }
25
+ export {};
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExternalQueue = void 0;
4
+ const data_aws_sqs_queue_1 = require("@cdktn/provider-aws/lib/data-aws-sqs-queue");
5
+ const resolver_1 = require("@lafken/resolver");
6
+ const base_1 = require("../base/base");
7
+ const queue_utils_1 = require("../queue.utils");
8
+ class ExternalQueue extends (0, base_1.QueueBase)(resolver_1.lafkenResource.make(data_aws_sqs_queue_1.DataAwsSqsQueue)) {
9
+ props;
10
+ constructor(scope, id, props) {
11
+ const { handler } = props;
12
+ super(scope, `${id}-queue`, {
13
+ name: '',
14
+ });
15
+ this.props = props;
16
+ this.setName();
17
+ if (handler.ref) {
18
+ this.register('queue', handler.ref);
19
+ }
20
+ this.validateEventParams(props);
21
+ this.addEventSource(id, props);
22
+ }
23
+ setName() {
24
+ const { handler } = this.props;
25
+ if (typeof handler.queueName === 'string') {
26
+ this.name = (0, queue_utils_1.sqsName)(handler.queueName, handler.isFifo ? '.fifo' : '');
27
+ return;
28
+ }
29
+ const queueName = (0, resolver_1.resolveCallbackResource)(this, handler.queueName);
30
+ if (!queueName) {
31
+ this.onResolve(() => {
32
+ this.setName();
33
+ if (!this.name) {
34
+ throw new Error('Unresolved external queue name');
35
+ }
36
+ });
37
+ return;
38
+ }
39
+ this.name = queueName;
40
+ }
41
+ }
42
+ exports.ExternalQueue = ExternalQueue;
@@ -1,20 +1,25 @@
1
1
  import { SqsQueue } from '@cdktn/provider-aws/lib/sqs-queue';
2
2
  import { type AppModule } from '@lafken/resolver';
3
- import type { QueueProps } from './queue.types';
4
- declare const Queue_base: (new (...args: any[]) => {
3
+ import type { QueueProps } from '../queue.types';
4
+ declare const InternalQueue_base: {
5
+ new (...args: any[]): {
6
+ addEventSource(id: string, props: QueueProps): void;
7
+ validateEventParams(props: QueueProps): void;
8
+ readonly node: import("constructs").Node;
9
+ with(...mixins: import("constructs").IMixin[]): import("constructs").IConstruct;
10
+ toString(): string;
11
+ arn: string;
12
+ };
13
+ } & (new (...args: any[]) => {
5
14
  register(namespaces: import("@lafken/common").RegisterNamespaces | (string & {}), id: string): void;
6
15
  onResolve(callback: () => void): void;
7
16
  readonly node: import("constructs").Node;
8
17
  with(...mixins: import("constructs").IMixin[]): import("constructs").IConstruct;
9
18
  toString(): string;
10
19
  }) & typeof SqsQueue;
11
- export declare class Queue extends Queue_base {
20
+ export declare class InternalQueue extends InternalQueue_base {
12
21
  private props;
13
22
  constructor(scope: AppModule, id: string, props: QueueProps);
14
23
  private addDeadLetterQueue;
15
- private addEventSource;
16
- private validateEventParams;
17
- private getParams;
18
- private validateParamType;
19
24
  }
20
25
  export {};
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InternalQueue = void 0;
4
+ const sqs_queue_1 = require("@cdktn/provider-aws/lib/sqs-queue");
5
+ const sqs_queue_redrive_policy_1 = require("@cdktn/provider-aws/lib/sqs-queue-redrive-policy");
6
+ const resolver_1 = require("@lafken/resolver");
7
+ const base_1 = require("../base/base");
8
+ const queue_utils_1 = require("../queue.utils");
9
+ class InternalQueue extends (0, base_1.QueueBase)(resolver_1.lafkenResource.make(sqs_queue_1.SqsQueue)) {
10
+ props;
11
+ constructor(scope, id, props) {
12
+ const { handler } = props;
13
+ super(scope, `${id}-queue`, {
14
+ name: (0, queue_utils_1.sqsName)(handler.queueName, handler.isFifo ? '.fifo' : ''),
15
+ fifoQueue: handler.isFifo,
16
+ contentBasedDeduplication: handler.contentBasedDeduplication,
17
+ visibilityTimeoutSeconds: handler.visibilityTimeout,
18
+ messageRetentionSeconds: handler.retentionPeriod,
19
+ maxMessageSize: handler.maxMessageSizeBytes,
20
+ delaySeconds: handler.deliveryDelay,
21
+ });
22
+ this.props = props;
23
+ if (handler.ref) {
24
+ this.register('queue', handler.ref);
25
+ }
26
+ this.addDeadLetterQueue(id);
27
+ this.validateEventParams(props);
28
+ this.addEventSource(id, props);
29
+ new resolver_1.ResourceOutput(this, handler.outputs);
30
+ }
31
+ addDeadLetterQueue(id) {
32
+ const { handler } = this.props;
33
+ if (!handler.dlq)
34
+ return;
35
+ const dlqName = (0, queue_utils_1.sqsName)(handler.queueName, `-dlq${handler.isFifo ? '.fifo' : ''}`);
36
+ const dlq = new sqs_queue_1.SqsQueue(this, `${id}-dlq`, {
37
+ name: dlqName,
38
+ fifoQueue: handler.isFifo,
39
+ messageRetentionSeconds: handler.dlq.retentionPeriod,
40
+ });
41
+ new sqs_queue_redrive_policy_1.SqsQueueRedrivePolicy(this, `${id}-redrive-policy`, {
42
+ queueUrl: this.url,
43
+ redrivePolicy: JSON.stringify({
44
+ deadLetterTargetArn: dlq.arn,
45
+ maxReceiveCount: handler.dlq.maxReceiveCount,
46
+ }),
47
+ });
48
+ }
49
+ }
50
+ exports.InternalQueue = InternalQueue;
@@ -1,7 +1,13 @@
1
1
  import type { ClassResource, ResourceMetadata } from '@lafken/common';
2
2
  import type { QueueLambdaMetadata } from '../../main';
3
- export interface QueueProps {
3
+ export interface InternalQueueProps {
4
4
  handler: QueueLambdaMetadata;
5
5
  resourceMetadata: ResourceMetadata;
6
6
  classResource: ClassResource;
7
7
  }
8
+ export interface ExternalQueueProps {
9
+ handler: QueueLambdaMetadata;
10
+ resourceMetadata: ResourceMetadata;
11
+ classResource: ClassResource;
12
+ }
13
+ export type QueueProps = InternalQueueProps | ExternalQueueProps;
@@ -4,7 +4,8 @@ exports.QueueResolver = void 0;
4
4
  const common_1 = require("@lafken/common");
5
5
  const resolver_1 = require("@lafken/resolver");
6
6
  const main_1 = require("../main");
7
- const queue_1 = require("./queue/queue");
7
+ const external_1 = require("./queue/external/external");
8
+ const internal_1 = require("./queue/internal/internal");
8
9
  class QueueResolver {
9
10
  type = main_1.RESOURCE_TYPE;
10
11
  create(module, resource) {
@@ -19,7 +20,15 @@ class QueueResolver {
19
20
  methods: handlers.map((handler) => handler.name),
20
21
  });
21
22
  for (const handler of handlers) {
22
- new queue_1.Queue(module, `${metadata.name}-${handler.name}`, {
23
+ if (handler.isExternal) {
24
+ new external_1.ExternalQueue(module, `${metadata.name}-${handler.name}`, {
25
+ resourceMetadata: metadata,
26
+ classResource: resource,
27
+ handler,
28
+ });
29
+ return;
30
+ }
31
+ new internal_1.InternalQueue(module, `${metadata.name}-${handler.name}`, {
23
32
  resourceMetadata: metadata,
24
33
  classResource: resource,
25
34
  handler,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lafken/queue",
3
- "version": "0.11.20",
3
+ "version": "0.12.1",
4
4
  "private": false,
5
5
  "description": "Define SQS queues and consumers using TypeScript decorators - automatic infrastructure generation with Lafken",
6
6
  "keywords": [
@@ -52,30 +52,29 @@
52
52
  "lib"
53
53
  ],
54
54
  "dependencies": {
55
- "@aws-sdk/client-sqs": "^3.1037.0",
56
- "aws-lambda": "^1.0.7",
55
+ "@aws-sdk/client-sqs": "^3.1045.0",
57
56
  "reflect-metadata": "^0.2.2",
58
- "@lafken/resolver": "0.11.20"
57
+ "@lafken/resolver": "0.12.1"
59
58
  },
60
59
  "devDependencies": {
61
- "@cdktn/provider-aws": "^23.9.0",
62
- "@swc/core": "^1.15.30",
60
+ "@cdktn/provider-aws": "^24.0.0",
61
+ "@swc/core": "^1.15.33",
63
62
  "@swc/helpers": "^0.5.21",
64
63
  "@types/aws-lambda": "^8.10.161",
65
64
  "@vitest/runner": "^4.1.5",
66
- "cdktn": "^0.22.1",
65
+ "cdktn": "^0.23.0",
67
66
  "cdktn-vitest": "^1.0.0",
68
67
  "constructs": "^10.6.0",
69
68
  "typescript": "6.0.3",
70
69
  "unplugin-swc": "^1.5.9",
71
70
  "vitest": "^4.1.5",
72
- "@lafken/common": "0.11.20"
71
+ "@lafken/common": "0.12.1"
73
72
  },
74
73
  "peerDependencies": {
75
74
  "@cdktn/provider-aws": ">=23.0.0",
76
75
  "cdktn": ">=0.22.0",
77
76
  "constructs": "^10.4.5",
78
- "@lafken/common": "0.11.20"
77
+ "@lafken/common": "0.12.1"
79
78
  },
80
79
  "engines": {
81
80
  "node": ">=20.19"
@@ -1,106 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Queue = void 0;
4
- const lambda_event_source_mapping_1 = require("@cdktn/provider-aws/lib/lambda-event-source-mapping");
5
- const sqs_queue_1 = require("@cdktn/provider-aws/lib/sqs-queue");
6
- const sqs_queue_redrive_policy_1 = require("@cdktn/provider-aws/lib/sqs-queue-redrive-policy");
7
- const common_1 = require("@lafken/common");
8
- const resolver_1 = require("@lafken/resolver");
9
- const queue_utils_1 = require("./queue.utils");
10
- const attributeAllowedTypes = new Set(['String', 'Number']);
11
- const bodyParsedTypes = new Set(['String', 'Object', 'Array']);
12
- const bodyUnparsedTypes = new Set(['String']);
13
- class Queue extends resolver_1.lafkenResource.make(sqs_queue_1.SqsQueue) {
14
- props;
15
- constructor(scope, id, props) {
16
- const { handler } = props;
17
- super(scope, `${id}-queue`, {
18
- name: (0, queue_utils_1.sqsName)(handler.queueName, handler.isFifo ? '.fifo' : ''),
19
- fifoQueue: handler.isFifo,
20
- contentBasedDeduplication: handler.contentBasedDeduplication,
21
- visibilityTimeoutSeconds: handler.visibilityTimeout,
22
- messageRetentionSeconds: handler.retentionPeriod,
23
- maxMessageSize: handler.maxMessageSizeBytes,
24
- delaySeconds: handler.deliveryDelay,
25
- });
26
- this.props = props;
27
- if (handler.ref) {
28
- this.register('queue', handler.ref);
29
- }
30
- this.addDeadLetterQueue(id);
31
- this.validateEventParams();
32
- this.addEventSource(id);
33
- new resolver_1.ResourceOutput(this, handler.outputs);
34
- }
35
- addDeadLetterQueue(id) {
36
- const { handler } = this.props;
37
- if (!handler.dlq)
38
- return;
39
- const dlqName = (0, queue_utils_1.sqsName)(handler.queueName, `-dlq${handler.isFifo ? '.fifo' : ''}`);
40
- const dlq = new sqs_queue_1.SqsQueue(this, `${id}-dlq`, {
41
- name: dlqName,
42
- fifoQueue: handler.isFifo,
43
- messageRetentionSeconds: handler.dlq.retentionPeriod,
44
- });
45
- new sqs_queue_redrive_policy_1.SqsQueueRedrivePolicy(this, `${id}-redrive-policy`, {
46
- queueUrl: this.url,
47
- redrivePolicy: JSON.stringify({
48
- deadLetterTargetArn: dlq.arn,
49
- maxReceiveCount: handler.dlq.maxReceiveCount,
50
- }),
51
- });
52
- }
53
- addEventSource(id) {
54
- const { handler, resourceMetadata } = this.props;
55
- const lambdaHandler = new resolver_1.LambdaHandler(this, `${id}-handler`, {
56
- ...handler,
57
- originalName: resourceMetadata.originalName,
58
- filename: resourceMetadata.filename,
59
- foldername: resourceMetadata.foldername,
60
- suffix: 'queue',
61
- });
62
- new lambda_event_source_mapping_1.LambdaEventSourceMapping(this, 'event-mapping', {
63
- batchSize: handler.batchSize,
64
- eventSourceArn: this.arn,
65
- functionName: lambdaHandler.arn,
66
- maximumBatchingWindowInSeconds: handler.maxBatchingWindow,
67
- functionResponseTypes: handler.isFifo ? ['ReportBatchItemFailures'] : undefined,
68
- scalingConfig: handler.maxConcurrency
69
- ? {
70
- maximumConcurrency: handler.maxConcurrency,
71
- }
72
- : undefined,
73
- dependsOn: [lambdaHandler, this],
74
- });
75
- }
76
- validateEventParams() {
77
- const param = this.getParams();
78
- if (!param) {
79
- return;
80
- }
81
- let bodyCount = 0;
82
- for (const property of param.properties) {
83
- this.validateParamType(property);
84
- if (property.source === 'body') {
85
- bodyCount++;
86
- }
87
- if (bodyCount >= 2) {
88
- throw new Error('Queue event only support one body param');
89
- }
90
- }
91
- }
92
- getParams() {
93
- const { classResource, handler } = this.props;
94
- const params = (0, common_1.getMetadataPrototypeByKey)(classResource, common_1.LambdaReflectKeys.event_param) || {};
95
- return params[handler.name];
96
- }
97
- validateParamType(param) {
98
- if (param.source === 'attribute' && !attributeAllowedTypes.has(param.type)) {
99
- throw new Error(`Attribute params only support ${[...attributeAllowedTypes].join(', ')} values`);
100
- }
101
- if (param?.source === 'body' && !param.parse && !bodyUnparsedTypes.has(param.type)) {
102
- throw new Error(`Body params only support ${[...bodyUnparsedTypes].join(', ')} values`);
103
- }
104
- }
105
- }
106
- exports.Queue = Queue;