Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
eebbf79
chore: add lint scripts to package.json for API and contracts
andrefelizardo Mar 2, 2026
3f8bc7f
chore: add commitlint job to CI workflow for linting commit messages
andrefelizardo Mar 2, 2026
7bf3396
chore: add pre-commit hook for linting with lint-staged
andrefelizardo Mar 2, 2026
793ea4e
chore: add commit-msg hook for linting commit messages with commitlint
andrefelizardo Mar 2, 2026
940fe00
chore: update package.json to include husky and lint-staged configura…
andrefelizardo Mar 2, 2026
834198e
chore: add commitlint configuration for standardized commit message l…
andrefelizardo Mar 2, 2026
cacf108
docs: update README to include Git hooks and conventional commits inf…
andrefelizardo Mar 2, 2026
af7f7e9
chore: enhance package.json with typecheck script and update lint-sta…
andrefelizardo Mar 2, 2026
067f1b0
chore: update package.json to replace lint script with eslint and add…
andrefelizardo Mar 2, 2026
c8eb46e
chore: add type-check step to CI workflow for TypeScript validation
andrefelizardo Mar 2, 2026
f696f5a
chore: add .eslintignore file to exclude build and coverage directori…
andrefelizardo Mar 2, 2026
28c3a67
chore: add ESLint configuration for TypeScript support and code quali…
andrefelizardo Mar 2, 2026
eb4fb5f
chore: add Prettier configuration for code formatting
andrefelizardo Mar 2, 2026
41a92ab
chore: add .prettierignore file to exclude build and coverage directo…
andrefelizardo Mar 2, 2026
eb94e42
docs: update README to include TypeScript type-checking command and e…
andrefelizardo Mar 2, 2026
5ef8abe
chore: update pnpm-lock.yaml to add and update dependencies for commi…
andrefelizardo Mar 2, 2026
49f5a07
chore: update ESLint to version 9.39.3 and add globals dependency in …
andrefelizardo Mar 2, 2026
19f9f56
chore: add flat ESLint configuration for TypeScript support in the AP…
andrefelizardo Mar 2, 2026
e830a50
Merge branch 'develop' into feat/SDK-85-pre-commit
andrefelizardo Mar 3, 2026
337e56a
chore: update pnpm-lock to upgrade ESLint to 9.39.3 and add globals d…
andrefelizardo Mar 3, 2026
8534234
chore: simplify commit-msg hook by removing unnecessary shell script …
andrefelizardo Mar 3, 2026
f348cf2
chore: remove unnecessary shell script lines from pre-commit hook
andrefelizardo Mar 3, 2026
6dd8d71
chore: add an empty changeset
andrefelizardo Mar 3, 2026
9351731
chore: add RequestInit and Response globals, disable no-namespace rul…
andrefelizardo Mar 3, 2026
d98318c
refactor: change type of metadat and provider_respons fields from 'an…
andrefelizardo Mar 3, 2026
c27eeef
refactor: remove unused import of ApiError from paymentService test file
andrefelizardo Mar 3, 2026
00f892b
fix(retryHandler): improve type safety for retryOnError function
andrefelizardo Mar 3, 2026
0c34780
fix(retryHandler): enhance type safety for retryOnError and onRetry f…
andrefelizardo Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/hip-bags-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
6 changes: 6 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dist/
coverage/
node_modules/
packages/**/dist/
packages/**/coverage/

29 changes: 29 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
parser: "@typescript-eslint/parser",
parserOptions: {
project: ["./packages/api/tsconfig.build.json"],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include test files in typed ESLint project

The ESLint config restricts parserOptions.project to packages/api/tsconfig.build.json, but that tsconfig excludes __tests__ while packages/api/package.json now lints __tests__/**/*.{ts,tsx}. Because plugin:@typescript-eslint/recommended-requiring-type-checking is enabled, ESLint will raise parsing errors for those test files not being in the configured TS project, so pnpm lint and the CI lint step will fail until tests are covered by a referenced tsconfig (or removed from the lint target).

Useful? React with 👍 / 👎.

tsconfigRootDir: __dirname,
sourceType: "module",
},
env: {
node: true,
es2022: true,
},
plugins: ["@typescript-eslint"],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"prettier",
],
ignorePatterns: [
"dist/",
"coverage/",
"node_modules/",
"packages/**/dist/",
"packages/**/coverage/",
],
};

29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,33 @@
branches: [main, develop]

