npm.io
1.0.38 • Published 2d ago

@scoutflo/integration-sdk

Licence
MIT
Version
1.0.38
Deps
6
Size
259 kB
Vulns
0
Weekly
520

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:

    git clone <repo-url>
    cd scoutflo-integration-sdk
  2. Install dependencies:

    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:

    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:

    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:

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:

  • callback now fails fast when Atlassian returns multiple accessible resources.
  • SDK throws atlassian_site_selection_required and does not silently choose accessible-resources[0].
  • product warning: Atlassian multi-site selection UX/API is still pending and must be implemented before broader rollout.
  • backlog item (mandatory): add explicit site-selection contract and persistence rules for multi-site callbacks.

OAuth callback-state security deferral (explicit):

  • accepted risk: callback state is used for context recovery, but it is not yet a signed, replay-protected integrity boundary.
  • do not treat as secure CSRF-grade state yet.
  • why deferred: V1 prioritized lifecycle migration and blast-radius control across SDK, Gateway, and Voyager.
  • owner: Platform Integrations (SDK + Gateway joint ownership)
  • target version/date: SDK 2.0.0 by April 30, 2026
  • mandatory V2 work: signed + replay-resistant state integrity, deterministic reject semantics, and negative tests for tampered/replayed/mismatched callback state.

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.

Versioning Rule (Documented Policy)

Current decision:

  • keep current semver line for this controlled rollout (no immediate major bump required right now).

Before wider/shared adoption:

  • either bump major to 2.0.0, or
  • make the interface fully backward-compatible and document that compatibility explicitly.

Do not widen adoption without one of the two conditions above being completed.

Rollout Checks Before Preprod/Prod

Run and capture evidence for all three paths before promoting:

  1. Slack install/callback path:
    • npm run test:slack-lifecycle
  2. Slack token refresh path:
    • npm run trace:slack-requested-flow
  3. Atlassian install/callback happy path (current assumptions):
    • npm run test:atlassian-lifecycle

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.

Keywords