@exabugs/dynamodb-client 1.26.0 → 1.27.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 +27 -0
- package/dist/__generated__/models/apiOperation.d.ts +1 -0
- package/dist/__generated__/models/apiOperation.d.ts.map +1 -1
- package/dist/__generated__/models/apiOperation.js +1 -0
- package/dist/__generated__/models/apiOperation.js.map +1 -1
- package/dist/__generated__/models/bulkOperationResult.d.ts +2 -0
- package/dist/__generated__/models/bulkOperationResult.d.ts.map +1 -1
- package/dist/__generated__/models/countParams.d.ts +31 -0
- package/dist/__generated__/models/countParams.d.ts.map +1 -0
- package/dist/__generated__/models/countParams.js +2 -0
- package/dist/__generated__/models/countParams.js.map +1 -0
- package/dist/__generated__/models/countResult.d.ts +37 -0
- package/dist/__generated__/models/countResult.d.ts.map +1 -0
- package/dist/__generated__/models/countResult.js +2 -0
- package/dist/__generated__/models/countResult.js.map +1 -0
- package/dist/__generated__/models/countResultConsumedCapacity.d.ts +35 -0
- package/dist/__generated__/models/countResultConsumedCapacity.d.ts.map +1 -0
- package/dist/__generated__/models/countResultConsumedCapacity.js +25 -0
- package/dist/__generated__/models/countResultConsumedCapacity.js.map +1 -0
- package/dist/__generated__/models/executeOperationBodyOp.d.ts +1 -0
- package/dist/__generated__/models/executeOperationBodyOp.d.ts.map +1 -1
- package/dist/__generated__/models/executeOperationBodyOp.js +1 -0
- package/dist/__generated__/models/executeOperationBodyOp.js.map +1 -1
- package/dist/__generated__/models/index.d.ts +3 -0
- package/dist/__generated__/models/index.d.ts.map +1 -1
- package/dist/__generated__/models/index.js +3 -0
- package/dist/__generated__/models/index.js.map +1 -1
- package/dist/client/Collection.d.ts +7 -0
- package/dist/client/Collection.d.ts.map +1 -1
- package/dist/client/Collection.js +20 -1
- package/dist/client/Collection.js.map +1 -1
- package/dist/scripts/repair-shadows.js +86 -42
- package/dist/scripts/repair-shadows.js.map +1 -1
- package/dist/scripts/utils/cliParser.d.ts +9 -22
- package/dist/scripts/utils/cliParser.d.ts.map +1 -1
- package/dist/scripts/utils/cliParser.js +14 -37
- package/dist/scripts/utils/cliParser.js.map +1 -1
- package/dist/scripts/utils/shadowAudit.d.ts +49 -0
- package/dist/scripts/utils/shadowAudit.d.ts.map +1 -0
- package/dist/scripts/utils/shadowAudit.js +84 -0
- package/dist/scripts/utils/shadowAudit.js.map +1 -0
- package/dist/scripts/utils/shadowRepair.d.ts +42 -0
- package/dist/scripts/utils/shadowRepair.d.ts.map +1 -0
- package/dist/scripts/utils/shadowRepair.js +110 -0
- package/dist/scripts/utils/shadowRepair.js.map +1 -0
- package/dist/server/handler.cjs +1005 -901
- package/dist/server/handler.cjs.map +4 -4
- package/dist/server/handler.js +2 -2
- package/dist/server/handler.js.map +1 -1
- package/dist/server/media-handler.cjs +2 -2
- package/dist/server/media-process-handler-dlq.cjs +19 -3
- package/dist/server/media-process-handler-dlq.cjs.map +2 -2
- package/dist/server/media-process-handler.cjs +19 -3
- package/dist/server/media-process-handler.cjs.map +2 -2
- package/dist/server/operations/count.d.ts +3 -0
- package/dist/server/operations/count.d.ts.map +1 -0
- package/dist/server/operations/count.js +81 -0
- package/dist/server/operations/count.js.map +1 -0
- package/dist/server/operations/deleteMany.d.ts.map +1 -1
- package/dist/server/operations/deleteMany.js +2 -1
- package/dist/server/operations/deleteMany.js.map +1 -1
- package/dist/server/operations/deleteOne.d.ts.map +1 -1
- package/dist/server/operations/deleteOne.js +3 -12
- package/dist/server/operations/deleteOne.js.map +1 -1
- package/dist/server/operations/find/keyCondition.d.ts +38 -0
- package/dist/server/operations/find/keyCondition.d.ts.map +1 -0
- package/dist/server/operations/find/keyCondition.js +184 -0
- package/dist/server/operations/find/keyCondition.js.map +1 -0
- package/dist/server/operations/find/shadowQuery.d.ts.map +1 -1
- package/dist/server/operations/find/shadowQuery.js +16 -143
- package/dist/server/operations/find/shadowQuery.js.map +1 -1
- package/dist/server/operations/find/utils.d.ts.map +1 -1
- package/dist/server/operations/find/utils.js +0 -5
- package/dist/server/operations/find/utils.js.map +1 -1
- package/dist/server/operations/insertMany.d.ts.map +1 -1
- package/dist/server/operations/insertMany.js +1 -4
- package/dist/server/operations/insertMany.js.map +1 -1
- package/dist/server/operations/insertOne.d.ts.map +1 -1
- package/dist/server/operations/insertOne.js +2 -6
- package/dist/server/operations/insertOne.js.map +1 -1
- package/dist/server/operations/operationDispatcher.d.ts.map +1 -1
- package/dist/server/operations/operationDispatcher.js +3 -0
- package/dist/server/operations/operationDispatcher.js.map +1 -1
- package/dist/server/operations/updateMany.d.ts.map +1 -1
- package/dist/server/operations/updateMany.js +6 -2
- package/dist/server/operations/updateMany.js.map +1 -1
- package/dist/server/operations/updateOne.d.ts.map +1 -1
- package/dist/server/operations/updateOne.js +10 -21
- package/dist/server/operations/updateOne.js.map +1 -1
- package/dist/server/types.d.ts +7 -1
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/bulkError.d.ts +12 -0
- package/dist/server/utils/bulkError.d.ts.map +1 -0
- package/dist/server/utils/bulkError.js +21 -0
- package/dist/server/utils/bulkError.js.map +1 -0
- package/dist/server/utils/chunking.d.ts +9 -1
- package/dist/server/utils/chunking.d.ts.map +1 -1
- package/dist/server/utils/chunking.js +20 -3
- package/dist/server/utils/chunking.js.map +1 -1
- package/dist/server/utils/filter.d.ts +3 -105
- package/dist/server/utils/filter.d.ts.map +1 -1
- package/dist/server/utils/filter.js +14 -218
- package/dist/server/utils/filter.js.map +1 -1
- package/docs/README.md +9 -12
- package/package.json +1 -1
- package/dist/scripts/operations/bulkRecordRepair.d.ts +0 -17
- package/dist/scripts/operations/bulkRecordRepair.d.ts.map +0 -1
- package/dist/scripts/operations/bulkRecordRepair.js +0 -76
- package/dist/scripts/operations/bulkRecordRepair.js.map +0 -1
- package/dist/scripts/operations/singleRecordRepair.d.ts +0 -18
- package/dist/scripts/operations/singleRecordRepair.d.ts.map +0 -1
- package/dist/scripts/operations/singleRecordRepair.js +0 -46
- package/dist/scripts/operations/singleRecordRepair.js.map +0 -1
- package/dist/scripts/utils/awsUtils.d.ts +0 -15
- package/dist/scripts/utils/awsUtils.d.ts.map +0 -1
- package/dist/scripts/utils/awsUtils.js +0 -31
- package/dist/scripts/utils/awsUtils.js.map +0 -1
- package/dist/scripts/utils/clientFactory.d.ts +0 -22
- package/dist/scripts/utils/clientFactory.d.ts.map +0 -1
- package/dist/scripts/utils/clientFactory.js +0 -36
- package/dist/scripts/utils/clientFactory.js.map +0 -1
- package/dist/scripts/utils/repairUtils.d.ts +0 -58
- package/dist/scripts/utils/repairUtils.d.ts.map +0 -1
- package/dist/scripts/utils/repairUtils.js +0 -52
- package/dist/scripts/utils/repairUtils.js.map +0 -1
- package/dist/server/utils/ttl.d.ts +0 -17
- package/dist/server/utils/ttl.d.ts.map +0 -1
- package/dist/server/utils/ttl.js +0 -64
- package/dist/server/utils/ttl.js.map +0 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* FilterExpression の構築とシャドーレコード除外条件の生成
|
|
2
|
+
* フィルターのフィールド指定(`field:$op:type`)の解析
|
|
4
3
|
*
|
|
5
|
-
* 要件:
|
|
4
|
+
* 要件: 12.1-12.12
|
|
6
5
|
*/
|
|
7
6
|
/**
|
|
8
7
|
* フィルターフィールド名をパースする
|
|
@@ -30,19 +29,15 @@ export function parseFilterField(fieldKey) {
|
|
|
30
29
|
}
|
|
31
30
|
if (parts.length === 2) {
|
|
32
31
|
// "priority:$gte" → { field: "priority", operator: "$gte", type: "string" }
|
|
32
|
+
assertSupportedOperator(parts[1]);
|
|
33
33
|
const operator = parts[1];
|
|
34
|
-
if (!isValidOperator(operator)) {
|
|
35
|
-
throw new Error(`Invalid filter operator: ${parts[1]}`);
|
|
36
|
-
}
|
|
37
34
|
return { field: parts[0], operator, type: 'string' };
|
|
38
35
|
}
|
|
39
36
|
if (parts.length === 3) {
|
|
40
37
|
// "priority:$gte:number" → { field: "priority", operator: "$gte", type: "number" }
|
|
38
|
+
assertSupportedOperator(parts[1]);
|
|
41
39
|
const operator = parts[1];
|
|
42
40
|
const type = parts[2];
|
|
43
|
-
if (!isValidOperator(operator)) {
|
|
44
|
-
throw new Error(`Invalid filter operator: ${parts[1]}`);
|
|
45
|
-
}
|
|
46
41
|
if (!isValidType(type)) {
|
|
47
42
|
throw new Error(`Invalid filter type: ${parts[2]}`);
|
|
48
43
|
}
|
|
@@ -66,226 +61,27 @@ function isValidOperator(operator) {
|
|
|
66
61
|
'$starts',
|
|
67
62
|
'$ends',
|
|
68
63
|
'$contains',
|
|
69
|
-
'$regex',
|
|
70
64
|
'$exists',
|
|
71
65
|
'$near',
|
|
72
66
|
].includes(operator);
|
|
73
67
|
}
|
|
74
68
|
/**
|
|
75
|
-
*
|
|
76
|
-
*/
|
|
77
|
-
function isValidType(type) {
|
|
78
|
-
return ['string', 'number', 'date', 'boolean'].includes(type);
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* シャドーレコードを除外するフィルター式を生成する
|
|
82
|
-
*
|
|
83
|
-
* シャドーレコードの特徴:
|
|
84
|
-
* - SK に '#' が含まれる(例: "name#value#id#ULID")
|
|
85
|
-
* - 本体レコードは "id#ULID" 形式で '#' が1つのみ
|
|
86
|
-
*
|
|
87
|
-
* 除外条件:
|
|
88
|
-
* - attribute_exists(data) AND NOT contains(SK, '#id#')
|
|
69
|
+
* 演算子が使えるものかを確かめる(使えなければ例外。find の呼び出し側で 400 になる)
|
|
89
70
|
*
|
|
90
|
-
*
|
|
71
|
+
* `$regex` は正規表現ではなく部分一致として動いていたため、黙って誤った結果を返さないよう受け付けない。
|
|
91
72
|
*/
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
names: {
|
|
96
|
-
'#data': 'data',
|
|
97
|
-
'#sk': 'SK',
|
|
98
|
-
},
|
|
99
|
-
values: {
|
|
100
|
-
':shadowMarker': '#id#',
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* ユーザー指定のフィルター条件から FilterExpression を構築する
|
|
106
|
-
*
|
|
107
|
-
* 注意: この実装は基本的な等価比較のみをサポート
|
|
108
|
-
* より複雑な条件(範囲検索、部分一致など)は将来の拡張として実装可能
|
|
109
|
-
*
|
|
110
|
-
* @param filter - フィルター条件(キー: フィールド名、値: 期待値)
|
|
111
|
-
* @returns フィルター式の構築結果
|
|
112
|
-
*/
|
|
113
|
-
export function buildFilterExpression(filter) {
|
|
114
|
-
const entries = Object.entries(filter);
|
|
115
|
-
// フィルター条件が空の場合は null を返す
|
|
116
|
-
if (entries.length === 0) {
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
const expressions = [];
|
|
120
|
-
const names = {};
|
|
121
|
-
const values = {};
|
|
122
|
-
entries.forEach(([key, value], index) => {
|
|
123
|
-
const nameKey = `#field${index}`;
|
|
124
|
-
const valueKey = `:value${index}`;
|
|
125
|
-
// data.{field} = :value 形式の条件を生成
|
|
126
|
-
expressions.push(`#data.${nameKey} = ${valueKey}`);
|
|
127
|
-
names['#data'] = 'data';
|
|
128
|
-
names[nameKey] = key;
|
|
129
|
-
values[valueKey] = value;
|
|
130
|
-
});
|
|
131
|
-
return {
|
|
132
|
-
expression: expressions.join(' AND '),
|
|
133
|
-
names,
|
|
134
|
-
values,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* 複数のフィルター式を AND 条件で結合する
|
|
139
|
-
*
|
|
140
|
-
* @param filters - 結合するフィルター式の配列
|
|
141
|
-
* @returns 結合されたフィルター式
|
|
142
|
-
*/
|
|
143
|
-
export function combineFilters(filters) {
|
|
144
|
-
// null を除外
|
|
145
|
-
const validFilters = filters.filter((f) => f !== null);
|
|
146
|
-
if (validFilters.length === 0) {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
if (validFilters.length === 1) {
|
|
150
|
-
return validFilters[0];
|
|
73
|
+
function assertSupportedOperator(operator) {
|
|
74
|
+
if (operator === '$regex') {
|
|
75
|
+
throw new Error('Invalid filter operator: $regex is not supported (use $contains or $starts)');
|
|
151
76
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
// names と values をマージ
|
|
155
|
-
const names = {};
|
|
156
|
-
const values = {};
|
|
157
|
-
validFilters.forEach((f) => {
|
|
158
|
-
Object.assign(names, f.names);
|
|
159
|
-
Object.assign(values, f.values);
|
|
160
|
-
});
|
|
161
|
-
return {
|
|
162
|
-
expression,
|
|
163
|
-
names,
|
|
164
|
-
values,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* フィルター式を DynamoDB Query/Scan パラメータに適用する
|
|
169
|
-
*
|
|
170
|
-
* @param params - DynamoDB Query/Scan パラメータ
|
|
171
|
-
* @param filter - フィルター式
|
|
172
|
-
* @returns フィルター式が適用されたパラメータ
|
|
173
|
-
*/
|
|
174
|
-
export function applyFilterExpression(params, filter) {
|
|
175
|
-
if (!filter) {
|
|
176
|
-
return params;
|
|
77
|
+
if (!isValidOperator(operator)) {
|
|
78
|
+
throw new Error(`Invalid filter operator: ${operator}`);
|
|
177
79
|
}
|
|
178
|
-
return {
|
|
179
|
-
...params,
|
|
180
|
-
FilterExpression: filter.expression,
|
|
181
|
-
ExpressionAttributeNames: {
|
|
182
|
-
...params.ExpressionAttributeNames,
|
|
183
|
-
...filter.names,
|
|
184
|
-
},
|
|
185
|
-
ExpressionAttributeValues: {
|
|
186
|
-
...params.ExpressionAttributeValues,
|
|
187
|
-
...filter.values,
|
|
188
|
-
},
|
|
189
|
-
};
|
|
190
80
|
}
|
|
191
81
|
/**
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* 要件: 12.5
|
|
195
|
-
*
|
|
196
|
-
* @param value - 変換する値
|
|
197
|
-
* @param type - 変換先の型
|
|
198
|
-
* @returns 変換後の値
|
|
199
|
-
*/
|
|
200
|
-
export function convertType(value, type) {
|
|
201
|
-
switch (type) {
|
|
202
|
-
case 'string':
|
|
203
|
-
return String(value);
|
|
204
|
-
case 'number':
|
|
205
|
-
return Number(value);
|
|
206
|
-
case 'date':
|
|
207
|
-
return new Date(String(value));
|
|
208
|
-
case 'boolean':
|
|
209
|
-
// 文字列 "true"/"false" または boolean値を処理
|
|
210
|
-
if (typeof value === 'boolean')
|
|
211
|
-
return value;
|
|
212
|
-
return String(value).toLowerCase() === 'true';
|
|
213
|
-
default:
|
|
214
|
-
return String(value);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* レコードが単一のフィルター条件に一致するかチェックする
|
|
219
|
-
*
|
|
220
|
-
* 要件: 12.2, 12.6, 12.8, 12.9
|
|
221
|
-
*
|
|
222
|
-
* @param record - チェック対象レコード
|
|
223
|
-
* @param parsed - パース済みフィルター条件
|
|
224
|
-
* @param value - フィルター値
|
|
225
|
-
* @returns 一致する場合true
|
|
226
|
-
*/
|
|
227
|
-
export function matchesFilter(record, parsed, value) {
|
|
228
|
-
const fieldValue = record[parsed.field];
|
|
229
|
-
// フィールドが存在しない場合は不一致
|
|
230
|
-
if (fieldValue === undefined || fieldValue === null) {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
// 型変換
|
|
234
|
-
const typedFieldValue = convertType(fieldValue, parsed.type);
|
|
235
|
-
const typedFilterValue = convertType(value, parsed.type);
|
|
236
|
-
// 演算子に応じた比較
|
|
237
|
-
switch (parsed.operator) {
|
|
238
|
-
case '$eq':
|
|
239
|
-
return typedFieldValue === typedFilterValue;
|
|
240
|
-
case '$lt':
|
|
241
|
-
return typedFieldValue < typedFilterValue;
|
|
242
|
-
case '$lte':
|
|
243
|
-
return typedFieldValue <= typedFilterValue;
|
|
244
|
-
case '$gt':
|
|
245
|
-
return typedFieldValue > typedFilterValue;
|
|
246
|
-
case '$gte':
|
|
247
|
-
return typedFieldValue >= typedFilterValue;
|
|
248
|
-
case '$in':
|
|
249
|
-
// value は配列のため convertType を使わず直接比較
|
|
250
|
-
return Array.isArray(value) && value.map(String).includes(String(fieldValue));
|
|
251
|
-
case '$nin':
|
|
252
|
-
// value は配列のため convertType を使わず直接比較
|
|
253
|
-
return Array.isArray(value) && !value.map(String).includes(String(fieldValue));
|
|
254
|
-
case '$starts':
|
|
255
|
-
return String(typedFieldValue).startsWith(String(typedFilterValue));
|
|
256
|
-
case '$ends':
|
|
257
|
-
return String(typedFieldValue).endsWith(String(typedFilterValue));
|
|
258
|
-
default:
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* レコードがすべてのフィルター条件に一致するかチェックする(AND条件)
|
|
264
|
-
*
|
|
265
|
-
* 要件: 12.9
|
|
266
|
-
*
|
|
267
|
-
* @param record - チェック対象レコード
|
|
268
|
-
* @param parsedFilters - パース済みフィルター条件の配列
|
|
269
|
-
* @returns すべての条件に一致する場合true
|
|
270
|
-
*/
|
|
271
|
-
export function matchesAllFilters(record, parsedFilters) {
|
|
272
|
-
return parsedFilters.every((f) => matchesFilter(record, f.parsed, f.value));
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Query最適化が可能かチェックする
|
|
276
|
-
*
|
|
277
|
-
* ソートフィールドと一致し、Query可能な演算子を持つフィルター条件を検出する
|
|
278
|
-
*
|
|
279
|
-
* 要件: 12.7
|
|
280
|
-
*
|
|
281
|
-
* @param sortField - ソート対象フィールド
|
|
282
|
-
* @param parsedFilters - パース済みフィルター条件
|
|
283
|
-
* @returns 最適化可能なフィルター条件(なければnull)
|
|
82
|
+
* 型が有効かチェックする
|
|
284
83
|
*/
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const queryableOperators = ['$eq', '$lt', '$lte', '$gt', '$gte', '$starts'];
|
|
288
|
-
// ソートフィールドと一致し、Query可能な演算子を持つフィルターを探す
|
|
289
|
-
return (parsedFilters.find((f) => f.parsed.field === sortField && queryableOperators.includes(f.parsed.operator)) || null);
|
|
84
|
+
function isValidType(type) {
|
|
85
|
+
return ['string', 'number', 'date', 'boolean'].includes(type);
|
|
290
86
|
}
|
|
291
87
|
//# sourceMappingURL=filter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../src/server/utils/filter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../src/server/utils/filter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2CH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAElC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,kEAAkE;QAClE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC9D,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,4EAA4E;QAC5E,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAmB,CAAC;QAC5C,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACvD,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,mFAAmF;QACnF,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAmB,CAAC;QAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAe,CAAC;QAEpC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,gCAAgC,QAAQ,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,MAAM;QACN,KAAK;QACL,MAAM;QACN,KAAK;QACL,MAAM;QACN,SAAS;QACT,OAAO;QACP,WAAW;QACX,SAAS;QACT,OAAO;KACR,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACvB,CAAC;AAED;;;;GAIG;AACH,SAAS,uBAAuB,CAAC,QAAgB;IAC/C,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,EAAE,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAChE,CAAC"}
|
package/docs/README.md
CHANGED
|
@@ -126,23 +126,20 @@ pnpm build:lambda # サーバーのみをビルド
|
|
|
126
126
|
|
|
127
127
|
### シャドーレコード修復
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
運用の道具です(アプリのコードから呼ばない)。テーブルを直接読み、本体とシャドーの食い違い(孤立・欠け・一覧の食い違い・本体の無いシャドー)を数えて直します。Records の HTTP は `__shadowKeys` を返さず、`updateMany` は古い一覧との差分しか書かないので、HTTP 経由では判定も修復もできません。
|
|
130
130
|
|
|
131
131
|
```bash
|
|
132
|
-
#
|
|
133
|
-
|
|
132
|
+
# 確認(既定。読み取りだけ)
|
|
133
|
+
tsx src/scripts/repair-shadows.ts --table <テーブル名> --region <リージョン> --lambda <Records の関数名> --resource articles
|
|
134
134
|
|
|
135
|
-
#
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
# 全レコードを修復
|
|
139
|
-
pnpm repair-shadows -- --resource articles --repair
|
|
135
|
+
# 修復(食い違いのあるレコードだけ、1 レコード 1 トランザクション)
|
|
136
|
+
tsx src/scripts/repair-shadows.ts --table <テーブル名> --region <リージョン> --lambda <Records の関数名> --resource articles --repair
|
|
140
137
|
```
|
|
141
138
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
- `
|
|
145
|
-
-
|
|
139
|
+
- テーブル名・リージョン・Lambda は必須(既定を持たない)。`--table` が Lambda の `TABLE_NAME` と違えば止まる
|
|
140
|
+
- シャドーの設定(`SHADOW_*`)は Lambda の環境変数から読み、実行の最初に表示する
|
|
141
|
+
- 本体の `data`・`updatedAt` は変えない。本体の `__shadowKeys` と `__rev` だけを更新し、孤立を削除し、欠けを作る。本体の無いシャドーは、本体が無いことを同じトランザクションで確かめて削除する
|
|
142
|
+
- 修復中に書き込まれたレコードは、条件に外れて飛ばす。もう一度実行すると直る
|
|
146
143
|
- `RECORDS_API_URL`: Records Lambda Function URL(省略時はAWS CLIで自動取得)
|
|
147
144
|
|
|
148
145
|
## ドキュメント
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exabugs/dynamodb-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.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",
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 一括レコード修復処理
|
|
3
|
-
*
|
|
4
|
-
* 全レコードをスキャンして修復する
|
|
5
|
-
*/
|
|
6
|
-
import type { Collection } from '../../client/index.iam.js';
|
|
7
|
-
/**
|
|
8
|
-
* 全レコードをスキャンして修復
|
|
9
|
-
*
|
|
10
|
-
* @param collection - DynamoClientのコレクション
|
|
11
|
-
* @param dryRun - ドライランモード(trueの場合は実際の修復は行わない)
|
|
12
|
-
*/
|
|
13
|
-
export declare function repairAllRecords<TAuthOptions = unknown>(collection: Collection<{
|
|
14
|
-
id: string;
|
|
15
|
-
[key: string]: unknown;
|
|
16
|
-
}, TAuthOptions>, dryRun: boolean): Promise<void>;
|
|
17
|
-
//# sourceMappingURL=bulkRecordRepair.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bulkRecordRepair.d.ts","sourceRoot":"","sources":["../../../src/scripts/operations/bulkRecordRepair.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAS5D;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,GAAG,OAAO,EAC3D,UAAU,EAAE,UAAU,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAAE,YAAY,CAAC,EAC5E,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC,CAuBf"}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { checkShadowIntegrity, displayRepairSummary, repairRecordViaDynamoClient, waitForRateLimit, } from '../utils/repairUtils.js';
|
|
2
|
-
/**
|
|
3
|
-
* 全レコードをスキャンして修復
|
|
4
|
-
*
|
|
5
|
-
* @param collection - DynamoClientのコレクション
|
|
6
|
-
* @param dryRun - ドライランモード(trueの場合は実際の修復は行わない)
|
|
7
|
-
*/
|
|
8
|
-
export async function repairAllRecords(collection, dryRun) {
|
|
9
|
-
const stats = {
|
|
10
|
-
scanned: 0,
|
|
11
|
-
needsRepair: 0,
|
|
12
|
-
repaired: 0,
|
|
13
|
-
failed: 0,
|
|
14
|
-
errors: [],
|
|
15
|
-
};
|
|
16
|
-
console.log(`\n=== Scanning all records ===`);
|
|
17
|
-
console.log(`Mode: ${dryRun ? 'DRY RUN' : 'REPAIR'}`);
|
|
18
|
-
// 全レコードを取得
|
|
19
|
-
const records = await fetchAllRecords(collection);
|
|
20
|
-
console.log(`Found ${records.length} records`);
|
|
21
|
-
// 各レコードを処理
|
|
22
|
-
for (const mainRecord of records) {
|
|
23
|
-
await processRecord(mainRecord, stats, dryRun, collection);
|
|
24
|
-
}
|
|
25
|
-
// 統計情報を表示
|
|
26
|
-
displayRepairSummary(stats);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* 全レコードを取得
|
|
30
|
-
*
|
|
31
|
-
* @param collection - DynamoClientのコレクション
|
|
32
|
-
* @returns 全レコードの配列
|
|
33
|
-
*/
|
|
34
|
-
async function fetchAllRecords(collection) {
|
|
35
|
-
// 修復中にレコードが更新されても取りこぼし・重複が出ないよう、不変の id 順で列挙する
|
|
36
|
-
return await collection.find({}).sort({ id: 'asc' }).toArrayAll();
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* 単一レコードを処理
|
|
40
|
-
*
|
|
41
|
-
* @param mainRecord - 処理対象のレコード
|
|
42
|
-
* @param stats - 修復統計情報
|
|
43
|
-
* @param dryRun - ドライランモード
|
|
44
|
-
* @param collection - DynamoClientのコレクション
|
|
45
|
-
*/
|
|
46
|
-
async function processRecord(mainRecord, stats, dryRun, collection) {
|
|
47
|
-
stats.scanned++;
|
|
48
|
-
const recordId = mainRecord.id;
|
|
49
|
-
try {
|
|
50
|
-
const { needsRepair, missingShadows, extraShadows } = await checkShadowIntegrity();
|
|
51
|
-
if (needsRepair) {
|
|
52
|
-
stats.needsRepair++;
|
|
53
|
-
console.log(`\n[${stats.scanned}] Record ${recordId}: Missing=${missingShadows}, Extra=${extraShadows}`);
|
|
54
|
-
if (!dryRun) {
|
|
55
|
-
await repairRecordViaDynamoClient(collection, recordId);
|
|
56
|
-
stats.repaired++;
|
|
57
|
-
console.log(` ✓ Repaired`);
|
|
58
|
-
// レート制限を避けるため少し待機
|
|
59
|
-
await waitForRateLimit();
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
/**
|
|
65
|
-
* NOTE: スクリプトでのエラーハンドリング
|
|
66
|
-
*
|
|
67
|
-
* このスクリプトはメンテナンス用のツールであり、本番コードではありません。
|
|
68
|
-
* エラーメッセージの取得のために unknown 型から Error 型への変換を行っています。
|
|
69
|
-
*/
|
|
70
|
-
stats.failed++;
|
|
71
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
72
|
-
stats.errors.push({ id: recordId, error: errorMessage });
|
|
73
|
-
console.error(` ✗ Failed: ${errorMessage}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
//# sourceMappingURL=bulkRecordRepair.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bulkRecordRepair.js","sourceRoot":"","sources":["../../../src/scripts/operations/bulkRecordRepair.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,oBAAoB,EACpB,oBAAoB,EACpB,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,UAA4E,EAC5E,MAAe;IAEf,MAAM,KAAK,GAAgB;QACzB,OAAO,EAAE,CAAC;QACV,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,CAAC;QACX,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEtD,WAAW;IACX,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,SAAS,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC;IAE/C,WAAW;IACX,KAAK,MAAM,UAAU,IAAI,OAAO,EAAE,CAAC;QACjC,MAAM,aAAa,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAC7D,CAAC;IAED,UAAU;IACV,oBAAoB,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,eAAe,CAC5B,UAA4E;IAE5E,8CAA8C;IAC9C,OAAO,MAAM,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC;AACpE,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,aAAa,CAC1B,UAAkD,EAClD,KAAkB,EAClB,MAAe,EACf,UAA4E;IAE5E,KAAK,CAAC,OAAO,EAAE,CAAC;IAChB,MAAM,QAAQ,GAAG,UAAU,CAAC,EAAE,CAAC;IAE/B,IAAI,CAAC;QACH,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,GAAG,MAAM,oBAAoB,EAAE,CAAC;QAEnF,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,CAAC,WAAW,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CACT,MAAM,KAAK,CAAC,OAAO,YAAY,QAAQ,aAAa,cAAc,WAAW,YAAY,EAAE,CAC5F,CAAC;YAEF,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,2BAA2B,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACxD,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACjB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBAE5B,kBAAkB;gBAClB,MAAM,gBAAgB,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB;;;;;WAKG;QACH,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5E,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,KAAK,CAAC,eAAe,YAAY,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 単一レコード修復処理
|
|
3
|
-
*
|
|
4
|
-
* 指定されたIDのレコードを修復する
|
|
5
|
-
*/
|
|
6
|
-
import type { Collection } from '../../client/index.iam.js';
|
|
7
|
-
/**
|
|
8
|
-
* 単一レコードを修復
|
|
9
|
-
*
|
|
10
|
-
* @param collection - DynamoClientのコレクション
|
|
11
|
-
* @param recordId - 修復対象のレコードID
|
|
12
|
-
* @param dryRun - ドライランモード(trueの場合は実際の修復は行わない)
|
|
13
|
-
*/
|
|
14
|
-
export declare function repairSingleRecord<TAuthOptions = unknown>(collection: Collection<{
|
|
15
|
-
id: string;
|
|
16
|
-
[key: string]: unknown;
|
|
17
|
-
}, TAuthOptions>, recordId: string, dryRun: boolean): Promise<void>;
|
|
18
|
-
//# sourceMappingURL=singleRecordRepair.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"singleRecordRepair.d.ts","sourceRoot":"","sources":["../../../src/scripts/operations/singleRecordRepair.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAO5D;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,YAAY,GAAG,OAAO,EAC7D,UAAU,EAAE,UAAU,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAAE,YAAY,CAAC,EAC5E,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { checkShadowIntegrity, repairRecordViaDynamoClient, } from '../utils/repairUtils.js';
|
|
2
|
-
/**
|
|
3
|
-
* 単一レコードを修復
|
|
4
|
-
*
|
|
5
|
-
* @param collection - DynamoClientのコレクション
|
|
6
|
-
* @param recordId - 修復対象のレコードID
|
|
7
|
-
* @param dryRun - ドライランモード(trueの場合は実際の修復は行わない)
|
|
8
|
-
*/
|
|
9
|
-
export async function repairSingleRecord(collection, recordId, dryRun) {
|
|
10
|
-
console.log(`\n=== Checking record: ${recordId} ===`);
|
|
11
|
-
// 本体レコードを取得
|
|
12
|
-
console.log(`Fetching record with id: ${recordId}`);
|
|
13
|
-
const mainRecord = await collection.findOne({ id: recordId });
|
|
14
|
-
console.log(`findOne result:`, mainRecord);
|
|
15
|
-
if (!mainRecord) {
|
|
16
|
-
console.error(`Record not found: ${recordId}`);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
// 整合性チェック
|
|
20
|
-
const integrityResult = await checkShadowIntegrity();
|
|
21
|
-
logIntegrityResult(integrityResult);
|
|
22
|
-
if (!integrityResult.needsRepair) {
|
|
23
|
-
console.log('✓ No repair needed');
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (dryRun) {
|
|
27
|
-
console.log('\n[DRY RUN] Would repair this record via DynamoClient.updateOne()');
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
// DynamoClient経由で修復
|
|
31
|
-
console.log('\nRepairing via DynamoClient.updateOne() with IAM auth...');
|
|
32
|
-
await repairRecordViaDynamoClient(collection, recordId);
|
|
33
|
-
console.log('✓ Repaired successfully');
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* 整合性チェック結果をログ出力
|
|
37
|
-
*
|
|
38
|
-
* @param result - 整合性チェック結果
|
|
39
|
-
*/
|
|
40
|
-
function logIntegrityResult(result) {
|
|
41
|
-
// Records Lambdaは__shadowKeysをレスポンスから除外するため、
|
|
42
|
-
// 実際のシャドー数は確認できません
|
|
43
|
-
console.log(`Missing shadows: ${result.missingShadows}`);
|
|
44
|
-
console.log(`Extra shadows: ${result.extraShadows}`);
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=singleRecordRepair.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"singleRecordRepair.js","sourceRoot":"","sources":["../../../src/scripts/operations/singleRecordRepair.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,oBAAoB,EACpB,2BAA2B,GAC5B,MAAM,yBAAyB,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,UAA4E,EAC5E,QAAgB,EAChB,MAAe;IAEf,OAAO,CAAC,GAAG,CAAC,0BAA0B,QAAQ,MAAM,CAAC,CAAC;IAEtD,YAAY;IACZ,OAAO,CAAC,GAAG,CAAC,4BAA4B,QAAQ,EAAE,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;IAE3C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IAED,UAAU;IACV,MAAM,eAAe,GAAG,MAAM,oBAAoB,EAAE,CAAC;IACrD,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAEpC,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,oBAAoB;IACpB,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;IACzE,MAAM,2BAA2B,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,MAA6B;IACvD,6CAA6C;IAC7C,mBAAmB;IACnB,OAAO,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AWS関連ユーティリティ
|
|
3
|
-
*
|
|
4
|
-
* AWS CLIやAWSサービスとの連携処理
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Records Lambda Function URLを取得
|
|
8
|
-
*
|
|
9
|
-
* @param env - 環境名
|
|
10
|
-
* @param region - AWSリージョン
|
|
11
|
-
* @returns Function URL
|
|
12
|
-
* @throws {Error} Function URLの取得に失敗した場合
|
|
13
|
-
*/
|
|
14
|
-
export declare function getRecordsApiUrl(env: string, region: string): Promise<string>;
|
|
15
|
-
//# sourceMappingURL=awsUtils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"awsUtils.d.ts","sourceRoot":"","sources":["../../../src/scripts/utils/awsUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBnF"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AWS関連ユーティリティ
|
|
3
|
-
*
|
|
4
|
-
* AWS CLIやAWSサービスとの連携処理
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Records Lambda Function URLを取得
|
|
8
|
-
*
|
|
9
|
-
* @param env - 環境名
|
|
10
|
-
* @param region - AWSリージョン
|
|
11
|
-
* @returns Function URL
|
|
12
|
-
* @throws {Error} Function URLの取得に失敗した場合
|
|
13
|
-
*/
|
|
14
|
-
export async function getRecordsApiUrl(env, region) {
|
|
15
|
-
// 環境変数から取得を試行
|
|
16
|
-
const envUrl = process.env.RECORDS_API_URL;
|
|
17
|
-
if (envUrl) {
|
|
18
|
-
return envUrl;
|
|
19
|
-
}
|
|
20
|
-
// AWS CLIで取得
|
|
21
|
-
const { execSync } = await import('child_process');
|
|
22
|
-
const functionName = `ainews-${env}-records`;
|
|
23
|
-
try {
|
|
24
|
-
const output = execSync(`aws lambda get-function-url-config --function-name ${functionName} --region ${region} --query 'FunctionUrl' --output text`, { encoding: 'utf-8' });
|
|
25
|
-
return output.trim();
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
throw new Error(`Failed to get Function URL for ${functionName}`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=awsUtils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"awsUtils.js","sourceRoot":"","sources":["../../../src/scripts/utils/awsUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,MAAc;IAChE,cAAc;IACd,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC3C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,aAAa;IACb,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,UAAU,GAAG,UAAU,CAAC;IAE7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CACrB,sDAAsD,YAAY,aAAa,MAAM,sCAAsC,EAC3H,EAAE,QAAQ,EAAE,OAAO,EAAE,CACtB,CAAC;QACF,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,kCAAkC,YAAY,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DynamoClientファクトリー
|
|
3
|
-
*
|
|
4
|
-
* DynamoClientの初期化処理
|
|
5
|
-
*/
|
|
6
|
-
import { type Collection, DynamoClient } from '../../client/index.iam.js';
|
|
7
|
-
/**
|
|
8
|
-
* DynamoClient(IAM認証)を作成・初期化する
|
|
9
|
-
*
|
|
10
|
-
* @param apiUrl - Records API URL
|
|
11
|
-
* @param region - AWSリージョン
|
|
12
|
-
* @param resource - リソース名
|
|
13
|
-
* @returns 初期化されたコレクション
|
|
14
|
-
*/
|
|
15
|
-
export declare function createDynamoClientCollection(apiUrl: string, region: string, resource: string): Promise<{
|
|
16
|
-
client: DynamoClient;
|
|
17
|
-
collection: Collection<{
|
|
18
|
-
id: string;
|
|
19
|
-
[key: string]: unknown;
|
|
20
|
-
}>;
|
|
21
|
-
}>;
|
|
22
|
-
//# sourceMappingURL=clientFactory.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"clientFactory.d.ts","sourceRoot":"","sources":["../../../src/scripts/utils/clientFactory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,UAAU,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE1E;;;;;;;GAOG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IACT,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC,CAwBD"}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DynamoClientファクトリー
|
|
3
|
-
*
|
|
4
|
-
* DynamoClientの初期化処理
|
|
5
|
-
*/
|
|
6
|
-
import { DynamoClient } from '../../client/index.iam.js';
|
|
7
|
-
/**
|
|
8
|
-
* DynamoClient(IAM認証)を作成・初期化する
|
|
9
|
-
*
|
|
10
|
-
* @param apiUrl - Records API URL
|
|
11
|
-
* @param region - AWSリージョン
|
|
12
|
-
* @param resource - リソース名
|
|
13
|
-
* @returns 初期化されたコレクション
|
|
14
|
-
*/
|
|
15
|
-
export async function createDynamoClientCollection(apiUrl, region, resource) {
|
|
16
|
-
console.log(`\nCreating DynamoClient with IAM auth...`);
|
|
17
|
-
console.log(`Region: ${region}`);
|
|
18
|
-
console.log(`Endpoint: ${apiUrl}`);
|
|
19
|
-
const client = new DynamoClient(apiUrl, {
|
|
20
|
-
auth: {
|
|
21
|
-
region: region,
|
|
22
|
-
},
|
|
23
|
-
autoConnect: true,
|
|
24
|
-
});
|
|
25
|
-
console.log(`Client connected: ${client.isConnected()}\n`);
|
|
26
|
-
const collection = client.db().collection(resource);
|
|
27
|
-
/**
|
|
28
|
-
* NOTE: テストユーティリティでの型アサーション
|
|
29
|
-
*
|
|
30
|
-
* このファイルはテスト・スクリプト用のユーティリティであり、本番コードではありません。
|
|
31
|
-
* Collection型の柔軟性を保つため、型アサーションを使用しています。
|
|
32
|
-
*/
|
|
33
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
-
return { client, collection: collection };
|
|
35
|
-
}
|
|
36
|
-
//# sourceMappingURL=clientFactory.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"clientFactory.js","sourceRoot":"","sources":["../../../src/scripts/utils/clientFactory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAmB,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE1E;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,MAAc,EACd,MAAc,EACd,QAAgB;IAKhB,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,EAAE,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE;QACtC,IAAI,EAAE;YACJ,MAAM,EAAE,MAAM;SACf;QACD,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,qBAAqB,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAE3D,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,EAAE,CAAC,UAAU,CAAyC,QAAQ,CAAC,CAAC;IAE5F;;;;;OAKG;IACH,8DAA8D;IAC9D,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAiB,EAAE,CAAC;AACnD,CAAC"}
|