jobs:
commitlint:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false

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

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

- name: Lint commit history with commitlint
run: pnpm commitlint --from origin/main --to HEAD

build-and-test:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
runs-on: ubuntu-latest

strategy:
Expand All @@ -34,6 +60,9 @@
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Type-check (tsc --noEmit)
run: pnpm typecheck

- name: Calculate next versions from changesets
run: pnpm changeset:status

Expand Down
2 changes: 2 additions & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pnpm commitlint --edit "$1"

2 changes: 2 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pnpm lint-staged

6 changes: 6 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dist/
coverage/
node_modules/
packages/**/dist/
packages/**/coverage/

130 changes: 96 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ CLIENT_SECRET=your-client-secret

Install `dotenv` to load these automatically: `pnpm add dotenv`, then add `import 'dotenv/config'` at the top of your entry file.

| Variable | Required | Description |
|---|---|---|
| `CLIENT_ID` | Yes | Your merchant client ID |
| `CLIENT_SECRET` | Yes | Your merchant client secret |
| Variable | Required | Description |
| --------------- | -------- | --------------------------- |
| `CLIENT_ID` | Yes | Your merchant client ID |
| `CLIENT_SECRET` | Yes | Your merchant client secret |

> Use different credentials for sandbox and production. Never commit `.env` files or log secrets.

