@cartanova/qgrid-cli 2.10.3 → 2.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +63 -140
  2. package/bundle/dist/application/qgrid/qgrid.frame.js +2 -5
  3. package/bundle/dist/application/setting/setting.model.js +2 -64
  4. package/bundle/dist/application/setting/setting.store.js +3 -4
  5. package/bundle/dist/application/setting/setting.types.js +2 -12
  6. package/bundle/dist/i18n/en.js +1 -3
  7. package/bundle/dist/i18n/ko.js +1 -3
  8. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +0 -111
  9. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +82 -178
  10. package/bundle/src/application/qgrid/qgrid.frame.test.ts +0 -38
  11. package/bundle/src/application/qgrid/qgrid.frame.ts +0 -4
  12. package/bundle/src/application/setting/setting.model.test.ts +1 -101
  13. package/bundle/src/application/setting/setting.model.ts +0 -73
  14. package/bundle/src/application/setting/setting.store.ts +2 -3
  15. package/bundle/src/application/setting/setting.types.ts +0 -12
  16. package/bundle/src/application/sonamu.generated.http +2 -7
  17. package/bundle/src/i18n/en.ts +0 -3
  18. package/bundle/src/i18n/ko.ts +0 -3
  19. package/bundle/web-dist/client/assets/index-CvG4UB9v.css +1 -0
  20. package/bundle/web-dist/client/assets/{index-BIC1sQxw.js → index-reW8VvJF.js} +4 -4
  21. package/bundle/web-dist/client/assets/{logs-zvdujZWn.js → logs-DDIt97D1.js} +1 -1
  22. package/bundle/web-dist/client/assets/{monit-CraVV3MQ.js → monit-DkABv7PG.js} +1 -1
  23. package/bundle/web-dist/client/assets/{routes-B3ZBoJ60.js → routes-BRmQ4M3-.js} +1 -1
  24. package/bundle/web-dist/client/assets/services.generated-jnPHYMER.js +51 -0
  25. package/bundle/web-dist/client/assets/settings-BHvtycEZ.js +1 -0
  26. package/bundle/web-dist/client/assets/{show-ItTExdAh.js → show-qeTIzgDZ.js} +1 -1
  27. package/bundle/web-dist/client/assets/{tokens-BynKx8Vn.js → tokens-5Bep_G-w.js} +1 -1
  28. package/bundle/web-dist/client/assets/{use-oauth-login-flow-8xw6on5P.js → use-oauth-login-flow-Cx-QO25M.js} +1 -1
  29. package/bundle/web-dist/client/assets/{use-update-token-mutation-D-Y8OySK.js → use-update-token-mutation-DQCwCYfR.js} +1 -1
  30. package/bundle/web-dist/client/index.html +3 -3
  31. package/bundle/web-dist/server/assets/{lazyRouteComponent-Bj1cPq6x.js → lazyRouteComponent-CUR-kWzI.js} +2 -2
  32. package/bundle/web-dist/server/assets/{logs-BSk9lOHe.js → logs-CagNGTBj.js} +3 -3
  33. package/bundle/web-dist/server/assets/{monit-D9W4ioUi.js → monit-DSxs4Jnl.js} +3 -3
  34. package/bundle/web-dist/server/assets/{plus-CmvbWuDf.js → plus-Bvdj8Pwx.js} +1 -1
  35. package/bundle/web-dist/server/assets/{react-dom-BjR1Iaz8.js → react-dom-CyuShs9K.js} +1 -1
  36. package/bundle/web-dist/server/assets/{refresh-cw-B8U9BL9-.js → refresh-cw-3QAiSWBd.js} +1 -1
  37. package/bundle/web-dist/server/assets/{routes-C7lB2Q85.js → routes-i-sTqXMX.js} +4 -4
  38. package/bundle/web-dist/server/assets/{services.generated-BM4X3Ecj.js → services.generated-FPwsG9p3.js} +116 -131
  39. package/bundle/web-dist/server/assets/{settings-BFVuldch.js → settings-DeHNwoMv.js} +40 -251
  40. package/bundle/web-dist/server/assets/{show-Cswh_tqs.js → show-C4jk1Hrp.js} +2 -2
  41. package/bundle/web-dist/server/assets/{tokens-DiTUwUwr.js → tokens-odgS2-9q.js} +4 -4
  42. package/bundle/web-dist/server/assets/{use-oauth-login-flow-DYKnG4A2.js → use-oauth-login-flow-DTQKdYBO.js} +1 -1
  43. package/bundle/web-dist/server/assets/{use-update-token-mutation-DqGMopII.js → use-update-token-mutation-xvXbPrCI.js} +1 -1
  44. package/bundle/web-dist/server/entry-server.generated.js +10 -10
  45. package/package.json +1 -1
  46. package/skills/qgrid/references/cli-env-and-server-boot.md +12 -9
  47. package/bundle/dist/utils/process-supervisor.js +0 -22
  48. package/bundle/dist/utils/server-restart.js +0 -61
  49. package/bundle/src/utils/process-supervisor.test.ts +0 -24
  50. package/bundle/src/utils/process-supervisor.ts +0 -17
  51. package/bundle/src/utils/server-restart.test.ts +0 -76
  52. package/bundle/src/utils/server-restart.ts +0 -68
  53. package/bundle/web-dist/client/assets/index-D_sagzsR.css +0 -1
  54. package/bundle/web-dist/client/assets/services.generated-Cbvg2sGQ.js +0 -51
  55. package/bundle/web-dist/client/assets/settings-DwbzT5jo.js +0 -1
