sonamu 0.7.12 → 0.7.13

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 (55) hide show
  1. package/dist/api/config.d.ts +0 -3
  2. package/dist/api/config.d.ts.map +1 -1
  3. package/dist/api/config.js +1 -1
  4. package/dist/api/sonamu.d.ts.map +1 -1
  5. package/dist/api/sonamu.js +14 -4
  6. package/dist/bin/cli.js +2 -58
  7. package/dist/syncer/api-parser.d.ts.map +1 -1
  8. package/dist/syncer/api-parser.js +3 -2
  9. package/dist/syncer/syncer.d.ts +2 -1
  10. package/dist/syncer/syncer.d.ts.map +1 -1
  11. package/dist/syncer/syncer.js +17 -18
  12. package/dist/types/types.d.ts +1 -1
  13. package/dist/ui/ai-api.d.ts +1 -0
  14. package/dist/ui/ai-api.d.ts.map +1 -0
  15. package/dist/ui/ai-api.js +50 -0
  16. package/dist/ui/ai-client.d.ts +1 -0
  17. package/dist/ui/ai-client.d.ts.map +1 -0
  18. package/dist/ui/ai-client.js +438 -0
  19. package/dist/ui/api.d.ts +3 -0
  20. package/dist/ui/api.d.ts.map +1 -0
  21. package/dist/ui/api.js +680 -0
  22. package/dist/ui-web/assets/brand-icons-Cu_C0hZ4.svg +1008 -0
  23. package/dist/ui-web/assets/brand-icons-F3SPCeH1.woff +0 -0
  24. package/dist/ui-web/assets/brand-icons-XL9sxUpA.woff2 +0 -0
  25. package/dist/ui-web/assets/brand-icons-sqJ2Pg7a.eot +0 -0
  26. package/dist/ui-web/assets/brand-icons-ubhWoxly.ttf +0 -0
  27. package/dist/ui-web/assets/flags-DOLqOU7Y.png +0 -0
  28. package/dist/ui-web/assets/icons-BOCtAERH.woff +0 -0
  29. package/dist/ui-web/assets/icons-CHzK1VD9.eot +0 -0
  30. package/dist/ui-web/assets/icons-D29ZQHHw.ttf +0 -0
  31. package/dist/ui-web/assets/icons-Du6TOHnR.woff2 +0 -0
  32. package/dist/ui-web/assets/icons-RwhydX30.svg +1518 -0
  33. package/dist/ui-web/assets/index-CpaB9P6g.css +1 -0
  34. package/dist/ui-web/assets/index-J9MCfjCd.js +95 -0
  35. package/dist/ui-web/assets/outline-icons-BfdLr8tr.svg +366 -0
  36. package/dist/ui-web/assets/outline-icons-DD8jm0uy.ttf +0 -0
  37. package/dist/ui-web/assets/outline-icons-DInHoiqI.woff2 +0 -0
  38. package/dist/ui-web/assets/outline-icons-LX8adJ4n.eot +0 -0
  39. package/dist/ui-web/assets/outline-icons-aQ88nltS.woff +0 -0
  40. package/dist/ui-web/assets/provider-utils_false-BKJD46kk.js +1 -0
  41. package/dist/ui-web/assets/provider-utils_false-Bu5lmX18.js +1 -0
  42. package/dist/ui-web/index.html +13 -0
  43. package/dist/ui-web/vite.svg +1 -0
  44. package/dist/vector/embedding.d.ts.map +1 -1
  45. package/dist/vector/embedding.js +7 -7
  46. package/package.json +7 -5
  47. package/src/api/config.ts +0 -3
  48. package/src/api/sonamu.ts +17 -4
  49. package/src/bin/cli.ts +1 -67
  50. package/src/syncer/api-parser.ts +2 -1
  51. package/src/syncer/syncer.ts +20 -21
  52. package/src/ui/ai-api.ts +60 -0
  53. package/src/ui/ai-client.ts +499 -0
  54. package/src/ui/api.ts +786 -0
  55. package/src/vector/embedding.ts +8 -6
