Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
11 changes: 11 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.1/schema.json",
"changelog": ["@changesets/cli/changelog", { "repo": "nexla/nexla-sdk" }],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
5 changes: 5 additions & 0 deletions .changeset/wise-lions-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nexla/sdk": major
---

Promote the TypeScript SDK to production-ready GA with OpenAPI coverage gates, spec metadata validation, and parity/migration documentation.
47 changes: 47 additions & 0 deletions .github/workflows/ci-ts-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI (TypeScript SDK Integration)

on:
workflow_dispatch:
schedule:
- cron: "0 9 * * 1"
pull_request:
branches: [ main ]
paths:
- "packages/ts-sdk/**"
- "plugin-redoc-0.yaml"
- "pnpm-workspace.yaml"
- "package.json"
- "pnpm-lock.yaml"
- ".github/workflows/ci-ts-integration.yml"

jobs:
integration:
if: ${{ secrets.NEXLA_SERVICE_KEY != '' || secrets.NEXLA_ACCESS_TOKEN != '' }}
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Generate SDK artifacts
run: pnpm -C packages/ts-sdk gen

- name: Run integration tests
run: pnpm -C packages/ts-sdk test:integration
env:
NEXLA_SERVICE_KEY: ${{ secrets.NEXLA_SERVICE_KEY }}
NEXLA_ACCESS_TOKEN: ${{ secrets.NEXLA_ACCESS_TOKEN }}
NEXLA_API_URL: ${{ vars.NEXLA_API_URL }}
63 changes: 63 additions & 0 deletions .github/workflows/ci-ts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: CI (TypeScript SDK)

on:
push:
branches: [ main ]
paths:
- "packages/ts-sdk/**"
- "plugin-redoc-0.yaml"
- "pnpm-workspace.yaml"
- "package.json"
- "pnpm-lock.yaml"
- "turbo.json"
- ".github/workflows/ci-ts.yml"
pull_request:
branches: [ main ]
paths:
- "packages/ts-sdk/**"
- "plugin-redoc-0.yaml"
- "pnpm-workspace.yaml"
- "package.json"
- "pnpm-lock.yaml"
- "turbo.json"
- ".github/workflows/ci-ts.yml"

jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Validate generated coverage and spec metadata
run: pnpm -C packages/ts-sdk check:generated

- name: Generate SDK artifacts
run: |
pnpm -C packages/ts-sdk gen
git diff --exit-code

- name: Lint
run: pnpm -C packages/ts-sdk lint

- name: Typecheck
run: pnpm -C packages/ts-sdk typecheck

- name: Test
run: pnpm -C packages/ts-sdk coverage

- name: Build
run: pnpm -C packages/ts-sdk build
23 changes: 22 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,26 @@ name: CI
on:
push:
branches: [ main ]
paths:
- "nexla_sdk/**"
- "scripts/**"
- "tests/**"
- "pyproject.toml"
- "requirements.txt"
- "pytest.ini"
- "README.md"
- ".github/workflows/ci.yml"
pull_request:
branches: [ main ]
paths:
- "nexla_sdk/**"
- "scripts/**"
- "tests/**"
- "pyproject.toml"
- "requirements.txt"
- "pytest.ini"
- "README.md"
- ".github/workflows/ci.yml"

jobs:
build-test:
Expand All @@ -30,9 +48,12 @@ jobs:
pip install ruff
ruff check nexla_sdk

- name: Check Generated Operation Map Sync
run: |
python scripts/parity/check_operation_map_sync.py

- name: Run unit tests
env:
PYTHONWARNINGS: default
run: |
pytest -m unit --maxfail=1 -q

12 changes: 12 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,20 @@ on:
push:
branches: [ main ]
tags: [ 'v*' ]
paths:
- "docs-site/**"
- "docs/**"
- "nexla_sdk/**"
- "README.md"
- ".github/workflows/docs.yml"
pull_request:
branches: [ main ]
paths:
- "docs-site/**"
- "docs/**"
- "nexla_sdk/**"
- "README.md"
- ".github/workflows/docs.yml"

permissions:
contents: read
Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/release-ts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Release TypeScript SDK

on:
push:
branches: [ main ]
paths:
- "packages/ts-sdk/**"
- ".changeset/**"
- "pnpm-workspace.yaml"
- "package.json"
- "pnpm-lock.yaml"
- ".github/workflows/release-ts.yml"

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Create release PR or publish
uses: changesets/action@v1
with:
publish: pnpm release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,6 @@ create_flow_sample/
.claude/
.direnv/
.envrc

