@databricks/appkit-ui 0.23.0 → 0.24.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/CLAUDE.md +1 -0
- package/dist/cli/commands/docs.js +7 -1
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/generate-types.js +20 -10
- package/dist/cli/commands/generate-types.js.map +1 -1
- package/dist/cli/commands/lint.js +3 -1
- package/dist/cli/commands/lint.js.map +1 -1
- package/dist/cli/commands/plugin/add-resource/add-resource.js +73 -8
- package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
- package/dist/cli/commands/plugin/create/create.js +164 -20
- package/dist/cli/commands/plugin/create/create.js.map +1 -1
- package/dist/cli/commands/plugin/create/resource-defaults.js +5 -1
- package/dist/cli/commands/plugin/create/resource-defaults.js.map +1 -1
- package/dist/cli/commands/plugin/index.js +7 -1
- package/dist/cli/commands/plugin/index.js.map +1 -1
- package/dist/cli/commands/plugin/list/list.js +7 -1
- package/dist/cli/commands/plugin/list/list.js.map +1 -1
- package/dist/cli/commands/plugin/sync/sync.js +27 -14
- package/dist/cli/commands/plugin/sync/sync.js.map +1 -1
- package/dist/cli/commands/plugin/validate/validate.js +39 -9
- package/dist/cli/commands/plugin/validate/validate.js.map +1 -1
- package/dist/cli/commands/setup.js +6 -5
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/react/hooks/types.d.ts +1 -1
- package/docs/api/appkit/TypeAlias.ServingFactory.md +9 -5
- package/docs/development/type-generation.md +6 -5
- package/docs/plugins/analytics.md +1 -1
- package/docs/plugins/custom-plugins.md +4 -0
- package/docs/plugins/plugin-management.md +22 -6
- package/docs/plugins/vector-search.md +247 -0
- package/llms.txt +1 -0
- package/package.json +1 -1
- package/sbom.cdx.json +1 -1
|
@@ -47,35 +47,65 @@ function resolveManifestPaths(paths, cwd, allowJsManifest) {
|
|
|
47
47
|
async function runPluginValidate(paths, options) {
|
|
48
48
|
const cwd = process.cwd();
|
|
49
49
|
const allowJsManifest = Boolean(options.allowJsManifest);
|
|
50
|
-
if (allowJsManifest) console.warn("Warning: --allow-js-manifest executes manifest.js/manifest.cjs files. Only use with trusted code.");
|
|
50
|
+
if (allowJsManifest && !options.json) console.warn("Warning: --allow-js-manifest executes manifest.js/manifest.cjs files. Only use with trusted code.");
|
|
51
51
|
const manifestPaths = resolveManifestPaths(paths.length > 0 ? paths : ["."], cwd, allowJsManifest);
|
|
52
52
|
if (manifestPaths.length === 0) {
|
|
53
|
-
console.
|
|
53
|
+
if (options.json) console.log("[]");
|
|
54
|
+
else console.error("No manifest files to validate.");
|
|
54
55
|
process.exit(1);
|
|
55
56
|
}
|
|
56
57
|
let hasFailure = false;
|
|
58
|
+
const jsonResults = [];
|
|
57
59
|
for (const { path: manifestPath, type } of manifestPaths) {
|
|
60
|
+
const relativePath = path.relative(cwd, manifestPath);
|
|
58
61
|
let obj;
|
|
59
62
|
try {
|
|
60
63
|
obj = await loadManifestFromFile(manifestPath, type, { allowJsManifest });
|
|
61
64
|
} catch (err) {
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
66
|
+
if (options.json) jsonResults.push({
|
|
67
|
+
path: relativePath,
|
|
68
|
+
valid: false,
|
|
69
|
+
errors: [errMsg]
|
|
70
|
+
});
|
|
71
|
+
else {
|
|
72
|
+
console.error(`✗ ${manifestPath}`);
|
|
73
|
+
console.error(` ${errMsg}`);
|
|
74
|
+
}
|
|
64
75
|
hasFailure = true;
|
|
65
76
|
continue;
|
|
66
77
|
}
|
|
67
78
|
const result = detectSchemaType(obj) === "template-plugins" ? validateTemplateManifest(obj) : validateManifest(obj);
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
if (result.valid) if (options.json) jsonResults.push({
|
|
80
|
+
path: relativePath,
|
|
81
|
+
valid: true
|
|
82
|
+
});
|
|
83
|
+
else console.log(`✓ ${relativePath}`);
|
|
70
84
|
else {
|
|
71
|
-
|
|
72
|
-
|
|
85
|
+
if (options.json) {
|
|
86
|
+
const errors = result.errors?.length ? formatValidationErrors(result.errors, obj).split("\n").filter(Boolean) : [];
|
|
87
|
+
jsonResults.push({
|
|
88
|
+
path: relativePath,
|
|
89
|
+
valid: false,
|
|
90
|
+
...errors.length > 0 && { errors }
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
console.error(`✗ ${relativePath}`);
|
|
94
|
+
if (result.errors?.length) console.error(formatValidationErrors(result.errors, obj));
|
|
95
|
+
}
|
|
73
96
|
hasFailure = true;
|
|
74
97
|
}
|
|
75
98
|
}
|
|
99
|
+
if (options.json) console.log(JSON.stringify(jsonResults, null, 2));
|
|
76
100
|
process.exit(hasFailure ? 1 : 0);
|
|
77
101
|
}
|
|
78
|
-
const pluginValidateCommand = new Command("validate").description("Validate plugin manifest(s) or template manifests against their JSON schema").argument("[paths...]", "Paths to manifest.json or appkit.plugins.json (or plugin directories); use --allow-js-manifest to include manifest.js").option("--allow-js-manifest", "Allow reading manifest.js/manifest.cjs (executes code; use only with trusted plugins)").
|
|
102
|
+
const pluginValidateCommand = new Command("validate").description("Validate plugin manifest(s) or template manifests against their JSON schema").argument("[paths...]", "Paths to manifest.json or appkit.plugins.json (or plugin directories); use --allow-js-manifest to include manifest.js").option("--allow-js-manifest", "Allow reading manifest.js/manifest.cjs (executes code; use only with trusted plugins)").option("--json", "Output validation results as JSON").addHelpText("after", `
|
|
103
|
+
Examples:
|
|
104
|
+
$ appkit plugin validate
|
|
105
|
+
$ appkit plugin validate plugins/my-plugin
|
|
106
|
+
$ appkit plugin validate plugins/my-plugin plugins/other
|
|
107
|
+
$ appkit plugin validate appkit.plugins.json
|
|
108
|
+
$ appkit plugin validate --json`).action((paths, opts) => runPluginValidate(paths, opts).catch((err) => {
|
|
79
109
|
console.error(err);
|
|
80
110
|
process.exit(1);
|
|
81
111
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","names":[],"sources":["../../../../../src/cli/commands/plugin/validate/validate.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport process from \"node:process\";\nimport { Command } from \"commander\";\nimport {\n loadManifestFromFile,\n type ResolvedManifest,\n resolveManifestInDir,\n} from \"../manifest-resolve\";\nimport {\n detectSchemaType,\n formatValidationErrors,\n validateManifest,\n validateTemplateManifest,\n} from \"./validate-manifest\";\n\nfunction resolveManifestPaths(\n paths: string[],\n cwd: string,\n allowJsManifest: boolean,\n): ResolvedManifest[] {\n const out: ResolvedManifest[] = [];\n for (const p of paths) {\n const resolved = path.resolve(cwd, p);\n if (!fs.existsSync(resolved)) {\n console.error(`Path not found: ${p}`);\n continue;\n }\n const stat = fs.statSync(resolved);\n if (stat.isDirectory()) {\n let found = false;\n const pluginResolved = resolveManifestInDir(resolved, {\n allowJsManifest,\n });\n if (pluginResolved) {\n out.push(pluginResolved);\n found = true;\n }\n const templateManifest = path.join(resolved, \"appkit.plugins.json\");\n if (fs.existsSync(templateManifest)) {\n out.push({ path: templateManifest, type: \"json\" });\n found = true;\n }\n if (!found) {\n console.error(\n `No ${allowJsManifest ? \"manifest.json, manifest.js, or\" : \"manifest.json or\"} appkit.plugins.json in directory: ${p}`,\n );\n }\n } else {\n const ext = path.extname(resolved).toLowerCase();\n if (!allowJsManifest && (ext === \".js\" || ext === \".cjs\")) {\n console.error(\n `JS manifest provided but disabled by default: ${p}. Re-run with --allow-js-manifest to opt in.`,\n );\n continue;\n }\n out.push({\n path: resolved,\n type: ext === \".js\" || ext === \".cjs\" ? \"js\" : \"json\",\n });\n }\n }\n return out;\n}\n\nasync function runPluginValidate(\n paths: string[],\n options:
|
|
1
|
+
{"version":3,"file":"validate.js","names":[],"sources":["../../../../../src/cli/commands/plugin/validate/validate.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport process from \"node:process\";\nimport { Command } from \"commander\";\nimport {\n loadManifestFromFile,\n type ResolvedManifest,\n resolveManifestInDir,\n} from \"../manifest-resolve\";\nimport {\n detectSchemaType,\n formatValidationErrors,\n validateManifest,\n validateTemplateManifest,\n} from \"./validate-manifest\";\n\nfunction resolveManifestPaths(\n paths: string[],\n cwd: string,\n allowJsManifest: boolean,\n): ResolvedManifest[] {\n const out: ResolvedManifest[] = [];\n for (const p of paths) {\n const resolved = path.resolve(cwd, p);\n if (!fs.existsSync(resolved)) {\n console.error(`Path not found: ${p}`);\n continue;\n }\n const stat = fs.statSync(resolved);\n if (stat.isDirectory()) {\n let found = false;\n const pluginResolved = resolveManifestInDir(resolved, {\n allowJsManifest,\n });\n if (pluginResolved) {\n out.push(pluginResolved);\n found = true;\n }\n const templateManifest = path.join(resolved, \"appkit.plugins.json\");\n if (fs.existsSync(templateManifest)) {\n out.push({ path: templateManifest, type: \"json\" });\n found = true;\n }\n if (!found) {\n console.error(\n `No ${allowJsManifest ? \"manifest.json, manifest.js, or\" : \"manifest.json or\"} appkit.plugins.json in directory: ${p}`,\n );\n }\n } else {\n const ext = path.extname(resolved).toLowerCase();\n if (!allowJsManifest && (ext === \".js\" || ext === \".cjs\")) {\n console.error(\n `JS manifest provided but disabled by default: ${p}. Re-run with --allow-js-manifest to opt in.`,\n );\n continue;\n }\n out.push({\n path: resolved,\n type: ext === \".js\" || ext === \".cjs\" ? \"js\" : \"json\",\n });\n }\n }\n return out;\n}\n\ninterface ValidateOptions {\n allowJsManifest?: boolean;\n json?: boolean;\n}\n\nasync function runPluginValidate(\n paths: string[],\n options: ValidateOptions,\n): Promise<void> {\n const cwd = process.cwd();\n const allowJsManifest = Boolean(options.allowJsManifest);\n if (allowJsManifest && !options.json) {\n console.warn(\n \"Warning: --allow-js-manifest executes manifest.js/manifest.cjs files. Only use with trusted code.\",\n );\n }\n const toValidate = paths.length > 0 ? paths : [\".\"];\n const manifestPaths = resolveManifestPaths(toValidate, cwd, allowJsManifest);\n\n if (manifestPaths.length === 0) {\n if (options.json) {\n console.log(\"[]\");\n } else {\n console.error(\"No manifest files to validate.\");\n }\n process.exit(1);\n }\n\n let hasFailure = false;\n const jsonResults: { path: string; valid: boolean; errors?: string[] }[] = [];\n\n for (const { path: manifestPath, type } of manifestPaths) {\n const relativePath = path.relative(cwd, manifestPath);\n let obj: unknown;\n try {\n obj = await loadManifestFromFile(manifestPath, type, { allowJsManifest });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n if (options.json) {\n jsonResults.push({\n path: relativePath,\n valid: false,\n errors: [errMsg],\n });\n } else {\n console.error(`✗ ${manifestPath}`);\n console.error(` ${errMsg}`);\n }\n hasFailure = true;\n continue;\n }\n\n const schemaType = detectSchemaType(obj);\n const result =\n schemaType === \"template-plugins\"\n ? validateTemplateManifest(obj)\n : validateManifest(obj);\n\n if (result.valid) {\n if (options.json) {\n jsonResults.push({ path: relativePath, valid: true });\n } else {\n console.log(`✓ ${relativePath}`);\n }\n } else {\n if (options.json) {\n const errors = result.errors?.length\n ? formatValidationErrors(result.errors, obj)\n .split(\"\\n\")\n .filter(Boolean)\n : [];\n jsonResults.push({\n path: relativePath,\n valid: false,\n ...(errors.length > 0 && { errors }),\n });\n } else {\n console.error(`✗ ${relativePath}`);\n if (result.errors?.length) {\n console.error(formatValidationErrors(result.errors, obj));\n }\n }\n hasFailure = true;\n }\n }\n\n if (options.json) {\n console.log(JSON.stringify(jsonResults, null, 2));\n }\n\n process.exit(hasFailure ? 1 : 0);\n}\n\nexport const pluginValidateCommand = new Command(\"validate\")\n .description(\n \"Validate plugin manifest(s) or template manifests against their JSON schema\",\n )\n .argument(\n \"[paths...]\",\n \"Paths to manifest.json or appkit.plugins.json (or plugin directories); use --allow-js-manifest to include manifest.js\",\n )\n .option(\n \"--allow-js-manifest\",\n \"Allow reading manifest.js/manifest.cjs (executes code; use only with trusted plugins)\",\n )\n .option(\"--json\", \"Output validation results as JSON\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ appkit plugin validate\n $ appkit plugin validate plugins/my-plugin\n $ appkit plugin validate plugins/my-plugin plugins/other\n $ appkit plugin validate appkit.plugins.json\n $ appkit plugin validate --json`,\n )\n .action((paths: string[], opts: ValidateOptions) =>\n runPluginValidate(paths, opts).catch((err) => {\n console.error(err);\n process.exit(1);\n }),\n );\n"],"mappings":"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"}
|
|
@@ -95,10 +95,8 @@ function runSetup(options) {
|
|
|
95
95
|
const installed = findInstalledPackages();
|
|
96
96
|
if (installed.length === 0) {
|
|
97
97
|
console.log("No @databricks/appkit packages found in node_modules.");
|
|
98
|
-
console.log("\
|
|
99
|
-
|
|
100
|
-
console.log(` - ${pkg.name}`);
|
|
101
|
-
});
|
|
98
|
+
console.log("\nInstall at least one of:");
|
|
99
|
+
for (const pkg of PACKAGES) console.log(` npm install ${pkg.name}`);
|
|
102
100
|
process.exit(1);
|
|
103
101
|
}
|
|
104
102
|
console.log("Detected packages:");
|
|
@@ -130,7 +128,10 @@ function runSetup(options) {
|
|
|
130
128
|
console.log("─".repeat(50));
|
|
131
129
|
}
|
|
132
130
|
}
|
|
133
|
-
const setupCommand = new Command("setup").description("Setup CLAUDE.md with AppKit package references").option("-w, --write", "Create or update CLAUDE.md file in current directory").
|
|
131
|
+
const setupCommand = new Command("setup").description("Setup CLAUDE.md with AppKit package references").option("-w, --write", "Create or update CLAUDE.md file in current directory").addHelpText("after", `
|
|
132
|
+
Examples:
|
|
133
|
+
$ appkit setup
|
|
134
|
+
$ appkit setup --write`).action(runSetup);
|
|
134
135
|
|
|
135
136
|
//#endregion
|
|
136
137
|
export { setupCommand };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","names":[],"sources":["../../../src/cli/commands/setup.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\n\nconst PACKAGES = [\n { name: \"@databricks/appkit\", description: \"Backend SDK\" },\n {\n name: \"@databricks/appkit-ui\",\n description: \"UI Integration, Charts, Tables, SSE, and more.\",\n },\n];\n\nconst SECTION_START = \"<!-- appkit-instructions-start -->\";\nconst SECTION_END = \"<!-- appkit-instructions-end -->\";\n\n/**\n * Find which AppKit packages are installed by checking for package.json\n */\nfunction findInstalledPackages() {\n const cwd = process.cwd();\n const installed = [];\n\n for (const pkg of PACKAGES) {\n const packagePath = path.join(\n cwd,\n \"node_modules\",\n pkg.name,\n \"package.json\",\n );\n if (fs.existsSync(packagePath)) {\n installed.push(pkg);\n }\n }\n\n return installed;\n}\n\n/**\n * Generate the AppKit section content\n */\nfunction generateSection(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n\n### Databricks Skills\n\nFor enhanced AI assistance with Databricks CLI operations, authentication, data exploration, and app development, install the Databricks skills:\n\n\\`\\`\\`bash\ndatabricks experimental aitools install\n\\`\\`\\`\n${SECTION_END}`;\n}\n\n/**\n * Generate standalone CLAUDE.md content (when no existing file)\n */\nfunction generateStandalone(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `# AI Assistant Instructions\n\n${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n\n### Databricks Skills\n\nFor enhanced AI assistance with Databricks CLI operations, authentication, data exploration, and app development, install the Databricks skills:\n\n\\`\\`\\`bash\ndatabricks experimental aitools install\n\\`\\`\\`\n${SECTION_END}\n`;\n}\n\n/**\n * Update existing content with AppKit section\n */\nfunction updateContent(existingContent: string, packages: typeof PACKAGES) {\n const newSection = generateSection(packages);\n\n // Check if AppKit section already exists\n const startIndex = existingContent.indexOf(SECTION_START);\n const endIndex = existingContent.indexOf(SECTION_END);\n\n if (startIndex !== -1 && endIndex !== -1) {\n // Replace existing section\n const before = existingContent.substring(0, startIndex);\n const after = existingContent.substring(endIndex + SECTION_END.length);\n return before + newSection + after;\n }\n\n // Append section to end\n return `${existingContent.trimEnd()}\\n\\n${newSection}\\n`;\n}\n\n/**\n * Setup command implementation\n */\nfunction runSetup(options: { write?: boolean }) {\n const shouldWrite = options.write;\n\n // Find installed packages\n const installed = findInstalledPackages();\n\n if (installed.length === 0) {\n console.log(\"No @databricks/appkit packages found in node_modules.\");\n console.log(\"\\
|
|
1
|
+
{"version":3,"file":"setup.js","names":[],"sources":["../../../src/cli/commands/setup.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\n\nconst PACKAGES = [\n { name: \"@databricks/appkit\", description: \"Backend SDK\" },\n {\n name: \"@databricks/appkit-ui\",\n description: \"UI Integration, Charts, Tables, SSE, and more.\",\n },\n];\n\nconst SECTION_START = \"<!-- appkit-instructions-start -->\";\nconst SECTION_END = \"<!-- appkit-instructions-end -->\";\n\n/**\n * Find which AppKit packages are installed by checking for package.json\n */\nfunction findInstalledPackages() {\n const cwd = process.cwd();\n const installed = [];\n\n for (const pkg of PACKAGES) {\n const packagePath = path.join(\n cwd,\n \"node_modules\",\n pkg.name,\n \"package.json\",\n );\n if (fs.existsSync(packagePath)) {\n installed.push(pkg);\n }\n }\n\n return installed;\n}\n\n/**\n * Generate the AppKit section content\n */\nfunction generateSection(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n\n### Databricks Skills\n\nFor enhanced AI assistance with Databricks CLI operations, authentication, data exploration, and app development, install the Databricks skills:\n\n\\`\\`\\`bash\ndatabricks experimental aitools install\n\\`\\`\\`\n${SECTION_END}`;\n}\n\n/**\n * Generate standalone CLAUDE.md content (when no existing file)\n */\nfunction generateStandalone(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `# AI Assistant Instructions\n\n${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n\n### Databricks Skills\n\nFor enhanced AI assistance with Databricks CLI operations, authentication, data exploration, and app development, install the Databricks skills:\n\n\\`\\`\\`bash\ndatabricks experimental aitools install\n\\`\\`\\`\n${SECTION_END}\n`;\n}\n\n/**\n * Update existing content with AppKit section\n */\nfunction updateContent(existingContent: string, packages: typeof PACKAGES) {\n const newSection = generateSection(packages);\n\n // Check if AppKit section already exists\n const startIndex = existingContent.indexOf(SECTION_START);\n const endIndex = existingContent.indexOf(SECTION_END);\n\n if (startIndex !== -1 && endIndex !== -1) {\n // Replace existing section\n const before = existingContent.substring(0, startIndex);\n const after = existingContent.substring(endIndex + SECTION_END.length);\n return before + newSection + after;\n }\n\n // Append section to end\n return `${existingContent.trimEnd()}\\n\\n${newSection}\\n`;\n}\n\n/**\n * Setup command implementation\n */\nfunction runSetup(options: { write?: boolean }) {\n const shouldWrite = options.write;\n\n // Find installed packages\n const installed = findInstalledPackages();\n\n if (installed.length === 0) {\n console.log(\"No @databricks/appkit packages found in node_modules.\");\n console.log(\"\\nInstall at least one of:\");\n for (const pkg of PACKAGES) {\n console.log(` npm install ${pkg.name}`);\n }\n process.exit(1);\n }\n\n console.log(\"Detected packages:\");\n installed.forEach((pkg) => {\n console.log(` ✓ ${pkg.name}`);\n });\n\n const claudePath = path.join(process.cwd(), \"CLAUDE.md\");\n const existingContent = fs.existsSync(claudePath)\n ? fs.readFileSync(claudePath, \"utf-8\")\n : null;\n\n let finalContent: string;\n let action: string;\n\n if (existingContent) {\n finalContent = updateContent(existingContent, installed);\n action = existingContent.includes(SECTION_START) ? \"Updated\" : \"Added to\";\n } else {\n finalContent = generateStandalone(installed);\n action = \"Created\";\n }\n\n if (shouldWrite) {\n fs.writeFileSync(claudePath, finalContent);\n console.log(`\\n✓ ${action} CLAUDE.md`);\n console.log(` Path: ${claudePath}`);\n } else {\n console.log(\"\\nTo create/update CLAUDE.md, run:\");\n console.log(\" npx appkit setup --write\\n\");\n\n if (existingContent) {\n console.log(\n `This will ${\n existingContent.includes(SECTION_START)\n ? \"update the existing\"\n : \"add a new\"\n } AppKit section.\\n`,\n );\n }\n\n console.log(\"Preview of AppKit section:\\n\");\n console.log(\"─\".repeat(50));\n console.log(generateSection(installed));\n console.log(\"─\".repeat(50));\n }\n}\n\nexport const setupCommand = new Command(\"setup\")\n .description(\"Setup CLAUDE.md with AppKit package references\")\n .option(\"-w, --write\", \"Create or update CLAUDE.md file in current directory\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ appkit setup\n $ appkit setup --write`,\n )\n .action(runSetup);\n"],"mappings":"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"}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# Type Alias: ServingFactory
|
|
2
2
|
|
|
3
3
|
```ts
|
|
4
|
-
type ServingFactory = keyof ServingEndpointRegistry extends never ? (alias?: string) => ServingEndpointHandle : <K>(alias: K) => ServingEndpointHandle<ServingEndpointRegistry[K]["request"], ServingEndpointRegistry[K]["response"]
|
|
4
|
+
type ServingFactory = keyof ServingEndpointRegistry extends never ? (alias?: string) => ServingEndpointHandle : true extends IsUnion<keyof ServingEndpointRegistry> ? <K>(alias: K) => ServingEndpointHandle<ServingEndpointRegistry[K]["request"], ServingEndpointRegistry[K]["response"]> : {
|
|
5
|
+
<K> (alias: K): ServingEndpointHandle<ServingEndpointRegistry[K]["request"], ServingEndpointRegistry[K]["response"]>;
|
|
6
|
+
(): ServingEndpointHandle<never, never>;
|
|
7
|
+
};
|
|
5
8
|
|
|
6
9
|
```
|
|
7
10
|
|
|
8
11
|
Factory function returned by `AppKit.serving`.
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
Adapts based on the `ServingEndpointRegistry` state:
|
|
11
14
|
|
|
12
|
-
* **
|
|
13
|
-
* **
|
|
15
|
+
* **Empty (default):** `(alias?: string) => ServingEndpointHandle` — any string, untyped.
|
|
16
|
+
* **Single key:** alias optional — `serving()` returns the typed handle for the only endpoint.
|
|
17
|
+
* **Multiple keys:** alias required — must specify which endpoint.
|
|
14
18
|
|
|
15
|
-
Run `
|
|
19
|
+
Run `npx appkit generate-types` or start the dev server to generate the registry.
|
|
@@ -4,7 +4,9 @@ AppKit can automatically generate TypeScript types for your SQL queries, providi
|
|
|
4
4
|
|
|
5
5
|
## Goal[](#goal "Direct link to Goal")
|
|
6
6
|
|
|
7
|
-
Generate
|
|
7
|
+
Generate type-safe TypeScript declarations for query keys, parameters, and result rows.
|
|
8
|
+
|
|
9
|
+
All generated files live in `shared/appkit-types/`, one per plugin (e.g. `analytics.d.ts`). They use [`declare module`](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) to augment existing interfaces, so the types apply globally — you never need to import them. TypeScript auto-discovers them through `"include": ["shared/appkit-types"]` in your tsconfig.
|
|
8
10
|
|
|
9
11
|
## Vite plugin: `appKitTypesPlugin`[](#vite-plugin-appkittypesplugin "Direct link to vite-plugin-appkittypesplugin")
|
|
10
12
|
|
|
@@ -12,7 +14,7 @@ The recommended approach is to use the Vite plugin, which watches your SQL files
|
|
|
12
14
|
|
|
13
15
|
### Configuration[](#configuration "Direct link to Configuration")
|
|
14
16
|
|
|
15
|
-
* `outFile?: string` - Output file path (default: `
|
|
17
|
+
* `outFile?: string` - Output file path (default: `shared/appkit-types/analytics.d.ts`)
|
|
16
18
|
* `watchFolders?: string[]` - Folders to watch for SQL files (default: `["../config/queries"]`)
|
|
17
19
|
|
|
18
20
|
### Example[](#example "Direct link to Example")
|
|
@@ -27,7 +29,6 @@ export default defineConfig({
|
|
|
27
29
|
plugins: [
|
|
28
30
|
react(),
|
|
29
31
|
appKitTypesPlugin({
|
|
30
|
-
outFile: "src/appKitTypes.d.ts",
|
|
31
32
|
watchFolders: ["../config/queries"],
|
|
32
33
|
}),
|
|
33
34
|
],
|
|
@@ -54,14 +55,14 @@ npx @databricks/appkit generate-types [rootDir] [outFile] [warehouseId]
|
|
|
54
55
|
* Generate types using warehouse ID from environment
|
|
55
56
|
|
|
56
57
|
```bash
|
|
57
|
-
npx @databricks/appkit generate-types .
|
|
58
|
+
npx @databricks/appkit generate-types . shared/appkit-types/analytics.d.ts
|
|
58
59
|
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
* Generate types using warehouse ID explicitly
|
|
62
63
|
|
|
63
64
|
```bash
|
|
64
|
-
npx @databricks/appkit generate-types .
|
|
65
|
+
npx @databricks/appkit generate-types . shared/appkit-types/analytics.d.ts abc123...
|
|
65
66
|
|
|
66
67
|
```
|
|
67
68
|
|
|
@@ -139,7 +139,7 @@ function SpendTable() {
|
|
|
139
139
|
Augment the `QueryRegistry` interface to get full type inference on parameters and results:
|
|
140
140
|
|
|
141
141
|
```ts
|
|
142
|
-
//
|
|
142
|
+
// shared/appkit-types/analytics.d.ts
|
|
143
143
|
declare module "@databricks/appkit-ui/react" {
|
|
144
144
|
interface QueryRegistry {
|
|
145
145
|
spend_summary: {
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
If you need custom API routes or background logic, implement an AppKit plugin. The fastest way is to use the CLI:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
+
# Interactive
|
|
6
7
|
npx @databricks/appkit plugin create
|
|
7
8
|
|
|
9
|
+
# Non-interactive
|
|
10
|
+
npx @databricks/appkit plugin create --placement in-repo --path plugins/my-plugin --name my-plugin --description "My plugin" --force
|
|
11
|
+
|
|
8
12
|
```
|
|
9
13
|
|
|
10
14
|
For a deeper understanding of the plugin structure, read on.
|
|
@@ -6,19 +6,30 @@ AppKit includes a CLI for managing plugins. All commands are available under `np
|
|
|
6
6
|
|
|
7
7
|
## Create a plugin[](#create-a-plugin "Direct link to Create a plugin")
|
|
8
8
|
|
|
9
|
-
Scaffold a new plugin interactively:
|
|
9
|
+
Scaffold a new plugin interactively or via flags:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
+
# Interactive mode (prompts for all options)
|
|
12
13
|
npx @databricks/appkit plugin create
|
|
13
14
|
|
|
15
|
+
# Non-interactive mode (all required flags provided)
|
|
16
|
+
npx @databricks/appkit plugin create \
|
|
17
|
+
--placement in-repo \
|
|
18
|
+
--path plugins/my-plugin \
|
|
19
|
+
--name my-plugin \
|
|
20
|
+
--description "My custom plugin" \
|
|
21
|
+
--resources sql_warehouse \
|
|
22
|
+
--force
|
|
23
|
+
|
|
14
24
|
```
|
|
15
25
|
|
|
16
|
-
|
|
26
|
+
In interactive mode, the wizard walks you through:
|
|
17
27
|
|
|
18
28
|
* **Placement**: In your repository (e.g. `plugins/my-plugin`) or as a standalone package
|
|
19
29
|
* **Metadata**: Name, display name, description
|
|
20
30
|
* **Resources**: Which Databricks resources the plugin needs (SQL Warehouse, Secret, etc.) and whether each is required or optional
|
|
21
|
-
|
|
31
|
+
|
|
32
|
+
In non-interactive mode, `--placement`, `--path`, `--name`, and `--description` are required. Resources can be specified as a comma-separated list (`--resources sql_warehouse,volume`) or as JSON for full control (`--resources-json '[{"type":"sql_warehouse","permission":"CAN_MANAGE"}]'`). For all available options, run `npx @databricks/appkit plugin create --help`.
|
|
22
33
|
|
|
23
34
|
The command generates a complete plugin scaffold with `manifest.json` and a TypeScript plugin class that imports the manifest directly — ready to register in your app.
|
|
24
35
|
|
|
@@ -91,12 +102,17 @@ npx @databricks/appkit plugin list --json
|
|
|
91
102
|
|
|
92
103
|
## Add a resource to a plugin[](#add-a-resource-to-a-plugin "Direct link to Add a resource to a plugin")
|
|
93
104
|
|
|
94
|
-
|
|
105
|
+
Add a new resource requirement to an existing plugin manifest. **Requires `manifest.json`** in the plugin directory (the command edits it in place; it does not modify `manifest.js`):
|
|
95
106
|
|
|
96
107
|
```bash
|
|
108
|
+
# Interactive mode
|
|
97
109
|
npx @databricks/appkit plugin add-resource
|
|
98
|
-
|
|
99
|
-
# Or specify the plugin directory
|
|
100
110
|
npx @databricks/appkit plugin add-resource --path plugins/my-plugin
|
|
101
111
|
|
|
112
|
+
# Non-interactive mode (--type triggers flag-based mode)
|
|
113
|
+
npx @databricks/appkit plugin add-resource --path plugins/my-plugin --type sql_warehouse
|
|
114
|
+
npx @databricks/appkit plugin add-resource --path plugins/my-plugin --type volume --no-required --dry-run
|
|
115
|
+
|
|
102
116
|
```
|
|
117
|
+
|
|
118
|
+
In non-interactive mode, only `--type` is required — all other fields (permission, resource key, field env vars) default to sensible values from the schema. Use `--dry-run` to preview the updated manifest without writing. For all available options, run `npx @databricks/appkit plugin add-resource --help`.
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Vector Search plugin
|
|
2
|
+
|
|
3
|
+
Query Databricks Vector Search indexes with hybrid search, reranking, and cursor pagination from your AppKit application.
|
|
4
|
+
|
|
5
|
+
**Key features:**
|
|
6
|
+
|
|
7
|
+
* Named index aliases for multiple Vector Search indexes
|
|
8
|
+
* Hybrid, ANN, and full-text query modes
|
|
9
|
+
* Optional reranking with column-level control
|
|
10
|
+
* Cursor-based pagination for large result sets
|
|
11
|
+
* Service principal (default) and on-behalf-of-user auth
|
|
12
|
+
* Self-managed embedding indexes via custom `embeddingFn`
|
|
13
|
+
|
|
14
|
+
## Basic usage[](#basic-usage "Direct link to Basic usage")
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { createApp, vectorSearch, server } from "@databricks/appkit";
|
|
18
|
+
|
|
19
|
+
await createApp({
|
|
20
|
+
plugins: [
|
|
21
|
+
server(),
|
|
22
|
+
vectorSearch({
|
|
23
|
+
indexes: {
|
|
24
|
+
products: {
|
|
25
|
+
indexName: "catalog.schema.products_idx",
|
|
26
|
+
columns: ["id", "name", "description"],
|
|
27
|
+
queryType: "hybrid",
|
|
28
|
+
numResults: 20,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
}),
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Configuration options[](#configuration-options "Direct link to Configuration options")
|
|
38
|
+
|
|
39
|
+
| Option | Type | Default | Description |
|
|
40
|
+
| --------- | ----------------------------- | ------- | -------------------------------------------------------- |
|
|
41
|
+
| `indexes` | `Record<string, IndexConfig>` | — | **Required.** Map of alias names to index configurations |
|
|
42
|
+
| `timeout` | `number` | `30000` | Query timeout in ms |
|
|
43
|
+
|
|
44
|
+
### Index aliases[](#index-aliases "Direct link to Index aliases")
|
|
45
|
+
|
|
46
|
+
Index aliases let you reference multiple Vector Search indexes by name. The alias is used in API routes and programmatic calls:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
vectorSearch({
|
|
50
|
+
indexes: {
|
|
51
|
+
products: {
|
|
52
|
+
indexName: "catalog.schema.products_idx",
|
|
53
|
+
columns: ["id", "name", "description"],
|
|
54
|
+
},
|
|
55
|
+
docs: {
|
|
56
|
+
indexName: "catalog.schema.docs_idx",
|
|
57
|
+
columns: ["id", "title", "content", "url"],
|
|
58
|
+
queryType: "full_text",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## IndexConfig[](#indexconfig "Direct link to IndexConfig")
|
|
66
|
+
|
|
67
|
+
| Field | Type | Default | Description |
|
|
68
|
+
| -------------- | -------------------------------------------- | --------------------- | ------------------------------------------------------------------------------- |
|
|
69
|
+
| `indexName` | `string` | — | **Required.** Three-level Unity Catalog name (`catalog.schema.index`) |
|
|
70
|
+
| `columns` | `string[]` | — | **Required.** Columns to return in query results |
|
|
71
|
+
| `queryType` | `"ann" \| "hybrid" \| "full_text"` | `"hybrid"` | Search mode |
|
|
72
|
+
| `numResults` | `number` | `20` | Maximum results per query |
|
|
73
|
+
| `reranker` | `boolean \| { columnsToRerank: string[] }` | — | Enable reranking. Pass `true` to rerank all result columns, or specify a subset |
|
|
74
|
+
| `auth` | `"service-principal" \| "on-behalf-of-user"` | `"service-principal"` | Authentication mode for query execution |
|
|
75
|
+
| `pagination` | `boolean` | — | Enable cursor-based pagination |
|
|
76
|
+
| `endpointName` | `string` | — | Vector Search endpoint name. Required when `pagination` is `true` |
|
|
77
|
+
| `embeddingFn` | `(text: string) => Promise<number[]>` | — | Custom embedding function for self-managed embedding indexes |
|
|
78
|
+
|
|
79
|
+
### Query types[](#query-types "Direct link to Query types")
|
|
80
|
+
|
|
81
|
+
* **`hybrid`** — Combines vector similarity and keyword search. Best for general-purpose retrieval.
|
|
82
|
+
* **`ann`** — Approximate nearest neighbor search using embeddings only. Best for semantic similarity.
|
|
83
|
+
* **`full_text`** — Keyword-based search with no embedding required.
|
|
84
|
+
|
|
85
|
+
### Reranking[](#reranking "Direct link to Reranking")
|
|
86
|
+
|
|
87
|
+
Reranking improves result relevance by running a second-stage model over the initial candidates:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
vectorSearch({
|
|
91
|
+
indexes: {
|
|
92
|
+
products: {
|
|
93
|
+
indexName: "catalog.schema.products_idx",
|
|
94
|
+
columns: ["id", "name", "description", "category"],
|
|
95
|
+
reranker: { columnsToRerank: ["name", "description"] },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Pass `reranker: true` to rerank across all returned columns.
|
|
103
|
+
|
|
104
|
+
### On-behalf-of-user auth[](#on-behalf-of-user-auth "Direct link to On-behalf-of-user auth")
|
|
105
|
+
|
|
106
|
+
By default, queries run as the app's service principal. Set `auth: "on-behalf-of-user"` to execute queries as the signed-in user instead:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
vectorSearch({
|
|
110
|
+
indexes: {
|
|
111
|
+
documents: {
|
|
112
|
+
indexName: "catalog.schema.documents_idx",
|
|
113
|
+
columns: ["id", "title", "body"],
|
|
114
|
+
auth: "on-behalf-of-user",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Pagination[](#pagination "Direct link to Pagination")
|
|
122
|
+
|
|
123
|
+
Enable cursor pagination to page through large result sets:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
vectorSearch({
|
|
127
|
+
indexes: {
|
|
128
|
+
products: {
|
|
129
|
+
indexName: "catalog.schema.products_idx",
|
|
130
|
+
columns: ["id", "name", "description"],
|
|
131
|
+
pagination: true,
|
|
132
|
+
endpointName: "my-vector-search-endpoint",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`endpointName` is required when `pagination` is `true`. Use the `/:alias/next-page` route to fetch subsequent pages.
|
|
140
|
+
|
|
141
|
+
### Self-managed embedding indexes[](#self-managed-embedding-indexes "Direct link to Self-managed embedding indexes")
|
|
142
|
+
|
|
143
|
+
For indexes that manage their own embeddings, provide an `embeddingFn` that takes a query string and returns a vector:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { embed } from "./my-embedding-client";
|
|
147
|
+
|
|
148
|
+
vectorSearch({
|
|
149
|
+
indexes: {
|
|
150
|
+
products: {
|
|
151
|
+
indexName: "catalog.schema.products_idx",
|
|
152
|
+
columns: ["id", "name", "description"],
|
|
153
|
+
queryType: "ann",
|
|
154
|
+
embeddingFn: (text) => embed(text),
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## HTTP routes[](#http-routes "Direct link to HTTP routes")
|
|
162
|
+
|
|
163
|
+
Routes are mounted at `/api/vector-search`.
|
|
164
|
+
|
|
165
|
+
| Method | Path | Description |
|
|
166
|
+
| ------ | ------------------- | ------------------------------------------------------------ |
|
|
167
|
+
| `POST` | `/:alias/query` | Query an index by alias |
|
|
168
|
+
| `POST` | `/:alias/next-page` | Fetch the next page of results (requires `pagination: true`) |
|
|
169
|
+
| `GET` | `/:alias/config` | Return the resolved config for an index alias |
|
|
170
|
+
|
|
171
|
+
### Query an index[](#query-an-index "Direct link to Query an index")
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
POST /api/vector-search/:alias/query
|
|
175
|
+
Content-Type: application/json
|
|
176
|
+
|
|
177
|
+
{
|
|
178
|
+
"queryText": "machine learning guide",
|
|
179
|
+
"numResults": 10
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Response:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"results": [
|
|
189
|
+
{ "id": "42", "name": "Intro to ML", "description": "..." }
|
|
190
|
+
],
|
|
191
|
+
"nextPageToken": "eyJvZmZzZXQiOjEwfQ=="
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
`nextPageToken` is only present when `pagination` is enabled and more results are available.
|
|
197
|
+
|
|
198
|
+
### Fetch the next page[](#fetch-the-next-page "Direct link to Fetch the next page")
|
|
199
|
+
|
|
200
|
+
```text
|
|
201
|
+
POST /api/vector-search/:alias/next-page
|
|
202
|
+
Content-Type: application/json
|
|
203
|
+
|
|
204
|
+
{
|
|
205
|
+
"queryText": "machine learning guide",
|
|
206
|
+
"pageToken": "eyJvZmZzZXQiOjEwfQ=="
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Get index config[](#get-index-config "Direct link to Get index config")
|
|
212
|
+
|
|
213
|
+
```text
|
|
214
|
+
GET /api/vector-search/:alias/config
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Returns the resolved `IndexConfig` for the alias (excluding `embeddingFn`).
|
|
219
|
+
|
|
220
|
+
## Programmatic access[](#programmatic-access "Direct link to Programmatic access")
|
|
221
|
+
|
|
222
|
+
The plugin exposes a `query` method for server-side use:
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
const AppKit = await createApp({
|
|
226
|
+
plugins: [
|
|
227
|
+
server(),
|
|
228
|
+
vectorSearch({
|
|
229
|
+
indexes: {
|
|
230
|
+
products: {
|
|
231
|
+
indexName: "catalog.schema.products_idx",
|
|
232
|
+
columns: ["id", "name", "description"],
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
}),
|
|
236
|
+
],
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const result = await AppKit.vectorSearch.query("products", {
|
|
240
|
+
queryText: "machine learning guide",
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
console.log(result.results);
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Pass optional overrides as a second argument to `query` to adjust `numResults` or other per-call settings.
|
package/llms.txt
CHANGED
|
@@ -52,6 +52,7 @@ npx @databricks/appkit docs <query>
|
|
|
52
52
|
- [Plugin management](./docs/plugins/plugin-management.md): AppKit includes a CLI for managing plugins. All commands are available under npx @databricks/appkit plugin.
|
|
53
53
|
- [Server plugin](./docs/plugins/server.md): Provides HTTP server capabilities with development and production modes.
|
|
54
54
|
- [Serving plugin](./docs/plugins/serving.md): Provides an authenticated proxy to Databricks Model Serving endpoints, with invoke and streaming support.
|
|
55
|
+
- [Vector Search plugin](./docs/plugins/vector-search.md): Query Databricks Vector Search indexes with hybrid search, reranking, and cursor pagination from your AppKit application.
|
|
55
56
|
|
|
56
57
|
## appkit API reference [collapsed]
|
|
57
58
|
|