Expand Down Expand Up @@ -75,18 +75,18 @@ if (result.ok) {

The SDK ships 10 service modules. Import the factory function for each service you need.

| Service | Factory | What it does |
|---|---|---|
| [Customers](https://www.oaknetwork.org/docs/sdk/api-sdk/customers) | `createCustomerService(client)` | Create, get, list, update, sync, and check balances |
| [Payments](https://www.oaknetwork.org/docs/sdk/api-sdk/payments) | `createPaymentService(client)` | Create, confirm, cancel payments |
| [Payment Methods](https://www.oaknetwork.org/docs/sdk/api-sdk/payment-methods) | `createPaymentMethodService(client)` | Add, list, get, delete payment methods |
| [Webhooks](https://www.oaknetwork.org/docs/sdk/api-sdk/webhooks) | `createWebhookService(client)` | Register, manage, and monitor webhooks |
| [Transactions](https://www.oaknetwork.org/docs/sdk/api-sdk/transactions) | `createTransactionService(client)` | List, get, and settle transactions |
| [Transfers](https://www.oaknetwork.org/docs/sdk/api-sdk/transfers) | `createTransferService(client)` | Create provider transfers (Stripe, PagarMe, BRLA) |
| [Plans](https://www.oaknetwork.org/docs/sdk/api-sdk/plans) | `createPlanService(client)` | CRUD subscription plans |
| [Refunds](https://www.oaknetwork.org/docs/sdk/api-sdk/refunds) | `createRefundService(client)` | Refund a payment (full or partial) |
| [Buy](https://www.oaknetwork.org/docs/sdk/api-sdk/buy-and-sell) | `createBuyService(client)` | Crypto on-ramp via Bridge |
| [Sell](https://www.oaknetwork.org/docs/sdk/api-sdk/buy-and-sell) | `createSellService(client)` | Crypto off-ramp via Avenia |
| Service | Factory | What it does |
| ------------------------------------------------------------------------------ | ------------------------------------ | --------------------------------------------------- |
| [Customers](https://www.oaknetwork.org/docs/sdk/api-sdk/customers) | `createCustomerService(client)` | Create, get, list, update, sync, and check balances |
| [Payments](https://www.oaknetwork.org/docs/sdk/api-sdk/payments) | `createPaymentService(client)` | Create, confirm, cancel payments |
| [Payment Methods](https://www.oaknetwork.org/docs/sdk/api-sdk/payment-methods) | `createPaymentMethodService(client)` | Add, list, get, delete payment methods |
| [Webhooks](https://www.oaknetwork.org/docs/sdk/api-sdk/webhooks) | `createWebhookService(client)` | Register, manage, and monitor webhooks |
| [Transactions](https://www.oaknetwork.org/docs/sdk/api-sdk/transactions) | `createTransactionService(client)` | List, get, and settle transactions |
| [Transfers](https://www.oaknetwork.org/docs/sdk/api-sdk/transfers) | `createTransferService(client)` | Create provider transfers (Stripe, PagarMe, BRLA) |
| [Plans](https://www.oaknetwork.org/docs/sdk/api-sdk/plans) | `createPlanService(client)` | CRUD subscription plans |
| [Refunds](https://www.oaknetwork.org/docs/sdk/api-sdk/refunds) | `createRefundService(client)` | Refund a payment (full or partial) |
| [Buy](https://www.oaknetwork.org/docs/sdk/api-sdk/buy-and-sell) | `createBuyService(client)` | Crypto on-ramp via Bridge |
| [Sell](https://www.oaknetwork.org/docs/sdk/api-sdk/buy-and-sell) | `createSellService(client)` | Crypto off-ramp via Avenia |

---

Expand Down Expand Up @@ -346,7 +346,10 @@ app.post('/webhooks/oak', express.raw({ type: 'application/json' }), (req, res)
Every method returns `Result<T, OakError>` — no uncaught exceptions. Check `result.ok` to branch on success or failure.

```typescript
const result = await customers.create({ email: 'user@example.com', first_name: 'John' });
const result = await customers.create({
email: 'user@example.com',
first_name: 'John',
});

if (result.ok) {
const customer = result.value.data;
Expand All @@ -358,12 +361,12 @@ if (result.ok) {
}
```

| Error type | Description |
|---|---|
| `ApiError` | HTTP errors from the API (4xx, 5xx) |
| `NetworkError` | Network failures, timeouts |
| `ParseError` | Invalid JSON responses |
| `AbortError` | Request aborted |
| Error type | Description |
| --------------------------- | ---------------------------------------- |
| `ApiError` | HTTP errors from the API (4xx, 5xx) |
| `NetworkError` | Network failures, timeouts |
| `ParseError` | Invalid JSON responses |
| `AbortError` | Request aborted |
| `EnvironmentViolationError` | Sandbox-only method called in production |

> Full error handling guide — [oaknetwork.org/docs/sdk/api-sdk/error-handling](https://www.oaknetwork.org/docs/sdk/api-sdk/error-handling)
Expand All @@ -374,10 +377,10 @@ if (result.ok) {

### Environments

| Environment | API Base URL | Description |
|---|---|---|
| `sandbox` | `https://api-stage.usecrowdpay.xyz` | Testing — all operations allowed |
| `production` | `https://app.usecrowdpay.xyz` | Live — test operations blocked |
| Environment | API Base URL | Description |
| ------------ | ----------------------------------- | -------------------------------- |
| `sandbox` | `https://api-stage.usecrowdpay.xyz` | Testing — all operations allowed |
| `production` | `https://app.usecrowdpay.xyz` | Live — test operations blocked |

```typescript
const client = createOakClient({
Expand Down Expand Up @@ -430,9 +433,10 @@ This project uses **pnpm** exclusively:

```bash
pnpm install # Install dependencies
pnpm build # Build all packages
pnpm test # Run tests
pnpm lint # Lint code
pnpm build # Build all packages
pnpm test # Run tests
pnpm lint # Lint code
pnpm typecheck # Run TypeScript type-checking in all workspaces
```

**Do not** use npm or yarn. The repository enforces pnpm >= 10.0.0.
Expand All @@ -450,10 +454,67 @@ pnpm test:watch # Watch mode

We use Changesets to manage versions and changelogs:

1. After making changes, run `pnpm changeset`
2. Select impact (Major / Minor / Patch) for affected packages
3. Commit the generated file in `.changeset/`
4. CI automatically calculates versions, generates changelogs, and creates a release PR
1. **After making changes**, run:

```bash
pnpm changeset
```

2. **Select impact** (Major/Minor/Patch) for affected packages

3. **Commit** the generated file in `.changeset/`

4. **CI automatically**:
- Calculates next versions
- Generates changelogs
- Creates release PR

### Git hooks & conventional commits

This repository uses Git hooks (via `husky`) and conventional commits (via `commitlint`) to keep history clean and enforce quality checks.

- **Pre-commit hook**:
- Runs `lint-staged` on staged files.
- For TypeScript/JavaScript files, runs ESLint with `--fix` and then Prettier with `--write` on the staged files only.
- Does **not** run `tsc --noEmit` locally, keeping commits fast while still auto-fixing issues.

- **Commit message hook**:
- Uses `commitlint` with `@commitlint/config-conventional` to enforce [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
- Example messages:
- `feat(api): add refunds service`
- `fix(ci): correct codecov token handling`
- `chore(release): prepare v0.2.0`

CI also runs:

- `commitlint` against the branch history to ensure all commits in a PR follow the convention, even if local hooks are bypassed.
- `pnpm typecheck` (TypeScript `tsc --noEmit` in workspaces) and `pnpm lint` (ESLint-based linting) as part of the main CI workflow.

### Running Tests

```bash
# Unit tests
pnpm test:unit

# Integration tests (requires credentials)
pnpm test:integration

# All tests with coverage
pnpm test:all

# Watch mode
pnpm test:watch
```

### Environment Variables for Testing

Create `.env` file in `packages/api`:

```env
CLIENT_ID=your_sandbox_client_id
CLIENT_SECRET=your_sandbox_client_secret
OAK_ENVIRONMENT=sandbox
```

### Code coverage

Expand All @@ -479,6 +540,7 @@ See [CLAUDE.md](./CLAUDE.md) for coding standards including architecture princip
- **Quickstart** — [oaknetwork.org/docs/sdk/api-sdk/quickstart](https://www.oaknetwork.org/docs/sdk/api-sdk/quickstart)
- **API package README** — [packages/api/README.md](./packages/api/README.md)
- **Changelog** — [CHANGELOG.md](./CHANGELOG.md)

---

## License
Expand Down
18 changes: 9 additions & 9 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

We actively maintain and provide security updates for the following versions of `@oaknetwork/api`:

| Version | Supported |
| ------- | ------------------ |
| 1.x | ✅ Active support |
| Version | Supported |
| ------- | ----------------- |
| 1.x | ✅ Active support |

## Reporting a Vulnerability

Expand All @@ -30,12 +30,12 @@ When reporting, please include as much detail as possible:

### What to Expect

| Timeline | Action |
| -------- | ------ |
| **Within 48 hours** | Acknowledgment of your report |
| **Within 7 days** | Initial severity assessment and triage |
| **Within 30 days** | A patch or mitigation plan for confirmed vulnerabilities |
| **Within 90 days** | Public disclosure (coordinated with reporter) |
| Timeline | Action |
| ------------------- | -------------------------------------------------------- |
| **Within 48 hours** | Acknowledgment of your report |
| **Within 7 days** | Initial severity assessment and triage |
| **Within 30 days** | A patch or mitigation plan for confirmed vulnerabilities |
| **Within 90 days** | Public disclosure (coordinated with reporter) |

We follow **coordinated vulnerability disclosure (CVD)** principles. We will keep you informed throughout the process and aim to resolve confirmed vulnerabilities within 30 days. For complex issues, we may request an extension and will communicate transparently about the timeline.

Expand Down
4 changes: 4 additions & 0 deletions commitlint.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
extends: ["@commitlint/config-conventional"],
};

70 changes: 70 additions & 0 deletions eslint.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Flat ESLint config for ESLint v9+
const eslintJs = require("@eslint/js");
const tseslint = require("@typescript-eslint/eslint-plugin");
const tsParser = require("@typescript-eslint/parser");
const eslintConfigPrettier = require("eslint-config-prettier");
const globals = require("globals");

/** @type {import("eslint").Linter.FlatConfig[]} */
module.exports = [
{
ignores: [
"dist/**",
"coverage/**",
"node_modules/**",
"packages/**/dist/**",
"packages/**/coverage/**",
],
},
{
files: ["packages/api/src/**/*.{ts,tsx}"],
languageOptions: {
parser: tsParser,
parserOptions: {
tsconfigRootDir: __dirname,
sourceType: "module",
},
ecmaVersion: 2022,
sourceType: "module",
globals: {
...globals.node,
RequestInit: "readonly",
Response: "readonly",
},
},
plugins: {
"@typescript-eslint": tseslint,
},
rules: {
...eslintJs.configs.recommended.rules,
...tseslint.configs.recommended.rules,
...eslintConfigPrettier.rules,
"@typescript-eslint/no-namespace": "off",
},
},
{
files: ["packages/api/__tests__/**/*.{ts,tsx}"],
languageOptions: {
parser: tsParser,
parserOptions: {
tsconfigRootDir: __dirname,
sourceType: "module",
},
ecmaVersion: 2022,
sourceType: "module",
globals: {
...globals.node,
...globals.jest,
},
},
plugins: {
"@typescript-eslint": tseslint,
},
rules: {
...eslintJs.configs.recommended.rules,
...tseslint.configs.recommended.rules,
...eslintConfigPrettier.rules,
},
},
];

Loading
Loading