somod-chat-service 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { Message, MessageInput } from "./types";
2
2
  export declare const putMessage: (tableName: string, userId: string, message: Omit<Message, "seqNo">) => Promise<Message>;
3
- export declare const validateIncomingMessage: (message: MessageInput, userId: string) => Promise<{
3
+ export declare const validateIncomingMessage: (message: MessageInput, userId: string, typeToAllowedActionsMap: Record<string, string[]>) => Promise<{
4
4
  statusCode: number;
5
5
  headers: {
6
6
  "Content-Type": string;
@@ -1,5 +1,4 @@
1
1
  import { marshall } from "@aws-sdk/util-dynamodb";
2
- import { typeToAllowedActionsMap } from "./types";
3
2
  import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
4
3
  import { threadCache } from "./threadCache";
5
4
  const dynamodb = new DynamoDBClient();
@@ -21,7 +20,7 @@ export const putMessage = async (tableName, userId, message) => {
21
20
  await dynamodb.send(putItemCommand);
22
21
  return msg;
23
22
  };
24
- export const validateIncomingMessage = async (message, userId) => {
23
+ export const validateIncomingMessage = async (message, userId, typeToAllowedActionsMap) => {
25
24
  let errorMessage = undefined;
26
25
  const thread = await threadCache.get(message.threadId);
27
26
  if (thread === undefined) {
@@ -30,6 +29,9 @@ export const validateIncomingMessage = async (message, userId) => {
30
29
  else if (!thread.participants.includes(userId)) {
31
30
  errorMessage = `Invalid threadId : from '${userId}' is not a participant in thread '${thread.id}'`;
32
31
  }
32
+ else if (!typeToAllowedActionsMap[message.type]) {
33
+ errorMessage = `Invalid type : type must be one of (${typeToAllowedActionsMap[message.type].join(", ")})`;
34
+ }
33
35
  else if (!typeToAllowedActionsMap[message.type].includes(message.action)) {
34
36
  errorMessage = `Invalid action : action must be '${typeToAllowedActionsMap[message.type].join(",")}' for '${message.type}' type`;
35
37
  }
@@ -7,5 +7,5 @@ export declare const Error: {
7
7
  required: string;
8
8
  invalid: string;
9
9
  };
10
- export declare const handleSessionToken: (userId: string, threadId: string, type: string, action: string, sessionToken?: string) => Promise<SessionIdResult>;
10
+ export declare const handleSessionToken: (userId: string, threadId: string, type: string, action: string, sessionRequirement: Record<string, Record<string, undefined | "thread" | "always">>, sessionToken?: string) => Promise<SessionIdResult>;
11
11
  export {};
@@ -1,5 +1,4 @@
1
1
  import { verify } from "jsonwebtoken";
2
- import { sessionRequirement } from "./types";
3
2
  import { threadCache } from "./threadCache";
4
3
  const sessionJwtSecret = process.env.SESSION_SECRET ?? "";
5
4
  const sessionForce = process.env.SESSION_FORCE ?? "";
@@ -7,7 +6,7 @@ export const Error = {
7
6
  required: "missing required field: sessionToken",
8
7
  invalid: "invalid field: sessionToken"
9
8
  };
10
- export const handleSessionToken = async (userId, threadId, type, action, sessionToken) => {
9
+ export const handleSessionToken = async (userId, threadId, type, action, sessionRequirement, sessionToken) => {
11
10
  const result = { sessionId: "" };
12
11
  if (sessionJwtSecret) {
13
12
  if (!sessionToken) {
@@ -11,8 +11,8 @@ export type Thread = {
11
11
  } & ThreadInput & ThreadSessionRequired;
12
12
  export type MessageInput = {
13
13
  threadId: string;
14
- type: "text" | "image" | "control" | "call" | "pooja" | "donation";
15
- action: "new" | "edit" | "delete" | "sessionStart" | "sessionExtend" | "sessionEnd" | "sessionRequirementChange" | "initiated" | "declined";
14
+ type: "text" | "image" | "control" | "audio-call" | "video-call";
15
+ action: "new" | "edit" | "delete" | "callStart" | "callConnect" | "callEnd";
16
16
  message: string;
17
17
  sessionToken?: string;
18
18
  };
@@ -29,15 +29,3 @@ export type Session = {
29
29
  startTime: number;
30
30
  endTime: number;
31
31
  };
32
- export declare const typeToAllowedActionsMap: {
33
- text: string[];
34
- image: string[];
35
- control: string[];
36
- call: string[];
37
- pooja: string[];
38
- donation: string[];
39
- };
40
- /**
41
- * Store the message type and actions for which the session token is required
42
- */
43
- export declare const sessionRequirement: Record<string, Record<string, undefined | "thread" | "always">>;
@@ -1,26 +1 @@
1
- export const typeToAllowedActionsMap = {
2
- text: ["new", "edit"],
3
- image: ["new", "edit"],
4
- control: [
5
- "delete",
6
- "sessionStart",
7
- "sessionExtend",
8
- "sessionEnd",
9
- "sessionRequirementChange"
10
- ],
11
- call: ["initiated", "declined"],
12
- pooja: ["new", "edit"],
13
- donation: ["new", "edit"]
14
- };
15
- /**
16
- * Store the message type and actions for which the session token is required
17
- */
18
- export const sessionRequirement = {
19
- text: { new: "thread", edit: "thread" },
20
- image: { new: "thread", edit: "thread" },
21
- control: {
22
- sessionStart: "always",
23
- sessionExtend: "always",
24
- sessionEnd: "always"
25
- }
26
- };
1
+ export {};
@@ -1 +1 @@
1
- {"parameters":{"chat.http-api.id":{"type":"string"},"chat.websocket-api.id":{"type":"string"},"chat.enable.websocket":{"type":"boolean","default":true},"dynamodb.pitr.enable":{"type":"boolean","default":false},"chat.session.jwt.secret":{"type":"string"},"chat.session.force":{"type":"boolean","default":false}}}
1
+ {"parameters":{"chat.http-api.id":{"type":"string"},"chat.websocket-api.id":{"type":"string"},"chat.enable.websocket":{"type":"boolean","default":true},"dynamodb.pitr.enable":{"type":"boolean","default":false},"chat.session.jwt.secret":{"type":"string"},"chat.session.force":{"type":"boolean","default":false},"chat.typeToAllowedActionsMap":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}},"default":{"text":["new","edit"],"image":["new","edit"],"control":["delete"],"audio-call":["callStart","callConnect","callEnd"],"video-call":["callStart","callConnect","callEnd"]}},"chat.sessionRequirementMap":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"enum":["thread","always"]}},"default":{"text":{"new":"thread","edit":"thread"},"image":{"new":"thread","edit":"thread"}}}}}
@@ -1 +1 @@
1
- {"/post-message":{"POST":{"body":{"parser":"json","schema":{"type":"object","additionalProperties":false,"required":["threadId","type","action","message"],"properties":{"threadId":{"type":"string","pattern":"^[a-f0-9]{32}$"},"type":{"enum":["text","image","control","call","pooja","donation"]},"action":{"enum":["new","edit","delete","sessionStart","sessionExtend","sessionEnd","initiated","declined"]},"message":{"type":"string","maxLength":512},"sessionToken":{"type":"string","maxLength":16384}}}}}},"/sync-messages":{"GET":{"parameters":[{"name":"from","in":"query","schema":{"type":"string","pattern":"^[0-9]*$"},"required":false}]}}}
1
+ {"/post-message":{"POST":{"body":{"parser":"json","schema":{"type":"object","additionalProperties":false,"required":["threadId","type","action","message"],"properties":{"threadId":{"type":"string","pattern":"^[a-f0-9]{32}$"},"type":{"type":"string","pattern":"^.{1,32}$"},"action":{"type":"string","pattern":"^.{1,32}$"},"message":{"type":"string","maxLength":512},"sessionToken":{"type":"string","maxLength":16384}}}}}},"/sync-messages":{"GET":{"parameters":[{"name":"from","in":"query","schema":{"type":"string","pattern":"^[0-9]*$"},"required":false}]}}}
@@ -8,13 +8,15 @@ import { handleSessionToken } from "../../lib/sessionUtil";
8
8
  import { getUserIdFromEvent } from "../../lib/getUserIdFromEvent";
9
9
  const dynamodb = new DynamoDBClient();
10
10
  const builder = new RouteBuilder();
11
+ const typeToAllowedActionsMap = JSON.parse(process.env.MAP_OF_TYPE_ACTION ?? "{}");
12
+ const sessionRequirement = JSON.parse(process.env.MAP_OF_TYPE_ACTION_SESSION ?? "{}");
11
13
  const postMessageHandler = async (request, event) => {
12
14
  const userId = event.somodMiddlewareContext.get(UserProviderMiddlewareKey);
13
- const messageValidationError = await validateIncomingMessage(request.body, userId);
15
+ const messageValidationError = await validateIncomingMessage(request.body, userId, typeToAllowedActionsMap);
14
16
  if (messageValidationError) {
15
17
  return messageValidationError;
16
18
  }
17
- const sessionIdResult = await handleSessionToken(userId, request.body.threadId, request.body.type, request.body.action, request.body.sessionToken);
19
+ const sessionIdResult = await handleSessionToken(userId, request.body.threadId, request.body.type, request.body.action, sessionRequirement, request.body.sessionToken);
18
20
  if (sessionIdResult.error) {
19
21
  return {
20
22
  statusCode: 400,
@@ -4,13 +4,15 @@ import { v1 as v1uuid } from "uuid";
4
4
  import { handleSessionToken } from "../../lib/sessionUtil";
5
5
  import { getUserIdFromEvent } from "../../lib/getUserIdFromEvent";
6
6
  const builder = new RouteBuilder();
7
+ const typeToAllowedActionsMap = JSON.parse(process.env.MAP_OF_TYPE_ACTION ?? "{}");
8
+ const sessionRequirement = JSON.parse(process.env.MAP_OF_TYPE_ACTION_SESSION ?? "{}");
7
9
  builder.add("$default", async (message, event) => {
8
10
  const userId = getUserIdFromEvent(event);
9
- const messageValidationError = await validateIncomingMessage(message.body, userId);
11
+ const messageValidationError = await validateIncomingMessage(message.body, userId, typeToAllowedActionsMap);
10
12
  if (messageValidationError) {
11
13
  return messageValidationError;
12
14
  }
13
- const sessionIdResult = await handleSessionToken(userId, message.body.threadId, message.body.type, message.body.action, message.body.sessionToken);
15
+ const sessionIdResult = await handleSessionToken(userId, message.body.threadId, message.body.type, message.body.action, sessionRequirement, message.body.sessionToken);
14
16
  if (sessionIdResult.error) {
15
17
  return {
16
18
  statusCode: 400,
@@ -1 +1 @@
1
- {"$default":{"body":{"parser":"json","schema":{"type":"object","additionalProperties":false,"required":["wsMsgId","threadId","type","action","message"],"properties":{"wsMsgId":{"type":"string","pattern":"^[a-f0-9]{32}$"},"threadId":{"type":"string","pattern":"^[a-f0-9]{32}$"},"type":{"enum":["text","image","control","call","pooja","donation"]},"action":{"enum":["new","edit","delete","sessionStart","sessionExtend","sessionEnd","initiated","declined"]},"message":{"type":"string","maxLength":512},"sessionToken":{"type":"string","maxLength":16384}}}}}}
1
+ {"$default":{"body":{"parser":"json","schema":{"type":"object","additionalProperties":false,"required":["wsMsgId","threadId","type","action","message"],"properties":{"wsMsgId":{"type":"string","pattern":"^[a-f0-9]{32}$"},"threadId":{"type":"string","pattern":"^[a-f0-9]{32}$"},"type":{"type":"string","pattern":"^.{1,32}$"},"action":{"type":"string","pattern":"^.{1,32}$"},"message":{"type":"string","maxLength":512},"sessionToken":{"type":"string","maxLength":16384}}}}}}
@@ -1 +1 @@
1
- {"Resources":{"ChatApi":{"Type":"AWS::Serverless::HttpApi","SOMOD::Access":"public","SOMOD::Output":{"default":true},"Properties":{}},"ThreadTable":{"Type":"AWS::DynamoDB::Table","SOMOD::Access":"public","SOMOD::Output":{"default":true,"attributes":["Arn"]},"Properties":{"TableName":{"SOMOD::ResourceName":"Thread"},"BillingMode":"PAY_PER_REQUEST","PointInTimeRecoverySpecification":{"PointInTimeRecoveryEnabled":{"SOMOD::Parameter":"dynamodb.pitr.enable"}},"KeySchema":[{"AttributeName":"id","KeyType":"HASH"}],"AttributeDefinitions":[{"AttributeName":"id","AttributeType":"S"}]}},"MessageBox":{"Type":"AWS::DynamoDB::Table","SOMOD::Access":"public","SOMOD::Output":{"default":true,"attributes":["Arn","StreamArn"]},"Properties":{"TableName":{"SOMOD::ResourceName":"MessageBox"},"BillingMode":"PAY_PER_REQUEST","PointInTimeRecoverySpecification":{"PointInTimeRecoveryEnabled":{"SOMOD::Parameter":"dynamodb.pitr.enable"}},"KeySchema":[{"AttributeName":"userId","KeyType":"HASH"},{"AttributeName":"seqNo","KeyType":"RANGE"}],"AttributeDefinitions":[{"AttributeName":"userId","AttributeType":"S"},{"AttributeName":"seqNo","AttributeType":"N"}],"StreamSpecification":{"StreamViewType":"NEW_IMAGE"}}},"MessageStreamHandlerDLQ":{"Type":"AWS::SQS::Queue","SOMOD::Output":{"default":true,"attributes":["Arn","QueueName","QueueUrl"]},"Properties":{"QueueName":{"SOMOD::ResourceName":"MessageStreamHandlerDLQ"}}},"MessageStreamHandler":{"Type":"AWS::Serverless::Function","SOMOD::Access":"public","Properties":{"FunctionName":{"SOMOD::ResourceName":"MsgStrmHandler"},"CodeUri":{"SOMOD::Function":{"name":"messageStreamHandler","type":"DynamoDB"}},"Environment":{"Variables":{"MESSAGE_BOX_TABLE_NAME":{"SOMOD::Ref":{"resource":"MessageBox"}},"THREAD_TABLE_NAME":{"SOMOD::Ref":{"resource":"ThreadTable"}},"MSG_NOTIFICATION_TOPIC":{"SOMOD::Ref":{"resource":"MessageNotificationTopic"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageBox","attribute":"Arn"}}],"Action":["dynamodb:PutItem"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ThreadTable","attribute":"Arn"}}],"Action":["dynamodb:GetItem"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageNotificationTopic"}}],"Action":["sns:Publish"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageStreamHandlerDLQ","attribute":"Arn"}}],"Action":["sqs:SendMessage"]}]}],"Events":{"Stream":{"Type":"DynamoDB","Properties":{"Stream":{"SOMOD::Ref":{"resource":"MessageBox","attribute":"StreamArn"}},"BatchSize":1,"MaximumRetryAttempts":3,"StartingPosition":"LATEST","DestinationConfig":{"OnFailure":{"Destination":{"SOMOD::Ref":{"resource":"MessageStreamHandlerDLQ","attribute":"Arn"}}}}}}}}},"UserProviderMiddleware":{"Type":"SOMOD::Serverless::FunctionMiddleware","SOMOD::Access":"public","SOMOD::Output":{"default":true},"Properties":{"CodeUri":{"SOMOD::FunctionMiddleware":{"name":"userProvider"}}}},"Message":{"Type":"AWS::Serverless::Function","SOMOD::Access":"public","Properties":{"FunctionName":{"SOMOD::ResourceName":"MessageApi"},"CodeUri":{"SOMOD::Function":{"name":"message","type":"HttpApi","middlewares":[{"module":"somod-http-extension","resource":"SomodHttpMiddleware"},{"resource":"UserProviderMiddleware"}]}},"Environment":{"Variables":{"MESSAGE_BOX_TABLE_NAME":{"SOMOD::Ref":{"resource":"MessageBox"}},"THREAD_TABLE_NAME":{"SOMOD::Ref":{"resource":"ThreadTable"}},"SESSION_SECRET":{"SOMOD::Parameter":"chat.session.jwt.secret"},"SESSION_FORCE":{"SOMOD::Parameter":"chat.session.force"}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageBox","attribute":"Arn"}}],"Action":["dynamodb:PutItem","dynamodb:Query"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ThreadTable","attribute":"Arn"}}],"Action":["dynamodb:GetItem"]}]}],"Events":{"PostMessage":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"POST","Path":"/post-message"}},"SyncMessages":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"GET","Path":"/sync-messages"}}}}},"Thread":{"Type":"AWS::Serverless::Function","SOMOD::Access":"public","Properties":{"FunctionName":{"SOMOD::ResourceName":"ThreadApi"},"CodeUri":{"SOMOD::Function":{"name":"thread","type":"HttpApi","middlewares":[{"module":"somod-http-extension","resource":"SomodHttpMiddleware"},{"resource":"UserProviderMiddleware"}]}},"Environment":{"Variables":{"THREAD_TABLE_NAME":{"SOMOD::Ref":{"resource":"ThreadTable"}},"MESSAGE_BOX_TABLE_NAME":{"SOMOD::Ref":{"resource":"MessageBox"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ThreadTable","attribute":"Arn"}}],"Action":["dynamodb:PutItem","dynamodb:GetItem","dynamodb:UpdateItem"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageBox","attribute":"Arn"}}],"Action":["dynamodb:PutItem"]}]}],"Events":{"CreateThread":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"POST","Path":"/thread"}},"GetThread":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"GET","Path":"/thread/{id}"}},"UpdateSessionRequireInThread":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"POST","Path":"/thread/{id}/session"}}}}},"MessageNotificationTopic":{"Type":"AWS::SNS::Topic","SOMOD::Access":"public","SOMOD::Output":{"default":true,"attributes":["TopicName"]},"Properties":{"TopicName":{"SOMOD::ResourceName":"MsgNotificationTopic"}}},"WebSocketApi":{"Type":"AWS::ApiGatewayV2::Api","SOMOD::Access":"public","Properties":{"Name":{"SOMOD::ResourceName":"ChatWebsocketApi"},"ProtocolType":"WEBSOCKET","RouteSelectionExpression":"$request.body.action"}},"ConnectRoute":{"Type":"AWS::ApiGatewayV2::Route","SOMOD::Access":"public","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"RouteKey":"$connect","OperationName":"ConnectRoute","Target":{"Fn::Join":["/",["integrations",{"SOMOD::Ref":{"resource":"ConnectInteg"}}]]}}},"ConnectInteg":{"Type":"AWS::ApiGatewayV2::Integration","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"Description":"Connect Integration","IntegrationType":"AWS_PROXY","IntegrationUri":{"Fn::Sub":["arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OnConnectFunctionArn}/invocations",{"OnConnectFunctionArn":{"SOMOD::Ref":{"resource":"OnConnectFunction","attribute":"Arn"}}}]}}},"DisconnectRoute":{"Type":"AWS::ApiGatewayV2::Route","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"RouteKey":"$disconnect","OperationName":"DisconnectRoute","Target":{"Fn::Join":["/",["integrations",{"SOMOD::Ref":{"resource":"DisconnectInteg"}}]]}}},"DisconnectInteg":{"Type":"AWS::ApiGatewayV2::Integration","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"Description":"Disconnect Integration","IntegrationType":"AWS_PROXY","IntegrationUri":{"Fn::Sub":["arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OnDisconnectFunctionArn}/invocations",{"OnDisconnectFunctionArn":{"SOMOD::Ref":{"resource":"OnDisconnectFunction","attribute":"Arn"}}}]}}},"DefaultRoute":{"Type":"AWS::ApiGatewayV2::Route","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"default":true},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"RouteKey":"$default","OperationName":"DefaultRoute","Target":{"Fn::Join":["/",["integrations",{"SOMOD::Ref":{"resource":"DefaultInteg"}}]]}}},"DefaultRouteResponse":{"Type":"AWS::ApiGatewayV2::RouteResponse","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"default":true},"Properties":{"RouteId":{"SOMOD::Ref":{"resource":"DefaultRoute"}},"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"RouteResponseKey":"$default"}},"DefaultInteg":{"Type":"AWS::ApiGatewayV2::Integration","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"default":true},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"Description":"Default Integration","IntegrationType":"AWS_PROXY","IntegrationUri":{"Fn::Sub":["arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OnMessageFunctionArn}/invocations",{"OnMessageFunctionArn":{"SOMOD::Ref":{"resource":"OnMessageFunction","attribute":"Arn"}}}]}}},"DefaultIntegResponse":{"Type":"AWS::ApiGatewayV2::IntegrationResponse","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"IntegrationId":{"SOMOD::Ref":{"resource":"DefaultInteg"}},"IntegrationResponseKey":"$default"}},"Stage":{"Type":"AWS::ApiGatewayV2::Stage","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"StageName":"$default","ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"AutoDeploy":true}},"ConnectionsTable":{"Type":"AWS::DynamoDB::Table","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"default":true,"attributes":["Arn"]},"Properties":{"BillingMode":"PAY_PER_REQUEST","PointInTimeRecoverySpecification":{"PointInTimeRecoveryEnabled":{"SOMOD::Parameter":"dynamodb.pitr.enable"}},"AttributeDefinitions":[{"AttributeName":"id","AttributeType":"S"},{"AttributeName":"userId","AttributeType":"S"}],"KeySchema":[{"AttributeName":"id","KeyType":"HASH"}],"GlobalSecondaryIndexes":[{"IndexName":"ByUserId","KeySchema":[{"AttributeName":"userId","KeyType":"HASH"}],"Projection":{"ProjectionType":"KEYS_ONLY"}}]}},"OnConnectFunction":{"Type":"AWS::Serverless::Function","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"attributes":["Arn"]},"Properties":{"CodeUri":{"SOMOD::Function":{"type":"WebSocket","name":"wsOnConnect","middlewares":[{"resource":"UserProviderMiddleware"}]}},"Environment":{"Variables":{"CONNECTIONS_TABLE_NAME":{"SOMOD::Ref":{"resource":"ConnectionsTable"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ConnectionsTable","attribute":"Arn"}}],"Action":["dynamodb:PutItem"]}]}]}},"OnConnectPermission":{"Type":"AWS::Lambda::Permission","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"Action":"lambda:InvokeFunction","FunctionName":{"SOMOD::Ref":{"resource":"OnConnectFunction"}},"Principal":"apigateway.amazonaws.com","SourceArn":{"Fn::Sub":["arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiId}/$default/$connect",{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]}}},"OnDisconnectFunction":{"Type":"AWS::Serverless::Function","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"attributes":["Arn"]},"Properties":{"CodeUri":{"SOMOD::Function":{"type":"WebSocket","name":"wsOnDisconnect"}},"Environment":{"Variables":{"CONNECTIONS_TABLE_NAME":{"SOMOD::Ref":{"resource":"ConnectionsTable"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ConnectionsTable","attribute":"Arn"}}],"Action":["dynamodb:DeleteItem"]}]}]}},"OnDisconnectPermission":{"Type":"AWS::Lambda::Permission","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"Action":"lambda:InvokeFunction","FunctionName":{"SOMOD::Ref":{"resource":"OnDisconnectFunction"}},"Principal":"apigateway.amazonaws.com","SourceArn":{"Fn::Sub":["arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiId}/$default/$disconnect",{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]}}},"OnMessageFunction":{"Type":"AWS::Serverless::Function","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"attributes":["Arn"]},"Properties":{"CodeUri":{"SOMOD::Function":{"type":"WebSocket","name":"wsOnMessage","middlewares":[{"module":"somod-websocket-extension","resource":"SomodWebSocketMiddleware"},{"resource":"UserProviderMiddleware"}]}},"Environment":{"Variables":{"MESSAGE_BOX_TABLE_NAME":{"SOMOD::Ref":{"resource":"MessageBox"}},"THREAD_TABLE_NAME":{"SOMOD::Ref":{"resource":"ThreadTable"}},"SESSION_SECRET":{"SOMOD::Parameter":"chat.session.jwt.secret"},"SESSION_FORCE":{"SOMOD::Parameter":"chat.session.force"}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageBox","attribute":"Arn"}}],"Action":["dynamodb:PutItem"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ThreadTable","attribute":"Arn"}}],"Action":["dynamodb:GetItem"]}]}]}},"OnMessagePermission":{"Type":"AWS::Lambda::Permission","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"Action":"lambda:InvokeFunction","FunctionName":{"SOMOD::Ref":{"resource":"OnMessageFunction"}},"Principal":"apigateway.amazonaws.com","SourceArn":{"Fn::Sub":["arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiId}/$default/$default",{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]}}},"NotifyMessageFunction":{"Type":"AWS::Serverless::Function","SOMOD::Access":"public","Properties":{"CodeUri":{"SOMOD::Function":{"type":"SNS","name":"wsNotifyMessage"}},"Environment":{"Variables":{"CONNECTIONS_TABLE_NAME":{"SOMOD::Ref":{"resource":"ConnectionsTable"}},"CONNECTIONS_ENDPOINT":{"Fn::Sub":["https://${WebSocketApi}.execute-api.${AWS::Region}.amazonaws.com/${Stage}",{"WebSocketApi":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"Stage":{"SOMOD::Ref":{"resource":"Stage"}}}]}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"Fn::Sub":["${ConnectionsTableArn}/index/ByUserId",{"ConnectionsTableArn":{"SOMOD::Ref":{"resource":"ConnectionsTable","attribute":"Arn"}}}]}],"Action":["dynamodb:Query"]}]},{"Statement":[{"Effect":"Allow","Action":["execute-api:ManageConnections"],"Resource":[{"Fn::Sub":["arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*",{"WebSocketApi":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]}]}]}],"Events":{"NotifyFromSNS":{"Type":"SNS","Properties":{"Topic":{"SOMOD::Ref":{"resource":"MessageNotificationTopic"}}}}},"Timeout":300}}},"Outputs":{"chat.http-api.id":{"Fn::Sub":["https://${apiId}.execute-api.${AWS::Region}.amazonaws.com/",{"apiId":{"SOMOD::Ref":{"resource":"ChatApi"}}}]},"chat.websocket-api.id":{"SOMOD::If":[{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},{"Fn::Sub":["wss://${apiId}.execute-api.${AWS::Region}.amazonaws.com/$default",{"apiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]},null]}}}
1
+ {"Resources":{"ChatApi":{"Type":"AWS::Serverless::HttpApi","SOMOD::Access":"public","SOMOD::Output":{"default":true},"Properties":{}},"ThreadTable":{"Type":"AWS::DynamoDB::Table","SOMOD::Access":"public","SOMOD::Output":{"default":true,"attributes":["Arn"]},"Properties":{"TableName":{"SOMOD::ResourceName":"Thread"},"BillingMode":"PAY_PER_REQUEST","PointInTimeRecoverySpecification":{"PointInTimeRecoveryEnabled":{"SOMOD::Parameter":"dynamodb.pitr.enable"}},"KeySchema":[{"AttributeName":"id","KeyType":"HASH"}],"AttributeDefinitions":[{"AttributeName":"id","AttributeType":"S"}]}},"MessageBox":{"Type":"AWS::DynamoDB::Table","SOMOD::Access":"public","SOMOD::Output":{"default":true,"attributes":["Arn","StreamArn"]},"Properties":{"TableName":{"SOMOD::ResourceName":"MessageBox"},"BillingMode":"PAY_PER_REQUEST","PointInTimeRecoverySpecification":{"PointInTimeRecoveryEnabled":{"SOMOD::Parameter":"dynamodb.pitr.enable"}},"KeySchema":[{"AttributeName":"userId","KeyType":"HASH"},{"AttributeName":"seqNo","KeyType":"RANGE"}],"AttributeDefinitions":[{"AttributeName":"userId","AttributeType":"S"},{"AttributeName":"seqNo","AttributeType":"N"}],"StreamSpecification":{"StreamViewType":"NEW_IMAGE"}}},"MessageStreamHandlerDLQ":{"Type":"AWS::SQS::Queue","SOMOD::Output":{"default":true,"attributes":["Arn","QueueName","QueueUrl"]},"Properties":{"QueueName":{"SOMOD::ResourceName":"MessageStreamHandlerDLQ"}}},"MessageStreamHandler":{"Type":"AWS::Serverless::Function","SOMOD::Access":"public","Properties":{"FunctionName":{"SOMOD::ResourceName":"MsgStrmHandler"},"CodeUri":{"SOMOD::Function":{"name":"messageStreamHandler","type":"DynamoDB"}},"Environment":{"Variables":{"MESSAGE_BOX_TABLE_NAME":{"SOMOD::Ref":{"resource":"MessageBox"}},"THREAD_TABLE_NAME":{"SOMOD::Ref":{"resource":"ThreadTable"}},"MSG_NOTIFICATION_TOPIC":{"SOMOD::Ref":{"resource":"MessageNotificationTopic"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageBox","attribute":"Arn"}}],"Action":["dynamodb:PutItem"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ThreadTable","attribute":"Arn"}}],"Action":["dynamodb:GetItem"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageNotificationTopic"}}],"Action":["sns:Publish"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageStreamHandlerDLQ","attribute":"Arn"}}],"Action":["sqs:SendMessage"]}]}],"Events":{"Stream":{"Type":"DynamoDB","Properties":{"Stream":{"SOMOD::Ref":{"resource":"MessageBox","attribute":"StreamArn"}},"BatchSize":1,"MaximumRetryAttempts":3,"StartingPosition":"LATEST","DestinationConfig":{"OnFailure":{"Destination":{"SOMOD::Ref":{"resource":"MessageStreamHandlerDLQ","attribute":"Arn"}}}}}}}}},"UserProviderMiddleware":{"Type":"SOMOD::Serverless::FunctionMiddleware","SOMOD::Access":"public","SOMOD::Output":{"default":true},"Properties":{"CodeUri":{"SOMOD::FunctionMiddleware":{"name":"userProvider"}}}},"Message":{"Type":"AWS::Serverless::Function","SOMOD::Access":"public","Properties":{"FunctionName":{"SOMOD::ResourceName":"MessageApi"},"CodeUri":{"SOMOD::Function":{"name":"message","type":"HttpApi","middlewares":[{"module":"somod-http-extension","resource":"SomodHttpMiddleware"},{"resource":"UserProviderMiddleware"}]}},"Environment":{"Variables":{"MESSAGE_BOX_TABLE_NAME":{"SOMOD::Ref":{"resource":"MessageBox"}},"THREAD_TABLE_NAME":{"SOMOD::Ref":{"resource":"ThreadTable"}},"SESSION_SECRET":{"SOMOD::Parameter":"chat.session.jwt.secret"},"SESSION_FORCE":{"SOMOD::Parameter":"chat.session.force"},"MAP_OF_TYPE_ACTION":{"SOMOD::JsonStringify":{"SOMOD::Parameter":"chat.typeToAllowedActionsMap"}},"MAP_OF_TYPE_ACTION_SESSION":{"SOMOD::JsonStringify":{"SOMOD::Parameter":"chat.sessionRequirementMap"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageBox","attribute":"Arn"}}],"Action":["dynamodb:PutItem","dynamodb:Query"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ThreadTable","attribute":"Arn"}}],"Action":["dynamodb:GetItem"]}]}],"Events":{"PostMessage":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"POST","Path":"/post-message"}},"SyncMessages":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"GET","Path":"/sync-messages"}}}}},"Thread":{"Type":"AWS::Serverless::Function","SOMOD::Access":"public","Properties":{"FunctionName":{"SOMOD::ResourceName":"ThreadApi"},"CodeUri":{"SOMOD::Function":{"name":"thread","type":"HttpApi","middlewares":[{"module":"somod-http-extension","resource":"SomodHttpMiddleware"},{"resource":"UserProviderMiddleware"}]}},"Environment":{"Variables":{"THREAD_TABLE_NAME":{"SOMOD::Ref":{"resource":"ThreadTable"}},"MESSAGE_BOX_TABLE_NAME":{"SOMOD::Ref":{"resource":"MessageBox"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ThreadTable","attribute":"Arn"}}],"Action":["dynamodb:PutItem","dynamodb:GetItem","dynamodb:UpdateItem"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageBox","attribute":"Arn"}}],"Action":["dynamodb:PutItem"]}]}],"Events":{"CreateThread":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"POST","Path":"/thread"}},"GetThread":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"GET","Path":"/thread/{id}"}},"UpdateSessionRequireInThread":{"Type":"HttpApi","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"ChatApi"}},"Method":"POST","Path":"/thread/{id}/session"}}}}},"MessageNotificationTopic":{"Type":"AWS::SNS::Topic","SOMOD::Access":"public","SOMOD::Output":{"default":true,"attributes":["TopicName"]},"Properties":{"TopicName":{"SOMOD::ResourceName":"MsgNotificationTopic"}}},"WebSocketApi":{"Type":"AWS::ApiGatewayV2::Api","SOMOD::Access":"public","Properties":{"Name":{"SOMOD::ResourceName":"ChatWebsocketApi"},"ProtocolType":"WEBSOCKET","RouteSelectionExpression":"$request.body.action"}},"ConnectRoute":{"Type":"AWS::ApiGatewayV2::Route","SOMOD::Access":"public","Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"RouteKey":"$connect","OperationName":"ConnectRoute","Target":{"Fn::Join":["/",["integrations",{"SOMOD::Ref":{"resource":"ConnectInteg"}}]]}}},"ConnectInteg":{"Type":"AWS::ApiGatewayV2::Integration","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"Description":"Connect Integration","IntegrationType":"AWS_PROXY","IntegrationUri":{"Fn::Sub":["arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OnConnectFunctionArn}/invocations",{"OnConnectFunctionArn":{"SOMOD::Ref":{"resource":"OnConnectFunction","attribute":"Arn"}}}]}}},"DisconnectRoute":{"Type":"AWS::ApiGatewayV2::Route","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"RouteKey":"$disconnect","OperationName":"DisconnectRoute","Target":{"Fn::Join":["/",["integrations",{"SOMOD::Ref":{"resource":"DisconnectInteg"}}]]}}},"DisconnectInteg":{"Type":"AWS::ApiGatewayV2::Integration","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"Description":"Disconnect Integration","IntegrationType":"AWS_PROXY","IntegrationUri":{"Fn::Sub":["arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OnDisconnectFunctionArn}/invocations",{"OnDisconnectFunctionArn":{"SOMOD::Ref":{"resource":"OnDisconnectFunction","attribute":"Arn"}}}]}}},"DefaultRoute":{"Type":"AWS::ApiGatewayV2::Route","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"default":true},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"RouteKey":"$default","OperationName":"DefaultRoute","Target":{"Fn::Join":["/",["integrations",{"SOMOD::Ref":{"resource":"DefaultInteg"}}]]}}},"DefaultRouteResponse":{"Type":"AWS::ApiGatewayV2::RouteResponse","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"default":true},"Properties":{"RouteId":{"SOMOD::Ref":{"resource":"DefaultRoute"}},"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"RouteResponseKey":"$default"}},"DefaultInteg":{"Type":"AWS::ApiGatewayV2::Integration","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"default":true},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"Description":"Default Integration","IntegrationType":"AWS_PROXY","IntegrationUri":{"Fn::Sub":["arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OnMessageFunctionArn}/invocations",{"OnMessageFunctionArn":{"SOMOD::Ref":{"resource":"OnMessageFunction","attribute":"Arn"}}}]}}},"DefaultIntegResponse":{"Type":"AWS::ApiGatewayV2::IntegrationResponse","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"IntegrationId":{"SOMOD::Ref":{"resource":"DefaultInteg"}},"IntegrationResponseKey":"$default"}},"Stage":{"Type":"AWS::ApiGatewayV2::Stage","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"StageName":"$default","ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"AutoDeploy":true}},"ConnectionsTable":{"Type":"AWS::DynamoDB::Table","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"default":true,"attributes":["Arn"]},"Properties":{"BillingMode":"PAY_PER_REQUEST","PointInTimeRecoverySpecification":{"PointInTimeRecoveryEnabled":{"SOMOD::Parameter":"dynamodb.pitr.enable"}},"AttributeDefinitions":[{"AttributeName":"id","AttributeType":"S"},{"AttributeName":"userId","AttributeType":"S"}],"KeySchema":[{"AttributeName":"id","KeyType":"HASH"}],"GlobalSecondaryIndexes":[{"IndexName":"ByUserId","KeySchema":[{"AttributeName":"userId","KeyType":"HASH"}],"Projection":{"ProjectionType":"KEYS_ONLY"}}]}},"OnConnectFunction":{"Type":"AWS::Serverless::Function","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"attributes":["Arn"]},"Properties":{"CodeUri":{"SOMOD::Function":{"type":"WebSocket","name":"wsOnConnect","middlewares":[{"resource":"UserProviderMiddleware"}]}},"Environment":{"Variables":{"CONNECTIONS_TABLE_NAME":{"SOMOD::Ref":{"resource":"ConnectionsTable"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ConnectionsTable","attribute":"Arn"}}],"Action":["dynamodb:PutItem"]}]}]}},"OnConnectPermission":{"Type":"AWS::Lambda::Permission","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"Action":"lambda:InvokeFunction","FunctionName":{"SOMOD::Ref":{"resource":"OnConnectFunction"}},"Principal":"apigateway.amazonaws.com","SourceArn":{"Fn::Sub":["arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiId}/$default/$connect",{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]}}},"OnDisconnectFunction":{"Type":"AWS::Serverless::Function","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"attributes":["Arn"]},"Properties":{"CodeUri":{"SOMOD::Function":{"type":"WebSocket","name":"wsOnDisconnect"}},"Environment":{"Variables":{"CONNECTIONS_TABLE_NAME":{"SOMOD::Ref":{"resource":"ConnectionsTable"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ConnectionsTable","attribute":"Arn"}}],"Action":["dynamodb:DeleteItem"]}]}]}},"OnDisconnectPermission":{"Type":"AWS::Lambda::Permission","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"Action":"lambda:InvokeFunction","FunctionName":{"SOMOD::Ref":{"resource":"OnDisconnectFunction"}},"Principal":"apigateway.amazonaws.com","SourceArn":{"Fn::Sub":["arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiId}/$default/$disconnect",{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]}}},"OnMessageFunction":{"Type":"AWS::Serverless::Function","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"SOMOD::Output":{"attributes":["Arn"]},"Properties":{"CodeUri":{"SOMOD::Function":{"type":"WebSocket","name":"wsOnMessage","middlewares":[{"module":"somod-websocket-extension","resource":"SomodWebSocketMiddleware"},{"resource":"UserProviderMiddleware"}]}},"Environment":{"Variables":{"MESSAGE_BOX_TABLE_NAME":{"SOMOD::Ref":{"resource":"MessageBox"}},"THREAD_TABLE_NAME":{"SOMOD::Ref":{"resource":"ThreadTable"}},"SESSION_SECRET":{"SOMOD::Parameter":"chat.session.jwt.secret"},"SESSION_FORCE":{"SOMOD::Parameter":"chat.session.force"},"MAP_OF_TYPE_ACTION":{"SOMOD::JsonStringify":{"SOMOD::Parameter":"chat.typeToAllowedActionsMap"}},"MAP_OF_TYPE_ACTION_SESSION":{"SOMOD::JsonStringify":{"SOMOD::Parameter":"chat.sessionRequirementMap"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"MessageBox","attribute":"Arn"}}],"Action":["dynamodb:PutItem"]},{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ThreadTable","attribute":"Arn"}}],"Action":["dynamodb:GetItem"]}]}]}},"OnMessagePermission":{"Type":"AWS::Lambda::Permission","SOMOD::CreateIf":{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},"Properties":{"Action":"lambda:InvokeFunction","FunctionName":{"SOMOD::Ref":{"resource":"OnMessageFunction"}},"Principal":"apigateway.amazonaws.com","SourceArn":{"Fn::Sub":["arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiId}/$default/$default",{"ApiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]}}},"NotifyMessageFunction":{"Type":"AWS::Serverless::Function","SOMOD::Access":"public","Properties":{"CodeUri":{"SOMOD::Function":{"type":"SNS","name":"wsNotifyMessage"}},"Environment":{"Variables":{"CONNECTIONS_TABLE_NAME":{"SOMOD::Ref":{"resource":"ConnectionsTable"}},"CONNECTIONS_ENDPOINT":{"Fn::Sub":["https://${WebSocketApi}.execute-api.${AWS::Region}.amazonaws.com/${Stage}",{"WebSocketApi":{"SOMOD::Ref":{"resource":"WebSocketApi"}},"Stage":{"SOMOD::Ref":{"resource":"Stage"}}}]}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"Fn::Sub":["${ConnectionsTableArn}/index/ByUserId",{"ConnectionsTableArn":{"SOMOD::Ref":{"resource":"ConnectionsTable","attribute":"Arn"}}}]}],"Action":["dynamodb:Query"]}]},{"Statement":[{"Effect":"Allow","Action":["execute-api:ManageConnections"],"Resource":[{"Fn::Sub":["arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*",{"WebSocketApi":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]}]}]}],"Events":{"NotifyFromSNS":{"Type":"SNS","Properties":{"Topic":{"SOMOD::Ref":{"resource":"MessageNotificationTopic"}}}}},"Timeout":300}}},"Outputs":{"chat.http-api.id":{"Fn::Sub":["https://${apiId}.execute-api.${AWS::Region}.amazonaws.com/",{"apiId":{"SOMOD::Ref":{"resource":"ChatApi"}}}]},"chat.websocket-api.id":{"SOMOD::If":[{"SOMOD::Equals":[{"SOMOD::Parameter":"chat.enable.websocket"},true]},{"Fn::Sub":["wss://${apiId}.execute-api.${AWS::Region}.amazonaws.com/$default",{"apiId":{"SOMOD::Ref":{"resource":"WebSocketApi"}}}]},null]}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "somod-chat-service",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "Serverless Chat Service from SOMOD",
5
5
  "scripts": {
6
6
  "prettier": "npx prettier --check --ignore-unknown --no-error-on-unmatched-pattern ./**/*",