@stacksjs/ts-cloud 0.1.7 → 0.1.9

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.
Files changed (77) hide show
  1. package/dist/aws/s3.d.ts +1 -1
  2. package/dist/bin/cli.js +223 -222
  3. package/dist/index.js +132 -132
  4. package/package.json +18 -16
  5. package/src/aws/acm.ts +768 -0
  6. package/src/aws/application-autoscaling.ts +845 -0
  7. package/src/aws/bedrock.ts +4074 -0
  8. package/src/aws/client.ts +891 -0
  9. package/src/aws/cloudformation.ts +896 -0
  10. package/src/aws/cloudfront.ts +1531 -0
  11. package/src/aws/cloudwatch-logs.ts +154 -0
  12. package/src/aws/comprehend.ts +839 -0
  13. package/src/aws/connect.ts +1056 -0
  14. package/src/aws/deploy-imap.ts +384 -0
  15. package/src/aws/dynamodb.ts +340 -0
  16. package/src/aws/ec2.ts +1385 -0
  17. package/src/aws/ecr.ts +621 -0
  18. package/src/aws/ecs.ts +615 -0
  19. package/src/aws/elasticache.ts +301 -0
  20. package/src/aws/elbv2.ts +942 -0
  21. package/src/aws/email.ts +928 -0
  22. package/src/aws/eventbridge.ts +248 -0
  23. package/src/aws/iam.ts +1689 -0
  24. package/src/aws/imap-server.ts +2100 -0
  25. package/src/aws/index.ts +213 -0
  26. package/src/aws/kendra.ts +1097 -0
  27. package/src/aws/lambda.ts +786 -0
  28. package/src/aws/opensearch.ts +158 -0
  29. package/src/aws/personalize.ts +977 -0
  30. package/src/aws/polly.ts +559 -0
  31. package/src/aws/rds.ts +888 -0
  32. package/src/aws/rekognition.ts +846 -0
  33. package/src/aws/route53-domains.ts +359 -0
  34. package/src/aws/route53.ts +1046 -0
  35. package/src/aws/s3.ts +2334 -0
  36. package/src/aws/scheduler.ts +571 -0
  37. package/src/aws/secrets-manager.ts +769 -0
  38. package/src/aws/ses.ts +1081 -0
  39. package/src/aws/setup-phone.ts +104 -0
  40. package/src/aws/setup-sms.ts +580 -0
  41. package/src/aws/sms.ts +1735 -0
  42. package/src/aws/smtp-server.ts +531 -0
  43. package/src/aws/sns.ts +758 -0
  44. package/src/aws/sqs.ts +382 -0
  45. package/src/aws/ssm.ts +807 -0
  46. package/src/aws/sts.ts +92 -0
  47. package/src/aws/support.ts +391 -0
  48. package/src/aws/test-imap.ts +86 -0
  49. package/src/aws/textract.ts +780 -0
  50. package/src/aws/transcribe.ts +108 -0
  51. package/src/aws/translate.ts +641 -0
  52. package/src/aws/voice.ts +1379 -0
  53. package/src/config.ts +35 -0
  54. package/src/deploy/index.ts +7 -0
  55. package/src/deploy/static-site-external-dns.ts +945 -0
  56. package/src/deploy/static-site.ts +1175 -0
  57. package/src/dns/cloudflare.ts +548 -0
  58. package/src/dns/godaddy.ts +412 -0
  59. package/src/dns/index.ts +205 -0
  60. package/src/dns/porkbun.ts +362 -0
  61. package/src/dns/route53-adapter.ts +414 -0
  62. package/src/dns/types.ts +119 -0
  63. package/src/dns/validator.ts +369 -0
  64. package/src/generators/index.ts +5 -0
  65. package/src/generators/infrastructure.ts +1660 -0
  66. package/src/index.ts +163 -0
  67. package/src/push/apns.ts +452 -0
  68. package/src/push/fcm.ts +506 -0
  69. package/src/push/index.ts +58 -0
  70. package/src/security/pre-deploy-scanner.ts +655 -0
  71. package/src/ssl/acme-client.ts +478 -0
  72. package/src/ssl/index.ts +7 -0
  73. package/src/ssl/letsencrypt.ts +747 -0
  74. package/src/types.ts +2 -0
  75. package/src/utils/cli.ts +398 -0
  76. package/src/validation/index.ts +5 -0
  77. package/src/validation/template.ts +405 -0
