@exabugs/dynamodb-client 0.2.2 → 0.3.1
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 +39 -0
- package/README.md +92 -28
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server/handler.cjs +137 -178
- package/dist/server/handler.cjs.map +4 -4
- package/dist/server/handler.d.ts.map +1 -1
- package/dist/server/handler.js +2 -15
- package/dist/server/handler.js.map +1 -1
- package/dist/server/operations/find.d.ts.map +1 -1
- package/dist/server/operations/find.js +5 -12
- package/dist/server/operations/find.js.map +1 -1
- package/dist/server/operations/findManyReference.d.ts.map +1 -1
- package/dist/server/operations/findManyReference.js +3 -10
- package/dist/server/operations/findManyReference.js.map +1 -1
- package/dist/server/operations/insertMany.d.ts.map +1 -1
- package/dist/server/operations/insertMany.js +3 -8
- 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 +3 -8
- package/dist/server/operations/insertOne.js.map +1 -1
- package/dist/server/operations/updateMany.d.ts.map +1 -1
- package/dist/server/operations/updateMany.js +3 -4
- 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 +3 -4
- package/dist/server/operations/updateOne.js.map +1 -1
- package/dist/server/shadow/config.d.ts +18 -112
- package/dist/server/shadow/config.d.ts.map +1 -1
- package/dist/server/shadow/config.js +33 -131
- package/dist/server/shadow/config.js.map +1 -1
- package/dist/server/shadow/generator.d.ts +92 -43
- package/dist/server/shadow/generator.d.ts.map +1 -1
- package/dist/server/shadow/generator.js +175 -56
- package/dist/server/shadow/generator.js.map +1 -1
- package/dist/server/shadow/index.d.ts +4 -3
- package/dist/server/shadow/index.d.ts.map +1 -1
- package/dist/server/shadow/index.js +4 -2
- package/dist/server/shadow/index.js.map +1 -1
- package/dist/server/shadow/typeInference.d.ts +61 -0
- package/dist/server/shadow/typeInference.d.ts.map +1 -0
- package/dist/server/shadow/typeInference.js +94 -0
- package/dist/server/shadow/typeInference.js.map +1 -0
- package/dist/server/shadow/types.d.ts +1 -1
- package/dist/server/shadow/types.d.ts.map +1 -1
- package/dist/server/utils/timestamps.d.ts.map +1 -1
- package/dist/server/utils/timestamps.js +3 -26
- package/dist/server/utils/timestamps.js.map +1 -1
- package/dist/server/utils/ttl.d.ts.map +1 -1
- package/dist/server/utils/ttl.js +11 -9
- package/dist/server/utils/ttl.js.map +1 -1
- package/dist/server/utils/validation.d.ts +14 -8
- package/dist/server/utils/validation.d.ts.map +1 -1
- package/dist/server/utils/validation.js +19 -26
- package/dist/server/utils/validation.js.map +1 -1
- package/package.json +1 -1
- package/terraform/README.md +3 -3
- package/terraform/main.tf +1 -1
- package/dist/scripts/generate-shadow-config.d.ts +0 -3
- package/dist/scripts/generate-shadow-config.d.ts.map +0 -1
- package/dist/scripts/generate-shadow-config.js +0 -159
- package/dist/scripts/generate-shadow-config.js.map +0 -1
|
@@ -1,3 +1,78 @@
|
|
|
1
|
+
import { inferFieldType } from './typeInference.js';
|
|
2
|
+
/**
|
|
3
|
+
* JSONオブジェクトのフィールドを正規化
|
|
4
|
+
*
|
|
5
|
+
* フィールドの順序を以下のルールで並び替えます:
|
|
6
|
+
* 1. id: 先頭
|
|
7
|
+
* 2. その他: アルファベット順
|
|
8
|
+
* 3. createdAt, updatedAt: 末尾
|
|
9
|
+
*
|
|
10
|
+
* @param value - 正規化する値
|
|
11
|
+
* @returns 正規化された値
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* normalizeJson({ updatedAt: '...', title: 'A', id: '1', author: 'B' })
|
|
16
|
+
* // => { id: '1', author: 'B', title: 'A', updatedAt: '...' }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function normalizeJson(value) {
|
|
20
|
+
if (value === null || value === undefined)
|
|
21
|
+
return value;
|
|
22
|
+
if (Array.isArray(value))
|
|
23
|
+
return value.map((item) => normalizeJson(item));
|
|
24
|
+
if (typeof value === 'object') {
|
|
25
|
+
const obj = value;
|
|
26
|
+
const sorted = {};
|
|
27
|
+
// 1. id を先頭に
|
|
28
|
+
if ('id' in obj)
|
|
29
|
+
sorted.id = normalizeJson(obj.id);
|
|
30
|
+
// 2. その他をアルファベット順に
|
|
31
|
+
const otherKeys = Object.keys(obj)
|
|
32
|
+
.filter((key) => key !== 'id' && key !== 'createdAt' && key !== 'updatedAt')
|
|
33
|
+
.sort();
|
|
34
|
+
for (const key of otherKeys) {
|
|
35
|
+
sorted[key] = normalizeJson(obj[key]);
|
|
36
|
+
}
|
|
37
|
+
// 3. タイムスタンプを末尾に
|
|
38
|
+
if ('createdAt' in obj)
|
|
39
|
+
sorted.createdAt = normalizeJson(obj.createdAt);
|
|
40
|
+
if ('updatedAt' in obj)
|
|
41
|
+
sorted.updatedAt = normalizeJson(obj.updatedAt);
|
|
42
|
+
return sorted;
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 文字列を先頭Nバイトまで切り詰める(UTF-8)
|
|
48
|
+
*
|
|
49
|
+
* マルチバイト文字の境界を考慮して切り詰めます。
|
|
50
|
+
* 切り詰め位置がマルチバイト文字の途中の場合、前の文字境界まで戻ります。
|
|
51
|
+
*
|
|
52
|
+
* @param value - 切り詰める文字列
|
|
53
|
+
* @param maxBytes - 最大バイト数
|
|
54
|
+
* @returns 切り詰められた文字列
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* truncateString('Hello World', 5) // => 'Hello'
|
|
59
|
+
* truncateString('こんにちは世界', 9) // => 'こんに' (9バイト = 3文字)
|
|
60
|
+
* truncateString('Hello', 100) // => 'Hello' (そのまま)
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function truncateString(value, maxBytes) {
|
|
64
|
+
const encoder = new TextEncoder();
|
|
65
|
+
const bytes = encoder.encode(value);
|
|
66
|
+
if (bytes.length <= maxBytes) {
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
// マルチバイト文字の境界を考慮して切り詰め
|
|
70
|
+
const decoder = new TextDecoder('utf-8', { fatal: false });
|
|
71
|
+
let truncated = decoder.decode(bytes.slice(0, maxBytes));
|
|
72
|
+
// 不完全な文字を削除(U+FFFDは置換文字)
|
|
73
|
+
truncated = truncated.replace(/[\uFFFD]$/, '');
|
|
74
|
+
return truncated;
|
|
75
|
+
}
|
|
1
76
|
/**
|
|
2
77
|
* 文字列値をエスケープする
|
|
3
78
|
* ルール: # → ##, スペース → #
|
|
@@ -11,22 +86,41 @@ export function escapeString(value) {
|
|
|
11
86
|
.replace(/ /g, '#'); // スペースを # に置換
|
|
12
87
|
}
|
|
13
88
|
/**
|
|
14
|
-
*
|
|
89
|
+
* 数値をオフセット方式でゼロパディング
|
|
15
90
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
91
|
+
* 負数を含む数値を文字列としてソート可能にするため、オフセットを加算します。
|
|
92
|
+
*
|
|
93
|
+
* 範囲: -10^padding ~ +10^padding
|
|
94
|
+
* オフセット: 10^padding
|
|
95
|
+
*
|
|
96
|
+
* 注意: padding は15以下を推奨(JavaScriptの安全な整数範囲: 2^53-1 ≈ 9×10^15)
|
|
97
|
+
*
|
|
98
|
+
* @param value - 変換する数値
|
|
99
|
+
* @param padding - パディング桁数(推奨: 15、デフォルト設定で使用)
|
|
100
|
+
* @returns ゼロパディングされた文字列
|
|
101
|
+
* @throws 数値が範囲外の場合
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* formatNumberWithOffset(-99999, 15) // => "0999999999900001"
|
|
106
|
+
* formatNumberWithOffset(0, 15) // => "1000000000000000"
|
|
107
|
+
* formatNumberWithOffset(99999, 15) // => "1000000000099999"
|
|
108
|
+
* ```
|
|
18
109
|
*/
|
|
19
|
-
export function
|
|
20
|
-
// null/undefined は空文字を返す
|
|
21
|
-
if (value === null || value === undefined) {
|
|
22
|
-
return '';
|
|
23
|
-
}
|
|
110
|
+
export function formatNumberWithOffset(value, padding) {
|
|
24
111
|
if (!Number.isFinite(value)) {
|
|
25
112
|
throw new Error(`Invalid number value: ${value}`);
|
|
26
113
|
}
|
|
27
|
-
//
|
|
28
|
-
const
|
|
29
|
-
|
|
114
|
+
// 範囲チェック
|
|
115
|
+
const maxValue = Math.pow(10, padding);
|
|
116
|
+
if (value < -maxValue || value >= maxValue) {
|
|
117
|
+
throw new Error(`Number ${value} is out of range (-10^${padding} to 10^${padding})`);
|
|
118
|
+
}
|
|
119
|
+
// オフセットを加算
|
|
120
|
+
const offset = maxValue;
|
|
121
|
+
const adjusted = Math.floor(value) + offset;
|
|
122
|
+
// ゼロパディング(padding + 1桁)
|
|
123
|
+
return adjusted.toString().padStart(padding + 1, '0');
|
|
30
124
|
}
|
|
31
125
|
/**
|
|
32
126
|
* 日時をUTC ISO 8601形式にフォーマットする
|
|
@@ -58,56 +152,50 @@ export function formatBoolean(value) {
|
|
|
58
152
|
return value ? '1' : '0';
|
|
59
153
|
}
|
|
60
154
|
/**
|
|
61
|
-
*
|
|
155
|
+
* フィールド値を型に応じてフォーマットする(更新版)
|
|
62
156
|
*
|
|
63
157
|
* @param type - フィールドの型
|
|
64
|
-
* @param value -
|
|
158
|
+
* @param value - フォーマットする値
|
|
159
|
+
* @param config - シャドウ設定
|
|
65
160
|
* @returns フォーマットされた文字列
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* const config = { stringMaxBytes: 100, numberPadding: 20, ... };
|
|
165
|
+
* formatFieldValue('string', 'Hello World', config) // => 'Hello#World'
|
|
166
|
+
* formatFieldValue('number', 123, config) // => '10000000000000000123'
|
|
167
|
+
* formatFieldValue('array', ['a', 'b'], config) // => '["a","b"]'
|
|
168
|
+
* ```
|
|
66
169
|
*/
|
|
67
|
-
export function formatFieldValue(type, value) {
|
|
170
|
+
export function formatFieldValue(type, value, config) {
|
|
68
171
|
switch (type) {
|
|
69
|
-
case 'string':
|
|
70
|
-
// 文字列型の場合、null/undefinedは空文字として扱う
|
|
172
|
+
case 'string': {
|
|
71
173
|
if (value === null || value === undefined) {
|
|
72
174
|
return '';
|
|
73
175
|
}
|
|
74
|
-
|
|
176
|
+
const str = String(value);
|
|
177
|
+
const truncated = truncateString(str, config.stringMaxBytes);
|
|
178
|
+
return escapeString(truncated);
|
|
179
|
+
}
|
|
75
180
|
case 'number':
|
|
76
|
-
return
|
|
181
|
+
return formatNumberWithOffset(value, config.numberPadding);
|
|
77
182
|
case 'datetime':
|
|
78
183
|
return formatDatetime(value);
|
|
79
184
|
case 'boolean':
|
|
80
185
|
return formatBoolean(value);
|
|
186
|
+
case 'array':
|
|
187
|
+
case 'object': {
|
|
188
|
+
// JSON文字列化して2倍のバイト制限で切り詰め
|
|
189
|
+
const normalized = normalizeJson(value);
|
|
190
|
+
const jsonStr = JSON.stringify(normalized);
|
|
191
|
+
const maxBytes = config.stringMaxBytes * 2;
|
|
192
|
+
const truncated = truncateString(jsonStr, maxBytes);
|
|
193
|
+
return escapeString(truncated);
|
|
194
|
+
}
|
|
81
195
|
default:
|
|
82
196
|
throw new Error(`Unknown shadow field type: ${type}`);
|
|
83
197
|
}
|
|
84
198
|
}
|
|
85
|
-
/**
|
|
86
|
-
* シャドーSKを生成する
|
|
87
|
-
* フォーマット: {fieldName}#{formattedValue}#id#{recordId}
|
|
88
|
-
*
|
|
89
|
-
* @param fieldName - フィールド名
|
|
90
|
-
* @param value - フィールド値
|
|
91
|
-
* @param recordId - レコードID(ULID)
|
|
92
|
-
* @param type - フィールドの型(デフォルト: 'string')
|
|
93
|
-
* @returns 生成されたシャドーSK
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* generateShadowSK('name', 'Tech News', '01HZXY123', 'string')
|
|
97
|
-
* // => 'name#Tech#News#id#01HZXY123'
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* generateShadowSK('priority', 123, '01HZXY123', 'number')
|
|
101
|
-
* // => 'priority#00000000000000000123#id#01HZXY123'
|
|
102
|
-
*
|
|
103
|
-
* @example
|
|
104
|
-
* generateShadowSK('createdAt', '2025-11-12T10:00:00.000Z', '01HZXY123', 'datetime')
|
|
105
|
-
* // => 'createdAt#2025-11-12T10:00:00.000Z#id#01HZXY123'
|
|
106
|
-
*/
|
|
107
|
-
export function generateShadowSK(fieldName, value, recordId, type = 'string') {
|
|
108
|
-
const formattedValue = formatFieldValue(type, value);
|
|
109
|
-
return `${fieldName}#${formattedValue}#id#${recordId}`;
|
|
110
|
-
}
|
|
111
199
|
/**
|
|
112
200
|
* レコードIDからメインレコードのSKを生成する
|
|
113
201
|
* フォーマット: id#{recordId}
|
|
@@ -119,26 +207,57 @@ export function generateMainRecordSK(recordId) {
|
|
|
119
207
|
return `id#${recordId}`;
|
|
120
208
|
}
|
|
121
209
|
/**
|
|
122
|
-
*
|
|
210
|
+
* レコードからシャドウレコードを自動生成する(更新版)
|
|
123
211
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
212
|
+
* レコードに存在するすべてのフィールドを自動的にシャドウ化します。
|
|
213
|
+
* スキーマ定義は不要で、実行時に型を推論します。
|
|
126
214
|
*
|
|
127
215
|
* @param record - レコードオブジェクト(idフィールドを含む)
|
|
128
|
-
* @param
|
|
216
|
+
* @param resourceName - リソース名
|
|
217
|
+
* @param config - シャドウ設定
|
|
129
218
|
* @returns 生成されたシャドウレコードの配列
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* const record = {
|
|
223
|
+
* id: '01HQXYZ...',
|
|
224
|
+
* title: 'Article',
|
|
225
|
+
* viewCount: 123,
|
|
226
|
+
* tags: ['tech', 'aws'],
|
|
227
|
+
* };
|
|
228
|
+
* const config = getShadowConfig();
|
|
229
|
+
* const shadows = generateShadowRecords(record, 'articles', config);
|
|
230
|
+
* // => [
|
|
231
|
+
* // { PK: 'articles', SK: 'id#01HQXYZ...#id#01HQXYZ...', data: { id: '01HQXYZ...' } },
|
|
232
|
+
* // { PK: 'articles', SK: 'title#Article#id#01HQXYZ...', data: { id: '01HQXYZ...' } },
|
|
233
|
+
* // { PK: 'articles', SK: 'viewCount#10000000000000000123#id#01HQXYZ...', data: { id: '01HQXYZ...' } },
|
|
234
|
+
* // { PK: 'articles', SK: 'tags#["aws","tech"]#id#01HQXYZ...', data: { id: '01HQXYZ...' } },
|
|
235
|
+
* // ]
|
|
236
|
+
* ```
|
|
130
237
|
*/
|
|
131
|
-
export function generateShadowRecords(record,
|
|
238
|
+
export function generateShadowRecords(record, resourceName, config) {
|
|
132
239
|
const shadows = [];
|
|
133
|
-
//
|
|
134
|
-
for (const [fieldName,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
240
|
+
// レコードの各フィールドを処理
|
|
241
|
+
for (const [fieldName, value] of Object.entries(record)) {
|
|
242
|
+
// __ プレフィックスは除外(内部メタデータ)
|
|
243
|
+
if (fieldName.startsWith('__')) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
// null/undefined は除外
|
|
247
|
+
if (value === null || value === undefined) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
// 型推論
|
|
251
|
+
const type = inferFieldType(value);
|
|
252
|
+
if (!type) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
// フィールド値をフォーマット
|
|
256
|
+
const formattedValue = formatFieldValue(type, value, config);
|
|
138
257
|
// シャドウキーを生成
|
|
139
|
-
const sk = `${fieldName}#${
|
|
258
|
+
const sk = `${fieldName}#${formattedValue}#id#${record.id}`;
|
|
140
259
|
shadows.push({
|
|
141
|
-
PK:
|
|
260
|
+
PK: resourceName,
|
|
142
261
|
SK: sk,
|
|
143
262
|
data: { id: record.id },
|
|
144
263
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../src/server/shadow/generator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../src/server/shadow/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* DynamoDB Single-Table設計における動的シャドーレコード管理を提供します。
|
|
5
5
|
*/
|
|
6
6
|
export type { ShadowFieldType, ShadowFieldConfig, ResourceShadowConfig, ShadowConfig, ShadowDiff, } from './types.js';
|
|
7
|
-
export type {
|
|
8
|
-
export { escapeString,
|
|
7
|
+
export type { ShadowRecord } from './generator.js';
|
|
8
|
+
export { escapeString, formatDatetime, formatBoolean, formatFieldValue, generateMainRecordSK, generateShadowRecords, formatNumberWithOffset, truncateString, normalizeJson, } from './generator.js';
|
|
9
9
|
export { calculateShadowDiff, isDiffEmpty, mergeShadowDiffs } from './differ.js';
|
|
10
|
-
export { getShadowConfig,
|
|
10
|
+
export { getShadowConfig, clearShadowConfigCache, } from './config.js';
|
|
11
|
+
export { inferFieldType, extractShadowableFields, } from './typeInference.js';
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/shadow/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/shadow/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACL,YAAY,EACZ,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,aAAa,GACd,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGjF,OAAO,EACL,eAAe,EACf,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,cAAc,EACd,uBAAuB,GACxB,MAAM,oBAAoB,CAAC"}
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* DynamoDB Single-Table設計における動的シャドーレコード管理を提供します。
|
|
5
5
|
*/
|
|
6
|
-
export { escapeString,
|
|
6
|
+
export { escapeString, formatDatetime, formatBoolean, formatFieldValue, generateMainRecordSK, generateShadowRecords, formatNumberWithOffset, truncateString, normalizeJson, } from './generator.js';
|
|
7
7
|
// 差分計算関数のエクスポート
|
|
8
8
|
export { calculateShadowDiff, isDiffEmpty, mergeShadowDiffs } from './differ.js';
|
|
9
9
|
// 設定管理関数のエクスポート
|
|
10
|
-
export { getShadowConfig,
|
|
10
|
+
export { getShadowConfig, clearShadowConfigCache, } from './config.js';
|
|
11
|
+
// 型推論関数のエクスポート
|
|
12
|
+
export { inferFieldType, extractShadowableFields, } from './typeInference.js';
|
|
11
13
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/shadow/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,EACL,YAAY,EACZ,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/shadow/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,EACL,YAAY,EACZ,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,aAAa,GACd,MAAM,gBAAgB,CAAC;AAExB,gBAAgB;AAChB,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEjF,gBAAgB;AAChB,OAAO,EACL,eAAe,EACf,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,eAAe;AACf,OAAO,EACL,cAAc,EACd,uBAAuB,GACxB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* シャドウフィールドの型推論
|
|
3
|
+
*
|
|
4
|
+
* レコードのフィールド値から型を自動的に推論します。
|
|
5
|
+
* JSON設定ファイルは不要で、実行時に型を判定します。
|
|
6
|
+
*
|
|
7
|
+
* 要件: 3.1-3.9
|
|
8
|
+
*/
|
|
9
|
+
import type { ShadowFieldType } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* フィールド値から型を推論する
|
|
12
|
+
*
|
|
13
|
+
* @param value - 推論するフィールド値
|
|
14
|
+
* @returns 推論された型、またはnull(シャドウ化不可能な場合)
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* inferFieldType('Hello') // => 'string'
|
|
19
|
+
* inferFieldType(123) // => 'number'
|
|
20
|
+
* inferFieldType(true) // => 'boolean'
|
|
21
|
+
* inferFieldType('2024-01-15T10:30:00.000Z') // => 'datetime'
|
|
22
|
+
* inferFieldType(['a', 'b']) // => 'array'
|
|
23
|
+
* inferFieldType({ key: 'value' }) // => 'object'
|
|
24
|
+
* inferFieldType(null) // => null
|
|
25
|
+
* inferFieldType(undefined) // => null
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function inferFieldType(value: unknown): ShadowFieldType | null;
|
|
29
|
+
/**
|
|
30
|
+
* レコードから自動的にシャドウ可能なフィールドを抽出する
|
|
31
|
+
*
|
|
32
|
+
* @param record - レコードオブジェクト
|
|
33
|
+
* @returns フィールド名と型のマップ
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const record = {
|
|
38
|
+
* id: '01HQXYZ...',
|
|
39
|
+
* title: 'Article',
|
|
40
|
+
* viewCount: 123,
|
|
41
|
+
* published: true,
|
|
42
|
+
* createdAt: '2024-01-15T10:30:00.000Z',
|
|
43
|
+
* tags: ['tech', 'aws'],
|
|
44
|
+
* metadata: { category: 'tech' },
|
|
45
|
+
* __shadowKeys: ['...'], // 除外される
|
|
46
|
+
* };
|
|
47
|
+
*
|
|
48
|
+
* extractShadowableFields(record);
|
|
49
|
+
* // => {
|
|
50
|
+
* // id: 'string',
|
|
51
|
+
* // title: 'string',
|
|
52
|
+
* // viewCount: 'number',
|
|
53
|
+
* // published: 'boolean',
|
|
54
|
+
* // createdAt: 'datetime',
|
|
55
|
+
* // tags: 'array',
|
|
56
|
+
* // metadata: 'object'
|
|
57
|
+
* // }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function extractShadowableFields(record: Record<string, unknown>): Record<string, ShadowFieldType>;
|
|
61
|
+
//# sourceMappingURL=typeInference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeInference.d.ts","sourceRoot":"","sources":["../../../src/server/shadow/typeInference.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAkCrE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAiBjC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* フィールド値から型を推論する
|
|
3
|
+
*
|
|
4
|
+
* @param value - 推論するフィールド値
|
|
5
|
+
* @returns 推論された型、またはnull(シャドウ化不可能な場合)
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* inferFieldType('Hello') // => 'string'
|
|
10
|
+
* inferFieldType(123) // => 'number'
|
|
11
|
+
* inferFieldType(true) // => 'boolean'
|
|
12
|
+
* inferFieldType('2024-01-15T10:30:00.000Z') // => 'datetime'
|
|
13
|
+
* inferFieldType(['a', 'b']) // => 'array'
|
|
14
|
+
* inferFieldType({ key: 'value' }) // => 'object'
|
|
15
|
+
* inferFieldType(null) // => null
|
|
16
|
+
* inferFieldType(undefined) // => null
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function inferFieldType(value) {
|
|
20
|
+
// null/undefined は除外
|
|
21
|
+
if (value === null || value === undefined) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
// 型判定
|
|
25
|
+
if (typeof value === 'string') {
|
|
26
|
+
// ISO 8601形式の日時文字列かチェック
|
|
27
|
+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)) {
|
|
28
|
+
return 'datetime';
|
|
29
|
+
}
|
|
30
|
+
return 'string';
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === 'number') {
|
|
33
|
+
return 'number';
|
|
34
|
+
}
|
|
35
|
+
if (typeof value === 'boolean') {
|
|
36
|
+
return 'boolean';
|
|
37
|
+
}
|
|
38
|
+
// array型
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
return 'array';
|
|
41
|
+
}
|
|
42
|
+
// object型
|
|
43
|
+
if (typeof value === 'object') {
|
|
44
|
+
return 'object';
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* レコードから自動的にシャドウ可能なフィールドを抽出する
|
|
50
|
+
*
|
|
51
|
+
* @param record - レコードオブジェクト
|
|
52
|
+
* @returns フィールド名と型のマップ
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const record = {
|
|
57
|
+
* id: '01HQXYZ...',
|
|
58
|
+
* title: 'Article',
|
|
59
|
+
* viewCount: 123,
|
|
60
|
+
* published: true,
|
|
61
|
+
* createdAt: '2024-01-15T10:30:00.000Z',
|
|
62
|
+
* tags: ['tech', 'aws'],
|
|
63
|
+
* metadata: { category: 'tech' },
|
|
64
|
+
* __shadowKeys: ['...'], // 除外される
|
|
65
|
+
* };
|
|
66
|
+
*
|
|
67
|
+
* extractShadowableFields(record);
|
|
68
|
+
* // => {
|
|
69
|
+
* // id: 'string',
|
|
70
|
+
* // title: 'string',
|
|
71
|
+
* // viewCount: 'number',
|
|
72
|
+
* // published: 'boolean',
|
|
73
|
+
* // createdAt: 'datetime',
|
|
74
|
+
* // tags: 'array',
|
|
75
|
+
* // metadata: 'object'
|
|
76
|
+
* // }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export function extractShadowableFields(record) {
|
|
80
|
+
const fields = {};
|
|
81
|
+
for (const [key, value] of Object.entries(record)) {
|
|
82
|
+
// __ プレフィックスは除外(内部メタデータ)
|
|
83
|
+
if (key.startsWith('__')) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
// 型推論
|
|
87
|
+
const type = inferFieldType(value);
|
|
88
|
+
if (type) {
|
|
89
|
+
fields[key] = type;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return fields;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=typeInference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeInference.js","sourceRoot":"","sources":["../../../src/server/shadow/typeInference.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,qBAAqB;IACrB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM;IACN,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,wBAAwB;QACxB,IAAI,sCAAsC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACvD,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,SAAS;IACT,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,UAAU;IACV,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAA+B;IAE/B,MAAM,MAAM,GAAoC,EAAE,CAAC;IAEnD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,yBAAyB;QACzB,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,SAAS;QACX,CAAC;QAED,MAAM;QACN,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/server/shadow/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/server/shadow/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC;KACvB,CAAC;IACF,OAAO,EAAE;QACP,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,CAAC;KACxC,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE;QACT,CAAC,YAAY,EAAE,MAAM,GAAG,oBAAoB,CAAC;KAC9C,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sBAAsB;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,sBAAsB;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timestamps.d.ts","sourceRoot":"","sources":["../../../src/server/utils/timestamps.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"timestamps.d.ts","sourceRoot":"","sources":["../../../src/server/utils/timestamps.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,IAAI,CAQ3D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAe1F;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczF"}
|
|
@@ -15,33 +15,10 @@ import { getShadowConfig } from '../../index.js';
|
|
|
15
15
|
*/
|
|
16
16
|
export function getTimestampFields() {
|
|
17
17
|
const shadowConfig = getShadowConfig();
|
|
18
|
-
//
|
|
19
|
-
if (!shadowConfig.database) {
|
|
20
|
-
// デフォルト値を返す
|
|
21
|
-
return {
|
|
22
|
-
createdAt: 'createdAt',
|
|
23
|
-
updatedAt: 'updatedAt',
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
const { timestamps } = shadowConfig.database;
|
|
27
|
-
// timestamps 設定がない場合はデフォルト値を返す
|
|
28
|
-
if (!timestamps) {
|
|
29
|
-
return {
|
|
30
|
-
createdAt: 'createdAt',
|
|
31
|
-
updatedAt: 'updatedAt',
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
// timestamps 設定がある場合はそれを使用
|
|
35
|
-
if (typeof timestamps === 'object') {
|
|
36
|
-
return {
|
|
37
|
-
createdAt: timestamps.createdAt,
|
|
38
|
-
updatedAt: timestamps.updatedAt,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
// デフォルト値を返す
|
|
18
|
+
// 新しい設定形式: 環境変数ベース
|
|
42
19
|
return {
|
|
43
|
-
createdAt:
|
|
44
|
-
updatedAt:
|
|
20
|
+
createdAt: shadowConfig.createdAtField,
|
|
21
|
+
updatedAt: shadowConfig.updatedAtField,
|
|
45
22
|
};
|
|
46
23
|
}
|
|
47
24
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timestamps.js","sourceRoot":"","sources":["../../../src/server/utils/timestamps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAUjD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;IAEvC,
|
|
1
|
+
{"version":3,"file":"timestamps.js","sourceRoot":"","sources":["../../../src/server/utils/timestamps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAUjD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;IAEvC,mBAAmB;IACnB,OAAO;QACL,SAAS,EAAE,YAAY,CAAC,cAAc;QACtC,SAAS,EAAE,YAAY,CAAC,cAAc;KACvC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAA6B;IAC/D,MAAM,eAAe,GAAG,kBAAkB,EAAE,CAAC;IAE7C,4BAA4B;IAC5B,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,OAAO;QACL,GAAG,IAAI;QACP,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,GAAG;QAChC,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,GAAG;KACjC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAA6B;IAC9D,MAAM,eAAe,GAAG,kBAAkB,EAAE,CAAC;IAE7C,4BAA4B;IAC5B,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,OAAO;QACL,GAAG,IAAI;QACP,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,GAAG;KACjC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ttl.d.ts","sourceRoot":"","sources":["../../../src/server/utils/ttl.ts"],"names":[],"mappings":"AAQA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"ttl.d.ts","sourceRoot":"","sources":["../../../src/server/utils/ttl.ts"],"names":[],"mappings":"AAQA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CA+BpF;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CACpB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzB"}
|
package/dist/server/utils/ttl.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* TTL(Time To Live)ユーティリティ
|
|
3
3
|
* DynamoDB TTL設定を管理
|
|
4
4
|
*/
|
|
5
|
-
import { createLogger
|
|
5
|
+
import { createLogger } from '../../index.js';
|
|
6
6
|
const logger = createLogger({ service: 'records-lambda' });
|
|
7
7
|
/**
|
|
8
8
|
* TTLを計算する
|
|
@@ -12,17 +12,19 @@ const logger = createLogger({ service: 'records-lambda' });
|
|
|
12
12
|
* @returns TTL(Unix timestamp、秒単位)、TTL不要の場合はundefined
|
|
13
13
|
*/
|
|
14
14
|
export function calculateTTL(resource, createdAt) {
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
15
|
+
// 新しい実装: 環境変数ベースのTTL設定
|
|
16
|
+
// 環境変数から取得(例: ARTICLES_TTL_DAYS=30)
|
|
17
|
+
const envKey = `${resource.toUpperCase()}_TTL_DAYS`;
|
|
18
|
+
const ttlDaysStr = process.env[envKey];
|
|
19
|
+
if (!ttlDaysStr) {
|
|
19
20
|
// TTL設定がないリソースはundefinedを返す
|
|
20
21
|
return undefined;
|
|
21
22
|
}
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const ttlDays = parseInt(ttlDaysStr, 10);
|
|
24
|
+
if (isNaN(ttlDays) || ttlDays <= 0) {
|
|
25
|
+
logger.warn('Invalid TTL_DAYS value', { resource, envKey, value: ttlDaysStr });
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
26
28
|
// 作成日時からTTLを計算
|
|
27
29
|
const createdAtMs = new Date(createdAt).getTime();
|
|
28
30
|
const ttlMs = createdAtMs + ttlDays * 24 * 60 * 60 * 1000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ttl.js","sourceRoot":"","sources":["../../../src/server/utils/ttl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"ttl.js","sourceRoot":"","sources":["../../../src/server/utils/ttl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAE3D;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,SAAiB;IAC9D,uBAAuB;IACvB,oCAAoC;IACpC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IACpD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAEvC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,4BAA4B;QAC5B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACzC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/E,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,eAAe;IACf,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;IAClD,MAAM,KAAK,GAAG,WAAW,GAAG,OAAO,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAErC,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE;QAC7B,QAAQ;QACR,OAAO;QACP,SAAS;QACT,GAAG;QACH,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;KAC5C,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CACpB,QAAgB,EAChB,UAAmC;IAEnC,MAAM,SAAS,GAAG,UAAU,CAAC,SAAmB,CAAC;IACjD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,+CAA+C,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3E,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC9C,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,aAAa;QACb,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,OAAO;QACL,GAAG,UAAU;QACb,GAAG;KACJ,CAAC;AACJ,CAAC"}
|