npm package: @scoutflo/integration-sdk
Description: TypeScript SDK for third-party integrations with auth lifecycle management.
Author: Scoutflo
Latest version: 1.0.18

# Scoutflo Integration SDK

This project is a TypeScript SDK for managing third-party integrations and their authentication lifecycles, supporting multiple providers and authentication strategies.

## Project Structure

- `src/index.ts`: SDK entry point, exposes the `createSDK` function.
- `src/connection-manager.ts`: Core logic for managing and resolving connections.
- `src/providers/`: Provider-specific logic (e.g., `sentry.provider.ts`).
- `src/storage/`: Storage interface and implementations:
  - `mongodb.storage.ts`: MongoDB storage provider
  - `redis.storage.ts`: Redis storage provider
  - `storage.interface.ts`: Storage provider interface
- `src/strategies/`: Authentication strategies:
  - `api-key.strategy.ts`: API Key auth
  - `basic.strategy.ts`: Basic Auth
  - `mapped-credentials.strategy.ts`: provider-mapped static credential auth
  - `oauth.strategy.ts`: reusable OAuth app lifecycle core for provider adapters
- `src/providers/atlassian-oauth.adapter.ts`: Atlassian adapter over the shared OAuth core
- `src/providers/atlassian-oauth.helpers.ts`: Atlassian-specific helper functions for state, scope, cache-key, runtime, and sibling-token handling
- `src/types/`: Shared types and enums
- `usage/my-service.ts`: Example usage of the SDK in a service
- `package.json`: Project metadata, scripts, and dependencies
- `tsconfig.json`: TypeScript compiler configuration

## Setup and Installation

1. **Clone or create the project directory:**
    ```bash
    git clone <repo-url>
    cd scoutflo-integration-sdk
    ```

2. **Install dependencies:**
    ```bash
    npm install
    ```
    This will install TypeScript, Zod, and the example database drivers (MongoDB, Redis, Mongoose).

## Usage

1. **Ensure your MongoDB and/or Redis instances are running** if you are using the provided storage implementations.

2. **Build the project:**
    ```bash
    npm run build
    ```
    This will compile the TypeScript files into JavaScript in the `dist` directory.

3. **Use the SDK in your service:**
    See `usage/my-service.ts` for an example. A minimal example:
    ```typescript
    import { Model } from "mongoose";
    import { createSDK } from "../src";
    import { MongoDBStorage } from "../src/storage/mongodb.storage";
    import { Integration } from "../src/types";

    const model = new Model<Integration>();
    const storage = new MongoDBStorage(model);
    const sdk = createSDK(storage);

    // Create or resolve connections using sdk.createConnection and sdk.resolveConnection
    ```

### Atlassian Jira/Confluence lifecycle

The SDK now includes adapter-backed lifecycle support for Atlassian Jira, JSM, and Confluence.

Current architecture:

1. `OAuthStrategy` owns shared OAuth mechanics such as install URL shell assembly, code exchange, refresh exchange, cache lookup, lock handling, and token invalidation.
2. `AtlassianProvider` remains the public Atlassian facade and still owns the resolved runtime contract.
3. `AtlassianOAuthAdapter` owns Atlassian-specific callback and refresh orchestration.
4. `atlassian-oauth.helpers.ts` owns smaller Atlassian-specific helpers for scope lookup, state shaping, cache-key compatibility, runtime shaping, and sibling refresh-token synchronization.

What is supported:

1. install URL generation for Atlassian OAuth 3LO through the shared OAuth core
2. callback handling that returns a single selected-product integration payload
3. sibling Atlassian integration scope-union support when extending an existing site install
4. install context recovery through encoded OAuth `state` for sibling integration installs
5. Redis-backed short-lived access-token caching with TTL
6. refresh-token based access-token renewal with sibling Atlassian refresh-token synchronization
7. normalized Jira/JSM/Confluence resolved runtime output for caller services

Minimal shape:

```typescript
import Redis from "ioredis";
import { createSDK } from "../src";
import { MongoDBStorage } from "../src/storage/mongodb.storage";
import { RedisStorage } from "../src/storage/redis.storage";

const persistentStorage = new MongoDBStorage(model);
const cacheStorage = new RedisStorage(new Redis(process.env.REDIS_URL));

const sdk = createSDK(persistentStorage, {
  cacheStorage,
  atlassian: {
    clientId: process.env.ATLASSIAN_CLIENT_ID!,
    clientSecret: process.env.ATLASSIAN_CLIENT_SECRET!,
    redirectUri: process.env.ATLASSIAN_REDIRECT_URI!,
    identityResolver: async (userId) => {
      return {
        account_id: "account-id",
        created_by: userId,
      };
    },
  },
});

const install = await sdk.buildInstallUrl({ user_id: "user-123", account_id: "acct-123", provider: "jira" as const });
const callback = await sdk.handleInstallCallback({ code: "oauth-code", state: install.state, provider: "jira" as const });

await sdk.createConnection(callback.integration);

const jiraRuntime = await sdk.resolveConnection("jira-integration-id");
```

Atlassian install behavior in the current V1 flow:

- scope union lookup runs only for Atlassian sibling providers (`jira`, `confluence`, `jsm`)
- sibling scope lookup is account-scoped via `account_id`
- refresh-token rotation is synchronized across Atlassian sibling integrations for the same Scoutflo `account_id`
- non-Atlassian integrations do not trigger Atlassian scope lookup
- Redis token cache key format is `integration:{provider}:{integration_id}:app_user:{account_id}:access_token`
- Redis refresh lock key format is `integration:{provider}:{integration_id}:app_user:{account_id}:refresh_lock`
- `resolveConnection()` still returns the Atlassian-specific runtime shape from `AtlassianProvider`

IMPORTANT V1 NOTE:

- the SDK currently accepts `accessible-resources[0]` as the selected site after callback
- this is a deliberate temporary V1 product assumption to avoid adding UI/callback complexity right now
- this means whichever Atlassian resource appears first in callback processing is treated as the connected site and its `cloud_id` + `site_url` are persisted
- this must be revisited later because Atlassian can return multiple resources and array order should not be treated as a permanent correctness guarantee
- do not forget this limitation when expanding multi-site Atlassian flows later

Important notes:

1. `handleInstallCallback(...)` returns the selected Atlassian integration payload but does not persist it automatically.
2. `cacheStorage` is required when Atlassian lifecycle support is enabled.
3. access tokens are cached in Redis per integration, while refresh tokens remain in persistent integration storage.
4. when a site already has sibling Atlassian integrations, the SDK can extend requested scopes and synchronize rotated refresh tokens across those sibling Atlassian integrations.

## Customization

- **Storage:** Implement the `IStorageProvider` interface in `src/storage/storage.interface.ts` to connect to your actual data store (e.g., a specific MongoDB database, a different Redis configuration, or another technology).
- **Providers:** Add new provider logic in `src/providers/` and update the `ConnectionManager` to support them.
- **Authentication Strategies:** Add or modify strategies in `src/strategies/` for different authentication methods.
- **Types:** Extend or modify types in `src/types/` as needed for your integrations.

## Scripts

- `npm run build`: Compile TypeScript to JavaScript in `dist/`
- `npm publish`: Publish the package (private)

## Dependencies

- `typescript`, `zod`, `ioredis`, `mongodb`, `mongoose`, `redis`

---

For more details, see the code in the respective directories and the example in `usage/my-service.ts`.