@exabugs/dynamodb-client 1.5.3 → 1.6.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/dist/server/handler.cjs +3 -3
- package/dist/server/media/magicBytes.d.ts.map +1 -1
- package/dist/server/media/magicBytes.js +17 -14
- package/dist/server/media/magicBytes.js.map +1 -1
- package/dist/server/media/media-handler.d.ts.map +1 -1
- package/dist/server/media/media-handler.js +38 -4
- package/dist/server/media/media-handler.js.map +1 -1
- package/dist/server/media/metadata.d.ts +29 -0
- package/dist/server/media/metadata.d.ts.map +1 -0
- package/dist/server/media/metadata.js +57 -0
- package/dist/server/media/metadata.js.map +1 -0
- package/dist/server/media/presign.d.ts.map +1 -1
- package/dist/server/media/presign.js +18 -1
- package/dist/server/media/presign.js.map +1 -1
- package/dist/server/media/process-handler-dlq.d.ts +0 -13
- package/dist/server/media/process-handler-dlq.d.ts.map +1 -1
- package/dist/server/media/process-handler-dlq.js +49 -7
- package/dist/server/media/process-handler-dlq.js.map +1 -1
- package/dist/server/media/process-handler.d.ts.map +1 -1
- package/dist/server/media/process-handler.js +40 -25
- package/dist/server/media/process-handler.js.map +1 -1
- package/dist/server/media/types.d.ts +1 -1
- package/dist/server/media/types.d.ts.map +1 -1
- package/dist/server/media/upload-handler.d.ts +50 -0
- package/dist/server/media/upload-handler.d.ts.map +1 -0
- package/dist/server/media/upload-handler.js +115 -0
- package/dist/server/media/upload-handler.js.map +1 -0
- package/dist/server/media-handler.cjs +27 -3
- package/dist/server/media-handler.cjs.map +2 -2
- package/dist/server/media-process-handler-dlq.cjs +25496 -13553
- package/dist/server/media-process-handler-dlq.cjs.map +4 -4
- package/dist/server/media-process-handler.cjs +648 -536
- package/dist/server/media-process-handler.cjs.map +4 -4
- package/dist/sharp-layer.zip +0 -0
- package/package.json +5 -1
- package/terraform/media/README.md +4 -1
- package/terraform/media/main.tf +86 -13
- package/terraform/media/variables.tf +33 -0
package/dist/sharp-layer.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exabugs/dynamodb-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "DynamoDB Single-Table Client SDK with MongoDB-like API, Shadow Records, and Lambda implementation for serverless applications",
|
|
5
5
|
"author": "exabugs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -91,6 +91,10 @@
|
|
|
91
91
|
"import": "./dist/server/media/presign.js",
|
|
92
92
|
"types": "./dist/server/media/presign.d.ts"
|
|
93
93
|
},
|
|
94
|
+
"./server/media/upload-handler": {
|
|
95
|
+
"import": "./dist/server/media/upload-handler.js",
|
|
96
|
+
"types": "./dist/server/media/upload-handler.d.ts"
|
|
97
|
+
},
|
|
94
98
|
"./server/media-process-handler": {
|
|
95
99
|
"import": "./dist/server/media-process-handler.cjs",
|
|
96
100
|
"types": "./dist/server/media/process-handler.d.ts"
|
|
@@ -17,7 +17,10 @@
|
|
|
17
17
|
- CloudFront Distribution(`/master/*`はS3直接配信、`/resize/*`はmedia-handler経由、両方とも署名付きURL必須)
|
|
18
18
|
- CloudFront Public Key / Key Group(署名鍵は呼び出し側がSSM Parameter Storeに別途登録する)
|
|
19
19
|
|
|
20
|
-
**含まないもの**: presign/署名URL発行用のLambda
|
|
20
|
+
**含まないもの**: presign/署名URL発行用のLambdaリソース。「誰にpresign/署名URLを発行してよいか」の認可判断はアプリごとに、かつ同一アプリ内でもクライアント(モバイル/管理画面等)ごとに異なるため、Terraformでは画一的なリソースとして定義できません。呼び出し側は次のいずれかの方法で自前にデプロイしてください:
|
|
21
|
+
|
|
22
|
+
- 既存のHTTP APIレイヤー(認証・権限チェック済み)から `../../src/server/media/presign.ts`・`sign.ts` を直接呼び出す
|
|
23
|
+
- 対応する既存HTTPレイヤーが無いクライアント向けには `../../src/server/media/upload-handler.ts` の `createUploadHandler()` を使い、専用の小さなLambdaとして自前でバンドル・デプロイする
|
|
21
24
|
|
|
22
25
|
## 前提条件
|
|
23
26
|
|
package/terraform/media/main.tf
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
# 詳細設計: ../../docs/media-design.md
|
|
4
4
|
# 決定事項・トレードオフ: ../../docs/adr/0002-media-design.md
|
|
5
5
|
#
|
|
6
|
-
# 本モジュールは upload-handler(presign/sign発行)のLambda
|
|
7
|
-
# 「誰にpresign/署名URL
|
|
8
|
-
#
|
|
9
|
-
#
|
|
6
|
+
# 本モジュールは upload-handler(presign/sign発行)のLambdaリソースを含まない。
|
|
7
|
+
# 「誰にpresign/署名URLを発行するか」の認可判断はアプリごとに、かつ同一アプリ内でも
|
|
8
|
+
# クライアント(モバイル/管理画面等)ごとに異なるため、Terraformでは画一的な
|
|
9
|
+
# リソースとして定義できない。呼び出し側は次のいずれかの方法で自前にデプロイすること:
|
|
10
|
+
# (a) 既存のHTTP APIレイヤー(認証・権限チェック済み)から
|
|
11
|
+
# `../../src/server/media/presign.ts`・`sign.ts` を直接呼び出す
|
|
12
|
+
# (b) 対応する既存HTTPレイヤーが無いクライアント(例: 別の認証方式を使う管理画面)向けには
|
|
13
|
+
# `../../src/server/media/upload-handler.ts` の `createUploadHandler()` を使い、
|
|
14
|
+
# 専用の小さなLambdaとして自前でバンドル・デプロイする
|
|
10
15
|
|
|
11
16
|
locals {
|
|
12
17
|
name_prefix = "${var.project_name}-${var.environment}-media"
|
|
@@ -51,6 +56,22 @@ resource "aws_s3_bucket_lifecycle_configuration" "media" {
|
|
|
51
56
|
}
|
|
52
57
|
}
|
|
53
58
|
|
|
59
|
+
# ブラウザ(管理画面等)からpresigned POSTで直接S3へアップロードする場合に必要。
|
|
60
|
+
# 無いとプリフライトリクエストが失敗しアップロードが全滅する
|
|
61
|
+
# (モバイルアプリ(React Native)はCORSの対象外のため影響しない)。
|
|
62
|
+
resource "aws_s3_bucket_cors_configuration" "media" {
|
|
63
|
+
count = length(var.allowed_upload_origins) > 0 ? 1 : 0
|
|
64
|
+
|
|
65
|
+
bucket = aws_s3_bucket.media.id
|
|
66
|
+
|
|
67
|
+
cors_rule {
|
|
68
|
+
allowed_methods = ["POST"]
|
|
69
|
+
allowed_origins = var.allowed_upload_origins
|
|
70
|
+
allowed_headers = ["*"]
|
|
71
|
+
max_age_seconds = 3000
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
54
75
|
# CloudFront OAC経由のアクセスのみ許可。Resourceはmaster/*に限定し、
|
|
55
76
|
# raw/*・cache/*をバケットポリシー経由で公開しない(cache/*はmedia-handlerの実行ロール経由のみ)
|
|
56
77
|
resource "aws_s3_bucket_policy" "media" {
|
|
@@ -158,8 +179,10 @@ resource "aws_iam_role_policy" "process_handler_dynamodb" {
|
|
|
158
179
|
Version = "2012-10-17"
|
|
159
180
|
Statement = [
|
|
160
181
|
{
|
|
161
|
-
Effect
|
|
162
|
-
|
|
182
|
+
Effect = "Allow"
|
|
183
|
+
# DeleteItem: updateMany(handleUpdateOneの内部実装)はTransactWriteの中で
|
|
184
|
+
# 更新前の古いShadow Recordを削除する処理を含むため、2回目以降の更新に必須
|
|
185
|
+
Action = ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem", "dynamodb:BatchGetItem", "dynamodb:Query"]
|
|
163
186
|
Resource = [var.table_arn, "${var.table_arn}/index/*"]
|
|
164
187
|
}
|
|
165
188
|
]
|
|
@@ -233,9 +256,13 @@ resource "aws_lambda_function" "process_handler" {
|
|
|
233
256
|
|
|
234
257
|
environment {
|
|
235
258
|
variables = {
|
|
236
|
-
REGION
|
|
237
|
-
TABLE_NAME
|
|
238
|
-
IMAGE_POLICY_PARAM
|
|
259
|
+
REGION = var.region
|
|
260
|
+
TABLE_NAME = var.table_name
|
|
261
|
+
IMAGE_POLICY_PARAM = var.image_policy_param
|
|
262
|
+
SHADOW_CREATED_AT_FIELD = var.shadow_created_at_field
|
|
263
|
+
SHADOW_UPDATED_AT_FIELD = var.shadow_updated_at_field
|
|
264
|
+
SHADOW_STRING_MAX_BYTES = var.shadow_string_max_bytes
|
|
265
|
+
SHADOW_NUMBER_PADDING = var.shadow_number_padding
|
|
239
266
|
}
|
|
240
267
|
}
|
|
241
268
|
|
|
@@ -254,6 +281,11 @@ resource "aws_lambda_function" "process_handler" {
|
|
|
254
281
|
resource "aws_lambda_function_event_invoke_config" "process_handler" {
|
|
255
282
|
function_name = aws_lambda_function.process_handler.function_name
|
|
256
283
|
maximum_retry_attempts = 2
|
|
284
|
+
# 既定の6時間だと、リトライが尽きてDLQ経由でfailedが書き込まれるまで
|
|
285
|
+
# 呼び出し側のポーリングが長時間ブロックされ得る。短く設定し、クライアントの
|
|
286
|
+
# タイムアウト判断(詳細: docs/media-design.md「ポーリングが区別すべき状態」)
|
|
287
|
+
# と整合させる。
|
|
288
|
+
maximum_event_age_in_seconds = 300
|
|
257
289
|
|
|
258
290
|
destination_config {
|
|
259
291
|
on_failure {
|
|
@@ -326,6 +358,27 @@ resource "aws_iam_role_policy" "process_handler_dlq_sqs" {
|
|
|
326
358
|
})
|
|
327
359
|
}
|
|
328
360
|
|
|
361
|
+
resource "aws_iam_role_policy" "process_handler_dlq_s3" {
|
|
362
|
+
name = "s3-access"
|
|
363
|
+
role = aws_iam_role.process_handler_dlq.id
|
|
364
|
+
|
|
365
|
+
# failedレコードにownerId等のアプリ固有メタデータを含めるため、raw/{fileId}を
|
|
366
|
+
# HeadObjectで再取得する(process-handler-dlq.ts)。この権限が無いとHeadObjectが
|
|
367
|
+
# 常にAccessDeniedになり、fail-soft設計により静かに失敗し続ける
|
|
368
|
+
# (メタデータ無しのfailedレコードが書き込まれ、権限スコープ付きポーリングで
|
|
369
|
+
# 読めないままクライアントが無限ポーリングする問題が再発する)。
|
|
370
|
+
policy = jsonencode({
|
|
371
|
+
Version = "2012-10-17"
|
|
372
|
+
Statement = [
|
|
373
|
+
{
|
|
374
|
+
Effect = "Allow"
|
|
375
|
+
Action = ["s3:GetObject"]
|
|
376
|
+
Resource = "${aws_s3_bucket.media.arn}/raw/*"
|
|
377
|
+
}
|
|
378
|
+
]
|
|
379
|
+
})
|
|
380
|
+
}
|
|
381
|
+
|
|
329
382
|
resource "aws_iam_role_policy" "process_handler_dlq_dynamodb" {
|
|
330
383
|
name = "dynamodb-access"
|
|
331
384
|
role = aws_iam_role.process_handler_dlq.id
|
|
@@ -335,7 +388,7 @@ resource "aws_iam_role_policy" "process_handler_dlq_dynamodb" {
|
|
|
335
388
|
Statement = [
|
|
336
389
|
{
|
|
337
390
|
Effect = "Allow"
|
|
338
|
-
Action = ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:BatchGetItem"]
|
|
391
|
+
Action = ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem", "dynamodb:BatchGetItem"]
|
|
339
392
|
Resource = [var.table_arn, "${var.table_arn}/index/*"]
|
|
340
393
|
}
|
|
341
394
|
]
|
|
@@ -374,8 +427,12 @@ resource "aws_lambda_function" "process_handler_dlq" {
|
|
|
374
427
|
|
|
375
428
|
environment {
|
|
376
429
|
variables = {
|
|
377
|
-
REGION
|
|
378
|
-
TABLE_NAME
|
|
430
|
+
REGION = var.region
|
|
431
|
+
TABLE_NAME = var.table_name
|
|
432
|
+
SHADOW_CREATED_AT_FIELD = var.shadow_created_at_field
|
|
433
|
+
SHADOW_UPDATED_AT_FIELD = var.shadow_updated_at_field
|
|
434
|
+
SHADOW_STRING_MAX_BYTES = var.shadow_string_max_bytes
|
|
435
|
+
SHADOW_NUMBER_PADDING = var.shadow_number_padding
|
|
379
436
|
}
|
|
380
437
|
}
|
|
381
438
|
|
|
@@ -383,6 +440,7 @@ resource "aws_lambda_function" "process_handler_dlq" {
|
|
|
383
440
|
aws_cloudwatch_log_group.process_handler_dlq,
|
|
384
441
|
aws_iam_role_policy.process_handler_dlq_sqs,
|
|
385
442
|
aws_iam_role_policy.process_handler_dlq_dynamodb,
|
|
443
|
+
aws_iam_role_policy.process_handler_dlq_s3,
|
|
386
444
|
]
|
|
387
445
|
|
|
388
446
|
tags = {
|
|
@@ -534,7 +592,7 @@ resource "aws_lambda_function_url" "media_handler" {
|
|
|
534
592
|
}
|
|
535
593
|
|
|
536
594
|
resource "aws_lambda_permission" "cloudfront_invoke_media_handler" {
|
|
537
|
-
statement_id = "
|
|
595
|
+
statement_id = "AllowCloudFrontInvokeFunctionUrl"
|
|
538
596
|
action = "lambda:InvokeFunctionUrl"
|
|
539
597
|
function_name = aws_lambda_function.media_handler.function_name
|
|
540
598
|
principal = "cloudfront.amazonaws.com"
|
|
@@ -542,6 +600,21 @@ resource "aws_lambda_permission" "cloudfront_invoke_media_handler" {
|
|
|
542
600
|
function_url_auth_type = "AWS_IAM"
|
|
543
601
|
}
|
|
544
602
|
|
|
603
|
+
# AWSはFunction URL + OAC経由の呼び出しに対してDual Auth(lambda:InvokeFunctionUrl
|
|
604
|
+
# とlambda:InvokeFunctionの両方の許可)を正式に要求する(移行猶予期間は2026-11-01
|
|
605
|
+
# まで)。lambda:InvokeFunctionUrlだけの許可では、猶予期間終了後に/resize/*が
|
|
606
|
+
# 全件403になる(詳細: docs/adr/0002-media-design.md)。
|
|
607
|
+
# invoked_via_function_url=true により、この許可をFunction URL経由の呼び出しに
|
|
608
|
+
# 限定する(AWS推奨の条件キー)。
|
|
609
|
+
resource "aws_lambda_permission" "cloudfront_invoke_media_handler_function" {
|
|
610
|
+
statement_id = "AllowCloudFrontInvokeFunction"
|
|
611
|
+
action = "lambda:InvokeFunction"
|
|
612
|
+
function_name = aws_lambda_function.media_handler.function_name
|
|
613
|
+
principal = "cloudfront.amazonaws.com"
|
|
614
|
+
source_arn = aws_cloudfront_distribution.media.arn
|
|
615
|
+
invoked_via_function_url = true
|
|
616
|
+
}
|
|
617
|
+
|
|
545
618
|
# ============================================================
|
|
546
619
|
# CloudFront配信(署名付きURL必須、/master/*・/resize/*の2ビヘイビア)
|
|
547
620
|
# ============================================================
|
|
@@ -31,6 +31,39 @@ variable "image_cache_ttl_days" {
|
|
|
31
31
|
default = 30
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
variable "allowed_upload_origins" {
|
|
35
|
+
description = "presigned POSTでのブラウザアップロードを許可するオリジン(例: Admin UIのドメイン)。空配列の場合はCORS設定自体を作らない(モバイルのみの利用等、ブラウザアップロードが不要な場合)"
|
|
36
|
+
type = list(string)
|
|
37
|
+
default = []
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# 呼び出し側の既存テーブルに相乗りするため、process-handlerが生成するShadow Recordsの
|
|
41
|
+
# 形式は呼び出し側の既存Lambda(records等)の設定と一致させる必要がある
|
|
42
|
+
# (詳細: docs/media-design.md「環境変数の一致」)。既定値は本体(terraform/variables.tf)と揃える。
|
|
43
|
+
variable "shadow_created_at_field" {
|
|
44
|
+
description = "作成日時フィールド名(呼び出し側の既存設定と一致させること)"
|
|
45
|
+
type = string
|
|
46
|
+
default = "createdAt"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
variable "shadow_updated_at_field" {
|
|
50
|
+
description = "更新日時フィールド名(呼び出し側の既存設定と一致させること)"
|
|
51
|
+
type = string
|
|
52
|
+
default = "updatedAt"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
variable "shadow_string_max_bytes" {
|
|
56
|
+
description = "プリミティブ型の最大バイト数(呼び出し側の既存設定と一致させること)"
|
|
57
|
+
type = number
|
|
58
|
+
default = 100
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
variable "shadow_number_padding" {
|
|
62
|
+
description = "数値のパディング桁数(呼び出し側の既存設定と一致させること)"
|
|
63
|
+
type = number
|
|
64
|
+
default = 15
|
|
65
|
+
}
|
|
66
|
+
|
|
34
67
|
variable "signing_public_key_param" {
|
|
35
68
|
description = "CloudFront署名用の公開鍵(PEM形式)を保持するSSM Parameter名。値そのものは呼び出し側が別途登録する"
|
|
36
69
|
type = string
|