Skip to main content
The @proton/shared package is the foundational library containing shared utilities, constants, API clients, authentication logic, and business logic used across all Proton applications.

Installation

yarn add @proton/shared
This package is typically already included as a peer dependency in @proton/components.

Package Information

{
  "name": "@proton/shared",
  "description": "Proton shared",
  "license": "GPL-3.0",
  "sideEffects": false
}

Key Features

API Clients

Type-safe API client functions for all Proton services

Constants

Application constants, brand names, and configuration

Authentication

Login, 2FA, SRP protocol, and session management

Utilities

Helper functions for dates, strings, URLs, and more

Core Modules

API Clients

The package provides typed API client functions for all endpoints:
import { auth, auth2FA, revoke } from '@proton/shared/lib/api/auth';
import { queryAddresses } from '@proton/shared/lib/api/addresses';
import { getEvents } from '@proton/shared/lib/api/events';

// API client functions return request configuration objects
const authRequest = auth(
  { Username: '[email protected]' },
  true // persistent
);

// Use with your API handler
const response = await api(authRequest);
API functions return request configuration objects that can be passed to the API handler. They don’t make requests directly.

Constants

Comprehensive application constants and configurations:
import {
  BRAND_NAME,
  MAIL_APP_NAME,
  CALENDAR_APP_NAME,
  DRIVE_APP_NAME,
  APPS,
  APPS_CONFIGURATION,
  DEFAULT_TIMEOUT,
  SECOND,
  MINUTE,
  HOUR,
  DAY,
} from '@proton/shared/lib/constants';

console.log(BRAND_NAME); // "Proton"
console.log(MAIL_APP_NAME); // "Proton Mail"
console.log(APPS.PROTONMAIL); // "proton-mail"
console.log(DEFAULT_TIMEOUT); // 30000

Time Constants

import {
  SECOND,
  MINUTE,
  HOUR,
  DAY,
  WEEK,
  MONTH,
  YEAR,
} from '@proton/shared/lib/constants';

// All values in milliseconds
setTimeout(callback, 5 * MINUTE); // 5 minutes
const cacheTime = 24 * HOUR; // 24 hours

Authentication

import { computeKeyPassword, generateKeySalt } from '@proton/shared/lib/keys';
import { srpAuth } from '@proton/shared/lib/srp';

// Generate key salt
const keySalt = generateKeySalt();

// Compute key password for authentication
const keyPassword = await computeKeyPassword(
  password,
  keySalt
);

// Perform SRP authentication
const result = await srpAuth({
  api,
  credentials: { username, password },
  config: auth({ Username: username }, persistent),
});

URL Helpers

import {
  getHost,
  getHostname,
  getSecondLevelDomain,
  stringifySearchParams,
  parseSearchParams,
} from '@proton/shared/lib/helpers/url';

const host = getHost('https://mail.proton.me');
// "mail.proton.me"

const params = stringifySearchParams({ 
  page: '1', 
  filter: 'unread' 
});
// "page=1&filter=unread"

const parsed = parseSearchParams('?page=1&filter=unread');
// { page: "1", filter: "unread" }

Date Utilities

import { fromUnixTime, toUnixTime } from '@proton/shared/lib/date/date';
import { convertUTCDateTimeToZone } from '@proton/shared/lib/date/timezone';

// Unix timestamp conversion
const date = fromUnixTime(1234567890);
const timestamp = toUnixTime(new Date());

// Timezone conversion
const localDate = convertUTCDateTimeToZone(
  utcDate,
  'America/New_York'
);

Helper Functions

import {
  capitalize,
  truncate,
  stripLeadingSlash,
  stripTrailingSlash,
} from '@proton/shared/lib/helpers/string';

capitalize('hello'); // "Hello"
truncate('Long text...', 10); // "Long text..."
stripLeadingSlash('/path'); // "path"
stripTrailingSlash('path/'); // "path"
import {
  bytesSize,
  sizeUnits,
  getLongSizeFormat,
  getShortSizeFormat,
} from '@proton/shared/lib/helpers/size';

bytesSize(1024 * 1024); // 1 MB
getLongSizeFormat(1024 * 1024); // "1 MB"
getShortSizeFormat(1024); // "1 KB"
import {
  isChrome,
  isFirefox,
  isSafari,
  isEdge,
  isMobile,
} from '@proton/shared/lib/helpers/browser';

if (isChrome()) {
  // Chrome-specific code
}

if (isMobile()) {
  // Mobile-specific code
}
import {
  isValidEmail,
  validateEmailAddress,
} from '@proton/shared/lib/helpers/email';
import { isValidDomain } from '@proton/shared/lib/helpers/domain';

isValidEmail('[email protected]'); // true
validateEmailAddress('[email protected]'); // returns detailed validation
isValidDomain('example.com'); // true

Event Manager

Subscribe to real-time API events:
import { EventManager } from '@proton/shared/lib/eventManager/eventManager';

const eventManager = new EventManager({
  api,
  eventID: latestEventID,
});

eventManager.subscribe((event) => {
  // Handle messages, contacts, labels updates, etc.
  if (event.Messages) {
    // Update messages
  }
  if (event.Contacts) {
    // Update contacts
  }
});

eventManager.start();

Interfaces & Types

Comprehensive TypeScript interfaces:
import type {
  User,
  UserSettings,
  Address,
  Key,
  Organization,
  Subscription,
  Api,
} from '@proton/shared/lib/interfaces';

// Strongly typed throughout the codebase
const user: User = await api(getUser());
const addresses: Address[] = await api(queryAddresses());

Dependencies

Core Dependencies

{
  "@proton/crypto": "workspace:^",
  "@proton/srp": "workspace:^",
  "date-fns": "^2.30.0",
  "dompurify": "^3.3.1",
  "idb": "^8.0.3",
  "zod": "^3.25.76"
}

Key External Libraries

  • date-fns - Date manipulation and formatting
  • dompurify - HTML sanitization
  • idb - IndexedDB wrapper for offline storage
  • zod - Runtime type validation
  • ical.js - Calendar event parsing
  • papaparse - CSV parsing
  • ua-parser-js - User agent parsing

Error Handling

import {
  HTTP_ERROR_CODES,
  API_CUSTOM_ERROR_CODES,
} from '@proton/shared/lib/errors';

try {
  await api(request);
} catch (error) {
  if (error.status === HTTP_ERROR_CODES.UNAUTHORIZED) {
    // Handle unauthorized
  }
  if (error.data?.Code === API_CUSTOM_ERROR_CODES.PASSWORD_WRONG) {
    // Handle wrong password
  }
}

Testing

# Run tests
yarn workspace @proton/shared test

# Run tests in watch mode
yarn workspace @proton/shared test:watch

# Type checking
yarn workspace @proton/shared check-types

Best Practices

Tree-shaking: Import specific modules rather than the entire package:
// Good
import { BRAND_NAME } from '@proton/shared/lib/constants';

// Avoid (imports entire constants file)
import * as constants from '@proton/shared/lib/constants';
API Clients: Always use the provided API client functions for type safety and consistency.
Constants: Prefer using named constants from this package rather than hardcoding values.

Build docs developers (and LLMs) love