@pikku/lambda 0.7.0 → 0.9.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/CHANGELOG.md +13 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/queue/index.d.ts +1 -0
- package/dist/queue/index.js +2 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/sqs-worker.d.ts +4 -0
- package/dist/queue/sqs-worker.js +59 -0
- package/dist/queue/sqs-worker.js.map +1 -0
- package/dist/websocket/lambda-eventhub-service.d.ts +5 -5
- package/dist/websocket/lambda-eventhub-service.js +4 -2
- package/dist/websocket/lambda-eventhub-service.js.map +1 -1
- package/dist/websocket/utils.d.ts +1 -1
- package/package.json +4 -3
- package/src/http/index.ts +1 -0
- package/src/http/run-fetch.ts +51 -0
- package/src/index.ts +3 -0
- package/src/queue/index.ts +1 -0
- package/src/queue/sqs-worker.ts +97 -0
- package/src/request-converter.ts +24 -0
- package/src/response-converter.ts +33 -0
- package/src/websocket/index.ts +4 -0
- package/src/websocket/lambda-channel-handler.ts +53 -0
- package/src/websocket/lambda-eventhub-service.ts +69 -0
- package/src/websocket/utils.ts +95 -0
- package/src/websocket/websocket-connect.ts +43 -0
- package/src/websocket/websocket-disconnect.ts +35 -0
- package/src/websocket/websocket-message.ts +49 -0
- package/src/websocket/websocket-types.ts +21 -0
- package/tsconfig.json +17 -0
- package/tsconfig.tsbuildinfo +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## 0.8.0
|
|
2
|
+
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Breaking Changes
|
|
6
|
+
|
|
7
|
+
- Normalized all transports to use "wirings" instead of events/routes/transports for consistency across the framework
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Major Features
|
|
11
|
+
|
|
12
|
+
- **SQS Queue Support**: Added SQS queue worker support
|
|
13
|
+
|
|
1
14
|
## 0.7.0
|
|
2
15
|
|
|
3
16
|
- Updating to match remaining packages
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { runSQSQueueWorker } from './sqs-worker.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/queue/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { SQSBatchResponse, SQSEvent, SQSRecord } from 'aws-lambda';
|
|
2
|
+
import type { CoreSingletonServices, CreateSessionServices, QueueJob } from '@pikku/core';
|
|
3
|
+
export declare function mapSQSRecordToQueueJob(record: SQSRecord, maxAttempts?: number): QueueJob;
|
|
4
|
+
export declare const runSQSQueueWorker: (singletonServices: CoreSingletonServices, createSessionServices: CreateSessionServices<any, any, any> | undefined, event: SQSEvent) => Promise<SQSBatchResponse>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { runQueueJob } from '@pikku/core/queue';
|
|
2
|
+
export function mapSQSRecordToQueueJob(record, maxAttempts) {
|
|
3
|
+
let data;
|
|
4
|
+
try {
|
|
5
|
+
data = JSON.parse(record.body);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
data = record.body;
|
|
9
|
+
}
|
|
10
|
+
if (!record.eventSourceARN) {
|
|
11
|
+
throw new Error('SQS record does not have eventSourceARN');
|
|
12
|
+
}
|
|
13
|
+
const queueName = record.eventSourceARN.split(':').pop();
|
|
14
|
+
const job = {
|
|
15
|
+
queueName,
|
|
16
|
+
data,
|
|
17
|
+
id: record.messageId,
|
|
18
|
+
status: async () => 'active',
|
|
19
|
+
metadata: () => ({
|
|
20
|
+
processedAt: new Date(),
|
|
21
|
+
attemptsMade: parseInt(record.attributes.ApproximateReceiveCount) - 1,
|
|
22
|
+
maxAttempts,
|
|
23
|
+
result: undefined,
|
|
24
|
+
progress: 0,
|
|
25
|
+
createdAt: new Date(parseInt(record.attributes.SentTimestamp)),
|
|
26
|
+
completedAt: undefined,
|
|
27
|
+
failedAt: undefined,
|
|
28
|
+
error: undefined,
|
|
29
|
+
}),
|
|
30
|
+
waitForCompletion: async () => {
|
|
31
|
+
throw new Error('SQS does not support waitForCompletion - jobs are fire-and-forget');
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
return job;
|
|
35
|
+
}
|
|
36
|
+
export const runSQSQueueWorker = async (singletonServices, createSessionServices, event) => {
|
|
37
|
+
console.log(JSON.stringify(event, null, 2));
|
|
38
|
+
const jobs = event.Records.map(mapSQSRecordToQueueJob);
|
|
39
|
+
const results = await Promise.allSettled(jobs.map((job) => runQueueJob({
|
|
40
|
+
singletonServices,
|
|
41
|
+
createSessionServices,
|
|
42
|
+
job,
|
|
43
|
+
})));
|
|
44
|
+
results.forEach((result, index) => {
|
|
45
|
+
if (result.status === 'rejected') {
|
|
46
|
+
singletonServices.logger.error(`Failed to process SQS message ${jobs[index].id}:`, result.reason);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
batchItemFailures: results
|
|
51
|
+
.map((result, index) => ({
|
|
52
|
+
result,
|
|
53
|
+
itemIdentifier: jobs[index].id || `message-${index}`,
|
|
54
|
+
}))
|
|
55
|
+
.filter(({ result }) => result.status === 'rejected')
|
|
56
|
+
.map(({ itemIdentifier }) => ({ itemIdentifier })),
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=sqs-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqs-worker.js","sourceRoot":"","sources":["../../src/queue/sqs-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { ChannelStore, EventHubService, EventHubStore } from '@pikku/core/channel';
|
|
2
2
|
import { Logger } from '@pikku/core/services';
|
|
3
3
|
import { APIGatewayEvent } from 'aws-lambda';
|
|
4
|
-
export declare class LambdaEventHubService<
|
|
4
|
+
export declare class LambdaEventHubService<EventTopics extends Record<string, any> = {}> implements EventHubService<EventTopics> {
|
|
5
5
|
private logger;
|
|
6
6
|
private channelStore;
|
|
7
7
|
private eventHubStore;
|
|
8
8
|
private callbackAPI;
|
|
9
|
-
constructor(logger: Logger, event: APIGatewayEvent, channelStore: ChannelStore, eventHubStore: EventHubStore);
|
|
10
|
-
subscribe(topic:
|
|
11
|
-
unsubscribe(topic:
|
|
12
|
-
publish(topic:
|
|
9
|
+
constructor(logger: Logger, event: APIGatewayEvent, channelStore: ChannelStore, eventHubStore: EventHubStore<EventTopics>);
|
|
10
|
+
subscribe<T extends keyof EventTopics>(topic: T, channelId: string): Promise<void>;
|
|
11
|
+
unsubscribe<T extends keyof EventTopics>(topic: T, channelId: string): Promise<void>;
|
|
12
|
+
publish<T extends keyof EventTopics>(topic: T, channelId: string | null, data: EventTopics[T], isBinary?: boolean): Promise<void>;
|
|
13
13
|
private sendMessages;
|
|
14
14
|
}
|
|
@@ -16,9 +16,11 @@ export class LambdaEventHubService {
|
|
|
16
16
|
async unsubscribe(topic, channelId) {
|
|
17
17
|
await this.eventHubStore.unsubscribe(topic, channelId);
|
|
18
18
|
}
|
|
19
|
-
async publish(topic,
|
|
19
|
+
async publish(topic, channelId, data, isBinary) {
|
|
20
20
|
const channelIds = await this.eventHubStore.getChannelIdsForTopic(topic);
|
|
21
|
-
|
|
21
|
+
if (channelId) {
|
|
22
|
+
await this.sendMessages(channelIds, channelId, data, isBinary);
|
|
23
|
+
}
|
|
22
24
|
}
|
|
23
25
|
async sendMessages(channelIds, fromChannelId, data, isBinary) {
|
|
24
26
|
await sendMessages(this.logger, this.channelStore, this.callbackAPI, fromChannelId, channelIds, data, isBinary);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lambda-eventhub-service.js","sourceRoot":"","sources":["../../src/websocket/lambda-eventhub-service.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,gCAAgC,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAI3E,MAAM,OAAO,qBAAqB;IAMtB;IAEA;IACA;IANF,WAAW,CAA+B;IAElD,YACU,MAAc,EACtB,KAAsB,EACd,YAA0B,EAC1B,
|
|
1
|
+
{"version":3,"file":"lambda-eventhub-service.js","sourceRoot":"","sources":["../../src/websocket/lambda-eventhub-service.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,gCAAgC,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAI3E,MAAM,OAAO,qBAAqB;IAMtB;IAEA;IACA;IANF,WAAW,CAA+B;IAElD,YACU,MAAc,EACtB,KAAsB,EACd,YAA0B,EAC1B,aAAyC;QAHzC,WAAM,GAAN,MAAM,CAAQ;QAEd,iBAAY,GAAZ,YAAY,CAAc;QAC1B,kBAAa,GAAb,aAAa,CAA4B;QAEjD,IAAI,CAAC,WAAW,GAAG,gCAAgC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IACpE,CAAC;IAED,KAAK,CAAC,SAAS,CACb,KAAQ,EACR,SAAiB;QAEjB,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IACtD,CAAC;IAED,KAAK,CAAC,WAAW,CACf,KAAQ,EACR,SAAiB;QAEjB,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IACxD,CAAC;IAED,KAAK,CAAC,OAAO,CACX,KAAQ,EACR,SAAwB,EACxB,IAAoB,EACpB,QAAkB;QAElB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAC/D,KAAe,CAChB,CAAA;QACD,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;QAChE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,YAAY,CACxB,UAAoB,EACpB,aAAqB,EACrB,IAAoC,EACpC,QAAkB;QAElB,MAAM,YAAY,CAChB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,WAAW,EAChB,aAAa,EACb,UAAU,EACV,IAAI,EACJ,QAAQ,CACT,CAAA;IACH,CAAC;CACF"}
|
|
@@ -9,5 +9,5 @@ export declare const getServerlessDependencies: (logger: Logger, channelStore: C
|
|
|
9
9
|
channelId: string;
|
|
10
10
|
callbackAPI: ApiGatewayManagementApiClient;
|
|
11
11
|
channelHandlerFactory: import("@pikku/core/channel").PikkuChannelHandlerFactory;
|
|
12
|
-
channelStore: ChannelStore<unknown, unknown, import("@pikku/core/
|
|
12
|
+
channelStore: ChannelStore<unknown, unknown, import("@pikku/core/src/index.js").CoreUserSession, import("@pikku/core/channel").Channel<unknown, unknown>>;
|
|
13
13
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/lambda",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "yasser.fadl@gmail.com",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -19,11 +19,12 @@
|
|
|
19
19
|
"exports": {
|
|
20
20
|
".": "./dist/index.js",
|
|
21
21
|
"./http": "./dist/http/index.js",
|
|
22
|
-
"./websocket": "./dist/websocket/index.js"
|
|
22
|
+
"./websocket": "./dist/websocket/index.js",
|
|
23
|
+
"./queue": "./dist/queue/index.js"
|
|
23
24
|
},
|
|
24
25
|
"peerDependencies": {
|
|
25
26
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.713.0",
|
|
26
|
-
"@pikku/core": "^0.
|
|
27
|
+
"@pikku/core": "^0.9.0",
|
|
27
28
|
"@types/aws-lambda": "^8.10.146"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './run-fetch.js'
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CoreSingletonServices,
|
|
3
|
+
CoreServices,
|
|
4
|
+
CreateSessionServices,
|
|
5
|
+
CoreUserSession,
|
|
6
|
+
} from '@pikku/core'
|
|
7
|
+
import { PikkuFetchHTTPResponse, fetchData } from '@pikku/core/http'
|
|
8
|
+
import { APIGatewayEvent, APIGatewayProxyResult } from 'aws-lambda'
|
|
9
|
+
import { responseToLambdaResult } from '../response-converter.js'
|
|
10
|
+
import { lambdaEventToRequest } from '../request-converter.js'
|
|
11
|
+
|
|
12
|
+
export const runFetch = async <
|
|
13
|
+
SingletonServices extends CoreSingletonServices,
|
|
14
|
+
Services extends CoreServices<SingletonServices>,
|
|
15
|
+
UserSession extends CoreUserSession,
|
|
16
|
+
>(
|
|
17
|
+
singletonServices: SingletonServices,
|
|
18
|
+
createSessionServices: CreateSessionServices<
|
|
19
|
+
SingletonServices,
|
|
20
|
+
Services,
|
|
21
|
+
UserSession
|
|
22
|
+
>,
|
|
23
|
+
event: APIGatewayEvent
|
|
24
|
+
): Promise<APIGatewayProxyResult> => {
|
|
25
|
+
const request = lambdaEventToRequest(event)
|
|
26
|
+
const response = new PikkuFetchHTTPResponse()
|
|
27
|
+
|
|
28
|
+
if (request.method === 'options') {
|
|
29
|
+
response.header(
|
|
30
|
+
'Access-Control-Allow-Headers',
|
|
31
|
+
'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'
|
|
32
|
+
)
|
|
33
|
+
response.header(
|
|
34
|
+
'Access-Control-Allow-Methods',
|
|
35
|
+
'OPTIONS,DELETE,GET,HEAD,PATCH,POST,PUT'
|
|
36
|
+
)
|
|
37
|
+
response.status(200)
|
|
38
|
+
return responseToLambdaResult(response.toResponse())
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
await fetchData(request, response, {
|
|
43
|
+
singletonServices,
|
|
44
|
+
createSessionServices: createSessionServices as any,
|
|
45
|
+
})
|
|
46
|
+
} catch {
|
|
47
|
+
// Error should have already been handled by fetch
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return responseToLambdaResult(response.toResponse())
|
|
51
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { runSQSQueueWorker } from './sqs-worker.js'
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { SQSBatchResponse, SQSEvent, SQSRecord } from 'aws-lambda'
|
|
2
|
+
import { runQueueJob } from '@pikku/core/queue'
|
|
3
|
+
import type {
|
|
4
|
+
CoreSingletonServices,
|
|
5
|
+
CreateSessionServices,
|
|
6
|
+
QueueJob,
|
|
7
|
+
QueueJobStatus,
|
|
8
|
+
} from '@pikku/core'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Enhanced version with additional SQS-specific features
|
|
12
|
+
*/
|
|
13
|
+
export function mapSQSRecordToQueueJob(
|
|
14
|
+
record: SQSRecord,
|
|
15
|
+
maxAttempts?: number
|
|
16
|
+
): QueueJob {
|
|
17
|
+
let data: any
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
data = JSON.parse(record.body)
|
|
21
|
+
} catch {
|
|
22
|
+
data = record.body
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!record.eventSourceARN) {
|
|
26
|
+
throw new Error('SQS record does not have eventSourceARN')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const queueName = record.eventSourceARN.split(':').pop()!
|
|
30
|
+
|
|
31
|
+
const job: QueueJob = {
|
|
32
|
+
queueName,
|
|
33
|
+
data,
|
|
34
|
+
id: record.messageId,
|
|
35
|
+
status: async () => 'active' as QueueJobStatus,
|
|
36
|
+
metadata: () => ({
|
|
37
|
+
processedAt: new Date(),
|
|
38
|
+
attemptsMade: parseInt(record.attributes.ApproximateReceiveCount) - 1,
|
|
39
|
+
maxAttempts,
|
|
40
|
+
result: undefined,
|
|
41
|
+
progress: 0,
|
|
42
|
+
createdAt: new Date(parseInt(record.attributes.SentTimestamp)),
|
|
43
|
+
completedAt: undefined,
|
|
44
|
+
failedAt: undefined,
|
|
45
|
+
error: undefined,
|
|
46
|
+
}),
|
|
47
|
+
waitForCompletion: async () => {
|
|
48
|
+
throw new Error(
|
|
49
|
+
'SQS does not support waitForCompletion - jobs are fire-and-forget'
|
|
50
|
+
)
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
return job
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create an SQS handler that processes queue jobs using Pikku
|
|
58
|
+
*/
|
|
59
|
+
export const runSQSQueueWorker = async (
|
|
60
|
+
singletonServices: CoreSingletonServices,
|
|
61
|
+
createSessionServices: CreateSessionServices<any, any, any> | undefined,
|
|
62
|
+
event: SQSEvent
|
|
63
|
+
): Promise<SQSBatchResponse> => {
|
|
64
|
+
console.log(JSON.stringify(event, null, 2))
|
|
65
|
+
const jobs = event.Records.map(mapSQSRecordToQueueJob)
|
|
66
|
+
|
|
67
|
+
// Process all jobs in parallel
|
|
68
|
+
const results = await Promise.allSettled(
|
|
69
|
+
jobs.map((job) =>
|
|
70
|
+
runQueueJob({
|
|
71
|
+
singletonServices,
|
|
72
|
+
createSessionServices,
|
|
73
|
+
job,
|
|
74
|
+
})
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
// Log any failures but don't throw (SQS will handle retries)
|
|
79
|
+
results.forEach((result, index) => {
|
|
80
|
+
if (result.status === 'rejected') {
|
|
81
|
+
singletonServices.logger.error(
|
|
82
|
+
`Failed to process SQS message ${jobs[index]!.id}:`,
|
|
83
|
+
result.reason
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
batchItemFailures: results
|
|
90
|
+
.map((result, index) => ({
|
|
91
|
+
result,
|
|
92
|
+
itemIdentifier: jobs[index]!.id || `message-${index}`,
|
|
93
|
+
}))
|
|
94
|
+
.filter(({ result }) => result.status === 'rejected')
|
|
95
|
+
.map(({ itemIdentifier }) => ({ itemIdentifier })),
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { APIGatewayProxyEvent } from 'aws-lambda'
|
|
2
|
+
|
|
3
|
+
export const lambdaEventToRequest = (event: APIGatewayProxyEvent): Request => {
|
|
4
|
+
const url = new URL(event.path, `https://${event.headers.host}`)
|
|
5
|
+
|
|
6
|
+
if (event.queryStringParameters) {
|
|
7
|
+
for (const [key, value] of Object.entries(event.queryStringParameters)) {
|
|
8
|
+
if (value !== undefined) url.searchParams.set(key, value)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const body =
|
|
13
|
+
event.body && event.isBase64Encoded
|
|
14
|
+
? Buffer.from(event.body, 'base64')
|
|
15
|
+
: event.body || undefined
|
|
16
|
+
|
|
17
|
+
return new Request(url.toString(), {
|
|
18
|
+
method: event.httpMethod,
|
|
19
|
+
headers: event.headers as HeadersInit,
|
|
20
|
+
body: ['GET', 'HEAD'].includes(event.httpMethod.toUpperCase())
|
|
21
|
+
? undefined
|
|
22
|
+
: body,
|
|
23
|
+
})
|
|
24
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { APIGatewayProxyResult } from 'aws-lambda'
|
|
2
|
+
|
|
3
|
+
export const responseToLambdaResult = async (
|
|
4
|
+
response: Response
|
|
5
|
+
): Promise<APIGatewayProxyResult> => {
|
|
6
|
+
const headers: Record<string, string> = {}
|
|
7
|
+
response.headers.forEach((value, key) => {
|
|
8
|
+
headers[key.toLowerCase()] = value
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
let body: string
|
|
12
|
+
let isBase64Encoded = false
|
|
13
|
+
|
|
14
|
+
const contentType = response.headers.get('content-type') || ''
|
|
15
|
+
const isBinary = !/^text\/|application\/(json|javascript|xml)/.test(
|
|
16
|
+
contentType
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
const buffer = Buffer.from(await response.arrayBuffer())
|
|
20
|
+
if (isBinary) {
|
|
21
|
+
body = buffer.toString('base64')
|
|
22
|
+
isBase64Encoded = true
|
|
23
|
+
} else {
|
|
24
|
+
body = buffer.toString('utf-8')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
statusCode: response.status,
|
|
29
|
+
headers,
|
|
30
|
+
body,
|
|
31
|
+
isBase64Encoded,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { CoreUserSession } from '@pikku/core'
|
|
2
|
+
import {
|
|
3
|
+
ChannelStore,
|
|
4
|
+
PikkuAbstractChannelHandler,
|
|
5
|
+
PikkuChannelHandlerFactory,
|
|
6
|
+
} from '@pikku/core/channel'
|
|
7
|
+
import { sendMessage } from './utils.js'
|
|
8
|
+
import { ApiGatewayManagementApiClient } from '@aws-sdk/client-apigatewaymanagementapi'
|
|
9
|
+
import { Logger } from '@pikku/core/services'
|
|
10
|
+
|
|
11
|
+
class LambdaChannelHandler<
|
|
12
|
+
UserSession extends CoreUserSession = CoreUserSession,
|
|
13
|
+
OpeningData = unknown,
|
|
14
|
+
Out = unknown,
|
|
15
|
+
> extends PikkuAbstractChannelHandler<OpeningData, Out> {
|
|
16
|
+
constructor(
|
|
17
|
+
private logger: Logger,
|
|
18
|
+
private callbackAPI: ApiGatewayManagementApiClient,
|
|
19
|
+
channelId: string,
|
|
20
|
+
channelName: string,
|
|
21
|
+
openingData: OpeningData
|
|
22
|
+
) {
|
|
23
|
+
super(channelId, channelName, openingData)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public async send(message: Out, isBinary?: boolean) {
|
|
27
|
+
if (isBinary) {
|
|
28
|
+
throw new Error('Binary data is not supported on serverless lambdas')
|
|
29
|
+
}
|
|
30
|
+
const data = JSON.stringify(message)
|
|
31
|
+
await sendMessage(this.logger, this.callbackAPI, this.channelId, data)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const createLambdaChannelHandlerFactory = (
|
|
36
|
+
logger: Logger,
|
|
37
|
+
channelStore: ChannelStore,
|
|
38
|
+
callbackAPI: ApiGatewayManagementApiClient
|
|
39
|
+
) => {
|
|
40
|
+
const factory: PikkuChannelHandlerFactory = (
|
|
41
|
+
channelId,
|
|
42
|
+
channelName,
|
|
43
|
+
openingData
|
|
44
|
+
) =>
|
|
45
|
+
new LambdaChannelHandler(
|
|
46
|
+
logger,
|
|
47
|
+
callbackAPI,
|
|
48
|
+
channelId,
|
|
49
|
+
channelName,
|
|
50
|
+
openingData
|
|
51
|
+
)
|
|
52
|
+
return factory
|
|
53
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ApiGatewayManagementApiClient } from '@aws-sdk/client-apigatewaymanagementapi'
|
|
2
|
+
import {
|
|
3
|
+
ChannelStore,
|
|
4
|
+
EventHubService,
|
|
5
|
+
EventHubStore,
|
|
6
|
+
} from '@pikku/core/channel'
|
|
7
|
+
import { getApiGatewayManagementApiClient, sendMessages } from './utils.js'
|
|
8
|
+
import { Logger } from '@pikku/core/services'
|
|
9
|
+
import { APIGatewayEvent } from 'aws-lambda'
|
|
10
|
+
|
|
11
|
+
export class LambdaEventHubService<EventTopics extends Record<string, any> = {}>
|
|
12
|
+
implements EventHubService<EventTopics>
|
|
13
|
+
{
|
|
14
|
+
private callbackAPI: ApiGatewayManagementApiClient
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
private logger: Logger,
|
|
18
|
+
event: APIGatewayEvent,
|
|
19
|
+
private channelStore: ChannelStore,
|
|
20
|
+
private eventHubStore: EventHubStore<EventTopics>
|
|
21
|
+
) {
|
|
22
|
+
this.callbackAPI = getApiGatewayManagementApiClient(logger, event)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async subscribe<T extends keyof EventTopics>(
|
|
26
|
+
topic: T,
|
|
27
|
+
channelId: string
|
|
28
|
+
): Promise<void> {
|
|
29
|
+
await this.eventHubStore.subscribe(topic, channelId)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async unsubscribe<T extends keyof EventTopics>(
|
|
33
|
+
topic: T,
|
|
34
|
+
channelId: string
|
|
35
|
+
): Promise<void> {
|
|
36
|
+
await this.eventHubStore.unsubscribe(topic, channelId)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async publish<T extends keyof EventTopics>(
|
|
40
|
+
topic: T,
|
|
41
|
+
channelId: string | null,
|
|
42
|
+
data: EventTopics[T],
|
|
43
|
+
isBinary?: boolean
|
|
44
|
+
): Promise<void> {
|
|
45
|
+
const channelIds = await this.eventHubStore.getChannelIdsForTopic(
|
|
46
|
+
topic as string
|
|
47
|
+
)
|
|
48
|
+
if (channelId) {
|
|
49
|
+
await this.sendMessages(channelIds, channelId, data, isBinary)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private async sendMessages(
|
|
54
|
+
channelIds: string[],
|
|
55
|
+
fromChannelId: string,
|
|
56
|
+
data: EventTopics[keyof EventTopics],
|
|
57
|
+
isBinary?: boolean
|
|
58
|
+
): Promise<void> {
|
|
59
|
+
await sendMessages(
|
|
60
|
+
this.logger,
|
|
61
|
+
this.channelStore,
|
|
62
|
+
this.callbackAPI,
|
|
63
|
+
fromChannelId,
|
|
64
|
+
channelIds,
|
|
65
|
+
data,
|
|
66
|
+
isBinary
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApiGatewayManagementApiClient,
|
|
3
|
+
PostToConnectionCommand,
|
|
4
|
+
} from '@aws-sdk/client-apigatewaymanagementapi'
|
|
5
|
+
import { Logger } from '@pikku/core/services'
|
|
6
|
+
import { APIGatewayEvent } from 'aws-lambda'
|
|
7
|
+
import { createLambdaChannelHandlerFactory } from './lambda-channel-handler.js'
|
|
8
|
+
import { ChannelStore } from '@pikku/core/channel'
|
|
9
|
+
|
|
10
|
+
export const sendMessage = async (
|
|
11
|
+
logger: Logger,
|
|
12
|
+
callbackAPI: ApiGatewayManagementApiClient,
|
|
13
|
+
ConnectionId: string,
|
|
14
|
+
Data: string
|
|
15
|
+
): Promise<boolean> => {
|
|
16
|
+
try {
|
|
17
|
+
await callbackAPI.send(new PostToConnectionCommand({ ConnectionId, Data }))
|
|
18
|
+
return true
|
|
19
|
+
} catch (e: any) {
|
|
20
|
+
// TODO: We need to check if it's a 410 and remove the connection if it is
|
|
21
|
+
// Otherwise we need to log the error
|
|
22
|
+
logger.error(e.message)
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const sendMessages = async (
|
|
28
|
+
logger: Logger,
|
|
29
|
+
channelStore: ChannelStore,
|
|
30
|
+
callbackAPI: ApiGatewayManagementApiClient,
|
|
31
|
+
fromChannelId: string,
|
|
32
|
+
channelIds: string[],
|
|
33
|
+
data: unknown,
|
|
34
|
+
isBinary?: boolean
|
|
35
|
+
): Promise<void> => {
|
|
36
|
+
if (isBinary) {
|
|
37
|
+
throw new Error('Binary data is not supported on serverless lambdas')
|
|
38
|
+
}
|
|
39
|
+
const staleWebsockets: string[] = []
|
|
40
|
+
const Data = JSON.stringify(data)
|
|
41
|
+
await Promise.all(
|
|
42
|
+
channelIds.map(async (channelId) => {
|
|
43
|
+
if (channelId !== fromChannelId) {
|
|
44
|
+
const success = await sendMessage(logger, callbackAPI, channelId, Data)
|
|
45
|
+
if (!success) {
|
|
46
|
+
staleWebsockets.push(channelId)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
)
|
|
51
|
+
if (staleWebsockets.length > 0) {
|
|
52
|
+
await channelStore.removeChannels(staleWebsockets)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const getApiGatewayManagementApiClient = (
|
|
57
|
+
logger: Logger,
|
|
58
|
+
event: APIGatewayEvent
|
|
59
|
+
) => {
|
|
60
|
+
let endpoint: string
|
|
61
|
+
if (process.env.IS_OFFLINE) {
|
|
62
|
+
logger.info('Assuming serverless offline mode due to IS_OFFLINE')
|
|
63
|
+
endpoint = `http://localhost:3001`
|
|
64
|
+
} else if (event.requestContext.domainName?.includes('amazonaws.com')) {
|
|
65
|
+
logger.info(
|
|
66
|
+
'Assuming we are using the default endpoint mode due to amazonaws.com domain'
|
|
67
|
+
)
|
|
68
|
+
endpoint = `https://${event.requestContext.domainName}/${event.requestContext.stage}`
|
|
69
|
+
} else {
|
|
70
|
+
logger.info('Assuming we are using a custom domain mode')
|
|
71
|
+
endpoint = `https://${event.requestContext.domainName}`
|
|
72
|
+
}
|
|
73
|
+
return new ApiGatewayManagementApiClient({
|
|
74
|
+
apiVersion: '2018-11-29',
|
|
75
|
+
endpoint,
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const getServerlessDependencies = (
|
|
80
|
+
logger: Logger,
|
|
81
|
+
channelStore: ChannelStore,
|
|
82
|
+
event: APIGatewayEvent
|
|
83
|
+
) => {
|
|
84
|
+
const channelId = event.requestContext.connectionId
|
|
85
|
+
if (!channelId) {
|
|
86
|
+
throw new Error('No connectionId found in requestContext')
|
|
87
|
+
}
|
|
88
|
+
const callbackAPI = getApiGatewayManagementApiClient(logger, event)
|
|
89
|
+
const channelHandlerFactory = createLambdaChannelHandlerFactory(
|
|
90
|
+
logger,
|
|
91
|
+
channelStore,
|
|
92
|
+
callbackAPI
|
|
93
|
+
)
|
|
94
|
+
return { channelId, callbackAPI, channelHandlerFactory, channelStore }
|
|
95
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CoreSingletonServices,
|
|
3
|
+
CoreServices,
|
|
4
|
+
CoreUserSession,
|
|
5
|
+
PikkuFetchHTTPRequest,
|
|
6
|
+
PikkuFetchHTTPResponse,
|
|
7
|
+
} from '@pikku/core'
|
|
8
|
+
import { APIGatewayEvent, APIGatewayProxyResult } from 'aws-lambda'
|
|
9
|
+
import { responseToLambdaResult } from '../response-converter.js'
|
|
10
|
+
import { runChannelConnect } from '@pikku/core/channel/serverless'
|
|
11
|
+
import { getServerlessDependencies } from './utils.js'
|
|
12
|
+
import { WebsocketParams } from './websocket-types.js'
|
|
13
|
+
import { lambdaEventToRequest } from '../request-converter.js'
|
|
14
|
+
|
|
15
|
+
export const connectWebsocket = async <
|
|
16
|
+
SingletonServices extends CoreSingletonServices,
|
|
17
|
+
Services extends CoreServices<SingletonServices>,
|
|
18
|
+
UserSession extends CoreUserSession,
|
|
19
|
+
>(
|
|
20
|
+
event: APIGatewayEvent,
|
|
21
|
+
{
|
|
22
|
+
singletonServices,
|
|
23
|
+
createSessionServices,
|
|
24
|
+
channelStore,
|
|
25
|
+
}: WebsocketParams<SingletonServices, Services, UserSession>
|
|
26
|
+
): Promise<APIGatewayProxyResult> => {
|
|
27
|
+
const runnerParams = getServerlessDependencies(
|
|
28
|
+
singletonServices.logger,
|
|
29
|
+
channelStore,
|
|
30
|
+
event
|
|
31
|
+
)
|
|
32
|
+
const request = new PikkuFetchHTTPRequest(lambdaEventToRequest(event))
|
|
33
|
+
const response = new PikkuFetchHTTPResponse()
|
|
34
|
+
await runChannelConnect({
|
|
35
|
+
...runnerParams,
|
|
36
|
+
request,
|
|
37
|
+
response,
|
|
38
|
+
singletonServices: singletonServices as any,
|
|
39
|
+
createSessionServices: createSessionServices as any,
|
|
40
|
+
route: event.path || '/',
|
|
41
|
+
})
|
|
42
|
+
return responseToLambdaResult(response.toResponse())
|
|
43
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CoreSingletonServices,
|
|
3
|
+
CoreServices,
|
|
4
|
+
CoreUserSession,
|
|
5
|
+
} from '@pikku/core'
|
|
6
|
+
import { runChannelDisconnect } from '@pikku/core/channel/serverless'
|
|
7
|
+
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'
|
|
8
|
+
|
|
9
|
+
import { getServerlessDependencies } from './utils.js'
|
|
10
|
+
import { WebsocketParams } from './websocket-types.js'
|
|
11
|
+
|
|
12
|
+
export const disconnectWebsocket = async <
|
|
13
|
+
SingletonServices extends CoreSingletonServices,
|
|
14
|
+
Services extends CoreServices<SingletonServices>,
|
|
15
|
+
UserSession extends CoreUserSession,
|
|
16
|
+
>(
|
|
17
|
+
event: APIGatewayProxyEvent,
|
|
18
|
+
{
|
|
19
|
+
singletonServices,
|
|
20
|
+
createSessionServices,
|
|
21
|
+
channelStore,
|
|
22
|
+
}: WebsocketParams<SingletonServices, Services, UserSession>
|
|
23
|
+
): Promise<APIGatewayProxyResult> => {
|
|
24
|
+
const runnerParams = getServerlessDependencies(
|
|
25
|
+
singletonServices.logger,
|
|
26
|
+
channelStore,
|
|
27
|
+
event
|
|
28
|
+
)
|
|
29
|
+
await runChannelDisconnect({
|
|
30
|
+
...runnerParams,
|
|
31
|
+
singletonServices: singletonServices as any,
|
|
32
|
+
createSessionServices: createSessionServices as any,
|
|
33
|
+
})
|
|
34
|
+
return { statusCode: 200, body: '' }
|
|
35
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CoreSingletonServices,
|
|
3
|
+
CoreServices,
|
|
4
|
+
CoreUserSession,
|
|
5
|
+
PikkuFetchHTTPResponse,
|
|
6
|
+
} from '@pikku/core'
|
|
7
|
+
import { runChannelMessage } from '@pikku/core/channel/serverless'
|
|
8
|
+
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'
|
|
9
|
+
import { getServerlessDependencies } from './utils.js'
|
|
10
|
+
import { WebsocketParams } from './websocket-types.js'
|
|
11
|
+
import { responseToLambdaResult } from '../response-converter.js'
|
|
12
|
+
|
|
13
|
+
export const processWebsocketMessage = async <
|
|
14
|
+
SingletonServices extends CoreSingletonServices,
|
|
15
|
+
Services extends CoreServices<SingletonServices>,
|
|
16
|
+
UserSession extends CoreUserSession,
|
|
17
|
+
>(
|
|
18
|
+
event: APIGatewayProxyEvent,
|
|
19
|
+
{
|
|
20
|
+
singletonServices,
|
|
21
|
+
createSessionServices,
|
|
22
|
+
channelStore,
|
|
23
|
+
}: WebsocketParams<SingletonServices, Services, UserSession>
|
|
24
|
+
): Promise<APIGatewayProxyResult> => {
|
|
25
|
+
const runnerParams = getServerlessDependencies(
|
|
26
|
+
singletonServices.logger,
|
|
27
|
+
channelStore,
|
|
28
|
+
event
|
|
29
|
+
)
|
|
30
|
+
const response = new PikkuFetchHTTPResponse()
|
|
31
|
+
try {
|
|
32
|
+
const result = await runChannelMessage(
|
|
33
|
+
{
|
|
34
|
+
...runnerParams,
|
|
35
|
+
singletonServices: singletonServices as any,
|
|
36
|
+
createSessionServices: createSessionServices as any,
|
|
37
|
+
},
|
|
38
|
+
event.body
|
|
39
|
+
)
|
|
40
|
+
if (result) {
|
|
41
|
+
// TODO: Support non json
|
|
42
|
+
response.json(result as any)
|
|
43
|
+
}
|
|
44
|
+
} catch (e) {
|
|
45
|
+
// Error should have already been handled by fetch
|
|
46
|
+
console.error(e)
|
|
47
|
+
}
|
|
48
|
+
return responseToLambdaResult(response.toResponse())
|
|
49
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CoreSingletonServices,
|
|
3
|
+
CoreServices,
|
|
4
|
+
CoreUserSession,
|
|
5
|
+
CreateSessionServices,
|
|
6
|
+
} from '@pikku/core'
|
|
7
|
+
import { ChannelStore } from '@pikku/core/channel'
|
|
8
|
+
|
|
9
|
+
export type WebsocketParams<
|
|
10
|
+
SingletonServices extends CoreSingletonServices,
|
|
11
|
+
Services extends CoreServices<SingletonServices>,
|
|
12
|
+
UserSession extends CoreUserSession,
|
|
13
|
+
> = {
|
|
14
|
+
channelStore: ChannelStore
|
|
15
|
+
singletonServices: SingletonServices
|
|
16
|
+
createSessionServices?: CreateSessionServices<
|
|
17
|
+
SingletonServices,
|
|
18
|
+
Services,
|
|
19
|
+
UserSession
|
|
20
|
+
>
|
|
21
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rootDir": "./src",
|
|
5
|
+
"module": "Node18",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"target": "esnext",
|
|
8
|
+
"declaration": true
|
|
9
|
+
},
|
|
10
|
+
"include": ["bin/**/*.ts", "src/**/*.ts"],
|
|
11
|
+
"exclude": ["**/*.test.ts", "node_modules", "bin/dist"],
|
|
12
|
+
"references": [
|
|
13
|
+
{
|
|
14
|
+
"path": "../../core/tsconfig.json"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/index.ts","./src/request-converter.ts","./src/response-converter.ts","./src/http/index.ts","./src/http/run-fetch.ts","./src/queue/index.ts","./src/queue/sqs-worker.ts","./src/websocket/index.ts","./src/websocket/lambda-channel-handler.ts","./src/websocket/lambda-eventhub-service.ts","./src/websocket/utils.ts","./src/websocket/websocket-connect.ts","./src/websocket/websocket-disconnect.ts","./src/websocket/websocket-message.ts","./src/websocket/websocket-types.ts"],"version":"5.8.3"}
|