splitwise
Version:
A TypeScript SDK for the Splitwise API.
191 lines • 8.31 kB
TypeScript
/**
* Splitwise SDK v2 client.
*
* Resource-namespaced client for the Splitwise API. Supports two OAuth flows
* (Client Credentials for app-owner access, Authorization Code + PKCE for
* end-user access), automatic retries, and zero runtime dependencies.
*
* @example
* ```typescript
* // Client Credentials (app owner's data)
* const sw = new Splitwise({ consumerKey: '...', consumerSecret: '...' });
* const expenses = await sw.expenses.list({ groupId: 123 });
*
* // Authorization Code with PKCE (end-user data)
* const auth = await Splitwise.createAuthorizationUrl({
* clientId: '...', redirectUri: 'http://localhost:3000/callback',
* });
* // ...redirect user to auth.url, capture `code` from callback...
* const sw = await Splitwise.fromAuthorizationCode({
* clientId: '...', clientSecret: '...',
* code, codeVerifier: auth.codeVerifier,
* redirectUri: 'http://localhost:3000/callback',
* });
* ```
*/
import type { AuthorizationUrlParams, AuthorizationUrlResult, ExchangeCodeParams, OAuthToken } from './auth/types.js';
import { type Hooks, type RequestOptions, type RequestOverrides } from './http.js';
import { Categories } from './resources/categories.js';
import { Comments } from './resources/comments.js';
import { Currencies } from './resources/currencies.js';
import { Expenses } from './resources/expenses.js';
import { Friends } from './resources/friends.js';
import { Groups } from './resources/groups.js';
import { Notifications } from './resources/notifications.js';
import { Users } from './resources/users.js';
import type { GetMainDataParams, Logger, LogLevel, ParseSentenceParams, ParseSentenceResponse } from './types.js';
/** Configuration accepted by the Splitwise constructor. */
export interface SplitwiseConfig {
/** OAuth consumer key. Required when accessToken is not provided. */
consumerKey?: string;
/** OAuth consumer secret. Required when accessToken is not provided. */
consumerSecret?: string;
/** Pre-obtained access token. If set, the client skips the OAuth flow. */
accessToken?: string;
/** Override the API base URL (useful for testing). */
baseUrl?: string;
/** Maximum automatic retries for transient failures. Default 2. */
maxRetries?: number;
/** Per-request timeout in ms. Default 30000. */
timeout?: number;
/** Inject a custom logger; the SDK never calls console.* directly. */
logger?: Logger;
/** Filter logs at or below this level. Default 'none'. */
logLevel?: LogLevel;
/** Inject a custom fetch (useful for testing). */
fetch?: typeof fetch;
/**
* Lifecycle hooks for observability (request/response/error). Hooks are
* called synchronously per attempt; thrown errors are caught and logged.
*/
hooks?: Hooks;
/**
* Identifies the calling application in the User-Agent header. Helps the
* Splitwise team trace requests back to a specific app/plugin if you need
* support; useful for telemetry on your own end too.
*/
appInfo?: AppInfo;
}
/** Identifies a calling application; concatenated into the User-Agent header. */
export interface AppInfo {
name: string;
version?: string;
url?: string;
}
export declare class Splitwise {
readonly expenses: Expenses;
readonly groups: Groups;
readonly users: Users;
readonly friends: Friends;
readonly comments: Comments;
readonly notifications: Notifications;
readonly currencies: Currencies;
readonly categories: Categories;
private readonly http;
private readonly config;
private readonly fetchImpl;
private cachedToken;
/**
* Holds an in-flight token fetch so concurrent first-call requests share a
* single network call instead of stampeding the OAuth endpoint.
*/
private inFlightTokenFetch;
/**
* Tracks where the active token came from. Determines what happens when
* `cachedToken` expires:
* - 'static' : the user passed `accessToken` directly; we
* have no way to refresh, just keep using it.
* - 'client_credentials' : we fetched it from the OAuth endpoint and
* can fetch another one.
* - 'authorization_code' : it came from fromAuthorizationCode(); there
* is no automatic refresh path (Splitwise
* doesn't issue refresh_tokens), so an
* expired token is a hard error.
*/
private readonly tokenSource;
constructor(config: SplitwiseConfig);
/**
* Returns identifying info about the authenticated client. Useful as a
* smoke test ("am I authenticated?") and for confirming which app/token
* the SDK is using.
*
* Despite the name, the endpoint is closer to a `whoami` than a generic
* health check.
*/
test(overrides?: RequestOverrides): Promise<{
clientId: number;
token: {
accessToken: string;
tokenType: string;
};
requestUrl: string;
params: Record<string, unknown>;
}>;
/**
* Parse a natural-language expense description (e.g. "I owe Bob $10").
*
* Unlike most endpoints, parse_sentence reports parse failures via the
* `valid` and `error` response fields rather than HTTP errors, so this
* method intentionally bypasses the SDK's "errors-in-body throw" check.
* Inspect `response.valid` and `response.error` after the call.
*/
parseSentence(params: ParseSentenceParams, overrides?: RequestOverrides): Promise<ParseSentenceResponse>;
/** Bulk fetch of user, groups, friends, currencies, categories, etc. */
getMainData(params?: GetMainDataParams, overrides?: RequestOverrides): Promise<unknown>;
/**
* Escape hatch for endpoints not (yet) covered by the typed resource API.
*
* Goes through the same pipeline as the typed methods (auth, retries,
* camelCase conversion, hooks, error mapping), so you don't lose those
* niceties — but you have to know the path/shape yourself.
*
* @example
* ```ts
* const result = await sw.rawRequest<MyShape>(
* 'GET',
* '/some_undocumented_endpoint',
* { query: { limit: 10 } },
* );
* ```
*/
rawRequest<T = unknown>(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, options?: RequestOptions): Promise<T>;
/**
* Returns a valid access token, fetching one via Client Credentials if
* necessary. Useful for callers who want to obtain a token once and persist
* it across process restarts (then pass it back as `accessToken`).
*
* Concurrent calls share a single in-flight fetch (no thundering herd).
*/
getAccessToken(): Promise<string>;
/**
* Generate an authorization URL for the OAuth Authorization Code + PKCE flow.
* Returns the URL plus the `state` and `codeVerifier` values your application
* must persist (e.g. in a session) to complete the exchange.
*/
static createAuthorizationUrl(params: AuthorizationUrlParams): Promise<AuthorizationUrlResult>;
/**
* Exchange an authorization code for an access token, then return a fully
* configured Splitwise client using that token.
*
* The full OAuthToken (including `expiresAt` and `refreshToken` if Splitwise
* provides them) is stored on the client; you can read it back via
* `sw.getOAuthToken()` to persist for later use.
*/
static fromAuthorizationCode(params: ExchangeCodeParams, config?: Omit<SplitwiseConfig, 'consumerKey' | 'consumerSecret' | 'accessToken'>): Promise<Splitwise>;
/**
* Returns the cached OAuthToken if one was obtained via Client Credentials
* or `fromAuthorizationCode`, or undefined if the client was constructed
* with a bare `accessToken` (no expiry metadata to share).
*
* Useful for persisting the token across process restarts:
*
* ```ts
* const token = sw.getOAuthToken();
* if (token !== undefined) {
* await persist(token); // store accessToken + expiresAt + refreshToken
* }
* ```
*/
getOAuthToken(): OAuthToken | undefined;
}
//# sourceMappingURL=client.d.ts.map