npm package: @loom_project/codeup
Description: Aliyun Yunxiao Codeup SDK - GitLab-compatible API client for Node.js, Deno, Bun and Browsers
Latest version: 1.0.3

# @loom_project/codeup

A typed [Aliyun Yunxiao (云效)](https://www.aliyun.com/product/yunxiao) SDK for Node.js, Deno, Bun and Browsers.

**100% Gitbeaker-compatible API** - Drop-in replacement for [@gitbeaker/rest](https://github.com/jdalrymple/gitbeaker) with Yunxiao backend.

## Features

- **Gitbeaker-compatible** - Same class names, method names, and signatures as Gitbeaker
- **Complete** - Covers all Yunxiao Codeup APIs
- **Universal** - Works in Node.js, Deno, Bun, and modern browsers
- **Typed** - Full TypeScript support

## Installation

```bash
npm install @loom_project/codeup
```

## Quick Start

```typescript
import { Yunxiao } from '@loom_project/codeup';

// Note: Yunxiao requires organizationId (unlike GitLab)
const api = new Yunxiao({
  token: 'your-yunxiao-personal-access-token',
  organizationId: 'your-organization-id',
});

// Now use it exactly like Gitbeaker!
const projects = await api.Projects.all();
const branches = await api.Branches.all(projectId);
const mr = await api.MergeRequests.create(projectId, 'feature', 'main', 'Title');
```

## API Reference

### Groups (Organizations in Yunxiao)

```typescript
await api.Groups.all();
await api.Groups.show(groupId);
await api.Groups.create('name', 'path', { description: '...' });
await api.Groups.edit(groupId, { name: 'new-name' });
await api.Groups.remove(groupId);
await api.Groups.allProjects(groupId);
await api.Groups.allSubgroups(groupId);
```

### Projects (Repositories in Yunxiao)

```typescript
await api.Projects.all();
await api.Projects.show(projectId);
await api.Projects.create({ name: 'my-project' });
await api.Projects.edit(projectId, { description: 'Updated' });
await api.Projects.remove(projectId);
await api.Projects.fork(projectId);
await api.Projects.star(projectId);
await api.Projects.unstar(projectId);
await api.Projects.archive(projectId);
await api.Projects.unarchive(projectId);
```

### Branches

```typescript
await api.Branches.all(projectId);
await api.Branches.show(projectId, 'main');
await api.Branches.create(projectId, 'new-branch', 'main');
await api.Branches.remove(projectId, 'old-branch');
await api.Branches.removeMerged(projectId);
```

### MergeRequests (ChangeRequests in Yunxiao)

```typescript
await api.MergeRequests.all();
await api.MergeRequests.all({ projectId, state: 'opened' });
await api.MergeRequests.show(projectId, mergeRequestIId);
await api.MergeRequests.create(projectId, 'source-branch', 'target-branch', 'Title', {
  description: 'Description',
  labels: ['feature'],
});
await api.MergeRequests.edit(projectId, mergeRequestIId, { title: 'New Title' });
await api.MergeRequests.accept(projectId, mergeRequestIId);
await api.MergeRequests.merge(projectId, mergeRequestIId);  // alias
await api.MergeRequests.rebase(projectId, mergeRequestIId);
await api.MergeRequests.allCommits(projectId, mergeRequestIId);
await api.MergeRequests.allDiffs(projectId, mergeRequestIId);
```

### Repositories

```typescript
await api.Repositories.allRepositoryTrees(projectId, { path: 'src', recursive: true });
await api.Repositories.compare(projectId, 'main', 'feature');
await api.Repositories.allContributors(projectId);
await api.Repositories.mergeBase(projectId, ['branch1', 'branch2']);
await api.Repositories.showBlob(projectId, 'sha');
await api.Repositories.showArchive(projectId, { format: 'zip' });
```

### Commits

```typescript
await api.Commits.all(projectId);
await api.Commits.show(projectId, 'sha');
await api.Commits.showDiff(projectId, 'sha');
```

### RepositoryFiles

```typescript
await api.RepositoryFiles.show(projectId, 'path/to/file.ts', 'main');
await api.RepositoryFiles.showRaw(projectId, 'path/to/file.ts', 'main');
await api.RepositoryFiles.allTree(projectId, { path: 'src' });
await api.RepositoryFiles.create(projectId, 'path/to/file.ts', 'main', 'content', 'Add file');
await api.RepositoryFiles.edit(projectId, 'path/to/file.ts', 'main', 'content', 'Update file');
await api.RepositoryFiles.remove(projectId, 'path/to/file.ts', 'main', 'Delete file');
await api.RepositoryFiles.showBlame(projectId, 'path/to/file.ts', { ref: 'main' });
```

### Keys (SSH Public Keys)

```typescript
// User SSH keys
await api.Keys.all();
await api.Keys.show(keyId);
await api.Keys.create('my-key', 'ssh-rsa AAAA...');
await api.Keys.remove(keyId);
```

### DeployKeys (Project Deploy Keys)

```typescript
await api.DeployKeys.all(projectId);
await api.DeployKeys.show(projectId, keyId);
await api.DeployKeys.create(projectId, 'deploy-key', 'ssh-rsa AAAA...', { canPush: true });
await api.DeployKeys.remove(projectId, keyId);
await api.DeployKeys.enable(projectId, keyId);
```

## Expanded Responses

Use `showExpanded: true` for metadata:

```typescript
const result = await api.Projects.all({ showExpanded: true });

console.log(result.data);    // The actual data
console.log(result.status);  // HTTP status code
console.log(result.headers); // Response headers
```

## Migrating from Gitbeaker

```typescript
// Before
import { Gitlab } from '@gitbeaker/rest';
const api = new Gitlab({ token: '...' });

// After
import { Yunxiao } from '@loom_project/codeup';
const api = new Yunxiao({ token: '...', organizationId: '...' });
```

All method calls remain the same!

## Key Differences from GitLab

| Aspect | GitLab | Yunxiao |
|--------|--------|---------|
| Auth header | `private-token` or `Bearer` | `x-yunxiao-token` |
| Organization | Optional namespace | Required `organizationId` |
| MergeRequest | Called "Merge Request" | Called "ChangeRequest" internally |
| API endpoint | `https://gitlab.com/api/v4` | `https://openapi-rdc.aliyuncs.com/oapi/v1` |

## License

MIT