sonamu 0.7.18 → 0.7.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/config.d.ts +19 -2
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +1 -1
- package/dist/api/context.d.ts +3 -3
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +1 -1
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +4 -8
- package/dist/api/index.d.ts +0 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -3
- package/dist/api/sonamu.d.ts +5 -3
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +10 -8
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/storage/drivers.d.ts +14 -0
- package/dist/storage/drivers.d.ts.map +1 -0
- package/dist/storage/drivers.js +11 -0
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +6 -0
- package/dist/storage/storage-manager.d.ts +21 -0
- package/dist/storage/storage-manager.d.ts.map +1 -0
- package/dist/storage/storage-manager.js +33 -0
- package/dist/storage/types.d.ts +12 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +5 -0
- package/dist/storage/uploaded-file.d.ts +35 -0
- package/dist/storage/uploaded-file.d.ts.map +1 -0
- package/dist/storage/uploaded-file.js +58 -0
- package/dist/template/implementations/services.template.js +5 -5
- package/package.json +7 -2
- package/src/api/config.ts +19 -2
- package/src/api/context.ts +3 -3
- package/src/api/decorators.ts +3 -8
- package/src/api/index.ts +0 -2
- package/src/api/sonamu.ts +12 -9
- package/src/index.ts +0 -1
- package/src/storage/drivers.ts +15 -0
- package/src/storage/index.ts +5 -0
- package/src/storage/storage-manager.ts +39 -0
- package/src/storage/types.ts +12 -0
- package/src/storage/uploaded-file.ts +81 -0
- package/src/template/implementations/service.template.ts.txt +328 -0
- package/src/template/implementations/services.template.ts +4 -4
- package/dist/file-storage/driver.d.ts +0 -48
- package/dist/file-storage/driver.d.ts.map +0 -1
- package/dist/file-storage/driver.js +0 -79
- package/dist/file-storage/file-storage.d.ts +0 -50
- package/dist/file-storage/file-storage.d.ts.map +0 -1
- package/dist/file-storage/file-storage.js +0 -75
- package/src/file-storage/driver.ts +0 -131
- package/src/file-storage/file-storage.ts +0 -100
|
@@ -36,19 +36,19 @@ export class Template__services extends Template {
|
|
|
36
36
|
// @stream 데코레이터가 있으면 SSE 스트림 함수 생성
|
|
37
37
|
if (api.streamOptions) {
|
|
38
38
|
const paramsWithoutContext = api.parameters.filter((param)=>!ApiParamType.isContext(param.type) && !ApiParamType.isRefKnex(param.type) && !(param.optional === true && param.name.startsWith("_")));
|
|
39
|
-
const paramsDef = apiParamToTsCode(paramsWithoutContext, importKeys);
|
|
40
39
|
const apiBaseUrl = `${Sonamu.config.api.route.prefix}${api.path}`;
|
|
41
40
|
const methodNameStream = api.options.resourceName ? `use${inflection.camelize(api.options.resourceName)}` : `use${inflection.camelize(api.methodName)}`;
|
|
42
41
|
const methodNameStreamCamelized = inflection.camelize(methodNameStream, true);
|
|
43
42
|
const eventsTypeDef = zodTypeToTsTypeDef(api.streamOptions.events);
|
|
44
|
-
|
|
43
|
+
// 파라미터를 객체 형태로 정의 (타입과 실제 값 모두에 사용)
|
|
44
|
+
const paramsDefAsObject = paramsWithoutContext.length > 0 ? `{ ${paramsWithoutContext.map((p)=>`${p.name}: ${apiParamTypeToTsType(p.type, importKeys)}`).join(", ")} }` : "{}";
|
|
45
45
|
functions.push(`
|
|
46
46
|
export function ${methodNameStreamCamelized}(
|
|
47
|
-
params: ${
|
|
47
|
+
params: ${paramsDefAsObject},
|
|
48
48
|
handlers: EventHandlers<${eventsTypeDef} & { end?: () => void }>,
|
|
49
49
|
options: SSEStreamOptions
|
|
50
50
|
) {
|
|
51
|
-
return useSSEStream<${eventsTypeDef}>(\`${apiBaseUrl}\`,
|
|
51
|
+
return useSSEStream<${eventsTypeDef}>(\`${apiBaseUrl}\`, params, handlers, options);
|
|
52
52
|
}
|
|
53
53
|
`.trim());
|
|
54
54
|
continue;
|
|
@@ -177,4 +177,4 @@ ${functions.join("\n\n")}
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90ZW1wbGF0ZS9pbXBsZW1lbnRhdGlvbnMvc2VydmljZXMudGVtcGxhdGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGluZmxlY3Rpb24gZnJvbSBcImluZmxlY3Rpb25cIjtcbmltcG9ydCB7IGRpZmYsIHVuaXF1ZSB9IGZyb20gXCJyYWRhc2hpXCI7XG5pbXBvcnQge1xuICBhcGlQYXJhbVRvVHNDb2RlLFxuICBhcGlQYXJhbVR5cGVUb1RzVHlwZSxcbiAgdW53cmFwUHJvbWlzZU9uY2UsXG59IGZyb20gXCIuLi8uLi9hcGkvY29kZS1jb252ZXJ0ZXJzXCI7XG5pbXBvcnQgdHlwZSB7IEV4dGVuZGVkQXBpIH0gZnJvbSBcIi4uLy4uL2FwaS9kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vLi4vYXBpL3NvbmFtdVwiO1xuaW1wb3J0IHR5cGUgeyBUZW1wbGF0ZU9wdGlvbnMgfSBmcm9tIFwiLi4vLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IEFwaVBhcmFtVHlwZSB9IGZyb20gXCIuLi8uLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgYXNzZXJ0RGVmaW5lZCB9IGZyb20gXCIuLi8uLi91dGlscy91dGlsc1wiO1xuaW1wb3J0IHsgVGVtcGxhdGUgfSBmcm9tIFwiLi4vdGVtcGxhdGVcIjtcbmltcG9ydCB7IHpvZFR5cGVUb1RzVHlwZURlZiB9IGZyb20gXCIuLi96b2QtY29udmVydGVyXCI7XG5cbmV4cG9ydCBjbGFzcyBUZW1wbGF0ZV9fc2VydmljZXMgZXh0ZW5kcyBUZW1wbGF0ZSB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKFwic2VydmljZXNcIik7XG4gIH1cblxuICBnZXRUYXJnZXRBbmRQYXRoKCkge1xuICAgIHJldHVybiB7XG4gICAgICB0YXJnZXQ6IFwiOnRhcmdldC9zcmMvc2VydmljZXNcIixcbiAgICAgIHBhdGg6IGBzZXJ2aWNlcy5nZW5lcmF0ZWQudHNgLFxuICAgIH07XG4gIH1cblxuICByZW5kZXIoe306IFRlbXBsYXRlT3B0aW9uc1tcInNlcnZpY2VzXCJdKSB7XG4gICAgY29uc3QgeyBhcGlzIH0gPSBTb25hbXUuc3luY2VyO1xuXG4gICAgLy8g66qo642467OE66GcIOq3uOujue2ZlFxuICAgIGNvbnN0IGFwaXNCeU1vZGVsID0gbmV3IE1hcDxzdHJpbmcsIEV4dGVuZGVkQXBpW10+KCk7XG4gICAgZm9yIChjb25zdCBhcGkgb2YgYXBpcykge1xuICAgICAgY29uc3QgbW9kZWxOYW1lID0gYXBpLm1vZGVsTmFtZS5yZXBsYWNlKC9Nb2RlbCQvLCBcIlwiKS5yZXBsYWNlKC9GcmFtZSQvLCBcIlwiKTtcbiAgICAgIGlmICghYXBpc0J5TW9kZWwuaGFzKG1vZGVsTmFtZSkpIHtcbiAgICAgICAgYXBpc0J5TW9kZWwuc2V0KG1vZGVsTmFtZSwgW10pO1xuICAgICAgfVxuICAgICAgYXBpc0J5TW9kZWwuZ2V0KG1vZGVsTmFtZSk/LnB1c2goYXBpKTtcbiAgICB9XG5cbiAgICBjb25zdCBpbXBvcnRLZXlzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IG5hbWVzcGFjZXM6IHN0cmluZ1tdID0gW107XG4gICAgbGV0IHR5cGVQYXJhbU5hbWVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBbbW9kZWxOYW1lLCBtb2RlbEFwaXNdIG9mIGFwaXNCeU1vZGVsKSB7XG4gICAgICBjb25zdCBmdW5jdGlvbnM6IHN0cmluZ1tdID0gW107XG5cbiAgICAgIGZvciAoY29uc3QgYXBpIG9mIG1vZGVsQXBpcykge1xuICAgICAgICAvLyBAc3RyZWFtIOuNsOy9lOugiOydtO2EsOqwgCDsnojsnLzrqbQgU1NFIOyKpO2KuOumvCDtlajsiJgg7IOd7ISxXG4gICAgICAgIGlmIChhcGkuc3RyZWFtT3B0aW9ucykge1xuICAgICAgICAgIGNvbnN0IHBhcmFtc1dpdGhvdXRDb250ZXh0ID0gYXBpLnBhcmFtZXRlcnMuZmlsdGVyKFxuICAgICAgICAgICAgKHBhcmFtKSA9PlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzUmVmS25leChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhKHBhcmFtLm9wdGlvbmFsID09PSB0cnVlICYmIHBhcmFtLm5hbWUuc3RhcnRzV2l0aChcIl9cIikpLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBjb25zdCBwYXJhbXNEZWYgPSBhcGlQYXJhbVRvVHNDb2RlKHBhcmFtc1dpdGhvdXRDb250ZXh0LCBpbXBvcnRLZXlzKTtcbiAgICAgICAgICBjb25zdCBhcGlCYXNlVXJsID0gYCR7U29uYW11LmNvbmZpZy5hcGkucm91dGUucHJlZml4fSR7YXBpLnBhdGh9YDtcblxuICAgICAgICAgIGNvbnN0IG1ldGhvZE5hbWVTdHJlYW0gPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICAgID8gYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUpfWBcbiAgICAgICAgICAgIDogYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSl9YDtcbiAgICAgICAgICBjb25zdCBtZXRob2ROYW1lU3RyZWFtQ2FtZWxpemVkID0gaW5mbGVjdGlvbi5jYW1lbGl6ZShtZXRob2ROYW1lU3RyZWFtLCB0cnVlKTtcblxuICAgICAgICAgIGNvbnN0IGV2ZW50c1R5cGVEZWYgPSB6b2RUeXBlVG9Uc1R5cGVEZWYoYXBpLnN0cmVhbU9wdGlvbnMuZXZlbnRzKTtcblxuICAgICAgICAgIGNvbnN0IHBhcmFtc0RlZkFzT2JqZWN0ID1cbiAgICAgICAgICAgIHBhcmFtc1dpdGhvdXRDb250ZXh0Lmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgPyBgeyAke3BhcmFtc1dpdGhvdXRDb250ZXh0Lm1hcCgocCkgPT4gcC5uYW1lKS5qb2luKFwiLCBcIil9IH1gXG4gICAgICAgICAgICAgIDogXCJ7fVwiO1xuXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgZnVuY3Rpb24gJHttZXRob2ROYW1lU3RyZWFtQ2FtZWxpemVkfShcbiAgcGFyYW1zOiAke3BhcmFtc0RlZiA/IGB7ICR7cGFyYW1zV2l0aG91dENvbnRleHQubWFwKChwKSA9PiBgJHtwLm5hbWV9OiAke2FwaVBhcmFtVHlwZVRvVHNUeXBlKHAudHlwZSwgaW1wb3J0S2V5cyl9YCkuam9pbihcIiwgXCIpfSB9YCA6IFwie31cIn0sXG4gIGhhbmRsZXJzOiBFdmVudEhhbmRsZXJzPCR7ZXZlbnRzVHlwZURlZn0gJiB7IGVuZD86ICgpID0+IHZvaWQgfT4sXG4gIG9wdGlvbnM6IFNTRVN0cmVhbU9wdGlvbnNcbikge1xuICByZXR1cm4gdXNlU1NFU3RyZWFtPCR7ZXZlbnRzVHlwZURlZn0+KFxcYCR7YXBpQmFzZVVybH1cXGAsICR7cGFyYW1zRGVmQXNPYmplY3R9LCBoYW5kbGVycywgb3B0aW9ucyk7XG59XG4gICAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29udGV4dCDsoJzsmbjtlZwg7YyM652866+47YSwXG4gICAgICAgIGNvbnN0IHBhcmFtc1dpdGhvdXRDb250ZXh0ID0gYXBpLnBhcmFtZXRlcnMuZmlsdGVyKFxuICAgICAgICAgIChwYXJhbSkgPT5cbiAgICAgICAgICAgICFBcGlQYXJhbVR5cGUuaXNDb250ZXh0KHBhcmFtLnR5cGUpICYmXG4gICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzUmVmS25leChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgIShwYXJhbS5vcHRpb25hbCA9PT0gdHJ1ZSAmJiBwYXJhbS5uYW1lLnN0YXJ0c1dpdGgoXCJfXCIpKSxcbiAgICAgICAgKTtcblxuICAgICAgICAvLyDtg4DsnoUg7YyM652866+47YSwIOygleydmFxuICAgICAgICBjb25zdCB0eXBlUGFyYW1ldGVyc0FzVHNUeXBlID0gYXBpLnR5cGVQYXJhbWV0ZXJzXG4gICAgICAgICAgLm1hcCgodHlwZVBhcmFtKSA9PiBhcGlQYXJhbVR5cGVUb1RzVHlwZSh0eXBlUGFyYW0sIGltcG9ydEtleXMpKVxuICAgICAgICAgIC5qb2luKFwiLCBcIik7XG4gICAgICAgIGNvbnN0IHR5cGVQYXJhbXNEZWYgPSB0eXBlUGFyYW1ldGVyc0FzVHNUeXBlID8gYDwke3R5cGVQYXJhbWV0ZXJzQXNUc1R5cGV9PmAgOiBcIlwiO1xuICAgICAgICB0eXBlUGFyYW1OYW1lcyA9IHR5cGVQYXJhbU5hbWVzLmNvbmNhdChhcGkudHlwZVBhcmFtZXRlcnMubWFwKCh0cCkgPT4gdHAuaWQpKTtcblxuICAgICAgICAvLyDtjIzrnbzrr7jthLAg7KCV7J2YXG4gICAgICAgIGNvbnN0IHBhcmFtc0RlZiA9IGFwaVBhcmFtVG9Uc0NvZGUocGFyYW1zV2l0aG91dENvbnRleHQsIGltcG9ydEtleXMpO1xuICAgICAgICBjb25zdCBwYXJhbU5hbWVzID0gcGFyYW1zV2l0aG91dENvbnRleHQubWFwKChwKSA9PiBwLm5hbWUpLmpvaW4oXCIsIFwiKTtcblxuICAgICAgICAvLyDrpqzthLQg7YOA7J6FIOygleydmFxuICAgICAgICBjb25zdCByZXR1cm5UeXBlRGVmID0gYXBpUGFyYW1UeXBlVG9Uc1R5cGUoXG4gICAgICAgICAgYXNzZXJ0RGVmaW5lZCh1bndyYXBQcm9taXNlT25jZShhcGkucmV0dXJuVHlwZSkpLFxuICAgICAgICAgIGltcG9ydEtleXMsXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8g6riw67O4IFVSTFxuICAgICAgICBjb25zdCBhcGlCYXNlVXJsID0gYCR7U29uYW11LmNvbmZpZy5hcGkucm91dGUucHJlZml4fSR7YXBpLnBhdGh9YDtcblxuICAgICAgICBjb25zdCBjbGllbnRzID0gYXBpLm9wdGlvbnMuY2xpZW50cyB8fCBbXTtcblxuICAgICAgICAvLyAxLiBheGlvcyDtlajsiJgg7IOd7ISxXG4gICAgICAgIC8vIHJlc291cmNlTmFtZeydtCDsnojsnLzrqbQgZ2V0ICsgcmVzb3VyY2VOYW1lIO2Yle2DnOuhnCDtlajsiJjrqoUg7IOd7ISxXG4gICAgICAgIGNvbnN0IG1ldGhvZE5hbWUgPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICA/IGBnZXQke2luZmxlY3Rpb24uY2FtZWxpemUoYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lKX1gXG4gICAgICAgICAgOiBhcGkubWV0aG9kTmFtZTtcblxuICAgICAgICAvLyBheGlvcy1tdWx0aXBhcnQg7LKY66asICjtjIzsnbwg7JeF66Gc65OcKVxuICAgICAgICBpZiAoY2xpZW50cy5pbmNsdWRlcyhcImF4aW9zLW11bHRpcGFydFwiKSkge1xuICAgICAgICAgIGNvbnN0IGlzTXVsdGlwbGUgPSBhcGkudXBsb2FkT3B0aW9ucz8ubW9kZSA9PT0gXCJtdWx0aXBsZVwiO1xuICAgICAgICAgIGNvbnN0IGZpbGVQYXJhbU5hbWUgPSBpc011bHRpcGxlID8gXCJmaWxlc1wiIDogXCJmaWxlXCI7XG4gICAgICAgICAgY29uc3QgZmlsZVBhcmFtVHlwZSA9IGlzTXVsdGlwbGUgPyBcIkZpbGVbXVwiIDogXCJGaWxlXCI7XG5cbiAgICAgICAgICBjb25zdCBmb3JtRGF0YUFwcGVuZCA9IGlzTXVsdGlwbGVcbiAgICAgICAgICAgID8gYCR7ZmlsZVBhcmFtTmFtZX0uZm9yRWFjaChmID0+IHsgZm9ybURhdGEuYXBwZW5kKFwiJHtmaWxlUGFyYW1OYW1lfVwiLCBmKTsgfSk7YFxuICAgICAgICAgICAgOiBgZm9ybURhdGEuYXBwZW5kKFwiJHtmaWxlUGFyYW1OYW1lfVwiLCAke2ZpbGVQYXJhbU5hbWV9KTtgO1xuXG4gICAgICAgICAgY29uc3Qgb3RoZXJQYXJhbXNBcHBlbmQgPSBwYXJhbXNXaXRob3V0Q29udGV4dFxuICAgICAgICAgICAgLm1hcCgocGFyYW0pID0+IGBmb3JtRGF0YS5hcHBlbmQoJyR7cGFyYW0ubmFtZX0nLCBTdHJpbmcoJHtwYXJhbS5uYW1lfSkpO2ApXG4gICAgICAgICAgICAuam9pbihcIlxcbiAgICBcIik7XG5cbiAgICAgICAgICBjb25zdCBwYXJhbXNEZWZDb21tYSA9IHBhcmFtc0RlZiAhPT0gXCJcIiA/IFwiLCBcIiA6IFwiXCI7XG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHttZXRob2ROYW1lfSR7dHlwZVBhcmFtc0RlZn0oXG4gICR7cGFyYW1zRGVmfSR7cGFyYW1zRGVmQ29tbWF9XG4gICR7ZmlsZVBhcmFtTmFtZX06ICR7ZmlsZVBhcmFtVHlwZX0sXG4gIG9uVXBsb2FkUHJvZ3Jlc3M/OiAocGU6IEF4aW9zUHJvZ3Jlc3NFdmVudCkgPT4gdm9pZFxuKTogUHJvbWlzZTwke3JldHVyblR5cGVEZWZ9PiB7XG4gIGNvbnN0IGZvcm1EYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICR7Zm9ybURhdGFBcHBlbmR9XG4gICR7b3RoZXJQYXJhbXNBcHBlbmR9XG4gIHJldHVybiBmZXRjaCh7XG4gICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgdXJsOiBcXGAke2FwaUJhc2VVcmx9XFxgLFxuICAgIGhlYWRlcnM6IHtcbiAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwibXVsdGlwYXJ0L2Zvcm0tZGF0YVwiLFxuICAgIH0sXG4gICAgb25VcGxvYWRQcm9ncmVzcyxcbiAgICBkYXRhOiBmb3JtRGF0YSxcbiAgICAke2FwaS5vcHRpb25zLnRpbWVvdXQgPyBgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pLGAgOiBcIlwifVxuICB9KTtcbn1cbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2UgaWYgKGFwaS5vcHRpb25zLmh0dHBNZXRob2QgPT09IFwiR0VUXCIpIHtcbiAgICAgICAgICBjb25zdCBoYXNQYXJhbXMgPSBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwO1xuICAgICAgICAgIGZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICAgICAgYFxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uICR7bWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSk6IFByb21pc2U8JHtyZXR1cm5UeXBlRGVmfT4ge1xuICByZXR1cm4gZmV0Y2goe1xuICAgIG1ldGhvZDogXCJHRVRcIixcbiAgICB1cmw6IFxcYCR7YXBpQmFzZVVybH0ke2hhc1BhcmFtcyA/IGA/XFwke3FzLnN0cmluZ2lmeSh7ICR7cGFyYW1OYW1lc30gfSl9YCA6IFwiXCJ9XFxgLFxuICAgICR7YXBpLm9wdGlvbnMudGltZW91dCA/IGBzaWduYWw6IEFib3J0U2lnbmFsLnRpbWVvdXQoJHthcGkub3B0aW9ucy50aW1lb3V0fSksYCA6IFwiXCJ9XG4gIH0pO1xufVxuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgaGFzUGFyYW1zID0gcGFyYW1zV2l0aG91dENvbnRleHQubGVuZ3RoID4gMDtcbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiAke21ldGhvZE5hbWV9JHt0eXBlUGFyYW1zRGVmfSgke3BhcmFtc0RlZn0pOiBQcm9taXNlPCR7cmV0dXJuVHlwZURlZn0+IHtcbiAgcmV0dXJuIGZldGNoKHtcbiAgICBtZXRob2Q6IFwiJHthcGkub3B0aW9ucy5odHRwTWV0aG9kfVwiLFxuICAgIHVybDogXFxgJHthcGlCYXNlVXJsfVxcYCxcbiAgICAke2hhc1BhcmFtcyA/IGBkYXRhOiB7ICR7cGFyYW1OYW1lc30gfSxgIDogXCJcIn1cbiAgICAke2FwaS5vcHRpb25zLnRpbWVvdXQgPyBgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pLGAgOiBcIlwifVxuICB9KTtcbn1cbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gMi4gcXVlcnlPcHRpb25zICsgdXNlUXVlcnkgKHRhbnN0YWNrLXF1ZXJ5KVxuICAgICAgICBpZiAoY2xpZW50cy5pbmNsdWRlcyhcInRhbnN0YWNrLXF1ZXJ5XCIpKSB7XG4gICAgICAgICAgY29uc3QgaG9va05hbWUgPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICAgID8gaW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUsIHRydWUpXG4gICAgICAgICAgICA6IGluZmxlY3Rpb24uY2FtZWxpemUoYXBpLm1ldGhvZE5hbWUsIHRydWUpO1xuXG4gICAgICAgICAgLy8gcXVlcnlPcHRpb25zXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgY29uc3QgJHttZXRob2ROYW1lfVF1ZXJ5T3B0aW9ucyA9ICR7dHlwZVBhcmFtc0RlZn0oJHtwYXJhbXNEZWZ9KSA9PiBxdWVyeU9wdGlvbnMoe1xuICBxdWVyeUtleTogWycke21vZGVsTmFtZX0nLCAnJHttZXRob2ROYW1lfScke3BhcmFtTmFtZXMgPyBgLCAke3BhcmFtTmFtZXN9YCA6IFwiXCJ9XSxcbiAgcXVlcnlGbjogKCkgPT4gJHttZXRob2ROYW1lfSgke3BhcmFtTmFtZXN9KVxufSk7XG4gICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIHVzZVF1ZXJ5IGhvb2tcbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCB1c2Uke2luZmxlY3Rpb24uY2FtZWxpemUoaG9va05hbWUpfSA9ICR7dHlwZVBhcmFtc0RlZn0oJHtwYXJhbXNEZWZ9JHtcbiAgICAgICAgICAgICAgcGFyYW1zRGVmID8gXCIsIFwiIDogXCJcIlxuICAgICAgICAgICAgfW9wdGlvbnM/OiB7IGVuYWJsZWQ/OiBib29sZWFuIH0pID0+XG4gIHVzZVF1ZXJ5KHtcbiAgICAuLi4ke21ldGhvZE5hbWV9UXVlcnlPcHRpb25zKCR7cGFyYW1OYW1lc30pLFxuICAgIC4uLm9wdGlvbnNcbiAgfSk7XG4gICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDMuIHVzZU11dGF0aW9uICh0YW5zdGFjay1tdXRhdGlvbilcbiAgICAgICAgaWYgKGNsaWVudHMuaW5jbHVkZXMoXCJ0YW5zdGFjay1tdXRhdGlvblwiKSkge1xuICAgICAgICAgIGNvbnN0IGhvb2tOYW1lID0gaW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSk7XG4gICAgICAgICAgY29uc3QgbXV0YXRpb25QYXJhbVR5cGUgPVxuICAgICAgICAgICAgcGFyYW1zV2l0aG91dENvbnRleHQubGVuZ3RoID4gMFxuICAgICAgICAgICAgICA/IGB7ICR7cGFyYW1zV2l0aG91dENvbnRleHRcbiAgICAgICAgICAgICAgICAgIC5tYXAoKHApID0+IGAke3AubmFtZX06ICR7YXBpUGFyYW1UeXBlVG9Uc1R5cGUocC50eXBlLCBbXSl9YClcbiAgICAgICAgICAgICAgICAgIC5qb2luKFwiLCBcIil9IH1gXG4gICAgICAgICAgICAgIDogXCJ2b2lkXCI7XG4gICAgICAgICAgY29uc3QgbXV0YXRpb25QYXJhbU5hbWVzID1cbiAgICAgICAgICAgIHBhcmFtc1dpdGhvdXRDb250ZXh0Lmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgPyBwYXJhbXNXaXRob3V0Q29udGV4dC5tYXAoKHApID0+IGBwYXJhbXMuJHtwLm5hbWV9YCkuam9pbihcIiwgXCIpXG4gICAgICAgICAgICAgIDogXCJcIjtcblxuICAgICAgICAgIGZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICAgICAgYFxuZXhwb3J0IGNvbnN0IHVzZSR7aG9va05hbWV9TXV0YXRpb24gPSAke3R5cGVQYXJhbXNEZWZ9KCkgPT4gdXNlTXV0YXRpb24oe1xuICBtdXRhdGlvbkZuOiAocGFyYW1zOiAke211dGF0aW9uUGFyYW1UeXBlfSkgPT4gJHttZXRob2ROYW1lfSgke211dGF0aW9uUGFyYW1OYW1lc30pXG59KTtcbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIG5hbWVzcGFjZXMucHVzaChcbiAgICAgICAgYFxuZXhwb3J0IG5hbWVzcGFjZSAke21vZGVsTmFtZX1TZXJ2aWNlIHtcbiR7ZnVuY3Rpb25zLmpvaW4oXCJcXG5cXG5cIil9XG59XG4gICAgICBgLnRyaW0oKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnRoaXMuZ2V0VGFyZ2V0QW5kUGF0aCgpLFxuICAgICAgYm9keTogbmFtZXNwYWNlcy5qb2luKFwiXFxuXFxuXCIpLFxuICAgICAgaW1wb3J0S2V5czogZGlmZih1bmlxdWUoaW1wb3J0S2V5cyksIFsuLi50eXBlUGFyYW1OYW1lcywgXCJMaXN0UmVzdWx0XCJdKSxcbiAgICAgIGN1c3RvbUhlYWRlcnM6IFtcbiAgICAgICAgYGltcG9ydCB7IHF1ZXJ5T3B0aW9ucywgdXNlUXVlcnksIHVzZU11dGF0aW9uIH0gZnJvbSAnQHRhbnN0YWNrL3JlYWN0LXF1ZXJ5JztgLFxuICAgICAgICBgaW1wb3J0IHR5cGUgeyBBeGlvc1Byb2dyZXNzRXZlbnQgfSBmcm9tICdheGlvcyc7YCxcbiAgICAgICAgYGltcG9ydCBxcyBmcm9tICdxcyc7YCxcbiAgICAgICAgYGltcG9ydCB7IHR5cGUgTGlzdFJlc3VsdCwgZmV0Y2gsIHR5cGUgRXZlbnRIYW5kbGVycywgdHlwZSBTU0VTdHJlYW1PcHRpb25zLCB1c2VTU0VTdHJlYW0gfSBmcm9tICcuL3NvbmFtdS5zaGFyZWQnO2AsXG4gICAgICBdLFxuICAgIH07XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJpbmZsZWN0aW9uIiwiZGlmZiIsInVuaXF1ZSIsImFwaVBhcmFtVG9Uc0NvZGUiLCJhcGlQYXJhbVR5cGVUb1RzVHlwZSIsInVud3JhcFByb21pc2VPbmNlIiwiU29uYW11IiwiQXBpUGFyYW1UeXBlIiwiYXNzZXJ0RGVmaW5lZCIsIlRlbXBsYXRlIiwiem9kVHlwZVRvVHNUeXBlRGVmIiwiVGVtcGxhdGVfX3NlcnZpY2VzIiwiZ2V0VGFyZ2V0QW5kUGF0aCIsInRhcmdldCIsInBhdGgiLCJyZW5kZXIiLCJhcGlzIiwic3luY2VyIiwiYXBpc0J5TW9kZWwiLCJNYXAiLCJhcGkiLCJtb2RlbE5hbWUiLCJyZXBsYWNlIiwiaGFzIiwic2V0IiwiZ2V0IiwicHVzaCIsImltcG9ydEtleXMiLCJuYW1lc3BhY2VzIiwidHlwZVBhcmFtTmFtZXMiLCJtb2RlbEFwaXMiLCJmdW5jdGlvbnMiLCJzdHJlYW1PcHRpb25zIiwicGFyYW1zV2l0aG91dENvbnRleHQiLCJwYXJhbWV0ZXJzIiwiZmlsdGVyIiwicGFyYW0iLCJpc0NvbnRleHQiLCJ0eXBlIiwiaXNSZWZLbmV4Iiwib3B0aW9uYWwiLCJuYW1lIiwic3RhcnRzV2l0aCIsInBhcmFtc0RlZiIsImFwaUJhc2VVcmwiLCJjb25maWciLCJyb3V0ZSIsInByZWZpeCIsIm1ldGhvZE5hbWVTdHJlYW0iLCJvcHRpb25zIiwicmVzb3VyY2VOYW1lIiwiY2FtZWxpemUiLCJtZXRob2ROYW1lIiwibWV0aG9kTmFtZVN0cmVhbUNhbWVsaXplZCIsImV2ZW50c1R5cGVEZWYiLCJldmVudHMiLCJwYXJhbXNEZWZBc09iamVjdCIsImxlbmd0aCIsIm1hcCIsInAiLCJqb2luIiwidHJpbSIsInR5cGVQYXJhbWV0ZXJzQXNUc1R5cGUiLCJ0eXBlUGFyYW1ldGVycyIsInR5cGVQYXJhbSIsInR5cGVQYXJhbXNEZWYiLCJjb25jYXQiLCJ0cCIsImlkIiwicGFyYW1OYW1lcyIsInJldHVyblR5cGVEZWYiLCJyZXR1cm5UeXBlIiwiY2xpZW50cyIsImluY2x1ZGVzIiwiaXNNdWx0aXBsZSIsInVwbG9hZE9wdGlvbnMiLCJtb2RlIiwiZmlsZVBhcmFtTmFtZSIsImZpbGVQYXJhbVR5cGUiLCJmb3JtRGF0YUFwcGVuZCIsIm90aGVyUGFyYW1zQXBwZW5kIiwicGFyYW1zRGVmQ29tbWEiLCJ0aW1lb3V0IiwiaHR0cE1ldGhvZCIsImhhc1BhcmFtcyIsImhvb2tOYW1lIiwibXV0YXRpb25QYXJhbVR5cGUiLCJtdXRhdGlvblBhcmFtTmFtZXMiLCJib2R5IiwiY3VzdG9tSGVhZGVycyJdLCJtYXBwaW5ncyI6IkFBQUEsT0FBT0EsZ0JBQWdCLGFBQWE7QUFDcEMsU0FBU0MsSUFBSSxFQUFFQyxNQUFNLFFBQVEsVUFBVTtBQUN2QyxTQUNFQyxnQkFBZ0IsRUFDaEJDLG9CQUFvQixFQUNwQkMsaUJBQWlCLFFBQ1osK0JBQTRCO0FBRW5DLFNBQVNDLE1BQU0sUUFBUSxzQkFBbUI7QUFFMUMsU0FBU0MsWUFBWSxRQUFRLHVCQUFvQjtBQUNqRCxTQUFTQyxhQUFhLFFBQVEsdUJBQW9CO0FBQ2xELFNBQVNDLFFBQVEsUUFBUSxpQkFBYztBQUN2QyxTQUFTQyxrQkFBa0IsUUFBUSxzQkFBbUI7QUFFdEQsT0FBTyxNQUFNQywyQkFBMkJGO0lBQ3RDLGFBQWM7UUFDWixLQUFLLENBQUM7SUFDUjtJQUVBRyxtQkFBbUI7UUFDakIsT0FBTztZQUNMQyxRQUFRO1lBQ1JDLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQztRQUMvQjtJQUNGO0lBRUFDLE9BQU8sRUFBK0IsRUFBRTtRQUN0QyxNQUFNLEVBQUVDLElBQUksRUFBRSxHQUFHVixPQUFPVyxNQUFNO1FBRTlCLFdBQVc7UUFDWCxNQUFNQyxjQUFjLElBQUlDO1FBQ3hCLEtBQUssTUFBTUMsT0FBT0osS0FBTTtZQUN0QixNQUFNSyxZQUFZRCxJQUFJQyxTQUFTLENBQUNDLE9BQU8sQ0FBQyxVQUFVLElBQUlBLE9BQU8sQ0FBQyxVQUFVO1lBQ3hFLElBQUksQ0FBQ0osWUFBWUssR0FBRyxDQUFDRixZQUFZO2dCQUMvQkgsWUFBWU0sR0FBRyxDQUFDSCxXQUFXLEVBQUU7WUFDL0I7WUFDQUgsWUFBWU8sR0FBRyxDQUFDSixZQUFZSyxLQUFLTjtRQUNuQztRQUVBLE1BQU1PLGFBQXVCLEVBQUU7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
|
|
180
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90ZW1wbGF0ZS9pbXBsZW1lbnRhdGlvbnMvc2VydmljZXMudGVtcGxhdGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGluZmxlY3Rpb24gZnJvbSBcImluZmxlY3Rpb25cIjtcbmltcG9ydCB7IGRpZmYsIHVuaXF1ZSB9IGZyb20gXCJyYWRhc2hpXCI7XG5pbXBvcnQge1xuICBhcGlQYXJhbVRvVHNDb2RlLFxuICBhcGlQYXJhbVR5cGVUb1RzVHlwZSxcbiAgdW53cmFwUHJvbWlzZU9uY2UsXG59IGZyb20gXCIuLi8uLi9hcGkvY29kZS1jb252ZXJ0ZXJzXCI7XG5pbXBvcnQgdHlwZSB7IEV4dGVuZGVkQXBpIH0gZnJvbSBcIi4uLy4uL2FwaS9kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vLi4vYXBpL3NvbmFtdVwiO1xuaW1wb3J0IHR5cGUgeyBUZW1wbGF0ZU9wdGlvbnMgfSBmcm9tIFwiLi4vLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IEFwaVBhcmFtVHlwZSB9IGZyb20gXCIuLi8uLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgYXNzZXJ0RGVmaW5lZCB9IGZyb20gXCIuLi8uLi91dGlscy91dGlsc1wiO1xuaW1wb3J0IHsgVGVtcGxhdGUgfSBmcm9tIFwiLi4vdGVtcGxhdGVcIjtcbmltcG9ydCB7IHpvZFR5cGVUb1RzVHlwZURlZiB9IGZyb20gXCIuLi96b2QtY29udmVydGVyXCI7XG5cbmV4cG9ydCBjbGFzcyBUZW1wbGF0ZV9fc2VydmljZXMgZXh0ZW5kcyBUZW1wbGF0ZSB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKFwic2VydmljZXNcIik7XG4gIH1cblxuICBnZXRUYXJnZXRBbmRQYXRoKCkge1xuICAgIHJldHVybiB7XG4gICAgICB0YXJnZXQ6IFwiOnRhcmdldC9zcmMvc2VydmljZXNcIixcbiAgICAgIHBhdGg6IGBzZXJ2aWNlcy5nZW5lcmF0ZWQudHNgLFxuICAgIH07XG4gIH1cblxuICByZW5kZXIoe306IFRlbXBsYXRlT3B0aW9uc1tcInNlcnZpY2VzXCJdKSB7XG4gICAgY29uc3QgeyBhcGlzIH0gPSBTb25hbXUuc3luY2VyO1xuXG4gICAgLy8g66qo642467OE66GcIOq3uOujue2ZlFxuICAgIGNvbnN0IGFwaXNCeU1vZGVsID0gbmV3IE1hcDxzdHJpbmcsIEV4dGVuZGVkQXBpW10+KCk7XG4gICAgZm9yIChjb25zdCBhcGkgb2YgYXBpcykge1xuICAgICAgY29uc3QgbW9kZWxOYW1lID0gYXBpLm1vZGVsTmFtZS5yZXBsYWNlKC9Nb2RlbCQvLCBcIlwiKS5yZXBsYWNlKC9GcmFtZSQvLCBcIlwiKTtcbiAgICAgIGlmICghYXBpc0J5TW9kZWwuaGFzKG1vZGVsTmFtZSkpIHtcbiAgICAgICAgYXBpc0J5TW9kZWwuc2V0KG1vZGVsTmFtZSwgW10pO1xuICAgICAgfVxuICAgICAgYXBpc0J5TW9kZWwuZ2V0KG1vZGVsTmFtZSk/LnB1c2goYXBpKTtcbiAgICB9XG5cbiAgICBjb25zdCBpbXBvcnRLZXlzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IG5hbWVzcGFjZXM6IHN0cmluZ1tdID0gW107XG4gICAgbGV0IHR5cGVQYXJhbU5hbWVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBbbW9kZWxOYW1lLCBtb2RlbEFwaXNdIG9mIGFwaXNCeU1vZGVsKSB7XG4gICAgICBjb25zdCBmdW5jdGlvbnM6IHN0cmluZ1tdID0gW107XG5cbiAgICAgIGZvciAoY29uc3QgYXBpIG9mIG1vZGVsQXBpcykge1xuICAgICAgICAvLyBAc3RyZWFtIOuNsOy9lOugiOydtO2EsOqwgCDsnojsnLzrqbQgU1NFIOyKpO2KuOumvCDtlajsiJgg7IOd7ISxXG4gICAgICAgIGlmIChhcGkuc3RyZWFtT3B0aW9ucykge1xuICAgICAgICAgIGNvbnN0IHBhcmFtc1dpdGhvdXRDb250ZXh0ID0gYXBpLnBhcmFtZXRlcnMuZmlsdGVyKFxuICAgICAgICAgICAgKHBhcmFtKSA9PlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzUmVmS25leChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhKHBhcmFtLm9wdGlvbmFsID09PSB0cnVlICYmIHBhcmFtLm5hbWUuc3RhcnRzV2l0aChcIl9cIikpLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBjb25zdCBhcGlCYXNlVXJsID0gYCR7U29uYW11LmNvbmZpZy5hcGkucm91dGUucHJlZml4fSR7YXBpLnBhdGh9YDtcblxuICAgICAgICAgIGNvbnN0IG1ldGhvZE5hbWVTdHJlYW0gPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICAgID8gYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUpfWBcbiAgICAgICAgICAgIDogYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSl9YDtcbiAgICAgICAgICBjb25zdCBtZXRob2ROYW1lU3RyZWFtQ2FtZWxpemVkID0gaW5mbGVjdGlvbi5jYW1lbGl6ZShtZXRob2ROYW1lU3RyZWFtLCB0cnVlKTtcblxuICAgICAgICAgIGNvbnN0IGV2ZW50c1R5cGVEZWYgPSB6b2RUeXBlVG9Uc1R5cGVEZWYoYXBpLnN0cmVhbU9wdGlvbnMuZXZlbnRzKTtcblxuICAgICAgICAgIC8vIO2MjOudvOuvuO2EsOulvCDqsJ3ssrQg7ZiV7YOc66GcIOygleydmCAo7YOA7J6F6rO8IOyLpOygnCDqsJIg66qo65GQ7JeQIOyCrOyaqSlcbiAgICAgICAgICBjb25zdCBwYXJhbXNEZWZBc09iamVjdCA9XG4gICAgICAgICAgICBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwXG4gICAgICAgICAgICAgID8gYHsgJHtwYXJhbXNXaXRob3V0Q29udGV4dC5tYXAoKHApID0+IGAke3AubmFtZX06ICR7YXBpUGFyYW1UeXBlVG9Uc1R5cGUocC50eXBlLCBpbXBvcnRLZXlzKX1gKS5qb2luKFwiLCBcIil9IH1gXG4gICAgICAgICAgICAgIDogXCJ7fVwiO1xuXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgZnVuY3Rpb24gJHttZXRob2ROYW1lU3RyZWFtQ2FtZWxpemVkfShcbiAgcGFyYW1zOiAke3BhcmFtc0RlZkFzT2JqZWN0fSxcbiAgaGFuZGxlcnM6IEV2ZW50SGFuZGxlcnM8JHtldmVudHNUeXBlRGVmfSAmIHsgZW5kPzogKCkgPT4gdm9pZCB9PixcbiAgb3B0aW9uczogU1NFU3RyZWFtT3B0aW9uc1xuKSB7XG4gIHJldHVybiB1c2VTU0VTdHJlYW08JHtldmVudHNUeXBlRGVmfT4oXFxgJHthcGlCYXNlVXJsfVxcYCwgcGFyYW1zLCBoYW5kbGVycywgb3B0aW9ucyk7XG59XG4gICAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29udGV4dCDsoJzsmbjtlZwg7YyM652866+47YSwXG4gICAgICAgIGNvbnN0IHBhcmFtc1dpdGhvdXRDb250ZXh0ID0gYXBpLnBhcmFtZXRlcnMuZmlsdGVyKFxuICAgICAgICAgIChwYXJhbSkgPT5cbiAgICAgICAgICAgICFBcGlQYXJhbVR5cGUuaXNDb250ZXh0KHBhcmFtLnR5cGUpICYmXG4gICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzUmVmS25leChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgIShwYXJhbS5vcHRpb25hbCA9PT0gdHJ1ZSAmJiBwYXJhbS5uYW1lLnN0YXJ0c1dpdGgoXCJfXCIpKSxcbiAgICAgICAgKTtcblxuICAgICAgICAvLyDtg4DsnoUg7YyM652866+47YSwIOygleydmFxuICAgICAgICBjb25zdCB0eXBlUGFyYW1ldGVyc0FzVHNUeXBlID0gYXBpLnR5cGVQYXJhbWV0ZXJzXG4gICAgICAgICAgLm1hcCgodHlwZVBhcmFtKSA9PiBhcGlQYXJhbVR5cGVUb1RzVHlwZSh0eXBlUGFyYW0sIGltcG9ydEtleXMpKVxuICAgICAgICAgIC5qb2luKFwiLCBcIik7XG4gICAgICAgIGNvbnN0IHR5cGVQYXJhbXNEZWYgPSB0eXBlUGFyYW1ldGVyc0FzVHNUeXBlID8gYDwke3R5cGVQYXJhbWV0ZXJzQXNUc1R5cGV9PmAgOiBcIlwiO1xuICAgICAgICB0eXBlUGFyYW1OYW1lcyA9IHR5cGVQYXJhbU5hbWVzLmNvbmNhdChhcGkudHlwZVBhcmFtZXRlcnMubWFwKCh0cCkgPT4gdHAuaWQpKTtcblxuICAgICAgICAvLyDtjIzrnbzrr7jthLAg7KCV7J2YXG4gICAgICAgIGNvbnN0IHBhcmFtc0RlZiA9IGFwaVBhcmFtVG9Uc0NvZGUocGFyYW1zV2l0aG91dENvbnRleHQsIGltcG9ydEtleXMpO1xuICAgICAgICBjb25zdCBwYXJhbU5hbWVzID0gcGFyYW1zV2l0aG91dENvbnRleHQubWFwKChwKSA9PiBwLm5hbWUpLmpvaW4oXCIsIFwiKTtcblxuICAgICAgICAvLyDrpqzthLQg7YOA7J6FIOygleydmFxuICAgICAgICBjb25zdCByZXR1cm5UeXBlRGVmID0gYXBpUGFyYW1UeXBlVG9Uc1R5cGUoXG4gICAgICAgICAgYXNzZXJ0RGVmaW5lZCh1bndyYXBQcm9taXNlT25jZShhcGkucmV0dXJuVHlwZSkpLFxuICAgICAgICAgIGltcG9ydEtleXMsXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8g6riw67O4IFVSTFxuICAgICAgICBjb25zdCBhcGlCYXNlVXJsID0gYCR7U29uYW11LmNvbmZpZy5hcGkucm91dGUucHJlZml4fSR7YXBpLnBhdGh9YDtcblxuICAgICAgICBjb25zdCBjbGllbnRzID0gYXBpLm9wdGlvbnMuY2xpZW50cyB8fCBbXTtcblxuICAgICAgICAvLyAxLiBheGlvcyDtlajsiJgg7IOd7ISxXG4gICAgICAgIC8vIHJlc291cmNlTmFtZeydtCDsnojsnLzrqbQgZ2V0ICsgcmVzb3VyY2VOYW1lIO2Yle2DnOuhnCDtlajsiJjrqoUg7IOd7ISxXG4gICAgICAgIGNvbnN0IG1ldGhvZE5hbWUgPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICA/IGBnZXQke2luZmxlY3Rpb24uY2FtZWxpemUoYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lKX1gXG4gICAgICAgICAgOiBhcGkubWV0aG9kTmFtZTtcblxuICAgICAgICAvLyBheGlvcy1tdWx0aXBhcnQg7LKY66asICjtjIzsnbwg7JeF66Gc65OcKVxuICAgICAgICBpZiAoY2xpZW50cy5pbmNsdWRlcyhcImF4aW9zLW11bHRpcGFydFwiKSkge1xuICAgICAgICAgIGNvbnN0IGlzTXVsdGlwbGUgPSBhcGkudXBsb2FkT3B0aW9ucz8ubW9kZSA9PT0gXCJtdWx0aXBsZVwiO1xuICAgICAgICAgIGNvbnN0IGZpbGVQYXJhbU5hbWUgPSBpc011bHRpcGxlID8gXCJmaWxlc1wiIDogXCJmaWxlXCI7XG4gICAgICAgICAgY29uc3QgZmlsZVBhcmFtVHlwZSA9IGlzTXVsdGlwbGUgPyBcIkZpbGVbXVwiIDogXCJGaWxlXCI7XG5cbiAgICAgICAgICBjb25zdCBmb3JtRGF0YUFwcGVuZCA9IGlzTXVsdGlwbGVcbiAgICAgICAgICAgID8gYCR7ZmlsZVBhcmFtTmFtZX0uZm9yRWFjaChmID0+IHsgZm9ybURhdGEuYXBwZW5kKFwiJHtmaWxlUGFyYW1OYW1lfVwiLCBmKTsgfSk7YFxuICAgICAgICAgICAgOiBgZm9ybURhdGEuYXBwZW5kKFwiJHtmaWxlUGFyYW1OYW1lfVwiLCAke2ZpbGVQYXJhbU5hbWV9KTtgO1xuXG4gICAgICAgICAgY29uc3Qgb3RoZXJQYXJhbXNBcHBlbmQgPSBwYXJhbXNXaXRob3V0Q29udGV4dFxuICAgICAgICAgICAgLm1hcCgocGFyYW0pID0+IGBmb3JtRGF0YS5hcHBlbmQoJyR7cGFyYW0ubmFtZX0nLCBTdHJpbmcoJHtwYXJhbS5uYW1lfSkpO2ApXG4gICAgICAgICAgICAuam9pbihcIlxcbiAgICBcIik7XG5cbiAgICAgICAgICBjb25zdCBwYXJhbXNEZWZDb21tYSA9IHBhcmFtc0RlZiAhPT0gXCJcIiA/IFwiLCBcIiA6IFwiXCI7XG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHttZXRob2ROYW1lfSR7dHlwZVBhcmFtc0RlZn0oXG4gICR7cGFyYW1zRGVmfSR7cGFyYW1zRGVmQ29tbWF9XG4gICR7ZmlsZVBhcmFtTmFtZX06ICR7ZmlsZVBhcmFtVHlwZX0sXG4gIG9uVXBsb2FkUHJvZ3Jlc3M/OiAocGU6IEF4aW9zUHJvZ3Jlc3NFdmVudCkgPT4gdm9pZFxuKTogUHJvbWlzZTwke3JldHVyblR5cGVEZWZ9PiB7XG4gIGNvbnN0IGZvcm1EYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICR7Zm9ybURhdGFBcHBlbmR9XG4gICR7b3RoZXJQYXJhbXNBcHBlbmR9XG4gIHJldHVybiBmZXRjaCh7XG4gICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgdXJsOiBcXGAke2FwaUJhc2VVcmx9XFxgLFxuICAgIGhlYWRlcnM6IHtcbiAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwibXVsdGlwYXJ0L2Zvcm0tZGF0YVwiLFxuICAgIH0sXG4gICAgb25VcGxvYWRQcm9ncmVzcyxcbiAgICBkYXRhOiBmb3JtRGF0YSxcbiAgICAke2FwaS5vcHRpb25zLnRpbWVvdXQgPyBgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pLGAgOiBcIlwifVxuICB9KTtcbn1cbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2UgaWYgKGFwaS5vcHRpb25zLmh0dHBNZXRob2QgPT09IFwiR0VUXCIpIHtcbiAgICAgICAgICBjb25zdCBoYXNQYXJhbXMgPSBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwO1xuICAgICAgICAgIGZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICAgICAgYFxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uICR7bWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSk6IFByb21pc2U8JHtyZXR1cm5UeXBlRGVmfT4ge1xuICByZXR1cm4gZmV0Y2goe1xuICAgIG1ldGhvZDogXCJHRVRcIixcbiAgICB1cmw6IFxcYCR7YXBpQmFzZVVybH0ke2hhc1BhcmFtcyA/IGA/XFwke3FzLnN0cmluZ2lmeSh7ICR7cGFyYW1OYW1lc30gfSl9YCA6IFwiXCJ9XFxgLFxuICAgICR7YXBpLm9wdGlvbnMudGltZW91dCA/IGBzaWduYWw6IEFib3J0U2lnbmFsLnRpbWVvdXQoJHthcGkub3B0aW9ucy50aW1lb3V0fSksYCA6IFwiXCJ9XG4gIH0pO1xufVxuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgaGFzUGFyYW1zID0gcGFyYW1zV2l0aG91dENvbnRleHQubGVuZ3RoID4gMDtcbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiAke21ldGhvZE5hbWV9JHt0eXBlUGFyYW1zRGVmfSgke3BhcmFtc0RlZn0pOiBQcm9taXNlPCR7cmV0dXJuVHlwZURlZn0+IHtcbiAgcmV0dXJuIGZldGNoKHtcbiAgICBtZXRob2Q6IFwiJHthcGkub3B0aW9ucy5odHRwTWV0aG9kfVwiLFxuICAgIHVybDogXFxgJHthcGlCYXNlVXJsfVxcYCxcbiAgICAke2hhc1BhcmFtcyA/IGBkYXRhOiB7ICR7cGFyYW1OYW1lc30gfSxgIDogXCJcIn1cbiAgICAke2FwaS5vcHRpb25zLnRpbWVvdXQgPyBgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pLGAgOiBcIlwifVxuICB9KTtcbn1cbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gMi4gcXVlcnlPcHRpb25zICsgdXNlUXVlcnkgKHRhbnN0YWNrLXF1ZXJ5KVxuICAgICAgICBpZiAoY2xpZW50cy5pbmNsdWRlcyhcInRhbnN0YWNrLXF1ZXJ5XCIpKSB7XG4gICAgICAgICAgY29uc3QgaG9va05hbWUgPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICAgID8gaW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUsIHRydWUpXG4gICAgICAgICAgICA6IGluZmxlY3Rpb24uY2FtZWxpemUoYXBpLm1ldGhvZE5hbWUsIHRydWUpO1xuXG4gICAgICAgICAgLy8gcXVlcnlPcHRpb25zXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgY29uc3QgJHttZXRob2ROYW1lfVF1ZXJ5T3B0aW9ucyA9ICR7dHlwZVBhcmFtc0RlZn0oJHtwYXJhbXNEZWZ9KSA9PiBxdWVyeU9wdGlvbnMoe1xuICBxdWVyeUtleTogWycke21vZGVsTmFtZX0nLCAnJHttZXRob2ROYW1lfScke3BhcmFtTmFtZXMgPyBgLCAke3BhcmFtTmFtZXN9YCA6IFwiXCJ9XSxcbiAgcXVlcnlGbjogKCkgPT4gJHttZXRob2ROYW1lfSgke3BhcmFtTmFtZXN9KVxufSk7XG4gICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIHVzZVF1ZXJ5IGhvb2tcbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCB1c2Uke2luZmxlY3Rpb24uY2FtZWxpemUoaG9va05hbWUpfSA9ICR7dHlwZVBhcmFtc0RlZn0oJHtwYXJhbXNEZWZ9JHtcbiAgICAgICAgICAgICAgcGFyYW1zRGVmID8gXCIsIFwiIDogXCJcIlxuICAgICAgICAgICAgfW9wdGlvbnM/OiB7IGVuYWJsZWQ/OiBib29sZWFuIH0pID0+XG4gIHVzZVF1ZXJ5KHtcbiAgICAuLi4ke21ldGhvZE5hbWV9UXVlcnlPcHRpb25zKCR7cGFyYW1OYW1lc30pLFxuICAgIC4uLm9wdGlvbnNcbiAgfSk7XG4gICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDMuIHVzZU11dGF0aW9uICh0YW5zdGFjay1tdXRhdGlvbilcbiAgICAgICAgaWYgKGNsaWVudHMuaW5jbHVkZXMoXCJ0YW5zdGFjay1tdXRhdGlvblwiKSkge1xuICAgICAgICAgIGNvbnN0IGhvb2tOYW1lID0gaW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSk7XG4gICAgICAgICAgY29uc3QgbXV0YXRpb25QYXJhbVR5cGUgPVxuICAgICAgICAgICAgcGFyYW1zV2l0aG91dENvbnRleHQubGVuZ3RoID4gMFxuICAgICAgICAgICAgICA/IGB7ICR7cGFyYW1zV2l0aG91dENvbnRleHRcbiAgICAgICAgICAgICAgICAgIC5tYXAoKHApID0+IGAke3AubmFtZX06ICR7YXBpUGFyYW1UeXBlVG9Uc1R5cGUocC50eXBlLCBbXSl9YClcbiAgICAgICAgICAgICAgICAgIC5qb2luKFwiLCBcIil9IH1gXG4gICAgICAgICAgICAgIDogXCJ2b2lkXCI7XG4gICAgICAgICAgY29uc3QgbXV0YXRpb25QYXJhbU5hbWVzID1cbiAgICAgICAgICAgIHBhcmFtc1dpdGhvdXRDb250ZXh0Lmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgPyBwYXJhbXNXaXRob3V0Q29udGV4dC5tYXAoKHApID0+IGBwYXJhbXMuJHtwLm5hbWV9YCkuam9pbihcIiwgXCIpXG4gICAgICAgICAgICAgIDogXCJcIjtcblxuICAgICAgICAgIGZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICAgICAgYFxuZXhwb3J0IGNvbnN0IHVzZSR7aG9va05hbWV9TXV0YXRpb24gPSAke3R5cGVQYXJhbXNEZWZ9KCkgPT4gdXNlTXV0YXRpb24oe1xuICBtdXRhdGlvbkZuOiAocGFyYW1zOiAke211dGF0aW9uUGFyYW1UeXBlfSkgPT4gJHttZXRob2ROYW1lfSgke211dGF0aW9uUGFyYW1OYW1lc30pXG59KTtcbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIG5hbWVzcGFjZXMucHVzaChcbiAgICAgICAgYFxuZXhwb3J0IG5hbWVzcGFjZSAke21vZGVsTmFtZX1TZXJ2aWNlIHtcbiR7ZnVuY3Rpb25zLmpvaW4oXCJcXG5cXG5cIil9XG59XG4gICAgICBgLnRyaW0oKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnRoaXMuZ2V0VGFyZ2V0QW5kUGF0aCgpLFxuICAgICAgYm9keTogbmFtZXNwYWNlcy5qb2luKFwiXFxuXFxuXCIpLFxuICAgICAgaW1wb3J0S2V5czogZGlmZih1bmlxdWUoaW1wb3J0S2V5cyksIFsuLi50eXBlUGFyYW1OYW1lcywgXCJMaXN0UmVzdWx0XCJdKSxcbiAgICAgIGN1c3RvbUhlYWRlcnM6IFtcbiAgICAgICAgYGltcG9ydCB7IHF1ZXJ5T3B0aW9ucywgdXNlUXVlcnksIHVzZU11dGF0aW9uIH0gZnJvbSAnQHRhbnN0YWNrL3JlYWN0LXF1ZXJ5JztgLFxuICAgICAgICBgaW1wb3J0IHR5cGUgeyBBeGlvc1Byb2dyZXNzRXZlbnQgfSBmcm9tICdheGlvcyc7YCxcbiAgICAgICAgYGltcG9ydCBxcyBmcm9tICdxcyc7YCxcbiAgICAgICAgYGltcG9ydCB7IHR5cGUgTGlzdFJlc3VsdCwgZmV0Y2gsIHR5cGUgRXZlbnRIYW5kbGVycywgdHlwZSBTU0VTdHJlYW1PcHRpb25zLCB1c2VTU0VTdHJlYW0gfSBmcm9tICcuL3NvbmFtdS5zaGFyZWQnO2AsXG4gICAgICBdLFxuICAgIH07XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJpbmZsZWN0aW9uIiwiZGlmZiIsInVuaXF1ZSIsImFwaVBhcmFtVG9Uc0NvZGUiLCJhcGlQYXJhbVR5cGVUb1RzVHlwZSIsInVud3JhcFByb21pc2VPbmNlIiwiU29uYW11IiwiQXBpUGFyYW1UeXBlIiwiYXNzZXJ0RGVmaW5lZCIsIlRlbXBsYXRlIiwiem9kVHlwZVRvVHNUeXBlRGVmIiwiVGVtcGxhdGVfX3NlcnZpY2VzIiwiZ2V0VGFyZ2V0QW5kUGF0aCIsInRhcmdldCIsInBhdGgiLCJyZW5kZXIiLCJhcGlzIiwic3luY2VyIiwiYXBpc0J5TW9kZWwiLCJNYXAiLCJhcGkiLCJtb2RlbE5hbWUiLCJyZXBsYWNlIiwiaGFzIiwic2V0IiwiZ2V0IiwicHVzaCIsImltcG9ydEtleXMiLCJuYW1lc3BhY2VzIiwidHlwZVBhcmFtTmFtZXMiLCJtb2RlbEFwaXMiLCJmdW5jdGlvbnMiLCJzdHJlYW1PcHRpb25zIiwicGFyYW1zV2l0aG91dENvbnRleHQiLCJwYXJhbWV0ZXJzIiwiZmlsdGVyIiwicGFyYW0iLCJpc0NvbnRleHQiLCJ0eXBlIiwiaXNSZWZLbmV4Iiwib3B0aW9uYWwiLCJuYW1lIiwic3RhcnRzV2l0aCIsImFwaUJhc2VVcmwiLCJjb25maWciLCJyb3V0ZSIsInByZWZpeCIsIm1ldGhvZE5hbWVTdHJlYW0iLCJvcHRpb25zIiwicmVzb3VyY2VOYW1lIiwiY2FtZWxpemUiLCJtZXRob2ROYW1lIiwibWV0aG9kTmFtZVN0cmVhbUNhbWVsaXplZCIsImV2ZW50c1R5cGVEZWYiLCJldmVudHMiLCJwYXJhbXNEZWZBc09iamVjdCIsImxlbmd0aCIsIm1hcCIsInAiLCJqb2luIiwidHJpbSIsInR5cGVQYXJhbWV0ZXJzQXNUc1R5cGUiLCJ0eXBlUGFyYW1ldGVycyIsInR5cGVQYXJhbSIsInR5cGVQYXJhbXNEZWYiLCJjb25jYXQiLCJ0cCIsImlkIiwicGFyYW1zRGVmIiwicGFyYW1OYW1lcyIsInJldHVyblR5cGVEZWYiLCJyZXR1cm5UeXBlIiwiY2xpZW50cyIsImluY2x1ZGVzIiwiaXNNdWx0aXBsZSIsInVwbG9hZE9wdGlvbnMiLCJtb2RlIiwiZmlsZVBhcmFtTmFtZSIsImZpbGVQYXJhbVR5cGUiLCJmb3JtRGF0YUFwcGVuZCIsIm90aGVyUGFyYW1zQXBwZW5kIiwicGFyYW1zRGVmQ29tbWEiLCJ0aW1lb3V0IiwiaHR0cE1ldGhvZCIsImhhc1BhcmFtcyIsImhvb2tOYW1lIiwibXV0YXRpb25QYXJhbVR5cGUiLCJtdXRhdGlvblBhcmFtTmFtZXMiLCJib2R5IiwiY3VzdG9tSGVhZGVycyJdLCJtYXBwaW5ncyI6IkFBQUEsT0FBT0EsZ0JBQWdCLGFBQWE7QUFDcEMsU0FBU0MsSUFBSSxFQUFFQyxNQUFNLFFBQVEsVUFBVTtBQUN2QyxTQUNFQyxnQkFBZ0IsRUFDaEJDLG9CQUFvQixFQUNwQkMsaUJBQWlCLFFBQ1osK0JBQTRCO0FBRW5DLFNBQVNDLE1BQU0sUUFBUSxzQkFBbUI7QUFFMUMsU0FBU0MsWUFBWSxRQUFRLHVCQUFvQjtBQUNqRCxTQUFTQyxhQUFhLFFBQVEsdUJBQW9CO0FBQ2xELFNBQVNDLFFBQVEsUUFBUSxpQkFBYztBQUN2QyxTQUFTQyxrQkFBa0IsUUFBUSxzQkFBbUI7QUFFdEQsT0FBTyxNQUFNQywyQkFBMkJGO0lBQ3RDLGFBQWM7UUFDWixLQUFLLENBQUM7SUFDUjtJQUVBRyxtQkFBbUI7UUFDakIsT0FBTztZQUNMQyxRQUFRO1lBQ1JDLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQztRQUMvQjtJQUNGO0lBRUFDLE9BQU8sRUFBK0IsRUFBRTtRQUN0QyxNQUFNLEVBQUVDLElBQUksRUFBRSxHQUFHVixPQUFPVyxNQUFNO1FBRTlCLFdBQVc7UUFDWCxNQUFNQyxjQUFjLElBQUlDO1FBQ3hCLEtBQUssTUFBTUMsT0FBT0osS0FBTTtZQUN0QixNQUFNSyxZQUFZRCxJQUFJQyxTQUFTLENBQUNDLE9BQU8sQ0FBQyxVQUFVLElBQUlBLE9BQU8sQ0FBQyxVQUFVO1lBQ3hFLElBQUksQ0FBQ0osWUFBWUssR0FBRyxDQUFDRixZQUFZO2dCQUMvQkgsWUFBWU0sR0FBRyxDQUFDSCxXQUFXLEVBQUU7WUFDL0I7WUFDQUgsWUFBWU8sR0FBRyxDQUFDSixZQUFZSyxLQUFLTjtRQUNuQztRQUVBLE1BQU1PLGFBQXVCLEVBQUU7UUFDL0IsTUFBTUMsYUFBdUIsRUFBRTtRQUMvQixJQUFJQyxpQkFBMkIsRUFBRTtRQUVqQyxLQUFLLE1BQU0sQ0FB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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonamu",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.19",
|
|
4
4
|
"description": "Sonamu — TypeScript Fullstack API Framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
"import": "./dist/vector/index.js",
|
|
22
22
|
"types": "./dist/vector/index.d.ts"
|
|
23
23
|
},
|
|
24
|
+
"./storage": {
|
|
25
|
+
"import": "./dist/storage/index.js",
|
|
26
|
+
"types": "./dist/storage/index.d.ts"
|
|
27
|
+
},
|
|
24
28
|
"./ai/providers/rtzr": {
|
|
25
29
|
"import": "./dist/ai/providers/rtzr/index.js",
|
|
26
30
|
"types": "./dist/ai/providers/rtzr/index.d.ts"
|
|
@@ -68,6 +72,7 @@
|
|
|
68
72
|
"fastify": "^4.23.2",
|
|
69
73
|
"fastify-qs": "^4.0.0",
|
|
70
74
|
"fastify-sse-v2": "^4.2.1",
|
|
75
|
+
"flydrive": "^1.3.0",
|
|
71
76
|
"inflection": "^1.13.2",
|
|
72
77
|
"knex": "^3.1.0",
|
|
73
78
|
"mime-types": "^3.0.1",
|
|
@@ -81,9 +86,9 @@
|
|
|
81
86
|
"tsicli": "^1.0.5",
|
|
82
87
|
"vitest": "^4.0.10",
|
|
83
88
|
"zod": "^4.1.12",
|
|
84
|
-
"@sonamu-kit/hmr-hook": "^0.4.1",
|
|
85
89
|
"@sonamu-kit/hmr-runner": "^0.1.1",
|
|
86
90
|
"@sonamu-kit/ts-loader": "^2.1.3",
|
|
91
|
+
"@sonamu-kit/hmr-hook": "^0.4.1",
|
|
87
92
|
"@sonamu-kit/tasks": "^0.1.1"
|
|
88
93
|
},
|
|
89
94
|
"devDependencies": {
|
package/src/api/config.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { FastifyInstance, FastifyReply, FastifyRequest, FastifyServerOption
|
|
|
8
8
|
import type { QsPluginOptions } from "fastify-qs";
|
|
9
9
|
import type { SsePluginOptions } from "fastify-sse-v2/lib/types";
|
|
10
10
|
import type { Knex } from "knex";
|
|
11
|
-
import type {
|
|
11
|
+
import type { StorageConfig } from "../storage/types";
|
|
12
12
|
import type { WorkflowOptions } from "../tasks/workflow-manager";
|
|
13
13
|
import type { Executable, SonamuFastifyConfig } from "../types/types";
|
|
14
14
|
import type { AuthContext, Context } from "./context";
|
|
@@ -84,7 +84,24 @@ export type SonamuServerOptions = {
|
|
|
84
84
|
|
|
85
85
|
apiConfig: SonamuFastifyConfig;
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Storage 드라이버 설정.
|
|
89
|
+
* DRIVE_DISK 환경변수로 사용할 드라이버를 선택합니다. (기본값: default 키)
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* import { drivers } from "sonamu/storage";
|
|
94
|
+
*
|
|
95
|
+
* storage: {
|
|
96
|
+
* default: process.env.DRIVE_DISK ?? "fs",
|
|
97
|
+
* drivers: {
|
|
98
|
+
* fs: drivers.fs({ location: "./uploads", urlBuilder: { ... } }),
|
|
99
|
+
* s3: drivers.s3({ bucket: "my-bucket", region: "ap-northeast-2", ... }),
|
|
100
|
+
* }
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
storage?: StorageConfig;
|
|
88
105
|
|
|
89
106
|
lifecycle?: {
|
|
90
107
|
onStart?: (server: FastifyInstance) => Promise<void> | void;
|
package/src/api/context.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { FastifyReply, FastifyRequest, PassportUser } from "fastify";
|
|
|
2
2
|
import type { RouteGenericInterface } from "fastify/types/route";
|
|
3
3
|
import type { IncomingHttpHeaders, IncomingMessage, Server, ServerResponse } from "http";
|
|
4
4
|
import type { ZodObject } from "zod";
|
|
5
|
-
import type { FileStorage } from "../file-storage/file-storage";
|
|
6
5
|
import type { NaiteStore } from "../naite/naite";
|
|
6
|
+
import type { UploadedFile } from "../storage/uploaded-file";
|
|
7
7
|
import type { createSSEFactory } from "../stream/sse";
|
|
8
8
|
|
|
9
9
|
// biome-ignore lint/suspicious/noEmptyInterface: Context 확장 타입
|
|
@@ -26,6 +26,6 @@ export type AuthContext = {
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
export type UploadContext = {
|
|
29
|
-
file?:
|
|
30
|
-
files:
|
|
29
|
+
file?: UploadedFile;
|
|
30
|
+
files: UploadedFile[];
|
|
31
31
|
};
|
package/src/api/decorators.ts
CHANGED
|
@@ -294,24 +294,19 @@ export function upload(options: UploadDecoratorOptions = {}) {
|
|
|
294
294
|
files: [],
|
|
295
295
|
};
|
|
296
296
|
|
|
297
|
-
const
|
|
298
|
-
if (!storage) {
|
|
299
|
-
throw new Error("Storage가 설정되지 않았습니다.");
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const { FileStorage } = await import("../file-storage/file-storage");
|
|
297
|
+
const { UploadedFile } = await import("../storage/uploaded-file");
|
|
303
298
|
if (options.mode === "multiple") {
|
|
304
299
|
const rawFilesIterator = request.files();
|
|
305
300
|
for await (const rawFile of rawFilesIterator) {
|
|
306
301
|
if (rawFile) {
|
|
307
302
|
await rawFile.toBuffer();
|
|
308
|
-
uploadContext.files.push(new
|
|
303
|
+
uploadContext.files.push(new UploadedFile(rawFile));
|
|
309
304
|
}
|
|
310
305
|
}
|
|
311
306
|
} else {
|
|
312
307
|
const rawFile = await request.file();
|
|
313
308
|
if (rawFile) {
|
|
314
|
-
uploadContext.file = new
|
|
309
|
+
uploadContext.file = new UploadedFile(rawFile);
|
|
315
310
|
}
|
|
316
311
|
}
|
|
317
312
|
|
package/src/api/index.ts
CHANGED
package/src/api/sonamu.ts
CHANGED
|
@@ -8,8 +8,8 @@ import path from "path";
|
|
|
8
8
|
import type { ZodObject } from "zod";
|
|
9
9
|
import { createMockSSEFactory, DB, isDaemonServer } from "..";
|
|
10
10
|
import type { SonamuDBConfig } from "../database/db";
|
|
11
|
-
import type { Driver } from "../file-storage/driver";
|
|
12
11
|
import { Naite } from "../naite/naite";
|
|
12
|
+
import type { StorageManager } from "../storage/storage-manager";
|
|
13
13
|
import type { Syncer } from "../syncer/syncer";
|
|
14
14
|
import type { WorkflowManager } from "../tasks/workflow-manager";
|
|
15
15
|
import type { SonamuFastifyConfig } from "../types/types";
|
|
@@ -117,11 +117,14 @@ class SonamuClass {
|
|
|
117
117
|
return this._secrets;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
private _storage:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
get storage():
|
|
120
|
+
private _storage: StorageManager | null = null;
|
|
121
|
+
/**
|
|
122
|
+
* StorageManager 인스턴스
|
|
123
|
+
*/
|
|
124
|
+
get storage(): StorageManager {
|
|
125
|
+
if (!this._storage) {
|
|
126
|
+
throw new Error("Storage has not been initialized. Check storage config.");
|
|
127
|
+
}
|
|
125
128
|
return this._storage;
|
|
126
129
|
}
|
|
127
130
|
|
|
@@ -250,9 +253,10 @@ class SonamuClass {
|
|
|
250
253
|
const server = fastify(options.fastify);
|
|
251
254
|
this.server = server;
|
|
252
255
|
|
|
253
|
-
// Storage 설정
|
|
256
|
+
// Storage 설정 → StorageManager 생성
|
|
254
257
|
if (options.storage) {
|
|
255
|
-
|
|
258
|
+
const { StorageManager } = await import("../storage/storage-manager");
|
|
259
|
+
this._storage = new StorageManager(options.storage);
|
|
256
260
|
}
|
|
257
261
|
|
|
258
262
|
// 플러그인 등록
|
|
@@ -714,7 +718,6 @@ class SonamuClass {
|
|
|
714
718
|
await BaseModel.destroy();
|
|
715
719
|
await this._workflows?.destroy();
|
|
716
720
|
await this.watcher?.close();
|
|
717
|
-
this.storage?.destroy();
|
|
718
721
|
}
|
|
719
722
|
}
|
|
720
723
|
export const Sonamu = new SonamuClass();
|
package/src/index.ts
CHANGED
|
@@ -15,7 +15,6 @@ export * from "./entity/entity";
|
|
|
15
15
|
export * from "./entity/entity-manager";
|
|
16
16
|
export * from "./exceptions/error-handler";
|
|
17
17
|
export * from "./exceptions/so-exceptions";
|
|
18
|
-
export * from "./file-storage/driver";
|
|
19
18
|
export * from "./migration/migration-set";
|
|
20
19
|
export * from "./migration/migrator";
|
|
21
20
|
export * from "./migration/postgresql-schema-reader";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FSDriver } from "flydrive/drivers/fs";
|
|
2
|
+
import type { FSDriverOptions } from "flydrive/drivers/fs/types";
|
|
3
|
+
import { S3Driver } from "flydrive/drivers/s3";
|
|
4
|
+
import type { S3DriverOptions } from "flydrive/drivers/s3/types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 드라이버 팩토리 함수
|
|
8
|
+
* 설정 → 드라이버 인스턴스 생성 함수 변환
|
|
9
|
+
*/
|
|
10
|
+
export const drivers = {
|
|
11
|
+
fs: (config: FSDriverOptions) => () => new FSDriver(config),
|
|
12
|
+
s3: (config: S3DriverOptions) => () => new S3Driver(config),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type DriverKey = keyof typeof drivers;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Disk } from "flydrive";
|
|
2
|
+
import { assertDefined } from "../utils/utils";
|
|
3
|
+
import type { DriverKey } from "./drivers";
|
|
4
|
+
import type { StorageConfig } from "./types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 여러 디스크를 관리하는 매니저
|
|
8
|
+
*/
|
|
9
|
+
export class StorageManager {
|
|
10
|
+
private disks: Map<DriverKey, Disk> = new Map();
|
|
11
|
+
|
|
12
|
+
constructor(private config: StorageConfig) {}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 디스크 인스턴스 반환 (lazy initialization)
|
|
16
|
+
* @param diskName 디스크 이름 (없으면 default)
|
|
17
|
+
*/
|
|
18
|
+
use(diskName?: DriverKey): Disk {
|
|
19
|
+
const name = diskName ?? (this.config.default as DriverKey);
|
|
20
|
+
|
|
21
|
+
if (!this.disks.has(name)) {
|
|
22
|
+
const factory = this.config.drivers[name];
|
|
23
|
+
if (!factory) {
|
|
24
|
+
const available = Object.keys(this.config.drivers).join(", ");
|
|
25
|
+
throw new Error(`Unknown disk: "${name}". Available: ${available}`);
|
|
26
|
+
}
|
|
27
|
+
this.disks.set(name, new Disk(factory()));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return assertDefined(this.disks.get(name), `Disk ${name} not found`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 기본 디스크 이름 반환
|
|
35
|
+
*/
|
|
36
|
+
get defaultDisk(): string {
|
|
37
|
+
return this.config.default;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DriverContract } from "flydrive/types";
|
|
2
|
+
import type { DriverKey } from "./drivers";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Storage 설정 타입
|
|
6
|
+
*/
|
|
7
|
+
export type StorageConfig = {
|
|
8
|
+
/** 기본 디스크 이름 */
|
|
9
|
+
default: string;
|
|
10
|
+
/** 디스크별 드라이버 팩토리 */
|
|
11
|
+
drivers: Record<DriverKey, () => DriverContract>;
|
|
12
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { MultipartFile } from "@fastify/multipart";
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
import mime from "mime-types";
|
|
4
|
+
import type { DriverKey } from "./drivers";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 업로드된 파일 래퍼
|
|
8
|
+
*/
|
|
9
|
+
export class UploadedFile {
|
|
10
|
+
private _file: MultipartFile;
|
|
11
|
+
private _buffer?: Buffer;
|
|
12
|
+
private _url?: string;
|
|
13
|
+
|
|
14
|
+
constructor(file: MultipartFile) {
|
|
15
|
+
this._file = file;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** 원본 파일명 */
|
|
19
|
+
get filename(): string {
|
|
20
|
+
return this._file.filename;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** MIME 타입 */
|
|
24
|
+
get mimetype(): string {
|
|
25
|
+
return this._file.mimetype;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** 파일 크기 (bytes) */
|
|
29
|
+
get size(): number {
|
|
30
|
+
return this._file.file.bytesRead;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** 확장자 (점 제외) */
|
|
34
|
+
get extname(): string | false {
|
|
35
|
+
return mime.extension(this._file.mimetype);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** saveToDisk 후 저장된 URL */
|
|
39
|
+
get url(): string | undefined {
|
|
40
|
+
return this._url;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Buffer로 변환 (캐싱됨) */
|
|
44
|
+
async toBuffer(): Promise<Buffer> {
|
|
45
|
+
if (!this._buffer) {
|
|
46
|
+
this._buffer = await this._file.toBuffer();
|
|
47
|
+
}
|
|
48
|
+
return this._buffer;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** MD5 해시 계산 */
|
|
52
|
+
async md5(): Promise<string> {
|
|
53
|
+
const buffer = await this.toBuffer();
|
|
54
|
+
return createHash("md5").update(buffer).digest("hex");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 파일을 디스크에 저장
|
|
59
|
+
* @param key 저장 경로 (예: 'uploads/avatar.png')
|
|
60
|
+
* @param diskName 디스크 이름 (기본: default disk)
|
|
61
|
+
* @returns 저장된 파일의 URL
|
|
62
|
+
*/
|
|
63
|
+
async saveToDisk(key: string, diskName?: DriverKey): Promise<string> {
|
|
64
|
+
// 순환 의존성 방지를 위해 동적 import
|
|
65
|
+
const { Sonamu } = await import("../api/sonamu");
|
|
66
|
+
const disk = Sonamu.storage.use(diskName);
|
|
67
|
+
const buffer = await this.toBuffer();
|
|
68
|
+
|
|
69
|
+
await disk.put(key, new Uint8Array(buffer), {
|
|
70
|
+
contentType: this.mimetype,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
this._url = await disk.getSignedUrl(key);
|
|
74
|
+
return this._url;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** 원본 MultipartFile 접근 */
|
|
78
|
+
get raw(): MultipartFile {
|
|
79
|
+
return this._file;
|
|
80
|
+
}
|
|
81
|
+
}
|