@exabugs/dynamodb-client 0.1.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 +41 -0
- package/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/client/Collection.d.ts +57 -0
- package/dist/client/Collection.d.ts.map +1 -0
- package/dist/client/Collection.js +174 -0
- package/dist/client/Collection.js.map +1 -0
- package/dist/client/Database.d.ts +35 -0
- package/dist/client/Database.d.ts.map +1 -0
- package/dist/client/Database.js +48 -0
- package/dist/client/Database.js.map +1 -0
- package/dist/client/DynamoClient.d.ts +43 -0
- package/dist/client/DynamoClient.d.ts.map +1 -0
- package/dist/client/DynamoClient.js +62 -0
- package/dist/client/DynamoClient.js.map +1 -0
- package/dist/client/FindCursor.d.ts +174 -0
- package/dist/client/FindCursor.d.ts.map +1 -0
- package/dist/client/FindCursor.js +256 -0
- package/dist/client/FindCursor.js.map +1 -0
- package/dist/client/aws-sigv4.d.ts +10 -0
- package/dist/client/aws-sigv4.d.ts.map +1 -0
- package/dist/client/aws-sigv4.js +54 -0
- package/dist/client/aws-sigv4.js.map +1 -0
- package/dist/client/index.cognito.d.ts +34 -0
- package/dist/client/index.cognito.d.ts.map +1 -0
- package/dist/client/index.cognito.js +30 -0
- package/dist/client/index.cognito.js.map +1 -0
- package/dist/client/index.d.ts +12 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.iam.d.ts +34 -0
- package/dist/client/index.iam.d.ts.map +1 -0
- package/dist/client/index.iam.js +28 -0
- package/dist/client/index.iam.js.map +1 -0
- package/dist/client/index.js +12 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/index.token.d.ts +33 -0
- package/dist/client/index.token.d.ts.map +1 -0
- package/dist/client/index.token.js +28 -0
- package/dist/client/index.token.js.map +1 -0
- package/dist/dynamodb.d.ts +20 -0
- package/dist/dynamodb.d.ts.map +1 -0
- package/dist/dynamodb.js +31 -0
- package/dist/dynamodb.js.map +1 -0
- package/dist/errors.d.ts +100 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +146 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/react-admin/dataProvider.d.ts +59 -0
- package/dist/integrations/react-admin/dataProvider.d.ts.map +1 -0
- package/dist/integrations/react-admin/dataProvider.js +364 -0
- package/dist/integrations/react-admin/dataProvider.js.map +1 -0
- package/dist/integrations/react-admin/index.d.ts +24 -0
- package/dist/integrations/react-admin/index.d.ts.map +1 -0
- package/dist/integrations/react-admin/index.js +23 -0
- package/dist/integrations/react-admin/index.js.map +1 -0
- package/dist/integrations/react-admin/types.d.ts +47 -0
- package/dist/integrations/react-admin/types.d.ts.map +1 -0
- package/dist/integrations/react-admin/types.js +5 -0
- package/dist/integrations/react-admin/types.js.map +1 -0
- package/dist/logger.d.ts +61 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +87 -0
- package/dist/logger.js.map +1 -0
- package/dist/scripts/repair-shadows.d.ts +3 -0
- package/dist/scripts/repair-shadows.d.ts.map +1 -0
- package/dist/scripts/repair-shadows.js +190 -0
- package/dist/scripts/repair-shadows.js.map +1 -0
- package/dist/server/handler.cjs +31378 -0
- package/dist/server/handler.cjs.map +7 -0
- package/dist/server/handler.d.ts +18 -0
- package/dist/server/handler.d.ts.map +1 -0
- package/dist/server/handler.js +435 -0
- package/dist/server/handler.js.map +1 -0
- package/dist/server/handler.zip +0 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +8 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/operations/deleteMany.d.ts +18 -0
- package/dist/server/operations/deleteMany.d.ts.map +1 -0
- package/dist/server/operations/deleteMany.js +222 -0
- package/dist/server/operations/deleteMany.js.map +1 -0
- package/dist/server/operations/deleteOne.d.ts +17 -0
- package/dist/server/operations/deleteOne.d.ts.map +1 -0
- package/dist/server/operations/deleteOne.js +87 -0
- package/dist/server/operations/deleteOne.js.map +1 -0
- package/dist/server/operations/find.d.ts +18 -0
- package/dist/server/operations/find.d.ts.map +1 -0
- package/dist/server/operations/find.js +382 -0
- package/dist/server/operations/find.js.map +1 -0
- package/dist/server/operations/findMany.d.ts +13 -0
- package/dist/server/operations/findMany.d.ts.map +1 -0
- package/dist/server/operations/findMany.js +61 -0
- package/dist/server/operations/findMany.js.map +1 -0
- package/dist/server/operations/findManyReference.d.ts +18 -0
- package/dist/server/operations/findManyReference.d.ts.map +1 -0
- package/dist/server/operations/findManyReference.js +150 -0
- package/dist/server/operations/findManyReference.js.map +1 -0
- package/dist/server/operations/findOne.d.ts +14 -0
- package/dist/server/operations/findOne.d.ts.map +1 -0
- package/dist/server/operations/findOne.js +56 -0
- package/dist/server/operations/findOne.js.map +1 -0
- package/dist/server/operations/insertMany.d.ts +19 -0
- package/dist/server/operations/insertMany.d.ts.map +1 -0
- package/dist/server/operations/insertMany.js +243 -0
- package/dist/server/operations/insertMany.js.map +1 -0
- package/dist/server/operations/insertOne.d.ts +18 -0
- package/dist/server/operations/insertOne.d.ts.map +1 -0
- package/dist/server/operations/insertOne.js +85 -0
- package/dist/server/operations/insertOne.js.map +1 -0
- package/dist/server/operations/updateMany.d.ts +20 -0
- package/dist/server/operations/updateMany.d.ts.map +1 -0
- package/dist/server/operations/updateMany.js +316 -0
- package/dist/server/operations/updateMany.js.map +1 -0
- package/dist/server/operations/updateOne.d.ts +20 -0
- package/dist/server/operations/updateOne.d.ts.map +1 -0
- package/dist/server/operations/updateOne.js +159 -0
- package/dist/server/operations/updateOne.js.map +1 -0
- package/dist/server/query/converter.d.ts +85 -0
- package/dist/server/query/converter.d.ts.map +1 -0
- package/dist/server/query/converter.js +161 -0
- package/dist/server/query/converter.js.map +1 -0
- package/dist/server/query/index.d.ts +5 -0
- package/dist/server/query/index.d.ts.map +1 -0
- package/dist/server/query/index.js +5 -0
- package/dist/server/query/index.js.map +1 -0
- package/dist/server/shadow/config.d.ts +147 -0
- package/dist/server/shadow/config.d.ts.map +1 -0
- package/dist/server/shadow/config.js +162 -0
- package/dist/server/shadow/config.js.map +1 -0
- package/dist/server/shadow/differ.d.ts +42 -0
- package/dist/server/shadow/differ.d.ts.map +1 -0
- package/dist/server/shadow/differ.js +66 -0
- package/dist/server/shadow/differ.js.map +1 -0
- package/dist/server/shadow/generator.d.ts +104 -0
- package/dist/server/shadow/generator.d.ts.map +1 -0
- package/dist/server/shadow/generator.js +148 -0
- package/dist/server/shadow/generator.js.map +1 -0
- package/dist/server/shadow/index.d.ts +11 -0
- package/dist/server/shadow/index.d.ts.map +1 -0
- package/dist/server/shadow/index.js +11 -0
- package/dist/server/shadow/index.js.map +1 -0
- package/dist/server/shadow/types.d.ts +44 -0
- package/dist/server/shadow/types.d.ts.map +1 -0
- package/dist/server/shadow/types.js +2 -0
- package/dist/server/shadow/types.js.map +1 -0
- package/dist/server/types.d.ts +295 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +7 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/utils/auth.d.ts +43 -0
- package/dist/server/utils/auth.d.ts.map +1 -0
- package/dist/server/utils/auth.js +123 -0
- package/dist/server/utils/auth.js.map +1 -0
- package/dist/server/utils/bulkOperations.d.ts +81 -0
- package/dist/server/utils/bulkOperations.d.ts.map +1 -0
- package/dist/server/utils/bulkOperations.js +147 -0
- package/dist/server/utils/bulkOperations.js.map +1 -0
- package/dist/server/utils/chunking.d.ts +96 -0
- package/dist/server/utils/chunking.d.ts.map +1 -0
- package/dist/server/utils/chunking.js +225 -0
- package/dist/server/utils/chunking.js.map +1 -0
- package/dist/server/utils/dynamodb.d.ts +41 -0
- package/dist/server/utils/dynamodb.d.ts.map +1 -0
- package/dist/server/utils/dynamodb.js +83 -0
- package/dist/server/utils/dynamodb.js.map +1 -0
- package/dist/server/utils/filter.d.ts +152 -0
- package/dist/server/utils/filter.d.ts.map +1 -0
- package/dist/server/utils/filter.js +270 -0
- package/dist/server/utils/filter.js.map +1 -0
- package/dist/server/utils/pagination.d.ts +27 -0
- package/dist/server/utils/pagination.d.ts.map +1 -0
- package/dist/server/utils/pagination.js +56 -0
- package/dist/server/utils/pagination.js.map +1 -0
- package/dist/server/utils/timestamps.d.ts +31 -0
- package/dist/server/utils/timestamps.d.ts.map +1 -0
- package/dist/server/utils/timestamps.js +84 -0
- package/dist/server/utils/timestamps.js.map +1 -0
- package/dist/server/utils/ttl.d.ts +17 -0
- package/dist/server/utils/ttl.d.ts.map +1 -0
- package/dist/server/utils/ttl.js +62 -0
- package/dist/server/utils/ttl.js.map +1 -0
- package/dist/server/utils/validation.d.ts +40 -0
- package/dist/server/utils/validation.d.ts.map +1 -0
- package/dist/server/utils/validation.js +54 -0
- package/dist/server/utils/validation.js.map +1 -0
- package/dist/shadows/config.d.ts +54 -0
- package/dist/shadows/config.d.ts.map +1 -0
- package/dist/shadows/config.js +95 -0
- package/dist/shadows/config.js.map +1 -0
- package/dist/shadows/differ.d.ts +42 -0
- package/dist/shadows/differ.d.ts.map +1 -0
- package/dist/shadows/differ.js +66 -0
- package/dist/shadows/differ.js.map +1 -0
- package/dist/shadows/generator.d.ts +63 -0
- package/dist/shadows/generator.d.ts.map +1 -0
- package/dist/shadows/generator.js +107 -0
- package/dist/shadows/generator.js.map +1 -0
- package/dist/shadows/index.d.ts +15 -0
- package/dist/shadows/index.d.ts.map +1 -0
- package/dist/shadows/index.js +17 -0
- package/dist/shadows/index.js.map +1 -0
- package/dist/shadows/types.d.ts +44 -0
- package/dist/shadows/types.d.ts.map +1 -0
- package/dist/shadows/types.js +2 -0
- package/dist/shadows/types.js.map +1 -0
- package/dist/types.d.ts +165 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ulid.d.ts +46 -0
- package/dist/ulid.d.ts.map +1 -0
- package/dist/ulid.js +66 -0
- package/dist/ulid.js.map +1 -0
- package/package.json +136 -0
- package/terraform/README.md +222 -0
- package/terraform/examples/advanced/README.md +129 -0
- package/terraform/examples/advanced/main.tf +158 -0
- package/terraform/examples/advanced/shadow.config.json +35 -0
- package/terraform/examples/advanced/variables.tf +28 -0
- package/terraform/examples/basic/README.md +53 -0
- package/terraform/examples/basic/main.tf +99 -0
- package/terraform/examples/basic/variables.tf +17 -0
- package/terraform/main.tf +159 -0
- package/terraform/outputs.tf +56 -0
- package/terraform/variables.tf +59 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* チャンク分割ユーティリティ
|
|
3
|
+
*
|
|
4
|
+
* DynamoDBのTransactWriteItemsは最大100アイテムまでしか処理できないため、
|
|
5
|
+
* バルク操作(createMany、updateMany、deleteMany)で大量のレコードを処理する際に
|
|
6
|
+
* チャンク分割が必要となる。
|
|
7
|
+
*
|
|
8
|
+
* 要件: 13.1, 13.2, 13.7, 13.8, 13.9
|
|
9
|
+
*/
|
|
10
|
+
import { createLogger } from '../../index.js';
|
|
11
|
+
const logger = createLogger({ service: 'records-lambda' });
|
|
12
|
+
/**
|
|
13
|
+
* DynamoDB TransactWriteItemsの最大アイテム数制限
|
|
14
|
+
*
|
|
15
|
+
* DynamoDBのTransactWriteItemsは最大100アイテムまでしか処理できない。
|
|
16
|
+
* この制限を超える場合は、複数のトランザクションに分割する必要がある。
|
|
17
|
+
*
|
|
18
|
+
* 参考: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html
|
|
19
|
+
*/
|
|
20
|
+
export const DYNAMODB_TRANSACT_WRITE_MAX_ITEMS = 100;
|
|
21
|
+
/**
|
|
22
|
+
* バルク操作のチャンクサイズを動的に計算する
|
|
23
|
+
*
|
|
24
|
+
* 各レコードのアイテム数(メインレコード + シャドーレコード)を考慮して、
|
|
25
|
+
* TransactWriteItemsの100アイテム制限内に収まるようにチャンクを分割する。
|
|
26
|
+
*
|
|
27
|
+
* @param records - 処理対象のレコード配列
|
|
28
|
+
* @param getItemCount - 各レコードのアイテム数を計算する関数
|
|
29
|
+
* @returns チャンク分割結果
|
|
30
|
+
* @throws {Error} 単一レコードが100アイテムを超える場合
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* // createMany操作の例
|
|
35
|
+
* const result = calculateChunks(records, (record) => {
|
|
36
|
+
* const shadowCount = calculateShadowCount(record);
|
|
37
|
+
* return 1 + shadowCount; // メイン + シャドー
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // updateMany操作の例
|
|
41
|
+
* const result = calculateChunks(records, (record) => {
|
|
42
|
+
* const oldShadowCount = record.__shadowKeys?.length || 0;
|
|
43
|
+
* const newShadowCount = calculateNewShadowCount(record);
|
|
44
|
+
* return 1 + oldShadowCount + newShadowCount; // メイン + 削除 + 追加
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function calculateChunks(records, getItemCount) {
|
|
49
|
+
const chunks = [];
|
|
50
|
+
const itemCounts = [];
|
|
51
|
+
let currentChunk = [];
|
|
52
|
+
let currentItemCount = 0;
|
|
53
|
+
for (const record of records) {
|
|
54
|
+
const itemCount = getItemCount(record);
|
|
55
|
+
// 単一レコードがDynamoDB制限を超える場合はエラー
|
|
56
|
+
if (itemCount > DYNAMODB_TRANSACT_WRITE_MAX_ITEMS) {
|
|
57
|
+
const errorMsg = `Single record exceeds ${DYNAMODB_TRANSACT_WRITE_MAX_ITEMS} items limit: ${itemCount} items`;
|
|
58
|
+
logger.error('Chunk validation failed', {
|
|
59
|
+
itemCount,
|
|
60
|
+
limit: DYNAMODB_TRANSACT_WRITE_MAX_ITEMS,
|
|
61
|
+
});
|
|
62
|
+
throw new Error(errorMsg);
|
|
63
|
+
}
|
|
64
|
+
// 現在のチャンクに追加するとDynamoDB制限を超える場合、新しいチャンクを開始
|
|
65
|
+
if (currentItemCount + itemCount > DYNAMODB_TRANSACT_WRITE_MAX_ITEMS) {
|
|
66
|
+
if (currentChunk.length > 0) {
|
|
67
|
+
chunks.push(currentChunk);
|
|
68
|
+
itemCounts.push(currentItemCount);
|
|
69
|
+
}
|
|
70
|
+
currentChunk = [record];
|
|
71
|
+
currentItemCount = itemCount;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
currentChunk.push(record);
|
|
75
|
+
currentItemCount += itemCount;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// 最後のチャンクを追加
|
|
79
|
+
if (currentChunk.length > 0) {
|
|
80
|
+
chunks.push(currentChunk);
|
|
81
|
+
itemCounts.push(currentItemCount);
|
|
82
|
+
}
|
|
83
|
+
// 詳細なチャンク分割情報をログ出力
|
|
84
|
+
logger.info('Chunk calculation completed', {
|
|
85
|
+
totalRecords: records.length,
|
|
86
|
+
chunkCount: chunks.length,
|
|
87
|
+
itemCounts,
|
|
88
|
+
minItemsPerChunk: itemCounts.length > 0 ? Math.min(...itemCounts) : 0,
|
|
89
|
+
maxItemsPerChunk: itemCounts.length > 0 ? Math.max(...itemCounts) : 0,
|
|
90
|
+
avgItemsPerChunk: itemCounts.length > 0
|
|
91
|
+
? Math.round(itemCounts.reduce((sum, count) => sum + count, 0) / itemCounts.length)
|
|
92
|
+
: 0,
|
|
93
|
+
});
|
|
94
|
+
return { chunks, itemCounts };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* チャンクを順次実行し、結果を集約する
|
|
98
|
+
*
|
|
99
|
+
* 各チャンクを独立したトランザクションとして実行し、1つのチャンクが失敗しても
|
|
100
|
+
* 他のチャンクの処理を継続する(部分成功サポート)。
|
|
101
|
+
*
|
|
102
|
+
* @param chunks - 実行するチャンク配列
|
|
103
|
+
* @param executeChunk - 各チャンクを実行する関数(成功したレコードを返す)
|
|
104
|
+
* @param getRecordId - レコードからIDを取得する関数
|
|
105
|
+
* @returns チャンク実行結果
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const result = await executeChunks(
|
|
110
|
+
* chunks,
|
|
111
|
+
* async (chunk) => {
|
|
112
|
+
* // TransactWriteItemsでチャンクを実行
|
|
113
|
+
* await dynamoDBClient.send(new TransactWriteItemsCommand({
|
|
114
|
+
* TransactItems: buildTransactItems(chunk)
|
|
115
|
+
* }));
|
|
116
|
+
* return chunk; // 成功したレコードを返す
|
|
117
|
+
* },
|
|
118
|
+
* (record) => record.id
|
|
119
|
+
* );
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export async function executeChunks(chunks, executeChunk, getRecordId) {
|
|
123
|
+
const successRecords = [];
|
|
124
|
+
const failedIds = [];
|
|
125
|
+
const errors = [];
|
|
126
|
+
const totalRecords = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
127
|
+
const executionStartTime = Date.now();
|
|
128
|
+
logger.info('Starting chunk execution', {
|
|
129
|
+
totalChunks: chunks.length,
|
|
130
|
+
totalRecords,
|
|
131
|
+
});
|
|
132
|
+
// 各チャンクを順次実行
|
|
133
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
134
|
+
const chunk = chunks[i];
|
|
135
|
+
const chunkStartTime = Date.now();
|
|
136
|
+
try {
|
|
137
|
+
logger.debug(`Executing chunk ${i + 1}/${chunks.length}`, {
|
|
138
|
+
chunkIndex: i,
|
|
139
|
+
recordCount: chunk.length,
|
|
140
|
+
});
|
|
141
|
+
// チャンクを実行
|
|
142
|
+
const successfulRecords = await executeChunk(chunk);
|
|
143
|
+
successRecords.push(...successfulRecords);
|
|
144
|
+
const chunkDuration = Date.now() - chunkStartTime;
|
|
145
|
+
logger.info(`Chunk ${i + 1}/${chunks.length} succeeded`, {
|
|
146
|
+
chunkIndex: i,
|
|
147
|
+
recordCount: chunk.length,
|
|
148
|
+
durationMs: chunkDuration,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
// チャンクが失敗した場合、そのチャンク内のすべてのレコードを失敗として記録
|
|
153
|
+
const chunkDuration = Date.now() - chunkStartTime;
|
|
154
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
155
|
+
const errorCode = getErrorCode(error);
|
|
156
|
+
logger.error(`Chunk ${i + 1}/${chunks.length} failed`, {
|
|
157
|
+
chunkIndex: i,
|
|
158
|
+
recordCount: chunk.length,
|
|
159
|
+
durationMs: chunkDuration,
|
|
160
|
+
error: errorMessage,
|
|
161
|
+
errorCode,
|
|
162
|
+
});
|
|
163
|
+
// チャンク内のすべてのレコードを失敗として記録
|
|
164
|
+
for (const record of chunk) {
|
|
165
|
+
const recordId = getRecordId(record);
|
|
166
|
+
failedIds.push(recordId);
|
|
167
|
+
errors.push({
|
|
168
|
+
id: recordId,
|
|
169
|
+
code: errorCode,
|
|
170
|
+
message: errorMessage,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const totalExecutionTime = Date.now() - executionStartTime;
|
|
176
|
+
// 実行結果のサマリーをログ出力
|
|
177
|
+
logger.info('Chunk execution completed', {
|
|
178
|
+
totalChunks: chunks.length,
|
|
179
|
+
totalRecords,
|
|
180
|
+
successCount: successRecords.length,
|
|
181
|
+
failedCount: failedIds.length,
|
|
182
|
+
totalExecutionTimeMs: totalExecutionTime,
|
|
183
|
+
avgTimePerChunkMs: chunks.length > 0 ? Math.round(totalExecutionTime / chunks.length) : 0,
|
|
184
|
+
});
|
|
185
|
+
// 部分失敗の場合、詳細なエラー情報をログ出力
|
|
186
|
+
if (failedIds.length > 0) {
|
|
187
|
+
logger.warn('Partial failure detected in chunk execution', {
|
|
188
|
+
totalRecords,
|
|
189
|
+
successCount: successRecords.length,
|
|
190
|
+
failedCount: failedIds.length,
|
|
191
|
+
failureRate: `${Math.round((failedIds.length / totalRecords) * 100)}%`,
|
|
192
|
+
failedIds: failedIds.slice(0, 10), // 最初の10件のみログ出力
|
|
193
|
+
errorSummary: errors.slice(0, 5).map((e) => ({
|
|
194
|
+
id: e.id,
|
|
195
|
+
code: e.code,
|
|
196
|
+
message: e.message.substring(0, 100), // メッセージを100文字に制限
|
|
197
|
+
})),
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
successRecords,
|
|
202
|
+
failedIds,
|
|
203
|
+
errors,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* エラーからエラーコードを抽出する
|
|
208
|
+
*
|
|
209
|
+
* @param error - エラーオブジェクト
|
|
210
|
+
* @returns エラーコード
|
|
211
|
+
*/
|
|
212
|
+
function getErrorCode(error) {
|
|
213
|
+
if (error && typeof error === 'object') {
|
|
214
|
+
// AWS SDK エラー
|
|
215
|
+
if ('name' in error && typeof error.name === 'string') {
|
|
216
|
+
return error.name;
|
|
217
|
+
}
|
|
218
|
+
// カスタムエラー
|
|
219
|
+
if ('code' in error && typeof error.code === 'string') {
|
|
220
|
+
return error.code;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return 'TRANSACTION_FAILED';
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=chunking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunking.js","sourceRoot":"","sources":["../../../src/server/utils/chunking.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DynamoDB操作ユーティリティ
|
|
3
|
+
*/
|
|
4
|
+
import type { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
|
|
5
|
+
/**
|
|
6
|
+
* DynamoDBクライアントを取得する(シングルトン)
|
|
7
|
+
*
|
|
8
|
+
* @returns DynamoDBDocumentClient
|
|
9
|
+
*/
|
|
10
|
+
export declare function getDBClient(): DynamoDBDocumentClient;
|
|
11
|
+
/**
|
|
12
|
+
* 環境変数からテーブル名を取得する
|
|
13
|
+
*
|
|
14
|
+
* @returns DynamoDBテーブル名
|
|
15
|
+
* @throws {ConfigError} TABLE_NAME環境変数が未設定の場合
|
|
16
|
+
*/
|
|
17
|
+
export declare function getTableName(): string;
|
|
18
|
+
/**
|
|
19
|
+
* レコードから__shadowKeysを除外する
|
|
20
|
+
*
|
|
21
|
+
* @param record - DynamoDBレコード
|
|
22
|
+
* @returns __shadowKeysを除外したレコード
|
|
23
|
+
*/
|
|
24
|
+
export declare function removeShadowKeys(record: Record<string, unknown>): Record<string, unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* data属性からレコードを抽出し、__shadowKeysを除外する
|
|
27
|
+
*
|
|
28
|
+
* @param item - DynamoDBアイテム(PK, SK, data構造)
|
|
29
|
+
* @returns クリーンなレコード
|
|
30
|
+
*/
|
|
31
|
+
export declare function extractCleanRecord(item: Record<string, unknown>): Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* DynamoDB操作を実行し、権限不足エラーを適切にハンドリングする
|
|
34
|
+
*
|
|
35
|
+
* @param operation - 実行するDynamoDB操作
|
|
36
|
+
* @param operationName - 操作名(ログ用)
|
|
37
|
+
* @returns 操作結果
|
|
38
|
+
* @throws {Error} 権限不足エラーまたはその他のエラー
|
|
39
|
+
*/
|
|
40
|
+
export declare function executeDynamoDBOperation<T>(operation: () => Promise<T>, operationName: string): Promise<T>;
|
|
41
|
+
//# sourceMappingURL=dynamodb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamodb.d.ts","sourceRoot":"","sources":["../../../src/server/utils/dynamodb.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAYpE;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,sBAAsB,CAOpD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAQrC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIzF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGzF;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,CAAC,CAAC,CAmBZ"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { ConfigError, createDynamoDBClient, createLogger } from '../../index.js';
|
|
2
|
+
// ロガーインスタンス
|
|
3
|
+
const logger = createLogger({ service: 'records-lambda' });
|
|
4
|
+
/**
|
|
5
|
+
* DynamoDBクライアントのシングルトンインスタンス
|
|
6
|
+
*/
|
|
7
|
+
let dbClient = null;
|
|
8
|
+
/**
|
|
9
|
+
* DynamoDBクライアントを取得する(シングルトン)
|
|
10
|
+
*
|
|
11
|
+
* @returns DynamoDBDocumentClient
|
|
12
|
+
*/
|
|
13
|
+
export function getDBClient() {
|
|
14
|
+
if (!dbClient) {
|
|
15
|
+
dbClient = createDynamoDBClient({
|
|
16
|
+
region: process.env.AWS_REGION || process.env.REGION,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return dbClient;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 環境変数からテーブル名を取得する
|
|
23
|
+
*
|
|
24
|
+
* @returns DynamoDBテーブル名
|
|
25
|
+
* @throws {ConfigError} TABLE_NAME環境変数が未設定の場合
|
|
26
|
+
*/
|
|
27
|
+
export function getTableName() {
|
|
28
|
+
const tableName = process.env.TABLE_NAME;
|
|
29
|
+
if (!tableName) {
|
|
30
|
+
throw new ConfigError('TABLE_NAME environment variable is not set');
|
|
31
|
+
}
|
|
32
|
+
return tableName;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* レコードから__shadowKeysを除外する
|
|
36
|
+
*
|
|
37
|
+
* @param record - DynamoDBレコード
|
|
38
|
+
* @returns __shadowKeysを除外したレコード
|
|
39
|
+
*/
|
|
40
|
+
export function removeShadowKeys(record) {
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
42
|
+
const { __shadowKeys, ...rest } = record;
|
|
43
|
+
return rest;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* data属性からレコードを抽出し、__shadowKeysを除外する
|
|
47
|
+
*
|
|
48
|
+
* @param item - DynamoDBアイテム(PK, SK, data構造)
|
|
49
|
+
* @returns クリーンなレコード
|
|
50
|
+
*/
|
|
51
|
+
export function extractCleanRecord(item) {
|
|
52
|
+
const data = item.data;
|
|
53
|
+
return removeShadowKeys(data);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* DynamoDB操作を実行し、権限不足エラーを適切にハンドリングする
|
|
57
|
+
*
|
|
58
|
+
* @param operation - 実行するDynamoDB操作
|
|
59
|
+
* @param operationName - 操作名(ログ用)
|
|
60
|
+
* @returns 操作結果
|
|
61
|
+
* @throws {Error} 権限不足エラーまたはその他のエラー
|
|
62
|
+
*/
|
|
63
|
+
export async function executeDynamoDBOperation(operation, operationName) {
|
|
64
|
+
try {
|
|
65
|
+
return await operation();
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
// 権限不足エラーの場合、詳細なログを出力
|
|
69
|
+
if (error instanceof Error && error.name === 'AccessDeniedException') {
|
|
70
|
+
logger.error('DynamoDB access denied', {
|
|
71
|
+
errorName: error.name,
|
|
72
|
+
errorMessage: error.message,
|
|
73
|
+
operation: operationName,
|
|
74
|
+
tableName: process.env.TABLE_NAME,
|
|
75
|
+
region: process.env.AWS_REGION || process.env.REGION,
|
|
76
|
+
});
|
|
77
|
+
throw new Error(`Insufficient permissions to access DynamoDB: ${operationName}`);
|
|
78
|
+
}
|
|
79
|
+
// その他のエラーはそのまま再スロー
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=dynamodb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamodb.js","sourceRoot":"","sources":["../../../src/server/utils/dynamodb.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEjF,YAAY;AACZ,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAE3D;;GAEG;AACH,IAAI,QAAQ,GAAkC,IAAI,CAAC;AAEnD;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,QAAQ,GAAG,oBAAoB,CAAC;YAC9B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM;SACrD,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IAEzC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,WAAW,CAAC,4CAA4C,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAA+B;IAC9D,6DAA6D;IAC7D,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;IACzC,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAA6B;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,IAA+B,CAAC;IAClD,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,SAA2B,EAC3B,aAAqB;IAErB,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,sBAAsB;QACtB,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;YACrE,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE;gBACrC,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,YAAY,EAAE,KAAK,CAAC,OAAO;gBAC3B,SAAS,EAAE,aAAa;gBACxB,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;gBACjC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM;aACrD,CAAC,CAAC;YACH,MAAM,IAAI,KAAK,CAAC,gDAAgD,aAAa,EAAE,CAAC,CAAC;QACnF,CAAC;QAED,mBAAmB;QACnB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DynamoDB フィルター式生成ユーティリティ
|
|
3
|
+
* FilterExpression の構築とシャドーレコード除外条件の生成
|
|
4
|
+
*
|
|
5
|
+
* 要件: 5.5, 7.1, 12.1-12.12
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* フィルター演算子
|
|
9
|
+
*
|
|
10
|
+
* 要件: 12.2
|
|
11
|
+
*/
|
|
12
|
+
export type FilterOperator = 'eq' | 'lt' | 'lte' | 'gt' | 'gte' | 'starts' | 'ends';
|
|
13
|
+
/**
|
|
14
|
+
* フィルター型
|
|
15
|
+
*
|
|
16
|
+
* 要件: 12.5
|
|
17
|
+
*/
|
|
18
|
+
export type FilterType = 'string' | 'number' | 'date' | 'boolean';
|
|
19
|
+
/**
|
|
20
|
+
* パース済みフィルターフィールド
|
|
21
|
+
*
|
|
22
|
+
* 要件: 12.1
|
|
23
|
+
*/
|
|
24
|
+
export interface ParsedFilterField {
|
|
25
|
+
/** 実際のフィールド名 */
|
|
26
|
+
field: string;
|
|
27
|
+
/** 演算子 */
|
|
28
|
+
operator: FilterOperator;
|
|
29
|
+
/** データ型 */
|
|
30
|
+
type: FilterType;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* フィルター式の構築結果
|
|
34
|
+
*/
|
|
35
|
+
export interface FilterExpressionResult {
|
|
36
|
+
/** FilterExpression 文字列 */
|
|
37
|
+
expression: string;
|
|
38
|
+
/** ExpressionAttributeNames マッピング */
|
|
39
|
+
names: Record<string, string>;
|
|
40
|
+
/** ExpressionAttributeValues マッピング */
|
|
41
|
+
values: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* フィルターフィールド名をパースする
|
|
45
|
+
*
|
|
46
|
+
* フォーマット: `フィールド名:オペレータ:型`
|
|
47
|
+
* - オペレータ省略時: eq(デフォルト)
|
|
48
|
+
* - 型省略時: string(デフォルト)
|
|
49
|
+
*
|
|
50
|
+
* 例:
|
|
51
|
+
* - "status" → { field: "status", operator: "eq", type: "string" }
|
|
52
|
+
* - "priority:gte" → { field: "priority", operator: "gte", type: "string" }
|
|
53
|
+
* - "priority:gte:number" → { field: "priority", operator: "gte", type: "number" }
|
|
54
|
+
*
|
|
55
|
+
* 要件: 12.1, 12.3, 12.4
|
|
56
|
+
*
|
|
57
|
+
* @param fieldKey - フィルターフィールド名
|
|
58
|
+
* @returns パース結果
|
|
59
|
+
* @throws Error - 構文エラーの場合
|
|
60
|
+
*/
|
|
61
|
+
export declare function parseFilterField(fieldKey: string): ParsedFilterField;
|
|
62
|
+
/**
|
|
63
|
+
* シャドーレコードを除外するフィルター式を生成する
|
|
64
|
+
*
|
|
65
|
+
* シャドーレコードの特徴:
|
|
66
|
+
* - SK に '#' が含まれる(例: "name#value#id#ULID")
|
|
67
|
+
* - 本体レコードは "id#ULID" 形式で '#' が1つのみ
|
|
68
|
+
*
|
|
69
|
+
* 除外条件:
|
|
70
|
+
* - attribute_exists(data) AND NOT contains(SK, '#id#')
|
|
71
|
+
*
|
|
72
|
+
* @returns シャドー除外フィルター式
|
|
73
|
+
*/
|
|
74
|
+
export declare function createShadowExclusionFilter(): FilterExpressionResult;
|
|
75
|
+
/**
|
|
76
|
+
* ユーザー指定のフィルター条件から FilterExpression を構築する
|
|
77
|
+
*
|
|
78
|
+
* 注意: この実装は基本的な等価比較のみをサポート
|
|
79
|
+
* より複雑な条件(範囲検索、部分一致など)は将来の拡張として実装可能
|
|
80
|
+
*
|
|
81
|
+
* @param filter - フィルター条件(キー: フィールド名、値: 期待値)
|
|
82
|
+
* @returns フィルター式の構築結果
|
|
83
|
+
*/
|
|
84
|
+
export declare function buildFilterExpression(filter: Record<string, unknown>): FilterExpressionResult | null;
|
|
85
|
+
/**
|
|
86
|
+
* 複数のフィルター式を AND 条件で結合する
|
|
87
|
+
*
|
|
88
|
+
* @param filters - 結合するフィルター式の配列
|
|
89
|
+
* @returns 結合されたフィルター式
|
|
90
|
+
*/
|
|
91
|
+
export declare function combineFilters(filters: (FilterExpressionResult | null)[]): FilterExpressionResult | null;
|
|
92
|
+
/**
|
|
93
|
+
* フィルター式を DynamoDB Query/Scan パラメータに適用する
|
|
94
|
+
*
|
|
95
|
+
* @param params - DynamoDB Query/Scan パラメータ
|
|
96
|
+
* @param filter - フィルター式
|
|
97
|
+
* @returns フィルター式が適用されたパラメータ
|
|
98
|
+
*/
|
|
99
|
+
export declare function applyFilterExpression<T extends Record<string, unknown>>(params: T, filter: FilterExpressionResult | null): T;
|
|
100
|
+
/**
|
|
101
|
+
* 型変換ヘルパー
|
|
102
|
+
*
|
|
103
|
+
* 要件: 12.5
|
|
104
|
+
*
|
|
105
|
+
* @param value - 変換する値
|
|
106
|
+
* @param type - 変換先の型
|
|
107
|
+
* @returns 変換後の値
|
|
108
|
+
*/
|
|
109
|
+
export declare function convertType(value: unknown, type: FilterType): string | number | Date | boolean;
|
|
110
|
+
/**
|
|
111
|
+
* レコードが単一のフィルター条件に一致するかチェックする
|
|
112
|
+
*
|
|
113
|
+
* 要件: 12.2, 12.6, 12.8, 12.9
|
|
114
|
+
*
|
|
115
|
+
* @param record - チェック対象レコード
|
|
116
|
+
* @param parsed - パース済みフィルター条件
|
|
117
|
+
* @param value - フィルター値
|
|
118
|
+
* @returns 一致する場合true
|
|
119
|
+
*/
|
|
120
|
+
export declare function matchesFilter(record: Record<string, unknown>, parsed: ParsedFilterField, value: unknown): boolean;
|
|
121
|
+
/**
|
|
122
|
+
* レコードがすべてのフィルター条件に一致するかチェックする(AND条件)
|
|
123
|
+
*
|
|
124
|
+
* 要件: 12.9
|
|
125
|
+
*
|
|
126
|
+
* @param record - チェック対象レコード
|
|
127
|
+
* @param parsedFilters - パース済みフィルター条件の配列
|
|
128
|
+
* @returns すべての条件に一致する場合true
|
|
129
|
+
*/
|
|
130
|
+
export declare function matchesAllFilters(record: Record<string, unknown>, parsedFilters: Array<{
|
|
131
|
+
parsed: ParsedFilterField;
|
|
132
|
+
value: unknown;
|
|
133
|
+
}>): boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Query最適化が可能かチェックする
|
|
136
|
+
*
|
|
137
|
+
* ソートフィールドと一致し、Query可能な演算子を持つフィルター条件を検出する
|
|
138
|
+
*
|
|
139
|
+
* 要件: 12.7
|
|
140
|
+
*
|
|
141
|
+
* @param sortField - ソート対象フィールド
|
|
142
|
+
* @param parsedFilters - パース済みフィルター条件
|
|
143
|
+
* @returns 最適化可能なフィルター条件(なければnull)
|
|
144
|
+
*/
|
|
145
|
+
export declare function findOptimizableFilter(sortField: string, parsedFilters: Array<{
|
|
146
|
+
parsed: ParsedFilterField;
|
|
147
|
+
value: unknown;
|
|
148
|
+
}>): {
|
|
149
|
+
parsed: ParsedFilterField;
|
|
150
|
+
value: unknown;
|
|
151
|
+
} | null;
|
|
152
|
+
//# sourceMappingURL=filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../src/server/utils/filter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEpF;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAElE;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,gBAAgB;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU;IACV,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW;IACX,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAiCpE;AAgBD;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,IAAI,sBAAsB,CAWpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,sBAAsB,GAAG,IAAI,CA4B/B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,CAAC,sBAAsB,GAAG,IAAI,CAAC,EAAE,GACzC,sBAAsB,GAAG,IAAI,CA6B/B;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrE,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,sBAAsB,GAAG,IAAI,GACpC,CAAC,CAiBH;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAe9F;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,OAAO,GACb,OAAO,CA+BT;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,aAAa,EAAE,KAAK,CAAC;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,GAClE,OAAO,CAET;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,KAAK,CAAC;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,GAClE;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAUtD"}
|