Skip to content

Commit 7951237

Browse files
authored
fix: add safe checker on QueryRegistry and use server static path for fe path (#43)
* fix: add safe checker on QueryRegistry and use server static path for d.ts path
1 parent 0d69081 commit 7951237

File tree

10 files changed

+72
-62
lines changed

10 files changed

+72
-62
lines changed

apps/dev-playground/config/appKitTypes.d.ts renamed to apps/dev-playground/client/src/appKitTypes.d.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
// Auto-generated by AppKit - DO NOT EDIT
2-
// Generated at: 2025-11-28T12:10:49.910Z
3-
42
import "@databricks/app-kit-ui/react";
53

64
declare module "@databricks/app-kit-ui/react" {

apps/dev-playground/client/src/routes/analytics.route.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// @ts-nocheck
21
import { useAnalyticsQuery } from "@databricks/app-kit-ui/react";
32
import { createFileRoute, retainSearchParams } from "@tanstack/react-router";
43
import { useMemo, useState } from "react";

apps/dev-playground/client/tsconfig.app.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@
2929
"@/*": ["./src/*"]
3030
}
3131
},
32-
"include": ["src", "../config/**/*.d.ts"]
32+
"include": ["src"]
3333
}

apps/dev-playground/client/tsconfig.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
"compilerOptions": {
88
"baseUrl": ".",
99
"paths": {
10-
"@/*": ["./src/*"],
11-
"@databricks/app-kit-ui": ["../../../packages/app-kit-ui/dist"]
10+
"@/*": ["./src/*"]
1211
}
1312
}
1413
}

