@cartanova/qgrid-cli 2.7.2 → 2.7.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.
- package/bundle/dist/application/queries.generated.js +2 -1
- package/bundle/dist/application/request-log/json-schema-type-text.js +58 -2
- package/bundle/dist/application/request-log/request-log.model.js +44 -3
- package/bundle/dist/application/request-log/request-log.types.js +10 -4
- package/bundle/dist/node_modules/.pnpm/{vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_2519c2e8d8013fcbc7b443879bc9da6d → vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_5b35fc1fb85d2af4d105e0d74f940f50}/node_modules/vite/dist/node/module-runner.js +2 -2
- package/bundle/dist/node_modules/.pnpm/{vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_3892b4338df694f79f7d384fad23d930 → vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618}/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js +2 -2
- package/bundle/dist/node_modules/.pnpm/{vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_3892b4338df694f79f7d384fad23d930 → vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618}/node_modules/vitest/dist/chunks/benchmark.CX_oY03V.js +2 -2
- package/bundle/dist/node_modules/.pnpm/{vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_3892b4338df694f79f7d384fad23d930 → vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618}/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js +3 -3
- package/bundle/dist/node_modules/.pnpm/{vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_3892b4338df694f79f7d384fad23d930 → vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618}/node_modules/vitest/dist/chunks/index.Chj8NDwU.js +2 -2
- package/bundle/dist/node_modules/.pnpm/{vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_3892b4338df694f79f7d384fad23d930 → vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618}/node_modules/vitest/dist/chunks/index.DdgEv5B1.js +2 -2
- package/bundle/dist/node_modules/.pnpm/{vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_3892b4338df694f79f7d384fad23d930 → vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618}/node_modules/vitest/dist/chunks/rpc.MzXet3jl.js +2 -2
- package/bundle/dist/node_modules/.pnpm/{vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_3892b4338df694f79f7d384fad23d930 → vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618}/node_modules/vitest/dist/chunks/test.DNmyFkvJ.js +2 -2
- package/bundle/dist/node_modules/.pnpm/{vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_3892b4338df694f79f7d384fad23d930 → vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618}/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.js +2 -2
- package/bundle/dist/node_modules/.pnpm/{vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_3892b4338df694f79f7d384fad23d930 → vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618}/node_modules/vitest/dist/index.js +2 -2
- package/bundle/dist/testing/setup-mocks.js +2 -2
- package/bundle/src/application/queries.generated.ts +3 -0
- package/bundle/src/application/request-log/json-schema-type-text.test.ts +115 -1
- package/bundle/src/application/request-log/json-schema-type-text.ts +91 -0
- package/bundle/src/application/request-log/request-log.model.test.ts +166 -0
- package/bundle/src/application/request-log/request-log.model.ts +52 -6
- package/bundle/src/application/request-log/request-log.types.ts +11 -2
- package/bundle/src/application/sonamu.generated.http +6 -2
- package/bundle/web-dist/client/assets/index-CPYQIUqO.js +106 -0
- package/bundle/web-dist/client/assets/index-D9xE_tO7.css +1 -0
- package/bundle/web-dist/client/assets/logs-UlTjUAUB.js +1 -0
- package/bundle/web-dist/client/assets/{monit-qap66dhi.js → monit-CVNZnd8j.js} +1 -1
- package/bundle/web-dist/client/assets/{routes-CV07Pzde.js → routes-CF7Jlmfi.js} +1 -1
- package/bundle/web-dist/client/assets/{services.generated-CSW8bhCP.js → services.generated-CA7oRRYY.js} +4 -4
- package/bundle/web-dist/client/assets/settings-N-8sXHl6.js +1 -0
- package/bundle/web-dist/client/assets/show-CGhg0fbn.js +2 -0
- package/bundle/web-dist/client/assets/{tokens-Dt3gfkwP.js → tokens-DaEtcsoL.js} +1 -1
- package/bundle/web-dist/client/assets/{use-oauth-login-flow-Cwi0HtJY.js → use-oauth-login-flow-Eovfx07A.js} +1 -1
- package/bundle/web-dist/client/index.html +3 -3
- package/bundle/web-dist/server/assets/{lazyRouteComponent-0y-znAfz.js → lazyRouteComponent-tS-rTksX.js} +2 -2
- package/bundle/web-dist/server/assets/{logs-CJBbHM3_.js → logs-ttf79emP.js} +3 -14
- package/bundle/web-dist/server/assets/{monit-8WAsPETB.js → monit-CJBUH0l6.js} +2 -2
- package/bundle/web-dist/server/assets/{plus-9das21ju.js → plus-BuSuoeon.js} +1 -1
- package/bundle/web-dist/server/assets/{react-dom-zmEq8BVp.js → react-dom-7_SqhNWR.js} +1 -1
- package/bundle/web-dist/server/assets/{routes-B6bX3o41.js → routes-z79f1sOM.js} +3 -3
- package/bundle/web-dist/server/assets/{services.generated-DyPeBI00.js → services.generated-B5UkNmgc.js} +20 -38
- package/bundle/web-dist/server/assets/{settings-D1u5WdpP.js → settings-nCv71sax.js} +2 -2
- package/bundle/web-dist/server/assets/{show-Cr7vwR0l.js → show-CLrA4ZQ-.js} +158 -37
- package/bundle/web-dist/server/assets/{tokens-BumM0gnH.js → tokens-BwlkZELV.js} +3 -3
- package/bundle/web-dist/server/assets/{use-oauth-login-flow-DmsHGOlx.js → use-oauth-login-flow-B2QllVMi.js} +1 -1
- package/bundle/web-dist/server/entry-server.generated.js +10 -11
- package/package.json +9 -4
- package/skills/qgrid/references/request-log-run-lifecycle.md +9 -1
- package/skills/qgrid/references/sonamu-api-web-flow.md +3 -1
- package/bundle/web-dist/client/assets/index-BldeEvAK.css +0 -1
- package/bundle/web-dist/client/assets/index-DkAXPF9q.js +0 -106
- package/bundle/web-dist/client/assets/logs-DlI6OojL.js +0 -1
- package/bundle/web-dist/client/assets/settings-CdYub4yo.js +0 -1
- package/bundle/web-dist/client/assets/show-DA1L8DVD.js +0 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getSafeTimers } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js";
|
|
2
|
-
//#region ../../node_modules/.pnpm/vitest@4.1.10_@opentelemetry+api@1.9.0_@types+node@25.0.7_@vitest+coverage-v8@4.1.
|
|
2
|
+
//#region ../../node_modules/.pnpm/vitest@4.1.10_@opentelemetry+api@1.9.0_@types+node@25.0.7_@vitest+coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.js
|
|
3
3
|
const NAME_WORKER_STATE = "__vitest_worker__";
|
|
4
4
|
var EnvironmentTeardownError = class extends Error {
|
|
5
5
|
name = "EnvironmentTeardownError";
|
|
@@ -56,4 +56,4 @@ async function waitForImportsToResolve() {
|
|
|
56
56
|
//#endregion
|
|
57
57
|
export { EnvironmentTeardownError as E, getSafeWorkerState as a, getWorkerState as g, isChildProcess as i, provideWorkerState as p, resetModules as r, waitForImportsToResolve as w };
|
|
58
58
|
|
|
59
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
59
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuQlg1Rmc4QzQuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL3ZpdGVzdEA0LjEuMTBfQG9wZW50ZWxlbWV0cnkrYXBpQDEuOS4wX0B0eXBlcytub2RlQDI1LjAuN19Adml0ZXN0K2NvdmVyYWdlLXY4QDQuMS4xMF92aV9hMTk3N2I5M2FmN2JiNjkzMDhiY2IxZGJhYjM5YjYxOC9ub2RlX21vZHVsZXMvdml0ZXN0L2Rpc3QvY2h1bmtzL3V0aWxzLkJYNUZnOEM0LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGdldFNhZmVUaW1lcnMgfSBmcm9tICdAdml0ZXN0L3V0aWxzL3RpbWVycyc7XG5cbmNvbnN0IE5BTUVfV09SS0VSX1NUQVRFID0gXCJfX3ZpdGVzdF93b3JrZXJfX1wiO1xuY2xhc3MgRW52aXJvbm1lbnRUZWFyZG93bkVycm9yIGV4dGVuZHMgRXJyb3Ige1xuXHRuYW1lID0gXCJFbnZpcm9ubWVudFRlYXJkb3duRXJyb3JcIjtcbn1cbmZ1bmN0aW9uIGdldFdvcmtlclN0YXRlKCkge1xuXHQvLyBAdHMtZXhwZWN0LWVycm9yIHVudHlwZWQgZ2xvYmFsXG5cdGNvbnN0IHdvcmtlclN0YXRlID0gZ2xvYmFsVGhpc1tOQU1FX1dPUktFUl9TVEFURV07XG5cdGlmICghd29ya2VyU3RhdGUpIHRocm93IG5ldyBFcnJvcihcIlZpdGVzdCBmYWlsZWQgdG8gYWNjZXNzIGl0cyBpbnRlcm5hbCBzdGF0ZS5cXG5cXG5PbmUgb2YgdGhlIGZvbGxvd2luZyBpcyBwb3NzaWJsZTpcXG4tIFxcXCJ2aXRlc3RcXFwiIGlzIGltcG9ydGVkIGRpcmVjdGx5IHdpdGhvdXQgcnVubmluZyBcXFwidml0ZXN0XFxcIiBjb21tYW5kXFxuLSBcXFwidml0ZXN0XFxcIiBpcyBpbXBvcnRlZCBpbnNpZGUgXFxcImdsb2JhbFNldHVwXFxcIiAodG8gZml4IHRoaXMsIHVzZSBcXFwic2V0dXBGaWxlc1xcXCIgaW5zdGVhZCwgYmVjYXVzZSBcXFwiZ2xvYmFsU2V0dXBcXFwiIHJ1bnMgaW4gYSBkaWZmZXJlbnQgY29udGV4dClcXG4tIFxcXCJ2aXRlc3RcXFwiIGlzIGltcG9ydGVkIGluc2lkZSBWaXRlIC8gVml0ZXN0IGNvbmZpZyBmaWxlXFxuLSBPdGhlcndpc2UsIGl0IG1pZ2h0IGJlIGEgVml0ZXN0IGJ1Zy4gUGxlYXNlIHJlcG9ydCBpdCB0byBodHRwczovL2dpdGh1Yi5jb20vdml0ZXN0LWRldi92aXRlc3QvaXNzdWVzXFxuXCIpO1xuXHRyZXR1cm4gd29ya2VyU3RhdGU7XG59XG5mdW5jdGlvbiBnZXRTYWZlV29ya2VyU3RhdGUoKSB7XG5cdC8vIEB0cy1leHBlY3QtZXJyb3IgdW50eXBlZCBnbG9iYWxcblx0cmV0dXJuIGdsb2JhbFRoaXNbTkFNRV9XT1JLRVJfU1RBVEVdO1xufVxuZnVuY3Rpb24gcHJvdmlkZVdvcmtlclN0YXRlKGNvbnRleHQsIHN0YXRlKSB7XG5cdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjb250ZXh0LCBOQU1FX1dPUktFUl9TVEFURSwge1xuXHRcdHZhbHVlOiBzdGF0ZSxcblx0XHRjb25maWd1cmFibGU6IHRydWUsXG5cdFx0d3JpdGFibGU6IHRydWUsXG5cdFx0ZW51bWVyYWJsZTogZmFsc2Vcblx0fSk7XG5cdHJldHVybiBzdGF0ZTtcbn1cbmZ1bmN0aW9uIGlzQ2hpbGRQcm9jZXNzKCkge1xuXHRyZXR1cm4gdHlwZW9mIHByb2Nlc3MgIT09IFwidW5kZWZpbmVkXCIgJiYgISFwcm9jZXNzLnNlbmQ7XG59XG5mdW5jdGlvbiByZXNldE1vZHVsZXMobW9kdWxlcywgcmVzZXRNb2NrcyA9IGZhbHNlKSB7XG5cdGNvbnN0IHNraXBQYXRocyA9IFtcblx0XHQvXFwvdml0ZXN0XFwvZGlzdFxcLy8sXG5cdFx0L3ZpdGVzdC12aXJ0dWFsLVxcdytcXC9kaXN0Lyxcblx0XHQvQHZpdGVzdFxcL2Rpc3QvLFxuXHRcdC4uLiFyZXNldE1vY2tzID8gWy9ebW9jazovXSA6IFtdXG5cdF07XG5cdG1vZHVsZXMuaWRUb01vZHVsZU1hcC5mb3JFYWNoKChub2RlLCBwYXRoKSA9PiB7XG5cdFx0aWYgKHNraXBQYXRocy5zb21lKChyZSkgPT4gcmUudGVzdChwYXRoKSkpIHJldHVybjtcblx0XHRub2RlLnByb21pc2UgPSB2b2lkIDA7XG5cdFx0bm9kZS5leHBvcnRzID0gdm9pZCAwO1xuXHRcdG5vZGUuZXZhbHVhdGVkID0gZmFsc2U7XG5cdFx0bm9kZS5pbXBvcnRlcnMuY2xlYXIoKTtcblx0fSk7XG59XG5mdW5jdGlvbiB3YWl0TmV4dFRpY2soKSB7XG5cdGNvbnN0IHsgc2V0VGltZW91dCB9ID0gZ2V0U2FmZVRpbWVycygpO1xuXHRyZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgMCkpO1xufVxuYXN5bmMgZnVuY3Rpb24gd2FpdEZvckltcG9ydHNUb1Jlc29sdmUoKSB7XG5cdGF3YWl0IHdhaXROZXh0VGljaygpO1xuXHRjb25zdCBzdGF0ZSA9IGdldFdvcmtlclN0YXRlKCk7XG5cdGNvbnN0IHByb21pc2VzID0gW107XG5cdGNvbnN0IHJlc29sdmluZ0NvdW50ID0gc3RhdGUucmVzb2x2aW5nTW9kdWxlcy5zaXplO1xuXHRmb3IgKGNvbnN0IFtfLCBtb2RdIG9mIHN0YXRlLmV2YWx1YXRlZE1vZHVsZXMuaWRUb01vZHVsZU1hcCkgaWYgKG1vZC5wcm9taXNlICYmICFtb2QuZXZhbHVhdGVkKSBwcm9taXNlcy5wdXNoKG1vZC5wcm9taXNlKTtcblx0aWYgKCFwcm9taXNlcy5sZW5ndGggJiYgIXJlc29sdmluZ0NvdW50KSByZXR1cm47XG5cdGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChwcm9taXNlcyk7XG5cdGF3YWl0IHdhaXRGb3JJbXBvcnRzVG9SZXNvbHZlKCk7XG59XG5cbmV4cG9ydCB7IEVudmlyb25tZW50VGVhcmRvd25FcnJvciBhcyBFLCBnZXRTYWZlV29ya2VyU3RhdGUgYXMgYSwgZ2V0V29ya2VyU3RhdGUgYXMgZywgaXNDaGlsZFByb2Nlc3MgYXMgaSwgcHJvdmlkZVdvcmtlclN0YXRlIGFzIHAsIHJlc2V0TW9kdWxlcyBhcyByLCB3YWl0Rm9ySW1wb3J0c1RvUmVzb2x2ZSBhcyB3IH07XG4iXSwieF9nb29nbGVfaWdub3JlTGlzdCI6WzBdLCJtYXBwaW5ncyI6Ijs7QUFFQSxNQUFNLG9CQUFvQjtBQUMxQixJQUFNLDJCQUFOLGNBQXVDLE1BQU07Q0FDNUMsT0FBTztBQUNSO0FBQ0EsU0FBUyxpQkFBaUI7Q0FFekIsTUFBTSxjQUFjLFdBQVc7Q0FDL0IsSUFBSSxDQUFDLGFBQWEsTUFBTSxJQUFJLE1BQU0sNmNBQTZjO0NBQy9lLE9BQU87QUFDUjtBQUNBLFNBQVMscUJBQXFCO0NBRTdCLE9BQU8sV0FBVztBQUNuQjtBQUNBLFNBQVMsbUJBQW1CLFNBQVMsT0FBTztDQUMzQyxPQUFPLGVBQWUsU0FBUyxtQkFBbUI7RUFDakQsT0FBTztFQUNQLGNBQWM7RUFDZCxVQUFVO0VBQ1YsWUFBWTtDQUNiLENBQUM7Q0FDRCxPQUFPO0FBQ1I7QUFDQSxTQUFTLGlCQUFpQjtDQUN6QixPQUFPLE9BQU8sWUFBWSxlQUFlLENBQUMsQ0FBQyxRQUFRO0FBQ3BEO0FBQ0EsU0FBUyxhQUFhLFNBQVMsYUFBYSxPQUFPO0NBQ2xELE1BQU0sWUFBWTtFQUNqQjtFQUNBO0VBQ0E7RUFDQSxHQUFHLENBQUMsYUFBYSxDQUFDLFFBQVEsSUFBSSxDQUFDO0NBQ2hDO0NBQ0EsUUFBUSxjQUFjLFNBQVMsTUFBTSxTQUFTO0VBQzdDLElBQUksVUFBVSxNQUFNLE9BQU8sR0FBRyxLQUFLLElBQUksQ0FBQyxHQUFHO0VBQzNDLEtBQUssVUFBVSxLQUFLO0VBQ3BCLEtBQUssVUFBVSxLQUFLO0VBQ3BCLEtBQUssWUFBWTtFQUNqQixLQUFLLFVBQVUsTUFBTTtDQUN0QixDQUFDO0FBQ0Y7QUFDQSxTQUFTLGVBQWU7Q0FDdkIsTUFBTSxFQUFFLGVBQWUsY0FBYztDQUNyQyxPQUFPLElBQUksU0FBUyxZQUFZLFdBQVcsU0FBUyxDQUFDLENBQUM7QUFDdkQ7QUFDQSxlQUFlLDBCQUEwQjtDQUN4QyxNQUFNLGFBQWE7Q0FDbkIsTUFBTSxRQUFRLGVBQWU7Q0FDN0IsTUFBTSxXQUFXLENBQUM7Q0FDbEIsTUFBTSxpQkFBaUIsTUFBTSxpQkFBaUI7Q0FDOUMsS0FBSyxNQUFNLENBQUMsR0FBRyxRQUFRLE1BQU0saUJBQWlCLGVBQWUsSUFBSSxJQUFJLFdBQVcsQ0FBQyxJQUFJLFdBQVcsU0FBUyxLQUFLLElBQUksT0FBTztDQUN6SCxJQUFJLENBQUMsU0FBUyxVQUFVLENBQUMsZ0JBQWdCO0NBQ3pDLE1BQU0sUUFBUSxXQUFXLFFBQVE7Q0FDakMsTUFBTSx3QkFBd0I7QUFDL0IifQ==
|
|
@@ -17,7 +17,7 @@ import "./chunks/index.Chj8NDwU.js";
|
|
|
17
17
|
import "./chunks/rpc.MzXet3jl.js";
|
|
18
18
|
import "../../../../@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js";
|
|
19
19
|
import { v as vi } from "./chunks/test.DNmyFkvJ.js";
|
|
20
|
-
import "../../../../vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.
|
|
20
|
+
import "../../../../vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_5b35fc1fb85d2af4d105e0d74f940f50/node_modules/vite/dist/node/module-runner.js";
|
|
21
21
|
import "./chunks/evaluatedModules.Dg1zASAC.js";
|
|
22
22
|
import { require_dist } from "../../../../expect-type@1.3.0/node_modules/expect-type/dist/index.js";
|
|
23
23
|
import "./chunks/index.DdgEv5B1.js";
|
|
@@ -25,4 +25,4 @@ require_dist();
|
|
|
25
25
|
//#endregion
|
|
26
26
|
export { vi };
|
|
27
27
|
|
|
28
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
28
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL3ZpdGVzdEA0LjEuMTBfQG9wZW50ZWxlbWV0cnkrYXBpQDEuOS4wX0B0eXBlcytub2RlQDI1LjAuN19Adml0ZXN0K2NvdmVyYWdlLXY4QDQuMS4xMF92aV9hMTk3N2I5M2FmN2JiNjkzMDhiY2IxZGJhYjM5YjYxOC9ub2RlX21vZHVsZXMvdml0ZXN0L2Rpc3QvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHsgTiBhcyBCZW5jaG1hcmtSdW5uZXIsIFMgYXMgU25hcHNob3RzLCBUIGFzIFRlc3RSdW5uZXIsIGEgYXMgYXNzZXJ0LCBjIGFzIGNyZWF0ZUV4cGVjdCwgZyBhcyBleHBlY3QsIGkgYXMgaW5qZWN0LCBzIGFzIHNob3VsZCwgdiBhcyB2aSwgYiBhcyB2aXRlc3QgfSBmcm9tICcuL2NodW5rcy90ZXN0LkRObXlGa3ZKLmpzJztcbmV4cG9ydCB7IGIgYXMgYmVuY2ggfSBmcm9tICcuL2NodW5rcy9iZW5jaG1hcmsuQ1hfb1kwM1YuanMnO1xuZXhwb3J0IHsgViBhcyBFdmFsdWF0ZWRNb2R1bGVzIH0gZnJvbSAnLi9jaHVua3MvZXZhbHVhdGVkTW9kdWxlcy5EZzF6QVNBQy5qcyc7XG5leHBvcnQgeyBhIGFzIGFzc2VydFR5cGUgfSBmcm9tICcuL2NodW5rcy9pbmRleC5EZGdFdjVCMS5qcyc7XG5leHBvcnQgeyBleHBlY3RUeXBlT2YgfSBmcm9tICdleHBlY3QtdHlwZSc7XG5leHBvcnQgeyBhZnRlckFsbCwgYWZ0ZXJFYWNoLCBhcm91bmRBbGwsIGFyb3VuZEVhY2gsIGJlZm9yZUFsbCwgYmVmb3JlRWFjaCwgZGVzY3JpYmUsIGl0LCBvblRlc3RGYWlsZWQsIG9uVGVzdEZpbmlzaGVkLCByZWNvcmRBcnRpZmFjdCwgc3VpdGUsIHRlc3QgfSBmcm9tICdAdml0ZXN0L3J1bm5lcic7XG5leHBvcnQgeyBjaGFpIH0gZnJvbSAnQHZpdGVzdC9leHBlY3QnO1xuaW1wb3J0ICdAdml0ZXN0L3V0aWxzL2hlbHBlcnMnO1xuaW1wb3J0ICdAdml0ZXN0L3V0aWxzL3RpbWVycyc7XG5pbXBvcnQgJy4vY2h1bmtzL3V0aWxzLkJYNUZnOEM0LmpzJztcbmltcG9ydCAnQHZpdGVzdC9ydW5uZXIvdXRpbHMnO1xuaW1wb3J0ICdAdml0ZXN0L3V0aWxzL2Vycm9yJztcbmltcG9ydCAncGF0aGUnO1xuaW1wb3J0ICdAdml0ZXN0L3NweSc7XG5pbXBvcnQgJ0B2aXRlc3QvdXRpbHMvb2Zmc2V0JztcbmltcG9ydCAnQHZpdGVzdC91dGlscy9zb3VyY2UtbWFwJztcbmltcG9ydCAnLi9jaHVua3MvX2NvbW1vbmpzSGVscGVycy5EMjZ0eTNFdy5qcyc7XG5pbXBvcnQgJy4vY2h1bmtzL3JwYy5NelhldDNqbC5qcyc7XG5pbXBvcnQgJy4vY2h1bmtzL2luZGV4LkNoajhORHdVLmpzJztcbmltcG9ydCAnQHZpdGVzdC9zbmFwc2hvdCc7XG5pbXBvcnQgJ3ZpdGUvbW9kdWxlLXJ1bm5lcic7XG4iXSwieF9nb29nbGVfaWdub3JlTGlzdCI6WzBdLCJtYXBwaW5ncyI6IiJ9
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { v as vi } from "../node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.
|
|
2
|
-
import "../node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.
|
|
1
|
+
import { v as vi } from "../node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/test.DNmyFkvJ.js";
|
|
2
|
+
import "../node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/index.js";
|
|
3
3
|
//#region src/testing/setup-mocks.ts
|
|
4
4
|
vi.mock("fs/promises", async (importOriginal) => {
|
|
5
5
|
const actual = await importOriginal();
|
|
@@ -97,6 +97,9 @@ export namespace RequestLogService {
|
|
|
97
97
|
|
|
98
98
|
export const responseTypeTs = (id: number): SSRQuery =>
|
|
99
99
|
createSSRQuery("RequestLogModel", "responseTypeTs", [id], ["RequestLog", "responseTypeTs"]);
|
|
100
|
+
|
|
101
|
+
export const toolsView = (id: number): SSRQuery =>
|
|
102
|
+
createSSRQuery("RequestLogModel", "toolsView", [id], ["RequestLog", "toolsView"]);
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
export namespace QgridService {
|
|
@@ -1,12 +1,50 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
renderJsonSchemaZodShapeText,
|
|
5
|
+
renderJsonSchemaTypeText,
|
|
6
|
+
renderParsedJsonSchemaTypeText,
|
|
7
|
+
} from "./json-schema-type-text";
|
|
4
8
|
|
|
5
9
|
function schema(value: unknown): string {
|
|
6
10
|
return JSON.stringify(value);
|
|
7
11
|
}
|
|
8
12
|
|
|
9
13
|
describe("renderJsonSchemaTypeText", () => {
|
|
14
|
+
it("preserves the existing parsed-schema output across supported node kinds", () => {
|
|
15
|
+
expect(
|
|
16
|
+
renderParsedJsonSchemaTypeText({
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
mode: { anyOf: [{ const: "fast" }, { const: "safe" }] },
|
|
20
|
+
attempts: { type: "integer" },
|
|
21
|
+
tag: { type: ["string", "null"] },
|
|
22
|
+
options: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
enabled: { type: "boolean" },
|
|
26
|
+
opaque: { format: "custom" },
|
|
27
|
+
},
|
|
28
|
+
required: ["enabled"],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ["mode", "attempts", "tag", "options"],
|
|
32
|
+
}),
|
|
33
|
+
).toBe(
|
|
34
|
+
[
|
|
35
|
+
"type Response = {",
|
|
36
|
+
' mode: "fast" | "safe"',
|
|
37
|
+
" attempts: number",
|
|
38
|
+
" tag: string | null",
|
|
39
|
+
" options: {",
|
|
40
|
+
" enabled: boolean",
|
|
41
|
+
" opaque?: unknown",
|
|
42
|
+
" }",
|
|
43
|
+
"}",
|
|
44
|
+
].join("\n"),
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
10
48
|
it("renders a flat object with optionality from required", () => {
|
|
11
49
|
const result = renderJsonSchemaTypeText(
|
|
12
50
|
schema({
|
|
@@ -94,3 +132,79 @@ describe("renderJsonSchemaTypeText", () => {
|
|
|
94
132
|
expect(renderJsonSchemaTypeText("{broken")).toBeNull();
|
|
95
133
|
});
|
|
96
134
|
});
|
|
135
|
+
|
|
136
|
+
describe("renderJsonSchemaZodShapeText", () => {
|
|
137
|
+
it("renders a compact object shape with required, optional, and default annotations", () => {
|
|
138
|
+
expect(
|
|
139
|
+
renderJsonSchemaZodShapeText(
|
|
140
|
+
{
|
|
141
|
+
type: "object",
|
|
142
|
+
properties: {
|
|
143
|
+
limit: { type: "integer", default: 10, maximum: 100 },
|
|
144
|
+
query: { type: "string", minLength: 1, pattern: "^[a-z]+$" },
|
|
145
|
+
},
|
|
146
|
+
required: ["query"],
|
|
147
|
+
},
|
|
148
|
+
6,
|
|
149
|
+
),
|
|
150
|
+
).toBe(
|
|
151
|
+
[
|
|
152
|
+
"z.object({",
|
|
153
|
+
" query: z.string(),",
|
|
154
|
+
" limit: z.number().optional(), // default=10",
|
|
155
|
+
"})",
|
|
156
|
+
].join("\n"),
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("shortens long string enums with an inline remainder comment", () => {
|
|
161
|
+
expect(
|
|
162
|
+
renderJsonSchemaZodShapeText(
|
|
163
|
+
{
|
|
164
|
+
type: "object",
|
|
165
|
+
properties: {
|
|
166
|
+
mode: { enum: ["one", "two", "three", "four", "five", "six", "seven", "eight"] },
|
|
167
|
+
},
|
|
168
|
+
required: ["mode"],
|
|
169
|
+
},
|
|
170
|
+
6,
|
|
171
|
+
),
|
|
172
|
+
).toBe(
|
|
173
|
+
[
|
|
174
|
+
"z.object({",
|
|
175
|
+
' mode: z.enum(["one", "two", "three", "four", "five", "six" /* +2 */]),',
|
|
176
|
+
"})",
|
|
177
|
+
].join("\n"),
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("renders nested objects, arrays, unions, literals, and unknown nodes", () => {
|
|
182
|
+
expect(
|
|
183
|
+
renderJsonSchemaZodShapeText({
|
|
184
|
+
type: "object",
|
|
185
|
+
properties: {
|
|
186
|
+
filters: {
|
|
187
|
+
type: "object",
|
|
188
|
+
properties: {
|
|
189
|
+
tags: { type: "array", items: { type: "string" } },
|
|
190
|
+
value: { anyOf: [{ const: 1 }, { type: "boolean" }] },
|
|
191
|
+
},
|
|
192
|
+
required: ["tags"],
|
|
193
|
+
},
|
|
194
|
+
opaque: { format: "custom" },
|
|
195
|
+
},
|
|
196
|
+
required: ["filters", "opaque"],
|
|
197
|
+
}),
|
|
198
|
+
).toBe(
|
|
199
|
+
[
|
|
200
|
+
"z.object({",
|
|
201
|
+
" filters: z.object({",
|
|
202
|
+
" tags: z.array(z.string()),",
|
|
203
|
+
" value: z.union([z.literal(1), z.boolean()]).optional(),",
|
|
204
|
+
" }),",
|
|
205
|
+
" opaque: z.unknown(),",
|
|
206
|
+
"})",
|
|
207
|
+
].join("\n"),
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
@@ -25,6 +25,92 @@ function renderPrimitive(type: unknown): string {
|
|
|
25
25
|
return "unknown";
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
function renderZodPrimitive(type: unknown): string {
|
|
29
|
+
if (type === "string") return "z.string()";
|
|
30
|
+
if (type === "number" || type === "integer") return "z.number()";
|
|
31
|
+
if (type === "boolean") return "z.boolean()";
|
|
32
|
+
if (type === "null") return "z.null()";
|
|
33
|
+
return "z.unknown()";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function renderZodEnum(values: unknown[], enumValueLimit?: number): string {
|
|
37
|
+
if (values.length === 0) return "z.never()";
|
|
38
|
+
|
|
39
|
+
const visibleValues =
|
|
40
|
+
enumValueLimit === undefined ? values : values.slice(0, Math.max(0, enumValueLimit));
|
|
41
|
+
const omittedCount = values.length - visibleValues.length;
|
|
42
|
+
const suffix = omittedCount > 0 ? ` /* +${omittedCount} */` : "";
|
|
43
|
+
|
|
44
|
+
if (values.every((value) => typeof value === "string")) {
|
|
45
|
+
return `z.enum([${visibleValues.map((value) => JSON.stringify(value)).join(", ")}${suffix}])`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const literals = visibleValues.map((value) => `z.literal(${JSON.stringify(value)})`);
|
|
49
|
+
if (literals.length === 1 && omittedCount === 0) return literals[0] ?? "z.never()";
|
|
50
|
+
return `z.union([${literals.join(", ")}${suffix}])`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function renderZodNode(node: unknown, depth: number, enumValueLimit?: number): string {
|
|
54
|
+
if (node === true) return "z.unknown()";
|
|
55
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return "z.unknown()";
|
|
56
|
+
const schema = node as SchemaNode;
|
|
57
|
+
|
|
58
|
+
if (Array.isArray(schema.enum)) return renderZodEnum(schema.enum, enumValueLimit);
|
|
59
|
+
if (schema.const !== undefined) return `z.literal(${JSON.stringify(schema.const)})`;
|
|
60
|
+
|
|
61
|
+
const variants = (schema.anyOf ?? schema.oneOf) as unknown;
|
|
62
|
+
if (Array.isArray(variants) && variants.length > 0) {
|
|
63
|
+
const rendered = [
|
|
64
|
+
...new Set(variants.map((variant) => renderZodNode(variant, depth, enumValueLimit))),
|
|
65
|
+
];
|
|
66
|
+
return rendered.length === 1
|
|
67
|
+
? (rendered[0] ?? "z.unknown()")
|
|
68
|
+
: `z.union([${rendered.join(", ")}])`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const type = schema.type;
|
|
72
|
+
if (Array.isArray(type)) {
|
|
73
|
+
const rendered = [...new Set(type.map(renderZodPrimitive))];
|
|
74
|
+
return rendered.length === 1
|
|
75
|
+
? (rendered[0] ?? "z.unknown()")
|
|
76
|
+
: `z.union([${rendered.join(", ")}])`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (type === "object" || (type === undefined && schema.properties)) {
|
|
80
|
+
const properties = (schema.properties ?? {}) as Record<string, unknown>;
|
|
81
|
+
const required = new Set(Array.isArray(schema.required) ? (schema.required as string[]) : []);
|
|
82
|
+
const keys = Object.keys(properties);
|
|
83
|
+
if (keys.length === 0) return "z.object({})";
|
|
84
|
+
const orderedKeys = [
|
|
85
|
+
...keys.filter((key) => required.has(key)),
|
|
86
|
+
...keys.filter((key) => !required.has(key)),
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const inner = " ".repeat(depth + 1);
|
|
90
|
+
const lines = orderedKeys.map((key) => {
|
|
91
|
+
const propertySchema = properties[key];
|
|
92
|
+
const rendered = renderZodNode(propertySchema, depth + 1, enumValueLimit);
|
|
93
|
+
const optional = required.has(key) ? rendered : `${rendered}.optional()`;
|
|
94
|
+
const defaultValue =
|
|
95
|
+
propertySchema &&
|
|
96
|
+
typeof propertySchema === "object" &&
|
|
97
|
+
!Array.isArray(propertySchema) &&
|
|
98
|
+
Object.hasOwn(propertySchema, "default")
|
|
99
|
+
? JSON.stringify((propertySchema as SchemaNode).default)
|
|
100
|
+
: undefined;
|
|
101
|
+
const defaultComment = defaultValue === undefined ? "" : ` // default=${defaultValue}`;
|
|
102
|
+
return `${inner}${renderKey(key)}: ${optional},${defaultComment}`;
|
|
103
|
+
});
|
|
104
|
+
return `z.object({\n${lines.join("\n")}\n${" ".repeat(depth)}})`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (type === "array") {
|
|
108
|
+
return `z.array(${renderZodNode(schema.items, depth, enumValueLimit)})`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return renderZodPrimitive(type);
|
|
112
|
+
}
|
|
113
|
+
|
|
28
114
|
function renderNode(node: unknown, depth: number): string {
|
|
29
115
|
if (node === true) return "unknown";
|
|
30
116
|
if (!node || typeof node !== "object" || Array.isArray(node)) return "unknown";
|
|
@@ -73,6 +159,11 @@ export function renderParsedJsonSchemaTypeText(schema: unknown, name = "Response
|
|
|
73
159
|
return `type ${name} = ${renderNode(schema, 0)}`;
|
|
74
160
|
}
|
|
75
161
|
|
|
162
|
+
/** Tool input 계약용 표시 전용 Zod shape. 검증 제약은 의도적으로 생략한다. */
|
|
163
|
+
export function renderJsonSchemaZodShapeText(schema: unknown, enumValueLimit?: number): string {
|
|
164
|
+
return renderZodNode(schema, 0, enumValueLimit);
|
|
165
|
+
}
|
|
166
|
+
|
|
76
167
|
/** 실패(파싱 불가 등) 시 null — 호출부가 표시 자체를 생략한다. */
|
|
77
168
|
export function renderJsonSchemaTypeText(schemaJson: string, name = "Response"): string | null {
|
|
78
169
|
try {
|
|
@@ -28,6 +28,16 @@ function mockTransactionalWritePuri(transactionPuri: unknown) {
|
|
|
28
28
|
return transaction;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
function mockToolsViewQuery(row: { tools: unknown } | undefined) {
|
|
32
|
+
const chain = mockQueryBuilder(row === undefined ? [] : [row]);
|
|
33
|
+
const from = vi.fn(() => chain);
|
|
34
|
+
vi.spyOn(
|
|
35
|
+
RequestLogModel as unknown as { getPuri: () => { from: typeof from } },
|
|
36
|
+
"getPuri",
|
|
37
|
+
).mockReturnValue({ from });
|
|
38
|
+
return { chain, from };
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
describe("RequestLogModel TTFT", () => {
|
|
32
42
|
afterEach(() => {
|
|
33
43
|
vi.restoreAllMocks();
|
|
@@ -108,6 +118,162 @@ describe("RequestLogModel TTFT", () => {
|
|
|
108
118
|
});
|
|
109
119
|
});
|
|
110
120
|
|
|
121
|
+
describe("RequestLogModel toolsView", () => {
|
|
122
|
+
afterEach(() => {
|
|
123
|
+
vi.restoreAllMocks();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("returns a display-ready required-first contract from the decoded JSONB value", async () => {
|
|
127
|
+
const tools = [
|
|
128
|
+
{
|
|
129
|
+
name: "search",
|
|
130
|
+
description: "Search indexed records",
|
|
131
|
+
inputSchema: {
|
|
132
|
+
type: "object",
|
|
133
|
+
properties: {
|
|
134
|
+
optionalEmpty: { type: "string", default: "" },
|
|
135
|
+
requiredEnum: {
|
|
136
|
+
enum: ["one", "two", "three", "four", "five", "six", "seven", "eight"],
|
|
137
|
+
description: "Search mode",
|
|
138
|
+
},
|
|
139
|
+
requiredFalse: { type: "boolean", default: false },
|
|
140
|
+
requiredZero: { type: "integer", default: 0 },
|
|
141
|
+
optionalNull: { type: ["string", "null"], default: null, description: 42 },
|
|
142
|
+
optionalAbsent: { type: "string", description: "Optional note" },
|
|
143
|
+
},
|
|
144
|
+
required: ["requiredEnum", "requiredFalse", "requiredZero"],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: "ping",
|
|
149
|
+
inputSchema: {
|
|
150
|
+
type: "object",
|
|
151
|
+
properties: { message: { type: "string" } },
|
|
152
|
+
required: ["message"],
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
];
|
|
156
|
+
const { chain, from } = mockToolsViewQuery({ tools });
|
|
157
|
+
|
|
158
|
+
await expect(RequestLogModel.toolsView(7)).resolves.toEqual([
|
|
159
|
+
{
|
|
160
|
+
name: "search",
|
|
161
|
+
description: "Search indexed records",
|
|
162
|
+
parameterCount: 6,
|
|
163
|
+
inputZod: [
|
|
164
|
+
"z.object({",
|
|
165
|
+
' requiredEnum: z.enum(["one", "two", "three", "four", "five", "six" /* +2 */]),',
|
|
166
|
+
" requiredFalse: z.boolean(), // default=false",
|
|
167
|
+
" requiredZero: z.number(), // default=0",
|
|
168
|
+
' optionalEmpty: z.string().optional(), // default=""',
|
|
169
|
+
" optionalNull: z.union([z.string(), z.null()]).optional(), // default=null",
|
|
170
|
+
" optionalAbsent: z.string().optional(),",
|
|
171
|
+
"})",
|
|
172
|
+
].join("\n"),
|
|
173
|
+
fullInputZod: [
|
|
174
|
+
"z.object({",
|
|
175
|
+
' requiredEnum: z.enum(["one", "two", "three", "four", "five", "six", "seven", "eight"]),',
|
|
176
|
+
" requiredFalse: z.boolean(), // default=false",
|
|
177
|
+
" requiredZero: z.number(), // default=0",
|
|
178
|
+
' optionalEmpty: z.string().optional(), // default=""',
|
|
179
|
+
" optionalNull: z.union([z.string(), z.null()]).optional(), // default=null",
|
|
180
|
+
" optionalAbsent: z.string().optional(),",
|
|
181
|
+
"})",
|
|
182
|
+
].join("\n"),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "ping",
|
|
186
|
+
parameterCount: 1,
|
|
187
|
+
inputZod: ["z.object({", " message: z.string(),", "})"].join("\n"),
|
|
188
|
+
},
|
|
189
|
+
]);
|
|
190
|
+
|
|
191
|
+
expect(from).toHaveBeenCalledWith("request_logs");
|
|
192
|
+
expect(chain.select).toHaveBeenCalledWith({ tools: "request_logs.tools" });
|
|
193
|
+
expect(chain.where).toHaveBeenCalledWith("request_logs.id", 7);
|
|
194
|
+
expect(chain.first).toHaveBeenCalledTimes(1);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("defensively decodes string storage without changing the view contract", async () => {
|
|
198
|
+
mockToolsViewQuery({
|
|
199
|
+
tools: JSON.stringify([
|
|
200
|
+
{
|
|
201
|
+
name: "lookup",
|
|
202
|
+
description: "Look up one record",
|
|
203
|
+
inputSchema: {
|
|
204
|
+
type: "object",
|
|
205
|
+
properties: { id: { type: "string" } },
|
|
206
|
+
required: ["id"],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
]),
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await expect(RequestLogModel.toolsView(11)).resolves.toEqual([
|
|
213
|
+
{
|
|
214
|
+
name: "lookup",
|
|
215
|
+
description: "Look up one record",
|
|
216
|
+
parameterCount: 1,
|
|
217
|
+
inputZod: ["z.object({", " id: z.string(),", "})"].join("\n"),
|
|
218
|
+
},
|
|
219
|
+
]);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// inputSchema 는 QgridTool 상 z.unknown() 이라 키 누락·null 도 wire 검증을 통과한다.
|
|
223
|
+
// 하나가 터지면 map 전체가 죽어 그 요청의 tool 계약이 통째로 사라지므로 개별 정규화한다.
|
|
224
|
+
it("renders unusable input schemas without failing the entire tool contract", async () => {
|
|
225
|
+
mockToolsViewQuery({
|
|
226
|
+
tools: [
|
|
227
|
+
{ name: "unknown_input", inputSchema: {} },
|
|
228
|
+
{ name: "empty_object_input", inputSchema: { type: "object" } },
|
|
229
|
+
{ name: "string_input", inputSchema: { type: "string" } },
|
|
230
|
+
{ name: "null_input", inputSchema: null },
|
|
231
|
+
{ name: "absent_input" },
|
|
232
|
+
],
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
await expect(RequestLogModel.toolsView(13)).resolves.toEqual([
|
|
236
|
+
{
|
|
237
|
+
name: "unknown_input",
|
|
238
|
+
parameterCount: 0,
|
|
239
|
+
inputZod: "z.unknown()",
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: "empty_object_input",
|
|
243
|
+
parameterCount: 0,
|
|
244
|
+
inputZod: "z.object({})",
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: "string_input",
|
|
248
|
+
parameterCount: 0,
|
|
249
|
+
inputZod: "z.string()",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "null_input",
|
|
253
|
+
parameterCount: 0,
|
|
254
|
+
inputZod: "z.unknown()",
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
name: "absent_input",
|
|
258
|
+
parameterCount: 0,
|
|
259
|
+
inputZod: "z.unknown()",
|
|
260
|
+
},
|
|
261
|
+
]);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it.each([
|
|
265
|
+
["a missing row", undefined],
|
|
266
|
+
["null tools", { tools: null }],
|
|
267
|
+
["an empty decoded array", { tools: [] }],
|
|
268
|
+
["empty stored text", { tools: "" }],
|
|
269
|
+
["invalid stored JSON", { tools: "{broken" }],
|
|
270
|
+
])("returns an empty view for %s", async (_label, row) => {
|
|
271
|
+
mockToolsViewQuery(row);
|
|
272
|
+
|
|
273
|
+
await expect(RequestLogModel.toolsView(12)).resolves.toEqual([]);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
111
277
|
describe("RequestLogModel run lifecycle", () => {
|
|
112
278
|
afterEach(() => {
|
|
113
279
|
vi.restoreAllMocks();
|
|
@@ -14,17 +14,32 @@ import { SD } from "../../i18n/sd.generated";
|
|
|
14
14
|
import { calculateCostUsd } from "../../utils/providers/common/model-cost";
|
|
15
15
|
import { type RequestLogSubsetKey, type RequestLogSubsetMapping } from "../sonamu.generated";
|
|
16
16
|
import { requestLogLoaderQueries, requestLogSubsetQueries } from "../sonamu.generated.sso";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
renderJsonSchemaZodShapeText,
|
|
19
|
+
renderParsedJsonSchemaTypeText,
|
|
20
|
+
} from "./json-schema-type-text";
|
|
18
21
|
import {
|
|
19
22
|
type RequestLogListParams,
|
|
20
23
|
type RequestLogSaveParams,
|
|
21
24
|
type ToolDefinitions,
|
|
25
|
+
type ToolView,
|
|
22
26
|
} from "./request-log.types";
|
|
23
27
|
import { formatZodCode } from "./zod-code-format";
|
|
24
28
|
|
|
25
29
|
// cost_usd는 정수 micro-USD로 저장. 실제 USD = cost_usd / MICRO_USD.
|
|
26
30
|
export const MICRO_USD = 1_000_000;
|
|
27
31
|
const REQUEST_LOG_RUN_LOCK_CLASS_ID = 718;
|
|
32
|
+
const TOOL_ENUM_VALUE_LIMIT = 6;
|
|
33
|
+
|
|
34
|
+
function decodeStoredTools(value: unknown): ToolDefinitions | null {
|
|
35
|
+
if (!value) return null;
|
|
36
|
+
if (typeof value !== "string") return value as ToolDefinitions;
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(value) as ToolDefinitions;
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
28
43
|
|
|
29
44
|
type ToolResultContinuation = {
|
|
30
45
|
toolCallId: string;
|
|
@@ -263,11 +278,6 @@ class RequestLogModelClass extends BaseModelClass<
|
|
|
263
278
|
qb.where("request_logs.model_name", params.model_name);
|
|
264
279
|
}
|
|
265
280
|
|
|
266
|
-
// structured 응답이 JSON 파싱에 실패한 행만 — broken 배치 조사용 필터.
|
|
267
|
-
if (params.response_json_broken) {
|
|
268
|
-
qb.where("request_logs.response_json_ok", false);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
281
|
if (params.search && params.keyword && params.keyword.length > 0) {
|
|
272
282
|
if (params.search === "id") {
|
|
273
283
|
qb.where("request_logs.id", Number(params.keyword));
|
|
@@ -426,6 +436,42 @@ class RequestLogModelClass extends BaseModelClass<
|
|
|
426
436
|
return { typescript: renderParsedJsonSchemaTypeText(parsed), zod };
|
|
427
437
|
}
|
|
428
438
|
|
|
439
|
+
// ── Tool Contract View
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* 요청에 장착된 tool 계약을 detail 화면용으로 축약한다. JSONB 는 이미 decode 된
|
|
443
|
+
* 배열로 오며 문자열인 경우만 방어적으로 parse 한다. 저장된 QgridTool 계약은
|
|
444
|
+
* 전수 검사로 확인됐으므로 항목별 보정이나 unreadable sentinel 은 만들지 않는다.
|
|
445
|
+
* 다만 `QgridTool.inputSchema` 는 `z.unknown()` 이라 키가 없거나 null 인 값도
|
|
446
|
+
* wire 검증을 통과하므로 빈 스키마로 정규화한다 — SDK 는 `{}` 로 채워 보낸다.
|
|
447
|
+
*/
|
|
448
|
+
@api({ httpMethod: "GET", clients: ["axios", "tanstack-query"] })
|
|
449
|
+
async toolsView(id: number): Promise<ToolView[]> {
|
|
450
|
+
const row = (await this.getPuri("r")
|
|
451
|
+
.from("request_logs")
|
|
452
|
+
.select({ tools: "request_logs.tools" })
|
|
453
|
+
.where("request_logs.id", id)
|
|
454
|
+
.first()) as { tools: unknown } | undefined;
|
|
455
|
+
const tools = decodeStoredTools(row?.tools);
|
|
456
|
+
if (!tools) return [];
|
|
457
|
+
|
|
458
|
+
return tools.map((tool) => {
|
|
459
|
+
const inputSchema = (tool.inputSchema ?? {}) as {
|
|
460
|
+
properties?: Record<string, unknown>;
|
|
461
|
+
};
|
|
462
|
+
const inputZod = renderJsonSchemaZodShapeText(inputSchema, TOOL_ENUM_VALUE_LIMIT);
|
|
463
|
+
const fullInputZod = renderJsonSchemaZodShapeText(inputSchema);
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
name: tool.name,
|
|
467
|
+
...(tool.description !== undefined ? { description: tool.description } : {}),
|
|
468
|
+
parameterCount: Object.keys(inputSchema.properties ?? {}).length,
|
|
469
|
+
inputZod,
|
|
470
|
+
...(inputZod !== fullInputZod ? { fullInputZod } : {}),
|
|
471
|
+
};
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
429
475
|
// ── Run Lifecycle ──────────────────────────────────────────────
|
|
430
476
|
|
|
431
477
|
async createRun(params: {
|
|
@@ -20,13 +20,22 @@ export type HistoryItems = z.infer<typeof HistoryItems>;
|
|
|
20
20
|
export const ToolDefinitions = z.array(QgridTool);
|
|
21
21
|
export type ToolDefinitions = z.infer<typeof ToolDefinitions>;
|
|
22
22
|
|
|
23
|
+
// request-log detail 화면이 소비하는 tool 계약 projection. API 반환 타입은 Sonamu
|
|
24
|
+
// syncer 가 모듈을 해석할 수 있도록 type-only 선언 대신 Zod schema 로 둔다.
|
|
25
|
+
export const ToolView = z.object({
|
|
26
|
+
name: z.string(),
|
|
27
|
+
description: z.string().optional(),
|
|
28
|
+
parameterCount: z.number(),
|
|
29
|
+
inputZod: z.string(),
|
|
30
|
+
fullInputZod: z.string().optional(),
|
|
31
|
+
});
|
|
32
|
+
export type ToolView = z.infer<typeof ToolView>;
|
|
33
|
+
|
|
23
34
|
// RequestLog - ListParams
|
|
24
35
|
// project_name NULL 분기: IS NULL만 조회(unassigned 필터) 또는 IS NOT NULL만(distinct 조회).
|
|
25
36
|
export const RequestLogListParams = RequestLogBaseListParams.extend({
|
|
26
37
|
project_name_is_null: z.boolean().optional(),
|
|
27
38
|
project_name_is_not_null: z.boolean().optional(),
|
|
28
|
-
// structured 응답이 깨진(JSON 파싱 실패) 행만 조회
|
|
29
|
-
response_json_broken: z.boolean().optional(),
|
|
30
39
|
});
|
|
31
40
|
export type RequestLogListParams = z.infer<typeof RequestLogListParams>;
|
|
32
41
|
|
|
@@ -226,7 +226,6 @@ GET {{baseUrl}}/api/requestLog/findMany
|
|
|
226
226
|
&rawParams[model_name]=
|
|
227
227
|
&rawParams[project_name_is_null]=false
|
|
228
228
|
&rawParams[project_name_is_not_null]=false
|
|
229
|
-
&rawParams[response_json_broken]=false
|
|
230
229
|
Content-Type: application/json
|
|
231
230
|
|
|
232
231
|
###
|
|
@@ -281,6 +280,12 @@ Content-Type: application/json
|
|
|
281
280
|
|
|
282
281
|
###
|
|
283
282
|
|
|
283
|
+
GET {{baseUrl}}/api/requestLog/toolsView
|
|
284
|
+
?id=0
|
|
285
|
+
Content-Type: application/json
|
|
286
|
+
|
|
287
|
+
###
|
|
288
|
+
|
|
284
289
|
POST {{baseUrl}}/api/requestLog/del
|
|
285
290
|
Content-Type: application/json
|
|
286
291
|
|
|
@@ -520,7 +525,6 @@ GET {{baseUrl}}/api/qgrid/totalCost
|
|
|
520
525
|
¶ms[model_name]=
|
|
521
526
|
¶ms[project_name_is_null]=false
|
|
522
527
|
¶ms[project_name_is_not_null]=false
|
|
523
|
-
¶ms[response_json_broken]=false
|
|
524
528
|
Content-Type: application/json
|
|
525
529
|
|
|
526
530
|
###
|