diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..bd46c64 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,60 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +```bash +# Build +npm run build # Compile TypeScript to ./dist/ + +# Test +npm test # Run all tests with coverage (requires .env file) +npm run test:ci # Run tests for CI (no .env required) + +# Run a single test file +npx jest tests/run/yepcodeRun.test.ts + +# Lint +npm run lint # Check for lint errors +npm run lint:fix # Auto-fix lint errors +``` + +Tests require a `.env` file with `YEPCODE_*` credentials to run against the real API. + +## Architecture + +This is a zero-dependency TypeScript SDK for the YepCode Cloud API. It requires Node.js >= 18 (uses native `fetch`). Output is compiled CommonJS to `./dist/`. + +### Public surface (`src/index.ts`) + +Four exported classes: +- **`YepCodeRun`** — Execute JavaScript/Python code in isolated YepCode sandboxes. Creates processes (deduplicated by SHA256 hash of code), executes them, and returns `Execution` instances. +- **`YepCodeEnv`** — CRUD for team-level environment variables with auto-pagination. +- **`YepCodeStorage`** — Upload/list/download/delete files (accepts `File`, `Blob`, or `Readable` streams). +- **`YepCodeApi`** — Raw HTTP client exposing the full REST API (processes, executions, schedules, modules, sandboxes, service accounts). + +### Key internals + +**`src/api/yepcodeApi.ts`** — The core HTTP client (~820 lines). Handles: +- Auth via API token, client credentials (OAuth), or direct access token +- Auto-refresh of expired access tokens +- All REST endpoints as typed methods + +**`src/run/execution.ts`** — Wraps a running execution with adaptive polling: +- 250ms × 4, then 500ms × 8, then 1000ms thereafter +- Logs polled every 2s or on completion +- Event callbacks: `onLog`, `onFinish`, `onError` + +**`src/api/configManager.ts`** — Reads `YEPCODE_API_TOKEN`, `YEPCODE_CLIENT_ID`, `YEPCODE_CLIENT_SECRET`, `YEPCODE_TEAM_ID`, `YEPCODE_ACCESS_TOKEN`, `YEPCODE_API_HOST` from the environment. + +**`src/utils/languageDetector.ts`** — Regex/scoring-based JS vs Python detection used when language is not specified explicitly. + +## OpenAPI spec + +The live spec is always available at: +``` +https://cloud.yepcode.io/api/rest/public/api-docs +``` + +Fetch it with `WebFetch` to audit which endpoints are missing from `src/api/yepcodeApi.ts` before adding new ones. New endpoints are deployed to that URL before this SDK is updated. diff --git a/src/api/types.ts b/src/api/types.ts index fa2ae87..d1c23cb 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -1,5 +1,7 @@ import { Readable } from "stream"; +export type ProgrammingLanguage = "JAVASCRIPT" | "PYTHON"; + export interface YepCodeApiConfig { apiHost?: string; timeout?: number; @@ -15,7 +17,7 @@ export interface CreateProcessInput { slug?: string; description?: string; readme?: string; - programmingLanguage?: "JAVASCRIPT" | "PYTHON"; + programmingLanguage?: ProgrammingLanguage; sourceCode?: string; parametersSchema?: string; webhook?: WebhookInput; @@ -141,7 +143,7 @@ export interface Process { [key: string]: any; }; }; - programmingLanguage?: "JAVASCRIPT" | "PYTHON"; + programmingLanguage?: ProgrammingLanguage; sourceCode?: string; webhook?: ProcessWebhook; settings?: ProcessSettings; @@ -279,7 +281,7 @@ export interface WebhookInput { export interface VersionedProcess { id: string; - programmingLanguage: "JAVASCRIPT" | "PYTHON"; + programmingLanguage: ProgrammingLanguage; sourceCode: string; parametersSchema: string; readme: string; @@ -330,7 +332,7 @@ export interface VersionedProcessAliasesPaginatedResult { export interface Module { id: string; name: string; - programmingLanguage?: "JAVASCRIPT" | "PYTHON"; + programmingLanguage?: ProgrammingLanguage; sourceCode?: string; createdBy?: string; createdAt?: string; @@ -340,7 +342,7 @@ export interface Module { export interface CreateModuleInput { name: string; - programmingLanguage?: "JAVASCRIPT" | "PYTHON"; + programmingLanguage?: ProgrammingLanguage; sourceCode?: string; script?: { programmingLanguage?: string; @@ -367,7 +369,7 @@ export interface ModulesPaginatedResult { export interface VersionedModule { id: string; - programmingLanguage: "JAVASCRIPT" | "PYTHON"; + programmingLanguage: ProgrammingLanguage; sourceCode: string; comment?: string; createdBy?: string; @@ -488,3 +490,54 @@ export interface ServiceAccountsListResult { total: number; data: ServiceAccount[]; } + +/** + * Teams + */ +export interface ErrorHandlerConfig { + processId?: string; + tag?: string; +} + +export interface ErrorHandlerConfigInput { + processId?: string; + tag?: string; +} + +export interface Team { + slug?: string; + name?: string; + zoneId?: string; + parentTeamSlugs?: string[]; + paramsSchemaValidationEnabled?: boolean; + errorHandlerConfig?: ErrorHandlerConfig | null; + createdAt?: string; +} + +export interface UpdateTeamInput { + name?: string; + zoneId?: string; + parentTeamSlugs?: string[] | null; + paramsSchemaValidationEnabled?: boolean; + errorHandlerConfig?: ErrorHandlerConfigInput | null; +} + +/** + * Dependencies + */ +export interface ProgrammingLanguageManifestInstallation { + status?: "PENDING" | "INSTALLING" | "INSTALLED" | "FAILED"; + error?: string; + dependencies?: { [name: string]: string }; +} + +export interface ProgrammingLanguageManifest { + id?: string; + programmingLanguage?: ProgrammingLanguage; + dependencies?: { [name: string]: string }; + nextInstallation?: ProgrammingLanguageManifestInstallation; +} + +export interface UpdateTeamDependenciesInput { + dependencies?: { [name: string]: string }; +} diff --git a/src/api/yepcodeApi.ts b/src/api/yepcodeApi.ts index 4a142d0..59de9ff 100644 --- a/src/api/yepcodeApi.ts +++ b/src/api/yepcodeApi.ts @@ -41,6 +41,11 @@ import { Sandbox, CreateSandboxInput, UpdateSandboxInput, + Team, + UpdateTeamInput, + ProgrammingLanguage, + ProgrammingLanguageManifest, + UpdateTeamDependenciesInput, } from "./types"; import { Readable } from "stream"; @@ -816,4 +821,37 @@ export class YepCodeApi { async deleteServiceAccount(id: string): Promise { return this.request("DELETE", `/auth/service-accounts/${id}`); } + + // Team endpoints + async getTeam(): Promise { + return this.request("GET", "/team"); + } + + async updateTeam(data: UpdateTeamInput): Promise { + return this.request("PATCH", "/team", { data }); + } + + // Dependencies endpoints + async getTeamDependencies( + language: ProgrammingLanguage + ): Promise { + return this.request("GET", `/dependencies/${language}`); + } + + async updateTeamDependencies( + language: ProgrammingLanguage, + data: UpdateTeamDependenciesInput + ): Promise { + return this.request("PUT", `/dependencies/${language}`, { data }); + } + + async installTeamDependencies(language: ProgrammingLanguage): Promise { + return this.request("POST", `/dependencies/${language}/install`); + } + + async discardTeamDependenciesInstallation( + language: ProgrammingLanguage + ): Promise { + return this.request("DELETE", `/dependencies/${language}/install`); + } }