lopata 0.0.1
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/README.md +15 -0
- package/package.json +51 -0
- package/runtime/bindings/ai.ts +132 -0
- package/runtime/bindings/analytics-engine.ts +96 -0
- package/runtime/bindings/browser.ts +64 -0
- package/runtime/bindings/cache.ts +179 -0
- package/runtime/bindings/cf-streams.ts +56 -0
- package/runtime/bindings/container-docker.ts +225 -0
- package/runtime/bindings/container.ts +662 -0
- package/runtime/bindings/crypto-extras.ts +89 -0
- package/runtime/bindings/d1.ts +315 -0
- package/runtime/bindings/do-executor-inprocess.ts +140 -0
- package/runtime/bindings/do-executor-worker.ts +368 -0
- package/runtime/bindings/do-executor.ts +45 -0
- package/runtime/bindings/do-websocket-bridge.ts +70 -0
- package/runtime/bindings/do-worker-entry.ts +220 -0
- package/runtime/bindings/do-worker-env.ts +74 -0
- package/runtime/bindings/durable-object.ts +992 -0
- package/runtime/bindings/email.ts +180 -0
- package/runtime/bindings/html-rewriter.ts +84 -0
- package/runtime/bindings/hyperdrive.ts +130 -0
- package/runtime/bindings/images.ts +381 -0
- package/runtime/bindings/kv.ts +359 -0
- package/runtime/bindings/queue.ts +507 -0
- package/runtime/bindings/r2.ts +759 -0
- package/runtime/bindings/rpc-stub.ts +267 -0
- package/runtime/bindings/scheduled.ts +172 -0
- package/runtime/bindings/service-binding.ts +217 -0
- package/runtime/bindings/static-assets.ts +481 -0
- package/runtime/bindings/websocket-pair.ts +182 -0
- package/runtime/bindings/workflow.ts +858 -0
- package/runtime/bunflare-config.ts +56 -0
- package/runtime/cli/cache.ts +39 -0
- package/runtime/cli/context.ts +105 -0
- package/runtime/cli/d1.ts +163 -0
- package/runtime/cli/dev.ts +392 -0
- package/runtime/cli/kv.ts +84 -0
- package/runtime/cli/queues.ts +109 -0
- package/runtime/cli/r2.ts +140 -0
- package/runtime/cli/traces.ts +251 -0
- package/runtime/cli.ts +102 -0
- package/runtime/config.ts +148 -0
- package/runtime/d1-migrate.ts +37 -0
- package/runtime/dashboard/api.ts +174 -0
- package/runtime/dashboard/app.tsx +220 -0
- package/runtime/dashboard/components/breadcrumb.tsx +16 -0
- package/runtime/dashboard/components/buttons.tsx +13 -0
- package/runtime/dashboard/components/code-block.tsx +5 -0
- package/runtime/dashboard/components/detail-field.tsx +8 -0
- package/runtime/dashboard/components/empty-state.tsx +8 -0
- package/runtime/dashboard/components/filter-input.tsx +11 -0
- package/runtime/dashboard/components/index.ts +16 -0
- package/runtime/dashboard/components/key-value-table.tsx +23 -0
- package/runtime/dashboard/components/modal.tsx +23 -0
- package/runtime/dashboard/components/page-header.tsx +11 -0
- package/runtime/dashboard/components/pill-button.tsx +14 -0
- package/runtime/dashboard/components/refresh-button.tsx +7 -0
- package/runtime/dashboard/components/service-info.tsx +45 -0
- package/runtime/dashboard/components/status-badge.tsx +7 -0
- package/runtime/dashboard/components/table-link.tsx +5 -0
- package/runtime/dashboard/components/table.tsx +26 -0
- package/runtime/dashboard/components.tsx +19 -0
- package/runtime/dashboard/index.html +23 -0
- package/runtime/dashboard/lib.ts +45 -0
- package/runtime/dashboard/rpc/client.ts +20 -0
- package/runtime/dashboard/rpc/handlers/ai.ts +71 -0
- package/runtime/dashboard/rpc/handlers/analytics-engine.ts +53 -0
- package/runtime/dashboard/rpc/handlers/cache.ts +24 -0
- package/runtime/dashboard/rpc/handlers/config.ts +137 -0
- package/runtime/dashboard/rpc/handlers/containers.ts +194 -0
- package/runtime/dashboard/rpc/handlers/d1.ts +84 -0
- package/runtime/dashboard/rpc/handlers/do.ts +117 -0
- package/runtime/dashboard/rpc/handlers/email.ts +82 -0
- package/runtime/dashboard/rpc/handlers/errors.ts +32 -0
- package/runtime/dashboard/rpc/handlers/generations.ts +60 -0
- package/runtime/dashboard/rpc/handlers/kv.ts +76 -0
- package/runtime/dashboard/rpc/handlers/overview.ts +94 -0
- package/runtime/dashboard/rpc/handlers/queue.ts +79 -0
- package/runtime/dashboard/rpc/handlers/r2.ts +72 -0
- package/runtime/dashboard/rpc/handlers/scheduled.ts +91 -0
- package/runtime/dashboard/rpc/handlers/traces.ts +64 -0
- package/runtime/dashboard/rpc/handlers/workers.ts +65 -0
- package/runtime/dashboard/rpc/handlers/workflows.ts +171 -0
- package/runtime/dashboard/rpc/hooks.ts +132 -0
- package/runtime/dashboard/rpc/server.ts +70 -0
- package/runtime/dashboard/rpc/types.ts +396 -0
- package/runtime/dashboard/sql-browser/data-browser-tab.tsx +122 -0
- package/runtime/dashboard/sql-browser/editable-cell.tsx +117 -0
- package/runtime/dashboard/sql-browser/filter-row.tsx +99 -0
- package/runtime/dashboard/sql-browser/history-panels.tsx +110 -0
- package/runtime/dashboard/sql-browser/hooks.ts +137 -0
- package/runtime/dashboard/sql-browser/index.ts +4 -0
- package/runtime/dashboard/sql-browser/insert-row-form.tsx +85 -0
- package/runtime/dashboard/sql-browser/modals.tsx +116 -0
- package/runtime/dashboard/sql-browser/schema-browser-tab.tsx +67 -0
- package/runtime/dashboard/sql-browser/sql-browser.tsx +52 -0
- package/runtime/dashboard/sql-browser/sql-console-tab.tsx +124 -0
- package/runtime/dashboard/sql-browser/table-data-view.tsx +566 -0
- package/runtime/dashboard/sql-browser/table-sidebar.tsx +38 -0
- package/runtime/dashboard/sql-browser/types.ts +61 -0
- package/runtime/dashboard/sql-browser/utils.ts +167 -0
- package/runtime/dashboard/style.css +177 -0
- package/runtime/dashboard/views/ai.tsx +152 -0
- package/runtime/dashboard/views/analytics-engine.tsx +169 -0
- package/runtime/dashboard/views/cache.tsx +93 -0
- package/runtime/dashboard/views/containers.tsx +197 -0
- package/runtime/dashboard/views/d1.tsx +81 -0
- package/runtime/dashboard/views/do.tsx +168 -0
- package/runtime/dashboard/views/email.tsx +235 -0
- package/runtime/dashboard/views/errors.tsx +558 -0
- package/runtime/dashboard/views/home.tsx +287 -0
- package/runtime/dashboard/views/kv.tsx +273 -0
- package/runtime/dashboard/views/queue.tsx +193 -0
- package/runtime/dashboard/views/r2.tsx +202 -0
- package/runtime/dashboard/views/scheduled.tsx +89 -0
- package/runtime/dashboard/views/trace-waterfall.tsx +410 -0
- package/runtime/dashboard/views/traces.tsx +768 -0
- package/runtime/dashboard/views/workers.tsx +55 -0
- package/runtime/dashboard/views/workflows.tsx +473 -0
- package/runtime/db.ts +258 -0
- package/runtime/env.ts +362 -0
- package/runtime/error-page/app.tsx +394 -0
- package/runtime/error-page/build.ts +269 -0
- package/runtime/error-page/index.html +16 -0
- package/runtime/error-page/style.css +31 -0
- package/runtime/execution-context.ts +18 -0
- package/runtime/file-watcher.ts +57 -0
- package/runtime/generation-manager.ts +230 -0
- package/runtime/generation.ts +411 -0
- package/runtime/plugin.ts +292 -0
- package/runtime/request-cf.ts +28 -0
- package/runtime/rpc-validate.ts +154 -0
- package/runtime/tracing/context.ts +40 -0
- package/runtime/tracing/db.ts +73 -0
- package/runtime/tracing/frames.ts +75 -0
- package/runtime/tracing/instrument.ts +186 -0
- package/runtime/tracing/span.ts +138 -0
- package/runtime/tracing/store.ts +499 -0
- package/runtime/tracing/types.ts +47 -0
- package/runtime/vite-plugin/config-plugin.ts +68 -0
- package/runtime/vite-plugin/dev-server-plugin.ts +493 -0
- package/runtime/vite-plugin/dist/index.mjs +52333 -0
- package/runtime/vite-plugin/globals-plugin.ts +94 -0
- package/runtime/vite-plugin/index.ts +43 -0
- package/runtime/vite-plugin/modules-plugin.ts +88 -0
- package/runtime/vite-plugin/react-router-plugin.ts +95 -0
- package/runtime/worker-registry.ts +52 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
// ─── Shared data types ───────────────────────────────────────────────
|
|
2
|
+
|
|
3
|
+
export type { GenerationInfo } from "../../generation";
|
|
4
|
+
import type { GenerationInfo } from "../../generation";
|
|
5
|
+
|
|
6
|
+
export interface Paginated<T> {
|
|
7
|
+
items: T[];
|
|
8
|
+
cursor: string | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface OkResponse {
|
|
12
|
+
ok: true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Overview
|
|
16
|
+
export interface OverviewData {
|
|
17
|
+
kv: number;
|
|
18
|
+
r2: number;
|
|
19
|
+
queue: number;
|
|
20
|
+
do: number;
|
|
21
|
+
workflows: number;
|
|
22
|
+
d1: number;
|
|
23
|
+
containers: number;
|
|
24
|
+
cache: number;
|
|
25
|
+
errors: number;
|
|
26
|
+
scheduled: number;
|
|
27
|
+
email: number;
|
|
28
|
+
ai: number;
|
|
29
|
+
analyticsEngine: number;
|
|
30
|
+
generations: GenerationInfo[];
|
|
31
|
+
runtime: {
|
|
32
|
+
bunVersion: string;
|
|
33
|
+
platform: string;
|
|
34
|
+
arch: string;
|
|
35
|
+
pid: number;
|
|
36
|
+
cwd: string;
|
|
37
|
+
uptime: number;
|
|
38
|
+
startedAt: number;
|
|
39
|
+
memory: {
|
|
40
|
+
rss: number;
|
|
41
|
+
heapUsed: number;
|
|
42
|
+
heapTotal: number;
|
|
43
|
+
external: number;
|
|
44
|
+
};
|
|
45
|
+
cpuUsage: {
|
|
46
|
+
user: number;
|
|
47
|
+
system: number;
|
|
48
|
+
};
|
|
49
|
+
env: Record<string, string>;
|
|
50
|
+
};
|
|
51
|
+
workerErrors: Record<string, number>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Containers
|
|
55
|
+
export interface ContainerSummary {
|
|
56
|
+
className: string;
|
|
57
|
+
image: string;
|
|
58
|
+
maxInstances: number | null;
|
|
59
|
+
bindingName: string;
|
|
60
|
+
instanceCount: number;
|
|
61
|
+
runningCount: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ContainerInstance {
|
|
65
|
+
id: string;
|
|
66
|
+
doName: string | null;
|
|
67
|
+
containerName: string;
|
|
68
|
+
state: string;
|
|
69
|
+
ports: Record<string, string>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ContainerDetail {
|
|
73
|
+
id: string;
|
|
74
|
+
doName: string | null;
|
|
75
|
+
containerName: string;
|
|
76
|
+
image: string;
|
|
77
|
+
state: string;
|
|
78
|
+
exitCode: number | null;
|
|
79
|
+
ports: Record<string, string>;
|
|
80
|
+
created: string | null;
|
|
81
|
+
config: {
|
|
82
|
+
defaultPort: number;
|
|
83
|
+
sleepAfter: string | number | null;
|
|
84
|
+
enableInternet: boolean;
|
|
85
|
+
pingEndpoint: string;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// KV
|
|
90
|
+
export interface KvNamespace {
|
|
91
|
+
namespace: string;
|
|
92
|
+
count: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface KvKey {
|
|
96
|
+
key: string;
|
|
97
|
+
size: number;
|
|
98
|
+
metadata: string | null;
|
|
99
|
+
expiration: number | null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface KvValue {
|
|
103
|
+
key: string;
|
|
104
|
+
value: string;
|
|
105
|
+
metadata: unknown;
|
|
106
|
+
expiration: number | null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// R2
|
|
110
|
+
export interface R2Bucket {
|
|
111
|
+
bucket: string;
|
|
112
|
+
count: number;
|
|
113
|
+
total_size: number;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface R2Object {
|
|
117
|
+
key: string;
|
|
118
|
+
size: number;
|
|
119
|
+
etag: string;
|
|
120
|
+
uploaded: string;
|
|
121
|
+
http_metadata: string | null;
|
|
122
|
+
custom_metadata: string | null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Queue
|
|
126
|
+
export interface QueueInfo {
|
|
127
|
+
queue: string;
|
|
128
|
+
pending: number;
|
|
129
|
+
acked: number;
|
|
130
|
+
failed: number;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface QueueMessage {
|
|
134
|
+
id: string;
|
|
135
|
+
body: string;
|
|
136
|
+
content_type: string;
|
|
137
|
+
status: string;
|
|
138
|
+
attempts: number;
|
|
139
|
+
visible_at: number;
|
|
140
|
+
created_at: number;
|
|
141
|
+
completed_at: number | null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Durable Objects
|
|
145
|
+
export interface DoNamespace {
|
|
146
|
+
namespace: string;
|
|
147
|
+
count: number;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface DoInstance {
|
|
151
|
+
id: string;
|
|
152
|
+
name?: string | null;
|
|
153
|
+
key_count: number;
|
|
154
|
+
alarm: number | null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface DoDetail {
|
|
158
|
+
entries: { key: string; value: string }[];
|
|
159
|
+
alarm: number | null;
|
|
160
|
+
hasAlarmHandler: boolean;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Workflows
|
|
164
|
+
export interface WorkflowSummary {
|
|
165
|
+
name: string;
|
|
166
|
+
total: number;
|
|
167
|
+
byStatus: Record<string, number>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface WorkflowInstance {
|
|
171
|
+
id: string;
|
|
172
|
+
status: string;
|
|
173
|
+
params: string | null;
|
|
174
|
+
output: string | null;
|
|
175
|
+
error: string | null;
|
|
176
|
+
created_at: number;
|
|
177
|
+
updated_at: number;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface WorkflowStepAttempt {
|
|
181
|
+
step_name: string;
|
|
182
|
+
failed_attempts: number;
|
|
183
|
+
last_error: string | null;
|
|
184
|
+
last_error_name: string | null;
|
|
185
|
+
last_error_id: string | null;
|
|
186
|
+
updated_at: number | null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface WorkflowDetail extends WorkflowInstance {
|
|
190
|
+
steps: { step_name: string; output: string | null; completed_at: number }[];
|
|
191
|
+
stepAttempts: WorkflowStepAttempt[];
|
|
192
|
+
events: { id: number; event_type: string; payload: string | null; created_at: number }[];
|
|
193
|
+
activeSleep: { stepName: string; until: number } | null;
|
|
194
|
+
waitingForEvents: string[];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// D1
|
|
198
|
+
export interface D1Database {
|
|
199
|
+
name: string;
|
|
200
|
+
tables: number;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface D1Table {
|
|
204
|
+
name: string;
|
|
205
|
+
sql: string;
|
|
206
|
+
rows: number;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface QueryResult {
|
|
210
|
+
columns: string[];
|
|
211
|
+
rows: Record<string, unknown>[];
|
|
212
|
+
count: number;
|
|
213
|
+
message?: string;
|
|
214
|
+
error?: string;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Cache
|
|
218
|
+
export interface CacheName {
|
|
219
|
+
cache_name: string;
|
|
220
|
+
count: number;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface CacheEntry {
|
|
224
|
+
url: string;
|
|
225
|
+
status: number;
|
|
226
|
+
headers: string;
|
|
227
|
+
expires_at: number | null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Generations
|
|
231
|
+
export interface WorkerGenerations {
|
|
232
|
+
workerName: string;
|
|
233
|
+
generations: GenerationInfo[];
|
|
234
|
+
gracePeriodMs: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface GenerationsData {
|
|
238
|
+
generations: GenerationInfo[];
|
|
239
|
+
gracePeriodMs: number;
|
|
240
|
+
workers?: WorkerGenerations[];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Workers
|
|
244
|
+
export interface WorkerBinding {
|
|
245
|
+
type: string;
|
|
246
|
+
name: string;
|
|
247
|
+
target: string;
|
|
248
|
+
href: string | null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface WorkerInfo {
|
|
252
|
+
name: string;
|
|
253
|
+
isMain: boolean;
|
|
254
|
+
bindings: WorkerBinding[];
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Errors
|
|
258
|
+
export interface ErrorSummary {
|
|
259
|
+
id: string;
|
|
260
|
+
timestamp: number;
|
|
261
|
+
errorName: string;
|
|
262
|
+
errorMessage: string;
|
|
263
|
+
requestMethod: string | null;
|
|
264
|
+
requestUrl: string | null;
|
|
265
|
+
workerName: string | null;
|
|
266
|
+
traceId: string | null;
|
|
267
|
+
spanId: string | null;
|
|
268
|
+
source: string | null;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export interface ErrorDetail {
|
|
272
|
+
id: string;
|
|
273
|
+
timestamp: number;
|
|
274
|
+
traceId: string | null;
|
|
275
|
+
spanId: string | null;
|
|
276
|
+
source: string | null;
|
|
277
|
+
data: {
|
|
278
|
+
error: {
|
|
279
|
+
name: string;
|
|
280
|
+
message: string;
|
|
281
|
+
stack: string;
|
|
282
|
+
frames: Array<{
|
|
283
|
+
file: string;
|
|
284
|
+
line: number;
|
|
285
|
+
column: number;
|
|
286
|
+
function: string;
|
|
287
|
+
source?: string[];
|
|
288
|
+
sourceLine?: number;
|
|
289
|
+
}>;
|
|
290
|
+
};
|
|
291
|
+
request: {
|
|
292
|
+
method: string;
|
|
293
|
+
url: string;
|
|
294
|
+
headers: Record<string, string>;
|
|
295
|
+
};
|
|
296
|
+
env: Record<string, string>;
|
|
297
|
+
bindings: Array<{ name: string; type: string }>;
|
|
298
|
+
runtime: {
|
|
299
|
+
bunVersion: string;
|
|
300
|
+
platform: string;
|
|
301
|
+
arch: string;
|
|
302
|
+
workerName?: string;
|
|
303
|
+
configName?: string;
|
|
304
|
+
};
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export interface TraceErrorSummary {
|
|
309
|
+
id: string;
|
|
310
|
+
timestamp: number;
|
|
311
|
+
errorName: string;
|
|
312
|
+
errorMessage: string;
|
|
313
|
+
source: string | null;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// AI
|
|
317
|
+
export interface AiRequest {
|
|
318
|
+
id: string;
|
|
319
|
+
model: string;
|
|
320
|
+
input_summary: string | null;
|
|
321
|
+
output_summary: string | null;
|
|
322
|
+
duration_ms: number;
|
|
323
|
+
status: string;
|
|
324
|
+
error: string | null;
|
|
325
|
+
is_streaming: number;
|
|
326
|
+
created_at: number;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Analytics Engine
|
|
330
|
+
export interface AnalyticsEngineDataPoint {
|
|
331
|
+
id: string;
|
|
332
|
+
dataset: string;
|
|
333
|
+
timestamp: number;
|
|
334
|
+
_sample_interval: number;
|
|
335
|
+
index1: string | null;
|
|
336
|
+
blob1: string | null;
|
|
337
|
+
blob2: string | null;
|
|
338
|
+
blob3: string | null;
|
|
339
|
+
blob4: string | null;
|
|
340
|
+
blob5: string | null;
|
|
341
|
+
double1: number | null;
|
|
342
|
+
double2: number | null;
|
|
343
|
+
double3: number | null;
|
|
344
|
+
double4: number | null;
|
|
345
|
+
double5: number | null;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Email
|
|
349
|
+
export interface EmailRecord {
|
|
350
|
+
id: string;
|
|
351
|
+
binding: string;
|
|
352
|
+
from_addr: string;
|
|
353
|
+
to_addr: string;
|
|
354
|
+
raw_size: number;
|
|
355
|
+
status: string;
|
|
356
|
+
reject_reason: string | null;
|
|
357
|
+
created_at: number;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Traces (re-export from tracing module)
|
|
361
|
+
export type { TraceSummary, TraceDetail, SpanData, SpanEventData, TraceEvent } from "../../tracing/types";
|
|
362
|
+
|
|
363
|
+
// ─── Handler context ─────────────────────────────────────────────────
|
|
364
|
+
|
|
365
|
+
import type { WranglerConfig } from "../../config";
|
|
366
|
+
import type { GenerationManager } from "../../generation-manager";
|
|
367
|
+
import type { WorkerRegistry } from "../../worker-registry";
|
|
368
|
+
|
|
369
|
+
export interface HandlerContext {
|
|
370
|
+
config: WranglerConfig | null;
|
|
371
|
+
manager: GenerationManager | null;
|
|
372
|
+
registry: WorkerRegistry | null;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** Collect configs from all workers (registry) or fall back to single config. */
|
|
376
|
+
export function getAllConfigs(ctx: HandlerContext): WranglerConfig[] {
|
|
377
|
+
if (ctx.registry) {
|
|
378
|
+
return Array.from(ctx.registry.listManagers().values()).map(m => m.config);
|
|
379
|
+
}
|
|
380
|
+
return ctx.config ? [ctx.config] : [];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** Find a DO namespace by class name across all active generations. */
|
|
384
|
+
export function getDoNamespace(ctx: HandlerContext, ns: string) {
|
|
385
|
+
if (ctx.registry) {
|
|
386
|
+
for (const manager of ctx.registry.listManagers().values()) {
|
|
387
|
+
const entry = manager.active?.registry.durableObjects.find(d => d.className === ns);
|
|
388
|
+
if (entry) return entry.namespace;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (ctx.manager) {
|
|
392
|
+
const entry = ctx.manager.active?.registry.durableObjects.find(d => d.className === ns);
|
|
393
|
+
if (entry) return entry.namespace;
|
|
394
|
+
}
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { useState, useEffect } from "preact/hooks";
|
|
2
|
+
import type { D1Table, QueryResult } from "../rpc/types";
|
|
3
|
+
import { navigate, replaceRoute } from "../lib";
|
|
4
|
+
import type { SortDir, BrowserHistoryEntry } from "./types";
|
|
5
|
+
import type { useHistory, useBrowserHistory } from "./hooks";
|
|
6
|
+
import { TableDataView } from "./table-data-view";
|
|
7
|
+
import { TableSidebar } from "./table-sidebar";
|
|
8
|
+
|
|
9
|
+
export function DataBrowserTab({ tables, execQuery, onOpenInConsole, history, browserHistory, historyScope, basePath, routeTable, routeQuery }: {
|
|
10
|
+
tables?: D1Table[] | null;
|
|
11
|
+
execQuery: (sql: string) => Promise<QueryResult>;
|
|
12
|
+
onOpenInConsole: (sql: string) => void;
|
|
13
|
+
history: ReturnType<typeof useHistory>;
|
|
14
|
+
browserHistory: ReturnType<typeof useBrowserHistory>;
|
|
15
|
+
historyScope?: string;
|
|
16
|
+
basePath?: string;
|
|
17
|
+
routeTable?: string | null;
|
|
18
|
+
routeQuery?: URLSearchParams;
|
|
19
|
+
}) {
|
|
20
|
+
// Table selection: URL-driven when basePath is set, local state otherwise
|
|
21
|
+
const [localTable, setLocalTable] = useState<string | null>(null);
|
|
22
|
+
const [localRestoredState, setLocalRestoredState] = useState<{ filters: Record<string, string>; sortCol: string | null; sortDir: SortDir } | null>(null);
|
|
23
|
+
const selectedTable = basePath ? (routeTable ?? null) : localTable;
|
|
24
|
+
|
|
25
|
+
// Auto-select first table
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!selectedTable && tables?.length) {
|
|
28
|
+
if (basePath) {
|
|
29
|
+
replaceRoute(basePath + "/data/" + encodeURIComponent(tables[0]!.name));
|
|
30
|
+
} else {
|
|
31
|
+
setLocalTable(tables[0]!.name);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}, [tables, selectedTable, basePath]);
|
|
35
|
+
|
|
36
|
+
const tableInfo = tables?.find(t => t.name === selectedTable) ?? null;
|
|
37
|
+
|
|
38
|
+
const handleRestoreHistory = (entry: BrowserHistoryEntry) => {
|
|
39
|
+
if (basePath) {
|
|
40
|
+
const params = new URLSearchParams();
|
|
41
|
+
for (const [col, val] of Object.entries(entry.filters)) {
|
|
42
|
+
if (val.trim()) params.set("f." + col, val);
|
|
43
|
+
}
|
|
44
|
+
if (entry.sortCol) {
|
|
45
|
+
params.set("s", entry.sortCol);
|
|
46
|
+
params.set("d", entry.sortDir);
|
|
47
|
+
}
|
|
48
|
+
const qs = params.toString();
|
|
49
|
+
navigate(basePath + "/data/" + encodeURIComponent(entry.table) + (qs ? "?" + qs : ""));
|
|
50
|
+
} else {
|
|
51
|
+
setLocalTable(entry.table);
|
|
52
|
+
setLocalRestoredState({ filters: entry.filters, sortCol: entry.sortCol, sortDir: entry.sortDir });
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const handleNavigateFK = (targetTable: string, targetColumn: string, value: unknown) => {
|
|
57
|
+
if (!tables?.some(t => t.name === targetTable)) return;
|
|
58
|
+
if (basePath) {
|
|
59
|
+
const params = new URLSearchParams();
|
|
60
|
+
params.set("f." + targetColumn, `=${String(value)}`);
|
|
61
|
+
navigate(basePath + "/data/" + encodeURIComponent(targetTable) + "?" + params.toString());
|
|
62
|
+
} else {
|
|
63
|
+
setLocalTable(targetTable);
|
|
64
|
+
setLocalRestoredState({ filters: { [targetColumn]: `=${String(value)}` }, sortCol: null, sortDir: "ASC" });
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const handleTableSelect = (name: string) => {
|
|
69
|
+
if (basePath) {
|
|
70
|
+
navigate(basePath + "/data/" + encodeURIComponent(name));
|
|
71
|
+
} else {
|
|
72
|
+
setLocalTable(name);
|
|
73
|
+
setLocalRestoredState(null);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Build effective query: from URL route or from local restored state
|
|
78
|
+
const effectiveQuery = (() => {
|
|
79
|
+
if (basePath) return routeQuery;
|
|
80
|
+
if (!localRestoredState) return undefined;
|
|
81
|
+
const params = new URLSearchParams();
|
|
82
|
+
for (const [col, val] of Object.entries(localRestoredState.filters)) {
|
|
83
|
+
if (val.trim()) params.set("f." + col, val);
|
|
84
|
+
}
|
|
85
|
+
if (localRestoredState.sortCol) {
|
|
86
|
+
params.set("s", localRestoredState.sortCol);
|
|
87
|
+
params.set("d", localRestoredState.sortDir);
|
|
88
|
+
}
|
|
89
|
+
return params;
|
|
90
|
+
})();
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div class="flex gap-5">
|
|
94
|
+
<TableSidebar
|
|
95
|
+
tables={tables}
|
|
96
|
+
selected={selectedTable}
|
|
97
|
+
onSelect={handleTableSelect}
|
|
98
|
+
/>
|
|
99
|
+
<div class="flex-1 min-w-0">
|
|
100
|
+
{tableInfo ? (
|
|
101
|
+
<TableDataView
|
|
102
|
+
key={tableInfo.name + "?" + (effectiveQuery?.toString() ?? "")}
|
|
103
|
+
table={tableInfo}
|
|
104
|
+
execQuery={execQuery}
|
|
105
|
+
onOpenInConsole={onOpenInConsole}
|
|
106
|
+
history={history}
|
|
107
|
+
browserHistory={browserHistory}
|
|
108
|
+
onRestoreHistory={handleRestoreHistory}
|
|
109
|
+
onNavigateFK={handleNavigateFK}
|
|
110
|
+
historyScope={historyScope}
|
|
111
|
+
basePath={basePath}
|
|
112
|
+
routeQuery={effectiveQuery}
|
|
113
|
+
/>
|
|
114
|
+
) : (
|
|
115
|
+
<div class="text-center py-16 text-text-muted text-sm font-medium">
|
|
116
|
+
{tables?.length ? "Select a table" : "No tables found"}
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "preact/hooks";
|
|
2
|
+
import type { ForeignKeyInfo } from "./types";
|
|
3
|
+
|
|
4
|
+
export function EditableCell({ value, onSave, foreignKey, onNavigateFK, onInspect, alignRight }: {
|
|
5
|
+
value: unknown;
|
|
6
|
+
onSave: (v: unknown) => void;
|
|
7
|
+
foreignKey?: ForeignKeyInfo | null;
|
|
8
|
+
onNavigateFK?: (fk: ForeignKeyInfo) => void;
|
|
9
|
+
onInspect?: () => void;
|
|
10
|
+
alignRight?: boolean;
|
|
11
|
+
}) {
|
|
12
|
+
const [editing, setEditing] = useState(false);
|
|
13
|
+
const [editValue, setEditValue] = useState("");
|
|
14
|
+
const [isNull, setIsNull] = useState(false);
|
|
15
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
16
|
+
|
|
17
|
+
const isLong = value !== null && value !== undefined && String(value).length > 80;
|
|
18
|
+
|
|
19
|
+
const startEdit = () => {
|
|
20
|
+
setIsNull(value === null);
|
|
21
|
+
setEditValue(value === null ? "" : String(value));
|
|
22
|
+
setEditing(true);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (editing && inputRef.current) {
|
|
27
|
+
inputRef.current.focus();
|
|
28
|
+
inputRef.current.select();
|
|
29
|
+
}
|
|
30
|
+
}, [editing]);
|
|
31
|
+
|
|
32
|
+
const save = () => {
|
|
33
|
+
const newValue = isNull ? null : editValue;
|
|
34
|
+
setEditing(false);
|
|
35
|
+
// Only save if value actually changed
|
|
36
|
+
if (newValue !== (value === null ? null : String(value))) {
|
|
37
|
+
onSave(newValue);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const cancel = () => {
|
|
42
|
+
setEditing(false);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
if (editing) {
|
|
46
|
+
return (
|
|
47
|
+
<div class="flex items-center gap-1 py-1">
|
|
48
|
+
<input
|
|
49
|
+
ref={inputRef}
|
|
50
|
+
type="text"
|
|
51
|
+
value={isNull ? "" : editValue}
|
|
52
|
+
disabled={isNull}
|
|
53
|
+
onInput={e => setEditValue((e.target as HTMLInputElement).value)}
|
|
54
|
+
onKeyDown={e => {
|
|
55
|
+
if (e.key === "Enter") save();
|
|
56
|
+
else if (e.key === "Escape") cancel();
|
|
57
|
+
}}
|
|
58
|
+
class={`w-full bg-panel-secondary border border-border rounded px-2 py-1 font-mono text-xs outline-none focus:border-ink focus:ring-1 focus:ring-border ${isNull ? "opacity-40" : ""}`}
|
|
59
|
+
/>
|
|
60
|
+
<button
|
|
61
|
+
onClick={() => { setIsNull(!isNull); if (!isNull) setEditValue(""); }}
|
|
62
|
+
title={isNull ? "Set to value" : "Set to NULL"}
|
|
63
|
+
class={`flex-shrink-0 rounded px-1.5 py-1 text-xs font-bold transition-colors ${
|
|
64
|
+
isNull ? "bg-amber-100 text-amber-700" : "bg-panel-hover text-text-muted hover:bg-panel-active"
|
|
65
|
+
}`}
|
|
66
|
+
>
|
|
67
|
+
N
|
|
68
|
+
</button>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const isFkNav = foreignKey && value != null && onNavigateFK;
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div class={`group/cell flex items-center gap-1 font-mono text-xs py-2 min-h-[2rem] ${alignRight ? "justify-end" : ""}`}>
|
|
77
|
+
{isFkNav ? (
|
|
78
|
+
<>
|
|
79
|
+
<span
|
|
80
|
+
onClick={() => onNavigateFK!(foreignKey!)}
|
|
81
|
+
class="truncate max-w-xs text-link hover:underline cursor-pointer"
|
|
82
|
+
title={`${String(value)} \u2192 ${foreignKey!.targetTable}.${foreignKey!.targetColumn}`}
|
|
83
|
+
>
|
|
84
|
+
{String(value)}
|
|
85
|
+
</span>
|
|
86
|
+
<button
|
|
87
|
+
onClick={(e) => { e.stopPropagation(); startEdit(); }}
|
|
88
|
+
class="flex-shrink-0 opacity-0 group-hover/cell:opacity-100 text-xs text-text-muted hover:text-text-data px-1.5 py-0.5 rounded hover:bg-panel-hover transition-all"
|
|
89
|
+
title="Edit value"
|
|
90
|
+
>
|
|
91
|
+
edit
|
|
92
|
+
</button>
|
|
93
|
+
</>
|
|
94
|
+
) : (
|
|
95
|
+
<div
|
|
96
|
+
onClick={startEdit}
|
|
97
|
+
class={`cursor-pointer flex-1 min-w-0 flex items-center ${alignRight ? "justify-end" : ""}`}
|
|
98
|
+
>
|
|
99
|
+
{value === null ? (
|
|
100
|
+
<span class="text-text-dim italic">NULL</span>
|
|
101
|
+
) : (
|
|
102
|
+
<span class="truncate max-w-xs" title={String(value)}>{String(value)}</span>
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
)}
|
|
106
|
+
{isLong && onInspect && (
|
|
107
|
+
<button
|
|
108
|
+
onClick={e => { e.stopPropagation(); onInspect(); }}
|
|
109
|
+
class="flex-shrink-0 text-[10px] text-text-muted hover:text-text-data px-1 py-0.5 rounded hover:bg-panel-hover transition-colors"
|
|
110
|
+
title="Inspect value"
|
|
111
|
+
>
|
|
112
|
+
⤢
|
|
113
|
+
</button>
|
|
114
|
+
)}
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|