diff --git a/.github/scripts/.gitignore b/.github/scripts/.gitignore new file mode 100644 index 0000000..a14702c --- /dev/null +++ b/.github/scripts/.gitignore @@ -0,0 +1,34 @@ +# dependencies (bun install) +node_modules + +# output +out +dist +*.tgz + +# code coverage +coverage +*.lcov + +# logs +logs +_.log +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# caches +.eslintcache +.cache +*.tsbuildinfo + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/.github/scripts/bun.lock b/.github/scripts/bun.lock new file mode 100644 index 0000000..cc1bb9d --- /dev/null +++ b/.github/scripts/bun.lock @@ -0,0 +1,39 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "scripts", + "dependencies": { + "@types/js-yaml": "^4.0.9", + "js-yaml": "^4.1.0", + }, + "devDependencies": { + "@types/bun": "latest", + }, + "peerDependencies": { + "typescript": "^5", + }, + }, + }, + "packages": { + "@types/bun": ["@types/bun@1.2.20", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="], + + "@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="], + + "@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="], + + "@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], + + "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], + + "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], + } +} diff --git a/.github/scripts/code_samples.config.json b/.github/scripts/code_samples.config.json new file mode 100644 index 0000000..f168e7f --- /dev/null +++ b/.github/scripts/code_samples.config.json @@ -0,0 +1,11 @@ +{ + "variants": { + "post /invocations": [ + { "name": "async", "overrides": { "async": true } } + ], + "post /browsers": [ + { "name": "timeout", "overrides": { "timeout_seconds": 300 } }, + { "name": "live-view", "overrides": { "log": "browser.browser_live_view_url" } } + ] + } +} diff --git a/.github/scripts/generate_code_samples.ts b/.github/scripts/generate_code_samples.ts new file mode 100644 index 0000000..2e6188d --- /dev/null +++ b/.github/scripts/generate_code_samples.ts @@ -0,0 +1,515 @@ +#!/usr/bin/env bun + +import { readdir, readFile, writeFile, mkdir, unlink } from "fs/promises"; +import path from "path"; +import yaml from "js-yaml"; // for YAML support + +const OPENAPI_URL = + "https://app.stainless.com/api/spec/documented/kernel/openapi.documented.yml"; + +const TARGET_DIRS = ["browsers", "apps"]; // adjust as needed +const SNIPPETS_ROOT = path.resolve("snippets/openapi"); + +// Only emit code samples for these languages (normalized): e.g., ["typescript", "python"] +const TARGET_LANGUAGES = ["typescript", "python"] as const; +type SupportedLanguage = + | (typeof TARGET_LANGUAGES)[number] + | "javascript" + | "go"; + +function normalizeLang(input: string): SupportedLanguage { + const lc = (input || "").toLowerCase(); + if (lc === "ts" || lc === "typescript") return "typescript"; + if (lc === "py" || lc === "python") return "python"; + if ( + lc === "js" || + lc === "javascript" || + lc === "node" || + lc === "node.js" || + lc === "nodejs" + ) + return "javascript"; + if (lc === "go" || lc === "golang") return "go"; + return lc as SupportedLanguage; +} + +function renderFenceInfo(lang: SupportedLanguage, rawLang: string): string { + if (lang === "typescript" || lang === "javascript") + return "typescript Typescript/Javascript"; + if (lang === "python") return "python Python"; + return `${lang} ${toTitleCase(rawLang)}`; +} + +function renderValueForLanguage( + lang: SupportedLanguage, + value: unknown +): string { + const type = typeof value; + if (type === "boolean") { + const b = value as boolean; + return lang === "python" ? (b ? "True" : "False") : b ? "true" : "false"; + } + if (type === "number") return String(value); + if (type === "string") { + // Use double quotes across both for simplicity + return JSON.stringify(value); + } + // Fallback to JSON for objects/arrays; Python will be JSON-like which is acceptable for docs + try { + return JSON.stringify(value); + } catch { + return String(value); + } +} + +function injectParamsIntoObjectLiteral( + lang: SupportedLanguage, + objectLiteral: string, + params: Record +): string { + let updated = objectLiteral; + for (const [key, val] of Object.entries(params)) { + const valueStr = renderValueForLanguage(lang, val); + const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + // Try to replace existing key first (handles both quoted and unquoted keys) + const keyPatterns = [ + new RegExp(`(([,\{\n\r\t\s])${escapedKey}\\s*:\\s*)([^,\n}]+)`, "m"), // JS/TS style key: value + new RegExp(`(([,\{\n\r\t\s])\"${escapedKey}\"\\s*:\\s*)([^,\n}]+)`, "m"), // JSON/Python style "key": value + ]; + let replaced = false; + for (const pattern of keyPatterns) { + if (pattern.test(updated)) { + updated = updated.replace(pattern, `$1${valueStr}`); + replaced = true; + break; + } + } + if (!replaced) { + // Insert after the first opening brace + if (lang === "python") { + const insertion = `"${key}": ${valueStr}, `; + updated = updated.replace(/\{\s*/, (m) => m + insertion); + } else { + const isMultiline = /\{\s*\n/.test(updated); + const indentMatch = updated.match(/\{\s*\n([ \t]*)/); + const indent = indentMatch?.[1] ?? ""; + const insertion = isMultiline + ? `${indent}${key}: ${valueStr},\n${indent}` + : `${key}: ${valueStr}, `; + if (isMultiline) { + // Normalize to a single newline after '{' then insert our line + updated = updated.replace(/\{\s*/, "{\n"); + updated = updated.replace(/\{\n/, `{\n${insertion}`); + } else { + updated = updated.replace(/\{\s*/, (m) => m + insertion); + } + } + } + } + // For JS/TS single-line objects, remove any trailing comma before the closing brace + if (lang !== "python") { + updated = updated.replace(/,\s*}/, " }"); + } + return updated; +} + +function injectParamsIntoPythonArgs( + argList: string, + params: Record +): string { + let updated = argList; + // Ensure trailing comma handling is clean; if arguments are on multiple lines, add newline before inserted kwarg + for (const [key, val] of Object.entries(params)) { + const valueStr = renderValueForLanguage("python", val); + const pattern = new RegExp(`(\\b${key}\\s*=)\\s*([^,\n)]+)`, "m"); + if (pattern.test(updated)) { + updated = updated.replace(pattern, `$1 ${valueStr}`); + } else { + const trimmed = updated.trim(); + if (trimmed.length === 0) { + updated = `${key}=${valueStr}`; + } else { + const isMultiline = /\n/.test(updated); + const hasTrailingComma = /,\s*$/.test(updated); + if (isMultiline) { + const firstArgIndentMatch = updated.match(/^([ \t]+)[A-Za-z_]/m); + const lastLineIndentMatch = updated.match(/\n([ \t]*)[^\n]*$/); + const indent = + firstArgIndentMatch?.[1] ?? lastLineIndentMatch?.[1] ?? " "; + const prefix = updated.replace(/\s*$/, ""); + const commaPrefix = hasTrailingComma ? prefix : `${prefix},`; + updated = `${commaPrefix}\n${indent}${key}=${valueStr},`; + } else { + const sep = hasTrailingComma ? " " : ", "; + updated = `${updated.replace(/\s*$/, "")}${sep}${key}=${valueStr}`; + } + } + } + } + return updated; +} + +function applyOverridesToSource( + lang: SupportedLanguage, + src: string, + overrides?: Record +): string { + if (!overrides || Object.keys(overrides).length === 0) return src; + let transformed = src; + + // Heuristic: find the first object literal in a X.create(...) call and inject params (excluding special keys like 'log') + const { log: _logOverride, ...injectionOverrides } = overrides as Record< + string, + unknown + >; + if (Object.keys(injectionOverrides).length > 0) { + const createCall = /(\b\w+\.(create|new)\()([\s\S]*?)(\))/m; + const match = transformed.match(createCall); + if (match) { + const before = transformed.slice(0, match.index ?? 0); + const after = transformed.slice((match.index ?? 0) + match[0].length); + const inside = match[3] ?? ""; + const objectMatch = inside.match(/\{[\s\S]*?\}/m); + if (objectMatch) { + const objBefore = inside.slice(0, objectMatch.index!); + const obj = objectMatch[0]; + const objAfter = inside.slice( + (objectMatch.index || 0) + objectMatch[0].length + ); + const injected = injectParamsIntoObjectLiteral( + lang, + obj, + injectionOverrides + ); + const newInside = objBefore + injected + objAfter; + transformed = before + match[1] + newInside + match[4] + after; + } else if (lang === "python") { + const injectedArgs = injectParamsIntoPythonArgs( + inside, + injectionOverrides + ); + const needsNewlineBeforeParen = + /\n/.test(injectedArgs) && !/\n\s*$/.test(injectedArgs); + const joiner = needsNewlineBeforeParen ? "\n" : ""; + transformed = + before + match[1] + injectedArgs + joiner + match[4] + after; + } else { + // JS/TS with no object literal: insert one and inject + const injectedObj = injectParamsIntoObjectLiteral( + lang, + "{}", + injectionOverrides + ); + transformed = before + match[1] + injectedObj + match[4] + after; + } + } + } + + // Apply log override if present: replace argument of the last console.log/print call + const logExpr = (overrides as Record)?.log; + if (typeof logExpr === "string" && logExpr.trim().length > 0) { + if (lang === "python") { + const regex = /print\(([^\)]*)\)/g; + let lastMatch: RegExpExecArray | null = null; + let m: RegExpExecArray | null; + while ((m = regex.exec(transformed)) !== null) lastMatch = m; + if (lastMatch) { + const start = lastMatch.index; + const end = start + lastMatch[0].length; + transformed = + transformed.slice(0, start) + + `print(${logExpr})` + + transformed.slice(end); + } + } else { + const regex = /console\.log\(([^\)]*)\)/g; + let lastMatch: RegExpExecArray | null = null; + let m: RegExpExecArray | null; + while ((m = regex.exec(transformed)) !== null) lastMatch = m; + if (lastMatch) { + const start = lastMatch.index; + const end = start + lastMatch[0].length; + transformed = + transformed.slice(0, start) + + `console.log(${logExpr})` + + transformed.slice(end); + } + } + } + + return transformed; +} + +function parseOverridesString( + raw: string +): Record | undefined { + // Rebuild as JSON object string; heuristically quote keys + let jsonish = `{ ${raw} }`; + // Quote unquoted keys (simple heuristic) + jsonish = jsonish.replace(/([,{\s])([A-Za-z_][A-Za-z0-9_]*)\s*:/g, '$1"$2":'); + // Normalize single quotes to double quotes + jsonish = jsonish.replace(/'([^']*)'/g, '"$1"'); + try { + return JSON.parse(jsonish); + } catch { + return undefined; + } +} + +function extractOverridesFromAttributes( + attrs: string | undefined +): Record | undefined { + if (!attrs) return undefined; + const idx = attrs.indexOf("overrides="); + if (idx === -1) return undefined; + // Find first '{' after 'overrides=' + const start = attrs.indexOf("{", idx); + if (start === -1) return undefined; + let depth = 0; + let end = -1; + for (let i = start; i < attrs.length; i++) { + const ch = attrs[i]; + if (ch === "{") depth++; + else if (ch === "}") { + depth--; + if (depth === 0) { + end = i; + break; + } + } + } + if (end === -1) return undefined; + const raw = attrs.slice(start, end + 1); + return parseOverridesString(raw); +} + +function toTitleCase(input: string): string { + if (!input) return ""; + return input.charAt(0).toUpperCase() + input.slice(1).toLowerCase(); +} + +type VariantConfig = { name: string; overrides?: Record }; +type CodeSamplesConfig = { + variants?: Record; // key: "method /path" lowercased +}; + +async function readConfig(): Promise { + const configPath = path.resolve(".github/scripts/code_samples.config.json"); + try { + const text = await readFile(configPath, "utf8"); + return JSON.parse(text) as CodeSamplesConfig; + } catch { + return {}; + } +} + +async function fetchOpenAPISpec() { + console.log(`📥 Fetching OpenAPI spec from ${OPENAPI_URL}`); + const res = await fetch(OPENAPI_URL!); + if (!res.ok) + throw new Error(`Failed to fetch OpenAPI spec: ${res.statusText}`); + const text = await res.text(); + + // Try JSON first, fallback to YAML + try { + return JSON.parse(text); + } catch { + return yaml.load(text); + } +} + +async function getMdxFiles(dir: string): Promise { + const entries = await readdir(dir, { withFileTypes: true }); + const files: string[] = []; + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...(await getMdxFiles(fullPath))); + } else if (entry.isFile() && entry.name.endsWith(".mdx")) { + files.push(fullPath); + } + } + return files; +} + +function extractCodeSamples( + spec: any, + endpoint: string, + method?: string, + overrides?: Record +): string { + const pathItem = spec.paths?.[endpoint]; + if (!pathItem) return `⚠️ No spec found for ${endpoint}`; + + const blocks: string[] = []; + + const methods = method ? [method.toLowerCase()] : Object.keys(pathItem); // all methods if not specified + + for (const m of methods) { + const op = pathItem[m]; + if (op?.["x-codeSamples"]) { + for (const sample of op["x-codeSamples"]) { + const rawLang = typeof sample.lang === "string" ? sample.lang : ""; + const normalized = normalizeLang(rawLang); + const allowedNormalized = [ + "typescript", + "javascript", + "python", + ] as const; + if (!(allowedNormalized as readonly string[]).includes(normalized)) + continue; + const displayLang: "typescript" | "python" = + normalized === "python" ? "python" : "typescript"; + + const fenceInfo = renderFenceInfo(displayLang, rawLang); + const transformedSource = applyOverridesToSource( + displayLang, + String(sample.source ?? "").trim(), + overrides + ); + blocks.push(`\n\`\`\`${fenceInfo}\n${transformedSource}\n\`\`\`\n`); + } + } + } + + return blocks.length > 0 + ? blocks.join("\n") + : `⚠️ No code samples for ${ + method ? method.toUpperCase() : "any" + } ${endpoint}`; +} + +function slugifyEndpoint(method: string, endpoint: string): string { + const m = (method || "").toLowerCase().replace(/[^a-z]/g, ""); + let ep = endpoint.replace(/^\//, ""); + // Unwrap path params like {id} -> id + ep = ep.replace(/\{([^}]+)\}/g, "$1"); + // Sanitize and normalize + ep = ep + .replace(/[^a-zA-Z0-9\-/_]/g, "-") + .replace(/[\/]/g, "-") + .replace(/--+/g, "-") + .replace(/^-+|-+$/g, ""); + return `${m}-${ep}`.toLowerCase(); +} + +async function writeSnippetFile(filePath: string, blocks: string) { + const dir = path.dirname(filePath); + await mkdir(dir, { recursive: true }); + const content = `\n${blocks.trim()}\n\n`; + await writeFile(filePath, content, "utf8"); +} + +async function generateSnippets(spec: any) { + const config = await readConfig(); + const paths = spec.paths || {}; + for (const endpoint of Object.keys(paths)) { + const pathItem = paths[endpoint]; + for (const method of Object.keys(pathItem)) { + const key = `${method.toLowerCase()} ${endpoint}`.toLowerCase(); + const baseBlocks = extractCodeSamples(spec, endpoint, method).trim(); + if (!baseBlocks.startsWith("⚠️ ")) { + const baseSlug = slugifyEndpoint(method, endpoint); + const baseFile = path.join(SNIPPETS_ROOT, `${baseSlug}.mdx`); + await writeSnippetFile(baseFile, baseBlocks); + console.log( + `🧩 Wrote snippet: ${path.relative(process.cwd(), baseFile)}` + ); + } + const variants = config.variants?.[key] || []; + for (const variant of variants) { + const vBlocks = extractCodeSamples( + spec, + endpoint, + method, + variant.overrides + ).trim(); + if (!vBlocks.startsWith("⚠️ ")) { + const vSlug = `${slugifyEndpoint(method, endpoint)}-${variant.name}`; + const vFile = path.join(SNIPPETS_ROOT, `${vSlug}.mdx`); + await writeSnippetFile(vFile, vBlocks); + console.log( + `🧩 Wrote snippet: ${path.relative(process.cwd(), vFile)}` + ); + } + } + } + } +} + +async function cleanupOldSnippets() { + try { + const entries = await readdir(SNIPPETS_ROOT, { withFileTypes: true }); + const stale = entries + .filter((e) => e.isFile()) + .map((e) => e.name) + .filter((name) => name.endsWith("-.mdx")); + for (const name of stale) { + const full = path.join(SNIPPETS_ROOT, name); + await unlink(full); + console.log( + `🧹 Removed stale snippet: ${path.relative(process.cwd(), full)}` + ); + } + } catch { + // ignore if folder doesn't exist yet + } +} + +async function processFile(file: string, spec: any) { + let content = await readFile(file, "utf8"); + + // Matches get /path + // or /path + const tagRegex = + /]*)>\s*(?:(get|post|put|delete|patch|options|head)\s+)?(\/[^\s<]+)(?:\s+(\{[\s\S]*?\}))?\s*<\/OpenAPICodeGroup>/gi; + + let changed = false; + content = content.replace( + tagRegex, + (_, attrs, method, endpoint, jsonOverrides) => { + changed = true; + let overrides: Record | undefined = undefined; + const attrOverrides = extractOverridesFromAttributes(attrs); + if (attrOverrides) overrides = { ...attrOverrides }; + if (jsonOverrides) { + const inline = parseOverridesString(jsonOverrides); + if (inline) overrides = { ...(overrides || {}), ...inline }; + } + const blocks = extractCodeSamples( + spec, + endpoint, + method, + overrides + ).trim(); + return `\n${blocks}\n`; + } + ); + + if (changed) { + console.log(`✏️ Updating ${file}`); + await writeFile(file, content, "utf8"); + } +} + +async function main() { + const spec = await fetchOpenAPISpec(); + + // Always generate snippet files from OpenAPI + await cleanupOldSnippets(); + await generateSnippets(spec); + + for (const dir of TARGET_DIRS) { + const files = await getMdxFiles(dir); + for (const file of files) { + await processFile(file, spec); + } + } + + console.log("✅ Done updating docs"); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/.github/scripts/package.json b/.github/scripts/package.json new file mode 100644 index 0000000..769e60e --- /dev/null +++ b/.github/scripts/package.json @@ -0,0 +1,14 @@ +{ + "name": "scripts", + "private": true, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5" + }, + "dependencies": { + "@types/js-yaml": "^4.0.9", + "js-yaml": "^4.1.0" + } +} diff --git a/.github/scripts/tsconfig.json b/.github/scripts/tsconfig.json new file mode 100644 index 0000000..bfa0fea --- /dev/null +++ b/.github/scripts/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + // Environment setup & latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "Preserve", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} diff --git a/.github/workflows/generate_code_snippets.yaml b/.github/workflows/generate_code_snippets.yaml new file mode 100644 index 0000000..753d74a --- /dev/null +++ b/.github/workflows/generate_code_snippets.yaml @@ -0,0 +1,34 @@ +name: Update Docs with Code Samples from OpenAPI + +on: + push: + branches-ignore: + - main + +permissions: + contents: write + +jobs: + update-docs: + runs-on: ubuntu-latest + if: github.actor != 'github-actions[bot]' # prevent infinite loop + steps: + - name: Checkout branch + uses: actions/checkout@v4 + with: + ref: ${{ github.ref_name }} + fetch-depth: 0 + + - name: Install Bun + uses: oven-sh/setup-bun@v1 + + - name: Run update script + run: bun run .github/scripts/generate_code_samples.ts + + - name: Commit changes + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git add . + git commit -m "docs: update code samples from OpenAPI" || echo "No changes" + git push origin "HEAD:${{ github.ref }}" diff --git a/README.md b/README.md index ac7552c..c9dd00c 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,48 @@ Follow @rfgarcia