@@ -50,10 +50,8 @@ var en_default = {
50
50
  "error.serviceUnavailable": "Service unavailable",
51
51
  "setting.invalidValue": (reason) => `Invalid setting value: ${reason}`,
52
52
  "setting.unknownKey": (key) => `Unknown setting key ${key}`,
53
- "setting.noSupervisor": () => "Restart is unavailable when running locally — nothing would bring the server back up",
54
53
  "qgrid.dispatcherFailed": (provider) => `${provider} dispatcher failed to initialize`,
55
54
  "qgrid.dispatcherStarting": (provider) => `${provider} dispatcher is starting up. Please retry shortly`,
56
- "qgrid.restartPending": () => "Server restart is in progress. Please retry shortly",
57
55
  "error.unauthorized": "Unauthorized",
58
56
  notFound: (name, id) => `${name} ID ${id} not found`,
59
57
  "validation.email": "Invalid email format",
@@ -65,4 +63,4 @@ var en_default = {
65
63
  //#endregion
66
64
  export { en_default as default };
67
65
 
68
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW4uanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2kxOG4vZW4udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcGx1cmFsIH0gZnJvbSBcInNvbmFtdS9kaWN0XCI7XG5cbi8qKlxuICogUHJvamVjdCBFTiBEaWN0aW9uYXJ5XG4gKi9cbmV4cG9ydCBkZWZhdWx0IHtcbiAgXCJjb21tb24uYWxsXCI6IFwiQWxsXCIsXG4gIFwiY29tbW9uLmJhY2tUb0xpc3RcIjogXCJCYWNrIHRvIExpc3RcIixcbiAgXCJjb21tb24uY2FuY2VsXCI6IFwiQ2FuY2VsXCIsXG4gIFwiY29tbW9uLmNsb3NlXCI6IFwiQ2xvc2VcIixcbiAgXCJjb21tb24uY29uZmlybVwiOiBcIkNvbmZpcm1cIixcbiAgXCJjb21tb24uY3JlYXRlXCI6IFwiQ3JlYXRlXCIsXG4gIFwiY29tbW9uLmNyZWF0ZWRBdFwiOiBcIkNyZWF0ZWQgQXRcIixcbiAgXCJjb21tb24uZGVsZXRlXCI6IFwiRGVsZXRlXCIsXG4gIFwiY29tbW9uLmVkaXRcIjogXCJFZGl0XCIsXG4gIFwiY29tbW9uLmxvZ2luXCI6IFwiTG9naW5cIixcbiAgXCJjb21tb24ubG9nb3V0XCI6IFwiTG9nb3V0XCIsXG4gIFwiY29tbW9uLm1hbmFnZVwiOiBcIk1hbmFnZVwiLFxuICBcImNvbW1vbi5yZXN1bHRzXCI6IChjb3VudDogbnVtYmVyKSA9PlxuICAgIHBsdXJhbChjb3VudCwgeyBvbmU6IGAke2NvdW50fSByZXN1bHRgLCBvdGhlcjogYCR7Y291bnR9IHJlc3VsdHNgIH0pLFxuICBcImNvbW1vbi5zYXZlXCI6IFwiU2F2ZVwiLFxuICBcImNvbW1vbi5zZWFyY2hcIjogXCJTZWFyY2hcIixcbiAgXCJjb21tb24uc2VhcmNoUGxhY2Vob2xkZXJcIjogXCJTZWFyY2guLi5cIixcbiAgXCJjb21tb24uc2VhcmNoVHlwZVwiOiBcIlNlYXJjaCBUeXBlXCIsXG4gIFwiY29tbW9uLnNvcnRcIjogXCJTb3J0XCIsXG4gIFwiY29uZmlybS5kZWxldGVcIjogXCJBcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gZGVsZXRlP1wiLFxuICBcImNvbmZpcm0uc2F2ZVwiOiBcIkRvIHlvdSB3YW50IHRvIHNhdmU/XCIsXG4gIFwiZGFzaGJvYXJkLmFkbWluTWVudVwiOiBcIkFkbWluIE1lbnVcIixcbiAgXCJkYXNoYm9hcmQuY3JlYXRlZEF0XCI6IFwiSm9pbmVkXCIsXG4gIFwiZGFzaGJvYXJkLmVtYWlsXCI6IFwiRW1haWxcIixcbiAgXCJkYXNoYm9hcmQubG9naW5SZXF1aXJlZFwiOiBcIlBsZWFzZSBsb2dpbiB0byBjb250aW51ZS5cIixcbiAgXCJkYXNoYm9hcmQubmFtZVwiOiBcIk5hbWVcIixcbiAgXCJkYXNoYm9hcmQucm9sZVwiOiBcIlJvbGVcIixcbiAgXCJkYXNoYm9hcmQudGl0bGVcIjogXCJBZG1pbiBEYXNoYm9hcmRcIixcbiAgXCJkYXNoYm9hcmQud2VsY29tZVwiOiBcIldlbGNvbWUhXCIsXG4gIFwiZGVsZXRlLmNvbmZpcm0uZGVzY3JpcHRpb25cIjpcbiAgICBcIlRoaXMgYWN0aW9uIGNhbm5vdCBiZSB1bmRvbmUuIFRoaXMgd2lsbCBwZXJtYW5lbnRseSBkZWxldGUgdGhpcyBpdGVtLlwiLFxuICBcImRlbGV0ZS5jb25maXJtLnRpdGxlXCI6IFwiQXJlIHlvdSBzdXJlP1wiLFxuICBcImVudGl0eS5jcmVhdGVcIjogKG5hbWU6IHN0cmluZykgPT4gYENyZWF0ZSAke25hbWV9YCxcbiAgXCJlbnRpdHkuZWRpdFwiOiAobmFtZTogc3RyaW5nLCBpZDogbnVtYmVyKSA9PiBgRWRpdCAke25hbWV9ICgjJHtpZH0pYCxcbiAgXCJlbnRpdHkubGlzdFwiOiAobmFtZTogc3RyaW5nKSA9PiBgJHtuYW1lfSBMaXN0YCxcbiAgXCJlbnRpdHkubGlzdE1hbmFnZVwiOiAobmFtZTogc3RyaW5nKSA9PiBgTWFuYWdlICR7bmFtZX0gTGlzdGAsXG4gIFwiZXJyb3IuYWxyZWFkeVByb2Nlc3NlZFwiOiBcIkFscmVhZHkgcHJvY2Vzc2VkXCIsXG4gIFwiZXJyb3IuYmFkUmVxdWVzdFwiOiBcIkJhZCByZXF1ZXN0XCIsXG4gIFwiZXJyb3IuZHVwbGljYXRlUm93XCI6IFwiRHVwbGljYXRlIGRhdGFcIixcbiAgXCJlcnJvci5mb3JiaWRkZW5cIjogXCJGb3JiaWRkZW5cIixcbiAgXCJlcnJvci5pbnRlcm5hbFNlcnZlckVycm9yXCI6IFwiSW50ZXJuYWwgc2VydmVyIGVycm9yXCIsXG4gIFwiZXJyb3Iubm90Rm91bmRcIjogXCJOb3QgZm91bmRcIixcbiAgXCJlcnJvci5zZXJ2aWNlVW5hdmFpbGFibGVcIjogXCJTZXJ2aWNlIHVuYXZhaWxhYmxlXCIsXG4gIFwic2V0dGluZy5pbnZhbGlkVmFsdWVcIjogKHJlYXNvbjogc3RyaW5nKSA9PiBgSW52YWxpZCBzZXR0aW5nIHZhbHVlOiAke3JlYXNvbn1gLFxuICBcInNldHRpbmcudW5rbm93bktleVwiOiAoa2V5OiBzdHJpbmcpID0+IGBVbmtub3duIHNldHRpbmcga2V5ICR7a2V5fWAsXG4gIFwic2V0dGluZy5ub1N1cGVydmlzb3JcIjogKCkgPT5cbiAgICBcIlJlc3RhcnQgaXMgdW5hdmFpbGFibGUgd2hlbiBydW5uaW5nIGxvY2FsbHkg4oCUIG5vdGhpbmcgd291bGQgYnJpbmcgdGhlIHNlcnZlciBiYWNrIHVwXCIsXG4gIFwicWdyaWQuZGlzcGF0Y2hlckZhaWxlZFwiOiAocHJvdmlkZXI6IHN0cmluZykgPT4gYCR7cHJvdmlkZXJ9IGRpc3BhdGNoZXIgZmFpbGVkIHRvIGluaXRpYWxpemVgLFxuICBcInFncmlkLmRpc3BhdGNoZXJTdGFydGluZ1wiOiAocHJvdmlkZXI6IHN0cmluZykgPT5cbiAgICBgJHtwcm92aWRlcn0gZGlzcGF0Y2hlciBpcyBzdGFydGluZyB1cC4gUGxlYXNlIHJldHJ5IHNob3J0bHlgLFxuICBcInFncmlkLnJlc3RhcnRQZW5kaW5nXCI6ICgpID0+IFwiU2VydmVyIHJlc3RhcnQgaXMgaW4gcHJvZ3Jlc3MuIFBsZWFzZSByZXRyeSBzaG9ydGx5XCIsXG4gIFwiZXJyb3IudW5hdXRob3JpemVkXCI6IFwiVW5hdXRob3JpemVkXCIsXG4gIG5vdEZvdW5kOiAobmFtZTogc3RyaW5nLCBpZDogbnVtYmVyKSA9PiBgJHtuYW1lfSBJRCAke2lkfSBub3QgZm91bmRgLFxuICBcInZhbGlkYXRpb24uZW1haWxcIjogXCJJbnZhbGlkIGVtYWlsIGZvcm1hdFwiLFxuICBcInZhbGlkYXRpb24ubWF4TGVuZ3RoXCI6IChmaWVsZDogc3RyaW5nLCBtYXg6IG51bWJlcikgPT5cbiAgICBgJHtmaWVsZH0gbXVzdCBiZSBhdCBtb3N0ICR7bWF4fSBjaGFyYWN0ZXJzYCxcbiAgXCJ2YWxpZGF0aW9uLm1pbkxlbmd0aFwiOiAoZmllbGQ6IHN0cmluZywgbWluOiBudW1iZXIpID0+XG4gICAgYCR7ZmllbGR9IG11c3QgYmUgYXQgbGVhc3QgJHttaW59IGNoYXJhY3RlcnNgLFxuICBcInZhbGlkYXRpb24ucmVxdWlyZWRcIjogKGZpZWxkOiBzdHJpbmcpID0+IGAke2ZpZWxkfSBpcyByZXF1aXJlZGAsXG4gIFwidmFsaWRhdGlvbi51cmxcIjogXCJJbnZhbGlkIFVSTCBmb3JtYXRcIixcbn07XG4iXSwibWFwcGluZ3MiOiI7Ozs7O0FBS0EsSUFBQSxhQUFlO0NBQ2IsY0FBYztDQUNkLHFCQUFxQjtDQUNyQixpQkFBaUI7Q0FDakIsZ0JBQWdCO0NBQ2hCLGtCQUFrQjtDQUNsQixpQkFBaUI7Q0FDakIsb0JBQW9CO0NBQ3BCLGlCQUFpQjtDQUNqQixlQUFlO0NBQ2YsZ0JBQWdCO0NBQ2hCLGlCQUFpQjtDQUNqQixpQkFBaUI7Q0FDakIsbUJBQW1CLFVBQ2pCLE9BQU8sT0FBTztFQUFFLEtBQUssR0FBRyxNQUFNO0VBQVUsT0FBTyxHQUFHLE1BQU07Q0FBVSxDQUFDO0NBQ3JFLGVBQWU7Q0FDZixpQkFBaUI7Q0FDakIsNEJBQTRCO0NBQzVCLHFCQUFxQjtDQUNyQixlQUFlO0NBQ2Ysa0JBQWtCO0NBQ2xCLGdCQUFnQjtDQUNoQix1QkFBdUI7Q0FDdkIsdUJBQXVCO0NBQ3ZCLG1CQUFtQjtDQUNuQiwyQkFBMkI7Q0FDM0Isa0JBQWtCO0NBQ2xCLGtCQUFrQjtDQUNsQixtQkFBbUI7Q0FDbkIscUJBQXFCO0NBQ3JCLDhCQUNFO0NBQ0Ysd0JBQXdCO0NBQ3hCLGtCQUFrQixTQUFpQixVQUFVO0NBQzdDLGdCQUFnQixNQUFjLE9BQWUsUUFBUSxLQUFLLEtBQUssR0FBRztDQUNsRSxnQkFBZ0IsU0FBaUIsR0FBRyxLQUFLO0NBQ3pDLHNCQUFzQixTQUFpQixVQUFVLEtBQUs7Q0FDdEQsMEJBQTBCO0NBQzFCLG9CQUFvQjtDQUNwQixzQkFBc0I7Q0FDdEIsbUJBQW1CO0NBQ25CLDZCQUE2QjtDQUM3QixrQkFBa0I7Q0FDbEIsNEJBQTRCO0NBQzVCLHlCQUF5QixXQUFtQiwwQkFBMEI7Q0FDdEUsdUJBQXVCLFFBQWdCLHVCQUF1QjtDQUM5RCw4QkFDRTtDQUNGLDJCQUEyQixhQUFxQixHQUFHLFNBQVM7Q0FDNUQsNkJBQTZCLGFBQzNCLEdBQUcsU0FBUztDQUNkLDhCQUE4QjtDQUM5QixzQkFBc0I7Q0FDdEIsV0FBVyxNQUFjLE9BQWUsR0FBRyxLQUFLLE1BQU0sR0FBRztDQUN6RCxvQkFBb0I7Q0FDcEIseUJBQXlCLE9BQWUsUUFDdEMsR0FBRyxNQUFNLG1CQUFtQixJQUFJO0NBQ2xDLHlCQUF5QixPQUFlLFFBQ3RDLEdBQUcsTUFBTSxvQkFBb0IsSUFBSTtDQUNuQyx3QkFBd0IsVUFBa0IsR0FBRyxNQUFNO0NBQ25ELGtCQUFrQjtBQUNwQiJ9
66
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW4uanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2kxOG4vZW4udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcGx1cmFsIH0gZnJvbSBcInNvbmFtdS9kaWN0XCI7XG5cbi8qKlxuICogUHJvamVjdCBFTiBEaWN0aW9uYXJ5XG4gKi9cbmV4cG9ydCBkZWZhdWx0IHtcbiAgXCJjb21tb24uYWxsXCI6IFwiQWxsXCIsXG4gIFwiY29tbW9uLmJhY2tUb0xpc3RcIjogXCJCYWNrIHRvIExpc3RcIixcbiAgXCJjb21tb24uY2FuY2VsXCI6IFwiQ2FuY2VsXCIsXG4gIFwiY29tbW9uLmNsb3NlXCI6IFwiQ2xvc2VcIixcbiAgXCJjb21tb24uY29uZmlybVwiOiBcIkNvbmZpcm1cIixcbiAgXCJjb21tb24uY3JlYXRlXCI6IFwiQ3JlYXRlXCIsXG4gIFwiY29tbW9uLmNyZWF0ZWRBdFwiOiBcIkNyZWF0ZWQgQXRcIixcbiAgXCJjb21tb24uZGVsZXRlXCI6IFwiRGVsZXRlXCIsXG4gIFwiY29tbW9uLmVkaXRcIjogXCJFZGl0XCIsXG4gIFwiY29tbW9uLmxvZ2luXCI6IFwiTG9naW5cIixcbiAgXCJjb21tb24ubG9nb3V0XCI6IFwiTG9nb3V0XCIsXG4gIFwiY29tbW9uLm1hbmFnZVwiOiBcIk1hbmFnZVwiLFxuICBcImNvbW1vbi5yZXN1bHRzXCI6IChjb3VudDogbnVtYmVyKSA9PlxuICAgIHBsdXJhbChjb3VudCwgeyBvbmU6IGAke2NvdW50fSByZXN1bHRgLCBvdGhlcjogYCR7Y291bnR9IHJlc3VsdHNgIH0pLFxuICBcImNvbW1vbi5zYXZlXCI6IFwiU2F2ZVwiLFxuICBcImNvbW1vbi5zZWFyY2hcIjogXCJTZWFyY2hcIixcbiAgXCJjb21tb24uc2VhcmNoUGxhY2Vob2xkZXJcIjogXCJTZWFyY2guLi5cIixcbiAgXCJjb21tb24uc2VhcmNoVHlwZVwiOiBcIlNlYXJjaCBUeXBlXCIsXG4gIFwiY29tbW9uLnNvcnRcIjogXCJTb3J0XCIsXG4gIFwiY29uZmlybS5kZWxldGVcIjogXCJBcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gZGVsZXRlP1wiLFxuICBcImNvbmZpcm0uc2F2ZVwiOiBcIkRvIHlvdSB3YW50IHRvIHNhdmU/XCIsXG4gIFwiZGFzaGJvYXJkLmFkbWluTWVudVwiOiBcIkFkbWluIE1lbnVcIixcbiAgXCJkYXNoYm9hcmQuY3JlYXRlZEF0XCI6IFwiSm9pbmVkXCIsXG4gIFwiZGFzaGJvYXJkLmVtYWlsXCI6IFwiRW1haWxcIixcbiAgXCJkYXNoYm9hcmQubG9naW5SZXF1aXJlZFwiOiBcIlBsZWFzZSBsb2dpbiB0byBjb250aW51ZS5cIixcbiAgXCJkYXNoYm9hcmQubmFtZVwiOiBcIk5hbWVcIixcbiAgXCJkYXNoYm9hcmQucm9sZVwiOiBcIlJvbGVcIixcbiAgXCJkYXNoYm9hcmQudGl0bGVcIjogXCJBZG1pbiBEYXNoYm9hcmRcIixcbiAgXCJkYXNoYm9hcmQud2VsY29tZVwiOiBcIldlbGNvbWUhXCIsXG4gIFwiZGVsZXRlLmNvbmZpcm0uZGVzY3JpcHRpb25cIjpcbiAgICBcIlRoaXMgYWN0aW9uIGNhbm5vdCBiZSB1bmRvbmUuIFRoaXMgd2lsbCBwZXJtYW5lbnRseSBkZWxldGUgdGhpcyBpdGVtLlwiLFxuICBcImRlbGV0ZS5jb25maXJtLnRpdGxlXCI6IFwiQXJlIHlvdSBzdXJlP1wiLFxuICBcImVudGl0eS5jcmVhdGVcIjogKG5hbWU6IHN0cmluZykgPT4gYENyZWF0ZSAke25hbWV9YCxcbiAgXCJlbnRpdHkuZWRpdFwiOiAobmFtZTogc3RyaW5nLCBpZDogbnVtYmVyKSA9PiBgRWRpdCAke25hbWV9ICgjJHtpZH0pYCxcbiAgXCJlbnRpdHkubGlzdFwiOiAobmFtZTogc3RyaW5nKSA9PiBgJHtuYW1lfSBMaXN0YCxcbiAgXCJlbnRpdHkubGlzdE1hbmFnZVwiOiAobmFtZTogc3RyaW5nKSA9PiBgTWFuYWdlICR7bmFtZX0gTGlzdGAsXG4gIFwiZXJyb3IuYWxyZWFkeVByb2Nlc3NlZFwiOiBcIkFscmVhZHkgcHJvY2Vzc2VkXCIsXG4gIFwiZXJyb3IuYmFkUmVxdWVzdFwiOiBcIkJhZCByZXF1ZXN0XCIsXG4gIFwiZXJyb3IuZHVwbGljYXRlUm93XCI6IFwiRHVwbGljYXRlIGRhdGFcIixcbiAgXCJlcnJvci5mb3JiaWRkZW5cIjogXCJGb3JiaWRkZW5cIixcbiAgXCJlcnJvci5pbnRlcm5hbFNlcnZlckVycm9yXCI6IFwiSW50ZXJuYWwgc2VydmVyIGVycm9yXCIsXG4gIFwiZXJyb3Iubm90Rm91bmRcIjogXCJOb3QgZm91bmRcIixcbiAgXCJlcnJvci5zZXJ2aWNlVW5hdmFpbGFibGVcIjogXCJTZXJ2aWNlIHVuYXZhaWxhYmxlXCIsXG4gIFwic2V0dGluZy5pbnZhbGlkVmFsdWVcIjogKHJlYXNvbjogc3RyaW5nKSA9PiBgSW52YWxpZCBzZXR0aW5nIHZhbHVlOiAke3JlYXNvbn1gLFxuICBcInNldHRpbmcudW5rbm93bktleVwiOiAoa2V5OiBzdHJpbmcpID0+IGBVbmtub3duIHNldHRpbmcga2V5ICR7a2V5fWAsXG4gIFwicWdyaWQuZGlzcGF0Y2hlckZhaWxlZFwiOiAocHJvdmlkZXI6IHN0cmluZykgPT4gYCR7cHJvdmlkZXJ9IGRpc3BhdGNoZXIgZmFpbGVkIHRvIGluaXRpYWxpemVgLFxuICBcInFncmlkLmRpc3BhdGNoZXJTdGFydGluZ1wiOiAocHJvdmlkZXI6IHN0cmluZykgPT5cbiAgICBgJHtwcm92aWRlcn0gZGlzcGF0Y2hlciBpcyBzdGFydGluZyB1cC4gUGxlYXNlIHJldHJ5IHNob3J0bHlgLFxuICBcImVycm9yLnVuYXV0aG9yaXplZFwiOiBcIlVuYXV0aG9yaXplZFwiLFxuICBub3RGb3VuZDogKG5hbWU6IHN0cmluZywgaWQ6IG51bWJlcikgPT4gYCR7bmFtZX0gSUQgJHtpZH0gbm90IGZvdW5kYCxcbiAgXCJ2YWxpZGF0aW9uLmVtYWlsXCI6IFwiSW52YWxpZCBlbWFpbCBmb3JtYXRcIixcbiAgXCJ2YWxpZGF0aW9uLm1heExlbmd0aFwiOiAoZmllbGQ6IHN0cmluZywgbWF4OiBudW1iZXIpID0+XG4gICAgYCR7ZmllbGR9IG11c3QgYmUgYXQgbW9zdCAke21heH0gY2hhcmFjdGVyc2AsXG4gIFwidmFsaWRhdGlvbi5taW5MZW5ndGhcIjogKGZpZWxkOiBzdHJpbmcsIG1pbjogbnVtYmVyKSA9PlxuICAgIGAke2ZpZWxkfSBtdXN0IGJlIGF0IGxlYXN0ICR7bWlufSBjaGFyYWN0ZXJzYCxcbiAgXCJ2YWxpZGF0aW9uLnJlcXVpcmVkXCI6IChmaWVsZDogc3RyaW5nKSA9PiBgJHtmaWVsZH0gaXMgcmVxdWlyZWRgLFxuICBcInZhbGlkYXRpb24udXJsXCI6IFwiSW52YWxpZCBVUkwgZm9ybWF0XCIsXG59O1xuIl0sIm1hcHBpbmdzIjoiOzs7OztBQUtBLElBQUEsYUFBZTtDQUNiLGNBQWM7Q0FDZCxxQkFBcUI7Q0FDckIsaUJBQWlCO0NBQ2pCLGdCQUFnQjtDQUNoQixrQkFBa0I7Q0FDbEIsaUJBQWlCO0NBQ2pCLG9CQUFvQjtDQUNwQixpQkFBaUI7Q0FDakIsZUFBZTtDQUNmLGdCQUFnQjtDQUNoQixpQkFBaUI7Q0FDakIsaUJBQWlCO0NBQ2pCLG1CQUFtQixVQUNqQixPQUFPLE9BQU87RUFBRSxLQUFLLEdBQUcsTUFBTTtFQUFVLE9BQU8sR0FBRyxNQUFNO0NBQVUsQ0FBQztDQUNyRSxlQUFlO0NBQ2YsaUJBQWlCO0NBQ2pCLDRCQUE0QjtDQUM1QixxQkFBcUI7Q0FDckIsZUFBZTtDQUNmLGtCQUFrQjtDQUNsQixnQkFBZ0I7Q0FDaEIsdUJBQXVCO0NBQ3ZCLHVCQUF1QjtDQUN2QixtQkFBbUI7Q0FDbkIsMkJBQTJCO0NBQzNCLGtCQUFrQjtDQUNsQixrQkFBa0I7Q0FDbEIsbUJBQW1CO0NBQ25CLHFCQUFxQjtDQUNyQiw4QkFDRTtDQUNGLHdCQUF3QjtDQUN4QixrQkFBa0IsU0FBaUIsVUFBVTtDQUM3QyxnQkFBZ0IsTUFBYyxPQUFlLFFBQVEsS0FBSyxLQUFLLEdBQUc7Q0FDbEUsZ0JBQWdCLFNBQWlCLEdBQUcsS0FBSztDQUN6QyxzQkFBc0IsU0FBaUIsVUFBVSxLQUFLO0NBQ3RELDBCQUEwQjtDQUMxQixvQkFBb0I7Q0FDcEIsc0JBQXNCO0NBQ3RCLG1CQUFtQjtDQUNuQiw2QkFBNkI7Q0FDN0Isa0JBQWtCO0NBQ2xCLDRCQUE0QjtDQUM1Qix5QkFBeUIsV0FBbUIsMEJBQTBCO0NBQ3RFLHVCQUF1QixRQUFnQix1QkFBdUI7Q0FDOUQsMkJBQTJCLGFBQXFCLEdBQUcsU0FBUztDQUM1RCw2QkFBNkIsYUFDM0IsR0FBRyxTQUFTO0NBQ2Qsc0JBQXNCO0NBQ3RCLFdBQVcsTUFBYyxPQUFlLEdBQUcsS0FBSyxNQUFNLEdBQUc7Q0FDekQsb0JBQW9CO0NBQ3BCLHlCQUF5QixPQUFlLFFBQ3RDLEdBQUcsTUFBTSxtQkFBbUIsSUFBSTtDQUNsQyx5QkFBeUIsT0FBZSxRQUN0QyxHQUFHLE1BQU0sb0JBQW9CLElBQUk7Q0FDbkMsd0JBQXdCLFVBQWtCLEdBQUcsTUFBTTtDQUNuRCxrQkFBa0I7QUFDcEIifQ==
@@ -48,10 +48,8 @@ var ko_default = {
48
48
  "error.serviceUnavailable": "서비스를 사용할 수 없습니다",
49
49
  "setting.invalidValue": (reason) => `설정 값이 올바르지 않습니다: ${reason}`,
50
50
  "setting.unknownKey": (key) => `알 수 없는 설정 키 ${key}`,
51
- "setting.noSupervisor": () => "로컬 실행 환경에서는 재시작할 수 없습니다 — 종료하면 다시 켜줄 모니터링 도구가 없습니다",
52
51
  "qgrid.dispatcherFailed": (provider) => `${provider} dispatcher 초기화에 실패했습니다`,
53
52
  "qgrid.dispatcherStarting": (provider) => `${provider} dispatcher 기동 중입니다. 잠시 후 다시 시도해주세요`,
54
- "qgrid.restartPending": () => "서버 재시작 중입니다. 잠시 후 다시 시도해주세요",
55
53
  "error.unauthorized": "인증이 필요합니다",
56
54
  "error.unknownSearchField": (field) => `구현되지 않은 검색 필드 ${field}`,
57
55
  notFound: (name, id) => `존재하지 않는 ${name} ID ${id}`,
@@ -64,4 +62,4 @@ var ko_default = {
64
62
  //#endregion
65
63
  export { ko_default as default };
66
64
 
67
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia28uanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2kxOG4va28udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgam9zYSB9IGZyb20gXCJzb25hbXUvZGljdFwiO1xuXG4vKipcbiAqIFByb2plY3QgS08gRGljdGlvbmFyeVxuICovXG5leHBvcnQgZGVmYXVsdCB7XG4gIFwiY29tbW9uLmFsbFwiOiBcIuyghOyytFwiLFxuICBcImNvbW1vbi5iYWNrVG9MaXN0XCI6IFwi66qp66Gd7Jy866GcXCIsXG4gIFwiY29tbW9uLmNhbmNlbFwiOiBcIuy3qOyGjFwiLFxuICBcImNvbW1vbi5jbG9zZVwiOiBcIuuLq+q4sFwiLFxuICBcImNvbW1vbi5jb25maXJtXCI6IFwi7ZmV7J24XCIsXG4gIFwiY29tbW9uLmNyZWF0ZVwiOiBcIuyDneyEsVwiLFxuICBcImNvbW1vbi5jcmVhdGVkQXRcIjogXCLrk7HroZ1cIixcbiAgXCJjb21tb24uZGVsZXRlXCI6IFwi7IKt7KCcXCIsXG4gIFwiY29tbW9uLmVkaXRcIjogXCLsiJjsoJVcIixcbiAgXCJjb21tb24ubG9naW5cIjogXCLroZzqt7jsnbhcIixcbiAgXCJjb21tb24ubG9nb3V0XCI6IFwi66Gc6re47JWE7JuDXCIsXG4gIFwiY29tbW9uLm1hbmFnZVwiOiBcIuq0gOumrFwiLFxuICBcImNvbW1vbi5yZXN1bHRzXCI6IChjb3VudDogbnVtYmVyKSA9PiBgJHtjb3VudH3qsJwg6rKw6rO8YCxcbiAgXCJjb21tb24uc2F2ZVwiOiBcIuyggOyepVwiLFxuICBcImNvbW1vbi5zZWFyY2hcIjogXCLqsoDsg4lcIixcbiAgXCJjb21tb24uc2VhcmNoUGxhY2Vob2xkZXJcIjogXCLqsoDsg4kuLi5cIixcbiAgXCJjb21tb24uc2VhcmNoVHlwZVwiOiBcIuqygOyDiSDsnKDtmJVcIixcbiAgXCJjb21tb24uc29ydFwiOiBcIuygleugrFwiLFxuICBcImNvbmZpcm0uZGVsZXRlXCI6IFwi7KCV66eQIOyCreygnO2VmOyLnOqyoOyKteuLiOq5jD9cIixcbiAgXCJjb25maXJtLnNhdmVcIjogXCLsoIDsnqXtlZjsi5zqsqDsirXri4jquYw/XCIsXG4gIFwiZGFzaGJvYXJkLmFkbWluTWVudVwiOiBcIuq0gOumrCDrqZTribRcIixcbiAgXCJkYXNoYm9hcmQuY3JlYXRlZEF0XCI6IFwi6rCA7J6F7J28XCIsXG4gIFwiZGFzaGJvYXJkLmVtYWlsXCI6IFwi7J2066mU7J28XCIsXG4gIFwiZGFzaGJvYXJkLmxvZ2luUmVxdWlyZWRcIjogXCLroZzqt7jsnbjsnbQg7ZWE7JqU7ZWp64uI64ukLlwiLFxuICBcImRhc2hib2FyZC5uYW1lXCI6IFwi7J2066aEXCIsXG4gIFwiZGFzaGJvYXJkLnJvbGVcIjogXCLsl63tlaBcIixcbiAgXCJkYXNoYm9hcmQudGl0bGVcIjogXCLqtIDrpqzsnpAg64yA7Iuc67O065OcXCIsXG4gIFwiZGFzaGJvYXJkLndlbGNvbWVcIjogXCLtmZjsmIHtlanri4jri6QhXCIsXG4gIFwiZGVsZXRlLmNvbmZpcm0uZGVzY3JpcHRpb25cIjogXCLsnbQg7J6R7JeF7J2AIOy3qOyGjO2VoCDsiJgg7JeG7Iq164uI64ukLiDtla3rqqnsnbQg7JiB6rWs7KCB7Jy866GcIOyCreygnOuQqeuLiOuLpC5cIixcbiAgXCJkZWxldGUuY29uZmlybS50aXRsZVwiOiBcIuygleunkCDsgq3soJztlZjsi5zqsqDsirXri4jquYw/XCIsXG4gIFwiZW50aXR5LmNyZWF0ZVwiOiAobmFtZTogc3RyaW5nKSA9PiBgJHtuYW1lfSDsg53shLFgLFxuICBcImVudGl0eS5lZGl0XCI6IChuYW1lOiBzdHJpbmcsIGlkOiBudW1iZXIpID0+IGAke25hbWV9IOyImOyglSAoIyR7aWR9KWAsXG4gIFwiZW50aXR5Lmxpc3RcIjogKG5hbWU6IHN0cmluZykgPT4gYCR7bmFtZX0g66qp66GdYCxcbiAgXCJlbnRpdHkubGlzdE1hbmFnZVwiOiAobmFtZTogc3RyaW5nKSA9PiBgJHtuYW1lfSDrqqnroZ0g6rSA66asYCxcbiAgXCJlcnJvci5hbHJlYWR5UHJvY2Vzc2VkXCI6IFwi7J2066+4IOyymOumrOuQmOyXiOyKteuLiOuLpFwiLFxuICBcImVycm9yLmJhZFJlcXVlc3RcIjogXCLsnpjrqrvrkJwg7JqU7LKt7J6F64uI64ukXCIsXG4gIFwiZXJyb3IuZHVwbGljYXRlUm93XCI6IFwi7KSR67O165CcIOuNsOydtO2EsOyeheuLiOuLpFwiLFxuICBcImVycm9yLmVudGl0eU5vdEZvdW5kXCI6IChuYW1lOiBzdHJpbmcsIGlkOiBudW1iZXIgfCBzdHJpbmcpID0+IGDsobTsnqztlZjsp4Ag7JWK64qUICR7bmFtZX0gSUQgJHtpZH1gLFxuICBcImVycm9yLmZvcmJpZGRlblwiOiBcIuq2jO2VnOydtCDsl4bsirXri4jri6RcIixcbiAgXCJlcnJvci5pbnRlcm5hbFNlcnZlckVycm9yXCI6IFwi7ISc67KEIOyYpOulmOqwgCDrsJzsg53tlojsirXri4jri6RcIixcbiAgXCJlcnJvci5ub3RGb3VuZFwiOiBcIuywvuydhCDsiJgg7JeG7Iq164uI64ukXCIsXG4gIFwiZXJyb3Iuc2VydmljZVVuYXZhaWxhYmxlXCI6IFwi7ISc67mE7Iqk66W8IOyCrOyaqe2VoCDsiJgg7JeG7Iq164uI64ukXCIsXG4gIFwic2V0dGluZy5pbnZhbGlkVmFsdWVcIjogKHJlYXNvbjogc3RyaW5nKSA9PiBg7ISk7KCVIOqwkuydtCDsmKzrsJTrpbTsp4Ag7JWK7Iq164uI64ukOiAke3JlYXNvbn1gLFxuICBcInNldHRpbmcudW5rbm93bktleVwiOiAoa2V5OiBzdHJpbmcpID0+IGDslYwg7IiYIOyXhuuKlCDshKTsoJUg7YKkICR7a2V5fWAsXG4gIFwic2V0dGluZy5ub1N1cGVydmlzb3JcIjogKCkgPT5cbiAgICBcIuuhnOy7rCDsi6Ttlokg7ZmY6rK97JeQ7ISc64qUIOyerOyLnOyeke2VoCDsiJgg7JeG7Iq164uI64ukIOKAlCDsooXro4ztlZjrqbQg64uk7IucIOy8nOykhCDrqqjri4jthLDrp4Eg64+E6rWs6rCAIOyXhuyKteuLiOuLpFwiLFxuICBcInFncmlkLmRpc3BhdGNoZXJGYWlsZWRcIjogKHByb3ZpZGVyOiBzdHJpbmcpID0+IGAke3Byb3ZpZGVyfSBkaXNwYXRjaGVyIOy0iOq4sO2ZlOyXkCDsi6TtjKjtlojsirXri4jri6RgLFxuICBcInFncmlkLmRpc3BhdGNoZXJTdGFydGluZ1wiOiAocHJvdmlkZXI6IHN0cmluZykgPT5cbiAgICBgJHtwcm92aWRlcn0gZGlzcGF0Y2hlciDquLDrj5kg7KSR7J6F64uI64ukLiDsnqDsi5wg7ZuEIOuLpOyLnCDsi5zrj4TtlbTso7zshLjsmpRgLFxuICBcInFncmlkLnJlc3RhcnRQZW5kaW5nXCI6ICgpID0+IFwi7ISc67KEIOyerOyLnOyekSDspJHsnoXri4jri6QuIOyeoOyLnCDtm4Qg64uk7IucIOyLnOuPhO2VtOyjvOyEuOyalFwiLFxuICBcImVycm9yLnVuYXV0aG9yaXplZFwiOiBcIuyduOymneydtCDtlYTsmpTtlanri4jri6RcIixcbiAgXCJlcnJvci51bmtub3duU2VhcmNoRmllbGRcIjogKGZpZWxkOiBzdHJpbmcpID0+IGDqtaztmITrkJjsp4Ag7JWK7J2AIOqygOyDiSDtlYTrk5wgJHtmaWVsZH1gLFxuICBub3RGb3VuZDogKG5hbWU6IHN0cmluZywgaWQ6IG51bWJlcikgPT4gYOyhtOyerO2VmOyngCDslYrripQgJHtuYW1lfSBJRCAke2lkfWAsXG4gIFwidmFsaWRhdGlvbi5lbWFpbFwiOiBcIuyYrOuwlOuluCDsnbTrqZTsnbwg7ZiV7Iud7J20IOyVhOuLmeuLiOuLpFwiLFxuICBcInZhbGlkYXRpb24ubWF4TGVuZ3RoXCI6IChmaWVsZDogc3RyaW5nLCBtYXg6IG51bWJlcikgPT5cbiAgICBgJHtmaWVsZH0ke2pvc2EoZmllbGQsIFwi7J2A64qUXCIpfSDstZzrjIAgJHttYXh97J6Q6rmM7KeAIOyeheugpe2VoCDsiJgg7J6I7Iq164uI64ukYCxcbiAgXCJ2YWxpZGF0aW9uLm1pbkxlbmd0aFwiOiAoZmllbGQ6IHN0cmluZywgbWluOiBudW1iZXIpID0+XG4gICAgYCR7ZmllbGR9JHtqb3NhKGZpZWxkLCBcIuydgOuKlFwiKX0g7LWc7IaMICR7bWlufeyekCDsnbTsg4HsnbTslrTslbwg7ZWp64uI64ukYCxcbiAgXCJ2YWxpZGF0aW9uLnJlcXVpcmVkXCI6IChmaWVsZDogc3RyaW5nKSA9PiBgJHtqb3NhKGZpZWxkLCBcIuydgOuKlFwiKX0g7ZWE7IiY7J6F64uI64ukYCxcbiAgXCJ2YWxpZGF0aW9uLnVybFwiOiBcIuyYrOuwlOuluCBVUkwg7ZiV7Iud7J20IOyVhOuLmeuLiOuLpFwiLFxufSBhcyBjb25zdDtcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFLQSxJQUFBLGFBQWU7Q0FDYixjQUFjO0NBQ2QscUJBQXFCO0NBQ3JCLGlCQUFpQjtDQUNqQixnQkFBZ0I7Q0FDaEIsa0JBQWtCO0NBQ2xCLGlCQUFpQjtDQUNqQixvQkFBb0I7Q0FDcEIsaUJBQWlCO0NBQ2pCLGVBQWU7Q0FDZixnQkFBZ0I7Q0FDaEIsaUJBQWlCO0NBQ2pCLGlCQUFpQjtDQUNqQixtQkFBbUIsVUFBa0IsR0FBRyxNQUFNO0NBQzlDLGVBQWU7Q0FDZixpQkFBaUI7Q0FDakIsNEJBQTRCO0NBQzVCLHFCQUFxQjtDQUNyQixlQUFlO0NBQ2Ysa0JBQWtCO0NBQ2xCLGdCQUFnQjtDQUNoQix1QkFBdUI7Q0FDdkIsdUJBQXVCO0NBQ3ZCLG1CQUFtQjtDQUNuQiwyQkFBMkI7Q0FDM0Isa0JBQWtCO0NBQ2xCLGtCQUFrQjtDQUNsQixtQkFBbUI7Q0FDbkIscUJBQXFCO0NBQ3JCLDhCQUE4QjtDQUM5Qix3QkFBd0I7Q0FDeEIsa0JBQWtCLFNBQWlCLEdBQUcsS0FBSztDQUMzQyxnQkFBZ0IsTUFBYyxPQUFlLEdBQUcsS0FBSyxRQUFRLEdBQUc7Q0FDaEUsZ0JBQWdCLFNBQWlCLEdBQUcsS0FBSztDQUN6QyxzQkFBc0IsU0FBaUIsR0FBRyxLQUFLO0NBQy9DLDBCQUEwQjtDQUMxQixvQkFBb0I7Q0FDcEIsc0JBQXNCO0NBQ3RCLHlCQUF5QixNQUFjLE9BQXdCLFdBQVcsS0FBSyxNQUFNO0NBQ3JGLG1CQUFtQjtDQUNuQiw2QkFBNkI7Q0FDN0Isa0JBQWtCO0NBQ2xCLDRCQUE0QjtDQUM1Qix5QkFBeUIsV0FBbUIsb0JBQW9CO0NBQ2hFLHVCQUF1QixRQUFnQixlQUFlO0NBQ3RELDhCQUNFO0NBQ0YsMkJBQTJCLGFBQXFCLEdBQUcsU0FBUztDQUM1RCw2QkFBNkIsYUFDM0IsR0FBRyxTQUFTO0NBQ2QsOEJBQThCO0NBQzlCLHNCQUFzQjtDQUN0Qiw2QkFBNkIsVUFBa0IsaUJBQWlCO0NBQ2hFLFdBQVcsTUFBYyxPQUFlLFdBQVcsS0FBSyxNQUFNO0NBQzlELG9CQUFvQjtDQUNwQix5QkFBeUIsT0FBZSxRQUN0QyxHQUFHLFFBQVEsS0FBSyxPQUFPLElBQUksRUFBRSxNQUFNLElBQUk7Q0FDekMseUJBQXlCLE9BQWUsUUFDdEMsR0FBRyxRQUFRLEtBQUssT0FBTyxJQUFJLEVBQUUsTUFBTSxJQUFJO0NBQ3pDLHdCQUF3QixVQUFrQixHQUFHLEtBQUssT0FBTyxJQUFJLEVBQUU7Q0FDL0Qsa0JBQWtCO0FBQ3BCIn0=
65
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia28uanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2kxOG4va28udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgam9zYSB9IGZyb20gXCJzb25hbXUvZGljdFwiO1xuXG4vKipcbiAqIFByb2plY3QgS08gRGljdGlvbmFyeVxuICovXG5leHBvcnQgZGVmYXVsdCB7XG4gIFwiY29tbW9uLmFsbFwiOiBcIuyghOyytFwiLFxuICBcImNvbW1vbi5iYWNrVG9MaXN0XCI6IFwi66qp66Gd7Jy866GcXCIsXG4gIFwiY29tbW9uLmNhbmNlbFwiOiBcIuy3qOyGjFwiLFxuICBcImNvbW1vbi5jbG9zZVwiOiBcIuuLq+q4sFwiLFxuICBcImNvbW1vbi5jb25maXJtXCI6IFwi7ZmV7J24XCIsXG4gIFwiY29tbW9uLmNyZWF0ZVwiOiBcIuyDneyEsVwiLFxuICBcImNvbW1vbi5jcmVhdGVkQXRcIjogXCLrk7HroZ1cIixcbiAgXCJjb21tb24uZGVsZXRlXCI6IFwi7IKt7KCcXCIsXG4gIFwiY29tbW9uLmVkaXRcIjogXCLsiJjsoJVcIixcbiAgXCJjb21tb24ubG9naW5cIjogXCLroZzqt7jsnbhcIixcbiAgXCJjb21tb24ubG9nb3V0XCI6IFwi66Gc6re47JWE7JuDXCIsXG4gIFwiY29tbW9uLm1hbmFnZVwiOiBcIuq0gOumrFwiLFxuICBcImNvbW1vbi5yZXN1bHRzXCI6IChjb3VudDogbnVtYmVyKSA9PiBgJHtjb3VudH3qsJwg6rKw6rO8YCxcbiAgXCJjb21tb24uc2F2ZVwiOiBcIuyggOyepVwiLFxuICBcImNvbW1vbi5zZWFyY2hcIjogXCLqsoDsg4lcIixcbiAgXCJjb21tb24uc2VhcmNoUGxhY2Vob2xkZXJcIjogXCLqsoDsg4kuLi5cIixcbiAgXCJjb21tb24uc2VhcmNoVHlwZVwiOiBcIuqygOyDiSDsnKDtmJVcIixcbiAgXCJjb21tb24uc29ydFwiOiBcIuygleugrFwiLFxuICBcImNvbmZpcm0uZGVsZXRlXCI6IFwi7KCV66eQIOyCreygnO2VmOyLnOqyoOyKteuLiOq5jD9cIixcbiAgXCJjb25maXJtLnNhdmVcIjogXCLsoIDsnqXtlZjsi5zqsqDsirXri4jquYw/XCIsXG4gIFwiZGFzaGJvYXJkLmFkbWluTWVudVwiOiBcIuq0gOumrCDrqZTribRcIixcbiAgXCJkYXNoYm9hcmQuY3JlYXRlZEF0XCI6IFwi6rCA7J6F7J28XCIsXG4gIFwiZGFzaGJvYXJkLmVtYWlsXCI6IFwi7J2066mU7J28XCIsXG4gIFwiZGFzaGJvYXJkLmxvZ2luUmVxdWlyZWRcIjogXCLroZzqt7jsnbjsnbQg7ZWE7JqU7ZWp64uI64ukLlwiLFxuICBcImRhc2hib2FyZC5uYW1lXCI6IFwi7J2066aEXCIsXG4gIFwiZGFzaGJvYXJkLnJvbGVcIjogXCLsl63tlaBcIixcbiAgXCJkYXNoYm9hcmQudGl0bGVcIjogXCLqtIDrpqzsnpAg64yA7Iuc67O065OcXCIsXG4gIFwiZGFzaGJvYXJkLndlbGNvbWVcIjogXCLtmZjsmIHtlanri4jri6QhXCIsXG4gIFwiZGVsZXRlLmNvbmZpcm0uZGVzY3JpcHRpb25cIjogXCLsnbQg7J6R7JeF7J2AIOy3qOyGjO2VoCDsiJgg7JeG7Iq164uI64ukLiDtla3rqqnsnbQg7JiB6rWs7KCB7Jy866GcIOyCreygnOuQqeuLiOuLpC5cIixcbiAgXCJkZWxldGUuY29uZmlybS50aXRsZVwiOiBcIuygleunkCDsgq3soJztlZjsi5zqsqDsirXri4jquYw/XCIsXG4gIFwiZW50aXR5LmNyZWF0ZVwiOiAobmFtZTogc3RyaW5nKSA9PiBgJHtuYW1lfSDsg53shLFgLFxuICBcImVudGl0eS5lZGl0XCI6IChuYW1lOiBzdHJpbmcsIGlkOiBudW1iZXIpID0+IGAke25hbWV9IOyImOyglSAoIyR7aWR9KWAsXG4gIFwiZW50aXR5Lmxpc3RcIjogKG5hbWU6IHN0cmluZykgPT4gYCR7bmFtZX0g66qp66GdYCxcbiAgXCJlbnRpdHkubGlzdE1hbmFnZVwiOiAobmFtZTogc3RyaW5nKSA9PiBgJHtuYW1lfSDrqqnroZ0g6rSA66asYCxcbiAgXCJlcnJvci5hbHJlYWR5UHJvY2Vzc2VkXCI6IFwi7J2066+4IOyymOumrOuQmOyXiOyKteuLiOuLpFwiLFxuICBcImVycm9yLmJhZFJlcXVlc3RcIjogXCLsnpjrqrvrkJwg7JqU7LKt7J6F64uI64ukXCIsXG4gIFwiZXJyb3IuZHVwbGljYXRlUm93XCI6IFwi7KSR67O165CcIOuNsOydtO2EsOyeheuLiOuLpFwiLFxuICBcImVycm9yLmVudGl0eU5vdEZvdW5kXCI6IChuYW1lOiBzdHJpbmcsIGlkOiBudW1iZXIgfCBzdHJpbmcpID0+IGDsobTsnqztlZjsp4Ag7JWK64qUICR7bmFtZX0gSUQgJHtpZH1gLFxuICBcImVycm9yLmZvcmJpZGRlblwiOiBcIuq2jO2VnOydtCDsl4bsirXri4jri6RcIixcbiAgXCJlcnJvci5pbnRlcm5hbFNlcnZlckVycm9yXCI6IFwi7ISc67KEIOyYpOulmOqwgCDrsJzsg53tlojsirXri4jri6RcIixcbiAgXCJlcnJvci5ub3RGb3VuZFwiOiBcIuywvuydhCDsiJgg7JeG7Iq164uI64ukXCIsXG4gIFwiZXJyb3Iuc2VydmljZVVuYXZhaWxhYmxlXCI6IFwi7ISc67mE7Iqk66W8IOyCrOyaqe2VoCDsiJgg7JeG7Iq164uI64ukXCIsXG4gIFwic2V0dGluZy5pbnZhbGlkVmFsdWVcIjogKHJlYXNvbjogc3RyaW5nKSA9PiBg7ISk7KCVIOqwkuydtCDsmKzrsJTrpbTsp4Ag7JWK7Iq164uI64ukOiAke3JlYXNvbn1gLFxuICBcInNldHRpbmcudW5rbm93bktleVwiOiAoa2V5OiBzdHJpbmcpID0+IGDslYwg7IiYIOyXhuuKlCDshKTsoJUg7YKkICR7a2V5fWAsXG4gIFwicWdyaWQuZGlzcGF0Y2hlckZhaWxlZFwiOiAocHJvdmlkZXI6IHN0cmluZykgPT4gYCR7cHJvdmlkZXJ9IGRpc3BhdGNoZXIg7LSI6riw7ZmU7JeQIOyLpO2MqO2WiOyKteuLiOuLpGAsXG4gIFwicWdyaWQuZGlzcGF0Y2hlclN0YXJ0aW5nXCI6IChwcm92aWRlcjogc3RyaW5nKSA9PlxuICAgIGAke3Byb3ZpZGVyfSBkaXNwYXRjaGVyIOq4sOuPmSDspJHsnoXri4jri6QuIOyeoOyLnCDtm4Qg64uk7IucIOyLnOuPhO2VtOyjvOyEuOyalGAsXG4gIFwiZXJyb3IudW5hdXRob3JpemVkXCI6IFwi7J247Kad7J20IO2VhOyalO2VqeuLiOuLpFwiLFxuICBcImVycm9yLnVua25vd25TZWFyY2hGaWVsZFwiOiAoZmllbGQ6IHN0cmluZykgPT4gYOq1rO2YhOuQmOyngCDslYrsnYAg6rKA7IOJIO2VhOuTnCAke2ZpZWxkfWAsXG4gIG5vdEZvdW5kOiAobmFtZTogc3RyaW5nLCBpZDogbnVtYmVyKSA9PiBg7KG07J6s7ZWY7KeAIOyViuuKlCAke25hbWV9IElEICR7aWR9YCxcbiAgXCJ2YWxpZGF0aW9uLmVtYWlsXCI6IFwi7Jis67CU66W4IOydtOuplOydvCDtmJXsi53snbQg7JWE64uZ64uI64ukXCIsXG4gIFwidmFsaWRhdGlvbi5tYXhMZW5ndGhcIjogKGZpZWxkOiBzdHJpbmcsIG1heDogbnVtYmVyKSA9PlxuICAgIGAke2ZpZWxkfSR7am9zYShmaWVsZCwgXCLsnYDripRcIil9IOy1nOuMgCAke21heH3snpDquYzsp4Ag7J6F66Cl7ZWgIOyImCDsnojsirXri4jri6RgLFxuICBcInZhbGlkYXRpb24ubWluTGVuZ3RoXCI6IChmaWVsZDogc3RyaW5nLCBtaW46IG51bWJlcikgPT5cbiAgICBgJHtmaWVsZH0ke2pvc2EoZmllbGQsIFwi7J2A64qUXCIpfSDstZzshowgJHttaW597J6QIOydtOyDgeydtOyWtOyVvCDtlanri4jri6RgLFxuICBcInZhbGlkYXRpb24ucmVxdWlyZWRcIjogKGZpZWxkOiBzdHJpbmcpID0+IGAke2pvc2EoZmllbGQsIFwi7J2A64qUXCIpfSDtlYTsiJjsnoXri4jri6RgLFxuICBcInZhbGlkYXRpb24udXJsXCI6IFwi7Jis67CU66W4IFVSTCDtmJXsi53snbQg7JWE64uZ64uI64ukXCIsXG59IGFzIGNvbnN0O1xuIl0sIm1hcHBpbmdzIjoiOzs7OztBQUtBLElBQUEsYUFBZTtDQUNiLGNBQWM7Q0FDZCxxQkFBcUI7Q0FDckIsaUJBQWlCO0NBQ2pCLGdCQUFnQjtDQUNoQixrQkFBa0I7Q0FDbEIsaUJBQWlCO0NBQ2pCLG9CQUFvQjtDQUNwQixpQkFBaUI7Q0FDakIsZUFBZTtDQUNmLGdCQUFnQjtDQUNoQixpQkFBaUI7Q0FDakIsaUJBQWlCO0NBQ2pCLG1CQUFtQixVQUFrQixHQUFHLE1BQU07Q0FDOUMsZUFBZTtDQUNmLGlCQUFpQjtDQUNqQiw0QkFBNEI7Q0FDNUIscUJBQXFCO0NBQ3JCLGVBQWU7Q0FDZixrQkFBa0I7Q0FDbEIsZ0JBQWdCO0NBQ2hCLHVCQUF1QjtDQUN2Qix1QkFBdUI7Q0FDdkIsbUJBQW1CO0NBQ25CLDJCQUEyQjtDQUMzQixrQkFBa0I7Q0FDbEIsa0JBQWtCO0NBQ2xCLG1CQUFtQjtDQUNuQixxQkFBcUI7Q0FDckIsOEJBQThCO0NBQzlCLHdCQUF3QjtDQUN4QixrQkFBa0IsU0FBaUIsR0FBRyxLQUFLO0NBQzNDLGdCQUFnQixNQUFjLE9BQWUsR0FBRyxLQUFLLFFBQVEsR0FBRztDQUNoRSxnQkFBZ0IsU0FBaUIsR0FBRyxLQUFLO0NBQ3pDLHNCQUFzQixTQUFpQixHQUFHLEtBQUs7Q0FDL0MsMEJBQTBCO0NBQzFCLG9CQUFvQjtDQUNwQixzQkFBc0I7Q0FDdEIseUJBQXlCLE1BQWMsT0FBd0IsV0FBVyxLQUFLLE1BQU07Q0FDckYsbUJBQW1CO0NBQ25CLDZCQUE2QjtDQUM3QixrQkFBa0I7Q0FDbEIsNEJBQTRCO0NBQzVCLHlCQUF5QixXQUFtQixvQkFBb0I7Q0FDaEUsdUJBQXVCLFFBQWdCLGVBQWU7Q0FDdEQsMkJBQTJCLGFBQXFCLEdBQUcsU0FBUztDQUM1RCw2QkFBNkIsYUFDM0IsR0FBRyxTQUFTO0NBQ2Qsc0JBQXNCO0NBQ3RCLDZCQUE2QixVQUFrQixpQkFBaUI7Q0FDaEUsV0FBVyxNQUFjLE9BQWUsV0FBVyxLQUFLLE1BQU07Q0FDOUQsb0JBQW9CO0NBQ3BCLHlCQUF5QixPQUFlLFFBQ3RDLEdBQUcsUUFBUSxLQUFLLE9BQU8sSUFBSSxFQUFFLE1BQU0sSUFBSTtDQUN6Qyx5QkFBeUIsT0FBZSxRQUN0QyxHQUFHLFFBQVEsS0FBSyxPQUFPLElBQUksRUFBRSxNQUFNLElBQUk7Q0FDekMsd0JBQXdCLFVBQWtCLEdBQUcsS0FBSyxPQUFPLElBQUksRUFBRTtDQUMvRCxrQkFBa0I7QUFDcEIifQ==
@@ -1,16 +1,10 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
2
 
3
- import {
4
- beginServerRestart,
5
- resetServerRestartForTests,
6
- } from "../../utils/server-restart";
7
3
  import {
8
4
  afterQuery,
9
5
  beforeQuery,
10
- finishActiveNativeRunsForRestart,
11
6
  finishRunAborted,
12
7
  finishRunWithError,
13
- resetNativeRunRegistryForTests,
14
8
  } from "./qgrid-run-lifecycle";
15
9
  import { type QueryOutput } from "./qgrid.types";
16
10
 
@@ -65,11 +59,6 @@ function queryOutput(overrides: Partial<QueryOutput> = {}): QueryOutput {
65
59
 
66
60
  let lifecycleNow = Date.now();
67
61
 
68
- afterEach(() => {
69
- resetServerRestartForTests();
70
- resetNativeRunRegistryForTests();
71
- });
72
-
73
62
  describe("qgrid run lifecycle start", () => {
74
63
  beforeEach(() => {
75
64
  lifecycleNow += 60_001;
@@ -221,107 +210,7 @@ describe("qgrid run lifecycle start", () => {
221
210
  expect(createRunMock).toHaveBeenCalledTimes(2);
222
211
  });
223
212
 
224
- it("rejects new native runs while a restart is pending", async () => {
225
- beginServerRestart();
226
-
227
- await expect(beforeQuery({ prompt: "hi" })).rejects.toMatchObject({ statusCode: 503 });
228
- expect(createRunMock).not.toHaveBeenCalled();
229
- });
230
-
231
- it("finishes a run prepared during the restart race before rejecting provider execution", async () => {
232
- let resolveCreate!: (requestLogId: number) => void;
233
- createRunMock.mockReturnValueOnce(
234
- new Promise<number>((resolve) => {
235
- resolveCreate = resolve;
236
- }),
237
- );
238
-
239
- const starting = beforeQuery({ prompt: "hi" });
240
- await vi.waitFor(() => expect(createRunMock).toHaveBeenCalledOnce());
241
- beginServerRestart();
242
- resolveCreate(22);
243
-
244
- await expect(starting).rejects.toMatchObject({ statusCode: 503 });
245
- expect(finishRunMock).toHaveBeenCalledWith(
246
- 22,
247
- expect.objectContaining({ status: "error", error_message: "server restarted" }),
248
- );
249
- });
250
-
251
- it("marks only active native runs as restarted and prevents a late success overwrite", async () => {
252
- const { requestLogId, stepIndex } = await beforeQuery({ prompt: "hi" });
253
-
254
- await finishActiveNativeRunsForRestart();
255
- expect(finishRunMock).toHaveBeenCalledWith(
256
- requestLogId,
257
- expect.objectContaining({ status: "error", error_message: "server restarted" }),
258
- );
259
-
260
- appendStepMock.mockClear();
261
- finishRunMock.mockClear();
262
- await expect(afterQuery(requestLogId, stepIndex, { prompt: "hi" }, queryOutput())).resolves.toEqual(
263
- {},
264
- );
265
- expect(appendStepMock).not.toHaveBeenCalled();
266
- expect(finishRunMock).not.toHaveBeenCalled();
267
- });
268
-
269
- it("waits for an in-flight finalizer and writes the restart error last", async () => {
270
- const { requestLogId, stepIndex } = await beforeQuery({ prompt: "hi" });
271
- let releaseAppend!: () => void;
272
- appendStepMock.mockReturnValueOnce(
273
- new Promise<void>((resolve) => {
274
- releaseAppend = resolve;
275
- }),
276
- );
277
-
278
- const finishing = afterQuery(requestLogId, stepIndex, { prompt: "hi" }, queryOutput());
279
- await vi.waitFor(() => expect(appendStepMock).toHaveBeenCalledOnce());
280
- const restarting = finishActiveNativeRunsForRestart();
281
-
282
- await Promise.resolve();
283
- expect(finishRunMock).not.toHaveBeenCalledWith(
284
- requestLogId,
285
- expect.objectContaining({ error_message: "server restarted" }),
286
- );
287
-
288
- releaseAppend();
289
- await Promise.all([finishing, restarting]);
290
-
291
- const terminalStatuses = finishRunMock.mock.calls
292
- .filter(([id]) => id === requestLogId)
293
- .map(([, payload]) => payload.status);
294
- expect(terminalStatuses.at(-1)).toBe("error");
295
- expect(finishRunMock).toHaveBeenLastCalledWith(
296
- requestLogId,
297
- expect.objectContaining({ status: "error", error_message: "server restarted" }),
298
- );
299
- });
300
-
301
- it("leaves tool-wait runs alone after their provider turn has completed", async () => {
302
- const { requestLogId, stepIndex } = await beforeQuery({ prompt: "use a tool" });
303
- await afterQuery(
304
- requestLogId,
305
- stepIndex,
306
- { prompt: "use a tool" },
307
- queryOutput({
308
- finishReason: "tool-calls",
309
- content: [
310
- {
311
- type: "tool-call",
312
- toolCallId: "call-1",
313
- toolName: "lookup",
314
- input: "{}",
315
- },
316
- ],
317
- }),
318
- );
319
- finishRunMock.mockClear();
320
-
321
- await finishActiveNativeRunsForRestart();
322
213
 
323
- expect(finishRunMock).not.toHaveBeenCalled();
324
- });
325
214
  });
326
215
 
327
216
  describe("qgrid run lifecycle TTFT", () => {
@@ -1,8 +1,5 @@
1
1
  import { getLogger } from "@logtape/logtape";
2
- import { ServiceUnavailableException } from "sonamu";
3
2
 
4
- import { SD } from "../../i18n/sd.generated";
5
- import { isRestartPending } from "../../utils/server-restart";
6
3
  import { RequestLogModel } from "../request-log/request-log.model";
7
4
  import {
8
5
  estimateImageGenerationCostMicroUsd,
@@ -20,44 +17,6 @@ const STALE_RUN_THRESHOLD_MS = 30 * 60 * 1000;
20
17
  const STALE_CLEANUP_INTERVAL_MS = 60 * 1000;
21
18
  let staleCleanupInFlight: Promise<void> | undefined;
22
19
  let lastStaleCleanupStartedAt = 0;
23
- const activeNativeRunRefs = new Map<number, number>();
24
- const interruptedNativeRunIds = new Set<number>();
25
- const activeNativeFinalizers = new Map<number, Set<Promise<void>>>();
26
-
27
- function restartUnavailable(): ServiceUnavailableException {
28
- return new ServiceUnavailableException(SD("qgrid.restartPending")());
29
- }
30
-
31
- function registerNativeRun(requestLogId: number): void {
32
- activeNativeRunRefs.set(requestLogId, (activeNativeRunRefs.get(requestLogId) ?? 0) + 1);
33
- }
34
-
35
- function releaseNativeRun(requestLogId: number): void {
36
- const refs = activeNativeRunRefs.get(requestLogId);
37
- if (refs === undefined || refs <= 1) activeNativeRunRefs.delete(requestLogId);
38
- else activeNativeRunRefs.set(requestLogId, refs - 1);
39
- }
40
-
41
- function trackNativeFinalizer<T>(requestLogId: number, finalize: () => Promise<T>): Promise<T> {
42
- const operation = finalize();
43
- const settled = operation.then(
44
- () => undefined,
45
- () => undefined,
46
- );
47
- const finalizers = activeNativeFinalizers.get(requestLogId) ?? new Set<Promise<void>>();
48
- finalizers.add(settled);
49
- activeNativeFinalizers.set(requestLogId, finalizers);
50
- void settled.then(() => {
51
- finalizers.delete(settled);
52
- if (finalizers.size === 0) activeNativeFinalizers.delete(requestLogId);
53
- });
54
- return operation;
55
- }
56
-
57
- export function assertNativeRunAdmission(): void {
58
- if (isRestartPending()) throw restartUnavailable();
59
- }
60
-
61
20
  function withProviderPrefix(
62
21
  routeModel: string | undefined,
63
22
  model: string | undefined,
@@ -110,8 +69,6 @@ export async function beforeQuery(args: QueryInput): Promise<{
110
69
  requestLogId: number;
111
70
  stepIndex: number;
112
71
  }> {
113
- assertNativeRunAdmission();
114
-
115
72
  let requestLogId: number;
116
73
  let stepIndex = 0;
117
74
 
@@ -140,14 +97,6 @@ export async function beforeQuery(args: QueryInput): Promise<{
140
97
  });
141
98
  }
142
99
 
143
- // DB 준비 중에 재시작이 시작됐다면 provider 실행으로 넘어가지 않는다.
144
- // 이 요청은 재시작 snapshot에 없었으므로 방금 준비한 run을 직접 마감한다.
145
- if (isRestartPending()) {
146
- await finishTerminalRun(requestLogId, "error", "server restarted");
147
- throw restartUnavailable();
148
- }
149
-
150
- registerNativeRun(requestLogId);
151
100
  return { requestLogId, stepIndex };
152
101
  }
153
102
 
@@ -157,102 +106,94 @@ export async function afterQuery(
157
106
  args: QueryInput,
158
107
  result: QueryOutput,
159
108
  ): Promise<RunLifecycleResult> {
160
- if (interruptedNativeRunIds.has(requestLogId)) return {};
109
+ // provider가 canonical model을 돌려줘도 요청 route 자체([1m] 등)는 보존한다.
110
+ const requestedModelName = withProviderPrefix(
111
+ args.model,
112
+ args.model ?? result.requestedModel ?? result.model,
113
+ );
114
+ const servedModelName = withProviderPrefix(args.model, result.model);
115
+
116
+ // generate step 기록
117
+ await RequestLogModel.appendStep(requestLogId, {
118
+ step_index: stepIndex,
119
+ type: "generate",
120
+ model_name: servedModelName,
121
+ requested_model_name: requestedModelName,
122
+ fallback_count: result.modelFallbacks?.length ?? 0,
123
+ input_tokens: result.usage.input_tokens,
124
+ output_tokens: result.usage.output_tokens,
125
+ cache_read_tokens: result.usage.cache_read_input_tokens,
126
+ cache_creation_tokens: result.usage.cache_creation_input_tokens,
127
+ cache_creation_5m_tokens: result.usage.cache_creation_5m_input_tokens,
128
+ cache_creation_1h_tokens: result.usage.cache_creation_1h_input_tokens,
129
+ cost_usd: Math.round(result.costUsd * 1_000_000),
130
+ cost_source: result.costSource,
131
+ duration_ms: result.durationMs,
132
+ ttft_ms: result.ttftMs,
133
+ finish_reason: result.finishReason,
134
+ });
161
135
 
162
- return trackNativeFinalizer(requestLogId, async () => {
163
- try {
164
- // provider가 canonical model을 돌려줘도 요청 route 자체([1m] 등)는 보존한다.
165
- const requestedModelName = withProviderPrefix(
166
- args.model,
167
- args.model ?? result.requestedModel ?? result.model,
168
- );
169
- const servedModelName = withProviderPrefix(args.model, result.model);
136
+ const imageParts = getImageParts(result);
137
+ const imageCostMicroUsd = estimateImageGenerationCostMicroUsd(
138
+ result,
139
+ args.imageGenerationOptions,
140
+ );
141
+ for (const step of buildImageGenerationToolSteps(args, imageParts, stepIndex)) {
142
+ await RequestLogModel.appendStep(requestLogId, step);
143
+ }
170
144
 
171
- // generate step 기록
145
+ if (result.finishReason === "tool-calls") {
146
+ // tool-call step을 즉시 기록하고, 다음 follow-up이 같은 row에 결과를 채운다.
147
+ const toolCalls = result.content.filter((c) => c.type === "tool-call");
148
+ for (let i = 0; i < toolCalls.length; i++) {
149
+ const tc = toolCalls[i]!;
150
+ if (tc.type !== "tool-call") continue;
172
151
  await RequestLogModel.appendStep(requestLogId, {
173
152
  step_index: stepIndex,
174
- type: "generate",
175
- model_name: servedModelName,
176
- requested_model_name: requestedModelName,
177
- fallback_count: result.modelFallbacks?.length ?? 0,
178
- input_tokens: result.usage.input_tokens,
179
- output_tokens: result.usage.output_tokens,
180
- cache_read_tokens: result.usage.cache_read_input_tokens,
181
- cache_creation_tokens: result.usage.cache_creation_input_tokens,
182
- cache_creation_5m_tokens: result.usage.cache_creation_5m_input_tokens,
183
- cache_creation_1h_tokens: result.usage.cache_creation_1h_input_tokens,
184
- cost_usd: Math.round(result.costUsd * 1_000_000),
185
- cost_source: result.costSource,
186
- duration_ms: result.durationMs,
187
- ttft_ms: result.ttftMs,
188
- finish_reason: result.finishReason,
153
+ type: "tool_call",
154
+ tool_call_index: imageParts.length + i,
155
+ tool_call_id: tc.toolCallId,
156
+ tool_name: tc.toolName,
157
+ tool_args: tc.input,
189
158
  });
159
+ }
190
160
 
191
- const imageParts = getImageParts(result);
192
- const imageCostMicroUsd = estimateImageGenerationCostMicroUsd(
193
- result,
194
- args.imageGenerationOptions,
195
- );
196
- for (const step of buildImageGenerationToolSteps(args, imageParts, stepIndex)) {
197
- await RequestLogModel.appendStep(requestLogId, step);
198
- }
199
-
200
- if (result.finishReason === "tool-calls") {
201
- // tool-call step을 즉시 기록하고, 다음 follow-up이 같은 row에 결과를 채운다.
202
- const toolCalls = result.content.filter((c) => c.type === "tool-call");
203
- for (let i = 0; i < toolCalls.length; i++) {
204
- const tc = toolCalls[i]!;
205
- if (tc.type !== "tool-call") continue;
206
- await RequestLogModel.appendStep(requestLogId, {
207
- step_index: stepIndex,
208
- type: "tool_call",
209
- tool_call_index: imageParts.length + i,
210
- tool_call_id: tc.toolCallId,
211
- tool_name: tc.toolName,
212
- tool_args: tc.input,
213
- });
214
- }
215
-
216
- return { runContext: { requestLogId } };
217
- }
218
-
219
- // finishReason === "stop" → run 종료 (전체 step usage 합산)
220
- const agg = await RequestLogModel.aggregateStepUsage(requestLogId);
221
- const responseText = formatResponseForLog(result);
222
- await RequestLogModel.finishRun(requestLogId, {
223
- status: "succeeded",
224
- response: responseText,
225
- // structured 요청만 판정한다. deti 배치의 broken JSON 류를 목록에서 바로
226
- // 구별하기 위한 기록이며, 비structured 요청은 null 로 남는다.
227
- response_json_ok: args.jsonSchema ? isParseableJson(responseText) : null,
228
- token_name: result.tokenName,
229
- input_tokens: agg.input_tokens,
230
- output_tokens: agg.output_tokens,
231
- cache_read_tokens: agg.cache_read_tokens,
232
- cache_creation_tokens: agg.cache_creation_tokens,
233
- cache_creation_5m_tokens: agg.cache_creation_5m_tokens,
234
- cache_creation_1h_tokens: agg.cache_creation_1h_tokens,
235
- duration_ms: agg.duration_ms,
236
- // multi-step run 부모의 모델은 최종 turn을 서빙한 모델이다.
237
- requested_model_name: requestedModelName,
238
- model_name: servedModelName,
239
- fallback_count: agg.fallback_count,
240
- cost_usd: agg.cost_usd,
241
- cost_source: agg.cost_source,
242
- image_cost_usd: imageCostMicroUsd,
243
- ...(imageParts.length > 0 ? { is_image_generation: true } : {}),
244
- image_cost_method:
245
- imageCostMicroUsd !== null
246
- ? imageGenerationCostMethod(args.imageGenerationOptions, result)
247
- : null,
248
- history: filterHistoryForStorage(args.history),
249
- });
161
+ return { runContext: { requestLogId } };
162
+ }
250
163
 
251
- return {};
252
- } finally {
253
- releaseNativeRun(requestLogId);
254
- }
164
+ // finishReason === "stop" → run 종료 (전체 step usage 합산)
165
+ const agg = await RequestLogModel.aggregateStepUsage(requestLogId);
166
+ const responseText = formatResponseForLog(result);
167
+ await RequestLogModel.finishRun(requestLogId, {
168
+ status: "succeeded",
169
+ response: responseText,
170
+ // structured 요청만 판정한다. deti 배치의 broken JSON 류를 목록에서 바로
171
+ // 구별하기 위한 기록이며, 비structured 요청은 null 로 남는다.
172
+ response_json_ok: args.jsonSchema ? isParseableJson(responseText) : null,
173
+ token_name: result.tokenName,
174
+ input_tokens: agg.input_tokens,
175
+ output_tokens: agg.output_tokens,
176
+ cache_read_tokens: agg.cache_read_tokens,
177
+ cache_creation_tokens: agg.cache_creation_tokens,
178
+ cache_creation_5m_tokens: agg.cache_creation_5m_tokens,
179
+ cache_creation_1h_tokens: agg.cache_creation_1h_tokens,
180
+ duration_ms: agg.duration_ms,
181
+ // multi-step run 부모의 모델은 최종 turn을 서빙한 모델이다.
182
+ requested_model_name: requestedModelName,
183
+ model_name: servedModelName,
184
+ fallback_count: agg.fallback_count,
185
+ cost_usd: agg.cost_usd,
186
+ cost_source: agg.cost_source,
187
+ image_cost_usd: imageCostMicroUsd,
188
+ ...(imageParts.length > 0 ? { is_image_generation: true } : {}),
189
+ image_cost_method:
190
+ imageCostMicroUsd !== null
191
+ ? imageGenerationCostMethod(args.imageGenerationOptions, result)
192
+ : null,
193
+ history: filterHistoryForStorage(args.history),
255
194
  });
195
+
196
+ return {};
256
197
  }
257
198
 
258
199
  export async function finishRunWithError(
@@ -260,48 +201,11 @@ export async function finishRunWithError(
260
201
  errorMessage: string,
261
202
  args?: QueryInput,
262
203
  ): Promise<void> {
263
- if (interruptedNativeRunIds.has(requestLogId)) return;
264
- return trackNativeFinalizer(requestLogId, async () => {
265
- try {
266
- await finishTerminalRun(requestLogId, "error", errorMessage, args);
267
- } finally {
268
- releaseNativeRun(requestLogId);
269
- }
270
- });
204
+ await finishTerminalRun(requestLogId, "error", errorMessage, args);
271
205
  }
272
206
 
273
207
  export async function finishRunAborted(requestLogId: number, args?: QueryInput): Promise<void> {
274
- if (interruptedNativeRunIds.has(requestLogId)) return;
275
- return trackNativeFinalizer(requestLogId, async () => {
276
- try {
277
- await finishTerminalRun(requestLogId, "aborted", "client disconnected", args);
278
- } finally {
279
- releaseNativeRun(requestLogId);
280
- }
281
- });
282
- }
283
-
284
- /** 현재 이 프로세스가 provider를 실행 중인 native run만 재시작 오류로 마감한다. */
285
- export async function finishActiveNativeRunsForRestart(): Promise<void> {
286
- const requestLogIds = [...activeNativeRunRefs.keys()];
287
- for (const requestLogId of requestLogIds) {
288
- interruptedNativeRunIds.add(requestLogId);
289
- activeNativeRunRefs.delete(requestLogId);
290
- }
291
-
292
- await Promise.all(
293
- requestLogIds.map(async (requestLogId) => {
294
- await Promise.all(activeNativeFinalizers.get(requestLogId) ?? []);
295
- await finishTerminalRun(requestLogId, "error", "server restarted");
296
- }),
297
- );
298
- }
299
-
300
- /** 프로세스 전역 registry를 격리해야 하는 단위 테스트 전용. */
301
- export function resetNativeRunRegistryForTests(): void {
302
- activeNativeRunRefs.clear();
303
- interruptedNativeRunIds.clear();
304
- activeNativeFinalizers.clear();
208
+ await finishTerminalRun(requestLogId, "aborted", "client disconnected", args);
305
209
  }
306
210
 
307
211
  async function finishTerminalRun(
@@ -21,7 +21,6 @@ const {
21
21
  dispatcherQueryStreamMock,
22
22
  beforeQueryMock,
23
23
  afterQueryMock,
24
- assertNativeRunAdmissionMock,
25
24
  finishRunWithErrorMock,
26
25
  finishRunAbortedMock,
27
26
  getRateLimitsByTokenIdMock,
@@ -45,7 +44,6 @@ const {
45
44
  dispatcherQueryStreamMock: vi.fn(),
46
45
  beforeQueryMock: vi.fn(),
47
46
  afterQueryMock: vi.fn(),
48
- assertNativeRunAdmissionMock: vi.fn(),
49
47
  finishRunWithErrorMock: vi.fn(),
50
48
  finishRunAbortedMock: vi.fn(),
51
49
  getRateLimitsByTokenIdMock: vi.fn(),
@@ -95,7 +93,6 @@ vi.mock("./qgrid.dispatcher", async (importOriginal) => {
95
93
  });
96
94
 
97
95
  vi.mock("./qgrid-run-lifecycle", () => ({
98
- assertNativeRunAdmission: assertNativeRunAdmissionMock,
99
96
  beforeQuery: beforeQueryMock,
100
97
  afterQuery: afterQueryMock,
101
98
  finishRunWithError: finishRunWithErrorMock,
@@ -215,7 +212,6 @@ describe("QgridFrame.query request logging", () => {
215
212
  beforeEach(() => {
216
213
  beforeQueryMock.mockReset().mockResolvedValue({ requestLogId: 41, stepIndex: 0 });
217
214
  afterQueryMock.mockReset().mockResolvedValue({});
218
- assertNativeRunAdmissionMock.mockReset();
219
215
  finishRunWithErrorMock.mockReset();
220
216
  dispatcherQueryMock.mockReset();
221
217
  findActiveByProviderAndNameMock.mockReset();
@@ -368,18 +364,6 @@ describe("QgridFrame.query request logging", () => {
368
364
  expect(finishRunWithErrorMock).not.toHaveBeenCalled();
369
365
  });
370
366
 
371
- it("rejects logger-disabled native dispatch while restart admission is closed", async () => {
372
- assertNativeRunAdmissionMock.mockImplementationOnce(() => {
373
- throw Object.assign(new Error("server restarting"), { statusCode: 503 });
374
- });
375
-
376
- await expect(
377
- QgridFrame.query({ prompt: "hi", model: "openai/gpt-5-codex", logger: false }),
378
- ).rejects.toMatchObject({ statusCode: 503 });
379
- expect(dispatcherQueryMock).not.toHaveBeenCalled();
380
- expect(beforeQueryMock).not.toHaveBeenCalled();
381
- });
382
-
383
367
  it("merges a tool run id with the provider thread coordinate", async () => {
384
368
  dispatcherQueryMock.mockResolvedValueOnce(queryOutput());
385
369
  afterQueryMock.mockResolvedValueOnce({ runContext: { requestLogId: 41 } });
@@ -952,7 +936,6 @@ describe("QgridFrame.queryStream request logging", () => {
952
936
  beforeEach(() => {
953
937
  beforeQueryMock.mockReset().mockResolvedValue({ requestLogId: 52, stepIndex: 0 });
954
938
  afterQueryMock.mockReset().mockResolvedValue({});
955
- assertNativeRunAdmissionMock.mockReset();
956
939
  finishRunWithErrorMock.mockReset();
957
940
  finishRunAbortedMock.mockReset();
958
941
  dispatcherQueryStreamMock.mockReset();
@@ -986,27 +969,6 @@ describe("QgridFrame.queryStream request logging", () => {
986
969
  };
987
970
  }
988
971
 
989
- it("rejects stream preparation while restart admission is closed", async () => {
990
- assertNativeRunAdmissionMock.mockImplementationOnce(() => {
991
- throw Object.assign(new Error("server restarting"), { statusCode: 503 });
992
- });
993
-
994
- await expect(QgridFrame.prepareStream({ prompt: "hi" })).rejects.toMatchObject({
995
- statusCode: 503,
996
- });
997
- expect(dispatcherQueryStreamMock).not.toHaveBeenCalled();
998
- });
999
-
1000
- it("rechecks admission before dispatching a previously prepared stream", async () => {
1001
- const { streamId } = await QgridFrame.prepareStream({ prompt: "hi", logger: false });
1002
- assertNativeRunAdmissionMock.mockImplementationOnce(() => {
1003
- throw Object.assign(new Error("server restarting"), { statusCode: 503 });
1004
- });
1005
-
1006
- await expect(QgridFrame.queryStream(streamId)).rejects.toMatchObject({ statusCode: 503 });
1007
- expect(dispatcherQueryStreamMock).not.toHaveBeenCalled();
1008
- });
1009
-
1010
972
  function installSseContext() {
1011
973
  let closeHandler: (() => void) | undefined;
1012
974
  const sse = {
@@ -38,7 +38,6 @@ import {
38
38
  RefreshFailedError,
39
39
  } from "./oauth";
40
40
  import {
41
- assertNativeRunAdmission,
42
41
  afterQuery,
43
42
  beforeQuery,
44
43
  finishRunAborted,
@@ -248,7 +247,6 @@ class QgridFrameClass extends BaseFrameClass {
248
247
 
249
248
  @api({ httpMethod: "POST", clients: ["axios", "tanstack-mutation"] })
250
249
  async query(args: QueryInput): Promise<QueryOutput> {
251
- assertNativeRunAdmission();
252
250
  rejectInvalidCallerSchemas(args);
253
251
  const resolvedArgs = await resolveTokenName(args);
254
252
  const disconnect = createHttpDisconnectHandle();
@@ -299,7 +297,6 @@ class QgridFrameClass extends BaseFrameClass {
299
297
 
300
298
  @api({ httpMethod: "POST", clients: ["axios", "tanstack-mutation"] })
301
299
  async prepareStream(args: QueryInput): Promise<{ streamId: string }> {
302
- assertNativeRunAdmission();
303
300
  rejectImageGenerationStream(args);
304
301
  rejectInvalidCallerSchemas(args);
305
302
  const resolvedArgs = await resolveTokenName(args);
@@ -315,7 +312,6 @@ class QgridFrameClass extends BaseFrameClass {
315
312
  const args = pendingStreams.get(streamId);
316
313
  pendingStreams.delete(streamId);
317
314
  if (!args) throw new Error("invalid or expired streamId");
318
- assertNativeRunAdmission();
319
315
  rejectImageGenerationStream(args);
320
316
 
321
317
  const ctx = Sonamu.getContext();