UNPKG

@unito/integration-sdk

Version:

Integration SDK

81 lines (58 loc) 5.11 kB
# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## What This Is `@unito/integration-sdk` — a TypeScript framework for building REST API integrations compatible with the Unito Integration API Specification. It wraps Express 5 and provides handler routing, middleware chains for request parsing, structured logging, a Provider HTTP client for downstream APIs, and standardized error handling. ## Commands ```bash npm install # Install deps (also runs compile via prepare hook) npm run compile # Build ESM (tsc), copy non-TS assets, then CJS (rollup) npm run compile:watch # Watch mode recompile npm test # Run all tests ONLY=Handler npm test # Run tests matching pattern "Handler" npm run test:debug # Run tests with --inspect-brk npm run lint # ESLint --fix + Prettier --write on src/ and test/ ``` Tests use **Node.js built-in test runner** (`node:test` + `node:assert/strict`) with `ts-node/esm` loader — no compilation needed to run tests. HTTP mocking uses `nock`. ## Architecture ### Request Flow ``` HTTP Request → finish (error/log hooks on response end) → express.json (1MB limit) → start (records hrtime) → correlationId (generates/extracts X-Correlation-Id) → logger (structured logger decorated with correlation ID) → credentials (decodes base64 JSON from X-Unito-Credentials header) → secrets (decodes base64 JSON from X-Unito-Secrets header) → filters / search / selects / relations (parse query params) → signal (AbortSignal from X-Unito-Operation-Deadline timestamp) → Handler routes (user-registered) → errors middleware (catches, formats HttpError responses) → notFound middleware (404 fallback) ``` ### Core Classes **Integration** (`src/integration.ts`) — entry point. Call `addHandler(path, handlers)` to register routes, then `start()`. All handlers must be added before `start()` — the server exits on violation. **Handler** (`src/handler.ts`) — takes a path and a handlers object, generates an Express Router. Path determines routing: - `/things/:thingId` — last segment is `:variable` → item route. `getItem` at `GET /things/:thingId`, `getCollection` at `GET /things`, `createItem` at `POST /things`, etc. - `/things` — no trailing variable → either item-level or collection-level ops, but not both on the same path. Handler types (pick one per `addHandler` call): - `ItemHandlers` — getItem, getCollection, createItem, updateItem, deleteItem - `BlobHandlers` — getBlob, createBlob - `CredentialAccountHandlers` — getCredentialAccount - `ParseWebhookHandlers`, `WebhookSubscriptionHandlers`, `AcknowledgeWebhookHandlers` **Provider** (`src/resources/provider.ts`) — HTTP client for calling downstream provider APIs. Initialized with `prepareRequest` (returns base URL + auth headers), optional `rateLimiter`, and optional `customErrorHandler`. Methods: `get`, `post`, `put`, `patch`, `delete`, `streamingGet`, `postForm`, `postStream`, `putBuffer`. **Context** (`src/resources/context.ts`) — typed context object passed to every handler. Contains `credentials`, `secrets`, `logger`, `signal`, `params`, `query`. GetCollectionContext additionally has `filters`, `search`, `selects`, `relations`. Create/Update contexts have `body`. **HttpErrors** (`src/httpErrors.ts`) — throw these from handlers for proper error responses. BadRequestError(400), UnauthorizedError(401), ForbiddenError(403), NotFoundError(404), TimeoutError(408), UnprocessableEntityError(422), ProviderInstanceLockedError(423), RateLimitExceededError(429). The latter two support `retryAfter`. ### Logging Logger (`src/resources/logger.ts`) produces Datadog-compatible structured JSON in production, colored output in dev. Keys are auto-converted to snake_case. Sensitive fields (access_token, password, email, etc.) are auto-redacted. Log size truncated at 20KB (configurable via `MAX_LOG_MESSAGE_SIZE` env var). ### Cache `Cache.create(redisUrl?)` returns a Redis-backed or local in-memory cache via the `cachette` library. ## Code Conventions - **ES Modules**`"type": "module"` in package.json. All internal imports use `.js` extensions (`import X from './foo.js'`). - **Dual output** — ESM via `tsc`, CJS via Rollup. Published with conditional exports. - **Strict TypeScript** — strict mode, noUncheckedIndexedAccess, exactOptionalPropertyTypes, no unused locals/params. - **Branded types** — e.g. `type Path = string & { __brand: 'Path' }` with assertion functions (`asserts path is Path`). - **No barrel files** — import directly from source modules, not from index re-exports. - **Prettier** — single quotes, trailing commas, 120 char width, no parens on single-param arrows. - **Test files**`test/**/*.test.ts` mirroring src structure. Use `describe`/`it`/`beforeEach`/`afterEach` from `node:test`, assertions from `node:assert/strict`, mocking with `mock.method()`. - **Express typing**`res.locals` is typed via global Express namespace augmentation.