- This is the documentation for the Kernel platform. It's connected to [docs.onkernel.com](https://docs.onkernel.com). +## Code Snippets + +Code samples in the docs are generated from our OpenAPI spec so the examples stay in sync with the API. There are two ways the generator is invoked: + +- Custom MDX tag: use `get /api/v1/users` (or omit the verb to use the default behavior). + +How the generator works (current behavior): + +- The script is `.github/scripts/generate_code_samples.ts` and is executed with Bun. It fetches the OpenAPI spec from the URL configured at the top of that script. +- It reads `x-codeSamples` entries for each operation and extracts samples for TypeScript/JavaScript and Python. Samples are normalized and may be transformed by simple "overrides" (see the script for the override parsing and injection heuristics). +- It writes snippet files under `snippets/openapi/` as MDX files containing a `` with the generated code fences. It also updates any MDX files under `apps/` and `browsers/` that contain the inline or tag forms by replacing them with the generated `` blocks. +- The generator can produce a base snippet and additional variant snippets controlled by `.github/scripts/code_samples.config.json` (variants are keyed by `"method /path"`). +- The script also removes stale snippet files matching the `-.mdx` suffix pattern. + +How it affects the repository: + +- New or updated files are created under `snippets/openapi/*.mdx`. +- MDX pages in `apps/` and `browsers/` may be modified in-place to replace ``/mustache tags with generated `` blocks. +- A GitHub Action (`.github/workflows/generate_code_snippets.yaml`) runs the script on push (except to `main`), commits any changes, and pushes them to the `gh_action_generated_docs` branch so Mintlify can deploy the generated docs. + +Notes and gotchas: + +- The generator runs remotely against the OpenAPI URL defined in the script, so it needs network access and the spec to include `x-codeSamples` for useful output. +- The override parsing and code injection are heuristic — complex sample sources might not be transformed exactly as intended. See the script for details on how keys/`log` overrides are applied. +- The GitHub Action installs Bun and runs the script; if you run it locally, install Bun and run `bun run .github/scripts/generate_code_samples.ts` from the repo root. + +Example: to add a snippet placeholder to a page, add `get /api/v1/users` and let the generator fill `snippets/openapi` and update the page during the next run. + +## Local Development + +To run the docs locally, you can use the following command: + +```bash +mintlify dev +``` + ## Contributing We welcome contributions to the documentation. Please feel free to submit a pull request with your changes. See [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for more details. ## License -This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details. \ No newline at end of file +This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details. diff --git a/apps/invoke.mdx b/apps/invoke.mdx index 5810ca6..16cca48 100644 --- a/apps/invoke.mdx +++ b/apps/invoke.mdx @@ -2,90 +2,22 @@ title: "Invoking" --- +import SynchronousInvocation from '/snippets/openapi/post-invocations.mdx'; +import AsyncInvocation from '/snippets/openapi/post-invocations-async.mdx'; + ## Via API -You can invoke your app by making a `POST` request to Kernel's API. **For automations and agents that take longer than 100 seconds, use [async invocations](/apps/invoke#asynchronous-invocations).** - - - Synchronous invocations time out after 100 seconds. - - - -```typescript Typescript/Javascript -import { Kernel } from '@onkernel/sdk'; - -const { - id, - status, - status_reason, - output -} = await Kernel.invocations.create({ - app_name: app_name, - action_name: action_name, - version: "latest" -}); -``` +You can invoke your app by making a `POST` request to Kernel's API. **For automations and agents that take longer than 100 seconds, use [async invocations](/apps/invoke#asynchronous-invocations).** -```python Python -import kernel - -result = kernel.invocations.create({ - "app_name": app_name, - "action_name": action_name, - "version": "latest" -}) -invocation_id, status, status_reason, output = ( - result["id"], - result["status"], - result["status_reason"], - result["output"] -) - result["id"], - result["status"], - result["status_reason"], - result["output"] -) -``` +Synchronous invocations time out after 100 seconds. - + ### Asynchronous invocations -For long running jobs, use asynchronous invocations to trigger Kernel actions without waiting for the result. You can then poll its [status](/apps/status) for the result. - - -```typescript Typescript/Javascript -import { Kernel } from '@onkernel/sdk'; - -const { - id, - status, // status will be QUEUED -} = await Kernel.invocations.create({ - app_name: app_name, - action_name: action_name, - version: "latest", - async: true, -}); -``` -```python Python -import kernel - -result = kernel.invocations.create({ - "app_name": app_name, - "action_name": action_name, - "version": "latest", - "async": True -}) -invocation_id, status = ( - result["id"], - result["status"] # status will be QUEUED -) - result["id"], - result["status"] # status will be QUEUED -) -``` +For long running jobs, use asynchronous invocations to trigger Kernel actions without waiting for the result. You can then poll its [status](/apps/status) for the result. - + ## Via CLI @@ -96,9 +28,11 @@ kernel invoke ``` ### Payload parameter + `--payload` allows you to invoke the action with specified parameters. This enables your action to receive and handle dynamic inputs at runtime. For example: + ```bash -kernel invoke +kernel invoke --payload '{"tshirt_size": "small", "color": "black", "shipping_address": "2 Mint Plz, San Francisco CA 94103"}' ``` diff --git a/apps/status.mdx b/apps/status.mdx index 8fcbf2f..6b3c717 100644 --- a/apps/status.mdx +++ b/apps/status.mdx @@ -2,41 +2,11 @@ title: "Status" --- -Once you've [deployed](/apps/deploy) an app and invoked it, you can check its status. - - -```typescript Typescript/Javascript -import { Kernel } from '@onkernel/sdk'; - -const { - id, - app_name, - action_name, - payload, - output, - started_at, - finished_at, - status, - status_reason -} = await Kernel.invocations.get(invocation_id); -``` +import GetInvocationStatus from '/snippets/openapi/get-invocations-id.mdx'; -```python Python -import kernel - -data = kernel.invocations.get(invocation_id) -invocation_id = data["id"] -app_name = data["app_name"] -action_name = data["action_name"] -payload = data["payload"] -output = data["output"] -started_at = data["started_at"] -finished_at = data["finished_at"] -status = data["status"] -status_reason = data["status_reason"] -``` +Once you've [deployed](/apps/deploy) an app and invoked it, you can check its status. - + An invocation ends once its code execution finishes. diff --git a/apps/stop.mdx b/apps/stop.mdx index 5bc6132..4164b3c 100644 --- a/apps/stop.mdx +++ b/apps/stop.mdx @@ -2,6 +2,8 @@ title: "Stopping" --- +import StopInvocation from '/snippets/openapi/patch-invocations-id.mdx'; + You can terminate an invocation that's running. You can use this to stop automations or agents stuck in an infinite loop. @@ -9,22 +11,9 @@ Terminating an invocation also destroys any browsers associated with it. ## Via API -You can also do this by making a `DELETE` request to Kernel's API: - - -```typescript Typescript/Javascript -import { Kernel } from '@onkernel/sdk'; - -await Kernel.invocations.delete(invocationId); -``` - -```python Python -import kernel - -kernel.invocations.delete(invocation_id) -``` - +You can also do this via the API: + ## Via CLI Use `ctrl-c` in the terminal tab where you launched the invocation. diff --git a/browsers/create-a-browser.mdx b/browsers/create-a-browser.mdx index e68269c..832e735 100644 --- a/browsers/create-a-browser.mdx +++ b/browsers/create-a-browser.mdx @@ -2,26 +2,16 @@ title: "Create a Browser" --- +import CreateBrowserSnippet from '/snippets/openapi/post-browsers.mdx'; +import DeleteBrowserSnippet from '/snippets/openapi/delete-browsers-id.mdx'; + Kernel browsers were designed to be lightweight, fast, and efficient for cloud-based browser automations at scale. They can be used as part of the Kernel [app platform](/apps/develop) or connected to from another service with the Chrome DevTools Protocol. ## 1. Create a Kernel browser Use our SDK to create a browser: - -```typescript Typescript/Javascript -import { Kernel } from '@onkernel/sdk'; -const kernel = new Kernel(); -const kernelBrowser = await kernel.browsers.create(); -``` - -```Python Python -import kernel -client = Kernel() -kernel_browser = client.browsers.create() -``` - - + ## 2. Connect to the browser with the Chrome DevTools Protocol @@ -50,16 +40,7 @@ browser = playwright.chromium.connect_over_cdp(kernel_browser.cdp_ws_url) When you're finished with the browser, you can delete it: - -```typescript Typescript/Javascript -await client.browsers.deleteByID(kernel_browser.session_id); -``` - -```Python Python -client.browsers.delete_by_id(kernel_browser.session_id) -``` - - + You can also delete the browser by [specifiying a timeout](/browsers/termination#timeouts-for-non-persisted-browsers) when you create the browser. ## Full example diff --git a/browsers/live-view.mdx b/browsers/live-view.mdx index 0c2cbc8..970825d 100644 --- a/browsers/live-view.mdx +++ b/browsers/live-view.mdx @@ -2,26 +2,13 @@ title: "Live View" --- +import CreateBrowserForLiveView from '/snippets/openapi/post-browsers-live-view.mdx'; + Humans-in-the-loop can access the live view of Kernel browsers in real-time to resolve errors or take unscripted actions. To access the live view, visit the `browser_live_view_url` provided when you create a Kernel browser: - -```typescript Typescript/Javascript -import { Kernel } from '@onkernel/sdk'; -const kernel = new Kernel(); -const kernelBrowser = await kernel.browsers.create(); -console.log(kernelBrowser.browser_live_view_url); -``` - -```python Python -import kernel -client = Kernel() -kernel_browser = client.browsers.create() -print(kernel_browser.browser_live_view_url) -``` - - + ## Query parameters diff --git a/browsers/termination.mdx b/browsers/termination.mdx index ca4062a..9798e67 100644 --- a/browsers/termination.mdx +++ b/browsers/termination.mdx @@ -2,37 +2,16 @@ title: "Termination & Timeouts" --- +import DeleteBrowser from '/snippets/openapi/delete-browsers-id.mdx'; +import CreateBrowserTimeout from '/snippets/openapi/post-browsers-timeout.mdx'; + Kernel browsers should be terminated after you're done with them. ## Via API You can delete a browser by making a `DELETE` request to Kernel's API: - -```typescript Typescript/Javascript -import Kernel from '@onkernel/sdk'; -const kernel = new Kernel(); - -// Delete a persisted browser -await kernel.browsers.delete({ persistent_id: 'persistent_id' }); - -// Delete a non-persisted browser -await kernel.browsers.deleteByID('htzv5orfit78e1m2biiifpbv'); -``` - -```python Python -from kernel import Kernel -client = Kernel() - -# Delete a persisted browser -client.browsers.delete( - persistent_id="persistent_id", -) - -# Delete a non-persisted browser -client.browsers.delete_by_id('htzv5orfit78e1m2biiifpbv') -``` - + ## Timeouts for non-persisted browsers @@ -40,16 +19,4 @@ If you don't manually delete a `non-persisted` browser, deletion will happen aut You can set a custom timeout of up to 24 hours via the API: - -```typescript Typescript/Javascript -import { Kernel } from '@onkernel/sdk'; -const kernel = new Kernel(); -const kernelBrowser = await kernel.browsers.create({ timeout_seconds: 300 }); -``` - -```python Python -import kernel -client = Kernel() -kernel_browser = client.browsers.create(timeout_seconds=300) -``` - \ No newline at end of file + \ No newline at end of file diff --git a/snippets/openapi/delete-browsers-id-fs-watch-watch_id.mdx b/snippets/openapi/delete-browsers-id-fs-watch-watch_id.mdx new file mode 100644 index 0000000..95a91e2 --- /dev/null +++ b/snippets/openapi/delete-browsers-id-fs-watch-watch_id.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.fs.watch.stop('watch_id', { id: 'id' }); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.fs.watch.stop( + watch_id="watch_id", + id="id", +) +``` + diff --git a/snippets/openapi/delete-browsers-id.mdx b/snippets/openapi/delete-browsers-id.mdx new file mode 100644 index 0000000..cdf3340 --- /dev/null +++ b/snippets/openapi/delete-browsers-id.mdx @@ -0,0 +1,23 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.deleteByID('htzv5orfit78e1m2biiifpbv'); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.delete_by_id( + "id", +) +``` + diff --git a/snippets/openapi/delete-browsers.mdx b/snippets/openapi/delete-browsers.mdx new file mode 100644 index 0000000..09f6c4f --- /dev/null +++ b/snippets/openapi/delete-browsers.mdx @@ -0,0 +1,23 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.delete({ persistent_id: 'persistent_id' }); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.delete( + persistent_id="persistent_id", +) +``` + diff --git a/snippets/openapi/delete-invocations-id-browsers.mdx b/snippets/openapi/delete-invocations-id-browsers.mdx new file mode 100644 index 0000000..9f8806c --- /dev/null +++ b/snippets/openapi/delete-invocations-id-browsers.mdx @@ -0,0 +1,23 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.invocations.deleteBrowsers('id'); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.invocations.delete_browsers( + "id", +) +``` + diff --git a/snippets/openapi/get-apps.mdx b/snippets/openapi/get-apps.mdx new file mode 100644 index 0000000..e86399f --- /dev/null +++ b/snippets/openapi/get-apps.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const apps = await client.apps.list(); + +console.log(apps); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +apps = client.apps.list() +print(apps) +``` + diff --git a/snippets/openapi/get-browsers-id-fs-file_info.mdx b/snippets/openapi/get-browsers-id-fs-file_info.mdx new file mode 100644 index 0000000..7a8875e --- /dev/null +++ b/snippets/openapi/get-browsers-id-fs-file_info.mdx @@ -0,0 +1,27 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const response = await client.browsers.fs.fileInfo('id', { path: '/J!' }); + +console.log(response.is_dir); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +response = client.browsers.fs.file_info( + id="id", + path="/J!", +) +print(response.is_dir) +``` + diff --git a/snippets/openapi/get-browsers-id-fs-list_files.mdx b/snippets/openapi/get-browsers-id-fs-list_files.mdx new file mode 100644 index 0000000..60d0851 --- /dev/null +++ b/snippets/openapi/get-browsers-id-fs-list_files.mdx @@ -0,0 +1,27 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const response = await client.browsers.fs.listFiles('id', { path: '/J!' }); + +console.log(response); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +response = client.browsers.fs.list_files( + id="id", + path="/J!", +) +print(response) +``` + diff --git a/snippets/openapi/get-browsers-id-fs-read_file.mdx b/snippets/openapi/get-browsers-id-fs-read_file.mdx new file mode 100644 index 0000000..55976f8 --- /dev/null +++ b/snippets/openapi/get-browsers-id-fs-read_file.mdx @@ -0,0 +1,32 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const response = await client.browsers.fs.readFile('id', { path: '/J!' }); + +console.log(response); + +const content = await response.blob(); +console.log(content); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +response = client.browsers.fs.read_file( + id="id", + path="/J!", +) +print(response) +content = response.read() +print(content) +``` + diff --git a/snippets/openapi/get-browsers-id-fs-watch-watch_id-events.mdx b/snippets/openapi/get-browsers-id-fs-watch-watch_id-events.mdx new file mode 100644 index 0000000..fb4d252 --- /dev/null +++ b/snippets/openapi/get-browsers-id-fs-watch-watch_id-events.mdx @@ -0,0 +1,27 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const response = await client.browsers.fs.watch.events('watch_id', { id: 'id' }); + +console.log(response.path); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +response = client.browsers.fs.watch.events( + watch_id="watch_id", + id="id", +) +print(response.path) +``` + diff --git a/snippets/openapi/get-browsers-id-replays-replay_id.mdx b/snippets/openapi/get-browsers-id-replays-replay_id.mdx new file mode 100644 index 0000000..0c47cb2 --- /dev/null +++ b/snippets/openapi/get-browsers-id-replays-replay_id.mdx @@ -0,0 +1,32 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const response = await client.browsers.replays.download('replay_id', { id: 'id' }); + +console.log(response); + +const content = await response.blob(); +console.log(content); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +response = client.browsers.replays.download( + replay_id="replay_id", + id="id", +) +print(response) +content = response.read() +print(content) +``` + diff --git a/snippets/openapi/get-browsers-id-replays.mdx b/snippets/openapi/get-browsers-id-replays.mdx new file mode 100644 index 0000000..27eca8d --- /dev/null +++ b/snippets/openapi/get-browsers-id-replays.mdx @@ -0,0 +1,26 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const replays = await client.browsers.replays.list('id'); + +console.log(replays); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +replays = client.browsers.replays.list( + "id", +) +print(replays) +``` + diff --git a/snippets/openapi/get-browsers-id.mdx b/snippets/openapi/get-browsers-id.mdx new file mode 100644 index 0000000..bc84e3b --- /dev/null +++ b/snippets/openapi/get-browsers-id.mdx @@ -0,0 +1,26 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const browser = await client.browsers.retrieve('htzv5orfit78e1m2biiifpbv'); + +console.log(browser.session_id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +browser = client.browsers.retrieve( + "id", +) +print(browser.session_id) +``` + diff --git a/snippets/openapi/get-browsers.mdx b/snippets/openapi/get-browsers.mdx new file mode 100644 index 0000000..ffc2c1c --- /dev/null +++ b/snippets/openapi/get-browsers.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const browsers = await client.browsers.list(); + +console.log(browsers); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +browsers = client.browsers.list() +print(browsers) +``` + diff --git a/snippets/openapi/get-deployments-id-events.mdx b/snippets/openapi/get-deployments-id-events.mdx new file mode 100644 index 0000000..b40d565 --- /dev/null +++ b/snippets/openapi/get-deployments-id-events.mdx @@ -0,0 +1,26 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const response = await client.deployments.follow('id'); + +console.log(response); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +response = client.deployments.follow( + id="id", +) +print(response) +``` + diff --git a/snippets/openapi/get-deployments-id.mdx b/snippets/openapi/get-deployments-id.mdx new file mode 100644 index 0000000..36935ca --- /dev/null +++ b/snippets/openapi/get-deployments-id.mdx @@ -0,0 +1,26 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const deployment = await client.deployments.retrieve('id'); + +console.log(deployment.id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +deployment = client.deployments.retrieve( + "id", +) +print(deployment.id) +``` + diff --git a/snippets/openapi/get-deployments.mdx b/snippets/openapi/get-deployments.mdx new file mode 100644 index 0000000..7cfb64f --- /dev/null +++ b/snippets/openapi/get-deployments.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const deployments = await client.deployments.list(); + +console.log(deployments); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +deployments = client.deployments.list() +print(deployments) +``` + diff --git a/snippets/openapi/get-invocations-id-events.mdx b/snippets/openapi/get-invocations-id-events.mdx new file mode 100644 index 0000000..fb08ac8 --- /dev/null +++ b/snippets/openapi/get-invocations-id-events.mdx @@ -0,0 +1,26 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const response = await client.invocations.follow('id'); + +console.log(response); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +response = client.invocations.follow( + "id", +) +print(response) +``` + diff --git a/snippets/openapi/get-invocations-id.mdx b/snippets/openapi/get-invocations-id.mdx new file mode 100644 index 0000000..7dbd194 --- /dev/null +++ b/snippets/openapi/get-invocations-id.mdx @@ -0,0 +1,26 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const invocation = await client.invocations.retrieve('rr33xuugxj9h0bkf1rdt2bet'); + +console.log(invocation.id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +invocation = client.invocations.retrieve( + "id", +) +print(invocation.id) +``` + diff --git a/snippets/openapi/patch-invocations-id.mdx b/snippets/openapi/patch-invocations-id.mdx new file mode 100644 index 0000000..6eebf72 --- /dev/null +++ b/snippets/openapi/patch-invocations-id.mdx @@ -0,0 +1,27 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const invocation = await client.invocations.update('id', { status: 'succeeded' }); + +console.log(invocation.id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +invocation = client.invocations.update( + id="id", + status="succeeded", +) +print(invocation.id) +``` + diff --git a/snippets/openapi/post-browsers-id-fs-watch.mdx b/snippets/openapi/post-browsers-id-fs-watch.mdx new file mode 100644 index 0000000..fcd1dbf --- /dev/null +++ b/snippets/openapi/post-browsers-id-fs-watch.mdx @@ -0,0 +1,27 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const response = await client.browsers.fs.watch.start('id', { path: 'path' }); + +console.log(response.watch_id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +response = client.browsers.fs.watch.start( + id="id", + path="path", +) +print(response.watch_id) +``` + diff --git a/snippets/openapi/post-browsers-id-replays-replay_id-stop.mdx b/snippets/openapi/post-browsers-id-replays-replay_id-stop.mdx new file mode 100644 index 0000000..7658510 --- /dev/null +++ b/snippets/openapi/post-browsers-id-replays-replay_id-stop.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.replays.stop('replay_id', { id: 'id' }); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.replays.stop( + replay_id="replay_id", + id="id", +) +``` + diff --git a/snippets/openapi/post-browsers-id-replays.mdx b/snippets/openapi/post-browsers-id-replays.mdx new file mode 100644 index 0000000..4b7a515 --- /dev/null +++ b/snippets/openapi/post-browsers-id-replays.mdx @@ -0,0 +1,26 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const response = await client.browsers.replays.start('id'); + +console.log(response.replay_id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +response = client.browsers.replays.start( + id="id", +) +print(response.replay_id) +``` + diff --git a/snippets/openapi/post-browsers-live-view.mdx b/snippets/openapi/post-browsers-live-view.mdx new file mode 100644 index 0000000..b511024 --- /dev/null +++ b/snippets/openapi/post-browsers-live-view.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const browser = await client.browsers.create(); + +console.log(browser.browser_live_view_url); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +browser = client.browsers.create() +print(browser.browser_live_view_url) +``` + diff --git a/snippets/openapi/post-browsers-timeout.mdx b/snippets/openapi/post-browsers-timeout.mdx new file mode 100644 index 0000000..d5e0644 --- /dev/null +++ b/snippets/openapi/post-browsers-timeout.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const browser = await client.browsers.create({timeout_seconds: 300 }); + +console.log(browser.session_id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +browser = client.browsers.create(timeout_seconds=300) +print(browser.session_id) +``` + diff --git a/snippets/openapi/post-browsers.mdx b/snippets/openapi/post-browsers.mdx new file mode 100644 index 0000000..264136b --- /dev/null +++ b/snippets/openapi/post-browsers.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const browser = await client.browsers.create(); + +console.log(browser.session_id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +browser = client.browsers.create() +print(browser.session_id) +``` + diff --git a/snippets/openapi/post-deployments.mdx b/snippets/openapi/post-deployments.mdx new file mode 100644 index 0000000..6212992 --- /dev/null +++ b/snippets/openapi/post-deployments.mdx @@ -0,0 +1,30 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const deployment = await client.deployments.create({ + entrypoint_rel_path: 'src/app.py', + file: fs.createReadStream('path/to/file'), +}); + +console.log(deployment.id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +deployment = client.deployments.create( + entrypoint_rel_path="src/app.py", + file=b"raw file contents", +) +print(deployment.id) +``` + diff --git a/snippets/openapi/post-invocations-async.mdx b/snippets/openapi/post-invocations-async.mdx new file mode 100644 index 0000000..1e62844 --- /dev/null +++ b/snippets/openapi/post-invocations-async.mdx @@ -0,0 +1,33 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const invocation = await client.invocations.create({ + async: true, + action_name: 'analyze', + app_name: 'my-app', + version: '1.0.0' }); + +console.log(invocation.id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +invocation = client.invocations.create( + action_name="analyze", + app_name="my-app", + version="1.0.0", + async=True, +) +print(invocation.id) +``` + diff --git a/snippets/openapi/post-invocations.mdx b/snippets/openapi/post-invocations.mdx new file mode 100644 index 0000000..31759ec --- /dev/null +++ b/snippets/openapi/post-invocations.mdx @@ -0,0 +1,32 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +const invocation = await client.invocations.create({ + action_name: 'analyze', + app_name: 'my-app', + version: '1.0.0', +}); + +console.log(invocation.id); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +invocation = client.invocations.create( + action_name="analyze", + app_name="my-app", + version="1.0.0", +) +print(invocation.id) +``` + diff --git a/snippets/openapi/put-browsers-id-fs-create_directory.mdx b/snippets/openapi/put-browsers-id-fs-create_directory.mdx new file mode 100644 index 0000000..c7607d3 --- /dev/null +++ b/snippets/openapi/put-browsers-id-fs-create_directory.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.fs.createDirectory('id', { path: '/J!' }); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.fs.create_directory( + id="id", + path="/J!", +) +``` + diff --git a/snippets/openapi/put-browsers-id-fs-delete_directory.mdx b/snippets/openapi/put-browsers-id-fs-delete_directory.mdx new file mode 100644 index 0000000..a2758b6 --- /dev/null +++ b/snippets/openapi/put-browsers-id-fs-delete_directory.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.fs.deleteDirectory('id', { path: '/J!' }); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.fs.delete_directory( + id="id", + path="/J!", +) +``` + diff --git a/snippets/openapi/put-browsers-id-fs-delete_file.mdx b/snippets/openapi/put-browsers-id-fs-delete_file.mdx new file mode 100644 index 0000000..ee84b33 --- /dev/null +++ b/snippets/openapi/put-browsers-id-fs-delete_file.mdx @@ -0,0 +1,24 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.fs.deleteFile('id', { path: '/J!' }); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.fs.delete_file( + id="id", + path="/J!", +) +``` + diff --git a/snippets/openapi/put-browsers-id-fs-move.mdx b/snippets/openapi/put-browsers-id-fs-move.mdx new file mode 100644 index 0000000..8fc4cfb --- /dev/null +++ b/snippets/openapi/put-browsers-id-fs-move.mdx @@ -0,0 +1,25 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.fs.move('id', { dest_path: '/J!', src_path: '/J!' }); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.fs.move( + id="id", + dest_path="/J!", + src_path="/J!", +) +``` + diff --git a/snippets/openapi/put-browsers-id-fs-set_file_permissions.mdx b/snippets/openapi/put-browsers-id-fs-set_file_permissions.mdx new file mode 100644 index 0000000..f898c3b --- /dev/null +++ b/snippets/openapi/put-browsers-id-fs-set_file_permissions.mdx @@ -0,0 +1,25 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.fs.setFilePermissions('id', { mode: '0611', path: '/J!' }); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.fs.set_file_permissions( + id="id", + mode="0611", + path="/J!", +) +``` + diff --git a/snippets/openapi/put-browsers-id-fs-write_file.mdx b/snippets/openapi/put-browsers-id-fs-write_file.mdx new file mode 100644 index 0000000..9b6c5de --- /dev/null +++ b/snippets/openapi/put-browsers-id-fs-write_file.mdx @@ -0,0 +1,25 @@ + +```typescript Typescript/Javascript +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', +}); + +await client.browsers.fs.writeFile('id', fs.createReadStream('path/to/file'), { path: '/J!' }); +``` + + +```python Python +from kernel import Kernel + +client = Kernel( + api_key="My API Key", +) +client.browsers.fs.write_file( + id="id", + contents=b"raw file contents", + path="/J!", +) +``` +