@exabugs/dynamodb-client 1.25.1 → 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.
Files changed (147) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/__generated__/models/apiOperation.d.ts +1 -0
  3. package/dist/__generated__/models/apiOperation.d.ts.map +1 -1
  4. package/dist/__generated__/models/apiOperation.js +1 -0
  5. package/dist/__generated__/models/apiOperation.js.map +1 -1
  6. package/dist/__generated__/models/bulkOperationResult.d.ts +2 -0
  7. package/dist/__generated__/models/bulkOperationResult.d.ts.map +1 -1
  8. package/dist/__generated__/models/countParams.d.ts +31 -0
  9. package/dist/__generated__/models/countParams.d.ts.map +1 -0
  10. package/dist/__generated__/models/countParams.js +2 -0
  11. package/dist/__generated__/models/countParams.js.map +1 -0
  12. package/dist/__generated__/models/countResult.d.ts +37 -0
  13. package/dist/__generated__/models/countResult.d.ts.map +1 -0
  14. package/dist/__generated__/models/countResult.js +2 -0
  15. package/dist/__generated__/models/countResult.js.map +1 -0
  16. package/dist/__generated__/models/countResultConsumedCapacity.d.ts +35 -0
  17. package/dist/__generated__/models/countResultConsumedCapacity.d.ts.map +1 -0
  18. package/dist/__generated__/models/countResultConsumedCapacity.js +25 -0
  19. package/dist/__generated__/models/countResultConsumedCapacity.js.map +1 -0
  20. package/dist/__generated__/models/executeOperationBodyOp.d.ts +1 -0
  21. package/dist/__generated__/models/executeOperationBodyOp.d.ts.map +1 -1
  22. package/dist/__generated__/models/executeOperationBodyOp.js +1 -0
  23. package/dist/__generated__/models/executeOperationBodyOp.js.map +1 -1
  24. package/dist/__generated__/models/index.d.ts +3 -0
  25. package/dist/__generated__/models/index.d.ts.map +1 -1
  26. package/dist/__generated__/models/index.js +3 -0
  27. package/dist/__generated__/models/index.js.map +1 -1
  28. package/dist/client/Collection.d.ts +7 -0
  29. package/dist/client/Collection.d.ts.map +1 -1
  30. package/dist/client/Collection.js +20 -1
  31. package/dist/client/Collection.js.map +1 -1
  32. package/dist/scripts/repair-shadows.js +86 -42
  33. package/dist/scripts/repair-shadows.js.map +1 -1
  34. package/dist/scripts/utils/cliParser.d.ts +9 -22
  35. package/dist/scripts/utils/cliParser.d.ts.map +1 -1
  36. package/dist/scripts/utils/cliParser.js +14 -37
  37. package/dist/scripts/utils/cliParser.js.map +1 -1
  38. package/dist/scripts/utils/shadowAudit.d.ts +49 -0
  39. package/dist/scripts/utils/shadowAudit.d.ts.map +1 -0
  40. package/dist/scripts/utils/shadowAudit.js +84 -0
  41. package/dist/scripts/utils/shadowAudit.js.map +1 -0
  42. package/dist/scripts/utils/shadowRepair.d.ts +42 -0
  43. package/dist/scripts/utils/shadowRepair.d.ts.map +1 -0
  44. package/dist/scripts/utils/shadowRepair.js +110 -0
  45. package/dist/scripts/utils/shadowRepair.js.map +1 -0
  46. package/dist/server/handler.cjs +1264 -1088
  47. package/dist/server/handler.cjs.map +4 -4
  48. package/dist/server/handler.js +2 -2
  49. package/dist/server/handler.js.map +1 -1
  50. package/dist/server/media-handler.cjs +2 -2
  51. package/dist/server/media-process-handler-dlq.cjs +19 -3
  52. package/dist/server/media-process-handler-dlq.cjs.map +2 -2
  53. package/dist/server/media-process-handler.cjs +19 -3
  54. package/dist/server/media-process-handler.cjs.map +2 -2
  55. package/dist/server/operations/count.d.ts +3 -0
  56. package/dist/server/operations/count.d.ts.map +1 -0
  57. package/dist/server/operations/count.js +81 -0
  58. package/dist/server/operations/count.js.map +1 -0
  59. package/dist/server/operations/deleteMany.d.ts.map +1 -1
  60. package/dist/server/operations/deleteMany.js +13 -1
  61. package/dist/server/operations/deleteMany.js.map +1 -1
  62. package/dist/server/operations/deleteOne.d.ts.map +1 -1
  63. package/dist/server/operations/deleteOne.js +7 -13
  64. package/dist/server/operations/deleteOne.js.map +1 -1
  65. package/dist/server/operations/find/idQuery.d.ts.map +1 -1
  66. package/dist/server/operations/find/idQuery.js +31 -22
  67. package/dist/server/operations/find/idQuery.js.map +1 -1
  68. package/dist/server/operations/find/keyCondition.d.ts +38 -0
  69. package/dist/server/operations/find/keyCondition.d.ts.map +1 -0
  70. package/dist/server/operations/find/keyCondition.js +184 -0
  71. package/dist/server/operations/find/keyCondition.js.map +1 -0
  72. package/dist/server/operations/find/shadowQuery.d.ts.map +1 -1
  73. package/dist/server/operations/find/shadowQuery.js +16 -143
  74. package/dist/server/operations/find/shadowQuery.js.map +1 -1
  75. package/dist/server/operations/find/utils.d.ts +11 -0
  76. package/dist/server/operations/find/utils.d.ts.map +1 -1
  77. package/dist/server/operations/find/utils.js +1 -6
  78. package/dist/server/operations/find/utils.js.map +1 -1
  79. package/dist/server/operations/findMany.d.ts.map +1 -1
  80. package/dist/server/operations/findMany.js +4 -1
  81. package/dist/server/operations/findMany.js.map +1 -1
  82. package/dist/server/operations/findOne.d.ts.map +1 -1
  83. package/dist/server/operations/findOne.js +1 -1
  84. package/dist/server/operations/findOne.js.map +1 -1
  85. package/dist/server/operations/insertMany.d.ts.map +1 -1
  86. package/dist/server/operations/insertMany.js +1 -4
  87. package/dist/server/operations/insertMany.js.map +1 -1
  88. package/dist/server/operations/insertOne.d.ts.map +1 -1
  89. package/dist/server/operations/insertOne.js +2 -6
  90. package/dist/server/operations/insertOne.js.map +1 -1
  91. package/dist/server/operations/operationDispatcher.d.ts.map +1 -1
  92. package/dist/server/operations/operationDispatcher.js +3 -0
  93. package/dist/server/operations/operationDispatcher.js.map +1 -1
  94. package/dist/server/operations/parameterConverter.d.ts +1 -0
  95. package/dist/server/operations/parameterConverter.d.ts.map +1 -1
  96. package/dist/server/operations/parameterConverter.js +34 -41
  97. package/dist/server/operations/parameterConverter.js.map +1 -1
  98. package/dist/server/operations/updateMany.d.ts.map +1 -1
  99. package/dist/server/operations/updateMany.js +37 -16
  100. package/dist/server/operations/updateMany.js.map +1 -1
  101. package/dist/server/operations/updateOne.d.ts.map +1 -1
  102. package/dist/server/operations/updateOne.js +18 -22
  103. package/dist/server/operations/updateOne.js.map +1 -1
  104. package/dist/server/types.d.ts +22 -7
  105. package/dist/server/types.d.ts.map +1 -1
  106. package/dist/server/utils/bulkError.d.ts +12 -0
  107. package/dist/server/utils/bulkError.d.ts.map +1 -0
  108. package/dist/server/utils/bulkError.js +21 -0
  109. package/dist/server/utils/bulkError.js.map +1 -0
  110. package/dist/server/utils/chunking.d.ts +9 -1
  111. package/dist/server/utils/chunking.d.ts.map +1 -1
  112. package/dist/server/utils/chunking.js +20 -3
  113. package/dist/server/utils/chunking.js.map +1 -1
  114. package/dist/server/utils/filter.d.ts +3 -105
  115. package/dist/server/utils/filter.d.ts.map +1 -1
  116. package/dist/server/utils/filter.js +14 -218
  117. package/dist/server/utils/filter.js.map +1 -1
  118. package/dist/server/utils/idFilter.d.ts +15 -0
  119. package/dist/server/utils/idFilter.d.ts.map +1 -0
  120. package/dist/server/utils/idFilter.js +32 -0
  121. package/dist/server/utils/idFilter.js.map +1 -0
  122. package/docs/README.md +9 -12
  123. package/package.json +1 -1
  124. package/dist/scripts/operations/bulkRecordRepair.d.ts +0 -17
  125. package/dist/scripts/operations/bulkRecordRepair.d.ts.map +0 -1
  126. package/dist/scripts/operations/bulkRecordRepair.js +0 -76
  127. package/dist/scripts/operations/bulkRecordRepair.js.map +0 -1
  128. package/dist/scripts/operations/singleRecordRepair.d.ts +0 -18
  129. package/dist/scripts/operations/singleRecordRepair.d.ts.map +0 -1
  130. package/dist/scripts/operations/singleRecordRepair.js +0 -46
  131. package/dist/scripts/operations/singleRecordRepair.js.map +0 -1
  132. package/dist/scripts/utils/awsUtils.d.ts +0 -15
  133. package/dist/scripts/utils/awsUtils.d.ts.map +0 -1
  134. package/dist/scripts/utils/awsUtils.js +0 -31
  135. package/dist/scripts/utils/awsUtils.js.map +0 -1
  136. package/dist/scripts/utils/clientFactory.d.ts +0 -22
  137. package/dist/scripts/utils/clientFactory.d.ts.map +0 -1
  138. package/dist/scripts/utils/clientFactory.js +0 -36
  139. package/dist/scripts/utils/clientFactory.js.map +0 -1
  140. package/dist/scripts/utils/repairUtils.d.ts +0 -58
  141. package/dist/scripts/utils/repairUtils.d.ts.map +0 -1
  142. package/dist/scripts/utils/repairUtils.js +0 -52
  143. package/dist/scripts/utils/repairUtils.js.map +0 -1
  144. package/dist/server/utils/ttl.d.ts +0 -17
  145. package/dist/server/utils/ttl.d.ts.map +0 -1
  146. package/dist/server/utils/ttl.js +0 -64
  147. package/dist/server/utils/ttl.js.map +0 -1
