{"id":50828811,"url":"https://github.com/eljijuna/argocd-api-client","last_synced_at":"2026-06-13T21:01:29.872Z","repository":{"id":363578344,"uuid":"1261673807","full_name":"ElJijuna/argocd-api-client","owner":"ElJijuna","description":"TypeScript client for the official Argo CD REST API. Fully typed, fetch-based, supports auth tokens, AbortSignal, common Argo CD resources, docs generation, benchmarks, and semantic-release publishing.","archived":false,"fork":false,"pushed_at":"2026-06-09T13:08:22.000Z","size":418,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T14:21:18.546Z","etag":null,"topics":["api-client","argo","argo-cd","argocd","cd","continuous-delivery","devops","gitops","javascript","k8s","kubernetes","nodejs","rest-api","sdk","typescript"],"latest_commit_sha":null,"homepage":"https://eljijuna.github.io/argocd-api-client/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ElJijuna.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-07T02:19:49.000Z","updated_at":"2026-06-09T13:12:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ElJijuna/argocd-api-client","commit_stats":null,"previous_names":["eljijuna/argocd-api-client"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/ElJijuna/argocd-api-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElJijuna%2Fargocd-api-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElJijuna%2Fargocd-api-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElJijuna%2Fargocd-api-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElJijuna%2Fargocd-api-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ElJijuna","download_url":"https://codeload.github.com/ElJijuna/argocd-api-client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElJijuna%2Fargocd-api-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34300116,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","argo","argo-cd","argocd","cd","continuous-delivery","devops","gitops","javascript","k8s","kubernetes","nodejs","rest-api","sdk","typescript"],"created_at":"2026-06-13T21:00:54.150Z","updated_at":"2026-06-13T21:01:29.859Z","avatar_url":"https://github.com/ElJijuna.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# argocd-api-client\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://argo-cd.readthedocs.io/en/stable/assets/logo.png\" alt=\"Argo CD logo\" width=\"160\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/ElJijuna/argocd-api-client/actions/workflows/release.yml\"\u003e\u003cimg src=\"https://github.com/ElJijuna/argocd-api-client/actions/workflows/release.yml/badge.svg\" alt=\"Release\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/argocd-api-client\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/argocd-api-client\" alt=\"npm version\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/argocd-api-client\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/argocd-api-client\" alt=\"npm downloads\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/package/argocd-api-client\"\u003e\u003cimg src=\"https://img.shields.io/bundlephobia/minzip/argocd-api-client\" alt=\"Bundle size\" /\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License: MIT\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.typescriptlang.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/TypeScript-6.x-blue?logo=typescript\u0026amp;logoColor=white\" alt=\"TypeScript\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://nodejs.org/\"\u003e\u003cimg src=\"https://img.shields.io/node/v/argocd-api-client\" alt=\"Node.js\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://semantic-release.gitbook.io/semantic-release/\"\u003e\u003cimg src=\"https://img.shields.io/badge/semantic--release-enabled-e10079?logo=semantic-release\" alt=\"semantic-release\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nTypeScript client for the official Argo CD REST API. Works in Node.js 18+ and browsers via `fetch`.\n\nArgo CD exposes Swagger docs at `/swagger-ui` on each Argo CD server. Argo CD authenticates API requests with JWTs; pass the JWT in the `Authorization` header as `Bearer \u003cjwt\u003e`.\n\n## Install\n\n```bash\nnpm install argocd-api-client\n```\n\n## Quick Start\n\n```typescript\nimport { ArgoCdClient } from 'argocd-api-client';\n\nconst argocd = new ArgoCdClient({\n  baseUrl: 'https://argocd.example.com',\n  token: process.env.ARGOCD_TOKEN,\n});\n\nconst apps = await argocd.applications.list({ project: ['default'] });\nconsole.log(apps.items.map((app) =\u003e app.metadata?.name));\n```\n\n## Login\n\n```typescript\nconst argocd = await ArgoCdClient.fromCredentials({\n  baseUrl: 'https://argocd.example.com',\n  username: 'admin',\n  password: 'password',\n});\n```\n\nThe client stores the credentials internally and automatically refreshes the session on 401 responses.\n\n## Resources\n\n```typescript\n// Applications\nawait argocd.applications.list({ project: ['default'] });\nawait argocd.applications.get('guestbook', { project: 'default' });\nawait argocd.applications.create({ metadata: { name: 'guestbook' } });\nawait argocd.applications.update('guestbook', { metadata: { name: 'guestbook' } });\nawait argocd.applications.patch('guestbook', { spec: {} });\nawait argocd.applications.sync('guestbook', { revision: 'main' });\nawait argocd.applications.revisionMetadata('guestbook', 'v2.1.0');\n// → ArgoCdRevisionMetadata  { author, date, tags, message }\n\nawait argocd.applications.terminateSync('guestbook');\nawait argocd.applications.wait('guestbook', { health: true, timeout: '60s' });\n// → ArgoCdApplication  returned once the app reaches the desired state\n\nawait argocd.applications.deleteResource('guestbook', {\n  kind: 'Pod',\n  resourceName: 'api-abc123',\n  version: 'v1',\n  namespace: 'default',\n  force: true,\n});\nawait argocd.applications.rollback('guestbook', { id: 3 });\nawait argocd.applications.deleteByName('guestbook');\n\n// Application observability\nconst tree = await argocd.applications.resourceTree('guestbook');\nconst managed = await argocd.applications.managedResources('guestbook');\nconst logs = await argocd.applications.logs('guestbook', { container: 'main', tailLines: 100 });\n// logs → ArgoCdLogEntry[]  (streamed NDJSON, returned as an array)\n\n// Convenience methods\nawait argocd.applications.images('guestbook');\n// → string[]  unique container images across all resources\n\nawait argocd.applications.pods('guestbook');\n// → ArgoCdPod[]  live pods with phase, nodeName and container specs/status\n\nawait argocd.applications.containers('guestbook');\n// → ArgoCdContainer[]  all containers flattened from every pod, each with podName\n\nawait argocd.applications.nodes('guestbook');\n// → ArgoCdNode[]  Kubernetes nodes hosting the app's pods (osImage, architecture, kernelVersion…)\n\nawait argocd.applications.health('guestbook');\n// → ArgoCdApplicationHealth  { status: 'Healthy' | 'Degraded' | …, message? }\n\nawait argocd.applications.diff('guestbook');\n// → ArgoCdManagedResource[]  only resources whose live state differs from target\n\nawait argocd.applications.events('guestbook');\n// → ArgoCdEvent[]  Kubernetes events for the application or a specific resource\n\n// ApplicationSets\nawait argocd.applicationSets.list();\nawait argocd.applicationSets.get('my-set');\nawait argocd.applicationSets.create({ metadata: { name: 'my-set' } });\nawait argocd.applicationSets.update('my-set', { metadata: { name: 'my-set' } });\nawait argocd.applicationSets.deleteByName('my-set');\n\n// Projects\nawait argocd.projects.list();\nawait argocd.projects.get('default');\nawait argocd.projects.create({ metadata: { name: 'default' } });\nawait argocd.projects.update('default', { metadata: { name: 'default' } });\nawait argocd.projects.deleteByName('default');\nawait argocd.projects.events('default');\n// → ArgoCdEvent[]  Kubernetes events for the project\n\nawait argocd.projects.repositories('default');\n// → ArgoCdRepositoryList  repositories associated with the project\n\n// Repositories\nawait argocd.repositories.list();\nawait argocd.repositories.get('https://github.com/acme/app.git');\nawait argocd.repositories.create({ repo: 'https://github.com/acme/app.git' });\nawait argocd.repositories.refs('https://github.com/acme/app.git');\nawait argocd.repositories.apps('https://github.com/acme/app.git', { revision: 'main' });\n// → ArgoCdRepoAppsResponse  { items: [{ type, path }] }\n\nawait argocd.repositories.deleteByRepo('https://github.com/acme/app.git');\n\n// Clusters\nawait argocd.clusters.list();\nawait argocd.clusters.get('https://kubernetes.default.svc');\nawait argocd.clusters.create({ name: 'prod', server: 'https://prod.k8s.io' });\nawait argocd.clusters.update('https://prod.k8s.io', { name: 'prod' });\nawait argocd.clusters.deleteByServer('https://kubernetes.default.svc');\nawait argocd.clusters.invalidateCache('https://kubernetes.default.svc');\n// → ArgoCdCluster  cluster with refreshed cache state\n\n// Accounts\nawait argocd.accounts.list();\nawait argocd.accounts.get('admin');\nawait argocd.accounts.canI('applications', 'get', '*');\nawait argocd.accounts.updatePassword({ name: 'admin', currentPassword: 'old', newPassword: 'new' });\nawait argocd.accounts.listTokens('admin');\n// → ArgoCdAccountTokenList  { items: ArgoCdAccountToken[] }\n\nawait argocd.accounts.createToken('admin', { expiresIn: '24h', id: 'ci-token' });\n// → ArgoCdAccountTokenCreated  { token, id, issuedAt, expiresAt }\n\nawait argocd.accounts.deleteToken('admin', 'token-id');\n\n// Repository credential templates\nawait argocd.repoCreds.list();\nawait argocd.repoCreds.create({ url: 'https://github.com/acme', username: 'bot', sshPrivateKey: '...' });\nawait argocd.repoCreds.deleteByUrl('https://github.com/acme');\n\n// Repository certificates (TLS/SSH)\nawait argocd.certificates.list();\nawait argocd.certificates.create([{ serverName: 'github.com', certType: 'ssh', certSubType: 'ssh-rsa', certData: '...' }]);\nawait argocd.certificates.delete({ hostNamePattern: 'github.com', certType: 'ssh' });\n\n// GPG keys (commit signature verification)\nawait argocd.gpgKeys.list();\n// → ArgoCdGpgKeyList  { items: Record\u003ckeyID, ArgoCdGpgKey\u003e }\n\nawait argocd.gpgKeys.create({ keyData: '-----BEGIN PGP PUBLIC KEY BLOCK-----...' });\n// → ArgoCdGpgKeyCreateResponse  { created: Record\u003ckeyID, ArgoCdGpgKey\u003e, skipped: string[] }\n\nawait argocd.gpgKeys.create({ keyData: '...' }, { upsert: true });\nawait argocd.gpgKeys.deleteByKeyId('A1B2C3D4');\n\n// Server settings (read-only)\nawait argocd.settings.get();\n// → ArgoCdSettings  { url, appLabelKey, statusBadgeEnabled, ... }\n\n// Server version\nawait argocd.version.get();\n// → ArgoCdVersion  { Version, BuildDate, GitCommit, GitTag, GoVersion, Platform, ... }\n\n// Session\nawait argocd.userInfo();\n// → ArgoCdUserInfo  { loggedIn, username, iss, groups }\n\nawait argocd.deleteSession();\n// Invalidates the current token on the server (logout)\n```\n\n## Abort Requests\n\nEvery request method accepts an optional `AbortSignal` as its final argument.\n\n```typescript\nconst controller = new AbortController();\n\nconst apps = await argocd.applications.list(\n  { project: ['default'] },\n  controller.signal,\n);\n\ncontroller.abort();\n```\n\n## Events\n\nUse `.on('request', callback)` to observe every HTTP request made by the client — useful for logging, metrics, and error tracking.\n\n```typescript\nargocd.on('request', (event) =\u003e {\n  console.log(`[${event.method}] ${event.url} → ${event.statusCode} (${event.durationMs}ms)`);\n  if (event.error) console.error('Request failed:', event.error.message);\n});\n```\n\nThe `RequestEvent` object includes:\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `url` | `string` | Full URL requested |\n| `method` | `'GET' \\| 'POST' \\| 'PUT' \\| 'PATCH' \\| 'DELETE'` | HTTP method |\n| `startedAt` | `Date` | When the request started |\n| `finishedAt` | `Date` | When the request finished |\n| `durationMs` | `number` | Duration in milliseconds |\n| `statusCode` | `number \\| undefined` | HTTP status code (absent on network errors) |\n| `error` | `Error \\| undefined` | Set on any failed request |\n\nMultiple listeners are supported and called in registration order. `.on()` returns `this` for chaining:\n\n```typescript\nargocd\n  .on('request', (e) =\u003e metrics.record(e.durationMs))\n  .on('request', (e) =\u003e { if (e.error) sentry.capture(e.error); });\n```\n\n\u003e Token auto-refresh on 401 is transparent: only one event is emitted per logical operation, reflecting the final outcome.\n\n## Express Integration\n\nInstall Express and (optionally) its types:\n\n```bash\nnpm install express\nnpm install -D @types/express\n```\n\nCreate a shared client instance and expose Argo CD resources through your own API:\n\n```typescript\n// src/argocd.ts\nimport { ArgoCdClient } from 'argocd-api-client';\n\nexport const argocd = new ArgoCdClient({\n  baseUrl: process.env.ARGOCD_BASE_URL!,\n  token: process.env.ARGOCD_TOKEN,\n});\n```\n\n```typescript\n// src/routes/apps.ts\nimport { Router } from 'express';\nimport { argocd } from '../argocd';\n\nconst router = Router();\n\n// GET /apps?project=default\nrouter.get('/', async (req, res, next) =\u003e {\n  try {\n    const project = req.query.project\n      ? [String(req.query.project)]\n      : undefined;\n\n    const apps = await argocd.applications.list(\n      { project },\n      req.signal, // forward the request's AbortSignal\n    );\n\n    res.json(apps.items?.map((app) =\u003e ({\n      name: app.metadata?.name,\n      namespace: app.metadata?.namespace,\n      health: app.status?.health?.status,\n      sync: app.status?.sync?.status,\n    })));\n  } catch (err) {\n    next(err);\n  }\n});\n\n// POST /apps/:name/sync\nrouter.post('/:name/sync', async (req, res, next) =\u003e {\n  try {\n    const result = await argocd.applications.sync(req.params.name, {\n      revision: req.body.revision ?? 'HEAD',\n    });\n    res.json(result);\n  } catch (err) {\n    next(err);\n  }\n});\n\nexport default router;\n```\n\n```typescript\n// src/index.ts\nimport express from 'express';\nimport appsRouter from './routes/apps';\n\nconst app = express();\napp.use(express.json());\napp.use('/apps', appsRouter);\n\napp.listen(3000, () =\u003e console.log('Listening on :3000'));\n```\n\n### Environment variables\n\n```env\nARGOCD_BASE_URL=https://argocd.example.com\nARGOCD_TOKEN=\u003cjwt\u003e\n```\n\nIf you don't have a static token, use `fromCredentials` to authenticate and get a ready-to-use client in one call:\n\n```typescript\nimport { ArgoCdClient } from 'argocd-api-client';\n\nexport const argocd = await ArgoCdClient.fromCredentials({\n  baseUrl: process.env.ARGOCD_BASE_URL!,\n  username: process.env.ARGOCD_USER!,\n  password: process.env.ARGOCD_PASS!,\n});\n```\n\n### Token refresh\n\nClients created with `fromCredentials` store the credentials internally and handle token expiry automatically:\n\n```typescript\n// Automatic — a 401 response triggers a session refresh and retries the request once\nawait argocd.applications.list();\n\n// Manual — force a refresh before the token expires\nawait argocd.refreshSession();\n```\n\nClients created with `new ArgoCdClient({ token })` do not store credentials; calling `refreshSession()` on them throws an error.\n\n### Express + createSession\n\nThis pattern exposes a `POST /auth/login` endpoint that exchanges credentials for an Argo CD JWT, then uses that token on every subsequent request via a middleware-created client.\n\n```typescript\n// src/routes/auth.ts\nimport { Router } from 'express';\nimport { ArgoCdClient } from 'argocd-api-client';\n\nconst router = Router();\n\n// POST /auth/login  { \"username\": \"admin\", \"password\": \"...\" }\nrouter.post('/login', async (req, res, next) =\u003e {\n  try {\n    const { username, password } = req.body as {\n      username: string;\n      password: string;\n    };\n\n    if (!username || !password) {\n      res.status(400).json({ error: 'username and password are required' });\n      return;\n    }\n\n    const client = new ArgoCdClient({ baseUrl: process.env.ARGOCD_BASE_URL! });\n    const { token } = await client.createSession({ username, password });\n\n    res.json({ token });\n  } catch (err) {\n    next(err);\n  }\n});\n\nexport default router;\n```\n\n```typescript\n// src/middleware/argocd.ts\nimport { RequestHandler } from 'express';\nimport { ArgoCdClient } from 'argocd-api-client';\n\ndeclare global {\n  namespace Express {\n    interface Request {\n      argocd: ArgoCdClient;\n    }\n  }\n}\n\nexport const argocdMiddleware: RequestHandler = (req, res, next) =\u003e {\n  const auth = req.headers.authorization;\n\n  if (!auth?.startsWith('Bearer ')) {\n    res.status(401).json({ error: 'Missing or invalid Authorization header' });\n    return;\n  }\n\n  req.argocd = new ArgoCdClient({\n    baseUrl: process.env.ARGOCD_BASE_URL!,\n    token: auth.slice(7),\n  });\n\n  next();\n};\n```\n\n```typescript\n// src/routes/apps.ts\nimport { Router } from 'express';\nimport { argocdMiddleware } from '../middleware/argocd';\n\nconst router = Router();\nrouter.use(argocdMiddleware);\n\n// GET /apps\nrouter.get('/', async (req, res, next) =\u003e {\n  try {\n    const apps = await req.argocd.applications.list({}, req.signal);\n    res.json(apps.items?.map((app) =\u003e ({\n      name: app.metadata?.name,\n      health: app.status?.health?.status,\n      sync: app.status?.sync?.status,\n    })));\n  } catch (err) {\n    next(err);\n  }\n});\n\nexport default router;\n```\n\n```typescript\n// src/index.ts\nimport express from 'express';\nimport authRouter from './routes/auth';\nimport appsRouter from './routes/apps';\n\nconst app = express();\napp.use(express.json());\napp.use('/auth', authRouter);\napp.use('/apps', appsRouter); // protected by argocdMiddleware\n\napp.listen(3000, () =\u003e console.log('Listening on :3000'));\n```\n\n**Flow:**\n\n```bash\n# 1. Obtain a token\ncurl -X POST http://localhost:3000/auth/login \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"username\":\"admin\",\"password\":\"secret\"}'\n# → { \"token\": \"\u003cjwt\u003e\" }\n\n# 2. Use the token in subsequent requests\ncurl http://localhost:3000/apps \\\n  -H 'Authorization: Bearer \u003cjwt\u003e'\n```\n\n## Benchmarks\n\n```bash\nnpm run bench\n```\n\nThe benchmark suite uses mocked `fetch` responses, so it never calls a real Argo CD server. It covers client construction, resource access, GET/POST/DELETE request paths, query params, error handling, `AbortSignal`, and memory pressure.\n\n## API Coverage\n\n| Service | Client property | Methods |\n| --- | --- | --- |\n| `SessionService` | — | `createSession` · `deleteSession` · `userInfo` |\n| `ApplicationService` | `applications` | `list` · `get` · `create` · `update` · `patch` · `sync` · `terminateSync` · `wait` · `rollback` · `deleteByName` · `deleteResource` · `refresh` · `revisionMetadata` · `resourceTree` · `managedResources` · `logs` · `images` · `pods` · `containers` · `nodes` · `health` · `diff` · `events` |\n| `ApplicationSetService` | `applicationSets` | `list` · `get` · `create` · `update` · `deleteByName` |\n| `ProjectService` | `projects` | `list` · `get` · `create` · `update` · `deleteByName` · `events` · `repositories` |\n| `RepositoryService` | `repositories` | `list` · `get` · `create` · `refs` · `apps` · `deleteByRepo` |\n| `RepoCredsService` | `repoCreds` | `list` · `create` · `deleteByUrl` |\n| `ClusterService` | `clusters` | `list` · `get` · `create` · `update` · `deleteByServer` · `invalidateCache` |\n| `AccountService` | `accounts` | `list` · `get` · `canI` · `updatePassword` · `listTokens` · `createToken` · `deleteToken` |\n| `CertificateService` | `certificates` | `list` · `create` · `delete` |\n| `GPGKeyService` | `gpgKeys` | `list` · `create` · `deleteByKeyId` |\n| `SettingsService` | `settings` | `get` |\n| `VersionService` | `version` | `get` |\n\nSee [ROADMAP.md](ROADMAP.md) for planned additions. Types keep Argo CD/Kubernetes payloads extensible with `Record\u003cstring, unknown\u003e` for areas where server versions vary.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feljijuna%2Fargocd-api-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feljijuna%2Fargocd-api-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feljijuna%2Fargocd-api-client/lists"}