sonamu 0.7.15 → 0.7.17

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 (96) hide show
  1. package/dist/ai/providers/rtzr/error.d.ts +1 -1
  2. package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
  3. package/dist/api/config.d.ts +1 -0
  4. package/dist/api/config.d.ts.map +1 -1
  5. package/dist/api/config.js +1 -1
  6. package/dist/api/decorators.d.ts +1 -1
  7. package/dist/api/decorators.d.ts.map +1 -1
  8. package/dist/api/decorators.js +1 -1
  9. package/dist/api/sonamu.d.ts +3 -1
  10. package/dist/api/sonamu.d.ts.map +1 -1
  11. package/dist/api/sonamu.js +51 -40
  12. package/dist/database/base-model.d.ts +16 -6
  13. package/dist/database/base-model.d.ts.map +1 -1
  14. package/dist/database/base-model.js +44 -3
  15. package/dist/database/base-model.types.d.ts +29 -48
  16. package/dist/database/base-model.types.d.ts.map +1 -1
  17. package/dist/database/base-model.types.js +12 -2
  18. package/dist/database/puri.d.ts +2 -1
  19. package/dist/database/puri.d.ts.map +1 -1
  20. package/dist/database/puri.js +2 -1
  21. package/dist/database/puri.types.d.ts +3 -3
  22. package/dist/database/puri.types.d.ts.map +1 -1
  23. package/dist/database/puri.types.js +1 -1
  24. package/dist/entity/entity-manager.d.ts +8 -4
  25. package/dist/entity/entity-manager.d.ts.map +1 -1
  26. package/dist/entity/entity.d.ts +10 -1
  27. package/dist/entity/entity.d.ts.map +1 -1
  28. package/dist/entity/entity.js +84 -39
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -1
  32. package/dist/syncer/checksum.d.ts +8 -3
  33. package/dist/syncer/checksum.d.ts.map +1 -1
  34. package/dist/syncer/checksum.js +17 -9
  35. package/dist/syncer/code-generator.js +7 -2
  36. package/dist/syncer/syncer.d.ts +6 -6
  37. package/dist/syncer/syncer.d.ts.map +1 -1
  38. package/dist/syncer/syncer.js +27 -13
  39. package/dist/tasks/workflow-manager.d.ts +3 -3
  40. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  41. package/dist/tasks/workflow-manager.js +15 -11
  42. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  43. package/dist/template/implementations/generated.template.js +8 -6
  44. package/dist/template/implementations/model.template.js +5 -5
  45. package/dist/template/implementations/services.template.d.ts +17 -0
  46. package/dist/template/implementations/services.template.d.ts.map +1 -0
  47. package/dist/template/implementations/services.template.js +159 -0
  48. package/dist/template/implementations/view_form.template.js +2 -2
  49. package/dist/template/implementations/view_id_async_select.template.js +2 -2
  50. package/dist/template/implementations/view_list.template.js +5 -5
  51. package/dist/types/types.d.ts +43 -25
  52. package/dist/types/types.d.ts.map +1 -1
  53. package/dist/types/types.js +29 -17
  54. package/dist/ui/ai-api.d.ts +2 -0
  55. package/dist/ui/ai-api.d.ts.map +1 -1
  56. package/dist/ui/ai-api.js +43 -49
  57. package/dist/ui/ai-client.d.ts +10 -0
  58. package/dist/ui/ai-client.d.ts.map +1 -1
  59. package/dist/ui/ai-client.js +457 -437
  60. package/dist/ui/api.d.ts.map +1 -1
  61. package/dist/ui/api.js +14 -3
  62. package/dist/ui-web/assets/{index-J9MCfjCd.js → index-DzqUrTB-.js} +56 -59
  63. package/dist/ui-web/index.html +1 -1
  64. package/package.json +12 -8
  65. package/src/api/config.ts +3 -0
  66. package/src/api/decorators.ts +6 -1
  67. package/src/api/sonamu.ts +71 -52
  68. package/src/database/base-model.ts +66 -11
  69. package/src/database/base-model.types.ts +79 -76
  70. package/src/database/puri.ts +5 -1
  71. package/src/database/puri.types.ts +3 -6
  72. package/src/entity/entity.ts +83 -34
  73. package/src/index.ts +1 -0
  74. package/src/shared/app.shared.ts.txt +1 -1
  75. package/src/shared/web.shared.ts.txt +0 -43
  76. package/src/syncer/checksum.ts +31 -9
  77. package/src/syncer/code-generator.ts +8 -1
  78. package/src/syncer/syncer.ts +38 -26
  79. package/src/tasks/workflow-manager.ts +16 -12
  80. package/src/template/implementations/generated.template.ts +17 -3
  81. package/src/template/implementations/model.template.ts +4 -4
  82. package/src/template/implementations/services.template.ts +226 -0
  83. package/src/template/implementations/view_form.template.ts +1 -1
  84. package/src/template/implementations/view_id_async_select.template.ts +1 -1
  85. package/src/template/implementations/view_list.template.ts +4 -4
  86. package/src/types/types.ts +33 -16
  87. package/src/ui/ai-api.ts +61 -60
  88. package/src/ui/ai-client.ts +535 -499
  89. package/src/ui/api.ts +14 -2
  90. package/src/ui/entity.instructions.md +536 -0
  91. package/dist/template/implementations/service.template.d.ts +0 -29
  92. package/dist/template/implementations/service.template.d.ts.map +0 -1
  93. package/dist/template/implementations/service.template.js +0 -202
  94. package/dist/ui-web/assets/provider-utils_false-BKJD46kk.js +0 -1
  95. package/dist/ui-web/assets/provider-utils_false-Bu5lmX18.js +0 -1
  96. package/src/template/implementations/service.template.ts +0 -328
