lopata 0.8.4 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashboard/{chunk-yxzrcvyh.js → chunk-hnsny9g7.js} +304 -80
- package/dist/dashboard/{chunk-csyd2tq2.css → chunk-jzyhpjad.css} +8 -0
- package/dist/dashboard/index.html +1 -1
- package/package.json +1 -1
- package/src/api/dispatch.ts +2 -0
- package/src/api/handlers/routes.ts +36 -0
- package/src/api/index.ts +11 -2
- package/src/api/types.ts +15 -0
- package/src/cli/dev.ts +97 -10
- package/src/config.ts +1 -0
- package/src/lopata-config.ts +1 -0
- package/src/route-matcher.ts +192 -0
- package/src/vite-plugin/dev-server-plugin.ts +219 -56
- package/src/vite-plugin/index.ts +1 -1
- package/src/vite-plugin/modules-plugin.ts +3 -0
|
@@ -930,6 +930,39 @@ var ICONS = {
|
|
|
930
930
|
}, undefined, false, undefined, this)
|
|
931
931
|
]
|
|
932
932
|
}, undefined, true, undefined, this),
|
|
933
|
+
routes: () => /* @__PURE__ */ u3("svg", {
|
|
934
|
+
width: "16",
|
|
935
|
+
height: "16",
|
|
936
|
+
viewBox: "0 0 16 16",
|
|
937
|
+
fill: "none",
|
|
938
|
+
stroke: "currentColor",
|
|
939
|
+
"stroke-width": "1.5",
|
|
940
|
+
"stroke-linecap": "round",
|
|
941
|
+
"stroke-linejoin": "round",
|
|
942
|
+
children: [
|
|
943
|
+
/* @__PURE__ */ u3("circle", {
|
|
944
|
+
cx: "4",
|
|
945
|
+
cy: "4",
|
|
946
|
+
r: "1.5"
|
|
947
|
+
}, undefined, false, undefined, this),
|
|
948
|
+
/* @__PURE__ */ u3("circle", {
|
|
949
|
+
cx: "12",
|
|
950
|
+
cy: "4",
|
|
951
|
+
r: "1.5"
|
|
952
|
+
}, undefined, false, undefined, this),
|
|
953
|
+
/* @__PURE__ */ u3("circle", {
|
|
954
|
+
cx: "12",
|
|
955
|
+
cy: "12",
|
|
956
|
+
r: "1.5"
|
|
957
|
+
}, undefined, false, undefined, this),
|
|
958
|
+
/* @__PURE__ */ u3("path", {
|
|
959
|
+
d: "M4 5.5v2c0 1.5 1 2.5 2.5 2.5h4"
|
|
960
|
+
}, undefined, false, undefined, this),
|
|
961
|
+
/* @__PURE__ */ u3("path", {
|
|
962
|
+
d: "M4 5.5v5c0 1 .5 1.5 1.5 1.5h5"
|
|
963
|
+
}, undefined, false, undefined, this)
|
|
964
|
+
]
|
|
965
|
+
}, undefined, true, undefined, this),
|
|
933
966
|
overview: () => /* @__PURE__ */ u3("svg", {
|
|
934
967
|
width: "16",
|
|
935
968
|
height: "16",
|
|
@@ -1109,6 +1142,50 @@ function toError(err) {
|
|
|
1109
1142
|
return err instanceof Error ? err : new Error(String(err));
|
|
1110
1143
|
}
|
|
1111
1144
|
|
|
1145
|
+
// src/dashboard/components/copy-markdown-button.tsx
|
|
1146
|
+
function CopyMarkdownButton({ getMarkdown, title }) {
|
|
1147
|
+
const [copied, setCopied] = d2(false);
|
|
1148
|
+
const timerRef = A2(null);
|
|
1149
|
+
y2(() => {
|
|
1150
|
+
return () => {
|
|
1151
|
+
if (timerRef.current)
|
|
1152
|
+
clearTimeout(timerRef.current);
|
|
1153
|
+
};
|
|
1154
|
+
}, []);
|
|
1155
|
+
const handleCopy = (e3) => {
|
|
1156
|
+
e3.stopPropagation();
|
|
1157
|
+
navigator.clipboard.writeText(getMarkdown()).then(() => {
|
|
1158
|
+
setCopied(true);
|
|
1159
|
+
if (timerRef.current)
|
|
1160
|
+
clearTimeout(timerRef.current);
|
|
1161
|
+
timerRef.current = setTimeout(() => setCopied(false), 1500);
|
|
1162
|
+
});
|
|
1163
|
+
};
|
|
1164
|
+
return /* @__PURE__ */ u3("button", {
|
|
1165
|
+
onClick: handleCopy,
|
|
1166
|
+
class: "rounded-md px-2 py-1 text-xs font-medium text-text-muted hover:text-text-data hover:bg-panel-hover border border-transparent hover:border-border transition-all",
|
|
1167
|
+
title: title ?? "Copy as Markdown",
|
|
1168
|
+
children: copied ? "Copied!" : "Copy MD"
|
|
1169
|
+
}, undefined, false, undefined, this);
|
|
1170
|
+
}
|
|
1171
|
+
function tableToMarkdown(headers, rows) {
|
|
1172
|
+
const escape = (v3) => String(v3 ?? "").replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
1173
|
+
const headerRow = `| ${headers.map(escape).join(" | ")} |`;
|
|
1174
|
+
const separator = `| ${headers.map(() => "---").join(" | ")} |`;
|
|
1175
|
+
const dataRows = rows.map((row) => `| ${row.map(escape).join(" | ")} |`);
|
|
1176
|
+
return [headerRow, separator, ...dataRows].join(`
|
|
1177
|
+
`);
|
|
1178
|
+
}
|
|
1179
|
+
function recordsToMarkdown(headers, rows) {
|
|
1180
|
+
return tableToMarkdown(headers, rows.map((row) => headers.map((h3) => row[h3])));
|
|
1181
|
+
}
|
|
1182
|
+
function keyValueToMarkdown(data) {
|
|
1183
|
+
const entries = Object.entries(data);
|
|
1184
|
+
if (entries.length === 0)
|
|
1185
|
+
return "";
|
|
1186
|
+
return tableToMarkdown(["Key", "Value"], entries);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1112
1189
|
// src/dashboard/sql-browser/editable-cell.tsx
|
|
1113
1190
|
function EditableCell({ value, onSave, foreignKey, onNavigateFK, onInspect, alignRight }) {
|
|
1114
1191
|
const [editing, setEditing] = d2(false);
|
|
@@ -2321,6 +2398,9 @@ function TableDataView({ table, execQuery, onOpenInConsole, history: history2, b
|
|
|
2321
2398
|
}, undefined, true, undefined, this)
|
|
2322
2399
|
]
|
|
2323
2400
|
}, undefined, true, undefined, this),
|
|
2401
|
+
/* @__PURE__ */ u3(CopyMarkdownButton, {
|
|
2402
|
+
getMarkdown: () => recordsToMarkdown(displayCols, rows)
|
|
2403
|
+
}, undefined, false, undefined, this),
|
|
2324
2404
|
/* @__PURE__ */ u3("button", {
|
|
2325
2405
|
onClick: () => setShowInsert(!showInsert),
|
|
2326
2406
|
class: `rounded-md px-3 py-1.5 text-sm font-medium transition-all ${showInsert ? "bg-panel-active text-text-data" : "bg-ink text-surface hover:opacity-80"}`,
|
|
@@ -2984,33 +3064,41 @@ function SqlConsoleTab({ execQuery, generateSql, initialSql, history: history2 }
|
|
|
2984
3064
|
function ResultTable({ columns, rows }) {
|
|
2985
3065
|
return /* @__PURE__ */ u3("div", {
|
|
2986
3066
|
class: "bg-panel rounded-lg border border-border overflow-x-auto",
|
|
2987
|
-
children:
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
/* @__PURE__ */ u3(
|
|
2991
|
-
|
|
2992
|
-
class: "border-b border-border-subtle",
|
|
2993
|
-
children: columns.map((col) => /* @__PURE__ */ u3("th", {
|
|
2994
|
-
class: "text-left px-4 py-2.5 font-medium text-xs text-text-muted uppercase tracking-wider font-mono",
|
|
2995
|
-
children: col
|
|
2996
|
-
}, col, false, undefined, this))
|
|
2997
|
-
}, undefined, false, undefined, this)
|
|
2998
|
-
}, undefined, false, undefined, this),
|
|
2999
|
-
/* @__PURE__ */ u3("tbody", {
|
|
3000
|
-
children: rows.map((row, i3) => /* @__PURE__ */ u3("tr", {
|
|
3001
|
-
class: "group border-b border-border-row last:border-0 hover:bg-panel-hover/50 transition-colors",
|
|
3002
|
-
children: columns.map((col) => /* @__PURE__ */ u3("td", {
|
|
3003
|
-
class: "px-4 py-2.5 font-mono text-xs",
|
|
3004
|
-
children: row[col] === null ? /* @__PURE__ */ u3("span", {
|
|
3005
|
-
class: "text-text-dim italic",
|
|
3006
|
-
children: "NULL"
|
|
3007
|
-
}, undefined, false, undefined, this) : String(row[col])
|
|
3008
|
-
}, col, false, undefined, this))
|
|
3009
|
-
}, i3, false, undefined, this))
|
|
3067
|
+
children: [
|
|
3068
|
+
/* @__PURE__ */ u3("div", {
|
|
3069
|
+
class: "flex justify-end px-2 pt-2",
|
|
3070
|
+
children: /* @__PURE__ */ u3(CopyMarkdownButton, {
|
|
3071
|
+
getMarkdown: () => recordsToMarkdown(columns, rows)
|
|
3010
3072
|
}, undefined, false, undefined, this)
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3073
|
+
}, undefined, false, undefined, this),
|
|
3074
|
+
/* @__PURE__ */ u3("table", {
|
|
3075
|
+
class: "w-full text-sm",
|
|
3076
|
+
children: [
|
|
3077
|
+
/* @__PURE__ */ u3("thead", {
|
|
3078
|
+
children: /* @__PURE__ */ u3("tr", {
|
|
3079
|
+
class: "border-b border-border-subtle",
|
|
3080
|
+
children: columns.map((col) => /* @__PURE__ */ u3("th", {
|
|
3081
|
+
class: "text-left px-4 py-2.5 font-medium text-xs text-text-muted uppercase tracking-wider font-mono",
|
|
3082
|
+
children: col
|
|
3083
|
+
}, col, false, undefined, this))
|
|
3084
|
+
}, undefined, false, undefined, this)
|
|
3085
|
+
}, undefined, false, undefined, this),
|
|
3086
|
+
/* @__PURE__ */ u3("tbody", {
|
|
3087
|
+
children: rows.map((row, i3) => /* @__PURE__ */ u3("tr", {
|
|
3088
|
+
class: "group border-b border-border-row last:border-0 hover:bg-panel-hover/50 transition-colors",
|
|
3089
|
+
children: columns.map((col) => /* @__PURE__ */ u3("td", {
|
|
3090
|
+
class: "px-4 py-2.5 font-mono text-xs",
|
|
3091
|
+
children: row[col] === null ? /* @__PURE__ */ u3("span", {
|
|
3092
|
+
class: "text-text-dim italic",
|
|
3093
|
+
children: "NULL"
|
|
3094
|
+
}, undefined, false, undefined, this) : String(row[col])
|
|
3095
|
+
}, col, false, undefined, this))
|
|
3096
|
+
}, i3, false, undefined, this))
|
|
3097
|
+
}, undefined, false, undefined, this)
|
|
3098
|
+
]
|
|
3099
|
+
}, undefined, true, undefined, this)
|
|
3100
|
+
]
|
|
3101
|
+
}, undefined, true, undefined, this);
|
|
3014
3102
|
}
|
|
3015
3103
|
|
|
3016
3104
|
// src/dashboard/sql-browser/sql-browser.tsx
|
|
@@ -3162,25 +3250,35 @@ function KeyValueTable({ data }) {
|
|
|
3162
3250
|
children: "No entries"
|
|
3163
3251
|
}, undefined, false, undefined, this);
|
|
3164
3252
|
}
|
|
3165
|
-
return /* @__PURE__ */ u3("
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
/* @__PURE__ */ u3("
|
|
3177
|
-
class: "
|
|
3178
|
-
children:
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3253
|
+
return /* @__PURE__ */ u3("div", {
|
|
3254
|
+
children: [
|
|
3255
|
+
/* @__PURE__ */ u3("div", {
|
|
3256
|
+
class: "flex justify-end px-2 pt-1",
|
|
3257
|
+
children: /* @__PURE__ */ u3(CopyMarkdownButton, {
|
|
3258
|
+
getMarkdown: () => keyValueToMarkdown(data)
|
|
3259
|
+
}, undefined, false, undefined, this)
|
|
3260
|
+
}, undefined, false, undefined, this),
|
|
3261
|
+
/* @__PURE__ */ u3("table", {
|
|
3262
|
+
class: "w-full text-sm",
|
|
3263
|
+
children: /* @__PURE__ */ u3("tbody", {
|
|
3264
|
+
children: entries.map(([key, value]) => /* @__PURE__ */ u3("tr", {
|
|
3265
|
+
class: "border-b border-border-subtle last:border-0 hover:bg-panel-hover/50 transition-colors",
|
|
3266
|
+
children: [
|
|
3267
|
+
/* @__PURE__ */ u3("td", {
|
|
3268
|
+
class: "px-4 py-2 font-medium text-text-secondary whitespace-nowrap align-top font-mono",
|
|
3269
|
+
style: "width: 1%;",
|
|
3270
|
+
children: key
|
|
3271
|
+
}, undefined, false, undefined, this),
|
|
3272
|
+
/* @__PURE__ */ u3("td", {
|
|
3273
|
+
class: "px-4 py-2 text-ink break-all font-mono",
|
|
3274
|
+
children: value
|
|
3275
|
+
}, undefined, false, undefined, this)
|
|
3276
|
+
]
|
|
3277
|
+
}, key, true, undefined, this))
|
|
3278
|
+
}, undefined, false, undefined, this)
|
|
3279
|
+
}, undefined, false, undefined, this)
|
|
3280
|
+
]
|
|
3281
|
+
}, undefined, true, undefined, this);
|
|
3184
3282
|
}
|
|
3185
3283
|
// src/dashboard/components/page-header.tsx
|
|
3186
3284
|
function PageHeader({ title, subtitle, actions }) {
|
|
@@ -3308,30 +3406,38 @@ function StatusBadge({ status, colorMap }) {
|
|
|
3308
3406
|
function Table({ headers, rows }) {
|
|
3309
3407
|
return /* @__PURE__ */ u3("div", {
|
|
3310
3408
|
class: "bg-panel rounded-lg border border-border overflow-x-auto",
|
|
3311
|
-
children:
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
/* @__PURE__ */ u3(
|
|
3315
|
-
|
|
3316
|
-
class: "border-b border-border-subtle",
|
|
3317
|
-
children: headers.map((h3) => /* @__PURE__ */ u3("th", {
|
|
3318
|
-
class: "text-left px-4 py-3 font-mono font-medium text-xs text-text-muted uppercase tracking-wider",
|
|
3319
|
-
children: h3
|
|
3320
|
-
}, h3, false, undefined, this))
|
|
3321
|
-
}, undefined, false, undefined, this)
|
|
3322
|
-
}, undefined, false, undefined, this),
|
|
3323
|
-
/* @__PURE__ */ u3("tbody", {
|
|
3324
|
-
children: rows.map((row, i3) => /* @__PURE__ */ u3("tr", {
|
|
3325
|
-
class: "group border-b border-border-row last:border-0 hover:bg-panel-hover/50 transition-colors",
|
|
3326
|
-
children: row.map((cell, j3) => /* @__PURE__ */ u3("td", {
|
|
3327
|
-
class: "px-4 py-3",
|
|
3328
|
-
children: cell
|
|
3329
|
-
}, j3, false, undefined, this))
|
|
3330
|
-
}, i3, false, undefined, this))
|
|
3409
|
+
children: [
|
|
3410
|
+
/* @__PURE__ */ u3("div", {
|
|
3411
|
+
class: "flex justify-end px-2 pt-2",
|
|
3412
|
+
children: /* @__PURE__ */ u3(CopyMarkdownButton, {
|
|
3413
|
+
getMarkdown: () => tableToMarkdown(headers, rows)
|
|
3331
3414
|
}, undefined, false, undefined, this)
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3415
|
+
}, undefined, false, undefined, this),
|
|
3416
|
+
/* @__PURE__ */ u3("table", {
|
|
3417
|
+
class: "w-full text-sm",
|
|
3418
|
+
children: [
|
|
3419
|
+
/* @__PURE__ */ u3("thead", {
|
|
3420
|
+
children: /* @__PURE__ */ u3("tr", {
|
|
3421
|
+
class: "border-b border-border-subtle",
|
|
3422
|
+
children: headers.map((h3) => /* @__PURE__ */ u3("th", {
|
|
3423
|
+
class: "text-left px-4 py-3 font-mono font-medium text-xs text-text-muted uppercase tracking-wider",
|
|
3424
|
+
children: h3
|
|
3425
|
+
}, h3, false, undefined, this))
|
|
3426
|
+
}, undefined, false, undefined, this)
|
|
3427
|
+
}, undefined, false, undefined, this),
|
|
3428
|
+
/* @__PURE__ */ u3("tbody", {
|
|
3429
|
+
children: rows.map((row, i3) => /* @__PURE__ */ u3("tr", {
|
|
3430
|
+
class: "group border-b border-border-row last:border-0 hover:bg-panel-hover/50 transition-colors",
|
|
3431
|
+
children: row.map((cell, j3) => /* @__PURE__ */ u3("td", {
|
|
3432
|
+
class: "px-4 py-3",
|
|
3433
|
+
children: cell
|
|
3434
|
+
}, j3, false, undefined, this))
|
|
3435
|
+
}, i3, false, undefined, this))
|
|
3436
|
+
}, undefined, false, undefined, this)
|
|
3437
|
+
]
|
|
3438
|
+
}, undefined, true, undefined, this)
|
|
3439
|
+
]
|
|
3440
|
+
}, undefined, true, undefined, this);
|
|
3335
3441
|
}
|
|
3336
3442
|
// src/dashboard/components/table-link.tsx
|
|
3337
3443
|
function TableLink({ href, children, mono }) {
|
|
@@ -5642,11 +5748,25 @@ function ErrorList() {
|
|
|
5642
5748
|
/* @__PURE__ */ u3(RefreshButton, {
|
|
5643
5749
|
onClick: () => loadErrors()
|
|
5644
5750
|
}, undefined, false, undefined, this),
|
|
5645
|
-
errors.length > 0 && /* @__PURE__ */ u3(
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5751
|
+
errors.length > 0 && /* @__PURE__ */ u3(k, {
|
|
5752
|
+
children: [
|
|
5753
|
+
/* @__PURE__ */ u3(CopyMarkdownButton, {
|
|
5754
|
+
getMarkdown: () => tableToMarkdown(["Source", "Error", "Message", "Context", "Worker", "Time"], errors.map((err) => [
|
|
5755
|
+
err.source ?? "-",
|
|
5756
|
+
err.errorName,
|
|
5757
|
+
err.errorMessage,
|
|
5758
|
+
err.requestMethod && err.requestUrl ? `${err.requestMethod} ${err.requestUrl}` : "-",
|
|
5759
|
+
err.workerName ?? "-",
|
|
5760
|
+
formatTimestamp2(err.timestamp)
|
|
5761
|
+
]))
|
|
5762
|
+
}, undefined, false, undefined, this),
|
|
5763
|
+
/* @__PURE__ */ u3("button", {
|
|
5764
|
+
onClick: handleClear,
|
|
5765
|
+
class: "rounded-md px-3 py-1.5 text-sm font-medium bg-panel border border-border text-text-secondary btn-danger transition-all",
|
|
5766
|
+
children: "Clear all"
|
|
5767
|
+
}, undefined, false, undefined, this)
|
|
5768
|
+
]
|
|
5769
|
+
}, undefined, true, undefined, this)
|
|
5650
5770
|
]
|
|
5651
5771
|
}, undefined, true, undefined, this)
|
|
5652
5772
|
]
|
|
@@ -5856,11 +5976,20 @@ function ErrorDetailPage({ errorId }) {
|
|
|
5856
5976
|
}, undefined, true, undefined, this)
|
|
5857
5977
|
]
|
|
5858
5978
|
}, undefined, true, undefined, this),
|
|
5859
|
-
/* @__PURE__ */ u3("
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5979
|
+
/* @__PURE__ */ u3("div", {
|
|
5980
|
+
class: "flex items-center gap-2",
|
|
5981
|
+
children: [
|
|
5982
|
+
/* @__PURE__ */ u3(CopyMarkdownButton, {
|
|
5983
|
+
getMarkdown: () => errorToMarkdown(detail),
|
|
5984
|
+
title: "Copy error as Markdown for LLM"
|
|
5985
|
+
}, undefined, false, undefined, this),
|
|
5986
|
+
/* @__PURE__ */ u3("button", {
|
|
5987
|
+
onClick: handleDelete,
|
|
5988
|
+
class: "rounded-md px-3 py-1.5 text-sm font-medium bg-panel border border-border text-text-secondary btn-danger transition-all",
|
|
5989
|
+
children: "Delete"
|
|
5990
|
+
}, undefined, false, undefined, this)
|
|
5991
|
+
]
|
|
5992
|
+
}, undefined, true, undefined, this)
|
|
5864
5993
|
]
|
|
5865
5994
|
}, undefined, true, undefined, this),
|
|
5866
5995
|
/* @__PURE__ */ u3("div", {
|
|
@@ -6263,6 +6392,60 @@ function truncateUrl(url) {
|
|
|
6263
6392
|
return url.length > 50 ? url.slice(0, 50) + "..." : url;
|
|
6264
6393
|
}
|
|
6265
6394
|
}
|
|
6395
|
+
function errorToMarkdown(detail) {
|
|
6396
|
+
const { data } = detail;
|
|
6397
|
+
const lines = [];
|
|
6398
|
+
lines.push(`## ${data.error.name}: ${data.error.message}`);
|
|
6399
|
+
if (detail.source)
|
|
6400
|
+
lines.push(`**Source:** ${detail.source}`);
|
|
6401
|
+
if (data.runtime.workerName)
|
|
6402
|
+
lines.push(`**Worker:** ${data.runtime.workerName}`);
|
|
6403
|
+
lines.push("");
|
|
6404
|
+
if (data.error.stack) {
|
|
6405
|
+
lines.push("### Stack Trace");
|
|
6406
|
+
lines.push("```");
|
|
6407
|
+
lines.push(data.error.stack);
|
|
6408
|
+
lines.push("```");
|
|
6409
|
+
lines.push("");
|
|
6410
|
+
}
|
|
6411
|
+
if (data.error.frames.length > 0) {
|
|
6412
|
+
lines.push("### Source Code");
|
|
6413
|
+
for (const frame of data.error.frames) {
|
|
6414
|
+
lines.push(`#### ${frame.file}:${frame.line}:${frame.column}${frame.function ? ` in ${frame.function}` : ""}`);
|
|
6415
|
+
if (frame.source && frame.source.length > 0) {
|
|
6416
|
+
const startLine = frame.line - (frame.sourceLine ?? 0);
|
|
6417
|
+
lines.push("```");
|
|
6418
|
+
frame.source.forEach((line, i3) => {
|
|
6419
|
+
const lineNum = startLine + i3;
|
|
6420
|
+
const marker = i3 === frame.sourceLine ? ">" : " ";
|
|
6421
|
+
lines.push(`${marker} ${lineNum} | ${line}`);
|
|
6422
|
+
});
|
|
6423
|
+
lines.push("```");
|
|
6424
|
+
}
|
|
6425
|
+
lines.push("");
|
|
6426
|
+
}
|
|
6427
|
+
}
|
|
6428
|
+
if (data.request.method && data.request.url) {
|
|
6429
|
+
lines.push("### Request");
|
|
6430
|
+
lines.push(`${data.request.method} ${data.request.url}`);
|
|
6431
|
+
const headers = Object.entries(data.request.headers);
|
|
6432
|
+
if (headers.length > 0) {
|
|
6433
|
+
lines.push("");
|
|
6434
|
+
lines.push(keyValueToMarkdown(data.request.headers));
|
|
6435
|
+
}
|
|
6436
|
+
lines.push("");
|
|
6437
|
+
}
|
|
6438
|
+
if (data.bindings.length > 0) {
|
|
6439
|
+
lines.push("### Bindings");
|
|
6440
|
+
lines.push(tableToMarkdown(["Name", "Type"], data.bindings.map((b) => [b.name, b.type])));
|
|
6441
|
+
lines.push("");
|
|
6442
|
+
}
|
|
6443
|
+
lines.push("### Runtime");
|
|
6444
|
+
lines.push(`- **Bun:** ${data.runtime.bunVersion}`);
|
|
6445
|
+
lines.push(`- **Platform:** ${data.runtime.platform} / ${data.runtime.arch}`);
|
|
6446
|
+
return lines.join(`
|
|
6447
|
+
`);
|
|
6448
|
+
}
|
|
6266
6449
|
|
|
6267
6450
|
// src/dashboard/views/generations.tsx
|
|
6268
6451
|
var STATE_COLORS = {
|
|
@@ -7825,6 +8008,44 @@ function R2ObjectList({ bucket }) {
|
|
|
7825
8008
|
}, undefined, true, undefined, this);
|
|
7826
8009
|
}
|
|
7827
8010
|
|
|
8011
|
+
// src/dashboard/views/routes.tsx
|
|
8012
|
+
var TYPE_COLORS = {
|
|
8013
|
+
route: "bg-emerald-500/15 text-emerald-500",
|
|
8014
|
+
host: "bg-blue-500/15 text-blue-500",
|
|
8015
|
+
fallback: "bg-panel-active text-text-data"
|
|
8016
|
+
};
|
|
8017
|
+
function RoutesView() {
|
|
8018
|
+
const { data: routes } = useQuery("routes.list");
|
|
8019
|
+
return /* @__PURE__ */ u3("div", {
|
|
8020
|
+
class: "p-4 sm:p-8",
|
|
8021
|
+
children: [
|
|
8022
|
+
/* @__PURE__ */ u3(PageHeader, {
|
|
8023
|
+
title: "Routes",
|
|
8024
|
+
subtitle: `${routes?.length ?? 0} route(s)`
|
|
8025
|
+
}, undefined, false, undefined, this),
|
|
8026
|
+
!routes?.length ? /* @__PURE__ */ u3(EmptyState, {
|
|
8027
|
+
message: "No routes configured"
|
|
8028
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ u3(Table, {
|
|
8029
|
+
headers: ["Pattern", "Worker", "Type"],
|
|
8030
|
+
rows: routes.map((r3) => [
|
|
8031
|
+
/* @__PURE__ */ u3("span", {
|
|
8032
|
+
class: "font-mono text-xs font-medium",
|
|
8033
|
+
children: r3.pattern
|
|
8034
|
+
}, undefined, false, undefined, this),
|
|
8035
|
+
/* @__PURE__ */ u3("span", {
|
|
8036
|
+
class: "text-text-secondary",
|
|
8037
|
+
children: r3.workerName
|
|
8038
|
+
}, undefined, false, undefined, this),
|
|
8039
|
+
/* @__PURE__ */ u3(StatusBadge, {
|
|
8040
|
+
status: r3.isFallback ? "fallback" : r3.type === "host" ? "host" : "route",
|
|
8041
|
+
colorMap: TYPE_COLORS
|
|
8042
|
+
}, undefined, false, undefined, this)
|
|
8043
|
+
])
|
|
8044
|
+
}, undefined, false, undefined, this)
|
|
8045
|
+
]
|
|
8046
|
+
}, undefined, true, undefined, this);
|
|
8047
|
+
}
|
|
8048
|
+
|
|
7828
8049
|
// src/dashboard/views/scheduled.tsx
|
|
7829
8050
|
function ScheduledView({ route }) {
|
|
7830
8051
|
return /* @__PURE__ */ u3(ScheduledList, {}, undefined, false, undefined, this);
|
|
@@ -8958,7 +9179,7 @@ function DurationBar({ durationMs, maxDuration }) {
|
|
|
8958
9179
|
}
|
|
8959
9180
|
|
|
8960
9181
|
// src/dashboard/views/workers.tsx
|
|
8961
|
-
var
|
|
9182
|
+
var TYPE_COLORS2 = {
|
|
8962
9183
|
kv: "bg-emerald-500/15 text-emerald-500",
|
|
8963
9184
|
r2: "bg-blue-500/15 text-blue-400",
|
|
8964
9185
|
d1: "bg-violet-500/15 text-violet-400",
|
|
@@ -9014,7 +9235,7 @@ function WorkersView() {
|
|
|
9014
9235
|
rows: w3.bindings.map((b) => [
|
|
9015
9236
|
/* @__PURE__ */ u3(StatusBadge, {
|
|
9016
9237
|
status: b.type,
|
|
9017
|
-
colorMap:
|
|
9238
|
+
colorMap: TYPE_COLORS2
|
|
9018
9239
|
}, undefined, false, undefined, this),
|
|
9019
9240
|
/* @__PURE__ */ u3("span", {
|
|
9020
9241
|
class: "font-mono text-xs font-medium",
|
|
@@ -9744,6 +9965,7 @@ var NAV_GROUPS = [
|
|
|
9744
9965
|
label: "Compute",
|
|
9745
9966
|
items: [
|
|
9746
9967
|
{ path: "/workers", label: "Workers", icon: "workers" },
|
|
9968
|
+
{ path: "/routes", label: "Routes", icon: "routes" },
|
|
9747
9969
|
{ path: "/do", label: "Durable Objects", icon: "do" },
|
|
9748
9970
|
{ path: "/containers", label: "Containers", icon: "containers" },
|
|
9749
9971
|
{ path: "/workflows", label: "Workflows", icon: "workflows" },
|
|
@@ -9880,6 +10102,8 @@ function App() {
|
|
|
9880
10102
|
}, undefined, false, undefined, this);
|
|
9881
10103
|
if (route.startsWith("/workers"))
|
|
9882
10104
|
return /* @__PURE__ */ u3(WorkersView, {}, undefined, false, undefined, this);
|
|
10105
|
+
if (route.startsWith("/routes"))
|
|
10106
|
+
return /* @__PURE__ */ u3(RoutesView, {}, undefined, false, undefined, this);
|
|
9883
10107
|
if (route.startsWith("/generations"))
|
|
9884
10108
|
return /* @__PURE__ */ u3(GenerationsView, {}, undefined, false, undefined, this);
|
|
9885
10109
|
if (route.startsWith("/kv"))
|
|
@@ -1756,6 +1756,14 @@
|
|
|
1756
1756
|
padding-top: calc(var(--spacing) * .5);
|
|
1757
1757
|
}
|
|
1758
1758
|
|
|
1759
|
+
.pt-1 {
|
|
1760
|
+
padding-top: calc(var(--spacing) * 1);
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
.pt-2 {
|
|
1764
|
+
padding-top: calc(var(--spacing) * 2);
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1759
1767
|
.pt-3 {
|
|
1760
1768
|
padding-top: calc(var(--spacing) * 3);
|
|
1761
1769
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
|
10
10
|
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/__dashboard/assets/chunk-
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/__dashboard/assets/chunk-jzyhpjad.css"><script type="module" crossorigin src="/__dashboard/assets/chunk-hnsny9g7.js"></script></head>
|
|
12
12
|
<body class="h-full bg-surface text-ink" style="font-family: system-ui, -apple-system, sans-serif;">
|
|
13
13
|
<script>
|
|
14
14
|
// Apply saved theme before first paint to prevent flash
|
package/package.json
CHANGED
package/src/api/dispatch.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { handlers as kv } from './handlers/kv'
|
|
|
13
13
|
import { handlers as overview } from './handlers/overview'
|
|
14
14
|
import { handlers as queue } from './handlers/queue'
|
|
15
15
|
import { handlers as r2 } from './handlers/r2'
|
|
16
|
+
import { handlers as routes } from './handlers/routes'
|
|
16
17
|
import { handlers as scheduled } from './handlers/scheduled'
|
|
17
18
|
import { handlers as traces } from './handlers/traces'
|
|
18
19
|
import { handlers as warnings } from './handlers/warnings'
|
|
@@ -40,6 +41,7 @@ const allHandlers = {
|
|
|
40
41
|
...ai,
|
|
41
42
|
...analyticsEngine,
|
|
42
43
|
...warnings,
|
|
44
|
+
...routes,
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
export type Procedures = {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { extractPathPattern } from '../../route-matcher'
|
|
2
|
+
import type { HandlerContext, RouteInfo } from '../types'
|
|
3
|
+
|
|
4
|
+
export const handlers = {
|
|
5
|
+
'routes.list'(_input: {}, ctx: HandlerContext): RouteInfo[] {
|
|
6
|
+
const routes: RouteInfo[] = []
|
|
7
|
+
|
|
8
|
+
// Show host-based routes
|
|
9
|
+
for (const hr of ctx.hostRoutes) {
|
|
10
|
+
routes.push({ pattern: hr.pattern, workerName: hr.workerName, isFallback: false, type: 'host' })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (ctx.routeDispatcher) {
|
|
14
|
+
for (const r of ctx.routeDispatcher.getRegisteredRoutes()) {
|
|
15
|
+
routes.push({ pattern: r.pattern, workerName: r.workerName, isFallback: false })
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// In single-worker mode, show routes from config
|
|
20
|
+
if (!ctx.routeDispatcher && ctx.config?.routes) {
|
|
21
|
+
const workerName = ctx.config.name || 'main'
|
|
22
|
+
for (const route of ctx.config.routes) {
|
|
23
|
+
if (typeof route === 'object' && route.custom_domain) continue
|
|
24
|
+
routes.push({ pattern: extractPathPattern(route), workerName, isFallback: false })
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Add main/fallback worker entry
|
|
29
|
+
const mainName = ctx.registry
|
|
30
|
+
? Array.from(ctx.registry.listManagers().keys())[0] ?? 'main'
|
|
31
|
+
: ctx.config?.name || 'main'
|
|
32
|
+
routes.push({ pattern: '/*', workerName: mainName, isFallback: true })
|
|
33
|
+
|
|
34
|
+
return routes
|
|
35
|
+
},
|
|
36
|
+
}
|
package/src/api/index.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { WranglerConfig } from '../config'
|
|
2
2
|
import type { GenerationManager } from '../generation-manager'
|
|
3
3
|
import type { LopataConfig } from '../lopata-config'
|
|
4
|
+
import type { RouteDispatcher } from '../route-matcher'
|
|
4
5
|
import type { WorkerRegistry } from '../worker-registry'
|
|
5
6
|
import { handlePreflight, withCors } from './cors'
|
|
6
7
|
import { dispatch } from './dispatch'
|
|
7
8
|
import { handleR2Download, handleR2Upload } from './r2'
|
|
8
|
-
import type { HandlerContext } from './types'
|
|
9
|
+
import type { HandlerContext, HostRouteInfo } from './types'
|
|
9
10
|
|
|
10
|
-
const ctx: HandlerContext = { config: null, manager: null, registry: null, lopataConfig: null }
|
|
11
|
+
const ctx: HandlerContext = { config: null, manager: null, registry: null, lopataConfig: null, routeDispatcher: null, hostRoutes: [] }
|
|
11
12
|
|
|
12
13
|
export function setDashboardConfig(config: WranglerConfig): void {
|
|
13
14
|
ctx.config = config
|
|
@@ -25,6 +26,14 @@ export function setLopataConfig(config: LopataConfig): void {
|
|
|
25
26
|
ctx.lopataConfig = config
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
export function setRouteDispatcher(dispatcher: RouteDispatcher): void {
|
|
30
|
+
ctx.routeDispatcher = dispatcher
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function setHostRoutes(routes: HostRouteInfo[]): void {
|
|
34
|
+
ctx.hostRoutes = routes
|
|
35
|
+
}
|
|
36
|
+
|
|
28
37
|
export function handleApiRequest(request: Request): Response | Promise<Response> {
|
|
29
38
|
const url = new URL(request.url)
|
|
30
39
|
|
package/src/api/types.ts
CHANGED
|
@@ -379,13 +379,28 @@ export type { SpanData, SpanEventData, TraceDetail, TraceEvent, TraceSummary } f
|
|
|
379
379
|
import type { WranglerConfig } from '../config'
|
|
380
380
|
import type { GenerationManager } from '../generation-manager'
|
|
381
381
|
import type { LopataConfig } from '../lopata-config'
|
|
382
|
+
import type { RouteDispatcher } from '../route-matcher'
|
|
382
383
|
import type { WorkerRegistry } from '../worker-registry'
|
|
383
384
|
|
|
385
|
+
export interface HostRouteInfo {
|
|
386
|
+
pattern: string
|
|
387
|
+
workerName: string
|
|
388
|
+
}
|
|
389
|
+
|
|
384
390
|
export interface HandlerContext {
|
|
385
391
|
config: WranglerConfig | null
|
|
386
392
|
manager: GenerationManager | null
|
|
387
393
|
registry: WorkerRegistry | null
|
|
388
394
|
lopataConfig: LopataConfig | null
|
|
395
|
+
routeDispatcher: RouteDispatcher | null
|
|
396
|
+
hostRoutes: HostRouteInfo[]
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export interface RouteInfo {
|
|
400
|
+
pattern: string
|
|
401
|
+
workerName: string
|
|
402
|
+
isFallback: boolean
|
|
403
|
+
type?: 'path' | 'host'
|
|
389
404
|
}
|
|
390
405
|
|
|
391
406
|
/** Collect configs from all workers (registry) or fall back to single config. */
|