@zintrust/trace 0.4.84 → 0.4.92

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.
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@zintrust/trace",
3
- "version": "0.4.84",
4
- "buildDate": "2026-04-08T17:51:22.444Z",
3
+ "version": "0.4.92",
4
+ "buildDate": "2026-04-10T08:41:38.521Z",
5
5
  "buildEnvironment": {
6
- "node": "v22.22.1",
7
- "platform": "darwin",
8
- "arch": "arm64"
6
+ "node": "v20.20.2",
7
+ "platform": "linux",
8
+ "arch": "x64"
9
9
  },
10
10
  "git": {
11
- "commit": "d4c31a0d",
12
- "branch": "release"
11
+ "commit": "d195a996",
12
+ "branch": "master"
13
13
  },
14
14
  "package": {
15
15
  "engines": {
@@ -21,10 +21,6 @@
21
21
  ]
22
22
  },
23
23
  "files": {
24
- "build-manifest.json": {
25
- "size": 14440,
26
- "sha256": "04b7ac17fd2a9abf208db4df6218eea2f97a4ce4e1dc6ce8d826036924e7ab84"
27
- },
28
24
  "cli-register.d.ts": {
29
25
  "size": 255,
30
26
  "sha256": "da8d689fe5ef32e97e755f28017e4d3cb1aa63489073a71907ea41ad5761ede9"
@@ -70,8 +66,8 @@
70
66
  "sha256": "4862b41e0477f01afa0dbb446d4553b65c22ed774cd1e2db3489059ced392f94"
71
67
  },
72
68
  "dashboard/ui.js": {
73
- "size": 70368,
74
- "sha256": "b9f67e7977a36b459ac8d37312547b2638fcab7fc9b6c3d0c072d02510fca62f"
69
+ "size": 73577,
70
+ "sha256": "2903901d8c0c5076118aa691727daa79be7abe87fdb393c5b389a2b1a8fce170"
75
71
  },
76
72
  "index.d.ts": {
77
73
  "size": 2470,
@@ -79,7 +75,7 @@
79
75
  },
80
76
  "index.js": {
81
77
  "size": 3255,
82
- "sha256": "f95401dc3b5ad76937e32978770c9568cf90e453bb1e77d0ecc8611e664b5ce0"
78
+ "sha256": "683151fa06b666ec62b150a4fda949c3d35221228b8538644ef740252b63587d"
83
79
  },
84
80
  "migrations/20260331000001_create_zin_trace_entries_table.d.ts": {
85
81
  "size": 304,
@@ -134,16 +130,8 @@
134
130
  "sha256": "71d366165dd36f1675aa253a76262b226fb6c62e5ab632746b8aea61c0c625fc"
135
131
  },
136
132
  "register.js": {
137
- "size": 12522,
138
- "sha256": "66bccec7fac4d669702fa18e439788325d36ce17f228639005ffcde2cd968d70"
139
- },
140
- "storage/DebuggerStorage.d.ts": {
141
- "size": 517,
142
- "sha256": "c9c215aaa414f7b0c1fec6c82b054fc52bdf97af58f96f35c7f96672fb859c31"
143
- },
144
- "storage/DebuggerStorage.js": {
145
- "size": 7442,
146
- "sha256": "5ecce0fcfcf695df587a7b90a7a5c7efd2e64ad13c9f2d104b392f89f34f0dc4"
133
+ "size": 14225,
134
+ "sha256": "07e1643982cc93149c609d44beb11dea168ecf1cac3f78d95d6d22fedcafbc23"
147
135
  },
148
136
  "storage/TraceContentRedaction.d.ts": {
149
137
  "size": 207,
@@ -342,8 +330,8 @@
342
330
  "sha256": "f3ddc5f8b58c6c86ac6b464dd48e5a55e79ab2bf2e735feacffc7480e4ccc0c4"
343
331
  },
344
332
  "watchers/LogWatcher.js": {
345
- "size": 2026,
346
- "sha256": "c5d2227cd76ce10162993ac31f474b2460cd41264c36f01b5130152f14a0ad21"
333
+ "size": 3126,
334
+ "sha256": "e0944661b48b682520d60ee9e98b3fa9f8ba4694743f134f98b04b8b2dd479e6"
347
335
  },
348
336
  "watchers/MailWatcher.d.ts": {
349
337
  "size": 244,
@@ -382,8 +370,8 @@
382
370
  "sha256": "5d5046c65e5b683369c7709f1acd09b60aec3e7f44748fd1baeb35498836465b"
383
371
  },
384
372
  "watchers/QueryWatcher.js": {
385
- "size": 2935,
386
- "sha256": "577c6fec0282d2290db5c4b6c606b9b6ecdd64209af2b09f3205a15bf656bbef"
373
+ "size": 3002,
374
+ "sha256": "c7131284e75ab2f0193597cdf3ef0aa7eab1a3872fe9193579a140a41fadb57e"
387
375
  },
388
376
  "watchers/RedisWatcher.d.ts": {
389
377
  "size": 294,
@@ -70,11 +70,11 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
70
70
  .panel{border-radius:var(--radius);border:1px solid var(--line);background:var(--surface);box-shadow:var(--shadow);backdrop-filter:blur(16px)}.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:16px;margin-bottom:18px}.stat-card{padding:20px;position:relative;overflow:hidden}.stat-card::after{content:'';position:absolute;right:-18px;bottom:-26px;width:92px;height:92px;border-radius:28px;background:linear-gradient(135deg,rgba(56,189,248,.16),rgba(34,197,94,.08));transform:rotate(18deg)}.stat-label{font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:800;margin-bottom:12px}.stat-value{font-size:2.25rem;font-weight:800;line-height:1}.stat-meta{margin-top:10px;color:var(--muted);font-size:.9rem}.content-grid{display:grid;grid-template-columns:minmax(0,1.65fr) minmax(320px,.95fr);gap:18px}.side-stack{display:grid;gap:18px}
71
71
  .section-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;padding:22px 24px 16px}.section-head h3{margin:0;font-size:1.04rem}.section-head p{margin:6px 0 0;color:var(--muted);font-size:.92rem}.toolbar{display:flex;flex-wrap:wrap;gap:10px;padding:0 24px 18px}.control,.toolbar input,.toolbar select{height:44px;border-radius:13px;border:1px solid var(--line);background:var(--surface-strong);color:var(--text);padding:0 14px;min-width:0}.toolbar input,.toolbar select{flex:1 1 180px}.toolbar input::placeholder{color:var(--muted)}.btn{height:44px;border:none;border-radius:13px;padding:0 16px;cursor:pointer;font-weight:800}.btn-primary{background:linear-gradient(135deg,var(--accent-strong),var(--accent));color:#fff}.btn-danger{background:rgba(239,68,68,.12);color:var(--danger);border:1px solid rgba(239,68,68,.18)}.btn-ghost{background:var(--surface-soft);color:var(--text);border:1px solid var(--line)}
72
72
  .table-wrap{overflow:auto;padding:0 12px 12px}table{width:100%;border-collapse:separate;border-spacing:0;min-width:880px}th{padding:14px;color:var(--muted);font-size:.74rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;text-align:left;border-bottom:1px solid var(--line)}td{padding:15px 14px;border-bottom:1px solid var(--line);vertical-align:top}.row-button{cursor:pointer}.row-button:hover td{background:rgba(56,189,248,.05)}.summary{font-size:.93rem;font-weight:700;line-height:1.4;color:var(--text)}.summary-sub{margin-top:6px;color:var(--muted);font-size:.82rem;line-height:1.4}.mono{font-family:var(--mono)}.empty{padding:44px 24px;color:var(--muted);line-height:1.65;text-align:center}.pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:0 24px 24px;color:var(--muted);flex-wrap:wrap}.pagination-controls{display:flex;gap:8px}.pagination button{height:40px;min-width:92px;padding:0 14px;border-radius:12px;border:1px solid var(--line);background:var(--surface-strong);color:var(--text);cursor:pointer}.pagination button:disabled{opacity:.45;cursor:not-allowed}