@@ -1,202 +0,0 @@
1
- import assert from "assert";
2
- import inflection from "inflection";
3
- import { diff, group, sort, unique } from "radashi";
4
- import { apiParamToTsCode, apiParamToTsCodeAsObject, apiParamTypeToTsType, unwrapPromiseOnce } from "../../api/code-converters.js";
5
- import { Sonamu } from "../../api/sonamu.js";
6
- import { Naite } from "../../naite/naite.js";
7
- import { ApiParamType } from "../../types/types.js";
8
- import { assertDefined } from "../../utils/utils.js";
9
- import { Template } from "../template.js";
10
- import { zodTypeToTsTypeDef } from "../zod-converter.js";
11
- export class Template__service extends Template {
12
- constructor(){
13
- super("service");
14
- }
15
- getTargetAndPath(names) {
16
- return {
17
- target: ":target/src/services",
18
- path: `${names.fs}/${names.fs}.service.ts`
19
- };
20
- }
21
- render({ namesRecord }) {
22
- Naite.t("render", {
23
- namesRecord
24
- });
25
- const { syncer: { apis } } = Sonamu;
26
- const apisForThisModel = apis.filter((api)=>api.modelName === `${namesRecord.capital}Model` || api.modelName === `${namesRecord.capital}Frame`);
27
- // 서비스 TypeSource
28
- const { lines, importKeys } = this.getTypeSource(apisForThisModel);
29
- // AxiosProgressEvent 있는지 확인
30
- const hasAxiosProgressEvent = apis.find((api)=>(api.options.clients ?? []).includes("axios-multipart"));
31
- return {
32
- ...this.getTargetAndPath(namesRecord),
33
- body: lines.join("\n"),
34
- importKeys: importKeys.filter((key)=>[
35
- "ListResult"
36
- ].includes(key) === false),
37
- customHeaders: [
38
- `import { z } from 'zod';`,
39
- `import qs from "qs";`,
40
- `import useSWR, { type SWRResponse } from "swr";`,
41
- `import { fetch, ListResult, SWRError, SwrOptions, handleConditional, swrPostFetcher, EventHandlers, SSEStreamOptions, useSSEStream } from '../sonamu.shared';`,
42
- ...hasAxiosProgressEvent ? [
43
- `import { type AxiosProgressEvent } from 'axios';`
44
- ] : []
45
- ]
46
- };
47
- }
48
- getTypeSource(apis) {
49
- const importKeys = [];
50
- // 제네릭에서 선언한 타입, importKeys에서 제외 필요
51
- let typeParamNames = [];
52
- const groups = group(apis, (api)=>api.modelName);
53
- const body = Object.keys(groups).map((modelName)=>{
54
- const methods = groups[modelName];
55
- assert(methods);
56
- const methodCodes = methods.map((api)=>{
57
- // 컨텍스트 제외된 파라미터 리스트
58
- const paramsWithoutContext = api.parameters.filter((param)=>!ApiParamType.isContext(param.type) && !ApiParamType.isRefKnex(param.type) && !(param.optional === true && param.name.startsWith("_")));
59
- // 파라미터 타입 정의
60
- const typeParametersAsTsType = api.typeParameters.map((typeParam)=>{
61
- return apiParamTypeToTsType(typeParam, importKeys);
62
- }).join(", ");
63
- const typeParamsDef = typeParametersAsTsType ? `<${typeParametersAsTsType}>` : "";
64
- typeParamNames = typeParamNames.concat(api.typeParameters.map((typeParam)=>typeParam.id));
65
- // 파라미터 정의
66
- const paramsDef = apiParamToTsCode(paramsWithoutContext, importKeys);
67
- // 파라미터 정의 (객체 형태)
68
- const paramsDefAsObject = apiParamToTsCodeAsObject(paramsWithoutContext, importKeys);
69
- // 리턴 타입 정의
70
- const returnTypeDef = apiParamTypeToTsType(assertDefined(unwrapPromiseOnce(api.returnType)), importKeys);
71
- // 페이로드 데이터 정의
72
- const payloadDef = `{ ${paramsWithoutContext.map((param)=>param.name).join(", ")} }`;
73
- // 기본 URL
74
- const apiBaseUrl = `${Sonamu.config.api.route.prefix}${api.path}`;
75
- const clients = api.options.clients ?? [];
76
- return [
77
- // 클라이언트별로 생성
78
- ...sort(clients, (client)=>client === "swr" ? 0 : 1).map((client)=>{
79
- switch(client){
80
- case "axios":
81
- return this.renderAxios(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, payloadDef);
82
- case "axios-multipart":
83
- return this.renderAxiosMultipart(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, paramsWithoutContext);
84
- case "swr":
85
- return this.renderSwr(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, payloadDef);
86
- case "window-fetch":
87
- return this.renderWindowFetch(api, apiBaseUrl, typeParamsDef, paramsDef, payloadDef);
88
- default:
89
- return `// Not supported ${inflection.camelize(client, true)} yet.`;
90
- }
91
- }),
92
- // 스트리밍인 경우
93
- ...api.streamOptions ? [
94
- this.renderStream(api, apiBaseUrl, paramsDefAsObject)
95
- ] : []
96
- ].join("\n");
97
- }).join("\n\n");
98
- return `export namespace ${modelName.replace(/Model$/, "Service").replace(/Frame$/, "Service")} {
99
- ${methodCodes}
100
- }`;
101
- }).join("\n\n");
102
- return {
103
- lines: [
104
- body
105
- ],
106
- importKeys: diff(unique(importKeys), typeParamNames)
107
- };
108
- }
109
- renderAxios(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, payloadDef) {
110
- const methodNameAxios = api.options.resourceName ? `get${inflection.camelize(api.options.resourceName)}` : api.methodName;
111
- if (api.options.httpMethod === "GET") {
112
- return `
113
- export async function ${methodNameAxios}${typeParamsDef}(${paramsDef}): Promise<${returnTypeDef}> {
114
- return fetch({
115
- method: "GET",
116
- url: \`${apiBaseUrl}?\${qs.stringify(${payloadDef})}\`,
117
- ${api.options.timeout ? `signal: AbortSignal.timeout(${api.options.timeout}),` : ""}
118
- });
119
- }
120
- `.trim();
121
- } else {
122
- return `
123
- export async function ${methodNameAxios}${typeParamsDef}(${paramsDef}): Promise<${returnTypeDef}> {
124
- return fetch({
125
- method: '${api.options.httpMethod}',
126
- url: \`${apiBaseUrl}\`,
127
- data: ${payloadDef},
128
- ${api.options.timeout ? `signal: AbortSignal.timeout(${api.options.timeout}),` : ""}
129
- });
130
- }
131
- `.trim();
132
- }
133
- }
134
- renderAxiosMultipart(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, paramsWithoutContext) {
135
- const isMultiple = api.uploadOptions?.mode === "multiple";
136
- const fileParamName = isMultiple ? "files" : "file";
137
- const fileParamType = isMultiple ? "File[]" : "File";
138
- const formDataDef = isMultiple ? [
139
- `${fileParamName}.forEach(f => { formData.append("${fileParamName}", f) } ); `,
140
- ...paramsWithoutContext.map((param)=>`formData.append('${param.name}', String(${param.name}));`)
141
- ].join("\n") : [
142
- `formData.append("${fileParamName}", ${fileParamName});`,
143
- ...paramsWithoutContext.map((param)=>`formData.append('${param.name}', String(${param.name}));`)
144
- ].join("\n");
145
- const paramsDefComma = paramsDef !== "" ? ", " : "";
146
- return `
147
- export async function ${api.methodName}${typeParamsDef}(
148
- ${paramsDef}${paramsDefComma}
149
- ${fileParamName}: ${fileParamType},
150
- onUploadProgress?: (pe:AxiosProgressEvent) => void
151
- ): Promise<${returnTypeDef}> {
152
- const formData = new FormData();
153
- ${formDataDef}
154
- return fetch({
155
- method: 'POST',
156
- url: \`${apiBaseUrl}\`,
157
- headers: {
158
- "Content-Type": "multipart/form-data",
159
- },
160
- onUploadProgress,
161
- data: formData,
162
- ${api.options.timeout ? `signal: AbortSignal.timeout(${api.options.timeout}),` : ""}
163
- });
164
- }
165
- `.trim();
166
- }
167
- renderSwr(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, payloadDef) {
168
- const methodNameSwr = api.options.resourceName ? `use${inflection.camelize(api.options.resourceName)}` : `use${inflection.camelize(api.methodName)}`;
169
- return ` export function ${inflection.camelize(methodNameSwr, true)}${typeParamsDef}(${[
170
- paramsDef,
171
- "swrOptions?: SwrOptions"
172
- ].filter((p)=>p !== "").join(",")}, ): SWRResponse<${returnTypeDef}, SWRError> {
173
- return useSWR(handleConditional([
174
- \`${apiBaseUrl}\`,
175
- ${payloadDef},
176
- ], swrOptions?.conditional)${api.options.httpMethod === "POST" ? ", swrPostFetcher" : ""}${api.options.timeout ? `, { loadingTimeout: ${api.options.timeout} }` : ""});
177
- }`;
178
- }
179
- renderWindowFetch(api, apiBaseUrl, typeParamsDef, paramsDef, payloadDef) {
180
- return `
181
- export async function ${api.methodName}${typeParamsDef}(${paramsDef}): Promise<Response> {
182
- return window.fetch(\`${apiBaseUrl}?\${qs.stringify(${payloadDef})}\`${api.options.timeout ? `, { signal: AbortSignal.timeout(${api.options.timeout}) }` : ""});
183
- }
184
- `.trim();
185
- }
186
- renderStream(api, apiBaseUrl, paramsDefAsObject) {
187
- if (!api.streamOptions) {
188
- return "// streamOptions not found";
189
- }
190
- const methodNameStream = api.options.resourceName ? `use${inflection.camelize(api.options.resourceName)}` : `use${inflection.camelize(api.methodName)}`;
191
- const methodNameStreamCamelized = inflection.camelize(methodNameStream, true);
192
- const eventsTypeDef = zodTypeToTsTypeDef(api.streamOptions.events);
193
- return ` export function ${methodNameStreamCamelized}(
194
- params: ${paramsDefAsObject},
195
- handlers: EventHandlers<${eventsTypeDef} & { end?: () => void }>,
196
- options: SSEStreamOptions) {
197
- return useSSEStream<${eventsTypeDef}>(\`${apiBaseUrl}\`, params, handlers, options);
198
- }`;
199
- }
200
- }
201
-
202
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90ZW1wbGF0ZS9pbXBsZW1lbnRhdGlvbnMvc2VydmljZS50ZW1wbGF0ZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBpbmZsZWN0aW9uIGZyb20gXCJpbmZsZWN0aW9uXCI7XG5pbXBvcnQgeyBkaWZmLCBncm91cCwgc29ydCwgdW5pcXVlIH0gZnJvbSBcInJhZGFzaGlcIjtcbmltcG9ydCB7XG4gIGFwaVBhcmFtVG9Uc0NvZGUsXG4gIGFwaVBhcmFtVG9Uc0NvZGVBc09iamVjdCxcbiAgYXBpUGFyYW1UeXBlVG9Uc1R5cGUsXG4gIHVud3JhcFByb21pc2VPbmNlLFxufSBmcm9tIFwiLi4vLi4vYXBpL2NvZGUtY29udmVydGVyc1wiO1xuaW1wb3J0IHR5cGUgeyBFeHRlbmRlZEFwaSB9IGZyb20gXCIuLi8uLi9hcGkvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgU29uYW11IH0gZnJvbSBcIi4uLy4uL2FwaS9zb25hbXVcIjtcbmltcG9ydCB0eXBlIHsgRW50aXR5TmFtZXNSZWNvcmQgfSBmcm9tIFwiLi4vLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBOYWl0ZSB9IGZyb20gXCIuLi8uLi9uYWl0ZS9uYWl0ZVwiO1xuaW1wb3J0IHR5cGUgeyBUZW1wbGF0ZU9wdGlvbnMgfSBmcm9tIFwiLi4vLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IHR5cGUgQXBpUGFyYW0sIEFwaVBhcmFtVHlwZSB9IGZyb20gXCIuLi8uLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgYXNzZXJ0RGVmaW5lZCB9IGZyb20gXCIuLi8uLi91dGlscy91dGlsc1wiO1xuaW1wb3J0IHsgVGVtcGxhdGUgfSBmcm9tIFwiLi4vdGVtcGxhdGVcIjtcbmltcG9ydCB7IHpvZFR5cGVUb1RzVHlwZURlZiB9IGZyb20gXCIuLi96b2QtY29udmVydGVyXCI7XG5cbmV4cG9ydCBjbGFzcyBUZW1wbGF0ZV9fc2VydmljZSBleHRlbmRzIFRlbXBsYXRlIHtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoXCJzZXJ2aWNlXCIpO1xuICB9XG5cbiAgZ2V0VGFyZ2V0QW5kUGF0aChuYW1lczogRW50aXR5TmFtZXNSZWNvcmQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgdGFyZ2V0OiBcIjp0YXJnZXQvc3JjL3NlcnZpY2VzXCIsXG4gICAgICBwYXRoOiBgJHtuYW1lcy5mc30vJHtuYW1lcy5mc30uc2VydmljZS50c2AsXG4gICAgfTtcbiAgfVxuXG4gIHJlbmRlcih7IG5hbWVzUmVjb3JkIH06IFRlbXBsYXRlT3B0aW9uc1tcInNlcnZpY2VcIl0pIHtcbiAgICBOYWl0ZS50KFwicmVuZGVyXCIsIHsgbmFtZXNSZWNvcmQgfSk7XG5cbiAgICBjb25zdCB7XG4gICAgICBzeW5jZXI6IHsgYXBpcyB9LFxuICAgIH0gPSBTb25hbXU7XG5cbiAgICBjb25zdCBhcGlzRm9yVGhpc01vZGVsID0gYXBpcy5maWx0ZXIoXG4gICAgICAoYXBpKSA9PlxuICAgICAgICBhcGkubW9kZWxOYW1lID09PSBgJHtuYW1lc1JlY29yZC5jYXBpdGFsfU1vZGVsYCB8fFxuICAgICAgICBhcGkubW9kZWxOYW1lID09PSBgJHtuYW1lc1JlY29yZC5jYXBpdGFsfUZyYW1lYCxcbiAgICApO1xuXG4gICAgLy8g7ISc67mE7IqkIFR5cGVTb3VyY2VcbiAgICBjb25zdCB7IGxpbmVzLCBpbXBvcnRLZXlzIH0gPSB0aGlzLmdldFR5cGVTb3VyY2UoYXBpc0ZvclRoaXNNb2RlbCk7XG5cbiAgICAvLyBBeGlvc1Byb2dyZXNzRXZlbnQg7J6I64qU7KeAIO2ZleyduFxuICAgIGNvbnN0IGhhc0F4aW9zUHJvZ3Jlc3NFdmVudCA9IGFwaXMuZmluZCgoYXBpKSA9PlxuICAgICAgKGFwaS5vcHRpb25zLmNsaWVudHMgPz8gW10pLmluY2x1ZGVzKFwiYXhpb3MtbXVsdGlwYXJ0XCIpLFxuICAgICk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4udGhpcy5nZXRUYXJnZXRBbmRQYXRoKG5hbWVzUmVjb3JkKSxcbiAgICAgIGJvZHk6IGxpbmVzLmpvaW4oXCJcXG5cIiksXG4gICAgICBpbXBvcnRLZXlzOiBpbXBvcnRLZXlzLmZpbHRlcigoa2V5KSA9PiBbXCJMaXN0UmVzdWx0XCJdLmluY2x1ZGVzKGtleSkgPT09IGZhbHNlKSxcbiAgICAgIGN1c3RvbUhlYWRlcnM6IFtcbiAgICAgICAgYGltcG9ydCB7IHogfSBmcm9tICd6b2QnO2AsXG4gICAgICAgIGBpbXBvcnQgcXMgZnJvbSBcInFzXCI7YCxcbiAgICAgICAgYGltcG9ydCB1c2VTV1IsIHsgdHlwZSBTV1JSZXNwb25zZSB9IGZyb20gXCJzd3JcIjtgLFxuICAgICAgICBgaW1wb3J0IHsgZmV0Y2gsIExpc3RSZXN1bHQsIFNXUkVycm9yLCBTd3JPcHRpb25zLCBoYW5kbGVDb25kaXRpb25hbCwgc3dyUG9zdEZldGNoZXIsIEV2ZW50SGFuZGxlcnMsIFNTRVN0cmVhbU9wdGlvbnMsIHVzZVNTRVN0cmVhbSB9IGZyb20gJy4uL3NvbmFtdS5zaGFyZWQnO2AsXG4gICAgICAgIC4uLihoYXNBeGlvc1Byb2dyZXNzRXZlbnQgPyBbYGltcG9ydCB7IHR5cGUgQXhpb3NQcm9ncmVzc0V2ZW50IH0gZnJvbSAnYXhpb3MnO2BdIDogW10pLFxuICAgICAgXSxcbiAgICB9O1xuICB9XG5cbiAgZ2V0VHlwZVNvdXJjZShhcGlzOiBFeHRlbmRlZEFwaVtdKToge1xuICAgIGxpbmVzOiBzdHJpbmdbXTtcbiAgICBpbXBvcnRLZXlzOiBzdHJpbmdbXTtcbiAgfSB7XG4gICAgY29uc3QgaW1wb3J0S2V5czogc3RyaW5nW10gPSBbXTtcblxuICAgIC8vIOygnOuEpOumreyXkOyEnCDshKDslrjtlZwg7YOA7J6FLCBpbXBvcnRLZXlz7JeQ7IScIOygnOyZuCDtlYTsmpRcbiAgICBsZXQgdHlwZVBhcmFtTmFtZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICBjb25zdCBncm91cHMgPSBncm91cChhcGlzLCAoYXBpKSA9PiBhcGkubW9kZWxOYW1lKTtcbiAgICBjb25zdCBib2R5ID0gT2JqZWN0LmtleXMoZ3JvdXBzKVxuICAgICAgLm1hcCgobW9kZWxOYW1lKSA9PiB7XG4gICAgICAgIGNvbnN0IG1ldGhvZHMgPSBncm91cHNbbW9kZWxOYW1lXTtcbiAgICAgICAgYXNzZXJ0KG1ldGhvZHMpO1xuICAgICAgICBjb25zdCBtZXRob2RDb2RlcyA9IG1ldGhvZHNcbiAgICAgICAgICAubWFwKChhcGkpID0+IHtcbiAgICAgICAgICAgIC8vIOy7qO2FjeyKpO2KuCDsoJzsmbjrkJwg7YyM652866+47YSwIOumrOyKpO2KuFxuICAgICAgICAgICAgY29uc3QgcGFyYW1zV2l0aG91dENvbnRleHQgPSBhcGkucGFyYW1ldGVycy5maWx0ZXIoXG4gICAgICAgICAgICAgIChwYXJhbSkgPT5cbiAgICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAgICFBcGlQYXJhbVR5cGUuaXNSZWZLbmV4KHBhcmFtLnR5cGUpICYmXG4gICAgICAgICAgICAgICAgIShwYXJhbS5vcHRpb25hbCA9PT0gdHJ1ZSAmJiBwYXJhbS5uYW1lLnN0YXJ0c1dpdGgoXCJfXCIpKSwgLy8gX+uhnCDsi5zsnpHtlZjripQg7YyM652866+47YSw64qUIOygnOyZuFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgLy8g7YyM652866+47YSwIO2DgOyehSDsoJXsnZhcbiAgICAgICAgICAgIGNvbnN0IHR5cGVQYXJhbWV0ZXJzQXNUc1R5cGUgPSBhcGkudHlwZVBhcmFtZXRlcnNcbiAgICAgICAgICAgICAgLm1hcCgodHlwZVBhcmFtKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFwaVBhcmFtVHlwZVRvVHNUeXBlKHR5cGVQYXJhbSwgaW1wb3J0S2V5cyk7XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIC5qb2luKFwiLCBcIik7XG4gICAgICAgICAgICBjb25zdCB0eXBlUGFyYW1zRGVmID0gdHlwZVBhcmFtZXRlcnNBc1RzVHlwZSA/IGA8JHt0eXBlUGFyYW1ldGVyc0FzVHNUeXBlfT5gIDogXCJcIjtcbiAgICAgICAgICAgIHR5cGVQYXJhbU5hbWVzID0gdHlwZVBhcmFtTmFtZXMuY29uY2F0KFxuICAgICAgICAgICAgICBhcGkudHlwZVBhcmFtZXRlcnMubWFwKCh0eXBlUGFyYW0pID0+IHR5cGVQYXJhbS5pZCksXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAvLyDtjIzrnbzrr7jthLAg7KCV7J2YXG4gICAgICAgICAgICBjb25zdCBwYXJhbXNEZWYgPSBhcGlQYXJhbVRvVHNDb2RlKHBhcmFtc1dpdGhvdXRDb250ZXh0LCBpbXBvcnRLZXlzKTtcblxuICAgICAgICAgICAgLy8g7YyM652866+47YSwIOygleydmCAo6rCd7LK0IO2Yle2DnClcbiAgICAgICAgICAgIGNvbnN0IHBhcmFtc0RlZkFzT2JqZWN0ID0gYXBpUGFyYW1Ub1RzQ29kZUFzT2JqZWN0KHBhcmFtc1dpdGhvdXRDb250ZXh0LCBpbXBvcnRLZXlzKTtcblxuICAgICAgICAgICAgLy8g66as7YS0IO2DgOyehSDsoJXsnZhcbiAgICAgICAgICAgIGNvbnN0IHJldHVyblR5cGVEZWYgPSBhcGlQYXJhbVR5cGVUb1RzVHlwZShcbiAgICAgICAgICAgICAgYXNzZXJ0RGVmaW5lZCh1bndyYXBQcm9taXNlT25jZShhcGkucmV0dXJuVHlwZSkpLFxuICAgICAgICAgICAgICBpbXBvcnRLZXlzLFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgLy8g7Y6Y7J2066Gc65OcIOuNsOydtO2EsCDsoJXsnZhcbiAgICAgICAgICAgIGNvbnN0IHBheWxvYWREZWYgPSBgeyAke3BhcmFtc1dpdGhvdXRDb250ZXh0Lm1hcCgocGFyYW0pID0+IHBhcmFtLm5hbWUpLmpvaW4oXCIsIFwiKX0gfWA7XG5cbiAgICAgICAgICAgIC8vIOq4sOuzuCBVUkxcbiAgICAgICAgICAgIGNvbnN0IGFwaUJhc2VVcmwgPSBgJHtTb25hbXUuY29uZmlnLmFwaS5yb3V0ZS5wcmVmaXh9JHthcGkucGF0aH1gO1xuXG4gICAgICAgICAgICBjb25zdCBjbGllbnRzID0gYXBpLm9wdGlvbnMuY2xpZW50cyA/PyBbXTtcbiAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgIC8vIO2BtOudvOydtOyWuO2KuOuzhOuhnCDsg53shLFcbiAgICAgICAgICAgICAgLi4uc29ydChjbGllbnRzLCAoY2xpZW50KSA9PiAoY2xpZW50ID09PSBcInN3clwiID8gMCA6IDEpKS5tYXAoKGNsaWVudCkgPT4ge1xuICAgICAgICAgICAgICAgIHN3aXRjaCAoY2xpZW50KSB7XG4gICAgICAgICAgICAgICAgICBjYXNlIFwiYXhpb3NcIjpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVuZGVyQXhpb3MoXG4gICAgICAgICAgICAgICAgICAgICAgYXBpLFxuICAgICAgICAgICAgICAgICAgICAgIGFwaUJhc2VVcmwsXG4gICAgICAgICAgICAgICAgICAgICAgdHlwZVBhcmFtc0RlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXJhbXNEZWYsXG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuVHlwZURlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXlsb2FkRGVmLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgY2FzZSBcImF4aW9zLW11bHRpcGFydFwiOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZW5kZXJBeGlvc011bHRpcGFydChcbiAgICAgICAgICAgICAgICAgICAgICBhcGksXG4gICAgICAgICAgICAgICAgICAgICAgYXBpQmFzZVVybCxcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlUGFyYW1zRGVmLFxuICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc0RlZixcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm5UeXBlRGVmLFxuICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc1dpdGhvdXRDb250ZXh0LFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgY2FzZSBcInN3clwiOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZW5kZXJTd3IoXG4gICAgICAgICAgICAgICAgICAgICAgYXBpLFxuICAgICAgICAgICAgICAgICAgICAgIGFwaUJhc2VVcmwsXG4gICAgICAgICAgICAgICAgICAgICAgdHlwZVBhcmFtc0RlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXJhbXNEZWYsXG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuVHlwZURlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXlsb2FkRGVmLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgY2FzZSBcIndpbmRvdy1mZXRjaFwiOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZW5kZXJXaW5kb3dGZXRjaChcbiAgICAgICAgICAgICAgICAgICAgICBhcGksXG4gICAgICAgICAgICAgICAgICAgICAgYXBpQmFzZVVybCxcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlUGFyYW1zRGVmLFxuICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc0RlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXlsb2FkRGVmLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGAvLyBOb3Qgc3VwcG9ydGVkICR7aW5mbGVjdGlvbi5jYW1lbGl6ZShjbGllbnQsIHRydWUpfSB5ZXQuYDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAvLyDsiqTtirjrpqzrsI3snbgg6rK97JqwXG4gICAgICAgICAgICAgIC4uLihhcGkuc3RyZWFtT3B0aW9ucyA/IFt0aGlzLnJlbmRlclN0cmVhbShhcGksIGFwaUJhc2VVcmwsIHBhcmFtc0RlZkFzT2JqZWN0KV0gOiBbXSksXG4gICAgICAgICAgICBdLmpvaW4oXCJcXG5cIik7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuam9pbihcIlxcblxcblwiKTtcblxuICAgICAgICByZXR1cm4gYGV4cG9ydCBuYW1lc3BhY2UgJHttb2RlbE5hbWUucmVwbGFjZSgvTW9kZWwkLywgXCJTZXJ2aWNlXCIpLnJlcGxhY2UoL0ZyYW1lJC8sIFwiU2VydmljZVwiKX0ge1xuJHttZXRob2RDb2Rlc31cbn1gO1xuICAgICAgfSlcbiAgICAgIC5qb2luKFwiXFxuXFxuXCIpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGxpbmVzOiBbYm9keV0sXG4gICAgICBpbXBvcnRLZXlzOiBkaWZmKHVuaXF1ZShpbXBvcnRLZXlzKSwgdHlwZVBhcmFtTmFtZXMpLFxuICAgIH07XG4gIH1cblxuICByZW5kZXJBeGlvcyhcbiAgICBhcGk6IEV4dGVuZGVkQXBpLFxuICAgIGFwaUJhc2VVcmw6IHN0cmluZyxcbiAgICB0eXBlUGFyYW1zRGVmOiBzdHJpbmcsXG4gICAgcGFyYW1zRGVmOiBzdHJpbmcsXG4gICAgcmV0dXJuVHlwZURlZjogc3RyaW5nLFxuICAgIHBheWxvYWREZWY6IHN0cmluZyxcbiAgKSB7XG4gICAgY29uc3QgbWV0aG9kTmFtZUF4aW9zID0gYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lXG4gICAgICA/IGBnZXQke2luZmxlY3Rpb24uY2FtZWxpemUoYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lKX1gXG4gICAgICA6IGFwaS5tZXRob2ROYW1lO1xuXG4gICAgaWYgKGFwaS5vcHRpb25zLmh0dHBNZXRob2QgPT09IFwiR0VUXCIpIHtcbiAgICAgIHJldHVybiBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHttZXRob2ROYW1lQXhpb3N9JHt0eXBlUGFyYW1zRGVmfSgke3BhcmFtc0RlZn0pOiBQcm9taXNlPCR7cmV0dXJuVHlwZURlZn0+IHtcbiAgICByZXR1cm4gZmV0Y2goe1xuICAgICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgICAgdXJsOiBcXGAke2FwaUJhc2VVcmx9P1xcJHtxcy5zdHJpbmdpZnkoJHtwYXlsb2FkRGVmfSl9XFxgLFxuICAgICAgJHthcGkub3B0aW9ucy50aW1lb3V0ID8gYHNpZ25hbDogQWJvcnRTaWduYWwudGltZW91dCgke2FwaS5vcHRpb25zLnRpbWVvdXR9KSxgIDogXCJcIn1cbiAgICB9KTtcbn1cbiAgICBgLnRyaW0oKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGBcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiAke21ldGhvZE5hbWVBeGlvc30ke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSk6IFByb21pc2U8JHtyZXR1cm5UeXBlRGVmfT4ge1xuICAgIHJldHVybiBmZXRjaCh7XG4gICAgICBtZXRob2Q6ICcke2FwaS5vcHRpb25zLmh0dHBNZXRob2R9JyxcbiAgICAgIHVybDogXFxgJHthcGlCYXNlVXJsfVxcYCxcbiAgICAgIGRhdGE6ICR7cGF5bG9hZERlZn0sXG4gICAgICAke2FwaS5vcHRpb25zLnRpbWVvdXQgPyBgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pLGAgOiBcIlwifVxuICAgIH0pO1xufVxuICAgICAgYC50cmltKCk7XG4gICAgfVxuICB9XG5cbiAgcmVuZGVyQXhpb3NNdWx0aXBhcnQoXG4gICAgYXBpOiBFeHRlbmRlZEFwaSxcbiAgICBhcGlCYXNlVXJsOiBzdHJpbmcsXG4gICAgdHlwZVBhcmFtc0RlZjogc3RyaW5nLFxuICAgIHBhcmFtc0RlZjogc3RyaW5nLFxuICAgIHJldHVyblR5cGVEZWY6IHN0cmluZyxcbiAgICBwYXJhbXNXaXRob3V0Q29udGV4dDogQXBpUGFyYW1bXSxcbiAgKSB7XG4gICAgY29uc3QgaXNNdWx0aXBsZSA9IGFwaS51cGxvYWRPcHRpb25zPy5tb2RlID09PSBcIm11bHRpcGxlXCI7XG4gICAgY29uc3QgZmlsZVBhcmFtTmFtZSA9IGlzTXVsdGlwbGUgPyBcImZpbGVzXCIgOiBcImZpbGVcIjtcbiAgICBjb25zdCBmaWxlUGFyYW1UeXBlID0gaXNNdWx0aXBsZSA/IFwiRmlsZVtdXCIgOiBcIkZpbGVcIjtcblxuICAgIGNvbnN0IGZvcm1EYXRhRGVmID0gaXNNdWx0aXBsZVxuICAgICAgPyBbXG4gICAgICAgICAgYCR7ZmlsZVBhcmFtTmFtZX0uZm9yRWFjaChmID0+IHsgZm9ybURhdGEuYXBwZW5kKFwiJHtmaWxlUGFyYW1OYW1lfVwiLCBmKSB9ICk7IGAsXG4gICAgICAgICAgLi4ucGFyYW1zV2l0aG91dENvbnRleHQubWFwKFxuICAgICAgICAgICAgKHBhcmFtKSA9PiBgZm9ybURhdGEuYXBwZW5kKCcke3BhcmFtLm5hbWV9JywgU3RyaW5nKCR7cGFyYW0ubmFtZX0pKTtgLFxuICAgICAgICAgICksXG4gICAgICAgIF0uam9pbihcIlxcblwiKVxuICAgICAgOiBbXG4gICAgICAgICAgYGZvcm1EYXRhLmFwcGVuZChcIiR7ZmlsZVBhcmFtTmFtZX1cIiwgJHtmaWxlUGFyYW1OYW1lfSk7YCxcbiAgICAgICAgICAuLi5wYXJhbXNXaXRob3V0Q29udGV4dC5tYXAoXG4gICAgICAgICAgICAocGFyYW0pID0+IGBmb3JtRGF0YS5hcHBlbmQoJyR7cGFyYW0ubmFtZX0nLCBTdHJpbmcoJHtwYXJhbS5uYW1lfSkpO2AsXG4gICAgICAgICAgKSxcbiAgICAgICAgXS5qb2luKFwiXFxuXCIpO1xuXG4gICAgY29uc3QgcGFyYW1zRGVmQ29tbWEgPSBwYXJhbXNEZWYgIT09IFwiXCIgPyBcIiwgXCIgOiBcIlwiO1xuICAgIHJldHVybiBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHthcGkubWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KFxuICAke3BhcmFtc0RlZn0ke3BhcmFtc0RlZkNvbW1hfVxuICAke2ZpbGVQYXJhbU5hbWV9OiAke2ZpbGVQYXJhbVR5cGV9LFxuICBvblVwbG9hZFByb2dyZXNzPzogKHBlOkF4aW9zUHJvZ3Jlc3NFdmVudCkgPT4gdm9pZFxuICApOiBQcm9taXNlPCR7cmV0dXJuVHlwZURlZn0+IHtcbiAgICBjb25zdCBmb3JtRGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICR7Zm9ybURhdGFEZWZ9XG4gICAgcmV0dXJuIGZldGNoKHtcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgdXJsOiBcXGAke2FwaUJhc2VVcmx9XFxgLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcIm11bHRpcGFydC9mb3JtLWRhdGFcIixcbiAgICAgIH0sXG4gICAgICBvblVwbG9hZFByb2dyZXNzLFxuICAgICAgZGF0YTogZm9ybURhdGEsXG4gICAgICAke2FwaS5vcHRpb25zLnRpbWVvdXQgPyBgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pLGAgOiBcIlwifVxuICAgIH0pO1xuICB9XG4gIGAudHJpbSgpO1xuICB9XG5cbiAgcmVuZGVyU3dyKFxuICAgIGFwaTogRXh0ZW5kZWRBcGksXG4gICAgYXBpQmFzZVVybDogc3RyaW5nLFxuICAgIHR5cGVQYXJhbXNEZWY6IHN0cmluZyxcbiAgICBwYXJhbXNEZWY6IHN0cmluZyxcbiAgICByZXR1cm5UeXBlRGVmOiBzdHJpbmcsXG4gICAgcGF5bG9hZERlZjogc3RyaW5nLFxuICApIHtcbiAgICBjb25zdCBtZXRob2ROYW1lU3dyID0gYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lXG4gICAgICA/IGB1c2Uke2luZmxlY3Rpb24uY2FtZWxpemUoYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lKX1gXG4gICAgICA6IGB1c2Uke2luZmxlY3Rpb24uY2FtZWxpemUoYXBpLm1ldGhvZE5hbWUpfWA7XG4gICAgcmV0dXJuIGAgIGV4cG9ydCBmdW5jdGlvbiAke2luZmxlY3Rpb24uY2FtZWxpemUobWV0aG9kTmFtZVN3ciwgdHJ1ZSl9JHt0eXBlUGFyYW1zRGVmfSgke1tcbiAgICAgIHBhcmFtc0RlZixcbiAgICAgIFwic3dyT3B0aW9ucz86IFN3ck9wdGlvbnNcIixcbiAgICBdXG4gICAgICAuZmlsdGVyKChwKSA9PiBwICE9PSBcIlwiKVxuICAgICAgLmpvaW4oXCIsXCIpfSwgKTogU1dSUmVzcG9uc2U8JHtyZXR1cm5UeXBlRGVmfSwgU1dSRXJyb3I+IHtcbiAgICByZXR1cm4gdXNlU1dSKGhhbmRsZUNvbmRpdGlvbmFsKFtcbiAgICAgIFxcYCR7YXBpQmFzZVVybH1cXGAsXG4gICAgICAke3BheWxvYWREZWZ9LFxuICAgIF0sIHN3ck9wdGlvbnM/LmNvbmRpdGlvbmFsKSR7YXBpLm9wdGlvbnMuaHR0cE1ldGhvZCA9PT0gXCJQT1NUXCIgPyBcIiwgc3dyUG9zdEZldGNoZXJcIiA6IFwiXCJ9JHtcbiAgICAgIGFwaS5vcHRpb25zLnRpbWVvdXQgPyBgLCB7IGxvYWRpbmdUaW1lb3V0OiAke2FwaS5vcHRpb25zLnRpbWVvdXR9IH1gIDogXCJcIlxuICAgIH0pO1xuICB9YDtcbiAgfVxuXG4gIHJlbmRlcldpbmRvd0ZldGNoKFxuICAgIGFwaTogRXh0ZW5kZWRBcGksXG4gICAgYXBpQmFzZVVybDogc3RyaW5nLFxuICAgIHR5cGVQYXJhbXNEZWY6IHN0cmluZyxcbiAgICBwYXJhbXNEZWY6IHN0cmluZyxcbiAgICBwYXlsb2FkRGVmOiBzdHJpbmcsXG4gICkge1xuICAgIHJldHVybiBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHthcGkubWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSk6IFByb21pc2U8UmVzcG9uc2U+IHtcbiAgICByZXR1cm4gd2luZG93LmZldGNoKFxcYCR7YXBpQmFzZVVybH0/XFwke3FzLnN0cmluZ2lmeSgke3BheWxvYWREZWZ9KX1cXGAke1xuICAgICAgYXBpLm9wdGlvbnMudGltZW91dCA/IGAsIHsgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pIH1gIDogXCJcIlxuICAgIH0pO1xufVxuICAgIGAudHJpbSgpO1xuICB9XG5cbiAgcmVuZGVyU3RyZWFtKGFwaTogRXh0ZW5kZWRBcGksIGFwaUJhc2VVcmw6IHN0cmluZywgcGFyYW1zRGVmQXNPYmplY3Q6IHN0cmluZykge1xuICAgIGlmICghYXBpLnN0cmVhbU9wdGlvbnMpIHtcbiAgICAgIHJldHVybiBcIi8vIHN0cmVhbU9wdGlvbnMgbm90IGZvdW5kXCI7XG4gICAgfVxuXG4gICAgY29uc3QgbWV0aG9kTmFtZVN0cmVhbSA9IGFwaS5vcHRpb25zLnJlc291cmNlTmFtZVxuICAgICAgPyBgdXNlJHtpbmZsZWN0aW9uLmNhbWVsaXplKGFwaS5vcHRpb25zLnJlc291cmNlTmFtZSl9YFxuICAgICAgOiBgdXNlJHtpbmZsZWN0aW9uLmNhbWVsaXplKGFwaS5tZXRob2ROYW1lKX1gO1xuICAgIGNvbnN0IG1ldGhvZE5hbWVTdHJlYW1DYW1lbGl6ZWQgPSBpbmZsZWN0aW9uLmNhbWVsaXplKG1ldGhvZE5hbWVTdHJlYW0sIHRydWUpO1xuXG4gICAgY29uc3QgZXZlbnRzVHlwZURlZiA9IHpvZFR5cGVUb1RzVHlwZURlZihhcGkuc3RyZWFtT3B0aW9ucy5ldmVudHMpO1xuXG4gICAgcmV0dXJuIGAgIGV4cG9ydCBmdW5jdGlvbiAke21ldGhvZE5hbWVTdHJlYW1DYW1lbGl6ZWR9KFxuICBwYXJhbXM6ICR7cGFyYW1zRGVmQXNPYmplY3R9LFxuICBoYW5kbGVyczogRXZlbnRIYW5kbGVyczwke2V2ZW50c1R5cGVEZWZ9ICYgeyBlbmQ/OiAoKSA9PiB2b2lkIH0+LFxuICBvcHRpb25zOiBTU0VTdHJlYW1PcHRpb25zKSB7XG4gICAgcmV0dXJuIHVzZVNTRVN0cmVhbTwke2V2ZW50c1R5cGVEZWZ9PihcXGAke2FwaUJhc2VVcmx9XFxgLCBwYXJhbXMsIGhhbmRsZXJzLCBvcHRpb25zKTtcbiAgfWA7XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJhc3NlcnQiLCJpbmZsZWN0aW9uIiwiZGlmZiIsImdyb3VwIiwic29ydCIsInVuaXF1ZSIsImFwaVBhcmFtVG9Uc0NvZGUiLCJhcGlQYXJhbVRvVHNDb2RlQXNPYmplY3QiLCJhcGlQYXJhbVR5cGVUb1RzVHlwZSIsInVud3JhcFByb21pc2VPbmNlIiwiU29uYW11IiwiTmFpdGUiLCJBcGlQYXJhbVR5cGUiLCJhc3NlcnREZWZpbmVkIiwiVGVtcGxhdGUiLCJ6b2RUeXBlVG9Uc1R5cGVEZWYiLCJUZW1wbGF0ZV9fc2VydmljZSIsImdldFRhcmdldEFuZFBhdGgiLCJuYW1lcyIsInRhcmdldCIsInBhdGgiLCJmcyIsInJlbmRlciIsIm5hbWVzUmVjb3JkIiwidCIsInN5bmNlciIsImFwaXMiLCJhcGlzRm9yVGhpc01vZGVsIiwiZmlsdGVyIiwiYXBpIiwibW9kZWxOYW1lIiwiY2FwaXRhbCIsImxpbmVzIiwiaW1wb3J0S2V5cyIsImdldFR5cGVTb3VyY2UiLCJoYXNBeGlvc1Byb2dyZXNzRXZlbnQiLCJmaW5kIiwib3B0aW9ucyIsImNsaWVudHMiLCJpbmNsdWRlcyIsImJvZHkiLCJqb2luIiwia2V5IiwiY3VzdG9tSGVhZGVycyIsInR5cGVQYXJhbU5hbWVzIiwiZ3JvdXBzIiwiT2JqZWN0Iiwia2V5cyIsIm1hcCIsIm1ldGhvZHMiLCJtZXRob2RDb2RlcyIsInBhcmFtc1dpdGhvdXRDb250ZXh0IiwicGFyYW1ldGVycyIsInBhcmFtIiwiaXNDb250ZXh0IiwidHlwZSIsImlzUmVmS25leCIsIm9wdGlvbmFsIiwibmFtZSIsInN0YXJ0c1dpdGgiLCJ0eXBlUGFyYW1ldGVyc0FzVHNUeXBlIiwidHlwZVBhcmFtZXRlcnMiLCJ0eXBlUGFyYW0iLCJ0eXBlUGFyYW1zRGVmIiwiY29uY2F0IiwiaWQiLCJwYXJhbXNEZWYiLCJwYXJhbXNEZWZBc09iamVjdCIsInJldHVyblR5cGVEZWYiLCJyZXR1cm5UeXBlIiwicGF5bG9hZERlZiIsImFwaUJhc2VVcmwiLCJjb25maWciLCJyb3V0ZSIsInByZWZpeCIsImNsaWVudCIsInJlbmRlckF4aW9zIiwicmVuZGVyQXhpb3NNdWx0aXBhcnQiLCJyZW5kZXJTd3IiLCJyZW5kZXJXaW5kb3dGZXRjaCIsImNhbWVsaXplIiwic3RyZWFtT3B0aW9ucyIsInJlbmRlclN0cmVhbSIsInJlcGxhY2UiLCJtZXRob2ROYW1lQXhpb3MiLCJyZXNvdXJjZU5hbWUiLCJtZXRob2ROYW1lIiwiaHR0cE1ldGhvZCIsInRpbWVvdXQiLCJ0cmltIiwiaXNNdWx0aXBsZSIsInVwbG9hZE9wdGlvbnMiLCJtb2RlIiwiZmlsZVBhcmFtTmFtZSIsImZpbGVQYXJhbVR5cGUiLCJmb3JtRGF0YURlZiIsInBhcmFtc0RlZkNvbW1hIiwibWV0aG9kTmFtZVN3ciIsInAiLCJtZXRob2ROYW1lU3RyZWFtIiwibWV0aG9kTmFtZVN0cmVhbUNhbWVsaXplZCIsImV2ZW50c1R5cGVEZWYiLCJldmVudHMiXSwibWFwcGluZ3MiOiJBQUFBLE9BQU9BLFlBQVksU0FBUztBQUM1QixPQUFPQyxnQkFBZ0IsYUFBYTtBQUNwQyxTQUFTQyxJQUFJLEVBQUVDLEtBQUssRUFBRUMsSUFBSSxFQUFFQyxNQUFNLFFBQVEsVUFBVTtBQUNwRCxTQUNFQyxnQkFBZ0IsRUFDaEJDLHdCQUF3QixFQUN4QkMsb0JBQW9CLEVBQ3BCQyxpQkFBaUIsUUFDWiwrQkFBNEI7QUFFbkMsU0FBU0MsTUFBTSxRQUFRLHNCQUFtQjtBQUUxQyxTQUFTQyxLQUFLLFFBQVEsdUJBQW9CO0FBRTFDLFNBQXdCQyxZQUFZLFFBQVEsdUJBQW9CO0FBQ2hFLFNBQVNDLGFBQWEsUUFBUSx1QkFBb0I7QUFDbEQsU0FBU0MsUUFBUSxRQUFRLGlCQUFjO0FBQ3ZDLFNBQVNDLGtCQUFrQixRQUFRLHNCQUFtQjtBQUV0RCxPQUFPLE1BQU1DLDBCQUEwQkY7SUFDckMsYUFBYztRQUNaLEtBQUssQ0FBQztJQUNSO0lBRUFHLGlCQUFpQkMsS0FBd0IsRUFBRTtRQUN6QyxPQUFPO1lBQ0xDLFFBQVE7WUFDUkMsTUFBTSxHQUFHRixNQUFNRyxFQUFFLENBQUMsQ0FBQyxFQUFFSCxNQUFNRyxFQUFFLENBQUMsV0FBVyxDQUFDO1FBQzVDO0lBQ0Y7SUFF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
@@ -1 +0,0 @@
1
- throw new Error('Could not resolve "@valibot/to-json-schema" imported by "@ai-sdk/provider-utils".');
@@ -1 +0,0 @@
1
- throw new Error('Could not resolve "effect" imported by "@ai-sdk/provider-utils".');
@@ -1,328 +0,0 @@
1
- import assert from "assert";
2
- import inflection from "inflection";
3
- import { diff, group, sort, unique } from "radashi";
4
- import {
5
- apiParamToTsCode,
6
- apiParamToTsCodeAsObject,
7
- apiParamTypeToTsType,
8
- unwrapPromiseOnce,
9
- } from "../../api/code-converters";
10
- import type { ExtendedApi } from "../../api/decorators";
11
- import { Sonamu } from "../../api/sonamu";
12
- import type { EntityNamesRecord } from "../../entity/entity-manager";
13
- import { Naite } from "../../naite/naite";
14
- import type { TemplateOptions } from "../../types/types";
15
- import { type ApiParam, ApiParamType } from "../../types/types";
16
- import { assertDefined } from "../../utils/utils";
17
- import { Template } from "../template";
18
- import { zodTypeToTsTypeDef } from "../zod-converter";
19
-
20
- export class Template__service extends Template {
21
- constructor() {
22
- super("service");
23
- }
24
-
25
- getTargetAndPath(names: EntityNamesRecord) {
26
- return {
27
- target: ":target/src/services",
28
- path: `${names.fs}/${names.fs}.service.ts`,
29
- };
30
- }
31
-
32
- render({ namesRecord }: TemplateOptions["service"]) {
33
- Naite.t("render", { namesRecord });
34
-
35
- const {
36
- syncer: { apis },
37
- } = Sonamu;
38
-
39
- const apisForThisModel = apis.filter(
40
- (api) =>
41
- api.modelName === `${namesRecord.capital}Model` ||
42
- api.modelName === `${namesRecord.capital}Frame`,
43
- );
44
-
45
- // 서비스 TypeSource
46
- const { lines, importKeys } = this.getTypeSource(apisForThisModel);
47
-
48
- // AxiosProgressEvent 있는지 확인
49
- const hasAxiosProgressEvent = apis.find((api) =>
50
- (api.options.clients ?? []).includes("axios-multipart"),
51
- );
52
-
53
- return {
54
- ...this.getTargetAndPath(namesRecord),
55
- body: lines.join("\n"),
56
- importKeys: importKeys.filter((key) => ["ListResult"].includes(key) === false),
57
- customHeaders: [
58
- `import { z } from 'zod';`,
59
- `import qs from "qs";`,
60
- `import useSWR, { type SWRResponse } from "swr";`,
61
- `import { fetch, ListResult, SWRError, SwrOptions, handleConditional, swrPostFetcher, EventHandlers, SSEStreamOptions, useSSEStream } from '../sonamu.shared';`,
62
- ...(hasAxiosProgressEvent ? [`import { type AxiosProgressEvent } from 'axios';`] : []),
63
- ],
64
- };
65
- }
66
-
67
- getTypeSource(apis: ExtendedApi[]): {
68
- lines: string[];
69
- importKeys: string[];
70
- } {
71
- const importKeys: string[] = [];
72
-
73
- // 제네릭에서 선언한 타입, importKeys에서 제외 필요
74
- let typeParamNames: string[] = [];
75
-
76
- const groups = group(apis, (api) => api.modelName);
77
- const body = Object.keys(groups)
78
- .map((modelName) => {
79
- const methods = groups[modelName];
80
- assert(methods);
81
- const methodCodes = methods
82
- .map((api) => {
83
- // 컨텍스트 제외된 파라미터 리스트
84
- const paramsWithoutContext = api.parameters.filter(
85
- (param) =>
86
- !ApiParamType.isContext(param.type) &&
87
- !ApiParamType.isRefKnex(param.type) &&
88
- !(param.optional === true && param.name.startsWith("_")), // _로 시작하는 파라미터는 제외
89
- );
90
-
91
- // 파라미터 타입 정의
92
- const typeParametersAsTsType = api.typeParameters
93
- .map((typeParam) => {
94
- return apiParamTypeToTsType(typeParam, importKeys);
95
- })
96
- .join(", ");
97
- const typeParamsDef = typeParametersAsTsType ? `<${typeParametersAsTsType}>` : "";
98
- typeParamNames = typeParamNames.concat(
99
- api.typeParameters.map((typeParam) => typeParam.id),
100
- );
101
-
102
- // 파라미터 정의
103
- const paramsDef = apiParamToTsCode(paramsWithoutContext, importKeys);
104
-
105
- // 파라미터 정의 (객체 형태)
106
- const paramsDefAsObject = apiParamToTsCodeAsObject(paramsWithoutContext, importKeys);
107
-
108
- // 리턴 타입 정의
109
- const returnTypeDef = apiParamTypeToTsType(
110
- assertDefined(unwrapPromiseOnce(api.returnType)),
111
- importKeys,
112
- );
113
-
114
- // 페이로드 데이터 정의
115
- const payloadDef = `{ ${paramsWithoutContext.map((param) => param.name).join(", ")} }`;
116
-
117
- // 기본 URL
118
- const apiBaseUrl = `${Sonamu.config.api.route.prefix}${api.path}`;
119
-
120
- const clients = api.options.clients ?? [];
121
- return [
122
- // 클라이언트별로 생성
123
- ...sort(clients, (client) => (client === "swr" ? 0 : 1)).map((client) => {
124
- switch (client) {
125
- case "axios":
126
- return this.renderAxios(
127
- api,
128
- apiBaseUrl,
129
- typeParamsDef,
130
- paramsDef,
131
- returnTypeDef,
132
- payloadDef,
133
- );
134
- case "axios-multipart":
135
- return this.renderAxiosMultipart(
136
- api,
137
- apiBaseUrl,
138
- typeParamsDef,
139
- paramsDef,
140
- returnTypeDef,
141
- paramsWithoutContext,
142
- );
143
- case "swr":
144
- return this.renderSwr(
145
- api,
146
- apiBaseUrl,
147
- typeParamsDef,
148
- paramsDef,
149
- returnTypeDef,
150
- payloadDef,
151
- );
152
- case "window-fetch":
153
- return this.renderWindowFetch(
154
- api,
155
- apiBaseUrl,
156
- typeParamsDef,
157
- paramsDef,
158
- payloadDef,
159
- );
160
- default:
161
- return `// Not supported ${inflection.camelize(client, true)} yet.`;
162
- }
163
- }),
164
- // 스트리밍인 경우
165
- ...(api.streamOptions ? [this.renderStream(api, apiBaseUrl, paramsDefAsObject)] : []),
166
- ].join("\n");
167
- })
168
- .join("\n\n");
169
-
170
- return `export namespace ${modelName.replace(/Model$/, "Service").replace(/Frame$/, "Service")} {
171
- ${methodCodes}
172
- }`;
173
- })
174
- .join("\n\n");
175
-
176
- return {
177
- lines: [body],
178
- importKeys: diff(unique(importKeys), typeParamNames),
179
- };
180
- }
181
-
182
- renderAxios(
183
- api: ExtendedApi,
184
- apiBaseUrl: string,
185
- typeParamsDef: string,
186
- paramsDef: string,
187
- returnTypeDef: string,
188
- payloadDef: string,
189
- ) {
190
- const methodNameAxios = api.options.resourceName
191
- ? `get${inflection.camelize(api.options.resourceName)}`
192
- : api.methodName;
193
-
194
- if (api.options.httpMethod === "GET") {
195
- return `
196
- export async function ${methodNameAxios}${typeParamsDef}(${paramsDef}): Promise<${returnTypeDef}> {
197
- return fetch({
198
- method: "GET",
199
- url: \`${apiBaseUrl}?\${qs.stringify(${payloadDef})}\`,
200
- ${api.options.timeout ? `signal: AbortSignal.timeout(${api.options.timeout}),` : ""}
201
- });
202
- }
203
- `.trim();
204
- } else {
205
- return `
206
- export async function ${methodNameAxios}${typeParamsDef}(${paramsDef}): Promise<${returnTypeDef}> {
207
- return fetch({
208
- method: '${api.options.httpMethod}',
209
- url: \`${apiBaseUrl}\`,
210
- data: ${payloadDef},
211
- ${api.options.timeout ? `signal: AbortSignal.timeout(${api.options.timeout}),` : ""}
212
- });
213
- }
214
- `.trim();
215
- }
216
- }
217
-
218
- renderAxiosMultipart(
219
- api: ExtendedApi,
220
- apiBaseUrl: string,
221
- typeParamsDef: string,
222
- paramsDef: string,
223
- returnTypeDef: string,
224
- paramsWithoutContext: ApiParam[],
225
- ) {
226
- const isMultiple = api.uploadOptions?.mode === "multiple";
227
- const fileParamName = isMultiple ? "files" : "file";
228
- const fileParamType = isMultiple ? "File[]" : "File";
229
-
230
- const formDataDef = isMultiple
231
- ? [
232
- `${fileParamName}.forEach(f => { formData.append("${fileParamName}", f) } ); `,
233
- ...paramsWithoutContext.map(
234
- (param) => `formData.append('${param.name}', String(${param.name}));`,
235
- ),
236
- ].join("\n")
237
- : [
238
- `formData.append("${fileParamName}", ${fileParamName});`,
239
- ...paramsWithoutContext.map(
240
- (param) => `formData.append('${param.name}', String(${param.name}));`,
241
- ),
242
- ].join("\n");
243
-
244
- const paramsDefComma = paramsDef !== "" ? ", " : "";
245
- return `
246
- export async function ${api.methodName}${typeParamsDef}(
247
- ${paramsDef}${paramsDefComma}
248
- ${fileParamName}: ${fileParamType},
249
- onUploadProgress?: (pe:AxiosProgressEvent) => void
250
- ): Promise<${returnTypeDef}> {
251
- const formData = new FormData();
252
- ${formDataDef}
253
- return fetch({
254
- method: 'POST',
255
- url: \`${apiBaseUrl}\`,
256
- headers: {
257
- "Content-Type": "multipart/form-data",
258
- },
259
- onUploadProgress,
260
- data: formData,
261
- ${api.options.timeout ? `signal: AbortSignal.timeout(${api.options.timeout}),` : ""}
262
- });
263
- }
264
- `.trim();
265
- }
266
-
267
- renderSwr(
268
- api: ExtendedApi,
269
- apiBaseUrl: string,
270
- typeParamsDef: string,
271
- paramsDef: string,
272
- returnTypeDef: string,
273
- payloadDef: string,
274
- ) {
275
- const methodNameSwr = api.options.resourceName
276
- ? `use${inflection.camelize(api.options.resourceName)}`
277
- : `use${inflection.camelize(api.methodName)}`;
278
- return ` export function ${inflection.camelize(methodNameSwr, true)}${typeParamsDef}(${[
279
- paramsDef,
280
- "swrOptions?: SwrOptions",
281
- ]
282
- .filter((p) => p !== "")
283
- .join(",")}, ): SWRResponse<${returnTypeDef}, SWRError> {
284
- return useSWR(handleConditional([
285
- \`${apiBaseUrl}\`,
286
- ${payloadDef},
287
- ], swrOptions?.conditional)${api.options.httpMethod === "POST" ? ", swrPostFetcher" : ""}${
288
- api.options.timeout ? `, { loadingTimeout: ${api.options.timeout} }` : ""
289
- });
290
- }`;
291
- }
292
-
293
- renderWindowFetch(
294
- api: ExtendedApi,
295
- apiBaseUrl: string,
296
- typeParamsDef: string,
297
- paramsDef: string,
298
- payloadDef: string,
299
- ) {
300
- return `
301
- export async function ${api.methodName}${typeParamsDef}(${paramsDef}): Promise<Response> {
302
- return window.fetch(\`${apiBaseUrl}?\${qs.stringify(${payloadDef})}\`${
303
- api.options.timeout ? `, { signal: AbortSignal.timeout(${api.options.timeout}) }` : ""
304
- });
305
- }
306
- `.trim();
307
- }
308
-
309
- renderStream(api: ExtendedApi, apiBaseUrl: string, paramsDefAsObject: string) {
310
- if (!api.streamOptions) {
311
- return "// streamOptions not found";
312
- }
313
-
314
- const methodNameStream = api.options.resourceName
315
- ? `use${inflection.camelize(api.options.resourceName)}`
316
- : `use${inflection.camelize(api.methodName)}`;
317
- const methodNameStreamCamelized = inflection.camelize(methodNameStream, true);
318
-
319
- const eventsTypeDef = zodTypeToTsTypeDef(api.streamOptions.events);
320
-
321
- return ` export function ${methodNameStreamCamelized}(
322
- params: ${paramsDefAsObject},
323
- handlers: EventHandlers<${eventsTypeDef} & { end?: () => void }>,
324
- options: SSEStreamOptions) {
325
- return useSSEStream<${eventsTypeDef}>(\`${apiBaseUrl}\`, params, handlers, options);
326
- }`;
327
- }
328
- }