diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml new file mode 100644 index 00000000..92ed114b --- /dev/null +++ b/.github/workflows/perf.yml @@ -0,0 +1,42 @@ +name: Performance + +on: + pull_request: + push: + branches: + - main + +permissions: {} + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + perf: + name: Startup time regression check + permissions: + contents: read + runs-on: ubuntu-latest + env: + NODE_OPTIONS: --max-old-space-size=6144 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + with: + node-version: 22.x + + - name: Install + run: npm ci + + - name: Build + run: npm run build + + - name: Install hyperfine + run: sudo apt-get install -y hyperfine + + - name: Run perf check + run: scripts/perf-check diff --git a/NOTICE.txt b/NOTICE.txt index 7519db8c..adf8baa9 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1133,7 +1133,7 @@ THIS SOFTWARE. ------------------------------------------------------------------------ -yaml@2.8.4 +yaml@2.9.0 License: ISC Repository: https://github.com/eemeli/yaml Publisher: Eemeli Aro diff --git a/package.json b/package.json index 5250328a..0effa3ad 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "scripts": { "prepare": "git config core.hooksPath .githooks || true", "build": "node --max-old-space-size=8192 node_modules/typescript/bin/tsc -b", - "postbuild": "node -e \"const {unlinkSync,readdirSync,existsSync}=require('fs'),{join}=require('path'),d='dist/es/apis/schemas';if(existsSync(d))readdirSync(d).filter(f=>/\\.(d\\.ts|d\\.ts\\.map|js\\.map)$/.test(f)).forEach(f=>unlinkSync(join(d,f)))\"", + "postbuild": "node -e \"const {unlinkSync,readdirSync,existsSync}=require('fs'),{join}=require('path'),d='dist/es/apis/schemas';if(existsSync(d))readdirSync(d).filter(f=>/\\.(d\\.ts|d\\.ts\\.map|js\\.map)$/.test(f)).forEach(f=>unlinkSync(join(d,f)))\" && node scripts/create-dist-package-jsons.mjs", "test": "npm run build && npm run test:unit && npm run test:license", "test:unit": "node --max-old-space-size=8192 --import tsx/esm --test --experimental-test-coverage --test-coverage-lines=90 --test-coverage-branches=90 --test-coverage-functions=90 --test-coverage-include='src/**/*.ts' --test-coverage-include='packages/*/src/**/*.ts' --test-coverage-exclude='src/cloud/apis/**' --test-coverage-exclude='src/es/apis.ts' --test-coverage-exclude='src/es/api-manifest.ts' --test-coverage-exclude='src/es/apis/**' --test-coverage-exclude='src/cloud/apis.ts' --test-coverage-exclude='src/cloud/serverless-apis.ts' --test-coverage-exclude='node_modules/**'", "test:lint": "eslint src packages", @@ -84,5 +84,10 @@ "tsx": "4.22.2", "typescript": "6.0.3", "typescript-eslint": "8.59.4" - } + }, + "bundleDependencies": [ + "@elastic/config-resolver", + "@elastic/es-schemas", + "zod" + ] } diff --git a/scripts/build-api-manifest.mjs b/scripts/build-api-manifest.mjs index d856e210..a334e0b8 100644 --- a/scripts/build-api-manifest.mjs +++ b/scripts/build-api-manifest.mjs @@ -13,7 +13,7 @@ const APIS_DIR = join(ROOT, 'src', 'es', 'apis') const OUT = join(ROOT, 'src', 'es', 'api-manifest.ts') const DEF_RE = /^\s*\{\s*$([\s\S]*?)^\s*\},/gm -const FIELD_RE = /^\s*(name|namespace|description|method|path|responseType|bodyFormat):\s*("(?:[^"\\]|\\.)*"|'[^']*'),?\s*$/gm +const FIELD_RE = /^\s*(name|namespace|description):\s*("(?:[^"\\]|\\.)*"|'[^']*'),?\s*$/gm const entries = [] const files = (await readdir(APIS_DIR)).filter(f => f.endsWith('.ts') && f !== 'types.ts') @@ -27,17 +27,12 @@ for (const file of files.sort()) { fields[fm[1]] = JSON.parse(fm[2].replace(/^'(.*)'$/, '"$1"')) } if (!fields.name) continue - const entry = { + entries.push({ name: fields.name, namespace: fields.namespace ?? null, description: fields.description ?? '', - method: fields.method, - path: fields.path, namespaceFile: fileStem, - } - if (fields.responseType) entry.responseType = fields.responseType - if (fields.bodyFormat) entry.bodyFormat = fields.bodyFormat - entries.push(entry) + }) } } @@ -58,10 +53,6 @@ export interface EsApiMeta { readonly name: string readonly namespace: string | null readonly description: string - readonly method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' - readonly path: string - readonly responseType?: 'json' | 'text' - readonly bodyFormat?: 'json' | 'ndjson' /** File stem under src/es/apis/ that holds the full EsApiDefinition. */ readonly namespaceFile: string } diff --git a/scripts/build-kb-manifest.mts b/scripts/build-kb-manifest.mts index 28e5e5cf..923974ee 100644 --- a/scripts/build-kb-manifest.mts +++ b/scripts/build-kb-manifest.mts @@ -11,8 +11,10 @@ function toCamelCase (stem: string): string { } interface Entry { - def: KbApiDefinition - file: string + name: string + namespace: string + description: string + namespaceFile: string } const entries: Entry[] = [] @@ -25,19 +27,15 @@ for (const file of files) { throw new Error(`src/kb/apis/${file} did not export ${exportName}`) } for (const def of defs) { - entries.push({ def, file: stem }) + entries.push({ + name: def.name, + namespace: def.namespace, + description: def.description, + namespaceFile: stem, + }) } } -const manifest = entries.map(({ def, file }) => ({ - name: def.name, - namespace: def.namespace, - description: def.description, - method: def.method, - path: def.path, - namespaceFile: file, -})) - const lines = [ '/*', ' * Copyright Elasticsearch B.V. and contributors', @@ -49,22 +47,18 @@ const lines = [ ' * DO NOT EDIT BY HAND. Regenerate after running the code generator.', ' */', '', - "import type { HttpMethod } from './types.ts'", - '', '/** Cheap metadata for every Kibana API command. No Zod schemas built. */', 'export interface KbApiMeta {', ' readonly name: string', ' readonly namespace: string', ' readonly description: string', - ' readonly method: HttpMethod', - ' readonly path: string', ' /** File stem under src/kb/apis/ that holds the full KbApiDefinition. */', ' readonly namespaceFile: string', '}', '', - 'export const kbApiManifest: readonly KbApiMeta[] = ' + JSON.stringify(manifest, null, 2), + `export const kbApiManifest: readonly KbApiMeta[] = ${JSON.stringify(entries, null, 2)} as const`, '', ] fs.writeFileSync('./src/kb/api-manifest.ts', lines.join('\n')) -console.log(`Wrote manifest with ${manifest.length} entries`) +console.log(`Wrote manifest with ${entries.length} entries`) diff --git a/scripts/create-dist-package-jsons.mjs b/scripts/create-dist-package-jsons.mjs new file mode 100644 index 00000000..2fcee073 --- /dev/null +++ b/scripts/create-dist-package-jsons.mjs @@ -0,0 +1,36 @@ +#!/usr/bin/env node +/* + * Copyright Elasticsearch B.V. and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { writeFileSync, existsSync } from 'node:fs' +import { join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const root = join(fileURLToPath(import.meta.url), '..', '..') +const content = '{"type":"module"}\n' + +// Create package.json in each dist subdirectory to short-circuit Node.js's +// upward package.json walk when resolving module types, saving ENOENT syscalls. +const dirs = [ + 'dist', + 'dist/cloud', + 'dist/completion', + 'dist/completion/completers', + 'dist/completion/shells', + 'dist/config', + 'dist/docs', + 'dist/es', + 'dist/extension', + 'dist/kb', + 'dist/lib', + 'dist/sanitize', + 'dist/status', +] + +for (const dir of dirs) { + const path = join(root, dir, 'package.json') + if (existsSync(join(root, dir))) { + writeFileSync(path, content) + } +} diff --git a/scripts/perf-check b/scripts/perf-check new file mode 100755 index 00000000..99201374 --- /dev/null +++ b/scripts/perf-check @@ -0,0 +1,113 @@ +#!/usr/bin/env node + +/* + * Copyright Elasticsearch B.V. and contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// Benchmark CLI startup time against recorded baselines from PR #400. +// Fails if any command's mean runtime exceeds its baseline by more than 20%. +// +// Usage: scripts/perf-check +// Override warmup/runs for local profiling: +// PERF_WARMUP=5 PERF_RUNS=30 scripts/perf-check + +import { execFileSync } from "node:child_process" +import { mkdtempSync, readFileSync, rmSync } from "node:fs" +import { tmpdir } from "node:os" +import { join, dirname } from "node:path" +import { fileURLToPath } from "node:url" + +const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..") +const CLI = join(REPO_ROOT, "dist", "cli.js") + +// Tuned for CI: fast enough to finish in ~60 s on a shared runner while still +// producing a stable mean. Override with env vars for local profiling. +const WARMUP = Number(process.env.PERF_WARMUP ?? 3) +const MIN_RUNS = Number(process.env.PERF_RUNS ?? 15) + +// Baselines (mean ms) recorded after the optimisations in PR #400. +// Measured with: hyperfine -w 10 -m 100 +// Hardware: Lenovo ThinkPad X1 Carbon, i7-1365U, 16 GB RAM, Arch Linux +const BASELINES_MS = { + "elastic": 99.0, + "elastic --help": 99.4, + "elastic es --help": 93.3, + "elastic es": 54.0, + "elastic cloud --help": 59.4, + "elastic cloud": 42.4, + "elastic kb --help": 83.7, + "elastic kb": 76.9, +} + + + +const THRESHOLD = 1.40 // fail if mean performance is 40% slower than baseline + +// build the list of full commands to benchmark, one entry per baseline key +const commands = Object.keys(BASELINES_MS).map((label) => { + const args = label.slice("elastic".length).trim() + return args.length > 0 ? `node ${CLI} ${args}` : `node ${CLI}` +}) + +const tmpDir = mkdtempSync(join(tmpdir(), "elastic-cli-bench-")) +const jsonOut = join(tmpDir, "results.json") + +try { + execFileSync( + "hyperfine", + [ + "--warmup", String(WARMUP), + "--min-runs", String(MIN_RUNS), + "--export-json", jsonOut, + "--shell=none", + ...commands, + ], + { stdio: "inherit" }, + ) + + const raw = JSON.parse(readFileSync(jsonOut, "utf8")) + + // hyperfine stores mean in seconds; convert to ms + // normalise the command string back to a BASELINES_MS key by stripping the + // absolute path prefix and collapsing any extra whitespace + const results = raw.results.map((r) => ({ + command: r.command + .replace(/^node\s+.*?dist[/\\]cli\.js/, "elastic") + .replace(/\s+/g, " ") + .trim(), + meanMs: r.mean * 1000, + })) + + let failed = false + + for (const { command, meanMs } of results) { + const baseline = BASELINES_MS[command] + if (baseline == null) { + console.warn(`⚠ No baseline for "${command}" — skipping`) + continue + } + const limit = baseline * THRESHOLD + const pct = ((meanMs / baseline - 1) * 100).toFixed(1) + const sign = meanMs > baseline ? "+" : "" + const ok = meanMs <= limit + const icon = ok ? "✓" : "✗" + console.log( + `${icon} ${command.padEnd(24)} mean ${meanMs.toFixed(1)} ms ` + + `(baseline ${baseline} ms, ${sign}${pct}%, limit ${limit.toFixed(1)} ms)`, + ) + if (!ok) failed = true + } + + if (failed) { + console.error( + "\nPerformance regression detected. " + + "One or more commands exceeded their baseline by more than 20%.", + ) + process.exit(1) + } + + console.log("\nAll commands within the 20% regression threshold.") +} finally { + rmSync(tmpDir, { recursive: true, force: true }) +} diff --git a/src/cli.ts b/src/cli.ts index 45fb2882..642091da 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -5,14 +5,33 @@ */ import { Command } from 'commander' -import { defineCommand, defineGroup, hideBlockedCommands, configureJsonHelp } from './factory.js' -import type { OpaqueCommandHandle } from './factory.js' -import { loadConfig } from './config/loader.ts' +import { createRequire } from 'node:module' +import { hideBlockedCommands, configureJsonHelp, hasGlobalJsonFlag } from './factory-core.js' +import type { OpaqueCommandHandle } from './factory-core.ts' import { BUILT_IN_PROFILES, type BuiltInProfile } from './config/profiles.ts' -import { setResolvedConfig } from './config/store.ts' -import { renderLogo } from './lib/logo.ts' -import { registerCompletionCommands, COMPLETION_COMMAND_NAMES } from './completion/index.ts' import { NAMESPACES } from './namespaces.ts' +import type { LoadConfigResult } from './config/loader.ts' + +// Lazy-loaded modules +const _require = createRequire(import.meta.url) + +let _renderLogo: ((v: string) => string) | null = null +function getRenderLogo (): (v: string) => string { + if (_renderLogo == null) _renderLogo = (_require('./lib/logo.js') as typeof import('./lib/logo.ts')).renderLogo + return _renderLogo +} + +// Argv pre-scan (single pass to detect flags, help, and operands) +const argv = process.argv.slice(2) +let hasGlobalFlags = false +let wantsHelp = false +const operandsFromScan: string[] = [] +for (const arg of argv) { + if (arg === '--help' || arg === '-h') wantsHelp = true + else if (arg.charCodeAt(0) === 45) { // starts with '-' + if (arg.charCodeAt(1) === 45 && arg !== '--json') hasGlobalFlags = true + } else operandsFromScan.push(arg) +} // x-release-please-start-version const VERSION = '0.2.0'; @@ -23,206 +42,249 @@ const program = new Command() program .name('elastic') .description('Interface with the Elastic Stack and Elastic Cloud from the command line.') - .version(VERSION, '-V, --version', 'Print the Elastic CLI version') - .option('--config-file ', 'path to a config file (default: ~/.elasticrc.yml)') - .option('--use-context ', 'override the active context from the config file') - .option(`--command-profile `, `restrict available commands to a deployment profile (${BUILT_IN_PROFILES.join(', ')})`) - .option('--json', 'output as JSON') - .option('--output-fields ', 'comma-separated list of fields to include in output (dot-notation supported)') - .option('--output-template ', 'Mustache-like template for custom text output (e.g. "{{id}}: {{name}}")') - -configureJsonHelp(program) - -// Before every sub-command action, load and resolve the config file. -// On error, print a structured message and exit -- never let a config failure -// silently propagate into the command handler. -// -const skipConfigNames = new Set(NAMESPACES.filter(ns => ns.requiresContext === false).map(ns => ns.name)) - -program.hook('preAction', async (thisCommand, actionCommand) => { - if (actionCommand.name() === 'version') return - // Shell completion commands must not depend on a working config: the user - // installs them before any context exists, and tab-completion errors must - // never poison the shell. They do their own (best-effort) config loading - // inside their handlers when they need context names. - if (COMPLETION_COMMAND_NAMES.includes(actionCommand.name())) return - // `status` loads the config itself so a partially broken config is reported as - // a structured result rather than exiting before any probe runs. - if (actionCommand.name() === 'status') return - // Walk up the command tree — if any ancestor doesn't require context, skip config loading. - for (let c: Command | null = actionCommand; c != null; c = c.parent) { - if (skipConfigNames.has(c.name())) return - } - // `extension` commands manage the extension registry, not the Elastic stack - for (let c = actionCommand.parent; c != null; c = c.parent) { - if (c.name() === 'extension') return - } - const { configFile: configPath, useContext: contextName, commandProfile: profileName } = thisCommand.opts() - const typedProfileName = profileName as BuiltInProfile | undefined - const hasOverrides = configPath != null || contextName != null || profileName != null - - const result = await loadConfig({ - ...(configPath != null && { configPath }), - ...(contextName != null && { contextName }), - ...(typedProfileName != null && { profileName: typedProfileName }), - refresh: hasOverrides, + +// Register global options only when argv actually contains them (common case: it doesn't) +if (hasGlobalFlags) { + program + .option('--config-file ', 'path to a config file (default: ~/.elasticrc.yml)') + .option('--use-context ', 'override the active context from the config file') + .option(`--command-profile `, `restrict available commands to a deployment profile (${BUILT_IN_PROFILES.join(', ')})`) + .option('--output-fields ', 'comma-separated list of fields to include in output (dot-notation supported)') + .option('--output-template ', 'Mustache-like template for custom text output (e.g. "{{id}}: {{name}}")') +} +program.option('--json', 'output as JSON') + +// preAction hook (skipped for --help paths since the hook never fires) +if (!wantsHelp) { + program.hook('preAction', async (thisCommand, actionCommand) => { + const skipActionNames: ReadonlySet = new Set(['version', 'completion', '__complete', 'status']) + if (skipActionNames.has(actionCommand.name())) return + // Groups with no sub-command will just call group.help() — no real action fires. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((actionCommand as any)._isGroup === true && actionCommand.args.length === 0) return + + const skipConfigNames: ReadonlySet = new Set(['docs', 'config', 'sanitize', 'cli-schema']) + for (let c: Command | null = actionCommand; c != null; c = c.parent) { + if (skipConfigNames.has(c.name())) return + } + + for (let c = actionCommand.parent; c != null; c = c.parent) { + if (c.name() === 'extension') return + } + + const { configFile: configPath, useContext: contextName, commandProfile: profileName } = thisCommand.opts() + const typedProfileName = profileName as BuiltInProfile | undefined + const hasOverrides = configPath != null || contextName != null || profileName != null + + const { loadConfig } = await import('./config/loader.js') + const { setResolvedConfig } = await import('./config/store.js') + const result = await loadConfig({ + ...(configPath != null && { configPath }), + ...(contextName != null && { contextName }), + ...(typedProfileName != null && { profileName: typedProfileName }), + refresh: hasOverrides, + }) + if (result.ok) { + setResolvedConfig(result.value) + } else { + process.stderr.write(`Error: ${result.error.message}\n`) + process.exit(1) + } }) - if (result.ok) { - setResolvedConfig(result.value) - } else { - process.stderr.write(`Error: ${result.error.message}\n`) - process.exit(1) - } -}) - -// All sub-commands are defined via the factory and registered here with addCommand(). -// Never use program.command() or new Command() directly for sub-commands -- always go -// through defineCommand() or defineGroup() so cross-cutting concerns are applied uniformly. - -const versionCmd = defineCommand({ - name: 'version', - description: 'Print the elastic CLI version', - handler: () => ({ version: VERSION }) -}) -program.addCommand(versionCmd) - -// Shell completion: `elastic completion ` prints a wrapper script and -// the hidden `__complete` command answers tab-completion callbacks from that -// wrapper. Both are config-free; the preAction hook above skips them. -for (const cmd of registerCompletionCommands()) { - program.addCommand(cmd) -} - -// Lazily load command trees only when the relevant top-level subcommand is actually -// invoked. For all other invocations (including `elastic --help`), a lightweight stub -// is registered so the group appears in help text without paying the cost of loading -// and compiling all API schemas. -const { operands } = program.parseOptions(process.argv.slice(2)) -let firstArg = operands[0] - -// Build a map of shortcut `from` names to the top-level namespace they belong to, -// so argv can be rewritten before Commander parses. -const allShortcuts = NAMESPACES.flatMap(ns => (ns.shortcuts ?? []).map(s => ({ ...s, nsName: ns.name }))) -const shortcutMap = new Map(allShortcuts.map(s => [s.from, s])) - -// Transparent argv rewrite: `elastic es ...` becomes `elastic stack es ...`. -// Done before Commander parses so routing, dot-paths, and option parsing are consistent. -const shortcutMatch = firstArg != null ? shortcutMap.get(firstArg) : undefined -if (shortcutMatch != null) { - const parentNs = shortcutMatch.to[0] +} + +// Determine first argument (namespace routing) +let operands: string[] +let firstArg: string | undefined +if (!hasGlobalFlags) { + operands = operandsFromScan + firstArg = operands[0] +} else { + const parsed = program.parseOptions(argv) + operands = parsed.operands + firstArg = operands[0] +} + +// Shortcut rewriting (e.g. `elastic es ...` to `elastic stack es ...`) +// Derived from NAMESPACES to keep a single canonical list. +const SHORTCUTS: ReadonlyMap = new Map( + NAMESPACES.flatMap(ns => (ns.shortcuts ?? []).map(s => [s.from, s.to] as const)) +) + +const shortcutTarget = firstArg != null ? SHORTCUTS.get(firstArg) : undefined +if (shortcutTarget != null) { + const parentNs = shortcutTarget[0] if (parentNs != null) { - // Scan forward past options and their values to find the first positional arg. - // Simple indexOf would incorrectly match a shortcut name used as an option value - // (e.g. --command-profile es). - const valueOptions = new Set(program.options.filter(o => o.required || o.optional).flatMap(o => [o.long, o.short].filter(Boolean) as string[])) - let idx = 2 - while (idx < process.argv.length) { - const arg = process.argv[idx] - if (arg == null) break - if (arg === firstArg) { process.argv.splice(idx, 0, parentNs); break } - idx++ - if (arg.startsWith('-') && arg.indexOf('=') === -1 && valueOptions.has(arg)) idx++ + if (!hasGlobalFlags) { + process.argv.splice(2, 0, parentNs) + } else { + const isValueOpt = (s: string): boolean => + s === '--config-file' || s === '--use-context' || s === '--command-profile' || + s === '--output-fields' || s === '--output-template' + let idx = 2 + while (idx < process.argv.length) { + const arg = process.argv[idx] + if (arg == null) break + if (arg === firstArg) { process.argv.splice(idx, 0, parentNs); break } + idx++ + if (arg.startsWith('-') && arg.indexOf('=') === -1 && isValueOpt(arg)) idx++ + } } operands.splice(0, 0, parentNs) firstArg = parentNs } } -// Register namespaces: load eagerly when first arg matches, otherwise register a lightweight stub. -// To add a new top-level namespace, add an entry to src/namespaces.ts — no changes needed here. -for (const ns of NAMESPACES) { - if (firstArg === ns.name) { - program.addCommand(await ns.load({ version: VERSION, rootProgram: program })) - } else { - program.addCommand(defineGroup({ name: ns.name, description: ns.description })) - } +// Command registration (lazy: only load the targeted namespace) + +// Version and JSON help only needed for root invocations +if (firstArg == null) { + program.version(VERSION, '-V, --version', 'Print the Elastic CLI version') + configureJsonHelp(program) } -// Register root-level shortcut stubs derived from NAMESPACES so they appear in -// `elastic --help`. Group by `to` path so multiple `from` names for the same -// target become Commander aliases of a single stub rather than separate commands. -// Argv has already been rewritten above so Commander routes correctly. -const stubsByTarget = new Map() -for (const shortcut of allShortcuts) { - const targetKey = shortcut.to.join('.') - const existing = stubsByTarget.get(targetKey) - if (existing == null) { - const description = `Shortcut for 'elastic ${shortcut.to.join(' ')}'` - const stub = defineGroup({ name: shortcut.from, description }) - stubsByTarget.set(targetKey, stub) +// Load the targeted namespace, or register lightweight stubs for --help +const nsMap: ReadonlyMap = new Map(NAMESPACES.map(ns => [ns.name, ns])) + +if (firstArg != null) { + const matchedNs = nsMap.get(firstArg) + if (matchedNs != null) { + const targetSubNamespace = operands[1] + program.addCommand(await matchedNs.load({ version: VERSION, rootProgram: program, targetSubNamespace })) + } +} else { + for (const ns of NAMESPACES) { + const stub = new Command(ns.name) + stub.description(ns.description) + stub.allowUnknownOption(true) program.addCommand(stub) - } else { - existing.alias(shortcut.from) } } +// Completion commands +if (firstArg === 'completion' || firstArg === '__complete') { + const { registerCompletionCommands } = await import('./completion/index.js') + for (const cmd of registerCompletionCommands()) { + program.addCommand(cmd) + } +} else if (firstArg == null) { + const completionStub = new Command('completion') + completionStub.description('Print a shell completion script (bash, zsh, fish)') + completionStub.allowUnknownOption(true) + completionStub.action(async () => { + const { registerCompletionCommands: real } = await import('./completion/index.js') + for (const cmd of real()) { program.addCommand(cmd) } + await program.parseAsync(process.argv) + }) + program.addCommand(completionStub) +} + +// Version command +if (firstArg == null || firstArg === 'version') { + const versionCmd = new Command('version') + versionCmd.description('Print the elastic CLI version') + versionCmd.option('--json', 'Output as JSON') + versionCmd.action(() => { + const json = versionCmd.opts().json === true || hasGlobalJsonFlag(versionCmd) + if (json) { + process.stdout.write(JSON.stringify({ version: VERSION }) + '\n') + } else { + process.stdout.write(`Elastic CLI v${VERSION}\n`) + } + }) + program.addCommand(versionCmd) +} + +// Shortcut stubs (only for root --help display) +if (firstArg == null) { + const stubsByTarget = new Map() + for (const [from, to] of SHORTCUTS) { + const targetKey = to.join('.') + const existing = stubsByTarget.get(targetKey) + if (existing == null) { + const stub = new Command(from) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ;(stub as any).description(`Shortcut for 'elastic ${to.join(' ')}'`) + stubsByTarget.set(targetKey, stub) + program.addCommand(stub) + } else { + existing.alias(from) + } + } +} + +// Extension commands if (firstArg === 'extension') { const { registerExtensionCommands } = await import('./extension/register.ts') program.addCommand(registerExtensionCommands()) -} else { - program.addCommand(defineGroup({ name: 'extension', description: 'Manage elastic CLI extensions' })) +} else if (firstArg == null) { + const stub = new Command('extension') + stub.description('Manage elastic CLI extensions') + stub.allowUnknownOption(true) + program.addCommand(stub) } +// Status command if (firstArg === 'status') { const { registerStatusCommand } = await import('./status/register.ts') program.addCommand(registerStatusCommand()) -} else { - // Stub: a leaf command that appears in --help without paying the import cost. - // The lazy branch above fires whenever `status` is the first arg, so the stub - // handler is never invoked. - program.addCommand(defineCommand({ - name: 'status', - description: 'Verify connectivity and authentication for the active context', - handler: () => '', - })) -} - -// Load config early so --help can hide blocked commands. Skip for commands that don't need -// config (requiresContext: false namespaces, extension, status, version, or completion commands) to -// avoid unnecessary file I/O and a confusing 'no config found' path. -// loadConfig() caches the result in-process; the preAction hook reuses it via the default cache path. -const SKIP_EARLY_CONFIG = new Set([ - 'version', 'extension', 'status', ...COMPLETION_COMMAND_NAMES, ...skipConfigNames, -]) -let earlyConfig: Awaited> | undefined -if (firstArg == null || !SKIP_EARLY_CONFIG.has(firstArg)) { - // Parse --profile early (before Commander's full parse) so the early config load - // and hideBlockedCommands can apply the correct profile-based allow-list to --help. - const profileArgIdx = process.argv.indexOf('--command-profile') - const earlyProfile = profileArgIdx !== -1 ? process.argv[profileArgIdx + 1] as BuiltInProfile | undefined : undefined - - earlyConfig = await loadConfig({ - ...(earlyProfile != null && { profileName: earlyProfile }), - }) - if (earlyConfig.ok) { - setResolvedConfig(earlyConfig.value) - hideBlockedCommands(program, earlyConfig.value.commands) +} else if (firstArg == null) { + const stub = new Command('status') + stub.description('Verify connectivity and authentication for the active context') + program.addCommand(stub) +} + +// Early config load (for --command-profile filtering in help output) +let earlyConfig: LoadConfigResult | undefined +const hasProfileFlag = argv.includes('--command-profile') +const CONTEXT_NAMESPACES = new Set(['stack', 'cloud']) +// skip early config when Commander will just print help — no action will fire. +// operands = [namespace, subcommand?, ...rest]; a sub-subcommand is at operands[2]. +const willJustPrintHelp = CONTEXT_NAMESPACES.has(firstArg ?? '') && operands.length < 3 +if (firstArg != null && (!willJustPrintHelp || hasProfileFlag)) { + const SKIP_EARLY_CONFIG: ReadonlySet = new Set([ + 'version', 'extension', 'status', 'completion', '__complete', + 'docs', 'config', 'sanitize', 'cli-schema', + ]) + if (!SKIP_EARLY_CONFIG.has(firstArg)) { + const profileArgIdx = process.argv.indexOf('--command-profile') + const earlyProfile = profileArgIdx !== -1 ? process.argv[profileArgIdx + 1] as BuiltInProfile | undefined : undefined + + const { loadConfig } = await import('./config/loader.js') + earlyConfig = await loadConfig({ + ...(earlyProfile != null && { profileName: earlyProfile }), + }) + if (earlyConfig.ok) { + const { setResolvedConfig } = await import('./config/store.js') + setResolvedConfig(earlyConfig.value) + hideBlockedCommands(program, earlyConfig.value.commands) + } } } -// Render the banner before --help output too, not just for bare `elastic` (#390). -program.addHelpText('before', () => - process.argv.includes('--json') || (earlyConfig?.ok === true && earlyConfig.value.banner === false) - ? '' : renderLogo(VERSION).replace(/\n$/, '') -) +// Logo banner (root help only) +if (firstArg == null) { + program.addHelpText('before', () => + process.argv.includes('--json') || (earlyConfig?.ok === true && earlyConfig.value.banner === false) + ? '' : getRenderLogo()(VERSION).replace(/\n$/, '') + ) +} -if (process.argv.slice(2).length === 0) { +// Bare invocation: show help +if (argv.length === 0) { program.outputHelp() process.exit(0) } -// If the first argument does not match any built-in command, attempt to -// dispatch to an installed extension named `elastic-`. -// Derived from registered commands so it never goes stale. -const BUILT_IN_COMMANDS = new Set(program.commands.flatMap(c => [c.name()].concat(c.aliases()))) - -if (firstArg != null && !BUILT_IN_COMMANDS.has(firstArg)) { +// Extension dispatch (unrecognized first argument; try installed extension) +if (!wantsHelp && firstArg != null && !program.commands.some(c => c.name() === firstArg)) { const { findExtension } = await import('./extension/store.ts') const ext = await findExtension(firstArg) if (ext != null) { const { buildContextEnv } = await import('./extension/context.ts') const { runExtension } = await import('./extension/runner.ts') - const cachedConfig = await loadConfig() + const { loadConfig: loadCfg } = await import('./config/loader.js') + const cachedConfig = await loadCfg() const contextEnv = cachedConfig?.ok === true ? buildContextEnv(cachedConfig.value) : {} const exitCode = await runExtension(ext, process.argv.slice(3), contextEnv) process.exit(exitCode) diff --git a/src/cloud/constants.ts b/src/cloud/constants.ts new file mode 100644 index 00000000..bcd7895f --- /dev/null +++ b/src/cloud/constants.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Maps internal Cloud API namespace keys to their short CLI display names. + * Namespaces in this map are promoted to direct children of `cloud` (rather + * than nested under `hosted` or `serverless`). + * + * Kept in a separate lightweight module so the lazy register path can import + * it without pulling in allCloudApis / allServerlessApis / Zod schemas. + */ +export const PROMOTED_NAMESPACES: ReadonlyMap = new Map([ + ['accounts', 'trust'], + ['authentication', 'auth'], + ['organizations', 'orgs'], + ['user-role-assignments', 'users'], + ['billing-costs-analysis','billing'], +]) diff --git a/src/cloud/register-lazy.ts b/src/cloud/register-lazy.ts new file mode 100644 index 00000000..93a19556 --- /dev/null +++ b/src/cloud/register-lazy.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Lazy registration path for the `cloud` namespace. + * + * Imports only the minimal set of modules needed to display `elastic cloud + * --help`: commander, the factory group builder, and the lightweight + * PROMOTED_NAMESPACES constant. The full API definition files (allCloudApis, + * allServerlessApis) and Zod schema builders are NOT imported at module + * evaluation time, keeping startup heap bounded. + * + * When the user invokes any actual cloud sub-command, the stub-swap mechanism + * below loads the full command tree on demand. + */ + +import { Command } from 'commander' +import { defineGroup } from '../factory-core.ts' +import type { OpaqueCommandHandle } from '../factory-core.ts' +import { PROMOTED_NAMESPACES } from './constants.ts' + +/** + * Returns a lightweight `cloud` command group whose sub-trees are stub + * `Command` objects. Stubs swap themselves for the real tree on first + * invocation (any action or option processing). + * + * When `targetSubNamespace` is set (forwarded from `cli.ts` via `LoadOptions`), + * the full tree is loaded eagerly so help shows real sub-commands. + */ +export async function registerCloudCommandsLazy (targetSubNamespace?: string): Promise { + if (targetSubNamespace != null) { + const { registerCloudCommands } = await import('./register.js') + return registerCloudCommands() + } + + // Top-level `cloud --help` path: build minimal stubs for the top-level groups. + const STUB_GROUPS: ReadonlyArray<{ name: string; description: string }> = [ + ...Array.from(PROMOTED_NAMESPACES.values()).map(name => ({ + name, + description: `Cloud ${name} commands`, + })), + { name: 'hosted', description: 'Manage Elastic Cloud Hosted deployments' }, + { name: 'serverless', description: 'Manage Elastic Serverless projects and resources' }, + ] + + const cloudGroup = defineGroup( + { name: 'cloud', description: 'Manage Elastic Cloud (hosted deployments and serverless projects)' }, + ) + + for (const stub of STUB_GROUPS) { + const cmd = new Command(stub.name) + cmd.description(stub.description) + cmd.allowUnknownOption(true) + ;(cloudGroup as Command).addCommand(cmd) + } + + return cloudGroup +} diff --git a/src/cloud/register.ts b/src/cloud/register.ts index c79730c7..54148ab4 100644 --- a/src/cloud/register.ts +++ b/src/cloud/register.ts @@ -11,6 +11,7 @@ import type { CloudApiDefinition, CloudPathParam, CloudQueryParam } from './type import { validateCloudApiDefinition } from './types.ts' import { allCloudApis } from './apis.ts' import { allServerlessApis } from './serverless-apis.ts' + import { createCloudHandler, isCreateProjectCommand } from './handler.ts' import { applyCredentialPolicy, @@ -83,13 +84,9 @@ const PROJECT_NAMESPACES: Record = { * apply to both Hosted deployments and Serverless projects. * Values are the display names shown in the CLI tree. */ -const PROMOTED_NAMESPACES = new Map([ - ['accounts', 'trust'], - ['authentication', 'auth'], - ['organizations', 'orgs'], - ['user-role-assignments', 'users'], - ['billing-costs-analysis','billing'], -]) +// PROMOTED_NAMESPACES is defined in ./constants.ts to allow the lazy register +// to import it without pulling in allCloudApis / Zod schemas. +import { PROMOTED_NAMESPACES } from './constants.ts' /** * Serverless namespaces whose commands are merged into a single `cross-project` diff --git a/src/completion/complete.ts b/src/completion/complete.ts index 6a786928..5dfc4612 100644 --- a/src/completion/complete.ts +++ b/src/completion/complete.ts @@ -35,14 +35,8 @@ import type { OpaqueCommandHandle } from '../factory.ts' import { rewriteTopLevelAliases } from './argv-aliases.ts' import { enumerate, DIRECTIVE_NO_FILE_COMP } from './enumerate.ts' import { defaultRegistry } from './registry.ts' -import { - discoverConfigFile, - loadConfigFile, - resolveEffectiveCommands, -} from '../config/loader.ts' import { StructuralConfigSchema, CommandPolicySchema } from '../config/schema.ts' import type { CommandPolicy } from '../config/types.ts' - /** Words recognised as the user-facing form of the `stack es` subtree. */ const ES_ALIASES = new Set(['es', 'elasticsearch']) /** Words recognised as the user-facing form of the `stack kb` subtree. */ @@ -59,6 +53,7 @@ const ENV_CONFIG_FILE = 'ELASTIC_CLI_CONFIG_FILE' * or invalid policy returns `undefined` so shell completion remains best-effort. */ async function loadCompletionCommandPolicy (): Promise { + const { discoverConfigFile, loadConfigFile, resolveEffectiveCommands } = await import('../config/loader.js') const envPath = process.env[ENV_CONFIG_FILE] const path = envPath != null && envPath.length > 0 ? envPath diff --git a/src/completion/completers/context-names.ts b/src/completion/completers/context-names.ts index 4418473d..3a64cd25 100644 --- a/src/completion/completers/context-names.ts +++ b/src/completion/completers/context-names.ts @@ -13,8 +13,6 @@ * Completion MUST NOT propagate errors: missing files, malformed YAML, * permission errors, or unresolved `$(...)` expressions all return `[]`. */ - -import { discoverConfigFile, loadConfigFile } from '../../config/loader.ts' import { StructuralConfigSchema } from '../../config/schema.ts' const ENV_CONFIG_FILE = 'ELASTIC_CLI_CONFIG_FILE' @@ -30,6 +28,7 @@ const ENV_CONFIG_FILE = 'ELASTIC_CLI_CONFIG_FILE' */ export async function completeContextNames (): Promise { try { + const { discoverConfigFile, loadConfigFile } = await import('../../config/loader.js') const envPath = process.env[ENV_CONFIG_FILE] const path = envPath != null && envPath.length > 0 ? envPath diff --git a/src/es/api-manifest.ts b/src/es/api-manifest.ts index ffbcceea..dc72e5a2 100644 --- a/src/es/api-manifest.ts +++ b/src/es/api-manifest.ts @@ -13,10 +13,6 @@ export interface EsApiMeta { readonly name: string readonly namespace: string | null readonly description: string - readonly method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' - readonly path: string - readonly responseType?: 'json' | 'text' - readonly bodyFormat?: 'json' | 'ndjson' /** File stem under src/es/apis/ that holds the full EsApiDefinition. */ readonly namespaceFile: string } @@ -26,4514 +22,3360 @@ export const apiManifest: readonly EsApiMeta[] = [ "name": "delete", "namespace": "async-search", "description": "Delete an async search.", - "method": "DELETE", - "path": "/_async_search/{id}", "namespaceFile": "async_search_delete" }, { "name": "get", "namespace": "async-search", "description": "Get async search results.", - "method": "GET", - "path": "/_async_search/{id}", "namespaceFile": "async_search_get" }, { "name": "status", "namespace": "async-search", "description": "Get the async search status.", - "method": "GET", - "path": "/_async_search/status/{id}", "namespaceFile": "async_search_status" }, { "name": "submit", "namespace": "async-search", "description": "Run an async search.", - "method": "POST", - "path": "/{index}/_async_search", "namespaceFile": "async_search_submit" }, { "name": "bulk", "namespace": null, "description": "Bulk index or delete documents.", - "method": "POST", - "path": "/{index}/_bulk", - "namespaceFile": "bulk", - "bodyFormat": "ndjson" + "namespaceFile": "bulk" }, { "name": "aliases", "namespace": "cat", "description": "Get aliases.", - "method": "GET", - "path": "/_cat/aliases/{name}", - "namespaceFile": "cat_aliases", - "responseType": "text" + "namespaceFile": "cat_aliases" }, { "name": "allocation", "namespace": "cat", "description": "Get shard allocation information.", - "method": "GET", - "path": "/_cat/allocation/{node_id}", - "namespaceFile": "cat_allocation", - "responseType": "text" + "namespaceFile": "cat_allocation" }, { "name": "circuit-breaker", "namespace": "cat", "description": "Get circuit breakers statistics.", - "method": "GET", - "path": "/_cat/circuit_breaker/{circuit_breaker_patterns}", - "namespaceFile": "cat_circuit_breaker", - "responseType": "text" + "namespaceFile": "cat_circuit_breaker" }, { "name": "component-templates", "namespace": "cat", "description": "Get component templates.", - "method": "GET", - "path": "/_cat/component_templates/{name}", - "namespaceFile": "cat_component_templates", - "responseType": "text" + "namespaceFile": "cat_component_templates" }, { "name": "count", "namespace": "cat", "description": "Get a document count.", - "method": "POST", - "path": "/_cat/count/{index}", - "namespaceFile": "cat_count", - "responseType": "text" + "namespaceFile": "cat_count" }, { "name": "fielddata", "namespace": "cat", "description": "Get field data cache information.", - "method": "GET", - "path": "/_cat/fielddata/{fields}", - "namespaceFile": "cat_fielddata", - "responseType": "text" + "namespaceFile": "cat_fielddata" }, { "name": "health", "namespace": "cat", "description": "Get the cluster health status.", - "method": "GET", - "path": "/_cat/health", - "namespaceFile": "cat_health", - "responseType": "text" + "namespaceFile": "cat_health" }, { "name": "help", "namespace": "cat", "description": "Get CAT help.", - "method": "GET", - "path": "/_cat", - "namespaceFile": "cat_help", - "responseType": "text" + "namespaceFile": "cat_help" }, { "name": "indices", "namespace": "cat", "description": "Get index information.", - "method": "GET", - "path": "/_cat/indices/{index}", - "namespaceFile": "cat_indices", - "responseType": "text" + "namespaceFile": "cat_indices" }, { "name": "master", "namespace": "cat", "description": "Get master node information.", - "method": "GET", - "path": "/_cat/master", - "namespaceFile": "cat_master", - "responseType": "text" + "namespaceFile": "cat_master" }, { "name": "ml-data-frame-analytics", "namespace": "cat", "description": "Get data frame analytics jobs.", - "method": "GET", - "path": "/_cat/ml/data_frame/analytics/{id}", - "namespaceFile": "cat_ml_data_frame_analytics", - "responseType": "text" + "namespaceFile": "cat_ml_data_frame_analytics" }, { "name": "ml-datafeeds", "namespace": "cat", "description": "Get datafeeds.", - "method": "GET", - "path": "/_cat/ml/datafeeds/{datafeed_id}", - "namespaceFile": "cat_ml_datafeeds", - "responseType": "text" + "namespaceFile": "cat_ml_datafeeds" }, { "name": "ml-jobs", "namespace": "cat", "description": "Get anomaly detection jobs.", - "method": "GET", - "path": "/_cat/ml/anomaly_detectors/{job_id}", - "namespaceFile": "cat_ml_jobs", - "responseType": "text" + "namespaceFile": "cat_ml_jobs" }, { "name": "ml-trained-models", "namespace": "cat", "description": "Get trained models.", - "method": "GET", - "path": "/_cat/ml/trained_models/{model_id}", - "namespaceFile": "cat_ml_trained_models", - "responseType": "text" + "namespaceFile": "cat_ml_trained_models" }, { "name": "nodeattrs", "namespace": "cat", "description": "Get node attribute information.", - "method": "GET", - "path": "/_cat/nodeattrs", - "namespaceFile": "cat_nodeattrs", - "responseType": "text" + "namespaceFile": "cat_nodeattrs" }, { "name": "nodes", "namespace": "cat", "description": "Get node information.", - "method": "GET", - "path": "/_cat/nodes", - "namespaceFile": "cat_nodes", - "responseType": "text" + "namespaceFile": "cat_nodes" }, { "name": "pending-tasks", "namespace": "cat", "description": "Get pending task information.", - "method": "GET", - "path": "/_cat/pending_tasks", - "namespaceFile": "cat_pending_tasks", - "responseType": "text" + "namespaceFile": "cat_pending_tasks" }, { "name": "plugins", "namespace": "cat", "description": "Get plugin information.", - "method": "GET", - "path": "/_cat/plugins", - "namespaceFile": "cat_plugins", - "responseType": "text" + "namespaceFile": "cat_plugins" }, { "name": "recovery", "namespace": "cat", "description": "Get shard recovery information.", - "method": "GET", - "path": "/_cat/recovery/{index}", - "namespaceFile": "cat_recovery", - "responseType": "text" + "namespaceFile": "cat_recovery" }, { "name": "repositories", "namespace": "cat", "description": "Get snapshot repository information.", - "method": "GET", - "path": "/_cat/repositories", - "namespaceFile": "cat_repositories", - "responseType": "text" + "namespaceFile": "cat_repositories" }, { "name": "segments", "namespace": "cat", "description": "Get segment information.", - "method": "GET", - "path": "/_cat/segments/{index}", - "namespaceFile": "cat_segments", - "responseType": "text" + "namespaceFile": "cat_segments" }, { "name": "shards", "namespace": "cat", "description": "Get shard information.", - "method": "GET", - "path": "/_cat/shards/{index}", - "namespaceFile": "cat_shards", - "responseType": "text" + "namespaceFile": "cat_shards" }, { "name": "snapshots", "namespace": "cat", "description": "Get snapshot information.", - "method": "GET", - "path": "/_cat/snapshots/{repository}", - "namespaceFile": "cat_snapshots", - "responseType": "text" + "namespaceFile": "cat_snapshots" }, { "name": "tasks", "namespace": "cat", "description": "Get task information.", - "method": "GET", - "path": "/_cat/tasks", - "namespaceFile": "cat_tasks", - "responseType": "text" + "namespaceFile": "cat_tasks" }, { "name": "templates", "namespace": "cat", "description": "Get index template information.", - "method": "GET", - "path": "/_cat/templates/{name}", - "namespaceFile": "cat_templates", - "responseType": "text" + "namespaceFile": "cat_templates" }, { "name": "thread-pool", "namespace": "cat", "description": "Get thread pool statistics.", - "method": "GET", - "path": "/_cat/thread_pool/{thread_pool_patterns}", - "namespaceFile": "cat_thread_pool", - "responseType": "text" + "namespaceFile": "cat_thread_pool" }, { "name": "transforms", "namespace": "cat", "description": "Get transform information.", - "method": "GET", - "path": "/_cat/transforms/{transform_id}", - "namespaceFile": "cat_transforms", - "responseType": "text" + "namespaceFile": "cat_transforms" }, { "name": "delete-auto-follow-pattern", "namespace": "ccr", "description": "Delete auto-follow patterns.", - "method": "DELETE", - "path": "/_ccr/auto_follow/{name}", "namespaceFile": "ccr_delete_auto_follow_pattern" }, { "name": "follow", "namespace": "ccr", "description": "Create a follower.", - "method": "PUT", - "path": "/{index}/_ccr/follow", "namespaceFile": "ccr_follow" }, { "name": "follow-info", "namespace": "ccr", "description": "Get follower information.", - "method": "GET", - "path": "/{index}/_ccr/info", "namespaceFile": "ccr_follow_info" }, { "name": "follow-stats", "namespace": "ccr", "description": "Get follower stats.", - "method": "GET", - "path": "/{index}/_ccr/stats", "namespaceFile": "ccr_follow_stats" }, { "name": "forget-follower", "namespace": "ccr", "description": "Forget a follower.", - "method": "POST", - "path": "/{index}/_ccr/forget_follower", "namespaceFile": "ccr_forget_follower" }, { "name": "get-auto-follow-pattern", "namespace": "ccr", "description": "Get auto-follow patterns.", - "method": "GET", - "path": "/_ccr/auto_follow/{name}", "namespaceFile": "ccr_get_auto_follow_pattern" }, { "name": "pause-auto-follow-pattern", "namespace": "ccr", "description": "Pause an auto-follow pattern.", - "method": "POST", - "path": "/_ccr/auto_follow/{name}/pause", "namespaceFile": "ccr_pause_auto_follow_pattern" }, { "name": "pause-follow", "namespace": "ccr", "description": "Pause a follower.", - "method": "POST", - "path": "/{index}/_ccr/pause_follow", "namespaceFile": "ccr_pause_follow" }, { "name": "put-auto-follow-pattern", "namespace": "ccr", "description": "Create or update auto-follow patterns.", - "method": "PUT", - "path": "/_ccr/auto_follow/{name}", "namespaceFile": "ccr_put_auto_follow_pattern" }, { "name": "resume-auto-follow-pattern", "namespace": "ccr", "description": "Resume an auto-follow pattern.", - "method": "POST", - "path": "/_ccr/auto_follow/{name}/resume", "namespaceFile": "ccr_resume_auto_follow_pattern" }, { "name": "resume-follow", "namespace": "ccr", "description": "Resume a follower.", - "method": "POST", - "path": "/{index}/_ccr/resume_follow", "namespaceFile": "ccr_resume_follow" }, { "name": "stats", "namespace": "ccr", "description": "Get cross-cluster replication stats.", - "method": "GET", - "path": "/_ccr/stats", "namespaceFile": "ccr_stats" }, { "name": "unfollow", "namespace": "ccr", "description": "Unfollow an index.", - "method": "POST", - "path": "/{index}/_ccr/unfollow", "namespaceFile": "ccr_unfollow" }, { "name": "clear-scroll", "namespace": null, "description": "Clear a scrolling search.", - "method": "DELETE", - "path": "/_search/scroll", "namespaceFile": "clear_scroll" }, { "name": "close-point-in-time", "namespace": null, "description": "Close a point in time.", - "method": "DELETE", - "path": "/_pit", "namespaceFile": "close_point_in_time" }, { "name": "allocation-explain", "namespace": "cluster", "description": "Explain the shard allocations.", - "method": "GET", - "path": "/_cluster/allocation/explain", "namespaceFile": "cluster_allocation_explain" }, { "name": "delete-component-template", "namespace": "cluster", "description": "Delete component templates.", - "method": "DELETE", - "path": "/_component_template/{name}", "namespaceFile": "cluster_delete_component_template" }, { "name": "delete-voting-config-exclusions", "namespace": "cluster", "description": "Clear cluster voting config exclusions.", - "method": "DELETE", - "path": "/_cluster/voting_config_exclusions", "namespaceFile": "cluster_delete_voting_config_exclusions" }, { "name": "exists-component-template", "namespace": "cluster", "description": "Check component templates.", - "method": "HEAD", - "path": "/_component_template/{name}", "namespaceFile": "cluster_exists_component_template" }, { "name": "get-component-template", "namespace": "cluster", "description": "Get component templates.", - "method": "GET", - "path": "/_component_template/{name}", "namespaceFile": "cluster_get_component_template" }, { "name": "get-settings", "namespace": "cluster", "description": "Get cluster-wide settings.", - "method": "GET", - "path": "/_cluster/settings", "namespaceFile": "cluster_get_settings" }, { "name": "health", "namespace": "cluster", "description": "Get the cluster health status.", - "method": "GET", - "path": "/_cluster/health/{index}", "namespaceFile": "cluster_health" }, { "name": "info", "namespace": "cluster", "description": "Get cluster info.", - "method": "GET", - "path": "/_info/{target}", "namespaceFile": "cluster_info" }, { "name": "pending-tasks", "namespace": "cluster", "description": "Get the pending cluster tasks.", - "method": "GET", - "path": "/_cluster/pending_tasks", "namespaceFile": "cluster_pending_tasks" }, { "name": "post-voting-config-exclusions", "namespace": "cluster", "description": "Update voting configuration exclusions.", - "method": "POST", - "path": "/_cluster/voting_config_exclusions", "namespaceFile": "cluster_post_voting_config_exclusions" }, { "name": "put-component-template", "namespace": "cluster", "description": "Create or update a component template.", - "method": "PUT", - "path": "/_component_template/{name}", "namespaceFile": "cluster_put_component_template" }, { "name": "put-settings", "namespace": "cluster", "description": "Update the cluster settings.", - "method": "PUT", - "path": "/_cluster/settings", "namespaceFile": "cluster_put_settings" }, { "name": "remote-info", "namespace": "cluster", "description": "Get remote cluster information.", - "method": "GET", - "path": "/_remote/info", "namespaceFile": "cluster_remote_info" }, { "name": "reroute", "namespace": "cluster", "description": "Reroute the cluster.", - "method": "POST", - "path": "/_cluster/reroute", "namespaceFile": "cluster_reroute" }, { "name": "state", "namespace": "cluster", "description": "Get the cluster state.", - "method": "GET", - "path": "/_cluster/state/{metric}/{index}", "namespaceFile": "cluster_state" }, { "name": "stats", "namespace": "cluster", "description": "Get cluster statistics.", - "method": "GET", - "path": "/_cluster/stats", "namespaceFile": "cluster_stats" }, { "name": "check-in", "namespace": "connector", "description": "Check in a connector.", - "method": "PUT", - "path": "/_connector/{connector_id}/_check_in", "namespaceFile": "connector_check_in" }, { "name": "delete", "namespace": "connector", "description": "Delete a connector.", - "method": "DELETE", - "path": "/_connector/{connector_id}", "namespaceFile": "connector_delete" }, { "name": "get", "namespace": "connector", "description": "Get a connector.", - "method": "GET", - "path": "/_connector/{connector_id}", "namespaceFile": "connector_get" }, { "name": "list", "namespace": "connector", "description": "Get all connectors.", - "method": "GET", - "path": "/_connector", "namespaceFile": "connector_list" }, { "name": "post", "namespace": "connector", "description": "Create a connector.", - "method": "POST", - "path": "/_connector", "namespaceFile": "connector_post" }, { "name": "put", "namespace": "connector", "description": "Create or update a connector.", - "method": "PUT", - "path": "/_connector/{connector_id}", "namespaceFile": "connector_put" }, { "name": "sync-job-cancel", "namespace": "connector", "description": "Cancel a connector sync job.", - "method": "PUT", - "path": "/_connector/_sync_job/{connector_sync_job_id}/_cancel", "namespaceFile": "connector_sync_job_cancel" }, { "name": "sync-job-check-in", "namespace": "connector", "description": "Check in a connector sync job.", - "method": "PUT", - "path": "/_connector/_sync_job/{connector_sync_job_id}/_check_in", "namespaceFile": "connector_sync_job_check_in" }, { "name": "sync-job-claim", "namespace": "connector", "description": "Claim a connector sync job.", - "method": "PUT", - "path": "/_connector/_sync_job/{connector_sync_job_id}/_claim", "namespaceFile": "connector_sync_job_claim" }, { "name": "sync-job-delete", "namespace": "connector", "description": "Delete a connector sync job.", - "method": "DELETE", - "path": "/_connector/_sync_job/{connector_sync_job_id}", "namespaceFile": "connector_sync_job_delete" }, { "name": "sync-job-error", "namespace": "connector", "description": "Set a connector sync job error.", - "method": "PUT", - "path": "/_connector/_sync_job/{connector_sync_job_id}/_error", "namespaceFile": "connector_sync_job_error" }, { "name": "sync-job-get", "namespace": "connector", "description": "Get a connector sync job.", - "method": "GET", - "path": "/_connector/_sync_job/{connector_sync_job_id}", "namespaceFile": "connector_sync_job_get" }, { "name": "sync-job-list", "namespace": "connector", "description": "Get all connector sync jobs.", - "method": "GET", - "path": "/_connector/_sync_job", "namespaceFile": "connector_sync_job_list" }, { "name": "sync-job-post", "namespace": "connector", "description": "Create a connector sync job.", - "method": "POST", - "path": "/_connector/_sync_job", "namespaceFile": "connector_sync_job_post" }, { "name": "sync-job-update-stats", "namespace": "connector", "description": "Set the connector sync job stats.", - "method": "PUT", - "path": "/_connector/_sync_job/{connector_sync_job_id}/_stats", "namespaceFile": "connector_sync_job_update_stats" }, { "name": "update-active-filtering", "namespace": "connector", "description": "Activate the connector draft filter.", - "method": "PUT", - "path": "/_connector/{connector_id}/_filtering/_activate", "namespaceFile": "connector_update_active_filtering" }, { "name": "update-api-key-id", "namespace": "connector", "description": "Update the connector API key ID.", - "method": "PUT", - "path": "/_connector/{connector_id}/_api_key_id", "namespaceFile": "connector_update_api_key_id" }, { "name": "update-configuration", "namespace": "connector", "description": "Update the connector configuration.", - "method": "PUT", - "path": "/_connector/{connector_id}/_configuration", "namespaceFile": "connector_update_configuration" }, { "name": "update-error", "namespace": "connector", "description": "Update the connector error field.", - "method": "PUT", - "path": "/_connector/{connector_id}/_error", "namespaceFile": "connector_update_error" }, { "name": "update-features", "namespace": "connector", "description": "Update the connector features.", - "method": "PUT", - "path": "/_connector/{connector_id}/_features", "namespaceFile": "connector_update_features" }, { "name": "update-filtering", "namespace": "connector", "description": "Update the connector filtering.", - "method": "PUT", - "path": "/_connector/{connector_id}/_filtering", "namespaceFile": "connector_update_filtering" }, { "name": "update-filtering-validation", "namespace": "connector", "description": "Update the connector draft filtering validation.", - "method": "PUT", - "path": "/_connector/{connector_id}/_filtering/_validation", "namespaceFile": "connector_update_filtering_validation" }, { "name": "update-index-name", "namespace": "connector", "description": "Update the connector index name.", - "method": "PUT", - "path": "/_connector/{connector_id}/_index_name", "namespaceFile": "connector_update_index_name" }, { "name": "update-name", "namespace": "connector", "description": "Update the connector name and description.", - "method": "PUT", - "path": "/_connector/{connector_id}/_name", "namespaceFile": "connector_update_name" }, { "name": "update-native", "namespace": "connector", "description": "Update the connector is_native flag.", - "method": "PUT", - "path": "/_connector/{connector_id}/_native", "namespaceFile": "connector_update_native" }, { "name": "update-pipeline", "namespace": "connector", "description": "Update the connector pipeline.", - "method": "PUT", - "path": "/_connector/{connector_id}/_pipeline", "namespaceFile": "connector_update_pipeline" }, { "name": "update-scheduling", "namespace": "connector", "description": "Update the connector scheduling.", - "method": "PUT", - "path": "/_connector/{connector_id}/_scheduling", "namespaceFile": "connector_update_scheduling" }, { "name": "update-service-type", "namespace": "connector", "description": "Update the connector service type.", - "method": "PUT", - "path": "/_connector/{connector_id}/_service_type", "namespaceFile": "connector_update_service_type" }, { "name": "update-status", "namespace": "connector", "description": "Update the connector status.", - "method": "PUT", - "path": "/_connector/{connector_id}/_status", "namespaceFile": "connector_update_status" }, { "name": "count", "namespace": null, "description": "Count search results.", - "method": "POST", - "path": "/{index}/_count", "namespaceFile": "count" }, { "name": "create", "namespace": null, "description": "Create a new document in the index.", - "method": "PUT", - "path": "/{index}/_create/{id}", "namespaceFile": "create" }, { "name": "delete-dangling-index", "namespace": "dangling-indices", "description": "Delete a dangling index.", - "method": "DELETE", - "path": "/_dangling/{index_uuid}", "namespaceFile": "dangling_indices_delete_dangling_index" }, { "name": "import-dangling-index", "namespace": "dangling-indices", "description": "Import a dangling index.", - "method": "POST", - "path": "/_dangling/{index_uuid}", "namespaceFile": "dangling_indices_import_dangling_index" }, { "name": "list-dangling-indices", "namespace": "dangling-indices", "description": "Get the dangling indices.", - "method": "GET", - "path": "/_dangling", "namespaceFile": "dangling_indices_list_dangling_indices" }, { "name": "delete", "namespace": null, "description": "Delete a document.", - "method": "DELETE", - "path": "/{index}/_doc/{id}", "namespaceFile": "delete" }, { "name": "delete-by-query", "namespace": null, "description": "Delete documents.", - "method": "POST", - "path": "/{index}/_delete_by_query", "namespaceFile": "delete_by_query" }, { "name": "delete-by-query-rethrottle", "namespace": null, "description": "Throttle a delete by query operation.", - "method": "POST", - "path": "/_delete_by_query/{task_id}/_rethrottle", "namespaceFile": "delete_by_query_rethrottle" }, { "name": "delete-script", "namespace": null, "description": "Delete a script or search template.", - "method": "DELETE", - "path": "/_scripts/{id}", "namespaceFile": "delete_script" }, { "name": "delete-policy", "namespace": "enrich", "description": "Delete an enrich policy.", - "method": "DELETE", - "path": "/_enrich/policy/{name}", "namespaceFile": "enrich_delete_policy" }, { "name": "execute-policy", "namespace": "enrich", "description": "Run an enrich policy.", - "method": "PUT", - "path": "/_enrich/policy/{name}/_execute", "namespaceFile": "enrich_execute_policy" }, { "name": "get-policy", "namespace": "enrich", "description": "Get an enrich policy.", - "method": "GET", - "path": "/_enrich/policy/{name}", "namespaceFile": "enrich_get_policy" }, { "name": "put-policy", "namespace": "enrich", "description": "Create an enrich policy.", - "method": "PUT", - "path": "/_enrich/policy/{name}", "namespaceFile": "enrich_put_policy" }, { "name": "stats", "namespace": "enrich", "description": "Get enrich stats.", - "method": "GET", - "path": "/_enrich/_stats", "namespaceFile": "enrich_stats" }, { "name": "delete", "namespace": "eql", "description": "Delete an async EQL search.", - "method": "DELETE", - "path": "/_eql/search/{id}", "namespaceFile": "eql_delete" }, { "name": "get", "namespace": "eql", "description": "Get async EQL search results.", - "method": "GET", - "path": "/_eql/search/{id}", "namespaceFile": "eql_get" }, { "name": "get-status", "namespace": "eql", "description": "Get the async EQL status.", - "method": "GET", - "path": "/_eql/search/status/{id}", "namespaceFile": "eql_get_status" }, { "name": "search", "namespace": "eql", "description": "Get EQL search results.", - "method": "GET", - "path": "/{index}/_eql/search", "namespaceFile": "eql_search" }, { "name": "async-query", "namespace": "esql", "description": "Run an async ES|QL query.", - "method": "POST", - "path": "/_query/async", "namespaceFile": "esql_async_query" }, { "name": "async-query-delete", "namespace": "esql", "description": "Delete an async ES|QL query.", - "method": "DELETE", - "path": "/_query/async/{id}", "namespaceFile": "esql_async_query_delete" }, { "name": "async-query-get", "namespace": "esql", "description": "Get async ES|QL query results.", - "method": "GET", - "path": "/_query/async/{id}", "namespaceFile": "esql_async_query_get" }, { "name": "async-query-stop", "namespace": "esql", "description": "Stop async ES|QL query.", - "method": "POST", - "path": "/_query/async/{id}/stop", "namespaceFile": "esql_async_query_stop" }, { "name": "delete-view", "namespace": "esql", "description": "Delete an ES|QL view.", - "method": "DELETE", - "path": "/_query/view/{name}", "namespaceFile": "esql_delete_view" }, { "name": "get-query", "namespace": "esql", "description": "Get a specific running ES|QL query information.", - "method": "GET", - "path": "/_query/queries/{id}", "namespaceFile": "esql_get_query" }, { "name": "get-view", "namespace": "esql", "description": "Get an ES|QL view.", - "method": "GET", - "path": "/_query/view/{name}", "namespaceFile": "esql_get_view" }, { "name": "list-queries", "namespace": "esql", "description": "Get running ES|QL queries information.", - "method": "GET", - "path": "/_query/queries", "namespaceFile": "esql_list_queries" }, { "name": "put-view", "namespace": "esql", "description": "Create or update an ES|QL view.", - "method": "PUT", - "path": "/_query/view/{name}", "namespaceFile": "esql_put_view" }, { "name": "query", "namespace": "esql", "description": "Run an ES|QL query.", - "method": "POST", - "path": "/_query", "namespaceFile": "esql_query" }, { "name": "exists", "namespace": null, "description": "Check a document.", - "method": "HEAD", - "path": "/{index}/_doc/{id}", "namespaceFile": "exists" }, { "name": "exists-source", "namespace": null, "description": "Check for a document source.", - "method": "HEAD", - "path": "/{index}/_source/{id}", "namespaceFile": "exists_source" }, { "name": "explain", "namespace": null, "description": "Explain a document match result.", - "method": "GET", - "path": "/{index}/_explain/{id}", "namespaceFile": "explain" }, { "name": "get-features", "namespace": "features", "description": "Get the features.", - "method": "GET", - "path": "/_features", "namespaceFile": "features_get_features" }, { "name": "reset-features", "namespace": "features", "description": "Reset the features.", - "method": "POST", - "path": "/_features/_reset", "namespaceFile": "features_reset_features" }, { "name": "field-caps", "namespace": null, "description": "Get the field capabilities.", - "method": "GET", - "path": "/{index}/_field_caps", "namespaceFile": "field_caps" }, { "name": "global-checkpoints", "namespace": "fleet", "description": "Get global checkpoints.", - "method": "GET", - "path": "/{index}/_fleet/global_checkpoints", "namespaceFile": "fleet_global_checkpoints" }, { "name": "msearch", "namespace": "fleet", "description": "Run multiple Fleet searches.", - "method": "GET", - "path": "/{index}/_fleet/_fleet_msearch", - "namespaceFile": "fleet_msearch", - "bodyFormat": "ndjson" + "namespaceFile": "fleet_msearch" }, { "name": "search", "namespace": "fleet", "description": "Run a Fleet search.", - "method": "GET", - "path": "/{index}/_fleet/_fleet_search", "namespaceFile": "fleet_search" }, { "name": "get", "namespace": null, "description": "Get a document by its ID.", - "method": "GET", - "path": "/{index}/_doc/{id}", "namespaceFile": "get" }, { "name": "get-script", "namespace": null, "description": "Get a script or search template.", - "method": "GET", - "path": "/_scripts/{id}", "namespaceFile": "get_script" }, { "name": "get-script-context", "namespace": null, "description": "Get script contexts.", - "method": "GET", - "path": "/_script_context", "namespaceFile": "get_script_context" }, { "name": "get-script-languages", "namespace": null, "description": "Get script languages.", - "method": "GET", - "path": "/_script_language", "namespaceFile": "get_script_languages" }, { "name": "get-source", "namespace": null, "description": "Get a document's source.", - "method": "GET", - "path": "/{index}/_source/{id}", "namespaceFile": "get_source" }, { "name": "explore", "namespace": "graph", "description": "Explore graph analytics.", - "method": "GET", - "path": "/{index}/_graph/explore", "namespaceFile": "graph_explore" }, { "name": "health-report", "namespace": null, "description": "Get the cluster health.", - "method": "GET", - "path": "/_health_report/{feature}", "namespaceFile": "health_report" }, { "name": "delete-lifecycle", "namespace": "ilm", "description": "Delete a lifecycle policy.", - "method": "DELETE", - "path": "/_ilm/policy/{policy}", "namespaceFile": "ilm_delete_lifecycle" }, { "name": "explain-lifecycle", "namespace": "ilm", "description": "Explain the lifecycle state.", - "method": "GET", - "path": "/{index}/_ilm/explain", "namespaceFile": "ilm_explain_lifecycle" }, { "name": "get-lifecycle", "namespace": "ilm", "description": "Get lifecycle policies.", - "method": "GET", - "path": "/_ilm/policy/{policy}", "namespaceFile": "ilm_get_lifecycle" }, { "name": "get-status", "namespace": "ilm", "description": "Get the ILM status.", - "method": "GET", - "path": "/_ilm/status", "namespaceFile": "ilm_get_status" }, { "name": "migrate-to-data-tiers", "namespace": "ilm", "description": "Migrate to data tiers routing.", - "method": "POST", - "path": "/_ilm/migrate_to_data_tiers", "namespaceFile": "ilm_migrate_to_data_tiers" }, { "name": "move-to-step", "namespace": "ilm", "description": "Move to a lifecycle step.", - "method": "POST", - "path": "/_ilm/move/{index}", "namespaceFile": "ilm_move_to_step" }, { "name": "put-lifecycle", "namespace": "ilm", "description": "Create or update a lifecycle policy.", - "method": "PUT", - "path": "/_ilm/policy/{policy}", "namespaceFile": "ilm_put_lifecycle" }, { "name": "remove-policy", "namespace": "ilm", "description": "Remove policies from an index.", - "method": "POST", - "path": "/{index}/_ilm/remove", "namespaceFile": "ilm_remove_policy" }, { "name": "retry", "namespace": "ilm", "description": "Retry a policy.", - "method": "POST", - "path": "/{index}/_ilm/retry", "namespaceFile": "ilm_retry" }, { "name": "start", "namespace": "ilm", "description": "Start the ILM plugin.", - "method": "POST", - "path": "/_ilm/start", "namespaceFile": "ilm_start" }, { "name": "stop", "namespace": "ilm", "description": "Stop the ILM plugin.", - "method": "POST", - "path": "/_ilm/stop", "namespaceFile": "ilm_stop" }, { "name": "index", "namespace": null, "description": "Create or update a document in an index.", - "method": "PUT", - "path": "/{index}/_doc/{id}", "namespaceFile": "index" }, { "name": "add-block", "namespace": "indices", "description": "Add an index block.", - "method": "PUT", - "path": "/{index}/_block/{block}", "namespaceFile": "indices_add_block" }, { "name": "analyze", "namespace": "indices", "description": "Get tokens from text analysis.", - "method": "GET", - "path": "/{index}/_analyze", "namespaceFile": "indices_analyze" }, { "name": "cancel-migrate-reindex", "namespace": "indices", "description": "Cancel a migration reindex operation.", - "method": "POST", - "path": "/_migration/reindex/{index}/_cancel", "namespaceFile": "indices_cancel_migrate_reindex" }, { "name": "clear-cache", "namespace": "indices", "description": "Clear the cache.", - "method": "POST", - "path": "/{index}/_cache/clear", "namespaceFile": "indices_clear_cache" }, { "name": "clone", "namespace": "indices", "description": "Clone an index.", - "method": "PUT", - "path": "/{index}/_clone/{target}", "namespaceFile": "indices_clone" }, { "name": "close", "namespace": "indices", "description": "Close an index.", - "method": "POST", - "path": "/{index}/_close", "namespaceFile": "indices_close" }, { "name": "create", "namespace": "indices", "description": "Create an index.", - "method": "PUT", - "path": "/{index}", "namespaceFile": "indices_create" }, { "name": "create-data-stream", "namespace": "indices", "description": "Create a data stream.", - "method": "PUT", - "path": "/_data_stream/{name}", "namespaceFile": "indices_create_data_stream" }, { "name": "create-from", "namespace": "indices", "description": "Create an index from a source index.", - "method": "PUT", - "path": "/_create_from/{source}/{dest}", "namespaceFile": "indices_create_from" }, { "name": "data-streams-stats", "namespace": "indices", "description": "Get data stream stats.", - "method": "GET", - "path": "/_data_stream/{name}/_stats", "namespaceFile": "indices_data_streams_stats" }, { "name": "delete", "namespace": "indices", "description": "Delete indices.", - "method": "DELETE", - "path": "/{index}", "namespaceFile": "indices_delete" }, { "name": "delete-alias", "namespace": "indices", "description": "Delete an alias.", - "method": "DELETE", - "path": "/{index}/_aliases/{name}", "namespaceFile": "indices_delete_alias" }, { "name": "delete-data-lifecycle", "namespace": "indices", "description": "Delete data stream lifecycles.", - "method": "DELETE", - "path": "/_data_stream/{name}/_lifecycle", "namespaceFile": "indices_delete_data_lifecycle" }, { "name": "delete-data-stream", "namespace": "indices", "description": "Delete data streams.", - "method": "DELETE", - "path": "/_data_stream/{name}", "namespaceFile": "indices_delete_data_stream" }, { "name": "delete-data-stream-options", "namespace": "indices", "description": "Delete data stream options.", - "method": "DELETE", - "path": "/_data_stream/{name}/_options", "namespaceFile": "indices_delete_data_stream_options" }, { "name": "delete-index-template", "namespace": "indices", "description": "Delete an index template.", - "method": "DELETE", - "path": "/_index_template/{name}", "namespaceFile": "indices_delete_index_template" }, { "name": "delete-template", "namespace": "indices", "description": "Delete a legacy index template.", - "method": "DELETE", - "path": "/_template/{name}", "namespaceFile": "indices_delete_template" }, { "name": "disk-usage", "namespace": "indices", "description": "Analyze the index disk usage.", - "method": "POST", - "path": "/{index}/_disk_usage", "namespaceFile": "indices_disk_usage" }, { "name": "downsample", "namespace": "indices", "description": "Downsample an index.", - "method": "POST", - "path": "/{index}/_downsample/{target_index}", "namespaceFile": "indices_downsample" }, { "name": "exists", "namespace": "indices", "description": "Check indices.", - "method": "HEAD", - "path": "/{index}", "namespaceFile": "indices_exists" }, { "name": "exists-alias", "namespace": "indices", "description": "Check aliases.", - "method": "HEAD", - "path": "/{index}/_alias/{name}", "namespaceFile": "indices_exists_alias" }, { "name": "exists-index-template", "namespace": "indices", "description": "Check index templates.", - "method": "HEAD", - "path": "/_index_template/{name}", "namespaceFile": "indices_exists_index_template" }, { "name": "exists-template", "namespace": "indices", "description": "Check existence of index templates.", - "method": "HEAD", - "path": "/_template/{name}", "namespaceFile": "indices_exists_template" }, { "name": "explain-data-lifecycle", "namespace": "indices", "description": "Get the status for a data stream lifecycle.", - "method": "GET", - "path": "/{index}/_lifecycle/explain", "namespaceFile": "indices_explain_data_lifecycle" }, { "name": "field-usage-stats", "namespace": "indices", "description": "Get field usage stats.", - "method": "GET", - "path": "/{index}/_field_usage_stats", "namespaceFile": "indices_field_usage_stats" }, { "name": "flush", "namespace": "indices", "description": "Flush data streams or indices.", - "method": "POST", - "path": "/{index}/_flush", "namespaceFile": "indices_flush" }, { "name": "forcemerge", "namespace": "indices", "description": "Force a merge.", - "method": "POST", - "path": "/{index}/_forcemerge", "namespaceFile": "indices_forcemerge" }, { "name": "get", "namespace": "indices", "description": "Get index information.", - "method": "GET", - "path": "/{index}", "namespaceFile": "indices_get" }, { "name": "get-alias", "namespace": "indices", "description": "Get aliases.", - "method": "GET", - "path": "/{index}/_alias/{name}", "namespaceFile": "indices_get_alias" }, { "name": "get-data-lifecycle", "namespace": "indices", "description": "Get data stream lifecycles.", - "method": "GET", - "path": "/_data_stream/{name}/_lifecycle", "namespaceFile": "indices_get_data_lifecycle" }, { "name": "get-data-lifecycle-stats", "namespace": "indices", "description": "Get data stream lifecycle stats.", - "method": "GET", - "path": "/_lifecycle/stats", "namespaceFile": "indices_get_data_lifecycle_stats" }, { "name": "get-data-stream", "namespace": "indices", "description": "Get data streams.", - "method": "GET", - "path": "/_data_stream/{name}", "namespaceFile": "indices_get_data_stream" }, { "name": "get-data-stream-mappings", "namespace": "indices", "description": "Get data stream mappings.", - "method": "GET", - "path": "/_data_stream/{name}/_mappings", "namespaceFile": "indices_get_data_stream_mappings" }, { "name": "get-data-stream-options", "namespace": "indices", "description": "Get data stream options.", - "method": "GET", - "path": "/_data_stream/{name}/_options", "namespaceFile": "indices_get_data_stream_options" }, { "name": "get-data-stream-settings", "namespace": "indices", "description": "Get data stream settings.", - "method": "GET", - "path": "/_data_stream/{name}/_settings", "namespaceFile": "indices_get_data_stream_settings" }, { "name": "get-field-mapping", "namespace": "indices", "description": "Get mapping definitions.", - "method": "GET", - "path": "/{index}/_mapping/field/{fields}", "namespaceFile": "indices_get_field_mapping" }, { "name": "get-index-template", "namespace": "indices", "description": "Get index templates.", - "method": "GET", - "path": "/_index_template/{name}", "namespaceFile": "indices_get_index_template" }, { "name": "get-mapping", "namespace": "indices", "description": "Get mapping definitions.", - "method": "GET", - "path": "/{index}/_mapping", "namespaceFile": "indices_get_mapping" }, { "name": "get-migrate-reindex-status", "namespace": "indices", "description": "Get the migration reindexing status.", - "method": "GET", - "path": "/_migration/reindex/{index}/_status", "namespaceFile": "indices_get_migrate_reindex_status" }, { "name": "get-settings", "namespace": "indices", "description": "Get index settings.", - "method": "GET", - "path": "/{index}/_settings/{name}", "namespaceFile": "indices_get_settings" }, { "name": "get-template", "namespace": "indices", "description": "Get legacy index templates.", - "method": "GET", - "path": "/_template/{name}", "namespaceFile": "indices_get_template" }, { "name": "migrate-reindex", "namespace": "indices", "description": "Reindex legacy backing indices.", - "method": "POST", - "path": "/_migration/reindex", "namespaceFile": "indices_migrate_reindex" }, { "name": "migrate-to-data-stream", "namespace": "indices", "description": "Convert an index alias to a data stream.", - "method": "POST", - "path": "/_data_stream/_migrate/{name}", "namespaceFile": "indices_migrate_to_data_stream" }, { "name": "modify-data-stream", "namespace": "indices", "description": "Update data streams.", - "method": "POST", - "path": "/_data_stream/_modify", "namespaceFile": "indices_modify_data_stream" }, { "name": "open", "namespace": "indices", "description": "Open a closed index.", - "method": "POST", - "path": "/{index}/_open", "namespaceFile": "indices_open" }, { "name": "promote-data-stream", "namespace": "indices", "description": "Promote a data stream.", - "method": "POST", - "path": "/_data_stream/_promote/{name}", "namespaceFile": "indices_promote_data_stream" }, { "name": "put-alias", "namespace": "indices", "description": "Create or update an alias.", - "method": "PUT", - "path": "/{index}/_aliases/{name}", "namespaceFile": "indices_put_alias" }, { "name": "put-data-lifecycle", "namespace": "indices", "description": "Update data stream lifecycles.", - "method": "PUT", - "path": "/_data_stream/{name}/_lifecycle", "namespaceFile": "indices_put_data_lifecycle" }, { "name": "put-data-stream-mappings", "namespace": "indices", "description": "Update data stream mappings.", - "method": "PUT", - "path": "/_data_stream/{name}/_mappings", "namespaceFile": "indices_put_data_stream_mappings" }, { "name": "put-data-stream-options", "namespace": "indices", "description": "Update data stream options.", - "method": "PUT", - "path": "/_data_stream/{name}/_options", "namespaceFile": "indices_put_data_stream_options" }, { "name": "put-data-stream-settings", "namespace": "indices", "description": "Update data stream settings.", - "method": "PUT", - "path": "/_data_stream/{name}/_settings", "namespaceFile": "indices_put_data_stream_settings" }, { "name": "put-index-template", "namespace": "indices", "description": "Create or update an index template.", - "method": "PUT", - "path": "/_index_template/{name}", "namespaceFile": "indices_put_index_template" }, { "name": "put-mapping", "namespace": "indices", "description": "Update field mappings.", - "method": "PUT", - "path": "/{index}/_mapping", "namespaceFile": "indices_put_mapping" }, { "name": "put-settings", "namespace": "indices", "description": "Update index settings.", - "method": "PUT", - "path": "/{index}/_settings", "namespaceFile": "indices_put_settings" }, { "name": "put-template", "namespace": "indices", "description": "Create or update a legacy index template.", - "method": "PUT", - "path": "/_template/{name}", "namespaceFile": "indices_put_template" }, { "name": "recovery", "namespace": "indices", "description": "Get index recovery information.", - "method": "GET", - "path": "/{index}/_recovery", "namespaceFile": "indices_recovery" }, { "name": "refresh", "namespace": "indices", "description": "Refresh an index.", - "method": "POST", - "path": "/{index}/_refresh", "namespaceFile": "indices_refresh" }, { "name": "reload-search-analyzers", "namespace": "indices", "description": "Reload search analyzers.", - "method": "GET", - "path": "/{index}/_reload_search_analyzers", "namespaceFile": "indices_reload_search_analyzers" }, { "name": "remove-block", "namespace": "indices", "description": "Remove an index block.", - "method": "DELETE", - "path": "/{index}/_block/{block}", "namespaceFile": "indices_remove_block" }, { "name": "resolve-cluster", "namespace": "indices", "description": "Resolve the cluster.", - "method": "GET", - "path": "/_resolve/cluster/{name}", "namespaceFile": "indices_resolve_cluster" }, { "name": "resolve-index", "namespace": "indices", "description": "Resolve indices.", - "method": "GET", - "path": "/_resolve/index/{name}", "namespaceFile": "indices_resolve_index" }, { "name": "rollover", "namespace": "indices", "description": "Roll over to a new index.", - "method": "POST", - "path": "/{alias}/_rollover/{new_index}", "namespaceFile": "indices_rollover" }, { "name": "segments", "namespace": "indices", "description": "Get index segments.", - "method": "GET", - "path": "/{index}/_segments", "namespaceFile": "indices_segments" }, { "name": "shard-stores", "namespace": "indices", "description": "Get index shard stores.", - "method": "GET", - "path": "/{index}/_shard_stores", "namespaceFile": "indices_shard_stores" }, { "name": "shrink", "namespace": "indices", "description": "Shrink an index.", - "method": "PUT", - "path": "/{index}/_shrink/{target}", "namespaceFile": "indices_shrink" }, { "name": "simulate-index-template", "namespace": "indices", "description": "Simulate an index.", - "method": "POST", - "path": "/_index_template/_simulate_index/{name}", "namespaceFile": "indices_simulate_index_template" }, { "name": "simulate-template", "namespace": "indices", "description": "Simulate an index template.", - "method": "POST", - "path": "/_index_template/_simulate/{name}", "namespaceFile": "indices_simulate_template" }, { "name": "split", "namespace": "indices", "description": "Split an index.", - "method": "PUT", - "path": "/{index}/_split/{target}", "namespaceFile": "indices_split" }, { "name": "stats", "namespace": "indices", "description": "Get index statistics.", - "method": "GET", - "path": "/{index}/_stats/{metric}", "namespaceFile": "indices_stats" }, { "name": "update-aliases", "namespace": "indices", "description": "Create or update an alias.", - "method": "POST", - "path": "/_aliases", "namespaceFile": "indices_update_aliases" }, { "name": "validate-query", "namespace": "indices", "description": "Validate a query.", - "method": "GET", - "path": "/{index}/_validate/query", "namespaceFile": "indices_validate_query" }, { "name": "chat-completion-unified", "namespace": "inference", "description": "Perform chat completion inference on the service.", - "method": "POST", - "path": "/_inference/chat_completion/{inference_id}/_stream", "namespaceFile": "inference_chat_completion_unified" }, { "name": "completion", "namespace": "inference", "description": "Perform completion inference on the service.", - "method": "POST", - "path": "/_inference/completion/{inference_id}", "namespaceFile": "inference_completion" }, { "name": "delete", "namespace": "inference", "description": "Delete an inference endpoint.", - "method": "DELETE", - "path": "/_inference/{task_type}/{inference_id}", "namespaceFile": "inference_delete" }, { "name": "embedding", "namespace": "inference", "description": "Perform dense embedding inference on the service.", - "method": "POST", - "path": "/_inference/embedding/{inference_id}", "namespaceFile": "inference_embedding" }, { "name": "get", "namespace": "inference", "description": "Get an inference endpoint.", - "method": "GET", - "path": "/_inference/{task_type}/{inference_id}", "namespaceFile": "inference_get" }, { "name": "inference", "namespace": "inference", "description": "Perform inference on the service.", - "method": "POST", - "path": "/_inference/{task_type}/{inference_id}", "namespaceFile": "inference_inference" }, { "name": "put", "namespace": "inference", "description": "Create an inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{inference_id}", "namespaceFile": "inference_put" }, { "name": "put-ai21", "namespace": "inference", "description": "Create a AI21 inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{ai21_inference_id}", "namespaceFile": "inference_put_ai21" }, { "name": "put-alibabacloud", "namespace": "inference", "description": "Create an AlibabaCloud AI Search inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{alibabacloud_inference_id}", "namespaceFile": "inference_put_alibabacloud" }, { "name": "put-amazonbedrock", "namespace": "inference", "description": "Create an Amazon Bedrock inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{amazonbedrock_inference_id}", "namespaceFile": "inference_put_amazonbedrock" }, { "name": "put-amazonsagemaker", "namespace": "inference", "description": "Create an Amazon SageMaker inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{amazonsagemaker_inference_id}", "namespaceFile": "inference_put_amazonsagemaker" }, { "name": "put-anthropic", "namespace": "inference", "description": "Create an Anthropic inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{anthropic_inference_id}", "namespaceFile": "inference_put_anthropic" }, { "name": "put-azureaistudio", "namespace": "inference", "description": "Create an Azure AI studio inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{azureaistudio_inference_id}", "namespaceFile": "inference_put_azureaistudio" }, { "name": "put-azureopenai", "namespace": "inference", "description": "Create an Azure OpenAI inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{azureopenai_inference_id}", "namespaceFile": "inference_put_azureopenai" }, { "name": "put-cohere", "namespace": "inference", "description": "Create a Cohere inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{cohere_inference_id}", "namespaceFile": "inference_put_cohere" }, { "name": "put-contextualai", "namespace": "inference", "description": "Create an Contextual AI inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{contextualai_inference_id}", "namespaceFile": "inference_put_contextualai" }, { "name": "put-custom", "namespace": "inference", "description": "Create a custom inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{custom_inference_id}", "namespaceFile": "inference_put_custom" }, { "name": "put-deepseek", "namespace": "inference", "description": "Create a DeepSeek inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{deepseek_inference_id}", "namespaceFile": "inference_put_deepseek" }, { "name": "put-elasticsearch", "namespace": "inference", "description": "Create an Elasticsearch inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{elasticsearch_inference_id}", "namespaceFile": "inference_put_elasticsearch" }, { "name": "put-elser", "namespace": "inference", "description": "Create an ELSER inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{elser_inference_id}", "namespaceFile": "inference_put_elser" }, { "name": "put-fireworksai", "namespace": "inference", "description": "Create a Fireworks AI inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{fireworksai_inference_id}", "namespaceFile": "inference_put_fireworksai" }, { "name": "put-googleaistudio", "namespace": "inference", "description": "Create an Google AI Studio inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{googleaistudio_inference_id}", "namespaceFile": "inference_put_googleaistudio" }, { "name": "put-googlevertexai", "namespace": "inference", "description": "Create a Google Vertex AI inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{googlevertexai_inference_id}", "namespaceFile": "inference_put_googlevertexai" }, { "name": "put-groq", "namespace": "inference", "description": "Create a Groq inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{groq_inference_id}", "namespaceFile": "inference_put_groq" }, { "name": "put-hugging-face", "namespace": "inference", "description": "Create a Hugging Face inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{huggingface_inference_id}", "namespaceFile": "inference_put_hugging_face" }, { "name": "put-jinaai", "namespace": "inference", "description": "Create an JinaAI inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{jinaai_inference_id}", "namespaceFile": "inference_put_jinaai" }, { "name": "put-llama", "namespace": "inference", "description": "Create a Llama inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{llama_inference_id}", "namespaceFile": "inference_put_llama" }, { "name": "put-mistral", "namespace": "inference", "description": "Create a Mistral inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{mistral_inference_id}", "namespaceFile": "inference_put_mistral" }, { "name": "put-nvidia", "namespace": "inference", "description": "Create an Nvidia inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{nvidia_inference_id}", "namespaceFile": "inference_put_nvidia" }, { "name": "put-openai", "namespace": "inference", "description": "Create an OpenAI inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{openai_inference_id}", "namespaceFile": "inference_put_openai" }, { "name": "put-openshift-ai", "namespace": "inference", "description": "Create an OpenShift AI inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{openshiftai_inference_id}", "namespaceFile": "inference_put_openshift_ai" }, { "name": "put-voyageai", "namespace": "inference", "description": "Create a VoyageAI inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{voyageai_inference_id}", "namespaceFile": "inference_put_voyageai" }, { "name": "put-watsonx", "namespace": "inference", "description": "Create a Watsonx inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{watsonx_inference_id}", "namespaceFile": "inference_put_watsonx" }, { "name": "rerank", "namespace": "inference", "description": "Perform reranking inference on the service.", - "method": "POST", - "path": "/_inference/rerank/{inference_id}", "namespaceFile": "inference_rerank" }, { "name": "sparse-embedding", "namespace": "inference", "description": "Perform sparse embedding inference on the service.", - "method": "POST", - "path": "/_inference/sparse_embedding/{inference_id}", "namespaceFile": "inference_sparse_embedding" }, { "name": "stream-completion", "namespace": "inference", "description": "Perform streaming completion inference on the service.", - "method": "POST", - "path": "/_inference/completion/{inference_id}/_stream", "namespaceFile": "inference_stream_completion" }, { "name": "text-embedding", "namespace": "inference", "description": "Perform text embedding inference on the service.", - "method": "POST", - "path": "/_inference/text_embedding/{inference_id}", "namespaceFile": "inference_text_embedding" }, { "name": "update", "namespace": "inference", "description": "Update an inference endpoint.", - "method": "PUT", - "path": "/_inference/{task_type}/{inference_id}/_update", "namespaceFile": "inference_update" }, { "name": "info", "namespace": null, "description": "Get cluster info.", - "method": "GET", - "path": "/", "namespaceFile": "info" }, { "name": "delete-geoip-database", "namespace": "ingest", "description": "Delete GeoIP database configurations.", - "method": "DELETE", - "path": "/_ingest/geoip/database/{id}", "namespaceFile": "ingest_delete_geoip_database" }, { "name": "delete-ip-location-database", "namespace": "ingest", "description": "Delete IP geolocation database configurations.", - "method": "DELETE", - "path": "/_ingest/ip_location/database/{id}", "namespaceFile": "ingest_delete_ip_location_database" }, { "name": "delete-pipeline", "namespace": "ingest", "description": "Delete pipelines.", - "method": "DELETE", - "path": "/_ingest/pipeline/{id}", "namespaceFile": "ingest_delete_pipeline" }, { "name": "geo-ip-stats", "namespace": "ingest", "description": "Get GeoIP statistics.", - "method": "GET", - "path": "/_ingest/geoip/stats", "namespaceFile": "ingest_geo_ip_stats" }, { "name": "get-geoip-database", "namespace": "ingest", "description": "Get GeoIP database configurations.", - "method": "GET", - "path": "/_ingest/geoip/database/{id}", "namespaceFile": "ingest_get_geoip_database" }, { "name": "get-ip-location-database", "namespace": "ingest", "description": "Get IP geolocation database configurations.", - "method": "GET", - "path": "/_ingest/ip_location/database/{id}", "namespaceFile": "ingest_get_ip_location_database" }, { "name": "get-pipeline", "namespace": "ingest", "description": "Get pipelines.", - "method": "GET", - "path": "/_ingest/pipeline/{id}", "namespaceFile": "ingest_get_pipeline" }, { "name": "processor-grok", "namespace": "ingest", "description": "Run a grok processor.", - "method": "GET", - "path": "/_ingest/processor/grok", "namespaceFile": "ingest_processor_grok" }, { "name": "put-geoip-database", "namespace": "ingest", "description": "Create or update a GeoIP database configuration.", - "method": "PUT", - "path": "/_ingest/geoip/database/{id}", "namespaceFile": "ingest_put_geoip_database" }, { "name": "put-ip-location-database", "namespace": "ingest", "description": "Create or update an IP geolocation database configuration.", - "method": "PUT", - "path": "/_ingest/ip_location/database/{id}", "namespaceFile": "ingest_put_ip_location_database" }, { "name": "put-pipeline", "namespace": "ingest", "description": "Create or update a pipeline.", - "method": "PUT", - "path": "/_ingest/pipeline/{id}", "namespaceFile": "ingest_put_pipeline" }, { "name": "simulate", "namespace": "ingest", "description": "Simulate a pipeline.", - "method": "GET", - "path": "/_ingest/pipeline/{id}/_simulate", "namespaceFile": "ingest_simulate" }, { "name": "delete", "namespace": "license", "description": "Delete the license.", - "method": "DELETE", - "path": "/_license", "namespaceFile": "license_delete" }, { "name": "get", "namespace": "license", "description": "Get license information.", - "method": "GET", - "path": "/_license", "namespaceFile": "license_get" }, { "name": "get-basic-status", "namespace": "license", "description": "Get the basic license status.", - "method": "GET", - "path": "/_license/basic_status", "namespaceFile": "license_get_basic_status" }, { "name": "get-trial-status", "namespace": "license", "description": "Get the trial status.", - "method": "GET", - "path": "/_license/trial_status", "namespaceFile": "license_get_trial_status" }, { "name": "post", "namespace": "license", "description": "Update the license.", - "method": "PUT", - "path": "/_license", "namespaceFile": "license_post" }, { "name": "post-start-basic", "namespace": "license", "description": "Start a basic license.", - "method": "POST", - "path": "/_license/start_basic", "namespaceFile": "license_post_start_basic" }, { "name": "post-start-trial", "namespace": "license", "description": "Start a trial.", - "method": "POST", - "path": "/_license/start_trial", "namespaceFile": "license_post_start_trial" }, { "name": "delete-pipeline", "namespace": "logstash", "description": "Delete a Logstash pipeline.", - "method": "DELETE", - "path": "/_logstash/pipeline/{id}", "namespaceFile": "logstash_delete_pipeline" }, { "name": "get-pipeline", "namespace": "logstash", "description": "Get Logstash pipelines.", - "method": "GET", - "path": "/_logstash/pipeline/{id}", "namespaceFile": "logstash_get_pipeline" }, { "name": "put-pipeline", "namespace": "logstash", "description": "Create or update a Logstash pipeline.", - "method": "PUT", - "path": "/_logstash/pipeline/{id}", "namespaceFile": "logstash_put_pipeline" }, { "name": "mget", "namespace": null, "description": "Get multiple documents.", - "method": "GET", - "path": "/{index}/_mget", "namespaceFile": "mget" }, { "name": "deprecations", "namespace": "migration", "description": "Get deprecation information.", - "method": "GET", - "path": "/{index}/_migration/deprecations", "namespaceFile": "migration_deprecations" }, { "name": "get-feature-upgrade-status", "namespace": "migration", "description": "Get feature migration information.", - "method": "GET", - "path": "/_migration/system_features", "namespaceFile": "migration_get_feature_upgrade_status" }, { "name": "post-feature-upgrade", "namespace": "migration", "description": "Start the feature migration.", - "method": "POST", - "path": "/_migration/system_features", "namespaceFile": "migration_post_feature_upgrade" }, { "name": "clear-trained-model-deployment-cache", "namespace": "ml", "description": "Clear trained model deployment cache.", - "method": "POST", - "path": "/_ml/trained_models/{model_id}/deployment/cache/_clear", "namespaceFile": "ml_clear_trained_model_deployment_cache" }, { "name": "close-job", "namespace": "ml", "description": "Close anomaly detection jobs.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/_close", "namespaceFile": "ml_close_job" }, { "name": "delete-calendar", "namespace": "ml", "description": "Delete a calendar.", - "method": "DELETE", - "path": "/_ml/calendars/{calendar_id}", "namespaceFile": "ml_delete_calendar" }, { "name": "delete-calendar-event", "namespace": "ml", "description": "Delete events from a calendar.", - "method": "DELETE", - "path": "/_ml/calendars/{calendar_id}/events/{event_id}", "namespaceFile": "ml_delete_calendar_event" }, { "name": "delete-calendar-job", "namespace": "ml", "description": "Delete anomaly jobs from a calendar.", - "method": "DELETE", - "path": "/_ml/calendars/{calendar_id}/jobs/{job_id}", "namespaceFile": "ml_delete_calendar_job" }, { "name": "delete-data-frame-analytics", "namespace": "ml", "description": "Delete a data frame analytics job.", - "method": "DELETE", - "path": "/_ml/data_frame/analytics/{id}", "namespaceFile": "ml_delete_data_frame_analytics" }, { "name": "delete-datafeed", "namespace": "ml", "description": "Delete a datafeed.", - "method": "DELETE", - "path": "/_ml/datafeeds/{datafeed_id}", "namespaceFile": "ml_delete_datafeed" }, { "name": "delete-expired-data", "namespace": "ml", "description": "Delete expired ML data.", - "method": "DELETE", - "path": "/_ml/_delete_expired_data/{job_id}", "namespaceFile": "ml_delete_expired_data" }, { "name": "delete-filter", "namespace": "ml", "description": "Delete a filter.", - "method": "DELETE", - "path": "/_ml/filters/{filter_id}", "namespaceFile": "ml_delete_filter" }, { "name": "delete-forecast", "namespace": "ml", "description": "Delete forecasts from a job.", - "method": "DELETE", - "path": "/_ml/anomaly_detectors/{job_id}/_forecast/{forecast_id}", "namespaceFile": "ml_delete_forecast" }, { "name": "delete-job", "namespace": "ml", "description": "Delete an anomaly detection job.", - "method": "DELETE", - "path": "/_ml/anomaly_detectors/{job_id}", "namespaceFile": "ml_delete_job" }, { "name": "delete-model-snapshot", "namespace": "ml", "description": "Delete a model snapshot.", - "method": "DELETE", - "path": "/_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}", "namespaceFile": "ml_delete_model_snapshot" }, { "name": "delete-trained-model", "namespace": "ml", "description": "Delete an unreferenced trained model.", - "method": "DELETE", - "path": "/_ml/trained_models/{model_id}", "namespaceFile": "ml_delete_trained_model" }, { "name": "delete-trained-model-alias", "namespace": "ml", "description": "Delete a trained model alias.", - "method": "DELETE", - "path": "/_ml/trained_models/{model_id}/model_aliases/{model_alias}", "namespaceFile": "ml_delete_trained_model_alias" }, { "name": "estimate-model-memory", "namespace": "ml", "description": "Estimate job model memory usage.", - "method": "POST", - "path": "/_ml/anomaly_detectors/_estimate_model_memory", "namespaceFile": "ml_estimate_model_memory" }, { "name": "evaluate-data-frame", "namespace": "ml", "description": "Evaluate data frame analytics.", - "method": "POST", - "path": "/_ml/data_frame/_evaluate", "namespaceFile": "ml_evaluate_data_frame" }, { "name": "explain-data-frame-analytics", "namespace": "ml", "description": "Explain data frame analytics config.", - "method": "GET", - "path": "/_ml/data_frame/analytics/{id}/_explain", "namespaceFile": "ml_explain_data_frame_analytics" }, { "name": "flush-job", "namespace": "ml", "description": "Force buffered data to be processed.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/_flush", "namespaceFile": "ml_flush_job" }, { "name": "forecast", "namespace": "ml", "description": "Predict future behavior of a time series.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/_forecast", "namespaceFile": "ml_forecast" }, { "name": "get-buckets", "namespace": "ml", "description": "Get anomaly detection job results for buckets.", - "method": "GET", - "path": "/_ml/anomaly_detectors/{job_id}/results/buckets/{timestamp}", "namespaceFile": "ml_get_buckets" }, { "name": "get-calendar-events", "namespace": "ml", "description": "Get info about events in calendars.", - "method": "GET", - "path": "/_ml/calendars/{calendar_id}/events", "namespaceFile": "ml_get_calendar_events" }, { "name": "get-calendars", "namespace": "ml", "description": "Get calendar configuration info.", - "method": "GET", - "path": "/_ml/calendars/{calendar_id}", "namespaceFile": "ml_get_calendars" }, { "name": "get-categories", "namespace": "ml", "description": "Get anomaly detection job results for categories.", - "method": "GET", - "path": "/_ml/anomaly_detectors/{job_id}/results/categories/{category_id}", "namespaceFile": "ml_get_categories" }, { "name": "get-data-frame-analytics", "namespace": "ml", "description": "Get data frame analytics job configuration info.", - "method": "GET", - "path": "/_ml/data_frame/analytics/{id}", "namespaceFile": "ml_get_data_frame_analytics" }, { "name": "get-data-frame-analytics-stats", "namespace": "ml", "description": "Get data frame analytics job stats.", - "method": "GET", - "path": "/_ml/data_frame/analytics/{id}/_stats", "namespaceFile": "ml_get_data_frame_analytics_stats" }, { "name": "get-datafeed-stats", "namespace": "ml", "description": "Get datafeed stats.", - "method": "GET", - "path": "/_ml/datafeeds/{datafeed_id}/_stats", "namespaceFile": "ml_get_datafeed_stats" }, { "name": "get-datafeeds", "namespace": "ml", "description": "Get datafeeds configuration info.", - "method": "GET", - "path": "/_ml/datafeeds/{datafeed_id}", "namespaceFile": "ml_get_datafeeds" }, { "name": "get-filters", "namespace": "ml", "description": "Get filters.", - "method": "GET", - "path": "/_ml/filters/{filter_id}", "namespaceFile": "ml_get_filters" }, { "name": "get-influencers", "namespace": "ml", "description": "Get anomaly detection job results for influencers.", - "method": "GET", - "path": "/_ml/anomaly_detectors/{job_id}/results/influencers", "namespaceFile": "ml_get_influencers" }, { "name": "get-job-stats", "namespace": "ml", "description": "Get anomaly detection job stats.", - "method": "GET", - "path": "/_ml/anomaly_detectors/{job_id}/_stats", "namespaceFile": "ml_get_job_stats" }, { "name": "get-jobs", "namespace": "ml", "description": "Get anomaly detection jobs configuration info.", - "method": "GET", - "path": "/_ml/anomaly_detectors/{job_id}", "namespaceFile": "ml_get_jobs" }, { "name": "get-memory-stats", "namespace": "ml", "description": "Get machine learning memory usage info.", - "method": "GET", - "path": "/_ml/memory/{node_id}/_stats", "namespaceFile": "ml_get_memory_stats" }, { "name": "get-model-snapshot-upgrade-stats", "namespace": "ml", "description": "Get anomaly detection job model snapshot upgrade usage info.", - "method": "GET", - "path": "/_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}/_upgrade/_stats", "namespaceFile": "ml_get_model_snapshot_upgrade_stats" }, { "name": "get-model-snapshots", "namespace": "ml", "description": "Get model snapshots info.", - "method": "GET", - "path": "/_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}", "namespaceFile": "ml_get_model_snapshots" }, { "name": "get-overall-buckets", "namespace": "ml", "description": "Get overall bucket results.", - "method": "GET", - "path": "/_ml/anomaly_detectors/{job_id}/results/overall_buckets", "namespaceFile": "ml_get_overall_buckets" }, { "name": "get-records", "namespace": "ml", "description": "Get anomaly records for an anomaly detection job.", - "method": "GET", - "path": "/_ml/anomaly_detectors/{job_id}/results/records", "namespaceFile": "ml_get_records" }, { "name": "get-trained-models", "namespace": "ml", "description": "Get trained model configuration info.", - "method": "GET", - "path": "/_ml/trained_models/{model_id}", "namespaceFile": "ml_get_trained_models" }, { "name": "get-trained-models-stats", "namespace": "ml", "description": "Get trained models usage info.", - "method": "GET", - "path": "/_ml/trained_models/{model_id}/_stats", "namespaceFile": "ml_get_trained_models_stats" }, { "name": "infer-trained-model", "namespace": "ml", "description": "Evaluate a trained model.", - "method": "POST", - "path": "/_ml/trained_models/{model_id}/_infer", "namespaceFile": "ml_infer_trained_model" }, { "name": "info", "namespace": "ml", "description": "Get machine learning information.", - "method": "GET", - "path": "/_ml/info", "namespaceFile": "ml_info" }, { "name": "open-job", "namespace": "ml", "description": "Open anomaly detection jobs.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/_open", "namespaceFile": "ml_open_job" }, { "name": "post-calendar-events", "namespace": "ml", "description": "Add scheduled events to the calendar.", - "method": "POST", - "path": "/_ml/calendars/{calendar_id}/events", "namespaceFile": "ml_post_calendar_events" }, { "name": "post-data", "namespace": "ml", "description": "Send data to an anomaly detection job for analysis.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/_data", - "namespaceFile": "ml_post_data", - "bodyFormat": "ndjson" + "namespaceFile": "ml_post_data" }, { "name": "preview-data-frame-analytics", "namespace": "ml", "description": "Preview features used by data frame analytics.", - "method": "GET", - "path": "/_ml/data_frame/analytics/{id}/_preview", "namespaceFile": "ml_preview_data_frame_analytics" }, { "name": "preview-datafeed", "namespace": "ml", "description": "Preview a datafeed.", - "method": "GET", - "path": "/_ml/datafeeds/{datafeed_id}/_preview", "namespaceFile": "ml_preview_datafeed" }, { "name": "put-calendar", "namespace": "ml", "description": "Create a calendar.", - "method": "PUT", - "path": "/_ml/calendars/{calendar_id}", "namespaceFile": "ml_put_calendar" }, { "name": "put-calendar-job", "namespace": "ml", "description": "Add anomaly detection job to calendar.", - "method": "PUT", - "path": "/_ml/calendars/{calendar_id}/jobs/{job_id}", "namespaceFile": "ml_put_calendar_job" }, { "name": "put-data-frame-analytics", "namespace": "ml", "description": "Create a data frame analytics job.", - "method": "PUT", - "path": "/_ml/data_frame/analytics/{id}", "namespaceFile": "ml_put_data_frame_analytics" }, { "name": "put-datafeed", "namespace": "ml", "description": "Create a datafeed.", - "method": "PUT", - "path": "/_ml/datafeeds/{datafeed_id}", "namespaceFile": "ml_put_datafeed" }, { "name": "put-filter", "namespace": "ml", "description": "Create a filter.", - "method": "PUT", - "path": "/_ml/filters/{filter_id}", "namespaceFile": "ml_put_filter" }, { "name": "put-job", "namespace": "ml", "description": "Create an anomaly detection job.", - "method": "PUT", - "path": "/_ml/anomaly_detectors/{job_id}", "namespaceFile": "ml_put_job" }, { "name": "put-trained-model", "namespace": "ml", "description": "Create a trained model.", - "method": "PUT", - "path": "/_ml/trained_models/{model_id}", "namespaceFile": "ml_put_trained_model" }, { "name": "put-trained-model-alias", "namespace": "ml", "description": "Create or update a trained model alias.", - "method": "PUT", - "path": "/_ml/trained_models/{model_id}/model_aliases/{model_alias}", "namespaceFile": "ml_put_trained_model_alias" }, { "name": "put-trained-model-definition-part", "namespace": "ml", "description": "Create part of a trained model definition.", - "method": "PUT", - "path": "/_ml/trained_models/{model_id}/definition/{part}", "namespaceFile": "ml_put_trained_model_definition_part" }, { "name": "put-trained-model-vocabulary", "namespace": "ml", "description": "Create a trained model vocabulary.", - "method": "PUT", - "path": "/_ml/trained_models/{model_id}/vocabulary", "namespaceFile": "ml_put_trained_model_vocabulary" }, { "name": "reset-job", "namespace": "ml", "description": "Reset an anomaly detection job.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/_reset", "namespaceFile": "ml_reset_job" }, { "name": "revert-model-snapshot", "namespace": "ml", "description": "Revert to a snapshot.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}/_revert", "namespaceFile": "ml_revert_model_snapshot" }, { "name": "set-upgrade-mode", "namespace": "ml", "description": "Set upgrade_mode for ML indices.", - "method": "POST", - "path": "/_ml/set_upgrade_mode", "namespaceFile": "ml_set_upgrade_mode" }, { "name": "start-data-frame-analytics", "namespace": "ml", "description": "Start a data frame analytics job.", - "method": "POST", - "path": "/_ml/data_frame/analytics/{id}/_start", "namespaceFile": "ml_start_data_frame_analytics" }, { "name": "start-datafeed", "namespace": "ml", "description": "Start datafeeds.", - "method": "POST", - "path": "/_ml/datafeeds/{datafeed_id}/_start", "namespaceFile": "ml_start_datafeed" }, { "name": "start-trained-model-deployment", "namespace": "ml", "description": "Start a trained model deployment.", - "method": "POST", - "path": "/_ml/trained_models/{model_id}/deployment/_start", "namespaceFile": "ml_start_trained_model_deployment" }, { "name": "stop-data-frame-analytics", "namespace": "ml", "description": "Stop data frame analytics jobs.", - "method": "POST", - "path": "/_ml/data_frame/analytics/{id}/_stop", "namespaceFile": "ml_stop_data_frame_analytics" }, { "name": "stop-datafeed", "namespace": "ml", "description": "Stop datafeeds.", - "method": "POST", - "path": "/_ml/datafeeds/{datafeed_id}/_stop", "namespaceFile": "ml_stop_datafeed" }, { "name": "stop-trained-model-deployment", "namespace": "ml", "description": "Stop a trained model deployment.", - "method": "POST", - "path": "/_ml/trained_models/{model_id}/deployment/_stop", "namespaceFile": "ml_stop_trained_model_deployment" }, { "name": "update-data-frame-analytics", "namespace": "ml", "description": "Update a data frame analytics job.", - "method": "POST", - "path": "/_ml/data_frame/analytics/{id}/_update", "namespaceFile": "ml_update_data_frame_analytics" }, { "name": "update-datafeed", "namespace": "ml", "description": "Update a datafeed.", - "method": "POST", - "path": "/_ml/datafeeds/{datafeed_id}/_update", "namespaceFile": "ml_update_datafeed" }, { "name": "update-filter", "namespace": "ml", "description": "Update a filter.", - "method": "POST", - "path": "/_ml/filters/{filter_id}/_update", "namespaceFile": "ml_update_filter" }, { "name": "update-job", "namespace": "ml", "description": "Update an anomaly detection job.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/_update", "namespaceFile": "ml_update_job" }, { "name": "update-model-snapshot", "namespace": "ml", "description": "Update a snapshot.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}/_update", "namespaceFile": "ml_update_model_snapshot" }, { "name": "update-trained-model-deployment", "namespace": "ml", "description": "Update a trained model deployment.", - "method": "POST", - "path": "/_ml/trained_models/{model_id}/deployment/_update", "namespaceFile": "ml_update_trained_model_deployment" }, { "name": "upgrade-job-snapshot", "namespace": "ml", "description": "Upgrade a snapshot.", - "method": "POST", - "path": "/_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}/_upgrade", "namespaceFile": "ml_upgrade_job_snapshot" }, { "name": "msearch", "namespace": null, "description": "Run multiple searches.", - "method": "GET", - "path": "/{index}/_msearch", - "namespaceFile": "msearch", - "bodyFormat": "ndjson" + "namespaceFile": "msearch" }, { "name": "msearch-template", "namespace": null, "description": "Run multiple templated searches.", - "method": "GET", - "path": "/{index}/_msearch/template", - "namespaceFile": "msearch_template", - "bodyFormat": "ndjson" + "namespaceFile": "msearch_template" }, { "name": "mtermvectors", "namespace": null, "description": "Get multiple term vectors.", - "method": "GET", - "path": "/{index}/_mtermvectors", "namespaceFile": "mtermvectors" }, { "name": "clear-repositories-metering-archive", "namespace": "nodes", "description": "Clear the archived repositories metering.", - "method": "DELETE", - "path": "/_nodes/{node_id}/_repositories_metering/{max_archive_version}", "namespaceFile": "nodes_clear_repositories_metering_archive" }, { "name": "get-repositories-metering-info", "namespace": "nodes", "description": "Get cluster repositories metering.", - "method": "GET", - "path": "/_nodes/{node_id}/_repositories_metering", "namespaceFile": "nodes_get_repositories_metering_info" }, { "name": "hot-threads", "namespace": "nodes", "description": "Get the hot threads for nodes.", - "method": "GET", - "path": "/_nodes/{node_id}/hot_threads", - "namespaceFile": "nodes_hot_threads", - "responseType": "text" + "namespaceFile": "nodes_hot_threads" }, { "name": "info", "namespace": "nodes", "description": "Get node information.", - "method": "GET", - "path": "/_nodes/{node_id}/{metric}", "namespaceFile": "nodes_info" }, { "name": "reload-secure-settings", "namespace": "nodes", "description": "Reload the keystore on nodes in the cluster.", - "method": "POST", - "path": "/_nodes/{node_id}/reload_secure_settings", "namespaceFile": "nodes_reload_secure_settings" }, { "name": "stats", "namespace": "nodes", "description": "Get node statistics.", - "method": "GET", - "path": "/_nodes/{node_id}/stats/{metric}/{index_metric}", "namespaceFile": "nodes_stats" }, { "name": "usage", "namespace": "nodes", "description": "Get feature usage information.", - "method": "GET", - "path": "/_nodes/{node_id}/usage/{metric}", "namespaceFile": "nodes_usage" }, { "name": "open-point-in-time", "namespace": null, "description": "Open a point in time.", - "method": "POST", - "path": "/{index}/_pit", "namespaceFile": "open_point_in_time" }, { "name": "ping", "namespace": null, "description": "Ping the cluster.", - "method": "HEAD", - "path": "/", "namespaceFile": "ping" }, { "name": "create-many-routing", "namespace": "project", "description": "Create or update project routing expressions.", - "method": "PUT", - "path": "/_project_routing", "namespaceFile": "project_create_many_routing" }, { "name": "create-routing", "namespace": "project", "description": "Create or update a project routing expression.", - "method": "PUT", - "path": "/_project_routing/{name}", "namespaceFile": "project_create_routing" }, { "name": "delete-routing", "namespace": "project", "description": "Delete a project routing expression.", - "method": "DELETE", - "path": "/_project_routing/{name}", "namespaceFile": "project_delete_routing" }, { "name": "get-many-routing", "namespace": "project", "description": "Get project routing expressions.", - "method": "GET", - "path": "/_project_routing", "namespaceFile": "project_get_many_routing" }, { "name": "get-routing", "namespace": "project", "description": "Get a project routing expression.", - "method": "GET", - "path": "/_project_routing/{name}", "namespaceFile": "project_get_routing" }, { "name": "tags", "namespace": "project", "description": "Get tags.", - "method": "GET", - "path": "/_project/tags", "namespaceFile": "project_tags" }, { "name": "put-script", "namespace": null, "description": "Create or update a script or search template.", - "method": "PUT", - "path": "/_scripts/{id}/{context}", "namespaceFile": "put_script" }, { "name": "delete-rule", "namespace": "query-rules", "description": "Delete a query rule.", - "method": "DELETE", - "path": "/_query_rules/{ruleset_id}/_rule/{rule_id}", "namespaceFile": "query_rules_delete_rule" }, { "name": "delete-ruleset", "namespace": "query-rules", "description": "Delete a query ruleset.", - "method": "DELETE", - "path": "/_query_rules/{ruleset_id}", "namespaceFile": "query_rules_delete_ruleset" }, { "name": "get-rule", "namespace": "query-rules", "description": "Get a query rule.", - "method": "GET", - "path": "/_query_rules/{ruleset_id}/_rule/{rule_id}", "namespaceFile": "query_rules_get_rule" }, { "name": "get-ruleset", "namespace": "query-rules", "description": "Get a query ruleset.", - "method": "GET", - "path": "/_query_rules/{ruleset_id}", "namespaceFile": "query_rules_get_ruleset" }, { "name": "list-rulesets", "namespace": "query-rules", "description": "Get all query rulesets.", - "method": "GET", - "path": "/_query_rules", "namespaceFile": "query_rules_list_rulesets" }, { "name": "put-rule", "namespace": "query-rules", "description": "Create or update a query rule.", - "method": "PUT", - "path": "/_query_rules/{ruleset_id}/_rule/{rule_id}", "namespaceFile": "query_rules_put_rule" }, { "name": "put-ruleset", "namespace": "query-rules", "description": "Create or update a query ruleset.", - "method": "PUT", - "path": "/_query_rules/{ruleset_id}", "namespaceFile": "query_rules_put_ruleset" }, { "name": "test", "namespace": "query-rules", "description": "Test a query ruleset.", - "method": "POST", - "path": "/_query_rules/{ruleset_id}/_test", "namespaceFile": "query_rules_test" }, { "name": "rank-eval", "namespace": null, "description": "Evaluate ranked search results.", - "method": "GET", - "path": "/{index}/_rank_eval", "namespaceFile": "rank_eval" }, { "name": "reindex", "namespace": null, "description": "Reindex documents.", - "method": "POST", - "path": "/_reindex", "namespaceFile": "reindex" }, { "name": "reindex-rethrottle", "namespace": null, "description": "Throttle a reindex operation.", - "method": "POST", - "path": "/_reindex/{task_id}/_rethrottle", "namespaceFile": "reindex_rethrottle" }, { "name": "render-search-template", "namespace": null, "description": "Render a search template.", - "method": "GET", - "path": "/_render/template/{id}", "namespaceFile": "render_search_template" }, { "name": "delete-job", "namespace": "rollup", "description": "Delete a rollup job.", - "method": "DELETE", - "path": "/_rollup/job/{id}", "namespaceFile": "rollup_delete_job" }, { "name": "get-jobs", "namespace": "rollup", "description": "Get rollup job information.", - "method": "GET", - "path": "/_rollup/job/{id}", "namespaceFile": "rollup_get_jobs" }, { "name": "get-rollup-caps", "namespace": "rollup", "description": "Get the rollup job capabilities.", - "method": "GET", - "path": "/_rollup/data/{id}", "namespaceFile": "rollup_get_rollup_caps" }, { "name": "get-rollup-index-caps", "namespace": "rollup", "description": "Get the rollup index capabilities.", - "method": "GET", - "path": "/{index}/_rollup/data", "namespaceFile": "rollup_get_rollup_index_caps" }, { "name": "put-job", "namespace": "rollup", "description": "Create a rollup job.", - "method": "PUT", - "path": "/_rollup/job/{id}", "namespaceFile": "rollup_put_job" }, { "name": "rollup-search", "namespace": "rollup", "description": "Search rolled-up data.", - "method": "GET", - "path": "/{index}/_rollup_search", "namespaceFile": "rollup_rollup_search" }, { "name": "start-job", "namespace": "rollup", "description": "Start rollup jobs.", - "method": "POST", - "path": "/_rollup/job/{id}/_start", "namespaceFile": "rollup_start_job" }, { "name": "stop-job", "namespace": "rollup", "description": "Stop rollup jobs.", - "method": "POST", - "path": "/_rollup/job/{id}/_stop", "namespaceFile": "rollup_stop_job" }, { "name": "scripts-painless-execute", "namespace": null, "description": "Run a script.", - "method": "GET", - "path": "/_scripts/painless/_execute", "namespaceFile": "scripts_painless_execute" }, { "name": "scroll", "namespace": null, "description": "Run a scrolling search.", - "method": "GET", - "path": "/_search/scroll", "namespaceFile": "scroll" }, { "name": "search", "namespace": null, "description": "Run a search.", - "method": "GET", - "path": "/{index}/_search", "namespaceFile": "search" }, { "name": "delete", "namespace": "search-application", "description": "Delete a search application.", - "method": "DELETE", - "path": "/_application/search_application/{name}", "namespaceFile": "search_application_delete" }, { "name": "delete-behavioral-analytics", "namespace": "search-application", "description": "Delete a behavioral analytics collection.", - "method": "DELETE", - "path": "/_application/analytics/{name}", "namespaceFile": "search_application_delete_behavioral_analytics" }, { "name": "get", "namespace": "search-application", "description": "Get search application details.", - "method": "GET", - "path": "/_application/search_application/{name}", "namespaceFile": "search_application_get" }, { "name": "get-behavioral-analytics", "namespace": "search-application", "description": "Get behavioral analytics collections.", - "method": "GET", - "path": "/_application/analytics/{name}", "namespaceFile": "search_application_get_behavioral_analytics" }, { "name": "list", "namespace": "search-application", "description": "Get search applications.", - "method": "GET", - "path": "/_application/search_application", "namespaceFile": "search_application_list" }, { "name": "post-behavioral-analytics-event", "namespace": "search-application", "description": "Create a behavioral analytics collection event.", - "method": "POST", - "path": "/_application/analytics/{collection_name}/event/{event_type}", "namespaceFile": "search_application_post_behavioral_analytics_event" }, { "name": "put", "namespace": "search-application", "description": "Create or update a search application.", - "method": "PUT", - "path": "/_application/search_application/{name}", "namespaceFile": "search_application_put" }, { "name": "put-behavioral-analytics", "namespace": "search-application", "description": "Create a behavioral analytics collection.", - "method": "PUT", - "path": "/_application/analytics/{name}", "namespaceFile": "search_application_put_behavioral_analytics" }, { "name": "render-query", "namespace": "search-application", "description": "Render a search application query.", - "method": "POST", - "path": "/_application/search_application/{name}/_render_query", "namespaceFile": "search_application_render_query" }, { "name": "search", "namespace": "search-application", "description": "Run a search application search.", - "method": "GET", - "path": "/_application/search_application/{name}/_search", "namespaceFile": "search_application_search" }, { "name": "search-mvt", "namespace": null, "description": "Search a vector tile.", - "method": "POST", - "path": "/{index}/_mvt/{field}/{zoom}/{x}/{y}", "namespaceFile": "search_mvt" }, { "name": "search-shards", "namespace": null, "description": "Get the search shards.", - "method": "GET", - "path": "/{index}/_search_shards", "namespaceFile": "search_shards" }, { "name": "search-template", "namespace": null, "description": "Run a search with a search template.", - "method": "GET", - "path": "/{index}/_search/template", "namespaceFile": "search_template" }, { "name": "cache-stats", "namespace": "searchable-snapshots", "description": "Get cache statistics.", - "method": "GET", - "path": "/_searchable_snapshots/{node_id}/cache/stats", "namespaceFile": "searchable_snapshots_cache_stats" }, { "name": "clear-cache", "namespace": "searchable-snapshots", "description": "Clear the cache.", - "method": "POST", - "path": "/{index}/_searchable_snapshots/cache/clear", "namespaceFile": "searchable_snapshots_clear_cache" }, { "name": "mount", "namespace": "searchable-snapshots", "description": "Mount a snapshot.", - "method": "POST", - "path": "/_snapshot/{repository}/{snapshot}/_mount", "namespaceFile": "searchable_snapshots_mount" }, { "name": "stats", "namespace": "searchable-snapshots", "description": "Get searchable snapshot statistics.", - "method": "GET", - "path": "/{index}/_searchable_snapshots/stats", "namespaceFile": "searchable_snapshots_stats" }, { "name": "activate-user-profile", "namespace": "security", "description": "Activate a user profile.", - "method": "POST", - "path": "/_security/profile/_activate", "namespaceFile": "security_activate_user_profile" }, { "name": "authenticate", "namespace": "security", "description": "Authenticate a user.", - "method": "GET", - "path": "/_security/_authenticate", "namespaceFile": "security_authenticate" }, { "name": "bulk-delete-role", "namespace": "security", "description": "Bulk delete roles.", - "method": "DELETE", - "path": "/_security/role", "namespaceFile": "security_bulk_delete_role" }, { "name": "bulk-put-role", "namespace": "security", "description": "Bulk create or update roles.", - "method": "POST", - "path": "/_security/role", "namespaceFile": "security_bulk_put_role" }, { "name": "bulk-update-api-keys", "namespace": "security", "description": "Bulk update API keys.", - "method": "POST", - "path": "/_security/api_key/_bulk_update", "namespaceFile": "security_bulk_update_api_keys" }, { "name": "change-password", "namespace": "security", "description": "Change passwords.", - "method": "PUT", - "path": "/_security/user/{username}/_password", "namespaceFile": "security_change_password" }, { "name": "clear-api-key-cache", "namespace": "security", "description": "Clear the API key cache.", - "method": "POST", - "path": "/_security/api_key/{ids}/_clear_cache", "namespaceFile": "security_clear_api_key_cache" }, { "name": "clear-cached-privileges", "namespace": "security", "description": "Clear the privileges cache.", - "method": "POST", - "path": "/_security/privilege/{application}/_clear_cache", "namespaceFile": "security_clear_cached_privileges" }, { "name": "clear-cached-realms", "namespace": "security", "description": "Clear the user cache.", - "method": "POST", - "path": "/_security/realm/{realms}/_clear_cache", "namespaceFile": "security_clear_cached_realms" }, { "name": "clear-cached-roles", "namespace": "security", "description": "Clear the roles cache.", - "method": "POST", - "path": "/_security/role/{name}/_clear_cache", "namespaceFile": "security_clear_cached_roles" }, { "name": "clear-cached-service-tokens", "namespace": "security", "description": "Clear service account token caches.", - "method": "POST", - "path": "/_security/service/{namespace}/{service}/credential/token/{name}/_clear_cache", "namespaceFile": "security_clear_cached_service_tokens" }, { "name": "clone-api-key", "namespace": "security", "description": "Clone an API key.", - "method": "POST", - "path": "/_security/api_key/clone", "namespaceFile": "security_clone_api_key" }, { "name": "create-api-key", "namespace": "security", "description": "Create an API key.", - "method": "PUT", - "path": "/_security/api_key", "namespaceFile": "security_create_api_key" }, { "name": "create-cross-cluster-api-key", "namespace": "security", "description": "Create a cross-cluster API key.", - "method": "POST", - "path": "/_security/cross_cluster/api_key", "namespaceFile": "security_create_cross_cluster_api_key" }, { "name": "create-service-token", "namespace": "security", "description": "Create a service account token.", - "method": "PUT", - "path": "/_security/service/{namespace}/{service}/credential/token/{name}", "namespaceFile": "security_create_service_token" }, { "name": "delegate-pki", "namespace": "security", "description": "Delegate PKI authentication.", - "method": "POST", - "path": "/_security/delegate_pki", "namespaceFile": "security_delegate_pki" }, { "name": "delete-privileges", "namespace": "security", "description": "Delete application privileges.", - "method": "DELETE", - "path": "/_security/privilege/{application}/{name}", "namespaceFile": "security_delete_privileges" }, { "name": "delete-role", "namespace": "security", "description": "Delete roles.", - "method": "DELETE", - "path": "/_security/role/{name}", "namespaceFile": "security_delete_role" }, { "name": "delete-role-mapping", "namespace": "security", "description": "Delete role mappings.", - "method": "DELETE", - "path": "/_security/role_mapping/{name}", "namespaceFile": "security_delete_role_mapping" }, { "name": "delete-service-token", "namespace": "security", "description": "Delete service account tokens.", - "method": "DELETE", - "path": "/_security/service/{namespace}/{service}/credential/token/{name}", "namespaceFile": "security_delete_service_token" }, { "name": "delete-user", "namespace": "security", "description": "Delete users.", - "method": "DELETE", - "path": "/_security/user/{username}", "namespaceFile": "security_delete_user" }, { "name": "disable-user", "namespace": "security", "description": "Disable users.", - "method": "PUT", - "path": "/_security/user/{username}/_disable", "namespaceFile": "security_disable_user" }, { "name": "disable-user-profile", "namespace": "security", "description": "Disable a user profile.", - "method": "PUT", - "path": "/_security/profile/{uid}/_disable", "namespaceFile": "security_disable_user_profile" }, { "name": "enable-user", "namespace": "security", "description": "Enable users.", - "method": "PUT", - "path": "/_security/user/{username}/_enable", "namespaceFile": "security_enable_user" }, { "name": "enable-user-profile", "namespace": "security", "description": "Enable a user profile.", - "method": "PUT", - "path": "/_security/profile/{uid}/_enable", "namespaceFile": "security_enable_user_profile" }, { "name": "enroll-kibana", "namespace": "security", "description": "Enroll Kibana.", - "method": "GET", - "path": "/_security/enroll/kibana", "namespaceFile": "security_enroll_kibana" }, { "name": "enroll-node", "namespace": "security", "description": "Enroll a node.", - "method": "GET", - "path": "/_security/enroll/node", "namespaceFile": "security_enroll_node" }, { "name": "get-api-key", "namespace": "security", "description": "Get API key information.", - "method": "GET", - "path": "/_security/api_key", "namespaceFile": "security_get_api_key" }, { "name": "get-builtin-privileges", "namespace": "security", "description": "Get builtin privileges.", - "method": "GET", - "path": "/_security/privilege/_builtin", "namespaceFile": "security_get_builtin_privileges" }, { "name": "get-privileges", "namespace": "security", "description": "Get application privileges.", - "method": "GET", - "path": "/_security/privilege/{application}/{name}", "namespaceFile": "security_get_privileges" }, { "name": "get-role", "namespace": "security", "description": "Get roles.", - "method": "GET", - "path": "/_security/role/{name}", "namespaceFile": "security_get_role" }, { "name": "get-role-mapping", "namespace": "security", "description": "Get role mappings.", - "method": "GET", - "path": "/_security/role_mapping/{name}", "namespaceFile": "security_get_role_mapping" }, { "name": "get-service-accounts", "namespace": "security", "description": "Get service accounts.", - "method": "GET", - "path": "/_security/service/{namespace}/{service}", "namespaceFile": "security_get_service_accounts" }, { "name": "get-service-credentials", "namespace": "security", "description": "Get service account credentials.", - "method": "GET", - "path": "/_security/service/{namespace}/{service}/credential", "namespaceFile": "security_get_service_credentials" }, { "name": "get-settings", "namespace": "security", "description": "Get security index settings.", - "method": "GET", - "path": "/_security/settings", "namespaceFile": "security_get_settings" }, { "name": "get-stats", "namespace": "security", "description": "Get security stats.", - "method": "GET", - "path": "/_security/stats", "namespaceFile": "security_get_stats" }, { "name": "get-token", "namespace": "security", "description": "Get a token.", - "method": "POST", - "path": "/_security/oauth2/token", "namespaceFile": "security_get_token" }, { "name": "get-user", "namespace": "security", "description": "Get users.", - "method": "GET", - "path": "/_security/user/{username}", "namespaceFile": "security_get_user" }, { "name": "get-user-privileges", "namespace": "security", "description": "Get user privileges.", - "method": "GET", - "path": "/_security/user/_privileges", "namespaceFile": "security_get_user_privileges" }, { "name": "get-user-profile", "namespace": "security", "description": "Get a user profile.", - "method": "GET", - "path": "/_security/profile/{uid}", "namespaceFile": "security_get_user_profile" }, { "name": "grant-api-key", "namespace": "security", "description": "Grant an API key.", - "method": "POST", - "path": "/_security/api_key/grant", "namespaceFile": "security_grant_api_key" }, { "name": "has-privileges", "namespace": "security", "description": "Check user privileges.", - "method": "GET", - "path": "/_security/user/{user}/_has_privileges", "namespaceFile": "security_has_privileges" }, { "name": "has-privileges-user-profile", "namespace": "security", "description": "Check user profile privileges.", - "method": "GET", - "path": "/_security/profile/_has_privileges", "namespaceFile": "security_has_privileges_user_profile" }, { "name": "invalidate-api-key", "namespace": "security", "description": "Invalidate API keys.", - "method": "DELETE", - "path": "/_security/api_key", "namespaceFile": "security_invalidate_api_key" }, { "name": "invalidate-token", "namespace": "security", "description": "Invalidate a token.", - "method": "DELETE", - "path": "/_security/oauth2/token", "namespaceFile": "security_invalidate_token" }, { "name": "oidc-authenticate", "namespace": "security", "description": "Authenticate OpenID Connect.", - "method": "POST", - "path": "/_security/oidc/authenticate", "namespaceFile": "security_oidc_authenticate" }, { "name": "oidc-logout", "namespace": "security", "description": "Logout of OpenID Connect.", - "method": "POST", - "path": "/_security/oidc/logout", "namespaceFile": "security_oidc_logout" }, { "name": "oidc-prepare-authentication", "namespace": "security", "description": "Prepare OpenID connect authentication.", - "method": "POST", - "path": "/_security/oidc/prepare", "namespaceFile": "security_oidc_prepare_authentication" }, { "name": "put-privileges", "namespace": "security", "description": "Create or update application privileges.", - "method": "PUT", - "path": "/_security/privilege", "namespaceFile": "security_put_privileges" }, { "name": "put-role", "namespace": "security", "description": "Create or update roles.", - "method": "PUT", - "path": "/_security/role/{name}", "namespaceFile": "security_put_role" }, { "name": "put-role-mapping", "namespace": "security", "description": "Create or update role mappings.", - "method": "PUT", - "path": "/_security/role_mapping/{name}", "namespaceFile": "security_put_role_mapping" }, { "name": "put-user", "namespace": "security", "description": "Create or update users.", - "method": "PUT", - "path": "/_security/user/{username}", "namespaceFile": "security_put_user" }, { "name": "query-api-keys", "namespace": "security", "description": "Find API keys with a query.", - "method": "GET", - "path": "/_security/_query/api_key", "namespaceFile": "security_query_api_keys" }, { "name": "query-role", "namespace": "security", "description": "Find roles with a query.", - "method": "GET", - "path": "/_security/_query/role", "namespaceFile": "security_query_role" }, { "name": "query-user", "namespace": "security", "description": "Find users with a query.", - "method": "GET", - "path": "/_security/_query/user", "namespaceFile": "security_query_user" }, { "name": "saml-authenticate", "namespace": "security", "description": "Authenticate SAML.", - "method": "POST", - "path": "/_security/saml/authenticate", "namespaceFile": "security_saml_authenticate" }, { "name": "saml-complete-logout", "namespace": "security", "description": "Logout of SAML completely.", - "method": "POST", - "path": "/_security/saml/complete_logout", "namespaceFile": "security_saml_complete_logout" }, { "name": "saml-invalidate", "namespace": "security", "description": "Invalidate SAML.", - "method": "POST", - "path": "/_security/saml/invalidate", "namespaceFile": "security_saml_invalidate" }, { "name": "saml-logout", "namespace": "security", "description": "Logout of SAML.", - "method": "POST", - "path": "/_security/saml/logout", "namespaceFile": "security_saml_logout" }, { "name": "saml-prepare-authentication", "namespace": "security", "description": "Prepare SAML authentication.", - "method": "POST", - "path": "/_security/saml/prepare", "namespaceFile": "security_saml_prepare_authentication" }, { "name": "saml-service-provider-metadata", "namespace": "security", "description": "Create SAML service provider metadata.", - "method": "GET", - "path": "/_security/saml/metadata/{realm_name}", "namespaceFile": "security_saml_service_provider_metadata" }, { "name": "suggest-user-profiles", "namespace": "security", "description": "Suggest a user profile.", - "method": "GET", - "path": "/_security/profile/_suggest", "namespaceFile": "security_suggest_user_profiles" }, { "name": "update-api-key", "namespace": "security", "description": "Update an API key.", - "method": "PUT", - "path": "/_security/api_key/{id}", "namespaceFile": "security_update_api_key" }, { "name": "update-cross-cluster-api-key", "namespace": "security", "description": "Update a cross-cluster API key.", - "method": "PUT", - "path": "/_security/cross_cluster/api_key/{id}", "namespaceFile": "security_update_cross_cluster_api_key" }, { "name": "update-settings", "namespace": "security", "description": "Update security index settings.", - "method": "PUT", - "path": "/_security/settings", "namespaceFile": "security_update_settings" }, { "name": "update-user-profile-data", "namespace": "security", "description": "Update user profile data.", - "method": "PUT", - "path": "/_security/profile/{uid}/_data", "namespaceFile": "security_update_user_profile_data" }, { "name": "ingest", "namespace": "simulate", "description": "Simulate data ingestion.", - "method": "GET", - "path": "/_ingest/{index}/_simulate", "namespaceFile": "simulate_ingest" }, { "name": "delete-lifecycle", "namespace": "slm", "description": "Delete a policy.", - "method": "DELETE", - "path": "/_slm/policy/{policy_id}", "namespaceFile": "slm_delete_lifecycle" }, { "name": "execute-lifecycle", "namespace": "slm", "description": "Run a policy.", - "method": "PUT", - "path": "/_slm/policy/{policy_id}/_execute", "namespaceFile": "slm_execute_lifecycle" }, { "name": "execute-retention", "namespace": "slm", "description": "Run a retention policy.", - "method": "POST", - "path": "/_slm/_execute_retention", "namespaceFile": "slm_execute_retention" }, { "name": "get-lifecycle", "namespace": "slm", "description": "Get policy information.", - "method": "GET", - "path": "/_slm/policy/{policy_id}", "namespaceFile": "slm_get_lifecycle" }, { "name": "get-stats", "namespace": "slm", "description": "Get snapshot lifecycle management statistics.", - "method": "GET", - "path": "/_slm/stats", "namespaceFile": "slm_get_stats" }, { "name": "get-status", "namespace": "slm", "description": "Get the snapshot lifecycle management status.", - "method": "GET", - "path": "/_slm/status", "namespaceFile": "slm_get_status" }, { "name": "put-lifecycle", "namespace": "slm", "description": "Create or update a policy.", - "method": "PUT", - "path": "/_slm/policy/{policy_id}", "namespaceFile": "slm_put_lifecycle" }, { "name": "start", "namespace": "slm", "description": "Start snapshot lifecycle management.", - "method": "POST", - "path": "/_slm/start", "namespaceFile": "slm_start" }, { "name": "stop", "namespace": "slm", "description": "Stop snapshot lifecycle management.", - "method": "POST", - "path": "/_slm/stop", "namespaceFile": "slm_stop" }, { "name": "cleanup-repository", "namespace": "snapshot", "description": "Clean up the snapshot repository.", - "method": "POST", - "path": "/_snapshot/{repository}/_cleanup", "namespaceFile": "snapshot_cleanup_repository" }, { "name": "clone", "namespace": "snapshot", "description": "Clone a snapshot.", - "method": "PUT", - "path": "/_snapshot/{repository}/{snapshot}/_clone/{target_snapshot}", "namespaceFile": "snapshot_clone" }, { "name": "create", "namespace": "snapshot", "description": "Create a snapshot.", - "method": "PUT", - "path": "/_snapshot/{repository}/{snapshot}", "namespaceFile": "snapshot_create" }, { "name": "create-repository", "namespace": "snapshot", "description": "Create or update a snapshot repository.", - "method": "PUT", - "path": "/_snapshot/{repository}", "namespaceFile": "snapshot_create_repository" }, { "name": "delete", "namespace": "snapshot", "description": "Delete snapshots.", - "method": "DELETE", - "path": "/_snapshot/{repository}/{snapshot}", "namespaceFile": "snapshot_delete" }, { "name": "delete-repository", "namespace": "snapshot", "description": "Delete snapshot repositories.", - "method": "DELETE", - "path": "/_snapshot/{repository}", "namespaceFile": "snapshot_delete_repository" }, { "name": "get", "namespace": "snapshot", "description": "Get snapshot information.", - "method": "GET", - "path": "/_snapshot/{repository}/{snapshot}", "namespaceFile": "snapshot_get" }, { "name": "get-repository", "namespace": "snapshot", "description": "Get snapshot repository information.", - "method": "GET", - "path": "/_snapshot/{repository}", "namespaceFile": "snapshot_get_repository" }, { "name": "repository-analyze", "namespace": "snapshot", "description": "Analyze a snapshot repository.", - "method": "POST", - "path": "/_snapshot/{repository}/_analyze", "namespaceFile": "snapshot_repository_analyze" }, { "name": "repository-verify-integrity", "namespace": "snapshot", "description": "Verify the repository integrity.", - "method": "POST", - "path": "/_snapshot/{repository}/_verify_integrity", "namespaceFile": "snapshot_repository_verify_integrity" }, { "name": "restore", "namespace": "snapshot", "description": "Restore a snapshot.", - "method": "POST", - "path": "/_snapshot/{repository}/{snapshot}/_restore", "namespaceFile": "snapshot_restore" }, { "name": "status", "namespace": "snapshot", "description": "Get the snapshot status.", - "method": "GET", - "path": "/_snapshot/{repository}/{snapshot}/_status", "namespaceFile": "snapshot_status" }, { "name": "verify-repository", "namespace": "snapshot", "description": "Verify a snapshot repository.", - "method": "POST", - "path": "/_snapshot/{repository}/_verify", "namespaceFile": "snapshot_verify_repository" }, { "name": "clear-cursor", "namespace": "sql", "description": "Clear an SQL search cursor.", - "method": "POST", - "path": "/_sql/close", "namespaceFile": "sql_clear_cursor" }, { "name": "delete-async", "namespace": "sql", "description": "Delete an async SQL search.", - "method": "DELETE", - "path": "/_sql/async/delete/{id}", "namespaceFile": "sql_delete_async" }, { "name": "get-async", "namespace": "sql", "description": "Get async SQL search results.", - "method": "GET", - "path": "/_sql/async/{id}", "namespaceFile": "sql_get_async" }, { "name": "get-async-status", "namespace": "sql", "description": "Get the async SQL search status.", - "method": "GET", - "path": "/_sql/async/status/{id}", "namespaceFile": "sql_get_async_status" }, { "name": "query", "namespace": "sql", "description": "Get SQL search results.", - "method": "POST", - "path": "/_sql", "namespaceFile": "sql_query" }, { "name": "translate", "namespace": "sql", "description": "Translate SQL into Elasticsearch queries.", - "method": "POST", - "path": "/_sql/translate", "namespaceFile": "sql_translate" }, { "name": "certificates", "namespace": "ssl", "description": "Get SSL certificates.", - "method": "GET", - "path": "/_ssl/certificates", "namespaceFile": "ssl_certificates" }, { "name": "logs-disable", "namespace": "streams", "description": "Disable a named stream.", - "method": "POST", - "path": "/_streams/{name}/_disable", "namespaceFile": "streams_logs_disable" }, { "name": "logs-enable", "namespace": "streams", "description": "Enable a named stream.", - "method": "POST", - "path": "/_streams/{name}/_enable", "namespaceFile": "streams_logs_enable" }, { "name": "status", "namespace": "streams", "description": "Get the status of streams.", - "method": "GET", - "path": "/_streams/status", "namespaceFile": "streams_status" }, { "name": "delete-synonym", "namespace": "synonyms", "description": "Delete a synonym set.", - "method": "DELETE", - "path": "/_synonyms/{id}", "namespaceFile": "synonyms_delete_synonym" }, { "name": "delete-synonym-rule", "namespace": "synonyms", "description": "Delete a synonym rule.", - "method": "DELETE", - "path": "/_synonyms/{set_id}/{rule_id}", "namespaceFile": "synonyms_delete_synonym_rule" }, { "name": "get-synonym", "namespace": "synonyms", "description": "Get a synonym set.", - "method": "GET", - "path": "/_synonyms/{id}", "namespaceFile": "synonyms_get_synonym" }, { "name": "get-synonym-rule", "namespace": "synonyms", "description": "Get a synonym rule.", - "method": "GET", - "path": "/_synonyms/{set_id}/{rule_id}", "namespaceFile": "synonyms_get_synonym_rule" }, { "name": "get-synonyms-sets", "namespace": "synonyms", "description": "Get all synonym sets.", - "method": "GET", - "path": "/_synonyms", "namespaceFile": "synonyms_get_synonyms_sets" }, { "name": "put-synonym", "namespace": "synonyms", "description": "Create or update a synonym set.", - "method": "PUT", - "path": "/_synonyms/{id}", "namespaceFile": "synonyms_put_synonym" }, { "name": "put-synonym-rule", "namespace": "synonyms", "description": "Create or update a synonym rule.", - "method": "PUT", - "path": "/_synonyms/{set_id}/{rule_id}", "namespaceFile": "synonyms_put_synonym_rule" }, { "name": "cancel", "namespace": "tasks", "description": "Cancel a task.", - "method": "POST", - "path": "/_tasks/{task_id}/_cancel", "namespaceFile": "tasks_cancel" }, { "name": "get", "namespace": "tasks", "description": "Get task information.", - "method": "GET", - "path": "/_tasks/{task_id}", "namespaceFile": "tasks_get" }, { "name": "list", "namespace": "tasks", "description": "Get all tasks.", - "method": "GET", - "path": "/_tasks", "namespaceFile": "tasks_list" }, { "name": "terms-enum", "namespace": null, "description": "Get terms in an index.", - "method": "GET", - "path": "/{index}/_terms_enum", "namespaceFile": "terms_enum" }, { "name": "termvectors", "namespace": null, "description": "Get term vector information.", - "method": "GET", - "path": "/{index}/_termvectors/{id}", "namespaceFile": "termvectors" }, { "name": "find-field-structure", "namespace": "text-structure", "description": "Find the structure of a text field.", - "method": "GET", - "path": "/_text_structure/find_field_structure", "namespaceFile": "text_structure_find_field_structure" }, { "name": "find-message-structure", "namespace": "text-structure", "description": "Find the structure of text messages.", - "method": "GET", - "path": "/_text_structure/find_message_structure", "namespaceFile": "text_structure_find_message_structure" }, { "name": "find-structure", "namespace": "text-structure", "description": "Find the structure of a text file.", - "method": "POST", - "path": "/_text_structure/find_structure", - "namespaceFile": "text_structure_find_structure", - "bodyFormat": "ndjson" + "namespaceFile": "text_structure_find_structure" }, { "name": "test-grok-pattern", "namespace": "text-structure", "description": "Test a Grok pattern.", - "method": "GET", - "path": "/_text_structure/test_grok_pattern", "namespaceFile": "text_structure_test_grok_pattern" }, { "name": "delete-transform", "namespace": "transform", "description": "Delete a transform.", - "method": "DELETE", - "path": "/_transform/{transform_id}", "namespaceFile": "transform_delete_transform" }, { "name": "get-node-stats", "namespace": "transform", "description": "Get node stats.", - "method": "GET", - "path": "/_transform/_node_stats", "namespaceFile": "transform_get_node_stats" }, { "name": "get-transform", "namespace": "transform", "description": "Get transforms.", - "method": "GET", - "path": "/_transform/{transform_id}", "namespaceFile": "transform_get_transform" }, { "name": "get-transform-stats", "namespace": "transform", "description": "Get transform stats.", - "method": "GET", - "path": "/_transform/{transform_id}/_stats", "namespaceFile": "transform_get_transform_stats" }, { "name": "preview-transform", "namespace": "transform", "description": "Preview a transform.", - "method": "GET", - "path": "/_transform/{transform_id}/_preview", "namespaceFile": "transform_preview_transform" }, { "name": "put-transform", "namespace": "transform", "description": "Create a transform.", - "method": "PUT", - "path": "/_transform/{transform_id}", "namespaceFile": "transform_put_transform" }, { "name": "reset-transform", "namespace": "transform", "description": "Reset a transform.", - "method": "POST", - "path": "/_transform/{transform_id}/_reset", "namespaceFile": "transform_reset_transform" }, { "name": "schedule-now-transform", "namespace": "transform", "description": "Schedule a transform to start now.", - "method": "POST", - "path": "/_transform/{transform_id}/_schedule_now", "namespaceFile": "transform_schedule_now_transform" }, { "name": "set-upgrade-mode", "namespace": "transform", "description": "Set upgrade_mode for transform indices.", - "method": "POST", - "path": "/_transform/set_upgrade_mode", "namespaceFile": "transform_set_upgrade_mode" }, { "name": "start-transform", "namespace": "transform", "description": "Start a transform.", - "method": "POST", - "path": "/_transform/{transform_id}/_start", "namespaceFile": "transform_start_transform" }, { "name": "stop-transform", "namespace": "transform", "description": "Stop transforms.", - "method": "POST", - "path": "/_transform/{transform_id}/_stop", "namespaceFile": "transform_stop_transform" }, { "name": "update-transform", "namespace": "transform", "description": "Update a transform.", - "method": "POST", - "path": "/_transform/{transform_id}/_update", "namespaceFile": "transform_update_transform" }, { "name": "upgrade-transforms", "namespace": "transform", "description": "Upgrade all transforms.", - "method": "POST", - "path": "/_transform/_upgrade", "namespaceFile": "transform_upgrade_transforms" }, { "name": "update", "namespace": null, "description": "Update a document.", - "method": "POST", - "path": "/{index}/_update/{id}", "namespaceFile": "update" }, { "name": "update-by-query", "namespace": null, "description": "Update documents.", - "method": "POST", - "path": "/{index}/_update_by_query", "namespaceFile": "update_by_query" }, { "name": "update-by-query-rethrottle", "namespace": null, "description": "Throttle an update by query operation.", - "method": "POST", - "path": "/_update_by_query/{task_id}/_rethrottle", "namespaceFile": "update_by_query_rethrottle" }, { "name": "ack-watch", "namespace": "watcher", "description": "Acknowledge a watch.", - "method": "PUT", - "path": "/_watcher/watch/{watch_id}/_ack/{action_id}", "namespaceFile": "watcher_ack_watch" }, { "name": "activate-watch", "namespace": "watcher", "description": "Activate a watch.", - "method": "PUT", - "path": "/_watcher/watch/{watch_id}/_activate", "namespaceFile": "watcher_activate_watch" }, { "name": "deactivate-watch", "namespace": "watcher", "description": "Deactivate a watch.", - "method": "PUT", - "path": "/_watcher/watch/{watch_id}/_deactivate", "namespaceFile": "watcher_deactivate_watch" }, { "name": "delete-watch", "namespace": "watcher", "description": "Delete a watch.", - "method": "DELETE", - "path": "/_watcher/watch/{id}", "namespaceFile": "watcher_delete_watch" }, { "name": "execute-watch", "namespace": "watcher", "description": "Run a watch.", - "method": "PUT", - "path": "/_watcher/watch/{id}/_execute", "namespaceFile": "watcher_execute_watch" }, { "name": "get-settings", "namespace": "watcher", "description": "Get Watcher index settings.", - "method": "GET", - "path": "/_watcher/settings", "namespaceFile": "watcher_get_settings" }, { "name": "get-watch", "namespace": "watcher", "description": "Get a watch.", - "method": "GET", - "path": "/_watcher/watch/{id}", "namespaceFile": "watcher_get_watch" }, { "name": "put-watch", "namespace": "watcher", "description": "Create or update a watch.", - "method": "PUT", - "path": "/_watcher/watch/{id}", "namespaceFile": "watcher_put_watch" }, { "name": "query-watches", "namespace": "watcher", "description": "Query watches.", - "method": "GET", - "path": "/_watcher/_query/watches", "namespaceFile": "watcher_query_watches" }, { "name": "start", "namespace": "watcher", "description": "Start the watch service.", - "method": "POST", - "path": "/_watcher/_start", "namespaceFile": "watcher_start" }, { "name": "stats", "namespace": "watcher", "description": "Get Watcher statistics.", - "method": "GET", - "path": "/_watcher/stats/{metric}", "namespaceFile": "watcher_stats" }, { "name": "stop", "namespace": "watcher", "description": "Stop the watch service.", - "method": "POST", - "path": "/_watcher/_stop", "namespaceFile": "watcher_stop" }, { "name": "update-settings", "namespace": "watcher", "description": "Update Watcher index settings.", - "method": "PUT", - "path": "/_watcher/settings", "namespaceFile": "watcher_update_settings" }, { "name": "info", "namespace": "xpack", "description": "Get information.", - "method": "GET", - "path": "/_xpack", "namespaceFile": "xpack_info" }, { "name": "usage", "namespace": "xpack", "description": "Get usage information.", - "method": "GET", - "path": "/_xpack/usage", "namespaceFile": "xpack_usage" } ] as const diff --git a/src/es/register.ts b/src/es/register.ts index 580b52fc..b50a976a 100644 --- a/src/es/register.ts +++ b/src/es/register.ts @@ -4,91 +4,60 @@ */ import { Command } from 'commander' -import { z } from 'zod' -import { defineCommand, defineGroup } from '../factory.ts' -import type { OpaqueCommandHandle } from '../factory.ts' +import type { z } from 'zod' +import { createRequire } from 'node:module' +import type { defineCommand as _DefCmd } from '../factory.ts' +import { defineGroup } from '../factory-core.ts' +import type { OpaqueCommandHandle } from '../factory-core.ts' import { inferIntentFromHttp } from '../cli-schema-intent.ts' import type { EsApiDefinition } from './types.ts' -import { validateApiDefinition, resolveInput } from './types.ts' import type { SchemaArgDefinition } from '../lib/schema-args.ts' -import { apiManifest, loadEsApi } from './apis.ts' +import { apiManifest } from './api-manifest.ts' import type { EsApiMeta } from './api-manifest.ts' -import { createEsHandler } from './handler.ts' -import { registerHelperCommands } from './helpers/register.ts' -/** - * Maps root-level (no-namespace) command names to the help section they belong to. - * Commands not listed here fall into the catch-all "Other commands" group. - * Order within each group reflects usage frequency — most-common first. - */ -const ROOT_COMMAND_GROUPS: Record = { - // Documents - get: 'Documents', - index: 'Documents', - create: 'Documents', - update: 'Documents', - delete: 'Documents', - bulk: 'Documents', - mget: 'Documents', - exists: 'Documents', - 'exists-source': 'Documents', - 'get-source': 'Documents', - 'delete-by-query': 'Documents', - 'update-by-query': 'Documents', - reindex: 'Documents', - // Search - search: 'Search', - msearch: 'Search', - 'search-template': 'Search', - 'msearch-template': 'Search', - scroll: 'Search', - 'clear-scroll': 'Search', - 'open-point-in-time': 'Search', - 'close-point-in-time': 'Search', - 'search-mvt': 'Search', - 'search-shards': 'Search', - 'render-search-template': 'Search', - // Analysis - count: 'Analysis', - explain: 'Analysis', - 'field-caps': 'Analysis', - termvectors: 'Analysis', - mtermvectors: 'Analysis', - 'rank-eval': 'Analysis', - 'terms-enum': 'Analysis', - // Scripts - 'get-script': 'Scripts', - 'put-script': 'Scripts', - 'delete-script': 'Scripts', - 'scripts-painless-execute': 'Scripts', - 'get-script-context': 'Scripts', - 'get-script-languages': 'Scripts', - // Cluster - ping: 'Cluster', - info: 'Cluster', - 'health-report': 'Cluster', - // Throttle / admin — shown but deprioritised - 'delete-by-query-rethrottle': 'Advanced', - 'update-by-query-rethrottle': 'Advanced', - 'reindex-rethrottle': 'Advanced', +// Lazy-loaded modules (deferred to keep `es --help` fast) +const _reqEs = createRequire(import.meta.url) + +function getZEs (): typeof z { + return (_reqEs('zod') as { z: typeof z }).z +} + +let _dc: typeof _DefCmd | null = null +async function getDefineCommand (): Promise { + if (_dc == null) _dc = (await import('../factory.js')).defineCommand + return _dc! +} + +// try .js first (compiled dist), fall back to .ts (dev/test with tsx) +let _typesMod: typeof import('./types.ts') | null = null +function getTypes (): typeof import('./types.ts') { + if (_typesMod == null) { + try { _typesMod = _reqEs('./types.js') as typeof import('./types.ts') } + catch { _typesMod = _reqEs('./types.ts') as typeof import('./types.ts') } + } + return _typesMod +} + +// Help grouping configuration +const ROOT_COMMAND_GROUPS: Readonly> = { + ...group('Documents', ['get', 'index', 'create', 'update', 'delete', 'bulk', 'mget', 'exists', 'exists-source', 'get-source', 'delete-by-query', 'update-by-query', 'reindex']), + ...group('Search', ['search', 'msearch', 'search-template', 'msearch-template', 'scroll', 'clear-scroll', 'open-point-in-time', 'close-point-in-time', 'search-mvt', 'search-shards', 'render-search-template']), + ...group('Analysis', ['count', 'explain', 'field-caps', 'termvectors', 'mtermvectors', 'rank-eval', 'terms-enum']), + ...group('Scripts', ['get-script', 'put-script', 'delete-script', 'scripts-painless-execute', 'get-script-context', 'get-script-languages']), + ...group('Cluster', ['ping', 'info', 'health-report']), + ...group('Advanced', ['delete-by-query-rethrottle', 'update-by-query-rethrottle', 'reindex-rethrottle']), +} + +function group (label: string, cmds: string[]): Record { + return Object.fromEntries(cmds.map(cmd => [cmd, label])) } /** Group label applied to every namespace sub-tree (cat, cluster, indices, …). */ const NAMESPACE_GROUP = 'API namespaces' -/** - * Controls the display order of root-level sections in help output. - * Lower numbers appear first. Sections not listed here sort after all listed ones. - */ -const GROUP_PRIORITY: Record = { - Documents: 0, - Search: 1, - Analysis: 2, - Scripts: 3, - Cluster: 4, - Advanced: 5, - 'Other commands': 6, -} +const GROUP_PRIORITY: Readonly> = Object.fromEntries( + ['Documents', 'Search', 'Analysis', 'Scripts', 'Cluster', 'Advanced', 'Other commands'].map((k, i) => [k, i]) +) /** Applies a help-section heading to a command handle (no-op if already set). */ function applyHelpGroup (handle: OpaqueCommandHandle, group: string): OpaqueCommandHandle { @@ -99,15 +68,19 @@ function applyHelpGroup (handle: OpaqueCommandHandle, group: string): OpaqueComm /** Builds a leaf command handle from an eagerly-available definition and its pre-computed schema args. */ function buildLeafHandle ( def: EsApiDefinition, - defSchemaArgs: Map + defSchemaArgs: Map, + defineCommand: typeof _DefCmd ): OpaqueCommandHandle { - const schema = def.input != null ? resolveInput(def.input) : z.looseObject({}) + const schema = def.input != null ? getTypes().resolveInput(def.input) : getZEs().looseObject({}) const schemaArgs = defSchemaArgs.get(def) ?? [] - const config: Parameters[0] = { + const config: Parameters[0] = { name: def.name, description: def.description, input: schema, - handler: createEsHandler(def, schemaArgs), + handler: async (parsed) => { + const { createEsHandler } = await import('./handler.js') + return createEsHandler(def, schemaArgs)(parsed) + }, ...(def.intent != null || inferIntentFromHttp(def.method) != null ? { intent: def.intent ?? inferIntentFromHttp(def.method)! } : {}), @@ -134,11 +107,13 @@ function buildStubLeaf (meta: EsApiMeta): OpaqueCommandHandle { // sniffer covers every direct-leaf and namespaced-leaf form). Fall back to // loading the definition on demand, swapping the stub for the real leaf, // and re-entering Commander parse so options dispatch correctly. + const { loadEsApi } = await import("./apis.js") const def = await loadEsApi(meta) - const schemaArgs = validateApiDefinition(def) + const schemaArgs = getTypes().validateApiDefinition(def) const defSchemaArgs = new Map() defSchemaArgs.set(def, schemaArgs) - const real = buildLeafHandle(def, defSchemaArgs) + const dc = await getDefineCommand() + const real = buildLeafHandle(def, defSchemaArgs, dc) const parent = cmd.parent if (parent != null) { // Commander's `commands` array is typed readonly but mutated internally; @@ -212,9 +187,9 @@ interface RegisterLazyOptions { * * @throws {Error} if any definition fails validation or there are duplicate names at any level */ -export function registerEsCommands ( +export async function registerEsCommands ( definitions: EsApiDefinition[] -): OpaqueCommandHandle { +): Promise { return buildEagerTree(definitions) } @@ -240,15 +215,17 @@ export async function registerEsCommandsLazy ( * Callers that only need CLI startup should prefer {@link registerEsCommandsLazy}. */ export async function registerEsCommandsEager (): Promise { - const defs = await Promise.all(apiManifest.map((m) => loadEsApi(m))) + const { loadEsApi: _loadEsApi } = await import("./apis.js") + const defs = await Promise.all(apiManifest.map((m) => _loadEsApi(m))) return buildEagerTree(defs) } /** Eager-tree builder: behaviourally identical to the original pre-lazy implementation. */ -function buildEagerTree (definitions: EsApiDefinition[]): OpaqueCommandHandle { +async function buildEagerTree (definitions: EsApiDefinition[]): Promise { + const defineCommand = await getDefineCommand() const defSchemaArgs = new Map() for (const def of definitions) { - defSchemaArgs.set(def, validateApiDefinition(def)) + defSchemaArgs.set(def, getTypes().validateApiDefinition(def)) } const byNamespace = new Map() @@ -283,7 +260,7 @@ function buildEagerTree (definitions: EsApiDefinition[]): OpaqueCommandHandle { seen.add(def.name) } - const leafHandles = defs.map((def) => buildLeafHandle(def, defSchemaArgs)) + const leafHandles = defs.map((def) => buildLeafHandle(def, defSchemaArgs, defineCommand)) const nsHandle = defineGroup({ name: namespace, description: `Elasticsearch ${namespace} API commands` }, ...leafHandles) applyHelpGroup(nsHandle, NAMESPACE_GROUP) namespaceHandles.push(nsHandle) @@ -301,12 +278,13 @@ function buildEagerTree (definitions: EsApiDefinition[]): OpaqueCommandHandle { throw new Error(`duplicate command name "${def.name}" at the top level of es`) } topLevelNames.add(def.name) - const h = buildLeafHandle(def, defSchemaArgs) + const h = buildLeafHandle(def, defSchemaArgs, defineCommand) applyHelpGroup(h, ROOT_COMMAND_GROUPS[def.name] ?? 'Other commands') rootHandles.push(h) } - const helpersGroup = registerHelperCommands() + // Stub for helpers; actual helpers sub-commands are loaded on demand via stub-swap. + const helpersGroup = defineGroup({ name: 'helpers', description: 'High-level helper commands for common Elasticsearch workflows' }) applyHelpGroup(helpersGroup, 'Helpers') return defineGroup({ name: 'es', description: 'Interact with the Elasticsearch API' }, ...namespaceHandles, ...rootHandles, helpersGroup) @@ -330,12 +308,13 @@ async function buildLazyTree (manifest: readonly EsApiMeta[], argv: readonly str // stays a stub. let invokedDef: EsApiDefinition | null = null if (invoked != null) { - invokedDef = await loadEsApi(invoked) + const { loadEsApi: _leafLoader } = await import("./apis.js") + invokedDef = await _leafLoader(invoked) } const invokedSchemaArgs = new Map() if (invokedDef != null) { - invokedSchemaArgs.set(invokedDef, validateApiDefinition(invokedDef)) + invokedSchemaArgs.set(invokedDef, getTypes().validateApiDefinition(invokedDef)) } const byNamespace = new Map() @@ -353,9 +332,11 @@ async function buildLazyTree (manifest: readonly EsApiMeta[], argv: readonly str } } - function leafHandleFor (m: EsApiMeta): OpaqueCommandHandle { + async function leafHandleFor (m: EsApiMeta): Promise { if (invoked != null && invokedDef != null && m === invoked) { - return buildLeafHandle(invokedDef, invokedSchemaArgs) + // Only load factory.ts (defineCommand) when a specific leaf is actually invoked. + const dc = await getDefineCommand() + return buildLeafHandle(invokedDef, invokedSchemaArgs, dc) } return buildStubLeaf(m) } @@ -389,7 +370,7 @@ async function buildLazyTree (manifest: readonly EsApiMeta[], argv: readonly str seen.add(m.name) } - const leafHandles = metas.map(leafHandleFor) + const leafHandles = await Promise.all(metas.map(leafHandleFor)) const nsHandle = defineGroup({ name: namespace, description: `Elasticsearch ${namespace} API commands` }, ...leafHandles) applyHelpGroup(nsHandle, NAMESPACE_GROUP) namespaceHandles.push(nsHandle) @@ -404,18 +385,30 @@ async function buildLazyTree (manifest: readonly EsApiMeta[], argv: readonly str const pb = GROUP_PRIORITY[ROOT_COMMAND_GROUPS[b.name] ?? 'Other commands'] ?? 99 return pa - pb || a.name.localeCompare(b.name) }) + // Check for duplicate names before parallel construction: for (const m of rootMetas) { if (topLevelNames.has(m.name)) { throw new Error(`duplicate command name "${m.name}" at the top level of es`) } topLevelNames.add(m.name) - const h = leafHandleFor(m) - applyHelpGroup(h, ROOT_COMMAND_GROUPS[m.name] ?? 'Other commands') - rootHandles.push(h) } + // Build root leaf stubs in parallel (all become buildStubLeaf → Commander Command): + const rootStubs = await Promise.all(rootMetas.map(async m => { + const h = await leafHandleFor(m) + applyHelpGroup(h, ROOT_COMMAND_GROUPS[m.name] ?? 'Other commands') + return h + })) + rootHandles.push(...rootStubs) } - const helpersGroup = registerHelperCommands() + // Use the real helpers group only when the user is targeting helpers; otherwise a + // lightweight stub suffices (sub-commands load on demand via stub-swap in buildStubLeaf). + const tokens = argv.slice(2).filter((t) => !t.startsWith('-')) + const esIdx = tokens.indexOf('es') + const isHelpersInvoked = esIdx >= 0 && tokens[esIdx + 1] === 'helpers' + const helpersGroup = isHelpersInvoked + ? (await import('./helpers/register.js')).registerHelperCommands() + : defineGroup({ name: 'helpers', description: 'High-level helper commands for common Elasticsearch workflows' }) applyHelpGroup(helpersGroup, 'Helpers') return defineGroup({ name: 'es', description: 'Interact with the Elasticsearch API' }, ...namespaceHandles, ...rootHandles, helpersGroup) diff --git a/src/es/types.ts b/src/es/types.ts index f369382b..04d03ac4 100644 --- a/src/es/types.ts +++ b/src/es/types.ts @@ -4,10 +4,21 @@ */ import type { z } from 'zod' -import { extractSchemaArgs } from '../lib/schema-args.ts' +import { createRequire } from 'node:module' import type { SchemaArgDefinition } from '../lib/schema-args.ts' import type { CommandIntent } from '../factory.ts' +// lazy-loaded to avoid pulling in schema-args eagerly +const _treq = createRequire(import.meta.url) +let _schemaArgsMod: typeof import('../lib/schema-args.ts') | null = null +function getExtractSchemaArgs (): typeof import('../lib/schema-args.ts').extractSchemaArgs { + if (_schemaArgsMod == null) { + try { _schemaArgsMod = _treq('../lib/schema-args.js') as typeof import('../lib/schema-args.ts') } + catch { _schemaArgsMod = _treq('../lib/schema-args.ts') as typeof import('../lib/schema-args.ts') } + } + return _schemaArgsMod.extractSchemaArgs +} + /** * Valid HTTP methods for Elasticsearch API requests. */ @@ -132,7 +143,7 @@ export function validateApiDefinition (def: EsApiDefinition): SchemaArgDefinitio if (def.input == null) return [] const tokens = new Set(extractPathTokens(def.path)) - const args = extractSchemaArgs(resolveInput(def.input)) + const args = getExtractSchemaArgs()(resolveInput(def.input)) const pathFields = new Set(args.filter((a) => a.foundIn === 'path').map((a) => a.schemaKey)) for (const token of tokens) { diff --git a/src/factory-core.ts b/src/factory-core.ts new file mode 100644 index 00000000..a463266c --- /dev/null +++ b/src/factory-core.ts @@ -0,0 +1,366 @@ +/* + * Copyright Elasticsearch B.V. and contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Lightweight core of the command factory — contains types and functions needed + * to build command groups and render `--help` output. + * + * This module is separated from factory.ts to avoid pulling in heavy transitive + * dependencies (Zod, schema-args, output formatters, config store) when all the + * caller needs is to define group structure for lazy namespace loading. + * + * factory.ts re-exports everything from this module, so consumers that already + * depend on the full factory do not need to change their imports. + */ + +import { Command } from 'commander' +import type { z } from 'zod' +import type { ResolvedConfig, CommandPolicy } from './config/types.ts' +import { resolveBuiltinProfile } from './config/profiles.ts' + +// --------------------------------------------------------------------------- +// Types +// --------------------------------------------------------------------------- + +/** Declared intent for a command, used by the CLI schema emitter. */ +export interface CommandIntent { + destructive?: boolean + idempotent?: boolean + scope?: 'file' | 'directory' | 'global' + requiresConfirmation?: boolean + requiresAuth?: boolean +} + +/** Definition for a single CLI option (flag). */ +export interface OptionDefinition { + long: string + short?: string + description: string + type?: 'string' | 'number' | 'boolean' + required?: boolean + defaultValue?: string | number | boolean +} + +/** Recursive JSON value type used throughout the CLI for structured output. */ +export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue } + +/** + * Wraps a raw JSON string alongside its parsed form. Used to carry body values + * that were provided as pre-serialised JSON (e.g. from stdin or --input-file). + */ +export class RawJsonValue { + constructor (public readonly raw: string, public readonly parsed: unknown) {} +} + +/** The parsed result passed to every command handler. */ +export interface ParsedResult { + options: Record + config?: ResolvedConfig + input?: T + arg?: string + rawBodyValues?: Record +} + +/** Full configuration for a leaf command (requires Zod for the input schema type). */ +export interface CommandConfig { + name: string + description: string + options?: OptionDefinition[] + positionalArg?: { name: string; description: string; required?: boolean } + handler: (parsed: ParsedResult>) => JsonValue | Promise + input?: T + formatOutput?: (result: JsonValue, parsed: ParsedResult>) => string + intent?: CommandIntent +} + +/** Configuration for a command group (namespace). */ +export interface GroupConfig { + /** group name (lowercase alphanumeric and hyphens only) */ + name: string + /** human-readable description shown in help text */ + description: string +} + +/** + * Opaque handle returned by {@link defineCommand} and {@link defineGroup}. + * + * Callers may pass this handle to {@link defineGroup} or register it with the CLI program + * via `program.addCommand(handle)`. Do not depend on the internal structure of this type -- + * the underlying implementation may change without notice. + */ +export type OpaqueCommandHandle = import('commander').Command + +// --------------------------------------------------------------------------- +// Name validation +// --------------------------------------------------------------------------- + +const VALID_NAME = /^[a-z0-9][a-z0-9-]*$/ + +/** + * Validates a command or group name against the data-model rules. + * @throws {Error} if the name is empty or contains invalid characters + */ +export function validateName (name: string, kind: 'command' | 'group'): void { + if (!VALID_NAME.test(name)) { + throw new Error( + `invalid ${kind} name ${JSON.stringify(name)}: ` + + 'names must be non-empty and contain only lowercase letters, digits, and hyphens' + ) + } +} + +// --------------------------------------------------------------------------- +// Command visibility helpers +// --------------------------------------------------------------------------- + +/** Mark a command as hidden (excluded from help output). */ +export function setHidden (cmd: OpaqueCommandHandle, value: boolean): void { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ;(cmd as unknown as any)._hidden = value +} + +/** Returns true if the command has been marked hidden. */ +export function isHidden (cmd: OpaqueCommandHandle): boolean { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (cmd as unknown as any)._hidden === true +} + +/** + * Returns true if `cmd` is a stub group — a group with no children that was + * registered as a lazy-loading placeholder. + * + * Stub groups should never be hidden by policy because their children have not + * been loaded yet; we cannot determine whether any child would be allowed. + * When the user navigates into the group its children are loaded and filtered + * correctly at that level. + */ +export function isStubGroup (cmd: OpaqueCommandHandle): boolean { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const c = cmd as unknown as any + return c._isGroup === true && (c.commands == null || c.commands.length === 0) +} + +// --------------------------------------------------------------------------- +// Command policy +// --------------------------------------------------------------------------- + +/** + * Returns true if `commandDotPath` is permitted under the given policy. + * + * Matching rules: + * - No policy (or empty policy) → always allowed + * - `allowed` list → command must match at least one entry + * - `blocked` list → command must NOT match any entry + * - Entries ending with `.*` match any command whose dot-path starts with the prefix + * (e.g. `elasticsearch.*` matches `elasticsearch.search` but NOT `elasticsearch` itself) + * - All other entries are exact matches + */ +export function isCommandAllowed (commandDotPath: string, policy: CommandPolicy | undefined): boolean { + if (policy == null) return true + + function matches (pattern: string): boolean { + if (pattern.endsWith('.*')) { + const prefix = pattern.slice(0, -2) + return commandDotPath === prefix + '.' + commandDotPath.slice(prefix.length + 1) && + commandDotPath.startsWith(prefix + '.') + } + return commandDotPath === pattern + } + + if (policy.profile != null) { + const profilePolicy = resolveBuiltinProfile(policy.profile) + if (profilePolicy != null) { + if (!profilePolicy.allowed.some(matches)) return false + } + if (policy.blocked != null) return !policy.blocked.some(matches) + return true + } + + if (policy.allowed != null) return policy.allowed.some(matches) + if (policy.blocked != null) return !policy.blocked.some(matches) + return true +} + +/** + * Walk the command tree and hide any commands the policy blocks. + * Groups where every child is hidden are hidden too. + * Stub groups (unloaded lazy namespaces) are never hidden. + * Call on the root program so dot-paths like `es.cat.health` are built correctly. + */ +export function hideBlockedCommands (root: OpaqueCommandHandle, policy: CommandPolicy | undefined, prefix = ''): void { + if (policy == null) return + for (const child of root.commands as OpaqueCommandHandle[]) { + const path = prefix ? `${prefix}.${child.name()}` : child.name() + const subs = child.commands as OpaqueCommandHandle[] + if (subs.length > 0) { + hideBlockedCommands(child, policy, path) + if (subs.every(isHidden)) setHidden(child, true) + } else if (!isStubGroup(child)) { + setHidden(child, !isCommandAllowed(path, policy)) + } + } +} + +// --------------------------------------------------------------------------- +// Transport metadata stripping +// --------------------------------------------------------------------------- + +/** + * Recursively removes `found_in` keys from a JSON value tree. + * + * `found_in` is internal routing metadata used by the request builder to classify + * parameters as path, query, or body. It is an HTTP transport implementation detail + * and MUST NOT be exposed in user-facing help text or agent-facing JSON Schema output. + */ +export function stripTransportMeta (value: JsonValue): JsonValue { + if (Array.isArray(value)) return value.map(stripTransportMeta) + if (value !== null && typeof value === 'object') { + const out: Record = {} + for (const [k, v] of Object.entries(value)) { + if (k === 'found_in') continue + out[k] = stripTransportMeta(v) + } + return out + } + return value +} + +// --------------------------------------------------------------------------- +// Help formatting +// --------------------------------------------------------------------------- + +/** + * Returns true when `--json` is set on the root program. Walks up the parent + * chain so it works regardless of whether `cmd` is the root, a group, or a leaf. + */ +export function hasGlobalJsonFlag (cmd: OpaqueCommandHandle): boolean { + let current: OpaqueCommandHandle = cmd + while (current.parent != null) current = current.parent + return (current.opts() as { json?: boolean }).json === true +} + +/** Builds the full command path by walking the parent chain (e.g. `"elastic cluster health"`). */ +export function commandPath (cmd: OpaqueCommandHandle): string { + const parts: string[] = [] + let current: OpaqueCommandHandle | null = cmd + while (current != null) { + if (current.name()) parts.unshift(current.name()) + current = current.parent + } + return parts.join(' ') +} + +/** + * Serialises a command's help structure as JSON: name, description, usage, + * visible options, and visible sub-commands. Used by {@link configureJsonHelp} + * so `--help --json` returns machine-readable output for groups and the root + * program (leaf commands with an input schema return the JSON Schema instead). + */ +function formatHelpAsJson (cmd: OpaqueCommandHandle): string { + const options = cmd.options + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .filter((o: any) => !o.hidden) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .map((o: any) => { + const entry: Record = { flags: o.flags, description: o.description } + if (typeof o.defaultValue === 'string' || typeof o.defaultValue === 'number' || typeof o.defaultValue === 'boolean') { + entry['defaultValue'] = o.defaultValue + } + if (o.mandatory === true) entry['mandatory'] = true + return entry + }) + const commands = (cmd.commands as OpaqueCommandHandle[]) + .filter(c => !isHidden(c) && c.name() !== 'help') + .map(c => { + const entry: Record = { name: c.name(), description: c.description() } + const aliases = c.aliases() + if (aliases.length > 0) entry['aliases'] = aliases + return entry + }) + return JSON.stringify({ name: cmd.name(), description: cmd.description(), usage: cmd.usage(), options, commands }) + '\n' +} + +/** + * Hooks into Commander's help formatter so `--help --json` emits structured + * JSON describing the command tree (name, description, options, sub-commands) + * instead of the text help. Apply to the root program and to command groups. + */ +export function configureJsonHelp (cmd: OpaqueCommandHandle): void { + const origHelp = cmd.createHelp() + cmd.configureHelp({ + formatHelp: (thisCmd, helper) => { + if (hasGlobalJsonFlag(thisCmd)) return formatHelpAsJson(thisCmd) + return origHelp.formatHelp(thisCmd, helper) + } + }) +} + +/** + * Configures a command's error output to match the factory error contract: + * + * ``` + * Error: + * + * Usage: + * + * Run " --help" for more information. + * ``` + */ +export function configureErrorOutput (cmd: OpaqueCommandHandle): void { + cmd.configureOutput({ + outputError: (str, write) => { + const msg = str.replace(/^error:\s*/i, '').trimEnd() + const path = commandPath(cmd) + write(`Error: ${msg}\n\nUsage: ${path} ${cmd.usage()}\n\nRun "${path} --help" for more information.\n`) + } + }) +} + +// --------------------------------------------------------------------------- +// Group definition +// --------------------------------------------------------------------------- + +/** + * Creates a new command group (namespace) that contains sub-commands. + * + * Groups are non-leaf nodes in the command tree. They display `--help` listing + * their children and error on unknown sub-commands. + * + * @example + * ```ts + * const esGroup = defineGroup( + * { name: 'es', description: 'Elasticsearch APIs' }, + * searchCmd, + * indexCmd, + * ) + * ``` + */ +export function defineGroup (config: GroupConfig, ...commands: OpaqueCommandHandle[]): OpaqueCommandHandle { + validateName(config.name, 'group') + const group = new Command(config.name) + group.description(config.description) + group.allowExcessArguments(true) + configureErrorOutput(group) + configureJsonHelp(group) + + // Mark as a group so isStubGroup can identify lazy placeholders + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ;(group as unknown as any)._isGroup = true + + for (const cmd of commands) { + group.addCommand(cmd) + } + + // Default action: error on unknown sub-command, show help otherwise + group.action(function (this: OpaqueCommandHandle) { + if (this.args.length > 0) { + group.error(`unknown command: ${this.args[0]}`) + } else { + group.help() + } + }) + + return group +} diff --git a/src/factory.ts b/src/factory.ts index 06811acd..04ce03b3 100644 --- a/src/factory.ts +++ b/src/factory.ts @@ -4,198 +4,61 @@ */ import { Command } from 'commander' -import { z } from 'zod' +import type { z } from 'zod' +import { createRequire } from 'node:module' import { readFileSync, writeSync } from 'node:fs' import assert from 'node:assert/strict' -import type { ResolvedConfig, CommandPolicy } from './config/types.ts' -import { resolveBuiltinProfile } from './config/profiles.ts' import { getResolvedConfig } from './config/store.ts' import { extractSchemaArgs, validateSchemaArgs } from './lib/schema-args.ts' import type { SchemaArgDefinition } from './lib/schema-args.ts' -import { simplifyZodIssues, formatIssuesText } from './lib/zod-error.ts' -import { renderText, formatHandlerError } from './output.ts' +import type { renderText as _RT, formatHandlerError as _FHE } from './output.ts' import { pickFields, parseFieldList, applyTemplate, TemplateAgainstPrimitiveError } from './lib/output-transform.ts' - -/** - * Declared intent for a command, used by the CLI schema emitter. - * All fields are optional — omit any that are unknown or inapplicable. - */ -export interface CommandIntent { - destructive?: boolean - idempotent?: boolean - scope?: 'file' | 'directory' | 'global' - requiresConfirmation?: boolean - requiresAuth?: boolean -} - -/** pre-built schema for coercing string → number, reused per option invocation */ -const numberSchema = z.coerce.number() - -/** - * Declarative definition of a named option or boolean flag for a command. - * - * @example - * ```ts - * const opt: OptionDefinition = { - * long: 'timeout', - * short: 't', - * type: 'number', - * description: 'Request timeout in seconds', - * defaultValue: 30, - * } - * ``` - */ -export interface OptionDefinition { - /** long option name without `--` prefix (e.g. `'timeout'`, `'output-dir'`) */ - long: string - /** single-character short alias without `-` prefix (e.g. `'t'`) */ - short?: string - /** human-readable description shown in help text */ - description: string - /** - * declared value type; governs parsing, coercion, and help text placeholder. - * defaults to `'string'` when omitted. - */ - type?: 'string' | 'number' | 'boolean' - /** when `true`, the command will not invoke the handler if this option is absent */ - required?: boolean - /** - * default value used when the option is not provided. - * type must match the declared `type` field. - */ - defaultValue?: string | number | boolean +import { validateName, hasGlobalJsonFlag, configureErrorOutput, commandPath, isCommandAllowed, stripTransportMeta } from './factory-core.ts' +import type { OpaqueCommandHandle, JsonValue, CommandConfig, ParsedResult } from './factory-core.ts' +import { RawJsonValue } from './factory-core.ts' + +// Re-export from factory-core for backward compatibility +export { + type CommandIntent, + type OptionDefinition, + type JsonValue, + RawJsonValue, + type ParsedResult, + type CommandConfig, + type GroupConfig, + type OpaqueCommandHandle, + isCommandAllowed, + hideBlockedCommands, + stripTransportMeta, + configureJsonHelp, + defineGroup, + setHidden, + isHidden, + validateName, + commandPath, + configureErrorOutput, +} from './factory-core.ts' + +// Lazy-loaded modules; deferred to improve performance of --help calls +const _require = createRequire(import.meta.url) +let _zMod: (typeof import('zod')) | null = null +function getZ (): typeof import('zod').z { + if (_zMod == null) _zMod = _require('zod') as typeof import('zod') + return _zMod.z } -/** - * Any value that can be round-tripped through `JSON.stringify` / `JSON.parse` without loss. - * All command handlers must return a `JsonValue`; the factory serializes it for output. - */ -export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue } - -/** - * Wraps a JSON-parsed value alongside its original string representation. - * Used by body args so the request builder can emit the original JSON - * (preserving number formatting like `100.0`) instead of re-serializing. - */ -export class RawJsonValue { - constructor (public readonly raw: string, public readonly parsed: unknown) {} -} - -/** - * Typed output of option parsing passed to the command handler. - * Options are keyed by their `long` name and coerced to their declared types. - * - * The generic parameter `T` carries the validated input type when a Zod schema is provided - * via {@link CommandConfig.input}. Defaults to `unknown` when no schema is used. - * - * @example - * ```ts - * const schema = z.object({ index: z.string(), size: z.number().default(10) }) - * defineCommand({ - * name: 'search', - * input: schema, - * handler: (parsed: ParsedResult>) => { - * // parsed.input is { index: string; size: number } -- fully typed - * }, - * }) - * ``` - */ -export interface ParsedResult { - /** parsed and type-coerced options, keyed by long option name */ - options: Record - /** resolved configuration from the active context, injected by the preAction hook */ - config?: ResolvedConfig - /** parsed JSON content when `input` is enabled and data is provided via --input-file or stdin */ - input?: T - /** value of the positional argument, if `positionalArg` was declared in the command config */ - arg?: string - /** - * Raw JSON strings for body args, preserving original formatting (e.g. float `100.0`). - * @internal used by the request builder — handlers should read `input` instead. - */ - rawBodyValues?: Record -} - -/** - * Declarative configuration for a leaf command (a command that has a handler and accepts options). - * - * When `input` is a Zod schema of type `T`, `CommandConfig` is generic over `T` and the handler - * receives a strongly-typed `ParsedResult>`. When `input` is omitted, the handler - * receives `ParsedResult` with `input` typed as `unknown`. - * - * @example - * ```ts - * const inputSchema = z.object({ index: z.string(), size: z.number().default(10) }) - * const searchCmd: CommandConfig = { - * name: 'search', - * description: 'Search an index', - * input: inputSchema, - * handler: (parsed) => { - * // parsed.input is { index: string; size: number } - * }, - * } - * ``` - */ -export interface CommandConfig { - /** command name (lowercase alphanumeric and hyphens only, e.g. `'health'`, `'dry-run'`) */ - name: string - /** human-readable description shown in help text */ - description: string - /** option and flag definitions */ - options?: OptionDefinition[] - /** optional single positional argument; appears in usage as `` (required) or `[name]` (optional) */ - positionalArg?: { name: string; description: string; required?: boolean } - /** - * invoked after successful parsing and type coercion. - * errors thrown here propagate to the caller; the factory does not catch handler errors. - */ - handler: (parsed: ParsedResult>) => JsonValue | Promise - /** - * optional input schema. when a Zod schema is provided, registers `--input-file` and reads JSON from - * stdin or file, validates against the schema, then passes the typed result to the handler. - */ - input?: T - /** - * optional text renderer for non-JSON output mode. - * when provided, called with the handler result and the full parsed result to produce a string - * written to stdout. when omitted, the factory auto-renders via {@link renderText}. - * never called when `--json` is active. - */ - formatOutput?: (result: JsonValue, parsed: ParsedResult>) => string - /** - * optional intent declaration for the CLI schema emitter. - * used to derive destructiveness, idempotency, and auth requirements in emitted schema. - */ - intent?: CommandIntent +let _outputMod: Promise<{ renderText: typeof _RT; formatHandlerError: typeof _FHE }> | null = null +function getOutput () { + if (_outputMod == null) _outputMod = import('./output.js') as unknown as typeof _outputMod + return _outputMod! } -/** - * Declarative configuration for a command group (a non-leaf command that contains child commands). - * - * @example - * ```ts - * const config: GroupConfig = { - * name: 'cluster', - * description: 'Manage Elasticsearch clusters', - * } - * ``` - */ -export interface GroupConfig { - /** group name (lowercase alphanumeric and hyphens only) */ - name: string - /** human-readable description shown in help text */ - description: string +let _numberSchema: ReturnType | null = null +function numberSchema () { + if (_numberSchema == null) _numberSchema = getZ().coerce.number() + return _numberSchema } -/** - * Opaque handle returned by {@link defineCommand} and {@link defineGroup}. - * - * Callers may pass this handle to {@link defineGroup} or register it with the CLI program - * via `program.addCommand(handle)`. Do not depend on the internal structure of this type -- - * the underlying implementation may change without notice. - */ -export type OpaqueCommandHandle = import('commander').Command - /** * Module-level stdin reader - swappable in tests via {@link _testSetStdinReader}. * Production default reads all of stdin synchronously using file descriptor 0, @@ -215,92 +78,6 @@ export function _testSetStdinReader (fn: () => string): () => void { return () => { stdinReader = prev } } -/** - * Returns true if `commandDotPath` is permitted under the given policy. - * - * Matching rules: - * - No policy (or empty policy) → always allowed - * - `allowed` list → command must match at least one entry - * - `blocked` list → command must NOT match any entry - * - Entries ending with `.*` match any command whose dot-path starts with the prefix and a `.` - * (e.g. `elasticsearch.*` matches `elasticsearch.search` and `elasticsearch.indices.get` - * but NOT `elasticsearch` itself) - * - All other entries are exact matches - */ -export function isCommandAllowed(commandDotPath: string, policy: CommandPolicy | undefined): boolean { - if (policy == null) return true - - function matches(pattern: string): boolean { - if (pattern.endsWith('.*')) { - const prefix = pattern.slice(0, -2) - return commandDotPath === prefix + '.' + commandDotPath.slice(prefix.length + 1) && - commandDotPath.startsWith(prefix + '.') - } - return commandDotPath === pattern - } - - // Profile-based filtering: resolve the named profile to its allow-list and - // check against it first, then apply any additional `blocked` restriction. - if (policy.profile != null) { - const profilePolicy = resolveBuiltinProfile(policy.profile) - if (profilePolicy != null) { - // Profile acts as an allow-list; if the command is not in it, deny. - if (!profilePolicy.allowed.some(matches)) return false - } - // `blocked` further restricts on top of the profile (always allowed to restrict more). - if (policy.blocked != null) return !policy.blocked.some(matches) - return true - } - - if (policy.allowed != null) return policy.allowed.some(matches) - if (policy.blocked != null) return !policy.blocked.some(matches) - return true -} - -// Commander checks `_hidden` to exclude commands from --help, but the -// property isn't in the public typings — -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function setHidden(cmd: OpaqueCommandHandle, value: boolean): void { (cmd as unknown as any)._hidden = value } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function isHidden(cmd: OpaqueCommandHandle): boolean { return (cmd as unknown as any)._hidden === true } - -/** - * Returns true if `cmd` is a stub group — a group with no children that was - * registered in cli.ts as a lazy-loading placeholder. - * - * Stub groups should never be hidden by policy because their children have not - * been loaded yet; we cannot determine whether any child would be allowed. - * When the user navigates into the group its children are loaded and filtered - * correctly at that level. - */ -function isStubGroup (cmd: OpaqueCommandHandle): boolean { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c = cmd as unknown as any - return c._isGroup === true && (c.commands == null || c.commands.length === 0) -} - -/** - * Walk the command tree and hide any commands the policy blocks. - * Groups where every child is hidden are hidden too. - * Stub groups (unloaded lazy namespaces) are never hidden. - * Call on the root program so dot-paths like `es.cat.health` are built correctly. - */ -export function hideBlockedCommands(root: OpaqueCommandHandle, policy: CommandPolicy | undefined, prefix = ''): void { - if (policy == null) return - for (const child of root.commands as OpaqueCommandHandle[]) { - const path = prefix ? `${prefix}.${child.name()}` : child.name() - const subs = child.commands as OpaqueCommandHandle[] - if (subs.length > 0) { - hideBlockedCommands(child, policy, path) - if (subs.every(isHidden)) setHidden(child, true) - } else if (isStubGroup(child)) { - // Unloaded lazy namespace: leave visible. Children are filtered when loaded. - } else { - setHidden(child, !isCommandAllowed(path, policy)) - } - } -} - /** converts a kebab-case option name to camelCase to match Commander's opts() keys */ function camelCase (s: string): string { return s.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase()) @@ -360,27 +137,11 @@ function singleValueGuard ( } } -/** valid command/group name: non-empty, lowercase alphanumeric characters and hyphens only */ -const VALID_NAME = /^[a-z0-9][a-z0-9-]*$/ - -/** - * Validates a command or group name against the data-model rules. - * @throws {Error} if the name is empty or contains invalid characters - */ -function validateName (name: string, kind: 'command' | 'group'): void { - if (!VALID_NAME.test(name)) { - throw new Error( - `invalid ${kind} name ${JSON.stringify(name)}: ` + - 'names must be non-empty and contain only lowercase letters, digits, and hyphens' - ) - } -} - /** * Validates all option definitions for a command. * @throws {Error} on short alias length, long name length, or duplicate name violations */ -function validateOptions (options: OptionDefinition[]): void { +function validateOptions (options: import('./factory-core.ts').OptionDefinition[]): void { const seenLong = new Set() const seenShort = new Set() @@ -419,97 +180,16 @@ function validateOptions (options: OptionDefinition[]): void { * @throws {Error} if `input` is defined but is not a `z.ZodType` instance */ function validateInput (name: string, input: unknown): void { - if (input !== undefined && !(input instanceof z.ZodType)) { + if (input !== undefined && !(input instanceof getZ().ZodType)) { throw new Error(`command ${JSON.stringify(name)}: input must be a Zod schema`) } } /** - * Recursively removes `found_in` keys from a JSON Schema object. - * Exported for reuse in cli-schema.ts validation extraction. - * - * `found_in` is internal routing metadata used by the request builder to classify - * parameters as path, query, or body. It is an HTTP transport implementation detail - * and MUST NOT be exposed in user-facing help text or agent-facing JSON Schema output - * (Constitution Principle VIII: Transport-Layer Abstraction). + * Configures `--help --json` on a leaf command to emit the JSON Schema derived + * from the command's input Zod schema. Uses synchronous blocking write to prevent + * truncation when stdout is piped. */ -export function stripTransportMeta (value: JsonValue): JsonValue { - if (Array.isArray(value)) return value.map(stripTransportMeta) - if (value !== null && typeof value === 'object') { - const out: Record = {} - for (const [k, v] of Object.entries(value)) { - if (k === 'found_in') continue - out[k] = stripTransportMeta(v) - } - return out - } - return value -} - -/** - * Returns true when `--json` is set on the root program. Walks up the parent - * chain so it works regardless of whether `cmd` is the root, a group, or a leaf. - */ -function hasGlobalJsonFlag (cmd: OpaqueCommandHandle): boolean { - let current: OpaqueCommandHandle = cmd - while (current.parent != null) current = current.parent - return (current.opts() as { json?: boolean }).json === true -} - -/** - * Serialises a command's help structure as JSON: name, description, usage, - * visible options, and visible sub-commands. Used by {@link configureJsonHelp} - * so `--help --json` returns machine-readable output for groups and the root - * program (leaf commands with an input schema continue to return that schema). - */ -function formatHelpAsJson (cmd: OpaqueCommandHandle): string { - const options = cmd.options - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .filter(o => (o as any).hidden !== true) - .map(o => { - const entry: Record = { flags: o.flags, description: o.description } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const dv = (o as any).defaultValue - if (typeof dv === 'string' || typeof dv === 'number' || typeof dv === 'boolean') { - entry['defaultValue'] = dv - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if ((o as any).mandatory === true) entry['mandatory'] = true - return entry - }) - const commands = (cmd.commands as OpaqueCommandHandle[]) - .filter(c => !isHidden(c) && c.name() !== 'help') - .map(c => { - const entry: Record = { name: c.name(), description: c.description() } - const aliases = c.aliases() - if (aliases.length > 0) entry['aliases'] = aliases - return entry - }) - const data: JsonValue = { - name: cmd.name(), - description: cmd.description(), - usage: cmd.usage(), - options, - commands, - } - return JSON.stringify(data) + '\n' -} - -/** - * Hooks into Commander's help formatter so `--help --json` emits structured - * JSON describing the command tree (name, description, options, sub-commands) - * instead of the text help. Apply to the root program and to command groups. - */ -export function configureJsonHelp (cmd: OpaqueCommandHandle): void { - const origHelp = cmd.createHelp() - cmd.configureHelp({ - formatHelp: (thisCmd, helper) => { - if (hasGlobalJsonFlag(thisCmd)) return formatHelpAsJson(thisCmd) - return origHelp.formatHelp(thisCmd, helper) - } - }) -} - function configureHelpWithSchema ( cmd: OpaqueCommandHandle, inputSchema: z.ZodType | undefined, @@ -519,7 +199,7 @@ function configureHelpWithSchema ( formatHelp: (thisCmd, helper) => { if (hasGlobalJsonFlag(thisCmd)) { const jsonSchema = inputSchema != null - ? stripTransportMeta(z.toJSONSchema(inputSchema, { reused: 'ref' }) as JsonValue) + ? stripTransportMeta(getZ().toJSONSchema(inputSchema, { reused: 'ref' }) as JsonValue) : undefined return jsonSchema != null ? JSON.stringify(jsonSchema) + '\n' : '' } @@ -535,9 +215,6 @@ function configureHelpWithSchema ( // pipe file-descriptors into non-blocking mode once process.stdout is // initialised, so a bare writeSync would also stop at the pipe-buffer limit; // setBlocking(true) restores blocking mode first. - // - // Tests replace writeOut after defineCommand() via cmd.configureOutput(), so - // this override is transparent to the test suite. cmd.configureOutput({ writeOut: (str) => { ;(process.stdout as NodeJS.WriteStream & { _handle?: { setBlocking?: (b: boolean) => void } }) @@ -547,41 +224,6 @@ function configureHelpWithSchema ( }) } -/** builds the full command path by walking the parent chain (e.g. `"elastic cluster health"`) */ -function commandPath (cmd: OpaqueCommandHandle): string { - const parts: string[] = [] - let current: OpaqueCommandHandle | null = cmd - while (current != null) { - if (current.name()) parts.unshift(current.name()) - current = current.parent - } - return parts.join(' ') -} - -/** - * Configures a command's error output to match the factory error contract: - * - * ``` - * Error: - * - * Usage: - * - * Run " --help" for more information. - * ``` - * - * Using `outputError` (rather than `writeErr`) ensures the formatting persists - * even when callers subsequently override `writeErr` for output capture. - */ -function configureErrorOutput (cmd: OpaqueCommandHandle): void { - cmd.configureOutput({ - outputError: (str, write) => { - const msg = str.replace(/^error:\s*/i, '').trimEnd() - const path = commandPath(cmd) - write(`Error: ${msg}\n\nUsage: ${path} ${cmd.usage()}\n\nRun "${path} --help" for more information.\n`) - } - }) -} - /** * Parses `raw` as JSON, routing errors through Commander's error handler. * `source` is the error prefix shown to the user (e.g. `'--input-file'` or `'stdin'`). @@ -648,7 +290,7 @@ export function defineCommand (config: CommandConfig): O validateOptions(config.options ?? []) validateInput(config.name, config.input) // --input-file is reserved when input is a schema; catch collision at definition time - if (config.input instanceof z.ZodType && config.options?.some((o) => o.long === 'input-file')) { + if (config.input instanceof getZ().ZodType && config.options?.some((o) => o.long === 'input-file')) { throw new Error( `command ${JSON.stringify(config.name)}: option --input-file is reserved when input is enabled` ) @@ -664,10 +306,6 @@ export function defineCommand (config: CommandConfig): O cmd.argument(placeholder, config.positionalArg.description) } - // EXTENSION POINT: output formatting (Principle II) - // Future: inspect config for a `format?: 'text' | 'json'` field and configure - // a global output serialiser here, before any option registration. - const optDefs = config.options ?? [] for (const opt of optDefs) { @@ -684,7 +322,7 @@ export function defineCommand (config: CommandConfig): O const flagWithArg = `${flag} ` const attrName = camelCase(opt.long) const parseNum = (val: string): number => { - const result = numberSchema.safeParse(val) + const result = numberSchema().safeParse(val) if (!result.success) { cmd.error(`option --${opt.long}: expected a number, got: ${val}`) } @@ -700,7 +338,7 @@ export function defineCommand (config: CommandConfig): O // schema-derived CLI options (registered before --input-file so help text order is correct) let schemaArgs: SchemaArgDefinition[] = [] - if (config.input instanceof z.ZodType) { + if (config.input instanceof getZ().ZodType) { schemaArgs = extractSchemaArgs(config.input) validateSchemaArgs(schemaArgs) for (const arg of schemaArgs) { @@ -717,7 +355,7 @@ export function defineCommand (config: CommandConfig): O } else if (arg.type === 'number') { const attrName = camelCase(arg.cliFlag) const parseNum = (val: string): number => { - const r = numberSchema.safeParse(val) + const r = numberSchema().safeParse(val) if (!r.success) cmd.error(`option --${arg.cliFlag}: expected a number, got: ${val}`) return r.data! } @@ -735,7 +373,7 @@ export function defineCommand (config: CommandConfig): O } } } - if (config.input instanceof z.ZodType) { + if (config.input instanceof getZ().ZodType) { cmd.option('--input-file ', 'path to a JSON file to use as command input') } const schemaClaimsDryRun = schemaArgs.some((a) => a.cliFlag === 'dry-run') @@ -745,7 +383,7 @@ export function defineCommand (config: CommandConfig): O configureHelpWithSchema( cmd, - config.input instanceof z.ZodType ? config.input : undefined, + config.input instanceof getZ().ZodType ? config.input : undefined, ) // Attach typed metadata for tooling (e.g. cli-schema). Non-enumerable so it @@ -782,7 +420,7 @@ export function defineCommand (config: CommandConfig): O const jsonFormat = allRaw.json let inputValue: unknown const rawBodyValues: Record = {} - if (config.input instanceof z.ZodType) { + if (config.input instanceof getZ().ZodType) { const filePath = cmd.getOptionValue('inputFile') as string | undefined if (filePath !== undefined) { let fileContent: string @@ -893,11 +531,11 @@ export function defineCommand (config: CommandConfig): O ...(positionalValue !== undefined ? { arg: positionalValue } : {}) } if (inputValue !== undefined) { - assert(config.input instanceof z.ZodType, `command ${JSON.stringify(config.name)}: input must be a Zod schema`) + assert(config.input instanceof getZ().ZodType, `command ${JSON.stringify(config.name)}: input must be a Zod schema`) // Use passthrough so unknown fields (plugin-specific, newer ES versions) flow // through to the server instead of being rejected client-side (#170). let validationSchema: z.ZodType = ( - config.input instanceof z.ZodObject && + config.input instanceof getZ().ZodObject && (config.input.def as unknown as { catchall?: { type: string } }).catchall?.type !== 'unknown' ) ? config.input.passthrough() @@ -915,10 +553,10 @@ export function defineCommand (config: CommandConfig): O a => a.foundIn === 'body' && (a.type === 'object' || a.type === 'array' || a.parseStyle === 'sort-pairs') ) - if (jsonBodyFields.length > 0 && validationSchema instanceof z.ZodObject) { + if (jsonBodyFields.length > 0 && validationSchema instanceof getZ().ZodObject) { const overrides: Record = {} for (const f of jsonBodyFields) { - overrides[f.schemaKey] = f.required ? z.any() : z.any().optional() + overrides[f.schemaKey] = f.required ? getZ().any() : getZ().any().optional() } validationSchema = (validationSchema as z.ZodObject).extend(overrides) } @@ -930,6 +568,7 @@ export function defineCommand (config: CommandConfig): O parsed.rawBodyValues = rawBodyValues } } else { + const { simplifyZodIssues, formatIssuesText } = await import('./lib/zod-error.js') const issues = simplifyZodIssues(result.error.issues) if (jsonFormat === true) { process.stderr.write(JSON.stringify({ @@ -954,6 +593,8 @@ export function defineCommand (config: CommandConfig): O return } const handlerResult = await config.handler(parsed) + + const { renderText, formatHandlerError } = await getOutput() assert(handlerResult !== undefined, `command ${JSON.stringify(config.name)}: handler must return a JsonValue`) if (isErrorResult(handlerResult)) { if (jsonFormat === true) { @@ -998,49 +639,3 @@ export function defineCommand (config: CommandConfig): O return cmd } - -/** - * Creates a command group from a declarative config, attaching child command handles. - * Returns an opaque handle registerable with the CLI program or a parent group. - * - * **Behaviour**: - * - When invoked without a sub-command: displays group-level help and exits cleanly (code 0) - * - When invoked with an unrecognised sub-command: emits a structured error message - * - When invoked with a known sub-command: dispatches to that command's handler - * - * @example - * ```ts - * const healthCmd = defineCommand({ name: 'health', ... }) - * const statsCmd = defineCommand({ name: 'stats', ... }) - * - * const clusterGroup = defineGroup( - * { name: 'cluster', description: 'Manage Elasticsearch clusters' }, - * healthCmd, - * statsCmd, - * ) - * ``` - */ -export function defineGroup (config: GroupConfig, ...commands: OpaqueCommandHandle[]): OpaqueCommandHandle { - validateName(config.name, 'group') - const group = new Command(config.name) - group.description(config.description) - group.allowExcessArguments(true) - configureErrorOutput(group) - configureJsonHelp(group) - // Mark as a group so hideBlockedCommands can distinguish groups from leaf commands. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ;(group as unknown as any)._isGroup = true - for (const cmd of commands) { - group.addCommand(cmd) - } - // when invoked without a sub-command: show help (exit 0); - // when invoked with an unrecognised sub-command: emit a clear error - group.action(function (this: OpaqueCommandHandle) { - if (this.args.length > 0) { - group.error(`unknown command: ${this.args[0]}`) - } else { - group.help() - } - }) - return group -} diff --git a/src/kb/api-manifest.ts b/src/kb/api-manifest.ts index 51fb2d98..26713ad7 100644 --- a/src/kb/api-manifest.ts +++ b/src/kb/api-manifest.ts @@ -8,15 +8,11 @@ * DO NOT EDIT BY HAND. Regenerate after running the code generator. */ -import type { HttpMethod } from './types.ts' - /** Cheap metadata for every Kibana API command. No Zod schemas built. */ export interface KbApiMeta { readonly name: string readonly namespace: string readonly description: string - readonly method: HttpMethod - readonly path: string /** File stem under src/kb/apis/ that holds the full KbApiDefinition. */ readonly namespaceFile: string } @@ -26,4008 +22,3006 @@ export const kbApiManifest: readonly KbApiMeta[] = [ "name": "post-agent-builder-a2a-agentid", "namespace": "agent-builder", "description": "Send A2A task", - "method": "POST", - "path": "/api/agent_builder/a2a/{agentId}", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-a2a-agentid-json", "namespace": "agent-builder", "description": "Get A2A agent card", - "method": "GET", - "path": "/api/agent_builder/a2a/{agentId}.json", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-agents", "namespace": "agent-builder", "description": "List agents", - "method": "GET", - "path": "/api/agent_builder/agents", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-agents", "namespace": "agent-builder", "description": "Create an agent", - "method": "POST", - "path": "/api/agent_builder/agents", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-agents-agent-id-consumption", "namespace": "agent-builder", "description": "Get agent consumption data", - "method": "POST", - "path": "/api/agent_builder/agents/{agent_id}/consumption", "namespaceFile": "agent-builder" }, { "name": "delete-agent-builder-agents-id", "namespace": "agent-builder", "description": "Delete an agent", - "method": "DELETE", - "path": "/api/agent_builder/agents/{id}", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-agents-id", "namespace": "agent-builder", "description": "Get an agent by ID", - "method": "GET", - "path": "/api/agent_builder/agents/{id}", "namespaceFile": "agent-builder" }, { "name": "put-agent-builder-agents-id", "namespace": "agent-builder", "description": "Update an agent", - "method": "PUT", - "path": "/api/agent_builder/agents/{id}", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-conversations", "namespace": "agent-builder", "description": "List conversations", - "method": "GET", - "path": "/api/agent_builder/conversations", "namespaceFile": "agent-builder" }, { "name": "delete-agent-builder-conversations-conversation-id", "namespace": "agent-builder", "description": "Delete conversation by ID", - "method": "DELETE", - "path": "/api/agent_builder/conversations/{conversation_id}", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-conversations-conversation-id", "namespace": "agent-builder", "description": "Get conversation by ID", - "method": "GET", - "path": "/api/agent_builder/conversations/{conversation_id}", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-conversations-conversation-id-attachments", "namespace": "agent-builder", "description": "List conversation attachments", - "method": "GET", - "path": "/api/agent_builder/conversations/{conversation_id}/attachments", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-conversations-conversation-id-attachments", "namespace": "agent-builder", "description": "Create conversation attachment", - "method": "POST", - "path": "/api/agent_builder/conversations/{conversation_id}/attachments", "namespaceFile": "agent-builder" }, { "name": "delete-agent-builder-conversations-conversation-id-attachments-attachment-id", "namespace": "agent-builder", "description": "Delete conversation attachment", - "method": "DELETE", - "path": "/api/agent_builder/conversations/{conversation_id}/attachments/{attachment_id}", "namespaceFile": "agent-builder" }, { "name": "patch-agent-builder-conversations-conversation-id-attachments-attachment-id", "namespace": "agent-builder", "description": "Rename attachment", - "method": "PATCH", - "path": "/api/agent_builder/conversations/{conversation_id}/attachments/{attachment_id}", "namespaceFile": "agent-builder" }, { "name": "put-agent-builder-conversations-conversation-id-attachments-attachment-id", "namespace": "agent-builder", "description": "Update conversation attachment", - "method": "PUT", - "path": "/api/agent_builder/conversations/{conversation_id}/attachments/{attachment_id}", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-conversations-conversation-id-attachments-attachment-id-restore", "namespace": "agent-builder", "description": "Restore deleted attachment", - "method": "POST", - "path": "/api/agent_builder/conversations/{conversation_id}/attachments/{attachment_id}/_restore", "namespaceFile": "agent-builder" }, { "name": "put-agent-builder-conversations-conversation-id-attachments-attachment-id-origin", "namespace": "agent-builder", "description": "Update attachment origin", - "method": "PUT", - "path": "/api/agent_builder/conversations/{conversation_id}/attachments/{attachment_id}/origin", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-conversations-conversation-id-attachments-stale", "namespace": "agent-builder", "description": "Check attachment staleness", - "method": "GET", - "path": "/api/agent_builder/conversations/{conversation_id}/attachments/stale", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-converse", "namespace": "agent-builder", "description": "Send chat message", - "method": "POST", - "path": "/api/agent_builder/converse", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-converse-async", "namespace": "agent-builder", "description": "Send chat message (streaming)", - "method": "POST", - "path": "/api/agent_builder/converse/async", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-mcp", "namespace": "agent-builder", "description": "MCP server", - "method": "POST", - "path": "/api/agent_builder/mcp", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-plugins", "namespace": "agent-builder", "description": "List plugins", - "method": "GET", - "path": "/api/agent_builder/plugins", "namespaceFile": "agent-builder" }, { "name": "delete-agent-builder-plugins-pluginid", "namespace": "agent-builder", "description": "Delete a plugin", - "method": "DELETE", - "path": "/api/agent_builder/plugins/{pluginId}", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-plugins-pluginid", "namespace": "agent-builder", "description": "Get a plugin by id", - "method": "GET", - "path": "/api/agent_builder/plugins/{pluginId}", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-plugins-install", "namespace": "agent-builder", "description": "Install a plugin", - "method": "POST", - "path": "/api/agent_builder/plugins/install", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-skills", "namespace": "agent-builder", "description": "List skills", - "method": "GET", - "path": "/api/agent_builder/skills", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-skills", "namespace": "agent-builder", "description": "Create a skill", - "method": "POST", - "path": "/api/agent_builder/skills", "namespaceFile": "agent-builder" }, { "name": "delete-agent-builder-skills-skillid", "namespace": "agent-builder", "description": "Delete a skill", - "method": "DELETE", - "path": "/api/agent_builder/skills/{skillId}", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-skills-skillid", "namespace": "agent-builder", "description": "Get a skill by id", - "method": "GET", - "path": "/api/agent_builder/skills/{skillId}", "namespaceFile": "agent-builder" }, { "name": "put-agent-builder-skills-skillid", "namespace": "agent-builder", "description": "Update a skill", - "method": "PUT", - "path": "/api/agent_builder/skills/{skillId}", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-tools", "namespace": "agent-builder", "description": "List tools", - "method": "GET", - "path": "/api/agent_builder/tools", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-tools", "namespace": "agent-builder", "description": "Create a tool", - "method": "POST", - "path": "/api/agent_builder/tools", "namespaceFile": "agent-builder" }, { "name": "post-agent-builder-tools-execute", "namespace": "agent-builder", "description": "Run a tool", - "method": "POST", - "path": "/api/agent_builder/tools/_execute", "namespaceFile": "agent-builder" }, { "name": "delete-agent-builder-tools-toolid", "namespace": "agent-builder", "description": "Delete a tool", - "method": "DELETE", - "path": "/api/agent_builder/tools/{toolId}", "namespaceFile": "agent-builder" }, { "name": "get-agent-builder-tools-toolid", "namespace": "agent-builder", "description": "Get a tool by id", - "method": "GET", - "path": "/api/agent_builder/tools/{toolId}", "namespaceFile": "agent-builder" }, { "name": "put-agent-builder-tools-toolid", "namespace": "agent-builder", "description": "Update a tool", - "method": "PUT", - "path": "/api/agent_builder/tools/{toolId}", "namespaceFile": "agent-builder" }, { "name": "delete-alerting-rule-id", "namespace": "alerting", "description": "Delete a rule", - "method": "DELETE", - "path": "/api/alerting/rule/{id}", "namespaceFile": "alerting" }, { "name": "get-alerting-rule-id", "namespace": "alerting", "description": "Get rule details", - "method": "GET", - "path": "/api/alerting/rule/{id}", "namespaceFile": "alerting" }, { "name": "post-alerting-rule-id", "namespace": "alerting", "description": "Create a rule", - "method": "POST", - "path": "/api/alerting/rule/{id}", "namespaceFile": "alerting" }, { "name": "put-alerting-rule-id", "namespace": "alerting", "description": "Update a rule", - "method": "PUT", - "path": "/api/alerting/rule/{id}", "namespaceFile": "alerting" }, { "name": "post-alerting-rule-id-disable", "namespace": "alerting", "description": "Disable a rule", - "method": "POST", - "path": "/api/alerting/rule/{id}/_disable", "namespaceFile": "alerting" }, { "name": "post-alerting-rule-id-enable", "namespace": "alerting", "description": "Enable a rule", - "method": "POST", - "path": "/api/alerting/rule/{id}/_enable", "namespaceFile": "alerting" }, { "name": "post-alerting-rule-id-mute-all", "namespace": "alerting", "description": "Mute all alerts", - "method": "POST", - "path": "/api/alerting/rule/{id}/_mute_all", "namespaceFile": "alerting" }, { "name": "post-alerting-rule-id-unmute-all", "namespace": "alerting", "description": "Unmute all alerts", - "method": "POST", - "path": "/api/alerting/rule/{id}/_unmute_all", "namespaceFile": "alerting" }, { "name": "post-alerting-rule-id-update-api-key", "namespace": "alerting", "description": "Update the API key for a rule", - "method": "POST", - "path": "/api/alerting/rule/{id}/_update_api_key", "namespaceFile": "alerting" }, { "name": "post-alerting-rule-id-snooze-schedule", "namespace": "alerting", "description": "Schedule a snooze for the rule", - "method": "POST", - "path": "/api/alerting/rule/{id}/snooze_schedule", "namespaceFile": "alerting" }, { "name": "post-alerting-rule-rule-id-alert-alert-id-mute", "namespace": "alerting", "description": "Mute an alert", - "method": "POST", - "path": "/api/alerting/rule/{rule_id}/alert/{alert_id}/_mute", "namespaceFile": "alerting" }, { "name": "post-alerting-rule-rule-id-alert-alert-id-unmute", "namespace": "alerting", "description": "Unmute an alert", - "method": "POST", - "path": "/api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute", "namespaceFile": "alerting" }, { "name": "delete-alerting-rule-ruleid-snooze-schedule-scheduleid", "namespace": "alerting", "description": "Delete a snooze schedule for a rule", - "method": "DELETE", - "path": "/api/alerting/rule/{ruleId}/snooze_schedule/{scheduleId}", "namespaceFile": "alerting" }, { "name": "get-alerting-rules-find", "namespace": "alerting", "description": "Get information about rules", - "method": "GET", - "path": "/api/alerting/rules/_find", "namespaceFile": "alerting" }, { "name": "post-alerting-rules-backfill-find", "namespace": "alerting", "description": "Find backfills for rules", - "method": "POST", - "path": "/api/alerting/rules/backfill/_find", "namespaceFile": "alerting" }, { "name": "post-alerting-rules-backfill-schedule", "namespace": "alerting", "description": "Schedule a backfill for rules", - "method": "POST", - "path": "/api/alerting/rules/backfill/_schedule", "namespaceFile": "alerting" }, { "name": "delete-alerting-rules-backfill-id", "namespace": "alerting", "description": "Delete a backfill by ID", - "method": "DELETE", - "path": "/api/alerting/rules/backfill/{id}", "namespaceFile": "alerting" }, { "name": "get-alerting-rules-backfill-id", "namespace": "alerting", "description": "Get a backfill by ID", - "method": "GET", - "path": "/api/alerting/rules/backfill/{id}", "namespaceFile": "alerting" }, { "name": "delete-agent-configuration", "namespace": "apm-agent-configuration", "description": "Delete agent configuration", - "method": "DELETE", - "path": "/api/apm/settings/agent-configuration", "namespaceFile": "apm-agent-configuration" }, { "name": "get-agent-configurations", "namespace": "apm-agent-configuration", "description": "Get a list of agent configurations", - "method": "GET", - "path": "/api/apm/settings/agent-configuration", "namespaceFile": "apm-agent-configuration" }, { "name": "create-update-agent-configuration", "namespace": "apm-agent-configuration", "description": "Create or update agent configuration", - "method": "PUT", - "path": "/api/apm/settings/agent-configuration", "namespaceFile": "apm-agent-configuration" }, { "name": "get-agent-name-for-service", "namespace": "apm-agent-configuration", "description": "Get agent name for service", - "method": "GET", - "path": "/api/apm/settings/agent-configuration/agent_name", "namespaceFile": "apm-agent-configuration" }, { "name": "get-environments-for-service", "namespace": "apm-agent-configuration", "description": "Get environments for service", - "method": "GET", - "path": "/api/apm/settings/agent-configuration/environments", "namespaceFile": "apm-agent-configuration" }, { "name": "search-single-configuration", "namespace": "apm-agent-configuration", "description": "Lookup single agent configuration", - "method": "POST", - "path": "/api/apm/settings/agent-configuration/search", "namespaceFile": "apm-agent-configuration" }, { "name": "get-single-agent-configuration", "namespace": "apm-agent-configuration", "description": "Get single agent configuration", - "method": "GET", - "path": "/api/apm/settings/agent-configuration/view", "namespaceFile": "apm-agent-configuration" }, { "name": "create-agent-key", "namespace": "apm-agent-keys", "description": "Create an APM agent key", - "method": "POST", - "path": "/api/apm/agent_keys", "namespaceFile": "apm-agent-keys" }, { "name": "create-annotation", "namespace": "apm-annotations", "description": "Create a service annotation", - "method": "POST", - "path": "/api/apm/services/{serviceName}/annotation", "namespaceFile": "apm-annotations" }, { "name": "get-annotation", "namespace": "apm-annotations", "description": "Search for annotations", - "method": "GET", - "path": "/api/apm/services/{serviceName}/annotation/search", "namespaceFile": "apm-annotations" }, { "name": "save-apm-server-schema", "namespace": "apm-server-schema", "description": "Save APM server schema", - "method": "POST", - "path": "/api/apm/fleet/apm_server_schema", "namespaceFile": "apm-server-schema" }, { "name": "get-source-maps", "namespace": "apm-sourcemaps", "description": "Get source maps", - "method": "GET", - "path": "/api/apm/sourcemaps", "namespaceFile": "apm-sourcemaps" }, { "name": "upload-source-map", "namespace": "apm-sourcemaps", "description": "Upload a source map", - "method": "POST", - "path": "/api/apm/sourcemaps", "namespaceFile": "apm-sourcemaps" }, { "name": "delete-source-map", "namespace": "apm-sourcemaps", "description": "Delete source map", - "method": "DELETE", - "path": "/api/apm/sourcemaps/{id}", "namespaceFile": "apm-sourcemaps" }, { "name": "get-actions-connector-types", "namespace": "connectors", "description": "Get connector types", - "method": "GET", - "path": "/api/actions/connector_types", "namespaceFile": "connectors" }, { "name": "get-actions-connector-oauth-callback", "namespace": "connectors", "description": "Handle OAuth callback", - "method": "GET", - "path": "/api/actions/connector/_oauth_callback", "namespaceFile": "connectors" }, { "name": "delete-actions-connector-id", "namespace": "connectors", "description": "Delete a connector", - "method": "DELETE", - "path": "/api/actions/connector/{id}", "namespaceFile": "connectors" }, { "name": "get-actions-connector-id", "namespace": "connectors", "description": "Get connector information", - "method": "GET", - "path": "/api/actions/connector/{id}", "namespaceFile": "connectors" }, { "name": "post-actions-connector-id", "namespace": "connectors", "description": "Create a connector", - "method": "POST", - "path": "/api/actions/connector/{id}", "namespaceFile": "connectors" }, { "name": "put-actions-connector-id", "namespace": "connectors", "description": "Update a connector", - "method": "PUT", - "path": "/api/actions/connector/{id}", "namespaceFile": "connectors" }, { "name": "post-actions-connector-id-execute", "namespace": "connectors", "description": "Run a connector", - "method": "POST", - "path": "/api/actions/connector/{id}/_execute", "namespaceFile": "connectors" }, { "name": "get-actions-connectors", "namespace": "connectors", "description": "Get all connectors", - "method": "GET", - "path": "/api/actions/connectors", "namespaceFile": "connectors" }, { "name": "get-fleet-data-streams", "namespace": "data-streams", "description": "Get data streams", - "method": "GET", - "path": "/api/fleet/data_streams", "namespaceFile": "data-streams" }, { "name": "get-fleet-epm-data-streams", "namespace": "data-streams", "description": "Get data streams", - "method": "GET", - "path": "/api/fleet/epm/data_streams", "namespaceFile": "data-streams" }, { "name": "get-all-data-views-default", "namespace": "data-views", "description": "Get all data views", - "method": "GET", - "path": "/api/data_views", "namespaceFile": "data-views" }, { "name": "create-data-view-defaultw", "namespace": "data-views", "description": "Create a data view", - "method": "POST", - "path": "/api/data_views/data_view", "namespaceFile": "data-views" }, { "name": "delete-data-view-default", "namespace": "data-views", "description": "Delete a data view", - "method": "DELETE", - "path": "/api/data_views/data_view/{viewId}", "namespaceFile": "data-views" }, { "name": "get-data-view-default", "namespace": "data-views", "description": "Get a data view", - "method": "GET", - "path": "/api/data_views/data_view/{viewId}", "namespaceFile": "data-views" }, { "name": "update-data-view-default", "namespace": "data-views", "description": "Update a data view", - "method": "POST", - "path": "/api/data_views/data_view/{viewId}", "namespaceFile": "data-views" }, { "name": "update-fields-metadata-default", "namespace": "data-views", "description": "Update data view fields metadata", - "method": "POST", - "path": "/api/data_views/data_view/{viewId}/fields", "namespaceFile": "data-views" }, { "name": "create-runtime-field-default", "namespace": "data-views", "description": "Create a runtime field", - "method": "POST", - "path": "/api/data_views/data_view/{viewId}/runtime_field", "namespaceFile": "data-views" }, { "name": "create-update-runtime-field-default", "namespace": "data-views", "description": "Create or update a runtime field", - "method": "PUT", - "path": "/api/data_views/data_view/{viewId}/runtime_field", "namespaceFile": "data-views" }, { "name": "delete-runtime-field-default", "namespace": "data-views", "description": "Delete a runtime field from a data view", - "method": "DELETE", - "path": "/api/data_views/data_view/{viewId}/runtime_field/{fieldName}", "namespaceFile": "data-views" }, { "name": "get-runtime-field-default", "namespace": "data-views", "description": "Get a runtime field", - "method": "GET", - "path": "/api/data_views/data_view/{viewId}/runtime_field/{fieldName}", "namespaceFile": "data-views" }, { "name": "update-runtime-field-default", "namespace": "data-views", "description": "Update a runtime field", - "method": "POST", - "path": "/api/data_views/data_view/{viewId}/runtime_field/{fieldName}", "namespaceFile": "data-views" }, { "name": "get-default-data-view-default", "namespace": "data-views", "description": "Get the default data view", - "method": "GET", - "path": "/api/data_views/default", "namespaceFile": "data-views" }, { "name": "set-default-datail-view-default", "namespace": "data-views", "description": "Set the default data view", - "method": "POST", - "path": "/api/data_views/default", "namespaceFile": "data-views" }, { "name": "swap-data-views-default", "namespace": "data-views", "description": "Swap saved object references", - "method": "POST", - "path": "/api/data_views/swap_references", "namespaceFile": "data-views" }, { "name": "preview-swap-data-views-default", "namespace": "data-views", "description": "Preview a saved object reference swap", - "method": "POST", - "path": "/api/data_views/swap_references/_preview", "namespaceFile": "data-views" }, { "name": "post-fleet-agents-agentid-actions", "namespace": "elastic-agent-actions", "description": "Create an agent action", - "method": "POST", - "path": "/api/fleet/agents/{agentId}/actions", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-agentid-reassign", "namespace": "elastic-agent-actions", "description": "Reassign an agent", - "method": "POST", - "path": "/api/fleet/agents/{agentId}/reassign", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-agentid-request-diagnostics", "namespace": "elastic-agent-actions", "description": "Request agent diagnostics", - "method": "POST", - "path": "/api/fleet/agents/{agentId}/request_diagnostics", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-agentid-rollback", "namespace": "elastic-agent-actions", "description": "Rollback an agent", - "method": "POST", - "path": "/api/fleet/agents/{agentId}/rollback", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-agentid-unenroll", "namespace": "elastic-agent-actions", "description": "Unenroll an agent", - "method": "POST", - "path": "/api/fleet/agents/{agentId}/unenroll", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-agentid-upgrade", "namespace": "elastic-agent-actions", "description": "Upgrade an agent", - "method": "POST", - "path": "/api/fleet/agents/{agentId}/upgrade", "namespaceFile": "elastic-agent-actions" }, { "name": "get-fleet-agents-action-status", "namespace": "elastic-agent-actions", "description": "Get an agent action status", - "method": "GET", - "path": "/api/fleet/agents/action_status", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-actions-actionid-cancel", "namespace": "elastic-agent-actions", "description": "Cancel an agent action", - "method": "POST", - "path": "/api/fleet/agents/actions/{actionId}/cancel", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-bulk-reassign", "namespace": "elastic-agent-actions", "description": "Bulk reassign agents", - "method": "POST", - "path": "/api/fleet/agents/bulk_reassign", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-bulk-request-diagnostics", "namespace": "elastic-agent-actions", "description": "Bulk request diagnostics from agents", - "method": "POST", - "path": "/api/fleet/agents/bulk_request_diagnostics", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-bulk-rollback", "namespace": "elastic-agent-actions", "description": "Bulk rollback agents", - "method": "POST", - "path": "/api/fleet/agents/bulk_rollback", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-bulk-unenroll", "namespace": "elastic-agent-actions", "description": "Bulk unenroll agents", - "method": "POST", - "path": "/api/fleet/agents/bulk_unenroll", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-bulk-update-agent-tags", "namespace": "elastic-agent-actions", "description": "Bulk update agent tags", - "method": "POST", - "path": "/api/fleet/agents/bulk_update_agent_tags", "namespaceFile": "elastic-agent-actions" }, { "name": "post-fleet-agents-bulk-upgrade", "namespace": "elastic-agent-actions", "description": "Bulk upgrade agents", - "method": "POST", - "path": "/api/fleet/agents/bulk_upgrade", "namespaceFile": "elastic-agent-actions" }, { "name": "get-fleet-agent-download-sources", "namespace": "elastic-agent-binary-download-sources", "description": "Get agent binary download sources", - "method": "GET", - "path": "/api/fleet/agent_download_sources", "namespaceFile": "elastic-agent-binary-download-sources" }, { "name": "post-fleet-agent-download-sources", "namespace": "elastic-agent-binary-download-sources", "description": "Create an agent binary download source", - "method": "POST", - "path": "/api/fleet/agent_download_sources", "namespaceFile": "elastic-agent-binary-download-sources" }, { "name": "delete-fleet-agent-download-sources-sourceid", "namespace": "elastic-agent-binary-download-sources", "description": "Delete an agent binary download source", - "method": "DELETE", - "path": "/api/fleet/agent_download_sources/{sourceId}", "namespaceFile": "elastic-agent-binary-download-sources" }, { "name": "get-fleet-agent-download-sources-sourceid", "namespace": "elastic-agent-binary-download-sources", "description": "Get an agent binary download source", - "method": "GET", - "path": "/api/fleet/agent_download_sources/{sourceId}", "namespaceFile": "elastic-agent-binary-download-sources" }, { "name": "put-fleet-agent-download-sources-sourceid", "namespace": "elastic-agent-binary-download-sources", "description": "Update an agent binary download source", - "method": "PUT", - "path": "/api/fleet/agent_download_sources/{sourceId}", "namespaceFile": "elastic-agent-binary-download-sources" }, { "name": "get-fleet-agent-policies", "namespace": "elastic-agent-policies", "description": "Get agent policies", - "method": "GET", - "path": "/api/fleet/agent_policies", "namespaceFile": "elastic-agent-policies" }, { "name": "post-fleet-agent-policies", "namespace": "elastic-agent-policies", "description": "Create an agent policy", - "method": "POST", - "path": "/api/fleet/agent_policies", "namespaceFile": "elastic-agent-policies" }, { "name": "post-fleet-agent-policies-bulk-get", "namespace": "elastic-agent-policies", "description": "Bulk get agent policies", - "method": "POST", - "path": "/api/fleet/agent_policies/_bulk_get", "namespaceFile": "elastic-agent-policies" }, { "name": "get-fleet-agent-policies-agentpolicyid", "namespace": "elastic-agent-policies", "description": "Get an agent policy", - "method": "GET", - "path": "/api/fleet/agent_policies/{agentPolicyId}", "namespaceFile": "elastic-agent-policies" }, { "name": "put-fleet-agent-policies-agentpolicyid", "namespace": "elastic-agent-policies", "description": "Update an agent policy", - "method": "PUT", - "path": "/api/fleet/agent_policies/{agentPolicyId}", "namespaceFile": "elastic-agent-policies" }, { "name": "get-fleet-agent-policies-agentpolicyid-auto-upgrade-agents-status", "namespace": "elastic-agent-policies", "description": "Get auto upgrade agent status", - "method": "GET", - "path": "/api/fleet/agent_policies/{agentPolicyId}/auto_upgrade_agents_status", "namespaceFile": "elastic-agent-policies" }, { "name": "post-fleet-agent-policies-agentpolicyid-copy", "namespace": "elastic-agent-policies", "description": "Copy an agent policy", - "method": "POST", - "path": "/api/fleet/agent_policies/{agentPolicyId}/copy", "namespaceFile": "elastic-agent-policies" }, { "name": "get-fleet-agent-policies-agentpolicyid-download", "namespace": "elastic-agent-policies", "description": "Download an agent policy", - "method": "GET", - "path": "/api/fleet/agent_policies/{agentPolicyId}/download", "namespaceFile": "elastic-agent-policies" }, { "name": "get-fleet-agent-policies-agentpolicyid-full", "namespace": "elastic-agent-policies", "description": "Get a full agent policy", - "method": "GET", - "path": "/api/fleet/agent_policies/{agentPolicyId}/full", "namespaceFile": "elastic-agent-policies" }, { "name": "get-fleet-agent-policies-agentpolicyid-outputs", "namespace": "elastic-agent-policies", "description": "Get outputs for an agent policy", - "method": "GET", - "path": "/api/fleet/agent_policies/{agentPolicyId}/outputs", "namespaceFile": "elastic-agent-policies" }, { "name": "post-fleet-agent-policies-delete", "namespace": "elastic-agent-policies", "description": "Delete an agent policy", - "method": "POST", - "path": "/api/fleet/agent_policies/delete", "namespaceFile": "elastic-agent-policies" }, { "name": "post-fleet-agent-policies-outputs", "namespace": "elastic-agent-policies", "description": "Get outputs for agent policies", - "method": "POST", - "path": "/api/fleet/agent_policies/outputs", "namespaceFile": "elastic-agent-policies" }, { "name": "get-fleet-kubernetes", "namespace": "elastic-agent-policies", "description": "Get a full K8s agent manifest", - "method": "GET", - "path": "/api/fleet/kubernetes", "namespaceFile": "elastic-agent-policies" }, { "name": "get-fleet-kubernetes-download", "namespace": "elastic-agent-policies", "description": "Download an agent manifest", - "method": "GET", - "path": "/api/fleet/kubernetes/download", "namespaceFile": "elastic-agent-policies" }, { "name": "get-fleet-agent-status", "namespace": "elastic-agent-status", "description": "Get an agent status summary", - "method": "GET", - "path": "/api/fleet/agent_status", "namespaceFile": "elastic-agent-status" }, { "name": "get-fleet-agent-status-data", "namespace": "elastic-agents", "description": "Get incoming agent data", - "method": "GET", - "path": "/api/fleet/agent_status/data", "namespaceFile": "elastic-agents" }, { "name": "get-fleet-agents", "namespace": "elastic-agents", "description": "Get agents", - "method": "GET", - "path": "/api/fleet/agents", "namespaceFile": "elastic-agents" }, { "name": "post-fleet-agents", "namespace": "elastic-agents", "description": "Get agents by action ids", - "method": "POST", - "path": "/api/fleet/agents", "namespaceFile": "elastic-agents" }, { "name": "delete-fleet-agents-agentid", "namespace": "elastic-agents", "description": "Delete an agent", - "method": "DELETE", - "path": "/api/fleet/agents/{agentId}", "namespaceFile": "elastic-agents" }, { "name": "get-fleet-agents-agentid", "namespace": "elastic-agents", "description": "Get an agent", - "method": "GET", - "path": "/api/fleet/agents/{agentId}", "namespaceFile": "elastic-agents" }, { "name": "put-fleet-agents-agentid", "namespace": "elastic-agents", "description": "Update an agent by ID", - "method": "PUT", - "path": "/api/fleet/agents/{agentId}", "namespaceFile": "elastic-agents" }, { "name": "post-fleet-agents-agentid-migrate", "namespace": "elastic-agents", "description": "Migrate a single agent", - "method": "POST", - "path": "/api/fleet/agents/{agentId}/migrate", "namespaceFile": "elastic-agents" }, { "name": "post-fleet-agents-agentid-privilege-level-change", "namespace": "elastic-agents", "description": "Change agent privilege level", - "method": "POST", - "path": "/api/fleet/agents/{agentId}/privilege_level_change", "namespaceFile": "elastic-agents" }, { "name": "get-fleet-agents-agentid-uploads", "namespace": "elastic-agents", "description": "Get agent uploads", - "method": "GET", - "path": "/api/fleet/agents/{agentId}/uploads", "namespaceFile": "elastic-agents" }, { "name": "get-fleet-agents-available-versions", "namespace": "elastic-agents", "description": "Get available agent versions", - "method": "GET", - "path": "/api/fleet/agents/available_versions", "namespaceFile": "elastic-agents" }, { "name": "post-fleet-agents-bulk-migrate", "namespace": "elastic-agents", "description": "Migrate multiple agents", - "method": "POST", - "path": "/api/fleet/agents/bulk_migrate", "namespaceFile": "elastic-agents" }, { "name": "post-fleet-agents-bulk-privilege-level-change", "namespace": "elastic-agents", "description": "Bulk change agent privilege level", - "method": "POST", - "path": "/api/fleet/agents/bulk_privilege_level_change", "namespaceFile": "elastic-agents" }, { "name": "delete-fleet-agents-files-fileid", "namespace": "elastic-agents", "description": "Delete an uploaded file", - "method": "DELETE", - "path": "/api/fleet/agents/files/{fileId}", "namespaceFile": "elastic-agents" }, { "name": "get-fleet-agents-files-fileid-filename", "namespace": "elastic-agents", "description": "Get an uploaded file", - "method": "GET", - "path": "/api/fleet/agents/files/{fileId}/{fileName}", "namespaceFile": "elastic-agents" }, { "name": "get-fleet-agents-setup", "namespace": "elastic-agents", "description": "Get agent setup info", - "method": "GET", - "path": "/api/fleet/agents/setup", "namespaceFile": "elastic-agents" }, { "name": "post-fleet-agents-setup", "namespace": "elastic-agents", "description": "Initiate agent setup", - "method": "POST", - "path": "/api/fleet/agents/setup", "namespaceFile": "elastic-agents" }, { "name": "get-fleet-agents-tags", "namespace": "elastic-agents", "description": "Get agent tags", - "method": "GET", - "path": "/api/fleet/agents/tags", "namespaceFile": "elastic-agents" }, { "name": "post-fleet-epm-bulk-assets", "namespace": "elastic-package-manager-epm", "description": "Bulk get assets", - "method": "POST", - "path": "/api/fleet/epm/bulk_assets", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-categories", "namespace": "elastic-package-manager-epm", "description": "Get package categories", - "method": "GET", - "path": "/api/fleet/epm/categories", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-custom-integrations", "namespace": "elastic-package-manager-epm", "description": "Create a custom integration", - "method": "POST", - "path": "/api/fleet/epm/custom_integrations", "namespaceFile": "elastic-package-manager-epm" }, { "name": "put-fleet-epm-custom-integrations-pkgname", "namespace": "elastic-package-manager-epm", "description": "Update a custom integration", - "method": "PUT", - "path": "/api/fleet/epm/custom_integrations/{pkgName}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages", "namespace": "elastic-package-manager-epm", "description": "Get packages", - "method": "GET", - "path": "/api/fleet/epm/packages", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages", "namespace": "elastic-package-manager-epm", "description": "Install a package by upload", - "method": "POST", - "path": "/api/fleet/epm/packages", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-bulk", "namespace": "elastic-package-manager-epm", "description": "Bulk install packages", - "method": "POST", - "path": "/api/fleet/epm/packages/_bulk", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-bulk-rollback", "namespace": "elastic-package-manager-epm", "description": "Bulk rollback packages", - "method": "POST", - "path": "/api/fleet/epm/packages/_bulk_rollback", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages-bulk-rollback-taskid", "namespace": "elastic-package-manager-epm", "description": "Get Bulk rollback packages details", - "method": "GET", - "path": "/api/fleet/epm/packages/_bulk_rollback/{taskId}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-bulk-uninstall", "namespace": "elastic-package-manager-epm", "description": "Bulk uninstall packages", - "method": "POST", - "path": "/api/fleet/epm/packages/_bulk_uninstall", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages-bulk-uninstall-taskid", "namespace": "elastic-package-manager-epm", "description": "Get Bulk uninstall packages details", - "method": "GET", - "path": "/api/fleet/epm/packages/_bulk_uninstall/{taskId}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-bulk-upgrade", "namespace": "elastic-package-manager-epm", "description": "Bulk upgrade packages", - "method": "POST", - "path": "/api/fleet/epm/packages/_bulk_upgrade", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages-bulk-upgrade-taskid", "namespace": "elastic-package-manager-epm", "description": "Get Bulk upgrade packages details", - "method": "GET", - "path": "/api/fleet/epm/packages/_bulk_upgrade/{taskId}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "delete-fleet-epm-packages-pkgname", "namespace": "elastic-package-manager-epm", "description": "Delete a package", - "method": "DELETE", - "path": "/api/fleet/epm/packages/{pkgName}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages-pkgname", "namespace": "elastic-package-manager-epm", "description": "Get a package", - "method": "GET", - "path": "/api/fleet/epm/packages/{pkgName}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-pkgname", "namespace": "elastic-package-manager-epm", "description": "Install a package from the registry", - "method": "POST", - "path": "/api/fleet/epm/packages/{pkgName}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "put-fleet-epm-packages-pkgname", "namespace": "elastic-package-manager-epm", "description": "Update package settings", - "method": "PUT", - "path": "/api/fleet/epm/packages/{pkgName}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "delete-fleet-epm-packages-pkgname-pkgversion", "namespace": "elastic-package-manager-epm", "description": "Delete a package", - "method": "DELETE", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages-pkgname-pkgversion", "namespace": "elastic-package-manager-epm", "description": "Get a package", - "method": "GET", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-pkgname-pkgversion", "namespace": "elastic-package-manager-epm", "description": "Install a package from the registry", - "method": "POST", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "put-fleet-epm-packages-pkgname-pkgversion", "namespace": "elastic-package-manager-epm", "description": "Update package settings", - "method": "PUT", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages-pkgname-pkgversion-filepath", "namespace": "elastic-package-manager-epm", "description": "Get a package file", - "method": "GET", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/{filePath}", "namespaceFile": "elastic-package-manager-epm" }, { "name": "delete-fleet-epm-packages-pkgname-pkgversion-datastream-assets", "namespace": "elastic-package-manager-epm", "description": "Delete assets for an input package", - "method": "DELETE", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/datastream_assets", "namespaceFile": "elastic-package-manager-epm" }, { "name": "delete-fleet-epm-packages-pkgname-pkgversion-kibana-assets", "namespace": "elastic-package-manager-epm", "description": "Delete Kibana assets for a package", - "method": "DELETE", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/kibana_assets", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-pkgname-pkgversion-kibana-assets", "namespace": "elastic-package-manager-epm", "description": "Install Kibana assets for a package", - "method": "POST", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/kibana_assets", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-pkgname-pkgversion-rule-assets", "namespace": "elastic-package-manager-epm", "description": "Install Kibana alert rule for a package", - "method": "POST", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/rule_assets", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-pkgname-pkgversion-transforms-authorize", "namespace": "elastic-package-manager-epm", "description": "Authorize transforms", - "method": "POST", - "path": "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/transforms/authorize", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-pkgname-review-upgrade", "namespace": "elastic-package-manager-epm", "description": "Review a pending policy upgrade for a package with deprecations", - "method": "POST", - "path": "/api/fleet/epm/packages/{pkgName}/review_upgrade", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-epm-packages-pkgname-rollback", "namespace": "elastic-package-manager-epm", "description": "Rollback a package to previous version", - "method": "POST", - "path": "/api/fleet/epm/packages/{pkgName}/rollback", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages-pkgname-stats", "namespace": "elastic-package-manager-epm", "description": "Get package stats", - "method": "GET", - "path": "/api/fleet/epm/packages/{pkgName}/stats", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages-installed", "namespace": "elastic-package-manager-epm", "description": "Get installed packages", - "method": "GET", - "path": "/api/fleet/epm/packages/installed", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-packages-limited", "namespace": "elastic-package-manager-epm", "description": "Get a limited package list", - "method": "GET", - "path": "/api/fleet/epm/packages/limited", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-templates-pkgname-pkgversion-inputs", "namespace": "elastic-package-manager-epm", "description": "Get an inputs template", - "method": "GET", - "path": "/api/fleet/epm/templates/{pkgName}/{pkgVersion}/inputs", "namespaceFile": "elastic-package-manager-epm" }, { "name": "get-fleet-epm-verification-key-id", "namespace": "elastic-package-manager-epm", "description": "Get a package signature verification key ID", - "method": "GET", - "path": "/api/fleet/epm/verification_key_id", "namespaceFile": "elastic-package-manager-epm" }, { "name": "post-fleet-agentless-policies", "namespace": "fleet-agentless-policies", "description": "Create an agentless policy", - "method": "POST", - "path": "/api/fleet/agentless_policies", "namespaceFile": "fleet-agentless-policies" }, { "name": "delete-fleet-agentless-policies-policyid", "namespace": "fleet-agentless-policies", "description": "Delete an agentless policy", - "method": "DELETE", - "path": "/api/fleet/agentless_policies/{policyId}", "namespaceFile": "fleet-agentless-policies" }, { "name": "get-fleet-cloud-connectors", "namespace": "fleet-cloud-connectors", "description": "Get cloud connectors", - "method": "GET", - "path": "/api/fleet/cloud_connectors", "namespaceFile": "fleet-cloud-connectors" }, { "name": "post-fleet-cloud-connectors", "namespace": "fleet-cloud-connectors", "description": "Create cloud connector", - "method": "POST", - "path": "/api/fleet/cloud_connectors", "namespaceFile": "fleet-cloud-connectors" }, { "name": "delete-fleet-cloud-connectors-cloudconnectorid", "namespace": "fleet-cloud-connectors", "description": "Delete cloud connector (supports force deletion)", - "method": "DELETE", - "path": "/api/fleet/cloud_connectors/{cloudConnectorId}", "namespaceFile": "fleet-cloud-connectors" }, { "name": "get-fleet-cloud-connectors-cloudconnectorid", "namespace": "fleet-cloud-connectors", "description": "Get cloud connector", - "method": "GET", - "path": "/api/fleet/cloud_connectors/{cloudConnectorId}", "namespaceFile": "fleet-cloud-connectors" }, { "name": "put-fleet-cloud-connectors-cloudconnectorid", "namespace": "fleet-cloud-connectors", "description": "Update cloud connector", - "method": "PUT", - "path": "/api/fleet/cloud_connectors/{cloudConnectorId}", "namespaceFile": "fleet-cloud-connectors" }, { "name": "get-fleet-cloud-connectors-cloudconnectorid-usage", "namespace": "fleet-cloud-connectors", "description": "Get cloud connector usage (package policies using the connector)", - "method": "GET", - "path": "/api/fleet/cloud_connectors/{cloudConnectorId}/usage", "namespaceFile": "fleet-cloud-connectors" }, { "name": "get-fleet-enrollment-api-keys", "namespace": "fleet-enrollment-api-keys", "description": "Get enrollment API keys", - "method": "GET", - "path": "/api/fleet/enrollment_api_keys", "namespaceFile": "fleet-enrollment-api-keys" }, { "name": "post-fleet-enrollment-api-keys", "namespace": "fleet-enrollment-api-keys", "description": "Create an enrollment API key", - "method": "POST", - "path": "/api/fleet/enrollment_api_keys", "namespaceFile": "fleet-enrollment-api-keys" }, { "name": "delete-fleet-enrollment-api-keys-keyid", "namespace": "fleet-enrollment-api-keys", "description": "Revoke an enrollment API key", - "method": "DELETE", - "path": "/api/fleet/enrollment_api_keys/{keyId}", "namespaceFile": "fleet-enrollment-api-keys" }, { "name": "get-fleet-enrollment-api-keys-keyid", "namespace": "fleet-enrollment-api-keys", "description": "Get an enrollment API key", - "method": "GET", - "path": "/api/fleet/enrollment_api_keys/{keyId}", "namespaceFile": "fleet-enrollment-api-keys" }, { "name": "get-fleet-check-permissions", "namespace": "fleet-internals", "description": "Check permissions", - "method": "GET", - "path": "/api/fleet/check-permissions", "namespaceFile": "fleet-internals" }, { "name": "post-fleet-health-check", "namespace": "fleet-internals", "description": "Check Fleet Server health", - "method": "POST", - "path": "/api/fleet/health_check", "namespaceFile": "fleet-internals" }, { "name": "get-fleet-settings", "namespace": "fleet-internals", "description": "Get settings", - "method": "GET", - "path": "/api/fleet/settings", "namespaceFile": "fleet-internals" }, { "name": "put-fleet-settings", "namespace": "fleet-internals", "description": "Update settings", - "method": "PUT", - "path": "/api/fleet/settings", "namespaceFile": "fleet-internals" }, { "name": "post-fleet-setup", "namespace": "fleet-internals", "description": "Initiate Fleet setup", - "method": "POST", - "path": "/api/fleet/setup", "namespaceFile": "fleet-internals" }, { "name": "post-fleet-logstash-api-keys", "namespace": "fleet-outputs", "description": "Generate a Logstash API key", - "method": "POST", - "path": "/api/fleet/logstash_api_keys", "namespaceFile": "fleet-outputs" }, { "name": "get-fleet-outputs", "namespace": "fleet-outputs", "description": "Get outputs", - "method": "GET", - "path": "/api/fleet/outputs", "namespaceFile": "fleet-outputs" }, { "name": "post-fleet-outputs", "namespace": "fleet-outputs", "description": "Create output", - "method": "POST", - "path": "/api/fleet/outputs", "namespaceFile": "fleet-outputs" }, { "name": "delete-fleet-outputs-outputid", "namespace": "fleet-outputs", "description": "Delete output", - "method": "DELETE", - "path": "/api/fleet/outputs/{outputId}", "namespaceFile": "fleet-outputs" }, { "name": "get-fleet-outputs-outputid", "namespace": "fleet-outputs", "description": "Get output", - "method": "GET", - "path": "/api/fleet/outputs/{outputId}", "namespaceFile": "fleet-outputs" }, { "name": "put-fleet-outputs-outputid", "namespace": "fleet-outputs", "description": "Update output", - "method": "PUT", - "path": "/api/fleet/outputs/{outputId}", "namespaceFile": "fleet-outputs" }, { "name": "get-fleet-outputs-outputid-health", "namespace": "fleet-outputs", "description": "Get the latest output health", - "method": "GET", - "path": "/api/fleet/outputs/{outputId}/health", "namespaceFile": "fleet-outputs" }, { "name": "get-fleet-package-policies", "namespace": "fleet-package-policies", "description": "Get package policies", - "method": "GET", - "path": "/api/fleet/package_policies", "namespaceFile": "fleet-package-policies" }, { "name": "post-fleet-package-policies", "namespace": "fleet-package-policies", "description": "Create a package policy", - "method": "POST", - "path": "/api/fleet/package_policies", "namespaceFile": "fleet-package-policies" }, { "name": "post-fleet-package-policies-bulk-get", "namespace": "fleet-package-policies", "description": "Bulk get package policies", - "method": "POST", - "path": "/api/fleet/package_policies/_bulk_get", "namespaceFile": "fleet-package-policies" }, { "name": "delete-fleet-package-policies-packagepolicyid", "namespace": "fleet-package-policies", "description": "Delete a package policy", - "method": "DELETE", - "path": "/api/fleet/package_policies/{packagePolicyId}", "namespaceFile": "fleet-package-policies" }, { "name": "get-fleet-package-policies-packagepolicyid", "namespace": "fleet-package-policies", "description": "Get a package policy", - "method": "GET", - "path": "/api/fleet/package_policies/{packagePolicyId}", "namespaceFile": "fleet-package-policies" }, { "name": "put-fleet-package-policies-packagepolicyid", "namespace": "fleet-package-policies", "description": "Update a package policy", - "method": "PUT", - "path": "/api/fleet/package_policies/{packagePolicyId}", "namespaceFile": "fleet-package-policies" }, { "name": "post-fleet-package-policies-delete", "namespace": "fleet-package-policies", "description": "Bulk delete package policies", - "method": "POST", - "path": "/api/fleet/package_policies/delete", "namespaceFile": "fleet-package-policies" }, { "name": "post-fleet-package-policies-upgrade", "namespace": "fleet-package-policies", "description": "Upgrade a package policy", - "method": "POST", - "path": "/api/fleet/package_policies/upgrade", "namespaceFile": "fleet-package-policies" }, { "name": "post-fleet-package-policies-upgrade-dryrun", "namespace": "fleet-package-policies", "description": "Dry run a package policy upgrade", - "method": "POST", - "path": "/api/fleet/package_policies/upgrade/dryrun", "namespaceFile": "fleet-package-policies" }, { "name": "get-fleet-proxies", "namespace": "fleet-proxies", "description": "Get proxies", - "method": "GET", - "path": "/api/fleet/proxies", "namespaceFile": "fleet-proxies" }, { "name": "post-fleet-proxies", "namespace": "fleet-proxies", "description": "Create a proxy", - "method": "POST", - "path": "/api/fleet/proxies", "namespaceFile": "fleet-proxies" }, { "name": "delete-fleet-proxies-itemid", "namespace": "fleet-proxies", "description": "Delete a proxy", - "method": "DELETE", - "path": "/api/fleet/proxies/{itemId}", "namespaceFile": "fleet-proxies" }, { "name": "get-fleet-proxies-itemid", "namespace": "fleet-proxies", "description": "Get a proxy", - "method": "GET", - "path": "/api/fleet/proxies/{itemId}", "namespaceFile": "fleet-proxies" }, { "name": "put-fleet-proxies-itemid", "namespace": "fleet-proxies", "description": "Update a proxy", - "method": "PUT", - "path": "/api/fleet/proxies/{itemId}", "namespaceFile": "fleet-proxies" }, { "name": "get-fleet-fleet-server-hosts", "namespace": "fleet-server-hosts", "description": "Get Fleet Server hosts", - "method": "GET", - "path": "/api/fleet/fleet_server_hosts", "namespaceFile": "fleet-server-hosts" }, { "name": "post-fleet-fleet-server-hosts", "namespace": "fleet-server-hosts", "description": "Create a Fleet Server host", - "method": "POST", - "path": "/api/fleet/fleet_server_hosts", "namespaceFile": "fleet-server-hosts" }, { "name": "delete-fleet-fleet-server-hosts-itemid", "namespace": "fleet-server-hosts", "description": "Delete a Fleet Server host", - "method": "DELETE", - "path": "/api/fleet/fleet_server_hosts/{itemId}", "namespaceFile": "fleet-server-hosts" }, { "name": "get-fleet-fleet-server-hosts-itemid", "namespace": "fleet-server-hosts", "description": "Get a Fleet Server host", - "method": "GET", - "path": "/api/fleet/fleet_server_hosts/{itemId}", "namespaceFile": "fleet-server-hosts" }, { "name": "put-fleet-fleet-server-hosts-itemid", "namespace": "fleet-server-hosts", "description": "Update a Fleet Server host", - "method": "PUT", - "path": "/api/fleet/fleet_server_hosts/{itemId}", "namespaceFile": "fleet-server-hosts" }, { "name": "get-fleet-uninstall-tokens", "namespace": "fleet-uninstall-tokens", "description": "Get metadata for latest uninstall tokens", - "method": "GET", - "path": "/api/fleet/uninstall_tokens", "namespaceFile": "fleet-uninstall-tokens" }, { "name": "get-fleet-uninstall-tokens-uninstalltokenid", "namespace": "fleet-uninstall-tokens", "description": "Get a decrypted uninstall token", - "method": "GET", - "path": "/api/fleet/uninstall_tokens/{uninstallTokenId}", "namespaceFile": "fleet-uninstall-tokens" }, { "name": "post-maintenance-window", "namespace": "maintenance-window", "description": "Create a maintenance window.", - "method": "POST", - "path": "/api/maintenance_window", "namespaceFile": "maintenance-window" }, { "name": "get-maintenance-window-find", "namespace": "maintenance-window", "description": "Search for a maintenance window.", - "method": "GET", - "path": "/api/maintenance_window/_find", "namespaceFile": "maintenance-window" }, { "name": "delete-maintenance-window-id", "namespace": "maintenance-window", "description": "Delete a maintenance window.", - "method": "DELETE", - "path": "/api/maintenance_window/{id}", "namespaceFile": "maintenance-window" }, { "name": "get-maintenance-window-id", "namespace": "maintenance-window", "description": "Get maintenance window details.", - "method": "GET", - "path": "/api/maintenance_window/{id}", "namespaceFile": "maintenance-window" }, { "name": "patch-maintenance-window-id", "namespace": "maintenance-window", "description": "Update a maintenance window.", - "method": "PATCH", - "path": "/api/maintenance_window/{id}", "namespaceFile": "maintenance-window" }, { "name": "post-maintenance-window-id-archive", "namespace": "maintenance-window", "description": "Archive a maintenance window.", - "method": "POST", - "path": "/api/maintenance_window/{id}/_archive", "namespaceFile": "maintenance-window" }, { "name": "post-maintenance-window-id-unarchive", "namespace": "maintenance-window", "description": "Unarchive a maintenance window.", - "method": "POST", - "path": "/api/maintenance_window/{id}/_unarchive", "namespaceFile": "maintenance-window" }, { "name": "post-fleet-message-signing-service-rotate-key-pair", "namespace": "message-signing-service", "description": "Rotate a Fleet message signing key pair", - "method": "POST", - "path": "/api/fleet/message_signing_service/rotate_key_pair", "namespaceFile": "message-signing-service" }, { "name": "get-actions-connector-oauth-callback-script", "namespace": "misc", "description": "", - "method": "GET", - "path": "/api/actions/connector/_oauth_callback_script", "namespaceFile": "misc" }, { "name": "get-fleet-space-settings", "namespace": "misc", "description": "Get space settings", - "method": "GET", - "path": "/api/fleet/space_settings", "namespaceFile": "misc" }, { "name": "put-fleet-space-settings", "namespace": "misc", "description": "Create space settings", - "method": "PUT", - "path": "/api/fleet/space_settings", "namespaceFile": "misc" }, { "name": "post-security-role-query", "namespace": "misc", "description": "Query roles", - "method": "POST", - "path": "/api/security/role/_query", "namespaceFile": "misc" }, { "name": "ml-sync", "namespace": "ml", "description": "Sync saved objects in the default space", - "method": "GET", - "path": "/api/ml/saved_objects/sync", "namespaceFile": "ml" }, { "name": "ml-update-jobs-spaces", "namespace": "ml", "description": "Update jobs spaces", - "method": "POST", - "path": "/api/ml/saved_objects/update_jobs_spaces", "namespaceFile": "ml" }, { "name": "ml-update-trained-models-spaces", "namespace": "ml", "description": "Update trained models spaces", - "method": "POST", - "path": "/api/ml/saved_objects/update_trained_models_spaces", "namespaceFile": "ml" }, { "name": "observability-ai-assistant-chat-complete", "namespace": "observabilityaiassistant", "description": "Generate a chat completion", - "method": "POST", - "path": "/api/observability_ai_assistant/chat/complete", "namespaceFile": "observabilityaiassistant" }, { "name": "get-security-role", "namespace": "roles", "description": "Get all roles", - "method": "GET", - "path": "/api/security/role", "namespaceFile": "roles" }, { "name": "delete-security-role-name", "namespace": "roles", "description": "Delete a role", - "method": "DELETE", - "path": "/api/security/role/{name}", "namespaceFile": "roles" }, { "name": "get-security-role-name", "namespace": "roles", "description": "Get a role", - "method": "GET", - "path": "/api/security/role/{name}", "namespaceFile": "roles" }, { "name": "put-security-role-name", "namespace": "roles", "description": "Create or update a role", - "method": "PUT", - "path": "/api/security/role/{name}", "namespaceFile": "roles" }, { "name": "post-security-roles", "namespace": "roles", "description": "Create or update roles", - "method": "POST", - "path": "/api/security/roles", "namespaceFile": "roles" }, { "name": "post-saved-objects-export", "namespace": "saved-objects", "description": "Export saved objects", - "method": "POST", - "path": "/api/saved_objects/_export", "namespaceFile": "saved-objects" }, { "name": "post-saved-objects-import", "namespace": "saved-objects", "description": "Import saved objects", - "method": "POST", - "path": "/api/saved_objects/_import", "namespaceFile": "saved-objects" }, { "name": "post-saved-objects-resolve-import-errors", "namespace": "saved-objects", "description": "Resolve import errors", - "method": "POST", - "path": "/api/saved_objects/_resolve_import_errors", "namespaceFile": "saved-objects" }, { "name": "perform-anonymization-fields-bulk-action", "namespace": "security-ai-assistant-api", "description": "Apply a bulk action to anonymization fields", - "method": "POST", - "path": "/api/security_ai_assistant/anonymization_fields/_bulk_action", "namespaceFile": "security-ai-assistant-api" }, { "name": "find-anonymization-fields", "namespace": "security-ai-assistant-api", "description": "Get anonymization fields", - "method": "GET", - "path": "/api/security_ai_assistant/anonymization_fields/_find", "namespaceFile": "security-ai-assistant-api" }, { "name": "chat-complete", "namespace": "security-ai-assistant-api", "description": "Create a model response", - "method": "POST", - "path": "/api/security_ai_assistant/chat/complete", "namespaceFile": "security-ai-assistant-api" }, { "name": "delete-all-conversations", "namespace": "security-ai-assistant-api", "description": "Delete conversations", - "method": "DELETE", - "path": "/api/security_ai_assistant/current_user/conversations", "namespaceFile": "security-ai-assistant-api" }, { "name": "create-conversation", "namespace": "security-ai-assistant-api", "description": "Create a conversation", - "method": "POST", - "path": "/api/security_ai_assistant/current_user/conversations", "namespaceFile": "security-ai-assistant-api" }, { "name": "find-conversations", "namespace": "security-ai-assistant-api", "description": "Get conversations", - "method": "GET", - "path": "/api/security_ai_assistant/current_user/conversations/_find", "namespaceFile": "security-ai-assistant-api" }, { "name": "delete-conversation", "namespace": "security-ai-assistant-api", "description": "Delete a conversation", - "method": "DELETE", - "path": "/api/security_ai_assistant/current_user/conversations/{id}", "namespaceFile": "security-ai-assistant-api" }, { "name": "read-conversation", "namespace": "security-ai-assistant-api", "description": "Get a conversation", - "method": "GET", - "path": "/api/security_ai_assistant/current_user/conversations/{id}", "namespaceFile": "security-ai-assistant-api" }, { "name": "update-conversation", "namespace": "security-ai-assistant-api", "description": "Update a conversation", - "method": "PUT", - "path": "/api/security_ai_assistant/current_user/conversations/{id}", "namespaceFile": "security-ai-assistant-api" }, { "name": "get-knowledge-base", "namespace": "security-ai-assistant-api", "description": "Read a KnowledgeBase", - "method": "GET", - "path": "/api/security_ai_assistant/knowledge_base", "namespaceFile": "security-ai-assistant-api" }, { "name": "post-knowledge-base", "namespace": "security-ai-assistant-api", "description": "Create a KnowledgeBase", - "method": "POST", - "path": "/api/security_ai_assistant/knowledge_base", "namespaceFile": "security-ai-assistant-api" }, { "name": "read-knowledge-base", "namespace": "security-ai-assistant-api", "description": "Read a KnowledgeBase for a resource", - "method": "GET", - "path": "/api/security_ai_assistant/knowledge_base/{resource}", "namespaceFile": "security-ai-assistant-api" }, { "name": "create-knowledge-base", "namespace": "security-ai-assistant-api", "description": "Create a KnowledgeBase for a resource", - "method": "POST", - "path": "/api/security_ai_assistant/knowledge_base/{resource}", "namespaceFile": "security-ai-assistant-api" }, { "name": "create-knowledge-base-entry", "namespace": "security-ai-assistant-api", "description": "Create a Knowledge Base Entry", - "method": "POST", - "path": "/api/security_ai_assistant/knowledge_base/entries", "namespaceFile": "security-ai-assistant-api" }, { "name": "perform-knowledge-base-entry-bulk-action", "namespace": "security-ai-assistant-api", "description": "Applies a bulk action to multiple Knowledge Base Entries", - "method": "POST", - "path": "/api/security_ai_assistant/knowledge_base/entries/_bulk_action", "namespaceFile": "security-ai-assistant-api" }, { "name": "find-knowledge-base-entries", "namespace": "security-ai-assistant-api", "description": "Finds Knowledge Base Entries that match the given query.", - "method": "GET", - "path": "/api/security_ai_assistant/knowledge_base/entries/_find", "namespaceFile": "security-ai-assistant-api" }, { "name": "delete-knowledge-base-entry", "namespace": "security-ai-assistant-api", "description": "Deletes a single Knowledge Base Entry using the `id` field", - "method": "DELETE", - "path": "/api/security_ai_assistant/knowledge_base/entries/{id}", "namespaceFile": "security-ai-assistant-api" }, { "name": "read-knowledge-base-entry", "namespace": "security-ai-assistant-api", "description": "Read a Knowledge Base Entry", - "method": "GET", - "path": "/api/security_ai_assistant/knowledge_base/entries/{id}", "namespaceFile": "security-ai-assistant-api" }, { "name": "update-knowledge-base-entry", "namespace": "security-ai-assistant-api", "description": "Update a Knowledge Base Entry", - "method": "PUT", - "path": "/api/security_ai_assistant/knowledge_base/entries/{id}", "namespaceFile": "security-ai-assistant-api" }, { "name": "perform-prompts-bulk-action", "namespace": "security-ai-assistant-api", "description": "Apply a bulk action to prompts", - "method": "POST", - "path": "/api/security_ai_assistant/prompts/_bulk_action", "namespaceFile": "security-ai-assistant-api" }, { "name": "find-prompts", "namespace": "security-ai-assistant-api", "description": "Get prompts", - "method": "GET", - "path": "/api/security_ai_assistant/prompts/_find", "namespaceFile": "security-ai-assistant-api" }, { "name": "post-attack-discovery-bulk", "namespace": "security-attack-discovery-api", "description": "Bulk update Attack discoveries", - "method": "POST", - "path": "/api/attack_discovery/_bulk", "namespaceFile": "security-attack-discovery-api" }, { "name": "attack-discovery-find", "namespace": "security-attack-discovery-api", "description": "Find Attack discoveries that match the search criteria", - "method": "GET", - "path": "/api/attack_discovery/_find", "namespaceFile": "security-attack-discovery-api" }, { "name": "post-attack-discovery-generate", "namespace": "security-attack-discovery-api", "description": "Generate attack discoveries from alerts", - "method": "POST", - "path": "/api/attack_discovery/_generate", "namespaceFile": "security-attack-discovery-api" }, { "name": "get-attack-discovery-generations", "namespace": "security-attack-discovery-api", "description": "Get the latest attack discovery generations metadata for the current user", - "method": "GET", - "path": "/api/attack_discovery/generations", "namespaceFile": "security-attack-discovery-api" }, { "name": "get-attack-discovery-generation", "namespace": "security-attack-discovery-api", "description": "Get a single Attack discovery generation, including its discoveries and (optional) generation metadata", - "method": "GET", - "path": "/api/attack_discovery/generations/{execution_uuid}", "namespaceFile": "security-attack-discovery-api" }, { "name": "post-attack-discovery-generations-dismiss", "namespace": "security-attack-discovery-api", "description": "Dismiss an attack discovery generation", - "method": "POST", - "path": "/api/attack_discovery/generations/{execution_uuid}/_dismiss", "namespaceFile": "security-attack-discovery-api" }, { "name": "create-attack-discovery-schedules", "namespace": "security-attack-discovery-api", "description": "Create Attack discovery schedule", - "method": "POST", - "path": "/api/attack_discovery/schedules", "namespaceFile": "security-attack-discovery-api" }, { "name": "find-attack-discovery-schedules", "namespace": "security-attack-discovery-api", "description": "Finds Attack discovery schedules that match the search criteria", - "method": "GET", - "path": "/api/attack_discovery/schedules/_find", "namespaceFile": "security-attack-discovery-api" }, { "name": "delete-attack-discovery-schedules", "namespace": "security-attack-discovery-api", "description": "Delete Attack discovery schedule", - "method": "DELETE", - "path": "/api/attack_discovery/schedules/{id}", "namespaceFile": "security-attack-discovery-api" }, { "name": "get-attack-discovery-schedules", "namespace": "security-attack-discovery-api", "description": "Get Attack discovery schedule by ID", - "method": "GET", - "path": "/api/attack_discovery/schedules/{id}", "namespaceFile": "security-attack-discovery-api" }, { "name": "update-attack-discovery-schedules", "namespace": "security-attack-discovery-api", "description": "Update Attack discovery schedule", - "method": "PUT", - "path": "/api/attack_discovery/schedules/{id}", "namespaceFile": "security-attack-discovery-api" }, { "name": "disable-attack-discovery-schedules", "namespace": "security-attack-discovery-api", "description": "Disable Attack discovery schedule", - "method": "POST", - "path": "/api/attack_discovery/schedules/{id}/_disable", "namespaceFile": "security-attack-discovery-api" }, { "name": "enable-attack-discovery-schedules", "namespace": "security-attack-discovery-api", "description": "Enable Attack discovery schedule", - "method": "POST", - "path": "/api/attack_discovery/schedules/{id}/_enable", "namespaceFile": "security-attack-discovery-api" }, { "name": "read-privileges", "namespace": "security-detections-api", "description": "Returns user privileges for the Kibana space", - "method": "GET", - "path": "/api/detection_engine/privileges", "namespaceFile": "security-detections-api" }, { "name": "delete-rule", "namespace": "security-detections-api", "description": "Delete a detection rule", - "method": "DELETE", - "path": "/api/detection_engine/rules", "namespaceFile": "security-detections-api" }, { "name": "read-rule", "namespace": "security-detections-api", "description": "Retrieve a detection rule", - "method": "GET", - "path": "/api/detection_engine/rules", "namespaceFile": "security-detections-api" }, { "name": "patch-rule", "namespace": "security-detections-api", "description": "Patch a detection rule", - "method": "PATCH", - "path": "/api/detection_engine/rules", "namespaceFile": "security-detections-api" }, { "name": "create-rule", "namespace": "security-detections-api", "description": "Create a detection rule", - "method": "POST", - "path": "/api/detection_engine/rules", "namespaceFile": "security-detections-api" }, { "name": "update-rule", "namespace": "security-detections-api", "description": "Update a detection rule", - "method": "PUT", - "path": "/api/detection_engine/rules", "namespaceFile": "security-detections-api" }, { "name": "perform-rules-bulk-action", "namespace": "security-detections-api", "description": "Apply a bulk action to detection rules", - "method": "POST", - "path": "/api/detection_engine/rules/_bulk_action", "namespaceFile": "security-detections-api" }, { "name": "export-rules", "namespace": "security-detections-api", "description": "Export detection rules", - "method": "POST", - "path": "/api/detection_engine/rules/_export", "namespaceFile": "security-detections-api" }, { "name": "find-rules", "namespace": "security-detections-api", "description": "List all detection rules", - "method": "GET", - "path": "/api/detection_engine/rules/_find", "namespaceFile": "security-detections-api" }, { "name": "import-rules", "namespace": "security-detections-api", "description": "Import detection rules", - "method": "POST", - "path": "/api/detection_engine/rules/_import", "namespaceFile": "security-detections-api" }, { "name": "rule-preview", "namespace": "security-detections-api", "description": "Preview rule alerts generated on specified time range", - "method": "POST", - "path": "/api/detection_engine/rules/preview", "namespaceFile": "security-detections-api" }, { "name": "set-alert-assignees", "namespace": "security-detections-api", "description": "Assign and unassign users from detection alerts", - "method": "POST", - "path": "/api/detection_engine/signals/assignees", "namespaceFile": "security-detections-api" }, { "name": "search-alerts", "namespace": "security-detections-api", "description": "Find and/or aggregate detection alerts", - "method": "POST", - "path": "/api/detection_engine/signals/search", "namespaceFile": "security-detections-api" }, { "name": "set-alerts-status", "namespace": "security-detections-api", "description": "Set a detection alert status", - "method": "POST", - "path": "/api/detection_engine/signals/status", "namespaceFile": "security-detections-api" }, { "name": "set-alert-tags", "namespace": "security-detections-api", "description": "Add and remove detection alert tags", - "method": "POST", - "path": "/api/detection_engine/signals/tags", "namespaceFile": "security-detections-api" }, { "name": "read-tags", "namespace": "security-detections-api", "description": "List all detection rule tags", - "method": "GET", - "path": "/api/detection_engine/tags", "namespaceFile": "security-detections-api" }, { "name": "create-endpoint-list", "namespace": "security-endpoint-exceptions-api", "description": "Create an Elastic Endpoint rule exception list", - "method": "POST", - "path": "/api/endpoint_list", "namespaceFile": "security-endpoint-exceptions-api" }, { "name": "delete-endpoint-list-item", "namespace": "security-endpoint-exceptions-api", "description": "Delete an Elastic Endpoint exception list item", - "method": "DELETE", - "path": "/api/endpoint_list/items", "namespaceFile": "security-endpoint-exceptions-api" }, { "name": "read-endpoint-list-item", "namespace": "security-endpoint-exceptions-api", "description": "Get an Elastic Endpoint rule exception list item", - "method": "GET", - "path": "/api/endpoint_list/items", "namespaceFile": "security-endpoint-exceptions-api" }, { "name": "create-endpoint-list-item", "namespace": "security-endpoint-exceptions-api", "description": "Create an Elastic Endpoint rule exception list item", - "method": "POST", - "path": "/api/endpoint_list/items", "namespaceFile": "security-endpoint-exceptions-api" }, { "name": "update-endpoint-list-item", "namespace": "security-endpoint-exceptions-api", "description": "Update an Elastic Endpoint rule exception list item", - "method": "PUT", - "path": "/api/endpoint_list/items", "namespaceFile": "security-endpoint-exceptions-api" }, { "name": "find-endpoint-list-items", "namespace": "security-endpoint-exceptions-api", "description": "Get Elastic Endpoint exception list items", - "method": "GET", - "path": "/api/endpoint_list/items/_find", "namespaceFile": "security-endpoint-exceptions-api" }, { "name": "endpoint-get-actions-list", "namespace": "security-endpoint-management-api", "description": "Get response actions", - "method": "GET", - "path": "/api/endpoint/action", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-get-actions-status", "namespace": "security-endpoint-management-api", "description": "Get response actions status", - "method": "GET", - "path": "/api/endpoint/action_status", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-get-actions-details", "namespace": "security-endpoint-management-api", "description": "Get action details", - "method": "GET", - "path": "/api/endpoint/action/{action_id}", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-file-info", "namespace": "security-endpoint-management-api", "description": "Get file information", - "method": "GET", - "path": "/api/endpoint/action/{action_id}/file/{file_id}", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-file-download", "namespace": "security-endpoint-management-api", "description": "Download a file", - "method": "GET", - "path": "/api/endpoint/action/{action_id}/file/{file_id}/download", "namespaceFile": "security-endpoint-management-api" }, { "name": "cancel-action", "namespace": "security-endpoint-management-api", "description": "Cancel a response action", - "method": "POST", - "path": "/api/endpoint/action/cancel", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-execute-action", "namespace": "security-endpoint-management-api", "description": "Run a command", - "method": "POST", - "path": "/api/endpoint/action/execute", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-get-file-action", "namespace": "security-endpoint-management-api", "description": "Get a file", - "method": "POST", - "path": "/api/endpoint/action/get_file", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-isolate-action", "namespace": "security-endpoint-management-api", "description": "Isolate an endpoint", - "method": "POST", - "path": "/api/endpoint/action/isolate", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-kill-process-action", "namespace": "security-endpoint-management-api", "description": "Terminate a process", - "method": "POST", - "path": "/api/endpoint/action/kill_process", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-generate-memory-dump", "namespace": "security-endpoint-management-api", "description": "Generate a memory dump from the host machine", - "method": "POST", - "path": "/api/endpoint/action/memory_dump", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-get-processes-action", "namespace": "security-endpoint-management-api", "description": "Get running processes", - "method": "POST", - "path": "/api/endpoint/action/running_procs", "namespaceFile": "security-endpoint-management-api" }, { "name": "run-script-action", "namespace": "security-endpoint-management-api", "description": "Run a script", - "method": "POST", - "path": "/api/endpoint/action/runscript", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-scan-action", "namespace": "security-endpoint-management-api", "description": "Scan a file or directory", - "method": "POST", - "path": "/api/endpoint/action/scan", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-get-actions-state", "namespace": "security-endpoint-management-api", "description": "Get actions state", - "method": "GET", - "path": "/api/endpoint/action/state", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-suspend-process-action", "namespace": "security-endpoint-management-api", "description": "Suspend a process", - "method": "POST", - "path": "/api/endpoint/action/suspend_process", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-unisolate-action", "namespace": "security-endpoint-management-api", "description": "Release an isolated endpoint", - "method": "POST", - "path": "/api/endpoint/action/unisolate", "namespaceFile": "security-endpoint-management-api" }, { "name": "endpoint-upload-action", "namespace": "security-endpoint-management-api", "description": "Upload a file", - "method": "POST", - "path": "/api/endpoint/action/upload", "namespaceFile": "security-endpoint-management-api" }, { "name": "get-endpoint-metadata-list", "namespace": "security-endpoint-management-api", "description": "Get a metadata list", - "method": "GET", - "path": "/api/endpoint/metadata", "namespaceFile": "security-endpoint-management-api" }, { "name": "get-endpoint-metadata", "namespace": "security-endpoint-management-api", "description": "Get metadata", - "method": "GET", - "path": "/api/endpoint/metadata/{id}", "namespaceFile": "security-endpoint-management-api" }, { "name": "get-policy-response", "namespace": "security-endpoint-management-api", "description": "Get a policy response", - "method": "GET", - "path": "/api/endpoint/policy_response", "namespaceFile": "security-endpoint-management-api" }, { "name": "get-protection-updates-note", "namespace": "security-endpoint-management-api", "description": "Get a protection updates note", - "method": "GET", - "path": "/api/endpoint/protection_updates_note/{package_policy_id}", "namespaceFile": "security-endpoint-management-api" }, { "name": "create-update-protection-updates-note", "namespace": "security-endpoint-management-api", "description": "Create or update a protection updates note", - "method": "POST", - "path": "/api/endpoint/protection_updates_note/{package_policy_id}", "namespaceFile": "security-endpoint-management-api" }, { "name": "delete-asset-criticality-record", "namespace": "security-entity-analytics-api", "description": "Delete an asset criticality record", - "method": "DELETE", - "path": "/api/asset_criticality", "namespaceFile": "security-entity-analytics-api" }, { "name": "get-asset-criticality-record", "namespace": "security-entity-analytics-api", "description": "Get an asset criticality record", - "method": "GET", - "path": "/api/asset_criticality", "namespaceFile": "security-entity-analytics-api" }, { "name": "create-asset-criticality-record", "namespace": "security-entity-analytics-api", "description": "Upsert an asset criticality record", - "method": "POST", - "path": "/api/asset_criticality", "namespaceFile": "security-entity-analytics-api" }, { "name": "bulk-upsert-asset-criticality-records", "namespace": "security-entity-analytics-api", "description": "Bulk upsert asset criticality records", - "method": "POST", - "path": "/api/asset_criticality/bulk", "namespaceFile": "security-entity-analytics-api" }, { "name": "find-asset-criticality-records", "namespace": "security-entity-analytics-api", "description": "List asset criticality records", - "method": "GET", - "path": "/api/asset_criticality/list", "namespaceFile": "security-entity-analytics-api" }, { "name": "delete-monitoring-engine", "namespace": "security-entity-analytics-api", "description": "Delete the Privilege Monitoring Engine", - "method": "DELETE", - "path": "/api/entity_analytics/monitoring/engine/delete", "namespaceFile": "security-entity-analytics-api" }, { "name": "disable-monitoring-engine", "namespace": "security-entity-analytics-api", "description": "Disable the Privilege Monitoring Engine", - "method": "POST", - "path": "/api/entity_analytics/monitoring/engine/disable", "namespaceFile": "security-entity-analytics-api" }, { "name": "init-monitoring-engine", "namespace": "security-entity-analytics-api", "description": "Initialize the Privilege Monitoring Engine", - "method": "POST", - "path": "/api/entity_analytics/monitoring/engine/init", "namespaceFile": "security-entity-analytics-api" }, { "name": "schedule-monitoring-engine", "namespace": "security-entity-analytics-api", "description": "Schedule the Privilege Monitoring Engine", - "method": "POST", - "path": "/api/entity_analytics/monitoring/engine/schedule_now", "namespaceFile": "security-entity-analytics-api" }, { "name": "priv-mon-health", "namespace": "security-entity-analytics-api", "description": "Health check on Privilege Monitoring", - "method": "GET", - "path": "/api/entity_analytics/monitoring/privileges/health", "namespaceFile": "security-entity-analytics-api" }, { "name": "priv-mon-privileges", "namespace": "security-entity-analytics-api", "description": "Run a privileges check on Privilege Monitoring", - "method": "GET", - "path": "/api/entity_analytics/monitoring/privileges/privileges", "namespaceFile": "security-entity-analytics-api" }, { "name": "create-priv-mon-user", "namespace": "security-entity-analytics-api", "description": "Create a new monitored user", - "method": "POST", - "path": "/api/entity_analytics/monitoring/users", "namespaceFile": "security-entity-analytics-api" }, { "name": "privmon-bulk-upload-users-c-s-v", "namespace": "security-entity-analytics-api", "description": "Upsert multiple monitored users via CSV upload", - "method": "POST", - "path": "/api/entity_analytics/monitoring/users/_csv", "namespaceFile": "security-entity-analytics-api" }, { "name": "delete-priv-mon-user", "namespace": "security-entity-analytics-api", "description": "Delete a monitored user", - "method": "DELETE", - "path": "/api/entity_analytics/monitoring/users/{id}", "namespaceFile": "security-entity-analytics-api" }, { "name": "update-priv-mon-user", "namespace": "security-entity-analytics-api", "description": "Update a monitored user", - "method": "PUT", - "path": "/api/entity_analytics/monitoring/users/{id}", "namespaceFile": "security-entity-analytics-api" }, { "name": "list-priv-mon-users", "namespace": "security-entity-analytics-api", "description": "List all monitored users", - "method": "GET", - "path": "/api/entity_analytics/monitoring/users/list", "namespaceFile": "security-entity-analytics-api" }, { "name": "install-privileged-access-detection-package", "namespace": "security-entity-analytics-api", "description": "Installs the privileged access detection package for the Entity Analytics privileged user monitoring experience", - "method": "POST", - "path": "/api/entity_analytics/privileged_user_monitoring/pad/install", "namespaceFile": "security-entity-analytics-api" }, { "name": "get-privileged-access-detection-package-status", "namespace": "security-entity-analytics-api", "description": "Gets the status of the privileged access detection package for the Entity Analytics privileged user monitoring experience", - "method": "GET", - "path": "/api/entity_analytics/privileged_user_monitoring/pad/status", "namespaceFile": "security-entity-analytics-api" }, { "name": "create-watchlist", "namespace": "security-entity-analytics-api", "description": "Create a new watchlist", - "method": "POST", - "path": "/api/entity_analytics/watchlists", "namespaceFile": "security-entity-analytics-api" }, { "name": "get-watchlist", "namespace": "security-entity-analytics-api", "description": "Get a watchlist by ID", - "method": "GET", - "path": "/api/entity_analytics/watchlists/{id}", "namespaceFile": "security-entity-analytics-api" }, { "name": "update-watchlist", "namespace": "security-entity-analytics-api", "description": "Update an existing watchlist", - "method": "PUT", - "path": "/api/entity_analytics/watchlists/{id}", "namespaceFile": "security-entity-analytics-api" }, { "name": "list-watchlists", "namespace": "security-entity-analytics-api", "description": "List all watchlists", - "method": "GET", - "path": "/api/entity_analytics/watchlists/list", "namespaceFile": "security-entity-analytics-api" }, { "name": "init-entity-store", "namespace": "security-entity-analytics-api", "description": "Initialize the Entity Store", - "method": "POST", - "path": "/api/entity_store/enable", "namespaceFile": "security-entity-analytics-api" }, { "name": "delete-entity-engines", "namespace": "security-entity-analytics-api", "description": "Delete Entity Engines", - "method": "DELETE", - "path": "/api/entity_store/engines", "namespaceFile": "security-entity-analytics-api" }, { "name": "list-entity-engines", "namespace": "security-entity-analytics-api", "description": "List the Entity Engines", - "method": "GET", - "path": "/api/entity_store/engines", "namespaceFile": "security-entity-analytics-api" }, { "name": "delete-entity-engine", "namespace": "security-entity-analytics-api", "description": "Delete the Entity Engine", - "method": "DELETE", - "path": "/api/entity_store/engines/{entityType}", "namespaceFile": "security-entity-analytics-api" }, { "name": "get-entity-engine", "namespace": "security-entity-analytics-api", "description": "Get an Entity Engine", - "method": "GET", - "path": "/api/entity_store/engines/{entityType}", "namespaceFile": "security-entity-analytics-api" }, { "name": "init-entity-engine", "namespace": "security-entity-analytics-api", "description": "Initialize an Entity Engine", - "method": "POST", - "path": "/api/entity_store/engines/{entityType}/init", "namespaceFile": "security-entity-analytics-api" }, { "name": "start-entity-engine", "namespace": "security-entity-analytics-api", "description": "Start an Entity Engine", - "method": "POST", - "path": "/api/entity_store/engines/{entityType}/start", "namespaceFile": "security-entity-analytics-api" }, { "name": "stop-entity-engine", "namespace": "security-entity-analytics-api", "description": "Stop an Entity Engine", - "method": "POST", - "path": "/api/entity_store/engines/{entityType}/stop", "namespaceFile": "security-entity-analytics-api" }, { "name": "apply-entity-engine-dataview-indices", "namespace": "security-entity-analytics-api", "description": "Apply DataView indices to all installed engines", - "method": "POST", - "path": "/api/entity_store/engines/apply_dataview_indices", "namespaceFile": "security-entity-analytics-api" }, { "name": "delete-single-entity", "namespace": "security-entity-analytics-api", "description": "Delete an entity in Entity Store", - "method": "DELETE", - "path": "/api/entity_store/entities/{entityType}", "namespaceFile": "security-entity-analytics-api" }, { "name": "upsert-entity", "namespace": "security-entity-analytics-api", "description": "Upsert an entity in Entity Store", - "method": "PUT", - "path": "/api/entity_store/entities/{entityType}", "namespaceFile": "security-entity-analytics-api" }, { "name": "upsert-entities-bulk", "namespace": "security-entity-analytics-api", "description": "Upsert many entities in Entity Store", - "method": "PUT", - "path": "/api/entity_store/entities/bulk", "namespaceFile": "security-entity-analytics-api" }, { "name": "list-entities", "namespace": "security-entity-analytics-api", "description": "List Entity Store Entities", - "method": "GET", - "path": "/api/entity_store/entities/list", "namespaceFile": "security-entity-analytics-api" }, { "name": "get-entity-store-status", "namespace": "security-entity-analytics-api", "description": "Get the status of the Entity Store", - "method": "GET", - "path": "/api/entity_store/status", "namespaceFile": "security-entity-analytics-api" }, { "name": "clean-up-risk-engine", "namespace": "security-entity-analytics-api", "description": "Cleanup the Risk Engine", - "method": "DELETE", - "path": "/api/risk_score/engine/dangerously_delete_data", "namespaceFile": "security-entity-analytics-api" }, { "name": "configure-risk-engine-saved-object", "namespace": "security-entity-analytics-api", "description": "Configure the Risk Engine Saved Object", - "method": "PATCH", - "path": "/api/risk_score/engine/saved_object/configure", "namespaceFile": "security-entity-analytics-api" }, { "name": "schedule-risk-engine-now", "namespace": "security-entity-analytics-api", "description": "Run the risk scoring engine", - "method": "POST", - "path": "/api/risk_score/engine/schedule_now", "namespaceFile": "security-entity-analytics-api" }, { "name": "create-rule-exception-list-items", "namespace": "security-exceptions-api", "description": "Create rule exception items", - "method": "POST", - "path": "/api/detection_engine/rules/{id}/exceptions", "namespaceFile": "security-exceptions-api" }, { "name": "delete-exception-list", "namespace": "security-exceptions-api", "description": "Delete an exception list", - "method": "DELETE", - "path": "/api/exception_lists", "namespaceFile": "security-exceptions-api" }, { "name": "read-exception-list", "namespace": "security-exceptions-api", "description": "Get exception list details", - "method": "GET", - "path": "/api/exception_lists", "namespaceFile": "security-exceptions-api" }, { "name": "create-exception-list", "namespace": "security-exceptions-api", "description": "Create an exception list", - "method": "POST", - "path": "/api/exception_lists", "namespaceFile": "security-exceptions-api" }, { "name": "update-exception-list", "namespace": "security-exceptions-api", "description": "Update an exception list", - "method": "PUT", - "path": "/api/exception_lists", "namespaceFile": "security-exceptions-api" }, { "name": "duplicate-exception-list", "namespace": "security-exceptions-api", "description": "Duplicate an exception list", - "method": "POST", - "path": "/api/exception_lists/_duplicate", "namespaceFile": "security-exceptions-api" }, { "name": "export-exception-list", "namespace": "security-exceptions-api", "description": "Export an exception list", - "method": "POST", - "path": "/api/exception_lists/_export", "namespaceFile": "security-exceptions-api" }, { "name": "find-exception-lists", "namespace": "security-exceptions-api", "description": "Get exception lists", - "method": "GET", - "path": "/api/exception_lists/_find", "namespaceFile": "security-exceptions-api" }, { "name": "import-exception-list", "namespace": "security-exceptions-api", "description": "Import an exception list", - "method": "POST", - "path": "/api/exception_lists/_import", "namespaceFile": "security-exceptions-api" }, { "name": "delete-exception-list-item", "namespace": "security-exceptions-api", "description": "Delete an exception list item", - "method": "DELETE", - "path": "/api/exception_lists/items", "namespaceFile": "security-exceptions-api" }, { "name": "read-exception-list-item", "namespace": "security-exceptions-api", "description": "Get an exception list item", - "method": "GET", - "path": "/api/exception_lists/items", "namespaceFile": "security-exceptions-api" }, { "name": "create-exception-list-item", "namespace": "security-exceptions-api", "description": "Create an exception list item", - "method": "POST", - "path": "/api/exception_lists/items", "namespaceFile": "security-exceptions-api" }, { "name": "update-exception-list-item", "namespace": "security-exceptions-api", "description": "Update an exception list item", - "method": "PUT", - "path": "/api/exception_lists/items", "namespaceFile": "security-exceptions-api" }, { "name": "find-exception-list-items", "namespace": "security-exceptions-api", "description": "Get exception list items", - "method": "GET", - "path": "/api/exception_lists/items/_find", "namespaceFile": "security-exceptions-api" }, { "name": "read-exception-list-summary", "namespace": "security-exceptions-api", "description": "Get an exception list summary", - "method": "GET", - "path": "/api/exception_lists/summary", "namespaceFile": "security-exceptions-api" }, { "name": "create-shared-exception-list", "namespace": "security-exceptions-api", "description": "Create a shared exception list", - "method": "POST", - "path": "/api/exceptions/shared", "namespaceFile": "security-exceptions-api" }, { "name": "delete-list", "namespace": "security-lists-api", "description": "Delete a value list", - "method": "DELETE", - "path": "/api/lists", "namespaceFile": "security-lists-api" }, { "name": "read-list", "namespace": "security-lists-api", "description": "Get value list details", - "method": "GET", - "path": "/api/lists", "namespaceFile": "security-lists-api" }, { "name": "patch-list", "namespace": "security-lists-api", "description": "Patch a value list", - "method": "PATCH", - "path": "/api/lists", "namespaceFile": "security-lists-api" }, { "name": "create-list", "namespace": "security-lists-api", "description": "Create a value list", - "method": "POST", - "path": "/api/lists", "namespaceFile": "security-lists-api" }, { "name": "update-list", "namespace": "security-lists-api", "description": "Update a value list", - "method": "PUT", - "path": "/api/lists", "namespaceFile": "security-lists-api" }, { "name": "find-lists", "namespace": "security-lists-api", "description": "Get value lists", - "method": "GET", - "path": "/api/lists/_find", "namespaceFile": "security-lists-api" }, { "name": "delete-list-index", "namespace": "security-lists-api", "description": "Delete value list data streams", - "method": "DELETE", - "path": "/api/lists/index", "namespaceFile": "security-lists-api" }, { "name": "read-list-index", "namespace": "security-lists-api", "description": "Get status of value list data streams", - "method": "GET", - "path": "/api/lists/index", "namespaceFile": "security-lists-api" }, { "name": "create-list-index", "namespace": "security-lists-api", "description": "Create list data streams", - "method": "POST", - "path": "/api/lists/index", "namespaceFile": "security-lists-api" }, { "name": "delete-list-item", "namespace": "security-lists-api", "description": "Delete a value list item", - "method": "DELETE", - "path": "/api/lists/items", "namespaceFile": "security-lists-api" }, { "name": "read-list-item", "namespace": "security-lists-api", "description": "Get a value list item", - "method": "GET", - "path": "/api/lists/items", "namespaceFile": "security-lists-api" }, { "name": "patch-list-item", "namespace": "security-lists-api", "description": "Patch a value list item", - "method": "PATCH", - "path": "/api/lists/items", "namespaceFile": "security-lists-api" }, { "name": "create-list-item", "namespace": "security-lists-api", "description": "Create a value list item", - "method": "POST", - "path": "/api/lists/items", "namespaceFile": "security-lists-api" }, { "name": "update-list-item", "namespace": "security-lists-api", "description": "Update a value list item", - "method": "PUT", - "path": "/api/lists/items", "namespaceFile": "security-lists-api" }, { "name": "export-list-items", "namespace": "security-lists-api", "description": "Export value list items", - "method": "POST", - "path": "/api/lists/items/_export", "namespaceFile": "security-lists-api" }, { "name": "find-list-items", "namespace": "security-lists-api", "description": "Get value list items", - "method": "GET", - "path": "/api/lists/items/_find", "namespaceFile": "security-lists-api" }, { "name": "import-list-items", "namespace": "security-lists-api", "description": "Import value list items", - "method": "POST", - "path": "/api/lists/items/_import", "namespaceFile": "security-lists-api" }, { "name": "read-list-privileges", "namespace": "security-lists-api", "description": "Get value list privileges", - "method": "GET", - "path": "/api/lists/privileges", "namespaceFile": "security-lists-api" }, { "name": "osquery-find-live-queries", "namespace": "security-osquery-api", "description": "Get live queries", - "method": "GET", - "path": "/api/osquery/live_queries", "namespaceFile": "security-osquery-api" }, { "name": "osquery-create-live-query", "namespace": "security-osquery-api", "description": "Create a live query", - "method": "POST", - "path": "/api/osquery/live_queries", "namespaceFile": "security-osquery-api" }, { "name": "osquery-get-live-query-details", "namespace": "security-osquery-api", "description": "Get live query details", - "method": "GET", - "path": "/api/osquery/live_queries/{id}", "namespaceFile": "security-osquery-api" }, { "name": "osquery-get-live-query-results", "namespace": "security-osquery-api", "description": "Get live query results", - "method": "GET", - "path": "/api/osquery/live_queries/{id}/results/{actionId}", "namespaceFile": "security-osquery-api" }, { "name": "osquery-find-packs", "namespace": "security-osquery-api", "description": "Get packs", - "method": "GET", - "path": "/api/osquery/packs", "namespaceFile": "security-osquery-api" }, { "name": "osquery-create-packs", "namespace": "security-osquery-api", "description": "Create a pack", - "method": "POST", - "path": "/api/osquery/packs", "namespaceFile": "security-osquery-api" }, { "name": "osquery-delete-packs", "namespace": "security-osquery-api", "description": "Delete a pack", - "method": "DELETE", - "path": "/api/osquery/packs/{id}", "namespaceFile": "security-osquery-api" }, { "name": "osquery-get-packs-details", "namespace": "security-osquery-api", "description": "Get pack details", - "method": "GET", - "path": "/api/osquery/packs/{id}", "namespaceFile": "security-osquery-api" }, { "name": "osquery-update-packs", "namespace": "security-osquery-api", "description": "Update a pack", - "method": "PUT", - "path": "/api/osquery/packs/{id}", "namespaceFile": "security-osquery-api" }, { "name": "osquery-find-saved-queries", "namespace": "security-osquery-api", "description": "Get saved queries", - "method": "GET", - "path": "/api/osquery/saved_queries", "namespaceFile": "security-osquery-api" }, { "name": "osquery-create-saved-query", "namespace": "security-osquery-api", "description": "Create a saved query", - "method": "POST", - "path": "/api/osquery/saved_queries", "namespaceFile": "security-osquery-api" }, { "name": "osquery-delete-saved-query", "namespace": "security-osquery-api", "description": "Delete a saved query", - "method": "DELETE", - "path": "/api/osquery/saved_queries/{id}", "namespaceFile": "security-osquery-api" }, { "name": "osquery-get-saved-query-details", "namespace": "security-osquery-api", "description": "Get saved query details", - "method": "GET", - "path": "/api/osquery/saved_queries/{id}", "namespaceFile": "security-osquery-api" }, { "name": "osquery-update-saved-query", "namespace": "security-osquery-api", "description": "Update a saved query", - "method": "PUT", - "path": "/api/osquery/saved_queries/{id}", "namespaceFile": "security-osquery-api" }, { "name": "delete-note", "namespace": "security-timeline-api", "description": "Delete a note", - "method": "DELETE", - "path": "/api/note", "namespaceFile": "security-timeline-api" }, { "name": "get-notes", "namespace": "security-timeline-api", "description": "Get notes", - "method": "GET", - "path": "/api/note", "namespaceFile": "security-timeline-api" }, { "name": "persist-note-route", "namespace": "security-timeline-api", "description": "Add or update a note", - "method": "PATCH", - "path": "/api/note", "namespaceFile": "security-timeline-api" }, { "name": "persist-pinned-event-route", "namespace": "security-timeline-api", "description": "Pin/unpin an event", - "method": "PATCH", - "path": "/api/pinned_event", "namespaceFile": "security-timeline-api" }, { "name": "delete-timelines", "namespace": "security-timeline-api", "description": "Delete Timelines or Timeline templates", - "method": "DELETE", - "path": "/api/timeline", "namespaceFile": "security-timeline-api" }, { "name": "get-timeline", "namespace": "security-timeline-api", "description": "Get Timeline or Timeline template details", - "method": "GET", - "path": "/api/timeline", "namespaceFile": "security-timeline-api" }, { "name": "patch-timeline", "namespace": "security-timeline-api", "description": "Update a Timeline", - "method": "PATCH", - "path": "/api/timeline", "namespaceFile": "security-timeline-api" }, { "name": "create-timelines", "namespace": "security-timeline-api", "description": "Create a Timeline or Timeline template", - "method": "POST", - "path": "/api/timeline", "namespaceFile": "security-timeline-api" }, { "name": "copy-timeline", "namespace": "security-timeline-api", "description": "Copies timeline or timeline template", - "method": "GET", - "path": "/api/timeline/_copy", "namespaceFile": "security-timeline-api" }, { "name": "get-draft-timelines", "namespace": "security-timeline-api", "description": "Get draft Timeline or Timeline template details", - "method": "GET", - "path": "/api/timeline/_draft", "namespaceFile": "security-timeline-api" }, { "name": "clean-draft-timelines", "namespace": "security-timeline-api", "description": "Create a clean draft Timeline or Timeline template", - "method": "POST", - "path": "/api/timeline/_draft", "namespaceFile": "security-timeline-api" }, { "name": "export-timelines", "namespace": "security-timeline-api", "description": "Export Timelines", - "method": "POST", - "path": "/api/timeline/_export", "namespaceFile": "security-timeline-api" }, { "name": "persist-favorite-route", "namespace": "security-timeline-api", "description": "Favorite a Timeline or Timeline template", - "method": "PATCH", - "path": "/api/timeline/_favorite", "namespaceFile": "security-timeline-api" }, { "name": "import-timelines", "namespace": "security-timeline-api", "description": "Import Timelines", - "method": "POST", - "path": "/api/timeline/_import", "namespaceFile": "security-timeline-api" }, { "name": "install-prepacked-timelines", "namespace": "security-timeline-api", "description": "Install prepackaged Timelines", - "method": "POST", - "path": "/api/timeline/_prepackaged", "namespaceFile": "security-timeline-api" }, { "name": "resolve-timeline", "namespace": "security-timeline-api", "description": "Get an existing saved Timeline or Timeline template", - "method": "GET", - "path": "/api/timeline/resolve", "namespaceFile": "security-timeline-api" }, { "name": "get-timelines", "namespace": "security-timeline-api", "description": "Get Timelines or Timeline templates", - "method": "GET", - "path": "/api/timelines", "namespaceFile": "security-timeline-api" }, { "name": "find-slos-op", "namespace": "slo", "description": "Get a paginated list of SLOs", - "method": "GET", - "path": "/s/{spaceId}/api/observability/slos", "namespaceFile": "slo" }, { "name": "create-slo-op", "namespace": "slo", "description": "Create an SLO", - "method": "POST", - "path": "/s/{spaceId}/api/observability/slos", "namespaceFile": "slo" }, { "name": "bulk-delete-op", "namespace": "slo", "description": "Bulk delete SLO definitions and their associated summary and rollup data.", - "method": "POST", - "path": "/s/{spaceId}/api/observability/slos/_bulk_delete", "namespaceFile": "slo" }, { "name": "bulk-delete-status-op", "namespace": "slo", "description": "Retrieve the status of the bulk deletion", - "method": "GET", - "path": "/s/{spaceId}/api/observability/slos/_bulk_delete/{taskId}", "namespaceFile": "slo" }, { "name": "delete-rollup-data-op", "namespace": "slo", "description": "Batch delete rollup and summary data", - "method": "POST", - "path": "/s/{spaceId}/api/observability/slos/_bulk_purge_rollup", "namespaceFile": "slo" }, { "name": "delete-slo-instances-op", "namespace": "slo", "description": "Batch delete rollup and summary data", - "method": "POST", - "path": "/s/{spaceId}/api/observability/slos/_delete_instances", "namespaceFile": "slo" }, { "name": "delete-slo-op", "namespace": "slo", "description": "Delete an SLO", - "method": "DELETE", - "path": "/s/{spaceId}/api/observability/slos/{sloId}", "namespaceFile": "slo" }, { "name": "get-slo-op", "namespace": "slo", "description": "Get an SLO", - "method": "GET", - "path": "/s/{spaceId}/api/observability/slos/{sloId}", "namespaceFile": "slo" }, { "name": "update-slo-op", "namespace": "slo", "description": "Update an SLO", - "method": "PUT", - "path": "/s/{spaceId}/api/observability/slos/{sloId}", "namespaceFile": "slo" }, { "name": "reset-slo-op", "namespace": "slo", "description": "Reset an SLO", - "method": "POST", - "path": "/s/{spaceId}/api/observability/slos/{sloId}/_reset", "namespaceFile": "slo" }, { "name": "disable-slo-op", "namespace": "slo", "description": "Disable an SLO", - "method": "POST", - "path": "/s/{spaceId}/api/observability/slos/{sloId}/disable", "namespaceFile": "slo" }, { "name": "enable-slo-op", "namespace": "slo", "description": "Enable an SLO", - "method": "POST", - "path": "/s/{spaceId}/api/observability/slos/{sloId}/enable", "namespaceFile": "slo" }, { "name": "get-definitions-op", "namespace": "slo", "description": "Get the SLO definitions", - "method": "GET", - "path": "/s/{spaceId}/internal/observability/slos/_definitions", "namespaceFile": "slo" }, { "name": "get-spaces-space", "namespace": "spaces", "description": "Get all spaces", - "method": "GET", - "path": "/api/spaces/space", "namespaceFile": "spaces" }, { "name": "post-spaces-space", "namespace": "spaces", "description": "Create a space", - "method": "POST", - "path": "/api/spaces/space", "namespaceFile": "spaces" }, { "name": "delete-spaces-space-id", "namespace": "spaces", "description": "Delete a space", - "method": "DELETE", - "path": "/api/spaces/space/{id}", "namespaceFile": "spaces" }, { "name": "get-spaces-space-id", "namespace": "spaces", "description": "Get a space", - "method": "GET", - "path": "/api/spaces/space/{id}", "namespaceFile": "spaces" }, { "name": "put-spaces-space-id", "namespace": "spaces", "description": "Update a space", - "method": "PUT", - "path": "/api/spaces/space/{id}", "namespaceFile": "spaces" }, { "name": "get-streams", "namespace": "streams", "description": "Get stream list", - "method": "GET", - "path": "/api/streams", "namespaceFile": "streams" }, { "name": "post-streams-disable", "namespace": "streams", "description": "Disable streams", - "method": "POST", - "path": "/api/streams/_disable", "namespaceFile": "streams" }, { "name": "post-streams-enable", "namespace": "streams", "description": "Enable streams", - "method": "POST", - "path": "/api/streams/_enable", "namespaceFile": "streams" }, { "name": "post-streams-resync", "namespace": "streams", "description": "Resync streams", - "method": "POST", - "path": "/api/streams/_resync", "namespaceFile": "streams" }, { "name": "delete-streams-name", "namespace": "streams", "description": "Delete a stream", - "method": "DELETE", - "path": "/api/streams/{name}", "namespaceFile": "streams" }, { "name": "get-streams-name", "namespace": "streams", "description": "Get a stream", - "method": "GET", - "path": "/api/streams/{name}", "namespaceFile": "streams" }, { "name": "put-streams-name", "namespace": "streams", "description": "Create or update a stream", - "method": "PUT", - "path": "/api/streams/{name}", "namespaceFile": "streams" }, { "name": "post-streams-name-fork", "namespace": "streams", "description": "Fork a stream", - "method": "POST", - "path": "/api/streams/{name}/_fork", "namespaceFile": "streams" }, { "name": "get-streams-name-ingest", "namespace": "streams", "description": "Get ingest stream settings", - "method": "GET", - "path": "/api/streams/{name}/_ingest", "namespaceFile": "streams" }, { "name": "put-streams-name-ingest", "namespace": "streams", "description": "Update ingest stream settings", - "method": "PUT", - "path": "/api/streams/{name}/_ingest", "namespaceFile": "streams" }, { "name": "get-streams-name-query", "namespace": "streams", "description": "Get query stream settings", - "method": "GET", - "path": "/api/streams/{name}/_query", "namespaceFile": "streams" }, { "name": "put-streams-name-query", "namespace": "streams", "description": "Upsert query stream settings", - "method": "PUT", - "path": "/api/streams/{name}/_query", "namespaceFile": "streams" }, { "name": "post-streams-name-content-export", "namespace": "streams", "description": "Export stream content", - "method": "POST", - "path": "/api/streams/{name}/content/export", "namespaceFile": "streams" }, { "name": "post-streams-name-content-import", "namespace": "streams", "description": "Import content into a stream", - "method": "POST", - "path": "/api/streams/{name}/content/import", "namespaceFile": "streams" }, { "name": "get-streams-name-queries", "namespace": "streams", "description": "Get stream queries", - "method": "GET", - "path": "/api/streams/{name}/queries", "namespaceFile": "streams" }, { "name": "post-streams-name-queries-bulk", "namespace": "streams", "description": "Bulk update queries", - "method": "POST", - "path": "/api/streams/{name}/queries/_bulk", "namespaceFile": "streams" }, { "name": "delete-streams-name-queries-queryid", "namespace": "streams", "description": "Remove a query from a stream", - "method": "DELETE", - "path": "/api/streams/{name}/queries/{queryId}", "namespaceFile": "streams" }, { "name": "put-streams-name-queries-queryid", "namespace": "streams", "description": "Upsert a query to a stream", - "method": "PUT", - "path": "/api/streams/{name}/queries/{queryId}", "namespaceFile": "streams" }, { "name": "get-streams-name-significant-events", "namespace": "streams", "description": "Read the significant events", - "method": "GET", - "path": "/api/streams/{name}/significant_events", "namespaceFile": "streams" }, { "name": "post-streams-name-significant-events-generate", "namespace": "streams", "description": "Generate significant events", - "method": "POST", - "path": "/api/streams/{name}/significant_events/_generate", "namespaceFile": "streams" }, { "name": "post-streams-name-significant-events-preview", "namespace": "streams", "description": "Preview significant events", - "method": "POST", - "path": "/api/streams/{name}/significant_events/_preview", "namespaceFile": "streams" }, { "name": "get-streams-streamname-attachments", "namespace": "streams", "description": "Get stream attachments", - "method": "GET", - "path": "/api/streams/{streamName}/attachments", "namespaceFile": "streams" }, { "name": "post-streams-streamname-attachments-bulk", "namespace": "streams", "description": "Bulk update attachments", - "method": "POST", - "path": "/api/streams/{streamName}/attachments/_bulk", "namespaceFile": "streams" }, { "name": "delete-streams-streamname-attachments-attachmenttype-attachmentid", "namespace": "streams", "description": "Unlink an attachment from a stream", - "method": "DELETE", - "path": "/api/streams/{streamName}/attachments/{attachmentType}/{attachmentId}", "namespaceFile": "streams" }, { "name": "put-streams-streamname-attachments-attachmenttype-attachmentid", "namespace": "streams", "description": "Link an attachment to a stream", - "method": "PUT", - "path": "/api/streams/{streamName}/attachments/{attachmentType}/{attachmentId}", "namespaceFile": "streams" }, { "name": "get-status", "namespace": "system", "description": "Get Kibana's current status", - "method": "GET", - "path": "/api/status", "namespaceFile": "system" }, { "name": "task-manager-health", "namespace": "task-manager", "description": "Get the task manager health", - "method": "GET", - "path": "/api/task_manager/_health", "namespaceFile": "task-manager" }, { "name": "delete-workflows", "namespace": "workflows", "description": "Bulk delete workflows", - "method": "DELETE", - "path": "/api/workflows", "namespaceFile": "workflows" }, { "name": "get-workflows", "namespace": "workflows", "description": "Get workflows", - "method": "GET", - "path": "/api/workflows", "namespaceFile": "workflows" }, { "name": "post-workflows", "namespace": "workflows", "description": "Bulk create workflows", - "method": "POST", - "path": "/api/workflows", "namespaceFile": "workflows" }, { "name": "get-workflows-aggs", "namespace": "workflows", "description": "Get workflow aggregations", - "method": "GET", - "path": "/api/workflows/aggs", "namespaceFile": "workflows" }, { "name": "get-workflows-connectors", "namespace": "workflows", "description": "Get available connectors", - "method": "GET", - "path": "/api/workflows/connectors", "namespaceFile": "workflows" }, { "name": "get-workflows-executions-executionid", "namespace": "workflows", "description": "Get a workflow execution", - "method": "GET", - "path": "/api/workflows/executions/{executionId}", "namespaceFile": "workflows" }, { "name": "post-workflows-executions-executionid-cancel", "namespace": "workflows", "description": "Cancel a workflow execution", - "method": "POST", - "path": "/api/workflows/executions/{executionId}/cancel", "namespaceFile": "workflows" }, { "name": "get-workflows-executions-executionid-children", "namespace": "workflows", "description": "Get child executions", - "method": "GET", - "path": "/api/workflows/executions/{executionId}/children", "namespaceFile": "workflows" }, { "name": "get-workflows-executions-executionid-logs", "namespace": "workflows", "description": "Get execution logs", - "method": "GET", - "path": "/api/workflows/executions/{executionId}/logs", "namespaceFile": "workflows" }, { "name": "post-workflows-executions-executionid-resume", "namespace": "workflows", "description": "Resume a workflow execution", - "method": "POST", - "path": "/api/workflows/executions/{executionId}/resume", "namespaceFile": "workflows" }, { "name": "get-workflows-executions-executionid-step-stepexecutionid", "namespace": "workflows", "description": "Get a step execution", - "method": "GET", - "path": "/api/workflows/executions/{executionId}/step/{stepExecutionId}", "namespaceFile": "workflows" }, { "name": "post-workflows-export", "namespace": "workflows", "description": "Export workflows", - "method": "POST", - "path": "/api/workflows/export", "namespaceFile": "workflows" }, { "name": "post-workflows-mget", "namespace": "workflows", "description": "Get workflows by IDs", - "method": "POST", - "path": "/api/workflows/mget", "namespaceFile": "workflows" }, { "name": "get-workflows-schema", "namespace": "workflows", "description": "Get workflow JSON schema", - "method": "GET", - "path": "/api/workflows/schema", "namespaceFile": "workflows" }, { "name": "get-workflows-stats", "namespace": "workflows", "description": "Get workflow statistics", - "method": "GET", - "path": "/api/workflows/stats", "namespaceFile": "workflows" }, { "name": "post-workflows-step-test", "namespace": "workflows", "description": "Test a workflow step", - "method": "POST", - "path": "/api/workflows/step/test", "namespaceFile": "workflows" }, { "name": "post-workflows-test", "namespace": "workflows", "description": "Test a workflow", - "method": "POST", - "path": "/api/workflows/test", "namespaceFile": "workflows" }, { "name": "post-workflows-workflow", "namespace": "workflows", "description": "Create a workflow", - "method": "POST", - "path": "/api/workflows/workflow", "namespaceFile": "workflows" }, { "name": "delete-workflows-workflow-id", "namespace": "workflows", "description": "Delete a workflow", - "method": "DELETE", - "path": "/api/workflows/workflow/{id}", "namespaceFile": "workflows" }, { "name": "get-workflows-workflow-id", "namespace": "workflows", "description": "Get a workflow", - "method": "GET", - "path": "/api/workflows/workflow/{id}", "namespaceFile": "workflows" }, { "name": "put-workflows-workflow-id", "namespace": "workflows", "description": "Update a workflow", - "method": "PUT", - "path": "/api/workflows/workflow/{id}", "namespaceFile": "workflows" }, { "name": "post-workflows-workflow-id-clone", "namespace": "workflows", "description": "Clone a workflow", - "method": "POST", - "path": "/api/workflows/workflow/{id}/clone", "namespaceFile": "workflows" }, { "name": "post-workflows-workflow-id-run", "namespace": "workflows", "description": "Run a workflow", - "method": "POST", - "path": "/api/workflows/workflow/{id}/run", "namespaceFile": "workflows" }, { "name": "get-workflows-workflow-workflowid-executions", "namespace": "workflows", "description": "Get workflow executions", - "method": "GET", - "path": "/api/workflows/workflow/{workflowId}/executions", "namespaceFile": "workflows" }, { "name": "get-workflows-workflow-workflowid-executions-steps", "namespace": "workflows", "description": "Get workflow step executions", - "method": "GET", - "path": "/api/workflows/workflow/{workflowId}/executions/steps", "namespaceFile": "workflows" } -] +] as const diff --git a/src/namespaces.ts b/src/namespaces.ts index 76152395..c51f9e27 100644 --- a/src/namespaces.ts +++ b/src/namespaces.ts @@ -4,8 +4,8 @@ */ import type { Command } from 'commander' -import { defineGroup } from './factory.ts' -import type { OpaqueCommandHandle } from './factory.ts' +import { defineGroup } from './factory-core.ts' +import type { OpaqueCommandHandle } from './factory-core.ts' export interface LoadOptions { /** @@ -18,6 +18,8 @@ export interface LoadOptions { version?: string /** Root Commander program; forwarded to namespaces that introspect global options. */ rootProgram?: Command + /** Sub-namespace hint; skips loading unrelated modules when set. Ignored when `eager` is true. */ + targetSubNamespace?: string | undefined } /** @@ -66,16 +68,23 @@ export const NAMESPACES: NamespaceEntry[] = [ ], load: async (opts) => { const eager = opts?.eager === true + const target = opts?.targetSubNamespace + const needEs = eager || target !== 'kb' + const needKb = eager || target !== 'es' const [esModule, kbModule] = await Promise.all([ - import('./es/register.ts'), - import('./kb/register.ts'), + needEs ? import('./es/register.ts') : null, + needKb ? import('./kb/register.ts') : null, ]) - const esGroup = eager - ? await esModule.registerEsCommandsEager() - : await esModule.registerEsCommandsLazy() + const esGroup = esModule == null + ? defineGroup({ name: 'es', description: 'Elasticsearch APIs' }) + : eager + ? await esModule.registerEsCommandsEager() + : await esModule.registerEsCommandsLazy() esGroup.alias('elasticsearch') let kbGroup: OpaqueCommandHandle - if (eager) { + if (kbModule == null) { + kbGroup = defineGroup({ name: 'kb', description: 'Kibana APIs' }) + } else if (eager) { const { loadAllKbApis } = await import('./kb/apis.ts') kbGroup = kbModule.registerKbCommands(await loadAllKbApis()) } else { @@ -92,9 +101,16 @@ export const NAMESPACES: NamespaceEntry[] = [ { name: 'cloud', description: 'Manage Elastic Cloud (hosted deployments and serverless projects)', - load: async () => { - const { registerCloudCommands } = await import('./cloud/register.ts') - return registerCloudCommands() + load: async (opts) => { + // For eager mode (cli-schema generation) load the full tree. + // For normal startup, use the lightweight lazy path that avoids loading + // all API definition files and Zod schemas. + if (opts?.eager === true) { + const { registerCloudCommands } = await import('./cloud/register.ts') + return registerCloudCommands() + } + const { registerCloudCommandsLazy } = await import('./cloud/register-lazy.ts') + return registerCloudCommandsLazy(opts?.targetSubNamespace) }, }, { diff --git a/test/cli.test.ts b/test/cli.test.ts index c4cd2807..cc1afeef 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -235,6 +235,17 @@ describe('elastic CLI -- config-free commands', () => { await rm(dir, { recursive: true }) } }) + + it('`elastic version` without --json outputs plain text', async () => { + const dir = await mkdtemp(join(tmpdir(), 'elastic-cli-noconfig-')) + try { + const { code, stdout } = await runCli(['version'], { cwd: dir, env: { HOME: dir } }) + assert.equal(code, 0, `expected exit code 0, got ${code}`) + assert.match(stdout.trim(), /^Elastic CLI v\d+\.\d+\.\d+$/) + } finally { + await rm(dir, { recursive: true }) + } + }) }) describe('elastic CLI -- stack command tree', () => { diff --git a/test/cloud/register-lazy.test.ts b/test/cloud/register-lazy.test.ts new file mode 100644 index 00000000..7831d5fa --- /dev/null +++ b/test/cloud/register-lazy.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' +import { registerCloudCommandsLazy } from '../../src/cloud/register-lazy.ts' + +describe('registerCloudCommandsLazy', () => { + it('returns a top-level "cloud" group (no sub-namespace)', async () => { + const group = await registerCloudCommandsLazy() + assert.equal(group.name(), 'cloud') + }) + + it('registers the expected top-level stub groups', async () => { + const group = await registerCloudCommandsLazy() + const names = group.commands.map((c) => c.name()).sort() + assert.ok(names.includes('hosted'), 'should have hosted') + assert.ok(names.includes('serverless'), 'should have serverless') + assert.ok(names.includes('users'), 'should have users') + }) + + it('builds real tree when targetSubNamespace is set', async () => { + const group = await registerCloudCommandsLazy('hosted') + assert.equal(group.name(), 'cloud') + const hosted = group.commands.find(c => c.name() === 'hosted') + assert.ok(hosted != null, 'should have hosted group') + assert.ok(hosted.commands.length > 0, 'hosted should have sub-commands in real tree') + }) +}) \ No newline at end of file diff --git a/test/completion/complete.test.ts b/test/completion/complete.test.ts index 61696700..33efd415 100644 --- a/test/completion/complete.test.ts +++ b/test/completion/complete.test.ts @@ -26,6 +26,24 @@ function parseOutput (output: string): { candidates: string[]; directive: number } } + +async function withConfig (yamlLines: string[], fn: () => Promise) { + const { mkdtemp, writeFile, rm } = await import('node:fs/promises') + const { tmpdir } = await import('node:os') + const { join } = await import('node:path') + const dir = await mkdtemp(join(tmpdir(), 'elastic-cli-test-')) + const path = join(dir, 'config.yml') + await writeFile(path, yamlLines.join('\n')) + const originalEnv = process.env['ELASTIC_CLI_CONFIG_FILE'] + process.env['ELASTIC_CLI_CONFIG_FILE'] = path + try { + await fn() + } finally { + if (originalEnv != null) process.env['ELASTIC_CLI_CONFIG_FILE'] = originalEnv + else delete process.env['ELASTIC_CLI_CONFIG_FILE'] + await rm(dir, { recursive: true }) + } +} describe('buildCompletionTree -- top-level commands', () => { it('registers version + every visible top-level group as stubs by default', async () => { const root = await buildCompletionTree([]) @@ -101,20 +119,9 @@ describe('buildCompletionTree -- lazy loading', () => { }) describe('handleComplete -- policy enforcement', () => { - const ORIGINAL_ENV = process.env['ELASTIC_CLI_CONFIG_FILE'] - beforeEach(() => { delete process.env['ELASTIC_CLI_CONFIG_FILE'] }) - afterEach(() => { - if (ORIGINAL_ENV != null) process.env['ELASTIC_CLI_CONFIG_FILE'] = ORIGINAL_ENV - else delete process.env['ELASTIC_CLI_CONFIG_FILE'] - }) it('hides top-level groups blocked by commands.blocked', async () => { - const { mkdtemp, writeFile, rm } = await import('node:fs/promises') - const { tmpdir } = await import('node:os') - const { join } = await import('node:path') - const dir = await mkdtemp(join(tmpdir(), 'elastic-cli-policy-')) - const path = join(dir, 'config.yml') - await writeFile(path, [ + await withConfig([ 'current_context: local', 'commands:', ' blocked:', @@ -125,10 +132,7 @@ describe('handleComplete -- policy enforcement', () => { ' elasticsearch:', ' url: http://localhost:9200', '', - ].join('\n')) - process.env['ELASTIC_CLI_CONFIG_FILE'] = path - - try { + ], async () => { const buf = bufferedWriter() await handleComplete([''], buf.write) @@ -139,18 +143,11 @@ describe('handleComplete -- policy enforcement', () => { // Groups not blocked should still appear. assert.ok(out.candidates.includes('stack')) assert.ok(out.candidates.includes('version')) - } finally { - await rm(dir, { recursive: true }) - } + }) }) it('applies blocked commands without resolving active-context expressions', async () => { - const { mkdtemp, writeFile, rm } = await import('node:fs/promises') - const { tmpdir } = await import('node:os') - const { join } = await import('node:path') - const dir = await mkdtemp(join(tmpdir(), 'elastic-cli-policy-')) - const path = join(dir, 'config.yml') - await writeFile(path, [ + await withConfig([ 'current_context: local', 'commands:', ' blocked:', @@ -160,11 +157,9 @@ describe('handleComplete -- policy enforcement', () => { ' elasticsearch:', ' url: $(env:ELASTIC_COMPLETION_MISSING_URL)', '', - ].join('\n')) - process.env['ELASTIC_CLI_CONFIG_FILE'] = path - delete process.env['ELASTIC_COMPLETION_MISSING_URL'] + ], async () => { + delete process.env['ELASTIC_COMPLETION_MISSING_URL'] - try { const buf = bufferedWriter() await handleComplete([''], buf.write) @@ -172,9 +167,7 @@ describe('handleComplete -- policy enforcement', () => { assert.ok(!out.candidates.includes('sanitize'), `sanitize should be hidden by policy even with unresolved expressions; got: ${out.candidates.join(',')}`) assert.ok(out.candidates.includes('stack')) - } finally { - await rm(dir, { recursive: true }) - } + }) }) }) @@ -222,20 +215,9 @@ describe('handleComplete -- stdout protocol', () => { }) describe('handleComplete -- dynamic context name completion', () => { - const ORIGINAL_ENV = process.env['ELASTIC_CLI_CONFIG_FILE'] - beforeEach(() => { delete process.env['ELASTIC_CLI_CONFIG_FILE'] }) - afterEach(() => { - if (ORIGINAL_ENV != null) process.env['ELASTIC_CLI_CONFIG_FILE'] = ORIGINAL_ENV - else delete process.env['ELASTIC_CLI_CONFIG_FILE'] - }) it('emits context names from the configured file', async () => { - const { mkdtemp, writeFile, rm } = await import('node:fs/promises') - const { tmpdir } = await import('node:os') - const { join } = await import('node:path') - const dir = await mkdtemp(join(tmpdir(), 'elastic-cli-cnames-')) - const path = join(dir, 'config.yml') - await writeFile(path, [ + await withConfig([ 'current_context: local', 'contexts:', ' local:', @@ -245,15 +227,13 @@ describe('handleComplete -- dynamic context name completion', () => { ' elasticsearch:', ' url: http://localhost:9200', '', - ].join('\n')) - process.env['ELASTIC_CLI_CONFIG_FILE'] = path - - const buf = bufferedWriter() - await handleComplete(['--use-context', ''], buf.write) - await rm(dir, { recursive: true }) + ], async () => { + const buf = bufferedWriter() + await handleComplete(['--use-context', ''], buf.write) - const out = parseOutput(buf.chunks.join('')) - assert.deepEqual(out.candidates.sort(), ['local', 'staging']) + const out = parseOutput(buf.chunks.join('')) + assert.deepEqual(out.candidates.sort(), ['local', 'staging']) + }) }) }) @@ -308,3 +288,116 @@ describe('buildCompleteCommand', () => { assert.match(captured.join(''), /:\d+/) }) }) + +describe('buildCompletionTree -- kb lazy loading', () => { + // kb lazy loading exercises the KB_ALIASES branch without importing kb modules that + // would bring uncovered kb/*.ts functions into the coverage scope. + it('shows kb as a stub when secondWord does not match kb aliases', async () => { + const root = await buildCompletionTree(['stack', 'something-else']) + const stack = root.commands.find((c) => c.name() === 'stack')! + const kb = stack.commands.find((c) => c.name() === 'kb')! + assert.ok(kb != null, 'kb should still be present as a stub') + }) +}) + +describe('handleComplete -- loadCompletionCommandPolicy edge cases', () => { + + it('returns all top-level groups when current_context is missing from contexts', async () => { + await withConfig([ + 'current_context: nonexistent', + 'contexts:', + ' local:', + ' elasticsearch:', + ' url: http://localhost:9200', + '', + ], async () => { + const buf = bufferedWriter() + await handleComplete([''], buf.write) + const out = parseOutput(buf.chunks.join('')) + // policy returns undefined → all commands visible + assert.ok(out.candidates.includes('stack')) + }) + }) + + it('returns all top-level groups when default_profile is invalid', async () => { + await withConfig([ + 'current_context: local', + 'default_profile: 123', + 'contexts:', + ' local:', + ' elasticsearch:', + ' url: http://localhost:9200', + '', + ], async () => { + const buf = bufferedWriter() + await handleComplete([''], buf.write) + const out = parseOutput(buf.chunks.join('')) + assert.ok(out.candidates.includes('stack')) + }) + }) + + it('returns all top-level groups when root commands block field is invalid', async () => { + await withConfig([ + 'current_context: local', + 'commands:', + ' blocked: not-an-array', + 'contexts:', + ' local:', + ' elasticsearch:', + ' url: http://localhost:9200', + '', + ], async () => { + const buf = bufferedWriter() + await handleComplete([''], buf.write) + const out = parseOutput(buf.chunks.join('')) + assert.ok(out.candidates.includes('stack')) + }) + }) + + it('returns all top-level groups when context commands block field is invalid', async () => { + await withConfig([ + 'current_context: local', + 'contexts:', + ' local:', + ' commands:', + ' blocked: not-an-array', + ' elasticsearch:', + ' url: http://localhost:9200', + '', + ], async () => { + const buf = bufferedWriter() + await handleComplete([''], buf.write) + const out = parseOutput(buf.chunks.join('')) + assert.ok(out.candidates.includes('stack')) + }) + }) +}) + +describe('buildCompletionTree -- docs and config subtrees', () => { + it('registers docs as a stub by default', async () => { + const root = await buildCompletionTree(['stack']) + const docs = root.commands.find((c) => c.name() === 'docs') + assert.ok(docs != null, 'docs group should be present') + }) + + it('registers config as a stub by default', async () => { + const root = await buildCompletionTree(['stack']) + const config = root.commands.find((c) => c.name() === 'config') + assert.ok(config != null, 'config group should be present') + }) + + it('deep-loads docs when first word is "docs"', async () => { + const root = await buildCompletionTree(['docs']) + const docs = root.commands.find((c) => c.name() === 'docs') + assert.ok(docs != null, 'docs should be present') + // deep-loaded docs should have child commands + assert.ok(docs.commands.length > 0, 'docs should have children when deep-loaded') + }) + + it('deep-loads config when first word is "config"', async () => { + const root = await buildCompletionTree(['config']) + const config = root.commands.find((c) => c.name() === 'config') + assert.ok(config != null, 'config should be present') + assert.ok(config.commands.length > 0, 'config should have children when deep-loaded') + }) +}) diff --git a/test/completion/context-names.test.ts b/test/completion/context-names.test.ts index 596112e8..6e473fb9 100644 --- a/test/completion/context-names.test.ts +++ b/test/completion/context-names.test.ts @@ -8,6 +8,7 @@ import assert from 'node:assert/strict' import { mkdtemp, writeFile, rm, chmod } from 'node:fs/promises' import { join } from 'node:path' import { tmpdir } from 'node:os' +import process from 'node:process' import { completeContextNames } from '../../src/completion/completers/context-names.ts' const VALID_YAML = ` @@ -134,4 +135,13 @@ describe('completeContextNames', () => { const names = await completeContextNames() assert.deepEqual(names.sort(), ['local', 'remote']) }) + + it('treats an empty ELASTIC_CLI_CONFIG_FILE env var as unset (discovery fallback)', async () => { + process.env['ELASTIC_CLI_CONFIG_FILE'] = '' + await (await import('node:os')).default.tmpdir() + // With empty env var, should fall back to discovery; in tmp dir, no config = [] + // Just verify it doesn't throw + const names = await completeContextNames() + assert.ok(Array.isArray(names)) + }) }) diff --git a/test/es/helpers/msearch.test.ts b/test/es/helpers/msearch.test.ts index d9a234a3..d7e28be9 100644 --- a/test/es/helpers/msearch.test.ts +++ b/test/es/helpers/msearch.test.ts @@ -59,6 +59,8 @@ async function runCommand (args: string[], deps: MsearchDeps): Promise const restoreStdin = _testSetStdinReader(() => '') try { await program.parseAsync(['node', 'test', 'msearch', ...args]) + } catch { + // Commander exitOverride throws on errors; output is already captured in stderr } finally { restoreStdin() process.stdout.write = origStdoutWrite @@ -66,13 +68,21 @@ async function runCommand (args: string[], deps: MsearchDeps): Promise process.exitCode = 0 } - // Prefer stderr (error results) over stdout; parse whichever has content + // The test runner may inject internal protocol bytes into stdout. + // Try each chunk individually (last-to-first) to find valid JSON. const errOutput = stderrChunks.join('') - const stdOutput = stdoutChunks.join('') - const output = errOutput.trim().length > 0 ? errOutput : stdOutput - if (output.trim().length > 0) { - try { return JSON.parse(output.trim()) } catch { return output.trim() } + if (errOutput.trim().length > 0) { + try { return JSON.parse(errOutput.trim()) } catch { return errOutput.trim() } + } + // Search stdout chunks in reverse for a parseable JSON chunk + for (let i = stdoutChunks.length - 1; i >= 0; i--) { + const chunk = stdoutChunks[i]!.trim() + if (chunk.length > 0 && (chunk[0] === '{' || chunk[0] === '[')) { + try { return JSON.parse(chunk) } catch { /* continue */ } + } } + const stdOutput = stdoutChunks.join('') + if (stdOutput.trim().length > 0) return stdOutput.trim() return undefined } @@ -105,7 +115,9 @@ describe('msearch command', () => { ) as Record assert.equal(requests.length, 1) - const responses = result.responses as unknown[] + assert.ok(result != null && typeof result === 'object', `Expected object result, got: ${JSON.stringify(result)}`) + assert.ok('responses' in (result as Record), `Expected responses key in result, got: ${JSON.stringify(result)}`) + const responses = (result as Record).responses as unknown[] assert.equal(responses.length, 2) }) @@ -129,7 +141,9 @@ describe('msearch command', () => { ) as Record assert.equal(requests.length, 3, 'Expected 3 batches of 2') - assert.equal((result.responses as unknown[]).length, 6) + assert.ok(result != null && typeof result === 'object', `Expected object result, got: ${JSON.stringify(result)}`) + assert.ok('responses' in (result as Record), `Expected responses key in result, got: ${JSON.stringify(result)}`) + assert.equal(((result as Record).responses as unknown[]).length, 6) }) it('applies default index from --index to items without header.index', async () => { diff --git a/test/es/register.test.ts b/test/es/register.test.ts index 58137844..6f139f97 100644 --- a/test/es/register.test.ts +++ b/test/es/register.test.ts @@ -7,7 +7,7 @@ import { describe, it } from 'node:test' import assert from 'node:assert/strict' import { z } from 'zod' import type { EsApiDefinition } from '../../src/es/types.ts' -import { registerEsCommands } from '../../src/es/register.ts' +import { registerEsCommands, registerEsCommandsLazy } from '../../src/es/register.ts' function makeDef(name: string, namespace: string, description = `${name} description`): EsApiDefinition { return { name, namespace, description, method: 'GET', path: `/_${namespace}/${name}` } @@ -26,19 +26,19 @@ const testDefs: EsApiDefinition[] = [ ] describe('registerEsCommands', () => { - it('returns an OpaqueCommandHandle named "es"', () => { - const handle = registerEsCommands(testDefs) + it('returns an OpaqueCommandHandle named "es"', async () => { + const handle = await registerEsCommands(testDefs) assert.equal(handle.name(), 'es') }) - it('creates one child group per unique namespace', () => { - const handle = registerEsCommands(testDefs) + it('creates one child group per unique namespace', async () => { + const handle = await registerEsCommands(testDefs) const groupNames = handle.commands.map((c) => c.name()).sort() assert.deepEqual(groupNames, ['cat', 'helpers', 'indices']) }) - it('each namespace group has leaf commands matching definition names', () => { - const handle = registerEsCommands(testDefs) + it('each namespace group has leaf commands matching definition names', async () => { + const handle = await registerEsCommands(testDefs) const cat = handle.commands.find((c) => c.name() === 'cat') assert.ok(cat != null) const catCommandNames = cat.commands.map((c) => c.name()).sort() @@ -50,8 +50,8 @@ describe('registerEsCommands', () => { assert.deepEqual(idxCommandNames, ['create', 'delete']) }) - it('leaf command descriptions match definitions', () => { - const handle = registerEsCommands(testDefs) + it('leaf command descriptions match definitions', async () => { + const handle = await registerEsCommands(testDefs) const cat = handle.commands.find((c) => c.name() === 'cat') assert.ok(cat != null) const health = cat.commands.find((c) => c.name() === 'health') @@ -59,9 +59,9 @@ describe('registerEsCommands', () => { assert.equal(health.description(), 'health description') }) - it('works with a single namespace', () => { + it('works with a single namespace', async () => { const defs: EsApiDefinition[] = [makeDef('health', 'cat'), makeDef('nodes', 'cat')] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) // 1 namespace group + 1 helpers group assert.equal(handle.commands.length, 2) const cat = handle.commands.find((c) => c.name() === 'cat') @@ -69,17 +69,17 @@ describe('registerEsCommands', () => { assert.equal(cat.commands.length, 2) }) - it('throws on duplicate command names within a namespace', () => { + it('throws on duplicate command names within a namespace', async () => { const defs: EsApiDefinition[] = [makeDef('health', 'cat'), makeDef('health', 'cat')] - assert.throws(() => registerEsCommands(defs), /duplicate.*health|health.*duplicate/i) + await assert.rejects(registerEsCommands(defs), /duplicate.*health|health.*duplicate/i) }) - it('allows the same command name in different namespaces', () => { + it('allows the same command name in different namespaces', async () => { const defs: EsApiDefinition[] = [makeDef('get', 'cat'), makeDef('get', 'indices')] - assert.doesNotThrow(() => registerEsCommands(defs)) + await assert.doesNotReject(registerEsCommands(defs)) }) - it('registers query params as --flags on leaf commands (via input schema)', () => { + it('registers query params as --flags on leaf commands (via input schema)', async () => { const defs: EsApiDefinition[] = [{ name: 'health', namespace: 'cat', @@ -91,7 +91,7 @@ describe('registerEsCommands', () => { pretty: z.boolean().optional().describe('Pretty').meta({ found_in: 'query' }), }), }] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cmd = handle.commands[0]?.commands[0] assert.ok(cmd != null) const optionNames = cmd.options.map((o) => o.long) @@ -99,7 +99,7 @@ describe('registerEsCommands', () => { assert.ok(optionNames.includes('--pretty'), `expected --pretty, got: ${optionNames.join(', ')}`) }) - it('registers path params as --flags on leaf commands (via input schema)', () => { + it('registers path params as --flags on leaf commands (via input schema)', async () => { const defs: EsApiDefinition[] = [{ name: 'create', namespace: 'indices', @@ -110,14 +110,14 @@ describe('registerEsCommands', () => { index: z.string().describe('Index name').meta({ found_in: 'path' }), }), }] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cmd = handle.commands[0]?.commands[0] assert.ok(cmd != null) const optionNames = cmd.options.map((o) => o.long) assert.ok(optionNames.includes('--index'), `expected --index flag, got: ${optionNames.join(', ')}`) }) - it('registers a --input-file flag when the definition has an input schema', () => { + it('registers a --input-file flag when the definition has an input schema', async () => { const defs: EsApiDefinition[] = [{ name: 'create', namespace: 'indices', @@ -129,7 +129,7 @@ describe('registerEsCommands', () => { settings: z.record(z.string(), z.unknown()).optional().meta({ found_in: 'body' }), }), }] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cmd = handle.commands[0]?.commands[0] assert.ok(cmd != null) // the factory registers --input-file whenever an input schema is provided @@ -139,28 +139,28 @@ describe('registerEsCommands', () => { }) describe('registerEsCommands - namespace-less (root) definitions', () => { - it('a definition without namespace registers as a direct leaf of `es`', () => { + it('a definition without namespace registers as a direct leaf of `es`', async () => { const defs: EsApiDefinition[] = [makeRootDef('search')] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const child = handle.commands.find((c) => c.name() === 'search') assert.ok(child != null, 'expected `search` as direct child of `es`') assert.equal(child.commands.length, 0, 'search should be a leaf, not a group') }) - it('namespace-less definitions do not create an intermediate group', () => { + it('namespace-less definitions do not create an intermediate group', async () => { const defs: EsApiDefinition[] = [makeRootDef('bulk'), makeRootDef('search')] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const names = handle.commands.map((c) => c.name()).sort() assert.deepEqual(names, ['bulk', 'helpers', 'search']) }) - it('namespace-less and namespaced definitions coexist under `es`', () => { + it('namespace-less and namespaced definitions coexist under `es`', async () => { const defs: EsApiDefinition[] = [ makeRootDef('search'), makeDef('health', 'cat'), makeDef('indices', 'cat'), ] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) // `cat` group and `search` leaf are both direct children of `es` const topNames = handle.commands.map((c) => c.name()).sort() assert.deepEqual(topNames, ['cat', 'helpers', 'search']) @@ -169,49 +169,49 @@ describe('registerEsCommands - namespace-less (root) definitions', () => { assert.deepEqual(cat.commands.map((c) => c.name()).sort(), ['health', 'indices']) }) - it('description from the definition is used on the leaf command', () => { + it('description from the definition is used on the leaf command', async () => { const defs: EsApiDefinition[] = [makeRootDef('search', 'Run a search')] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cmd = handle.commands.find((c) => c.name() === 'search') assert.ok(cmd != null) assert.equal(cmd.description(), 'Run a search') }) - it('throws on duplicate names among namespace-less definitions', () => { + it('throws on duplicate names among namespace-less definitions', async () => { const defs: EsApiDefinition[] = [makeRootDef('search'), makeRootDef('search')] - assert.throws(() => registerEsCommands(defs), /duplicate.*search|search.*duplicate/i) + await assert.rejects(registerEsCommands(defs), /duplicate.*search|search.*duplicate/i) }) - it('throws when a namespace-less name collides with a namespace group name', () => { + it('throws when a namespace-less name collides with a namespace group name', async () => { const defs: EsApiDefinition[] = [ makeRootDef('cat'), makeDef('health', 'cat'), ] - assert.throws(() => registerEsCommands(defs), /duplicate.*cat|cat.*duplicate/i) + await assert.rejects(registerEsCommands(defs), /duplicate.*cat|cat.*duplicate/i) }) }) describe('registerEsCommands - extensibility', () => { - it('a definition added to an existing namespace appears in the command tree with no other changes', () => { + it('a definition added to an existing namespace appears in the command tree with no other changes', async () => { const defs: EsApiDefinition[] = [ makeDef('health', 'cat'), makeDef('nodes', 'cat'), makeDef('count', 'cat'), ] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cat = handle.commands.find((c) => c.name() === 'cat') assert.ok(cat != null) const names = cat.commands.map((c) => c.name()).sort() assert.deepEqual(names, ['count', 'health', 'nodes']) }) - it('a new namespace array spread into allApis causes a new group to appear', () => { + it('a new namespace array spread into allApis causes a new group to appear', async () => { const defs: EsApiDefinition[] = [ makeDef('health', 'cat'), makeDef('stats', 'cluster'), makeDef('settings', 'cluster'), ] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const groupNames = handle.commands.map((c) => c.name()).sort() assert.deepEqual(groupNames, ['cat', 'cluster', 'helpers']) const cluster = handle.commands.find((c) => c.name() === 'cluster') @@ -219,28 +219,28 @@ describe('registerEsCommands - extensibility', () => { assert.equal(cluster.commands.length, 2) }) - it('rejects a malformed definition (bad name) at registration time', () => { + it('rejects a malformed definition (bad name) at registration time', async () => { const defs: EsApiDefinition[] = [{ ...makeDef('health', 'cat'), name: 'Bad_Name' }] - assert.throws(() => registerEsCommands(defs), /invalid.*name/i) + await assert.rejects(registerEsCommands(defs), /invalid.*name/i) }) - it('rejects a malformed definition (path missing leading slash) at registration time', () => { + it('rejects a malformed definition (path missing leading slash) at registration time', async () => { const defs: EsApiDefinition[] = [{ ...makeDef('health', 'cat'), path: '_cat/health' }] - assert.throws(() => registerEsCommands(defs), /path.*must start/i) + await assert.rejects(registerEsCommands(defs), /path.*must start/i) }) - it('rejects a malformed definition (path token with no found_in: "path" field) at registration time', () => { + it('rejects a malformed definition (path token with no found_in: "path" field) at registration time', async () => { const defs: EsApiDefinition[] = [{ ...makeDef('get', 'indices'), path: '/{index}', input: z.looseObject({}), // {index} token in path but no found_in: "path" field }] - assert.throws(() => registerEsCommands(defs), /path.*param.*index/i) + await assert.rejects(registerEsCommands(defs), /path.*param.*index/i) }) }) describe('registerEsCommands - body field flattening', () => { - it('registers body fields as individual --flags, not a --body flag', () => { + it('registers body fields as individual --flags, not a --body flag', async () => { const defs: EsApiDefinition[] = [{ name: 'create', namespace: 'indices', @@ -253,7 +253,7 @@ describe('registerEsCommands - body field flattening', () => { mappings: z.record(z.string(), z.unknown()).optional().describe('Index mappings').meta({ found_in: 'body' }), }), }] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cmd = handle.commands[0]?.commands[0] assert.ok(cmd != null) const optionNames = cmd.options.map((o) => o.long) @@ -264,7 +264,7 @@ describe('registerEsCommands - body field flattening', () => { }) describe('registerEsCommands - unified input schema', () => { - it('registers a command with a unified input schema: flags, help text, and validation all work', () => { + it('registers a command with a unified input schema: flags, help text, and validation all work', async () => { const input = z.looseObject({ index: z.string().describe('Target index').meta({ found_in: 'path' }), pretty: z.boolean().optional().describe('Pretty-print response').meta({ found_in: 'query' }), @@ -278,7 +278,7 @@ describe('registerEsCommands - unified input schema', () => { path: '/{index}', input, }] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cmd = handle.commands[0]?.commands[0] assert.ok(cmd != null) const optionNames = cmd.options.map((o) => o.long) @@ -297,7 +297,7 @@ describe('registerEsCommands - external schema consumption', () => { mappings: z.record(z.string(), z.unknown()).optional().describe('Index mappings').meta({ found_in: 'body' }), }) - it('registers a command using an externally defined input schema', () => { + it('registers a command using an externally defined input schema', async () => { const defs: EsApiDefinition[] = [{ name: 'create', namespace: 'indices', @@ -306,7 +306,7 @@ describe('registerEsCommands - external schema consumption', () => { path: '/{index}', input: externalCreateSchema, }] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cmd = handle.commands[0]?.commands[0] assert.ok(cmd != null) const optionNames = cmd.options.map((o) => o.long) @@ -316,7 +316,7 @@ describe('registerEsCommands - external schema consumption', () => { assert.ok(optionNames.includes('--mappings'), `expected --mappings, got: ${optionNames.join(', ')}`) }) - it('validates an externally sourced schema paired with a local manifest without throwing', () => { + it('validates an externally sourced schema paired with a local manifest without throwing', async () => { const defs: EsApiDefinition[] = [{ name: 'create', namespace: 'indices', @@ -325,10 +325,10 @@ describe('registerEsCommands - external schema consumption', () => { path: '/{index}', input: externalCreateSchema, }] - assert.doesNotThrow(() => registerEsCommands(defs)) + await assert.doesNotReject(registerEsCommands(defs)) }) - it('--input-file flag is registered (external schema enables file/stdin merging)', () => { + it('--input-file flag is registered (external schema enables file/stdin merging)', async () => { const defs: EsApiDefinition[] = [{ name: 'create', namespace: 'indices', @@ -337,7 +337,7 @@ describe('registerEsCommands - external schema consumption', () => { path: '/{index}', input: externalCreateSchema, }] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cmd = handle.commands[0]?.commands[0] assert.ok(cmd != null) const optionNames = cmd.options.map((o) => o.long) @@ -346,9 +346,9 @@ describe('registerEsCommands - external schema consumption', () => { }) describe('registerEsCommands - help groups', () => { - it('namespace commands belong to the "API namespaces" group', () => { + it('namespace commands belong to the "API namespaces" group', async () => { const defs: EsApiDefinition[] = [makeDef('health', 'cat'), makeDef('create', 'indices')] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cat = handle.commands.find((c) => c.name() === 'cat') assert.ok(cat != null) assert.equal(cat.helpGroup(), 'API namespaces') @@ -357,14 +357,14 @@ describe('registerEsCommands - help groups', () => { assert.equal(idx.helpGroup(), 'API namespaces') }) - it('helpers group belongs to the "Helpers" group', () => { - const handle = registerEsCommands([]) + it('helpers group belongs to the "Helpers" group', async () => { + const handle = await registerEsCommands([]) const helpers = handle.commands.find((c) => c.name() === 'helpers') assert.ok(helpers != null) assert.equal(helpers.helpGroup(), 'Helpers') }) - it('known root-level commands are assigned to their domain group', () => { + it('known root-level commands are assigned to their domain group', async () => { const defs: EsApiDefinition[] = [ makeRootDef('search'), makeRootDef('get'), @@ -373,7 +373,7 @@ describe('registerEsCommands - help groups', () => { makeRootDef('ping'), makeRootDef('reindex-rethrottle'), ] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const groupOf = (name: string) => handle.commands.find((c) => c.name() === name)?.helpGroup() assert.equal(groupOf('search'), 'Search') assert.equal(groupOf('get'), 'Documents') @@ -383,21 +383,21 @@ describe('registerEsCommands - help groups', () => { assert.equal(groupOf('reindex-rethrottle'), 'Advanced') }) - it('unknown root-level commands fall back to "Other commands"', () => { + it('unknown root-level commands fall back to "Other commands"', async () => { const defs: EsApiDefinition[] = [makeRootDef('some-new-command')] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const cmd = handle.commands.find((c) => c.name() === 'some-new-command') assert.ok(cmd != null) assert.equal(cmd.helpGroup(), 'Other commands') }) - it('root-level commands appear in section order: Documents before Search before Analysis', () => { + it('root-level commands appear in section order: Documents before Search before Analysis', async () => { const defs: EsApiDefinition[] = [ makeRootDef('search'), makeRootDef('count'), makeRootDef('get'), ] - const handle = registerEsCommands(defs) + const handle = await registerEsCommands(defs) const rootCmds = handle.commands.filter((c) => c.name() !== 'helpers') const names = rootCmds.map((c) => c.name()) assert.ok(names.indexOf('get') < names.indexOf('search'), 'Documents (get) should precede Search (search)') @@ -428,7 +428,7 @@ describe('registerEsCommands - built-in API surface', () => { assert.strictEqual(result.status, 0, `Schema validation failed:\n${result.stderr}`) }) - it('throws at registration time when a schema contains z.date()', () => { + it('throws at registration time when a schema contains z.date()', async () => { const defs: EsApiDefinition[] = [{ name: 'search', description: 'Search', @@ -438,9 +438,74 @@ describe('registerEsCommands - built-in API surface', () => { timestamp: z.date().optional().describe('A JS Date - not valid in a REST API schema').meta({ found_in: 'query' }), }), }] - assert.throws( - () => registerEsCommands(defs), - /Date cannot be represented in JSON Schema/, - ) + await assert.rejects(registerEsCommands(defs), /Date cannot be represented in JSON Schema/) + }) +}) + +describe('registerEsCommandsLazy', () => { + it('returns an OpaqueCommandHandle named "es" with no argv sniff match', async () => { + // Pass arbitrary argv that does not target any specific leaf → all stubs + const handle = await registerEsCommandsLazy({ argv: ['node', 'elastic', 'es'] }) + assert.equal(handle.name(), 'es') + assert.ok(handle.commands.length > 0, 'should have at least one child (namespace or root stub)') + }) + + it('contains helpers group as a stub when helpers is not invoked', async () => { + const handle = await registerEsCommandsLazy({ argv: ['node', 'elastic', 'es'] }) + const helpers = handle.commands.find((c) => c.name() === 'helpers') + assert.ok(helpers != null, 'should have a helpers command') + }) + + it('loads helpers group fully when es helpers is invoked', async () => { + const handle = await registerEsCommandsLazy({ argv: ['node', 'elastic', 'es', 'helpers'] }) + const helpers = handle.commands.find((c) => c.name() === 'helpers') + assert.ok(helpers != null, 'should have a helpers command') + // When helpers is invoked, the group should be fully populated (> 0 subcommands) + assert.ok(helpers.commands.length > 0, 'helpers should have sub-commands when invoked') + }) + + it('sniffs a namespaced leaf and expands that namespace fully', async () => { + // cat health is a real leaf in the manifest + const handle = await registerEsCommandsLazy({ argv: ['node', 'elastic', 'es', 'cat', 'health'] }) + const cat = handle.commands.find((c) => c.name() === 'cat') + assert.ok(cat != null, 'cat namespace should be present') + // The invoked namespace (cat) should have its leaves fully populated + assert.ok(cat.commands.length > 0, 'cat namespace should have leaf commands when sniffed') + }) + + it('sniffs a root-level leaf command', async () => { + // 'search' is a root-level command (no namespace) + const handle = await registerEsCommandsLazy({ argv: ['node', 'elastic', 'es', 'search'] }) + const search = handle.commands.find((c) => c.name() === 'search') + assert.ok(search != null, 'root-level search command should be present') + }) +}) + +describe('registerEsCommands - responseType and intent', () => { + it('registers formatOutput for text responseType', async () => { + const defs: EsApiDefinition[] = [{ + name: 'explain', + description: 'Explain something', + method: 'GET', + path: '/_explain', + responseType: 'text', + }] + // Should register without error and produce a handle + const handle = await registerEsCommands(defs) + const cmd = handle.commands.find((c) => c.name() === 'explain') + assert.ok(cmd != null, 'command should be registered') + }) + + it('propagates explicit intent override on a definition', async () => { + const defs: EsApiDefinition[] = [{ + name: 'reindex', + description: 'Reindex data', + method: 'POST', + path: '/_reindex', + intent: { verb: 'write', object: 'index' }, + }] + const handle = await registerEsCommands(defs) + const cmd = handle.commands.find((c) => c.name() === 'reindex') + assert.ok(cmd != null, 'command should be registered with intent') }) }) diff --git a/test/factory.test.ts b/test/factory.test.ts index 23d7b0d5..e7100144 100644 --- a/test/factory.test.ts +++ b/test/factory.test.ts @@ -2791,7 +2791,7 @@ describe('no Commander API leaks', () => { it('factory module exports only public API and test seam at runtime', async () => { const factory = await import('../src/factory.ts') const exported = Object.keys(factory) - assert.deepEqual(exported.sort(), ['RawJsonValue', '_testSetStdinReader', 'configureJsonHelp', 'defineCommand', 'defineGroup', 'hideBlockedCommands', 'isCommandAllowed', 'stripTransportMeta']) + assert.deepEqual(exported.sort(), ['RawJsonValue', '_testSetStdinReader', 'commandPath', 'configureErrorOutput', 'configureJsonHelp', 'defineCommand', 'defineGroup', 'hideBlockedCommands', 'isCommandAllowed', 'isHidden', 'setHidden', 'stripTransportMeta', 'validateName']) }) it('defineCommand return value requires no Commander import to use', () => { diff --git a/tsconfig.json b/tsconfig.json index 4fde09fc..07731f09 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,13 +21,18 @@ "isolatedModules": true, "noUncheckedSideEffectImports": true, "moduleDetection": "force", - "skipLibCheck": true + "skipLibCheck": true, + "removeComments": true }, "include": [ "src/**/*" ], "references": [ - { "path": "./packages/config-resolver" }, - { "path": "./packages/es-schemas" } + { + "path": "./packages/config-resolver" + }, + { + "path": "./packages/es-schemas" + } ] }