sonamu 0.10.8 → 0.10.10

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.
@@ -201,7 +201,7 @@ export const ${infiniteHookName} = ${typeParamsDef}(${paramsDef}${paramsDef ? ",
201
201
  const mutationParamNames = paramsWithoutContext.length > 0 ? paramsWithoutContext.map((p) => `params.${p.name}`).join(", ") : "";
202
202
  functions.push(`
203
203
  export const use${hookName}Mutation = ${typeParamsDef}() => useMutation({
204
- mutationFn: (params: ${mutationParamType}) => ${methodName}(${mutationParamNames})
204
+ mutationFn: (params: ${mutationParamType}) => ${modelName}Service.${methodName}(${mutationParamNames})
205
205
  });
206
206
  `.trim());
207
207
  }
@@ -209,7 +209,7 @@ export const use${hookName}Mutation = ${typeParamsDef}() => useMutation({
209
209
  const hookName = inflection.camelize(api.methodName);
210
210
  const paramsTypeDef = paramsWithoutContext.length > 0 ? paramsDef.split(":").slice(1).join(":").trim() : "";
211
211
  const mutationParamType = paramsWithoutContext.length > 0 ? `{ params: ${paramsTypeDef}, files: File[] }` : `{ files: File[] }`;
212
- const mutationFnCall = paramsWithoutContext.length > 0 ? `${methodName}(params.params, params.files)` : `${methodName}(params.files)`;
212
+ const mutationFnCall = paramsWithoutContext.length > 0 ? `${modelName}Service.${methodName}(params.params, params.files)` : `${modelName}Service.${methodName}(params.files)`;
213
213
  functions.push(`
214
214
  export const use${hookName}Mutation = ${typeParamsDef}(
215
215
  options?: UseMutationOptions<${returnTypeDef}, Error, ${mutationParamType}> & {
@@ -300,4 +300,4 @@ export const ${names.capital}AsyncIdConfig: AsyncIdConfig<${names.capital}Subset
300
300
  //#endregion
301
301
  export { Template__services };
302
302
 
303
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZXMudGVtcGxhdGUuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RlbXBsYXRlL2ltcGxlbWVudGF0aW9ucy9zZXJ2aWNlcy50ZW1wbGF0ZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgaW5mbGVjdGlvbiBmcm9tIFwiaW5mbGVjdGlvblwiO1xuaW1wb3J0IHsgZGlmZiwgdW5pcXVlIH0gZnJvbSBcInJhZGFzaGlcIjtcblxuaW1wb3J0IHtcbiAgYXBpUGFyYW1Ub1RzQ29kZSxcbiAgYXBpUGFyYW1UeXBlVG9Uc1R5cGUsXG4gIHVud3JhcFByb21pc2VPbmNlLFxufSBmcm9tIFwiLi4vLi4vYXBpL2NvZGUtY29udmVydGVyc1wiO1xuaW1wb3J0IHsgdHlwZSBFeHRlbmRlZEFwaSB9IGZyb20gXCIuLi8uLi9hcGkvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgU29uYW11IH0gZnJvbSBcIi4uLy4uL2FwaS9zb25hbXVcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIgfSBmcm9tIFwiLi4vLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyB0eXBlIFRlbXBsYXRlT3B0aW9ucyB9IGZyb20gXCIuLi8uLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgQXBpUGFyYW1UeXBlIH0gZnJvbSBcIi4uLy4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBhc3NlcnREZWZpbmVkIH0gZnJvbSBcIi4uLy4uL3V0aWxzL3V0aWxzXCI7XG5pbXBvcnQgeyBUZW1wbGF0ZSB9IGZyb20gXCIuLi90ZW1wbGF0ZVwiO1xuaW1wb3J0IHsgQlVJTFRfSU5fVFlQRVMsIHpvZFR5cGVUb1RzVHlwZURlZiB9IGZyb20gXCIuLi96b2QtY29udmVydGVyXCI7XG5cbmV4cG9ydCBjbGFzcyBUZW1wbGF0ZV9fc2VydmljZXMgZXh0ZW5kcyBUZW1wbGF0ZSB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKFwic2VydmljZXNcIik7XG4gIH1cblxuICBnZXRUYXJnZXRBbmRQYXRoKCkge1xuICAgIHJldHVybiB7XG4gICAgICB0YXJnZXQ6IFwiOnRhcmdldC9zcmMvc2VydmljZXNcIixcbiAgICAgIHBhdGg6IGBzZXJ2aWNlcy5nZW5lcmF0ZWQudHNgLFxuICAgIH07XG4gIH1cblxuICByZW5kZXIoe306IFRlbXBsYXRlT3B0aW9uc1tcInNlcnZpY2VzXCJdKSB7XG4gICAgY29uc3QgeyBhcGlzIH0gPSBTb25hbXUuc3luY2VyO1xuXG4gICAgLy8g66qo642467OE66GcIOq3uOujue2ZlFxuICAgIGNvbnN0IGFwaXNCeU1vZGVsID0gbmV3IE1hcDxzdHJpbmcsIEV4dGVuZGVkQXBpW10+KCk7XG4gICAgZm9yIChjb25zdCBhcGkgb2YgYXBpcykge1xuICAgICAgY29uc3QgbW9kZWxOYW1lID0gYXBpLm1vZGVsTmFtZS5yZXBsYWNlKC9Nb2RlbCQvLCBcIlwiKS5yZXBsYWNlKC9GcmFtZSQvLCBcIlwiKTtcbiAgICAgIGlmICghYXBpc0J5TW9kZWwuaGFzKG1vZGVsTmFtZSkpIHtcbiAgICAgICAgYXBpc0J5TW9kZWwuc2V0KG1vZGVsTmFtZSwgW10pO1xuICAgICAgfVxuICAgICAgYXBpc0J5TW9kZWwuZ2V0KG1vZGVsTmFtZSk/LnB1c2goYXBpKTtcbiAgICB9XG5cbiAgICBjb25zdCBpbXBvcnRLZXlzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IG5hbWVzcGFjZXM6IHN0cmluZ1tdID0gW107XG4gICAgbGV0IHR5cGVQYXJhbU5hbWVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IHJlc29sdmVXZWJTb2NrZXRFdmVudFR5cGVEZWYgPSAoXG4gICAgICB0eXBlUmVmOiBBcGlQYXJhbVR5cGUuUmVmIHwgdW5kZWZpbmVkLFxuICAgICAgc2NoZW1hOiBQYXJhbWV0ZXJzPHR5cGVvZiB6b2RUeXBlVG9Uc1R5cGVEZWY+WzBdLFxuICAgICk6IHN0cmluZyA9PiB7XG4gICAgICBpZiAodHlwZVJlZikge1xuICAgICAgICBjb25zdCBjYW5kaWRhdGVJbXBvcnRLZXlzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBjb25zdCBjYW5kaWRhdGVUeXBlRGVmID0gYXBpUGFyYW1UeXBlVG9Uc1R5cGUodHlwZVJlZiwgY2FuZGlkYXRlSW1wb3J0S2V5cyk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBmb3IgKGNvbnN0IGtleSBvZiB1bmlxdWUoY2FuZGlkYXRlSW1wb3J0S2V5cykpIHtcbiAgICAgICAgICAgIEVudGl0eU1hbmFnZXIuZ2V0TW9kdWxlUGF0aChrZXkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpbXBvcnRLZXlzLnB1c2goLi4uY2FuZGlkYXRlSW1wb3J0S2V5cyk7XG4gICAgICAgICAgcmV0dXJuIGNhbmRpZGF0ZVR5cGVEZWY7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIOuhnOy7rCBjb25zdCDrk7EgaW1wb3J0IOqwgOuKpe2VnCDsi6zrs7zsnbQg7JWE64uI66m0IOq4sOyhtCBpbmxpbmUg7IOd7ISx7Jy866GcIO2bhO2HtFxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB6b2RUeXBlVG9Uc1R5cGVEZWYoc2NoZW1hKTtcbiAgICB9O1xuXG4gICAgZm9yIChjb25zdCBbbW9kZWxOYW1lLCBtb2RlbEFwaXNdIG9mIGFwaXNCeU1vZGVsKSB7XG4gICAgICBjb25zdCBmdW5jdGlvbnM6IHN0cmluZ1tdID0gW107XG5cbiAgICAgIGZvciAoY29uc3QgYXBpIG9mIG1vZGVsQXBpcykge1xuICAgICAgICAvLyBAc3RyZWFtIOuNsOy9lOugiOydtO2EsOqwgCDsnojsnLzrqbQgU1NFIOyKpO2KuOumvCDtlajsiJgg7IOd7ISxXG4gICAgICAgIGlmIChhcGkuc3RyZWFtT3B0aW9ucykge1xuICAgICAgICAgIGNvbnN0IHBhcmFtc1dpdGhvdXRDb250ZXh0ID0gYXBpLnBhcmFtZXRlcnMuZmlsdGVyKFxuICAgICAgICAgICAgKHBhcmFtKSA9PlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzUmVmS25leChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhKHBhcmFtLm9wdGlvbmFsICYmIHBhcmFtLm5hbWUuc3RhcnRzV2l0aChcIl9cIikpLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBjb25zdCBhcGlCYXNlVXJsID0gYCR7U29uYW11LmNvbmZpZy5hcGkucm91dGUucHJlZml4fSR7YXBpLnBhdGh9YDtcblxuICAgICAgICAgIGNvbnN0IG1ldGhvZE5hbWVTdHJlYW0gPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICAgID8gYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUpfWBcbiAgICAgICAgICAgIDogYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSl9YDtcbiAgICAgICAgICBjb25zdCBtZXRob2ROYW1lU3RyZWFtQ2FtZWxpemVkID0gaW5mbGVjdGlvbi5jYW1lbGl6ZShtZXRob2ROYW1lU3RyZWFtLCB0cnVlKTtcblxuICAgICAgICAgIGNvbnN0IGV2ZW50c1R5cGVEZWYgPSB6b2RUeXBlVG9Uc1R5cGVEZWYoYXBpLnN0cmVhbU9wdGlvbnMuZXZlbnRzKTtcblxuICAgICAgICAgIC8vIO2MjOudvOuvuO2EsOulvCDqsJ3ssrQg7ZiV7YOc66GcIOygleydmCAo7YOA7J6F6rO8IOyLpOygnCDqsJIg66qo65GQ7JeQIOyCrOyaqSlcbiAgICAgICAgICBjb25zdCBwYXJhbXNEZWZBc09iamVjdCA9XG4gICAgICAgICAgICBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwXG4gICAgICAgICAgICAgID8gYHsgJHtwYXJhbXNXaXRob3V0Q29udGV4dC5tYXAoKHApID0+IGAke3AubmFtZX06ICR7YXBpUGFyYW1UeXBlVG9Uc1R5cGUocC50eXBlLCBpbXBvcnRLZXlzKX1gKS5qb2luKFwiLCBcIil9IH1gXG4gICAgICAgICAgICAgIDogXCJ7fVwiO1xuXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgZnVuY3Rpb24gJHttZXRob2ROYW1lU3RyZWFtQ2FtZWxpemVkfShcbiAgcGFyYW1zOiAke3BhcmFtc0RlZkFzT2JqZWN0fSxcbiAgaGFuZGxlcnM6IEV2ZW50SGFuZGxlcnM8JHtldmVudHNUeXBlRGVmfSAmIHsgZW5kPzogKCkgPT4gdm9pZCB9PixcbiAgb3B0aW9uczogU1NFU3RyZWFtT3B0aW9uc1xuKSB7XG4gIHJldHVybiB1c2VTU0VTdHJlYW08JHtldmVudHNUeXBlRGVmfT4oXFxgJHthcGlCYXNlVXJsfVxcYCwgcGFyYW1zLCBoYW5kbGVycywgb3B0aW9ucyk7XG59XG4gICAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGFwaS53ZWJzb2NrZXRPcHRpb25zKSB7XG4gICAgICAgICAgLy8gd2Vic29ja2V0IHN1cmZhY2XripQgZmV0Y2gg7ZWo7IiYIOuMgOyLoCB0eXBlZCBob29r7J2EIOyDneyEse2VqFxuICAgICAgICAgIGNvbnN0IHBhcmFtc1dpdGhvdXRDb250ZXh0ID0gYXBpLnBhcmFtZXRlcnMuZmlsdGVyKFxuICAgICAgICAgICAgKHBhcmFtKSA9PlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzUmVmS25leChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhKHBhcmFtLm9wdGlvbmFsICYmIHBhcmFtLm5hbWUuc3RhcnRzV2l0aChcIl9cIikpLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBjb25zdCBhcGlCYXNlVXJsID0gYCR7U29uYW11LmNvbmZpZy5hcGkucm91dGUucHJlZml4fSR7YXBpLnBhdGh9YDtcblxuICAgICAgICAgIGNvbnN0IG1ldGhvZE5hbWVXZWJTb2NrZXQgPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICAgID8gYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUpfWBcbiAgICAgICAgICAgIDogYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSl9YDtcbiAgICAgICAgICBjb25zdCBtZXRob2ROYW1lV2ViU29ja2V0Q2FtZWxpemVkID0gaW5mbGVjdGlvbi5jYW1lbGl6ZShtZXRob2ROYW1lV2ViU29ja2V0LCB0cnVlKTtcblxuICAgICAgICAgIC8vIG91dEV2ZW50c+uKlCDsiJjsi6Ag7YOA7J6FLCBpbkV2ZW50c+uKlCBzZW5kKCkg7J6F66ClIO2DgOyeheycvOuhnCDsgqzsmqntlahcbiAgICAgICAgICBjb25zdCBvdXRFdmVudHNUeXBlRGVmID0gcmVzb2x2ZVdlYlNvY2tldEV2ZW50VHlwZURlZihcbiAgICAgICAgICAgIGFwaS53ZWJzb2NrZXRPcHRpb25zLm91dEV2ZW50c1R5cGVSZWYsXG4gICAgICAgICAgICBhcGkud2Vic29ja2V0T3B0aW9ucy5vdXRFdmVudHMsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBpbkV2ZW50c1R5cGVEZWYgPSByZXNvbHZlV2ViU29ja2V0RXZlbnRUeXBlRGVmKFxuICAgICAgICAgICAgYXBpLndlYnNvY2tldE9wdGlvbnMuaW5FdmVudHNUeXBlUmVmLFxuICAgICAgICAgICAgYXBpLndlYnNvY2tldE9wdGlvbnMuaW5FdmVudHMsXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIGNvbnRleHQvcmVmS25leC9pbnRlcm5hbCBvcHRpb25hbCDtjIzrnbzrr7jthLDripQg7YG065287J207Ja47Yq4IOyeheugpeyXkOyEnCDsoJzsmbjtlahcbiAgICAgICAgICBjb25zdCBwYXJhbXNEZWZBc09iamVjdCA9XG4gICAgICAgICAgICBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwXG4gICAgICAgICAgICAgID8gYHsgJHtwYXJhbXNXaXRob3V0Q29udGV4dC5tYXAoKHApID0+IGAke3AubmFtZX06ICR7YXBpUGFyYW1UeXBlVG9Uc1R5cGUocC50eXBlLCBpbXBvcnRLZXlzKX1gKS5qb2luKFwiLCBcIil9IH1gXG4gICAgICAgICAgICAgIDogXCJ7fVwiO1xuXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgZnVuY3Rpb24gJHttZXRob2ROYW1lV2ViU29ja2V0Q2FtZWxpemVkfShcbiAgcGFyYW1zOiAke3BhcmFtc0RlZkFzT2JqZWN0fSxcbiAgaGFuZGxlcnM6IEV2ZW50SGFuZGxlcnM8JHtvdXRFdmVudHNUeXBlRGVmfT4sXG4gIG9wdGlvbnM6IFdlYlNvY2tldENoYW5uZWxPcHRpb25zID0ge31cbikge1xuICByZXR1cm4gdXNlV2ViU29ja2V0Q2hhbm5lbDwke291dEV2ZW50c1R5cGVEZWZ9LCAke2luRXZlbnRzVHlwZURlZn0+KFxcYCR7YXBpQmFzZVVybH1cXGAsIHBhcmFtcywgaGFuZGxlcnMsIG9wdGlvbnMpO1xufVxuICAgICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENvbnRleHQg7KCc7Jm47ZWcIO2MjOudvOuvuO2EsFxuICAgICAgICBjb25zdCBwYXJhbXNXaXRob3V0Q29udGV4dCA9IGFwaS5wYXJhbWV0ZXJzLmZpbHRlcihcbiAgICAgICAgICAocGFyYW0pID0+XG4gICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgIUFwaVBhcmFtVHlwZS5pc1JlZktuZXgocGFyYW0udHlwZSkgJiZcbiAgICAgICAgICAgICEocGFyYW0ub3B0aW9uYWwgJiYgcGFyYW0ubmFtZS5zdGFydHNXaXRoKFwiX1wiKSksXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8g7YOA7J6FIO2MjOudvOuvuO2EsCDsoJXsnZhcbiAgICAgICAgY29uc3QgdHlwZVBhcmFtZXRlcnNBc1RzVHlwZSA9IGFwaS50eXBlUGFyYW1ldGVyc1xuICAgICAgICAgIC5tYXAoKHR5cGVQYXJhbSkgPT4gYXBpUGFyYW1UeXBlVG9Uc1R5cGUodHlwZVBhcmFtLCBpbXBvcnRLZXlzKSlcbiAgICAgICAgICAuam9pbihcIiwgXCIpO1xuICAgICAgICBjb25zdCB0eXBlUGFyYW1zRGVmID0gdHlwZVBhcmFtZXRlcnNBc1RzVHlwZSA/IGA8JHt0eXBlUGFyYW1ldGVyc0FzVHNUeXBlfT5gIDogXCJcIjtcbiAgICAgICAgdHlwZVBhcmFtTmFtZXMgPSB0eXBlUGFyYW1OYW1lcy5jb25jYXQoYXBpLnR5cGVQYXJhbWV0ZXJzLm1hcCgodHApID0+IHRwLmlkKSk7XG5cbiAgICAgICAgLy8g7YyM652866+47YSwIOygleydmFxuICAgICAgICBjb25zdCBwYXJhbXNEZWYgPSBhcGlQYXJhbVRvVHNDb2RlKHBhcmFtc1dpdGhvdXRDb250ZXh0LCBpbXBvcnRLZXlzKTtcbiAgICAgICAgY29uc3QgcGFyYW1OYW1lcyA9IHBhcmFtc1dpdGhvdXRDb250ZXh0Lm1hcCgocCkgPT4gcC5uYW1lKS5qb2luKFwiLCBcIik7XG5cbiAgICAgICAgLy8g66as7YS0IO2DgOyehSDsoJXsnZhcbiAgICAgICAgY29uc3QgcmV0dXJuVHlwZURlZiA9IGFwaVBhcmFtVHlwZVRvVHNUeXBlKFxuICAgICAgICAgIGFzc2VydERlZmluZWQodW53cmFwUHJvbWlzZU9uY2UoYXBpLnJldHVyblR5cGUpKSxcbiAgICAgICAgICBpbXBvcnRLZXlzLFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIOq4sOuzuCBVUkxcbiAgICAgICAgY29uc3QgYXBpQmFzZVVybCA9IGAke1NvbmFtdS5jb25maWcuYXBpLnJvdXRlLnByZWZpeH0ke2FwaS5wYXRofWA7XG5cbiAgICAgICAgY29uc3QgY2xpZW50cyA9IGFwaS5vcHRpb25zLmNsaWVudHMgfHwgW107XG5cbiAgICAgICAgLy8gMS4gYXhpb3Mg7ZWo7IiYIOyDneyEsVxuICAgICAgICAvLyByZXNvdXJjZU5hbWXsnbQg7J6I7Jy866m0IGdldCArIHJlc291cmNlTmFtZSDtmJXtg5zroZwg7ZWo7IiY66qFIOyDneyEsVxuICAgICAgICBjb25zdCBtZXRob2ROYW1lID0gYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lXG4gICAgICAgICAgPyBgZ2V0JHtpbmZsZWN0aW9uLmNhbWVsaXplKGFwaS5vcHRpb25zLnJlc291cmNlTmFtZSl9YFxuICAgICAgICAgIDogYXBpLm1ldGhvZE5hbWU7XG5cbiAgICAgICAgLy8gYXhpb3MtbXVsdGlwYXJ0IOyymOumrCAo7YyM7J28IOyXheuhnOuTnClcbiAgICAgICAgaWYgKGNsaWVudHMuaW5jbHVkZXMoXCJheGlvcy1tdWx0aXBhcnRcIikpIHtcbiAgICAgICAgICBjb25zdCBmb3JtRGF0YUFwcGVuZCA9IGBmaWxlcy5mb3JFYWNoKGYgPT4geyBmb3JtRGF0YS5hcHBlbmQoXCJmaWxlc1wiLCBmKTsgfSk7YDtcblxuICAgICAgICAgIGNvbnN0IG90aGVyUGFyYW1zQXBwZW5kID0gcGFyYW1zV2l0aG91dENvbnRleHRcbiAgICAgICAgICAgIC5tYXAoKHBhcmFtKSA9PiB7XG4gICAgICAgICAgICAgIC8vIHByaW1pdGl2ZSDtg4DsnoXsnbjsp4Ag7LK07YGsXG4gICAgICAgICAgICAgIGNvbnN0IGlzUHJpbWl0aXZlID1cbiAgICAgICAgICAgICAgICB0eXBlb2YgcGFyYW0udHlwZSA9PT0gXCJzdHJpbmdcIiAmJlxuICAgICAgICAgICAgICAgIFtcInN0cmluZ1wiLCBcIm51bWJlclwiLCBcImJvb2xlYW5cIl0uaW5jbHVkZXMocGFyYW0udHlwZSk7XG5cbiAgICAgICAgICAgICAgaWYgKGlzUHJpbWl0aXZlKSB7XG4gICAgICAgICAgICAgICAgLy8gcHJpbWl0aXZlOiDsp4HsoJEgZm9ybURhdGEuYXBwZW5kXG4gICAgICAgICAgICAgICAgcmV0dXJuIGBmb3JtRGF0YS5hcHBlbmQoJyR7cGFyYW0ubmFtZX0nLCBTdHJpbmcoJHtwYXJhbS5uYW1lfSkpO2A7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gb2JqZWN0OiB0b0Zvcm1EYXRhIOyCrOyaqVxuICAgICAgICAgICAgICAgIHJldHVybiBgdG9Gb3JtRGF0YSgke3BhcmFtLm5hbWV9LCBmb3JtRGF0YSwgJyR7cGFyYW0ubmFtZX0nKTtgO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmpvaW4oXCJcXG4gICAgXCIpO1xuXG4gICAgICAgICAgY29uc3QgcGFyYW1zRGVmQ29tbWEgPSBwYXJhbXNEZWYgIT09IFwiXCIgPyBcIiwgXCIgOiBcIlwiO1xuICAgICAgICAgIGZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICAgICAgYFxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uICR7bWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KFxuICAke3BhcmFtc0RlZn0ke3BhcmFtc0RlZkNvbW1hfVxuICBmaWxlczogRmlsZVtdLFxuICBvblVwbG9hZFByb2dyZXNzPzogKHBlOiBBeGlvc1Byb2dyZXNzRXZlbnQpID0+IHZvaWRcbik6IFByb21pc2U8JHtyZXR1cm5UeXBlRGVmfT4ge1xuICBjb25zdCBmb3JtRGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAke2Zvcm1EYXRhQXBwZW5kfVxuICAke290aGVyUGFyYW1zQXBwZW5kfVxuICByZXR1cm4gZmV0Y2goe1xuICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgIHVybDogXFxgJHthcGlCYXNlVXJsfVxcYCxcbiAgICBvblVwbG9hZFByb2dyZXNzLFxuICAgIGRhdGE6IGZvcm1EYXRhLFxuICAgICR7YXBpLm9wdGlvbnMudGltZW91dCA/IGBzaWduYWw6IEFib3J0U2lnbmFsLnRpbWVvdXQoJHthcGkub3B0aW9ucy50aW1lb3V0fSksYCA6IFwiXCJ9XG4gIH0pO1xufVxuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSBpZiAoYXBpLm9wdGlvbnMuaHR0cE1ldGhvZCA9PT0gXCJHRVRcIikge1xuICAgICAgICAgIGNvbnN0IGhhc1BhcmFtcyA9IHBhcmFtc1dpdGhvdXRDb250ZXh0Lmxlbmd0aCA+IDA7XG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHttZXRob2ROYW1lfSR7dHlwZVBhcmFtc0RlZn0oJHtwYXJhbXNEZWZ9KTogUHJvbWlzZTwke3JldHVyblR5cGVEZWZ9PiB7XG4gIHJldHVybiBmZXRjaCh7XG4gICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgIHVybDogXFxgJHthcGlCYXNlVXJsfSR7aGFzUGFyYW1zID8gYD9cXCR7cXMuc3RyaW5naWZ5KHsgJHtwYXJhbU5hbWVzfSB9KX1gIDogXCJcIn1cXGAsXG4gICAgJHthcGkub3B0aW9ucy50aW1lb3V0ID8gYHNpZ25hbDogQWJvcnRTaWduYWwudGltZW91dCgke2FwaS5vcHRpb25zLnRpbWVvdXR9KSxgIDogXCJcIn1cbiAgfSk7XG59XG4gICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBoYXNQYXJhbXMgPSBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwO1xuICAgICAgICAgIGZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICAgICAgYFxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uICR7bWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSk6IFByb21pc2U8JHtyZXR1cm5UeXBlRGVmfT4ge1xuICByZXR1cm4gZmV0Y2goe1xuICAgIG1ldGhvZDogXCIke2FwaS5vcHRpb25zLmh0dHBNZXRob2R9XCIsXG4gICAgdXJsOiBcXGAke2FwaUJhc2VVcmx9XFxgLFxuICAgICR7aGFzUGFyYW1zID8gYGRhdGE6IHsgJHtwYXJhbU5hbWVzfSB9LGAgOiBcIlwifVxuICAgICR7YXBpLm9wdGlvbnMudGltZW91dCA/IGBzaWduYWw6IEFib3J0U2lnbmFsLnRpbWVvdXQoJHthcGkub3B0aW9ucy50aW1lb3V0fSksYCA6IFwiXCJ9XG4gIH0pO1xufVxuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAyLiBxdWVyeU9wdGlvbnMgKyB1c2VRdWVyeSAodGFuc3RhY2stcXVlcnkpXG4gICAgICAgIGlmIChjbGllbnRzLmluY2x1ZGVzKFwidGFuc3RhY2stcXVlcnlcIikpIHtcbiAgICAgICAgICBjb25zdCBob29rTmFtZSA9IGFwaS5vcHRpb25zLnJlc291cmNlTmFtZVxuICAgICAgICAgICAgPyBpbmZsZWN0aW9uLmNhbWVsaXplKGFwaS5vcHRpb25zLnJlc291cmNlTmFtZSwgdHJ1ZSlcbiAgICAgICAgICAgIDogaW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSwgdHJ1ZSk7XG5cbiAgICAgICAgICAvLyBxdWVyeU9wdGlvbnNcbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCAke21ldGhvZE5hbWV9UXVlcnlPcHRpb25zID0gJHt0eXBlUGFyYW1zRGVmfSgke3BhcmFtc0RlZn0pID0+IHF1ZXJ5T3B0aW9ucyh7XG4gIHF1ZXJ5S2V5OiBbJyR7bW9kZWxOYW1lfScsICcke21ldGhvZE5hbWV9JyR7cGFyYW1OYW1lcyA/IGAsICR7cGFyYW1OYW1lc31gIDogXCJcIn1dLFxuICBxdWVyeUZuOiAoKSA9PiAke21ldGhvZE5hbWV9KCR7cGFyYW1OYW1lc30pXG59KTtcbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gdXNlUXVlcnkgaG9vayAodXNlUmVmcmVzaGFibGXroZwg656Y7ZWR7ZW0IHJlZnJlc2gvaXNSZWZyZXNoaW5n7J2EIOq4sOuzuCDsoJzqs7UpXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgY29uc3QgdXNlJHtpbmZsZWN0aW9uLmNhbWVsaXplKGhvb2tOYW1lKX0gPSAke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSR7XG4gICAgICAgICAgICAgIHBhcmFtc0RlZiA/IFwiLCBcIiA6IFwiXCJcbiAgICAgICAgICAgIH1vcHRpb25zPzogeyBlbmFibGVkPzogYm9vbGVhbiB9KSA9PlxuICB1c2VSZWZyZXNoYWJsZSh1c2VRdWVyeSh7XG4gICAgLi4uJHttZXRob2ROYW1lfVF1ZXJ5T3B0aW9ucygke3BhcmFtTmFtZXN9KSxcbiAgICAuLi5vcHRpb25zXG4gIH0pKTtcbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gaW5maW5pdGVRdWVyeU9wdGlvbnMgKyB1c2VJbmZpbml0ZVF1ZXJ5IChBc3luY0lkQ29uZmlnLnVzZUxpc3RJbmZpbml0ZSDrjIDsg4Eg7KGw6rG0KVxuICAgICAgICAgIC8vIOyhsOqxtDogcmVzb3VyY2VOYW1l7J20IOuzteyImO2YleydtOqzoCBtZXRob2ROYW1lID09PSBcImZpbmRNYW55XCJcbiAgICAgICAgICBjb25zdCByZXNvdXJjZU5hbWUgPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWU7XG4gICAgICAgICAgY29uc3QgaXNJbmZpbml0ZVRhcmdldCA9XG4gICAgICAgICAgICAhIXJlc291cmNlTmFtZSAmJlxuICAgICAgICAgICAgaW5mbGVjdGlvbi5wbHVyYWxpemUocmVzb3VyY2VOYW1lKSA9PT0gcmVzb3VyY2VOYW1lICYmXG4gICAgICAgICAgICBhcGkubWV0aG9kTmFtZSA9PT0gXCJmaW5kTWFueVwiO1xuXG4gICAgICAgICAgaWYgKGlzSW5maW5pdGVUYXJnZXQpIHtcbiAgICAgICAgICAgIGNvbnN0IGluZmluaXRlTWV0aG9kTmFtZSA9IGAke21ldGhvZE5hbWV9SW5maW5pdGVgO1xuICAgICAgICAgICAgY29uc3QgaW5maW5pdGVIb29rTmFtZSA9IGB1c2Uke2luZmxlY3Rpb24uY2FtZWxpemUoaG9va05hbWUpfUluZmluaXRlYDtcblxuICAgICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCAke2luZmluaXRlTWV0aG9kTmFtZX1RdWVyeU9wdGlvbnMgPSAke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSkgPT4gaW5maW5pdGVRdWVyeU9wdGlvbnMoe1xuICBxdWVyeUtleTogWycke21vZGVsTmFtZX0nLCAnJHttZXRob2ROYW1lfScsICdpbmZpbml0ZScke3BhcmFtTmFtZXMgPyBgLCAke3BhcmFtTmFtZXN9YCA6IFwiXCJ9XSxcbiAgcXVlcnlGbjogKHsgcGFnZVBhcmFtIH0pID0+ICR7bWV0aG9kTmFtZX0oJHtcbiAgICBwYXJhbU5hbWVzID8gcGFyYW1OYW1lcy5yZXBsYWNlKC9cXGJyYXdQYXJhbXNcXGIvLCBcInsgLi4ucmF3UGFyYW1zLCBwYWdlOiBwYWdlUGFyYW0gfVwiKSA6IFwiXCJcbiAgfSksXG4gIGluaXRpYWxQYWdlUGFyYW06IDEgYXMgbnVtYmVyLFxuICBnZXROZXh0UGFnZVBhcmFtOiAobGFzdFBhZ2UsIGFsbFBhZ2VzKSA9PiB7XG4gICAgY29uc3QgdG90YWwgPSAobGFzdFBhZ2UgYXMgeyB0b3RhbD86IG51bWJlciB9KT8udG90YWwgPz8gMDtcbiAgICBjb25zdCBsb2FkZWQgPSBhbGxQYWdlcy5yZWR1Y2UoXG4gICAgICAoc3VtLCBwKSA9PiBzdW0gKyAoKHAgYXMgeyByb3dzPzogdW5rbm93bltdIH0pPy5yb3dzPy5sZW5ndGggPz8gMCksXG4gICAgICAwLFxuICAgICk7XG4gICAgcmV0dXJuIGxvYWRlZCA8IHRvdGFsID8gYWxsUGFnZXMubGVuZ3RoICsgMSA6IHVuZGVmaW5lZDtcbiAgfSxcbiAgc2VsZWN0OiBkZWR1cGVBbmRGbGF0dGVuLFxufSk7XG4gICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgICAgYFxuZXhwb3J0IGNvbnN0ICR7aW5maW5pdGVIb29rTmFtZX0gPSAke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSR7XG4gICAgICAgICAgICAgICAgcGFyYW1zRGVmID8gXCIsIFwiIDogXCJcIlxuICAgICAgICAgICAgICB9b3B0aW9ucz86IHsgZW5hYmxlZD86IGJvb2xlYW4gfSkgPT5cbiAgdXNlUmVmcmVzaGFibGUodXNlSW5maW5pdGVRdWVyeSh7XG4gICAgLi4uJHtpbmZpbml0ZU1ldGhvZE5hbWV9UXVlcnlPcHRpb25zKCR7cGFyYW1OYW1lc30pLFxuICAgIC4uLm9wdGlvbnNcbiAgfSkpO1xuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyAzLiB1c2VNdXRhdGlvbiAodGFuc3RhY2stbXV0YXRpb24pXG4gICAgICAgIGlmIChjbGllbnRzLmluY2x1ZGVzKFwidGFuc3RhY2stbXV0YXRpb25cIikpIHtcbiAgICAgICAgICBjb25zdCBob29rTmFtZSA9IGluZmxlY3Rpb24uY2FtZWxpemUoYXBpLm1ldGhvZE5hbWUpO1xuICAgICAgICAgIGNvbnN0IG11dGF0aW9uUGFyYW1UeXBlID1cbiAgICAgICAgICAgIHBhcmFtc1dpdGhvdXRDb250ZXh0Lmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgPyBgeyAke3BhcmFtc1dpdGhvdXRDb250ZXh0XG4gICAgICAgICAgICAgICAgICAubWFwKChwKSA9PiBgJHtwLm5hbWV9OiAke2FwaVBhcmFtVHlwZVRvVHNUeXBlKHAudHlwZSwgW10pfWApXG4gICAgICAgICAgICAgICAgICAuam9pbihcIiwgXCIpfSB9YFxuICAgICAgICAgICAgICA6IFwidm9pZFwiO1xuICAgICAgICAgIGNvbnN0IG11dGF0aW9uUGFyYW1OYW1lcyA9XG4gICAgICAgICAgICBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwXG4gICAgICAgICAgICAgID8gcGFyYW1zV2l0aG91dENvbnRleHQubWFwKChwKSA9PiBgcGFyYW1zLiR7cC5uYW1lfWApLmpvaW4oXCIsIFwiKVxuICAgICAgICAgICAgICA6IFwiXCI7XG5cbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCB1c2Uke2hvb2tOYW1lfU11dGF0aW9uID0gJHt0eXBlUGFyYW1zRGVmfSgpID0+IHVzZU11dGF0aW9uKHtcbiAgbXV0YXRpb25GbjogKHBhcmFtczogJHttdXRhdGlvblBhcmFtVHlwZX0pID0+ICR7bWV0aG9kTmFtZX0oJHttdXRhdGlvblBhcmFtTmFtZXN9KVxufSk7XG4gICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDQuIHVzZU11dGF0aW9uIHdpdGggbXVsdGlwYXJ0ICh0YW5zdGFjay1tdXRhdGlvbi1tdWx0aXBhcnQpXG4gICAgICAgIGlmIChjbGllbnRzLmluY2x1ZGVzKFwidGFuc3RhY2stbXV0YXRpb24tbXVsdGlwYXJ0XCIpKSB7XG4gICAgICAgICAgY29uc3QgaG9va05hbWUgPSBpbmZsZWN0aW9uLmNhbWVsaXplKGFwaS5tZXRob2ROYW1lKTtcblxuICAgICAgICAgIC8vIO2MjOudvOuvuO2EsCDtg4DsnoUg7KCV7J2YOiBwYXJhbXNEZWbsl5DshJwg7YOA7J6F66eMIOy2lOy2nFxuICAgICAgICAgIC8vIHBhcmFtc0RlZiDsmIg6IFwicGFyYW1zOiB7IGNhdGVnb3J5OiBzdHJpbmcgfVwiIOKGkiBcInsgY2F0ZWdvcnk6IHN0cmluZyB9XCJcbiAgICAgICAgICBjb25zdCBwYXJhbXNUeXBlRGVmID1cbiAgICAgICAgICAgIHBhcmFtc1dpdGhvdXRDb250ZXh0Lmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgPyBwYXJhbXNEZWYuc3BsaXQoXCI6XCIpLnNsaWNlKDEpLmpvaW4oXCI6XCIpLnRyaW0oKSAvLyBcInBhcmFtczogeyBjYXRlZ29yeTogc3RyaW5nIH1cIiDihpIgXCJ7IGNhdGVnb3J5OiBzdHJpbmcgfVwiXG4gICAgICAgICAgICAgIDogXCJcIjtcblxuICAgICAgICAgIGNvbnN0IG11dGF0aW9uUGFyYW1UeXBlID1cbiAgICAgICAgICAgIHBhcmFtc1dpdGhvdXRDb250ZXh0Lmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgPyBgeyBwYXJhbXM6ICR7cGFyYW1zVHlwZURlZn0sIGZpbGVzOiBGaWxlW10gfWBcbiAgICAgICAgICAgICAgOiBgeyBmaWxlczogRmlsZVtdIH1gO1xuXG4gICAgICAgICAgLy8gbXV0YXRpb25GbiDtmLjstpwg7YyM652866+47YSwXG4gICAgICAgICAgY29uc3QgbXV0YXRpb25GbkNhbGwgPVxuICAgICAgICAgICAgcGFyYW1zV2l0aG91dENvbnRleHQubGVuZ3RoID4gMFxuICAgICAgICAgICAgICA/IGAke21ldGhvZE5hbWV9KHBhcmFtcy5wYXJhbXMsIHBhcmFtcy5maWxlcylgXG4gICAgICAgICAgICAgIDogYCR7bWV0aG9kTmFtZX0ocGFyYW1zLmZpbGVzKWA7XG5cbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCB1c2Uke2hvb2tOYW1lfU11dGF0aW9uID0gJHt0eXBlUGFyYW1zRGVmfShcbiAgb3B0aW9ucz86IFVzZU11dGF0aW9uT3B0aW9uczwke3JldHVyblR5cGVEZWZ9LCBFcnJvciwgJHttdXRhdGlvblBhcmFtVHlwZX0+ICYge1xuICAgIG9uVXBsb2FkUHJvZ3Jlc3M/OiAoZTogQXhpb3NQcm9ncmVzc0V2ZW50KSA9PiB2b2lkO1xuICB9XG4pID0+IHVzZU11dGF0aW9uKHtcbiAgbXV0YXRpb25GbjogKHBhcmFtczogJHttdXRhdGlvblBhcmFtVHlwZX0pID0+ICR7bXV0YXRpb25GbkNhbGx9LFxuICByZXRyeTogZmFsc2UsXG4gIC4uLm9wdGlvbnMsXG59KTtcbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIG5hbWVzcGFjZXMucHVzaChcbiAgICAgICAgYFxuZXhwb3J0IG5hbWVzcGFjZSAke21vZGVsTmFtZX1TZXJ2aWNlIHtcbiR7ZnVuY3Rpb25zLmpvaW4oXCJcXG5cXG5cIil9XG59XG4gICAgICBgLnRyaW0oKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQXN5bmNJZENvbmZpZyDsg53shLEgKEVudGl0eeuzhOuhnClcbiAgICBjb25zdCBlbnRpdHlJZHMgPSBFbnRpdHlNYW5hZ2VyLmdldEFsbElkcygpO1xuICAgIGNvbnN0IGFzeW5jSWRDb25maWdzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBlbnRpdHlJZCBvZiBlbnRpdHlJZHMpIHtcbiAgICAgIGNvbnN0IG5hbWVzID0gRW50aXR5TWFuYWdlci5nZXROYW1lc0Zyb21JZChlbnRpdHlJZCk7XG5cbiAgICAgIC8vIEFzeW5jSWRDb25maWfsmqkg66as7Iqk7Yq4IOyhsO2ajCBBUEkg7LC+6riwXG4gICAgICBjb25zdCBsaXN0QXBpID0gYXBpc0J5TW9kZWwuZ2V0KG5hbWVzLmNhcGl0YWwpPy5maW5kKChhcGkpID0+IHtcbiAgICAgICAgLy8gcmVzb3VyY2VOYW1l7J20IOyXhuqxsOuCmCB0YW5zdGFjay1xdWVyeeulvCDsgqzsmqntlZjsp4Ag7JWK64qUIEFQSeuKlCDsoJzsmbhcbiAgICAgICAgaWYgKCFhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUgfHwgIWFwaS5vcHRpb25zLmNsaWVudHM/LmluY2x1ZGVzKFwidGFuc3RhY2stcXVlcnlcIikpIHtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgLy8gcmVzb3VyY2VOYW1l7J20IOuzteyImO2YleydtOqzoCDrqZTshJzrk5zrqoXsnbQgZmluZE1hbnnsnbggQVBJXG4gICAgICAgIGNvbnN0IHJlc291cmNlTmFtZSA9IGFwaS5vcHRpb25zLnJlc291cmNlTmFtZTtcbiAgICAgICAgcmV0dXJuIGluZmxlY3Rpb24ucGx1cmFsaXplKHJlc291cmNlTmFtZSkgPT09IHJlc291cmNlTmFtZSAmJiBhcGkubWV0aG9kTmFtZSA9PT0gXCJmaW5kTWFueVwiO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChsaXN0QXBpKSB7XG4gICAgICAgIC8vIHJlc291cmNlTmFtZeyXkOyEnCBob29rIOydtOumhCDsg53shLEgKOq4sOyhtCDroZzsp4Hqs7wg64+Z7J28KVxuICAgICAgICBjb25zdCBob29rTmFtZSA9IGluZmxlY3Rpb24uY2FtZWxpemUoYXNzZXJ0RGVmaW5lZChsaXN0QXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lKSwgdHJ1ZSk7XG4gICAgICAgIGNvbnN0IHVzZUhvb2tOYW1lID0gYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShob29rTmFtZSl9YDtcbiAgICAgICAgY29uc3QgdXNlSG9va0luZmluaXRlTmFtZSA9IGAke3VzZUhvb2tOYW1lfUluZmluaXRlYDtcblxuICAgICAgICAvLyBMaXN0UGFyYW1zIO2DgOyeheuqhSDqtazshLFcbiAgICAgICAgY29uc3QgbGlzdFBhcmFtc1R5cGUgPSBgJHtuYW1lcy5jYXBpdGFsfUxpc3RQYXJhbXNgO1xuXG4gICAgICAgIGFzeW5jSWRDb25maWdzLnB1c2goXG4gICAgICAgICAgYFxuLy8gQXN5bmNJZENvbmZpZzogJHtuYW1lcy5jYXBpdGFsfVxuZXhwb3J0IGNvbnN0ICR7bmFtZXMuY2FwaXRhbH1Bc3luY0lkQ29uZmlnOiBBc3luY0lkQ29uZmlnPCR7bmFtZXMuY2FwaXRhbH1TdWJzZXRLZXksICR7bmFtZXMuY2FwaXRhbH1TdWJzZXRNYXBwaW5nLCAke2xpc3RQYXJhbXNUeXBlfT4gPSB7XG4gIHBsYWNlaG9sZGVyS2V5OiBcImVudGl0eS4ke25hbWVzLmNhcGl0YWx9XCIsXG4gIHVzZUxpc3Q6ICR7bmFtZXMuY2FwaXRhbH1TZXJ2aWNlLiR7dXNlSG9va05hbWV9LFxuICB1c2VMaXN0SW5maW5pdGU6ICR7bmFtZXMuY2FwaXRhbH1TZXJ2aWNlLiR7dXNlSG9va0luZmluaXRlTmFtZX0sXG59O1xuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEJVSUxUX0lOX1RZUEVT7JeQ7IScIOyCrOyaqeuQmOuKlCDtg4DsnoXrk6TsnYQg7ZmV7J247ZWY7JesIOuPmeyggeycvOuhnCBpbXBvcnQg6rWs7ISxXG4gICAgY29uc3QgYnVpbHRJblR5cGVJbXBvcnRzID0gT2JqZWN0LmtleXMoQlVJTFRfSU5fVFlQRVMpXG4gICAgICAuZmlsdGVyKCh0eXBlS2V5KSA9PiBpbXBvcnRLZXlzLmluY2x1ZGVzKHR5cGVLZXkpKVxuICAgICAgLm1hcCgodHlwZUtleSkgPT4gYHR5cGUgJHt0eXBlS2V5fWApO1xuXG4gICAgLy8gc29uYW11LnNoYXJlZOyXkOyEnCBpbXBvcnTtlaAg7ZWt66qp65Ok7J2EIOuPmeyggeycvOuhnCDqtazshLFcbiAgICAvLyBib2R5IOusuOyekOyXtOydhCDquLDspIDsnLzroZwgaW5maW5pdGUg7ZuFIOyDneyEsSDsl6zrtoAg7YyQ64uoIChmaW5kTWFueSDrs7XsiJjtmJUg67aE6riw7JeQ7ISc66eMIOywuOyhsOuQqClcbiAgICBjb25zdCBib2R5Rm9ySW1wb3J0Q2hlY2sgPSBuYW1lc3BhY2VzLmpvaW4oXCJcXG5cXG5cIik7XG4gICAgY29uc3QgbmVlZHNEZWR1cGVBbmRGbGF0dGVuID0gYm9keUZvckltcG9ydENoZWNrLmluY2x1ZGVzKFwiZGVkdXBlQW5kRmxhdHRlblwiKTtcbiAgICBjb25zdCBuZWVkc1VzZVJlZnJlc2hhYmxlID0gYm9keUZvckltcG9ydENoZWNrLmluY2x1ZGVzKFwidXNlUmVmcmVzaGFibGVcIik7XG5cbiAgICBjb25zdCBzb25hbXVTaGFyZWRJbXBvcnRzID0gW1xuICAgICAgXCJ0eXBlIExpc3RSZXN1bHRcIixcbiAgICAgIFwidHlwZSBGaWx0ZXJRdWVyeVwiLFxuICAgICAgLi4uYnVpbHRJblR5cGVJbXBvcnRzLFxuICAgICAgXCJmZXRjaFwiLFxuICAgICAgXCJ0eXBlIEV2ZW50SGFuZGxlcnNcIixcbiAgICAgIFwidHlwZSBTU0VTdHJlYW1PcHRpb25zXCIsXG4gICAgICBcInR5cGUgV2ViU29ja2V0Q2hhbm5lbE9wdGlvbnNcIixcbiAgICAgIFwidXNlU1NFU3RyZWFtXCIsXG4gICAgICBcInVzZVdlYlNvY2tldENoYW5uZWxcIixcbiAgICAgIFwidG9Gb3JtRGF0YVwiLFxuICAgICAgLi4uKG5lZWRzRGVkdXBlQW5kRmxhdHRlbiA/IFtcImRlZHVwZUFuZEZsYXR0ZW5cIl0gOiBbXSksXG4gICAgICAuLi4obmVlZHNVc2VSZWZyZXNoYWJsZSA/IFtcInVzZVJlZnJlc2hhYmxlXCJdIDogW10pLFxuICAgIF0uam9pbihcIiwgXCIpO1xuXG4gICAgLy8gYm9keSDqtazshLE6IG5hbWVzcGFjZXMgKyBhc3luY0lkQ29uZmlnc1xuICAgIGNvbnN0IGJvZHlQYXJ0cyA9IFsuLi5uYW1lc3BhY2VzLCAuLi5hc3luY0lkQ29uZmlnc107XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4udGhpcy5nZXRUYXJnZXRBbmRQYXRoKCksXG4gICAgICBib2R5OiBib2R5UGFydHMuam9pbihcIlxcblxcblwiKSxcbiAgICAgIGltcG9ydEtleXM6IGRpZmYodW5pcXVlKGltcG9ydEtleXMpLCBbXG4gICAgICAgIC4uLnR5cGVQYXJhbU5hbWVzLFxuICAgICAgICBcIkxpc3RSZXN1bHRcIixcbiAgICAgICAgLi4uT2JqZWN0LmtleXMoQlVJTFRfSU5fVFlQRVMpLFxuICAgICAgXSksXG4gICAgICBjdXN0b21IZWFkZXJzOiBbXG4gICAgICAgIFwiLyoqXCIsXG4gICAgICAgIFwiICogQGdlbmVyYXRlZFwiLFxuICAgICAgICBcIiAqIOyngeygkSDsiJjsoJXtlZjsp4Ag66eI7IS47JqULlwiLFxuICAgICAgICBcIiAqL1wiLFxuICAgICAgICBcIlwiLFxuICAgICAgICBcIi8qIG94bGludC1kaXNhYmxlICovXCIsXG4gICAgICAgIFwiXCIsXG4gICAgICAgIGBpbXBvcnQgeyBxdWVyeU9wdGlvbnMsIHVzZVF1ZXJ5LCB1c2VJbmZpbml0ZVF1ZXJ5LCBpbmZpbml0ZVF1ZXJ5T3B0aW9ucywgdXNlTXV0YXRpb24sIHR5cGUgVXNlTXV0YXRpb25PcHRpb25zIH0gZnJvbSAnQHRhbnN0YWNrL3JlYWN0LXF1ZXJ5JztgLFxuICAgICAgICBgaW1wb3J0IHsgdHlwZSBBeGlvc1Byb2dyZXNzRXZlbnQgfSBmcm9tICdheGlvcyc7YCxcbiAgICAgICAgYGltcG9ydCBxcyBmcm9tICdxcyc7YCxcbiAgICAgICAgYGltcG9ydCB7ICR7c29uYW11U2hhcmVkSW1wb3J0c30gfSBmcm9tICcuL3NvbmFtdS5zaGFyZWQnO2AsXG4gICAgICAgIGBpbXBvcnQgeyB0eXBlIEFzeW5jSWRDb25maWcgfSBmcm9tICdAc29uYW11LWtpdC9yZWFjdC1jb21wb25lbnRzL2NvbXBvbmVudHMnO2AsXG4gICAgICBdLFxuICAgIH07XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztxQkFPa0M7WUFFTztvQkFDa0I7V0FFWDtXQUNDO2NBQ1g7bUJBQytCO0FBRXJFLElBQWEscUJBQWIsY0FBd0MsU0FBUztDQUMvQyxjQUFjO0VBQ1osTUFBTSxVQUFVO0NBQ2xCO0NBRUEsbUJBQW1CO0VBQ2pCLE9BQU87R0FDTCxRQUFRO0dBQ1IsTUFBTTtFQUNSO0NBQ0Y7Q0FFQSxPQUFPLElBQWlDO0VBQ3RDLE1BQU0sRUFBRSxTQUFTLE9BQU87RUFHeEIsTUFBTSw4QkFBYyxJQUFJLElBQTJCO0VBQ25ELEtBQUssTUFBTSxPQUFPLE1BQU07R0FDdEIsTUFBTSxZQUFZLElBQUksVUFBVSxRQUFRLFVBQVUsRUFBRSxDQUFDLENBQUMsUUFBUSxVQUFVLEVBQUU7R0FDMUUsSUFBSSxDQUFDLFlBQVksSUFBSSxTQUFTLEdBQzVCLFlBQVksSUFBSSxXQUFXLENBQUMsQ0FBQztHQUUvQixZQUFZLElBQUksU0FBUyxDQUFDLEVBQUUsS0FBSyxHQUFHO0VBQ3RDO0VBRUEsTUFBTSxhQUF1QixDQUFDO0VBQzlCLE1BQU0sYUFB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
303
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZXMudGVtcGxhdGUuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RlbXBsYXRlL2ltcGxlbWVudGF0aW9ucy9zZXJ2aWNlcy50ZW1wbGF0ZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgaW5mbGVjdGlvbiBmcm9tIFwiaW5mbGVjdGlvblwiO1xuaW1wb3J0IHsgZGlmZiwgdW5pcXVlIH0gZnJvbSBcInJhZGFzaGlcIjtcblxuaW1wb3J0IHtcbiAgYXBpUGFyYW1Ub1RzQ29kZSxcbiAgYXBpUGFyYW1UeXBlVG9Uc1R5cGUsXG4gIHVud3JhcFByb21pc2VPbmNlLFxufSBmcm9tIFwiLi4vLi4vYXBpL2NvZGUtY29udmVydGVyc1wiO1xuaW1wb3J0IHsgdHlwZSBFeHRlbmRlZEFwaSB9IGZyb20gXCIuLi8uLi9hcGkvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgU29uYW11IH0gZnJvbSBcIi4uLy4uL2FwaS9zb25hbXVcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIgfSBmcm9tIFwiLi4vLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyB0eXBlIFRlbXBsYXRlT3B0aW9ucyB9IGZyb20gXCIuLi8uLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgQXBpUGFyYW1UeXBlIH0gZnJvbSBcIi4uLy4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBhc3NlcnREZWZpbmVkIH0gZnJvbSBcIi4uLy4uL3V0aWxzL3V0aWxzXCI7XG5pbXBvcnQgeyBUZW1wbGF0ZSB9IGZyb20gXCIuLi90ZW1wbGF0ZVwiO1xuaW1wb3J0IHsgQlVJTFRfSU5fVFlQRVMsIHpvZFR5cGVUb1RzVHlwZURlZiB9IGZyb20gXCIuLi96b2QtY29udmVydGVyXCI7XG5cbmV4cG9ydCBjbGFzcyBUZW1wbGF0ZV9fc2VydmljZXMgZXh0ZW5kcyBUZW1wbGF0ZSB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKFwic2VydmljZXNcIik7XG4gIH1cblxuICBnZXRUYXJnZXRBbmRQYXRoKCkge1xuICAgIHJldHVybiB7XG4gICAgICB0YXJnZXQ6IFwiOnRhcmdldC9zcmMvc2VydmljZXNcIixcbiAgICAgIHBhdGg6IGBzZXJ2aWNlcy5nZW5lcmF0ZWQudHNgLFxuICAgIH07XG4gIH1cblxuICByZW5kZXIoe306IFRlbXBsYXRlT3B0aW9uc1tcInNlcnZpY2VzXCJdKSB7XG4gICAgY29uc3QgeyBhcGlzIH0gPSBTb25hbXUuc3luY2VyO1xuXG4gICAgLy8g66qo642467OE66GcIOq3uOujue2ZlFxuICAgIGNvbnN0IGFwaXNCeU1vZGVsID0gbmV3IE1hcDxzdHJpbmcsIEV4dGVuZGVkQXBpW10+KCk7XG4gICAgZm9yIChjb25zdCBhcGkgb2YgYXBpcykge1xuICAgICAgY29uc3QgbW9kZWxOYW1lID0gYXBpLm1vZGVsTmFtZS5yZXBsYWNlKC9Nb2RlbCQvLCBcIlwiKS5yZXBsYWNlKC9GcmFtZSQvLCBcIlwiKTtcbiAgICAgIGlmICghYXBpc0J5TW9kZWwuaGFzKG1vZGVsTmFtZSkpIHtcbiAgICAgICAgYXBpc0J5TW9kZWwuc2V0KG1vZGVsTmFtZSwgW10pO1xuICAgICAgfVxuICAgICAgYXBpc0J5TW9kZWwuZ2V0KG1vZGVsTmFtZSk/LnB1c2goYXBpKTtcbiAgICB9XG5cbiAgICBjb25zdCBpbXBvcnRLZXlzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IG5hbWVzcGFjZXM6IHN0cmluZ1tdID0gW107XG4gICAgbGV0IHR5cGVQYXJhbU5hbWVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IHJlc29sdmVXZWJTb2NrZXRFdmVudFR5cGVEZWYgPSAoXG4gICAgICB0eXBlUmVmOiBBcGlQYXJhbVR5cGUuUmVmIHwgdW5kZWZpbmVkLFxuICAgICAgc2NoZW1hOiBQYXJhbWV0ZXJzPHR5cGVvZiB6b2RUeXBlVG9Uc1R5cGVEZWY+WzBdLFxuICAgICk6IHN0cmluZyA9PiB7XG4gICAgICBpZiAodHlwZVJlZikge1xuICAgICAgICBjb25zdCBjYW5kaWRhdGVJbXBvcnRLZXlzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBjb25zdCBjYW5kaWRhdGVUeXBlRGVmID0gYXBpUGFyYW1UeXBlVG9Uc1R5cGUodHlwZVJlZiwgY2FuZGlkYXRlSW1wb3J0S2V5cyk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBmb3IgKGNvbnN0IGtleSBvZiB1bmlxdWUoY2FuZGlkYXRlSW1wb3J0S2V5cykpIHtcbiAgICAgICAgICAgIEVudGl0eU1hbmFnZXIuZ2V0TW9kdWxlUGF0aChrZXkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpbXBvcnRLZXlzLnB1c2goLi4uY2FuZGlkYXRlSW1wb3J0S2V5cyk7XG4gICAgICAgICAgcmV0dXJuIGNhbmRpZGF0ZVR5cGVEZWY7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIOuhnOy7rCBjb25zdCDrk7EgaW1wb3J0IOqwgOuKpe2VnCDsi6zrs7zsnbQg7JWE64uI66m0IOq4sOyhtCBpbmxpbmUg7IOd7ISx7Jy866GcIO2bhO2HtFxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB6b2RUeXBlVG9Uc1R5cGVEZWYoc2NoZW1hKTtcbiAgICB9O1xuXG4gICAgZm9yIChjb25zdCBbbW9kZWxOYW1lLCBtb2RlbEFwaXNdIG9mIGFwaXNCeU1vZGVsKSB7XG4gICAgICBjb25zdCBmdW5jdGlvbnM6IHN0cmluZ1tdID0gW107XG5cbiAgICAgIGZvciAoY29uc3QgYXBpIG9mIG1vZGVsQXBpcykge1xuICAgICAgICAvLyBAc3RyZWFtIOuNsOy9lOugiOydtO2EsOqwgCDsnojsnLzrqbQgU1NFIOyKpO2KuOumvCDtlajsiJgg7IOd7ISxXG4gICAgICAgIGlmIChhcGkuc3RyZWFtT3B0aW9ucykge1xuICAgICAgICAgIGNvbnN0IHBhcmFtc1dpdGhvdXRDb250ZXh0ID0gYXBpLnBhcmFtZXRlcnMuZmlsdGVyKFxuICAgICAgICAgICAgKHBhcmFtKSA9PlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzUmVmS25leChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhKHBhcmFtLm9wdGlvbmFsICYmIHBhcmFtLm5hbWUuc3RhcnRzV2l0aChcIl9cIikpLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBjb25zdCBhcGlCYXNlVXJsID0gYCR7U29uYW11LmNvbmZpZy5hcGkucm91dGUucHJlZml4fSR7YXBpLnBhdGh9YDtcblxuICAgICAgICAgIGNvbnN0IG1ldGhvZE5hbWVTdHJlYW0gPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICAgID8gYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUpfWBcbiAgICAgICAgICAgIDogYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSl9YDtcbiAgICAgICAgICBjb25zdCBtZXRob2ROYW1lU3RyZWFtQ2FtZWxpemVkID0gaW5mbGVjdGlvbi5jYW1lbGl6ZShtZXRob2ROYW1lU3RyZWFtLCB0cnVlKTtcblxuICAgICAgICAgIGNvbnN0IGV2ZW50c1R5cGVEZWYgPSB6b2RUeXBlVG9Uc1R5cGVEZWYoYXBpLnN0cmVhbU9wdGlvbnMuZXZlbnRzKTtcblxuICAgICAgICAgIC8vIO2MjOudvOuvuO2EsOulvCDqsJ3ssrQg7ZiV7YOc66GcIOygleydmCAo7YOA7J6F6rO8IOyLpOygnCDqsJIg66qo65GQ7JeQIOyCrOyaqSlcbiAgICAgICAgICBjb25zdCBwYXJhbXNEZWZBc09iamVjdCA9XG4gICAgICAgICAgICBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwXG4gICAgICAgICAgICAgID8gYHsgJHtwYXJhbXNXaXRob3V0Q29udGV4dC5tYXAoKHApID0+IGAke3AubmFtZX06ICR7YXBpUGFyYW1UeXBlVG9Uc1R5cGUocC50eXBlLCBpbXBvcnRLZXlzKX1gKS5qb2luKFwiLCBcIil9IH1gXG4gICAgICAgICAgICAgIDogXCJ7fVwiO1xuXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgZnVuY3Rpb24gJHttZXRob2ROYW1lU3RyZWFtQ2FtZWxpemVkfShcbiAgcGFyYW1zOiAke3BhcmFtc0RlZkFzT2JqZWN0fSxcbiAgaGFuZGxlcnM6IEV2ZW50SGFuZGxlcnM8JHtldmVudHNUeXBlRGVmfSAmIHsgZW5kPzogKCkgPT4gdm9pZCB9PixcbiAgb3B0aW9uczogU1NFU3RyZWFtT3B0aW9uc1xuKSB7XG4gIHJldHVybiB1c2VTU0VTdHJlYW08JHtldmVudHNUeXBlRGVmfT4oXFxgJHthcGlCYXNlVXJsfVxcYCwgcGFyYW1zLCBoYW5kbGVycywgb3B0aW9ucyk7XG59XG4gICAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGFwaS53ZWJzb2NrZXRPcHRpb25zKSB7XG4gICAgICAgICAgLy8gd2Vic29ja2V0IHN1cmZhY2XripQgZmV0Y2gg7ZWo7IiYIOuMgOyLoCB0eXBlZCBob29r7J2EIOyDneyEse2VqFxuICAgICAgICAgIGNvbnN0IHBhcmFtc1dpdGhvdXRDb250ZXh0ID0gYXBpLnBhcmFtZXRlcnMuZmlsdGVyKFxuICAgICAgICAgICAgKHBhcmFtKSA9PlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzUmVmS25leChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAhKHBhcmFtLm9wdGlvbmFsICYmIHBhcmFtLm5hbWUuc3RhcnRzV2l0aChcIl9cIikpLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBjb25zdCBhcGlCYXNlVXJsID0gYCR7U29uYW11LmNvbmZpZy5hcGkucm91dGUucHJlZml4fSR7YXBpLnBhdGh9YDtcblxuICAgICAgICAgIGNvbnN0IG1ldGhvZE5hbWVXZWJTb2NrZXQgPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWVcbiAgICAgICAgICAgID8gYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUpfWBcbiAgICAgICAgICAgIDogYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSl9YDtcbiAgICAgICAgICBjb25zdCBtZXRob2ROYW1lV2ViU29ja2V0Q2FtZWxpemVkID0gaW5mbGVjdGlvbi5jYW1lbGl6ZShtZXRob2ROYW1lV2ViU29ja2V0LCB0cnVlKTtcblxuICAgICAgICAgIC8vIG91dEV2ZW50c+uKlCDsiJjsi6Ag7YOA7J6FLCBpbkV2ZW50c+uKlCBzZW5kKCkg7J6F66ClIO2DgOyeheycvOuhnCDsgqzsmqntlahcbiAgICAgICAgICBjb25zdCBvdXRFdmVudHNUeXBlRGVmID0gcmVzb2x2ZVdlYlNvY2tldEV2ZW50VHlwZURlZihcbiAgICAgICAgICAgIGFwaS53ZWJzb2NrZXRPcHRpb25zLm91dEV2ZW50c1R5cGVSZWYsXG4gICAgICAgICAgICBhcGkud2Vic29ja2V0T3B0aW9ucy5vdXRFdmVudHMsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBpbkV2ZW50c1R5cGVEZWYgPSByZXNvbHZlV2ViU29ja2V0RXZlbnRUeXBlRGVmKFxuICAgICAgICAgICAgYXBpLndlYnNvY2tldE9wdGlvbnMuaW5FdmVudHNUeXBlUmVmLFxuICAgICAgICAgICAgYXBpLndlYnNvY2tldE9wdGlvbnMuaW5FdmVudHMsXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIGNvbnRleHQvcmVmS25leC9pbnRlcm5hbCBvcHRpb25hbCDtjIzrnbzrr7jthLDripQg7YG065287J207Ja47Yq4IOyeheugpeyXkOyEnCDsoJzsmbjtlahcbiAgICAgICAgICBjb25zdCBwYXJhbXNEZWZBc09iamVjdCA9XG4gICAgICAgICAgICBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwXG4gICAgICAgICAgICAgID8gYHsgJHtwYXJhbXNXaXRob3V0Q29udGV4dC5tYXAoKHApID0+IGAke3AubmFtZX06ICR7YXBpUGFyYW1UeXBlVG9Uc1R5cGUocC50eXBlLCBpbXBvcnRLZXlzKX1gKS5qb2luKFwiLCBcIil9IH1gXG4gICAgICAgICAgICAgIDogXCJ7fVwiO1xuXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgZnVuY3Rpb24gJHttZXRob2ROYW1lV2ViU29ja2V0Q2FtZWxpemVkfShcbiAgcGFyYW1zOiAke3BhcmFtc0RlZkFzT2JqZWN0fSxcbiAgaGFuZGxlcnM6IEV2ZW50SGFuZGxlcnM8JHtvdXRFdmVudHNUeXBlRGVmfT4sXG4gIG9wdGlvbnM6IFdlYlNvY2tldENoYW5uZWxPcHRpb25zID0ge31cbikge1xuICByZXR1cm4gdXNlV2ViU29ja2V0Q2hhbm5lbDwke291dEV2ZW50c1R5cGVEZWZ9LCAke2luRXZlbnRzVHlwZURlZn0+KFxcYCR7YXBpQmFzZVVybH1cXGAsIHBhcmFtcywgaGFuZGxlcnMsIG9wdGlvbnMpO1xufVxuICAgICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENvbnRleHQg7KCc7Jm47ZWcIO2MjOudvOuvuO2EsFxuICAgICAgICBjb25zdCBwYXJhbXNXaXRob3V0Q29udGV4dCA9IGFwaS5wYXJhbWV0ZXJzLmZpbHRlcihcbiAgICAgICAgICAocGFyYW0pID0+XG4gICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgIUFwaVBhcmFtVHlwZS5pc1JlZktuZXgocGFyYW0udHlwZSkgJiZcbiAgICAgICAgICAgICEocGFyYW0ub3B0aW9uYWwgJiYgcGFyYW0ubmFtZS5zdGFydHNXaXRoKFwiX1wiKSksXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8g7YOA7J6FIO2MjOudvOuvuO2EsCDsoJXsnZhcbiAgICAgICAgY29uc3QgdHlwZVBhcmFtZXRlcnNBc1RzVHlwZSA9IGFwaS50eXBlUGFyYW1ldGVyc1xuICAgICAgICAgIC5tYXAoKHR5cGVQYXJhbSkgPT4gYXBpUGFyYW1UeXBlVG9Uc1R5cGUodHlwZVBhcmFtLCBpbXBvcnRLZXlzKSlcbiAgICAgICAgICAuam9pbihcIiwgXCIpO1xuICAgICAgICBjb25zdCB0eXBlUGFyYW1zRGVmID0gdHlwZVBhcmFtZXRlcnNBc1RzVHlwZSA/IGA8JHt0eXBlUGFyYW1ldGVyc0FzVHNUeXBlfT5gIDogXCJcIjtcbiAgICAgICAgdHlwZVBhcmFtTmFtZXMgPSB0eXBlUGFyYW1OYW1lcy5jb25jYXQoYXBpLnR5cGVQYXJhbWV0ZXJzLm1hcCgodHApID0+IHRwLmlkKSk7XG5cbiAgICAgICAgLy8g7YyM652866+47YSwIOygleydmFxuICAgICAgICBjb25zdCBwYXJhbXNEZWYgPSBhcGlQYXJhbVRvVHNDb2RlKHBhcmFtc1dpdGhvdXRDb250ZXh0LCBpbXBvcnRLZXlzKTtcbiAgICAgICAgY29uc3QgcGFyYW1OYW1lcyA9IHBhcmFtc1dpdGhvdXRDb250ZXh0Lm1hcCgocCkgPT4gcC5uYW1lKS5qb2luKFwiLCBcIik7XG5cbiAgICAgICAgLy8g66as7YS0IO2DgOyehSDsoJXsnZhcbiAgICAgICAgY29uc3QgcmV0dXJuVHlwZURlZiA9IGFwaVBhcmFtVHlwZVRvVHNUeXBlKFxuICAgICAgICAgIGFzc2VydERlZmluZWQodW53cmFwUHJvbWlzZU9uY2UoYXBpLnJldHVyblR5cGUpKSxcbiAgICAgICAgICBpbXBvcnRLZXlzLFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIOq4sOuzuCBVUkxcbiAgICAgICAgY29uc3QgYXBpQmFzZVVybCA9IGAke1NvbmFtdS5jb25maWcuYXBpLnJvdXRlLnByZWZpeH0ke2FwaS5wYXRofWA7XG5cbiAgICAgICAgY29uc3QgY2xpZW50cyA9IGFwaS5vcHRpb25zLmNsaWVudHMgfHwgW107XG5cbiAgICAgICAgLy8gMS4gYXhpb3Mg7ZWo7IiYIOyDneyEsVxuICAgICAgICAvLyByZXNvdXJjZU5hbWXsnbQg7J6I7Jy866m0IGdldCArIHJlc291cmNlTmFtZSDtmJXtg5zroZwg7ZWo7IiY66qFIOyDneyEsVxuICAgICAgICBjb25zdCBtZXRob2ROYW1lID0gYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lXG4gICAgICAgICAgPyBgZ2V0JHtpbmZsZWN0aW9uLmNhbWVsaXplKGFwaS5vcHRpb25zLnJlc291cmNlTmFtZSl9YFxuICAgICAgICAgIDogYXBpLm1ldGhvZE5hbWU7XG5cbiAgICAgICAgLy8gYXhpb3MtbXVsdGlwYXJ0IOyymOumrCAo7YyM7J28IOyXheuhnOuTnClcbiAgICAgICAgaWYgKGNsaWVudHMuaW5jbHVkZXMoXCJheGlvcy1tdWx0aXBhcnRcIikpIHtcbiAgICAgICAgICBjb25zdCBmb3JtRGF0YUFwcGVuZCA9IGBmaWxlcy5mb3JFYWNoKGYgPT4geyBmb3JtRGF0YS5hcHBlbmQoXCJmaWxlc1wiLCBmKTsgfSk7YDtcblxuICAgICAgICAgIGNvbnN0IG90aGVyUGFyYW1zQXBwZW5kID0gcGFyYW1zV2l0aG91dENvbnRleHRcbiAgICAgICAgICAgIC5tYXAoKHBhcmFtKSA9PiB7XG4gICAgICAgICAgICAgIC8vIHByaW1pdGl2ZSDtg4DsnoXsnbjsp4Ag7LK07YGsXG4gICAgICAgICAgICAgIGNvbnN0IGlzUHJpbWl0aXZlID1cbiAgICAgICAgICAgICAgICB0eXBlb2YgcGFyYW0udHlwZSA9PT0gXCJzdHJpbmdcIiAmJlxuICAgICAgICAgICAgICAgIFtcInN0cmluZ1wiLCBcIm51bWJlclwiLCBcImJvb2xlYW5cIl0uaW5jbHVkZXMocGFyYW0udHlwZSk7XG5cbiAgICAgICAgICAgICAgaWYgKGlzUHJpbWl0aXZlKSB7XG4gICAgICAgICAgICAgICAgLy8gcHJpbWl0aXZlOiDsp4HsoJEgZm9ybURhdGEuYXBwZW5kXG4gICAgICAgICAgICAgICAgcmV0dXJuIGBmb3JtRGF0YS5hcHBlbmQoJyR7cGFyYW0ubmFtZX0nLCBTdHJpbmcoJHtwYXJhbS5uYW1lfSkpO2A7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gb2JqZWN0OiB0b0Zvcm1EYXRhIOyCrOyaqVxuICAgICAgICAgICAgICAgIHJldHVybiBgdG9Gb3JtRGF0YSgke3BhcmFtLm5hbWV9LCBmb3JtRGF0YSwgJyR7cGFyYW0ubmFtZX0nKTtgO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmpvaW4oXCJcXG4gICAgXCIpO1xuXG4gICAgICAgICAgY29uc3QgcGFyYW1zRGVmQ29tbWEgPSBwYXJhbXNEZWYgIT09IFwiXCIgPyBcIiwgXCIgOiBcIlwiO1xuICAgICAgICAgIGZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICAgICAgYFxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uICR7bWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KFxuICAke3BhcmFtc0RlZn0ke3BhcmFtc0RlZkNvbW1hfVxuICBmaWxlczogRmlsZVtdLFxuICBvblVwbG9hZFByb2dyZXNzPzogKHBlOiBBeGlvc1Byb2dyZXNzRXZlbnQpID0+IHZvaWRcbik6IFByb21pc2U8JHtyZXR1cm5UeXBlRGVmfT4ge1xuICBjb25zdCBmb3JtRGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAke2Zvcm1EYXRhQXBwZW5kfVxuICAke290aGVyUGFyYW1zQXBwZW5kfVxuICByZXR1cm4gZmV0Y2goe1xuICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgIHVybDogXFxgJHthcGlCYXNlVXJsfVxcYCxcbiAgICBvblVwbG9hZFByb2dyZXNzLFxuICAgIGRhdGE6IGZvcm1EYXRhLFxuICAgICR7YXBpLm9wdGlvbnMudGltZW91dCA/IGBzaWduYWw6IEFib3J0U2lnbmFsLnRpbWVvdXQoJHthcGkub3B0aW9ucy50aW1lb3V0fSksYCA6IFwiXCJ9XG4gIH0pO1xufVxuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSBpZiAoYXBpLm9wdGlvbnMuaHR0cE1ldGhvZCA9PT0gXCJHRVRcIikge1xuICAgICAgICAgIGNvbnN0IGhhc1BhcmFtcyA9IHBhcmFtc1dpdGhvdXRDb250ZXh0Lmxlbmd0aCA+IDA7XG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHttZXRob2ROYW1lfSR7dHlwZVBhcmFtc0RlZn0oJHtwYXJhbXNEZWZ9KTogUHJvbWlzZTwke3JldHVyblR5cGVEZWZ9PiB7XG4gIHJldHVybiBmZXRjaCh7XG4gICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgIHVybDogXFxgJHthcGlCYXNlVXJsfSR7aGFzUGFyYW1zID8gYD9cXCR7cXMuc3RyaW5naWZ5KHsgJHtwYXJhbU5hbWVzfSB9KX1gIDogXCJcIn1cXGAsXG4gICAgJHthcGkub3B0aW9ucy50aW1lb3V0ID8gYHNpZ25hbDogQWJvcnRTaWduYWwudGltZW91dCgke2FwaS5vcHRpb25zLnRpbWVvdXR9KSxgIDogXCJcIn1cbiAgfSk7XG59XG4gICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBoYXNQYXJhbXMgPSBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwO1xuICAgICAgICAgIGZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICAgICAgYFxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uICR7bWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSk6IFByb21pc2U8JHtyZXR1cm5UeXBlRGVmfT4ge1xuICByZXR1cm4gZmV0Y2goe1xuICAgIG1ldGhvZDogXCIke2FwaS5vcHRpb25zLmh0dHBNZXRob2R9XCIsXG4gICAgdXJsOiBcXGAke2FwaUJhc2VVcmx9XFxgLFxuICAgICR7aGFzUGFyYW1zID8gYGRhdGE6IHsgJHtwYXJhbU5hbWVzfSB9LGAgOiBcIlwifVxuICAgICR7YXBpLm9wdGlvbnMudGltZW91dCA/IGBzaWduYWw6IEFib3J0U2lnbmFsLnRpbWVvdXQoJHthcGkub3B0aW9ucy50aW1lb3V0fSksYCA6IFwiXCJ9XG4gIH0pO1xufVxuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAyLiBxdWVyeU9wdGlvbnMgKyB1c2VRdWVyeSAodGFuc3RhY2stcXVlcnkpXG4gICAgICAgIGlmIChjbGllbnRzLmluY2x1ZGVzKFwidGFuc3RhY2stcXVlcnlcIikpIHtcbiAgICAgICAgICBjb25zdCBob29rTmFtZSA9IGFwaS5vcHRpb25zLnJlc291cmNlTmFtZVxuICAgICAgICAgICAgPyBpbmZsZWN0aW9uLmNhbWVsaXplKGFwaS5vcHRpb25zLnJlc291cmNlTmFtZSwgdHJ1ZSlcbiAgICAgICAgICAgIDogaW5mbGVjdGlvbi5jYW1lbGl6ZShhcGkubWV0aG9kTmFtZSwgdHJ1ZSk7XG5cbiAgICAgICAgICAvLyBxdWVyeU9wdGlvbnNcbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCAke21ldGhvZE5hbWV9UXVlcnlPcHRpb25zID0gJHt0eXBlUGFyYW1zRGVmfSgke3BhcmFtc0RlZn0pID0+IHF1ZXJ5T3B0aW9ucyh7XG4gIHF1ZXJ5S2V5OiBbJyR7bW9kZWxOYW1lfScsICcke21ldGhvZE5hbWV9JyR7cGFyYW1OYW1lcyA/IGAsICR7cGFyYW1OYW1lc31gIDogXCJcIn1dLFxuICBxdWVyeUZuOiAoKSA9PiAke21ldGhvZE5hbWV9KCR7cGFyYW1OYW1lc30pXG59KTtcbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gdXNlUXVlcnkgaG9vayAodXNlUmVmcmVzaGFibGXroZwg656Y7ZWR7ZW0IHJlZnJlc2gvaXNSZWZyZXNoaW5n7J2EIOq4sOuzuCDsoJzqs7UpXG4gICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICBgXG5leHBvcnQgY29uc3QgdXNlJHtpbmZsZWN0aW9uLmNhbWVsaXplKGhvb2tOYW1lKX0gPSAke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSR7XG4gICAgICAgICAgICAgIHBhcmFtc0RlZiA/IFwiLCBcIiA6IFwiXCJcbiAgICAgICAgICAgIH1vcHRpb25zPzogeyBlbmFibGVkPzogYm9vbGVhbiB9KSA9PlxuICB1c2VSZWZyZXNoYWJsZSh1c2VRdWVyeSh7XG4gICAgLi4uJHttZXRob2ROYW1lfVF1ZXJ5T3B0aW9ucygke3BhcmFtTmFtZXN9KSxcbiAgICAuLi5vcHRpb25zXG4gIH0pKTtcbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gaW5maW5pdGVRdWVyeU9wdGlvbnMgKyB1c2VJbmZpbml0ZVF1ZXJ5IChBc3luY0lkQ29uZmlnLnVzZUxpc3RJbmZpbml0ZSDrjIDsg4Eg7KGw6rG0KVxuICAgICAgICAgIC8vIOyhsOqxtDogcmVzb3VyY2VOYW1l7J20IOuzteyImO2YleydtOqzoCBtZXRob2ROYW1lID09PSBcImZpbmRNYW55XCJcbiAgICAgICAgICBjb25zdCByZXNvdXJjZU5hbWUgPSBhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWU7XG4gICAgICAgICAgY29uc3QgaXNJbmZpbml0ZVRhcmdldCA9XG4gICAgICAgICAgICAhIXJlc291cmNlTmFtZSAmJlxuICAgICAgICAgICAgaW5mbGVjdGlvbi5wbHVyYWxpemUocmVzb3VyY2VOYW1lKSA9PT0gcmVzb3VyY2VOYW1lICYmXG4gICAgICAgICAgICBhcGkubWV0aG9kTmFtZSA9PT0gXCJmaW5kTWFueVwiO1xuXG4gICAgICAgICAgaWYgKGlzSW5maW5pdGVUYXJnZXQpIHtcbiAgICAgICAgICAgIGNvbnN0IGluZmluaXRlTWV0aG9kTmFtZSA9IGAke21ldGhvZE5hbWV9SW5maW5pdGVgO1xuICAgICAgICAgICAgY29uc3QgaW5maW5pdGVIb29rTmFtZSA9IGB1c2Uke2luZmxlY3Rpb24uY2FtZWxpemUoaG9va05hbWUpfUluZmluaXRlYDtcblxuICAgICAgICAgICAgZnVuY3Rpb25zLnB1c2goXG4gICAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCAke2luZmluaXRlTWV0aG9kTmFtZX1RdWVyeU9wdGlvbnMgPSAke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSkgPT4gaW5maW5pdGVRdWVyeU9wdGlvbnMoe1xuICBxdWVyeUtleTogWycke21vZGVsTmFtZX0nLCAnJHttZXRob2ROYW1lfScsICdpbmZpbml0ZScke3BhcmFtTmFtZXMgPyBgLCAke3BhcmFtTmFtZXN9YCA6IFwiXCJ9XSxcbiAgcXVlcnlGbjogKHsgcGFnZVBhcmFtIH0pID0+ICR7bWV0aG9kTmFtZX0oJHtcbiAgICBwYXJhbU5hbWVzID8gcGFyYW1OYW1lcy5yZXBsYWNlKC9cXGJyYXdQYXJhbXNcXGIvLCBcInsgLi4ucmF3UGFyYW1zLCBwYWdlOiBwYWdlUGFyYW0gfVwiKSA6IFwiXCJcbiAgfSksXG4gIGluaXRpYWxQYWdlUGFyYW06IDEgYXMgbnVtYmVyLFxuICBnZXROZXh0UGFnZVBhcmFtOiAobGFzdFBhZ2UsIGFsbFBhZ2VzKSA9PiB7XG4gICAgY29uc3QgdG90YWwgPSAobGFzdFBhZ2UgYXMgeyB0b3RhbD86IG51bWJlciB9KT8udG90YWwgPz8gMDtcbiAgICBjb25zdCBsb2FkZWQgPSBhbGxQYWdlcy5yZWR1Y2UoXG4gICAgICAoc3VtLCBwKSA9PiBzdW0gKyAoKHAgYXMgeyByb3dzPzogdW5rbm93bltdIH0pPy5yb3dzPy5sZW5ndGggPz8gMCksXG4gICAgICAwLFxuICAgICk7XG4gICAgcmV0dXJuIGxvYWRlZCA8IHRvdGFsID8gYWxsUGFnZXMubGVuZ3RoICsgMSA6IHVuZGVmaW5lZDtcbiAgfSxcbiAgc2VsZWN0OiBkZWR1cGVBbmRGbGF0dGVuLFxufSk7XG4gICAgICAgICAgYC50cmltKCksXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgICAgYFxuZXhwb3J0IGNvbnN0ICR7aW5maW5pdGVIb29rTmFtZX0gPSAke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSR7XG4gICAgICAgICAgICAgICAgcGFyYW1zRGVmID8gXCIsIFwiIDogXCJcIlxuICAgICAgICAgICAgICB9b3B0aW9ucz86IHsgZW5hYmxlZD86IGJvb2xlYW4gfSkgPT5cbiAgdXNlUmVmcmVzaGFibGUodXNlSW5maW5pdGVRdWVyeSh7XG4gICAgLi4uJHtpbmZpbml0ZU1ldGhvZE5hbWV9UXVlcnlPcHRpb25zKCR7cGFyYW1OYW1lc30pLFxuICAgIC4uLm9wdGlvbnNcbiAgfSkpO1xuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyAzLiB1c2VNdXRhdGlvbiAodGFuc3RhY2stbXV0YXRpb24pXG4gICAgICAgIGlmIChjbGllbnRzLmluY2x1ZGVzKFwidGFuc3RhY2stbXV0YXRpb25cIikpIHtcbiAgICAgICAgICBjb25zdCBob29rTmFtZSA9IGluZmxlY3Rpb24uY2FtZWxpemUoYXBpLm1ldGhvZE5hbWUpO1xuICAgICAgICAgIGNvbnN0IG11dGF0aW9uUGFyYW1UeXBlID1cbiAgICAgICAgICAgIHBhcmFtc1dpdGhvdXRDb250ZXh0Lmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgPyBgeyAke3BhcmFtc1dpdGhvdXRDb250ZXh0XG4gICAgICAgICAgICAgICAgICAubWFwKChwKSA9PiBgJHtwLm5hbWV9OiAke2FwaVBhcmFtVHlwZVRvVHNUeXBlKHAudHlwZSwgW10pfWApXG4gICAgICAgICAgICAgICAgICAuam9pbihcIiwgXCIpfSB9YFxuICAgICAgICAgICAgICA6IFwidm9pZFwiO1xuICAgICAgICAgIGNvbnN0IG11dGF0aW9uUGFyYW1OYW1lcyA9XG4gICAgICAgICAgICBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwXG4gICAgICAgICAgICAgID8gcGFyYW1zV2l0aG91dENvbnRleHQubWFwKChwKSA9PiBgcGFyYW1zLiR7cC5uYW1lfWApLmpvaW4oXCIsIFwiKVxuICAgICAgICAgICAgICA6IFwiXCI7XG5cbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCB1c2Uke2hvb2tOYW1lfU11dGF0aW9uID0gJHt0eXBlUGFyYW1zRGVmfSgpID0+IHVzZU11dGF0aW9uKHtcbiAgbXV0YXRpb25GbjogKHBhcmFtczogJHttdXRhdGlvblBhcmFtVHlwZX0pID0+ICR7bW9kZWxOYW1lfVNlcnZpY2UuJHttZXRob2ROYW1lfSgke211dGF0aW9uUGFyYW1OYW1lc30pXG59KTtcbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gNC4gdXNlTXV0YXRpb24gd2l0aCBtdWx0aXBhcnQgKHRhbnN0YWNrLW11dGF0aW9uLW11bHRpcGFydClcbiAgICAgICAgaWYgKGNsaWVudHMuaW5jbHVkZXMoXCJ0YW5zdGFjay1tdXRhdGlvbi1tdWx0aXBhcnRcIikpIHtcbiAgICAgICAgICBjb25zdCBob29rTmFtZSA9IGluZmxlY3Rpb24uY2FtZWxpemUoYXBpLm1ldGhvZE5hbWUpO1xuXG4gICAgICAgICAgLy8g7YyM652866+47YSwIO2DgOyehSDsoJXsnZg6IHBhcmFtc0RlZuyXkOyEnCDtg4DsnoXrp4wg7LaU7LacXG4gICAgICAgICAgLy8gcGFyYW1zRGVmIOyYiDogXCJwYXJhbXM6IHsgY2F0ZWdvcnk6IHN0cmluZyB9XCIg4oaSIFwieyBjYXRlZ29yeTogc3RyaW5nIH1cIlxuICAgICAgICAgIGNvbnN0IHBhcmFtc1R5cGVEZWYgPVxuICAgICAgICAgICAgcGFyYW1zV2l0aG91dENvbnRleHQubGVuZ3RoID4gMFxuICAgICAgICAgICAgICA/IHBhcmFtc0RlZi5zcGxpdChcIjpcIikuc2xpY2UoMSkuam9pbihcIjpcIikudHJpbSgpIC8vIFwicGFyYW1zOiB7IGNhdGVnb3J5OiBzdHJpbmcgfVwiIOKGkiBcInsgY2F0ZWdvcnk6IHN0cmluZyB9XCJcbiAgICAgICAgICAgICAgOiBcIlwiO1xuXG4gICAgICAgICAgY29uc3QgbXV0YXRpb25QYXJhbVR5cGUgPVxuICAgICAgICAgICAgcGFyYW1zV2l0aG91dENvbnRleHQubGVuZ3RoID4gMFxuICAgICAgICAgICAgICA/IGB7IHBhcmFtczogJHtwYXJhbXNUeXBlRGVmfSwgZmlsZXM6IEZpbGVbXSB9YFxuICAgICAgICAgICAgICA6IGB7IGZpbGVzOiBGaWxlW10gfWA7XG5cbiAgICAgICAgICAvLyBtdXRhdGlvbkZuIO2YuOy2nCDtjIzrnbzrr7jthLBcbiAgICAgICAgICBjb25zdCBtdXRhdGlvbkZuQ2FsbCA9XG4gICAgICAgICAgICBwYXJhbXNXaXRob3V0Q29udGV4dC5sZW5ndGggPiAwXG4gICAgICAgICAgICAgID8gYCR7bW9kZWxOYW1lfVNlcnZpY2UuJHttZXRob2ROYW1lfShwYXJhbXMucGFyYW1zLCBwYXJhbXMuZmlsZXMpYFxuICAgICAgICAgICAgICA6IGAke21vZGVsTmFtZX1TZXJ2aWNlLiR7bWV0aG9kTmFtZX0ocGFyYW1zLmZpbGVzKWA7XG5cbiAgICAgICAgICBmdW5jdGlvbnMucHVzaChcbiAgICAgICAgICAgIGBcbmV4cG9ydCBjb25zdCB1c2Uke2hvb2tOYW1lfU11dGF0aW9uID0gJHt0eXBlUGFyYW1zRGVmfShcbiAgb3B0aW9ucz86IFVzZU11dGF0aW9uT3B0aW9uczwke3JldHVyblR5cGVEZWZ9LCBFcnJvciwgJHttdXRhdGlvblBhcmFtVHlwZX0+ICYge1xuICAgIG9uVXBsb2FkUHJvZ3Jlc3M/OiAoZTogQXhpb3NQcm9ncmVzc0V2ZW50KSA9PiB2b2lkO1xuICB9XG4pID0+IHVzZU11dGF0aW9uKHtcbiAgbXV0YXRpb25GbjogKHBhcmFtczogJHttdXRhdGlvblBhcmFtVHlwZX0pID0+ICR7bXV0YXRpb25GbkNhbGx9LFxuICByZXRyeTogZmFsc2UsXG4gIC4uLm9wdGlvbnMsXG59KTtcbiAgICAgICAgICBgLnRyaW0oKSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIG5hbWVzcGFjZXMucHVzaChcbiAgICAgICAgYFxuZXhwb3J0IG5hbWVzcGFjZSAke21vZGVsTmFtZX1TZXJ2aWNlIHtcbiR7ZnVuY3Rpb25zLmpvaW4oXCJcXG5cXG5cIil9XG59XG4gICAgICBgLnRyaW0oKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQXN5bmNJZENvbmZpZyDsg53shLEgKEVudGl0eeuzhOuhnClcbiAgICBjb25zdCBlbnRpdHlJZHMgPSBFbnRpdHlNYW5hZ2VyLmdldEFsbElkcygpO1xuICAgIGNvbnN0IGFzeW5jSWRDb25maWdzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBlbnRpdHlJZCBvZiBlbnRpdHlJZHMpIHtcbiAgICAgIGNvbnN0IG5hbWVzID0gRW50aXR5TWFuYWdlci5nZXROYW1lc0Zyb21JZChlbnRpdHlJZCk7XG5cbiAgICAgIC8vIEFzeW5jSWRDb25maWfsmqkg66as7Iqk7Yq4IOyhsO2ajCBBUEkg7LC+6riwXG4gICAgICBjb25zdCBsaXN0QXBpID0gYXBpc0J5TW9kZWwuZ2V0KG5hbWVzLmNhcGl0YWwpPy5maW5kKChhcGkpID0+IHtcbiAgICAgICAgLy8gcmVzb3VyY2VOYW1l7J20IOyXhuqxsOuCmCB0YW5zdGFjay1xdWVyeeulvCDsgqzsmqntlZjsp4Ag7JWK64qUIEFQSeuKlCDsoJzsmbhcbiAgICAgICAgaWYgKCFhcGkub3B0aW9ucy5yZXNvdXJjZU5hbWUgfHwgIWFwaS5vcHRpb25zLmNsaWVudHM/LmluY2x1ZGVzKFwidGFuc3RhY2stcXVlcnlcIikpIHtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgLy8gcmVzb3VyY2VOYW1l7J20IOuzteyImO2YleydtOqzoCDrqZTshJzrk5zrqoXsnbQgZmluZE1hbnnsnbggQVBJXG4gICAgICAgIGNvbnN0IHJlc291cmNlTmFtZSA9IGFwaS5vcHRpb25zLnJlc291cmNlTmFtZTtcbiAgICAgICAgcmV0dXJuIGluZmxlY3Rpb24ucGx1cmFsaXplKHJlc291cmNlTmFtZSkgPT09IHJlc291cmNlTmFtZSAmJiBhcGkubWV0aG9kTmFtZSA9PT0gXCJmaW5kTWFueVwiO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChsaXN0QXBpKSB7XG4gICAgICAgIC8vIHJlc291cmNlTmFtZeyXkOyEnCBob29rIOydtOumhCDsg53shLEgKOq4sOyhtCDroZzsp4Hqs7wg64+Z7J28KVxuICAgICAgICBjb25zdCBob29rTmFtZSA9IGluZmxlY3Rpb24uY2FtZWxpemUoYXNzZXJ0RGVmaW5lZChsaXN0QXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lKSwgdHJ1ZSk7XG4gICAgICAgIGNvbnN0IHVzZUhvb2tOYW1lID0gYHVzZSR7aW5mbGVjdGlvbi5jYW1lbGl6ZShob29rTmFtZSl9YDtcbiAgICAgICAgY29uc3QgdXNlSG9va0luZmluaXRlTmFtZSA9IGAke3VzZUhvb2tOYW1lfUluZmluaXRlYDtcblxuICAgICAgICAvLyBMaXN0UGFyYW1zIO2DgOyeheuqhSDqtazshLFcbiAgICAgICAgY29uc3QgbGlzdFBhcmFtc1R5cGUgPSBgJHtuYW1lcy5jYXBpdGFsfUxpc3RQYXJhbXNgO1xuXG4gICAgICAgIGFzeW5jSWRDb25maWdzLnB1c2goXG4gICAgICAgICAgYFxuLy8gQXN5bmNJZENvbmZpZzogJHtuYW1lcy5jYXBpdGFsfVxuZXhwb3J0IGNvbnN0ICR7bmFtZXMuY2FwaXRhbH1Bc3luY0lkQ29uZmlnOiBBc3luY0lkQ29uZmlnPCR7bmFtZXMuY2FwaXRhbH1TdWJzZXRLZXksICR7bmFtZXMuY2FwaXRhbH1TdWJzZXRNYXBwaW5nLCAke2xpc3RQYXJhbXNUeXBlfT4gPSB7XG4gIHBsYWNlaG9sZGVyS2V5OiBcImVudGl0eS4ke25hbWVzLmNhcGl0YWx9XCIsXG4gIHVzZUxpc3Q6ICR7bmFtZXMuY2FwaXRhbH1TZXJ2aWNlLiR7dXNlSG9va05hbWV9LFxuICB1c2VMaXN0SW5maW5pdGU6ICR7bmFtZXMuY2FwaXRhbH1TZXJ2aWNlLiR7dXNlSG9va0luZmluaXRlTmFtZX0sXG59O1xuICAgICAgICAgIGAudHJpbSgpLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEJVSUxUX0lOX1RZUEVT7JeQ7IScIOyCrOyaqeuQmOuKlCDtg4DsnoXrk6TsnYQg7ZmV7J247ZWY7JesIOuPmeyggeycvOuhnCBpbXBvcnQg6rWs7ISxXG4gICAgY29uc3QgYnVpbHRJblR5cGVJbXBvcnRzID0gT2JqZWN0LmtleXMoQlVJTFRfSU5fVFlQRVMpXG4gICAgICAuZmlsdGVyKCh0eXBlS2V5KSA9PiBpbXBvcnRLZXlzLmluY2x1ZGVzKHR5cGVLZXkpKVxuICAgICAgLm1hcCgodHlwZUtleSkgPT4gYHR5cGUgJHt0eXBlS2V5fWApO1xuXG4gICAgLy8gc29uYW11LnNoYXJlZOyXkOyEnCBpbXBvcnTtlaAg7ZWt66qp65Ok7J2EIOuPmeyggeycvOuhnCDqtazshLFcbiAgICAvLyBib2R5IOusuOyekOyXtOydhCDquLDspIDsnLzroZwgaW5maW5pdGUg7ZuFIOyDneyEsSDsl6zrtoAg7YyQ64uoIChmaW5kTWFueSDrs7XsiJjtmJUg67aE6riw7JeQ7ISc66eMIOywuOyhsOuQqClcbiAgICBjb25zdCBib2R5Rm9ySW1wb3J0Q2hlY2sgPSBuYW1lc3BhY2VzLmpvaW4oXCJcXG5cXG5cIik7XG4gICAgY29uc3QgbmVlZHNEZWR1cGVBbmRGbGF0dGVuID0gYm9keUZvckltcG9ydENoZWNrLmluY2x1ZGVzKFwiZGVkdXBlQW5kRmxhdHRlblwiKTtcbiAgICBjb25zdCBuZWVkc1VzZVJlZnJlc2hhYmxlID0gYm9keUZvckltcG9ydENoZWNrLmluY2x1ZGVzKFwidXNlUmVmcmVzaGFibGVcIik7XG5cbiAgICBjb25zdCBzb25hbXVTaGFyZWRJbXBvcnRzID0gW1xuICAgICAgXCJ0eXBlIExpc3RSZXN1bHRcIixcbiAgICAgIFwidHlwZSBGaWx0ZXJRdWVyeVwiLFxuICAgICAgLi4uYnVpbHRJblR5cGVJbXBvcnRzLFxuICAgICAgXCJmZXRjaFwiLFxuICAgICAgXCJ0eXBlIEV2ZW50SGFuZGxlcnNcIixcbiAgICAgIFwidHlwZSBTU0VTdHJlYW1PcHRpb25zXCIsXG4gICAgICBcInR5cGUgV2ViU29ja2V0Q2hhbm5lbE9wdGlvbnNcIixcbiAgICAgIFwidXNlU1NFU3RyZWFtXCIsXG4gICAgICBcInVzZVdlYlNvY2tldENoYW5uZWxcIixcbiAgICAgIFwidG9Gb3JtRGF0YVwiLFxuICAgICAgLi4uKG5lZWRzRGVkdXBlQW5kRmxhdHRlbiA/IFtcImRlZHVwZUFuZEZsYXR0ZW5cIl0gOiBbXSksXG4gICAgICAuLi4obmVlZHNVc2VSZWZyZXNoYWJsZSA/IFtcInVzZVJlZnJlc2hhYmxlXCJdIDogW10pLFxuICAgIF0uam9pbihcIiwgXCIpO1xuXG4gICAgLy8gYm9keSDqtazshLE6IG5hbWVzcGFjZXMgKyBhc3luY0lkQ29uZmlnc1xuICAgIGNvbnN0IGJvZHlQYXJ0cyA9IFsuLi5uYW1lc3BhY2VzLCAuLi5hc3luY0lkQ29uZmlnc107XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4udGhpcy5nZXRUYXJnZXRBbmRQYXRoKCksXG4gICAgICBib2R5OiBib2R5UGFydHMuam9pbihcIlxcblxcblwiKSxcbiAgICAgIGltcG9ydEtleXM6IGRpZmYodW5pcXVlKGltcG9ydEtleXMpLCBbXG4gICAgICAgIC4uLnR5cGVQYXJhbU5hbWVzLFxuICAgICAgICBcIkxpc3RSZXN1bHRcIixcbiAgICAgICAgLi4uT2JqZWN0LmtleXMoQlVJTFRfSU5fVFlQRVMpLFxuICAgICAgXSksXG4gICAgICBjdXN0b21IZWFkZXJzOiBbXG4gICAgICAgIFwiLyoqXCIsXG4gICAgICAgIFwiICogQGdlbmVyYXRlZFwiLFxuICAgICAgICBcIiAqIOyngeygkSDsiJjsoJXtlZjsp4Ag66eI7IS47JqULlwiLFxuICAgICAgICBcIiAqL1wiLFxuICAgICAgICBcIlwiLFxuICAgICAgICBcIi8qIG94bGludC1kaXNhYmxlICovXCIsXG4gICAgICAgIFwiXCIsXG4gICAgICAgIGBpbXBvcnQgeyBxdWVyeU9wdGlvbnMsIHVzZVF1ZXJ5LCB1c2VJbmZpbml0ZVF1ZXJ5LCBpbmZpbml0ZVF1ZXJ5T3B0aW9ucywgdXNlTXV0YXRpb24sIHR5cGUgVXNlTXV0YXRpb25PcHRpb25zIH0gZnJvbSAnQHRhbnN0YWNrL3JlYWN0LXF1ZXJ5JztgLFxuICAgICAgICBgaW1wb3J0IHsgdHlwZSBBeGlvc1Byb2dyZXNzRXZlbnQgfSBmcm9tICdheGlvcyc7YCxcbiAgICAgICAgYGltcG9ydCBxcyBmcm9tICdxcyc7YCxcbiAgICAgICAgYGltcG9ydCB7ICR7c29uYW11U2hhcmVkSW1wb3J0c30gfSBmcm9tICcuL3NvbmFtdS5zaGFyZWQnO2AsXG4gICAgICAgIGBpbXBvcnQgeyB0eXBlIEFzeW5jSWRDb25maWcgfSBmcm9tICdAc29uYW11LWtpdC9yZWFjdC1jb21wb25lbnRzL2NvbXBvbmVudHMnO2AsXG4gICAgICBdLFxuICAgIH07XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztxQkFPa0M7WUFFTztvQkFDa0I7V0FFWDtXQUNDO2NBQ1g7bUJBQytCO0FBRXJFLElBQWEscUJBQWIsY0FBd0MsU0FBUztDQUMvQyxjQUFjO0VBQ1osTUFBTSxVQUFVO0NBQ2xCO0NBRUEsbUJBQW1CO0VBQ2pCLE9BQU87R0FDTCxRQUFRO0dBQ1IsTUFBTTtFQUNSO0NBQ0Y7Q0FFQSxPQUFPLElBQWlDO0VBQ3RDLE1BQU0sRUFBRSxTQUFTLE9BQU87RUFHeEIsTUFBTSw4QkFBYyxJQUFJLElBQTJCO0VBQ25ELEtBQUssTUFBTSxPQUFPLE1BQU07R0FDdEIsTUFBTSxZQUFZLElBQUksVUFBVSxRQUFRLFVBQVUsRUFBRSxDQUFDLENBQUMsUUFBUSxVQUFVLEVBQUU7R0FDMUUsSUFBSSxDQUFDLFlBQVksSUFBSSxTQUFTLEdBQzVCLFlBQVksSUFBSSxXQUFXLENBQUMsQ0FBQztHQUUvQixZQUFZLElBQUksU0FBUyxD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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonamu",
3
- "version": "0.10.8",
3
+ "version": "0.10.10",
4
4
  "description": "Sonamu — TypeScript Fullstack API Framework",
5
5
  "keywords": [
6
6
  "framework",
@@ -130,8 +130,8 @@
130
130
  "vite": "8.0.16",
131
131
  "vitest": "^4.1.9",
132
132
  "@sonamu-kit/hmr-hook": "^0.5.1",
133
- "@sonamu-kit/hmr-runner": "^0.2.0",
134
133
  "@sonamu-kit/tasks": "^0.3.1",
134
+ "@sonamu-kit/hmr-runner": "^0.2.0",
135
135
  "@sonamu-kit/ts-loader": "^2.2.0"
136
136
  },
137
137
  "devDependencies": {
@@ -396,9 +396,7 @@ export function transactional(options: TransactionalOptions = {}) {
396
396
  method: methodName,
397
397
  });
398
398
 
399
- const existingContext = DB.transactionStorage.getStore();
400
-
401
- // AsyncLocalStorage 컨텍스트 없거나 해당 preset의 트랜잭션이 없으면 새로 시작
399
+ // 해당 preset의 트랜잭션이 없으면 새 트랜잭션과 scope를 함께 시작한다.
402
400
  const startTransaction = async () => {
403
401
  const puri = this.getPuri(dbPreset);
404
402
 
@@ -406,33 +404,24 @@ export function transactional(options: TransactionalOptions = {}) {
406
404
  async (trx) => {
407
405
  this.logger.debug("new transaction context: {dbPreset}", { dbPreset });
408
406
  const trxWrapper = new PuriTransactionWrapper(trx, new UpsertBuilder());
409
- // TransactionContext에 트랜잭션 저장
410
- DB.getTransactionContext().setTransaction(dbPreset, trxWrapper);
411
-
412
- try {
413
- return await originalMethod.apply(this, args);
414
- } finally {
415
- // 트랜잭션 제거
416
- this.logger.debug("delete transaction context: {dbPreset}", { dbPreset });
417
- DB.getTransactionContext().deleteTransaction(dbPreset);
418
- }
407
+
408
+ return DB.runWithTransactionScope(dbPreset, trxWrapper, () =>
409
+ originalMethod.apply(this, args),
410
+ );
419
411
  },
420
412
  { isolationLevel: isolation, readOnly },
421
413
  );
422
414
  };
423
415
 
424
- // AsyncLocalStorage 컨텍스트가 없으면 새로 생성
425
- if (!existingContext) {
426
- return DB.runWithTransaction(startTransaction);
427
- }
428
-
429
- // 이미 AsyncLocalStorage 컨텍스트 안에 있는지 확인 후 해당 preset의 트랜잭션이 이미 있으면 재사용
430
- if (existingContext?.getTransaction(dbPreset)) {
416
+ const existingTransaction = DB.transactionStorage.getStore()?.getTransaction(dbPreset);
417
+ if (existingTransaction) {
431
418
  this.logger.debug("reuse transaction context: {dbPreset}", { dbPreset });
432
- return originalMethod.apply(this, args);
419
+ // 다른 preset이 안쪽에 있어도 이 메서드가 재사용한 트랜잭션을 현재 scope로 표시한다.
420
+ return DB.runWithTransactionScope(dbPreset, existingTransaction, () =>
421
+ originalMethod.apply(this, args),
422
+ );
433
423
  }
434
424
 
435
- // 컨텍스트는 있지만 이 preset의 트랜잭션은 없는 경우 (같은 컨텍스트 내에서 실행)
436
425
  return startTransaction();
437
426
  };
438
427
 
@@ -0,0 +1,227 @@
1
+ import { type Knex } from "knex";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import { type DBPreset, DBClass } from "../db";
5
+ import { PuriTransactionWrapper } from "../puri-wrapper";
6
+ import { UpsertBuilder } from "../upsert-builder";
7
+
8
+ type TransactionScopeDB = DBClass & {
9
+ runWithTransactionScope?<T>(
10
+ preset: DBPreset,
11
+ transaction: PuriTransactionWrapper,
12
+ callback: () => Promise<T>,
13
+ ): Promise<T>;
14
+ };
15
+
16
+ function createTransactionWrapper(): PuriTransactionWrapper {
17
+ return new PuriTransactionWrapper({} as Knex.Transaction, new UpsertBuilder());
18
+ }
19
+
20
+ function createDeferred() {
21
+ let resolve!: () => void;
22
+ const promise = new Promise<void>((done) => {
23
+ resolve = done;
24
+ });
25
+ return { promise, resolve };
26
+ }
27
+
28
+ function expectScopeRunner(db: TransactionScopeDB) {
29
+ expect(db.runWithTransactionScope).toBeTypeOf("function");
30
+ return db.runWithTransactionScope;
31
+ }
32
+
33
+ describe("DB.runWithTransactionScope", () => {
34
+ it("저장소가 없어도 루트 scope를 설치하고 콜백 결과를 반환한 뒤 정리한다", async () => {
35
+ const db = new DBClass() as TransactionScopeDB;
36
+ const transaction = createTransactionWrapper();
37
+ const runScope = expectScopeRunner(db);
38
+ if (!runScope) return;
39
+
40
+ let callbackContext: ReturnType<DBClass["getTransactionContext"]> | undefined;
41
+ const result = await runScope.call(db, "w", transaction, async () => {
42
+ callbackContext = db.getTransactionContext();
43
+ expect(db.transactionStorage.getStore()).toBe(callbackContext);
44
+ expect(callbackContext.getActiveTransaction()).toBe(transaction);
45
+ expect(callbackContext.getTransaction("w")).toBe(transaction);
46
+ return "완료";
47
+ });
48
+
49
+ expect(result).toBe("완료");
50
+ expect(callbackContext?.getActiveTransaction()).toBeUndefined();
51
+ expect(callbackContext?.getTransaction("w")).toBeUndefined();
52
+ expect(db.transactionStorage.getStore()).toBeUndefined();
53
+ });
54
+
55
+ it("scope 안에서 생성된 detached descendant가 완료된 자식 트랜잭션을 다시 사용하지 않는다", async () => {
56
+ const db = new DBClass() as TransactionScopeDB;
57
+ const parentTransaction = createTransactionWrapper();
58
+ const childTransaction = createTransactionWrapper();
59
+ const descendantReady = createDeferred();
60
+ const resumeDescendant = createDeferred();
61
+ const runScope = expectScopeRunner(db);
62
+ if (!runScope) return;
63
+
64
+ let parentContext: ReturnType<DBClass["getTransactionContext"]> | undefined;
65
+ let childContext: ReturnType<DBClass["getTransactionContext"]> | undefined;
66
+
67
+ await runScope.call(db, "r", parentTransaction, async () => {
68
+ parentContext = db.getTransactionContext();
69
+
70
+ let descendantPromise:
71
+ | Promise<{
72
+ context: ReturnType<DBClass["getTransactionContext"]>;
73
+ active: PuriTransactionWrapper | undefined;
74
+ write: PuriTransactionWrapper | undefined;
75
+ read: PuriTransactionWrapper | undefined;
76
+ }>
77
+ | undefined;
78
+
79
+ childContext = await runScope.call(db, "w", childTransaction, async () => {
80
+ const scopedContext = db.getTransactionContext();
81
+ descendantPromise = (async () => {
82
+ descendantReady.resolve();
83
+ await resumeDescendant.promise;
84
+ const context = db.getTransactionContext();
85
+ return {
86
+ context,
87
+ active: context.getActiveTransaction(),
88
+ write: context.getTransaction("w"),
89
+ read: context.getTransaction("r"),
90
+ };
91
+ })();
92
+
93
+ await descendantReady.promise;
94
+ return scopedContext;
95
+ });
96
+
97
+ expect(db.getTransactionContext()).toBe(parentContext);
98
+ expect(childContext.getActiveTransaction()).toBe(parentTransaction);
99
+ expect(childContext.getTransaction("w")).toBeUndefined();
100
+ expect(childContext.getTransaction("r")).toBe(parentTransaction);
101
+
102
+ resumeDescendant.resolve();
103
+ if (!descendantPromise) {
104
+ throw new Error("detached descendant가 생성되지 않았습니다");
105
+ }
106
+ const descendantResult = await descendantPromise;
107
+
108
+ expect(descendantResult.context).toBe(childContext);
109
+ expect(descendantResult.active).toBe(parentTransaction);
110
+ expect(descendantResult.write).toBeUndefined();
111
+ expect(descendantResult.read).toBe(parentTransaction);
112
+ });
113
+
114
+ expect(parentContext?.getActiveTransaction()).toBeUndefined();
115
+ expect(parentContext?.getTransaction("r")).toBeUndefined();
116
+ expect(childContext?.getActiveTransaction()).toBeUndefined();
117
+ expect(childContext?.getTransaction("r")).toBeUndefined();
118
+ expect(db.transactionStorage.getStore()).toBeUndefined();
119
+ });
120
+
121
+ it("같거나 다른 preset의 중첩 범위를 복원하고 같은 오류를 다시 던진다", async () => {
122
+ const db = new DBClass() as TransactionScopeDB;
123
+ const outer = createTransactionWrapper();
124
+ const samePresetInner = createTransactionWrapper();
125
+ const differentPresetInner = createTransactionWrapper();
126
+ const expectedError = new Error("의도한 scope 오류");
127
+ const runScope = expectScopeRunner(db);
128
+ if (!runScope) return;
129
+
130
+ await runScope.call(db, "w", outer, async () => {
131
+ const outerContext = db.getTransactionContext();
132
+ expect(outerContext.getActiveTransaction()).toBe(outer);
133
+
134
+ await runScope.call(db, "w", samePresetInner, async () => {
135
+ expect(db.getTransactionContext().getActiveTransaction()).toBe(samePresetInner);
136
+ expect(db.getTransactionContext().getTransaction("w")).toBe(samePresetInner);
137
+ });
138
+ expect(db.getTransactionContext()).toBe(outerContext);
139
+ expect(outerContext.getActiveTransaction()).toBe(outer);
140
+
141
+ await expect(
142
+ runScope.call(db, "fixture", differentPresetInner, async () => {
143
+ const innerContext = db.getTransactionContext();
144
+ expect(innerContext.getActiveTransaction()).toBe(differentPresetInner);
145
+ expect(innerContext.getTransaction("w")).toBe(outer);
146
+ expect(innerContext.getTransaction("fixture")).toBe(differentPresetInner);
147
+ throw expectedError;
148
+ }),
149
+ ).rejects.toBe(expectedError);
150
+
151
+ expect(db.getTransactionContext()).toBe(outerContext);
152
+ expect(outerContext.getActiveTransaction()).toBe(outer);
153
+ expect(outerContext.getTransaction("fixture")).toBeUndefined();
154
+ });
155
+
156
+ expect(db.transactionStorage.getStore()).toBeUndefined();
157
+ });
158
+
159
+ it("겹치는 sibling 범위가 완료 순서와 무관하게 서로의 활성 트랜잭션을 보지 않는다", async () => {
160
+ const db = new DBClass() as TransactionScopeDB;
161
+ const parentTransaction = createTransactionWrapper();
162
+ const firstTransaction = createTransactionWrapper();
163
+ const secondTransaction = createTransactionWrapper();
164
+ const firstReady = createDeferred();
165
+ const secondReady = createDeferred();
166
+ const firstExited = createDeferred();
167
+ const runScope = expectScopeRunner(db);
168
+ if (!runScope) return;
169
+
170
+ let firstContext: ReturnType<DBClass["getTransactionContext"]> | undefined;
171
+ let secondContext: ReturnType<DBClass["getTransactionContext"]> | undefined;
172
+
173
+ await runScope.call(db, "r", parentTransaction, async () => {
174
+ const parentContext = db.getTransactionContext();
175
+ const firstPromise = runScope.call(db, "w", firstTransaction, async () => {
176
+ firstReady.resolve();
177
+ await secondReady.promise;
178
+ return {
179
+ context: db.getTransactionContext(),
180
+ active: db.getTransactionContext().getActiveTransaction(),
181
+ write: db.getTransactionContext().getTransaction("w"),
182
+ inheritedRead: db.getTransactionContext().getTransaction("r"),
183
+ };
184
+ });
185
+
186
+ await firstReady.promise;
187
+ const secondPromise = runScope.call(db, "w", secondTransaction, async () => {
188
+ secondReady.resolve();
189
+ await firstExited.promise;
190
+ return {
191
+ context: db.getTransactionContext(),
192
+ active: db.getTransactionContext().getActiveTransaction(),
193
+ write: db.getTransactionContext().getTransaction("w"),
194
+ inheritedRead: db.getTransactionContext().getTransaction("r"),
195
+ };
196
+ });
197
+
198
+ const firstResult = await firstPromise;
199
+ firstExited.resolve();
200
+ const secondResult = await secondPromise;
201
+ firstContext = firstResult.context;
202
+ secondContext = secondResult.context;
203
+
204
+ expect(firstResult.context).not.toBe(secondResult.context);
205
+ expect(firstResult.active).toBe(firstTransaction);
206
+ expect(firstResult.write).toBe(firstTransaction);
207
+ expect(firstResult.inheritedRead).toBe(parentTransaction);
208
+ expect(secondResult.active).toBe(secondTransaction);
209
+ expect(secondResult.write).toBe(secondTransaction);
210
+ expect(secondResult.inheritedRead).toBe(parentTransaction);
211
+ expect(firstResult.context.getActiveTransaction()).toBe(parentTransaction);
212
+ expect(secondResult.context.getActiveTransaction()).toBe(parentTransaction);
213
+ expect(db.getTransactionContext()).toBe(parentContext);
214
+ expect(parentContext.getActiveTransaction()).toBe(parentTransaction);
215
+ });
216
+
217
+ expect(firstContext?.getActiveTransaction()).toBeUndefined();
218
+ expect(secondContext?.getActiveTransaction()).toBeUndefined();
219
+ expect(db.transactionStorage.getStore()).toBeUndefined();
220
+ });
221
+
222
+ it("기존 bootstrap helper를 런타임 API로 노출하지 않는다", () => {
223
+ const db = new DBClass();
224
+
225
+ expect(db).not.toHaveProperty("runWithTransaction");
226
+ });
227
+ });
@@ -67,6 +67,15 @@ export class BaseModelClass<
67
67
  return new PuriWrapper(db, new UpsertBuilder());
68
68
  }
69
69
 
70
+ private getSubsetQueryPuri(): PuriWrapper {
71
+ const activeTransaction = DB.getTransactionContext().getActiveTransaction();
72
+ if (activeTransaction) {
73
+ return activeTransaction;
74
+ }
75
+
76
+ return new PuriWrapper(this.getDB("r"), new UpsertBuilder());
77
+ }
78
+
70
79
  async destroy() {
71
80
  return DB.destroy();
72
81
  }
@@ -120,7 +129,7 @@ export class BaseModelClass<
120
129
  throw new Error("subsetQueries is not defined");
121
130
  }
122
131
 
123
- const puriWrapper = new PuriWrapper(this.getDB("r"), new UpsertBuilder());
132
+ const puriWrapper = this.getSubsetQueryPuri();
124
133
  const qb = this.subsetQueries[subset]?.(puriWrapper);
125
134
 
126
135
  // NonAllowedAsSingleTable: 단일 테이블 컬럼 접근 방지용 마커
@@ -201,6 +210,8 @@ export class BaseModelClass<
201
210
  }
202
211
 
203
212
  const { num, page } = queryParams;
213
+ // 모든 로더가 root query와 같은 연결을 사용하도록 실행 시점의 knex에서 한 번만 파생한다.
214
+ const puriWrapper = new PuriWrapper(qb.knex, new UpsertBuilder());
204
215
 
205
216
  // COUNT 쿼리 실행 (queryMode: list일 때는 0 리턴)
206
217
  const total = await this.executeCountQuery(qb, queryParams, debug, optimizeCountQuery);
@@ -210,7 +221,15 @@ export class BaseModelClass<
210
221
  }
211
222
 
212
223
  // LIST 쿼리 실행
213
- const computedRows = await this.executeListQuery(subset, qb, queryParams, num, page, debug);
224
+ const computedRows = await this.executeListQuery(
225
+ subset,
226
+ qb,
227
+ queryParams,
228
+ num,
229
+ page,
230
+ debug,
231
+ puriWrapper,
232
+ );
214
233
 
215
234
  // Enhancer 적용
216
235
  const enhancer = (params as any).enhancers?.[subset];
@@ -457,6 +476,7 @@ export class BaseModelClass<
457
476
  num: number,
458
477
  page: number,
459
478
  debug: boolean,
479
+ puriWrapper: PuriWrapper,
460
480
  ): Promise<any[]> {
461
481
  if (params.queryMode === "count") {
462
482
  return [];
@@ -478,7 +498,7 @@ export class BaseModelClass<
478
498
  // 로더 처리
479
499
  const loaders = (this.loaderQueries as any)[subset];
480
500
  if (loaders && Array.isArray(loaders)) {
481
- unloadedRows = await this.processLoaders(unloadedRows, loaders, debug);
501
+ unloadedRows = await this.processLoaders(unloadedRows, loaders, debug, puriWrapper);
482
502
  }
483
503
 
484
504
  return this.hydrate(unloadedRows);
@@ -487,12 +507,17 @@ export class BaseModelClass<
487
507
  /**
488
508
  * 재귀적 로더 처리
489
509
  */
490
- private async processLoaders(rows: any[], loaders: any[], debug: boolean): Promise<any[]> {
510
+ private async processLoaders(
511
+ rows: any[],
512
+ loaders: any[],
513
+ debug: boolean,
514
+ puriWrapper: PuriWrapper,
515
+ ): Promise<any[]> {
491
516
  for (const resolveLoader of loaders) {
492
517
  const { as, refId, qb: resolveLoaderQbFn, loaders: nestedLoaders } = resolveLoader;
493
518
 
494
519
  const resolveLoaderQb = resolveLoaderQbFn(
495
- new PuriWrapper(this.getDB("r"), new UpsertBuilder()),
520
+ puriWrapper,
496
521
  rows.map((row) => row[refId]),
497
522
  );
498
523
 
@@ -504,7 +529,7 @@ export class BaseModelClass<
504
529
 
505
530
  // 중첩 loaders가 있으면 재귀 처리
506
531
  if (nestedLoaders && nestedLoaders.length > 0) {
507
- loadedRows = await this.processLoaders(loadedRows, nestedLoaders, debug);
532
+ loadedRows = await this.processLoaders(loadedRows, nestedLoaders, debug, puriWrapper);
508
533
  }
509
534
 
510
535
  const subRowGroups = group(loadedRows, (row) => row.refId);
@@ -6,6 +6,7 @@ import { type Knex } from "knex";
6
6
  import { type DatabaseConfig, type SonamuConfig } from "../api/config";
7
7
  import { getSonamuEnvironment, type EnvironmentSnapshots, type SonamuEnvironment } from "../env";
8
8
  import { createKnexInstance } from "./knex";
9
+ import { type PuriTransactionWrapper } from "./puri-wrapper";
9
10
  import { TransactionContext } from "./transaction-context";
10
11
 
11
12
  function isPlainObject(value: unknown): value is Record<string, unknown> {
@@ -155,8 +156,22 @@ export class DBClass {
155
156
 
156
157
  public transactionStorage = new AsyncLocalStorage<TransactionContext>();
157
158
 
158
- public runWithTransaction<T>(callback: () => Promise<T>): Promise<T> {
159
- return this.transactionStorage.run(new TransactionContext(), callback);
159
+ public runWithTransactionScope<T>(
160
+ preset: DBPreset,
161
+ transaction: PuriTransactionWrapper,
162
+ callback: () => Promise<T>,
163
+ ): Promise<T> {
164
+ const parentContext = this.transactionStorage.getStore();
165
+ const transactionContext = new TransactionContext(parentContext, { preset, transaction });
166
+
167
+ return this.transactionStorage.run(transactionContext, async () => {
168
+ try {
169
+ return await callback();
170
+ } finally {
171
+ // detached descendant가 완료된 트랜잭션을 다시 사용하지 않도록 local scope를 비운다.
172
+ transactionContext.clearLocal();
173
+ }
174
+ });
160
175
  }
161
176
 
162
177
  setConfig(dbConfig: SonamuDBConfig): void {