@exabugs/dynamodb-client 1.14.1 → 1.15.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 +28 -0
- package/dist/server/handler.cjs +3 -3
- package/dist/server/media/process-handler-dlq.d.ts.map +1 -1
- package/dist/server/media/process-handler-dlq.js +8 -19
- 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 +5 -18
- package/dist/server/media/process-handler.js.map +1 -1
- package/dist/server/media/recordsClient.d.ts +13 -0
- package/dist/server/media/recordsClient.d.ts.map +1 -0
- package/dist/server/media/recordsClient.js +55 -0
- package/dist/server/media/recordsClient.js.map +1 -0
- package/dist/server/media-handler.cjs +2 -2
- package/dist/server/media-process-handler-dlq.cjs +1143 -3613
- package/dist/server/media-process-handler-dlq.cjs.map +4 -4
- package/dist/server/media-process-handler.cjs +1194 -3679
- package/dist/server/media-process-handler.cjs.map +4 -4
- package/docs/DYNAMODB_ACCESS.md +17 -9
- package/package.json +1 -1
- package/terraform/media/README.md +5 -2
- package/terraform/media/main.tf +26 -27
- package/terraform/media/variables.tf +36 -9
package/docs/DYNAMODB_ACCESS.md
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
# DynamoDB へのアクセスのガードレール
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## アーキテクチャ(全文。他の文書は、これを要約して参照する)
|
|
4
4
|
|
|
5
|
-
dynamodb-client
|
|
6
|
-
|
|
5
|
+
**DynamoDB の操作は、dynamodb-client(Records)の 1 か所で行う。**
|
|
6
|
+
|
|
7
|
+
- クライアント(BFF、管理画面、media の Lambda、運用スクリプト)は、**ビジネスのリクエスト**を受け、dynamodb-client の API(Records)への操作に展開する。通常の操作の API は `DynamoClient`。**media のアップロードの処理も、ビジネスのリクエストの一つ**であり、BFF など他のクライアントと区別しない。
|
|
8
|
+
- DynamoDB の操作の制御(認可、監査、シャドーの維持、観測、容量)は、Records の **1 か所**で行う。全クライアントが Records に依存する、同じ構造である。
|
|
9
|
+
- **例外を作らない。** 例外(Lambda が本体テーブルを直接読み書きするなど)は、監査ログ(ADR 0004)のような横断機能の穴になる。直接アクセスは、ガードレール(ESLint と IAM の検査。許可リスト)で禁止する。
|
|
10
|
+
- **対象外**(別テーブル `notices` など)は、構造が違う内部用のテーブルで、ビジネスのデータではない。「例外」ではない。
|
|
11
|
+
|
|
12
|
+
### 書き方の規則
|
|
13
|
+
|
|
14
|
+
設計書・ADR では、Records への依存や HTTP 1 回分の遅延を、「限界」「問題」として書かない。**アーキテクチャの帰結(設計上の性質)**として書く。Records にリソースごとの認可がない、という既知の制約は、この構造とは独立に、別に書く([AUTHORIZATION.md](AUTHORIZATION.md))。
|
|
15
|
+
|
|
16
|
+
関連: [ADR 0005](adr/0005-writes-through-records.md)(書き込みを Records に通す。「0. アーキテクチャ(前提)」)。
|
|
7
17
|
|
|
8
18
|
## 検査
|
|
9
19
|
|
|
@@ -128,7 +138,7 @@ ESLint は、エディタでも違反をその場で示す。CLI は ESLint の
|
|
|
128
138
|
|
|
129
139
|
## 許可リストの種別と約束
|
|
130
140
|
|
|
131
|
-
- **恒久(permanent)**: 構造上必要な例外。このライブラリでは、Records の本体、Records が使う共有部品、別テーブル `notices`(`src/notify/store.ts
|
|
141
|
+
- **恒久(permanent)**: 構造上必要な例外。このライブラリでは、Records の本体、Records が使う共有部品、別テーブル `notices`(`src/notify/store.ts`)。`notices` は例外ではなく原則の**対象外**(構造が違う別テーブルで、通知の重複抑制・流量制限の内部用。ビジネスのデータではない)。検査が IAM をテーブルごとに区別できないため permanent として載せる(ADR 0005)
|
|
132
142
|
- **負債(debt)**: 期限つき。消す作業が決まっている
|
|
133
143
|
|
|
134
144
|
運用の約束:
|
|
@@ -145,8 +155,6 @@ ESLint は、エディタでも違反をその場で示す。CLI は ESLint の
|
|
|
145
155
|
|
|
146
156
|
## 現状の負債
|
|
147
157
|
|
|
148
|
-
| 場所
|
|
149
|
-
|
|
|
150
|
-
| `src/
|
|
151
|
-
| `terraform/media/main.tf` の `process_handler_dynamodb`、`process_handler_dlq_dynamodb` | media の Lambda に本体テーブルの権限 | 同上 |
|
|
152
|
-
| `src/dynamodb.ts` | 本体と重複した未使用のクライアント生成(テストからのみ参照) | `src/dynamodb.ts` と `__tests__/dynamodb.test.ts` の削除 |
|
|
158
|
+
| 場所 | 内容 | 消す作業 |
|
|
159
|
+
| ----------------- | ------------------------------------------------------------ | -------------------------------------------------------- |
|
|
160
|
+
| `src/dynamodb.ts` | 本体と重複した未使用のクライアント生成(テストからのみ参照) | `src/dynamodb.ts` と `__tests__/dynamodb.test.ts` の削除 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exabugs/dynamodb-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.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",
|
|
@@ -38,8 +38,11 @@ module "media" {
|
|
|
38
38
|
environment = "dev"
|
|
39
39
|
region = "ap-northeast-1"
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
table_arn
|
|
41
|
+
# Records の IAM 版 Function URL とエイリアスの ARN(本体の出力)。media の Lambda は
|
|
42
|
+
# DynamoDB に直接触れず、Records を呼ぶ(ADR 0005)。table_name / table_arn / shadow_* は
|
|
43
|
+
# deprecated(1.16.0 で削除)で、渡しても無視される
|
|
44
|
+
records_iam_function_url = module.records.iam_function_url
|
|
45
|
+
records_iam_alias_arn = module.records.iam_alias_arn
|
|
43
46
|
|
|
44
47
|
signing_public_key_param = "/my-project/dev/media/signing-public-key"
|
|
45
48
|
image_policy_param = "/my-project/dev/media/image-policy"
|
package/terraform/media/main.tf
CHANGED
|
@@ -104,6 +104,11 @@ resource "aws_sqs_queue" "process_handler_dlq" {
|
|
|
104
104
|
name = "${local.name_prefix}-process-dlq"
|
|
105
105
|
message_retention_seconds = 1209600 # 14日(SQS上限)
|
|
106
106
|
|
|
107
|
+
# Lambda(process-handler-dlq)のイベントソースになるキューの可視性タイムアウトは、関数の
|
|
108
|
+
# timeout 以上が必須(満たさないとマッピングの作成・更新が拒否される)。AWS の推奨は 6 倍
|
|
109
|
+
# (AWS Lambda 開発者ガイド「Amazon SQS でのイベントソースマッピング」、ADR 0005)
|
|
110
|
+
visibility_timeout_seconds = var.process_handler_dlq_timeout * 6
|
|
111
|
+
|
|
107
112
|
tags = {
|
|
108
113
|
Name = "${local.name_prefix}-process-dlq"
|
|
109
114
|
}
|
|
@@ -180,19 +185,19 @@ resource "aws_iam_role_policy" "process_handler_s3" {
|
|
|
180
185
|
})
|
|
181
186
|
}
|
|
182
187
|
|
|
183
|
-
resource "aws_iam_role_policy" "
|
|
184
|
-
name = "
|
|
188
|
+
resource "aws_iam_role_policy" "process_handler_records" {
|
|
189
|
+
name = "records-invoke"
|
|
185
190
|
role = aws_iam_role.process_handler.id
|
|
186
191
|
|
|
192
|
+
# DynamoDB には直接触れず、Records の IAM 版 Function URL を呼ぶ(ADR 0005)
|
|
187
193
|
policy = jsonencode({
|
|
188
194
|
Version = "2012-10-17"
|
|
189
195
|
Statement = [
|
|
190
196
|
{
|
|
191
197
|
Effect = "Allow"
|
|
192
|
-
#
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
Resource = [var.table_arn, "${var.table_arn}/index/*"]
|
|
198
|
+
# 2025 年 10 月以降の新しい Function URL(AWS_IAM)は両方の権限が必要(AWS 公式ドキュメント urls-auth、ADR 0005)
|
|
199
|
+
Action = ["lambda:InvokeFunction", "lambda:InvokeFunctionUrl"]
|
|
200
|
+
Resource = var.records_iam_alias_arn
|
|
196
201
|
}
|
|
197
202
|
]
|
|
198
203
|
})
|
|
@@ -265,20 +270,16 @@ resource "aws_lambda_function" "process_handler" {
|
|
|
265
270
|
|
|
266
271
|
environment {
|
|
267
272
|
variables = {
|
|
268
|
-
REGION
|
|
269
|
-
|
|
270
|
-
IMAGE_POLICY_PARAM
|
|
271
|
-
SHADOW_CREATED_AT_FIELD = var.shadow_created_at_field
|
|
272
|
-
SHADOW_UPDATED_AT_FIELD = var.shadow_updated_at_field
|
|
273
|
-
SHADOW_STRING_MAX_BYTES = var.shadow_string_max_bytes
|
|
274
|
-
SHADOW_NUMBER_PADDING = var.shadow_number_padding
|
|
273
|
+
REGION = var.region
|
|
274
|
+
RECORDS_IAM_URL = var.records_iam_function_url
|
|
275
|
+
IMAGE_POLICY_PARAM = var.image_policy_param
|
|
275
276
|
}
|
|
276
277
|
}
|
|
277
278
|
|
|
278
279
|
depends_on = [
|
|
279
280
|
aws_cloudwatch_log_group.process_handler,
|
|
280
281
|
aws_iam_role_policy.process_handler_s3,
|
|
281
|
-
aws_iam_role_policy.
|
|
282
|
+
aws_iam_role_policy.process_handler_records,
|
|
282
283
|
aws_iam_role_policy.process_handler_ssm,
|
|
283
284
|
]
|
|
284
285
|
|
|
@@ -388,17 +389,19 @@ resource "aws_iam_role_policy" "process_handler_dlq_s3" {
|
|
|
388
389
|
})
|
|
389
390
|
}
|
|
390
391
|
|
|
391
|
-
resource "aws_iam_role_policy" "
|
|
392
|
-
name = "
|
|
392
|
+
resource "aws_iam_role_policy" "process_handler_dlq_records" {
|
|
393
|
+
name = "records-invoke"
|
|
393
394
|
role = aws_iam_role.process_handler_dlq.id
|
|
394
395
|
|
|
396
|
+
# DynamoDB には直接触れず、Records の IAM 版 Function URL を呼ぶ(ADR 0005)
|
|
395
397
|
policy = jsonencode({
|
|
396
398
|
Version = "2012-10-17"
|
|
397
399
|
Statement = [
|
|
398
400
|
{
|
|
399
|
-
Effect
|
|
400
|
-
|
|
401
|
-
|
|
401
|
+
Effect = "Allow"
|
|
402
|
+
# 2025 年 10 月以降の新しい Function URL(AWS_IAM)は両方の権限が必要(AWS 公式ドキュメント urls-auth、ADR 0005)
|
|
403
|
+
Action = ["lambda:InvokeFunction", "lambda:InvokeFunctionUrl"]
|
|
404
|
+
Resource = var.records_iam_alias_arn
|
|
402
405
|
}
|
|
403
406
|
]
|
|
404
407
|
})
|
|
@@ -431,24 +434,20 @@ resource "aws_lambda_function" "process_handler_dlq" {
|
|
|
431
434
|
architectures = ["arm64"]
|
|
432
435
|
handler = "media-process-handler-dlq.handler"
|
|
433
436
|
|
|
434
|
-
timeout =
|
|
437
|
+
timeout = var.process_handler_dlq_timeout
|
|
435
438
|
memory_size = 256
|
|
436
439
|
|
|
437
440
|
environment {
|
|
438
441
|
variables = {
|
|
439
|
-
REGION
|
|
440
|
-
|
|
441
|
-
SHADOW_CREATED_AT_FIELD = var.shadow_created_at_field
|
|
442
|
-
SHADOW_UPDATED_AT_FIELD = var.shadow_updated_at_field
|
|
443
|
-
SHADOW_STRING_MAX_BYTES = var.shadow_string_max_bytes
|
|
444
|
-
SHADOW_NUMBER_PADDING = var.shadow_number_padding
|
|
442
|
+
REGION = var.region
|
|
443
|
+
RECORDS_IAM_URL = var.records_iam_function_url
|
|
445
444
|
}
|
|
446
445
|
}
|
|
447
446
|
|
|
448
447
|
depends_on = [
|
|
449
448
|
aws_cloudwatch_log_group.process_handler_dlq,
|
|
450
449
|
aws_iam_role_policy.process_handler_dlq_sqs,
|
|
451
|
-
aws_iam_role_policy.
|
|
450
|
+
aws_iam_role_policy.process_handler_dlq_records,
|
|
452
451
|
aws_iam_role_policy.process_handler_dlq_s3,
|
|
453
452
|
]
|
|
454
453
|
|
|
@@ -15,14 +15,37 @@ variable "region" {
|
|
|
15
15
|
type = string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
variable "records_iam_function_url" {
|
|
19
|
+
description = "Records の IAM 認証版の Function URL(本体の出力 iam_function_url。認証なし版の URL ではない)。media の Lambda はこれを SigV4 署名で呼び、DynamoDB には直接触れない(ADR 0005)"
|
|
20
|
+
type = string
|
|
21
|
+
|
|
22
|
+
# IAM 版と認証なし版は URL では区別できないので、形だけ検査する
|
|
23
|
+
validation {
|
|
24
|
+
condition = can(regex("^https://[a-z0-9]+\\.lambda-url\\.[a-z0-9-]+\\.on\\.aws/$", var.records_iam_function_url))
|
|
25
|
+
error_message = "Records の IAM 認証版の Function URL(dynamodb_client_api_iam_function_url)を渡すこと。形式: https://<id>.lambda-url.<region>.on.aws/(末尾は /)。"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
variable "records_iam_alias_arn" {
|
|
30
|
+
description = "Records の IAM 版エイリアスの ARN(本体の出力 iam_alias_arn)。lambda:InvokeFunctionUrl と lambda:InvokeFunction の許可の対象(ADR 0005)"
|
|
31
|
+
type = string
|
|
32
|
+
|
|
33
|
+
validation {
|
|
34
|
+
condition = can(regex("^arn:aws[a-z-]*:lambda:[a-z0-9-]+:[0-9]{12}:function:[^:]+:[^:]+$", var.records_iam_alias_arn))
|
|
35
|
+
error_message = "Records の IAM 版エイリアスの ARN(dynamodb_client_api_iam_alias_arn。…:function:<名前>:<エイリアス> の修飾つき)を渡すこと。"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
18
39
|
variable "table_name" {
|
|
19
|
-
description = "
|
|
40
|
+
description = "deprecated。1.16.0 で削除(ADR 0005)。media の Lambda は DynamoDB に直接触れなくなったため無視される。"
|
|
20
41
|
type = string
|
|
42
|
+
default = ""
|
|
21
43
|
}
|
|
22
44
|
|
|
23
45
|
variable "table_arn" {
|
|
24
|
-
description = "
|
|
46
|
+
description = "deprecated。1.16.0 で削除(ADR 0005)。media の Lambda は DynamoDB に直接触れなくなったため無視される。"
|
|
25
47
|
type = string
|
|
48
|
+
default = ""
|
|
26
49
|
}
|
|
27
50
|
|
|
28
51
|
variable "image_cache_ttl_days" {
|
|
@@ -37,29 +60,27 @@ variable "allowed_upload_origins" {
|
|
|
37
60
|
default = []
|
|
38
61
|
}
|
|
39
62
|
|
|
40
|
-
#
|
|
41
|
-
# 形式は呼び出し側の既存Lambda(records等)の設定と一致させる必要がある
|
|
42
|
-
# (詳細: docs/media-design.md「環境変数の一致」)。既定値は本体(terraform/variables.tf)と揃える。
|
|
63
|
+
# 以下の shadow_* は deprecated(1.16.0 で削除。ADR 0005)。Records 経由になったため無視される。
|
|
43
64
|
variable "shadow_created_at_field" {
|
|
44
|
-
description = "
|
|
65
|
+
description = "deprecated。1.16.0 で削除(ADR 0005)。media の Lambda は DynamoDB に直接触れなくなったため無視される。"
|
|
45
66
|
type = string
|
|
46
67
|
default = "createdAt"
|
|
47
68
|
}
|
|
48
69
|
|
|
49
70
|
variable "shadow_updated_at_field" {
|
|
50
|
-
description = "
|
|
71
|
+
description = "deprecated。1.16.0 で削除(ADR 0005)。media の Lambda は DynamoDB に直接触れなくなったため無視される。"
|
|
51
72
|
type = string
|
|
52
73
|
default = "updatedAt"
|
|
53
74
|
}
|
|
54
75
|
|
|
55
76
|
variable "shadow_string_max_bytes" {
|
|
56
|
-
description = "
|
|
77
|
+
description = "deprecated。1.16.0 で削除(ADR 0005)。media の Lambda は DynamoDB に直接触れなくなったため無視される。"
|
|
57
78
|
type = number
|
|
58
79
|
default = 100
|
|
59
80
|
}
|
|
60
81
|
|
|
61
82
|
variable "shadow_number_padding" {
|
|
62
|
-
description = "
|
|
83
|
+
description = "deprecated。1.16.0 で削除(ADR 0005)。media の Lambda は DynamoDB に直接触れなくなったため無視される。"
|
|
63
84
|
type = number
|
|
64
85
|
default = 15
|
|
65
86
|
}
|
|
@@ -115,3 +136,9 @@ variable "route53_zone_id" {
|
|
|
115
136
|
type = string
|
|
116
137
|
default = null
|
|
117
138
|
}
|
|
139
|
+
|
|
140
|
+
variable "process_handler_dlq_timeout" {
|
|
141
|
+
description = "process-handler-dlq Lambdaのタイムアウト(秒)。Records の読み取り・書き込みのクライアント timeout(各 15 秒)と HeadObject が収まる値にする"
|
|
142
|
+
type = number
|
|
143
|
+
default = 60
|
|
144
|
+
}
|