@@ -0,0 +1,839 @@
1
+ /**
2
+ * AWS Comprehend Client
3
+ * Natural Language Processing - sentiment, entities, key phrases, language detection, PII
4
+ * No external SDK dependencies - implements AWS Signature V4 directly
5
+ */
6
+
7
+ import { AWSClient } from './client'
8
+
9
+ // ============================================================================
10
+ // Types
11
+ // ============================================================================
12
+
13
+ export interface DetectSentimentCommandInput {
14
+ Text: string
15
+ LanguageCode: 'en' | 'es' | 'fr' | 'de' | 'it' | 'pt' | 'ar' | 'hi' | 'ja' | 'ko' | 'zh' | 'zh-TW'
16
+ }
17
+
18
+ export interface DetectSentimentCommandOutput {
19
+ Sentiment: 'POSITIVE' | 'NEGATIVE' | 'NEUTRAL' | 'MIXED'
20
+ SentimentScore: {
21
+ Positive: number
22
+ Negative: number
23
+ Neutral: number
24
+ Mixed: number
25
+ }
26
+ }
27
+
28
+ export interface DetectEntitiesCommandInput {
29
+ Text: string
30
+ LanguageCode: string
31
+ EndpointArn?: string
32
+ Bytes?: Uint8Array
33
+ DocumentReaderConfig?: {
34
+ DocumentReadAction: 'TEXTRACT_DETECT_DOCUMENT_TEXT' | 'TEXTRACT_ANALYZE_DOCUMENT'
35
+ DocumentReadMode?: 'SERVICE_DEFAULT' | 'FORCE_DOCUMENT_READ_ACTION'
36
+ FeatureTypes?: ('TABLES' | 'FORMS')[]
37
+ }
38
+ }
39
+
40
+ export interface Entity {
41
+ Score?: number
42
+ Type?: 'PERSON' | 'LOCATION' | 'ORGANIZATION' | 'COMMERCIAL_ITEM' | 'EVENT' | 'DATE' | 'QUANTITY' | 'TITLE' | 'OTHER'
43
+ Text?: string
44
+ BeginOffset?: number
45
+ EndOffset?: number
46
+ BlockReferences?: Array<{
47
+ BlockId?: string
48
+ BeginOffset?: number
49
+ EndOffset?: number
50
+ ChildBlocks?: Array<{
51
+ ChildBlockId?: string
52
+ BeginOffset?: number
53
+ EndOffset?: number
54
+ }>
55
+ }>
56
+ }
57
+
58
+ export interface DetectEntitiesCommandOutput {
59
+ Entities: Entity[]
60
+ DocumentMetadata?: {
61
+ Pages?: number
62
+ ExtractedCharacters?: Array<{
63
+ Page?: number
64
+ Count?: number
65
+ }>
66
+ }
67
+ DocumentType?: Array<{
68
+ Page?: number
69
+ Type?: 'NATIVE_PDF' | 'SCANNED_PDF' | 'MS_WORD' | 'IMAGE' | 'PLAIN_TEXT' | 'TEXTRACT_DETECT_DOCUMENT_TEXT_JSON' | 'TEXTRACT_ANALYZE_DOCUMENT_JSON'
70
+ }>
71
+ Blocks?: Array<{
72
+ Id?: string
73
+ BlockType?: 'LINE' | 'WORD'
74
+ Text?: string
75
+ Page?: number
76
+ Geometry?: {
77
+ BoundingBox?: {
78
+ Height?: number
79
+ Left?: number
80
+ Top?: number
81
+ Width?: number
82
+ }
83
+ Polygon?: Array<{
84
+ X?: number
85
+ Y?: number
86
+ }>
87
+ }
88
+ Relationships?: Array<{
89
+ Ids?: string[]
90
+ Type?: 'CHILD'
91
+ }>
92
+ }>
93
+ Errors?: Array<{
94
+ Page?: number
95
+ ErrorCode?: 'TEXTRACT_BAD_PAGE' | 'TEXTRACT_PROVISIONED_THROUGHPUT_EXCEEDED' | 'PAGE_CHARACTERS_EXCEEDED' | 'PAGE_SIZE_EXCEEDED' | 'INTERNAL_SERVER_ERROR'
96
+ ErrorMessage?: string
97
+ }>
98
+ }
99
+
100
+ export interface DetectKeyPhrasesCommandInput {
101
+ Text: string
102
+ LanguageCode: string
103
+ }
104
+
105
+ export interface KeyPhrase {
106
+ Score?: number
107
+ Text?: string
108
+ BeginOffset?: number
109
+ EndOffset?: number
110
+ }
111
+
112
+ export interface DetectKeyPhrasesCommandOutput {
113
+ KeyPhrases: KeyPhrase[]
114
+ }
115
+
116
+ export interface DetectDominantLanguageCommandInput {
117
+ Text: string
118
+ }
119
+
120
+ export interface DominantLanguage {
121
+ LanguageCode?: string
122
+ Score?: number
123
+ }
124
+
125
+ export interface DetectDominantLanguageCommandOutput {
126
+ Languages: DominantLanguage[]
127
+ }
128
+
129
+ export interface DetectPiiEntitiesCommandInput {
130
+ Text: string
131
+ LanguageCode: string
132
+ }
133
+
134
+ export interface PiiEntity {
135
+ Score?: number
136
+ Type?: 'BANK_ACCOUNT_NUMBER' | 'BANK_ROUTING' | 'CREDIT_DEBIT_NUMBER' | 'CREDIT_DEBIT_CVV' | 'CREDIT_DEBIT_EXPIRY' | 'PIN' | 'EMAIL' | 'ADDRESS' | 'NAME' | 'PHONE' | 'SSN' | 'DATE_TIME' | 'PASSPORT_NUMBER' | 'DRIVER_ID' | 'URL' | 'AGE' | 'USERNAME' | 'PASSWORD' | 'AWS_ACCESS_KEY' | 'AWS_SECRET_KEY' | 'IP_ADDRESS' | 'MAC_ADDRESS' | 'LICENSE_PLATE' | 'VEHICLE_IDENTIFICATION_NUMBER' | 'UK_NATIONAL_INSURANCE_NUMBER' | 'CA_SOCIAL_INSURANCE_NUMBER' | 'US_INDIVIDUAL_TAX_IDENTIFICATION_NUMBER' | 'UK_UNIQUE_TAXPAYER_REFERENCE_NUMBER' | 'IN_PERMANENT_ACCOUNT_NUMBER' | 'IN_NREGA' | 'INTERNATIONAL_BANK_ACCOUNT_NUMBER' | 'SWIFT_CODE' | 'UK_NATIONAL_HEALTH_SERVICE_NUMBER' | 'CA_HEALTH_NUMBER' | 'IN_AADHAAR' | 'IN_VOTER_NUMBER'
137
+ BeginOffset?: number
138
+ EndOffset?: number
139
+ }
140
+
141
+ export interface DetectPiiEntitiesCommandOutput {
142
+ Entities: PiiEntity[]
143
+ }
144
+
145
+ export interface ContainsPiiEntitiesCommandInput {
146
+ Text: string
147
+ LanguageCode: string
148
+ }
149
+
150
+ export interface ContainsPiiEntitiesCommandOutput {
151
+ Labels: Array<{
152
+ Name?: string
153
+ Score?: number
154
+ }>
155
+ }
156
+
157
+ export interface DetectSyntaxCommandInput {
158
+ Text: string
159
+ LanguageCode: 'en' | 'es' | 'fr' | 'de' | 'it' | 'pt'
160
+ }
161
+
162
+ export interface SyntaxToken {
163
+ TokenId?: number
164
+ Text?: string
165
+ BeginOffset?: number
166
+ EndOffset?: number
167
+ PartOfSpeech?: {
168
+ Tag?: 'ADJ' | 'ADP' | 'ADV' | 'AUX' | 'CONJ' | 'CCONJ' | 'DET' | 'INTJ' | 'NOUN' | 'NUM' | 'O' | 'PART' | 'PRON' | 'PROPN' | 'PUNCT' | 'SCONJ' | 'SYM' | 'VERB'
169
+ Score?: number
170
+ }
171
+ }
172
+
173
+ export interface DetectSyntaxCommandOutput {
174
+ SyntaxTokens: SyntaxToken[]
175
+ }
176
+
177
+ export interface DetectTargetedSentimentCommandInput {
178
+ Text: string
179
+ LanguageCode: string
180
+ }
181
+
182
+ export interface TargetedSentimentEntity {
183
+ DescriptiveMentionIndex?: number[]
184
+ Mentions?: Array<{
185
+ Score?: number
186
+ GroupScore?: number
187
+ Text?: string
188
+ Type?: 'PERSON' | 'LOCATION' | 'ORGANIZATION' | 'FACILITY' | 'BRAND' | 'COMMERCIAL_ITEM' | 'MOVIE' | 'MUSIC' | 'BOOK' | 'SOFTWARE' | 'GAME' | 'PERSONAL_TITLE' | 'EVENT' | 'DATE' | 'QUANTITY' | 'ATTRIBUTE' | 'OTHER'
189
+ MentionSentiment?: {
190
+ Sentiment?: 'POSITIVE' | 'NEGATIVE' | 'NEUTRAL' | 'MIXED'
191
+ SentimentScore?: {
192
+ Positive?: number
193
+ Negative?: number
194
+ Neutral?: number
195
+ Mixed?: number
196
+ }
197
+ }
198
+ BeginOffset?: number
199
+ EndOffset?: number
200
+ }>
201
+ }
202
+
203
+ export interface DetectTargetedSentimentCommandOutput {
204
+ Entities: TargetedSentimentEntity[]
205
+ }
206
+
207
+ export interface ClassifyDocumentCommandInput {
208
+ Text?: string
209
+ EndpointArn: string
210
+ Bytes?: Uint8Array
211
+ DocumentReaderConfig?: {
212
+ DocumentReadAction: 'TEXTRACT_DETECT_DOCUMENT_TEXT' | 'TEXTRACT_ANALYZE_DOCUMENT'
213
+ DocumentReadMode?: 'SERVICE_DEFAULT' | 'FORCE_DOCUMENT_READ_ACTION'
214
+ FeatureTypes?: ('TABLES' | 'FORMS')[]
215
+ }
216
+ }
217
+
218
+ export interface ClassifyDocumentCommandOutput {
219
+ Classes?: Array<{
220
+ Name?: string
221
+ Score?: number
222
+ Page?: number
223
+ }>
224
+ Labels?: Array<{
225
+ Name?: string
226
+ Score?: number
227
+ Page?: number
228
+ }>
229
+ DocumentMetadata?: {
230
+ Pages?: number
231
+ ExtractedCharacters?: Array<{
232
+ Page?: number
233
+ Count?: number
234
+ }>
235
+ }
236
+ DocumentType?: Array<{
237
+ Page?: number
238
+ Type?: string
239
+ }>
240
+ Errors?: Array<{
241
+ Page?: number
242
+ ErrorCode?: string
243
+ ErrorMessage?: string
244
+ }>
245
+ Warnings?: Array<{
246
+ Page?: number
247
+ WarnCode?: string
248
+ WarnMessage?: string
249
+ }>
250
+ }
251
+
252
+ export interface BatchDetectSentimentCommandInput {
253
+ TextList: string[]
254
+ LanguageCode: string
255
+ }
256
+
257
+ export interface BatchDetectSentimentCommandOutput {
258
+ ResultList: Array<{
259
+ Index?: number
260
+ Sentiment?: 'POSITIVE' | 'NEGATIVE' | 'NEUTRAL' | 'MIXED'
261
+ SentimentScore?: {
262
+ Positive?: number
263
+ Negative?: number
264
+ Neutral?: number
265
+ Mixed?: number
266
+ }
267
+ }>
268
+ ErrorList: Array<{
269
+ Index?: number
270
+ ErrorCode?: string
271
+ ErrorMessage?: string
272
+ }>
273
+ }
274
+
275
+ export interface BatchDetectEntitiesCommandInput {
276
+ TextList: string[]
277
+ LanguageCode: string
278
+ }
279
+
280
+ export interface BatchDetectEntitiesCommandOutput {
281
+ ResultList: Array<{
282
+ Index?: number
283
+ Entities?: Entity[]
284
+ }>
285
+ ErrorList: Array<{
286
+ Index?: number
287
+ ErrorCode?: string
288
+ ErrorMessage?: string
289
+ }>
290
+ }
291
+
292
+ export interface BatchDetectKeyPhrasesCommandInput {
293
+ TextList: string[]
294
+ LanguageCode: string
295
+ }
296
+
297
+ export interface BatchDetectKeyPhrasesCommandOutput {
298
+ ResultList: Array<{
299
+ Index?: number
300
+ KeyPhrases?: KeyPhrase[]
301
+ }>
302
+ ErrorList: Array<{
303
+ Index?: number
304
+ ErrorCode?: string
305
+ ErrorMessage?: string
306
+ }>
307
+ }
308
+
309
+ export interface BatchDetectDominantLanguageCommandInput {
310
+ TextList: string[]
311
+ }
312
+
313
+ export interface BatchDetectDominantLanguageCommandOutput {
314
+ ResultList: Array<{
315
+ Index?: number
316
+ Languages?: DominantLanguage[]
317
+ }>
318
+ ErrorList: Array<{
319
+ Index?: number
320
+ ErrorCode?: string
321
+ ErrorMessage?: string
322
+ }>
323
+ }
324
+
325
+ export interface BatchDetectSyntaxCommandInput {
326
+ TextList: string[]
327
+ LanguageCode: string
328
+ }
329
+
330
+ export interface BatchDetectSyntaxCommandOutput {
331
+ ResultList: Array<{
332
+ Index?: number
333
+ SyntaxTokens?: SyntaxToken[]
334
+ }>
335
+ ErrorList: Array<{
336
+ Index?: number
337
+ ErrorCode?: string
338
+ ErrorMessage?: string
339
+ }>
340
+ }
341
+
342
+ export interface StartSentimentDetectionJobCommandInput {
343
+ InputDataConfig: {
344
+ S3Uri: string
345
+ InputFormat?: 'ONE_DOC_PER_FILE' | 'ONE_DOC_PER_LINE'
346
+ DocumentReaderConfig?: {
347
+ DocumentReadAction: 'TEXTRACT_DETECT_DOCUMENT_TEXT' | 'TEXTRACT_ANALYZE_DOCUMENT'
348
+ DocumentReadMode?: 'SERVICE_DEFAULT' | 'FORCE_DOCUMENT_READ_ACTION'
349
+ FeatureTypes?: ('TABLES' | 'FORMS')[]
350
+ }
351
+ }
352
+ OutputDataConfig: {
353
+ S3Uri: string
354
+ KmsKeyId?: string
355
+ }
356
+ DataAccessRoleArn: string
357
+ JobName?: string
358
+ LanguageCode: string
359
+ ClientRequestToken?: string
360
+ VolumeKmsKeyId?: string
361
+ VpcConfig?: {
362
+ SecurityGroupIds: string[]
363
+ Subnets: string[]
364
+ }
365
+ Tags?: Array<{ Key: string; Value: string }>
366
+ }
367
+
368
+ export interface StartSentimentDetectionJobCommandOutput {
369
+ JobId?: string
370
+ JobArn?: string
371
+ JobStatus?: 'SUBMITTED' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'STOP_REQUESTED' | 'STOPPED'
372
+ }
373
+
374
+ export interface StartEntitiesDetectionJobCommandInput {
375
+ InputDataConfig: {
376
+ S3Uri: string
377
+ InputFormat?: 'ONE_DOC_PER_FILE' | 'ONE_DOC_PER_LINE'
378
+ DocumentReaderConfig?: {
379
+ DocumentReadAction: 'TEXTRACT_DETECT_DOCUMENT_TEXT' | 'TEXTRACT_ANALYZE_DOCUMENT'
380
+ DocumentReadMode?: 'SERVICE_DEFAULT' | 'FORCE_DOCUMENT_READ_ACTION'
381
+ FeatureTypes?: ('TABLES' | 'FORMS')[]
382
+ }
383
+ }
384
+ OutputDataConfig: {
385
+ S3Uri: string
386
+ KmsKeyId?: string
387
+ }
388
+ DataAccessRoleArn: string
389
+ JobName?: string
390
+ EntityRecognizerArn?: string
391
+ LanguageCode: string
392
+ ClientRequestToken?: string
393
+ VolumeKmsKeyId?: string
394
+ VpcConfig?: {
395
+ SecurityGroupIds: string[]
396
+ Subnets: string[]
397
+ }
398
+ Tags?: Array<{ Key: string; Value: string }>
399
+ FlywheelArn?: string
400
+ }
401
+
402
+ export interface StartEntitiesDetectionJobCommandOutput {
403
+ JobId?: string
404
+ JobArn?: string
405
+ JobStatus?: 'SUBMITTED' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'STOP_REQUESTED' | 'STOPPED'
406
+ EntityRecognizerArn?: string
407
+ }
408
+
409
+ export interface StartKeyPhrasesDetectionJobCommandInput {
410
+ InputDataConfig: {
411
+ S3Uri: string
412
+ InputFormat?: 'ONE_DOC_PER_FILE' | 'ONE_DOC_PER_LINE'
413
+ }
414
+ OutputDataConfig: {
415
+ S3Uri: string
416
+ KmsKeyId?: string
417
+ }
418
+ DataAccessRoleArn: string
419
+ JobName?: string
420
+ LanguageCode: string
421
+ ClientRequestToken?: string
422
+ VolumeKmsKeyId?: string
423
+ VpcConfig?: {
424
+ SecurityGroupIds: string[]
425
+ Subnets: string[]
426
+ }
427
+ Tags?: Array<{ Key: string; Value: string }>
428
+ }
429
+
430
+ export interface StartKeyPhrasesDetectionJobCommandOutput {
431
+ JobId?: string
432
+ JobArn?: string
433
+ JobStatus?: 'SUBMITTED' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'STOP_REQUESTED' | 'STOPPED'
434
+ }
435
+
436
+ export interface StartPiiEntitiesDetectionJobCommandInput {
437
+ InputDataConfig: {
438
+ S3Uri: string
439
+ InputFormat?: 'ONE_DOC_PER_FILE' | 'ONE_DOC_PER_LINE'
440
+ }
441
+ OutputDataConfig: {
442
+ S3Uri: string
443
+ KmsKeyId?: string
444
+ }
445
+ Mode: 'ONLY_REDACTION' | 'ONLY_OFFSETS'
446
+ RedactionConfig?: {
447
+ PiiEntityTypes?: string[]
448
+ MaskMode?: 'MASK' | 'REPLACE_WITH_PII_ENTITY_TYPE'
449
+ MaskCharacter?: string
450
+ }
451
+ DataAccessRoleArn: string
452
+ JobName?: string
453
+ LanguageCode: string
454
+ ClientRequestToken?: string
455
+ Tags?: Array<{ Key: string; Value: string }>
456
+ }
457
+
458
+ export interface StartPiiEntitiesDetectionJobCommandOutput {
459
+ JobId?: string
460
+ JobArn?: string
461
+ JobStatus?: 'SUBMITTED' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'STOP_REQUESTED' | 'STOPPED'
462
+ }
463
+
464
+ export interface DescribeSentimentDetectionJobCommandInput {
465
+ JobId: string
466
+ }
467
+
468
+ export interface DescribeSentimentDetectionJobCommandOutput {
469
+ SentimentDetectionJobProperties?: {
470
+ JobId?: string
471
+ JobArn?: string
472
+ JobName?: string
473
+ JobStatus?: 'SUBMITTED' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'STOP_REQUESTED' | 'STOPPED'
474
+ Message?: string
475
+ SubmitTime?: string
476
+ EndTime?: string
477
+ InputDataConfig?: {
478
+ S3Uri?: string
479
+ InputFormat?: string
480
+ }
481
+ OutputDataConfig?: {
482
+ S3Uri?: string
483
+ KmsKeyId?: string
484
+ }
485
+ LanguageCode?: string
486
+ DataAccessRoleArn?: string
487
+ VolumeKmsKeyId?: string
488
+ VpcConfig?: {
489
+ SecurityGroupIds?: string[]
490
+ Subnets?: string[]
491
+ }
492
+ }
493
+ }
494
+
495
+ // ============================================================================
496
+ // Comprehend Client
497
+ // ============================================================================
498
+
499
+ export class ComprehendClient {
500
+ private client: AWSClient
501
+ private region: string
502
+
503
+ constructor(region: string = 'us-east-1') {
504
+ this.region = region
505
+ this.client = new AWSClient()
506
+ }
507
+
508
+ private async request<T>(action: string, params: Record<string, unknown>): Promise<T> {
509
+ return this.client.request({
510
+ service: 'comprehend',
511
+ region: this.region,
512
+ method: 'POST',
513
+ path: '/',
514
+ headers: {
515
+ 'Content-Type': 'application/x-amz-json-1.1',
516
+ 'X-Amz-Target': `Comprehend_20171127.${action}`,
517
+ },
518
+ body: JSON.stringify(params),
519
+ })
520
+ }
521
+
522
+ // -------------------------------------------------------------------------
523
+ // Detect Operations (Synchronous)
524
+ // -------------------------------------------------------------------------
525
+
526
+ /**
527
+ * Detect sentiment in text
528
+ */
529
+ async detectSentiment(params: DetectSentimentCommandInput): Promise<DetectSentimentCommandOutput> {
530
+ return this.request('DetectSentiment', params as unknown as Record<string, unknown>)
531
+ }
532
+
533
+ /**
534
+ * Detect entities in text
535
+ */
536
+ async detectEntities(params: DetectEntitiesCommandInput): Promise<DetectEntitiesCommandOutput> {
537
+ return this.request('DetectEntities', params as unknown as Record<string, unknown>)
538
+ }
539
+
540
+ /**
541
+ * Detect key phrases in text
542
+ */
543
+ async detectKeyPhrases(params: DetectKeyPhrasesCommandInput): Promise<DetectKeyPhrasesCommandOutput> {
544
+ return this.request('DetectKeyPhrases', params as unknown as Record<string, unknown>)
545
+ }
546
+
547
+ /**
548
+ * Detect the dominant language of text
549
+ */
550
+ async detectDominantLanguage(params: DetectDominantLanguageCommandInput): Promise<DetectDominantLanguageCommandOutput> {
551
+ return this.request('DetectDominantLanguage', params as unknown as Record<string, unknown>)
552
+ }
553
+
554
+ /**
555
+ * Detect PII entities in text
556
+ */
557
+ async detectPiiEntities(params: DetectPiiEntitiesCommandInput): Promise<DetectPiiEntitiesCommandOutput> {
558
+ return this.request('DetectPiiEntities', params as unknown as Record<string, unknown>)
559
+ }
560
+
561
+ /**
562
+ * Check if text contains PII
563
+ */
564
+ async containsPiiEntities(params: ContainsPiiEntitiesCommandInput): Promise<ContainsPiiEntitiesCommandOutput> {
565
+ return this.request('ContainsPiiEntities', params as unknown as Record<string, unknown>)
566
+ }
567
+
568
+ /**
569
+ * Detect syntax (parts of speech) in text
570
+ */
571
+ async detectSyntax(params: DetectSyntaxCommandInput): Promise<DetectSyntaxCommandOutput> {
572
+ return this.request('DetectSyntax', params as unknown as Record<string, unknown>)
573
+ }
574
+
575
+ /**
576
+ * Detect targeted sentiment (sentiment per entity)
577
+ */
578
+ async detectTargetedSentiment(params: DetectTargetedSentimentCommandInput): Promise<DetectTargetedSentimentCommandOutput> {
579
+ return this.request('DetectTargetedSentiment', params as unknown as Record<string, unknown>)
580
+ }
581
+
582
+ /**
583
+ * Classify a document using a custom endpoint
584
+ */
585
+ async classifyDocument(params: ClassifyDocumentCommandInput): Promise<ClassifyDocumentCommandOutput> {
586
+ return this.request('ClassifyDocument', params as unknown as Record<string, unknown>)
587
+ }
588
+
589
+ // -------------------------------------------------------------------------
590
+ // Batch Operations
591
+ // -------------------------------------------------------------------------
592
+
593
+ /**
594
+ * Batch detect sentiment
595
+ */
596
+ async batchDetectSentiment(params: BatchDetectSentimentCommandInput): Promise<BatchDetectSentimentCommandOutput> {
597
+ return this.request('BatchDetectSentiment', params as unknown as Record<string, unknown>)
598
+ }
599
+
600
+ /**
601
+ * Batch detect entities
602
+ */
603
+ async batchDetectEntities(params: BatchDetectEntitiesCommandInput): Promise<BatchDetectEntitiesCommandOutput> {
604
+ return this.request('BatchDetectEntities', params as unknown as Record<string, unknown>)
605
+ }
606
+
607
+ /**
608
+ * Batch detect key phrases
609
+ */
610
+ async batchDetectKeyPhrases(params: BatchDetectKeyPhrasesCommandInput): Promise<BatchDetectKeyPhrasesCommandOutput> {
611
+ return this.request('BatchDetectKeyPhrases', params as unknown as Record<string, unknown>)
612
+ }
613
+
614
+ /**
615
+ * Batch detect dominant language
616
+ */
617
+ async batchDetectDominantLanguage(params: BatchDetectDominantLanguageCommandInput): Promise<BatchDetectDominantLanguageCommandOutput> {
618
+ return this.request('BatchDetectDominantLanguage', params as unknown as Record<string, unknown>)
619
+ }
620
+
621
+ /**
622
+ * Batch detect syntax
623
+ */
624
+ async batchDetectSyntax(params: BatchDetectSyntaxCommandInput): Promise<BatchDetectSyntaxCommandOutput> {
625
+ return this.request('BatchDetectSyntax', params as unknown as Record<string, unknown>)
626
+ }
627
+
628
+ // -------------------------------------------------------------------------
629
+ // Async Job Operations
630
+ // -------------------------------------------------------------------------
631
+
632
+ /**
633
+ * Start an async sentiment detection job
634
+ */
635
+ async startSentimentDetectionJob(params: StartSentimentDetectionJobCommandInput): Promise<StartSentimentDetectionJobCommandOutput> {
636
+ return this.request('StartSentimentDetectionJob', params as unknown as Record<string, unknown>)
637
+ }
638
+
639
+ /**
640
+ * Start an async entities detection job
641
+ */
642
+ async startEntitiesDetectionJob(params: StartEntitiesDetectionJobCommandInput): Promise<StartEntitiesDetectionJobCommandOutput> {
643
+ return this.request('StartEntitiesDetectionJob', params as unknown as Record<string, unknown>)
644
+ }
645
+
646
+ /**
647
+ * Start an async key phrases detection job
648
+ */
649
+ async startKeyPhrasesDetectionJob(params: StartKeyPhrasesDetectionJobCommandInput): Promise<StartKeyPhrasesDetectionJobCommandOutput> {
650
+ return this.request('StartKeyPhrasesDetectionJob', params as unknown as Record<string, unknown>)
651
+ }
652
+
653
+ /**
654
+ * Start an async PII entities detection job
655
+ */
656
+ async startPiiEntitiesDetectionJob(params: StartPiiEntitiesDetectionJobCommandInput): Promise<StartPiiEntitiesDetectionJobCommandOutput> {
657
+ return this.request('StartPiiEntitiesDetectionJob', params as unknown as Record<string, unknown>)
658
+ }
659
+
660
+ /**
661
+ * Describe a sentiment detection job
662
+ */
663
+ async describeSentimentDetectionJob(params: DescribeSentimentDetectionJobCommandInput): Promise<DescribeSentimentDetectionJobCommandOutput> {
664
+ return this.request('DescribeSentimentDetectionJob', params as unknown as Record<string, unknown>)
665
+ }
666
+
667
+ // -------------------------------------------------------------------------
668
+ // Convenience Methods
669
+ // -------------------------------------------------------------------------
670
+
671
+ /**
672
+ * Simple sentiment analysis
673
+ */
674
+ async analyzeSentiment(text: string, languageCode: string = 'en'): Promise<{
675
+ sentiment: 'POSITIVE' | 'NEGATIVE' | 'NEUTRAL' | 'MIXED'
676
+ scores: { positive: number; negative: number; neutral: number; mixed: number }
677
+ }> {
678
+ const result = await this.detectSentiment({
679
+ Text: text,
680
+ LanguageCode: languageCode as DetectSentimentCommandInput['LanguageCode'],
681
+ })
682
+ return {
683
+ sentiment: result.Sentiment,
684
+ scores: {
685
+ positive: result.SentimentScore.Positive,
686
+ negative: result.SentimentScore.Negative,
687
+ neutral: result.SentimentScore.Neutral,
688
+ mixed: result.SentimentScore.Mixed,
689
+ },
690
+ }
691
+ }
692
+
693
+ /**
694
+ * Extract entities from text
695
+ */
696
+ async extractEntities(text: string, languageCode: string = 'en'): Promise<Array<{
697
+ text: string
698
+ type: string
699
+ score: number
700
+ }>> {
701
+ const result = await this.detectEntities({
702
+ Text: text,
703
+ LanguageCode: languageCode,
704
+ })
705
+ return result.Entities.map(e => ({
706
+ text: e.Text || '',
707
+ type: e.Type || 'UNKNOWN',
708
+ score: e.Score || 0,
709
+ }))
710
+ }
711
+
712
+ /**
713
+ * Extract key phrases from text
714
+ */
715
+ async extractKeyPhrases(text: string, languageCode: string = 'en'): Promise<string[]> {
716
+ const result = await this.detectKeyPhrases({
717
+ Text: text,
718
+ LanguageCode: languageCode,
719
+ })
720
+ return result.KeyPhrases.map(kp => kp.Text || '').filter(Boolean)
721
+ }
722
+
723
+ /**
724
+ * Detect language of text
725
+ */
726
+ async detectLanguage(text: string): Promise<{ languageCode: string; confidence: number }> {
727
+ const result = await this.detectDominantLanguage({ Text: text })
728
+ const dominant = result.Languages[0]
729
+ return {
730
+ languageCode: dominant?.LanguageCode || 'unknown',
731
+ confidence: dominant?.Score || 0,
732
+ }
733
+ }
734
+
735
+ /**
736
+ * Find PII in text
737
+ */
738
+ async findPii(text: string, languageCode: string = 'en'): Promise<Array<{
739
+ type: string
740
+ beginOffset: number
741
+ endOffset: number
742
+ score: number
743
+ }>> {
744
+ const result = await this.detectPiiEntities({
745
+ Text: text,
746
+ LanguageCode: languageCode,
747
+ })
748
+ return result.Entities.map(e => ({
749
+ type: e.Type || 'UNKNOWN',
750
+ beginOffset: e.BeginOffset || 0,
751
+ endOffset: e.EndOffset || 0,
752
+ score: e.Score || 0,
753
+ }))
754
+ }
755
+
756
+ /**
757
+ * Check if text contains any PII
758
+ */
759
+ async hasPii(text: string, languageCode: string = 'en'): Promise<boolean> {
760
+ const result = await this.detectPiiEntities({
761
+ Text: text,
762
+ LanguageCode: languageCode,
763
+ })
764
+ return result.Entities.length > 0
765
+ }
766
+
767
+ /**
768
+ * Redact PII from text (replaces PII with [TYPE])
769
+ */
770
+ async redactPii(text: string, languageCode: string = 'en'): Promise<string> {
771
+ const result = await this.detectPiiEntities({
772
+ Text: text,
773
+ LanguageCode: languageCode,
774
+ })
775
+
776
+ // Sort by end offset descending to replace from end to start
777
+ const sorted = [...result.Entities].sort((a, b) => (b.EndOffset || 0) - (a.EndOffset || 0))
778
+
779
+ let redacted = text
780
+ for (const entity of sorted) {
781
+ if (entity.BeginOffset !== undefined && entity.EndOffset !== undefined) {
782
+ redacted = redacted.slice(0, entity.BeginOffset) + `[${entity.Type}]` + redacted.slice(entity.EndOffset)
783
+ }
784
+ }
785
+
786
+ return redacted
787
+ }
788
+ }
789
+
790
+ // ============================================================================
791
+ // Helper Functions
792
+ // ============================================================================
793
+
794
+ /**
795
+ * Quick sentiment analysis
796
+ */
797
+ export async function analyzeSentiment(
798
+ text: string,
799
+ options?: { languageCode?: string; region?: string },
800
+ ): Promise<{ sentiment: string; confidence: number }> {
801
+ const client = new ComprehendClient(options?.region || 'us-east-1')
802
+ const result = await client.analyzeSentiment(text, options?.languageCode || 'en')
803
+ const maxScore = Math.max(result.scores.positive, result.scores.negative, result.scores.neutral, result.scores.mixed)
804
+ return { sentiment: result.sentiment, confidence: maxScore }
805
+ }
806
+
807
+ /**
808
+ * Quick entity extraction
809
+ */
810
+ export async function extractEntities(
811
+ text: string,
812
+ options?: { languageCode?: string; region?: string },
813
+ ): Promise<Array<{ text: string; type: string }>> {
814
+ const client = new ComprehendClient(options?.region || 'us-east-1')
815
+ return client.extractEntities(text, options?.languageCode || 'en')
816
+ }
817
+
818
+ /**
819
+ * Quick language detection
820
+ */
821
+ export async function detectLanguage(
822
+ text: string,
823
+ region?: string,
824
+ ): Promise<string> {
825
+ const client = new ComprehendClient(region || 'us-east-1')
826
+ const result = await client.detectLanguage(text)
827
+ return result.languageCode
828
+ }
829
+
830
+ /**
831
+ * Quick PII check
832
+ */
833
+ export async function containsPii(
834
+ text: string,
835
+ options?: { languageCode?: string; region?: string },
836
+ ): Promise<boolean> {
837
+ const client = new ComprehendClient(options?.region || 'us-east-1')
838
+ return client.hasPii(text, options?.languageCode || 'en')
839
+ }