73
- .activity-list{list-style:none;margin:0;padding:0 24px 24px}.activity-item{padding:14px 0;border-top:1px solid var(--line)}.activity-item:first-child{border-top:none}.activity-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.activity-time{color:var(--muted);font-size:.85rem}.activity-summary{margin-top:8px;color:var(--text);line-height:1.48}.back-link{display:inline-flex;align-items:center;gap:8px;margin:0 0 14px;color:var(--accent);font-weight:800;cursor:pointer}.detail-card{padding:24px}.detail-meta{display:flex;flex-wrap:wrap;gap:10px;margin:14px 0 20px;color:var(--muted);font-size:.9rem}.detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px}.detail-stack{display:grid;gap:16px;margin-top:18px}.detail-box{padding:16px;border-radius:16px;background:var(--surface-soft);border:1px solid var(--line)}.detail-box h4{margin:0 0 10px;font-size:.92rem}.detail-box dl{margin:0;display:grid;gap:8px}.detail-box dt{font-size:.76rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:800}.detail-box dd{margin:0;color:var(--text);line-height:1.45}.trace-tabs{display:flex;gap:10px;flex-wrap:wrap;margin:20px 0 16px}.trace-tab{border:none;border-radius:12px;padding:10px 12px;background:transparent;color:var(--muted);cursor:pointer;box-shadow:inset 0 0 0 1px var(--line);font-weight:800}.trace-tab.active{background:rgba(56,189,248,.12);color:var(--text);box-shadow:inset 0 0 0 1px rgba(56,189,248,.28)}.trace-panel{display:grid;gap:14px}.trace-item{padding:18px;border-radius:16px;background:var(--surface-soft);border:1px solid var(--line)}.trace-item-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.trace-item-summary{margin-top:10px;display:grid;gap:10px}.trace-note{color:var(--muted);line-height:1.6}
73
+ .activity-list{list-style:none;margin:0;padding:0 24px 24px}.activity-item{padding:14px 0;border-top:1px solid var(--line)}.activity-item:first-child{border-top:none}.activity-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.activity-time{color:var(--muted);font-size:.85rem}.activity-summary{margin-top:8px;color:var(--text);line-height:1.48}.back-link{display:inline-flex;align-items:center;gap:8px;margin:0 0 14px;color:var(--accent);font-weight:800;cursor:pointer}.detail-card{padding:24px}.detail-meta{display:flex;flex-wrap:wrap;gap:10px;margin:14px 0 20px;color:var(--muted);font-size:.9rem;overflow-wrap:anywhere}.detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px}.detail-stack{display:grid;gap:16px;margin-top:18px}.detail-box{padding:16px;border-radius:16px;background:var(--surface-soft);border:1px solid var(--line)}.detail-box h4{margin:0 0 10px;font-size:.92rem}.detail-box dl{margin:0;display:grid;gap:8px}.detail-box dt{font-size:.76rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:800}.detail-box dd{margin:0;color:var(--text);line-height:1.45;overflow-wrap:anywhere}.trace-tabs{display:flex;gap:10px;flex-wrap:wrap;margin:20px 0 16px}.trace-tab{border:none;border-radius:12px;padding:10px 12px;background:transparent;color:var(--muted);cursor:pointer;box-shadow:inset 0 0 0 1px var(--line);font-weight:800}.trace-tab.active{background:rgba(56,189,248,.12);color:var(--text);box-shadow:inset 0 0 0 1px rgba(56,189,248,.28)}.trace-panel{display:grid;gap:14px}.trace-item{padding:18px;border-radius:16px;background:var(--surface-soft);border:1px solid var(--line)}.trace-item-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.trace-item-summary{margin-top:10px;display:grid;gap:10px}.trace-note{color:var(--muted);line-height:1.6}.trace-disclosure{padding:0;overflow:hidden}.trace-disclosure[open]{padding-bottom:18px}.trace-disclosure .trace-item-summary{margin-top:0}.trace-disclosure-body{display:grid;gap:12px;padding:0 18px}.trace-summary{list-style:none;cursor:pointer;padding:18px}.trace-summary::-webkit-details-marker{display:none}.trace-summary-main{display:grid;gap:10px;min-width:0;flex:1}.trace-summary-copy{display:grid;gap:6px;min-width:0}.trace-summary-copy .summary,.trace-summary-copy .summary-sub{display:block;overflow-wrap:anywhere}.trace-disclosure-body .summary-sub{overflow-wrap:anywhere}
74
74
  .tag{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:999px;background:rgba(56,189,248,.12);color:#bae6fd;font-size:.78rem;font-weight:800;margin:0 6px 6px 0;border:1px solid rgba(56,189,248,.18);text-decoration:none}button.tag{cursor:pointer}html[data-theme='light'] .tag{color:#075985}.tag.failed{background:rgba(239,68,68,.14);color:#fecaca;border-color:rgba(239,68,68,.2)}html[data-theme='light'] .tag.failed{color:#b91c1c}.tag.slow{background:rgba(245,158,11,.12);color:#fde68a;border-color:rgba(245,158,11,.18)}html[data-theme='light'] .tag.slow{color:#92400e}.type-pill{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:999px;font-size:.74rem;font-weight:900;text-transform:uppercase;letter-spacing:.08em;border:1px solid transparent}.pill-request{background:rgba(56,189,248,.14);color:#93c5fd}.pill-request.method-get{background:rgba(34,197,94,.16);color:#bbf7d0}.pill-request.method-post{background:rgba(59,130,246,.16);color:#bfdbfe}.pill-request.method-other{background:rgba(245,158,11,.16);color:#fde68a}.pill-query{background:rgba(34,197,94,.12);color:#86efac}.pill-exception{background:rgba(239,68,68,.14);color:#fecaca}.pill-log{background:rgba(168,85,247,.14);color:#ddd6fe}.pill-job,.pill-batch{background:rgba(245,158,11,.14);color:#fde68a}.pill-cache{background:rgba(20,184,166,.12);color:#99f6e4}.pill-schedule,.pill-command{background:rgba(14,165,233,.14);color:#bae6fd}.pill-mail,.pill-notification{background:rgba(236,72,153,.14);color:#fbcfe8}.pill-auth{background:rgba(148,163,184,.16);color:#e2e8f0}.pill-event,.pill-model{background:rgba(74,222,128,.14);color:#bbf7d0}.pill-redis{background:rgba(239,68,68,.12);color:#fecaca}.pill-gate{background:rgba(99,102,241,.14);color:#c7d2fe}.pill-middleware{background:rgba(45,212,191,.12);color:#ccfbf1}.pill-dump,.pill-view{background:rgba(148,163,184,.14);color:#e2e8f0}.pill-client-request{background:rgba(59,130,246,.14);color:#bfdbfe}html[data-theme='light'] .pill-request{color:#1d4ed8}html[data-theme='light'] .pill-request.method-get{color:#166534}html[data-theme='light'] .pill-request.method-post{color:#1d4ed8}html[data-theme='light'] .pill-request.method-other{color:#92400e}html[data-theme='light'] .pill-query{color:#166534}html[data-theme='light'] .pill-exception{color:#b91c1c}html[data-theme='light'] .pill-log{color:#6d28d9}html[data-theme='light'] .pill-job,html[data-theme='light'] .pill-batch{color:#92400e}html[data-theme='light'] .pill-cache{color:#115e59}html[data-theme='light'] .pill-schedule,html[data-theme='light'] .pill-command{color:#0c4a6e}html[data-theme='light'] .pill-mail,html[data-theme='light'] .pill-notification{color:#9d174d}html[data-theme='light'] .pill-auth,html[data-theme='light'] .pill-dump,html[data-theme='light'] .pill-view{color:#334155}html[data-theme='light'] .pill-event,html[data-theme='light'] .pill-model{color:#166534}html[data-theme='light'] .pill-redis{color:#991b1b}html[data-theme='light'] .pill-gate{color:#3730a3}html[data-theme='light'] .pill-middleware{color:#155e75}html[data-theme='light'] .pill-client-request{color:#1d4ed8}
75
75
  .monitoring-wrap{padding:0 24px 24px}.tag-list{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:18px}.tag-item{display:inline-flex;align-items:center;gap:10px;padding:10px 14px;border-radius:999px;border:1px solid var(--line);background:var(--surface-strong)}.tag-remove{border:none;background:rgba(239,68,68,.14);color:var(--danger);border-radius:999px;width:24px;height:24px;cursor:pointer;font-size:1rem;line-height:1}.helper-text{color:var(--muted);line-height:1.6}
76
76
  .duration-chip{display:inline-flex;align-items:center;padding:5px 9px;border-radius:999px;border:1px solid transparent;font-size:.8rem;font-weight:700;color:var(--text);white-space:nowrap}.duration-chip.vfast{background:rgba(34,197,94,.14);border-color:rgba(34,197,94,.28);color:#bbf7d0}.duration-chip.fast{background:rgba(56,189,248,.12);border-color:rgba(56,189,248,.24);color:#bae6fd}.duration-chip.slow{background:rgba(245,158,11,.12);border-color:rgba(245,158,11,.22);color:#fde68a}.duration-chip.vslow{background:rgba(239,68,68,.14);border-color:rgba(239,68,68,.24);color:#fecaca}html[data-theme='light'] .duration-chip.vfast{color:#166534}html[data-theme='light'] .duration-chip.fast{color:#1d4ed8}html[data-theme='light'] .duration-chip.slow{color:#92400e}html[data-theme='light'] .duration-chip.vslow{color:#b91c1c}
77
- .code-card{border-radius:16px;border:1px solid var(--code-border);background:var(--surface-soft);overflow:hidden}.code-toolbar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:1px solid var(--line)}.code-label{font-size:.76rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:800}.copy-button{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:38px;height:38px;border-radius:12px;border:1px solid var(--line);background:var(--surface-strong);color:var(--text);cursor:pointer;transition:border-color .16s ease,color .16s ease}.copy-button:hover{border-color:rgba(56,189,248,.35);color:var(--accent)}.copy-button[data-copied='true']{color:var(--success);border-color:rgba(34,197,94,.28)}.copy-button svg{width:16px;height:16px;display:block}.code-block{margin:0;padding:18px 20px;background:var(--code-bg);color:#dbeafe;border:0;overflow:auto;white-space:pre;line-height:1.72;font-family:var(--mono);font-size:.92rem}.code-block code{font-family:inherit}.html-preview-wrap{padding:14px;background:var(--surface-strong);border-top:1px solid var(--line)}.html-preview{display:block;width:100%;min-height:320px;border:1px solid var(--line);border-radius:14px;background:#fff}.tok-key{color:#93c5fd}.tok-string{color:#86efac}.tok-number{color:#f9a8d4}.tok-boolean{color:#facc15}.tok-null{color:#fb7185}.tok-punctuation{color:#94a3b8}.tok-sql-keyword{color:#f472b6;font-weight:700}.tok-sql-identifier{color:#93c5fd}.tok-sql-string{color:#86efac}.tok-sql-number{color:#facc15}.tok-sql-comment{color:#64748b;font-style:italic}html[data-theme='light'] .code-block{color:#0f172a}html[data-theme='light'] .tok-key{color:#1d4ed8}html[data-theme='light'] .tok-string{color:#15803d}html[data-theme='light'] .tok-number{color:#c026d3}html[data-theme='light'] .tok-boolean{color:#b45309}html[data-theme='light'] .tok-null{color:#dc2626}html[data-theme='light'] .tok-punctuation{color:#64748b}html[data-theme='light'] .tok-sql-keyword{color:#db2777}html[data-theme='light'] .tok-sql-identifier{color:#2563eb}html[data-theme='light'] .tok-sql-string{color:#15803d}html[data-theme='light'] .tok-sql-number{color:#b45309}html[data-theme='light'] .tok-sql-comment{color:#6b7280}
77
+ .code-card{border-radius:16px;border:1px solid var(--code-border);background:var(--surface-soft);overflow:hidden}.code-toolbar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:1px solid var(--line)}.code-label{font-size:.76rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:800}.copy-button{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:38px;height:38px;border-radius:12px;border:1px solid var(--line);background:var(--surface-strong);color:var(--text);cursor:pointer;transition:border-color .16s ease,color .16s ease}.copy-button:hover{border-color:rgba(56,189,248,.35);color:var(--accent)}.copy-button[data-copied='true']{color:var(--success);border-color:rgba(34,197,94,.28)}.copy-button svg{width:16px;height:16px;display:block}.code-block{margin:0;padding:18px 20px;background:var(--code-bg);color:#dbeafe;border:0;overflow:auto;white-space:pre;line-height:1.72;font-family:var(--mono);font-size:.92rem}.code-block.wrap{white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word}.code-block code{font-family:inherit}.html-preview-wrap{padding:14px;background:var(--surface-strong);border-top:1px solid var(--line)}.html-preview{display:block;width:100%;min-height:320px;border:1px solid var(--line);border-radius:14px;background:#fff}.inline-collapse{margin:0;border-top:1px solid var(--line);background:var(--surface-strong)}.inline-collapse summary{cursor:pointer;list-style:none;padding:14px 16px;font-size:.82rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:800}.inline-collapse summary::-webkit-details-marker{display:none}.inline-collapse[open] summary{border-bottom:1px solid var(--line)}.inline-collapse .code-block{border-top:none}.tok-key{color:#93c5fd}.tok-string{color:#86efac}.tok-number{color:#f9a8d4}.tok-boolean{color:#facc15}.tok-null{color:#fb7185}.tok-punctuation{color:#94a3b8}.tok-sql-keyword{color:#f472b6;font-weight:700}.tok-sql-identifier{color:#93c5fd}.tok-sql-string{color:#86efac}.tok-sql-number{color:#facc15}.tok-sql-comment{color:#64748b;font-style:italic}html[data-theme='light'] .code-block{color:#0f172a}html[data-theme='light'] .tok-key{color:#1d4ed8}html[data-theme='light'] .tok-string{color:#15803d}html[data-theme='light'] .tok-number{color:#c026d3}html[data-theme='light'] .tok-boolean{color:#b45309}html[data-theme='light'] .tok-null{color:#dc2626}html[data-theme='light'] .tok-punctuation{color:#64748b}html[data-theme='light'] .tok-sql-keyword{color:#db2777}html[data-theme='light'] .tok-sql-identifier{color:#2563eb}html[data-theme='light'] .tok-sql-string{color:#15803d}html[data-theme='light'] .tok-sql-number{color:#b45309}html[data-theme='light'] .tok-sql-comment{color:#6b7280}
78
78
  @media (max-width:1120px){.content-grid{grid-template-columns:1fr}}@media (max-width:920px){.layout{grid-template-columns:1fr}.sidebar{position:static;height:auto;border-right:none;border-bottom:1px solid var(--line);padding:20px 16px 18px}.brand-row{padding:0 0 16px}.sidebar-status{margin:0 0 16px}.sidebar-group{padding:0}.main{padding:20px}}@media (max-width:640px){.stats-grid{grid-template-columns:1fr}.detail-card{padding:18px}.toolbar,.section-head,.pagination,.activity-list,.monitoring-wrap{padding-left:18px;padding-right:18px}.table-wrap{padding:0 8px 10px}.brand-row{align-items:stretch;gap:14px;padding:0 0 14px}.brand{width:100%;align-items:flex-start}.brand-copy{min-width:0}.brand-copy h1{font-size:1.18rem;line-height:1.12}.brand-copy p{font-size:.82rem;overflow-wrap:anywhere}.icon-button{align-self:flex-end}.sidebar-status{padding:12px}.nav-button{padding:11px 12px}.nav-title{font-size:.95rem}.nav-meta{font-size:.72rem}}@media (max-width:480px){.brand-row{flex-direction:column}.icon-button{align-self:flex-start}.nav-button{align-items:flex-start;flex-direction:column}.nav-meta{font-size:.7rem}}
79
79
  </style>
80
80
  </head>
@@ -322,8 +322,9 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
322
322
  return id;
323
323
  };
324
324
 
325
- const renderCodeCard = (label, rawText, highlightedHtml, languageClass) => {
325
+ const renderCodeCard = (label, rawText, highlightedHtml, languageClass, options = {}) => {
326
326
  const copyId = registerCopyPayload(rawText);
327
+ const wrapClass = options.wrap === true ? ' wrap' : '';
327
328
  return [
328
329
  '<section class="code-card">',
329
330
  '<div class="code-toolbar">',
@@ -332,19 +333,23 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
332
333
  COPY_ICON,
333
334
  '</button>',
334
335
  '</div>',
335
- '<pre class="code-block ' + escapeHtml(languageClass) + '"><code>' + highlightedHtml + '</code></pre>',
336
+ '<pre class="code-block ' + escapeHtml(languageClass) + wrapClass + '"><code>' + highlightedHtml + '</code></pre>',
336
337
  '</section>'
337
338
  ].join('');
338
339
  };
339
340
 
340
341
  const renderTextCard = (label, value) => {
341
342
  const source = String(value ?? '');
342
- return renderCodeCard(label, source, escapeHtml(source), 'language-text');
343
+ return renderCodeCard(label, source, escapeHtml(source), 'language-text', { wrap: true });
343
344
  };
344
345
 
345
- const renderHtmlPreview = (label, html) => {
346
+ const renderHtmlPreview = (label, html, options = {}) => {
346
347
  const source = String(html ?? '');
347
348
  const copyId = registerCopyPayload(source);
349
+ const rawHtmlBlock = '<pre class="code-block language-html wrap"><code>' + escapeHtml(source) + '</code></pre>';
350
+ const rawHtmlSection = options.collapseSource === true
351
+ ? '<details class="inline-collapse"><summary>View raw HTML source</summary>' + rawHtmlBlock + '</details>'
352
+ : rawHtmlBlock;
348
353
  return [
349
354
  '<section class="code-card">',
350
355
  '<div class="code-toolbar">',
@@ -353,8 +358,8 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
353
358
  COPY_ICON,
354
359
  '</button>',
355
360
  '</div>',
356
- '<pre class="code-block language-html"><code>' + escapeHtml(source) + '</code></pre>',
357
361
  '<div class="html-preview-wrap"><iframe class="html-preview" sandbox="allow-same-origin" srcdoc="' + escapeHtml(source) + '"></iframe></div>',
362
+ rawHtmlSection,
358
363
  '</section>'
359
364
  ].join('');
360
365
  };
@@ -378,7 +383,7 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
378
383
  }
379
384
 
380
385
  output += escapeHtml(source.slice(lastIndex));
381
- return renderCodeCard(label, source, output, 'language-json');
386
+ return renderCodeCard(label, source, output, 'language-json', { wrap: true });
382
387
  };
383
388
 
384
389
  const highlightSql = (sql) => {
@@ -413,7 +418,9 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
413
418
  const renderPayload = (label, value) => {
414
419
  if (value === undefined) return '<p class="trace-note">No ' + escapeHtml(label.toLowerCase()) + ' was captured.</p>';
415
420
  if (typeof value === 'string') {
416
- return looksLikeHtml(value) ? renderHtmlPreview(label, value) : renderTextCard(label, value);
421
+ return looksLikeHtml(value)
422
+ ? renderHtmlPreview(label, value, { collapseSource: true })
423
+ : renderTextCard(label, value);
417
424
  }
418
425
  return detailJson(value, label);
419
426
  };
@@ -453,6 +460,17 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
453
460
  return '<div class="summary">' + summary + '</div><div class="summary-sub">' + escapeHtml(secondary) + '</div>';
454
461
  };
455
462
 
463
+ const entrySummaryInlineHtml = (entry) => {
464
+ const summary = escapeHtml(entrySummaryText(entry) || 'No summary available');
465
+ const secondary = [
466
+ entry.type === 'request' ? 'Incoming request' : '',
467
+ entry.type === 'query' ? 'Database query' : '',
468
+ entry.type === 'exception' ? 'Unhandled error' : '',
469
+ entry.type === 'client_request' ? 'Outbound HTTP call' : ''
470
+ ].find(Boolean) || 'Trace record';
471
+ return '<span class="summary">' + summary + '</span><span class="summary-sub">' + escapeHtml(secondary) + '</span>';
472
+ };
473
+
456
474
  const renderMetricBox = (title, items) => {
457
475
  return [
458
476
  '<section class="detail-box">',
@@ -577,8 +595,8 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
577
595
  ]),
578
596
  '</div>',
579
597
  '<div class="detail-stack">',
580
- renderPayload('Mail Text', content.text),
581
598
  renderPayload('Mail Html', content.html),
599
+ renderPayload('Mail Text', content.text),
582
600
  '</div>'
583
601
  ].join('');