@@ -1,8 +1,7 @@
1
1
  /**
2
- * DynamoDB フィルター式生成ユーティリティ
3
- * FilterExpression の構築とシャドーレコード除外条件の生成
2
+ * フィルターのフィールド指定(`field:$op:type`)の解析
4
3
  *
5
- * 要件: 5.5, 7.1, 12.1-12.12
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
- * @returns シャドー除外フィルター式
71
+ * `$regex` は正規表現ではなく部分一致として動いていたため、黙って誤った結果を返さないよう受け付けない。
91
72
  */
92
- export function createShadowExclusionFilter() {
93
- return {
94
- expression: 'attribute_exists(#data) AND NOT contains(#sk, :shadowMarker)',
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
- // 式を AND で結合
153
- const expression = validFilters.map((f) => `(${f.expression})`).join(' AND ');
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
- export function findOptimizableFilter(sortField, parsedFilters) {
286
- // Query可能な演算子
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":"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"}
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"}
@@ -0,0 +1,15 @@
1
+ export interface SplitIdFilter {
2
+ /** id の等値(`{ id: 'x' }`) */
3
+ id?: string;
4
+ /** id の $in(`{ id: { $in: [...] } }`) */
5
+ ids?: string[];
6
+ /** id 以外の条件 */
7
+ rest: Record<string, unknown>;
8
+ }
9
+ /** フィルタを id の条件と、それ以外の条件に分ける */
10
+ export declare function splitIdFilter(filter: Record<string, unknown> | undefined): SplitIdFilter;
11
+ /** rest が空なら条件なし(undefined)にする */
12
+ export declare function conditionOf(rest: Record<string, unknown>): Record<string, unknown> | undefined;
13
+ /** 条件に一致するかを返す関数を作る(条件なしなら常に true) */
14
+ export declare function conditionMatcher(condition: Record<string, unknown> | undefined): (record: Record<string, unknown>) => boolean;
15
+ //# sourceMappingURL=idFilter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idFilter.d.ts","sourceRoot":"","sources":["../../../src/server/utils/idFilter.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,4BAA4B;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,eAAe;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,gCAAgC;AAChC,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,aAAa,CAUxF;AAED,kCAAkC;AAClC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAE9F;AAED,sCAAsC;AACtC,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC7C,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAM9C"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * フィルタの id 条件と、それ以外の条件(rest)の分離
3
+ *
4
+ * id で 1 件ずつ引く経路でも、id 以外の条件を捨てない。
5
+ * 「id で引く → 残りの条件をメモリで確かめる」に統一する(読み取りの量は変わらない)。
6
+ */
7
+ import { matchesAllFilters, parseFilters } from '../operations/find/utils.js';
8
+ /** フィルタを id の条件と、それ以外の条件に分ける */
9
+ export function splitIdFilter(filter) {
10
+ const { id, ...rest } = filter ?? {};
11
+ if (typeof id === 'string') {
12
+ return { id, rest };
13
+ }
14
+ if (typeof id === 'object' && id !== null && '$in' in id) {
15
+ return { ids: (id.$in ?? []).slice(), rest };
16
+ }
17
+ // id が無い、または対応していない形($eq など)のときは、元の条件をすべて rest に残す
18
+ return { rest: filter ?? {} };
19
+ }
20
+ /** rest が空なら条件なし(undefined)にする */
21
+ export function conditionOf(rest) {
22
+ return Object.keys(rest).length > 0 ? rest : undefined;
23
+ }
24
+ /** 条件に一致するかを返す関数を作る(条件なしなら常に true) */
25
+ export function conditionMatcher(condition) {
26
+ if (!condition || Object.keys(condition).length === 0) {
27
+ return () => true;
28
+ }
29
+ const parsed = parseFilters(condition);
30
+ return (record) => matchesAllFilters(record, parsed);
31
+ }
32
+ //# sourceMappingURL=idFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idFilter.js","sourceRoot":"","sources":["../../../src/server/utils/idFilter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAW9E,gCAAgC;AAChC,MAAM,UAAU,aAAa,CAAC,MAA2C;IACvE,MAAM,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IACrC,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IACD,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,IAAI,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;QACzD,OAAO,EAAE,GAAG,EAAE,CAAE,EAAyB,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC;IACvE,CAAC;IACD,mDAAmD;IACnD,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC;AAChC,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,WAAW,CAAC,IAA6B;IACvD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,gBAAgB,CAC9B,SAA8C;IAE9C,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC;IACpB,CAAC;IACD,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC"}
package/docs/README.md CHANGED
@@ -126,23 +126,20 @@ pnpm build:lambda # サーバーのみをビルド
126
126
 
127
127
  ### シャドーレコード修復
128
128
 
129
- DynamoClient(IAM認証)を使用してシャドーレコードを修復するスクリプトです。
129
+ 運用の道具です(アプリのコードから呼ばない)。テーブルを直接読み、本体とシャドーの食い違い(孤立・欠け・一覧の食い違い・本体の無いシャドー)を数えて直します。Records の HTTP は `__shadowKeys` を返さず、`updateMany` は古い一覧との差分しか書かないので、HTTP 経由では判定も修復もできません。
130
130
 
131
131
  ```bash
132
- # Dry run(変更なし)
133
- pnpm repair-shadows -- --resource articles --dry-run
132
+ # 確認(既定。読み取りだけ)
133
+ tsx src/scripts/repair-shadows.ts --table <テーブル名> --region <リージョン> --lambda <Records の関数名> --resource articles
134
134
 
135
- # 単一レコードを修復
136
- pnpm repair-shadows -- --resource articles --id <RECORD_ID> --repair
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
- - `ENV`: 環境(dev/stg/prd)、デフォルト: `dev`
145
- - `AWS_REGION`: AWSリージョン、デフォルト: `us-east-1`
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.25.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