@walkeros/server-destination-aws 4.4.0 → 4.5.1-next-1788726985928

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @walkeros/server-destination-aws
2
2
 
3
+ ## 4.5.1-next-1788726985928
4
+
5
+ ### Patch Changes
6
+
7
+ - 403ff6c: The Firehose destination no longer discards every config field except
8
+ `settings` during init, which silently dropped `before`, `consent`, `mapping`,
9
+ `data` and `next`. A `before` transformer chain configured on the destination
10
+ never ran, and a `consent` requirement was never enforced. The SNS destination
11
+ in the same package was already correct.
12
+ - @walkeros/server-core@4.5.1-next-1788726985928
13
+ - @walkeros/core@4.5.1-next-1788726985928
14
+
15
+ ## 4.5.0
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [63845bb]
20
+ - Updated dependencies [79cdcb0]
21
+ - Updated dependencies [756b571]
22
+ - @walkeros/core@4.5.0
23
+ - @walkeros/server-core@4.5.0
24
+
3
25
  ## 4.4.0
4
26
 
5
27
  ### Patch Changes
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.create;var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=(Object.getPrototypeOf,Object.prototype.hasOwnProperty),__copyProps=(to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to},index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationFirehose:()=>types_exports,DestinationSNS:()=>types_exports2,default:()=>destinationFirehose,destinationFirehose:()=>destinationFirehose,destinationSNS:()=>destinationSNS}),module.exports=(mod=index_exports,__copyProps(__defProp({},"__esModule",{value:!0}),mod));var import_core2=require("@walkeros/core"),import_core=require("@walkeros/core");function isAWSEnvironment(env){return Boolean(env&&"object"==typeof env&&"AWS"in env&&env.AWS?.FirehoseClient)}function getConfig(partialConfig={},env){const settings=partialConfig.settings||{};return settings.firehose&&(settings.firehose=function(firehoseConfig,env){const{streamName:streamName,region:region="eu-central-1",config:config={}}=firehoseConfig;streamName||(0,import_core.throwError)("Firehose: Config custom streamName missing"),config.region||(config.region=region);let client=firehoseConfig.client;return!client&&isAWSEnvironment(env)&&(client=new env.AWS.FirehoseClient(config)),{streamName:streamName,client:client,region:region}}(settings.firehose,env)),{settings:settings}}var push=async function(event,context){const{firehose:firehose}=context.config.settings||{};firehose&&async function(pushEvents,config,context){const{client:client,streamName:streamName}=config,{env:env,logger:logger}=context;if(!client)return{queue:pushEvents};const records=pushEvents.map(({event:event})=>({Data:Buffer.from(JSON.stringify(event))}));if(logger.debug("Calling AWS Firehose API",{stream:streamName,recordCount:records.length}),isAWSEnvironment(env))await client.send(new env.AWS.PutRecordBatchCommand({DeliveryStreamName:streamName,Records:records}));else{const{PutRecordBatchCommand:PutRecordBatchCommand}=await import("@aws-sdk/client-firehose");await client.send(new PutRecordBatchCommand({DeliveryStreamName:streamName,Records:records}))}logger?.debug("AWS Firehose API response",{ok:!0})}([{event:event}],firehose,context)},types_exports={},destinationFirehose={type:"aws-firehose",config:{},async init({config:partialConfig,env:env,logger:logger}){const config=getConfig(partialConfig,env);return(0,import_core2.isSameType)(config.settings,{})||logger.throw("Config settings invalid"),config},push:async(event,context)=>await push(event,context)},import_core3=require("@walkeros/core");function isAWSEnvironment2(env){if("object"!=typeof env||null===env)return!1;if(!("AWS"in env))return!1;const aws=env.AWS;return"object"==typeof aws&&null!==aws&&"SNSClient"in aws}function getConfig2(partial={},env){const settings=function(partial,env){const{topicName:topicName,topicArn:topicArn,config:config={}}=partial,region=partial.region??"eu-central-1";topicName||(0,import_core3.throwError)("SNS: Settings topicName missing");const sdkConfig=config.region?config:{...config,region:region};let client=partial.client;!client&&isAWSEnvironment2(env)&&(client=new env.AWS.SNSClient(sdkConfig));const resolved={topicName:topicName,region:region,config:sdkConfig};return client&&(resolved.client=client),topicArn&&(resolved.topicArn=topicArn),resolved}(partial.settings&&"object"==typeof partial.settings?partial.settings:{},env);return{...partial,settings:settings}}var import_core4=require("@walkeros/core");function isMessageAttribute(value){if(!(0,import_core4.isObject)(value))return!1;return"string"==typeof value.DataType}async function resolveStringMappingValue(event,value,collector){const resolved=await(0,import_core4.getMappingValue)(event,value,{collector:collector});return"string"==typeof resolved&&resolved.length>0?resolved:null!=resolved?String(resolved):void 0}var push2=async function(event,context){const{config:config,env:env,rule:rule,collector:collector,logger:logger,id:id}=context,settings=config.settings,client=settings?.client,topicArn=settings?.topicArn;if(!client)return logger.throw("SNS push: client missing, init() not run");if(!topicArn)return logger.throw("SNS push: topicArn missing, init() not run");if(!isAWSEnvironment2(env))return logger.throw("SNS push: env.AWS not injected");const ruleSettings=(value=rule?.settings,"object"==typeof value&&null!==value?rule.settings:{});var value;let messageGroupId,messageDeduplicationId;void 0!==ruleSettings.messageGroupId&&(messageGroupId=await resolveStringMappingValue(event,ruleSettings.messageGroupId,collector)),void 0!==ruleSettings.messageDeduplicationId&&(messageDeduplicationId=await resolveStringMappingValue(event,ruleSettings.messageDeduplicationId,collector));const messageAttributes=await async function(event,source,collector){if(!source)return;const result={};let touched=!1;for(const[key,value]of Object.entries(source)){const resolved=await(0,import_core4.getMappingValue)(event,value,{collector:collector});isMessageAttribute(resolved)?(result[key]=resolved,touched=!0):"string"==typeof resolved&&resolved.length>0?(result[key]={DataType:"String",StringValue:resolved},touched=!0):null!=resolved&&(result[key]={DataType:"String",StringValue:String(resolved)},touched=!0)}return touched?result:void 0}(event,ruleSettings.messageAttributes,collector),input={TopicArn:topicArn,Message:JSON.stringify(event)};messageGroupId&&(input.MessageGroupId=messageGroupId),messageDeduplicationId&&(input.MessageDeduplicationId=messageDeduplicationId),messageAttributes&&(input.MessageAttributes=messageAttributes),logger.debug("SNS Publish",{topicArn:topicArn,fifo:topicArn.endsWith(".fifo"),event:event.name});try{await client.send(new env.AWS.PublishCommand(input))}catch(err){throw logger.error(`SNS Publish failed for "${topicArn}". Run "walkeros setup destination.${id}" if the topic is missing.`,{topicArn:topicArn,event:event.name,error:err instanceof Error?err.message:String(err)}),err}},import_core5=require("@walkeros/core"),DEFAULT_SETUP={region:"eu-central-1",fifoTopic:!1},accountIdCache=new Map;function buildSubscribeAttributes(sub){const attrs={};return void 0!==sub.rawMessageDelivery&&(attrs.RawMessageDelivery=String(sub.rawMessageDelivery)),void 0!==sub.filterPolicy&&(attrs.FilterPolicy=JSON.stringify(sub.filterPolicy)),void 0!==sub.deadLetterTargetArn&&(attrs.RedrivePolicy=JSON.stringify({deadLetterTargetArn:sub.deadLetterTargetArn})),Object.keys(attrs).length>0?attrs:void 0}var types_exports2={};var destinationSNS={type:"aws-sns",config:{},setup:async function(ctx){const{config:config,env:env,logger:logger}=ctx,merged=(0,import_core5.resolveSetup)(config.setup,DEFAULT_SETUP);if(!merged)return void logger.debug("setup: skipped (config.setup is false or unset)");const settings=config.settings;if(!settings||!settings.topicName)return void logger.throw("setup: settings.topicName is required. There is no safe default for the SNS topic name.");const region=merged.region??DEFAULT_SETUP.region,fifo=merged.fifoTopic??!1,declaredName=settings.topicName,finalName=function(name,fifo){if(fifo)return name.endsWith(".fifo")?name:`${name}.fifo`;if(name.endsWith(".fifo"))throw new Error(`FIFO suffix '.fifo' on standard topic name '${name}'. Set setup.fifoTopic: true or rename the topic.`);return name}(declaredName,fifo);fifo&&finalName!==declaredName&&logger.info(`setup: appended .fifo suffix to FIFO topic name '${declaredName}' -> '${finalName}'`);const client=function(settings,env,region){if(settings?.client)return settings.client;const config=settings?.config??{},merged=config.region?config:{...config,region:region};return new env.AWS.SNSClient(merged)}(settings,env,region),accountId=await async function(env,region){const cached=accountIdCache.get(region);if(cached)return cached;const stsClient=new env.AWS.STSClient({region:region}),res=await stsClient.send(new env.AWS.GetCallerIdentityCommand({}));if("object"==typeof res&&null!==res&&"Account"in res&&"string"==typeof res.Account){const accountId=res.Account;return accountIdCache.set(region,accountId),accountId}throw new Error("STS GetCallerIdentity returned no Account")}(env,region),candidateArn=`arn:aws:sns:${region}:${accountId}:${finalName}`;let topicCreated=!1;try{await client.send(new env.AWS.GetTopicAttributesCommand({TopicArn:candidateArn}))}catch(err){if(!function(err){return!(!function(err){return"object"==typeof err&&null!==err}(err)||"NotFoundException"!==err.name&&"NotFound"!==err.name&&(!err.$metadata||404!==err.$metadata.httpStatusCode))}(err))throw err;topicCreated=!0}const attributes={};fifo&&(attributes.FifoTopic="true",attributes.ContentBasedDeduplication="true"),void 0!==merged.displayName&&(attributes.DisplayName=merged.displayName),void 0!==merged.kmsMasterKeyId&&(attributes.KmsMasterKeyId=merged.kmsMasterKeyId);const tagEntries=merged.tags?Object.entries(merged.tags).map(([Key,Value])=>({Key:Key,Value:Value})):void 0,createInput={Name:finalName};Object.keys(attributes).length>0&&(createInput.Attributes=attributes),tagEntries&&tagEntries.length>0&&(createInput.Tags=tagEntries);const topicArn=function(res){if("object"==typeof(v=res)&&null!==v&&"string"==typeof res.TopicArn)return res.TopicArn;var v;throw new Error("SNS CreateTopic returned no TopicArn")}(await client.send(new env.AWS.CreateTopicCommand(createInput)));topicCreated?logger.info("setup: topic created",{topicArn:topicArn,region:region}):logger.debug("setup: topic exists; declared state re-applied",{topicArn:topicArn,region:region});const subscriptionsCreated=await async function(client,env,topicArn,declared){let count=0;for(const sub of declared){const input={TopicArn:topicArn,Protocol:sub.protocol,Endpoint:sub.endpoint},attrs=buildSubscribeAttributes(sub);attrs&&(input.Attributes=attrs),await client.send(new env.AWS.SubscribeCommand(input)),count+=1}return count}(client,env,topicArn,merged.subscriptions??[]);return{topicArn:topicArn,topicCreated:topicCreated,tagsApplied:merged.tags?Object.keys(merged.tags).length:0,subscriptionsCreated:subscriptionsCreated}},async init({config:partial,env:env,logger:logger,id:id}){const config=getConfig2(partial,env);if(!config.settings.client)return void logger.throw("SNS init: client missing (env not injected)");if(!isAWSEnvironment2(env))return void logger.throw("SNS init: env.AWS missing");if(config.settings.topicArn)return config;const{client:client,topicName:topicName,region:region}=config.settings;try{const res=await client.send(new env.AWS.CreateTopicCommand({Name:topicName}));if("object"!=typeof(v=res)||null===v||"string"!=typeof res.TopicArn||0===res.TopicArn.length)return void logger.throw(`SNS init: CreateTopic returned no ARN for "${topicName}"`);config.settings.topicArn=res.TopicArn}catch(err){throw logger.error(`SNS init failed for topic "${topicName}" in region ${region??"eu-central-1"}. Either set settings.topicArn directly, run "walkeros setup destination.${id}", or grant sns:CreateTopic to the runtime role.`,{topicName:topicName,region:region,error:err instanceof Error?err.message:String(err)}),err}var v;return config},push:async(event,context)=>await push2(event,context)};//# sourceMappingURL=index.js.map
1
+ "use strict";Object.create;var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=(Object.getPrototypeOf,Object.prototype.hasOwnProperty),__copyProps=(to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to},index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationFirehose:()=>types_exports,DestinationSNS:()=>types_exports2,default:()=>destinationFirehose,destinationFirehose:()=>destinationFirehose,destinationSNS:()=>destinationSNS}),module.exports=(mod=index_exports,__copyProps(__defProp({},"__esModule",{value:!0}),mod));var import_core2=require("@walkeros/core"),import_core=require("@walkeros/core");function isAWSEnvironment(env){return Boolean(env&&"object"==typeof env&&"AWS"in env&&env.AWS?.FirehoseClient)}function getConfig(partialConfig={},env){const settings=partialConfig.settings||{};return settings.firehose&&(settings.firehose=function(firehoseConfig,env){const{streamName:streamName,region:region="eu-central-1",config:config={}}=firehoseConfig;streamName||(0,import_core.throwError)("Firehose: Config custom streamName missing"),config.region||(config.region=region);let client=firehoseConfig.client;return!client&&isAWSEnvironment(env)&&(client=new env.AWS.FirehoseClient(config)),{streamName:streamName,client:client,region:region}}(settings.firehose,env)),{...partialConfig,settings:settings}}var push=async function(event,context){const{firehose:firehose}=context.config.settings||{};firehose&&async function(pushEvents,config,context){const{client:client,streamName:streamName}=config,{env:env,logger:logger}=context;if(!client)return{queue:pushEvents};const records=pushEvents.map(({event:event})=>({Data:Buffer.from(JSON.stringify(event))}));if(logger.debug("Calling AWS Firehose API",{stream:streamName,recordCount:records.length}),isAWSEnvironment(env))await client.send(new env.AWS.PutRecordBatchCommand({DeliveryStreamName:streamName,Records:records}));else{const{PutRecordBatchCommand:PutRecordBatchCommand}=await import("@aws-sdk/client-firehose");await client.send(new PutRecordBatchCommand({DeliveryStreamName:streamName,Records:records}))}logger?.debug("AWS Firehose API response",{ok:!0})}([{event:event}],firehose,context)},types_exports={},destinationFirehose={type:"aws-firehose",config:{},async init({config:partialConfig,env:env,logger:logger}){const config=getConfig(partialConfig,env);return(0,import_core2.isSameType)(config.settings,{})||logger.throw("Config settings invalid"),config},push:async(event,context)=>await push(event,context)},import_core3=require("@walkeros/core");function isAWSEnvironment2(env){if("object"!=typeof env||null===env)return!1;if(!("AWS"in env))return!1;const aws=env.AWS;return"object"==typeof aws&&null!==aws&&"SNSClient"in aws}function getConfig2(partial={},env){const settings=function(partial,env){const{topicName:topicName,topicArn:topicArn,config:config={}}=partial,region=partial.region??"eu-central-1";topicName||(0,import_core3.throwError)("SNS: Settings topicName missing");const sdkConfig=config.region?config:{...config,region:region};let client=partial.client;!client&&isAWSEnvironment2(env)&&(client=new env.AWS.SNSClient(sdkConfig));const resolved={topicName:topicName,region:region,config:sdkConfig};return client&&(resolved.client=client),topicArn&&(resolved.topicArn=topicArn),resolved}(partial.settings&&"object"==typeof partial.settings?partial.settings:{},env);return{...partial,settings:settings}}var import_core4=require("@walkeros/core");function isMessageAttribute(value){if(!(0,import_core4.isObject)(value))return!1;return"string"==typeof value.DataType}async function resolveStringMappingValue(event,value,collector){const resolved=await(0,import_core4.getMappingValue)(event,value,{collector:collector});return"string"==typeof resolved&&resolved.length>0?resolved:null!=resolved?String(resolved):void 0}var push2=async function(event,context){const{config:config,env:env,rule:rule,collector:collector,logger:logger,id:id}=context,settings=config.settings,client=settings?.client,topicArn=settings?.topicArn;if(!client)return logger.throw("SNS push: client missing, init() not run");if(!topicArn)return logger.throw("SNS push: topicArn missing, init() not run");if(!isAWSEnvironment2(env))return logger.throw("SNS push: env.AWS not injected");const ruleSettings=(value=rule?.settings,"object"==typeof value&&null!==value?rule.settings:{});var value;let messageGroupId,messageDeduplicationId;void 0!==ruleSettings.messageGroupId&&(messageGroupId=await resolveStringMappingValue(event,ruleSettings.messageGroupId,collector)),void 0!==ruleSettings.messageDeduplicationId&&(messageDeduplicationId=await resolveStringMappingValue(event,ruleSettings.messageDeduplicationId,collector));const messageAttributes=await async function(event,source,collector){if(!source)return;const result={};let touched=!1;for(const[key,value]of Object.entries(source)){const resolved=await(0,import_core4.getMappingValue)(event,value,{collector:collector});isMessageAttribute(resolved)?(result[key]=resolved,touched=!0):"string"==typeof resolved&&resolved.length>0?(result[key]={DataType:"String",StringValue:resolved},touched=!0):null!=resolved&&(result[key]={DataType:"String",StringValue:String(resolved)},touched=!0)}return touched?result:void 0}(event,ruleSettings.messageAttributes,collector),input={TopicArn:topicArn,Message:JSON.stringify(event)};messageGroupId&&(input.MessageGroupId=messageGroupId),messageDeduplicationId&&(input.MessageDeduplicationId=messageDeduplicationId),messageAttributes&&(input.MessageAttributes=messageAttributes),logger.debug("SNS Publish",{topicArn:topicArn,fifo:topicArn.endsWith(".fifo"),event:event.name});try{await client.send(new env.AWS.PublishCommand(input))}catch(err){throw logger.error(`SNS Publish failed for "${topicArn}". Run "walkeros setup destination.${id}" if the topic is missing.`,{topicArn:topicArn,event:event.name,error:err instanceof Error?err.message:String(err)}),err}},import_core5=require("@walkeros/core"),DEFAULT_SETUP={region:"eu-central-1",fifoTopic:!1},accountIdCache=new Map;function buildSubscribeAttributes(sub){const attrs={};return void 0!==sub.rawMessageDelivery&&(attrs.RawMessageDelivery=String(sub.rawMessageDelivery)),void 0!==sub.filterPolicy&&(attrs.FilterPolicy=JSON.stringify(sub.filterPolicy)),void 0!==sub.deadLetterTargetArn&&(attrs.RedrivePolicy=JSON.stringify({deadLetterTargetArn:sub.deadLetterTargetArn})),Object.keys(attrs).length>0?attrs:void 0}var types_exports2={};var destinationSNS={type:"aws-sns",config:{},setup:async function(ctx){const{config:config,env:env,logger:logger}=ctx,merged=(0,import_core5.resolveSetup)(config.setup,DEFAULT_SETUP);if(!merged)return void logger.debug("setup: skipped (config.setup is false or unset)");const settings=config.settings;if(!settings||!settings.topicName)return void logger.throw("setup: settings.topicName is required. There is no safe default for the SNS topic name.");const region=merged.region??DEFAULT_SETUP.region,fifo=merged.fifoTopic??!1,declaredName=settings.topicName,finalName=function(name,fifo){if(fifo)return name.endsWith(".fifo")?name:`${name}.fifo`;if(name.endsWith(".fifo"))throw new Error(`FIFO suffix '.fifo' on standard topic name '${name}'. Set setup.fifoTopic: true or rename the topic.`);return name}(declaredName,fifo);fifo&&finalName!==declaredName&&logger.info(`setup: appended .fifo suffix to FIFO topic name '${declaredName}' -> '${finalName}'`);const client=function(settings,env,region){if(settings?.client)return settings.client;const config=settings?.config??{},merged=config.region?config:{...config,region:region};return new env.AWS.SNSClient(merged)}(settings,env,region),accountId=await async function(env,region){const cached=accountIdCache.get(region);if(cached)return cached;const stsClient=new env.AWS.STSClient({region:region}),res=await stsClient.send(new env.AWS.GetCallerIdentityCommand({}));if("object"==typeof res&&null!==res&&"Account"in res&&"string"==typeof res.Account){const accountId=res.Account;return accountIdCache.set(region,accountId),accountId}throw new Error("STS GetCallerIdentity returned no Account")}(env,region),candidateArn=`arn:aws:sns:${region}:${accountId}:${finalName}`;let topicCreated=!1;try{await client.send(new env.AWS.GetTopicAttributesCommand({TopicArn:candidateArn}))}catch(err){if(!function(err){return!(!function(err){return"object"==typeof err&&null!==err}(err)||"NotFoundException"!==err.name&&"NotFound"!==err.name&&(!err.$metadata||404!==err.$metadata.httpStatusCode))}(err))throw err;topicCreated=!0}const attributes={};fifo&&(attributes.FifoTopic="true",attributes.ContentBasedDeduplication="true"),void 0!==merged.displayName&&(attributes.DisplayName=merged.displayName),void 0!==merged.kmsMasterKeyId&&(attributes.KmsMasterKeyId=merged.kmsMasterKeyId);const tagEntries=merged.tags?Object.entries(merged.tags).map(([Key,Value])=>({Key:Key,Value:Value})):void 0,createInput={Name:finalName};Object.keys(attributes).length>0&&(createInput.Attributes=attributes),tagEntries&&tagEntries.length>0&&(createInput.Tags=tagEntries);const topicArn=function(res){if("object"==typeof(v=res)&&null!==v&&"string"==typeof res.TopicArn)return res.TopicArn;var v;throw new Error("SNS CreateTopic returned no TopicArn")}(await client.send(new env.AWS.CreateTopicCommand(createInput)));topicCreated?logger.info("setup: topic created",{topicArn:topicArn,region:region}):logger.debug("setup: topic exists; declared state re-applied",{topicArn:topicArn,region:region});const subscriptionsCreated=await async function(client,env,topicArn,declared){let count=0;for(const sub of declared){const input={TopicArn:topicArn,Protocol:sub.protocol,Endpoint:sub.endpoint},attrs=buildSubscribeAttributes(sub);attrs&&(input.Attributes=attrs),await client.send(new env.AWS.SubscribeCommand(input)),count+=1}return count}(client,env,topicArn,merged.subscriptions??[]);return{topicArn:topicArn,topicCreated:topicCreated,tagsApplied:merged.tags?Object.keys(merged.tags).length:0,subscriptionsCreated:subscriptionsCreated}},async init({config:partial,env:env,logger:logger,id:id}){const config=getConfig2(partial,env);if(!config.settings.client)return void logger.throw("SNS init: client missing (env not injected)");if(!isAWSEnvironment2(env))return void logger.throw("SNS init: env.AWS missing");if(config.settings.topicArn)return config;const{client:client,topicName:topicName,region:region}=config.settings;try{const res=await client.send(new env.AWS.CreateTopicCommand({Name:topicName}));if("object"!=typeof(v=res)||null===v||"string"!=typeof res.TopicArn||0===res.TopicArn.length)return void logger.throw(`SNS init: CreateTopic returned no ARN for "${topicName}"`);config.settings.topicArn=res.TopicArn}catch(err){throw logger.error(`SNS init failed for topic "${topicName}" in region ${region??"eu-central-1"}. Either set settings.topicArn directly, run "walkeros setup destination.${id}", or grant sns:CreateTopic to the runtime role.`,{topicName:topicName,region:region,error:err instanceof Error?err.message:String(err)}),err}var v;return config},push:async(event,context)=>await push2(event,context)};//# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/firehose/index.ts","../src/firehose/lib/firehose.ts","../src/firehose/config.ts","../src/firehose/push.ts","../src/firehose/types/index.ts","../src/sns/lib/sns.ts","../src/sns/config.ts","../src/sns/push.ts","../src/sns/setup.ts","../src/sns/types/index.ts","../src/sns/index.ts"],"sourcesContent":["// AWS Firehose\nexport { destinationFirehose } from './firehose';\nexport * as DestinationFirehose from './firehose/types';\n\n// AWS SNS\nexport { destinationSNS } from './sns';\nexport * as DestinationSNS from './sns/types';\n\n// Default remains Firehose for backward compatibility.\nexport { destinationFirehose as default } from './firehose';\n","import type { Settings, Destination } from './types';\nimport { isSameType } from '@walkeros/core';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationFirehose from './types';\n\nexport const destinationFirehose: Destination = {\n type: 'aws-firehose',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env);\n\n if (!isSameType(config.settings, {} as Settings))\n logger.throw('Config settings invalid');\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationFirehose;\n","import type { Destination, Logger } from '@walkeros/core';\nimport type { FirehoseConfig, Env } from '../types';\nimport { throwError } from '@walkeros/core';\n\n// Type guard to check if environment has AWS SDK\nfunction isAWSEnvironment(env: unknown): env is Env {\n return Boolean(\n env &&\n typeof env === 'object' &&\n 'AWS' in env &&\n (env as Env).AWS?.FirehoseClient,\n );\n}\n\nexport function getConfigFirehose(\n firehoseConfig: Partial<FirehoseConfig>,\n env?: unknown,\n): FirehoseConfig {\n const { streamName, region = 'eu-central-1', config = {} } = firehoseConfig;\n\n if (!streamName) throwError('Firehose: Config custom streamName missing');\n\n if (!config.region) config.region = region;\n\n // Use environment-injected SDK or fall back to provided client\n let client = firehoseConfig.client;\n if (!client && isAWSEnvironment(env)) {\n client = new env.AWS.FirehoseClient(config);\n }\n\n return {\n streamName,\n client,\n region,\n };\n}\n\nexport async function pushFirehose(\n pushEvents: Destination.PushEvents,\n config: FirehoseConfig,\n context: Destination.PushContext,\n) {\n const { client, streamName } = config;\n const { env, logger } = context;\n\n if (!client) return { queue: pushEvents };\n\n // Up to 500 records per batch\n const records = pushEvents.map(({ event }) => ({\n Data: Buffer.from(JSON.stringify(event)),\n }));\n\n logger.debug('Calling AWS Firehose API', {\n stream: streamName,\n recordCount: records.length,\n });\n\n // Use environment-injected SDK command or fall back to direct import\n if (isAWSEnvironment(env)) {\n await client.send(\n new env.AWS.PutRecordBatchCommand({\n DeliveryStreamName: streamName,\n Records: records,\n }),\n );\n } else {\n // Fall back to direct import for backward compatibility\n const { PutRecordBatchCommand } = await import('@aws-sdk/client-firehose');\n await client.send(\n new PutRecordBatchCommand({\n DeliveryStreamName: streamName,\n Records: records,\n }),\n );\n }\n\n logger?.debug('AWS Firehose API response', { ok: true });\n}\n","import type { Config, Settings, PartialConfig, Env } from './types';\nimport { getConfigFirehose } from './lib/firehose';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env?: unknown,\n): Config {\n const settings = partialConfig.settings || ({} as Settings);\n\n if (settings.firehose)\n settings.firehose = getConfigFirehose(settings.firehose, env);\n\n return { settings };\n}\n","import type { PushFn } from './types';\nimport { pushFirehose } from './lib/firehose';\n\nexport const push: PushFn = async function (event, context) {\n const { firehose } = context.config.settings || {};\n\n if (firehose) pushFirehose([{ event }], firehose, context);\n\n return;\n};\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type {\n FirehoseClient,\n FirehoseClientConfig,\n PutRecordBatchCommand,\n} from '@aws-sdk/client-firehose';\n\nexport interface Settings {\n firehose?: FirehoseConfig;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n AWS: {\n FirehoseClient: typeof FirehoseClient;\n PutRecordBatchCommand: typeof PutRecordBatchCommand;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\nexport interface FirehoseConfig {\n streamName: string;\n client?: FirehoseClient;\n region?: string;\n config?: FirehoseClientConfig;\n}\n","import type { Env, Settings } from '../types';\nimport { throwError } from '@walkeros/core';\n\n/** Type guard to check if environment has the AWS SNS SDK injected. */\nexport function isAWSEnvironment(env: unknown): env is Env {\n if (typeof env !== 'object' || env === null) return false;\n if (!('AWS' in env)) return false;\n const aws = (env as { AWS?: unknown }).AWS;\n if (typeof aws !== 'object' || aws === null) return false;\n return 'SNSClient' in aws;\n}\n\n/**\n * Resolve `Settings` from a partial input. Validates `topicName`, fills\n * `region` from default, builds an SNSClient from the env-injected\n * constructor when none was supplied.\n */\nexport function getConfigSNS(\n partial: Partial<Settings>,\n env?: unknown,\n): Settings {\n const { topicName, topicArn, config = {} } = partial;\n const region = partial.region ?? 'eu-central-1';\n\n if (!topicName) throwError('SNS: Settings topicName missing');\n\n const sdkConfig = config.region ? config : { ...config, region };\n\n let client = partial.client;\n if (!client && isAWSEnvironment(env)) {\n client = new env.AWS.SNSClient(sdkConfig);\n }\n\n const resolved: Settings = {\n topicName,\n region,\n config: sdkConfig,\n };\n if (client) resolved.client = client;\n if (topicArn) resolved.topicArn = topicArn;\n return resolved;\n}\n","import type { Config, PartialConfig, Settings } from './types';\nimport { getConfigSNS } from './lib/sns';\n\nexport function getConfig(partial: PartialConfig = {}, env?: unknown): Config {\n const partialSettings: Partial<Settings> =\n partial.settings && typeof partial.settings === 'object'\n ? partial.settings\n : {};\n const settings = getConfigSNS(partialSettings, env);\n return { ...partial, settings };\n}\n","import type { PushFn, Mapping } from './types';\nimport type { Mapping as WalkerOSMapping, Collector } from '@walkeros/core';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { isAWSEnvironment } from './lib/sns';\n\ninterface MessageAttribute {\n DataType: string;\n StringValue?: string;\n BinaryValue?: Uint8Array;\n}\n\nfunction isMessageAttribute(value: unknown): value is MessageAttribute {\n if (!isObject(value)) return false;\n const candidate = value as Record<string, unknown>;\n return typeof candidate.DataType === 'string';\n}\n\nasync function resolveMessageAttributes(\n event: Parameters<PushFn>[0],\n source: WalkerOSMapping.Map | undefined,\n collector: Collector.Instance,\n): Promise<Record<string, MessageAttribute> | undefined> {\n if (!source) return undefined;\n const result: Record<string, MessageAttribute> = {};\n let touched = false;\n for (const [key, value] of Object.entries(source)) {\n const resolved = await getMappingValue(event, value, { collector });\n if (isMessageAttribute(resolved)) {\n result[key] = resolved;\n touched = true;\n } else if (typeof resolved === 'string' && resolved.length > 0) {\n // Bare-string convenience: wrap into String DataType.\n result[key] = { DataType: 'String', StringValue: resolved };\n touched = true;\n } else if (resolved !== undefined && resolved !== null) {\n result[key] = { DataType: 'String', StringValue: String(resolved) };\n touched = true;\n }\n }\n return touched ? result : undefined;\n}\n\nfunction isMapping(value: unknown): value is Mapping {\n return typeof value === 'object' && value !== null;\n}\n\nasync function resolveStringMappingValue(\n event: Parameters<PushFn>[0],\n value: WalkerOSMapping.Value,\n collector: Collector.Instance,\n): Promise<string | undefined> {\n const resolved = await getMappingValue(event, value, { collector });\n if (typeof resolved === 'string' && resolved.length > 0) return resolved;\n if (resolved === undefined || resolved === null) return undefined;\n return String(resolved);\n}\n\nexport const push: PushFn = async function (event, context) {\n const { config, env, rule, collector, logger, id } = context;\n const settings = config.settings;\n const client = settings?.client;\n const topicArn = settings?.topicArn;\n\n if (!client) return logger.throw('SNS push: client missing, init() not run');\n if (!topicArn)\n return logger.throw('SNS push: topicArn missing, init() not run');\n if (!isAWSEnvironment(env))\n return logger.throw('SNS push: env.AWS not injected');\n\n const ruleSettings: Mapping = isMapping(rule?.settings) ? rule.settings : {};\n\n let messageGroupId: string | undefined;\n if (ruleSettings.messageGroupId !== undefined) {\n messageGroupId = await resolveStringMappingValue(\n event,\n ruleSettings.messageGroupId,\n collector,\n );\n }\n\n let messageDeduplicationId: string | undefined;\n if (ruleSettings.messageDeduplicationId !== undefined) {\n messageDeduplicationId = await resolveStringMappingValue(\n event,\n ruleSettings.messageDeduplicationId,\n collector,\n );\n }\n\n const messageAttributes = await resolveMessageAttributes(\n event,\n ruleSettings.messageAttributes,\n collector,\n );\n\n const input: {\n TopicArn: string;\n Message: string;\n MessageGroupId?: string;\n MessageDeduplicationId?: string;\n MessageAttributes?: Record<string, MessageAttribute>;\n } = {\n TopicArn: topicArn,\n Message: JSON.stringify(event),\n };\n if (messageGroupId) input.MessageGroupId = messageGroupId;\n if (messageDeduplicationId)\n input.MessageDeduplicationId = messageDeduplicationId;\n if (messageAttributes) input.MessageAttributes = messageAttributes;\n\n logger.debug('SNS Publish', {\n topicArn,\n fifo: topicArn.endsWith('.fifo'),\n event: event.name,\n });\n\n try {\n await client.send(new env.AWS.PublishCommand(input));\n } catch (err) {\n logger.error(\n `SNS Publish failed for \"${topicArn}\". ` +\n `Run \"walkeros setup destination.${id}\" if the topic is missing.`,\n {\n topicArn,\n event: event.name,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n throw err;\n }\n};\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type { Env, Setup, SetupSubscription, Settings, Types } from './types';\nimport type { LifecycleContext } from '@walkeros/core';\nimport { resolveSetup } from '@walkeros/core';\nimport type { SNSClient as SNSClientType } from '@aws-sdk/client-sns';\n\n// Setup is wired to the destination's `setup` slot which uses the broader\n// `DestinationServer.Config<Types>` (settings is optional). We runtime-narrow\n// instead of using the local Config alias so the assignment in index.ts\n// type-checks without contravariance issues.\ntype WideConfig = DestinationServer.Config<Types>;\n\nexport const DEFAULT_SETUP: Required<Pick<Setup, 'region' | 'fifoTopic'>> &\n Setup = {\n region: 'eu-central-1',\n fifoTopic: false,\n};\n\nexport interface SetupResult {\n topicArn: string;\n /** True when the GetTopicAttributes probe returned 404 (topic absent before this run). */\n topicCreated: boolean;\n tagsApplied: number;\n subscriptionsCreated: number;\n}\n\n// Module-level account-ID cache so re-running setup in the same process is\n// a no-op for the STS GetCallerIdentity call. Keyed by region (in case\n// future versions support cross-region setup in one process).\nconst accountIdCache: Map<string, string> = new Map();\n\n/** Test-only: clear the account-ID cache between test cases. */\nexport function __resetAccountIdCache(): void {\n accountIdCache.clear();\n}\n\ninterface CreateTopicResponse {\n TopicArn?: string;\n}\n\ninterface AwsErrorMeta {\n name?: string;\n $metadata?: { httpStatusCode?: number };\n}\n\nfunction isAwsError(err: unknown): err is AwsErrorMeta {\n return typeof err === 'object' && err !== null;\n}\n\nfunction isNotFound(err: unknown): boolean {\n if (!isAwsError(err)) return false;\n if (err.name === 'NotFoundException' || err.name === 'NotFound') return true;\n if (err.$metadata && err.$metadata.httpStatusCode === 404) return true;\n return false;\n}\n\nfunction resolveTopicName(name: string, fifo: boolean): string {\n if (fifo) {\n if (name.endsWith('.fifo')) return name;\n return `${name}.fifo`;\n }\n if (name.endsWith('.fifo')) {\n throw new Error(\n `FIFO suffix '.fifo' on standard topic name '${name}'. Set setup.fifoTopic: true or rename the topic.`,\n );\n }\n return name;\n}\n\nfunction resolveClient(\n settings: Settings | undefined,\n env: Env,\n region: string,\n): SNSClientType {\n if (settings?.client) return settings.client;\n const config = settings?.config ?? {};\n const merged = config.region ? config : { ...config, region };\n return new env.AWS.SNSClient(merged);\n}\n\nasync function getAccountId(env: Env, region: string): Promise<string> {\n const cached = accountIdCache.get(region);\n if (cached) return cached;\n const stsClient = new env.AWS.STSClient({ region });\n const res: unknown = await stsClient.send(\n new env.AWS.GetCallerIdentityCommand({}),\n );\n if (\n typeof res === 'object' &&\n res !== null &&\n 'Account' in res &&\n typeof (res as { Account?: unknown }).Account === 'string'\n ) {\n const accountId = (res as { Account: string }).Account;\n accountIdCache.set(region, accountId);\n return accountId;\n }\n throw new Error('STS GetCallerIdentity returned no Account');\n}\n\nfunction isCreateTopicResponse(v: unknown): v is CreateTopicResponse {\n return typeof v === 'object' && v !== null;\n}\n\nfunction extractTopicArn(res: unknown): string {\n if (isCreateTopicResponse(res) && typeof res.TopicArn === 'string')\n return res.TopicArn;\n throw new Error('SNS CreateTopic returned no TopicArn');\n}\n\nfunction buildSubscribeAttributes(\n sub: SetupSubscription,\n): Record<string, string> | undefined {\n const attrs: Record<string, string> = {};\n if (sub.rawMessageDelivery !== undefined) {\n attrs.RawMessageDelivery = String(sub.rawMessageDelivery);\n }\n if (sub.filterPolicy !== undefined) {\n attrs.FilterPolicy = JSON.stringify(sub.filterPolicy);\n }\n if (sub.deadLetterTargetArn !== undefined) {\n attrs.RedrivePolicy = JSON.stringify({\n deadLetterTargetArn: sub.deadLetterTargetArn,\n });\n }\n return Object.keys(attrs).length > 0 ? attrs : undefined;\n}\n\nasync function applyDeclaredSubscriptions(\n client: SNSClientType,\n env: Env,\n topicArn: string,\n declared: SetupSubscription[],\n): Promise<number> {\n let count = 0;\n for (const sub of declared) {\n const input: {\n TopicArn: string;\n Protocol: string;\n Endpoint: string;\n Attributes?: Record<string, string>;\n } = {\n TopicArn: topicArn,\n Protocol: sub.protocol,\n Endpoint: sub.endpoint,\n };\n const attrs = buildSubscribeAttributes(sub);\n if (attrs) input.Attributes = attrs;\n await client.send(new env.AWS.SubscribeCommand(input));\n count += 1;\n }\n return count;\n}\n\nexport async function setup(\n ctx: LifecycleContext<WideConfig, Env>,\n): Promise<SetupResult | undefined> {\n const { config, env, logger } = ctx;\n const merged = resolveSetup(config.setup, DEFAULT_SETUP);\n if (!merged) {\n logger.debug('setup: skipped (config.setup is false or unset)');\n return;\n }\n\n const settings = config.settings;\n if (!settings || !settings.topicName) {\n logger.throw(\n 'setup: settings.topicName is required. There is no safe default for the SNS topic name.',\n );\n return;\n }\n\n const region = merged.region ?? DEFAULT_SETUP.region;\n const fifo = merged.fifoTopic ?? false;\n const declaredName = settings.topicName;\n const finalName = resolveTopicName(declaredName, fifo);\n if (fifo && finalName !== declaredName) {\n logger.info(\n `setup: appended .fifo suffix to FIFO topic name '${declaredName}' -> '${finalName}'`,\n );\n }\n\n // Topic-existence probe via candidate ARN derived from STS account ID.\n const client = resolveClient(settings, env, region);\n const accountId = await getAccountId(env, region);\n const candidateArn = `arn:aws:sns:${region}:${accountId}:${finalName}`;\n\n let topicCreated = false;\n try {\n await client.send(\n new env.AWS.GetTopicAttributesCommand({ TopicArn: candidateArn }),\n );\n } catch (err) {\n if (isNotFound(err)) {\n topicCreated = true;\n } else {\n throw err;\n }\n }\n\n // Authoritative-apply: full declared state in one CreateTopic call.\n // SNS:CreateTopic is idempotent on identical Name+Attributes+Tags inputs.\n const attributes: Record<string, string> = {};\n if (fifo) {\n attributes.FifoTopic = 'true';\n attributes.ContentBasedDeduplication = 'true';\n }\n if (merged.displayName !== undefined)\n attributes.DisplayName = merged.displayName;\n if (merged.kmsMasterKeyId !== undefined)\n attributes.KmsMasterKeyId = merged.kmsMasterKeyId;\n\n const tagEntries = merged.tags\n ? Object.entries(merged.tags).map(([Key, Value]) => ({ Key, Value }))\n : undefined;\n\n const createInput: {\n Name: string;\n Attributes?: Record<string, string>;\n Tags?: Array<{ Key: string; Value: string }>;\n } = { Name: finalName };\n if (Object.keys(attributes).length > 0) createInput.Attributes = attributes;\n if (tagEntries && tagEntries.length > 0) createInput.Tags = tagEntries;\n\n const createRes = await client.send(\n new env.AWS.CreateTopicCommand(createInput),\n );\n const topicArn = extractTopicArn(createRes);\n\n if (topicCreated) {\n logger.info('setup: topic created', { topicArn, region });\n } else {\n logger.debug('setup: topic exists; declared state re-applied', {\n topicArn,\n region,\n });\n }\n\n const subscriptionsCreated = await applyDeclaredSubscriptions(\n client,\n env,\n topicArn,\n merged.subscriptions ?? [],\n );\n\n return {\n topicArn,\n topicCreated,\n tagsApplied: merged.tags ? Object.keys(merged.tags).length : 0,\n subscriptionsCreated,\n };\n}\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n SetupFn as CoreSetupFn,\n} from '@walkeros/core';\nimport type {\n SNSClient,\n SNSClientConfig,\n CreateTopicCommand,\n PublishCommand,\n GetTopicAttributesCommand,\n SubscribeCommand,\n} from '@aws-sdk/client-sns';\nimport type { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts';\n\nexport interface Settings {\n /** Topic name (without `.fifo` suffix unless fifoTopic is true). REQUIRED. */\n topicName: string;\n /** Pre-configured client. Optional; created from env if absent. */\n client?: SNSClient;\n /** AWS region. Mirrors setup.region default ('eu-central-1'). */\n region?: string;\n /** SDK client config (credentials, etc.). Optional. */\n config?: SNSClientConfig;\n /** Topic ARN, populated at init() from CreateTopic. Operator may pre-set to skip init's CreateTopic call. */\n topicArn?: string;\n}\n\nexport interface InitSettings {\n topicName: string;\n client?: SNSClient;\n region?: string;\n config?: SNSClientConfig;\n topicArn?: string;\n}\n\nexport interface Mapping {\n /**\n * Per-event message attributes resolved via mapping. Each attribute value\n * resolves to the SDK's expected `{ DataType, StringValue }` shape; operators\n * write either a literal `{ DataType: 'String', StringValue: '$path' }` value\n * or use `{ value: { DataType: 'String', StringValue: '$user.id' } }` style\n * to drive the StringValue from event data.\n */\n messageAttributes?: WalkerOSMapping.Map;\n /**\n * FIFO group ID for FIFO topics. `Mapping.Value` so operators can write\n * `messageGroupId: 'user.id'` (path) instead of hard-coding a literal.\n */\n messageGroupId?: WalkerOSMapping.Value;\n /** FIFO deduplication ID. `Mapping.Value`, same reasoning as `messageGroupId`. */\n messageDeduplicationId?: WalkerOSMapping.Value;\n}\n\nexport interface Env extends DestinationServer.Env {\n AWS: {\n SNSClient: typeof SNSClient;\n CreateTopicCommand: typeof CreateTopicCommand;\n PublishCommand: typeof PublishCommand;\n GetTopicAttributesCommand: typeof GetTopicAttributesCommand;\n SubscribeCommand: typeof SubscribeCommand;\n STSClient: typeof STSClient;\n GetCallerIdentityCommand: typeof GetCallerIdentityCommand;\n };\n}\n\n/**\n * Provisioning options for `walkeros setup destination.<id>` when targeting SNS.\n * Triggered only by the explicit CLI command. Idempotent, never auto-run.\n *\n * `topicName` lives in Settings (one source of truth for setup AND runtime publish).\n */\nexport interface Setup {\n /** AWS region for the topic. Default: 'eu-central-1'. */\n region?: string;\n /** Display name. Optional. */\n displayName?: string;\n /** FIFO topic with content-based deduplication. Default: false. */\n fifoTopic?: boolean;\n /** KMS key for at-rest encryption. Optional. */\n kmsMasterKeyId?: string;\n /** Tags for cost allocation. Optional. */\n tags?: Record<string, string>;\n /** Subscriptions to create or update on the topic. Each is opt-in. */\n subscriptions?: SetupSubscription[];\n}\n\nexport interface SetupSubscription {\n protocol: 'sqs' | 'lambda' | 'https' | 'http' | 'email' | 'sms';\n endpoint: string;\n rawMessageDelivery?: boolean;\n filterPolicy?: Record<string, unknown>;\n deadLetterTargetArn?: string;\n}\n\nexport type Types = CoreDestination.Types<\n Settings,\n Mapping,\n Env,\n InitSettings,\n Setup\n>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type SetupFn = CoreSetupFn<Config, Env>;\n\n// Local override of PartialConfig to forward the Setup (`U`) type arg.\n// Mirrors the BigQuery destination's pattern.\nexport type PartialConfig = Omit<\n DestinationServer.PartialConfig<Types>,\n 'settings' | 'setup'\n> & {\n settings?: Partial<Settings> | Settings;\n setup?: boolean | Setup;\n};\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\nimport { setup } from './setup';\nimport { isAWSEnvironment } from './lib/sns';\n\n// Types\nexport * as DestinationSNS from './types';\n\ninterface CreateTopicResponse {\n TopicArn?: string;\n}\n\nfunction isCreateTopicResponse(v: unknown): v is CreateTopicResponse {\n return typeof v === 'object' && v !== null;\n}\n\nexport const destinationSNS: Destination = {\n type: 'aws-sns',\n\n config: {},\n\n setup,\n\n async init({ config: partial, env, logger, id }) {\n const config = getConfig(partial, env);\n if (!config.settings.client) {\n logger.throw('SNS init: client missing (env not injected)');\n return;\n }\n if (!isAWSEnvironment(env)) {\n logger.throw('SNS init: env.AWS missing');\n return;\n }\n\n // Operator-supplied ARN: skip CreateTopic to avoid the runtime IAM cost.\n if (config.settings.topicArn) return config;\n\n const { client, topicName, region } = config.settings;\n try {\n const res: unknown = await client.send(\n new env.AWS.CreateTopicCommand({ Name: topicName }),\n );\n if (\n !isCreateTopicResponse(res) ||\n typeof res.TopicArn !== 'string' ||\n res.TopicArn.length === 0\n ) {\n logger.throw(\n `SNS init: CreateTopic returned no ARN for \"${topicName}\"`,\n );\n return;\n }\n config.settings.topicArn = res.TopicArn;\n } catch (err) {\n logger.error(\n `SNS init failed for topic \"${topicName}\" in region ${region ?? 'eu-central-1'}. ` +\n `Either set settings.topicArn directly, run \"walkeros setup destination.${id}\", ` +\n `or grant sns:CreateTopic to the runtime role.`,\n {\n topicName,\n region,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n throw err;\n }\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationSNS;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA,wBAAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,IAAAC,eAA2B;;;ACC3B,kBAA2B;AAG3B,SAAS,iBAAiB,KAA0B;AAClD,SAAO;AAAA,IACL,OACE,OAAO,QAAQ,YACf,SAAS,OACR,IAAY,KAAK;AAAA,EACtB;AACF;AAEO,SAAS,kBACd,gBACA,KACgB;AAChB,QAAM,EAAE,YAAY,SAAS,gBAAgB,SAAS,CAAC,EAAE,IAAI;AAE7D,MAAI,CAAC,WAAY,6BAAW,4CAA4C;AAExE,MAAI,CAAC,OAAO,OAAQ,QAAO,SAAS;AAGpC,MAAI,SAAS,eAAe;AAC5B,MAAI,CAAC,UAAU,iBAAiB,GAAG,GAAG;AACpC,aAAS,IAAI,IAAI,IAAI,eAAe,MAAM;AAAA,EAC5C;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,aACpB,YACA,QACA,SACA;AACA,QAAM,EAAE,QAAQ,WAAW,IAAI;AAC/B,QAAM,EAAE,KAAK,OAAO,IAAI;AAExB,MAAI,CAAC,OAAQ,QAAO,EAAE,OAAO,WAAW;AAGxC,QAAM,UAAU,WAAW,IAAI,CAAC,EAAE,MAAM,OAAO;AAAA,IAC7C,MAAM,OAAO,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,EACzC,EAAE;AAEF,SAAO,MAAM,4BAA4B;AAAA,IACvC,QAAQ;AAAA,IACR,aAAa,QAAQ;AAAA,EACvB,CAAC;AAGD,MAAI,iBAAiB,GAAG,GAAG;AACzB,UAAM,OAAO;AAAA,MACX,IAAI,IAAI,IAAI,sBAAsB;AAAA,QAChC,oBAAoB;AAAA,QACpB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF,OAAO;AAEL,UAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,0BAA0B;AACzE,UAAM,OAAO;AAAA,MACX,IAAI,sBAAsB;AAAA,QACxB,oBAAoB;AAAA,QACpB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAEA,UAAQ,MAAM,6BAA6B,EAAE,IAAI,KAAK,CAAC;AACzD;;;AC1EO,SAAS,UACd,gBAA+B,CAAC,GAChC,KACQ;AACR,QAAM,WAAW,cAAc,YAAa,CAAC;AAE7C,MAAI,SAAS;AACX,aAAS,WAAW,kBAAkB,SAAS,UAAU,GAAG;AAE9D,SAAO,EAAE,SAAS;AACpB;;;ACVO,IAAM,OAAe,eAAgB,OAAO,SAAS;AAC1D,QAAM,EAAE,SAAS,IAAI,QAAQ,OAAO,YAAY,CAAC;AAEjD,MAAI,SAAU,cAAa,CAAC,EAAE,MAAM,CAAC,GAAG,UAAU,OAAO;AAEzD;AACF;;;ACTA;;;AJQO,IAAM,sBAAmC;AAAA,EAC9C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,KAAK,OAAO,GAAG;AACjD,UAAM,SAAS,UAAU,eAAe,GAAG;AAE3C,QAAI,KAAC,yBAAW,OAAO,UAAU,CAAC,CAAa;AAC7C,aAAO,MAAM,yBAAyB;AAExC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AACF;;;AKxBA,IAAAC,eAA2B;AAGpB,SAASC,kBAAiB,KAA0B;AACzD,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AACpD,MAAI,EAAE,SAAS,KAAM,QAAO;AAC5B,QAAM,MAAO,IAA0B;AACvC,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AACpD,SAAO,eAAe;AACxB;AAOO,SAAS,aACd,SACA,KACU;AACV,QAAM,EAAE,WAAW,UAAU,SAAS,CAAC,EAAE,IAAI;AAC7C,QAAM,SAAS,QAAQ,UAAU;AAEjC,MAAI,CAAC,UAAW,8BAAW,iCAAiC;AAE5D,QAAM,YAAY,OAAO,SAAS,SAAS,EAAE,GAAG,QAAQ,OAAO;AAE/D,MAAI,SAAS,QAAQ;AACrB,MAAI,CAAC,UAAUA,kBAAiB,GAAG,GAAG;AACpC,aAAS,IAAI,IAAI,IAAI,UAAU,SAAS;AAAA,EAC1C;AAEA,QAAM,WAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,EACV;AACA,MAAI,OAAQ,UAAS,SAAS;AAC9B,MAAI,SAAU,UAAS,WAAW;AAClC,SAAO;AACT;;;ACtCO,SAASC,WAAU,UAAyB,CAAC,GAAG,KAAuB;AAC5E,QAAM,kBACJ,QAAQ,YAAY,OAAO,QAAQ,aAAa,WAC5C,QAAQ,WACR,CAAC;AACP,QAAM,WAAW,aAAa,iBAAiB,GAAG;AAClD,SAAO,EAAE,GAAG,SAAS,SAAS;AAChC;;;ACRA,IAAAC,eAA0C;AAS1C,SAAS,mBAAmB,OAA2C;AACrE,MAAI,KAAC,uBAAS,KAAK,EAAG,QAAO;AAC7B,QAAM,YAAY;AAClB,SAAO,OAAO,UAAU,aAAa;AACvC;AAEA,eAAe,yBACb,OACA,QACA,WACuD;AACvD,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,SAA2C,CAAC;AAClD,MAAI,UAAU;AACd,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,UAAM,WAAW,UAAM,8BAAgB,OAAO,OAAO,EAAE,UAAU,CAAC;AAClE,QAAI,mBAAmB,QAAQ,GAAG;AAChC,aAAO,GAAG,IAAI;AACd,gBAAU;AAAA,IACZ,WAAW,OAAO,aAAa,YAAY,SAAS,SAAS,GAAG;AAE9D,aAAO,GAAG,IAAI,EAAE,UAAU,UAAU,aAAa,SAAS;AAC1D,gBAAU;AAAA,IACZ,WAAW,aAAa,UAAa,aAAa,MAAM;AACtD,aAAO,GAAG,IAAI,EAAE,UAAU,UAAU,aAAa,OAAO,QAAQ,EAAE;AAClE,gBAAU;AAAA,IACZ;AAAA,EACF;AACA,SAAO,UAAU,SAAS;AAC5B;AAEA,SAAS,UAAU,OAAkC;AACnD,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,eAAe,0BACb,OACA,OACA,WAC6B;AAC7B,QAAM,WAAW,UAAM,8BAAgB,OAAO,OAAO,EAAE,UAAU,CAAC;AAClE,MAAI,OAAO,aAAa,YAAY,SAAS,SAAS,EAAG,QAAO;AAChE,MAAI,aAAa,UAAa,aAAa,KAAM,QAAO;AACxD,SAAO,OAAO,QAAQ;AACxB;AAEO,IAAMC,QAAe,eAAgB,OAAO,SAAS;AAC1D,QAAM,EAAE,QAAQ,KAAK,MAAM,WAAW,QAAQ,GAAG,IAAI;AACrD,QAAM,WAAW,OAAO;AACxB,QAAM,SAAS,UAAU;AACzB,QAAM,WAAW,UAAU;AAE3B,MAAI,CAAC,OAAQ,QAAO,OAAO,MAAM,0CAA0C;AAC3E,MAAI,CAAC;AACH,WAAO,OAAO,MAAM,4CAA4C;AAClE,MAAI,CAACC,kBAAiB,GAAG;AACvB,WAAO,OAAO,MAAM,gCAAgC;AAEtD,QAAM,eAAwB,UAAU,MAAM,QAAQ,IAAI,KAAK,WAAW,CAAC;AAE3E,MAAI;AACJ,MAAI,aAAa,mBAAmB,QAAW;AAC7C,qBAAiB,MAAM;AAAA,MACrB;AAAA,MACA,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACJ,MAAI,aAAa,2BAA2B,QAAW;AACrD,6BAAyB,MAAM;AAAA,MAC7B;AAAA,MACA,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,QAAM,oBAAoB,MAAM;AAAA,IAC9B;AAAA,IACA,aAAa;AAAA,IACb;AAAA,EACF;AAEA,QAAM,QAMF;AAAA,IACF,UAAU;AAAA,IACV,SAAS,KAAK,UAAU,KAAK;AAAA,EAC/B;AACA,MAAI,eAAgB,OAAM,iBAAiB;AAC3C,MAAI;AACF,UAAM,yBAAyB;AACjC,MAAI,kBAAmB,OAAM,oBAAoB;AAEjD,SAAO,MAAM,eAAe;AAAA,IAC1B;AAAA,IACA,MAAM,SAAS,SAAS,OAAO;AAAA,IAC/B,OAAO,MAAM;AAAA,EACf,CAAC;AAED,MAAI;AACF,UAAM,OAAO,KAAK,IAAI,IAAI,IAAI,eAAe,KAAK,CAAC;AAAA,EACrD,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,2BAA2B,QAAQ,sCACE,EAAE;AAAA,MACvC;AAAA,QACE;AAAA,QACA,OAAO,MAAM;AAAA,QACb,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;;;AC/HA,IAAAC,eAA6B;AAStB,IAAM,gBACH;AAAA,EACR,QAAQ;AAAA,EACR,WAAW;AACb;AAaA,IAAM,iBAAsC,oBAAI,IAAI;AAgBpD,SAAS,WAAW,KAAmC;AACrD,SAAO,OAAO,QAAQ,YAAY,QAAQ;AAC5C;AAEA,SAAS,WAAW,KAAuB;AACzC,MAAI,CAAC,WAAW,GAAG,EAAG,QAAO;AAC7B,MAAI,IAAI,SAAS,uBAAuB,IAAI,SAAS,WAAY,QAAO;AACxE,MAAI,IAAI,aAAa,IAAI,UAAU,mBAAmB,IAAK,QAAO;AAClE,SAAO;AACT;AAEA,SAAS,iBAAiB,MAAc,MAAuB;AAC7D,MAAI,MAAM;AACR,QAAI,KAAK,SAAS,OAAO,EAAG,QAAO;AACnC,WAAO,GAAG,IAAI;AAAA,EAChB;AACA,MAAI,KAAK,SAAS,OAAO,GAAG;AAC1B,UAAM,IAAI;AAAA,MACR,+CAA+C,IAAI;AAAA,IACrD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cACP,UACA,KACA,QACe;AACf,MAAI,UAAU,OAAQ,QAAO,SAAS;AACtC,QAAM,SAAS,UAAU,UAAU,CAAC;AACpC,QAAM,SAAS,OAAO,SAAS,SAAS,EAAE,GAAG,QAAQ,OAAO;AAC5D,SAAO,IAAI,IAAI,IAAI,UAAU,MAAM;AACrC;AAEA,eAAe,aAAa,KAAU,QAAiC;AACrE,QAAM,SAAS,eAAe,IAAI,MAAM;AACxC,MAAI,OAAQ,QAAO;AACnB,QAAM,YAAY,IAAI,IAAI,IAAI,UAAU,EAAE,OAAO,CAAC;AAClD,QAAM,MAAe,MAAM,UAAU;AAAA,IACnC,IAAI,IAAI,IAAI,yBAAyB,CAAC,CAAC;AAAA,EACzC;AACA,MACE,OAAO,QAAQ,YACf,QAAQ,QACR,aAAa,OACb,OAAQ,IAA8B,YAAY,UAClD;AACA,UAAM,YAAa,IAA4B;AAC/C,mBAAe,IAAI,QAAQ,SAAS;AACpC,WAAO;AAAA,EACT;AACA,QAAM,IAAI,MAAM,2CAA2C;AAC7D;AAEA,SAAS,sBAAsB,GAAsC;AACnE,SAAO,OAAO,MAAM,YAAY,MAAM;AACxC;AAEA,SAAS,gBAAgB,KAAsB;AAC7C,MAAI,sBAAsB,GAAG,KAAK,OAAO,IAAI,aAAa;AACxD,WAAO,IAAI;AACb,QAAM,IAAI,MAAM,sCAAsC;AACxD;AAEA,SAAS,yBACP,KACoC;AACpC,QAAM,QAAgC,CAAC;AACvC,MAAI,IAAI,uBAAuB,QAAW;AACxC,UAAM,qBAAqB,OAAO,IAAI,kBAAkB;AAAA,EAC1D;AACA,MAAI,IAAI,iBAAiB,QAAW;AAClC,UAAM,eAAe,KAAK,UAAU,IAAI,YAAY;AAAA,EACtD;AACA,MAAI,IAAI,wBAAwB,QAAW;AACzC,UAAM,gBAAgB,KAAK,UAAU;AAAA,MACnC,qBAAqB,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AACA,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AACjD;AAEA,eAAe,2BACb,QACA,KACA,UACA,UACiB;AACjB,MAAI,QAAQ;AACZ,aAAW,OAAO,UAAU;AAC1B,UAAM,QAKF;AAAA,MACF,UAAU;AAAA,MACV,UAAU,IAAI;AAAA,MACd,UAAU,IAAI;AAAA,IAChB;AACA,UAAM,QAAQ,yBAAyB,GAAG;AAC1C,QAAI,MAAO,OAAM,aAAa;AAC9B,UAAM,OAAO,KAAK,IAAI,IAAI,IAAI,iBAAiB,KAAK,CAAC;AACrD,aAAS;AAAA,EACX;AACA,SAAO;AACT;AAEA,eAAsB,MACpB,KACkC;AAClC,QAAM,EAAE,QAAQ,KAAK,OAAO,IAAI;AAChC,QAAM,aAAS,2BAAa,OAAO,OAAO,aAAa;AACvD,MAAI,CAAC,QAAQ;AACX,WAAO,MAAM,iDAAiD;AAC9D;AAAA,EACF;AAEA,QAAM,WAAW,OAAO;AACxB,MAAI,CAAC,YAAY,CAAC,SAAS,WAAW;AACpC,WAAO;AAAA,MACL;AAAA,IACF;AACA;AAAA,EACF;AAEA,QAAM,SAAS,OAAO,UAAU,cAAc;AAC9C,QAAM,OAAO,OAAO,aAAa;AACjC,QAAM,eAAe,SAAS;AAC9B,QAAM,YAAY,iBAAiB,cAAc,IAAI;AACrD,MAAI,QAAQ,cAAc,cAAc;AACtC,WAAO;AAAA,MACL,oDAAoD,YAAY,SAAS,SAAS;AAAA,IACpF;AAAA,EACF;AAGA,QAAM,SAAS,cAAc,UAAU,KAAK,MAAM;AAClD,QAAM,YAAY,MAAM,aAAa,KAAK,MAAM;AAChD,QAAM,eAAe,eAAe,MAAM,IAAI,SAAS,IAAI,SAAS;AAEpE,MAAI,eAAe;AACnB,MAAI;AACF,UAAM,OAAO;AAAA,MACX,IAAI,IAAI,IAAI,0BAA0B,EAAE,UAAU,aAAa,CAAC;AAAA,IAClE;AAAA,EACF,SAAS,KAAK;AACZ,QAAI,WAAW,GAAG,GAAG;AACnB,qBAAe;AAAA,IACjB,OAAO;AACL,YAAM;AAAA,IACR;AAAA,EACF;AAIA,QAAM,aAAqC,CAAC;AAC5C,MAAI,MAAM;AACR,eAAW,YAAY;AACvB,eAAW,4BAA4B;AAAA,EACzC;AACA,MAAI,OAAO,gBAAgB;AACzB,eAAW,cAAc,OAAO;AAClC,MAAI,OAAO,mBAAmB;AAC5B,eAAW,iBAAiB,OAAO;AAErC,QAAM,aAAa,OAAO,OACtB,OAAO,QAAQ,OAAO,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,IAClE;AAEJ,QAAM,cAIF,EAAE,MAAM,UAAU;AACtB,MAAI,OAAO,KAAK,UAAU,EAAE,SAAS,EAAG,aAAY,aAAa;AACjE,MAAI,cAAc,WAAW,SAAS,EAAG,aAAY,OAAO;AAE5D,QAAM,YAAY,MAAM,OAAO;AAAA,IAC7B,IAAI,IAAI,IAAI,mBAAmB,WAAW;AAAA,EAC5C;AACA,QAAM,WAAW,gBAAgB,SAAS;AAE1C,MAAI,cAAc;AAChB,WAAO,KAAK,wBAAwB,EAAE,UAAU,OAAO,CAAC;AAAA,EAC1D,OAAO;AACL,WAAO,MAAM,kDAAkD;AAAA,MAC7D;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,uBAAuB,MAAM;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,iBAAiB,CAAC;AAAA,EAC3B;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,OAAO,OAAO,OAAO,KAAK,OAAO,IAAI,EAAE,SAAS;AAAA,IAC7D;AAAA,EACF;AACF;;;AC3PA,IAAAC,iBAAA;;;ACaA,SAASC,uBAAsB,GAAsC;AACnE,SAAO,OAAO,MAAM,YAAY,MAAM;AACxC;AAEO,IAAM,iBAA8B;AAAA,EACzC,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET;AAAA,EAEA,MAAM,KAAK,EAAE,QAAQ,SAAS,KAAK,QAAQ,GAAG,GAAG;AAC/C,UAAM,SAASC,WAAU,SAAS,GAAG;AACrC,QAAI,CAAC,OAAO,SAAS,QAAQ;AAC3B,aAAO,MAAM,6CAA6C;AAC1D;AAAA,IACF;AACA,QAAI,CAACC,kBAAiB,GAAG,GAAG;AAC1B,aAAO,MAAM,2BAA2B;AACxC;AAAA,IACF;AAGA,QAAI,OAAO,SAAS,SAAU,QAAO;AAErC,UAAM,EAAE,QAAQ,WAAW,OAAO,IAAI,OAAO;AAC7C,QAAI;AACF,YAAM,MAAe,MAAM,OAAO;AAAA,QAChC,IAAI,IAAI,IAAI,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAAA,MACpD;AACA,UACE,CAACF,uBAAsB,GAAG,KAC1B,OAAO,IAAI,aAAa,YACxB,IAAI,SAAS,WAAW,GACxB;AACA,eAAO;AAAA,UACL,8CAA8C,SAAS;AAAA,QACzD;AACA;AAAA,MACF;AACA,aAAO,SAAS,WAAW,IAAI;AAAA,IACjC,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,8BAA8B,SAAS,eAAe,UAAU,cAAc,4EACF,EAAE;AAAA,QAE9E;AAAA,UACE;AAAA,UACA;AAAA,UACA,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACxD;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAMG,MAAK,OAAO,OAAO;AAAA,EAClC;AACF;","names":["types_exports","import_core","import_core","isAWSEnvironment","getConfig","import_core","push","isAWSEnvironment","import_core","types_exports","isCreateTopicResponse","getConfig","isAWSEnvironment","push"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/firehose/index.ts","../src/firehose/lib/firehose.ts","../src/firehose/config.ts","../src/firehose/push.ts","../src/firehose/types/index.ts","../src/sns/lib/sns.ts","../src/sns/config.ts","../src/sns/push.ts","../src/sns/setup.ts","../src/sns/types/index.ts","../src/sns/index.ts"],"sourcesContent":["// AWS Firehose\nexport { destinationFirehose } from './firehose';\nexport * as DestinationFirehose from './firehose/types';\n\n// AWS SNS\nexport { destinationSNS } from './sns';\nexport * as DestinationSNS from './sns/types';\n\n// Default remains Firehose for backward compatibility.\nexport { destinationFirehose as default } from './firehose';\n","import type { Settings, Destination } from './types';\nimport { isSameType } from '@walkeros/core';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationFirehose from './types';\n\nexport const destinationFirehose: Destination = {\n type: 'aws-firehose',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env);\n\n if (!isSameType(config.settings, {} as Settings))\n logger.throw('Config settings invalid');\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationFirehose;\n","import type { Destination, Logger } from '@walkeros/core';\nimport type { FirehoseConfig, Env } from '../types';\nimport { throwError } from '@walkeros/core';\n\n// Type guard to check if environment has AWS SDK\nfunction isAWSEnvironment(env: unknown): env is Env {\n return Boolean(\n env &&\n typeof env === 'object' &&\n 'AWS' in env &&\n (env as Env).AWS?.FirehoseClient,\n );\n}\n\nexport function getConfigFirehose(\n firehoseConfig: Partial<FirehoseConfig>,\n env?: unknown,\n): FirehoseConfig {\n const { streamName, region = 'eu-central-1', config = {} } = firehoseConfig;\n\n if (!streamName) throwError('Firehose: Config custom streamName missing');\n\n if (!config.region) config.region = region;\n\n // Use environment-injected SDK or fall back to provided client\n let client = firehoseConfig.client;\n if (!client && isAWSEnvironment(env)) {\n client = new env.AWS.FirehoseClient(config);\n }\n\n return {\n streamName,\n client,\n region,\n };\n}\n\nexport async function pushFirehose(\n pushEvents: Destination.PushEvents,\n config: FirehoseConfig,\n context: Destination.PushContext,\n) {\n const { client, streamName } = config;\n const { env, logger } = context;\n\n if (!client) return { queue: pushEvents };\n\n // Up to 500 records per batch\n const records = pushEvents.map(({ event }) => ({\n Data: Buffer.from(JSON.stringify(event)),\n }));\n\n logger.debug('Calling AWS Firehose API', {\n stream: streamName,\n recordCount: records.length,\n });\n\n // Use environment-injected SDK command or fall back to direct import\n if (isAWSEnvironment(env)) {\n await client.send(\n new env.AWS.PutRecordBatchCommand({\n DeliveryStreamName: streamName,\n Records: records,\n }),\n );\n } else {\n // Fall back to direct import for backward compatibility\n const { PutRecordBatchCommand } = await import('@aws-sdk/client-firehose');\n await client.send(\n new PutRecordBatchCommand({\n DeliveryStreamName: streamName,\n Records: records,\n }),\n );\n }\n\n logger?.debug('AWS Firehose API response', { ok: true });\n}\n","import type { Config, Settings, PartialConfig, Env } from './types';\nimport { getConfigFirehose } from './lib/firehose';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env?: unknown,\n): Config {\n const settings = partialConfig.settings || ({} as Settings);\n\n if (settings.firehose)\n settings.firehose = getConfigFirehose(settings.firehose, env);\n\n return { ...partialConfig, settings };\n}\n","import type { PushFn } from './types';\nimport { pushFirehose } from './lib/firehose';\n\nexport const push: PushFn = async function (event, context) {\n const { firehose } = context.config.settings || {};\n\n if (firehose) pushFirehose([{ event }], firehose, context);\n\n return;\n};\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type {\n FirehoseClient,\n FirehoseClientConfig,\n PutRecordBatchCommand,\n} from '@aws-sdk/client-firehose';\n\nexport interface Settings {\n firehose?: FirehoseConfig;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n AWS: {\n FirehoseClient: typeof FirehoseClient;\n PutRecordBatchCommand: typeof PutRecordBatchCommand;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\nexport interface FirehoseConfig {\n streamName: string;\n client?: FirehoseClient;\n region?: string;\n config?: FirehoseClientConfig;\n}\n","import type { Env, Settings } from '../types';\nimport { throwError } from '@walkeros/core';\n\n/** Type guard to check if environment has the AWS SNS SDK injected. */\nexport function isAWSEnvironment(env: unknown): env is Env {\n if (typeof env !== 'object' || env === null) return false;\n if (!('AWS' in env)) return false;\n const aws = (env as { AWS?: unknown }).AWS;\n if (typeof aws !== 'object' || aws === null) return false;\n return 'SNSClient' in aws;\n}\n\n/**\n * Resolve `Settings` from a partial input. Validates `topicName`, fills\n * `region` from default, builds an SNSClient from the env-injected\n * constructor when none was supplied.\n */\nexport function getConfigSNS(\n partial: Partial<Settings>,\n env?: unknown,\n): Settings {\n const { topicName, topicArn, config = {} } = partial;\n const region = partial.region ?? 'eu-central-1';\n\n if (!topicName) throwError('SNS: Settings topicName missing');\n\n const sdkConfig = config.region ? config : { ...config, region };\n\n let client = partial.client;\n if (!client && isAWSEnvironment(env)) {\n client = new env.AWS.SNSClient(sdkConfig);\n }\n\n const resolved: Settings = {\n topicName,\n region,\n config: sdkConfig,\n };\n if (client) resolved.client = client;\n if (topicArn) resolved.topicArn = topicArn;\n return resolved;\n}\n","import type { Config, PartialConfig, Settings } from './types';\nimport { getConfigSNS } from './lib/sns';\n\nexport function getConfig(partial: PartialConfig = {}, env?: unknown): Config {\n const partialSettings: Partial<Settings> =\n partial.settings && typeof partial.settings === 'object'\n ? partial.settings\n : {};\n const settings = getConfigSNS(partialSettings, env);\n return { ...partial, settings };\n}\n","import type { PushFn, Mapping } from './types';\nimport type { Mapping as WalkerOSMapping, Collector } from '@walkeros/core';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { isAWSEnvironment } from './lib/sns';\n\ninterface MessageAttribute {\n DataType: string;\n StringValue?: string;\n BinaryValue?: Uint8Array;\n}\n\nfunction isMessageAttribute(value: unknown): value is MessageAttribute {\n if (!isObject(value)) return false;\n const candidate = value as Record<string, unknown>;\n return typeof candidate.DataType === 'string';\n}\n\nasync function resolveMessageAttributes(\n event: Parameters<PushFn>[0],\n source: WalkerOSMapping.Map | undefined,\n collector: Collector.Instance,\n): Promise<Record<string, MessageAttribute> | undefined> {\n if (!source) return undefined;\n const result: Record<string, MessageAttribute> = {};\n let touched = false;\n for (const [key, value] of Object.entries(source)) {\n const resolved = await getMappingValue(event, value, { collector });\n if (isMessageAttribute(resolved)) {\n result[key] = resolved;\n touched = true;\n } else if (typeof resolved === 'string' && resolved.length > 0) {\n // Bare-string convenience: wrap into String DataType.\n result[key] = { DataType: 'String', StringValue: resolved };\n touched = true;\n } else if (resolved !== undefined && resolved !== null) {\n result[key] = { DataType: 'String', StringValue: String(resolved) };\n touched = true;\n }\n }\n return touched ? result : undefined;\n}\n\nfunction isMapping(value: unknown): value is Mapping {\n return typeof value === 'object' && value !== null;\n}\n\nasync function resolveStringMappingValue(\n event: Parameters<PushFn>[0],\n value: WalkerOSMapping.Value,\n collector: Collector.Instance,\n): Promise<string | undefined> {\n const resolved = await getMappingValue(event, value, { collector });\n if (typeof resolved === 'string' && resolved.length > 0) return resolved;\n if (resolved === undefined || resolved === null) return undefined;\n return String(resolved);\n}\n\nexport const push: PushFn = async function (event, context) {\n const { config, env, rule, collector, logger, id } = context;\n const settings = config.settings;\n const client = settings?.client;\n const topicArn = settings?.topicArn;\n\n if (!client) return logger.throw('SNS push: client missing, init() not run');\n if (!topicArn)\n return logger.throw('SNS push: topicArn missing, init() not run');\n if (!isAWSEnvironment(env))\n return logger.throw('SNS push: env.AWS not injected');\n\n const ruleSettings: Mapping = isMapping(rule?.settings) ? rule.settings : {};\n\n let messageGroupId: string | undefined;\n if (ruleSettings.messageGroupId !== undefined) {\n messageGroupId = await resolveStringMappingValue(\n event,\n ruleSettings.messageGroupId,\n collector,\n );\n }\n\n let messageDeduplicationId: string | undefined;\n if (ruleSettings.messageDeduplicationId !== undefined) {\n messageDeduplicationId = await resolveStringMappingValue(\n event,\n ruleSettings.messageDeduplicationId,\n collector,\n );\n }\n\n const messageAttributes = await resolveMessageAttributes(\n event,\n ruleSettings.messageAttributes,\n collector,\n );\n\n const input: {\n TopicArn: string;\n Message: string;\n MessageGroupId?: string;\n MessageDeduplicationId?: string;\n MessageAttributes?: Record<string, MessageAttribute>;\n } = {\n TopicArn: topicArn,\n Message: JSON.stringify(event),\n };\n if (messageGroupId) input.MessageGroupId = messageGroupId;\n if (messageDeduplicationId)\n input.MessageDeduplicationId = messageDeduplicationId;\n if (messageAttributes) input.MessageAttributes = messageAttributes;\n\n logger.debug('SNS Publish', {\n topicArn,\n fifo: topicArn.endsWith('.fifo'),\n event: event.name,\n });\n\n try {\n await client.send(new env.AWS.PublishCommand(input));\n } catch (err) {\n logger.error(\n `SNS Publish failed for \"${topicArn}\". ` +\n `Run \"walkeros setup destination.${id}\" if the topic is missing.`,\n {\n topicArn,\n event: event.name,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n throw err;\n }\n};\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type { Env, Setup, SetupSubscription, Settings, Types } from './types';\nimport type { LifecycleContext } from '@walkeros/core';\nimport { resolveSetup } from '@walkeros/core';\nimport type { SNSClient as SNSClientType } from '@aws-sdk/client-sns';\n\n// Setup is wired to the destination's `setup` slot which uses the broader\n// `DestinationServer.Config<Types>` (settings is optional). We runtime-narrow\n// instead of using the local Config alias so the assignment in index.ts\n// type-checks without contravariance issues.\ntype WideConfig = DestinationServer.Config<Types>;\n\nexport const DEFAULT_SETUP: Required<Pick<Setup, 'region' | 'fifoTopic'>> &\n Setup = {\n region: 'eu-central-1',\n fifoTopic: false,\n};\n\nexport interface SetupResult {\n topicArn: string;\n /** True when the GetTopicAttributes probe returned 404 (topic absent before this run). */\n topicCreated: boolean;\n tagsApplied: number;\n subscriptionsCreated: number;\n}\n\n// Module-level account-ID cache so re-running setup in the same process is\n// a no-op for the STS GetCallerIdentity call. Keyed by region (in case\n// future versions support cross-region setup in one process).\nconst accountIdCache: Map<string, string> = new Map();\n\n/** Test-only: clear the account-ID cache between test cases. */\nexport function __resetAccountIdCache(): void {\n accountIdCache.clear();\n}\n\ninterface CreateTopicResponse {\n TopicArn?: string;\n}\n\ninterface AwsErrorMeta {\n name?: string;\n $metadata?: { httpStatusCode?: number };\n}\n\nfunction isAwsError(err: unknown): err is AwsErrorMeta {\n return typeof err === 'object' && err !== null;\n}\n\nfunction isNotFound(err: unknown): boolean {\n if (!isAwsError(err)) return false;\n if (err.name === 'NotFoundException' || err.name === 'NotFound') return true;\n if (err.$metadata && err.$metadata.httpStatusCode === 404) return true;\n return false;\n}\n\nfunction resolveTopicName(name: string, fifo: boolean): string {\n if (fifo) {\n if (name.endsWith('.fifo')) return name;\n return `${name}.fifo`;\n }\n if (name.endsWith('.fifo')) {\n throw new Error(\n `FIFO suffix '.fifo' on standard topic name '${name}'. Set setup.fifoTopic: true or rename the topic.`,\n );\n }\n return name;\n}\n\nfunction resolveClient(\n settings: Settings | undefined,\n env: Env,\n region: string,\n): SNSClientType {\n if (settings?.client) return settings.client;\n const config = settings?.config ?? {};\n const merged = config.region ? config : { ...config, region };\n return new env.AWS.SNSClient(merged);\n}\n\nasync function getAccountId(env: Env, region: string): Promise<string> {\n const cached = accountIdCache.get(region);\n if (cached) return cached;\n const stsClient = new env.AWS.STSClient({ region });\n const res: unknown = await stsClient.send(\n new env.AWS.GetCallerIdentityCommand({}),\n );\n if (\n typeof res === 'object' &&\n res !== null &&\n 'Account' in res &&\n typeof (res as { Account?: unknown }).Account === 'string'\n ) {\n const accountId = (res as { Account: string }).Account;\n accountIdCache.set(region, accountId);\n return accountId;\n }\n throw new Error('STS GetCallerIdentity returned no Account');\n}\n\nfunction isCreateTopicResponse(v: unknown): v is CreateTopicResponse {\n return typeof v === 'object' && v !== null;\n}\n\nfunction extractTopicArn(res: unknown): string {\n if (isCreateTopicResponse(res) && typeof res.TopicArn === 'string')\n return res.TopicArn;\n throw new Error('SNS CreateTopic returned no TopicArn');\n}\n\nfunction buildSubscribeAttributes(\n sub: SetupSubscription,\n): Record<string, string> | undefined {\n const attrs: Record<string, string> = {};\n if (sub.rawMessageDelivery !== undefined) {\n attrs.RawMessageDelivery = String(sub.rawMessageDelivery);\n }\n if (sub.filterPolicy !== undefined) {\n attrs.FilterPolicy = JSON.stringify(sub.filterPolicy);\n }\n if (sub.deadLetterTargetArn !== undefined) {\n attrs.RedrivePolicy = JSON.stringify({\n deadLetterTargetArn: sub.deadLetterTargetArn,\n });\n }\n return Object.keys(attrs).length > 0 ? attrs : undefined;\n}\n\nasync function applyDeclaredSubscriptions(\n client: SNSClientType,\n env: Env,\n topicArn: string,\n declared: SetupSubscription[],\n): Promise<number> {\n let count = 0;\n for (const sub of declared) {\n const input: {\n TopicArn: string;\n Protocol: string;\n Endpoint: string;\n Attributes?: Record<string, string>;\n } = {\n TopicArn: topicArn,\n Protocol: sub.protocol,\n Endpoint: sub.endpoint,\n };\n const attrs = buildSubscribeAttributes(sub);\n if (attrs) input.Attributes = attrs;\n await client.send(new env.AWS.SubscribeCommand(input));\n count += 1;\n }\n return count;\n}\n\nexport async function setup(\n ctx: LifecycleContext<WideConfig, Env>,\n): Promise<SetupResult | undefined> {\n const { config, env, logger } = ctx;\n const merged = resolveSetup(config.setup, DEFAULT_SETUP);\n if (!merged) {\n logger.debug('setup: skipped (config.setup is false or unset)');\n return;\n }\n\n const settings = config.settings;\n if (!settings || !settings.topicName) {\n logger.throw(\n 'setup: settings.topicName is required. There is no safe default for the SNS topic name.',\n );\n return;\n }\n\n const region = merged.region ?? DEFAULT_SETUP.region;\n const fifo = merged.fifoTopic ?? false;\n const declaredName = settings.topicName;\n const finalName = resolveTopicName(declaredName, fifo);\n if (fifo && finalName !== declaredName) {\n logger.info(\n `setup: appended .fifo suffix to FIFO topic name '${declaredName}' -> '${finalName}'`,\n );\n }\n\n // Topic-existence probe via candidate ARN derived from STS account ID.\n const client = resolveClient(settings, env, region);\n const accountId = await getAccountId(env, region);\n const candidateArn = `arn:aws:sns:${region}:${accountId}:${finalName}`;\n\n let topicCreated = false;\n try {\n await client.send(\n new env.AWS.GetTopicAttributesCommand({ TopicArn: candidateArn }),\n );\n } catch (err) {\n if (isNotFound(err)) {\n topicCreated = true;\n } else {\n throw err;\n }\n }\n\n // Authoritative-apply: full declared state in one CreateTopic call.\n // SNS:CreateTopic is idempotent on identical Name+Attributes+Tags inputs.\n const attributes: Record<string, string> = {};\n if (fifo) {\n attributes.FifoTopic = 'true';\n attributes.ContentBasedDeduplication = 'true';\n }\n if (merged.displayName !== undefined)\n attributes.DisplayName = merged.displayName;\n if (merged.kmsMasterKeyId !== undefined)\n attributes.KmsMasterKeyId = merged.kmsMasterKeyId;\n\n const tagEntries = merged.tags\n ? Object.entries(merged.tags).map(([Key, Value]) => ({ Key, Value }))\n : undefined;\n\n const createInput: {\n Name: string;\n Attributes?: Record<string, string>;\n Tags?: Array<{ Key: string; Value: string }>;\n } = { Name: finalName };\n if (Object.keys(attributes).length > 0) createInput.Attributes = attributes;\n if (tagEntries && tagEntries.length > 0) createInput.Tags = tagEntries;\n\n const createRes = await client.send(\n new env.AWS.CreateTopicCommand(createInput),\n );\n const topicArn = extractTopicArn(createRes);\n\n if (topicCreated) {\n logger.info('setup: topic created', { topicArn, region });\n } else {\n logger.debug('setup: topic exists; declared state re-applied', {\n topicArn,\n region,\n });\n }\n\n const subscriptionsCreated = await applyDeclaredSubscriptions(\n client,\n env,\n topicArn,\n merged.subscriptions ?? [],\n );\n\n return {\n topicArn,\n topicCreated,\n tagsApplied: merged.tags ? Object.keys(merged.tags).length : 0,\n subscriptionsCreated,\n };\n}\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n SetupFn as CoreSetupFn,\n} from '@walkeros/core';\nimport type {\n SNSClient,\n SNSClientConfig,\n CreateTopicCommand,\n PublishCommand,\n GetTopicAttributesCommand,\n SubscribeCommand,\n} from '@aws-sdk/client-sns';\nimport type { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts';\n\nexport interface Settings {\n /** Topic name (without `.fifo` suffix unless fifoTopic is true). REQUIRED. */\n topicName: string;\n /** Pre-configured client. Optional; created from env if absent. */\n client?: SNSClient;\n /** AWS region. Mirrors setup.region default ('eu-central-1'). */\n region?: string;\n /** SDK client config (credentials, etc.). Optional. */\n config?: SNSClientConfig;\n /** Topic ARN, populated at init() from CreateTopic. Operator may pre-set to skip init's CreateTopic call. */\n topicArn?: string;\n}\n\nexport interface InitSettings {\n topicName: string;\n client?: SNSClient;\n region?: string;\n config?: SNSClientConfig;\n topicArn?: string;\n}\n\nexport interface Mapping {\n /**\n * Per-event message attributes resolved via mapping. Each attribute value\n * resolves to the SDK's expected `{ DataType, StringValue }` shape; operators\n * write either a literal `{ DataType: 'String', StringValue: '$path' }` value\n * or use `{ value: { DataType: 'String', StringValue: '$user.id' } }` style\n * to drive the StringValue from event data.\n */\n messageAttributes?: WalkerOSMapping.Map;\n /**\n * FIFO group ID for FIFO topics. `Mapping.Value` so operators can write\n * `messageGroupId: 'user.id'` (path) instead of hard-coding a literal.\n */\n messageGroupId?: WalkerOSMapping.Value;\n /** FIFO deduplication ID. `Mapping.Value`, same reasoning as `messageGroupId`. */\n messageDeduplicationId?: WalkerOSMapping.Value;\n}\n\nexport interface Env extends DestinationServer.Env {\n AWS: {\n SNSClient: typeof SNSClient;\n CreateTopicCommand: typeof CreateTopicCommand;\n PublishCommand: typeof PublishCommand;\n GetTopicAttributesCommand: typeof GetTopicAttributesCommand;\n SubscribeCommand: typeof SubscribeCommand;\n STSClient: typeof STSClient;\n GetCallerIdentityCommand: typeof GetCallerIdentityCommand;\n };\n}\n\n/**\n * Provisioning options for `walkeros setup destination.<id>` when targeting SNS.\n * Triggered only by the explicit CLI command. Idempotent, never auto-run.\n *\n * `topicName` lives in Settings (one source of truth for setup AND runtime publish).\n */\nexport interface Setup {\n /** AWS region for the topic. Default: 'eu-central-1'. */\n region?: string;\n /** Display name. Optional. */\n displayName?: string;\n /** FIFO topic with content-based deduplication. Default: false. */\n fifoTopic?: boolean;\n /** KMS key for at-rest encryption. Optional. */\n kmsMasterKeyId?: string;\n /** Tags for cost allocation. Optional. */\n tags?: Record<string, string>;\n /** Subscriptions to create or update on the topic. Each is opt-in. */\n subscriptions?: SetupSubscription[];\n}\n\nexport interface SetupSubscription {\n protocol: 'sqs' | 'lambda' | 'https' | 'http' | 'email' | 'sms';\n endpoint: string;\n rawMessageDelivery?: boolean;\n filterPolicy?: Record<string, unknown>;\n deadLetterTargetArn?: string;\n}\n\nexport type Types = CoreDestination.Types<\n Settings,\n Mapping,\n Env,\n InitSettings,\n Setup\n>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type SetupFn = CoreSetupFn<Config, Env>;\n\n// Local override of PartialConfig to forward the Setup (`U`) type arg.\n// Mirrors the BigQuery destination's pattern.\nexport type PartialConfig = Omit<\n DestinationServer.PartialConfig<Types>,\n 'settings' | 'setup'\n> & {\n settings?: Partial<Settings> | Settings;\n setup?: boolean | Setup;\n};\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\nimport { setup } from './setup';\nimport { isAWSEnvironment } from './lib/sns';\n\n// Types\nexport * as DestinationSNS from './types';\n\ninterface CreateTopicResponse {\n TopicArn?: string;\n}\n\nfunction isCreateTopicResponse(v: unknown): v is CreateTopicResponse {\n return typeof v === 'object' && v !== null;\n}\n\nexport const destinationSNS: Destination = {\n type: 'aws-sns',\n\n config: {},\n\n setup,\n\n async init({ config: partial, env, logger, id }) {\n const config = getConfig(partial, env);\n if (!config.settings.client) {\n logger.throw('SNS init: client missing (env not injected)');\n return;\n }\n if (!isAWSEnvironment(env)) {\n logger.throw('SNS init: env.AWS missing');\n return;\n }\n\n // Operator-supplied ARN: skip CreateTopic to avoid the runtime IAM cost.\n if (config.settings.topicArn) return config;\n\n const { client, topicName, region } = config.settings;\n try {\n const res: unknown = await client.send(\n new env.AWS.CreateTopicCommand({ Name: topicName }),\n );\n if (\n !isCreateTopicResponse(res) ||\n typeof res.TopicArn !== 'string' ||\n res.TopicArn.length === 0\n ) {\n logger.throw(\n `SNS init: CreateTopic returned no ARN for \"${topicName}\"`,\n );\n return;\n }\n config.settings.topicArn = res.TopicArn;\n } catch (err) {\n logger.error(\n `SNS init failed for topic \"${topicName}\" in region ${region ?? 'eu-central-1'}. ` +\n `Either set settings.topicArn directly, run \"walkeros setup destination.${id}\", ` +\n `or grant sns:CreateTopic to the runtime role.`,\n {\n topicName,\n region,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n throw err;\n }\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationSNS;\n"],"mappings":"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","names":["types_exports","import_core","import_core","isAWSEnvironment","getConfig","import_core","push","isAWSEnvironment","import_core","types_exports","isCreateTopicResponse","getConfig","isAWSEnvironment","push"]}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{isSameType}from"@walkeros/core";import{throwError}from"@walkeros/core";function isAWSEnvironment(env){return Boolean(env&&"object"==typeof env&&"AWS"in env&&env.AWS?.FirehoseClient)}function getConfig(partialConfig={},env){const settings=partialConfig.settings||{};return settings.firehose&&(settings.firehose=function(firehoseConfig,env){const{streamName:streamName,region:region="eu-central-1",config:config={}}=firehoseConfig;streamName||throwError("Firehose: Config custom streamName missing"),config.region||(config.region=region);let client=firehoseConfig.client;return!client&&isAWSEnvironment(env)&&(client=new env.AWS.FirehoseClient(config)),{streamName:streamName,client:client,region:region}}(settings.firehose,env)),{settings:settings}}var push=async function(event,context){const{firehose:firehose}=context.config.settings||{};firehose&&async function(pushEvents,config,context){const{client:client,streamName:streamName}=config,{env:env,logger:logger}=context;if(!client)return{queue:pushEvents};const records=pushEvents.map(({event:event})=>({Data:Buffer.from(JSON.stringify(event))}));if(logger.debug("Calling AWS Firehose API",{stream:streamName,recordCount:records.length}),isAWSEnvironment(env))await client.send(new env.AWS.PutRecordBatchCommand({DeliveryStreamName:streamName,Records:records}));else{const{PutRecordBatchCommand:PutRecordBatchCommand}=await import("@aws-sdk/client-firehose");await client.send(new PutRecordBatchCommand({DeliveryStreamName:streamName,Records:records}))}logger?.debug("AWS Firehose API response",{ok:!0})}([{event:event}],firehose,context)},types_exports={},destinationFirehose={type:"aws-firehose",config:{},async init({config:partialConfig,env:env,logger:logger}){const config=getConfig(partialConfig,env);return isSameType(config.settings,{})||logger.throw("Config settings invalid"),config},push:async(event,context)=>await push(event,context)};import{throwError as throwError2}from"@walkeros/core";function isAWSEnvironment2(env){if("object"!=typeof env||null===env)return!1;if(!("AWS"in env))return!1;const aws=env.AWS;return"object"==typeof aws&&null!==aws&&"SNSClient"in aws}function getConfig2(partial={},env){const settings=function(partial,env){const{topicName:topicName,topicArn:topicArn,config:config={}}=partial,region=partial.region??"eu-central-1";topicName||throwError2("SNS: Settings topicName missing");const sdkConfig=config.region?config:{...config,region:region};let client=partial.client;!client&&isAWSEnvironment2(env)&&(client=new env.AWS.SNSClient(sdkConfig));const resolved={topicName:topicName,region:region,config:sdkConfig};return client&&(resolved.client=client),topicArn&&(resolved.topicArn=topicArn),resolved}(partial.settings&&"object"==typeof partial.settings?partial.settings:{},env);return{...partial,settings:settings}}import{getMappingValue,isObject}from"@walkeros/core";function isMessageAttribute(value){if(!isObject(value))return!1;return"string"==typeof value.DataType}async function resolveStringMappingValue(event,value,collector){const resolved=await getMappingValue(event,value,{collector:collector});return"string"==typeof resolved&&resolved.length>0?resolved:null!=resolved?String(resolved):void 0}var push2=async function(event,context){const{config:config,env:env,rule:rule,collector:collector,logger:logger,id:id}=context,settings=config.settings,client=settings?.client,topicArn=settings?.topicArn;if(!client)return logger.throw("SNS push: client missing, init() not run");if(!topicArn)return logger.throw("SNS push: topicArn missing, init() not run");if(!isAWSEnvironment2(env))return logger.throw("SNS push: env.AWS not injected");const ruleSettings=(value=rule?.settings,"object"==typeof value&&null!==value?rule.settings:{});var value;let messageGroupId,messageDeduplicationId;void 0!==ruleSettings.messageGroupId&&(messageGroupId=await resolveStringMappingValue(event,ruleSettings.messageGroupId,collector)),void 0!==ruleSettings.messageDeduplicationId&&(messageDeduplicationId=await resolveStringMappingValue(event,ruleSettings.messageDeduplicationId,collector));const messageAttributes=await async function(event,source,collector){if(!source)return;const result={};let touched=!1;for(const[key,value]of Object.entries(source)){const resolved=await getMappingValue(event,value,{collector:collector});isMessageAttribute(resolved)?(result[key]=resolved,touched=!0):"string"==typeof resolved&&resolved.length>0?(result[key]={DataType:"String",StringValue:resolved},touched=!0):null!=resolved&&(result[key]={DataType:"String",StringValue:String(resolved)},touched=!0)}return touched?result:void 0}(event,ruleSettings.messageAttributes,collector),input={TopicArn:topicArn,Message:JSON.stringify(event)};messageGroupId&&(input.MessageGroupId=messageGroupId),messageDeduplicationId&&(input.MessageDeduplicationId=messageDeduplicationId),messageAttributes&&(input.MessageAttributes=messageAttributes),logger.debug("SNS Publish",{topicArn:topicArn,fifo:topicArn.endsWith(".fifo"),event:event.name});try{await client.send(new env.AWS.PublishCommand(input))}catch(err){throw logger.error(`SNS Publish failed for "${topicArn}". Run "walkeros setup destination.${id}" if the topic is missing.`,{topicArn:topicArn,event:event.name,error:err instanceof Error?err.message:String(err)}),err}};import{resolveSetup}from"@walkeros/core";var DEFAULT_SETUP={region:"eu-central-1",fifoTopic:!1},accountIdCache=new Map;function buildSubscribeAttributes(sub){const attrs={};return void 0!==sub.rawMessageDelivery&&(attrs.RawMessageDelivery=String(sub.rawMessageDelivery)),void 0!==sub.filterPolicy&&(attrs.FilterPolicy=JSON.stringify(sub.filterPolicy)),void 0!==sub.deadLetterTargetArn&&(attrs.RedrivePolicy=JSON.stringify({deadLetterTargetArn:sub.deadLetterTargetArn})),Object.keys(attrs).length>0?attrs:void 0}var types_exports2={};var destinationSNS={type:"aws-sns",config:{},setup:async function(ctx){const{config:config,env:env,logger:logger}=ctx,merged=resolveSetup(config.setup,DEFAULT_SETUP);if(!merged)return void logger.debug("setup: skipped (config.setup is false or unset)");const settings=config.settings;if(!settings||!settings.topicName)return void logger.throw("setup: settings.topicName is required. There is no safe default for the SNS topic name.");const region=merged.region??DEFAULT_SETUP.region,fifo=merged.fifoTopic??!1,declaredName=settings.topicName,finalName=function(name,fifo){if(fifo)return name.endsWith(".fifo")?name:`${name}.fifo`;if(name.endsWith(".fifo"))throw new Error(`FIFO suffix '.fifo' on standard topic name '${name}'. Set setup.fifoTopic: true or rename the topic.`);return name}(declaredName,fifo);fifo&&finalName!==declaredName&&logger.info(`setup: appended .fifo suffix to FIFO topic name '${declaredName}' -> '${finalName}'`);const client=function(settings,env,region){if(settings?.client)return settings.client;const config=settings?.config??{},merged=config.region?config:{...config,region:region};return new env.AWS.SNSClient(merged)}(settings,env,region),accountId=await async function(env,region){const cached=accountIdCache.get(region);if(cached)return cached;const stsClient=new env.AWS.STSClient({region:region}),res=await stsClient.send(new env.AWS.GetCallerIdentityCommand({}));if("object"==typeof res&&null!==res&&"Account"in res&&"string"==typeof res.Account){const accountId=res.Account;return accountIdCache.set(region,accountId),accountId}throw new Error("STS GetCallerIdentity returned no Account")}(env,region),candidateArn=`arn:aws:sns:${region}:${accountId}:${finalName}`;let topicCreated=!1;try{await client.send(new env.AWS.GetTopicAttributesCommand({TopicArn:candidateArn}))}catch(err){if(!function(err){return!(!function(err){return"object"==typeof err&&null!==err}(err)||"NotFoundException"!==err.name&&"NotFound"!==err.name&&(!err.$metadata||404!==err.$metadata.httpStatusCode))}(err))throw err;topicCreated=!0}const attributes={};fifo&&(attributes.FifoTopic="true",attributes.ContentBasedDeduplication="true"),void 0!==merged.displayName&&(attributes.DisplayName=merged.displayName),void 0!==merged.kmsMasterKeyId&&(attributes.KmsMasterKeyId=merged.kmsMasterKeyId);const tagEntries=merged.tags?Object.entries(merged.tags).map(([Key,Value])=>({Key:Key,Value:Value})):void 0,createInput={Name:finalName};Object.keys(attributes).length>0&&(createInput.Attributes=attributes),tagEntries&&tagEntries.length>0&&(createInput.Tags=tagEntries);const topicArn=function(res){if("object"==typeof(v=res)&&null!==v&&"string"==typeof res.TopicArn)return res.TopicArn;var v;throw new Error("SNS CreateTopic returned no TopicArn")}(await client.send(new env.AWS.CreateTopicCommand(createInput)));topicCreated?logger.info("setup: topic created",{topicArn:topicArn,region:region}):logger.debug("setup: topic exists; declared state re-applied",{topicArn:topicArn,region:region});const subscriptionsCreated=await async function(client,env,topicArn,declared){let count=0;for(const sub of declared){const input={TopicArn:topicArn,Protocol:sub.protocol,Endpoint:sub.endpoint},attrs=buildSubscribeAttributes(sub);attrs&&(input.Attributes=attrs),await client.send(new env.AWS.SubscribeCommand(input)),count+=1}return count}(client,env,topicArn,merged.subscriptions??[]);return{topicArn:topicArn,topicCreated:topicCreated,tagsApplied:merged.tags?Object.keys(merged.tags).length:0,subscriptionsCreated:subscriptionsCreated}},async init({config:partial,env:env,logger:logger,id:id}){const config=getConfig2(partial,env);if(!config.settings.client)return void logger.throw("SNS init: client missing (env not injected)");if(!isAWSEnvironment2(env))return void logger.throw("SNS init: env.AWS missing");if(config.settings.topicArn)return config;const{client:client,topicName:topicName,region:region}=config.settings;try{const res=await client.send(new env.AWS.CreateTopicCommand({Name:topicName}));if("object"!=typeof(v=res)||null===v||"string"!=typeof res.TopicArn||0===res.TopicArn.length)return void logger.throw(`SNS init: CreateTopic returned no ARN for "${topicName}"`);config.settings.topicArn=res.TopicArn}catch(err){throw logger.error(`SNS init failed for topic "${topicName}" in region ${region??"eu-central-1"}. Either set settings.topicArn directly, run "walkeros setup destination.${id}", or grant sns:CreateTopic to the runtime role.`,{topicName:topicName,region:region,error:err instanceof Error?err.message:String(err)}),err}var v;return config},push:async(event,context)=>await push2(event,context)};export{types_exports as DestinationFirehose,types_exports2 as DestinationSNS,destinationFirehose as default,destinationFirehose,destinationSNS};//# sourceMappingURL=index.mjs.map
1
+ import{isSameType}from"@walkeros/core";import{throwError}from"@walkeros/core";function isAWSEnvironment(env){return Boolean(env&&"object"==typeof env&&"AWS"in env&&env.AWS?.FirehoseClient)}function getConfig(partialConfig={},env){const settings=partialConfig.settings||{};return settings.firehose&&(settings.firehose=function(firehoseConfig,env){const{streamName:streamName,region:region="eu-central-1",config:config={}}=firehoseConfig;streamName||throwError("Firehose: Config custom streamName missing"),config.region||(config.region=region);let client=firehoseConfig.client;return!client&&isAWSEnvironment(env)&&(client=new env.AWS.FirehoseClient(config)),{streamName:streamName,client:client,region:region}}(settings.firehose,env)),{...partialConfig,settings:settings}}var push=async function(event,context){const{firehose:firehose}=context.config.settings||{};firehose&&async function(pushEvents,config,context){const{client:client,streamName:streamName}=config,{env:env,logger:logger}=context;if(!client)return{queue:pushEvents};const records=pushEvents.map(({event:event})=>({Data:Buffer.from(JSON.stringify(event))}));if(logger.debug("Calling AWS Firehose API",{stream:streamName,recordCount:records.length}),isAWSEnvironment(env))await client.send(new env.AWS.PutRecordBatchCommand({DeliveryStreamName:streamName,Records:records}));else{const{PutRecordBatchCommand:PutRecordBatchCommand}=await import("@aws-sdk/client-firehose");await client.send(new PutRecordBatchCommand({DeliveryStreamName:streamName,Records:records}))}logger?.debug("AWS Firehose API response",{ok:!0})}([{event:event}],firehose,context)},types_exports={},destinationFirehose={type:"aws-firehose",config:{},async init({config:partialConfig,env:env,logger:logger}){const config=getConfig(partialConfig,env);return isSameType(config.settings,{})||logger.throw("Config settings invalid"),config},push:async(event,context)=>await push(event,context)};import{throwError as throwError2}from"@walkeros/core";function isAWSEnvironment2(env){if("object"!=typeof env||null===env)return!1;if(!("AWS"in env))return!1;const aws=env.AWS;return"object"==typeof aws&&null!==aws&&"SNSClient"in aws}function getConfig2(partial={},env){const settings=function(partial,env){const{topicName:topicName,topicArn:topicArn,config:config={}}=partial,region=partial.region??"eu-central-1";topicName||throwError2("SNS: Settings topicName missing");const sdkConfig=config.region?config:{...config,region:region};let client=partial.client;!client&&isAWSEnvironment2(env)&&(client=new env.AWS.SNSClient(sdkConfig));const resolved={topicName:topicName,region:region,config:sdkConfig};return client&&(resolved.client=client),topicArn&&(resolved.topicArn=topicArn),resolved}(partial.settings&&"object"==typeof partial.settings?partial.settings:{},env);return{...partial,settings:settings}}import{getMappingValue,isObject}from"@walkeros/core";function isMessageAttribute(value){if(!isObject(value))return!1;return"string"==typeof value.DataType}async function resolveStringMappingValue(event,value,collector){const resolved=await getMappingValue(event,value,{collector:collector});return"string"==typeof resolved&&resolved.length>0?resolved:null!=resolved?String(resolved):void 0}var push2=async function(event,context){const{config:config,env:env,rule:rule,collector:collector,logger:logger,id:id}=context,settings=config.settings,client=settings?.client,topicArn=settings?.topicArn;if(!client)return logger.throw("SNS push: client missing, init() not run");if(!topicArn)return logger.throw("SNS push: topicArn missing, init() not run");if(!isAWSEnvironment2(env))return logger.throw("SNS push: env.AWS not injected");const ruleSettings=(value=rule?.settings,"object"==typeof value&&null!==value?rule.settings:{});var value;let messageGroupId,messageDeduplicationId;void 0!==ruleSettings.messageGroupId&&(messageGroupId=await resolveStringMappingValue(event,ruleSettings.messageGroupId,collector)),void 0!==ruleSettings.messageDeduplicationId&&(messageDeduplicationId=await resolveStringMappingValue(event,ruleSettings.messageDeduplicationId,collector));const messageAttributes=await async function(event,source,collector){if(!source)return;const result={};let touched=!1;for(const[key,value]of Object.entries(source)){const resolved=await getMappingValue(event,value,{collector:collector});isMessageAttribute(resolved)?(result[key]=resolved,touched=!0):"string"==typeof resolved&&resolved.length>0?(result[key]={DataType:"String",StringValue:resolved},touched=!0):null!=resolved&&(result[key]={DataType:"String",StringValue:String(resolved)},touched=!0)}return touched?result:void 0}(event,ruleSettings.messageAttributes,collector),input={TopicArn:topicArn,Message:JSON.stringify(event)};messageGroupId&&(input.MessageGroupId=messageGroupId),messageDeduplicationId&&(input.MessageDeduplicationId=messageDeduplicationId),messageAttributes&&(input.MessageAttributes=messageAttributes),logger.debug("SNS Publish",{topicArn:topicArn,fifo:topicArn.endsWith(".fifo"),event:event.name});try{await client.send(new env.AWS.PublishCommand(input))}catch(err){throw logger.error(`SNS Publish failed for "${topicArn}". Run "walkeros setup destination.${id}" if the topic is missing.`,{topicArn:topicArn,event:event.name,error:err instanceof Error?err.message:String(err)}),err}};import{resolveSetup}from"@walkeros/core";var DEFAULT_SETUP={region:"eu-central-1",fifoTopic:!1},accountIdCache=new Map;function buildSubscribeAttributes(sub){const attrs={};return void 0!==sub.rawMessageDelivery&&(attrs.RawMessageDelivery=String(sub.rawMessageDelivery)),void 0!==sub.filterPolicy&&(attrs.FilterPolicy=JSON.stringify(sub.filterPolicy)),void 0!==sub.deadLetterTargetArn&&(attrs.RedrivePolicy=JSON.stringify({deadLetterTargetArn:sub.deadLetterTargetArn})),Object.keys(attrs).length>0?attrs:void 0}var types_exports2={};var destinationSNS={type:"aws-sns",config:{},setup:async function(ctx){const{config:config,env:env,logger:logger}=ctx,merged=resolveSetup(config.setup,DEFAULT_SETUP);if(!merged)return void logger.debug("setup: skipped (config.setup is false or unset)");const settings=config.settings;if(!settings||!settings.topicName)return void logger.throw("setup: settings.topicName is required. There is no safe default for the SNS topic name.");const region=merged.region??DEFAULT_SETUP.region,fifo=merged.fifoTopic??!1,declaredName=settings.topicName,finalName=function(name,fifo){if(fifo)return name.endsWith(".fifo")?name:`${name}.fifo`;if(name.endsWith(".fifo"))throw new Error(`FIFO suffix '.fifo' on standard topic name '${name}'. Set setup.fifoTopic: true or rename the topic.`);return name}(declaredName,fifo);fifo&&finalName!==declaredName&&logger.info(`setup: appended .fifo suffix to FIFO topic name '${declaredName}' -> '${finalName}'`);const client=function(settings,env,region){if(settings?.client)return settings.client;const config=settings?.config??{},merged=config.region?config:{...config,region:region};return new env.AWS.SNSClient(merged)}(settings,env,region),accountId=await async function(env,region){const cached=accountIdCache.get(region);if(cached)return cached;const stsClient=new env.AWS.STSClient({region:region}),res=await stsClient.send(new env.AWS.GetCallerIdentityCommand({}));if("object"==typeof res&&null!==res&&"Account"in res&&"string"==typeof res.Account){const accountId=res.Account;return accountIdCache.set(region,accountId),accountId}throw new Error("STS GetCallerIdentity returned no Account")}(env,region),candidateArn=`arn:aws:sns:${region}:${accountId}:${finalName}`;let topicCreated=!1;try{await client.send(new env.AWS.GetTopicAttributesCommand({TopicArn:candidateArn}))}catch(err){if(!function(err){return!(!function(err){return"object"==typeof err&&null!==err}(err)||"NotFoundException"!==err.name&&"NotFound"!==err.name&&(!err.$metadata||404!==err.$metadata.httpStatusCode))}(err))throw err;topicCreated=!0}const attributes={};fifo&&(attributes.FifoTopic="true",attributes.ContentBasedDeduplication="true"),void 0!==merged.displayName&&(attributes.DisplayName=merged.displayName),void 0!==merged.kmsMasterKeyId&&(attributes.KmsMasterKeyId=merged.kmsMasterKeyId);const tagEntries=merged.tags?Object.entries(merged.tags).map(([Key,Value])=>({Key:Key,Value:Value})):void 0,createInput={Name:finalName};Object.keys(attributes).length>0&&(createInput.Attributes=attributes),tagEntries&&tagEntries.length>0&&(createInput.Tags=tagEntries);const topicArn=function(res){if("object"==typeof(v=res)&&null!==v&&"string"==typeof res.TopicArn)return res.TopicArn;var v;throw new Error("SNS CreateTopic returned no TopicArn")}(await client.send(new env.AWS.CreateTopicCommand(createInput)));topicCreated?logger.info("setup: topic created",{topicArn:topicArn,region:region}):logger.debug("setup: topic exists; declared state re-applied",{topicArn:topicArn,region:region});const subscriptionsCreated=await async function(client,env,topicArn,declared){let count=0;for(const sub of declared){const input={TopicArn:topicArn,Protocol:sub.protocol,Endpoint:sub.endpoint},attrs=buildSubscribeAttributes(sub);attrs&&(input.Attributes=attrs),await client.send(new env.AWS.SubscribeCommand(input)),count+=1}return count}(client,env,topicArn,merged.subscriptions??[]);return{topicArn:topicArn,topicCreated:topicCreated,tagsApplied:merged.tags?Object.keys(merged.tags).length:0,subscriptionsCreated:subscriptionsCreated}},async init({config:partial,env:env,logger:logger,id:id}){const config=getConfig2(partial,env);if(!config.settings.client)return void logger.throw("SNS init: client missing (env not injected)");if(!isAWSEnvironment2(env))return void logger.throw("SNS init: env.AWS missing");if(config.settings.topicArn)return config;const{client:client,topicName:topicName,region:region}=config.settings;try{const res=await client.send(new env.AWS.CreateTopicCommand({Name:topicName}));if("object"!=typeof(v=res)||null===v||"string"!=typeof res.TopicArn||0===res.TopicArn.length)return void logger.throw(`SNS init: CreateTopic returned no ARN for "${topicName}"`);config.settings.topicArn=res.TopicArn}catch(err){throw logger.error(`SNS init failed for topic "${topicName}" in region ${region??"eu-central-1"}. Either set settings.topicArn directly, run "walkeros setup destination.${id}", or grant sns:CreateTopic to the runtime role.`,{topicName:topicName,region:region,error:err instanceof Error?err.message:String(err)}),err}var v;return config},push:async(event,context)=>await push2(event,context)};export{types_exports as DestinationFirehose,types_exports2 as DestinationSNS,destinationFirehose as default,destinationFirehose,destinationSNS};//# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/firehose/index.ts","../src/firehose/lib/firehose.ts","../src/firehose/config.ts","../src/firehose/push.ts","../src/firehose/types/index.ts","../src/sns/lib/sns.ts","../src/sns/config.ts","../src/sns/push.ts","../src/sns/setup.ts","../src/sns/types/index.ts","../src/sns/index.ts"],"sourcesContent":["import type { Settings, Destination } from './types';\nimport { isSameType } from '@walkeros/core';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationFirehose from './types';\n\nexport const destinationFirehose: Destination = {\n type: 'aws-firehose',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env);\n\n if (!isSameType(config.settings, {} as Settings))\n logger.throw('Config settings invalid');\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationFirehose;\n","import type { Destination, Logger } from '@walkeros/core';\nimport type { FirehoseConfig, Env } from '../types';\nimport { throwError } from '@walkeros/core';\n\n// Type guard to check if environment has AWS SDK\nfunction isAWSEnvironment(env: unknown): env is Env {\n return Boolean(\n env &&\n typeof env === 'object' &&\n 'AWS' in env &&\n (env as Env).AWS?.FirehoseClient,\n );\n}\n\nexport function getConfigFirehose(\n firehoseConfig: Partial<FirehoseConfig>,\n env?: unknown,\n): FirehoseConfig {\n const { streamName, region = 'eu-central-1', config = {} } = firehoseConfig;\n\n if (!streamName) throwError('Firehose: Config custom streamName missing');\n\n if (!config.region) config.region = region;\n\n // Use environment-injected SDK or fall back to provided client\n let client = firehoseConfig.client;\n if (!client && isAWSEnvironment(env)) {\n client = new env.AWS.FirehoseClient(config);\n }\n\n return {\n streamName,\n client,\n region,\n };\n}\n\nexport async function pushFirehose(\n pushEvents: Destination.PushEvents,\n config: FirehoseConfig,\n context: Destination.PushContext,\n) {\n const { client, streamName } = config;\n const { env, logger } = context;\n\n if (!client) return { queue: pushEvents };\n\n // Up to 500 records per batch\n const records = pushEvents.map(({ event }) => ({\n Data: Buffer.from(JSON.stringify(event)),\n }));\n\n logger.debug('Calling AWS Firehose API', {\n stream: streamName,\n recordCount: records.length,\n });\n\n // Use environment-injected SDK command or fall back to direct import\n if (isAWSEnvironment(env)) {\n await client.send(\n new env.AWS.PutRecordBatchCommand({\n DeliveryStreamName: streamName,\n Records: records,\n }),\n );\n } else {\n // Fall back to direct import for backward compatibility\n const { PutRecordBatchCommand } = await import('@aws-sdk/client-firehose');\n await client.send(\n new PutRecordBatchCommand({\n DeliveryStreamName: streamName,\n Records: records,\n }),\n );\n }\n\n logger?.debug('AWS Firehose API response', { ok: true });\n}\n","import type { Config, Settings, PartialConfig, Env } from './types';\nimport { getConfigFirehose } from './lib/firehose';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env?: unknown,\n): Config {\n const settings = partialConfig.settings || ({} as Settings);\n\n if (settings.firehose)\n settings.firehose = getConfigFirehose(settings.firehose, env);\n\n return { settings };\n}\n","import type { PushFn } from './types';\nimport { pushFirehose } from './lib/firehose';\n\nexport const push: PushFn = async function (event, context) {\n const { firehose } = context.config.settings || {};\n\n if (firehose) pushFirehose([{ event }], firehose, context);\n\n return;\n};\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type {\n FirehoseClient,\n FirehoseClientConfig,\n PutRecordBatchCommand,\n} from '@aws-sdk/client-firehose';\n\nexport interface Settings {\n firehose?: FirehoseConfig;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n AWS: {\n FirehoseClient: typeof FirehoseClient;\n PutRecordBatchCommand: typeof PutRecordBatchCommand;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\nexport interface FirehoseConfig {\n streamName: string;\n client?: FirehoseClient;\n region?: string;\n config?: FirehoseClientConfig;\n}\n","import type { Env, Settings } from '../types';\nimport { throwError } from '@walkeros/core';\n\n/** Type guard to check if environment has the AWS SNS SDK injected. */\nexport function isAWSEnvironment(env: unknown): env is Env {\n if (typeof env !== 'object' || env === null) return false;\n if (!('AWS' in env)) return false;\n const aws = (env as { AWS?: unknown }).AWS;\n if (typeof aws !== 'object' || aws === null) return false;\n return 'SNSClient' in aws;\n}\n\n/**\n * Resolve `Settings` from a partial input. Validates `topicName`, fills\n * `region` from default, builds an SNSClient from the env-injected\n * constructor when none was supplied.\n */\nexport function getConfigSNS(\n partial: Partial<Settings>,\n env?: unknown,\n): Settings {\n const { topicName, topicArn, config = {} } = partial;\n const region = partial.region ?? 'eu-central-1';\n\n if (!topicName) throwError('SNS: Settings topicName missing');\n\n const sdkConfig = config.region ? config : { ...config, region };\n\n let client = partial.client;\n if (!client && isAWSEnvironment(env)) {\n client = new env.AWS.SNSClient(sdkConfig);\n }\n\n const resolved: Settings = {\n topicName,\n region,\n config: sdkConfig,\n };\n if (client) resolved.client = client;\n if (topicArn) resolved.topicArn = topicArn;\n return resolved;\n}\n","import type { Config, PartialConfig, Settings } from './types';\nimport { getConfigSNS } from './lib/sns';\n\nexport function getConfig(partial: PartialConfig = {}, env?: unknown): Config {\n const partialSettings: Partial<Settings> =\n partial.settings && typeof partial.settings === 'object'\n ? partial.settings\n : {};\n const settings = getConfigSNS(partialSettings, env);\n return { ...partial, settings };\n}\n","import type { PushFn, Mapping } from './types';\nimport type { Mapping as WalkerOSMapping, Collector } from '@walkeros/core';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { isAWSEnvironment } from './lib/sns';\n\ninterface MessageAttribute {\n DataType: string;\n StringValue?: string;\n BinaryValue?: Uint8Array;\n}\n\nfunction isMessageAttribute(value: unknown): value is MessageAttribute {\n if (!isObject(value)) return false;\n const candidate = value as Record<string, unknown>;\n return typeof candidate.DataType === 'string';\n}\n\nasync function resolveMessageAttributes(\n event: Parameters<PushFn>[0],\n source: WalkerOSMapping.Map | undefined,\n collector: Collector.Instance,\n): Promise<Record<string, MessageAttribute> | undefined> {\n if (!source) return undefined;\n const result: Record<string, MessageAttribute> = {};\n let touched = false;\n for (const [key, value] of Object.entries(source)) {\n const resolved = await getMappingValue(event, value, { collector });\n if (isMessageAttribute(resolved)) {\n result[key] = resolved;\n touched = true;\n } else if (typeof resolved === 'string' && resolved.length > 0) {\n // Bare-string convenience: wrap into String DataType.\n result[key] = { DataType: 'String', StringValue: resolved };\n touched = true;\n } else if (resolved !== undefined && resolved !== null) {\n result[key] = { DataType: 'String', StringValue: String(resolved) };\n touched = true;\n }\n }\n return touched ? result : undefined;\n}\n\nfunction isMapping(value: unknown): value is Mapping {\n return typeof value === 'object' && value !== null;\n}\n\nasync function resolveStringMappingValue(\n event: Parameters<PushFn>[0],\n value: WalkerOSMapping.Value,\n collector: Collector.Instance,\n): Promise<string | undefined> {\n const resolved = await getMappingValue(event, value, { collector });\n if (typeof resolved === 'string' && resolved.length > 0) return resolved;\n if (resolved === undefined || resolved === null) return undefined;\n return String(resolved);\n}\n\nexport const push: PushFn = async function (event, context) {\n const { config, env, rule, collector, logger, id } = context;\n const settings = config.settings;\n const client = settings?.client;\n const topicArn = settings?.topicArn;\n\n if (!client) return logger.throw('SNS push: client missing, init() not run');\n if (!topicArn)\n return logger.throw('SNS push: topicArn missing, init() not run');\n if (!isAWSEnvironment(env))\n return logger.throw('SNS push: env.AWS not injected');\n\n const ruleSettings: Mapping = isMapping(rule?.settings) ? rule.settings : {};\n\n let messageGroupId: string | undefined;\n if (ruleSettings.messageGroupId !== undefined) {\n messageGroupId = await resolveStringMappingValue(\n event,\n ruleSettings.messageGroupId,\n collector,\n );\n }\n\n let messageDeduplicationId: string | undefined;\n if (ruleSettings.messageDeduplicationId !== undefined) {\n messageDeduplicationId = await resolveStringMappingValue(\n event,\n ruleSettings.messageDeduplicationId,\n collector,\n );\n }\n\n const messageAttributes = await resolveMessageAttributes(\n event,\n ruleSettings.messageAttributes,\n collector,\n );\n\n const input: {\n TopicArn: string;\n Message: string;\n MessageGroupId?: string;\n MessageDeduplicationId?: string;\n MessageAttributes?: Record<string, MessageAttribute>;\n } = {\n TopicArn: topicArn,\n Message: JSON.stringify(event),\n };\n if (messageGroupId) input.MessageGroupId = messageGroupId;\n if (messageDeduplicationId)\n input.MessageDeduplicationId = messageDeduplicationId;\n if (messageAttributes) input.MessageAttributes = messageAttributes;\n\n logger.debug('SNS Publish', {\n topicArn,\n fifo: topicArn.endsWith('.fifo'),\n event: event.name,\n });\n\n try {\n await client.send(new env.AWS.PublishCommand(input));\n } catch (err) {\n logger.error(\n `SNS Publish failed for \"${topicArn}\". ` +\n `Run \"walkeros setup destination.${id}\" if the topic is missing.`,\n {\n topicArn,\n event: event.name,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n throw err;\n }\n};\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type { Env, Setup, SetupSubscription, Settings, Types } from './types';\nimport type { LifecycleContext } from '@walkeros/core';\nimport { resolveSetup } from '@walkeros/core';\nimport type { SNSClient as SNSClientType } from '@aws-sdk/client-sns';\n\n// Setup is wired to the destination's `setup` slot which uses the broader\n// `DestinationServer.Config<Types>` (settings is optional). We runtime-narrow\n// instead of using the local Config alias so the assignment in index.ts\n// type-checks without contravariance issues.\ntype WideConfig = DestinationServer.Config<Types>;\n\nexport const DEFAULT_SETUP: Required<Pick<Setup, 'region' | 'fifoTopic'>> &\n Setup = {\n region: 'eu-central-1',\n fifoTopic: false,\n};\n\nexport interface SetupResult {\n topicArn: string;\n /** True when the GetTopicAttributes probe returned 404 (topic absent before this run). */\n topicCreated: boolean;\n tagsApplied: number;\n subscriptionsCreated: number;\n}\n\n// Module-level account-ID cache so re-running setup in the same process is\n// a no-op for the STS GetCallerIdentity call. Keyed by region (in case\n// future versions support cross-region setup in one process).\nconst accountIdCache: Map<string, string> = new Map();\n\n/** Test-only: clear the account-ID cache between test cases. */\nexport function __resetAccountIdCache(): void {\n accountIdCache.clear();\n}\n\ninterface CreateTopicResponse {\n TopicArn?: string;\n}\n\ninterface AwsErrorMeta {\n name?: string;\n $metadata?: { httpStatusCode?: number };\n}\n\nfunction isAwsError(err: unknown): err is AwsErrorMeta {\n return typeof err === 'object' && err !== null;\n}\n\nfunction isNotFound(err: unknown): boolean {\n if (!isAwsError(err)) return false;\n if (err.name === 'NotFoundException' || err.name === 'NotFound') return true;\n if (err.$metadata && err.$metadata.httpStatusCode === 404) return true;\n return false;\n}\n\nfunction resolveTopicName(name: string, fifo: boolean): string {\n if (fifo) {\n if (name.endsWith('.fifo')) return name;\n return `${name}.fifo`;\n }\n if (name.endsWith('.fifo')) {\n throw new Error(\n `FIFO suffix '.fifo' on standard topic name '${name}'. Set setup.fifoTopic: true or rename the topic.`,\n );\n }\n return name;\n}\n\nfunction resolveClient(\n settings: Settings | undefined,\n env: Env,\n region: string,\n): SNSClientType {\n if (settings?.client) return settings.client;\n const config = settings?.config ?? {};\n const merged = config.region ? config : { ...config, region };\n return new env.AWS.SNSClient(merged);\n}\n\nasync function getAccountId(env: Env, region: string): Promise<string> {\n const cached = accountIdCache.get(region);\n if (cached) return cached;\n const stsClient = new env.AWS.STSClient({ region });\n const res: unknown = await stsClient.send(\n new env.AWS.GetCallerIdentityCommand({}),\n );\n if (\n typeof res === 'object' &&\n res !== null &&\n 'Account' in res &&\n typeof (res as { Account?: unknown }).Account === 'string'\n ) {\n const accountId = (res as { Account: string }).Account;\n accountIdCache.set(region, accountId);\n return accountId;\n }\n throw new Error('STS GetCallerIdentity returned no Account');\n}\n\nfunction isCreateTopicResponse(v: unknown): v is CreateTopicResponse {\n return typeof v === 'object' && v !== null;\n}\n\nfunction extractTopicArn(res: unknown): string {\n if (isCreateTopicResponse(res) && typeof res.TopicArn === 'string')\n return res.TopicArn;\n throw new Error('SNS CreateTopic returned no TopicArn');\n}\n\nfunction buildSubscribeAttributes(\n sub: SetupSubscription,\n): Record<string, string> | undefined {\n const attrs: Record<string, string> = {};\n if (sub.rawMessageDelivery !== undefined) {\n attrs.RawMessageDelivery = String(sub.rawMessageDelivery);\n }\n if (sub.filterPolicy !== undefined) {\n attrs.FilterPolicy = JSON.stringify(sub.filterPolicy);\n }\n if (sub.deadLetterTargetArn !== undefined) {\n attrs.RedrivePolicy = JSON.stringify({\n deadLetterTargetArn: sub.deadLetterTargetArn,\n });\n }\n return Object.keys(attrs).length > 0 ? attrs : undefined;\n}\n\nasync function applyDeclaredSubscriptions(\n client: SNSClientType,\n env: Env,\n topicArn: string,\n declared: SetupSubscription[],\n): Promise<number> {\n let count = 0;\n for (const sub of declared) {\n const input: {\n TopicArn: string;\n Protocol: string;\n Endpoint: string;\n Attributes?: Record<string, string>;\n } = {\n TopicArn: topicArn,\n Protocol: sub.protocol,\n Endpoint: sub.endpoint,\n };\n const attrs = buildSubscribeAttributes(sub);\n if (attrs) input.Attributes = attrs;\n await client.send(new env.AWS.SubscribeCommand(input));\n count += 1;\n }\n return count;\n}\n\nexport async function setup(\n ctx: LifecycleContext<WideConfig, Env>,\n): Promise<SetupResult | undefined> {\n const { config, env, logger } = ctx;\n const merged = resolveSetup(config.setup, DEFAULT_SETUP);\n if (!merged) {\n logger.debug('setup: skipped (config.setup is false or unset)');\n return;\n }\n\n const settings = config.settings;\n if (!settings || !settings.topicName) {\n logger.throw(\n 'setup: settings.topicName is required. There is no safe default for the SNS topic name.',\n );\n return;\n }\n\n const region = merged.region ?? DEFAULT_SETUP.region;\n const fifo = merged.fifoTopic ?? false;\n const declaredName = settings.topicName;\n const finalName = resolveTopicName(declaredName, fifo);\n if (fifo && finalName !== declaredName) {\n logger.info(\n `setup: appended .fifo suffix to FIFO topic name '${declaredName}' -> '${finalName}'`,\n );\n }\n\n // Topic-existence probe via candidate ARN derived from STS account ID.\n const client = resolveClient(settings, env, region);\n const accountId = await getAccountId(env, region);\n const candidateArn = `arn:aws:sns:${region}:${accountId}:${finalName}`;\n\n let topicCreated = false;\n try {\n await client.send(\n new env.AWS.GetTopicAttributesCommand({ TopicArn: candidateArn }),\n );\n } catch (err) {\n if (isNotFound(err)) {\n topicCreated = true;\n } else {\n throw err;\n }\n }\n\n // Authoritative-apply: full declared state in one CreateTopic call.\n // SNS:CreateTopic is idempotent on identical Name+Attributes+Tags inputs.\n const attributes: Record<string, string> = {};\n if (fifo) {\n attributes.FifoTopic = 'true';\n attributes.ContentBasedDeduplication = 'true';\n }\n if (merged.displayName !== undefined)\n attributes.DisplayName = merged.displayName;\n if (merged.kmsMasterKeyId !== undefined)\n attributes.KmsMasterKeyId = merged.kmsMasterKeyId;\n\n const tagEntries = merged.tags\n ? Object.entries(merged.tags).map(([Key, Value]) => ({ Key, Value }))\n : undefined;\n\n const createInput: {\n Name: string;\n Attributes?: Record<string, string>;\n Tags?: Array<{ Key: string; Value: string }>;\n } = { Name: finalName };\n if (Object.keys(attributes).length > 0) createInput.Attributes = attributes;\n if (tagEntries && tagEntries.length > 0) createInput.Tags = tagEntries;\n\n const createRes = await client.send(\n new env.AWS.CreateTopicCommand(createInput),\n );\n const topicArn = extractTopicArn(createRes);\n\n if (topicCreated) {\n logger.info('setup: topic created', { topicArn, region });\n } else {\n logger.debug('setup: topic exists; declared state re-applied', {\n topicArn,\n region,\n });\n }\n\n const subscriptionsCreated = await applyDeclaredSubscriptions(\n client,\n env,\n topicArn,\n merged.subscriptions ?? [],\n );\n\n return {\n topicArn,\n topicCreated,\n tagsApplied: merged.tags ? Object.keys(merged.tags).length : 0,\n subscriptionsCreated,\n };\n}\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n SetupFn as CoreSetupFn,\n} from '@walkeros/core';\nimport type {\n SNSClient,\n SNSClientConfig,\n CreateTopicCommand,\n PublishCommand,\n GetTopicAttributesCommand,\n SubscribeCommand,\n} from '@aws-sdk/client-sns';\nimport type { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts';\n\nexport interface Settings {\n /** Topic name (without `.fifo` suffix unless fifoTopic is true). REQUIRED. */\n topicName: string;\n /** Pre-configured client. Optional; created from env if absent. */\n client?: SNSClient;\n /** AWS region. Mirrors setup.region default ('eu-central-1'). */\n region?: string;\n /** SDK client config (credentials, etc.). Optional. */\n config?: SNSClientConfig;\n /** Topic ARN, populated at init() from CreateTopic. Operator may pre-set to skip init's CreateTopic call. */\n topicArn?: string;\n}\n\nexport interface InitSettings {\n topicName: string;\n client?: SNSClient;\n region?: string;\n config?: SNSClientConfig;\n topicArn?: string;\n}\n\nexport interface Mapping {\n /**\n * Per-event message attributes resolved via mapping. Each attribute value\n * resolves to the SDK's expected `{ DataType, StringValue }` shape; operators\n * write either a literal `{ DataType: 'String', StringValue: '$path' }` value\n * or use `{ value: { DataType: 'String', StringValue: '$user.id' } }` style\n * to drive the StringValue from event data.\n */\n messageAttributes?: WalkerOSMapping.Map;\n /**\n * FIFO group ID for FIFO topics. `Mapping.Value` so operators can write\n * `messageGroupId: 'user.id'` (path) instead of hard-coding a literal.\n */\n messageGroupId?: WalkerOSMapping.Value;\n /** FIFO deduplication ID. `Mapping.Value`, same reasoning as `messageGroupId`. */\n messageDeduplicationId?: WalkerOSMapping.Value;\n}\n\nexport interface Env extends DestinationServer.Env {\n AWS: {\n SNSClient: typeof SNSClient;\n CreateTopicCommand: typeof CreateTopicCommand;\n PublishCommand: typeof PublishCommand;\n GetTopicAttributesCommand: typeof GetTopicAttributesCommand;\n SubscribeCommand: typeof SubscribeCommand;\n STSClient: typeof STSClient;\n GetCallerIdentityCommand: typeof GetCallerIdentityCommand;\n };\n}\n\n/**\n * Provisioning options for `walkeros setup destination.<id>` when targeting SNS.\n * Triggered only by the explicit CLI command. Idempotent, never auto-run.\n *\n * `topicName` lives in Settings (one source of truth for setup AND runtime publish).\n */\nexport interface Setup {\n /** AWS region for the topic. Default: 'eu-central-1'. */\n region?: string;\n /** Display name. Optional. */\n displayName?: string;\n /** FIFO topic with content-based deduplication. Default: false. */\n fifoTopic?: boolean;\n /** KMS key for at-rest encryption. Optional. */\n kmsMasterKeyId?: string;\n /** Tags for cost allocation. Optional. */\n tags?: Record<string, string>;\n /** Subscriptions to create or update on the topic. Each is opt-in. */\n subscriptions?: SetupSubscription[];\n}\n\nexport interface SetupSubscription {\n protocol: 'sqs' | 'lambda' | 'https' | 'http' | 'email' | 'sms';\n endpoint: string;\n rawMessageDelivery?: boolean;\n filterPolicy?: Record<string, unknown>;\n deadLetterTargetArn?: string;\n}\n\nexport type Types = CoreDestination.Types<\n Settings,\n Mapping,\n Env,\n InitSettings,\n Setup\n>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type SetupFn = CoreSetupFn<Config, Env>;\n\n// Local override of PartialConfig to forward the Setup (`U`) type arg.\n// Mirrors the BigQuery destination's pattern.\nexport type PartialConfig = Omit<\n DestinationServer.PartialConfig<Types>,\n 'settings' | 'setup'\n> & {\n settings?: Partial<Settings> | Settings;\n setup?: boolean | Setup;\n};\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\nimport { setup } from './setup';\nimport { isAWSEnvironment } from './lib/sns';\n\n// Types\nexport * as DestinationSNS from './types';\n\ninterface CreateTopicResponse {\n TopicArn?: string;\n}\n\nfunction isCreateTopicResponse(v: unknown): v is CreateTopicResponse {\n return typeof v === 'object' && v !== null;\n}\n\nexport const destinationSNS: Destination = {\n type: 'aws-sns',\n\n config: {},\n\n setup,\n\n async init({ config: partial, env, logger, id }) {\n const config = getConfig(partial, env);\n if (!config.settings.client) {\n logger.throw('SNS init: client missing (env not injected)');\n return;\n }\n if (!isAWSEnvironment(env)) {\n logger.throw('SNS init: env.AWS missing');\n return;\n }\n\n // Operator-supplied ARN: skip CreateTopic to avoid the runtime IAM cost.\n if (config.settings.topicArn) return config;\n\n const { client, topicName, region } = config.settings;\n try {\n const res: unknown = await client.send(\n new env.AWS.CreateTopicCommand({ Name: topicName }),\n );\n if (\n !isCreateTopicResponse(res) ||\n typeof res.TopicArn !== 'string' ||\n res.TopicArn.length === 0\n ) {\n logger.throw(\n `SNS init: CreateTopic returned no ARN for \"${topicName}\"`,\n );\n return;\n }\n config.settings.topicArn = res.TopicArn;\n } catch (err) {\n logger.error(\n `SNS init failed for topic \"${topicName}\" in region ${region ?? 'eu-central-1'}. ` +\n `Either set settings.topicArn directly, run \"walkeros setup destination.${id}\", ` +\n `or grant sns:CreateTopic to the runtime role.`,\n {\n topicName,\n region,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n throw err;\n }\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationSNS;\n"],"mappings":"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","names":["throwError","isAWSEnvironment","getConfig","push","isAWSEnvironment","types_exports","isCreateTopicResponse","getConfig","isAWSEnvironment","push"]}
1
+ {"version":3,"sources":["../src/firehose/index.ts","../src/firehose/lib/firehose.ts","../src/firehose/config.ts","../src/firehose/push.ts","../src/firehose/types/index.ts","../src/sns/lib/sns.ts","../src/sns/config.ts","../src/sns/push.ts","../src/sns/setup.ts","../src/sns/types/index.ts","../src/sns/index.ts"],"sourcesContent":["import type { Settings, Destination } from './types';\nimport { isSameType } from '@walkeros/core';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationFirehose from './types';\n\nexport const destinationFirehose: Destination = {\n type: 'aws-firehose',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env);\n\n if (!isSameType(config.settings, {} as Settings))\n logger.throw('Config settings invalid');\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationFirehose;\n","import type { Destination, Logger } from '@walkeros/core';\nimport type { FirehoseConfig, Env } from '../types';\nimport { throwError } from '@walkeros/core';\n\n// Type guard to check if environment has AWS SDK\nfunction isAWSEnvironment(env: unknown): env is Env {\n return Boolean(\n env &&\n typeof env === 'object' &&\n 'AWS' in env &&\n (env as Env).AWS?.FirehoseClient,\n );\n}\n\nexport function getConfigFirehose(\n firehoseConfig: Partial<FirehoseConfig>,\n env?: unknown,\n): FirehoseConfig {\n const { streamName, region = 'eu-central-1', config = {} } = firehoseConfig;\n\n if (!streamName) throwError('Firehose: Config custom streamName missing');\n\n if (!config.region) config.region = region;\n\n // Use environment-injected SDK or fall back to provided client\n let client = firehoseConfig.client;\n if (!client && isAWSEnvironment(env)) {\n client = new env.AWS.FirehoseClient(config);\n }\n\n return {\n streamName,\n client,\n region,\n };\n}\n\nexport async function pushFirehose(\n pushEvents: Destination.PushEvents,\n config: FirehoseConfig,\n context: Destination.PushContext,\n) {\n const { client, streamName } = config;\n const { env, logger } = context;\n\n if (!client) return { queue: pushEvents };\n\n // Up to 500 records per batch\n const records = pushEvents.map(({ event }) => ({\n Data: Buffer.from(JSON.stringify(event)),\n }));\n\n logger.debug('Calling AWS Firehose API', {\n stream: streamName,\n recordCount: records.length,\n });\n\n // Use environment-injected SDK command or fall back to direct import\n if (isAWSEnvironment(env)) {\n await client.send(\n new env.AWS.PutRecordBatchCommand({\n DeliveryStreamName: streamName,\n Records: records,\n }),\n );\n } else {\n // Fall back to direct import for backward compatibility\n const { PutRecordBatchCommand } = await import('@aws-sdk/client-firehose');\n await client.send(\n new PutRecordBatchCommand({\n DeliveryStreamName: streamName,\n Records: records,\n }),\n );\n }\n\n logger?.debug('AWS Firehose API response', { ok: true });\n}\n","import type { Config, Settings, PartialConfig, Env } from './types';\nimport { getConfigFirehose } from './lib/firehose';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env?: unknown,\n): Config {\n const settings = partialConfig.settings || ({} as Settings);\n\n if (settings.firehose)\n settings.firehose = getConfigFirehose(settings.firehose, env);\n\n return { ...partialConfig, settings };\n}\n","import type { PushFn } from './types';\nimport { pushFirehose } from './lib/firehose';\n\nexport const push: PushFn = async function (event, context) {\n const { firehose } = context.config.settings || {};\n\n if (firehose) pushFirehose([{ event }], firehose, context);\n\n return;\n};\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type {\n FirehoseClient,\n FirehoseClientConfig,\n PutRecordBatchCommand,\n} from '@aws-sdk/client-firehose';\n\nexport interface Settings {\n firehose?: FirehoseConfig;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n AWS: {\n FirehoseClient: typeof FirehoseClient;\n PutRecordBatchCommand: typeof PutRecordBatchCommand;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\nexport interface FirehoseConfig {\n streamName: string;\n client?: FirehoseClient;\n region?: string;\n config?: FirehoseClientConfig;\n}\n","import type { Env, Settings } from '../types';\nimport { throwError } from '@walkeros/core';\n\n/** Type guard to check if environment has the AWS SNS SDK injected. */\nexport function isAWSEnvironment(env: unknown): env is Env {\n if (typeof env !== 'object' || env === null) return false;\n if (!('AWS' in env)) return false;\n const aws = (env as { AWS?: unknown }).AWS;\n if (typeof aws !== 'object' || aws === null) return false;\n return 'SNSClient' in aws;\n}\n\n/**\n * Resolve `Settings` from a partial input. Validates `topicName`, fills\n * `region` from default, builds an SNSClient from the env-injected\n * constructor when none was supplied.\n */\nexport function getConfigSNS(\n partial: Partial<Settings>,\n env?: unknown,\n): Settings {\n const { topicName, topicArn, config = {} } = partial;\n const region = partial.region ?? 'eu-central-1';\n\n if (!topicName) throwError('SNS: Settings topicName missing');\n\n const sdkConfig = config.region ? config : { ...config, region };\n\n let client = partial.client;\n if (!client && isAWSEnvironment(env)) {\n client = new env.AWS.SNSClient(sdkConfig);\n }\n\n const resolved: Settings = {\n topicName,\n region,\n config: sdkConfig,\n };\n if (client) resolved.client = client;\n if (topicArn) resolved.topicArn = topicArn;\n return resolved;\n}\n","import type { Config, PartialConfig, Settings } from './types';\nimport { getConfigSNS } from './lib/sns';\n\nexport function getConfig(partial: PartialConfig = {}, env?: unknown): Config {\n const partialSettings: Partial<Settings> =\n partial.settings && typeof partial.settings === 'object'\n ? partial.settings\n : {};\n const settings = getConfigSNS(partialSettings, env);\n return { ...partial, settings };\n}\n","import type { PushFn, Mapping } from './types';\nimport type { Mapping as WalkerOSMapping, Collector } from '@walkeros/core';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { isAWSEnvironment } from './lib/sns';\n\ninterface MessageAttribute {\n DataType: string;\n StringValue?: string;\n BinaryValue?: Uint8Array;\n}\n\nfunction isMessageAttribute(value: unknown): value is MessageAttribute {\n if (!isObject(value)) return false;\n const candidate = value as Record<string, unknown>;\n return typeof candidate.DataType === 'string';\n}\n\nasync function resolveMessageAttributes(\n event: Parameters<PushFn>[0],\n source: WalkerOSMapping.Map | undefined,\n collector: Collector.Instance,\n): Promise<Record<string, MessageAttribute> | undefined> {\n if (!source) return undefined;\n const result: Record<string, MessageAttribute> = {};\n let touched = false;\n for (const [key, value] of Object.entries(source)) {\n const resolved = await getMappingValue(event, value, { collector });\n if (isMessageAttribute(resolved)) {\n result[key] = resolved;\n touched = true;\n } else if (typeof resolved === 'string' && resolved.length > 0) {\n // Bare-string convenience: wrap into String DataType.\n result[key] = { DataType: 'String', StringValue: resolved };\n touched = true;\n } else if (resolved !== undefined && resolved !== null) {\n result[key] = { DataType: 'String', StringValue: String(resolved) };\n touched = true;\n }\n }\n return touched ? result : undefined;\n}\n\nfunction isMapping(value: unknown): value is Mapping {\n return typeof value === 'object' && value !== null;\n}\n\nasync function resolveStringMappingValue(\n event: Parameters<PushFn>[0],\n value: WalkerOSMapping.Value,\n collector: Collector.Instance,\n): Promise<string | undefined> {\n const resolved = await getMappingValue(event, value, { collector });\n if (typeof resolved === 'string' && resolved.length > 0) return resolved;\n if (resolved === undefined || resolved === null) return undefined;\n return String(resolved);\n}\n\nexport const push: PushFn = async function (event, context) {\n const { config, env, rule, collector, logger, id } = context;\n const settings = config.settings;\n const client = settings?.client;\n const topicArn = settings?.topicArn;\n\n if (!client) return logger.throw('SNS push: client missing, init() not run');\n if (!topicArn)\n return logger.throw('SNS push: topicArn missing, init() not run');\n if (!isAWSEnvironment(env))\n return logger.throw('SNS push: env.AWS not injected');\n\n const ruleSettings: Mapping = isMapping(rule?.settings) ? rule.settings : {};\n\n let messageGroupId: string | undefined;\n if (ruleSettings.messageGroupId !== undefined) {\n messageGroupId = await resolveStringMappingValue(\n event,\n ruleSettings.messageGroupId,\n collector,\n );\n }\n\n let messageDeduplicationId: string | undefined;\n if (ruleSettings.messageDeduplicationId !== undefined) {\n messageDeduplicationId = await resolveStringMappingValue(\n event,\n ruleSettings.messageDeduplicationId,\n collector,\n );\n }\n\n const messageAttributes = await resolveMessageAttributes(\n event,\n ruleSettings.messageAttributes,\n collector,\n );\n\n const input: {\n TopicArn: string;\n Message: string;\n MessageGroupId?: string;\n MessageDeduplicationId?: string;\n MessageAttributes?: Record<string, MessageAttribute>;\n } = {\n TopicArn: topicArn,\n Message: JSON.stringify(event),\n };\n if (messageGroupId) input.MessageGroupId = messageGroupId;\n if (messageDeduplicationId)\n input.MessageDeduplicationId = messageDeduplicationId;\n if (messageAttributes) input.MessageAttributes = messageAttributes;\n\n logger.debug('SNS Publish', {\n topicArn,\n fifo: topicArn.endsWith('.fifo'),\n event: event.name,\n });\n\n try {\n await client.send(new env.AWS.PublishCommand(input));\n } catch (err) {\n logger.error(\n `SNS Publish failed for \"${topicArn}\". ` +\n `Run \"walkeros setup destination.${id}\" if the topic is missing.`,\n {\n topicArn,\n event: event.name,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n throw err;\n }\n};\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type { Env, Setup, SetupSubscription, Settings, Types } from './types';\nimport type { LifecycleContext } from '@walkeros/core';\nimport { resolveSetup } from '@walkeros/core';\nimport type { SNSClient as SNSClientType } from '@aws-sdk/client-sns';\n\n// Setup is wired to the destination's `setup` slot which uses the broader\n// `DestinationServer.Config<Types>` (settings is optional). We runtime-narrow\n// instead of using the local Config alias so the assignment in index.ts\n// type-checks without contravariance issues.\ntype WideConfig = DestinationServer.Config<Types>;\n\nexport const DEFAULT_SETUP: Required<Pick<Setup, 'region' | 'fifoTopic'>> &\n Setup = {\n region: 'eu-central-1',\n fifoTopic: false,\n};\n\nexport interface SetupResult {\n topicArn: string;\n /** True when the GetTopicAttributes probe returned 404 (topic absent before this run). */\n topicCreated: boolean;\n tagsApplied: number;\n subscriptionsCreated: number;\n}\n\n// Module-level account-ID cache so re-running setup in the same process is\n// a no-op for the STS GetCallerIdentity call. Keyed by region (in case\n// future versions support cross-region setup in one process).\nconst accountIdCache: Map<string, string> = new Map();\n\n/** Test-only: clear the account-ID cache between test cases. */\nexport function __resetAccountIdCache(): void {\n accountIdCache.clear();\n}\n\ninterface CreateTopicResponse {\n TopicArn?: string;\n}\n\ninterface AwsErrorMeta {\n name?: string;\n $metadata?: { httpStatusCode?: number };\n}\n\nfunction isAwsError(err: unknown): err is AwsErrorMeta {\n return typeof err === 'object' && err !== null;\n}\n\nfunction isNotFound(err: unknown): boolean {\n if (!isAwsError(err)) return false;\n if (err.name === 'NotFoundException' || err.name === 'NotFound') return true;\n if (err.$metadata && err.$metadata.httpStatusCode === 404) return true;\n return false;\n}\n\nfunction resolveTopicName(name: string, fifo: boolean): string {\n if (fifo) {\n if (name.endsWith('.fifo')) return name;\n return `${name}.fifo`;\n }\n if (name.endsWith('.fifo')) {\n throw new Error(\n `FIFO suffix '.fifo' on standard topic name '${name}'. Set setup.fifoTopic: true or rename the topic.`,\n );\n }\n return name;\n}\n\nfunction resolveClient(\n settings: Settings | undefined,\n env: Env,\n region: string,\n): SNSClientType {\n if (settings?.client) return settings.client;\n const config = settings?.config ?? {};\n const merged = config.region ? config : { ...config, region };\n return new env.AWS.SNSClient(merged);\n}\n\nasync function getAccountId(env: Env, region: string): Promise<string> {\n const cached = accountIdCache.get(region);\n if (cached) return cached;\n const stsClient = new env.AWS.STSClient({ region });\n const res: unknown = await stsClient.send(\n new env.AWS.GetCallerIdentityCommand({}),\n );\n if (\n typeof res === 'object' &&\n res !== null &&\n 'Account' in res &&\n typeof (res as { Account?: unknown }).Account === 'string'\n ) {\n const accountId = (res as { Account: string }).Account;\n accountIdCache.set(region, accountId);\n return accountId;\n }\n throw new Error('STS GetCallerIdentity returned no Account');\n}\n\nfunction isCreateTopicResponse(v: unknown): v is CreateTopicResponse {\n return typeof v === 'object' && v !== null;\n}\n\nfunction extractTopicArn(res: unknown): string {\n if (isCreateTopicResponse(res) && typeof res.TopicArn === 'string')\n return res.TopicArn;\n throw new Error('SNS CreateTopic returned no TopicArn');\n}\n\nfunction buildSubscribeAttributes(\n sub: SetupSubscription,\n): Record<string, string> | undefined {\n const attrs: Record<string, string> = {};\n if (sub.rawMessageDelivery !== undefined) {\n attrs.RawMessageDelivery = String(sub.rawMessageDelivery);\n }\n if (sub.filterPolicy !== undefined) {\n attrs.FilterPolicy = JSON.stringify(sub.filterPolicy);\n }\n if (sub.deadLetterTargetArn !== undefined) {\n attrs.RedrivePolicy = JSON.stringify({\n deadLetterTargetArn: sub.deadLetterTargetArn,\n });\n }\n return Object.keys(attrs).length > 0 ? attrs : undefined;\n}\n\nasync function applyDeclaredSubscriptions(\n client: SNSClientType,\n env: Env,\n topicArn: string,\n declared: SetupSubscription[],\n): Promise<number> {\n let count = 0;\n for (const sub of declared) {\n const input: {\n TopicArn: string;\n Protocol: string;\n Endpoint: string;\n Attributes?: Record<string, string>;\n } = {\n TopicArn: topicArn,\n Protocol: sub.protocol,\n Endpoint: sub.endpoint,\n };\n const attrs = buildSubscribeAttributes(sub);\n if (attrs) input.Attributes = attrs;\n await client.send(new env.AWS.SubscribeCommand(input));\n count += 1;\n }\n return count;\n}\n\nexport async function setup(\n ctx: LifecycleContext<WideConfig, Env>,\n): Promise<SetupResult | undefined> {\n const { config, env, logger } = ctx;\n const merged = resolveSetup(config.setup, DEFAULT_SETUP);\n if (!merged) {\n logger.debug('setup: skipped (config.setup is false or unset)');\n return;\n }\n\n const settings = config.settings;\n if (!settings || !settings.topicName) {\n logger.throw(\n 'setup: settings.topicName is required. There is no safe default for the SNS topic name.',\n );\n return;\n }\n\n const region = merged.region ?? DEFAULT_SETUP.region;\n const fifo = merged.fifoTopic ?? false;\n const declaredName = settings.topicName;\n const finalName = resolveTopicName(declaredName, fifo);\n if (fifo && finalName !== declaredName) {\n logger.info(\n `setup: appended .fifo suffix to FIFO topic name '${declaredName}' -> '${finalName}'`,\n );\n }\n\n // Topic-existence probe via candidate ARN derived from STS account ID.\n const client = resolveClient(settings, env, region);\n const accountId = await getAccountId(env, region);\n const candidateArn = `arn:aws:sns:${region}:${accountId}:${finalName}`;\n\n let topicCreated = false;\n try {\n await client.send(\n new env.AWS.GetTopicAttributesCommand({ TopicArn: candidateArn }),\n );\n } catch (err) {\n if (isNotFound(err)) {\n topicCreated = true;\n } else {\n throw err;\n }\n }\n\n // Authoritative-apply: full declared state in one CreateTopic call.\n // SNS:CreateTopic is idempotent on identical Name+Attributes+Tags inputs.\n const attributes: Record<string, string> = {};\n if (fifo) {\n attributes.FifoTopic = 'true';\n attributes.ContentBasedDeduplication = 'true';\n }\n if (merged.displayName !== undefined)\n attributes.DisplayName = merged.displayName;\n if (merged.kmsMasterKeyId !== undefined)\n attributes.KmsMasterKeyId = merged.kmsMasterKeyId;\n\n const tagEntries = merged.tags\n ? Object.entries(merged.tags).map(([Key, Value]) => ({ Key, Value }))\n : undefined;\n\n const createInput: {\n Name: string;\n Attributes?: Record<string, string>;\n Tags?: Array<{ Key: string; Value: string }>;\n } = { Name: finalName };\n if (Object.keys(attributes).length > 0) createInput.Attributes = attributes;\n if (tagEntries && tagEntries.length > 0) createInput.Tags = tagEntries;\n\n const createRes = await client.send(\n new env.AWS.CreateTopicCommand(createInput),\n );\n const topicArn = extractTopicArn(createRes);\n\n if (topicCreated) {\n logger.info('setup: topic created', { topicArn, region });\n } else {\n logger.debug('setup: topic exists; declared state re-applied', {\n topicArn,\n region,\n });\n }\n\n const subscriptionsCreated = await applyDeclaredSubscriptions(\n client,\n env,\n topicArn,\n merged.subscriptions ?? [],\n );\n\n return {\n topicArn,\n topicCreated,\n tagsApplied: merged.tags ? Object.keys(merged.tags).length : 0,\n subscriptionsCreated,\n };\n}\n","import type { DestinationServer } from '@walkeros/server-core';\nimport type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n SetupFn as CoreSetupFn,\n} from '@walkeros/core';\nimport type {\n SNSClient,\n SNSClientConfig,\n CreateTopicCommand,\n PublishCommand,\n GetTopicAttributesCommand,\n SubscribeCommand,\n} from '@aws-sdk/client-sns';\nimport type { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts';\n\nexport interface Settings {\n /** Topic name (without `.fifo` suffix unless fifoTopic is true). REQUIRED. */\n topicName: string;\n /** Pre-configured client. Optional; created from env if absent. */\n client?: SNSClient;\n /** AWS region. Mirrors setup.region default ('eu-central-1'). */\n region?: string;\n /** SDK client config (credentials, etc.). Optional. */\n config?: SNSClientConfig;\n /** Topic ARN, populated at init() from CreateTopic. Operator may pre-set to skip init's CreateTopic call. */\n topicArn?: string;\n}\n\nexport interface InitSettings {\n topicName: string;\n client?: SNSClient;\n region?: string;\n config?: SNSClientConfig;\n topicArn?: string;\n}\n\nexport interface Mapping {\n /**\n * Per-event message attributes resolved via mapping. Each attribute value\n * resolves to the SDK's expected `{ DataType, StringValue }` shape; operators\n * write either a literal `{ DataType: 'String', StringValue: '$path' }` value\n * or use `{ value: { DataType: 'String', StringValue: '$user.id' } }` style\n * to drive the StringValue from event data.\n */\n messageAttributes?: WalkerOSMapping.Map;\n /**\n * FIFO group ID for FIFO topics. `Mapping.Value` so operators can write\n * `messageGroupId: 'user.id'` (path) instead of hard-coding a literal.\n */\n messageGroupId?: WalkerOSMapping.Value;\n /** FIFO deduplication ID. `Mapping.Value`, same reasoning as `messageGroupId`. */\n messageDeduplicationId?: WalkerOSMapping.Value;\n}\n\nexport interface Env extends DestinationServer.Env {\n AWS: {\n SNSClient: typeof SNSClient;\n CreateTopicCommand: typeof CreateTopicCommand;\n PublishCommand: typeof PublishCommand;\n GetTopicAttributesCommand: typeof GetTopicAttributesCommand;\n SubscribeCommand: typeof SubscribeCommand;\n STSClient: typeof STSClient;\n GetCallerIdentityCommand: typeof GetCallerIdentityCommand;\n };\n}\n\n/**\n * Provisioning options for `walkeros setup destination.<id>` when targeting SNS.\n * Triggered only by the explicit CLI command. Idempotent, never auto-run.\n *\n * `topicName` lives in Settings (one source of truth for setup AND runtime publish).\n */\nexport interface Setup {\n /** AWS region for the topic. Default: 'eu-central-1'. */\n region?: string;\n /** Display name. Optional. */\n displayName?: string;\n /** FIFO topic with content-based deduplication. Default: false. */\n fifoTopic?: boolean;\n /** KMS key for at-rest encryption. Optional. */\n kmsMasterKeyId?: string;\n /** Tags for cost allocation. Optional. */\n tags?: Record<string, string>;\n /** Subscriptions to create or update on the topic. Each is opt-in. */\n subscriptions?: SetupSubscription[];\n}\n\nexport interface SetupSubscription {\n protocol: 'sqs' | 'lambda' | 'https' | 'http' | 'email' | 'sms';\n endpoint: string;\n rawMessageDelivery?: boolean;\n filterPolicy?: Record<string, unknown>;\n deadLetterTargetArn?: string;\n}\n\nexport type Types = CoreDestination.Types<\n Settings,\n Mapping,\n Env,\n InitSettings,\n Setup\n>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type SetupFn = CoreSetupFn<Config, Env>;\n\n// Local override of PartialConfig to forward the Setup (`U`) type arg.\n// Mirrors the BigQuery destination's pattern.\nexport type PartialConfig = Omit<\n DestinationServer.PartialConfig<Types>,\n 'settings' | 'setup'\n> & {\n settings?: Partial<Settings> | Settings;\n setup?: boolean | Setup;\n};\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\nimport { setup } from './setup';\nimport { isAWSEnvironment } from './lib/sns';\n\n// Types\nexport * as DestinationSNS from './types';\n\ninterface CreateTopicResponse {\n TopicArn?: string;\n}\n\nfunction isCreateTopicResponse(v: unknown): v is CreateTopicResponse {\n return typeof v === 'object' && v !== null;\n}\n\nexport const destinationSNS: Destination = {\n type: 'aws-sns',\n\n config: {},\n\n setup,\n\n async init({ config: partial, env, logger, id }) {\n const config = getConfig(partial, env);\n if (!config.settings.client) {\n logger.throw('SNS init: client missing (env not injected)');\n return;\n }\n if (!isAWSEnvironment(env)) {\n logger.throw('SNS init: env.AWS missing');\n return;\n }\n\n // Operator-supplied ARN: skip CreateTopic to avoid the runtime IAM cost.\n if (config.settings.topicArn) return config;\n\n const { client, topicName, region } = config.settings;\n try {\n const res: unknown = await client.send(\n new env.AWS.CreateTopicCommand({ Name: topicName }),\n );\n if (\n !isCreateTopicResponse(res) ||\n typeof res.TopicArn !== 'string' ||\n res.TopicArn.length === 0\n ) {\n logger.throw(\n `SNS init: CreateTopic returned no ARN for \"${topicName}\"`,\n );\n return;\n }\n config.settings.topicArn = res.TopicArn;\n } catch (err) {\n logger.error(\n `SNS init failed for topic \"${topicName}\" in region ${region ?? 'eu-central-1'}. ` +\n `Either set settings.topicArn directly, run \"walkeros setup destination.${id}\", ` +\n `or grant sns:CreateTopic to the runtime role.`,\n {\n topicName,\n region,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n throw err;\n }\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationSNS;\n"],"mappings":"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","names":["throwError","isAWSEnvironment","getConfig","push","isAWSEnvironment","types_exports","isCreateTopicResponse","getConfig","isAWSEnvironment","push"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/server-destination-aws",
4
- "version": "4.4.0",
4
+ "version": "4.5.1-next-1788726985928",
5
5
  "type": "destination",
6
6
  "platform": [
7
7
  "server"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@walkeros/server-destination-aws",
3
3
  "description": "AWS server destination for walkerOS",
4
- "version": "4.4.0",
4
+ "version": "4.5.1-next-1788726985928",
5
5
  "license": "MIT",
6
6
  "exports": {
7
7
  ".": {
@@ -38,8 +38,8 @@
38
38
  "@aws-sdk/client-firehose": "^3.952.0",
39
39
  "@aws-sdk/client-sns": "^3.952.0",
40
40
  "@aws-sdk/client-sts": "^3.952.0",
41
- "@walkeros/core": "4.4.0",
42
- "@walkeros/server-core": "4.4.0"
41
+ "@walkeros/core": "4.5.1-next-1788726985928",
42
+ "@walkeros/server-core": "4.5.1-next-1788726985928"
43
43
  },
44
44
  "devDependencies": {},
45
45
  "repository": {