npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@symbo.ls/sdk

v3.6.1

Published

[![npm version](https://img.shields.io/npm/v/@symbo.ls/sdk.svg)](https://www.npmjs.com/package/@symbo.ls/sdk) [![npm downloads](https://img.shields.io/npm/dm/@symbo.ls/sdk.svg)](https://www.npmjs.com/package/@symbo.ls/sdk) [![bundle size](https://img.shie

Readme

@symbo.ls/sdk

npm version npm downloads bundle size license node ESM

Official SDK for the Symbols design platform — manage projects, collaborate in real-time, handle branches, pull requests, and more.

Installation

npm install @symbo.ls/sdk

Basic Usage

Initialize SDK

import { SDK } from '@symbo.ls/sdk'

const sdk = new SDK({
  apiUrl: 'https://api.symbols.app',
  socketUrl: 'https://api.symbols.app',
  timeout: 30000,
  retryAttempts: 3,
  debug: false
})

await sdk.initialize({
  authToken: 'your-auth-token',
  appKey: 'your-app-key'
})

Service Access

const auth = sdk.getService('auth')
const project = sdk.getService('project')
const branch = sdk.getService('branch')
const pullRequest = sdk.getService('pullRequest')
const collab = sdk.getService('collab')
const file = sdk.getService('file')
const payment = sdk.getService('payment')
const plan = sdk.getService('plan')
const subscription = sdk.getService('subscription')
const dns = sdk.getService('dns')
const admin = sdk.getService('admin')
const screenshot = sdk.getService('screenshot')
const tracking = sdk.getService('tracking')
const waitlist = sdk.getService('waitlist')
const metrics = sdk.getService('metrics')
const integration = sdk.getService('integration')
const featureFlag = sdk.getService('featureFlag')

All service methods are also available directly on the SDK instance via proxy methods:

// These are equivalent:
sdk.getService('project').getProject(projectId)
sdk.getProject(projectId)

Status & Context

// Check if SDK is ready
sdk.isReady()

// Get detailed status
const status = sdk.getStatus()
// { ready: true, services: [...], context: {...} }

// Update context
sdk.updateContext({ ... })

// Cleanup
await sdk.destroy()

Root Event Bus

The SDK exposes a global event bus for cross-service communication:

sdk.rootBus.on('checkpoint:done', (payload) => { ... })
sdk.rootBus.on('clients:updated', (payload) => { ... })
sdk.rootBus.on('bundle:done', (payload) => { ... })
sdk.rootBus.on('bundle:error', (payload) => { ... })

Services

Auth Service

Authentication:

const auth = sdk.getService('auth')

await auth.register(userData, options)
await auth.login(email, password, options)
await auth.logout()
await auth.refreshToken(refreshToken)
await auth.googleAuth(idToken, inviteToken, options)
await auth.googleAuthCallback(code, redirectUri, inviteToken, options)
await auth.githubAuth(code, inviteToken, options)
await auth.requestPasswordReset(email)
await auth.confirmPasswordReset(token, password)
await auth.confirmRegistration(token)
await auth.requestPasswordChange()
await auth.confirmPasswordChange(currentPassword, newPassword, code)

User Data:

await auth.getMe(options)
auth.getStoredAuthState()
auth.getAuthToken()
auth.getUserProfile()
await auth.updateUserProfile(profileData)
await auth.getUserProjects()
await auth.getUser(userId)
await auth.getUserByEmail(email)
auth.isAuthenticated()
auth.hasValidTokens()
auth.getCurrentUser()

Project Roles:

await auth.getMyProjectRole(projectId)       // cached
await auth.getMyProjectRoleByKey(projectKey)  // cached
auth.clearProjectRoleCache(projectId)

Permissions:

auth.hasPermission(requiredPermission)
auth.hasGlobalPermission(globalRole, requiredPermission)
auth.checkProjectPermission(projectRole, requiredPermission)
auth.checkProjectFeature(projectTier, feature)
await auth.canPerformOperation(projectId, operation, options)
await auth.withPermission(projectId, operation, action)

Project Service

Project Management:

const project = sdk.getService('project')

await project.createProject(projectData)
await project.getProjects(params)
await project.getProject(projectId)
await project.getProjectByKey(key)
await project.getProjectDataByKey(key, options)
await project.getPublicProject(projectId)
await project.listPublicProjects(params)
await project.updateProject(projectId, data)
await project.updateProjectComponents(projectId, components)
await project.updateProjectSettings(projectId, settings)
await project.updateProjectName(projectId, name)
await project.updateProjectPackage(projectId, pkg)
await project.duplicateProject(projectId, newName, newKey, targetUserId)
await project.removeProject(projectId)
await project.checkProjectKeyAvailability(key)

Role Permissions Config:

await project.getProjectRolePermissionsConfig(projectId, options)
await project.updateProjectRolePermissionsConfig(projectId, rolePermissions, options)

Members:

await project.getProjectMembers(projectId)
await project.inviteMember(projectId, email, role, options)
await project.createMagicInviteLink(projectId, options)
await project.acceptInvite(token)
await project.updateMemberRole(projectId, memberId, role)
await project.removeMember(projectId, memberId)

Libraries:

await project.getAvailableLibraries(params)
await project.getProjectLibraries(projectId)
await project.addProjectLibraries(projectId, libraryIds)
await project.removeProjectLibraries(projectId, libraryIds)

Project Data (Version Control):

await project.applyProjectChanges(projectId, changes, options)
// changes: [['update', ['components', 'Button'], { color: 'blue' }], ['delete', ['pages', 'old']]]
// options: { message: 'Update button', type: 'patch' }

await project.getProjectData(projectId, options)
await project.getProjectVersions(projectId, options)
await project.restoreProjectVersion(projectId, version, options)
await project.updateProjectItem(projectId, path, value, options)
await project.deleteProjectItem(projectId, path, options)
await project.setProjectValue(projectId, path, value, options)
await project.addProjectItems(projectId, items, options)
await project.getProjectItemByPath(projectId, path, options)

Environments:

await project.listEnvironments(projectId, options)
await project.activateMultipleEnvironments(projectId, options)
await project.upsertEnvironment(projectId, envKey, config, options)
await project.updateEnvironment(projectId, envKey, updates, options)
await project.publishToEnvironment(projectId, envKey, payload, options)
await project.deleteEnvironment(projectId, envKey, options)
await project.promoteEnvironment(projectId, fromEnvKey, toEnvKey, options)

Favorites & Recent:

await project.getFavoriteProjects()
await project.addFavoriteProject(projectId)
await project.removeFavoriteProject(projectId)
await project.getRecentProjects(options)

Access Control:

await project.setProjectAccess(projectId, access)       // account/team/organization/public
await project.setProjectVisibility(projectId, visibility) // public/private/password-protected

Branch Service

const branch = sdk.getService('branch')

await branch.listBranches(projectId)
await branch.createBranch(projectId, branchData)
await branch.deleteBranch(projectId, branchName)
await branch.renameBranch(projectId, branchName, newName)
await branch.getBranchChanges(projectId, branchName, options)
await branch.mergeBranch(projectId, branchName, mergeData)
await branch.resetBranch(projectId, branchName)
await branch.publishVersion(projectId, publishData)

// Helper methods
await branch.createFeatureBranch(projectId, featureName)  // creates 'feature/<name>'
await branch.createHotfixBranch(projectId, hotfixName)
await branch.branchExists(projectId, branchName)
await branch.previewMerge(projectId, sourceBranch, targetBranch)
await branch.commitMerge(projectId, sourceBranch, options)
await branch.getBranchStatus(projectId, branchName)
await branch.deleteBranchSafely(projectId, branchName, options)
await branch.getBranchesWithStatus(projectId)
branch.validateBranchName(branchName)
branch.sanitizeBranchName(branchName)

Pull Request Service

const pr = sdk.getService('pullRequest')

await pr.createPullRequest(projectId, pullRequestData)
await pr.listPullRequests(projectId, options)
await pr.getPullRequest(projectId, prId)
await pr.reviewPullRequest(projectId, prId, reviewData)
await pr.addPullRequestComment(projectId, prId, commentData)
await pr.mergePullRequest(projectId, prId)
await pr.getPullRequestDiff(projectId, prId)
await pr.closePullRequest(projectId, prId)
await pr.reopenPullRequest(projectId, prId)

// Helper methods
await pr.approvePullRequest(projectId, prId, comment)
await pr.requestPullRequestChanges(projectId, prId, threads)
await pr.getOpenPullRequests(projectId, options)
await pr.getClosedPullRequests(projectId, options)
await pr.getMergedPullRequests(projectId, options)
await pr.isPullRequestMergeable(projectId, prId)
await pr.getPullRequestStatusSummary(projectId, prId)
await pr.getPullRequestStats(projectId, options)

Collab Service

Real-time collaboration via WebSocket and Yjs.

const collab = sdk.getService('collab')

// Connection
await collab.connect({ projectId, branch, authToken })
collab.disconnect()
collab.isConnected()
collab.getConnectionInfo()

// Data updates
collab.updateData(tuples, options)
collab.addItem(type, data, opts)
collab.addMultipleItems(items, opts)
collab.updateItem(type, data, opts)
collab.deleteItem(type, key, opts)

// Undo/Redo
collab.undo()
collab.redo()
collab.canUndo()
collab.canRedo()
collab.getUndoStackSize()
collab.getRedoStackSize()
collab.clearUndoHistory()
collab.checkpoint()

// Presence
collab.sendCursor(data)
collab.sendPresence(data)
collab.toggleLive(flag)

// Accessors
collab.ydoc   // Yjs document
collab.socket  // Socket instance

File Service

const file = sdk.getService('file')

await file.uploadFile(file, options)
await file.updateProjectIcon(projectId, iconFile)
await file.uploadImage(imageFile, options)
await file.uploadDocument(documentFile, options)
await file.uploadMultipleFiles(files, options)
file.getFileUrl(fileId)
file.validateFile(file, options)

Payment Service

const payment = sdk.getService('payment')

await payment.checkout(options)
await payment.getSubscriptionStatus(projectId)
await payment.hasActiveSubscription(projectId)
await payment.getSubscriptionDetails(projectId)
await payment.checkoutForPlan(options)
await payment.checkoutForTeam(options)
await payment.getSubscriptionSummary(projectId)

Plan Service

const plan = sdk.getService('plan')

// Public (no auth required)
await plan.getPlans()
await plan.getPlan(planId)
await plan.getPlansWithPricing()
await plan.getPlanByKey(key)
await plan.getActivePlans()
await plan.getPlansByPriceRange(minPrice, maxPrice)

// Admin
await plan.getAdminPlans()
await plan.createPlan(planData)
await plan.updatePlan(planId, planData)
await plan.deletePlan(planId)
await plan.initializePlans()

Subscription Service

const subscription = sdk.getService('subscription')

await subscription.createSubscription(subscriptionData)
await subscription.getProjectStatus(projectId)
await subscription.getUsage(subscriptionId)
await subscription.cancelSubscription(subscriptionId)
await subscription.listInvoices(subscriptionId, options)
await subscription.getPortalUrl(projectId)
await subscription.getProjectSubscription(projectId)
await subscription.getProjectUsage(projectId)
await subscription.hasActiveSubscription(projectId)
await subscription.changeSubscription(projectId, planId)
await subscription.downgrade(projectId)

DNS Service

const dns = sdk.getService('dns')

await dns.createDnsRecord(domain, options)
await dns.getDnsRecord(domain)
await dns.removeDnsRecord(domain)
await dns.getCustomHost(hostname)
await dns.addProjectCustomDomains(projectId, customDomains, options)
await dns.isDomainAvailable(domain)
await dns.getDomainStatus(domain)
await dns.verifyDomainOwnership(domain)
await dns.getProjectDomains(projectId)
await dns.removeProjectCustomDomain(projectId, domain)
dns.validateDomain(domain)
dns.formatDomain(domain)
dns.extractDomainFromUrl(url)

Admin Service

const admin = sdk.getService('admin')

await admin.getAdminUsers(params)
await admin.updateUser(userId, userData)
await admin.searchAdminUsers(searchQuery, options)
await admin.getAdminUsersByEmails(emails)
await admin.getAdminUsersByIds(ids)
await admin.assignProjectsToUser(userId, options)
await admin.assignSpecificProjectsToUser(userId, projectIds, role)
await admin.assignAllProjectsToUser(userId, role)
await admin.getUserStats(userId)
await admin.bulkUpdateUsers(updates)
await admin.getUsersByRole(role)
await admin.getUsersByStatus(status)
await admin.activateUser(userId)
await admin.deactivateUser(userId)
await admin.suspendUser(userId)
await admin.promoteToAdmin(userId)
await admin.demoteFromAdmin(userId)

Screenshot Service

const screenshot = sdk.getService('screenshot')

await screenshot.createScreenshotProject(payload)
await screenshot.getProjectScreenshots(projectKey, params)
await screenshot.reprocessProjectScreenshots(projectKey, body)
await screenshot.recreateProjectScreenshots(projectKey, body)
await screenshot.deleteProjectScreenshots(projectKey)
await screenshot.getThumbnailCandidate(projectKey, options)
await screenshot.updateProjectThumbnail(projectKey, body)
await screenshot.refreshThumbnail(projectKey)
await screenshot.getPageScreenshot(screenshotId, format)
await screenshot.getComponentScreenshot(screenshotId, format)
await screenshot.getScreenshotByKey(key)
await screenshot.getQueueStatistics()

Tracking Service (Grafana Faro)

const tracking = sdk.getService('tracking')

// Events
tracking.trackEvent('purchase', { amount: 42, currency: 'USD' })
tracking.trackError(new Error('Login failed'), { context: { screen: 'Login' } })
tracking.captureException(error, context)
tracking.trackMeasurement('cart_value', 42, { context: { currency: 'USD' } })
tracking.trackView('Dashboard', { section: 'Analytics' })

// Logging
tracking.logMessage(message)
tracking.logDebug(message)
tracking.logInfo(message)
tracking.logWarning(message)
tracking.logError(message)
tracking.addBreadcrumb('Open modal', { id: 'planLimits' })

// User & Session
tracking.setUser({ id: 'u_123', role: 'admin' })
tracking.clearUser()
tracking.setSession(session)
tracking.clearSession()

// Global Attributes
tracking.setGlobalAttributes(attributes)
tracking.setGlobalAttribute(key, value)
tracking.removeGlobalAttribute(key)

// Queue & Status
tracking.flushQueue()
tracking.getClient()
tracking.isEnabled()
tracking.isInitialized()

Tracking Configuration

const sdk = new SDK({
  tracking: {
    url: 'https://<your-faro-receiver-url>',
    appName: 'Symbols Platform',
    environment: 'production',
    appVersion: '1.0.0',
    sessionTracking: true,
    enableTracing: true,
    globalAttributes: { region: 'us-east-1' }
  }
})

Tracking is automatically disabled on localhost and in non-browser environments.

Waitlist Service

const waitlist = sdk.getService('waitlist')

await waitlist.joinWaitlist(data)              // public
await waitlist.listWaitlistEntries(options)     // admin
await waitlist.updateWaitlistEntry(id, update)  // admin
await waitlist.inviteWaitlistEntry(id)          // admin

Metrics Service

const metrics = sdk.getService('metrics')

await metrics.getContributions(options)  // contribution heat-map stats

Integration Service

const integration = sdk.getService('integration')

// Integration management
await integration.integrationWhoami(apiKey, options)
await integration.listIntegrations(options)
await integration.createIntegration(data)
await integration.updateIntegration(integrationId, update)

// API Keys
await integration.createIntegrationApiKey(integrationId, data)
await integration.listIntegrationApiKeys(integrationId)
await integration.revokeIntegrationApiKey(integrationId, keyId)

// Webhooks
await integration.createIntegrationWebhook(integrationId, data)
await integration.listIntegrationWebhooks(integrationId)
await integration.updateIntegrationWebhook(integrationId, webhookId, update)
await integration.deleteIntegrationWebhook(integrationId, webhookId)
await integration.listIntegrationWebhookDeliveries(integrationId, webhookId, options)
await integration.replayIntegrationWebhookDelivery(integrationId, webhookId, deliveryId)

// GitHub Connectors
await integration.listGitHubConnectors()
await integration.createGitHubConnector(data)
await integration.updateGitHubConnector(connectorId, update)
await integration.deleteGitHubConnector(connectorId)

Feature Flag Service

const featureFlag = sdk.getService('featureFlag')

// User-facing
await featureFlag.getFeatureFlags(params)
await featureFlag.getFeatureFlag(key)

// Admin
await featureFlag.getAdminFeatureFlags(params)
await featureFlag.createFeatureFlag(flagData)
await featureFlag.updateFeatureFlag(id, patch)
await featureFlag.archiveFeatureFlag(id)

Token Management

The SDK includes automatic token management with persistence and refresh:

  • Automatic Token Refresh - tokens are refreshed before expiration
  • Persistent Storage - tokens persist across page refreshes via localStorage
  • Secure Handling - automatic cleanup on logout
  • Flexible Storage - supports localStorage, sessionStorage, or memory
import { getTokenManager } from '@symbo.ls/sdk'

const tokenManager = getTokenManager({
  storageType: 'localStorage',        // 'localStorage' | 'sessionStorage' | 'memory'
  refreshBuffer: 60 * 1000,           // refresh 1 minute before expiry
  apiUrl: '/api',
  onTokenRefresh: (tokens) => { ... },
  onTokenExpired: () => { ... },
  onTokenError: (error) => { ... }
})

All authenticated API calls automatically use fresh tokens via the BaseService _request() method.


Permissions

Role Permissions

// Global roles
const ROLE_PERMISSIONS = {
  guest: ['viewPublicProjects'],
  user: ['viewPublicProjects', 'createProject'],
  admin: ['viewPublicProjects', 'createProject', 'governance'],
  superAdmin: ['viewPublicProjects', 'createProject', 'governance', 'managePlatform']
}

// Project roles
const PROJECT_ROLE_PERMISSIONS = {
  guest: ['platformSettings', 'showContent'],
  editor: ['platformSettings', 'showContent', 'showCode', 'editMode', 'versions'],
  admin: [/* editor + */ 'inviteMembers', 'branchProtection', 'projectSettings'],
  owner: [/* admin + */ 'copyPasteAllowanceSetting', 'iam']
}

Permission Checks

auth.hasPermission('edit')
auth.hasGlobalPermission('admin', 'governance')
auth.checkProjectPermission('editor', 'editMode')
auth.checkProjectFeature('pro1', 'aiCopilot')  // returns tier limit (e.g. 5)
await auth.canPerformOperation(projectId, 'edit', { checkFeatures: true })
await auth.withPermission(projectId, 'edit', () => { /* action */ })

Tier Features

| Feature | Free | Pro1 | Pro2 | |---------|------|------|------| | aiCopilot | 3 | 5 | 15 | | aiChatbot | 3 | 5 | 15 |


Environment Configuration

The SDK auto-detects environment from hostname and provides:

import { environment } from '@symbo.ls/sdk'

environment.apiUrl      // HTTP API URL
environment.socketUrl   // WebSocket URL
environment.features    // { trackingEnabled, betaFeatures, newUserOnboarding }

Supported environments: local, development, testing, upcoming, staging, preview, production.


Error Handling

try {
  await sdk.initialize()
} catch (error) {
  console.error('SDK initialization failed:', error.message)
}

try {
  await project.mergePullRequest(projectId, prId)
} catch (error) {
  if (error.message.includes('conflicts')) {
    // Handle merge conflicts
  } else if (error.message.includes('403')) {
    // Handle permission errors
  }
}

Direct Service Creation

Services can be created independently without the SDK class:

import { createAuthService, createProjectService } from '@symbo.ls/sdk'

const auth = createAuthService({ context, options })
await auth.init({ context, options })

Available factory functions: createAuthService, createCollabService, createProjectService, createPlanService, createFileService, createPaymentService, createDnsService, createBranchService, createPullRequestService, createAdminService, createSubscriptionService, createScreenshotService, createTrackingService, createWaitlistService, createMetricsService, createIntegrationService, createFeatureFlagService.