@@ -0,0 +1,438 @@
1
+ // import { anthropic } from "@ai-sdk/anthropic";
2
+ // import { type ModelMessage, stepCountIs, streamText, tool } from "ai";
3
+ // import assert from "assert";
4
+ // import fs from "fs";
5
+ // import path from "path";
6
+ // import {
7
+ // EntityManager,
8
+ // type EntityProp,
9
+ // type FixtureRecord,
10
+ // nonNullable,
11
+ // Sonamu,
12
+ // TemplateOptions,
13
+ // } from "sonamu";
14
+ // import { z } from "zod";
15
+ // type ValidationError = {
16
+ // field: string;
17
+ // message: string;
18
+ // };
19
+ // class AIClient {
20
+ // private model = anthropic("claude-sonnet-4-5");
21
+ // async init() {
22
+ // console.log("AI client initialized with AI SDK");
23
+ // }
24
+ // handleFixture(messages: ModelMessage[], fixtureRecords: FixtureRecord[]) {
25
+ // // 현재 fixtureRecords에서 사용된 엔티티들의 구조 정보 수집
26
+ // const usedEntityIds = [...new Set(fixtureRecords.map((r) => r.entityId))];
27
+ // const entityStructures = usedEntityIds.map((entityId) => {
28
+ // const entity = EntityManager.get(entityId);
29
+ // return {
30
+ // entityId: entity.id,
31
+ // table: entity.table,
32
+ // props: entity.props,
33
+ // relations: entity.relations,
34
+ // enumLabels: entity.enumLabels,
35
+ // };
36
+ // });
37
+ // const systemMessage = `
38
+ // 당신은 픽스쳐 레코드를 수정하고 생성할 수 있는 도우미입니다.
39
+ // 현재 픽스쳐 레코드:
40
+ // ${JSON.stringify(fixtureRecords, null, 2)}
41
+ // 엔티티 구조 정보:
42
+ // ${JSON.stringify(entityStructures, null, 2)}
43
+ // ## 픽스쳐 수정
44
+ // 사용자가 픽스쳐 값 수정을 요청하면 updateFixtures 도구를 사용하여 변경사항을 적용하세요.
45
+ // - fixtureId: 수정할 픽스쳐 ID (형식: "EntityId#id")
46
+ // - updates: 컬럼명을 키로, 새 값을 값으로 하는 객체
47
+ // 예시: "User#1" 픽스쳐의 "name" 컬럼을 "홍길동"으로 변경하려면:
48
+ // updateFixtures({ updates: [{ fixtureId: "User#1", updates: { name: "홍길동" } }] })
49
+ // 변경될 컬럼의 type이 relation인 경우, 관련 엔티티에도 반영되어야 할 컬럼이 있는지 확인하세요.
50
+ // ## 픽스쳐 생성
51
+ // 사용자가 새로운 픽스쳐 생성을 요청하면 createFixtures 도구를 사용하세요.
52
+ // - entityId: 생성할 엔티티 ID
53
+ // - id: 새 레코드의 ID (기존 픽스쳐와 중복되지 않는 음수 사용 권장, 예: -1, -2)
54
+ // - columns: 컬럼명을 키로, 값을 값으로 하는 객체 (엔티티 구조 참고)
55
+ // 예시: 새로운 User 픽스쳐를 생성하려면:
56
+ // createFixtures({ fixtures: [{ entityId: "User", id: -1, columns: { name: "홍길동", email: "hong@example.com" } }] })
57
+ // `;
58
+ // return streamText({
59
+ // model: this.model,
60
+ // system: systemMessage,
61
+ // messages,
62
+ // tools: {
63
+ // updateFixtures: tool({
64
+ // description:
65
+ // "픽스쳐 레코드의 값을 수정합니다. 사용자가 특정 컬럼이나 값을 변경해달라고 요청할 때 사용하세요.",
66
+ // inputSchema: z.object({
67
+ // updates: z.array(
68
+ // z.object({
69
+ // fixtureId: z.string().describe("수정할 픽스쳐 ID (형식: EntityId#id)"),
70
+ // updates: z
71
+ // .record(z.string(), z.unknown())
72
+ // .describe("컬럼명을 키로, 새 값을 값으로 하는 객체"),
73
+ // }),
74
+ // ),
75
+ // }),
76
+ // execute: async ({
77
+ // updates,
78
+ // }): Promise<{ success: boolean; updatedRecords: FixtureRecord[] }> => {
79
+ // // fixtureRecords를 복사하고 업데이트 적용
80
+ // const updatedRecords: FixtureRecord[] = fixtureRecords.map((record) => {
81
+ // const update = updates.find((u) => u.fixtureId === record.fixtureId);
82
+ // if (update) {
83
+ // // columns의 value를 업데이트
84
+ // for (const [columnName, newValue] of Object.entries(update.updates)) {
85
+ // record.columns[columnName].value =
86
+ // newValue as FixtureRecord["columns"][string]["value"];
87
+ // }
88
+ // return record;
89
+ // }
90
+ // return record;
91
+ // });
92
+ // return { success: true, updatedRecords };
93
+ // },
94
+ // }),
95
+ // createFixtures: tool({
96
+ // description:
97
+ // "새로운 픽스쳐 레코드를 생성합니다. 사용자가 새로운 데이터를 추가해달라고 요청할 때 사용하세요.",
98
+ // inputSchema: z.object({
99
+ // fixtures: z.array(
100
+ // z.object({
101
+ // entityId: z.string().describe("생성할 엔티티 ID"),
102
+ // id: z.number().describe("새 레코드의 ID (음수 권장, 예: -1, -2)"),
103
+ // columns: z
104
+ // .record(z.string(), z.unknown())
105
+ // .describe("컬럼명을 키로, 값을 값으로 하는 객체"),
106
+ // }),
107
+ // ),
108
+ // }),
109
+ // execute: async ({
110
+ // fixtures,
111
+ // }): Promise<{ success: boolean; updatedRecords: FixtureRecord[] }> => {
112
+ // const newRecords: FixtureRecord[] = fixtures.map((fixture) => {
113
+ // const entity = EntityManager.get(fixture.entityId);
114
+ // // 엔티티 props를 기반으로 columns 구성
115
+ // const columns: FixtureRecord["columns"] = {};
116
+ // for (const prop of entity.props) {
117
+ // if (prop.type === "virtual") continue;
118
+ // let value = fixture.columns[prop.name] ?? null;
119
+ // if (prop.name === "created_at") {
120
+ // // 현재 시간으로 설정
121
+ // value = new Date().toISOString();
122
+ // } else if (
123
+ // prop.type === "relation" &&
124
+ // (prop.relationType === "HasMany" || prop.relationType === "ManyToMany")
125
+ // ) {
126
+ // // 배열로 변환
127
+ // value = Array.isArray(value) ? value : [value].filter(nonNullable);
128
+ // }
129
+ // columns[prop.name] = {
130
+ // prop,
131
+ // value: value as FixtureRecord["columns"][string]["value"],
132
+ // };
133
+ // }
134
+ // return {
135
+ // fixtureId: `${fixture.entityId}#${fixture.id}`,
136
+ // entityId: fixture.entityId,
137
+ // id: fixture.id,
138
+ // columns,
139
+ // fetchedRecords: [],
140
+ // belongsRecords: [],
141
+ // override: false,
142
+ // };
143
+ // });
144
+ // // 새 레코드들의 relation 컬럼을 확인하여 기존 레코드들의 역방향 relation 업데이트
145
+ // for (const newRecord of newRecords) {
146
+ // for (const [_colName, col] of Object.entries(newRecord.columns)) {
147
+ // if (col.prop.type !== "relation" || col.value === null) continue;
148
+ // const relatedEntityId = col.prop.with;
149
+ // const relatedIds = Array.isArray(col.value) ? col.value : [col.value];
150
+ // for (const relatedId of relatedIds) {
151
+ // const relatedFixtureId = `${relatedEntityId}#${relatedId}`;
152
+ // const relatedRecord = newRecords.find((r) => r.fixtureId === relatedFixtureId);
153
+ // if (relatedRecord) {
154
+ // // 역방향 relation 찾기
155
+ // const reverseCol = Object.entries(relatedRecord.columns).find(
156
+ // ([, c]) => c.prop.type === "relation" && c.prop.with === newRecord.entityId,
157
+ // );
158
+ // if (reverseCol) {
159
+ // const [reverseColName, reverseColValue] = reverseCol;
160
+ // const currentValue = reverseColValue.value;
161
+ // // 역방향이 배열인 경우 (HasMany, ManyToMany)
162
+ // if (
163
+ // reverseColValue.prop.type === "relation" &&
164
+ // (reverseColValue.prop.relationType === "HasMany" ||
165
+ // reverseColValue.prop.relationType === "ManyToMany")
166
+ // ) {
167
+ // assert(Array.isArray(currentValue), "currentValue must be an array");
168
+ // if (!currentValue.includes(newRecord.id)) {
169
+ // relatedRecord.columns[reverseColName] = {
170
+ // ...reverseColValue,
171
+ // value: [...currentValue, newRecord.id],
172
+ // };
173
+ // }
174
+ // } else {
175
+ // // 역방향이 단일 값인 경우 (BelongsToOne, OneToOne)
176
+ // relatedRecord.columns[reverseColName] = {
177
+ // ...reverseColValue,
178
+ // value: newRecord.id,
179
+ // };
180
+ // }
181
+ // }
182
+ // }
183
+ // }
184
+ // }
185
+ // }
186
+ // return { success: true, updatedRecords: newRecords };
187
+ // },
188
+ // }),
189
+ // },
190
+ // });
191
+ // }
192
+ // handleEntity(messages: ModelMessage[]) {
193
+ // // entity.instructions.md 파일 읽기
194
+ // const instructionsPath = path.join(import.meta.dirname, "..", "entity.instructions.md");
195
+ // const instructions = fs.readFileSync(instructionsPath, "utf-8");
196
+ // // 현재 등록된 엔티티 정보 수집
197
+ // const entityIds = EntityManager.getAllIds();
198
+ // const existingEntities = entityIds.map((entityId) => {
199
+ // const entity = EntityManager.get(entityId);
200
+ // return {
201
+ // id: entity.id,
202
+ // title: entity.title,
203
+ // table: entity.table,
204
+ // props: entity.props.map((p) => ({
205
+ // name: p.name,
206
+ // type: p.type,
207
+ // desc: p.desc,
208
+ // })),
209
+ // };
210
+ // });
211
+ // const systemMessage = `
212
+ // 당신은 Sonamu 프레임워크에서 Entity와 Enum을 생성하는 도우미입니다.
213
+ // ${instructions}
214
+ // ## 현재 등록된 Entity 목록
215
+ // 다른 엔티티와 관계(relation)를 맺거나 subset에서 참조할 때 반드시 아래 정보를 확인하세요.
216
+ // ${JSON.stringify(existingEntities, null, 2)}
217
+ // ## Tool 사용 가이드
218
+ // ### Entity 생성 (createEntity)
219
+ // 사용자가 새로운 Entity 생성을 요청하면 createEntity 도구를 사용하세요.
220
+ // - entityId: PascalCase로 된 Entity ID (예: "User", "ProductCategory")
221
+ // - title: 한글 제목 (예: "사용자", "상품 카테고리")
222
+ // - table: snake_case로 된 테이블명 (예: "users", "product_categories")
223
+ // - parentId: 부모 Entity ID (선택사항)
224
+ // - props: Entity의 프로퍼티 배열 (위 문서의 Property Types 참고)
225
+ // - indexes: 인덱스 배열
226
+ // - subsets: 서브셋 정의 (기본값: { A: ["id"] })
227
+ // - enums: Enum 정의
228
+ // ### Entity 수정 (updateEntity)
229
+ // 기존 Entity를 수정할 때 updateEntity 도구를 사용하세요. Enum 추가, props 추가/수정, indexes 수정 등 모든 수정 작업에 사용합니다.
230
+ // - entityId: 수정할 Entity ID
231
+ // - updates: 수정할 필드들 (부분 업데이트)
232
+ // - title: 엔티티 한글 제목
233
+ // - table: 테이블명
234
+ // - props: 추가할 프로퍼티 배열 (기존 props에 추가, 같은 이름이면 교체)
235
+ // - indexes: 추가할 인덱스 배열 (기존 indexes에 추가)
236
+ // - subsets: 서브셋 정의 (기존 subsets에 병합)
237
+ // - enumLabels: Enum 정의 (기존 enumLabels에 병합)
238
+ // - mode: "merge"(기본값) 또는 "replace"
239
+ // - merge: 기존 값에 병합
240
+ // - replace: 해당 필드 전체 교체
241
+ // 예시: Employee에 새 Enum 추가
242
+ // updateEntity({ entityId: "Employee", updates: { enumLabels: { "EmployeeRole": { "admin": "관리자", "user": "일반" } } } })
243
+ // 예시: Project에 새 프로퍼티 추가
244
+ // updateEntity({ entityId: "Project", updates: { props: [{ name: "priority", type: "integer", desc: "우선순위" }] } })
245
+ // ## 필수 사항
246
+ // - Entity의 props에는 최소한 id(integer, unsigned), created_at(timestamp)가 포함되어야 합니다.
247
+ // - relation 필드는 onUpdate, onDelete가 필수입니다. (예외: OneToOne에서 hasJoinColumn이 false인 경우)
248
+ // - Enum ID는 보통 EntityId + 속성명 형태입니다 (예: UserStatus, ProductType)
249
+ // - subset에서 다른 엔티티의 프로퍼티를 참조할 때는 반드시 해당 엔티티의 실제 프로퍼티명을 사용하세요.
250
+ // ## 검증 오류 처리
251
+ // 도구 호출 결과로 검증 오류(validationErrors)가 반환되면:
252
+ // 1. 오류 메시지를 분석하여 문제점을 파악하세요.
253
+ // 2. 오류를 수정한 데이터로 createEntity를 다시 호출하세요.
254
+ // 3. 사용자에게 오류를 그대로 전달하지 말고, 수정 후 재시도하세요.
255
+ // ### 일반적인 검증 오류와 수정 방법
256
+ // | 오류 메시지 | 수정 방법 |
257
+ // |------------|----------|
258
+ // | "id 프로퍼티가 필수" | props에 { name: "id", type: "integer", unsigned: true } 추가 |
259
+ // | "created_at 프로퍼티가 필수" | props에 { name: "created_at", type: "timestamp", dbDefault: "CURRENT_TIMESTAMP" } 추가 |
260
+ // | "XxxOrderBy enum이 필수" | enums에 { "XxxOrderBy": { "id-desc": "ID최신순" } } 추가 |
261
+ // | "XxxSearchField enum이 필수" | enums에 { "XxxSearchField": { "id": "ID" } } 추가 |
262
+ // | "string 타입은 length가 필수" | 해당 prop에 length 추가 (예: 255) |
263
+ // | "text 타입은 textType이 필수" | 해당 prop에 textType 추가 ("text", "mediumtext", "longtext") |
264
+ // | "onUpdate가 필수" | 해당 relation prop에 onUpdate, onDelete 추가 ("CASCADE") |
265
+ // `;
266
+ // return streamText({
267
+ // model: this.model,
268
+ // system: systemMessage,
269
+ // messages,
270
+ // stopWhen: stepCountIs(2),
271
+ // tools: {
272
+ // createEntity: tool({
273
+ // description:
274
+ // "새로운 Entity를 생성합니다. 사용자가 새로운 엔티티나 테이블 생성을 요청할 때 사용하세요.",
275
+ // inputSchema: TemplateOptions.shape.entity,
276
+ // execute: async (
277
+ // entity,
278
+ // ): Promise<{
279
+ // success: boolean;
280
+ // entityId: string;
281
+ // error?: string;
282
+ // validationErrors?: ValidationError[];
283
+ // }> => {
284
+ // try {
285
+ // // 입력 검증
286
+ // const validationErrors = validateEntityJson(entity);
287
+ // if (validationErrors.length > 0) {
288
+ // return {
289
+ // success: false,
290
+ // entityId: entity.entityId,
291
+ // error: `검증 오류: ${validationErrors.map((e) => `[${e.field}] ${e.message}`).join(", ")}`,
292
+ // validationErrors,
293
+ // };
294
+ // }
295
+ // await Sonamu.syncer.createEntity({
296
+ // subsets: { A: ["id"] },
297
+ // enums: {},
298
+ // ...entity,
299
+ // });
300
+ // // EntityManager 리로드
301
+ // await EntityManager.reload();
302
+ // return { success: true, entityId: entity.entityId };
303
+ // } catch (e) {
304
+ // const error = e instanceof Error ? e.message : "Unknown error";
305
+ // return { success: false, entityId: entity.entityId, error };
306
+ // }
307
+ // },
308
+ // }),
309
+ // updateEntity: tool({
310
+ // description:
311
+ // "기존 Entity를 수정합니다. Enum 추가, props 추가/수정, indexes 수정, subsets 수정 등 모든 엔티티 수정 작업에 사용하세요.",
312
+ // inputSchema: z.object({
313
+ // entityId: z.string().describe("수정할 Entity ID"),
314
+ // updates: TemplateOptions.shape.entity.partial().describe("수정할 필드들"),
315
+ // mode: z
316
+ // .enum(["merge", "replace"])
317
+ // .optional()
318
+ // .describe("수정 모드: merge(기본값, 기존 값에 병합) 또는 replace(전체 교체)"),
319
+ // }),
320
+ // execute: async ({
321
+ // entityId,
322
+ // updates,
323
+ // mode = "merge",
324
+ // }): Promise<{
325
+ // success: boolean;
326
+ // entityId: string;
327
+ // error?: string;
328
+ // validationErrors?: ValidationError[];
329
+ // }> => {
330
+ // try {
331
+ // const entity = EntityManager.get(entityId);
332
+ // for (const [key, value] of Object.entries(updates)) {
333
+ // if (
334
+ // ["entityId", "parentId", "title", "table"].includes(key) &&
335
+ // value !== undefined
336
+ // ) {
337
+ // entity[key] = value;
338
+ // }
339
+ // }
340
+ // // props: merge 시 이름 기준 병합, replace 시 교체
341
+ // if (updates.props !== undefined) {
342
+ // if (mode === "replace") {
343
+ // entity.props = updates.props as EntityProp[];
344
+ // } else {
345
+ // for (const newProp of updates.props) {
346
+ // const existingIndex = entity.props.findIndex((p) => p.name === newProp.name);
347
+ // if (existingIndex >= 0) {
348
+ // entity.props[existingIndex] = newProp as EntityProp;
349
+ // } else {
350
+ // entity.props.push(newProp as EntityProp);
351
+ // }
352
+ // }
353
+ // }
354
+ // }
355
+ // // indexes: merge 시 추가, replace 시 교체
356
+ // if (updates.indexes !== undefined) {
357
+ // entity.indexes =
358
+ // mode === "replace" ? updates.indexes : [...entity.indexes, ...updates.indexes];
359
+ // }
360
+ // // subsets, enumLabels: assign으로 병합 또는 교체
361
+ // if (updates.subsets !== undefined) {
362
+ // entity.subsets =
363
+ // mode === "replace" ? updates.subsets : { ...entity.subsets, ...updates.subsets };
364
+ // }
365
+ // if (updates.enums !== undefined) {
366
+ // entity.enumLabels =
367
+ // mode === "replace" ? updates.enums : { ...entity.enumLabels, ...updates.enums };
368
+ // }
369
+ // // 저장 전 검증
370
+ // const validationErrors = validateEntityJson({
371
+ // ...entity,
372
+ // entityId: entity.id,
373
+ // enums: entity.enumLabels,
374
+ // });
375
+ // if (validationErrors.length > 0) {
376
+ // return {
377
+ // success: false,
378
+ // entityId,
379
+ // error: `검증 오류: ${validationErrors.map((e) => `[${e.field}] ${e.message}`).join(", ")}`,
380
+ // validationErrors,
381
+ // };
382
+ // }
383
+ // await entity.save();
384
+ // return { success: true, entityId };
385
+ // } catch (e) {
386
+ // const error = e instanceof Error ? e.message : "Unknown error";
387
+ // return { success: false, entityId, error };
388
+ // }
389
+ // },
390
+ // }),
391
+ // },
392
+ // });
393
+ // }
394
+ // }
395
+ // /**
396
+ // * Entity JSON이 entity.instructions.md의 규칙을 따르는지 검증합니다.
397
+ // */
398
+ // function validateEntityJson(input: TemplateOptions["entity"]): ValidationError[] {
399
+ // const errors: ValidationError[] = [];
400
+ // const { entityId, props, enums } = input;
401
+ // // 1. id, created_at prop 필수
402
+ // const hasIdProp = props?.some((p) => p.name === "id");
403
+ // if (!hasIdProp) {
404
+ // errors.push({ field: "props", message: "id 프로퍼티가 필수입니다." });
405
+ // }
406
+ // const hasCreatedAtProp = props?.some((p) => p.name === "created_at");
407
+ // if (!hasCreatedAtProp) {
408
+ // errors.push({ field: "props", message: "created_at 프로퍼티가 필수입니다." });
409
+ // }
410
+ // // 2. 필수 enum 검증: EntityNameOrderBy, EntityNameSearchField
411
+ // const orderByEnumId = `${entityId}OrderBy`;
412
+ // const searchFieldEnumId = `${entityId}SearchField`;
413
+ // if (!enums?.[orderByEnumId]) {
414
+ // errors.push({
415
+ // field: "enums",
416
+ // message: `${orderByEnumId} enum이 필수입니다. (예: { "id-desc": "ID최신순" })`,
417
+ // });
418
+ // }
419
+ // if (!enums?.[searchFieldEnumId]) {
420
+ // errors.push({
421
+ // field: "enums",
422
+ // message: `${searchFieldEnumId} enum이 필수입니다. (예: { "id": "ID" })`,
423
+ // });
424
+ // }
425
+ // // 3. enum prop의 id가 enums에 정의되어 있는지 확인 (cross-field 검증)
426
+ // for (const prop of props ?? []) {
427
+ // if (prop.type === "enum" && !enums?.[prop.id]) {
428
+ // errors.push({
429
+ // field: `props.${prop.name}`,
430
+ // message: `enum id "${prop.id}"가 enums에 정의되어 있지 않습니다.`,
431
+ // });
432
+ // }
433
+ // }
434
+ // return errors;
435
+ // }
436
+ // export const aiClient = new AIClient();
437
+
438
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91aS9haS1jbGllbnQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gaW1wb3J0IHsgYW50aHJvcGljIH0gZnJvbSBcIkBhaS1zZGsvYW50aHJvcGljXCI7XG4vLyBpbXBvcnQgeyB0eXBlIE1vZGVsTWVzc2FnZSwgc3RlcENvdW50SXMsIHN0cmVhbVRleHQsIHRvb2wgfSBmcm9tIFwiYWlcIjtcbi8vIGltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuLy8gaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuLy8gaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbi8vIGltcG9ydCB7XG4vLyAgIEVudGl0eU1hbmFnZXIsXG4vLyAgIHR5cGUgRW50aXR5UHJvcCxcbi8vICAgdHlwZSBGaXh0dXJlUmVjb3JkLFxuLy8gICBub25OdWxsYWJsZSxcbi8vICAgU29uYW11LFxuLy8gICBUZW1wbGF0ZU9wdGlvbnMsXG4vLyB9IGZyb20gXCJzb25hbXVcIjtcbi8vIGltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5cbi8vIHR5cGUgVmFsaWRhdGlvbkVycm9yID0ge1xuLy8gICBmaWVsZDogc3RyaW5nO1xuLy8gICBtZXNzYWdlOiBzdHJpbmc7XG4vLyB9O1xuXG4vLyBjbGFzcyBBSUNsaWVudCB7XG4vLyAgIHByaXZhdGUgbW9kZWwgPSBhbnRocm9waWMoXCJjbGF1ZGUtc29ubmV0LTQtNVwiKTtcblxuLy8gICBhc3luYyBpbml0KCkge1xuLy8gICAgIGNvbnNvbGUubG9nKFwiQUkgY2xpZW50IGluaXRpYWxpemVkIHdpdGggQUkgU0RLXCIpO1xuLy8gICB9XG5cbi8vICAgaGFuZGxlRml4dHVyZShtZXNzYWdlczogTW9kZWxNZXNzYWdlW10sIGZpeHR1cmVSZWNvcmRzOiBGaXh0dXJlUmVjb3JkW10pIHtcbi8vICAgICAvLyDtmITsnqwgZml4dHVyZVJlY29yZHPsl5DshJwg7IKs7Jqp65CcIOyXlO2LsO2LsOuTpOydmCDqtazsobAg7KCV67O0IOyImOynkVxuLy8gICAgIGNvbnN0IHVzZWRFbnRpdHlJZHMgPSBbLi4ubmV3IFNldChmaXh0dXJlUmVjb3Jkcy5tYXAoKHIpID0+IHIuZW50aXR5SWQpKV07XG4vLyAgICAgY29uc3QgZW50aXR5U3RydWN0dXJlcyA9IHVzZWRFbnRpdHlJZHMubWFwKChlbnRpdHlJZCkgPT4ge1xuLy8gICAgICAgY29uc3QgZW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpO1xuXG4vLyAgICAgICByZXR1cm4ge1xuLy8gICAgICAgICBlbnRpdHlJZDogZW50aXR5LmlkLFxuLy8gICAgICAgICB0YWJsZTogZW50aXR5LnRhYmxlLFxuLy8gICAgICAgICBwcm9wczogZW50aXR5LnByb3BzLFxuLy8gICAgICAgICByZWxhdGlvbnM6IGVudGl0eS5yZWxhdGlvbnMsXG4vLyAgICAgICAgIGVudW1MYWJlbHM6IGVudGl0eS5lbnVtTGFiZWxzLFxuLy8gICAgICAgfTtcbi8vICAgICB9KTtcblxuLy8gICAgIGNvbnN0IHN5c3RlbU1lc3NhZ2UgPSBgXG4vLyAgICAgICAgIOuLueyLoOydgCDtlL3siqTss5Ag66CI7L2U65Oc66W8IOyImOygle2VmOqzoCDsg53shLHtlaAg7IiYIOyeiOuKlCDrj4TsmrDrr7jsnoXri4jri6QuXG5cbi8vICAgICAgICAg7ZiE7J6sIO2UveyKpOyzkCDroIjsvZTrk5w6XG4vLyAgICAgICAgICR7SlNPTi5zdHJpbmdpZnkoZml4dHVyZVJlY29yZHMsIG51bGwsIDIpfVxuXG4vLyAgICAgICAgIOyXlO2LsO2LsCDqtazsobAg7KCV67O0OlxuLy8gICAgICAgICAke0pTT04uc3RyaW5naWZ5KGVudGl0eVN0cnVjdHVyZXMsIG51bGwsIDIpfVxuXG4vLyAgICAgICAgICMjIO2UveyKpOyzkCDsiJjsoJVcbi8vICAgICAgICAg7IKs7Jqp7J6Q6rCAIO2UveyKpOyzkCDqsJIg7IiY7KCV7J2EIOyalOyyre2VmOuptCB1cGRhdGVGaXh0dXJlcyDrj4Tqtazrpbwg7IKs7Jqp7ZWY7JesIOuzgOqyveyCrO2VreydhCDsoIHsmqntlZjshLjsmpQuXG4vLyAgICAgICAgIC0gZml4dHVyZUlkOiDsiJjsoJXtlaAg7ZS97Iqk7LOQIElEICjtmJXsi506IFwiRW50aXR5SWQjaWRcIilcbi8vICAgICAgICAgLSB1cGRhdGVzOiDsu6zrn7zrqoXsnYQg7YKk66GcLCDsg4gg6rCS7J2EIOqwkuycvOuhnCDtlZjripQg6rCd7LK0XG5cbi8vICAgICAgICAg7JiI7IucOiBcIlVzZXIjMVwiIO2UveyKpOyzkOydmCBcIm5hbWVcIiDsu6zrn7zsnYQgXCLtmY3quLjrj5lcIuycvOuhnCDrs4Dqsr3tlZjroKTrqbQ6XG4vLyAgICAgICAgIHVwZGF0ZUZpeHR1cmVzKHsgdXBkYXRlczogW3sgZml4dHVyZUlkOiBcIlVzZXIjMVwiLCB1cGRhdGVzOiB7IG5hbWU6IFwi7ZmN6ri464+ZXCIgfSB9XSB9KVxuXG4vLyAgICAgICAgIOuzgOqyveuQoCDsu6zrn7zsnZggdHlwZeydtCByZWxhdGlvbuyduCDqsr3smrAsIOq0gOugqCDsl5Tti7Dti7Dsl5Drj4Qg67CY7JiB65CY7Ja07JW8IO2VoCDsu6zrn7zsnbQg7J6I64qU7KeAIO2ZleyduO2VmOyEuOyalC5cblxuLy8gICAgICAgICAjIyDtlL3siqTss5Ag7IOd7ISxXG4vLyAgICAgICAgIOyCrOyaqeyekOqwgCDsg4jroZzsmrQg7ZS97Iqk7LOQIOyDneyEseydhCDsmpTssq3tlZjrqbQgY3JlYXRlRml4dHVyZXMg64+E6rWs66W8IOyCrOyaqe2VmOyEuOyalC5cbi8vICAgICAgICAgLSBlbnRpdHlJZDog7IOd7ISx7ZWgIOyXlO2LsO2LsCBJRFxuLy8gICAgICAgICAtIGlkOiDsg4gg66CI7L2U65Oc7J2YIElEICjquLDsobQg7ZS97Iqk7LOQ7JmAIOykkeuzteuQmOyngCDslYrripQg7J2M7IiYIOyCrOyaqSDqtozsnqUsIOyYiDogLTEsIC0yKVxuLy8gICAgICAgICAtIGNvbHVtbnM6IOy7rOufvOuqheydhCDtgqTroZwsIOqwkuydhCDqsJLsnLzroZwg7ZWY64qUIOqwneyytCAo7JeU7Yuw7YuwIOq1rOyhsCDssLjqs6ApXG5cbi8vICAgICAgICAg7JiI7IucOiDsg4jroZzsmrQgVXNlciDtlL3siqTss5Drpbwg7IOd7ISx7ZWY66Ck66m0OlxuLy8gICAgICAgICBjcmVhdGVGaXh0dXJlcyh7IGZpeHR1cmVzOiBbeyBlbnRpdHlJZDogXCJVc2VyXCIsIGlkOiAtMSwgY29sdW1uczogeyBuYW1lOiBcIu2Zjeq4uOuPmVwiLCBlbWFpbDogXCJob25nQGV4YW1wbGUuY29tXCIgfSB9XSB9KVxuLy8gICAgICAgYDtcblxuLy8gICAgIHJldHVybiBzdHJlYW1UZXh0KHtcbi8vICAgICAgIG1vZGVsOiB0aGlzLm1vZGVsLFxuLy8gICAgICAgc3lzdGVtOiBzeXN0ZW1NZXNzYWdlLFxuLy8gICAgICAgbWVzc2FnZXMsXG4vLyAgICAgICB0b29sczoge1xuLy8gICAgICAgICB1cGRhdGVGaXh0dXJlczogdG9vbCh7XG4vLyAgICAgICAgICAgZGVzY3JpcHRpb246XG4vLyAgICAgICAgICAgICBcIu2UveyKpOyzkCDroIjsvZTrk5zsnZgg6rCS7J2EIOyImOygle2VqeuLiOuLpC4g7IKs7Jqp7J6Q6rCAIO2KueyglSDsu6zrn7zsnbTrgpgg6rCS7J2EIOuzgOqyve2VtOuLrOudvOqzoCDsmpTssq3tlaAg65WMIOyCrOyaqe2VmOyEuOyalC5cIixcbi8vICAgICAgICAgICBpbnB1dFNjaGVtYTogei5vYmplY3Qoe1xuLy8gICAgICAgICAgICAgdXBkYXRlczogei5hcnJheShcbi8vICAgICAgICAgICAgICAgei5vYmplY3Qoe1xuLy8gICAgICAgICAgICAgICAgIGZpeHR1cmVJZDogei5zdHJpbmcoKS5kZXNjcmliZShcIuyImOygle2VoCDtlL3siqTss5AgSUQgKO2YleyLnTogRW50aXR5SWQjaWQpXCIpLFxuLy8gICAgICAgICAgICAgICAgIHVwZGF0ZXM6IHpcbi8vICAgICAgICAgICAgICAgICAgIC5yZWNvcmQoei5zdHJpbmcoKSwgei51bmtub3duKCkpXG4vLyAgICAgICAgICAgICAgICAgICAuZGVzY3JpYmUoXCLsu6zrn7zrqoXsnYQg7YKk66GcLCDsg4gg6rCS7J2EIOqwkuycvOuhnCDtlZjripQg6rCd7LK0XCIpLFxuLy8gICAgICAgICAgICAgICB9KSxcbi8vICAgICAgICAgICAgICksXG4vLyAgICAgICAgICAgfSksXG4vLyAgICAgICAgICAgZXhlY3V0ZTogYXN5bmMgKHtcbi8vICAgICAgICAgICAgIHVwZGF0ZXMsXG4vLyAgICAgICAgICAgfSk6IFByb21pc2U8eyBzdWNjZXNzOiBib29sZWFuOyB1cGRhdGVkUmVjb3JkczogRml4dHVyZVJlY29yZFtdIH0+ID0+IHtcbi8vICAgICAgICAgICAgIC8vIGZpeHR1cmVSZWNvcmRz66W8IOuzteyCrO2VmOqzoCDsl4XrjbDsnbTtirgg7KCB7JqpXG4vLyAgICAgICAgICAgICBjb25zdCB1cGRhdGVkUmVjb3JkczogRml4dHVyZVJlY29yZFtdID0gZml4dHVyZVJlY29yZHMubWFwKChyZWNvcmQpID0+IHtcbi8vICAgICAgICAgICAgICAgY29uc3QgdXBkYXRlID0gdXBkYXRlcy5maW5kKCh1KSA9PiB1LmZpeHR1cmVJZCA9PT0gcmVjb3JkLmZpeHR1cmVJZCk7XG4vLyAgICAgICAgICAgICAgIGlmICh1cGRhdGUpIHtcbi8vICAgICAgICAgICAgICAgICAvLyBjb2x1bW5z7J2YIHZhbHVl66W8IOyXheuNsOydtO2KuFxuLy8gICAgICAgICAgICAgICAgIGZvciAoY29uc3QgW2NvbHVtbk5hbWUsIG5ld1ZhbHVlXSBvZiBPYmplY3QuZW50cmllcyh1cGRhdGUudXBkYXRlcykpIHtcbi8vICAgICAgICAgICAgICAgICAgIHJlY29yZC5jb2x1bW5zW2NvbHVtbk5hbWVdLnZhbHVlID1cbi8vICAgICAgICAgICAgICAgICAgICAgbmV3VmFsdWUgYXMgRml4dHVyZVJlY29yZFtcImNvbHVtbnNcIl1bc3RyaW5nXVtcInZhbHVlXCJdO1xuLy8gICAgICAgICAgICAgICAgIH1cbi8vICAgICAgICAgICAgICAgICByZXR1cm4gcmVjb3JkO1xuLy8gICAgICAgICAgICAgICB9XG5cbi8vICAgICAgICAgICAgICAgcmV0dXJuIHJlY29yZDtcbi8vICAgICAgICAgICAgIH0pO1xuXG4vLyAgICAgICAgICAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCB1cGRhdGVkUmVjb3JkcyB9O1xuLy8gICAgICAgICAgIH0sXG4vLyAgICAgICAgIH0pLFxuLy8gICAgICAgICBjcmVhdGVGaXh0dXJlczogdG9vbCh7XG4vLyAgICAgICAgICAgZGVzY3JpcHRpb246XG4vLyAgICAgICAgICAgICBcIuyDiOuhnOyatCDtlL3siqTss5Ag66CI7L2U65Oc66W8IOyDneyEse2VqeuLiOuLpC4g7IKs7Jqp7J6Q6rCAIOyDiOuhnOyatCDrjbDsnbTthLDrpbwg7LaU6rCA7ZW064us65286rOgIOyalOyyre2VoCDrlYwg7IKs7Jqp7ZWY7IS47JqULlwiLFxuLy8gICAgICAgICAgIGlucHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4vLyAgICAgICAgICAgICBmaXh0dXJlczogei5hcnJheShcbi8vICAgICAgICAgICAgICAgei5vYmplY3Qoe1xuLy8gICAgICAgICAgICAgICAgIGVudGl0eUlkOiB6LnN0cmluZygpLmRlc2NyaWJlKFwi7IOd7ISx7ZWgIOyXlO2LsO2LsCBJRFwiKSxcbi8vICAgICAgICAgICAgICAgICBpZDogei5udW1iZXIoKS5kZXNjcmliZShcIuyDiCDroIjsvZTrk5zsnZggSUQgKOydjOyImCDqtozsnqUsIOyYiDogLTEsIC0yKVwiKSxcbi8vICAgICAgICAgICAgICAgICBjb2x1bW5zOiB6XG4vLyAgICAgICAgICAgICAgICAgICAucmVjb3JkKHouc3RyaW5nKCksIHoudW5rbm93bigpKVxuLy8gICAgICAgICAgICAgICAgICAgLmRlc2NyaWJlKFwi7Lus65+866qF7J2EIO2CpOuhnCwg6rCS7J2EIOqwkuycvOuhnCDtlZjripQg6rCd7LK0XCIpLFxuLy8gICAgICAgICAgICAgICB9KSxcbi8vICAgICAgICAgICAgICksXG4vLyAgICAgICAgICAgfSksXG4vLyAgICAgICAgICAgZXhlY3V0ZTogYXN5bmMgKHtcbi8vICAgICAgICAgICAgIGZpeHR1cmVzLFxuLy8gICAgICAgICAgIH0pOiBQcm9taXNlPHsgc3VjY2VzczogYm9vbGVhbjsgdXBkYXRlZFJlY29yZHM6IEZpeHR1cmVSZWNvcmRbXSB9PiA9PiB7XG4vLyAgICAgICAgICAgICBjb25zdCBuZXdSZWNvcmRzOiBGaXh0dXJlUmVjb3JkW10gPSBmaXh0dXJlcy5tYXAoKGZpeHR1cmUpID0+IHtcbi8vICAgICAgICAgICAgICAgY29uc3QgZW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQoZml4dHVyZS5lbnRpdHlJZCk7XG5cbi8vICAgICAgICAgICAgICAgLy8g7JeU7Yuw7YuwIHByb3Bz66W8IOq4sOuwmOycvOuhnCBjb2x1bW5zIOq1rOyEsVxuLy8gICAgICAgICAgICAgICBjb25zdCBjb2x1bW5zOiBGaXh0dXJlUmVjb3JkW1wiY29sdW1uc1wiXSA9IHt9O1xuLy8gICAgICAgICAgICAgICBmb3IgKGNvbnN0IHByb3Agb2YgZW50aXR5LnByb3BzKSB7XG4vLyAgICAgICAgICAgICAgICAgaWYgKHByb3AudHlwZSA9PT0gXCJ2aXJ0dWFsXCIpIGNvbnRpbnVlO1xuXG4vLyAgICAgICAgICAgICAgICAgbGV0IHZhbHVlID0gZml4dHVyZS5jb2x1bW5zW3Byb3AubmFtZV0gPz8gbnVsbDtcblxuLy8gICAgICAgICAgICAgICAgIGlmIChwcm9wLm5hbWUgPT09IFwiY3JlYXRlZF9hdFwiKSB7XG4vLyAgICAgICAgICAgICAgICAgICAvLyDtmITsnqwg7Iuc6rCE7Jy866GcIOyEpOyglVxuLy8gICAgICAgICAgICAgICAgICAgdmFsdWUgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG4vLyAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChcbi8vICAgICAgICAgICAgICAgICAgIHByb3AudHlwZSA9PT0gXCJyZWxhdGlvblwiICYmXG4vLyAgICAgICAgICAgICAgICAgICAocHJvcC5yZWxhdGlvblR5cGUgPT09IFwiSGFzTWFueVwiIHx8IHByb3AucmVsYXRpb25UeXBlID09PSBcIk1hbnlUb01hbnlcIilcbi8vICAgICAgICAgICAgICAgICApIHtcbi8vICAgICAgICAgICAgICAgICAgIC8vIOuwsOyXtOuhnCDrs4DtmZhcbi8vICAgICAgICAgICAgICAgICAgIHZhbHVlID0gQXJyYXkuaXNBcnJheSh2YWx1ZSkgPyB2YWx1ZSA6IFt2YWx1ZV0uZmlsdGVyKG5vbk51bGxhYmxlKTtcbi8vICAgICAgICAgICAgICAgICB9XG5cbi8vICAgICAgICAgICAgICAgICBjb2x1bW5zW3Byb3AubmFtZV0gPSB7XG4vLyAgICAgICAgICAgICAgICAgICBwcm9wLFxuLy8gICAgICAgICAgICAgICAgICAgdmFsdWU6IHZhbHVlIGFzIEZpeHR1cmVSZWNvcmRbXCJjb2x1bW5zXCJdW3N0cmluZ11bXCJ2YWx1ZVwiXSxcbi8vICAgICAgICAgICAgICAgICB9O1xuLy8gICAgICAgICAgICAgICB9XG5cbi8vICAgICAgICAgICAgICAgcmV0dXJuIHtcbi8vICAgICAgICAgICAgICAgICBmaXh0dXJlSWQ6IGAke2ZpeHR1cmUuZW50aXR5SWR9IyR7Zml4dHVyZS5pZH1gLFxuLy8gICAgICAgICAgICAgICAgIGVudGl0eUlkOiBmaXh0dXJlLmVudGl0eUlkLFxuLy8gICAgICAgICAgICAgICAgIGlkOiBmaXh0dXJlLmlkLFxuLy8gICAgICAgICAgICAgICAgIGNvbHVtbnMsXG4vLyAgICAgICAgICAgICAgICAgZmV0Y2hlZFJlY29yZHM6IFtdLFxuLy8gICAgICAgICAgICAgICAgIGJlbG9uZ3NSZWNvcmRzOiBbXSxcbi8vICAgICAgICAgICAgICAgICBvdmVycmlkZTogZmFsc2UsXG4vLyAgICAgICAgICAgICAgIH07XG4vLyAgICAgICAgICAgICB9KTtcblxuLy8gICAgICAgICAgICAgLy8g7IOIIOugiOy9lOuTnOuTpOydmCByZWxhdGlvbiDsu6zrn7zsnYQg7ZmV7J247ZWY7JesIOq4sOyhtCDroIjsvZTrk5zrk6TsnZgg7Jet67Cp7ZalIHJlbGF0aW9uIOyXheuNsOydtO2KuFxuLy8gICAgICAgICAgICAgZm9yIChjb25zdCBuZXdSZWNvcmQgb2YgbmV3UmVjb3Jkcykge1xuLy8gICAgICAgICAgICAgICBmb3IgKGNvbnN0IFtfY29sTmFtZSwgY29sXSBvZiBPYmplY3QuZW50cmllcyhuZXdSZWNvcmQuY29sdW1ucykpIHtcbi8vICAgICAgICAgICAgICAgICBpZiAoY29sLnByb3AudHlwZSAhPT0gXCJyZWxhdGlvblwiIHx8IGNvbC52YWx1ZSA9PT0gbnVsbCkgY29udGludWU7XG5cbi8vICAgICAgICAgICAgICAgICBjb25zdCByZWxhdGVkRW50aXR5SWQgPSBjb2wucHJvcC53aXRoO1xuLy8gICAgICAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRJZHMgPSBBcnJheS5pc0FycmF5KGNvbC52YWx1ZSkgPyBjb2wudmFsdWUgOiBbY29sLnZhbHVlXTtcblxuLy8gICAgICAgICAgICAgICAgIGZvciAoY29uc3QgcmVsYXRlZElkIG9mIHJlbGF0ZWRJZHMpIHtcbi8vICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRGaXh0dXJlSWQgPSBgJHtyZWxhdGVkRW50aXR5SWR9IyR7cmVsYXRlZElkfWA7XG4vLyAgICAgICAgICAgICAgICAgICBjb25zdCByZWxhdGVkUmVjb3JkID0gbmV3UmVjb3Jkcy5maW5kKChyKSA9PiByLmZpeHR1cmVJZCA9PT0gcmVsYXRlZEZpeHR1cmVJZCk7XG5cbi8vICAgICAgICAgICAgICAgICAgIGlmIChyZWxhdGVkUmVjb3JkKSB7XG4vLyAgICAgICAgICAgICAgICAgICAgIC8vIOyXreuwqe2WpSByZWxhdGlvbiDssL7quLBcbi8vICAgICAgICAgICAgICAgICAgICAgY29uc3QgcmV2ZXJzZUNvbCA9IE9iamVjdC5lbnRyaWVzKHJlbGF0ZWRSZWNvcmQuY29sdW1ucykuZmluZChcbi8vICAgICAgICAgICAgICAgICAgICAgICAoWywgY10pID0+IGMucHJvcC50eXBlID09PSBcInJlbGF0aW9uXCIgJiYgYy5wcm9wLndpdGggPT09IG5ld1JlY29yZC5lbnRpdHlJZCxcbi8vICAgICAgICAgICAgICAgICAgICAgKTtcblxuLy8gICAgICAgICAgICAgICAgICAgICBpZiAocmV2ZXJzZUNvbCkge1xuLy8gICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IFtyZXZlcnNlQ29sTmFtZSwgcmV2ZXJzZUNvbFZhbHVlXSA9IHJldmVyc2VDb2w7XG4vLyAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY3VycmVudFZhbHVlID0gcmV2ZXJzZUNvbFZhbHVlLnZhbHVlO1xuXG4vLyAgICAgICAgICAgICAgICAgICAgICAgLy8g7Jet67Cp7Zal7J20IOuwsOyXtOyduCDqsr3smrAgKEhhc01hbnksIE1hbnlUb01hbnkpXG4vLyAgICAgICAgICAgICAgICAgICAgICAgaWYgKFxuLy8gICAgICAgICAgICAgICAgICAgICAgICAgcmV2ZXJzZUNvbFZhbHVlLnByb3AudHlwZSA9PT0gXCJyZWxhdGlvblwiICYmXG4vLyAgICAgICAgICAgICAgICAgICAgICAgICAocmV2ZXJzZUNvbFZhbHVlLnByb3AucmVsYXRpb25UeXBlID09PSBcIkhhc01hbnlcIiB8fFxuLy8gICAgICAgICAgICAgICAgICAgICAgICAgICByZXZlcnNlQ29sVmFsdWUucHJvcC5yZWxhdGlvblR5cGUgPT09IFwiTWFueVRvTWFueVwiKVxuLy8gICAgICAgICAgICAgICAgICAgICAgICkge1xuLy8gICAgICAgICAgICAgICAgICAgICAgICAgYXNzZXJ0KEFycmF5LmlzQXJyYXkoY3VycmVudFZhbHVlKSwgXCJjdXJyZW50VmFsdWUgbXVzdCBiZSBhbiBhcnJheVwiKTtcbi8vICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghY3VycmVudFZhbHVlLmluY2x1ZGVzKG5ld1JlY29yZC5pZCkpIHtcbi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVsYXRlZFJlY29yZC5jb2x1bW5zW3JldmVyc2VDb2xOYW1lXSA9IHtcbi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5yZXZlcnNlQ29sVmFsdWUsXG4vLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IFsuLi5jdXJyZW50VmFsdWUsIG5ld1JlY29yZC5pZF0sXG4vLyAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XG4vLyAgICAgICAgICAgICAgICAgICAgICAgICB9XG4vLyAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbi8vICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOyXreuwqe2WpeydtCDri6jsnbwg6rCS7J24IOqyveyasCAoQmVsb25nc1RvT25lLCBPbmVUb09uZSlcbi8vICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGF0ZWRSZWNvcmQuY29sdW1uc1tyZXZlcnNlQ29sTmFtZV0gPSB7XG4vLyAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLnJldmVyc2VDb2xWYWx1ZSxcbi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IG5ld1JlY29yZC5pZCxcbi8vICAgICAgICAgICAgICAgICAgICAgICAgIH07XG4vLyAgICAgICAgICAgICAgICAgICAgICAgfVxuLy8gICAgICAgICAgICAgICAgICAgICB9XG4vLyAgICAgICAgICAgICAgICAgICB9XG4vLyAgICAgICAgICAgICAgICAgfVxuLy8gICAgICAgICAgICAgICB9XG4vLyAgICAgICAgICAgICB9XG5cbi8vICAgICAgICAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIHVwZGF0ZWRSZWNvcmRzOiBuZXdSZWNvcmRzIH07XG4vLyAgICAgICAgICAgfSxcbi8vICAgICAgICAgfSksXG4vLyAgICAgICB9LFxuLy8gICAgIH0pO1xuLy8gICB9XG5cbi8vICAgaGFuZGxlRW50aXR5KG1lc3NhZ2VzOiBNb2RlbE1lc3NhZ2VbXSkge1xuLy8gICAgIC8vIGVudGl0eS5pbnN0cnVjdGlvbnMubWQg7YyM7J28IOydveq4sFxuLy8gICAgIGNvbnN0IGluc3RydWN0aW9uc1BhdGggPSBwYXRoLmpvaW4oaW1wb3J0Lm1ldGEuZGlybmFtZSwgXCIuLlwiLCBcImVudGl0eS5pbnN0cnVjdGlvbnMubWRcIik7XG4vLyAgICAgY29uc3QgaW5zdHJ1Y3Rpb25zID0gZnMucmVhZEZpbGVTeW5jKGluc3RydWN0aW9uc1BhdGgsIFwidXRmLThcIik7XG5cbi8vICAgICAvLyDtmITsnqwg65Ox66Gd65CcIOyXlO2LsO2LsCDsoJXrs7Qg7IiY7KeRXG4vLyAgICAgY29uc3QgZW50aXR5SWRzID0gRW50aXR5TWFuYWdlci5nZXRBbGxJZHMoKTtcbi8vICAgICBjb25zdCBleGlzdGluZ0VudGl0aWVzID0gZW50aXR5SWRzLm1hcCgoZW50aXR5SWQpID0+IHtcbi8vICAgICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKTtcbi8vICAgICAgIHJldHVybiB7XG4vLyAgICAgICAgIGlkOiBlbnRpdHkuaWQsXG4vLyAgICAgICAgIHRpdGxlOiBlbnRpdHkudGl0bGUsXG4vLyAgICAgICAgIHRhYmxlOiBlbnRpdHkudGFibGUsXG4vLyAgICAgICAgIHByb3BzOiBlbnRpdHkucHJvcHMubWFwKChwKSA9PiAoe1xuLy8gICAgICAgICAgIG5hbWU6IHAubmFtZSxcbi8vICAgICAgICAgICB0eXBlOiBwLnR5cGUsXG4vLyAgICAgICAgICAgZGVzYzogcC5kZXNjLFxuLy8gICAgICAgICB9KSksXG4vLyAgICAgICB9O1xuLy8gICAgIH0pO1xuXG4vLyAgICAgY29uc3Qgc3lzdGVtTWVzc2FnZSA9IGBcbi8vIOuLueyLoOydgCBTb25hbXUg7ZSE66CI7J6E7JuM7YGs7JeQ7IScIEVudGl0eeyZgCBFbnVt7J2EIOyDneyEse2VmOuKlCDrj4TsmrDrr7jsnoXri4jri6QuXG5cbi8vICR7aW5zdHJ1Y3Rpb25zfVxuXG4vLyAjIyDtmITsnqwg65Ox66Gd65CcIEVudGl0eSDrqqnroZ1cbi8vIOuLpOuluCDsl5Tti7Dti7DsmYAg6rSA6rOEKHJlbGF0aW9uKeulvCDrp7rqsbDrgpggc3Vic2V07JeQ7IScIOywuOyhsO2VoCDrlYwg67CY65Oc7IucIOyVhOuemCDsoJXrs7Trpbwg7ZmV7J247ZWY7IS47JqULlxuXG4vLyAke0pTT04uc3RyaW5naWZ5KGV4aXN0aW5nRW50aXRpZXMsIG51bGwsIDIpfVxuXG4vLyAjIyBUb29sIOyCrOyaqSDqsIDsnbTrk5xcblxuLy8gIyMjIEVudGl0eSDsg53shLEgKGNyZWF0ZUVudGl0eSlcbi8vIOyCrOyaqeyekOqwgCDsg4jroZzsmrQgRW50aXR5IOyDneyEseydhCDsmpTssq3tlZjrqbQgY3JlYXRlRW50aXR5IOuPhOq1rOulvCDsgqzsmqntlZjshLjsmpQuXG4vLyAtIGVudGl0eUlkOiBQYXNjYWxDYXNl66GcIOuQnCBFbnRpdHkgSUQgKOyYiDogXCJVc2VyXCIsIFwiUHJvZHVjdENhdGVnb3J5XCIpXG4vLyAtIHRpdGxlOiDtlZzquIAg7KCc66qpICjsmIg6IFwi7IKs7Jqp7J6QXCIsIFwi7IOB7ZKIIOy5tO2FjOqzoOumrFwiKVxuLy8gLSB0YWJsZTogc25ha2VfY2FzZeuhnCDrkJwg7YWM7J2067iU66qFICjsmIg6IFwidXNlcnNcIiwgXCJwcm9kdWN0X2NhdGVnb3JpZXNcIilcbi8vIC0gcGFyZW50SWQ6IOu2gOuqqCBFbnRpdHkgSUQgKOyEoO2DneyCrO2VrSlcbi8vIC0gcHJvcHM6IEVudGl0eeydmCDtlITroZztjbzti7Ag67Cw7Je0ICjsnIQg66y47ISc7J2YIFByb3BlcnR5IFR5cGVzIOywuOqzoClcbi8vIC0gaW5kZXhlczog7J24642x7IqkIOuwsOyXtFxuLy8gLSBzdWJzZXRzOiDshJzruIzshYsg7KCV7J2YICjquLDrs7jqsJI6IHsgQTogW1wiaWRcIl0gfSlcbi8vIC0gZW51bXM6IEVudW0g7KCV7J2YXG5cbi8vICMjIyBFbnRpdHkg7IiY7KCVICh1cGRhdGVFbnRpdHkpXG4vLyDquLDsobQgRW50aXR566W8IOyImOygle2VoCDrlYwgdXBkYXRlRW50aXR5IOuPhOq1rOulvCDsgqzsmqntlZjshLjsmpQuIEVudW0g7LaU6rCALCBwcm9wcyDstpTqsIAv7IiY7KCVLCBpbmRleGVzIOyImOyglSDrk7Eg66qo65OgIOyImOyglSDsnpHsl4Xsl5Ag7IKs7Jqp7ZWp64uI64ukLlxuLy8gLSBlbnRpdHlJZDog7IiY7KCV7ZWgIEVudGl0eSBJRFxuLy8gLSB1cGRhdGVzOiDsiJjsoJXtlaAg7ZWE65Oc65OkICjrtoDrtoQg7JeF642w7J207Yq4KVxuLy8gICAtIHRpdGxlOiDsl5Tti7Dti7Ag7ZWc6riAIOygnOuqqVxuLy8gICAtIHRhYmxlOiDthYzsnbTruJTrqoVcbi8vICAgLSBwcm9wczog7LaU6rCA7ZWgIO2UhOuhnO2NvO2LsCDrsLDsl7QgKOq4sOyhtCBwcm9wc+yXkCDstpTqsIAsIOqwmeydgCDsnbTrpoTsnbTrqbQg6rWQ7LK0KVxuLy8gICAtIGluZGV4ZXM6IOy2lOqwgO2VoCDsnbjrjbHsiqQg67Cw7Je0ICjquLDsobQgaW5kZXhlc+yXkCDstpTqsIApXG4vLyAgIC0gc3Vic2V0czog7ISc67iM7IWLIOygleydmCAo6riw7KG0IHN1YnNldHPsl5Ag67OR7ZWpKVxuLy8gICAtIGVudW1MYWJlbHM6IEVudW0g7KCV7J2YICjquLDsobQgZW51bUxhYmVsc+yXkCDrs5HtlakpXG4vLyAtIG1vZGU6IFwibWVyZ2VcIijquLDrs7jqsJIpIOuYkOuKlCBcInJlcGxhY2VcIlxuLy8gICAtIG1lcmdlOiDquLDsobQg6rCS7JeQIOuzke2VqVxuLy8gICAtIHJlcGxhY2U6IO2VtOuLuSDtlYTrk5wg7KCE7LK0IOq1kOyytFxuXG4vLyDsmIjsi5w6IEVtcGxveWVl7JeQIOyDiCBFbnVtIOy2lOqwgFxuLy8gdXBkYXRlRW50aXR5KHsgZW50aXR5SWQ6IFwiRW1wbG95ZWVcIiwgdXBkYXRlczogeyBlbnVtTGFiZWxzOiB7IFwiRW1wbG95ZWVSb2xlXCI6IHsgXCJhZG1pblwiOiBcIuq0gOumrOyekFwiLCBcInVzZXJcIjogXCLsnbzrsJhcIiB9IH0gfSB9KVxuXG4vLyDsmIjsi5w6IFByb2plY3Tsl5Ag7IOIIO2UhOuhnO2NvO2LsCDstpTqsIBcbi8vIHVwZGF0ZUVudGl0eSh7IGVudGl0eUlkOiBcIlByb2plY3RcIiwgdXBkYXRlczogeyBwcm9wczogW3sgbmFtZTogXCJwcmlvcml0eVwiLCB0eXBlOiBcImludGVnZXJcIiwgZGVzYzogXCLsmrDshKDsiJzsnIRcIiB9XSB9IH0pXG5cbi8vICMjIO2VhOyImCDsgqztla1cbi8vIC0gRW50aXR57J2YIHByb3Bz7JeQ64qUIOy1nOyGjO2VnCBpZChpbnRlZ2VyLCB1bnNpZ25lZCksIGNyZWF0ZWRfYXQodGltZXN0YW1wKeqwgCDtj6ztlajrkJjslrTslbwg7ZWp64uI64ukLlxuLy8gLSByZWxhdGlvbiDtlYTrk5zripQgb25VcGRhdGUsIG9uRGVsZXRl6rCAIO2VhOyImOyeheuLiOuLpC4gKOyYiOyZuDogT25lVG9PbmXsl5DshJwgaGFzSm9pbkNvbHVtbuydtCBmYWxzZeyduCDqsr3smrApXG4vLyAtIEVudW0gSUTripQg67O07Ya1IEVudGl0eUlkICsg7IaN7ISx66qFIO2Yle2DnOyeheuLiOuLpCAo7JiIOiBVc2VyU3RhdHVzLCBQcm9kdWN0VHlwZSlcbi8vIC0gc3Vic2V07JeQ7IScIOuLpOuluCDsl5Tti7Dti7DsnZgg7ZSE66Gc7Y287Yuw66W8IOywuOyhsO2VoCDrlYzripQg67CY65Oc7IucIO2VtOuLuSDsl5Tti7Dti7DsnZgg7Iuk7KCcIO2UhOuhnO2NvO2LsOuqheydhCDsgqzsmqntlZjshLjsmpQuXG5cbi8vICMjIOqygOymnSDsmKTrpZgg7LKY66asXG4vLyDrj4Tqtawg7Zi47LacIOqysOqzvOuhnCDqsoDspp0g7Jik66WYKHZhbGlkYXRpb25FcnJvcnMp6rCAIOuwmO2ZmOuQmOuptDpcbi8vIDEuIOyYpOulmCDrqZTsi5zsp4Drpbwg67aE7ISd7ZWY7JesIOusuOygnOygkOydhCDtjIzslYXtlZjshLjsmpQuXG4vLyAyLiDsmKTrpZjrpbwg7IiY7KCV7ZWcIOuNsOydtO2EsOuhnCBjcmVhdGVFbnRpdHnrpbwg64uk7IucIO2YuOy2nO2VmOyEuOyalC5cbi8vIDMuIOyCrOyaqeyekOyXkOqyjCDsmKTrpZjrpbwg6re464yA66GcIOyghOuLrO2VmOyngCDrp5Dqs6AsIOyImOyglSDtm4Qg7J6s7Iuc64+E7ZWY7IS47JqULlxuXG4vLyAjIyMg7J2867CY7KCB7J24IOqygOymnSDsmKTrpZjsmYAg7IiY7KCVIOuwqeuylVxuLy8gfCDsmKTrpZgg66mU7Iuc7KeAIHwg7IiY7KCVIOuwqeuylSB8XG4vLyB8LS0tLS0tLS0tLS0tfC0tLS0tLS0tLS18XG4vLyB8IFwiaWQg7ZSE66Gc7Y287Yuw6rCAIO2VhOyImFwiIHwgcHJvcHPsl5AgeyBuYW1lOiBcImlkXCIsIHR5cGU6IFwiaW50ZWdlclwiLCB1bnNpZ25lZDogdHJ1ZSB9IOy2lOqwgCB8XG4vLyB8IFwiY3JlYXRlZF9hdCDtlITroZztjbzti7DqsIAg7ZWE7IiYXCIgfCBwcm9wc+yXkCB7IG5hbWU6IFwiY3JlYXRlZF9hdFwiLCB0eXBlOiBcInRpbWVzdGFtcFwiLCBkYkRlZmF1bHQ6IFwiQ1VSUkVOVF9USU1FU1RBTVBcIiB9IOy2lOqwgCB8XG4vLyB8IFwiWHh4T3JkZXJCeSBlbnVt7J20IO2VhOyImFwiIHwgZW51bXPsl5AgeyBcIlh4eE9yZGVyQnlcIjogeyBcImlkLWRlc2NcIjogXCJJROy1nOyLoOyInFwiIH0gfSDstpTqsIAgfFxuLy8gfCBcIlh4eFNlYXJjaEZpZWxkIGVudW3snbQg7ZWE7IiYXCIgfCBlbnVtc+yXkCB7IFwiWHh4U2VhcmNoRmllbGRcIjogeyBcImlkXCI6IFwiSURcIiB9IH0g7LaU6rCAIHxcbi8vIHwgXCJzdHJpbmcg7YOA7J6F7J2AIGxlbmd0aOqwgCDtlYTsiJhcIiB8IO2VtOuLuSBwcm9w7JeQIGxlbmd0aCDstpTqsIAgKOyYiDogMjU1KSB8XG4vLyB8IFwidGV4dCDtg4DsnoXsnYAgdGV4dFR5cGXsnbQg7ZWE7IiYXCIgfCDtlbTri7kgcHJvcOyXkCB0ZXh0VHlwZSDstpTqsIAgKFwidGV4dFwiLCBcIm1lZGl1bXRleHRcIiwgXCJsb25ndGV4dFwiKSB8XG4vLyB8IFwib25VcGRhdGXqsIAg7ZWE7IiYXCIgfCDtlbTri7kgcmVsYXRpb24gcHJvcOyXkCBvblVwZGF0ZSwgb25EZWxldGUg7LaU6rCAIChcIkNBU0NBREVcIikgfFxuLy8gICAgICAgYDtcblxuLy8gICAgIHJldHVybiBzdHJlYW1UZXh0KHtcbi8vICAgICAgIG1vZGVsOiB0aGlzLm1vZGVsLFxuLy8gICAgICAgc3lzdGVtOiBzeXN0ZW1NZXNzYWdlLFxuLy8gICAgICAgbWVzc2FnZXMsXG4vLyAgICAgICBzdG9wV2hlbjogc3RlcENvdW50SXMoMiksXG4vLyAgICAgICB0b29sczoge1xuLy8gICAgICAgICBjcmVhdGVFbnRpdHk6IHRvb2woe1xuLy8gICAgICAgICAgIGRlc2NyaXB0aW9uOlxuLy8gICAgICAgICAgICAgXCLsg4jroZzsmrQgRW50aXR566W8IOyDneyEse2VqeuLiOuLpC4g7IKs7Jqp7J6Q6rCAIOyDiOuhnOyatCDsl5Tti7Dti7Drgpgg7YWM7J2067iUIOyDneyEseydhCDsmpTssq3tlaAg65WMIOyCrOyaqe2VmOyEuOyalC5cIixcbi8vICAgICAgICAgICBpbnB1dFNjaGVtYTogVGVtcGxhdGVPcHRpb25zLnNoYXBlLmVudGl0eSxcbi8vICAgICAgICAgICBleGVjdXRlOiBhc3luYyAoXG4vLyAgICAgICAgICAgICBlbnRpdHksXG4vLyAgICAgICAgICAgKTogUHJvbWlzZTx7XG4vLyAgICAgICAgICAgICBzdWNjZXNzOiBib29sZWFuO1xuLy8gICAgICAgICAgICAgZW50aXR5SWQ6IHN0cmluZztcbi8vICAgICAgICAgICAgIGVycm9yPzogc3RyaW5nO1xuLy8gICAgICAgICAgICAgdmFsaWRhdGlvbkVycm9ycz86IFZhbGlkYXRpb25FcnJvcltdO1xuLy8gICAgICAgICAgIH0+ID0+IHtcbi8vICAgICAgICAgICAgIHRyeSB7XG4vLyAgICAgICAgICAgICAgIC8vIOyeheugpSDqsoDspp1cbi8vICAgICAgICAgICAgICAgY29uc3QgdmFsaWRhdGlvbkVycm9ycyA9IHZhbGlkYXRlRW50aXR5SnNvbihlbnRpdHkpO1xuXG4vLyAgICAgICAgICAgICAgIGlmICh2YWxpZGF0aW9uRXJyb3JzLmxlbmd0aCA+IDApIHtcbi8vICAgICAgICAgICAgICAgICByZXR1cm4ge1xuLy8gICAgICAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4vLyAgICAgICAgICAgICAgICAgICBlbnRpdHlJZDogZW50aXR5LmVudGl0eUlkLFxuLy8gICAgICAgICAgICAgICAgICAgZXJyb3I6IGDqsoDspp0g7Jik66WYOiAke3ZhbGlkYXRpb25FcnJvcnMubWFwKChlKSA9PiBgWyR7ZS5maWVsZH1dICR7ZS5tZXNzYWdlfWApLmpvaW4oXCIsIFwiKX1gLFxuLy8gICAgICAgICAgICAgICAgICAgdmFsaWRhdGlvbkVycm9ycyxcbi8vICAgICAgICAgICAgICAgICB9O1xuLy8gICAgICAgICAgICAgICB9XG5cbi8vICAgICAgICAgICAgICAgYXdhaXQgU29uYW11LnN5bmNlci5jcmVhdGVFbnRpdHkoe1xuLy8gICAgICAgICAgICAgICAgIHN1YnNldHM6IHsgQTogW1wiaWRcIl0gfSxcbi8vICAgICAgICAgICAgICAgICBlbnVtczoge30sXG4vLyAgICAgICAgICAgICAgICAgLi4uZW50aXR5LFxuLy8gICAgICAgICAgICAgICB9KTtcblxuLy8gICAgICAgICAgICAgICAvLyBFbnRpdHlNYW5hZ2VyIOumrOuhnOuTnFxuLy8gICAgICAgICAgICAgICBhd2FpdCBFbnRpdHlNYW5hZ2VyLnJlbG9hZCgpO1xuXG4vLyAgICAgICAgICAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIGVudGl0eUlkOiBlbnRpdHkuZW50aXR5SWQgfTtcbi8vICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbi8vICAgICAgICAgICAgICAgY29uc3QgZXJyb3IgPSBlIGluc3RhbmNlb2YgRXJyb3IgPyBlLm1lc3NhZ2UgOiBcIlVua25vd24gZXJyb3JcIjtcbi8vICAgICAgICAgICAgICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVudGl0eUlkOiBlbnRpdHkuZW50aXR5SWQsIGVycm9yIH07XG4vLyAgICAgICAgICAgICB9XG4vLyAgICAgICAgICAgfSxcbi8vICAgICAgICAgfSksXG4vLyAgICAgICAgIHVwZGF0ZUVudGl0eTogdG9vbCh7XG4vLyAgICAgICAgICAgZGVzY3JpcHRpb246XG4vLyAgICAgICAgICAgICBcIuq4sOyhtCBFbnRpdHnrpbwg7IiY7KCV7ZWp64uI64ukLiBFbnVtIOy2lOqwgCwgcHJvcHMg7LaU6rCAL+yImOyglSwgaW5kZXhlcyDsiJjsoJUsIHN1YnNldHMg7IiY7KCVIOuTsSDrqqjrk6Ag7JeU7Yuw7YuwIOyImOyglSDsnpHsl4Xsl5Ag7IKs7Jqp7ZWY7IS47JqULlwiLFxuLy8gICAgICAgICAgIGlucHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4vLyAgICAgICAgICAgICBlbnRpdHlJZDogei5zdHJpbmcoKS5kZXNjcmliZShcIuyImOygle2VoCBFbnRpdHkgSURcIiksXG4vLyAgICAgICAgICAgICB1cGRhdGVzOiBUZW1wbGF0ZU9wdGlvbnMuc2hhcGUuZW50aXR5LnBhcnRpYWwoKS5kZXNjcmliZShcIuyImOygle2VoCDtlYTrk5zrk6RcIiksXG4vLyAgICAgICAgICAgICBtb2RlOiB6XG4vLyAgICAgICAgICAgICAgIC5lbnVtKFtcIm1lcmdlXCIsIFwicmVwbGFjZVwiXSlcbi8vICAgICAgICAgICAgICAgLm9wdGlvbmFsKClcbi8vICAgICAgICAgICAgICAgLmRlc2NyaWJlKFwi7IiY7KCVIOuqqOuTnDogbWVyZ2Uo6riw67O46rCSLCDquLDsobQg6rCS7JeQIOuzke2VqSkg65iQ64qUIHJlcGxhY2Uo7KCE7LK0IOq1kOyytClcIiksXG4vLyAgICAgICAgICAgfSksXG4vLyAgICAgICAgICAgZXhlY3V0ZTogYXN5bmMgKHtcbi8vICAgICAgICAgICAgIGVudGl0eUlkLFxuLy8gICAgICAgICAgICAgdXBkYXRlcyxcbi8vICAgICAgICAgICAgIG1vZGUgPSBcIm1lcmdlXCIsXG4vLyAgICAgICAgICAgfSk6IFByb21pc2U8e1xuLy8gICAgICAgICAgICAgc3VjY2VzczogYm9vbGVhbjtcbi8vICAgICAgICAgICAgIGVudGl0eUlkOiBzdHJpbmc7XG4vLyAgICAgICAgICAgICBlcnJvcj86IHN0cmluZztcbi8vICAgICAgICAgICAgIHZhbGlkYXRpb25FcnJvcnM/OiBWYWxpZGF0aW9uRXJyb3JbXTtcbi8vICAgICAgICAgICB9PiA9PiB7XG4vLyAgICAgICAgICAgICB0cnkge1xuLy8gICAgICAgICAgICAgICBjb25zdCBlbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCk7XG5cbi8vICAgICAgICAgICAgICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXModXBkYXRlcykpIHtcbi8vICAgICAgICAgICAgICAgICBpZiAoXG4vLyAgICAgICAgICAgICAgICAgICBbXCJlbnRpdHlJZFwiLCBcInBhcmVudElkXCIsIFwidGl0bGVcIiwgXCJ0YWJsZVwiXS5pbmNsdWRlcyhrZXkpICYmXG4vLyAgICAgICAgICAgICAgICAgICB2YWx1ZSAhPT0gdW5kZWZpbmVkXG4vLyAgICAgICAgICAgICAgICAgKSB7XG4vLyAgICAgICAgICAgICAgICAgICBlbnRpdHlba2V5XSA9IHZhbHVlO1xuLy8gICAgICAgICAgICAgICAgIH1cbi8vICAgICAgICAgICAgICAgfVxuXG4vLyAgICAgICAgICAgICAgIC8vIHByb3BzOiBtZXJnZSDsi5wg7J2066aEIOq4sOykgCDrs5HtlaksIHJlcGxhY2Ug7IucIOq1kOyytFxuLy8gICAgICAgICAgICAgICBpZiAodXBkYXRlcy5wcm9wcyAhPT0gdW5kZWZpbmVkKSB7XG4vLyAgICAgICAgICAgICAgICAgaWYgKG1vZGUgPT09IFwicmVwbGFjZVwiKSB7XG4vLyAgICAgICAgICAgICAgICAgICBlbnRpdHkucHJvcHMgPSB1cGRhdGVzLnByb3BzIGFzIEVudGl0eVByb3BbXTtcbi8vICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuLy8gICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBuZXdQcm9wIG9mIHVwZGF0ZXMucHJvcHMpIHtcbi8vICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXhpc3RpbmdJbmRleCA9IGVudGl0eS5wcm9wcy5maW5kSW5kZXgoKHApID0+IHAubmFtZSA9PT0gbmV3UHJvcC5uYW1lKTtcbi8vICAgICAgICAgICAgICAgICAgICAgaWYgKGV4aXN0aW5nSW5kZXggPj0gMCkge1xuLy8gICAgICAgICAgICAgICAgICAgICAgIGVudGl0eS5wcm9wc1tleGlzdGluZ0luZGV4XSA9IG5ld1Byb3AgYXMgRW50aXR5UHJvcDtcbi8vICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbi8vICAgICAgICAgICAgICAgICAgICAgICBlbnRpdHkucHJvcHMucHVzaChuZXdQcm9wIGFzIEVudGl0eVByb3ApO1xuLy8gICAgICAgICAgICAgICAgICAgICB9XG4vLyAgICAgICAgICAgICAgICAgICB9XG4vLyAgICAgICAgICAgICAgICAgfVxuLy8gICAgICAgICAgICAgICB9XG5cbi8vICAgICAgICAgICAgICAgLy8gaW5kZXhlczogbWVyZ2Ug7IucIOy2lOqwgCwgcmVwbGFjZSDsi5wg6rWQ7LK0XG4vLyAgICAgICAgICAgICAgIGlmICh1cGRhdGVzLmluZGV4ZXMgIT09IHVuZGVmaW5lZCkge1xuLy8gICAgICAgICAgICAgICAgIGVudGl0eS5pbmRleGVzID1cbi8vICAgICAgICAgICAgICAgICAgIG1vZGUgPT09IFwicmVwbGFjZVwiID8gdXBkYXRlcy5pbmRleGVzIDogWy4uLmVudGl0eS5pbmRleGVzLCAuLi51cGRhdGVzLmluZGV4ZXNdO1xuLy8gICAgICAgICAgICAgICB9XG5cbi8vICAgICAgICAgICAgICAgLy8gc3Vic2V0cywgZW51bUxhYmVsczogYXNzaWdu7Jy866GcIOuzke2VqSDrmJDripQg6rWQ7LK0XG4vLyAgICAgICAgICAgICAgIGlmICh1cGRhdGVzLnN1YnNldHMgIT09IHVuZGVmaW5lZCkge1xuLy8gICAgICAgICAgICAgICAgIGVudGl0eS5zdWJzZXRzID1cbi8vICAgICAgICAgICAgICAgICAgIG1vZGUgPT09IFwicmVwbGFjZVwiID8gdXBkYXRlcy5zdWJzZXRzIDogeyAuLi5lbnRpdHkuc3Vic2V0cywgLi4udXBkYXRlcy5zdWJzZXRzIH07XG4vLyAgICAgICAgICAgICAgIH1cblxuLy8gICAgICAgICAgICAgICBpZiAodXBkYXRlcy5lbnVtcyAhPT0gdW5kZWZpbmVkKSB7XG4vLyAgICAgICAgICAgICAgICAgZW50aXR5LmVudW1MYWJlbHMgPVxuLy8gICAgICAgICAgICAgICAgICAgbW9kZSA9PT0gXCJyZXBsYWNlXCIgPyB1cGRhdGVzLmVudW1zIDogeyAuLi5lbnRpdHkuZW51bUxhYmVscywgLi4udXBkYXRlcy5lbnVtcyB9O1xuLy8gICAgICAgICAgICAgICB9XG5cbi8vICAgICAgICAgICAgICAgLy8g7KCA7J6lIOyghCDqsoDspp1cbi8vICAgICAgICAgICAgICAgY29uc3QgdmFsaWRhdGlvbkVycm9ycyA9IHZhbGlkYXRlRW50aXR5SnNvbih7XG4vLyAgICAgICAgICAgICAgICAgLi4uZW50aXR5LFxuLy8gICAgICAgICAgICAgICAgIGVudGl0eUlkOiBlbnRpdHkuaWQsXG4vLyAgICAgICAgICAgICAgICAgZW51bXM6IGVudGl0eS5lbnVtTGFiZWxzLFxuLy8gICAgICAgICAgICAgICB9KTtcblxuLy8gICAgICAgICAgICAgICBpZiAodmFsaWRhdGlvbkVycm9ycy5sZW5ndGggPiAwKSB7XG4vLyAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbi8vICAgICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuLy8gICAgICAgICAgICAgICAgICAgZW50aXR5SWQsXG4vLyAgICAgICAgICAgICAgICAgICBlcnJvcjogYOqygOymnSDsmKTrpZg6ICR7dmFsaWRhdGlvbkVycm9ycy5tYXAoKGUpID0+IGBbJHtlLmZpZWxkfV0gJHtlLm1lc3NhZ2V9YCkuam9pbihcIiwgXCIpfWAsXG4vLyAgICAgICAgICAgICAgICAgICB2YWxpZGF0aW9uRXJyb3JzLFxuLy8gICAgICAgICAgICAgICAgIH07XG4vLyAgICAgICAgICAgICAgIH1cblxuLy8gICAgICAgICAgICAgICBhd2FpdCBlbnRpdHkuc2F2ZSgpO1xuXG4vLyAgICAgICAgICAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIGVudGl0eUlkIH07XG4vLyAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4vLyAgICAgICAgICAgICAgIGNvbnN0IGVycm9yID0gZSBpbnN0YW5jZW9mIEVycm9yID8gZS5tZXNzYWdlIDogXCJVbmtub3duIGVycm9yXCI7XG4vLyAgICAgICAgICAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IGZhbHNlLCBlbnRpdHlJZCwgZXJyb3IgfTtcbi8vICAgICAgICAgICAgIH1cbi8vICAgICAgICAgICB9LFxuLy8gICAgICAgICB9KSxcbi8vICAgICAgIH0sXG4vLyAgICAgfSk7XG4vLyAgIH1cbi8vIH1cblxuLy8gLyoqXG4vLyAgKiBFbnRpdHkgSlNPTuydtCBlbnRpdHkuaW5zdHJ1Y3Rpb25zLm1k7J2YIOq3nOy5meydhCDrlLDrpbTripTsp4Ag6rKA7Kad7ZWp64uI64ukLlxuLy8gICovXG4vLyBmdW5jdGlvbiB2YWxpZGF0ZUVudGl0eUpzb24oaW5wdXQ6IFRlbXBsYXRlT3B0aW9uc1tcImVudGl0eVwiXSk6IFZhbGlkYXRpb25FcnJvcltdIHtcbi8vICAgY29uc3QgZXJyb3JzOiBWYWxpZGF0aW9uRXJyb3JbXSA9IFtdO1xuLy8gICBjb25zdCB7IGVudGl0eUlkLCBwcm9wcywgZW51bXMgfSA9IGlucHV0O1xuXG4vLyAgIC8vIDEuIGlkLCBjcmVhdGVkX2F0IHByb3Ag7ZWE7IiYXG4vLyAgIGNvbnN0IGhhc0lkUHJvcCA9IHByb3BzPy5zb21lKChwKSA9PiBwLm5hbWUgPT09IFwiaWRcIik7XG4vLyAgIGlmICghaGFzSWRQcm9wKSB7XG4vLyAgICAgZXJyb3JzLnB1c2goeyBmaWVsZDogXCJwcm9wc1wiLCBtZXNzYWdlOiBcImlkIO2UhOuhnO2NvO2LsOqwgCDtlYTsiJjsnoXri4jri6QuXCIgfSk7XG4vLyAgIH1cbi8vICAgY29uc3QgaGFzQ3JlYXRlZEF0UHJvcCA9IHByb3BzPy5zb21lKChwKSA9PiBwLm5hbWUgPT09IFwiY3JlYXRlZF9hdFwiKTtcbi8vICAgaWYgKCFoYXNDcmVhdGVkQXRQcm9wKSB7XG4vLyAgICAgZXJyb3JzLnB1c2goeyBmaWVsZDogXCJwcm9wc1wiLCBtZXNzYWdlOiBcImNyZWF0ZWRfYXQg7ZSE66Gc7Y287Yuw6rCAIO2VhOyImOyeheuLiOuLpC5cIiB9KTtcbi8vICAgfVxuXG4vLyAgIC8vIDIuIO2VhOyImCBlbnVtIOqygOymnTogRW50aXR5TmFtZU9yZGVyQnksIEVudGl0eU5hbWVTZWFyY2hGaWVsZFxuLy8gICBjb25zdCBvcmRlckJ5RW51bUlkID0gYCR7ZW50aXR5SWR9T3JkZXJCeWA7XG4vLyAgIGNvbnN0IHNlYXJjaEZpZWxkRW51bUlkID0gYCR7ZW50aXR5SWR9U2VhcmNoRmllbGRgO1xuXG4vLyAgIGlmICghZW51bXM/LltvcmRlckJ5RW51bUlkXSkge1xuLy8gICAgIGVycm9ycy5wdXNoKHtcbi8vICAgICAgIGZpZWxkOiBcImVudW1zXCIsXG4vLyAgICAgICBtZXNzYWdlOiBgJHtvcmRlckJ5RW51bUlkfSBlbnVt7J20IO2VhOyImOyeheuLiOuLpC4gKOyYiDogeyBcImlkLWRlc2NcIjogXCJJROy1nOyLoOyInFwiIH0pYCxcbi8vICAgICB9KTtcbi8vICAgfVxuLy8gICBpZiAoIWVudW1zPy5bc2VhcmNoRmllbGRFbnVtSWRdKSB7XG4vLyAgICAgZXJyb3JzLnB1c2goe1xuLy8gICAgICAgZmllbGQ6IFwiZW51bXNcIixcbi8vICAgICAgIG1lc3NhZ2U6IGAke3NlYXJjaEZpZWxkRW51bUlkfSBlbnVt7J20IO2VhOyImOyeheuLiOuLpC4gKOyYiDogeyBcImlkXCI6IFwiSURcIiB9KWAsXG4vLyAgICAgfSk7XG4vLyAgIH1cblxuLy8gICAvLyAzLiBlbnVtIHByb3DsnZggaWTqsIAgZW51bXPsl5Ag7KCV7J2Y65CY7Ja0IOyeiOuKlOyngCDtmZXsnbggKGNyb3NzLWZpZWxkIOqygOymnSlcbi8vICAgZm9yIChjb25zdCBwcm9wIG9mIHByb3BzID8/IFtdKSB7XG4vLyAgICAgaWYgKHByb3AudHlwZSA9PT0gXCJlbnVtXCIgJiYgIWVudW1zPy5bcHJvcC5pZF0pIHtcbi8vICAgICAgIGVycm9ycy5wdXNoKHtcbi8vICAgICAgICAgZmllbGQ6IGBwcm9wcy4ke3Byb3AubmFtZX1gLFxuLy8gICAgICAgICBtZXNzYWdlOiBgZW51bSBpZCBcIiR7cHJvcC5pZH1cIuqwgCBlbnVtc+yXkCDsoJXsnZjrkJjslrQg7J6I7KeAIOyViuyKteuLiOuLpC5gLFxuLy8gICAgICAgfSk7XG4vLyAgICAgfVxuLy8gICB9XG5cbi8vICAgcmV0dXJuIGVycm9ycztcbi8vIH1cblxuLy8gZXhwb3J0IGNvbnN0IGFpQ2xpZW50ID0gbmV3IEFJQ2xpZW50KCk7XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsaURBQWlEO0FBQ2pELHlFQUF5RTtBQUN6RSwrQkFBK0I7QUFDL0IsdUJBQXVCO0FBQ3ZCLDJCQUEyQjtBQUMzQixXQUFXO0FBQ1gsbUJBQW1CO0FBQ25CLHFCQUFxQjtBQUNyQix3QkFBd0I7QUFDeEIsaUJBQWlCO0FBQ2pCLFlBQVk7QUFDWixxQkFBcUI7QUFDckIsbUJBQW1CO0FBQ25CLDJCQUEyQjtBQUUzQiwyQkFBMkI7QUFDM0IsbUJBQW1CO0FBQ25CLHFCQUFxQjtBQUNyQixLQUFLO0FBRUwsbUJBQW1CO0FBQ25CLG9EQUFvRDtBQUVwRCxtQkFBbUI7QUFDbkIsd0RBQXdEO0FBQ3hELE1BQU07QUFFTiwrRUFBK0U7QUFDL0UsZ0RBQWdEO0FBQ2hELGlGQUFpRjtBQUNqRixpRUFBaUU7QUFDakUsb0RBQW9EO0FBRXBELGlCQUFpQjtBQUNqQiwrQkFBK0I7QUFDL0IsK0JBQStCO0FBQy9CLCtCQUErQjtBQUMvQix1Q0FB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
@@ -0,0 +1,3 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ export declare function sonamuUIApiPlugin(fastify: FastifyInstance): Promise<void>;
3
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/ui/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA4B/C,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,eAAe,iBAovB/D"}