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.
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +5 -12
- package/dist/database/base-model.d.ts +1 -0
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +14 -8
- package/dist/database/db.d.ts +2 -1
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +13 -3
- package/dist/database/puri-wrapper.d.ts.map +1 -1
- package/dist/database/puri-wrapper.js +4 -11
- package/dist/database/transaction-context.d.ts +8 -3
- package/dist/database/transaction-context.d.ts.map +1 -1
- package/dist/database/transaction-context.js +12 -7
- package/dist/naite/naite-reporter.d.ts +8 -3
- package/dist/naite/naite-reporter.d.ts.map +1 -1
- package/dist/naite/naite-reporter.js +9 -4
- package/dist/template/implementations/services.template.js +3 -3
- package/package.json +2 -2
- package/src/api/decorators.ts +11 -22
- package/src/database/__tests__/transaction-scope.test.ts +227 -0
- package/src/database/base-model.ts +31 -6
- package/src/database/db.ts +17 -2
- package/src/database/puri-wrapper.ts +5 -22
- package/src/database/transaction-context.ts +14 -6
- package/src/naite/naite-reporter.ts +8 -3
- package/src/template/__tests__/services.template.mutation.test.ts +169 -0
- package/src/template/implementations/services.template.ts +3 -3
|
@@ -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.
|
|
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": {
|
package/src/api/decorators.ts
CHANGED
|
@@ -396,9 +396,7 @@ export function transactional(options: TransactionalOptions = {}) {
|
|
|
396
396
|
method: methodName,
|
|
397
397
|
});
|
|
398
398
|
|
|
399
|
-
|
|
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
|
-
|
|
410
|
-
DB.
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
425
|
-
if (
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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);
|
package/src/database/db.ts
CHANGED
|
@@ -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
|
|
159
|
-
|
|
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 {
|