@stacksjs/ts-cloud-core 0.1.6 → 0.1.7
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/dist/advanced-features.test.d.ts +0 -0
- package/dist/aws/cloudformation.d.ts +69 -0
- package/dist/aws/cloudfront.d.ts +21 -0
- package/dist/aws/credentials.d.ts +66 -0
- package/dist/aws/credentials.test.d.ts +0 -0
- package/dist/aws/index.d.ts +73 -0
- package/dist/aws/s3.d.ts +130 -0
- package/dist/aws/s3.test.d.ts +0 -0
- package/dist/aws/signature.d.ts +101 -0
- package/dist/aws/signature.test.d.ts +0 -0
- package/dist/backup/disaster-recovery.d.ts +98 -0
- package/dist/backup/disaster-recovery.test.d.ts +0 -0
- package/dist/backup/index.d.ts +24 -0
- package/dist/backup/manager.d.ts +112 -0
- package/dist/backup/manager.test.d.ts +0 -0
- package/dist/cicd/circleci.d.ts +47 -0
- package/dist/cicd/github-actions.d.ts +55 -0
- package/dist/cicd/gitlab-ci.d.ts +46 -0
- package/dist/cicd/index.d.ts +3 -0
- package/dist/cli/history.d.ts +66 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/progress.d.ts +97 -0
- package/dist/cli/repl.d.ts +76 -0
- package/dist/cli/suggestions.d.ts +67 -0
- package/dist/cli/table.d.ts +70 -0
- package/dist/cli/table.test.d.ts +0 -0
- package/dist/cloudformation/builder.d.ts +59 -0
- package/dist/cloudformation/builder.test.d.ts +0 -0
- package/dist/cloudformation/builders/api-gateway.d.ts +30 -0
- package/dist/cloudformation/builders/cache.d.ts +35 -0
- package/dist/cloudformation/builders/cdn.d.ts +34 -0
- package/dist/cloudformation/builders/compute.d.ts +66 -0
- package/dist/cloudformation/builders/database.d.ts +61 -0
- package/dist/cloudformation/builders/functions.d.ts +32 -0
- package/dist/cloudformation/builders/messaging.d.ts +17 -0
- package/dist/cloudformation/builders/monitoring.d.ts +36 -0
- package/dist/cloudformation/builders/network.d.ts +14 -0
- package/dist/cloudformation/builders/queue.d.ts +8 -0
- package/dist/cloudformation/builders/security.d.ts +31 -0
- package/dist/cloudformation/builders/storage.d.ts +8 -0
- package/dist/cloudformation/index.d.ts +24 -0
- package/dist/cloudformation/types.d.ts +132 -0
- package/dist/compliance/aws-config.d.ts +88 -0
- package/dist/compliance/cloudtrail.d.ts +96 -0
- package/dist/compliance/compliance.test.d.ts +0 -0
- package/dist/compliance/guardduty.d.ts +110 -0
- package/dist/compliance/index.d.ts +50 -0
- package/dist/compliance/security-hub.d.ts +110 -0
- package/dist/containers/build-optimization.d.ts +110 -0
- package/dist/containers/containers.test.d.ts +0 -0
- package/dist/containers/image-scanning.d.ts +96 -0
- package/dist/containers/index.d.ts +4 -0
- package/dist/containers/registry.d.ts +99 -0
- package/dist/containers/service-mesh.d.ts +206 -0
- package/dist/database/database.test.d.ts +0 -0
- package/dist/database/index.d.ts +4 -0
- package/dist/database/migrations.d.ts +102 -0
- package/dist/database/performance.d.ts +168 -0
- package/dist/database/replicas.d.ts +146 -0
- package/dist/database/users.d.ts +102 -0
- package/dist/dependency-graph.d.ts +19 -0
- package/dist/deployment/ab-testing.d.ts +114 -0
- package/dist/deployment/blue-green.d.ts +98 -0
- package/dist/deployment/canary.d.ts +103 -0
- package/dist/deployment/deployment.test.d.ts +0 -0
- package/dist/deployment/index.d.ts +45 -0
- package/dist/deployment/progressive.d.ts +34 -0
- package/dist/dns/dns.test.d.ts +0 -0
- package/dist/dns/dnssec.d.ts +75 -0
- package/dist/dns/index.d.ts +3 -0
- package/dist/dns/resolver.d.ts +150 -0
- package/dist/dns/routing.d.ts +217 -0
- package/dist/email/advanced/analytics.d.ts +78 -0
- package/dist/email/advanced/index.d.ts +7 -0
- package/dist/email/advanced/rules.d.ts +60 -0
- package/dist/email/advanced/scheduling.d.ts +63 -0
- package/dist/email/advanced/search.d.ts +76 -0
- package/dist/email/advanced/shared-mailboxes.d.ts +66 -0
- package/dist/email/advanced/templates.d.ts +39 -0
- package/dist/email/advanced/threading.d.ts +53 -0
- package/dist/email/analytics.d.ts +144 -0
- package/dist/email/bounce-handling.d.ts +120 -0
- package/dist/email/email.test.d.ts +0 -0
- package/dist/email/handlers/__tests__/inbound.test.d.ts +0 -0
- package/dist/email/handlers/__tests__/outbound.test.d.ts +0 -0
- package/dist/email/handlers/converter.d.ts +225 -0
- package/dist/email/handlers/feedback.d.ts +226 -0
- package/dist/email/handlers/inbound.d.ts +167 -0
- package/dist/email/handlers/outbound.d.ts +176 -0
- package/dist/email/index.d.ts +6 -0
- package/dist/email/reputation.d.ts +97 -0
- package/dist/email/templates.d.ts +82 -0
- package/dist/errors/index.d.ts +186 -0
- package/dist/errors/index.test.d.ts +0 -0
- package/dist/health-checks/index.d.ts +35 -0
- package/dist/index.d.ts +256 -0
- package/dist/index.js +63499 -0
- package/dist/intrinsic-functions.d.ts +37 -0
- package/dist/lambda/concurrency.d.ts +98 -0
- package/dist/lambda/destinations.d.ts +99 -0
- package/dist/lambda/dlq.d.ts +109 -0
- package/dist/lambda/index.d.ts +6 -0
- package/dist/lambda/lambda.test.d.ts +0 -0
- package/dist/lambda/layers.d.ts +81 -0
- package/dist/lambda/versions.d.ts +91 -0
- package/dist/lambda/vpc.d.ts +116 -0
- package/dist/local/config.d.ts +44 -0
- package/dist/local/index.d.ts +2 -0
- package/dist/local/mock-aws.d.ts +60 -0
- package/dist/modules/ai.d.ts +47 -0
- package/dist/modules/api.d.ts +98 -0
- package/dist/modules/auth.d.ts +165 -0
- package/dist/modules/cache.d.ts +73 -0
- package/dist/modules/cdn.d.ts +125 -0
- package/dist/modules/communication.d.ts +98 -0
- package/dist/modules/compute.d.ts +309 -0
- package/dist/modules/database.d.ts +105 -0
- package/dist/modules/deployment.d.ts +181 -0
- package/dist/modules/dns.d.ts +45 -0
- package/dist/modules/email.d.ts +217 -0
- package/dist/modules/filesystem.d.ts +94 -0
- package/dist/modules/index.d.ts +27 -0
- package/dist/modules/messaging.d.ts +108 -0
- package/dist/modules/monitoring.d.ts +127 -0
- package/dist/modules/network.d.ts +102 -0
- package/dist/modules/parameter-store.d.ts +33 -0
- package/dist/modules/permissions.d.ts +132 -0
- package/dist/modules/phone.d.ts +80 -0
- package/dist/modules/queue.d.ts +210 -0
- package/dist/modules/redirects.d.ts +59 -0
- package/dist/modules/registry.d.ts +73 -0
- package/dist/modules/search.d.ts +56 -0
- package/dist/modules/secrets.d.ts +80 -0
- package/dist/modules/security.d.ts +100 -0
- package/dist/modules/sms.d.ts +52 -0
- package/dist/modules/storage.d.ts +160 -0
- package/dist/modules/workflow.d.ts +205 -0
- package/dist/multi-account/config.d.ts +315 -0
- package/dist/multi-account/index.d.ts +2 -0
- package/dist/multi-account/manager.d.ts +100 -0
- package/dist/multi-region/cross-region.d.ts +114 -0
- package/dist/multi-region/index.d.ts +3 -0
- package/dist/multi-region/manager.d.ts +72 -0
- package/dist/multi-region/regions.d.ts +98 -0
- package/dist/network-security/index.d.ts +39 -0
- package/dist/observability/index.d.ts +4 -0
- package/dist/observability/logs.d.ts +129 -0
- package/dist/observability/metrics.d.ts +153 -0
- package/dist/observability/observability.test.d.ts +0 -0
- package/dist/observability/synthetics.d.ts +146 -0
- package/dist/observability/xray.d.ts +129 -0
- package/dist/phone/advanced/analytics.d.ts +66 -0
- package/dist/phone/advanced/callbacks.d.ts +50 -0
- package/dist/phone/advanced/index.d.ts +4 -0
- package/dist/phone/advanced/ivr-builder.d.ts +83 -0
- package/dist/phone/advanced/recording.d.ts +48 -0
- package/dist/phone/handlers/__tests__/incoming-call.test.d.ts +0 -0
- package/dist/phone/handlers/incoming-call.d.ts +115 -0
- package/dist/phone/handlers/missed-call.d.ts +114 -0
- package/dist/phone/handlers/voicemail.d.ts +177 -0
- package/dist/phone/index.d.ts +2 -0
- package/dist/presets/api-backend.d.ts +11 -0
- package/dist/presets/data-pipeline.d.ts +11 -0
- package/dist/presets/extend.d.ts +194 -0
- package/dist/presets/extend.test.d.ts +0 -0
- package/dist/presets/fullstack-app.d.ts +12 -0
- package/dist/presets/index.d.ts +24 -0
- package/dist/presets/jamstack.d.ts +12 -0
- package/dist/presets/microservices.d.ts +18 -0
- package/dist/presets/ml-api.d.ts +13 -0
- package/dist/presets/nodejs-server.d.ts +14 -0
- package/dist/presets/nodejs-serverless.d.ts +14 -0
- package/dist/presets/realtime-app.d.ts +11 -0
- package/dist/presets/static-site.d.ts +12 -0
- package/dist/presets/traditional-web-app.d.ts +16 -0
- package/dist/presets/wordpress.d.ts +12 -0
- package/dist/preview/github.d.ts +32 -0
- package/dist/preview/github.test.d.ts +0 -0
- package/dist/preview/index.d.ts +27 -0
- package/dist/preview/manager.d.ts +58 -0
- package/dist/preview/manager.test.d.ts +0 -0
- package/dist/preview/notifications.d.ts +55 -0
- package/dist/preview/notifications.test.d.ts +0 -0
- package/dist/queue/batch-processing.d.ts +87 -0
- package/dist/queue/dlq-monitoring.d.ts +95 -0
- package/dist/queue/fifo.d.ts +90 -0
- package/dist/queue/index.d.ts +4 -0
- package/dist/queue/management.d.ts +105 -0
- package/dist/queue/queue.test.d.ts +0 -0
- package/dist/resource-mgmt/index.d.ts +29 -0
- package/dist/resource-naming.d.ts +26 -0
- package/dist/s3/index.d.ts +173 -0
- package/dist/schema/index.d.ts +9 -0
- package/dist/security/certificate-manager.d.ts +121 -0
- package/dist/security/index.d.ts +4 -0
- package/dist/security/scanning.d.ts +147 -0
- package/dist/security/secrets-manager.d.ts +144 -0
- package/dist/security/secrets-rotation.d.ts +115 -0
- package/dist/security/security.test.d.ts +0 -0
- package/dist/sms/advanced/ab-testing.d.ts +54 -0
- package/dist/sms/advanced/analytics.d.ts +56 -0
- package/dist/sms/advanced/campaigns.d.ts +82 -0
- package/dist/sms/advanced/chatbot.d.ts +48 -0
- package/dist/sms/advanced/index.d.ts +6 -0
- package/dist/sms/advanced/link-tracking.d.ts +42 -0
- package/dist/sms/advanced/mms.d.ts +35 -0
- package/dist/sms/handlers/__tests__/send.test.d.ts +0 -0
- package/dist/sms/handlers/delivery-status.d.ts +131 -0
- package/dist/sms/handlers/receive.d.ts +160 -0
- package/dist/sms/handlers/send.d.ts +172 -0
- package/dist/sms/index.d.ts +2 -0
- package/dist/stack-diff.d.ts +34 -0
- package/dist/static-site/index.d.ts +49 -0
- package/dist/template-builder.d.ts +14 -0
- package/dist/template-validator.d.ts +24 -0
- package/dist/utils/cache.d.ts +55 -0
- package/dist/utils/diff.d.ts +48 -0
- package/dist/utils/hash.d.ts +58 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/parallel.d.ts +60 -0
- package/dist/validators/credentials.d.ts +23 -0
- package/dist/validators/credentials.test.d.ts +0 -0
- package/dist/validators/quotas.d.ts +60 -0
- package/dist/validators/quotas.test.d.ts +0 -0
- package/package.json +4 -4
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callback Requests and Queue Management
|
|
3
|
+
*
|
|
4
|
+
* Provides callback scheduling and queue management
|
|
5
|
+
*/
|
|
6
|
+
export declare interface CallbackRequest {
|
|
7
|
+
id: string
|
|
8
|
+
phoneNumber: string
|
|
9
|
+
customerName?: string
|
|
10
|
+
reason?: string
|
|
11
|
+
preferredTime?: string
|
|
12
|
+
queueId?: string
|
|
13
|
+
priority: number
|
|
14
|
+
status: 'pending' | 'scheduled' | 'in-progress' | 'completed' | 'failed' | 'cancelled'
|
|
15
|
+
attempts: number
|
|
16
|
+
maxAttempts: number
|
|
17
|
+
createdAt: string
|
|
18
|
+
scheduledFor?: string
|
|
19
|
+
completedAt?: string
|
|
20
|
+
notes?: string
|
|
21
|
+
}
|
|
22
|
+
export declare interface QueuePosition {
|
|
23
|
+
position: number
|
|
24
|
+
estimatedWaitTime: number
|
|
25
|
+
callersAhead: number
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Callback Module
|
|
29
|
+
*/
|
|
30
|
+
export declare class Callbacks {
|
|
31
|
+
static CallbackRequestCode: any;
|
|
32
|
+
static CallbackProcessorCode: any;
|
|
33
|
+
static createCallbacksTable(config: { slug: string }): Record<string, any>;
|
|
34
|
+
static createCallbackRequestLambda(config: {
|
|
35
|
+
slug: string
|
|
36
|
+
roleArn: string
|
|
37
|
+
callbacksTable: string
|
|
38
|
+
notificationTopicArn?: string
|
|
39
|
+
}): Record<string, any>;
|
|
40
|
+
static createCallbackProcessorLambda(config: {
|
|
41
|
+
slug: string
|
|
42
|
+
roleArn: string
|
|
43
|
+
callbacksTable: string
|
|
44
|
+
connectInstanceId: string
|
|
45
|
+
contactFlowId: string
|
|
46
|
+
sourcePhoneNumber: string
|
|
47
|
+
queueId?: string
|
|
48
|
+
}): Record<string, any>;
|
|
49
|
+
}
|
|
50
|
+
export default Callbacks;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IVR Builder (Visual Contact Flow Editor)
|
|
3
|
+
*
|
|
4
|
+
* Provides a programmatic way to build Amazon Connect contact flows
|
|
5
|
+
*/
|
|
6
|
+
export declare interface IVRFlow {
|
|
7
|
+
id: string
|
|
8
|
+
name: string
|
|
9
|
+
description?: string
|
|
10
|
+
nodes: IVRNode[]
|
|
11
|
+
connections: IVRConnection[]
|
|
12
|
+
startNodeId: string
|
|
13
|
+
version: number
|
|
14
|
+
createdAt: string
|
|
15
|
+
updatedAt: string
|
|
16
|
+
}
|
|
17
|
+
export declare interface IVRNode {
|
|
18
|
+
id: string
|
|
19
|
+
type: IVRNodeType
|
|
20
|
+
position: { x: number; y: number }
|
|
21
|
+
config: Record<string, any>
|
|
22
|
+
label?: string
|
|
23
|
+
}
|
|
24
|
+
export declare interface IVRConnection {
|
|
25
|
+
id: string
|
|
26
|
+
sourceNodeId: string
|
|
27
|
+
targetNodeId: string
|
|
28
|
+
sourcePort: string
|
|
29
|
+
label?: string
|
|
30
|
+
}
|
|
31
|
+
export type IVRNodeType = | 'start'
|
|
32
|
+
| 'play-prompt'
|
|
33
|
+
| 'get-input'
|
|
34
|
+
| 'menu'
|
|
35
|
+
| 'transfer-queue'
|
|
36
|
+
| 'transfer-agent'
|
|
37
|
+
| 'transfer-phone'
|
|
38
|
+
| 'invoke-lambda'
|
|
39
|
+
| 'set-attribute'
|
|
40
|
+
| 'check-attribute'
|
|
41
|
+
| 'check-hours'
|
|
42
|
+
| 'check-queue'
|
|
43
|
+
| 'record-voicemail'
|
|
44
|
+
| 'disconnect'
|
|
45
|
+
| 'loop'
|
|
46
|
+
| 'wait'
|
|
47
|
+
/**
|
|
48
|
+
* IVR Builder Module
|
|
49
|
+
*/
|
|
50
|
+
export declare class IVRBuilder {
|
|
51
|
+
private nodes: IVRNode[];
|
|
52
|
+
private connections: IVRConnection[];
|
|
53
|
+
private startNodeId: string;
|
|
54
|
+
static create(name: string): IVRBuilder;
|
|
55
|
+
start(): this;
|
|
56
|
+
playPrompt(text: string, options?: { ssml?: boolean; voice?: string }): this;
|
|
57
|
+
getInput(prompt: string, options?: {
|
|
58
|
+
maxDigits?: number
|
|
59
|
+
timeout?: number
|
|
60
|
+
errorPrompt?: string
|
|
61
|
+
}): this;
|
|
62
|
+
menu(prompt: string, options: Record<string, string>): this;
|
|
63
|
+
transferToQueue(queueArn: string, options?: { priority?: number }): this;
|
|
64
|
+
transferToPhone(phoneNumber: string): this;
|
|
65
|
+
invokeLambda(functionArn: string, options?: { timeout?: number }): this;
|
|
66
|
+
setAttribute(key: string, value: string): this;
|
|
67
|
+
checkHours(hoursOfOperationArn: string): this;
|
|
68
|
+
recordVoicemail(options?: {
|
|
69
|
+
maxDuration?: number
|
|
70
|
+
greeting?: string
|
|
71
|
+
beep?: boolean
|
|
72
|
+
}): this;
|
|
73
|
+
wait(seconds: number): this;
|
|
74
|
+
disconnect(): this;
|
|
75
|
+
build(): IVRFlow;
|
|
76
|
+
toContactFlow(): string;
|
|
77
|
+
private nodeToAction(node: IVRNode, nodeMap: Map<string, IVRNode>): any;
|
|
78
|
+
private connectToLast(targetId: string): void;
|
|
79
|
+
private getNextNodeId(nodeId: string): string | null;
|
|
80
|
+
private generateId(): string;
|
|
81
|
+
static readonly Templates: any;
|
|
82
|
+
}
|
|
83
|
+
export default IVRBuilder;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Call Recording with Transcription
|
|
3
|
+
*
|
|
4
|
+
* Provides call recording storage and transcription
|
|
5
|
+
*/
|
|
6
|
+
export declare interface CallRecording {
|
|
7
|
+
recordingId: string
|
|
8
|
+
contactId: string
|
|
9
|
+
startTime: string
|
|
10
|
+
endTime: string
|
|
11
|
+
duration: number
|
|
12
|
+
participants: string[]
|
|
13
|
+
recordingUrl: string
|
|
14
|
+
transcription?: CallTranscription
|
|
15
|
+
status: 'recording' | 'processing' | 'completed' | 'failed'
|
|
16
|
+
createdAt: string
|
|
17
|
+
}
|
|
18
|
+
export declare interface CallTranscription {
|
|
19
|
+
transcriptId: string
|
|
20
|
+
text: string
|
|
21
|
+
segments: TranscriptionSegment[]
|
|
22
|
+
language: string
|
|
23
|
+
confidence: number
|
|
24
|
+
status: 'pending' | 'processing' | 'completed' | 'failed'
|
|
25
|
+
}
|
|
26
|
+
export declare interface TranscriptionSegment {
|
|
27
|
+
speaker: string
|
|
28
|
+
startTime: number
|
|
29
|
+
endTime: number
|
|
30
|
+
text: string
|
|
31
|
+
confidence: number
|
|
32
|
+
sentiment?: 'positive' | 'neutral' | 'negative'
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Call Recording Module
|
|
36
|
+
*/
|
|
37
|
+
export declare class CallRecording {
|
|
38
|
+
static RecordingProcessorCode: any;
|
|
39
|
+
static TranscriptionCompleteCode: any;
|
|
40
|
+
static createRecordingsTable(config: { slug: string }): Record<string, any>;
|
|
41
|
+
static createRecordingProcessorLambda(config: {
|
|
42
|
+
slug: string
|
|
43
|
+
roleArn: string
|
|
44
|
+
recordingBucket: string
|
|
45
|
+
recordingsTable: string
|
|
46
|
+
}): Record<string, any>;
|
|
47
|
+
}
|
|
48
|
+
export default CallRecording;
|
|
File without changes
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Incoming Call Lambda Handler
|
|
3
|
+
*
|
|
4
|
+
* Processes incoming calls from Amazon Connect:
|
|
5
|
+
* - Logs call details
|
|
6
|
+
* - Sends notifications (SNS, webhook)
|
|
7
|
+
* - Routes based on caller ID
|
|
8
|
+
*/
|
|
9
|
+
export declare const handler: `
|
|
10
|
+
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
11
|
+
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
12
|
+
|
|
13
|
+
const sns = new SNSClient({});
|
|
14
|
+
const dynamodb = new DynamoDBClient({});
|
|
15
|
+
|
|
16
|
+
exports.handler = async (event) => {
|
|
17
|
+
console.log('Incoming call event:', JSON.stringify(event, null, 2));
|
|
18
|
+
|
|
19
|
+
const notificationTopicArn = process.env.NOTIFICATION_TOPIC_ARN;
|
|
20
|
+
const callLogTable = process.env.CALL_LOG_TABLE;
|
|
21
|
+
const webhookUrl = process.env.WEBHOOK_URL;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Extract call details from Connect event
|
|
25
|
+
const contactData = event.Details?.ContactData || {};
|
|
26
|
+
const parameters = event.Details?.Parameters || {};
|
|
27
|
+
|
|
28
|
+
const callDetails = {
|
|
29
|
+
contactId: contactData.ContactId,
|
|
30
|
+
channel: contactData.Channel || 'VOICE',
|
|
31
|
+
initiationMethod: contactData.InitiationMethod,
|
|
32
|
+
customerEndpoint: contactData.CustomerEndpoint?.Address,
|
|
33
|
+
systemEndpoint: contactData.SystemEndpoint?.Address,
|
|
34
|
+
queue: contactData.Queue?.Name,
|
|
35
|
+
attributes: contactData.Attributes || {},
|
|
36
|
+
timestamp: new Date().toISOString(),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
console.log('Call details:', callDetails);
|
|
40
|
+
|
|
41
|
+
// Log call to DynamoDB
|
|
42
|
+
if (callLogTable) {
|
|
43
|
+
await dynamodb.send(new PutItemCommand({
|
|
44
|
+
TableName: callLogTable,
|
|
45
|
+
Item: {
|
|
46
|
+
contactId: { S: callDetails.contactId },
|
|
47
|
+
timestamp: { S: callDetails.timestamp },
|
|
48
|
+
callerNumber: { S: callDetails.customerEndpoint || 'unknown' },
|
|
49
|
+
calledNumber: { S: callDetails.systemEndpoint || 'unknown' },
|
|
50
|
+
channel: { S: callDetails.channel },
|
|
51
|
+
initiationMethod: { S: callDetails.initiationMethod || 'unknown' },
|
|
52
|
+
status: { S: 'incoming' },
|
|
53
|
+
ttl: { N: String(Math.floor(Date.now() / 1000) + 90 * 24 * 60 * 60) }, // 90 days
|
|
54
|
+
},
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Send SNS notification
|
|
59
|
+
if (notificationTopicArn) {
|
|
60
|
+
await sns.send(new PublishCommand({
|
|
61
|
+
TopicArn: notificationTopicArn,
|
|
62
|
+
Subject: 'Incoming Call',
|
|
63
|
+
Message: JSON.stringify({
|
|
64
|
+
type: 'incoming_call',
|
|
65
|
+
from: callDetails.customerEndpoint,
|
|
66
|
+
to: callDetails.systemEndpoint,
|
|
67
|
+
contactId: callDetails.contactId,
|
|
68
|
+
timestamp: callDetails.timestamp,
|
|
69
|
+
}, null, 2),
|
|
70
|
+
MessageAttributes: {
|
|
71
|
+
eventType: {
|
|
72
|
+
DataType: 'String',
|
|
73
|
+
StringValue: 'incoming_call',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Send webhook notification
|
|
80
|
+
if (webhookUrl) {
|
|
81
|
+
try {
|
|
82
|
+
await fetch(webhookUrl, {
|
|
83
|
+
method: 'POST',
|
|
84
|
+
headers: { 'Content-Type': 'application/json' },
|
|
85
|
+
body: JSON.stringify({
|
|
86
|
+
event: 'incoming_call',
|
|
87
|
+
data: callDetails,
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.error('Webhook notification failed:', err.message);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Return routing decision
|
|
96
|
+
// Can be customized based on caller ID, time of day, etc.
|
|
97
|
+
return {
|
|
98
|
+
statusCode: 200,
|
|
99
|
+
route: parameters.defaultRoute || 'main_queue',
|
|
100
|
+
callerInfo: {
|
|
101
|
+
number: callDetails.customerEndpoint,
|
|
102
|
+
isKnown: false, // Could lookup in CRM
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error('Error processing incoming call:', error);
|
|
108
|
+
return {
|
|
109
|
+
statusCode: 500,
|
|
110
|
+
error: error.message,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
`;
|
|
115
|
+
export default handler;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Missed Call Lambda Handler
|
|
3
|
+
*
|
|
4
|
+
* Processes missed call events:
|
|
5
|
+
* - Logs missed call
|
|
6
|
+
* - Sends notification
|
|
7
|
+
*/
|
|
8
|
+
export declare const handler: `
|
|
9
|
+
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
10
|
+
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
11
|
+
|
|
12
|
+
const sns = new SNSClient({});
|
|
13
|
+
const dynamodb = new DynamoDBClient({});
|
|
14
|
+
|
|
15
|
+
exports.handler = async (event) => {
|
|
16
|
+
console.log('Missed call event:', JSON.stringify(event, null, 2));
|
|
17
|
+
|
|
18
|
+
const notificationTopicArn = process.env.NOTIFICATION_TOPIC_ARN;
|
|
19
|
+
const callLogTable = process.env.CALL_LOG_TABLE;
|
|
20
|
+
const webhookUrl = process.env.WEBHOOK_URL;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// Extract call details from Connect event
|
|
24
|
+
const contactData = event.Details?.ContactData || {};
|
|
25
|
+
|
|
26
|
+
const callDetails = {
|
|
27
|
+
contactId: contactData.ContactId,
|
|
28
|
+
customerEndpoint: contactData.CustomerEndpoint?.Address,
|
|
29
|
+
systemEndpoint: contactData.SystemEndpoint?.Address,
|
|
30
|
+
queue: contactData.Queue?.Name,
|
|
31
|
+
waitTime: contactData.Queue?.EnqueueTimestamp
|
|
32
|
+
? Math.floor((Date.now() - new Date(contactData.Queue.EnqueueTimestamp).getTime()) / 1000)
|
|
33
|
+
: 0,
|
|
34
|
+
disconnectReason: event.Details?.Parameters?.disconnectReason || 'customer_abandoned',
|
|
35
|
+
timestamp: new Date().toISOString(),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
console.log('Missed call details:', callDetails);
|
|
39
|
+
|
|
40
|
+
// Update call log
|
|
41
|
+
if (callLogTable && callDetails.contactId) {
|
|
42
|
+
await dynamodb.send(new UpdateItemCommand({
|
|
43
|
+
TableName: callLogTable,
|
|
44
|
+
Key: {
|
|
45
|
+
contactId: { S: callDetails.contactId },
|
|
46
|
+
},
|
|
47
|
+
UpdateExpression: 'SET #status = :status, disconnectReason = :reason, waitTime = :wait, missedAt = :at',
|
|
48
|
+
ExpressionAttributeNames: {
|
|
49
|
+
'#status': 'status',
|
|
50
|
+
},
|
|
51
|
+
ExpressionAttributeValues: {
|
|
52
|
+
':status': { S: 'missed' },
|
|
53
|
+
':reason': { S: callDetails.disconnectReason },
|
|
54
|
+
':wait': { N: String(callDetails.waitTime) },
|
|
55
|
+
':at': { S: callDetails.timestamp },
|
|
56
|
+
},
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Send SNS notification
|
|
61
|
+
if (notificationTopicArn) {
|
|
62
|
+
await sns.send(new PublishCommand({
|
|
63
|
+
TopicArn: notificationTopicArn,
|
|
64
|
+
Subject: 'Missed Call Alert',
|
|
65
|
+
Message: JSON.stringify({
|
|
66
|
+
type: 'missed_call',
|
|
67
|
+
from: callDetails.customerEndpoint,
|
|
68
|
+
to: callDetails.systemEndpoint,
|
|
69
|
+
queue: callDetails.queue,
|
|
70
|
+
waitTime: callDetails.waitTime,
|
|
71
|
+
reason: callDetails.disconnectReason,
|
|
72
|
+
contactId: callDetails.contactId,
|
|
73
|
+
timestamp: callDetails.timestamp,
|
|
74
|
+
}, null, 2),
|
|
75
|
+
MessageAttributes: {
|
|
76
|
+
eventType: {
|
|
77
|
+
DataType: 'String',
|
|
78
|
+
StringValue: 'missed_call',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Send webhook notification
|
|
85
|
+
if (webhookUrl) {
|
|
86
|
+
try {
|
|
87
|
+
await fetch(webhookUrl, {
|
|
88
|
+
method: 'POST',
|
|
89
|
+
headers: { 'Content-Type': 'application/json' },
|
|
90
|
+
body: JSON.stringify({
|
|
91
|
+
event: 'missed_call',
|
|
92
|
+
data: callDetails,
|
|
93
|
+
}),
|
|
94
|
+
});
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.error('Webhook notification failed:', err.message);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
statusCode: 200,
|
|
102
|
+
message: 'Missed call logged',
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error('Error processing missed call:', error);
|
|
107
|
+
return {
|
|
108
|
+
statusCode: 500,
|
|
109
|
+
error: error.message,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
`;
|
|
114
|
+
export default handler;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Voicemail Lambda Handler
|
|
3
|
+
*
|
|
4
|
+
* Processes voicemail recordings:
|
|
5
|
+
* - Processes voicemail recordings from S3
|
|
6
|
+
* - Transcribes using Amazon Transcribe
|
|
7
|
+
* - Sends notification with transcription
|
|
8
|
+
*/
|
|
9
|
+
export declare const handler: `
|
|
10
|
+
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
11
|
+
const { TranscribeClient, StartTranscriptionJobCommand, GetTranscriptionJobCommand } = require('@aws-sdk/client-transcribe');
|
|
12
|
+
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
13
|
+
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
14
|
+
|
|
15
|
+
const s3 = new S3Client({});
|
|
16
|
+
const transcribe = new TranscribeClient({});
|
|
17
|
+
const sns = new SNSClient({});
|
|
18
|
+
const dynamodb = new DynamoDBClient({});
|
|
19
|
+
|
|
20
|
+
exports.handler = async (event) => {
|
|
21
|
+
console.log('Voicemail event:', JSON.stringify(event, null, 2));
|
|
22
|
+
|
|
23
|
+
const notificationTopicArn = process.env.NOTIFICATION_TOPIC_ARN;
|
|
24
|
+
const voicemailBucket = process.env.VOICEMAIL_BUCKET;
|
|
25
|
+
const callLogTable = process.env.CALL_LOG_TABLE;
|
|
26
|
+
const transcriptionEnabled = process.env.TRANSCRIPTION_ENABLED === 'true';
|
|
27
|
+
|
|
28
|
+
for (const record of event.Records) {
|
|
29
|
+
try {
|
|
30
|
+
const s3Event = record.s3 || {};
|
|
31
|
+
const bucket = s3Event.bucket?.name || voicemailBucket;
|
|
32
|
+
const key = decodeURIComponent(s3Event.object?.key?.replace(/\\+/g, ' ') || '');
|
|
33
|
+
|
|
34
|
+
if (!key.includes('voicemail') || !key.endsWith('.wav')) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log(\`Processing voicemail: \${key}\`);
|
|
39
|
+
|
|
40
|
+
// Extract metadata from key (format: voicemails/{contactId}/{timestamp}.wav)
|
|
41
|
+
const parts = key.split('/');
|
|
42
|
+
const contactId = parts[1] || 'unknown';
|
|
43
|
+
const filename = parts[parts.length - 1];
|
|
44
|
+
const timestamp = filename.replace('.wav', '');
|
|
45
|
+
|
|
46
|
+
// Get voicemail metadata if exists
|
|
47
|
+
let metadata = {};
|
|
48
|
+
try {
|
|
49
|
+
const metaResult = await s3.send(new GetObjectCommand({
|
|
50
|
+
Bucket: bucket,
|
|
51
|
+
Key: key.replace('.wav', '.json'),
|
|
52
|
+
}));
|
|
53
|
+
metadata = JSON.parse(await metaResult.Body.transformToString());
|
|
54
|
+
} catch {
|
|
55
|
+
// No metadata file
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let transcription = null;
|
|
59
|
+
|
|
60
|
+
// Start transcription if enabled
|
|
61
|
+
if (transcriptionEnabled) {
|
|
62
|
+
const jobName = \`voicemail-\${contactId}-\${Date.now()}\`;
|
|
63
|
+
|
|
64
|
+
await transcribe.send(new StartTranscriptionJobCommand({
|
|
65
|
+
TranscriptionJobName: jobName,
|
|
66
|
+
LanguageCode: 'en-US',
|
|
67
|
+
MediaFormat: 'wav',
|
|
68
|
+
Media: {
|
|
69
|
+
MediaFileUri: \`s3://\${bucket}/\${key}\`,
|
|
70
|
+
},
|
|
71
|
+
OutputBucketName: bucket,
|
|
72
|
+
OutputKey: key.replace('.wav', '-transcript.json'),
|
|
73
|
+
}));
|
|
74
|
+
|
|
75
|
+
// Wait for transcription (with timeout)
|
|
76
|
+
let attempts = 0;
|
|
77
|
+
const maxAttempts = 30; // 5 minutes max
|
|
78
|
+
|
|
79
|
+
while (attempts < maxAttempts) {
|
|
80
|
+
await new Promise(resolve => setTimeout(resolve, 10000)); // 10 seconds
|
|
81
|
+
|
|
82
|
+
const jobResult = await transcribe.send(new GetTranscriptionJobCommand({
|
|
83
|
+
TranscriptionJobName: jobName,
|
|
84
|
+
}));
|
|
85
|
+
|
|
86
|
+
const status = jobResult.TranscriptionJob?.TranscriptionJobStatus;
|
|
87
|
+
|
|
88
|
+
if (status === 'COMPLETED') {
|
|
89
|
+
// Get transcription result
|
|
90
|
+
try {
|
|
91
|
+
const transcriptResult = await s3.send(new GetObjectCommand({
|
|
92
|
+
Bucket: bucket,
|
|
93
|
+
Key: key.replace('.wav', '-transcript.json'),
|
|
94
|
+
}));
|
|
95
|
+
const transcriptData = JSON.parse(await transcriptResult.Body.transformToString());
|
|
96
|
+
transcription = transcriptData.results?.transcripts?.[0]?.transcript || '';
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.error('Error getting transcription:', err.message);
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
} else if (status === 'FAILED') {
|
|
102
|
+
console.error('Transcription failed');
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
attempts++;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Update call log
|
|
111
|
+
if (callLogTable && contactId !== 'unknown') {
|
|
112
|
+
await dynamodb.send(new UpdateItemCommand({
|
|
113
|
+
TableName: callLogTable,
|
|
114
|
+
Key: {
|
|
115
|
+
contactId: { S: contactId },
|
|
116
|
+
},
|
|
117
|
+
UpdateExpression: 'SET voicemailKey = :key, voicemailTranscript = :transcript, voicemailAt = :at',
|
|
118
|
+
ExpressionAttributeValues: {
|
|
119
|
+
':key': { S: key },
|
|
120
|
+
':transcript': { S: transcription || '' },
|
|
121
|
+
':at': { S: new Date().toISOString() },
|
|
122
|
+
},
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Save voicemail metadata
|
|
127
|
+
await s3.send(new PutObjectCommand({
|
|
128
|
+
Bucket: bucket,
|
|
129
|
+
Key: key.replace('.wav', '-metadata.json'),
|
|
130
|
+
Body: JSON.stringify({
|
|
131
|
+
contactId,
|
|
132
|
+
callerNumber: metadata.callerNumber || 'unknown',
|
|
133
|
+
calledNumber: metadata.calledNumber || 'unknown',
|
|
134
|
+
duration: metadata.duration || 0,
|
|
135
|
+
recordedAt: timestamp,
|
|
136
|
+
processedAt: new Date().toISOString(),
|
|
137
|
+
transcription,
|
|
138
|
+
audioKey: key,
|
|
139
|
+
}, null, 2),
|
|
140
|
+
ContentType: 'application/json',
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
// Send notification
|
|
144
|
+
if (notificationTopicArn) {
|
|
145
|
+
await sns.send(new PublishCommand({
|
|
146
|
+
TopicArn: notificationTopicArn,
|
|
147
|
+
Subject: 'New Voicemail',
|
|
148
|
+
Message: JSON.stringify({
|
|
149
|
+
type: 'voicemail',
|
|
150
|
+
contactId,
|
|
151
|
+
from: metadata.callerNumber || 'unknown',
|
|
152
|
+
to: metadata.calledNumber || 'unknown',
|
|
153
|
+
duration: metadata.duration || 0,
|
|
154
|
+
transcription: transcription || '(transcription not available)',
|
|
155
|
+
audioUrl: \`s3://\${bucket}/\${key}\`,
|
|
156
|
+
timestamp: new Date().toISOString(),
|
|
157
|
+
}, null, 2),
|
|
158
|
+
MessageAttributes: {
|
|
159
|
+
eventType: {
|
|
160
|
+
DataType: 'String',
|
|
161
|
+
StringValue: 'voicemail',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
console.log(\`Processed voicemail: \${contactId}\`);
|
|
168
|
+
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error('Error processing voicemail:', error);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return { statusCode: 200, body: 'OK' };
|
|
175
|
+
};
|
|
176
|
+
`;
|
|
177
|
+
export default handler;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CloudConfig } from '@stacksjs/ts-cloud-types';
|
|
2
|
+
/**
|
|
3
|
+
* API-Only Backend Preset
|
|
4
|
+
* Perfect for: REST APIs, GraphQL APIs, mobile backends
|
|
5
|
+
* Includes: API Gateway + Lambda functions + DynamoDB
|
|
6
|
+
*/
|
|
7
|
+
export declare function createApiBackendPreset(options: {
|
|
8
|
+
name: string
|
|
9
|
+
slug: string
|
|
10
|
+
domain?: string
|
|
11
|
+
}): Partial<CloudConfig>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CloudConfig } from '@stacksjs/ts-cloud-types';
|
|
2
|
+
/**
|
|
3
|
+
* Data Pipeline Preset
|
|
4
|
+
* Perfect for: ETL pipelines, data processing, analytics workflows
|
|
5
|
+
* Includes: Kinesis + Lambda + S3 + Athena + Glue
|
|
6
|
+
*/
|
|
7
|
+
export declare function createDataPipelinePreset(options: {
|
|
8
|
+
name: string
|
|
9
|
+
slug: string
|
|
10
|
+
retentionDays?: number
|
|
11
|
+
}): Partial<CloudConfig>;
|