Getting Started
Core Architecture
Link Engine
Analytics & Attribution
Partners & Affiliates
Third-Party Integrations
Identity & Security
Automation & Messaging
Developer Tools
The following files were used as context for generating this wiki page:
The Dub CLI tool (dub) is a command-line interface designed to streamline URL shortening and link management directly from the terminal using the Dub API. It serves developers and platform users by offering native command execution, persistent local configuration storage, and secure authentication workflows that mirror core web capabilities without requiring a browser interface. Sources: packages/cli/src/index.ts:17-19, packages/cli/package.json:2-4
The executable bootstrapping process initializes the dub command-line application, configuring signal handlers, loading package metadata, registering root command modules via commander, and executing argument parsing.
Sources: packages/cli/src/index.ts:11-34
The entry point script packages/cli/src/index.ts begins with the Node.js environment hashbang #!/usr/bin/env node and registers global listeners for SIGINT and SIGTERM signals to ensure clean process termination via process.exit(0).
Sources: packages/cli/src/index.ts:1-12
The asynchronous main() function drives the root setup sequence:
getPackageInfo() is called to fetch remote package metadata for dub-cli.Command instance is initialized with .name("dub"), .description("A CLI for shortening links with the Dub API."), and .version(packageInfo.version || "1.0.0", "-v, --version", "display the version number")..addCommand() for login, config, domains, shorten, and links.program.parse() executes command resolution and argument evaluation.Note
getPackageInfo() retrieves metadata dynamically by querying package-json for "dub-cli", falling back to "1.0.0" if the version field is undefined.
Sources: packages/cli/src/index.ts:3-31
The package utilizes tsup for building the CLI bundle as defined in packages/cli/tsup.config.ts. The configuration specifies ECMAScript module output format (esm), target environment esnext, source maps enabled, code minification enabled, and declaration generation (dts: true) into the dist directory with src/index.ts as the primary entry point.
Sources: packages/cli/tsup.config.ts:1-12
The login command orchestrates a browser-based OAuth authentication flow using PKCE, spinning up a local callback server listener to acquire API tokens from the Dub platform. Sources: packages/cli/src/commands/login.ts:9-38
The oauthClient instance is initialized via @badgateway/oauth2-client with a predefined client ID and explicit authorization and token endpoints on the Dub platform. Sources: packages/cli/src/utils/oauth.ts:1-8
Sources: packages/cli/src/utils/oauth.ts:3-8
The call-chain execution proceeds through the login command action handler:
getNanoid(64) generates a 64-character cryptographic codeVerifier. Sources: packages/cli/src/commands/login.ts:14-14oauthClient.authorizationCode.getAuthorizeUri() constructs the authorization URI using redirectUri (http://localhost:4587/callback), codeVerifier, and the required scopes. Sources: packages/cli/src/commands/login.ts:15-21open(authUrl) opens the browser for authentication while an ora spinner displays status updates. Sources: packages/cli/src/commands/login.ts:23-27oauthCallbackServer() spins up the local listener passing the client, redirect URI, code verifier, and spinner to finalize token acquisition. Sources: packages/cli/src/commands/login.ts:29-34Note
The OAuth flow requests three specific permission scopes: links.read, links.write, and domains.read. Sources: packages/cli/src/commands/login.ts:20-20
State management and credential persistence are handled through the Configstore library under the application identifier "dub-cli". Active settings and tokens are structured according to the DubConfig interface and manipulated via dedicated retrieval and persistence utility functions. Sources: packages/cli/src/types/index.ts:1-6, packages/cli/src/utils/config.ts:3-6
The configuration schema defines authentication tokens, expiration metadata, and active workspace parameters. Sources: packages/cli/src/types/index.ts:1-6
Sources: packages/cli/src/types/index.ts:1-6
The configuration retrieval mechanism validates stored credentials and automatically triggers a token refresh if the access token has expired. Sources: packages/cli/src/utils/config.ts:5-32
The call-chain execution proceeds through getConfig():
new Configstore("dub-cli") instantiates the persistent store handler. Sources: packages/cli/src/utils/config.ts:6-6configStore.size is checked; if empty, it throws an error instructing the user to run dub login. Sources: packages/cli/src/utils/config.ts:8-12configStore.all is cast to DubConfig, and config.expires_at is evaluated against Date.now(). Sources: packages/cli/src/utils/config.ts:14-16oauthClient.refreshToken() is called with existing tokens and expiration data. Sources: packages/cli/src/utils/config.ts:17-22setConfig() updates the store with the newly acquired token set and returns the updated configuration object. Sources: packages/cli/src/utils/config.ts:24-28Warning
If configStore.size evaluates to zero, getConfig() immediately throws an error requiring re-authentication rather than returning an empty configuration object. Sources: packages/cli/src/utils/config.ts:8-12
The setConfig() function accepts partial configuration updates, merges them into the existing state store, and validates the disk path before returning the finalized configuration. Sources: packages/cli/src/utils/config.ts:34-52
export async function setConfig(
newConfig: Partial<DubConfig>,
): Promise<DubConfig> {
const configStore = new Configstore("dub-cli");
const existingConfig: DubConfig = configStore.all;
const updatedConfig: DubConfig = {
...existingConfig,
...newConfig,
};
configStore.set(updatedConfig);
if (!configStore.path) {
throw new Error("Failed to create or update config file");
}
return updatedConfig;
}Note
Setting configuration values performs a shallow spread merge over existing configuration data, preserving unmentioned properties such as active tokens while updating specific fields like the active domain. Sources: packages/cli/src/utils/config.ts:38-43
The link management subsystem integrates Commander command definitions with the official Dub SDK to query workspaces and generate short links remotely. Operations retrieve local credentials via getConfig(), instantiate the Dub client with the stored access token, and format query results into a structured console table using ora spinners for terminal feedback.
The links command exposes search and pagination options using Commander.
The link search execution path processes user input through configuration loading, SDK querying, and tabular formatting:
getConfig() retrieves the active OAuth access token from persistent storage.ora("Fetching links").start() initiates a terminal spinner animation during network traversal.new Dub({ token }) instantiates the SDK client using the retrieved access token.dub.links.list({ search, pageSize }) queries remote workspace links, parsing limit via parseInt or falling back to 10.spinner.stop() halts the CLI loading animation upon response receipt.links.result.map() transforms raw link objects into structured key-value pairs (Short Link, Destination URL, Clicks, and localized Created At dates), which are rendered via console.table().Warning
Any uncaught errors during configuration retrieval, Dub client initialization, or remote API execution are intercepted by the catch block and piped directly into handleError(error).
The createLink helper function provisions new short links against the configured workspace domain.
Sources: packages/cli/src/api/links.ts:4-16
export async function createLink({ url, key }: { url: string; key: string }) {
const config = await getConfig();
const dub = new Dub({
token: config.access_token,
});
return await dub.links.create({
domain: config.domain,
url: url,
key: key,
});
}Sources: packages/cli/src/api/links.ts:4-16
Tip
The createLink function automatically binds the generated short link to config.domain retrieved from the active workspace settings alongside the provided destination url and custom slug key.
Sources: packages/cli/src/api/links.ts:5-15
The domains command manages workspace domain configuration by retrieving available custom and default domains, presenting an interactive selection menu via prompts, and saving the chosen domain to local storage.
The domain discovery workflow aggregates available domain slugs from both the Dub SDK and direct platform APIs:
getConfig() reads the local access token from disk configuration.new Dub({ token }) instantiates the Dub client.Promise.all() executes concurrent requests to fetch custom domains via dub.domains.list() and default domains via a fetch call to https://api.dub.co/domains/default.parseApiResponse<string[]>(defaultDomainsResponse) parses the raw HTTP response body into a string array..slug properties, combines them with default domains, and passes the concatenated list into Array.from(new Set(allSlugs)) to eliminate duplicate entries before returning the unique slugs.Sources: packages/cli/src/api/domains.ts:7-33
Note
getDomains performs concurrent retrieval against both the SDK domain listing endpoint and the default domains route, unifying custom workspace domains and fallback options into a single deduplicated array.
The domains command presents an interactive terminal prompt using ora and prompts, validating user selection against a Zod schema before persisting the result.
Caution
If a user cancels the interactive domain prompt via keyboard interruption or escape, the onCancel handler forces an immediate process termination (process.exit(0)), preventing subsequent configuration writes.