somod-chat-service 0.4.3 → 0.5.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.
- package/build/lib/getUserIdFromEvent.d.ts +2 -0
- package/build/lib/getUserIdFromEvent.js +5 -0
- package/build/lib/message.js +1 -1
- package/build/lib/sessionUtil.d.ts +1 -1
- package/build/lib/sessionUtil.js +46 -31
- package/build/lib/threadCache.d.ts +1 -1
- package/build/lib/threadCache.js +2 -2
- package/build/lib/types.d.ts +5 -2
- package/build/lib/types.js +7 -1
- package/build/serverless/functions/message.js +9 -6
- package/build/serverless/functions/middlewares/userProvider.js +1 -1
- package/build/serverless/functions/thread.http.json +1 -1
- package/build/serverless/functions/thread.js +57 -5
- package/build/serverless/functions/wsOnMessage.js +8 -6
- package/build/serverless/template.json +1 -1
- package/package.json +1 -1
package/build/lib/message.js
CHANGED
|
@@ -52,7 +52,7 @@ export var validateIncomingMessage = function (message, userId) { return __await
|
|
|
52
52
|
if (errorMessage) {
|
|
53
53
|
return [2 /*return*/, {
|
|
54
54
|
statusCode: 400,
|
|
55
|
-
headers: { "Content-Type": "application/json" },
|
|
55
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
56
56
|
body: JSON.stringify({
|
|
57
57
|
message: errorMessage
|
|
58
58
|
})
|
|
@@ -6,5 +6,5 @@ export declare const Error: {
|
|
|
6
6
|
required: string;
|
|
7
7
|
invalid: string;
|
|
8
8
|
};
|
|
9
|
-
export declare const handleSessionToken: (userId: string, sessionToken?: string) => SessionIdResult
|
|
9
|
+
export declare const handleSessionToken: (userId: string, threadId: string, sessionToken?: string) => Promise<SessionIdResult>;
|
|
10
10
|
export {};
|
package/build/lib/sessionUtil.js
CHANGED
|
@@ -1,44 +1,59 @@
|
|
|
1
1
|
var _a, _b;
|
|
2
|
+
import { __awaiter, __generator } from "tslib";
|
|
2
3
|
import { verify } from "jsonwebtoken";
|
|
4
|
+
import { threadCache } from "./threadCache";
|
|
3
5
|
var sessionJwtSecret = (_a = process.env.SESSION_SECRET) !== null && _a !== void 0 ? _a : "";
|
|
4
6
|
var sessionForce = (_b = process.env.SESSION_FORCE) !== null && _b !== void 0 ? _b : "";
|
|
5
7
|
export var Error = {
|
|
6
8
|
required: "missing required field: sessionToken",
|
|
7
9
|
invalid: "invalid field: sessionToken"
|
|
8
10
|
};
|
|
9
|
-
export var handleSessionToken = function (userId, sessionToken) {
|
|
10
|
-
var result
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
export var handleSessionToken = function (userId, threadId, sessionToken) { return __awaiter(void 0, void 0, void 0, function () {
|
|
12
|
+
var result, thread, session, now;
|
|
13
|
+
var _a;
|
|
14
|
+
return __generator(this, function (_b) {
|
|
15
|
+
switch (_b.label) {
|
|
16
|
+
case 0:
|
|
17
|
+
result = { sessionId: "" };
|
|
18
|
+
if (!sessionJwtSecret) return [3 /*break*/, 5];
|
|
19
|
+
if (!!sessionToken) return [3 /*break*/, 4];
|
|
20
|
+
if (!(sessionForce == "true")) return [3 /*break*/, 1];
|
|
14
21
|
result.error = Error.required;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
return [3 /*break*/, 3];
|
|
23
|
+
case 1: return [4 /*yield*/, threadCache.get(threadId, 5000)];
|
|
24
|
+
case 2:
|
|
25
|
+
thread = _b.sent();
|
|
26
|
+
if ((_a = thread === null || thread === void 0 ? void 0 : thread.sessionRequired) === null || _a === void 0 ? void 0 : _a.includes(userId)) {
|
|
27
|
+
result.error = Error.required;
|
|
28
|
+
}
|
|
29
|
+
_b.label = 3;
|
|
30
|
+
case 3: return [3 /*break*/, 5];
|
|
31
|
+
case 4:
|
|
32
|
+
try {
|
|
33
|
+
session = verify(sessionToken, sessionJwtSecret + "", {
|
|
34
|
+
algorithms: ["HS512"],
|
|
35
|
+
ignoreExpiration: true
|
|
36
|
+
});
|
|
37
|
+
now = Date.now();
|
|
38
|
+
if (session.participants.includes(userId) &&
|
|
39
|
+
session.startTime <= now &&
|
|
40
|
+
now <= session.endTime) {
|
|
41
|
+
result.sessionId = session.id;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
result.error = Error.invalid;
|
|
45
|
+
}
|
|
28
46
|
}
|
|
29
|
-
|
|
47
|
+
catch (err) {
|
|
48
|
+
// eslint-disable-next-line no-console
|
|
49
|
+
console.error("session token verification failed. userId=" +
|
|
50
|
+
userId +
|
|
51
|
+
", error=" +
|
|
52
|
+
err);
|
|
30
53
|
result.error = Error.invalid;
|
|
31
54
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// eslint-disable-next-line no-console
|
|
35
|
-
console.error("session token verification failed. userId=" +
|
|
36
|
-
userId +
|
|
37
|
-
", error=" +
|
|
38
|
-
err);
|
|
39
|
-
result.error = Error.invalid;
|
|
40
|
-
}
|
|
55
|
+
_b.label = 5;
|
|
56
|
+
case 5: return [2 /*return*/, result];
|
|
41
57
|
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
};
|
|
58
|
+
});
|
|
59
|
+
}); };
|
package/build/lib/threadCache.js
CHANGED
|
@@ -5,7 +5,7 @@ import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
|
|
|
5
5
|
var dynamodb = new DynamoDBClient();
|
|
6
6
|
var _threadCache = cache(100, 60 * 60000);
|
|
7
7
|
export var threadCache = {
|
|
8
|
-
get: function (threadId) { return __awaiter(void 0, void 0, void 0, function () {
|
|
8
|
+
get: function (threadId, ttl) { return __awaiter(void 0, void 0, void 0, function () {
|
|
9
9
|
return __generator(this, function (_a) {
|
|
10
10
|
switch (_a.label) {
|
|
11
11
|
case 0: return [4 /*yield*/, _threadCache.get(threadId, function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -23,7 +23,7 @@ export var threadCache = {
|
|
|
23
23
|
: undefined];
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
|
-
}); })];
|
|
26
|
+
}); }, ttl)];
|
|
27
27
|
case 1: return [2 /*return*/, _a.sent()];
|
|
28
28
|
}
|
|
29
29
|
});
|
package/build/lib/types.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export type ThreadInput = {
|
|
2
2
|
participants: string[];
|
|
3
3
|
};
|
|
4
|
+
export type ThreadSessionRequired = {
|
|
5
|
+
sessionRequired?: string[];
|
|
6
|
+
};
|
|
4
7
|
export type Thread = {
|
|
5
8
|
id: string;
|
|
6
|
-
} & ThreadInput;
|
|
9
|
+
} & ThreadInput & ThreadSessionRequired;
|
|
7
10
|
export type MessageInput = {
|
|
8
11
|
threadId: string;
|
|
9
12
|
type: "text" | "image" | "control";
|
|
10
|
-
action: "new" | "edit" | "delete" | "sessionStart" | "sessionExtend" | "sessionEnd";
|
|
13
|
+
action: "new" | "edit" | "delete" | "sessionStart" | "sessionExtend" | "sessionEnd" | "sessionRequirementChange";
|
|
11
14
|
message: string;
|
|
12
15
|
sessionToken?: string;
|
|
13
16
|
};
|
package/build/lib/types.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export var typeToAllowedActionsMap = {
|
|
2
2
|
text: ["new", "edit"],
|
|
3
3
|
image: ["new", "edit"],
|
|
4
|
-
control: [
|
|
4
|
+
control: [
|
|
5
|
+
"delete",
|
|
6
|
+
"sessionStart",
|
|
7
|
+
"sessionExtend",
|
|
8
|
+
"sessionEnd",
|
|
9
|
+
"sessionRequirementChange"
|
|
10
|
+
]
|
|
5
11
|
};
|
|
@@ -6,6 +6,7 @@ import { v1 as v1uuid } from "uuid";
|
|
|
6
6
|
import { QueryCommand, DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
7
7
|
import { convertToAttr, unmarshall } from "@aws-sdk/util-dynamodb";
|
|
8
8
|
import { handleSessionToken } from "../../lib/sessionUtil";
|
|
9
|
+
import { getUserIdFromEvent } from "../../lib/getUserIdFromEvent";
|
|
9
10
|
var dynamodb = new DynamoDBClient();
|
|
10
11
|
var builder = new RouteBuilder();
|
|
11
12
|
var postMessageHandler = function (request, event) { return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -20,11 +21,13 @@ var postMessageHandler = function (request, event) { return __awaiter(void 0, vo
|
|
|
20
21
|
if (messageValidationError) {
|
|
21
22
|
return [2 /*return*/, messageValidationError];
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
+
return [4 /*yield*/, handleSessionToken(userId, request.body.threadId, request.body.sessionToken)];
|
|
25
|
+
case 2:
|
|
26
|
+
sessionIdResult = _b.sent();
|
|
24
27
|
if (sessionIdResult.error) {
|
|
25
28
|
return [2 /*return*/, {
|
|
26
29
|
statusCode: 400,
|
|
27
|
-
headers: { "Content-Type": "application/json" },
|
|
30
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
28
31
|
body: JSON.stringify({
|
|
29
32
|
message: sessionIdResult.error
|
|
30
33
|
})
|
|
@@ -35,11 +38,11 @@ var postMessageHandler = function (request, event) { return __awaiter(void 0, vo
|
|
|
35
38
|
return [4 /*yield*/, putMessage(process.env.MESSAGE_BOX_TABLE_NAME + "", userId, __assign(__assign(__assign({}, msg), { sessionId: sessionIdResult.sessionId, id: v1uuid().split("-").join(""), from: userId, sentAt: Date.now() }), (actions.includes(request.body.action)
|
|
36
39
|
? { sessionToken: sessionToken }
|
|
37
40
|
: {})))];
|
|
38
|
-
case
|
|
41
|
+
case 3:
|
|
39
42
|
message = _b.sent();
|
|
40
43
|
return [2 /*return*/, {
|
|
41
44
|
statusCode: 200,
|
|
42
|
-
headers: { "Content-Type": "application/json" },
|
|
45
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
43
46
|
body: JSON.stringify({
|
|
44
47
|
id: message.id,
|
|
45
48
|
seqNo: message.seqNo,
|
|
@@ -55,7 +58,7 @@ var syncMessagesHandler = function (request, event) { return __awaiter(void 0, v
|
|
|
55
58
|
return __generator(this, function (_a) {
|
|
56
59
|
switch (_a.label) {
|
|
57
60
|
case 0:
|
|
58
|
-
userId = event
|
|
61
|
+
userId = getUserIdFromEvent(event);
|
|
59
62
|
queryCommandInput = {
|
|
60
63
|
TableName: process.env.MESSAGE_BOX_TABLE_NAME + "",
|
|
61
64
|
KeyConditionExpression: "#userId = :userId",
|
|
@@ -85,7 +88,7 @@ var syncMessagesHandler = function (request, event) { return __awaiter(void 0, v
|
|
|
85
88
|
return [2 /*return*/, {
|
|
86
89
|
statusCode: 200,
|
|
87
90
|
headers: {
|
|
88
|
-
"Content-Type": "application/json"
|
|
91
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
89
92
|
},
|
|
90
93
|
body: JSON.stringify(messages)
|
|
91
94
|
}];
|
|
@@ -24,7 +24,7 @@ var userProviderMiddleware = function (next, event) { return __awaiter(void 0, v
|
|
|
24
24
|
if (key === undefined) {
|
|
25
25
|
return [2 /*return*/, {
|
|
26
26
|
statusCode: 400,
|
|
27
|
-
headers: { "Content-Type": "application/json" },
|
|
27
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
28
28
|
body: JSON.stringify({
|
|
29
29
|
message: "Expected ".concat(UserProviderMiddlewareKey, " in the request headers or message body")
|
|
30
30
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"/thread":{"POST":{"body":{"parser":"json","schema":{"type":"object","additionalProperties":false,"required":["participants"],"properties":{"participants":{"type":"array","items":{"type":"string","pattern":"^[a-zA-Z0-9-_]{1,50}$"},"minItems":2,"maxItems":2}}}}}},"/thread/{id}":{"GET":{"parameters":[{"name":"id","in":"path","schema":{"type":"string","pattern":"^[a-f0-9]{32}$"},"required":true}]}}}
|
|
1
|
+
{"/thread":{"POST":{"body":{"parser":"json","schema":{"type":"object","additionalProperties":false,"required":["participants"],"properties":{"participants":{"type":"array","items":{"type":"string","pattern":"^[a-zA-Z0-9-_]{1,50}$"},"minItems":2,"maxItems":2}}}}}},"/thread/{id}":{"GET":{"parameters":[{"name":"id","in":"path","schema":{"type":"string","pattern":"^[a-f0-9]{32}$"},"required":true}]}},"/thread/{id}/session":{"POST":{"parameters":[{"name":"id","in":"path","schema":{"type":"string","pattern":"^[a-f0-9]{32}$"},"required":true}],"body":{"parser":"json","schema":{"type":"object","required":["sessionRequired"],"properties":{"sessionRequired":{"type":"array","items":{"type":"string","pattern":"^[a-zA-Z0-9-_]{1,50}$"},"minItems":2,"maxItems":2}}}}}}}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { __assign, __awaiter, __generator } from "tslib";
|
|
2
2
|
import { RouteBuilder } from "somod-http-extension";
|
|
3
|
-
import { DynamoDBClient, GetItemCommand, PutItemCommand } from "@aws-sdk/client-dynamodb";
|
|
4
|
-
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
|
|
5
|
-
import { v1 as v1uuid } from "uuid";
|
|
3
|
+
import { DynamoDBClient, GetItemCommand, PutItemCommand, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
|
|
4
|
+
import { convertToAttr, marshall, unmarshall } from "@aws-sdk/util-dynamodb";
|
|
5
|
+
import { v1, v1 as v1uuid } from "uuid";
|
|
6
|
+
import { putMessage } from "../../lib/message";
|
|
7
|
+
import { getUserIdFromEvent } from "../../lib/getUserIdFromEvent";
|
|
6
8
|
var builder = new RouteBuilder();
|
|
7
9
|
var dynamodb = new DynamoDBClient();
|
|
8
10
|
var createThread = function (request) { return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -24,7 +26,7 @@ var createThread = function (request) { return __awaiter(void 0, void 0, void 0,
|
|
|
24
26
|
_a.sent();
|
|
25
27
|
return [2 /*return*/, {
|
|
26
28
|
statusCode: 200,
|
|
27
|
-
headers: { "Content-Type": "application/json" },
|
|
29
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
28
30
|
body: JSON.stringify(thread)
|
|
29
31
|
}];
|
|
30
32
|
}
|
|
@@ -45,13 +47,63 @@ var getThread = function (request) { return __awaiter(void 0, void 0, void 0, fu
|
|
|
45
47
|
return [2 /*return*/, result.Item
|
|
46
48
|
? {
|
|
47
49
|
statusCode: 200,
|
|
48
|
-
headers: { "Content-Type": "application/json" },
|
|
50
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
49
51
|
body: JSON.stringify(unmarshall(result.Item))
|
|
50
52
|
}
|
|
51
53
|
: { statusCode: 404 }];
|
|
52
54
|
}
|
|
53
55
|
});
|
|
54
56
|
}); };
|
|
57
|
+
var updateSessionRequired = function (request, event) { return __awaiter(void 0, void 0, void 0, function () {
|
|
58
|
+
var userId, updateItemCommand, e_1;
|
|
59
|
+
var _a;
|
|
60
|
+
return __generator(this, function (_b) {
|
|
61
|
+
switch (_b.label) {
|
|
62
|
+
case 0:
|
|
63
|
+
userId = getUserIdFromEvent(event);
|
|
64
|
+
updateItemCommand = new UpdateItemCommand({
|
|
65
|
+
TableName: process.env.THREAD_TABLE_NAME + "",
|
|
66
|
+
Key: marshall({ id: request.parameters.path.id }),
|
|
67
|
+
UpdateExpression: "SET #sessionRequired = :sessionRequired",
|
|
68
|
+
ExpressionAttributeNames: {
|
|
69
|
+
"#sessionRequired": "sessionRequired"
|
|
70
|
+
},
|
|
71
|
+
ExpressionAttributeValues: {
|
|
72
|
+
":sessionRequired": convertToAttr(request.body.sessionRequired)
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return [4 /*yield*/, dynamodb.send(updateItemCommand)];
|
|
76
|
+
case 1:
|
|
77
|
+
_b.sent();
|
|
78
|
+
_b.label = 2;
|
|
79
|
+
case 2:
|
|
80
|
+
_b.trys.push([2, 4, , 5]);
|
|
81
|
+
return [4 /*yield*/, putMessage((_a = process.env.MESSAGE_BOX_TABLE_NAME) !== null && _a !== void 0 ? _a : "", userId, {
|
|
82
|
+
id: v1().split("-").join(""),
|
|
83
|
+
type: "control",
|
|
84
|
+
action: "sessionRequirementChange",
|
|
85
|
+
from: userId,
|
|
86
|
+
message: JSON.stringify(request.body.sessionRequired),
|
|
87
|
+
sentAt: Date.now(),
|
|
88
|
+
threadId: request.parameters.path.id
|
|
89
|
+
})];
|
|
90
|
+
case 3:
|
|
91
|
+
_b.sent();
|
|
92
|
+
return [3 /*break*/, 5];
|
|
93
|
+
case 4:
|
|
94
|
+
e_1 = _b.sent();
|
|
95
|
+
// eslint-disable-next-line no-console
|
|
96
|
+
console.error(e_1);
|
|
97
|
+
return [3 /*break*/, 5];
|
|
98
|
+
case 5: return [2 /*return*/, {
|
|
99
|
+
statusCode: 200,
|
|
100
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
101
|
+
body: JSON.stringify({ message: "Thread updated successfully" })
|
|
102
|
+
}];
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}); };
|
|
55
106
|
builder.add("/thread", "POST", createThread);
|
|
56
107
|
builder.add("/thread/{id}", "GET", getThread);
|
|
108
|
+
builder.add("/thread/{id}/session", "POST", updateSessionRequired);
|
|
57
109
|
export default builder.getHandler();
|
|
@@ -2,26 +2,28 @@ import { __assign, __awaiter, __generator, __rest } from "tslib";
|
|
|
2
2
|
import { RouteBuilder } from "somod-websocket-extension";
|
|
3
3
|
import { putMessage, validateIncomingMessage } from "../../lib/message";
|
|
4
4
|
import { v1 as v1uuid } from "uuid";
|
|
5
|
-
import { UserProviderMiddlewareKey } from "../../lib";
|
|
6
5
|
import { handleSessionToken } from "../../lib/sessionUtil";
|
|
6
|
+
import { getUserIdFromEvent } from "../../lib/getUserIdFromEvent";
|
|
7
7
|
var builder = new RouteBuilder();
|
|
8
8
|
builder.add("$default", function (message, event) { return __awaiter(void 0, void 0, void 0, function () {
|
|
9
9
|
var userId, messageValidationError, sessionIdResult, _a, wsMsgId, sessionToken, msg, actions, messageResult;
|
|
10
10
|
return __generator(this, function (_b) {
|
|
11
11
|
switch (_b.label) {
|
|
12
12
|
case 0:
|
|
13
|
-
userId = event
|
|
13
|
+
userId = getUserIdFromEvent(event);
|
|
14
14
|
return [4 /*yield*/, validateIncomingMessage(message.body, userId)];
|
|
15
15
|
case 1:
|
|
16
16
|
messageValidationError = _b.sent();
|
|
17
17
|
if (messageValidationError) {
|
|
18
18
|
return [2 /*return*/, messageValidationError];
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
return [4 /*yield*/, handleSessionToken(userId, message.body.threadId, message.body.sessionToken)];
|
|
21
|
+
case 2:
|
|
22
|
+
sessionIdResult = _b.sent();
|
|
21
23
|
if (sessionIdResult.error) {
|
|
22
24
|
return [2 /*return*/, {
|
|
23
25
|
statusCode: 400,
|
|
24
|
-
headers: { "Content-Type": "application/json" },
|
|
26
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
25
27
|
body: JSON.stringify({
|
|
26
28
|
message: sessionIdResult.error
|
|
27
29
|
})
|
|
@@ -32,11 +34,11 @@ builder.add("$default", function (message, event) { return __awaiter(void 0, voi
|
|
|
32
34
|
return [4 /*yield*/, putMessage(process.env.MESSAGE_BOX_TABLE_NAME + "", userId, __assign(__assign(__assign({}, msg), { sessionId: sessionIdResult.sessionId, from: userId, id: v1uuid().split("-").join(""), sentAt: Date.now() }), (actions.includes(message.body.action)
|
|
33
35
|
? { sessionToken: sessionToken }
|
|
34
36
|
: {})))];
|
|
35
|
-
case
|
|
37
|
+
case 3:
|
|
36
38
|
messageResult = _b.sent();
|
|
37
39
|
return [2 /*return*/, {
|
|
38
40
|
statusCode: 200,
|
|
39
|
-
headers: { "Content-Type": "application/json" },
|
|
41
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
40
42
|
body: JSON.stringify({
|
|
41
43
|
wsMsgId: wsMsgId,
|
|
42
44
|
type: "ack",
|
|
@@ -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"}}}},"CommonLibsLayer":{"Type":"AWS::Serverless::LayerVersion","SOMOD::Output":{"default":true},"Properties":{"RetentionPolicy":"Delete","ContentUri":{"SOMOD::FunctionLayer":{"name":"commonlibs","libraries":["decorated-ajv"]}}}},"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"}]}},"Layers":[{"SOMOD::Ref":{"resource":"CommonLibsLayer"}}],"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"}]}},"Layers":[{"SOMOD::Ref":{"resource":"CommonLibsLayer"}}],"Environment":{"Variables":{"THREAD_TABLE_NAME":{"SOMOD::Ref":{"resource":"ThreadTable"}}}},"Policies":[{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":[{"SOMOD::Ref":{"resource":"ThreadTable","attribute":"Arn"}}],"Action":["dynamodb:PutItem","dynamodb:GetItem"]}]}],"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}"}}}}},"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"}]}},"Layers":[{"SOMOD::Ref":{"resource":"CommonLibsLayer"}}],"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"}}}},"CommonLibsLayer":{"Type":"AWS::Serverless::LayerVersion","SOMOD::Output":{"default":true},"Properties":{"RetentionPolicy":"Delete","ContentUri":{"SOMOD::FunctionLayer":{"name":"commonlibs","libraries":["decorated-ajv"]}}}},"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"}]}},"Layers":[{"SOMOD::Ref":{"resource":"CommonLibsLayer"}}],"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"}]}},"Layers":[{"SOMOD::Ref":{"resource":"CommonLibsLayer"}}],"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"]},{"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"}]}},"Layers":[{"SOMOD::Ref":{"resource":"CommonLibsLayer"}}],"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]}}}
|
package/package.json
CHANGED