@ubean/devtools 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,561 @@
1
+ import { Plugin } from "vite";
2
+ import { ViteDevToolsNodeContext, defineRpcFunction } from "@vitejs/devtools-kit";
3
+ import { SharedState } from "devframe/utils/shared-state";
4
+ //#region src/shared/env.d.ts
5
+ declare function maskSensitiveEnv(env: Record<string, string>): Record<string, string>;
6
+ //#endregion
7
+ //#region src/server/hooks.d.ts
8
+ interface DevToolsHooks {
9
+ beforeCreate: (ctx: CrudHookContext) => void | Promise<void>;
10
+ afterCreate: (ctx: CrudHookContext) => void | Promise<void>;
11
+ beforeUpdate: (ctx: CrudHookContext) => void | Promise<void>;
12
+ afterUpdate: (ctx: CrudHookContext) => void | Promise<void>;
13
+ beforeDelete: (ctx: CrudHookContext) => void | Promise<void>;
14
+ afterDelete: (ctx: CrudHookContext) => void | Promise<void>;
15
+ }
16
+ declare function createDevToolsHooks(): {
17
+ registerHook: (type: CrudHookType, handler: CrudHookHandler) => void;
18
+ runHook: (type: CrudHookType, ctx: CrudHookContext) => Promise<void>;
19
+ removeHook: (type: CrudHookType, handler: CrudHookHandler) => void;
20
+ removeAllHooks: () => void;
21
+ hook: <NameT extends import("hookable").HookKeys<DevToolsHooks>>(name: NameT, function_: DevToolsHooks[NameT] extends import("hookable").HookCallback ? DevToolsHooks[NameT] : never, options?: {
22
+ allowDeprecated?: boolean;
23
+ }) => () => void;
24
+ callHook: <NameT extends import("hookable").HookKeys<DevToolsHooks>>(name: NameT, ...args: Parameters<DevToolsHooks[NameT] extends import("hookable").HookCallback ? DevToolsHooks[NameT] : never>) => Promise<any> | void;
25
+ };
26
+ type DevToolsHooksInstance = ReturnType<typeof createDevToolsHooks>;
27
+ //#endregion
28
+ //#region src/server/crud.d.ts
29
+ interface CrudServerOptions {
30
+ cwd: string;
31
+ hooks?: DevToolsHooksInstance;
32
+ getEnv?: () => Record<string, string>;
33
+ setEnv?: (env: Record<string, string>) => void;
34
+ getConfig?: () => Record<string, unknown>;
35
+ onFileChange?: () => void | Promise<void>;
36
+ scaffoldOps?: DevToolsScaffoldOps;
37
+ }
38
+ declare function createCrudServer(options: CrudServerOptions): {
39
+ create: (params: CreateCrudParams) => Promise<CrudResult>;
40
+ read: (params: ReadCrudParams) => Promise<{
41
+ success: boolean;
42
+ content?: string;
43
+ data?: unknown;
44
+ error?: string;
45
+ }>;
46
+ update: (params: UpdateCrudParams) => Promise<CrudResult>;
47
+ delete: (params: DeleteCrudParams) => Promise<CrudResult>;
48
+ restore: (path: string) => Promise<CrudResult>;
49
+ };
50
+ type DevToolsCrudServer = ReturnType<typeof createCrudServer>;
51
+ //#endregion
52
+ //#region src/server/ai.d.ts
53
+ interface AiToolCall {
54
+ id: string;
55
+ name: string;
56
+ arguments: Record<string, unknown>;
57
+ }
58
+ interface AiToolResult {
59
+ toolCallId: string;
60
+ result?: unknown;
61
+ error?: string;
62
+ }
63
+ interface AiChatMessage {
64
+ role: 'user' | 'assistant' | 'system' | 'tool';
65
+ content: string;
66
+ toolCalls?: AiToolCall[];
67
+ toolCallId?: string;
68
+ toolResults?: AiToolResult[];
69
+ timestamp: number;
70
+ }
71
+ interface AiToolDefinition {
72
+ name: string;
73
+ description: string;
74
+ parameters: {
75
+ type: 'object';
76
+ properties: Record<string, AiToolParam>;
77
+ required?: string[];
78
+ };
79
+ }
80
+ interface AiToolParam {
81
+ type: 'string' | 'number' | 'boolean' | 'object' | 'array';
82
+ description: string;
83
+ enum?: string[];
84
+ items?: {
85
+ type: 'string' | 'number' | 'boolean' | 'object' | 'array';
86
+ };
87
+ }
88
+ interface AiChatOptions {
89
+ messages: AiChatMessage[];
90
+ model?: string;
91
+ apiKey?: string;
92
+ apiBase?: string;
93
+ /** When provided, the server streams text deltas via this callback. */
94
+ requestId?: string;
95
+ }
96
+ interface AiChatResponse {
97
+ message: AiChatMessage;
98
+ toolResults?: AiToolResult[];
99
+ }
100
+ /** A chunk pushed to the client during streaming. */
101
+ interface AiStreamChunk {
102
+ requestId: string;
103
+ /** Accumulated text so far (not a delta). */
104
+ text: string;
105
+ done: boolean;
106
+ toolCalls?: AiToolCall[];
107
+ toolResults?: AiToolResult[];
108
+ error?: string;
109
+ }
110
+ declare function createAiServer(crud: DevToolsCrudServer, getInfo: () => DevToolsInfo, onStreamChunk?: (chunk: AiStreamChunk) => void): {
111
+ getToolDefinitions: () => AiToolDefinition[];
112
+ executeToolCall: (call: AiToolCall) => Promise<AiToolResult>;
113
+ chat: (options: AiChatOptions) => Promise<AiChatResponse>;
114
+ parseCommand: (input: string) => {
115
+ toolCalls?: AiToolCall[];
116
+ response?: string;
117
+ } | null;
118
+ formatToolResult: (name: string, result: unknown) => string;
119
+ };
120
+ type DevToolsAiServer = ReturnType<typeof createAiServer>;
121
+ //#endregion
122
+ //#region src/node/rpc/playground.d.ts
123
+ interface PlaygroundInvokeParams {
124
+ method: string;
125
+ path: string;
126
+ body?: unknown;
127
+ headers?: Record<string, string>;
128
+ }
129
+ interface PlaygroundInvokeResult {
130
+ status: number;
131
+ statusText: string;
132
+ body: unknown;
133
+ headers: Record<string, string>;
134
+ }
135
+ //#endregion
136
+ //#region src/server/terminal.d.ts
137
+ interface TerminalStartParams {
138
+ cwd: string;
139
+ cols?: number;
140
+ rows?: number;
141
+ /** Shell command; defaults to the user's default shell. */
142
+ shell?: string;
143
+ }
144
+ interface TerminalPollResult {
145
+ data: string;
146
+ exited: boolean;
147
+ exitCode: number | null;
148
+ }
149
+ declare function createTerminalServer(): {
150
+ start: (params: TerminalStartParams) => {
151
+ sessionId: string;
152
+ };
153
+ input: (sessionId: string, data: string) => boolean;
154
+ resize: (sessionId: string, cols: number, rows: number) => boolean;
155
+ poll: (sessionId: string) => TerminalPollResult;
156
+ kill: (sessionId: string) => boolean;
157
+ killAll: () => void;
158
+ };
159
+ type TerminalServer = ReturnType<typeof createTerminalServer>;
160
+ //#endregion
161
+ //#region src/types.d.ts
162
+ interface DevToolsOptions {
163
+ enabled?: boolean;
164
+ port?: number;
165
+ host?: string;
166
+ ai?: {
167
+ apiKey?: string;
168
+ apiBase?: string;
169
+ model?: string;
170
+ };
171
+ }
172
+ interface DevToolsRouteInfo {
173
+ method: string;
174
+ path: string;
175
+ filePath?: string;
176
+ }
177
+ interface DevToolsPageInfo {
178
+ path: string;
179
+ name?: string;
180
+ filePath?: string;
181
+ layout?: string;
182
+ }
183
+ interface DevToolsMiddlewareInfo {
184
+ path: string;
185
+ filePath?: string;
186
+ global: boolean;
187
+ }
188
+ interface DevToolsCronInfo {
189
+ name: string;
190
+ schedule?: string;
191
+ filePath?: string;
192
+ }
193
+ interface DevToolsLayoutInfo {
194
+ name: string;
195
+ path: string;
196
+ filePath?: string;
197
+ isDefault: boolean;
198
+ }
199
+ interface DevToolsCustomTab {
200
+ id: string;
201
+ label: string;
202
+ icon?: string;
203
+ src: string;
204
+ sandbox?: string[];
205
+ }
206
+ interface DevToolsInfo {
207
+ version: string;
208
+ startTime: number;
209
+ config: Record<string, unknown>;
210
+ env?: Record<string, string>;
211
+ pages: number;
212
+ apiRoutes: number;
213
+ middleware: number;
214
+ layouts?: number;
215
+ crons?: number;
216
+ presets?: string[];
217
+ routes?: DevToolsRouteInfo[];
218
+ pagesList?: DevToolsPageInfo[];
219
+ middlewaresList?: DevToolsMiddlewareInfo[];
220
+ layoutsList?: DevToolsLayoutInfo[];
221
+ cronsList?: DevToolsCronInfo[];
222
+ openAPI?: {
223
+ enabled: boolean;
224
+ scalarPath?: string;
225
+ openAPIPath?: string;
226
+ };
227
+ database?: {
228
+ drizzleStudioAvailable?: boolean;
229
+ studioUrl?: string;
230
+ };
231
+ ai?: {
232
+ enabled: boolean;
233
+ provider?: string;
234
+ model?: string;
235
+ };
236
+ customTabs?: DevToolsCustomTab[];
237
+ }
238
+ /** Read-result shape returned by `ubean:crud:read`. */
239
+ interface CrudReadResult {
240
+ success: boolean;
241
+ content?: string;
242
+ data?: unknown;
243
+ error?: string;
244
+ }
245
+ /** Params for `ubean:ai:chat`. */
246
+ interface AiChatParams {
247
+ messages: AiChatMessage[];
248
+ apiKey?: string;
249
+ apiBase?: string;
250
+ model?: string;
251
+ }
252
+ declare module 'devframe' {
253
+ interface DevframeRpcServerFunctions {
254
+ 'ubean:get-info': () => Promise<DevToolsInfo>;
255
+ 'ubean:get-env': () => Promise<Record<string, string>>;
256
+ 'ubean:crud:create': (params: CreateCrudParams) => Promise<CrudResult>;
257
+ 'ubean:crud:read': (params: ReadCrudParams) => Promise<CrudReadResult>;
258
+ 'ubean:crud:update': (params: UpdateCrudParams) => Promise<CrudResult>;
259
+ 'ubean:crud:delete': (params: DeleteCrudParams) => Promise<CrudResult>;
260
+ 'ubean:crud:restore': (path: string) => Promise<CrudResult>;
261
+ 'ubean:ai:tools': () => Promise<AiToolDefinition[]>;
262
+ 'ubean:ai:chat': (params: AiChatParams) => Promise<AiChatResponse>;
263
+ 'ubean:playground:invoke': (params: PlaygroundInvokeParams) => Promise<PlaygroundInvokeResult>;
264
+ 'ubean:terminal:start': (params: TerminalStartParams) => Promise<{
265
+ sessionId: string;
266
+ }>;
267
+ 'ubean:terminal:input': (params: {
268
+ sessionId: string;
269
+ data: string;
270
+ }) => Promise<boolean>;
271
+ 'ubean:terminal:resize': (params: {
272
+ sessionId: string;
273
+ cols: number;
274
+ rows: number;
275
+ }) => Promise<boolean>;
276
+ 'ubean:terminal:poll': (params: {
277
+ sessionId: string;
278
+ }) => Promise<TerminalPollResult>;
279
+ 'ubean:terminal:kill': (params: {
280
+ sessionId: string;
281
+ }) => Promise<boolean>;
282
+ }
283
+ interface DevframeRpcSharedStates {
284
+ 'ubean:info': DevToolsInfo;
285
+ }
286
+ }
287
+ type RpcHandler = (params: unknown) => unknown | Promise<unknown>;
288
+ interface DevToolsServer {
289
+ rpcHandlers: Map<string, RpcHandler>;
290
+ registerHandler: (name: string, handler: RpcHandler) => void;
291
+ getInfo: () => DevToolsInfo;
292
+ }
293
+ interface RpcRequest {
294
+ id: string;
295
+ method: string;
296
+ params?: unknown;
297
+ }
298
+ interface RpcResponse<T = unknown> {
299
+ id: string;
300
+ result?: T;
301
+ error?: string;
302
+ }
303
+ interface DevToolsTab {
304
+ id: string;
305
+ label: string;
306
+ icon?: string;
307
+ }
308
+ type CrudResourceType = 'page' | 'api' | 'layout' | 'middleware' | 'reuse' | 'cron' | 'plugin';
309
+ interface CrudResult {
310
+ success: boolean;
311
+ created?: string[];
312
+ deleted?: string[];
313
+ restored?: string[];
314
+ updated?: string[];
315
+ skipped?: string[];
316
+ errors?: string[];
317
+ }
318
+ interface CreateCrudParams {
319
+ type: CrudResourceType;
320
+ path: string;
321
+ method?: string;
322
+ schedule?: string;
323
+ content?: string;
324
+ force?: boolean;
325
+ }
326
+ interface ReadCrudParams {
327
+ type: CrudResourceType | 'env' | 'config';
328
+ path?: string;
329
+ }
330
+ interface UpdateCrudParams {
331
+ type: CrudResourceType | 'env' | 'config';
332
+ path?: string;
333
+ key?: string;
334
+ content?: string;
335
+ value?: string;
336
+ }
337
+ interface DeleteCrudParams {
338
+ type: CrudResourceType | 'env';
339
+ path?: string;
340
+ key?: string;
341
+ force?: boolean;
342
+ }
343
+ type CrudHookType = 'beforeCreate' | 'afterCreate' | 'beforeUpdate' | 'afterUpdate' | 'beforeDelete' | 'afterDelete';
344
+ interface CrudHookContext {
345
+ type: CrudResourceType | 'env' | 'config';
346
+ path?: string;
347
+ key?: string;
348
+ content?: string;
349
+ value?: string;
350
+ }
351
+ type CrudHookHandler = (ctx: CrudHookContext) => void | Promise<void>;
352
+ type DevToolsScaffoldType = 'page' | 'api' | 'layout' | 'middleware' | 'reuse';
353
+ interface ScaffoldResult {
354
+ created: string[];
355
+ deleted: string[];
356
+ restored: string[];
357
+ skipped: string[];
358
+ errors: string[];
359
+ }
360
+ interface ScaffoldOptions {
361
+ cwd?: string;
362
+ type: DevToolsScaffoldType;
363
+ path: string;
364
+ method?: string;
365
+ force?: boolean;
366
+ dry?: boolean;
367
+ baseDir?: string;
368
+ }
369
+ interface DevToolsFsOps {
370
+ exists: (path: string) => Promise<boolean>;
371
+ readFile: (path: string, enc?: BufferEncoding) => Promise<string>;
372
+ writeFile: (path: string, content: string, enc?: BufferEncoding) => Promise<void>;
373
+ remove: (path: string) => Promise<void>;
374
+ copyFile: (src: string, dest: string) => Promise<void>;
375
+ createBackup: (path: string, opts?: {
376
+ backupSuffix?: string;
377
+ removeOriginal?: boolean;
378
+ }) => Promise<string | null>;
379
+ removeBackup: (path: string, opts?: {
380
+ backupSuffix?: string;
381
+ }) => Promise<void>;
382
+ }
383
+ interface DevToolsScaffoldOps {
384
+ createFsOps: (cwd: string) => DevToolsFsOps;
385
+ scaffold: (opts: ScaffoldOptions) => Promise<ScaffoldResult>;
386
+ deleteScaffold: (opts: ScaffoldOptions) => Promise<ScaffoldResult>;
387
+ recoverScaffold: (opts: ScaffoldOptions) => Promise<ScaffoldResult>;
388
+ }
389
+ //#endregion
390
+ //#region src/node/state.d.ts
391
+ /** SharedState key for the ubean devtools info snapshot. */
392
+ declare const UBEAN_INFO_STATE_KEY = "ubean:info";
393
+ /**
394
+ * Structural shape of the scan data passed by `dev.ts`. Defined here
395
+ * (rather than importing ubean's `ScanResult`) so `@ubean/devtools`
396
+ * has no static dependency on `ubean`.
397
+ */
398
+ interface ScanResultLike {
399
+ apiRoutes: Array<{
400
+ method?: string;
401
+ route: string;
402
+ relativePath: string;
403
+ fullPath: string;
404
+ }>;
405
+ pages: Array<{
406
+ route: string;
407
+ name: string;
408
+ relativePath: string;
409
+ fullPath: string;
410
+ isReuse: boolean;
411
+ layout?: string | false;
412
+ }>;
413
+ middlewares: Array<{
414
+ global: boolean;
415
+ relativePath: string;
416
+ fullPath: string;
417
+ }>;
418
+ layouts: Array<{
419
+ name: string;
420
+ path: string;
421
+ relativePath: string;
422
+ fullPath: string;
423
+ isDefault: boolean;
424
+ }>;
425
+ crons: Array<{
426
+ name: string;
427
+ relativePath: string;
428
+ fullPath: string;
429
+ }>;
430
+ }
431
+ /** Config metadata passed by `dev.ts` for the DevToolsInfo.config field. */
432
+ interface DevToolsConfigMeta {
433
+ preset: string;
434
+ rootDir: string;
435
+ srcDir: string;
436
+ openAPI?: {
437
+ enabled: boolean;
438
+ scalarPath?: string;
439
+ openAPIPath?: string;
440
+ };
441
+ database?: {
442
+ drizzleStudioAvailable?: boolean;
443
+ studioUrl?: string;
444
+ };
445
+ /** Directory configuration for project structure (e.g. { routes: 'routes', pages: 'pages' }). */
446
+ dir?: Record<string, string>;
447
+ }
448
+ interface BuildInfoOptions {
449
+ scan: ScanResultLike | null;
450
+ configMeta: DevToolsConfigMeta | null;
451
+ customTabs: DevToolsCustomTab[];
452
+ ai?: {
453
+ apiKey?: string;
454
+ apiBase?: string;
455
+ model?: string;
456
+ };
457
+ startTime: number;
458
+ envData: Record<string, string>;
459
+ }
460
+ /** Build a fresh `DevToolsInfo` from scan + config metadata. */
461
+ declare function buildDevToolsInfo(opts: BuildInfoOptions): DevToolsInfo;
462
+ /** Initial empty state (used before scan data arrives). */
463
+ declare function emptyDevToolsInfo(startTime: number): DevToolsInfo;
464
+ //#endregion
465
+ //#region src/node/index.d.ts
466
+ /**
467
+ * Options injected by the ubean dev runner so the DevTools plugin can reach
468
+ * Hono-runtime data (scanned routes/pages, the Hono app for in-process
469
+ * playground forwarding) without `@ubean/devtools` statically depending on
470
+ * `ubean`.
471
+ */
472
+ interface UbeanDevtoolsPluginOptions {
473
+ /** Project root directory (used by the CRUD server for file scaffolding). */
474
+ getCwd: () => string;
475
+ /** Accessor for the live Hono app — used by the playground RPC to forward
476
+ * HTTP requests in-process without a network round-trip. */
477
+ getApp?: () => {
478
+ fetch: (req: Request) => Response | Promise<Response>;
479
+ } | undefined;
480
+ /** Accessor for the latest project scan result (routes/pages/middleware/...). */
481
+ getScanResult?: () => ScanResultLike | null;
482
+ /** Accessor for resolved config metadata shown in the Overview tab. */
483
+ getConfigMeta?: () => DevToolsConfigMeta | null;
484
+ /** Accessor for user-defined custom tabs (from `defineDevToolsTab`). */
485
+ getCustomTabs?: () => DevToolsCustomTab[];
486
+ /**
487
+ * Scaffold operations injected by ubean so @ubean/devtools never has a
488
+ * hard runtime dependency on ubean. Provides fs ops + scaffold/delete/recover
489
+ * functions used by the CRUD server for file creation/deletion.
490
+ */
491
+ scaffoldOps?: DevToolsScaffoldOps;
492
+ /** AI provider configuration forwarded to the AI server. */
493
+ ai?: {
494
+ apiKey?: string;
495
+ apiBase?: string;
496
+ model?: string;
497
+ };
498
+ /**
499
+ * Trigger an immediate project rescan + app reload. Called by the CRUD
500
+ * server after file create/update/delete so the DevTools list updates
501
+ * without waiting for the file watcher's debounce.
502
+ */
503
+ triggerRescan?: () => void | Promise<void>;
504
+ /**
505
+ * The dev runner registers a refresh callback here. Whenever the app is
506
+ * rebuilt (file change), the runner invokes it so the plugin can rebuild
507
+ * `DevToolsInfo` from the latest scan data and push patches to clients
508
+ * via sharedState — replacing the old 3s polling pattern.
509
+ */
510
+ registerRefresh?: (fn: () => void) => void;
511
+ }
512
+ /**
513
+ * Ubean DevTools as a Vite plugin.
514
+ *
515
+ * Registers a dock entry (iframe pointing at the pre-built SPA), hosts the
516
+ * SPA's static assets, and wires up the type-safe RPC + sharedState used by
517
+ * the SPA. This replaces the previous Hono-middleware-based transport with
518
+ * the Vite DevTools Kit (DTK) birpc + shared-state machinery.
519
+ */
520
+ declare function ubeanDevtoolsPlugin(options?: UbeanDevtoolsPluginOptions): Plugin;
521
+ //#endregion
522
+ //#region src/node/rpc/index.d.ts
523
+ interface RpcDeps {
524
+ state: SharedState<DevToolsInfo>;
525
+ getEnvData: () => Record<string, string>;
526
+ crud: DevToolsCrudServer;
527
+ ai: DevToolsAiServer;
528
+ terminal: TerminalServer;
529
+ getApp?: () => {
530
+ fetch: (req: Request) => Response | Promise<Response>;
531
+ } | undefined;
532
+ }
533
+ /**
534
+ * Returns an array of `defineRpcFunction` definitions. The return type is
535
+ * intentionally loose (`any[]`) because the DTK `ctx.rpc.register()` accepts
536
+ * definitions parameterized on `ViteDevToolsNodeContext`, and the exact
537
+ * generic instantiation varies per function — the individual functions are
538
+ * already type-checked at their definition site.
539
+ */
540
+ declare function createAllRpcFunctions(deps: RpcDeps): any[];
541
+ //#endregion
542
+ //#region src/define-tab.d.ts
543
+ /**
544
+ * Custom DevTools tab registration API.
545
+ *
546
+ * Migrated from `packages/ubean/src/core/devtools/define-tab.ts` during
547
+ * Phase 7 aggregator switch. Provides a global registry for user-defined
548
+ * DevTools tabs that are surfaced in the DevTools SPA via `DevToolsInfo.customTabs`.
549
+ */
550
+ interface DevToolsTabDefinition {
551
+ id: string;
552
+ label: string;
553
+ icon?: string;
554
+ src: string;
555
+ sandbox?: string[];
556
+ }
557
+ declare function defineDevToolsTab(tab: DevToolsTabDefinition): DevToolsTabDefinition;
558
+ declare function getCustomTabs(): DevToolsTabDefinition[];
559
+ declare function clearCustomTabs(): void;
560
+ //#endregion
561
+ export { type AiChatMessage, AiChatParams, type AiChatResponse, type AiToolDefinition, CreateCrudParams, CrudHookContext, CrudHookHandler, CrudHookType, CrudReadResult, CrudResourceType, CrudResult, DeleteCrudParams, type DevToolsAiServer, type DevToolsConfigMeta, DevToolsCronInfo, type DevToolsCrudServer, DevToolsCustomTab, DevToolsFsOps, type DevToolsHooks, type DevToolsHooksInstance, DevToolsInfo, DevToolsLayoutInfo, DevToolsMiddlewareInfo, DevToolsOptions, DevToolsPageInfo, DevToolsRouteInfo, DevToolsScaffoldOps, DevToolsScaffoldType, DevToolsServer, DevToolsTab, type DevToolsTabDefinition, ReadCrudParams, RpcHandler, RpcRequest, RpcResponse, ScaffoldOptions, ScaffoldResult, type ScanResultLike, type TerminalPollResult, type TerminalServer, type TerminalStartParams, UBEAN_INFO_STATE_KEY, type UbeanDevtoolsPluginOptions, UpdateCrudParams, type ViteDevToolsNodeContext, buildDevToolsInfo, clearCustomTabs, createAiServer, createAllRpcFunctions, createCrudServer, createDevToolsHooks, createTerminalServer, defineDevToolsTab, defineRpcFunction, emptyDevToolsInfo, getCustomTabs, maskSensitiveEnv, ubeanDevtoolsPlugin };