@geekmidas/events 10.0.0-alpha.39 → 10.0.0-alpha.40

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["snsUrl.parse"],"sources":["../../src/sns/SNSConnection.ts","../../src/sns/SNSPublisher.ts","../../src/sns/SNSSubscriber.ts"],"sourcesContent":["import { SNSClient, type SNSClientConfig } from '@aws-sdk/client-sns';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\nimport * as snsUrl from './snsUrl';\n\nexport interface SNSConnectionConfig {\n\ttopicArn: string;\n\tregion?: string;\n\tendpoint?: string; // Custom endpoint (e.g., for LocalStack)\n\tcredentials?: {\n\t\taccessKeyId: string;\n\t\tsecretAccessKey: string;\n\t\tsessionToken?: string;\n\t};\n}\n\nexport class SNSConnection implements EventConnection {\n\treadonly type = EventPublisherType.SNS;\n\tprivate client: SNSClient;\n\tprivate connected = false;\n\tprivate config: SNSConnectionConfig;\n\n\tconstructor(config: SNSConnectionConfig) {\n\t\tthis.config = config;\n\n\t\tconst clientConfig: SNSClientConfig = {\n\t\t\tregion: config.region,\n\t\t\tendpoint: config.endpoint,\n\t\t\tcredentials: config.credentials,\n\t\t};\n\n\t\tthis.client = new SNSClient(clientConfig);\n\t}\n\n\t/**\n\t * Create an SNSConnection from a connection string\n\t * Format: sns://?topicArn=arn:aws:sns:region:account:topic&region=us-east-1&endpoint=http://localhost:4566\n\t */\n\tstatic async fromConnectionString(\n\t\tconnectionString: string,\n\t): Promise<SNSConnection> {\n\t\t// Through the codec, not a second hand-rolled parse: the deploy target\n\t\t// composes these with `snsUrl.build`, and a string it cannot read back is\n\t\t// exactly the drift one shared module rules out.\n\t\tconst { topicArn, region, endpoint } = snsUrl.parse(connectionString);\n\t\tconst params = new URL(connectionString).searchParams;\n\n\t\tconst config: SNSConnectionConfig = {\n\t\t\ttopicArn,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t};\n\n\t\t// Credentials are not part of the address — see `snsUrl` — but a caller\n\t\t// may still pin them here, so they are read beside it rather than in it.\n\t\tconst accessKeyId = params.get('accessKeyId');\n\t\tconst secretAccessKey = params.get('secretAccessKey');\n\t\tif (accessKeyId && secretAccessKey) {\n\t\t\tconfig.credentials = {\n\t\t\t\taccessKeyId,\n\t\t\t\tsecretAccessKey,\n\t\t\t\tsessionToken: params.get('sessionToken') || undefined,\n\t\t\t};\n\t\t}\n\n\t\tconst connection = new SNSConnection(config);\n\t\tawait connection.connect();\n\t\treturn connection;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\t// SNS doesn't have a traditional connection, but we mark as connected\n\t\tthis.connected = true;\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.client.destroy();\n\t\tthis.connected = false;\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.connected;\n\t}\n\n\t/**\n\t * Get the underlying SNS client\n\t */\n\tget snsClient(): SNSClient {\n\t\treturn this.client;\n\t}\n\n\t/**\n\t * Get the topic ARN for this connection\n\t */\n\tget topicArn(): string {\n\t\treturn this.config.topicArn;\n\t}\n}\n","import { PublishCommand } from '@aws-sdk/client-sns';\nimport type { EventPublisher, PublishableMessage } from '../types';\nimport type { SNSConnection } from './SNSConnection';\n\nexport type SNSPublisherOptions = {};\n\nexport class SNSPublisher<TMessage extends PublishableMessage<string, any>>\n\timplements EventPublisher<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: SNSConnection,\n\t\t_options: SNSPublisherOptions = {},\n\t) {}\n\n\t/**\n\t * Create an SNSPublisher from a connection string\n\t * Format: sns://?topicArn=arn:aws:sns:region:account:topic&region=us-east-1&endpoint=http://localhost:4566\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<SNSPublisher<TMessage>> {\n\t\tconst { SNSConnection } = await import('./SNSConnection');\n\t\tconst connection =\n\t\t\tawait SNSConnection.fromConnectionString(connectionString);\n\n\t\treturn new SNSPublisher<TMessage>(connection);\n\t}\n\n\tasync publish(messages: TMessage[]): Promise<void> {\n\t\tif (messages.length === 0) return;\n\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\t// Publish all messages\n\t\tawait Promise.all(messages.map((message) => this.publishMessage(message)));\n\t}\n\n\tprivate async publishMessage(message: TMessage): Promise<void> {\n\t\tconst command = new PublishCommand({\n\t\t\tTopicArn: this.connection.topicArn,\n\t\t\tMessage: JSON.stringify({\n\t\t\t\ttype: message.type,\n\t\t\t\tpayload: message.payload,\n\t\t\t}),\n\t\t\tMessageAttributes: {\n\t\t\t\ttype: {\n\t\t\t\t\tDataType: 'String',\n\t\t\t\t\tStringValue: message.type,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\n\t\tawait this.connection.snsClient.send(command);\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// Publisher doesn't own the connection\n\t\t// Connection should be closed by whoever created it\n\t}\n}\n","import { SubscribeCommand, UnsubscribeCommand } from '@aws-sdk/client-sns';\nimport {\n\tCreateQueueCommand,\n\tDeleteQueueCommand,\n\tGetQueueAttributesCommand,\n\tSetQueueAttributesCommand,\n\tSQSClient,\n} from '@aws-sdk/client-sqs';\nimport { SQSConnection } from '../sqs/SQSConnection';\nimport { SQSSubscriber } from '../sqs/SQSSubscriber';\nimport type { EventSubscriber, PublishableMessage } from '../types';\nimport type { SNSConnection } from './SNSConnection';\n\nexport interface SNSSubscriberOptions {\n\tqueueName?: string; // Optional queue name (defaults to auto-generated)\n\tcreateQueue?: boolean; // Auto-create SQS queue (default: true)\n\tdeleteQueueOnClose?: boolean; // Delete queue when subscriber closes (default: false for named queues, true for auto-generated)\n\twaitTimeSeconds?: number; // SQS long polling (default: 20)\n\tmaxMessages?: number; // Max messages per poll (default: 10)\n}\n\n/**\n * SNS Subscriber - receives push-based messages from SNS via SQS queue\n *\n * Architecture:\n * SNS Topic → (push) → SQS Queue → Subscriber\n *\n * This subscriber automatically:\n * 1. Creates an SQS queue (or uses existing one)\n * 2. Subscribes the queue to the SNS topic\n * 3. Receives messages pushed from SNS to the queue\n * 4. Filters messages by topic ARN and message type\n * 5. Processes and acknowledges messages\n *\n * Note: While SQS long-polling is used internally to receive messages,\n * this is an implementation detail of the SNS push delivery mechanism.\n * Messages are pushed from SNS to SQS, and we receive those pushed messages.\n */\nexport class SNSSubscriber<TMessage extends PublishableMessage<string, any>>\n\timplements EventSubscriber<TMessage>\n{\n\tprivate sqsClient: SQSClient;\n\tprivate queueUrl?: string;\n\tprivate queueArn?: string;\n\tprivate subscriptionArn?: string;\n\tprivate sqsSubscriber?: SQSSubscriber<TMessage>;\n\tprivate options: Required<SNSSubscriberOptions>;\n\n\tconstructor(\n\t\tprivate connection: SNSConnection,\n\t\toptions: SNSSubscriberOptions = {},\n\t) {\n\t\tthis.options = {\n\t\t\tqueueName:\n\t\t\t\toptions.queueName ||\n\t\t\t\t`sns-sub-${Date.now()}-${Math.random().toString(36).substring(7)}`,\n\t\t\tcreateQueue: options.createQueue ?? true,\n\t\t\tdeleteQueueOnClose: options.deleteQueueOnClose ?? !options.queueName, // Delete auto-generated queues\n\t\t\twaitTimeSeconds: options.waitTimeSeconds ?? 20,\n\t\t\tmaxMessages: options.maxMessages ?? 10,\n\t\t};\n\n\t\t// Create SQS client with same config as SNS\n\t\tthis.sqsClient = new SQSClient({\n\t\t\tregion: (this.connection as any).config.region,\n\t\t\tendpoint: (this.connection as any).config.endpoint,\n\t\t\tcredentials: (this.connection as any).config.credentials,\n\t\t});\n\t}\n\n\t/**\n\t * Create an SNSSubscriber from a connection string\n\t * Format: sns://?topicArn=...&queueName=myqueue&region=us-east-1\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<SNSSubscriber<TMessage>> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst { SNSConnection } = await import('./SNSConnection');\n\t\tconst connection =\n\t\t\tawait SNSConnection.fromConnectionString(connectionString);\n\n\t\tconst options: SNSSubscriberOptions = {\n\t\t\tqueueName: params.get('queueName') || undefined,\n\t\t\tcreateQueue: params.get('createQueue') !== 'false',\n\t\t\tdeleteQueueOnClose: params.get('deleteQueueOnClose') === 'true',\n\t\t\twaitTimeSeconds: params.get('waitTimeSeconds')\n\t\t\t\t? Number.parseInt(params.get('waitTimeSeconds')!, 10)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\treturn new SNSSubscriber<TMessage>(connection, options);\n\t}\n\n\tasync subscribe(\n\t\tmessages: TMessage['type'][],\n\t\tlistener: (payload: TMessage) => Promise<void>,\n\t): Promise<void> {\n\t\t// Setup SQS queue and SNS subscription\n\t\tawait this.setupQueue();\n\t\tawait this.subscribeToTopic();\n\n\t\t// Create SQS connection for the subscriber\n\t\tconst sqsConnection = new SQSConnection({\n\t\t\tqueueUrl: this.queueUrl!,\n\t\t\tregion: (this.connection as any).config.region,\n\t\t\tendpoint: (this.connection as any).config.endpoint,\n\t\t\tcredentials: (this.connection as any).config.credentials,\n\t\t});\n\t\tawait sqsConnection.connect();\n\n\t\t// Use SQSSubscriber to receive messages, with topic filtering\n\t\tthis.sqsSubscriber = new SQSSubscriber<TMessage>(sqsConnection, {\n\t\t\twaitTimeSeconds: this.options.waitTimeSeconds,\n\t\t\tmaxMessages: this.options.maxMessages,\n\t\t\texpectedTopicArn: this.connection.topicArn,\n\t\t});\n\n\t\tawait this.sqsSubscriber.subscribe(messages, listener);\n\t}\n\n\t/**\n\t * Stop receiving messages and clean up resources\n\t */\n\tasync stop(): Promise<void> {\n\t\t// Stop SQS subscriber\n\t\tif (this.sqsSubscriber) {\n\t\t\tthis.sqsSubscriber.stop();\n\t\t}\n\n\t\t// Unsubscribe from topic\n\t\tif (this.subscriptionArn) {\n\t\t\ttry {\n\t\t\t\tconst command = new UnsubscribeCommand({\n\t\t\t\t\tSubscriptionArn: this.subscriptionArn,\n\t\t\t\t});\n\t\t\t\tawait this.connection.snsClient.send(command);\n\t\t\t} catch (_error) {}\n\t\t}\n\n\t\t// Delete queue if configured\n\t\tif (this.queueUrl && this.options.deleteQueueOnClose) {\n\t\t\ttry {\n\t\t\t\tconst command = new DeleteQueueCommand({\n\t\t\t\t\tQueueUrl: this.queueUrl,\n\t\t\t\t});\n\t\t\t\tawait this.sqsClient.send(command);\n\t\t\t} catch (_error) {}\n\t\t}\n\n\t\tthis.sqsClient.destroy();\n\t}\n\n\tprivate async setupQueue(): Promise<void> {\n\t\tif (this.options.createQueue) {\n\t\t\t// Create queue\n\t\t\tconst createCommand = new CreateQueueCommand({\n\t\t\t\tQueueName: this.options.queueName,\n\t\t\t});\n\t\t\tconst response = await this.sqsClient.send(createCommand);\n\t\t\tthis.queueUrl = response.QueueUrl!;\n\t\t} else {\n\t\t\tthrow new SnsQueueMissing(this.options.queueName);\n\t\t}\n\n\t\t// Get queue ARN\n\t\tconst attrsCommand = new GetQueueAttributesCommand({\n\t\t\tQueueUrl: this.queueUrl,\n\t\t\tAttributeNames: ['QueueArn'],\n\t\t});\n\t\tconst attrsResponse = await this.sqsClient.send(attrsCommand);\n\t\tthis.queueArn = attrsResponse.Attributes?.QueueArn!;\n\n\t\t// Set queue policy to allow SNS\n\t\tawait this.setQueuePolicy();\n\t}\n\n\tprivate async setQueuePolicy(): Promise<void> {\n\t\tconst policy = {\n\t\t\tVersion: '2012-10-17',\n\t\t\tStatement: [\n\t\t\t\t{\n\t\t\t\t\tEffect: 'Allow',\n\t\t\t\t\tPrincipal: '*',\n\t\t\t\t\tAction: 'SQS:SendMessage',\n\t\t\t\t\tResource: this.queueArn,\n\t\t\t\t\tCondition: {\n\t\t\t\t\t\tArnEquals: {\n\t\t\t\t\t\t\t'aws:SourceArn': this.connection.topicArn,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\n\t\tconst command = new SetQueueAttributesCommand({\n\t\t\tQueueUrl: this.queueUrl,\n\t\t\tAttributes: {\n\t\t\t\tPolicy: JSON.stringify(policy),\n\t\t\t},\n\t\t});\n\n\t\tawait this.sqsClient.send(command);\n\t}\n\n\tprivate async subscribeToTopic(): Promise<void> {\n\t\tconst command = new SubscribeCommand({\n\t\t\tTopicArn: this.connection.topicArn,\n\t\t\tProtocol: 'sqs',\n\t\t\tEndpoint: this.queueArn,\n\t\t});\n\n\t\tconst response = await this.connection.snsClient.send(command);\n\t\tthis.subscriptionArn = response.SubscriptionArn!;\n\t}\n}\n\n/**\n * A subscriber asked to use a queue it may not create. The SQS queue behind an\n * SNS subscription has to exist first, or `createQueue` has to allow it.\n */\nexport class SnsQueueMissing extends Error {\n\tconstructor(readonly queueName: string | undefined) {\n\t\tsuper(\n\t\t\t`The SNS subscriber's queue${queueName ? ` \"${queueName}\"` : ''} is not created here: pass createQueue: true, or create the queue first.`,\n\t\t);\n\t\tthis.name = 'SnsQueueMissing';\n\t}\n}\n"],"mappings":";;;;;;AAgBA,IAAa,gBAAb,MAAa,cAAyC;CACrD,OAAS;CACT;CACA,YAAoB;CACpB;CAEA,YAAY,QAA6B;EACxC,KAAK,SAAS;EAEd,MAAM,eAAgC;GACrC,QAAQ,OAAO;GACf,UAAU,OAAO;GACjB,aAAa,OAAO;EACrB;EAEA,KAAK,SAAS,IAAI,UAAU,YAAY;CACzC;;;;;CAMA,aAAa,qBACZ,kBACyB;EAIzB,MAAM,EAAE,UAAU,QAAQ,aAAaA,MAAa,gBAAgB;EACpE,MAAM,SAAS,IAAI,IAAI,gBAAgB,CAAC,CAAC;EAEzC,MAAM,SAA8B;GACnC;GACA;GACA;EACD;EAIA,MAAM,cAAc,OAAO,IAAI,aAAa;EAC5C,MAAM,kBAAkB,OAAO,IAAI,iBAAiB;EACpD,IAAI,eAAe,iBAClB,OAAO,cAAc;GACpB;GACA;GACA,cAAc,OAAO,IAAI,cAAc,KAAK,KAAA;EAC7C;EAGD,MAAM,aAAa,IAAI,cAAc,MAAM;EAC3C,MAAM,WAAW,QAAQ;EACzB,OAAO;CACR;CAEA,MAAM,UAAyB;EAE9B,KAAK,YAAY;CAClB;CAEA,MAAM,QAAuB;EAC5B,KAAK,OAAO,QAAQ;EACpB,KAAK,YAAY;CAClB;CAEA,cAAuB;EACtB,OAAO,KAAK;CACb;;;;CAKA,IAAI,YAAuB;EAC1B,OAAO,KAAK;CACb;;;;CAKA,IAAI,WAAmB;EACtB,OAAO,KAAK,OAAO;CACpB;AACD;;;AC3FA,IAAa,eAAb,MAAa,aAEb;CAEU;CADT,YACC,YACA,WAAgC,CAAC,GAChC;EAFO,KAAA,aAAA;CAEN;;;;;CAMH,aAAa,qBAEX,kBAA2D;EAC5D,MAAM,EAAE,kBAAkB,MAAM,OAAO;EACvC,MAAM,aACL,MAAM,cAAc,qBAAqB,gBAAgB;EAE1D,OAAO,IAAI,aAAuB,UAAU;CAC7C;CAEA,MAAM,QAAQ,UAAqC;EAClD,IAAI,SAAS,WAAW,GAAG;EAE3B,IAAI,CAAC,KAAK,WAAW,YAAY,GAChC,MAAM,KAAK,WAAW,QAAQ;EAI/B,MAAM,QAAQ,IAAI,SAAS,KAAK,YAAY,KAAK,eAAe,OAAO,CAAC,CAAC;CAC1E;CAEA,MAAc,eAAe,SAAkC;EAC9D,MAAM,UAAU,IAAI,eAAe;GAClC,UAAU,KAAK,WAAW;GAC1B,SAAS,KAAK,UAAU;IACvB,MAAM,QAAQ;IACd,SAAS,QAAQ;GAClB,CAAC;GACD,mBAAmB,EAClB,MAAM;IACL,UAAU;IACV,aAAa,QAAQ;GACtB,EACD;EACD,CAAC;EAED,MAAM,KAAK,WAAW,UAAU,KAAK,OAAO;CAC7C;CAEA,MAAM,QAAuB,CAG7B;AACD;;;;;;;;;;;;;;;;;;;;ACvBA,IAAa,gBAAb,MAAa,cAEb;CASU;CART;CACA;CACA;CACA;CACA;CACA;CAEA,YACC,YACA,UAAgC,CAAC,GAChC;EAFO,KAAA,aAAA;EAGR,KAAK,UAAU;GACd,WACC,QAAQ,aACR,WAAW,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC;GAChE,aAAa,QAAQ,eAAe;GACpC,oBAAoB,QAAQ,sBAAsB,CAAC,QAAQ;GAC3D,iBAAiB,QAAQ,mBAAmB;GAC5C,aAAa,QAAQ,eAAe;EACrC;EAGA,KAAK,YAAY,IAAI,UAAU;GAC9B,QAAS,KAAK,WAAmB,OAAO;GACxC,UAAW,KAAK,WAAmB,OAAO;GAC1C,aAAc,KAAK,WAAmB,OAAO;EAC9C,CAAC;CACF;;;;;CAMA,aAAa,qBAEX,kBAA4D;EAE7D,MAAM,SAAS,IADC,IAAI,gBACH,CAAC,CAAC;EAEnB,MAAM,EAAE,kBAAkB,MAAM,OAAO;EACvC,MAAM,aACL,MAAM,cAAc,qBAAqB,gBAAgB;EAE1D,MAAM,UAAgC;GACrC,WAAW,OAAO,IAAI,WAAW,KAAK,KAAA;GACtC,aAAa,OAAO,IAAI,aAAa,MAAM;GAC3C,oBAAoB,OAAO,IAAI,oBAAoB,MAAM;GACzD,iBAAiB,OAAO,IAAI,iBAAiB,IAC1C,OAAO,SAAS,OAAO,IAAI,iBAAiB,GAAI,EAAE,IAClD,KAAA;EACJ;EAEA,OAAO,IAAI,cAAwB,YAAY,OAAO;CACvD;CAEA,MAAM,UACL,UACA,UACgB;EAEhB,MAAM,KAAK,WAAW;EACtB,MAAM,KAAK,iBAAiB;EAG5B,MAAM,gBAAgB,IAAI,cAAc;GACvC,UAAU,KAAK;GACf,QAAS,KAAK,WAAmB,OAAO;GACxC,UAAW,KAAK,WAAmB,OAAO;GAC1C,aAAc,KAAK,WAAmB,OAAO;EAC9C,CAAC;EACD,MAAM,cAAc,QAAQ;EAG5B,KAAK,gBAAgB,IAAI,cAAwB,eAAe;GAC/D,iBAAiB,KAAK,QAAQ;GAC9B,aAAa,KAAK,QAAQ;GAC1B,kBAAkB,KAAK,WAAW;EACnC,CAAC;EAED,MAAM,KAAK,cAAc,UAAU,UAAU,QAAQ;CACtD;;;;CAKA,MAAM,OAAsB;EAE3B,IAAI,KAAK,eACR,KAAK,cAAc,KAAK;EAIzB,IAAI,KAAK,iBACR,IAAI;GACH,MAAM,UAAU,IAAI,mBAAmB,EACtC,iBAAiB,KAAK,gBACvB,CAAC;GACD,MAAM,KAAK,WAAW,UAAU,KAAK,OAAO;EAC7C,SAAS,QAAQ,CAAC;EAInB,IAAI,KAAK,YAAY,KAAK,QAAQ,oBACjC,IAAI;GACH,MAAM,UAAU,IAAI,mBAAmB,EACtC,UAAU,KAAK,SAChB,CAAC;GACD,MAAM,KAAK,UAAU,KAAK,OAAO;EAClC,SAAS,QAAQ,CAAC;EAGnB,KAAK,UAAU,QAAQ;CACxB;CAEA,MAAc,aAA4B;EACzC,IAAI,KAAK,QAAQ,aAAa;GAE7B,MAAM,gBAAgB,IAAI,mBAAmB,EAC5C,WAAW,KAAK,QAAQ,UACzB,CAAC;GACD,MAAM,WAAW,MAAM,KAAK,UAAU,KAAK,aAAa;GACxD,KAAK,WAAW,SAAS;EAC1B,OACC,MAAM,IAAI,gBAAgB,KAAK,QAAQ,SAAS;EAIjD,MAAM,eAAe,IAAI,0BAA0B;GAClD,UAAU,KAAK;GACf,gBAAgB,CAAC,UAAU;EAC5B,CAAC;EACD,MAAM,gBAAgB,MAAM,KAAK,UAAU,KAAK,YAAY;EAC5D,KAAK,WAAW,cAAc,YAAY;EAG1C,MAAM,KAAK,eAAe;CAC3B;CAEA,MAAc,iBAAgC;EAC7C,MAAM,SAAS;GACd,SAAS;GACT,WAAW,CACV;IACC,QAAQ;IACR,WAAW;IACX,QAAQ;IACR,UAAU,KAAK;IACf,WAAW,EACV,WAAW,EACV,iBAAiB,KAAK,WAAW,SAClC,EACD;GACD,CACD;EACD;EAEA,MAAM,UAAU,IAAI,0BAA0B;GAC7C,UAAU,KAAK;GACf,YAAY,EACX,QAAQ,KAAK,UAAU,MAAM,EAC9B;EACD,CAAC;EAED,MAAM,KAAK,UAAU,KAAK,OAAO;CAClC;CAEA,MAAc,mBAAkC;EAC/C,MAAM,UAAU,IAAI,iBAAiB;GACpC,UAAU,KAAK,WAAW;GAC1B,UAAU;GACV,UAAU,KAAK;EAChB,CAAC;EAED,MAAM,WAAW,MAAM,KAAK,WAAW,UAAU,KAAK,OAAO;EAC7D,KAAK,kBAAkB,SAAS;CACjC;AACD;;;;;AAMA,IAAa,kBAAb,cAAqC,MAAM;CACrB;CAArB,YAAY,WAAwC;EACnD,MACC,6BAA6B,YAAY,KAAK,UAAU,KAAK,GAAG,yEACjE;EAHoB,KAAA,YAAA;EAIpB,KAAK,OAAO;CACb;AACD"}
1
+ {"version":3,"file":"index.mjs","names":["snsUrl.parse"],"sources":["../../src/sns/push.ts","../../src/sns/SNSConnection.ts","../../src/sns/SNSPublisher.ts","../../src/sns/SNSSubscriber.ts"],"sourcesContent":["import { createVerify } from 'node:crypto';\nimport {\n\tGetSubscriptionAttributesCommand,\n\tListSubscriptionsByTopicCommand,\n\tSetSubscriptionAttributesCommand,\n\tSubscribeCommand,\n\ttype SubscribeCommandInput,\n\tUnsubscribeCommand,\n} from '@aws-sdk/client-sns';\nimport type { SNSConnection } from './SNSConnection';\n\n/**\n * SNS delivering to an HTTP(S) endpoint, rather than to a queue that is polled.\n *\n * SNS POSTs each message to the subscribed URL as JSON. That is the whole\n * transport: no queue in between, no poller, and the endpoint is handed the\n * same envelope a Lambda subscription receives inside `Records[].Sns` — so the\n * handler that runs deployed can be the one that runs here.\n *\n * The endpoint is public, so a message is trusted only once its signature\n * checks out against a certificate SNS itself serves. Anything else that POSTs\n * there is somebody's guess at the shape.\n */\n\n/** A message SNS POSTs to a subscribed HTTP endpoint. */\nexport interface SnsHttpMessage {\n\tType: 'Notification' | 'SubscriptionConfirmation' | 'UnsubscribeConfirmation';\n\tMessageId: string;\n\tTopicArn: string;\n\tMessage: string;\n\tTimestamp: string;\n\tSignatureVersion: string;\n\tSignature: string;\n\tSigningCertURL: string;\n\tSubject?: string;\n\t/** Confirmation messages only. */\n\tToken?: string;\n\t/** Confirmation messages only: GET it to confirm. */\n\tSubscribeURL?: string;\n\t/** Notifications only. */\n\tUnsubscribeURL?: string;\n\tMessageAttributes?: Record<string, { Type: string; Value: string }>;\n}\n\n/** The fields signed, in the order SNS signs them, per message type. */\nconst SIGNED_FIELDS: Record<SnsHttpMessage['Type'], (keyof SnsHttpMessage)[]> =\n\t{\n\t\tNotification: [\n\t\t\t'Message',\n\t\t\t'MessageId',\n\t\t\t'Subject',\n\t\t\t'Timestamp',\n\t\t\t'TopicArn',\n\t\t\t'Type',\n\t\t],\n\t\tSubscriptionConfirmation: [\n\t\t\t'Message',\n\t\t\t'MessageId',\n\t\t\t'SubscribeURL',\n\t\t\t'Timestamp',\n\t\t\t'Token',\n\t\t\t'TopicArn',\n\t\t\t'Type',\n\t\t],\n\t\tUnsubscribeConfirmation: [\n\t\t\t'Message',\n\t\t\t'MessageId',\n\t\t\t'SubscribeURL',\n\t\t\t'Timestamp',\n\t\t\t'Token',\n\t\t\t'TopicArn',\n\t\t\t'Type',\n\t\t],\n\t};\n\n/**\n * Where SNS serves its signing certificates. Anywhere else is a certificate\n * the sender chose, which would let the sender sign its own forgeries.\n */\nconst SNS_CERTIFICATE_HOST = /^sns\\.[a-z0-9-]+\\.amazonaws\\.com(\\.cn)?$/;\n\nexport interface VerifySnsMessageOptions {\n\t/**\n\t * Fetch the PEM at a certificate URL. `fetch` by default; replaceable so a\n\t * test signs with its own key instead of SNS's.\n\t */\n\tfetchCertificate?: (url: string) => Promise<string>;\n}\n\nconst certificates = new Map<string, Promise<string>>();\n\nasync function defaultFetchCertificate(url: string): Promise<string> {\n\tconst response = await fetch(url);\n\tif (!response.ok) throw new SnsCertificateUnavailable(url, response.status);\n\treturn response.text();\n}\n\n/**\n * A URL, or undefined for a value that is not one at all — what an emulator\n * sends — so it is untrusted rather than a crash. (`URL.parse` is Node 22.1+.)\n */\nfunction parseUrl(value: unknown): URL | undefined {\n\ttry {\n\t\treturn new URL(String(value));\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** The string SNS signed for this message. */\nexport function snsStringToSign(message: SnsHttpMessage): string {\n\tconst fields = SIGNED_FIELDS[message.Type];\n\tif (!fields) throw new SnsMessageTypeUnknown(String(message.Type));\n\n\treturn fields\n\t\t.filter((field) => message[field] !== undefined)\n\t\t.map((field) => `${field}\\n${message[field]}\\n`)\n\t\t.join('');\n}\n\n/**\n * Check that SNS sent this message: the certificate is SNS's own, and the\n * signature over the message's signed fields verifies against it.\n *\n * Throws rather than returning false, so a caller cannot forget to look.\n */\nexport async function verifySnsMessage(\n\tmessage: SnsHttpMessage,\n\toptions: VerifySnsMessageOptions = {},\n): Promise<void> {\n\tconst url = parseUrl(message.SigningCertURL);\n\tif (url?.protocol !== 'https:' || !SNS_CERTIFICATE_HOST.test(url.hostname)) {\n\t\tthrow new SnsCertificateUntrusted(message.SigningCertURL);\n\t}\n\n\tconst algorithm =\n\t\tmessage.SignatureVersion === '1'\n\t\t\t? 'RSA-SHA1'\n\t\t\t: message.SignatureVersion === '2'\n\t\t\t\t? 'RSA-SHA256'\n\t\t\t\t: undefined;\n\tif (!algorithm) {\n\t\tthrow new SnsSignatureVersionUnknown(message.SignatureVersion);\n\t}\n\n\tconst fetchCertificate = options.fetchCertificate ?? defaultFetchCertificate;\n\tlet certificate = certificates.get(message.SigningCertURL);\n\tif (!certificate || options.fetchCertificate) {\n\t\tcertificate = fetchCertificate(message.SigningCertURL);\n\t\t// Only SNS's real fetch is cached: a test's key belongs to that test.\n\t\tif (!options.fetchCertificate) {\n\t\t\tcertificates.set(message.SigningCertURL, certificate);\n\t\t\tcertificate.catch(() => certificates.delete(message.SigningCertURL));\n\t\t}\n\t}\n\n\tconst verifier = createVerify(algorithm);\n\tverifier.update(snsStringToSign(message), 'utf8');\n\tif (!verifier.verify(await certificate, message.Signature, 'base64')) {\n\t\tthrow new SnsSignatureInvalid(message.MessageId, message.TopicArn);\n\t}\n}\n\n/**\n * Confirm a subscription by visiting the URL SNS sent. Until this happens SNS\n * delivers nothing to the endpoint.\n */\nexport async function confirmSnsSubscription(\n\tmessage: SnsHttpMessage,\n\trequest: (url: string) => Promise<{ ok: boolean; status: number }> = fetch,\n): Promise<void> {\n\tif (message.Type !== 'SubscriptionConfirmation' || !message.SubscribeURL) {\n\t\tthrow new SnsNotAConfirmation(message.Type);\n\t}\n\n\tconst response = await request(message.SubscribeURL);\n\tif (!response.ok) {\n\t\tthrow new SnsConfirmationFailed(message.TopicArn, response.status);\n\t}\n}\n\nexport interface SubscribeHttpEndpointOptions {\n\t/** The URL SNS POSTs to — `http:` or `https:`, which picks the protocol. */\n\tendpoint: string;\n\t/**\n\t * The event types this endpoint takes. Becomes the subscription's filter\n\t * policy on the `type` attribute `SNSPublisher` sets, so SNS sends nothing\n\t * else — fan-out to every subscriber, each seeing only what it named.\n\t */\n\tevents: readonly string[];\n\t/**\n\t * An SQS queue's ARN for what SNS gives up delivering. SNS retries an HTTP\n\t * endpoint for a limited time and then drops the message, so without one an\n\t * outage longer than that loses events.\n\t */\n\tdeadLetterQueueArn?: string;\n}\n\n/**\n * Subscribe an HTTP endpoint to the connection's topic, converging on one\n * confirmed subscription with the filter asked for — so it is safe on every\n * start:\n *\n * - **none yet** — subscribed; SNS sends a confirmation to the endpoint.\n * - **confirmed** — its filter and dead-letter queue are brought up to date.\n * Subscribing again with different attributes is an error on SNS, and the\n * events a subscriber names change.\n * - **stuck pending** — a confirmation that never landed (the endpoint was\n * down, or answered wrong). Subscribing the same endpoint again is a no-op\n * on an emulator, so it is dropped and subscribed afresh, which sends a new\n * confirmation.\n */\nexport async function subscribeHttpEndpoint(\n\tconnection: SNSConnection,\n\toptions: SubscribeHttpEndpointOptions,\n): Promise<string | undefined> {\n\tconst protocol = new URL(options.endpoint).protocol.replace(':', '');\n\tif (protocol !== 'http' && protocol !== 'https') {\n\t\tthrow new SnsEndpointNotHttp(options.endpoint);\n\t}\n\n\tconst attributes: Record<string, string> = {\n\t\tFilterPolicyScope: 'MessageAttributes',\n\t\tFilterPolicy: JSON.stringify({ type: [...options.events] }),\n\t};\n\tif (options.deadLetterQueueArn) {\n\t\tattributes.RedrivePolicy = JSON.stringify({\n\t\t\tdeadLetterTargetArn: options.deadLetterQueueArn,\n\t\t});\n\t}\n\n\tconst client = connection.snsClient;\n\tconst existing = await existingSubscription(connection, options.endpoint);\n\tif (existing) {\n\t\tconst { Attributes = {} } = await client.send(\n\t\t\tnew GetSubscriptionAttributesCommand({ SubscriptionArn: existing }),\n\t\t);\n\t\tif (Attributes.PendingConfirmation === 'true') {\n\t\t\tawait client.send(new UnsubscribeCommand({ SubscriptionArn: existing }));\n\t\t} else {\n\t\t\tfor (const [name, value] of Object.entries(attributes)) {\n\t\t\t\tif (Attributes[name] === value) continue;\n\t\t\t\tawait client.send(\n\t\t\t\t\tnew SetSubscriptionAttributesCommand({\n\t\t\t\t\t\tSubscriptionArn: existing,\n\t\t\t\t\t\tAttributeName: name,\n\t\t\t\t\t\tAttributeValue: value,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn existing;\n\t\t}\n\t}\n\n\tconst { SubscriptionArn } = await client.send(\n\t\tnew SubscribeCommand({\n\t\t\tTopicArn: connection.topicArn,\n\t\t\tProtocol: protocol,\n\t\t\tEndpoint: options.endpoint,\n\t\t\tAttributes: attributes as SubscribeCommandInput['Attributes'],\n\t\t\tReturnSubscriptionArn: true,\n\t\t}),\n\t);\n\treturn SubscriptionArn;\n}\n\n/**\n * The ARN of the endpoint's subscription to the topic, if it has one SNS will\n * name. (Real SNS lists a pending one as `PendingConfirmation`, with no ARN to\n * act on — and resends its confirmation on a new Subscribe anyway.)\n */\nasync function existingSubscription(\n\tconnection: SNSConnection,\n\tendpoint: string,\n): Promise<string | undefined> {\n\tlet NextToken: string | undefined;\n\tdo {\n\t\tconst page = await connection.snsClient.send(\n\t\t\tnew ListSubscriptionsByTopicCommand({\n\t\t\t\tTopicArn: connection.topicArn,\n\t\t\t\tNextToken,\n\t\t\t}),\n\t\t);\n\t\tconst match = page.Subscriptions?.find(\n\t\t\t(s) => s.Endpoint === endpoint && s.SubscriptionArn?.startsWith('arn:'),\n\t\t);\n\t\tif (match) return match.SubscriptionArn;\n\t\tNextToken = page.NextToken;\n\t} while (NextToken);\n\treturn undefined;\n}\n\n/**\n * A pushed notification as the Lambda event SNS would have invoked a function\n * with, so it can be handed to the same adaptor.\n */\nexport function toSnsEvent(message: SnsHttpMessage, subscriptionArn = '') {\n\treturn {\n\t\tRecords: [\n\t\t\t{\n\t\t\t\tEventSource: 'aws:sns',\n\t\t\t\tEventVersion: '1.0',\n\t\t\t\tEventSubscriptionArn: subscriptionArn,\n\t\t\t\tSns: {\n\t\t\t\t\tType: message.Type,\n\t\t\t\t\tMessageId: message.MessageId,\n\t\t\t\t\tTopicArn: message.TopicArn,\n\t\t\t\t\tSubject: message.Subject ?? null,\n\t\t\t\t\tMessage: message.Message,\n\t\t\t\t\tTimestamp: message.Timestamp,\n\t\t\t\t\tSignatureVersion: message.SignatureVersion,\n\t\t\t\t\tSignature: message.Signature,\n\t\t\t\t\t// Lambda spells these two differently from the HTTP envelope.\n\t\t\t\t\tSigningCertUrl: message.SigningCertURL,\n\t\t\t\t\tUnsubscribeUrl: message.UnsubscribeURL ?? '',\n\t\t\t\t\tMessageAttributes: message.MessageAttributes ?? {},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t};\n}\n\nexport class SnsCertificateUntrusted extends Error {\n\tconstructor(readonly url: string) {\n\t\tsuper(\n\t\t\t`The SNS message names a signing certificate at '${url}', which is not ` +\n\t\t\t\t'an https URL on sns.<region>.amazonaws.com. Only SNS can send to ' +\n\t\t\t\t'this endpoint; reject the request.',\n\t\t);\n\t\tthis.name = 'SnsCertificateUntrusted';\n\t}\n}\n\nexport class SnsCertificateUnavailable extends Error {\n\tconstructor(\n\t\treadonly url: string,\n\t\treadonly status: number,\n\t) {\n\t\tsuper(\n\t\t\t`Fetching the SNS signing certificate at '${url}' answered ${status}. ` +\n\t\t\t\t'The message cannot be verified, so it is not handled; SNS will retry.',\n\t\t);\n\t\tthis.name = 'SnsCertificateUnavailable';\n\t}\n}\n\nexport class SnsSignatureVersionUnknown extends Error {\n\tconstructor(readonly version: string) {\n\t\tsuper(\n\t\t\t`SNS signature version '${version}' is not one this endpoint verifies ` +\n\t\t\t\t\"(it knows '1' and '2'). Reject the request.\",\n\t\t);\n\t\tthis.name = 'SnsSignatureVersionUnknown';\n\t}\n}\n\nexport class SnsSignatureInvalid extends Error {\n\tconstructor(\n\t\treadonly messageId: string,\n\t\treadonly topicArn: string,\n\t) {\n\t\tsuper(\n\t\t\t`SNS message '${messageId}' from '${topicArn}' does not verify against ` +\n\t\t\t\t'its signing certificate. It was not sent by SNS, or was altered ' +\n\t\t\t\t'on the way; reject it.',\n\t\t);\n\t\tthis.name = 'SnsSignatureInvalid';\n\t}\n}\n\nexport class SnsMessageTypeUnknown extends Error {\n\tconstructor(readonly type: string) {\n\t\tsuper(\n\t\t\t`'${type}' is not an SNS message type (Notification, ` +\n\t\t\t\t'SubscriptionConfirmation, UnsubscribeConfirmation). Reject it.',\n\t\t);\n\t\tthis.name = 'SnsMessageTypeUnknown';\n\t}\n}\n\nexport class SnsNotAConfirmation extends Error {\n\tconstructor(readonly type: string) {\n\t\tsuper(\n\t\t\t`Only a SubscriptionConfirmation carries a URL to confirm; this is a ` +\n\t\t\t\t`'${type}'.`,\n\t\t);\n\t\tthis.name = 'SnsNotAConfirmation';\n\t}\n}\n\nexport class SnsConfirmationFailed extends Error {\n\tconstructor(\n\t\treadonly topicArn: string,\n\t\treadonly status: number,\n\t) {\n\t\tsuper(\n\t\t\t`Confirming the subscription to '${topicArn}' answered ${status}. ` +\n\t\t\t\t'SNS will deliver nothing until it is confirmed; it resends the ' +\n\t\t\t\t'confirmation, or subscribe the endpoint again.',\n\t\t);\n\t\tthis.name = 'SnsConfirmationFailed';\n\t}\n}\n\nexport class SnsEndpointNotHttp extends Error {\n\tconstructor(readonly endpoint: string) {\n\t\tsuper(\n\t\t\t`'${endpoint}' is not an http(s) URL. SNS pushes to an HTTP endpoint; ` +\n\t\t\t\t'subscribe a queue for anything else.',\n\t\t);\n\t\tthis.name = 'SnsEndpointNotHttp';\n\t}\n}\n","import { SNSClient, type SNSClientConfig } from '@aws-sdk/client-sns';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\nimport * as snsUrl from './snsUrl';\n\nexport interface SNSConnectionConfig {\n\ttopicArn: string;\n\tregion?: string;\n\tendpoint?: string; // Custom endpoint (e.g., for LocalStack)\n\tcredentials?: {\n\t\taccessKeyId: string;\n\t\tsecretAccessKey: string;\n\t\tsessionToken?: string;\n\t};\n}\n\nexport class SNSConnection implements EventConnection {\n\treadonly type = EventPublisherType.SNS;\n\tprivate client: SNSClient;\n\tprivate connected = false;\n\tprivate config: SNSConnectionConfig;\n\n\tconstructor(config: SNSConnectionConfig) {\n\t\tthis.config = config;\n\n\t\tconst clientConfig: SNSClientConfig = {\n\t\t\tregion: config.region,\n\t\t\tendpoint: config.endpoint,\n\t\t\tcredentials: config.credentials,\n\t\t};\n\n\t\tthis.client = new SNSClient(clientConfig);\n\t}\n\n\t/**\n\t * Create an SNSConnection from a connection string\n\t * Format: sns://?topicArn=arn:aws:sns:region:account:topic&region=us-east-1&endpoint=http://localhost:4566\n\t */\n\tstatic async fromConnectionString(\n\t\tconnectionString: string,\n\t): Promise<SNSConnection> {\n\t\t// Through the codec, not a second hand-rolled parse: the deploy target\n\t\t// composes these with `snsUrl.build`, and a string it cannot read back is\n\t\t// exactly the drift one shared module rules out.\n\t\tconst { topicArn, region, endpoint } = snsUrl.parse(connectionString);\n\t\tconst params = new URL(connectionString).searchParams;\n\n\t\tconst config: SNSConnectionConfig = {\n\t\t\ttopicArn,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t};\n\n\t\t// Credentials are not part of the address — see `snsUrl` — but a caller\n\t\t// may still pin them here, so they are read beside it rather than in it.\n\t\tconst accessKeyId = params.get('accessKeyId');\n\t\tconst secretAccessKey = params.get('secretAccessKey');\n\t\tif (accessKeyId && secretAccessKey) {\n\t\t\tconfig.credentials = {\n\t\t\t\taccessKeyId,\n\t\t\t\tsecretAccessKey,\n\t\t\t\tsessionToken: params.get('sessionToken') || undefined,\n\t\t\t};\n\t\t}\n\n\t\tconst connection = new SNSConnection(config);\n\t\tawait connection.connect();\n\t\treturn connection;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\t// SNS doesn't have a traditional connection, but we mark as connected\n\t\tthis.connected = true;\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.client.destroy();\n\t\tthis.connected = false;\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.connected;\n\t}\n\n\t/**\n\t * Get the underlying SNS client\n\t */\n\tget snsClient(): SNSClient {\n\t\treturn this.client;\n\t}\n\n\t/**\n\t * Get the topic ARN for this connection\n\t */\n\tget topicArn(): string {\n\t\treturn this.config.topicArn;\n\t}\n}\n","import { PublishCommand } from '@aws-sdk/client-sns';\nimport type { EventPublisher, PublishableMessage } from '../types';\nimport type { SNSConnection } from './SNSConnection';\n\nexport type SNSPublisherOptions = {};\n\nexport class SNSPublisher<TMessage extends PublishableMessage<string, any>>\n\timplements EventPublisher<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: SNSConnection,\n\t\t_options: SNSPublisherOptions = {},\n\t) {}\n\n\t/**\n\t * Create an SNSPublisher from a connection string\n\t * Format: sns://?topicArn=arn:aws:sns:region:account:topic&region=us-east-1&endpoint=http://localhost:4566\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<SNSPublisher<TMessage>> {\n\t\tconst { SNSConnection } = await import('./SNSConnection');\n\t\tconst connection =\n\t\t\tawait SNSConnection.fromConnectionString(connectionString);\n\n\t\treturn new SNSPublisher<TMessage>(connection);\n\t}\n\n\tasync publish(messages: TMessage[]): Promise<void> {\n\t\tif (messages.length === 0) return;\n\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\t// Publish all messages\n\t\tawait Promise.all(messages.map((message) => this.publishMessage(message)));\n\t}\n\n\tprivate async publishMessage(message: TMessage): Promise<void> {\n\t\tconst command = new PublishCommand({\n\t\t\tTopicArn: this.connection.topicArn,\n\t\t\tMessage: JSON.stringify({\n\t\t\t\ttype: message.type,\n\t\t\t\tpayload: message.payload,\n\t\t\t}),\n\t\t\tMessageAttributes: {\n\t\t\t\ttype: {\n\t\t\t\t\tDataType: 'String',\n\t\t\t\t\tStringValue: message.type,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\n\t\tawait this.connection.snsClient.send(command);\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// Publisher doesn't own the connection\n\t\t// Connection should be closed by whoever created it\n\t}\n}\n","import { SubscribeCommand, UnsubscribeCommand } from '@aws-sdk/client-sns';\nimport {\n\tCreateQueueCommand,\n\tDeleteQueueCommand,\n\tGetQueueAttributesCommand,\n\tSetQueueAttributesCommand,\n\tSQSClient,\n} from '@aws-sdk/client-sqs';\nimport { SQSConnection } from '../sqs/SQSConnection';\nimport { SQSSubscriber } from '../sqs/SQSSubscriber';\nimport type { EventSubscriber, PublishableMessage } from '../types';\nimport type { SNSConnection } from './SNSConnection';\n\nexport interface SNSSubscriberOptions {\n\tqueueName?: string; // Optional queue name (defaults to auto-generated)\n\tcreateQueue?: boolean; // Auto-create SQS queue (default: true)\n\tdeleteQueueOnClose?: boolean; // Delete queue when subscriber closes (default: false for named queues, true for auto-generated)\n\twaitTimeSeconds?: number; // SQS long polling (default: 20)\n\tmaxMessages?: number; // Max messages per poll (default: 10)\n}\n\n/**\n * SNS Subscriber - receives push-based messages from SNS via SQS queue\n *\n * Architecture:\n * SNS Topic → (push) → SQS Queue → Subscriber\n *\n * This subscriber automatically:\n * 1. Creates an SQS queue (or uses existing one)\n * 2. Subscribes the queue to the SNS topic\n * 3. Receives messages pushed from SNS to the queue\n * 4. Filters messages by topic ARN and message type\n * 5. Processes and acknowledges messages\n *\n * Note: While SQS long-polling is used internally to receive messages,\n * this is an implementation detail of the SNS push delivery mechanism.\n * Messages are pushed from SNS to SQS, and we receive those pushed messages.\n */\nexport class SNSSubscriber<TMessage extends PublishableMessage<string, any>>\n\timplements EventSubscriber<TMessage>\n{\n\tprivate sqsClient: SQSClient;\n\tprivate queueUrl?: string;\n\tprivate queueArn?: string;\n\tprivate subscriptionArn?: string;\n\tprivate sqsSubscriber?: SQSSubscriber<TMessage>;\n\tprivate options: Required<SNSSubscriberOptions>;\n\n\tconstructor(\n\t\tprivate connection: SNSConnection,\n\t\toptions: SNSSubscriberOptions = {},\n\t) {\n\t\tthis.options = {\n\t\t\tqueueName:\n\t\t\t\toptions.queueName ||\n\t\t\t\t`sns-sub-${Date.now()}-${Math.random().toString(36).substring(7)}`,\n\t\t\tcreateQueue: options.createQueue ?? true,\n\t\t\tdeleteQueueOnClose: options.deleteQueueOnClose ?? !options.queueName, // Delete auto-generated queues\n\t\t\twaitTimeSeconds: options.waitTimeSeconds ?? 20,\n\t\t\tmaxMessages: options.maxMessages ?? 10,\n\t\t};\n\n\t\t// Create SQS client with same config as SNS\n\t\tthis.sqsClient = new SQSClient({\n\t\t\tregion: (this.connection as any).config.region,\n\t\t\tendpoint: (this.connection as any).config.endpoint,\n\t\t\tcredentials: (this.connection as any).config.credentials,\n\t\t});\n\t}\n\n\t/**\n\t * Create an SNSSubscriber from a connection string\n\t * Format: sns://?topicArn=...&queueName=myqueue&region=us-east-1\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<SNSSubscriber<TMessage>> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst { SNSConnection } = await import('./SNSConnection');\n\t\tconst connection =\n\t\t\tawait SNSConnection.fromConnectionString(connectionString);\n\n\t\tconst options: SNSSubscriberOptions = {\n\t\t\tqueueName: params.get('queueName') || undefined,\n\t\t\tcreateQueue: params.get('createQueue') !== 'false',\n\t\t\tdeleteQueueOnClose: params.get('deleteQueueOnClose') === 'true',\n\t\t\twaitTimeSeconds: params.get('waitTimeSeconds')\n\t\t\t\t? Number.parseInt(params.get('waitTimeSeconds')!, 10)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\treturn new SNSSubscriber<TMessage>(connection, options);\n\t}\n\n\tasync subscribe(\n\t\tmessages: TMessage['type'][],\n\t\tlistener: (payload: TMessage) => Promise<void>,\n\t): Promise<void> {\n\t\t// Setup SQS queue and SNS subscription\n\t\tawait this.setupQueue();\n\t\tawait this.subscribeToTopic();\n\n\t\t// Create SQS connection for the subscriber\n\t\tconst sqsConnection = new SQSConnection({\n\t\t\tqueueUrl: this.queueUrl!,\n\t\t\tregion: (this.connection as any).config.region,\n\t\t\tendpoint: (this.connection as any).config.endpoint,\n\t\t\tcredentials: (this.connection as any).config.credentials,\n\t\t});\n\t\tawait sqsConnection.connect();\n\n\t\t// Use SQSSubscriber to receive messages, with topic filtering\n\t\tthis.sqsSubscriber = new SQSSubscriber<TMessage>(sqsConnection, {\n\t\t\twaitTimeSeconds: this.options.waitTimeSeconds,\n\t\t\tmaxMessages: this.options.maxMessages,\n\t\t\texpectedTopicArn: this.connection.topicArn,\n\t\t});\n\n\t\tawait this.sqsSubscriber.subscribe(messages, listener);\n\t}\n\n\t/**\n\t * Stop receiving messages and clean up resources\n\t */\n\tasync stop(): Promise<void> {\n\t\t// Stop SQS subscriber\n\t\tif (this.sqsSubscriber) {\n\t\t\tthis.sqsSubscriber.stop();\n\t\t}\n\n\t\t// Unsubscribe from topic\n\t\tif (this.subscriptionArn) {\n\t\t\ttry {\n\t\t\t\tconst command = new UnsubscribeCommand({\n\t\t\t\t\tSubscriptionArn: this.subscriptionArn,\n\t\t\t\t});\n\t\t\t\tawait this.connection.snsClient.send(command);\n\t\t\t} catch (_error) {}\n\t\t}\n\n\t\t// Delete queue if configured\n\t\tif (this.queueUrl && this.options.deleteQueueOnClose) {\n\t\t\ttry {\n\t\t\t\tconst command = new DeleteQueueCommand({\n\t\t\t\t\tQueueUrl: this.queueUrl,\n\t\t\t\t});\n\t\t\t\tawait this.sqsClient.send(command);\n\t\t\t} catch (_error) {}\n\t\t}\n\n\t\tthis.sqsClient.destroy();\n\t}\n\n\tprivate async setupQueue(): Promise<void> {\n\t\tif (this.options.createQueue) {\n\t\t\t// Create queue\n\t\t\tconst createCommand = new CreateQueueCommand({\n\t\t\t\tQueueName: this.options.queueName,\n\t\t\t});\n\t\t\tconst response = await this.sqsClient.send(createCommand);\n\t\t\tthis.queueUrl = response.QueueUrl!;\n\t\t} else {\n\t\t\tthrow new SnsQueueMissing(this.options.queueName);\n\t\t}\n\n\t\t// Get queue ARN\n\t\tconst attrsCommand = new GetQueueAttributesCommand({\n\t\t\tQueueUrl: this.queueUrl,\n\t\t\tAttributeNames: ['QueueArn'],\n\t\t});\n\t\tconst attrsResponse = await this.sqsClient.send(attrsCommand);\n\t\tthis.queueArn = attrsResponse.Attributes?.QueueArn!;\n\n\t\t// Set queue policy to allow SNS\n\t\tawait this.setQueuePolicy();\n\t}\n\n\tprivate async setQueuePolicy(): Promise<void> {\n\t\tconst policy = {\n\t\t\tVersion: '2012-10-17',\n\t\t\tStatement: [\n\t\t\t\t{\n\t\t\t\t\tEffect: 'Allow',\n\t\t\t\t\tPrincipal: '*',\n\t\t\t\t\tAction: 'SQS:SendMessage',\n\t\t\t\t\tResource: this.queueArn,\n\t\t\t\t\tCondition: {\n\t\t\t\t\t\tArnEquals: {\n\t\t\t\t\t\t\t'aws:SourceArn': this.connection.topicArn,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\n\t\tconst command = new SetQueueAttributesCommand({\n\t\t\tQueueUrl: this.queueUrl,\n\t\t\tAttributes: {\n\t\t\t\tPolicy: JSON.stringify(policy),\n\t\t\t},\n\t\t});\n\n\t\tawait this.sqsClient.send(command);\n\t}\n\n\tprivate async subscribeToTopic(): Promise<void> {\n\t\tconst command = new SubscribeCommand({\n\t\t\tTopicArn: this.connection.topicArn,\n\t\t\tProtocol: 'sqs',\n\t\t\tEndpoint: this.queueArn,\n\t\t});\n\n\t\tconst response = await this.connection.snsClient.send(command);\n\t\tthis.subscriptionArn = response.SubscriptionArn!;\n\t}\n}\n\n/**\n * A subscriber asked to use a queue it may not create. The SQS queue behind an\n * SNS subscription has to exist first, or `createQueue` has to allow it.\n */\nexport class SnsQueueMissing extends Error {\n\tconstructor(readonly queueName: string | undefined) {\n\t\tsuper(\n\t\t\t`The SNS subscriber's queue${queueName ? ` \"${queueName}\"` : ''} is not created here: pass createQueue: true, or create the queue first.`,\n\t\t);\n\t\tthis.name = 'SnsQueueMissing';\n\t}\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/events",
3
- "version": "10.0.0-alpha.39",
3
+ "version": "10.0.0-alpha.40",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -103,7 +103,7 @@
103
103
  "@aws-sdk/client-sqs": ">=3.1136.0",
104
104
  "@aws-sdk/client-sns": ">=3.1136.0",
105
105
  "pg-boss": ">=12.33.3",
106
- "@geekmidas/schema": "^10.0.0-alpha.39"
106
+ "@geekmidas/schema": "^10.0.0-alpha.40"
107
107
  },
108
108
  "peerDependenciesMeta": {
109
109
  "@geekmidas/schema": {
@@ -128,6 +128,6 @@
128
128
  "@types/pg": "~8.23.1",
129
129
  "pg": "~8.23.0",
130
130
  "pg-boss": "~12.33.3",
131
- "@geekmidas/schema": "^10.0.0-alpha.39"
131
+ "@geekmidas/schema": "^10.0.0-alpha.40"
132
132
  }
133
133
  }