@tezx/devtools 1.0.4 โ 1.0.5
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/cjs/devtools/dumpRoutes.js +3 -4
- package/cjs/devtools/index.js +4 -8
- package/cjs/devtools/middlewares.js +29 -19
- package/cjs/html/cookies.js +146 -127
- package/cjs/html/env.js +145 -0
- package/cjs/html/index.js +22 -8
- package/cjs/html/middlewares.js +184 -0
- package/cjs/html/routes.js +112 -83
- package/cjs/index.js +27 -10
- package/devtools/dumpRoutes.d.ts +2 -3
- package/devtools/dumpRoutes.js +3 -4
- package/devtools/index.d.ts +1 -5
- package/devtools/index.js +2 -7
- package/devtools/middlewares.d.ts +6 -6
- package/devtools/middlewares.js +28 -18
- package/html/cookies.js +146 -127
- package/html/env.d.ts +2 -0
- package/html/env.js +142 -0
- package/html/index.d.ts +2 -2
- package/html/index.js +22 -8
- package/html/middlewares.d.ts +7 -0
- package/html/middlewares.js +181 -0
- package/html/routes.js +112 -83
- package/index.d.ts +2 -2
- package/index.js +27 -10
- package/package.json +1 -1
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Middlewares = Middlewares;
|
|
4
|
+
const devtools_1 = require("../devtools");
|
|
5
|
+
function Middlewares(ctx, app) {
|
|
6
|
+
const allRoutes = (0, devtools_1.dumpMiddlewares)(app);
|
|
7
|
+
const totalRoutes = allRoutes.length;
|
|
8
|
+
const middlewareRoutes = {};
|
|
9
|
+
for (const route of allRoutes) {
|
|
10
|
+
for (const mw of route.appliedMiddlewares || []) {
|
|
11
|
+
(middlewareRoutes[mw] ||= []).push(route);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const rawJSON = JSON.stringify(allRoutes, null, 2);
|
|
15
|
+
const toCSV = (data) => {
|
|
16
|
+
const headers = ["pattern", "type", "appliedMiddlewares"];
|
|
17
|
+
const csvRows = [
|
|
18
|
+
headers.join(","),
|
|
19
|
+
...data.map((r) => headers.map((h) => JSON.stringify(r[h] ?? "")).join(",")),
|
|
20
|
+
];
|
|
21
|
+
return csvRows.join("\n");
|
|
22
|
+
};
|
|
23
|
+
const csvString = toCSV(allRoutes).replace(/"/g, """);
|
|
24
|
+
return `
|
|
25
|
+
<style>
|
|
26
|
+
.download {
|
|
27
|
+
margin-top: 1rem;
|
|
28
|
+
display: flex;
|
|
29
|
+
gap: 1rem;
|
|
30
|
+
}
|
|
31
|
+
.download a {
|
|
32
|
+
padding: 0.5rem 1rem;
|
|
33
|
+
border: 1px solid var(--accent);
|
|
34
|
+
color: var(--accent);
|
|
35
|
+
text-decoration: none;
|
|
36
|
+
border-radius: 6px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.download a:hover {
|
|
40
|
+
background: var(--accent);
|
|
41
|
+
color: white;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#searchBar {
|
|
45
|
+
margin: 1rem 0;
|
|
46
|
+
display: flex;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#searchBar input {
|
|
50
|
+
flex: 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
table td button {
|
|
54
|
+
background: #e2e8f0;
|
|
55
|
+
border: none;
|
|
56
|
+
padding: 0.2rem 0.5rem;
|
|
57
|
+
border-radius: 0.375rem;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
margin-left: 0.5rem;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
table td button:hover {
|
|
63
|
+
background: #cbd5e1;
|
|
64
|
+
}
|
|
65
|
+
</style>
|
|
66
|
+
|
|
67
|
+
<div class="tabs toolbar">
|
|
68
|
+
<a class="tab-btn active counting" data-count="${totalRoutes}" onclick="showTab('routes')">๐ Routes</a>
|
|
69
|
+
<a class="tab-btn counting" data-count="${Object.keys(middlewareRoutes).length}" onclick="showTab('middlewares')">๐งฉ Middlewares</a>
|
|
70
|
+
<a class="tab-btn" onclick="showTab('json')">๐งพ Raw JSON</a>
|
|
71
|
+
<a class="tab-btn" onclick="showTab('export')">๐ค Export</a>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div id="searchBar">
|
|
75
|
+
<input type="text" id="search" placeholder="Filter by pattern/type/middleware..." />
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<!-- ROUTES -->
|
|
79
|
+
<div id="routesTab" class="table-container">
|
|
80
|
+
<table id="routesTable">
|
|
81
|
+
<thead>
|
|
82
|
+
<tr>
|
|
83
|
+
<th>#</th>
|
|
84
|
+
<th>Pattern</th>
|
|
85
|
+
<th>Type</th>
|
|
86
|
+
<th>Middlewares</th>
|
|
87
|
+
</tr>
|
|
88
|
+
</thead>
|
|
89
|
+
<tbody>
|
|
90
|
+
${allRoutes
|
|
91
|
+
.map((r, i) => `
|
|
92
|
+
<tr>
|
|
93
|
+
<td>${i + 1}</td>
|
|
94
|
+
<td>
|
|
95
|
+
${r.pattern}
|
|
96
|
+
<button onclick="copyText(\`${r.pattern}\`)">๐</button>
|
|
97
|
+
</td>
|
|
98
|
+
<td>
|
|
99
|
+
<span style="
|
|
100
|
+
display: inline-block;
|
|
101
|
+
padding: 0.2rem 0.5rem;
|
|
102
|
+
border-radius: 0.375rem;
|
|
103
|
+
color: white;
|
|
104
|
+
font-size: 0.75rem;
|
|
105
|
+
background-color: ${r.type === "static"
|
|
106
|
+
? "#16a34a"
|
|
107
|
+
: r.type === "wildcard"
|
|
108
|
+
? "#f97316"
|
|
109
|
+
: r.type === "optional params"
|
|
110
|
+
? "#3b82f6"
|
|
111
|
+
: r.type === "dynamic params"
|
|
112
|
+
? "#9333ea"
|
|
113
|
+
: "#6b7280"};
|
|
114
|
+
">
|
|
115
|
+
${r.type}
|
|
116
|
+
</span>
|
|
117
|
+
</td>
|
|
118
|
+
<td>${(r.appliedMiddlewares || []).join(", ")}</td>
|
|
119
|
+
</tr>
|
|
120
|
+
`)
|
|
121
|
+
.join("")}
|
|
122
|
+
</tbody>
|
|
123
|
+
</table>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<!-- MIDDLEWARES -->
|
|
127
|
+
<div id="middlewaresTab" style="display:none">
|
|
128
|
+
${Object.entries(middlewareRoutes)
|
|
129
|
+
.map(([mw, routes]) => `
|
|
130
|
+
<h3>๐น ${mw} (${routes.length})</h3>
|
|
131
|
+
<ul>
|
|
132
|
+
${routes.map((r) => `<li><code>${r.pattern}</code> <span>(${r.type})</span></li>`).join("")}
|
|
133
|
+
</ul>
|
|
134
|
+
`)
|
|
135
|
+
.join("")}
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<!-- RAW JSON -->
|
|
139
|
+
<div id="jsonTab" style="display:none">
|
|
140
|
+
<div class="json-view"><pre>${rawJSON}</pre></div>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<!-- EXPORT -->
|
|
144
|
+
<div id="exportTab" style="display:none">
|
|
145
|
+
<div class="download">
|
|
146
|
+
<a href="data:text/json;charset=utf-8,${encodeURIComponent(rawJSON)}" download="middlewares.json">๐ฅ JSON</a>
|
|
147
|
+
<a href="data:text/csv;charset=utf-8,${csvString}" download="middlewares.csv">๐ฅ CSV</a>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<script>
|
|
152
|
+
const tabs = ['routes', 'middlewares', 'json', 'export'];
|
|
153
|
+
const tabBtns = document.querySelectorAll('.tab-btn');
|
|
154
|
+
|
|
155
|
+
function showTab(tab) {
|
|
156
|
+
tabs.forEach(t => {
|
|
157
|
+
document.getElementById(t + 'Tab').style.display = t === tab ? 'block' : 'none';
|
|
158
|
+
document.getElementById(t + 'Tab').classList.toggle('active', t === tab);
|
|
159
|
+
});
|
|
160
|
+
tabBtns.forEach(btn => {
|
|
161
|
+
const active = btn.textContent.toLowerCase().includes(tab);
|
|
162
|
+
btn.classList.toggle('active', active);
|
|
163
|
+
});
|
|
164
|
+
document.getElementById('searchBar').style.display = (tab === 'routes') ? 'flex' : 'none';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
document.getElementById('search').addEventListener('input', (e) => {
|
|
168
|
+
const keyword = e.target.value.toLowerCase();
|
|
169
|
+
const rows = document.querySelectorAll('#routesTable tbody tr');
|
|
170
|
+
rows.forEach(row => {
|
|
171
|
+
row.style.display = row.textContent.toLowerCase().includes(keyword) ? '' : 'none';
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
function copyText(text) {
|
|
176
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
177
|
+
alert('โ
Copied: ' + text);
|
|
178
|
+
}).catch(err => {
|
|
179
|
+
alert('โ Failed to copy: ' + err);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
</script>
|
|
183
|
+
`;
|
|
184
|
+
}
|
package/cjs/html/routes.js
CHANGED
|
@@ -15,14 +15,14 @@ function Routes(ctx, app) {
|
|
|
15
15
|
}
|
|
16
16
|
const rawJSON = JSON.stringify(allRoutes, null, 2);
|
|
17
17
|
const toCSV = (data) => {
|
|
18
|
-
const headers = [
|
|
18
|
+
const headers = ["method", "endpoint", "pattern", "appliedMiddlewares"];
|
|
19
19
|
const csvRows = [
|
|
20
|
-
headers.join(
|
|
21
|
-
...data.map(r => headers.map(h => JSON.stringify(r[h] ??
|
|
20
|
+
headers.join(","),
|
|
21
|
+
...data.map((r) => headers.map((h) => JSON.stringify(r[h] ?? "")).join(",")),
|
|
22
22
|
];
|
|
23
|
-
return csvRows.join(
|
|
23
|
+
return csvRows.join("\n");
|
|
24
24
|
};
|
|
25
|
-
const csvString = toCSV(allRoutes).replace(/"/g,
|
|
25
|
+
const csvString = toCSV(allRoutes).replace(/"/g, """);
|
|
26
26
|
return `
|
|
27
27
|
<style>
|
|
28
28
|
.download {
|
|
@@ -52,107 +52,136 @@ function Routes(ctx, app) {
|
|
|
52
52
|
#searchBar input {
|
|
53
53
|
flex: 1;
|
|
54
54
|
}
|
|
55
|
-
</style>
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
table td button {
|
|
57
|
+
background: #e2e8f0;
|
|
58
|
+
border: none;
|
|
59
|
+
padding: 0.2rem 0.5rem;
|
|
60
|
+
border-radius: 0.375rem;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
margin-left: 0.5rem;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
table td button:hover {
|
|
66
|
+
background: #cbd5e1;
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
69
|
+
|
|
70
|
+
<div class="tabs toolbar">
|
|
58
71
|
<a class="tab-btn active counting" data-count="${totalRoutes}" onclick="showTab('routes')">๐ Routes</a>
|
|
59
|
-
<a class="tab-btn counting" data-count="${Object.keys(middlewareStats).length}" onclick="showTab('stats')">๐
|
|
60
|
-
Stats</a>
|
|
72
|
+
<a class="tab-btn counting" data-count="${Object.keys(middlewareStats).length}" onclick="showTab('stats')">๐ Stats</a>
|
|
61
73
|
<a class="tab-btn" onclick="showTab('middlewares')">๐งฉ Middlewares</a>
|
|
62
74
|
<a class="tab-btn" onclick="showTab('json')">๐งพ Raw JSON</a>
|
|
63
75
|
<a class="tab-btn" onclick="showTab('export')">๐ค Export</a>
|
|
64
|
-
</div>
|
|
76
|
+
</div>
|
|
65
77
|
|
|
66
|
-
<div id="searchBar"
|
|
78
|
+
<div id="searchBar">
|
|
67
79
|
<input type="text" id="search" placeholder="Filter by method/path/middleware..." />
|
|
68
|
-
</div>
|
|
80
|
+
</div>
|
|
69
81
|
|
|
70
|
-
<!-- ROUTES -->
|
|
71
|
-
<div id="routesTab">
|
|
82
|
+
<!-- ROUTES -->
|
|
83
|
+
<div id="routesTab" class="table-container">
|
|
72
84
|
<table id="routesTable">
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
<thead>
|
|
86
|
+
<tr>
|
|
87
|
+
<th>#</th>
|
|
88
|
+
<th>Method</th>
|
|
89
|
+
<th>Endpoint</th>
|
|
90
|
+
<th>Pattern</th>
|
|
91
|
+
<th>Middlewares</th>
|
|
92
|
+
</tr>
|
|
93
|
+
</thead>
|
|
94
|
+
<tbody>
|
|
95
|
+
${allRoutes
|
|
96
|
+
.map((r, i) => `
|
|
97
|
+
<tr>
|
|
98
|
+
<td>${i + 1}</td>
|
|
99
|
+
<td>${r.method}</td>
|
|
100
|
+
<td>
|
|
101
|
+
${r.endpoint}
|
|
102
|
+
<button onclick="copyText(\`${r.endpoint}\`)">๐</button>
|
|
103
|
+
</td>
|
|
104
|
+
<td>
|
|
105
|
+
${r.pattern}
|
|
106
|
+
<button onclick="copyText(\`${r.pattern}\`)">๐</button>
|
|
107
|
+
</td>
|
|
108
|
+
<td>${(r.appliedMiddlewares || []).join(", ")}</td>
|
|
109
|
+
</tr>
|
|
110
|
+
`)
|
|
111
|
+
.join("")}
|
|
112
|
+
</tbody>
|
|
92
113
|
</table>
|
|
93
|
-
</div>
|
|
114
|
+
</div>
|
|
94
115
|
|
|
95
|
-
<!-- STATS -->
|
|
96
|
-
<div id="statsTab" style="display:none">
|
|
116
|
+
<!-- STATS -->
|
|
117
|
+
<div id="statsTab" style="display:none">
|
|
97
118
|
<div class="json-view">
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
119
|
+
Total Routes: ${totalRoutes}<br />
|
|
120
|
+
Middleware Used: ${Object.keys(middlewareStats).length}<br />
|
|
121
|
+
<pre>
|
|
122
|
+
${Object.entries(middlewareStats)
|
|
123
|
+
.map(([mw, count]) => `- ${mw}: ${count} routes`)
|
|
124
|
+
.join("\n")}
|
|
125
|
+
</pre>
|
|
102
126
|
</div>
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
|
-
<!-- MIDDLEWARES -->
|
|
106
|
-
<div id="middlewaresTab" style="display:none">
|
|
107
|
-
${Object.entries(middlewareRoutes)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<!-- MIDDLEWARES -->
|
|
130
|
+
<div id="middlewaresTab" style="display:none">
|
|
131
|
+
${Object.entries(middlewareRoutes)
|
|
132
|
+
.map(([mw, routes]) => `
|
|
133
|
+
<h3>๐น ${mw} (${routes.length})</h3>
|
|
134
|
+
<ul>
|
|
135
|
+
${routes.map((r) => `<li><code>${r.method} ${r.endpoint}</code></li>`).join("")}
|
|
136
|
+
</ul>
|
|
137
|
+
`)
|
|
138
|
+
.join("")}
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<!-- RAW JSON -->
|
|
142
|
+
<div id="jsonTab" style="display:none">
|
|
143
|
+
<div class="json-view"><pre>${rawJSON}</pre></div>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<!-- EXPORT -->
|
|
147
|
+
<div id="exportTab" style="display:none">
|
|
122
148
|
<div class="download">
|
|
123
|
-
|
|
124
|
-
|
|
149
|
+
<a href="data:text/json;charset=utf-8,${encodeURIComponent(rawJSON)}" download="routes.json">๐ฅ JSON</a>
|
|
150
|
+
<a href="data:text/csv;charset=utf-8,${csvString}" download="routes.csv">๐ฅ CSV</a>
|
|
125
151
|
</div>
|
|
126
|
-
</div>
|
|
152
|
+
</div>
|
|
127
153
|
|
|
128
|
-
<script>
|
|
154
|
+
<script>
|
|
129
155
|
const tabs = ['routes', 'stats', 'middlewares', 'json', 'export'];
|
|
130
156
|
const tabBtns = document.querySelectorAll('.tab-btn');
|
|
131
157
|
|
|
132
158
|
function showTab(tab) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
tabBtns.forEach(btn => {
|
|
143
|
-
const active = btn.textContent.toLowerCase().includes(tab);
|
|
144
|
-
btn.classList.toggle('active', active);
|
|
145
|
-
});
|
|
146
|
-
document.getElementById('searchBar').style.display = (tab === 'routes') ? 'flex' : 'none';
|
|
159
|
+
tabs.forEach(t => {
|
|
160
|
+
document.getElementById(t + 'Tab').style.display = t === tab ? 'block' : 'none';
|
|
161
|
+
document.getElementById(t + 'Tab').classList.toggle('active', t === tab);
|
|
162
|
+
});
|
|
163
|
+
tabBtns.forEach(btn => {
|
|
164
|
+
const active = btn.textContent.toLowerCase().includes(tab);
|
|
165
|
+
btn.classList.toggle('active', active);
|
|
166
|
+
});
|
|
167
|
+
document.getElementById('searchBar').style.display = (tab === 'routes') ? 'flex' : 'none';
|
|
147
168
|
}
|
|
148
169
|
|
|
149
170
|
document.getElementById('search').addEventListener('input', (e) => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
171
|
+
const keyword = e.target.value.toLowerCase();
|
|
172
|
+
const rows = document.querySelectorAll('#routesTable tbody tr');
|
|
173
|
+
rows.forEach(row => {
|
|
174
|
+
row.style.display = row.textContent.toLowerCase().includes(keyword) ? '' : 'none';
|
|
175
|
+
});
|
|
155
176
|
});
|
|
156
|
-
|
|
177
|
+
|
|
178
|
+
function copyText(text) {
|
|
179
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
180
|
+
alert('โ
Copied: ' + text);
|
|
181
|
+
}).catch(err => {
|
|
182
|
+
alert('โ Failed to copy: ' + err);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
</script>
|
|
157
186
|
`;
|
|
158
187
|
}
|
package/cjs/index.js
CHANGED
|
@@ -2,23 +2,31 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DevTools = DevTools;
|
|
4
4
|
const index_js_1 = require("./html/index.js");
|
|
5
|
-
function DevTools(app, options = { disableTabs: []
|
|
5
|
+
function DevTools(app, options = { disableTabs: [] }) {
|
|
6
6
|
let { disableTabs, extraTabs } = options;
|
|
7
|
-
return (ctx) => {
|
|
8
|
-
let
|
|
7
|
+
return async (ctx) => {
|
|
8
|
+
let extraTabs = await (typeof options.extraTabs === "function"
|
|
9
|
+
? options.extraTabs(ctx)
|
|
10
|
+
: []);
|
|
11
|
+
let html = [
|
|
12
|
+
...(disableTabs?.length
|
|
13
|
+
? (0, index_js_1.html)(ctx, app)?.filter((r) => !disableTabs?.includes(r?.tab))
|
|
14
|
+
: (0, index_js_1.html)(ctx, app)),
|
|
15
|
+
...extraTabs,
|
|
16
|
+
];
|
|
9
17
|
let tab = ctx.req.query?._tab || html?.[0]?.tab;
|
|
10
18
|
const navbar = `
|
|
11
19
|
<header>
|
|
12
20
|
<div class="tabs">
|
|
13
21
|
<img src="http://papernxt.com/favicon.ico" style="height:32px;"/>
|
|
14
|
-
${html?.map(r => `<a href = "?_tab=${r?.tab}" class="${tab === r?.tab ?
|
|
22
|
+
${html?.map((r) => `<a href = "?_tab=${r?.tab}" class="${tab === r?.tab ? "active" : ""}" > ${r?.label} </a>`)?.join("\n")}
|
|
15
23
|
</div>
|
|
16
24
|
<div class="tabs">
|
|
17
25
|
<a class="toggle-dark" onclick="toggleTheme()">๐ Toggle Dark</a>
|
|
18
26
|
</div>
|
|
19
27
|
</header>
|
|
20
28
|
`;
|
|
21
|
-
let find = html.find(r => r?.tab == tab);
|
|
29
|
+
let find = html.find((r) => r?.tab == tab);
|
|
22
30
|
return ctx.html `
|
|
23
31
|
<!DOCTYPE html>
|
|
24
32
|
<html lang="en">
|
|
@@ -94,7 +102,13 @@ function DevTools(app, options = { disableTabs: [], extraTabs: [] }) {
|
|
|
94
102
|
gap: 6px;
|
|
95
103
|
align-items: center;
|
|
96
104
|
}
|
|
97
|
-
|
|
105
|
+
.toolbar ,.action{
|
|
106
|
+
display: flex;
|
|
107
|
+
padding: 16px;
|
|
108
|
+
align-items: center;
|
|
109
|
+
gap: 6px;
|
|
110
|
+
flex-wrap: wrap;
|
|
111
|
+
}
|
|
98
112
|
.tabs a {
|
|
99
113
|
padding: 0.4rem 0.8rem;
|
|
100
114
|
text-decoration: none;
|
|
@@ -180,8 +194,10 @@ function DevTools(app, options = { disableTabs: [], extraTabs: [] }) {
|
|
|
180
194
|
}
|
|
181
195
|
|
|
182
196
|
.table-container {
|
|
183
|
-
overflow
|
|
197
|
+
overflow: auto;
|
|
198
|
+
margin-top: 16px;
|
|
184
199
|
border-radius: 0.5rem;
|
|
200
|
+
height: 75vh;
|
|
185
201
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
186
202
|
}
|
|
187
203
|
|
|
@@ -204,6 +220,8 @@ function DevTools(app, options = { disableTabs: [], extraTabs: [] }) {
|
|
|
204
220
|
thead {
|
|
205
221
|
background-color: var(--accent);
|
|
206
222
|
color: white;
|
|
223
|
+
position: sticky;
|
|
224
|
+
top: 0px;
|
|
207
225
|
}
|
|
208
226
|
|
|
209
227
|
/* Light mode zebra striping */
|
|
@@ -229,9 +247,8 @@ function DevTools(app, options = { disableTabs: [], extraTabs: [] }) {
|
|
|
229
247
|
color: red;
|
|
230
248
|
font-weight: bold;
|
|
231
249
|
}
|
|
232
|
-
|
|
250
|
+
/**
|
|
233
251
|
@media (max-width: 768px) {
|
|
234
|
-
|
|
235
252
|
table,
|
|
236
253
|
thead,
|
|
237
254
|
tbody,
|
|
@@ -265,6 +282,7 @@ function DevTools(app, options = { disableTabs: [], extraTabs: [] }) {
|
|
|
265
282
|
color: var(--accent);
|
|
266
283
|
}
|
|
267
284
|
}
|
|
285
|
+
**/
|
|
268
286
|
</style>
|
|
269
287
|
</head>
|
|
270
288
|
<body>
|
|
@@ -277,7 +295,6 @@ function DevTools(app, options = { disableTabs: [], extraTabs: [] }) {
|
|
|
277
295
|
${find?.content}
|
|
278
296
|
</section>
|
|
279
297
|
<script>
|
|
280
|
-
|
|
281
298
|
const themeCookieName = "tezx-theme";
|
|
282
299
|
|
|
283
300
|
function setCookie(name, value, days = 30) {
|
package/devtools/dumpRoutes.d.ts
CHANGED
|
@@ -6,10 +6,9 @@ export type RouteEntry = {
|
|
|
6
6
|
endpoint: string;
|
|
7
7
|
appliedMiddlewares: string[];
|
|
8
8
|
};
|
|
9
|
-
export declare function dumpRoutes(TezX: TezX<any>):
|
|
10
|
-
match: boolean;
|
|
9
|
+
export declare function dumpRoutes(TezX: TezX<any>): {
|
|
11
10
|
endpoint: string;
|
|
12
11
|
pattern: string;
|
|
13
12
|
method: any;
|
|
14
13
|
appliedMiddlewares: any[];
|
|
15
|
-
}
|
|
14
|
+
}[];
|
package/devtools/dumpRoutes.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export function sanitizePathSplit(basePath, path) {
|
|
2
2
|
const parts = `${basePath}/${path}`
|
|
3
|
-
.replace(/\\/g,
|
|
4
|
-
.replace(/\/+/g,
|
|
3
|
+
.replace(/\\/g, "")
|
|
4
|
+
.replace(/\/+/g, "/")
|
|
5
5
|
?.split("/")
|
|
6
6
|
.filter(Boolean);
|
|
7
7
|
return parts;
|
|
8
8
|
}
|
|
9
|
-
function collectRoutes(node, basePath =
|
|
9
|
+
function collectRoutes(node, basePath = "/") {
|
|
10
10
|
const routes = [];
|
|
11
11
|
let fullPath = basePath;
|
|
12
12
|
if (node.isParam && node.paramName) {
|
|
@@ -34,7 +34,6 @@ export function dumpRoutes(TezX) {
|
|
|
34
34
|
for (const [path, handlers] of app.routers) {
|
|
35
35
|
for (const [method, handler] of handlers) {
|
|
36
36
|
staticRoutes.push({
|
|
37
|
-
match: true,
|
|
38
37
|
endpoint: `/${path}`,
|
|
39
38
|
pattern: `/${path}`,
|
|
40
39
|
method,
|
package/devtools/index.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
export { dumpRoutes } from "./dumpRoutes";
|
|
2
|
+
export { dumpMiddlewares } from "./middlewares";
|
|
2
3
|
export type { RouteEntry } from "./dumpRoutes";
|
|
3
|
-
import { TezX } from "tezx";
|
|
4
4
|
export default class devtools {
|
|
5
5
|
static get runtime(): string;
|
|
6
|
-
static dumpMiddlewares(TezX: TezX): {
|
|
7
|
-
pathname: string;
|
|
8
|
-
middlewares: string[];
|
|
9
|
-
}[];
|
|
10
6
|
}
|
package/devtools/index.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import { inspectMiddlewares } from "./middlewares";
|
|
2
1
|
export { dumpRoutes } from "./dumpRoutes";
|
|
2
|
+
export { dumpMiddlewares } from "./middlewares";
|
|
3
3
|
export default class devtools {
|
|
4
4
|
static get runtime() {
|
|
5
|
-
return
|
|
6
|
-
}
|
|
7
|
-
static dumpMiddlewares(TezX) {
|
|
8
|
-
let app = TezX;
|
|
9
|
-
let middlewares = app?.triMiddlewares;
|
|
10
|
-
return inspectMiddlewares(middlewares);
|
|
5
|
+
return "";
|
|
11
6
|
}
|
|
12
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
type MiddlewareEntry = {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { TezX } from "tezx";
|
|
2
|
+
export type MiddlewareEntry = {
|
|
3
|
+
pattern: string;
|
|
4
|
+
type: "static" | "wildcard" | "optional params" | "dynamic params";
|
|
5
|
+
appliedMiddlewares: string[];
|
|
5
6
|
};
|
|
6
|
-
export declare function
|
|
7
|
-
export {};
|
|
7
|
+
export declare function dumpMiddlewares(TezX: TezX<any>): MiddlewareEntry[];
|
package/devtools/middlewares.js
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
import { sanitizePathSplit } from "./dumpRoutes";
|
|
2
|
+
function detectRouteType(pathname, isOptional) {
|
|
3
|
+
if (pathname.includes("*"))
|
|
4
|
+
return "wildcard";
|
|
5
|
+
if (pathname.includes(":"))
|
|
6
|
+
return "dynamic params";
|
|
7
|
+
if (isOptional)
|
|
8
|
+
return "optional params";
|
|
9
|
+
return "static";
|
|
10
|
+
}
|
|
11
|
+
function collectMiddlewares(node, basePath = "/") {
|
|
12
|
+
const routes = [];
|
|
13
|
+
const fullPath = sanitizePathSplit("/", basePath).join("/");
|
|
14
|
+
const routeType = detectRouteType(fullPath, node.isOptional);
|
|
15
|
+
routes.push({
|
|
16
|
+
type: routeType,
|
|
17
|
+
pattern: `/${fullPath}`,
|
|
18
|
+
appliedMiddlewares: Array.isArray(node.middlewares)
|
|
19
|
+
? node.middlewares.map((mw) => mw?.name || "anonymous")
|
|
20
|
+
: Array.from(node.middlewares).map((mw) => mw?.name || "anonymous"),
|
|
21
|
+
});
|
|
22
|
+
for (const [childPath, childNode] of node.children.entries()) {
|
|
23
|
+
const newPath = sanitizePathSplit(basePath, childPath).join("/");
|
|
24
|
+
routes.push(...collectMiddlewares(childNode, newPath));
|
|
18
25
|
}
|
|
19
|
-
return
|
|
26
|
+
return routes;
|
|
27
|
+
}
|
|
28
|
+
export function dumpMiddlewares(TezX) {
|
|
29
|
+
return collectMiddlewares(TezX.triMiddlewares);
|
|
20
30
|
}
|