# Parity artifacts generated from local backend/spec analysis
artifacts/parity/*.json
52 changes: 51 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

A Python SDK for interacting with the Nexla API.

## TypeScript SDK (New)

This repository now includes a production-ready TypeScript SDK in `packages/ts-sdk`.

### Install

```bash
npm install @nexla/sdk
```

### Quick Start

```ts
import { NexlaClient } from "@nexla/sdk";

const client = new NexlaClient({ serviceKey: process.env.NEXLA_SERVICE_KEY });
const flows = await client.request("get", "/flows");
```

## Installation

```bash
Expand Down Expand Up @@ -576,6 +595,25 @@ doc_audit = client.doc_containers.get_audit_log(doc_container_id=1001)
schema_audit = client.data_schemas.get_audit_log(schema_id=5001)
```

### Raw Operation-Level Access

```python
# List available OpenAPI operation ids
ops = client.raw.list_operations()

# Call by operation id with typed path/query/body slots
project_flows = client.raw.call(
"get_project_flows",
path_params={"project_id": 123},
)

# Direct raw HTTP helpers are also available
limits = client.raw.get("/limits")

# Backend-only or non-spec route access
approved = client.raw.request("POST", "/self_signup_requests/42/approve")
```

## Coverage Matrix

Mapping of major OpenAPI areas to SDK resources. All requests set `Accept: application/vnd.nexla.api.v1+json` and default base URL `https://dataops.nexla.io/nexla-api`.
Expand Down Expand Up @@ -605,7 +643,8 @@ Mapping of major OpenAPI areas to SDK resources. All requests set `Accept: appli
- GenAI Configurations/Org Settings: `client.genai` — configs CRUD; org settings CRUD; active_config
- Doc Containers: `client.doc_containers` — audit_log; (access control via BaseResource helpers)
- Data Schemas: `client.data_schemas` — audit_log; (access control via BaseResource helpers)
- Webhooks: not included as a dedicated helper yet (use direct HTTP with API key per spec)
- Webhooks: `client.create_webhook_client(api_key=...)` for API-key authenticated webhook sends
- Full OpenAPI operation-level access: `client.raw.call(operation_id, ...)`

## Error Handling

Expand Down Expand Up @@ -682,6 +721,17 @@ export NEXLA_API_URL="https://your-nexla-instance.com/nexla-api"
pytest tests/integration/
```

### Parity Tooling

```bash
# Generate operation map for client.raw
python scripts/parity/generate_operation_map.py

# Build OpenAPI/admin-routes/SDK parity matrices
python scripts/parity/build_matrices.py \
--admin-routes /Users/sakshammittal/Documents/GitHub/admin-api/config/routes.rb
```

### Setting Up Environment

```bash
Expand Down
70 changes: 70 additions & 0 deletions docs/ts-sdk/api-coverage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# TypeScript SDK API Coverage Process

## Coverage Dimensions

The TS SDK tracks coverage in two dimensions:

- **OpenAPI operation coverage:** whether every API `operationId` is available through generated TS resource methods.
- **Python-to-TS surface parity:** whether Python `client.<resource>` surfaces exist as first-class TS resource clients.

Operation coverage can be high while resource parity is still incomplete; these are tracked separately by design.

## Source of Truth

- OpenAPI spec: `plugin-redoc-0.yaml`
- Generated TS schema: `packages/ts-sdk/src/generated/schema.ts`
- Generated TS resources: `packages/ts-sdk/src/resources/generated/*.ts`
- Python resource surface: `nexla_sdk/client.py`
- Generated parity report: `docs/ts-sdk/parity-matrix.md`

## Refresh Workflow

Run this from repository root whenever API surface changes:

```bash
pnpm -C packages/ts-sdk gen
node packages/ts-sdk/scripts/generate-parity-matrix.mjs
pnpm -C packages/ts-sdk lint
pnpm -C packages/ts-sdk typecheck
pnpm -C packages/ts-sdk coverage
```

What this does:

1. Regenerates all TS OpenAPI artifacts.
2. Recomputes Python->TS parity and operation coverage matrix.
3. Verifies SDK quality gates still pass.

## CI Expectations

`ci-ts.yml` already enforces generated artifact consistency (`pnpm -C packages/ts-sdk gen` + clean git diff) and blocks merges if generated files are stale.

The parity matrix file is documentation output and should be refreshed in the same PR when parity or coverage changes.

## Interpreting `parity-matrix.md`

- **Python resource parity %**: how many Python resource surfaces currently have first-class TS resource clients.
- **Session operationId coverage %**: how many spec operationIds are generated into TS resource clients.
- **TS-only resources**: TS resource clients that do not yet exist as Python first-class resource properties.

## Gap Handling Policy

If a Python resource is not yet available as a generated TS resource client:

- Use `client.raw` as a typed fallback for path-level access.
- Keep migration docs updated with guidance for that resource.
- Track progress by refreshing `docs/ts-sdk/parity-matrix.md`.

## PR Checklist (Coverage-Sensitive Changes)

1. Regenerate TS artifacts (`pnpm -C packages/ts-sdk gen`).
2. Refresh parity matrix (`node packages/ts-sdk/scripts/generate-parity-matrix.mjs`).
3. Run lint/typecheck/tests for TS SDK.
4. Update `docs/ts-sdk/migration-guide.md` if Python->TS mapping changed.
5. Include generated doc diffs (`docs/ts-sdk/parity-matrix.md`) in the PR.

## Related Docs

- [Architecture](./architecture.md)
- [Migration guide](./migration-guide.md)
- [Integration testing (non-blocking guidance)](./integration-tests.md)
Loading
Loading