packages/app-kit-ui/src/react/hooks/types.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,39 @@ export interface UseAnalyticsQueryResult<T> {
3535
* }
3636
* ```
3737
*/
38-
// biome-ignore lint/suspicious/noEmptyInterface: Required for module augmentation
39-
export interface QueryRegistry {}
38+
export interface QueryRegistry {
39+
[key: string]: any[];
40+
}
41+
42+
/** Gets only literal keys from a registry (excludes index signature) */
43+
export type AugmentedRegistry<T> = keyof {
44+
[K in keyof T as string extends K ? never : K]: T[K];
45+
};
4046

4147
/** Resolves to registry keys if defined, otherwise string */
42-
export type QueryKey = keyof QueryRegistry extends never
48+
export type QueryKey = AugmentedRegistry<QueryRegistry> extends never
4349
? string
44-
: keyof QueryRegistry;
50+
: AugmentedRegistry<QueryRegistry>;
51+
52+
/**
53+
* Infers result type: uses QueryRegistry if key exists, otherwise falls back to explicit type T
54+
*/
55+
export type InferResult<T, K> = K extends AugmentedRegistry<QueryRegistry>
56+
? QueryRegistry[K]
57+
: T;
4558

46-
// biome-ignore lint/suspicious/noEmptyInterface: Required for module augmentation
47-
export interface PluginRegistry {}
59+
export interface PluginRegistry {
60+
[key: string]: Record<string, any>;
61+
}
4862

49-
export type PluginName = keyof PluginRegistry extends never
63+
export type PluginName = AugmentedRegistry<PluginRegistry> extends never
5064
? string
51-
: keyof PluginRegistry;
65+
: AugmentedRegistry<PluginRegistry>;
5266

53-
export type PluginRoutes<P extends PluginName> = P extends keyof PluginRegistry
54-
? keyof PluginRegistry[P]
55-
: string;
67+
export type PluginRoutes<P extends PluginName> =
68+
P extends AugmentedRegistry<PluginRegistry>
69+
? AugmentedRegistry<PluginRegistry[P]>
70+
: string;
5671

5772
export type RouteResponse<
5873
P extends PluginName,

packages/app-kit-ui/src/react/hooks/use-analytics-query.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
22
import { connectSSE } from "@/js";
33
import type {
4+
InferResult,
45
QueryKey,
5-
QueryRegistry,
66
UseAnalyticsQueryOptions,
77
UseAnalyticsQueryResult,
88
} from "./types";
99
import { useQueryHMR } from "./use-query-hmr";
1010

11-
/**
12-
* Infers result type: uses QueryRegistry if key exists, otherwise falls back to explicit type T
13-
*/
14-
type InferResult<T, K> = K extends keyof QueryRegistry ? QueryRegistry[K] : T;
15-
1611
function getDevMode() {
1712
const url = new URL(window.location.href);
1813
const searchParams = url.searchParams;

packages/app-kit/src/core/app-kit.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { existsSync, type FSWatcher, watch } from "node:fs";
22
import path from "node:path";
3-
import type { TelemetryConfig } from "../telemetry";
4-
import { TelemetryManager } from "../telemetry";
53
import type {
64
BasePlugin,
75
InputPluginMap,
@@ -11,7 +9,10 @@ import type {
119
PluginMap,
1210
QuerySchemas,
1311
} from "shared";
12+
import type { TelemetryConfig } from "../telemetry";
13+
import { TelemetryManager } from "../telemetry";
1414
import { generatePluginTypes } from "./type-generator";
15+
1516
export class AppKit<TPlugins extends InputPluginMap> {
1617
private static _instance: AppKit<InputPluginMap> | null = null;
1718
private pluginInstances: Record<string, BasePlugin> = {};
@@ -131,6 +132,10 @@ export class AppKit<TPlugins extends InputPluginMap> {
131132
private _generatePluginTypes(
132133
rawPlugins: PluginData<PluginConstructor, unknown, string>[],
133134
) {
135+
const serverPlugin = rawPlugins.find((p) => p.name === "server");
136+
const staticPath = (serverPlugin?.config as { staticPath?: string })
137+
?.staticPath;
138+
134139
const schemaDir = path.join(process.cwd(), "config/queries");
135140
const querySchemaPath = path.join(schemaDir, "schema.ts");
136141

@@ -152,6 +157,7 @@ export class AppKit<TPlugins extends InputPluginMap> {
152157
generatePluginTypes(
153158
rawPlugins.map((p) => ({ name: p.name })),
154159
querySchemas,
160+
staticPath,
155161
);
156162
};
157163
generate();

packages/app-kit/src/core/type-generator.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import fs from "node:fs";
22
import path from "node:path";
3-
import { routeSchemaRegistry } from "../plugin";
43
import type { QuerySchemas } from "shared";
54
import { createAuxiliaryTypeStore, printNode, zodToTs } from "zod-to-ts";
5+
import { routeSchemaRegistry } from "../plugin";
66

77
interface PluginTypeInfo {
88
name: string;
@@ -20,6 +20,7 @@ function indentType(typeString: string, baseIndent: string): string {
2020
export function generatePluginTypes(
2121
plugins: PluginTypeInfo[],
2222
querySchemas: QuerySchemas,
23+
fePath?: string,
2324
): void {
2425
const auxiliaryTypeStore = createAuxiliaryTypeStore();
2526

@@ -40,11 +41,6 @@ export function generatePluginTypes(
4041
.filter(Boolean)
4142
.join("\n");
4243

43-
const auxiliaryTypes = Array.from(auxiliaryTypeStore.definitions.values())
44-
.map((definition) => printNode(definition.node))
45-
.join("\n");
46-
47-
const auxiliaryPreamble = auxiliaryTypes ? `${auxiliaryTypes}\n\n` : "";
4844
let queryTypes = "";
4945
if (querySchemas && Object.keys(querySchemas).length > 0) {
5046
const queryEntries = Object.entries(querySchemas)
@@ -59,25 +55,27 @@ export function generatePluginTypes(
5955
}
6056

6157
const content = `// Auto-generated by AppKit - DO NOT EDIT
62-
// Generated at: ${new Date().toISOString()}
63-
6458
import "@databricks/app-kit-ui/react";
6559
66-
${auxiliaryPreamble}declare module "@databricks/app-kit-ui/react" {
60+
declare module "@databricks/app-kit-ui/react" {
6761
interface PluginRegistry {
6862
${pluginTypes}
6963
}
7064
${queryTypes}
7165
}
7266
`;
7367

74-
const configDir = path.join(process.cwd(), "config");
75-
if (!fs.existsSync(configDir)) {
76-
fs.mkdirSync(configDir, { recursive: true });
68+
const defaultPath = path.join(process.cwd(), "client", "src");
69+
const clientSrcDir = fePath ? fePath.replace(/dist$/, "src") : defaultPath;
70+
71+
if (!fs.existsSync(clientSrcDir)) {
72+
console.log(
73+
`[AppKit] Client src dir not found: ${clientSrcDir}, skipping type generation`,
74+
);
75+
return;
7776
}
7877

79-
const filePath = path.join(configDir, "appKitTypes.d.ts");
78+
const filePath = path.join(clientSrcDir, "appKitTypes.d.ts");
8079
fs.writeFileSync(filePath, content, "utf-8");
81-
8280
console.log(`[AppKit] Plugin types generated: ${filePath}`);
8381
}

packages/app-kit/src/server/index.ts

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,29 @@
11
import fs from "node:fs";
22
import type { Server as HTTPServer } from "node:http";
33
import path from "node:path";
4-
import { Plugin, toPlugin } from "../plugin";
5-
import type { BasePluginConfig, PluginPhase } from "shared";
6-
import { databricksClientMiddleware, isRemoteServerEnabled } from "../utils";
74
import dotenv from "dotenv";
85
import express from "express";
6+
import type { PluginPhase } from "shared";
7+
import { Plugin, toPlugin } from "../plugin";
8+
import { instrumentations } from "../telemetry";
9+
import { databricksClientMiddleware, isRemoteServerEnabled } from "../utils";
910
import { DevModeManager } from "./dev-mode";
11+
import type { ServerConfig } from "./types";
1012
import { getQueries, getRoutes } from "./utils";
11-
import { instrumentations } from "../telemetry";
1213

1314
dotenv.config({ path: path.resolve(process.cwd(), "./server/.env") });
1415

15-
export interface ServerConfig extends BasePluginConfig {
16-
port?: number;
17-
plugins?: Record<string, Plugin>;
18-
staticPath?: string;
19-
autoStart?: boolean;
20-
host?: string;
21-
watch?: boolean;
22-
}
23-
2416
export class ServerPlugin extends Plugin {
25-
public name = "server" as const;
26-
public envVars = ["DATABRICKS_APP_PORT", "FLASK_RUN_HOST"];
2717
public static DEFAULT_CONFIG = {
2818
autoStart: true,
2919
staticPath: path.resolve(process.cwd(), "client", "dist"),
3020
host: process.env.FLASK_RUN_HOST || "0.0.0.0",
3121
port: Number(process.env.DATABRICKS_APP_PORT) || 8000,
3222
watch: process.env.NODE_ENV === "development",
3323
};
24+
25+
public name = "server" as const;
26+
public envVars = ["DATABRICKS_APP_PORT", "FLASK_RUN_HOST"];
3427
private serverApplication: express.Application;
3528
private server: HTTPServer | null;
3629
private devModeManager?: DevModeManager;
@@ -63,7 +56,7 @@ export class ServerPlugin extends Plugin {
6356
}
6457

6558
shouldAutoStart() {
66-
return this.config.autoStart ?? ServerPlugin.DEFAULT_CONFIG.autoStart;
59+
return this.config.autoStart;
6760
}
6861

6962
isRemoteServingEnabled() {
@@ -99,14 +92,10 @@ export class ServerPlugin extends Plugin {
9992
}
10093

10194
const server = this.serverApplication.listen(
102-
this.config.port || ServerPlugin.DEFAULT_CONFIG.port,
103-
this.config.host || ServerPlugin.DEFAULT_CONFIG.host,
95+
this.config.port ?? ServerPlugin.DEFAULT_CONFIG.port,
96+
this.config.host ?? ServerPlugin.DEFAULT_CONFIG.host,
10497
() => {
105-
console.log(
106-
`Server is running on port ${
107-
this.config.port || ServerPlugin.DEFAULT_CONFIG.port
108-
}`,
109-
);
98+
console.log(`Server is running on port ${this.config.port}`);
11099
if (this.config.staticPath && !this.config.watch) {
111100
console.log(`Serving static files from: ${this.config.staticPath}`);
112101
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import type { BasePluginConfig } from "shared";
2+
import type { Plugin } from "@/plugin";
3+
4+
export interface ServerConfig extends BasePluginConfig {
5+
port?: number;
6+
plugins?: Record<string, Plugin>;
7+
staticPath?: string;
8+
autoStart?: boolean;
9+
host?: string;
10+
watch?: boolean;
11+
}

0 commit comments

Comments
 (0)