# Foundations TS Definitions

[![npm version](https://img.shields.io/npm/v/@reapit/foundations-ts-definitions.svg)](https://www.npmjs.com/package/@reapit/foundations-ts-definitions)
[![license](https://img.shields.io/npm/l/@reapit/foundations-ts-definitions.svg)](./package.json)

Auto-generated TypeScript type definitions for the Reapit Foundations API Platform.

This package scrapes the Swagger/OpenAPI documents published by the Foundations
platform APIs on a weekly schedule, converts them to TypeScript `.d.ts`
interfaces, and publishes the result to npm as
[`@reapit/foundations-ts-definitions`](https://www.npmjs.com/package/@reapit/foundations-ts-definitions).

For higher-level documentation see the
[Foundations documentation site](https://foundations-documentation.reapit.cloud/app-development/foundations-ts-defintions).

---

## Table of contents

- [Foundations TS Definitions](#foundations-ts-definitions)
  - [Table of contents](#table-of-contents)
  - [Installation](#installation)
  - [Usage](#usage)
  - [What's in the package](#whats-in-the-package)
  - [How it works](#how-it-works)
    - [Source endpoints](#source-endpoints)
    - [Authentication](#authentication)
    - [Reapit APP Setup](#reapit-app-setup)
    - [Fetch sequence](#fetch-sequence)
  - [Build pipeline](#build-pipeline)
  - [GitHub workflows](#github-workflows)
  - [Local development](#local-development)
    - [Testing authentication locally](#testing-authentication-locally)
    - [Project layout](#project-layout)
  - [Release process](#release-process)
  - [License](#license)

---

## Installation

```bash
yarn add @reapit/foundations-ts-definitions
# or
npm install @reapit/foundations-ts-definitions
```

## Usage

All generated namespaces and hand-written schemas are re-exported from the
package root:

```ts
import type {
  Platform,
  Marketplace,
  Payments,
  Organisations,
} from '@reapit/foundations-ts-definitions'

type Contact = Platform.ContactModel
```

The package ships both CommonJS (`dist/index.js`) and ES module
(`dist/index.mjs`) builds, plus a bundled `dist/index.d.ts`.

## What's in the package

The exported surface is a union of:

| Source | Origin | Location |
| --- | --- | --- |
| `Platform` namespace | Fetched from Foundations swagger | [src/types/platform-schema.ts](src/types/platform-schema.ts) (generated) |
| `Marketplace` namespace | Fetched from Marketplace swagger | [src/types/marketplace-schema.ts](src/types/marketplace-schema.ts) (generated) |
| `Payments` namespace | Fetched from Payments swagger | [src/types/payments-schema.ts](src/types/payments-schema.ts) (generated) |
| `Organisations` namespace | Fetched from Organisations swagger | [src/types/organisations-schema.ts](src/types/organisations-schema.ts) (generated) |
| Traffic event schema | Hand-written | [src/traffic-schema/marketplace-traffic-event-schema.ts](src/traffic-schema/marketplace-traffic-event-schema.ts) |
| Deployment schema | Hand-written | [src/deployment-schema/index.ts](src/deployment-schema/index.ts) |
| API key schema | Hand-written | [src/api-key-schema/index.ts](src/api-key-schema/index.ts) |
| Marketplace CMS schema | Hand-written | [src/marketplace-cms/index.ts](src/marketplace-cms/index.ts) |
| Webhook schema | Hand-written | [src/webhook-schema/index.ts](src/webhook-schema/index.ts) |

Generated files under `src/types/` are regenerated on every scheduled run;
hand-written schemas are committed and maintained by contributors.

## How it works

At a high level, a cron job runs the fetch script, which pulls Swagger JSON
from each platform API, converts it to TypeScript via
[`sw2dts`](https://www.npmjs.com/package/sw2dts), formats the output with
Prettier and writes one file per namespace into `src/types/`. An aggregated
barrel `index.ts` is then written that re-exports everything (generated +
hand-written) so the whole package compiles as a single entry.

```mermaid
flowchart LR
    subgraph Remote["Foundations Platform APIs"]
        A1[Platform swagger]
        A2[Marketplace swagger]
        A3[Payments swagger]
        A4[Organisations swagger]
    end

    subgraph Fetch["src/scripts/fetch-definitions.js"]
        B1[fetch JSON]
        B2[sw2dts convert]
        B3[prettier format]
        B4[write .ts file]
    end

    subgraph Repo["src/"]
        C1[(types/*.ts generated)]
        C2[(index.ts barrel)]
        C3[hand-written schemas]
    end

    A1 & A2 & A3 & A4 --> B1 --> B2 --> B3 --> B4 --> C1
    C3 --> C2
    C1 --> C2
    C2 --> D[tsup build]
    D --> E[(dist/ cjs + esm + dts)]
    E --> F((npm: @reapit/foundations-ts-definitions))
```

### Source endpoints

The fetcher is configured in
[src/scripts/fetch-definitions.js](src/scripts/fetch-definitions.js):

| Namespace | Endpoint |
| --- | --- |
| `Platform` | `https://reapit-swagger-dev.s3.eu-west-2.amazonaws.com/foundations_swagger.json` (S3 fallback while the `/docs` endpoint is down) |
| `Marketplace` | `${PLATFORM_API_BASE_URL}/marketplace/swagger/v1.0/swagger.json` |
| `Payments` | `${PLATFORM_API_BASE_URL}/payments/swagger/latest/swagger.json` |
| `Organisations` | `${PLATFORM_API_BASE_URL}/organisations/swagger/v1.0/swagger.json` |

`PLATFORM_API_BASE_URL` is defined in
[src/scripts/constants.js](src/scripts/constants.js) and currently points at
`https://platform.dev.paas.reapit.cloud`.

### Authentication

Some platform-hosted swagger endpoints require a Bearer token. The fetch script
obtains one automatically via the OAuth2 `client_credentials` grant against the
Reapit Connect token endpoint before fetching definitions.

| Variable | Purpose |
| --- | --- |
| `CONNECT_CLIENT_ID` | OAuth2 client ID for the Connect token endpoint |
| `CONNECT_CLIENT_SECRET` | OAuth2 client secret |

These are stored as **GitHub repository secrets** and injected by the
`definitions-update.yml` workflow.

**Local development:** If neither variable is set, the script logs a warning and
falls back to unauthenticated requests. This is fine for endpoints that don't
require auth (e.g. the Platform S3 swagger), but authenticated endpoints will
fail. To test locally with auth, export the variables in your shell:

```bash
CONNECT_CLIENT_ID=xxx CONNECT_CLIENT_SECRET=yyy yarn start
```

### Reapit APP Setup
`reapit-ltd-foundations-ts-definition-party-time` is the name of the app that used from https://developers.dev.paas.reapit.cloud with the CONNECT_CLIENT_ID and CONNECT_CLIENT_SECRET variables.


### Fetch sequence

```mermaid
sequenceDiagram
    participant Cron as GitHub Actions cron
    participant Script as fetch-definitions.js
    participant API as Platform Swagger endpoint
    participant FS as src/types/
    participant PR as peter-evans/create-pull-request

    Cron->>Script: yarn start
    Script->>FS: rimraf + mkdir src/types
    loop For each schema
        Script->>API: GET swagger.json
        API-->>Script: OpenAPI document
        Script->>Script: sw2dts.convert(namespace)
        Script->>Script: prettier format
        Script->>FS: append export to <ns>-schema.ts
    end
    Script->>FS: write index.ts barrel
    Cron->>PR: open "chore: Update TS Definitions" PR
```

## Build pipeline

Bundling is handled by [tsup](https://tsup.egoist.dev/) - see
[tsup.config.ts](tsup.config.ts):

- Entry: `src/index.ts`
- Formats: `cjs` + `esm`
- Target: `node18`
- `clean: true`, `minify: true`, `dts: true`

`yarn build` produces:

```
dist/
├── index.js     # CommonJS
├── index.mjs    # ESM
└── index.d.ts   # Bundled types
```

Only the `dist/` folder is published to npm (see `files` in
[package.json](package.json)).

## GitHub workflows

Under [.github/workflows](.github/workflows):

```mermaid
flowchart TD
    PR[Pull Request opened/synchronized] --> BuildPR[build-pr.yml: yarn build]
    PR --> CheckPR[check-pr.yml: yarn typecheck]
    PR --> LintPR[lint-pr.yml / pr-lint.yml]

    Cron{{Monday 00:00 UTC cron}} --> Update[definitions-update.yml]
    Update --> Fetch[yarn start - regenerate types]
    Fetch --> OpenPR[create-pull-request action]
    OpenPR --> PR

    Merge[Release published on GitHub] --> Release[release-prod.yml]
    Release --> Publish[npm publish --tag latest]

    Delete[Release deleted on GitHub] --> Rollback[rollback-prod.yml]
    Rollback --> Retag[npm tag latest -> previous version]
```

| Workflow | Trigger | Purpose |
| --- | --- | --- |
| [build-pr.yml](.github/workflows/build-pr.yml) | PR opened/synchronized | `yarn build` |
| [check-pr.yml](.github/workflows/check-pr.yml) | PR opened/synchronized | `yarn typecheck` |
| [lint-pr.yml](.github/workflows/lint-pr.yml), [pr-lint.yml](.github/workflows/pr-lint.yml) | PR opened/synchronized | Lint checks |
| [definitions-update.yml](.github/workflows/definitions-update.yml) | Cron `0 0 * * 1` | Re-fetch swagger, open PR with regenerated types |
| [release-prod.yml](.github/workflows/release-prod.yml) | GitHub Release `published` | Build and `npm publish --tag latest` |
| [rollback-prod.yml](.github/workflows/rollback-prod.yml) | GitHub Release `deleted` | Repoint `latest` npm dist-tag to previous version |

All jobs run on the self-hosted runner group `rpt-gbl-linux-x64` with Node 22.

## Local development

Requirements: Node 22+, Yarn 4 (Berry - pinned via `packageManager` in
[package.json](package.json)).

```bash
# Install deps
yarn

# Regenerate types from upstream swagger (writes src/types/*.ts)
yarn start

# Typecheck without emitting
yarn typecheck

# Build the package into dist/
yarn build

# Lint
yarn lint

# Test auth and probe swagger endpoints
yarn test:auth
```

> `yarn start` hits live Reapit platform endpoints. Any changes in the upstream
> swagger will appear as diffs under `src/types/`.

### Testing authentication locally

A diagnostic script is provided to verify credentials and endpoint availability
without running the full fetch pipeline:

```bash
yarn test:auth
```

The script runs four steps:

1. **Env var check** — verifies `CONNECT_CLIENT_ID` and `CONNECT_CLIENT_SECRET` are set
2. **OAuth2 token** — attempts `client_credentials` auth against Connect; auto-retries with `application/x-www-form-urlencoded` if JSON fails
3. **Authenticated endpoints** — probes all three authenticated swagger endpoints (Marketplace, Payments, Organisations)
4. **Unauthenticated endpoint** — probes the Platform S3 fallback swagger

Successful swagger responses are saved to `./tempSwaggers/` for local inspection (this directory is git-ignored).

Credentials can be provided via a `.env` file in the project root:

```env
CONNECT_CLIENT_ID=your_client_id
CONNECT_CLIENT_SECRET=your_client_secret
```

The script loads `.env` automatically — no extra dependencies required.

### Project layout

```
src/
├── index.ts                        # Public entry, re-exports everything
├── api-key-schema/                 # Hand-written
├── deployment-schema/              # Hand-written
├── marketplace-cms/                # Hand-written
├── traffic-schema/                 # Hand-written
├── webhook-schema/                 # Hand-written
├── types/                          # GENERATED - do not edit by hand
│   ├── index.ts
│   ├── platform-schema.ts
│   ├── marketplace-schema.ts
│   ├── payments-schema.ts
│   └── organisations-schema.ts
└── scripts/                        # Node scripts used by `yarn start`
    ├── constants.js
    ├── fetch-definitions.js
    ├── create-index-file.js
    ├── format-code.js
    ├── handle-cronjob.js
    └── ...
```

## Release process

1. The weekly cron job opens a `chore: Update TS Definitions` PR if the
   generated types have changed.
2. A human reviews and merges the PR.
3. A maintainer cuts a GitHub Release (semver tag).
4. `release-prod.yml` fires, builds the package and publishes to npm under the
   `latest` dist-tag.
5. If a release is ever deleted, `rollback-prod.yml` re-points `latest` to the
   previous tagged version on npm.

## License

MIT - see [package.json](package.json).