584
602
  }
@@ -603,10 +621,31 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
603
621
  return detailJson(content);
604
622
  };
605
623
 
606
- const renderTraceItems = (entries) => {
624
+ const renderTraceItems = (entries, options = {}) => {
607
625
  if (entries.length === 0) return '<p class="trace-note">No related entries captured.</p>';
608
626
 
627
+ const collapsible = options.collapsible === true;
628
+ const isInitiallyOpen = options.collapsed !== true;
629
+
609
630
  return '<div class="trace-panel">' + entries.map((entry) => {
631
+ if (collapsible) {
632
+ return [
633
+ '<details class="trace-item trace-disclosure"' + (isInitiallyOpen ? ' open' : '') + '>',
634
+ '<summary class="trace-item-head trace-summary">',
635
+ '<span class="trace-summary-main">',
636
+ '<span><span class="' + typeClass(entry) + '">' + escapeHtml(entry.type) + '</span></span>',
637
+ '<span class="trace-summary-copy">' + entrySummaryInlineHtml(entry) + '</span>',
638
+ '</span>',
639
+ '<span class="activity-head">' + durationHtml(entry) + '<span class="activity-time">' + escapeHtml(timeSince(entry.createdAt)) + '</span></span>',
640
+ '</summary>',
641
+ '<div class="trace-disclosure-body">',
642
+ '<div>' + tagsHtml(entry.tags) + '</div>',
643
+ renderEntryBody(entry),
644
+ '</div>',
645
+ '</details>'
646
+ ].join('');
647
+ }
648
+
610
649
  return [
611
650
  '<section class="trace-item">',
612
651
  '<div class="trace-item-head">',
@@ -665,7 +704,7 @@ const DASHBOARD_DOCUMENT = String.raw `<!DOCTYPE html>
665
704
  payload: detailJson(content.payload || {}, 'Payload Json'),
666
705
  headers: '<div class="detail-stack">' + detailJson(content.headers || {}, 'Request Header Json') + detailJson(content.responseHeaders || {}, 'Response Header Json') + '</div>',
667
706
  response: '<div class="detail-stack"><div class="detail-grid">' + renderMetricBox('Status', [{ label: 'Response status', value: escapeHtml(content.responseStatus || '') }, { label: 'Duration', value: escapeHtml(formatDuration(getEntryDuration(entry))) }]) + '</div>' + (content.responseBody === undefined ? '<p class="trace-note">No response body was captured for this request.</p>' : detailJson(content.responseBody, 'Response Body Json')) + detailJson(content.responseHeaders || {}, 'Response Header Json') + '</div>',
668
- queries: renderTraceItems(batchEntriesByType('query')),
707
+ queries: renderTraceItems(batchEntriesByType('query'), { collapsible: true, collapsed: true }),
669
708
  logs: renderTraceItems(batchEntriesByType('log')),
670
709
  exceptions: renderTraceItems(batchEntriesByType('exception')),
671
710
  http: renderTraceItems(batchEntriesByType('client_request')),
package/dist/register.js CHANGED
@@ -39,6 +39,11 @@ const importCore = async () => {
39
39
  return {};
40
40
  }
41
41
  };
42
+ const TRACE_REQUIRED_TABLES = [
43
+ 'zin_trace_entries',
44
+ 'zin_trace_entries_tags',
45
+ 'zin_trace_monitoring',
46
+ ];
42
47
  const resolveRegisterMiddleware = () => {
43
48
  const globalMiddlewareRegistrarState = globalThis;
44
49
  return (middleware) => {
@@ -69,7 +74,7 @@ const resolveObservedConnectionName = (env, configuredObservedConnection, storag
69
74
  configuredObservedConnection.trim() !== '') {
70
75
  return resolveTraceConnectionName(env, configuredObservedConnection);
71
76
  }
72
- const defaultConnectionName = resolveTraceConnectionName(env, undefined);
77
+ const defaultConnectionName = resolveTraceConnectionName(env);
73
78
  if (storageConnectionName !== defaultConnectionName) {
74
79
  return defaultConnectionName;
75
80
  }
@@ -150,6 +155,43 @@ const buildTraceRedactionOverrides = (input) => {
150
155
  ? redaction
151
156
  : undefined;
152
157
  };
158
+ const createTraceConfigError = (coreApi, message, details) => {
159
+ if (coreApi.ErrorFactory?.createConfigError !== undefined) {
160
+ return coreApi.ErrorFactory.createConfigError(message, details);
161
+ }
162
+ const error = new globalThis.Error(message);
163
+ error.name = 'ConfigError';
164
+ error.code = 'CONFIG_ERROR';
165
+ error.statusCode = 500;
166
+ error.details = details;
167
+ return error;
168
+ };
169
+ function assertTraceConnectionResolved(coreApi, db, params) {
170
+ if (db !== undefined) {
171
+ return;
172
+ }
173
+ throw createTraceConfigError(coreApi, `Trace connection "${params.connectionName}" could not be resolved.`, {
174
+ connectionName: params.connectionName,
175
+ envKey: params.envKey,
176
+ hint: params.envKey === 'TRACE_DB_CONNECTION'
177
+ ? 'Configure TRACE_DB_CONNECTION to an existing database connection before enabling TRACE_ENABLED.'
178
+ : 'Configure TRACE_QUERY_CONNECTION, or ensure DB_CONNECTION resolves to an existing database connection.',
179
+ });
180
+ }
181
+ const assertTraceStorageReady = async (coreApi, db, connectionName) => {
182
+ try {
183
+ await Promise.all(TRACE_REQUIRED_TABLES.map(async (table) => {
184
+ await db.queryOne(`SELECT 1 AS ok FROM ${table} LIMIT 1`, []);
185
+ }));
186
+ }
187
+ catch (error) {
188
+ throw createTraceConfigError(coreApi, `Trace storage connection "${connectionName}" is not ready. Create the database if needed and run \`zin migrate:trace\` before enabling TRACE_ENABLED.`, {
189
+ connectionName,
190
+ error,
191
+ requiredTables: [...TRACE_REQUIRED_TABLES],
192
+ });
193
+ }
194
+ };
153
195
  const core = (await importCore());
154
196
  const Env = core.Env;
155
197
  const startupOverrides = resolveTraceStartupOverrides(core);
@@ -205,62 +247,65 @@ if (!traceAlreadyInitialized && Env) {
205
247
  const resolvedObservedConnectionName = resolveObservedConnectionName(Env, config.observeConnection, resolvedConnectionName);
206
248
  const storageDb = core.useDatabase?.(undefined, resolvedConnectionName);
207
249
  const observedDb = core.useDatabase?.(undefined, resolvedObservedConnectionName);
208
- if (storageDb && observedDb) {
209
- const storage = TraceWriteDiagnostics.wrapStorage(TraceContentRedaction.wrapStorage(TraceEntryFiltering.wrapStorage(TraceStorage.resolveStorage(storageDb), config), config.redaction), {
210
- connectionName: resolvedConnectionName,
211
- logger: core.Logger,
212
- });
213
- if (core.RequestContext) {
214
- TraceContext.setRequestContextImpl(core.RequestContext);
215
- }
216
- const [{ HttpWatcher }, { QueryWatcher }, { LogWatcher }, { ExceptionWatcher }, { JobWatcher }, { CacheWatcher }, { ScheduleWatcher }, { MailWatcher }, { AuthWatcher }, { EventWatcher }, { ModelWatcher }, { NotificationWatcher }, { RedisWatcher }, { GateWatcher }, { MiddlewareWatcher }, { CommandWatcher }, { BatchWatcher }, { DumpWatcher }, { ViewWatcher }, { HttpClientWatcher },] = await Promise.all([
217
- import('./watchers/HttpWatcher.js'),
218
- import('./watchers/QueryWatcher.js'),
219
- import('./watchers/LogWatcher.js'),
220
- import('./watchers/ExceptionWatcher.js'),
221
- import('./watchers/JobWatcher.js'),
222
- import('./watchers/CacheWatcher.js'),
223
- import('./watchers/ScheduleWatcher.js'),
224
- import('./watchers/MailWatcher.js'),
225
- import('./watchers/AuthWatcher.js'),
226
- import('./watchers/EventWatcher.js'),
227
- import('./watchers/ModelWatcher.js'),
228
- import('./watchers/NotificationWatcher.js'),
229
- import('./watchers/RedisWatcher.js'),
230
- import('./watchers/GateWatcher.js'),
231
- import('./watchers/MiddlewareWatcher.js'),
232
- import('./watchers/CommandWatcher.js'),
233
- import('./watchers/BatchWatcher.js'),
234
- import('./watchers/DumpWatcher.js'),
235
- import('./watchers/ViewWatcher.js'),
236
- import('./watchers/HttpClientWatcher.js'),
237
- ]);
238
- const watcherArgs = { storage, config, db: observedDb };
239
- HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
240
- QueryWatcher.register(watcherArgs);
241
- LogWatcher.register(watcherArgs);
242
- ExceptionWatcher.register(watcherArgs);
243
- JobWatcher.register(watcherArgs);
244
- CacheWatcher.register(watcherArgs);
245
- ScheduleWatcher.register(watcherArgs);
246
- MailWatcher.register(watcherArgs);
247
- AuthWatcher.register(watcherArgs);
248
- EventWatcher.register(watcherArgs);
249
- ModelWatcher.register(watcherArgs);
250
- NotificationWatcher.register(watcherArgs);
251
- RedisWatcher.register(watcherArgs);
252
- GateWatcher.register(watcherArgs);
253
- MiddlewareWatcher.register(watcherArgs);
254
- CommandWatcher.register(watcherArgs);
255
- BatchWatcher.register(watcherArgs);
256
- DumpWatcher.register(watcherArgs);
257
- ViewWatcher.register(watcherArgs);
258
- HttpClientWatcher.register(watcherArgs);
259
- }
260
- else {
261
- // eslint-disable-next-line no-console
262
- console.warn('[trace] Could not resolve database connection - skipping init.');
250
+ assertTraceConnectionResolved(core, storageDb, {
251
+ connectionName: resolvedConnectionName,
252
+ envKey: 'TRACE_DB_CONNECTION',
253
+ });
254
+ assertTraceConnectionResolved(core, observedDb, {
255
+ connectionName: resolvedObservedConnectionName,
256
+ envKey: 'TRACE_QUERY_CONNECTION',
257
+ });
258
+ await assertTraceStorageReady(core, storageDb, resolvedConnectionName);
259
+ const storage = TraceWriteDiagnostics.wrapStorage(TraceContentRedaction.wrapStorage(TraceEntryFiltering.wrapStorage(TraceStorage.resolveStorage(storageDb), config), config.redaction), {
260
+ connectionName: resolvedConnectionName,
261
+ logger: core.Logger,
262
+ });
263
+ if (core.RequestContext) {
264
+ TraceContext.setRequestContextImpl(core.RequestContext);
263
265
  }
266
+ const [{ HttpWatcher }, { QueryWatcher }, { LogWatcher }, { ExceptionWatcher }, { JobWatcher }, { CacheWatcher }, { ScheduleWatcher }, { MailWatcher }, { AuthWatcher }, { EventWatcher }, { ModelWatcher }, { NotificationWatcher }, { RedisWatcher }, { GateWatcher }, { MiddlewareWatcher }, { CommandWatcher }, { BatchWatcher }, { DumpWatcher }, { ViewWatcher }, { HttpClientWatcher },] = await Promise.all([
267
+ import('./watchers/HttpWatcher.js'),
268
+ import('./watchers/QueryWatcher.js'),
269
+ import('./watchers/LogWatcher.js'),
270
+ import('./watchers/ExceptionWatcher.js'),
271
+ import('./watchers/JobWatcher.js'),
272
+ import('./watchers/CacheWatcher.js'),
273
+ import('./watchers/ScheduleWatcher.js'),
274
+ import('./watchers/MailWatcher.js'),
275
+ import('./watchers/AuthWatcher.js'),
276
+ import('./watchers/EventWatcher.js'),
277
+ import('./watchers/ModelWatcher.js'),
278
+ import('./watchers/NotificationWatcher.js'),
279
+ import('./watchers/RedisWatcher.js'),
280
+ import('./watchers/GateWatcher.js'),
281
+ import('./watchers/MiddlewareWatcher.js'),
282
+ import('./watchers/CommandWatcher.js'),
283
+ import('./watchers/BatchWatcher.js'),
284
+ import('./watchers/DumpWatcher.js'),
285
+ import('./watchers/ViewWatcher.js'),
286
+ import('./watchers/HttpClientWatcher.js'),
287
+ ]);
288
+ const watcherArgs = { storage, config, db: observedDb };
289
+ HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
290
+ QueryWatcher.register(watcherArgs);
291
+ LogWatcher.register(watcherArgs);
292
+ ExceptionWatcher.register(watcherArgs);
293
+ JobWatcher.register(watcherArgs);
294
+ CacheWatcher.register(watcherArgs);
295
+ ScheduleWatcher.register(watcherArgs);
296
+ MailWatcher.register(watcherArgs);
297
+ AuthWatcher.register(watcherArgs);
298
+ EventWatcher.register(watcherArgs);
299
+ ModelWatcher.register(watcherArgs);
300
+ NotificationWatcher.register(watcherArgs);
301
+ RedisWatcher.register(watcherArgs);
302
+ GateWatcher.register(watcherArgs);
303
+ MiddlewareWatcher.register(watcherArgs);
304
+ CommandWatcher.register(watcherArgs);
305
+ BatchWatcher.register(watcherArgs);
306
+ DumpWatcher.register(watcherArgs);
307
+ ViewWatcher.register(watcherArgs);
308
+ HttpClientWatcher.register(watcherArgs);
264
309
  }
265
310
  }
266
311
  else if (!traceAlreadyInitialized) {
@@ -17,8 +17,37 @@ const TRACE_INFRASTRUCTURE_LOG_MESSAGES = new Set([
17
17
  '[MySQLProxyAdapter] Proxy request failed',
18
18
  '[trace] Trace storage write degraded',
19
19
  ]);
20
- const shouldSkipTraceInfrastructureLog = (message) => {
21
- return TRACE_INFRASTRUCTURE_LOG_MESSAGES.has(message.trim());
20
+ const TRACE_STORAGE_TABLE_NAMES = [
21
+ 'zin_trace_entries',
22
+ 'zin_trace_entries_tags',
23
+ 'zin_trace_monitoring',
24
+ ];
25
+ const isTraceStorageQuery = (sql) => {
26
+ const normalized = sql.toLowerCase();
27
+ return TRACE_STORAGE_TABLE_NAMES.some((tableName) => normalized.includes(tableName));
28
+ };
29
+ const extractSqlFromLog = (message, context) => {
30
+ const contextSql = context?.['sql'];
31
+ if (typeof contextSql === 'string')
32
+ return contextSql;
33
+ const trimmed = message.trim();
34
+ const rawPrefix = 'Raw SQL Query executed:';
35
+ if (trimmed.startsWith(rawPrefix)) {
36
+ const sql = trimmed.slice(rawPrefix.length).trim();
37
+ return sql === '' ? undefined : sql;
38
+ }
39
+ return undefined;
40
+ };
41
+ const isTraceStorageQueryLog = (message, context) => {
42
+ const normalizedMessage = message.trim().toLowerCase();
43
+ if (!normalizedMessage.includes('query executed'))
44
+ return false;
45
+ const sql = extractSqlFromLog(message, context);
46
+ return typeof sql === 'string' && isTraceStorageQuery(sql);
47
+ };
48
+ const shouldSkipTraceInfrastructureLog = (message, context) => {
49
+ return (TRACE_INFRASTRUCTURE_LOG_MESSAGES.has(message.trim()) ||
50
+ isTraceStorageQueryLog(message, context));
22
51
  };
23
52
  export const LogWatcher = Object.freeze({
24
53
  register({ storage, config }) {
@@ -34,7 +63,7 @@ export const LogWatcher = Object.freeze({
34
63
  return;
35
64
  if (RequestFilter.shouldIgnoreCurrentRequest(config.ignoreRoutes))
36
65
  return;
37
- if (shouldSkipTraceInfrastructureLog(message))
66
+ if (shouldSkipTraceInfrastructureLog(message, context))
38
67
  return;
39
68
  const content = {
40
69
  level,
@@ -22,7 +22,9 @@ const bindingsInterpolated = (sql, params) => {
22
22
  };
23
23
  const isTraceStorageQuery = (sql) => {
24
24
  const normalized = sql.toLowerCase();
25
- return normalized.includes('zin_trace_entries') || normalized.includes('zin_trace_monitoring');
25
+ return (normalized.includes('zin_trace_entries') ||
26
+ normalized.includes('zin_trace_entries_tags') ||
27
+ normalized.includes('zin_trace_monitoring'));
26
28
  };
27
29
  const emit = (query, params, duration, connection = 'default') => {
28
30
  if (_storage === null || _config === null)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/trace",
3
- "version": "0.4.84",
3
+ "version": "0.4.92",
4
4
  "description": "Trace assistant for ZinTrust: logs requests, queries, exceptions, jobs, and more.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -40,7 +40,7 @@
40
40
  "node": ">=20.0.0"
41
41
  },
42
42
  "peerDependencies": {
43
- "@zintrust/core": "^0.4.83"
43
+ "@zintrust/core": "^0.4.91"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"