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

@retyc/sdk

v1.0.3

Published

TypeScript SDK for the Retyc API — OIDC auth + E2E encrypted transfers

Readme

Retyc TypeScript SDK

Official TypeScript SDK for Retyc — manage file transfers programmatically


What is Retyc?

Retyc is a European sovereign file-sharing platform with end-to-end post-quantum encryption. Data stays in Europe, GDPR-compliant by design.

@retyc/sdk lets you integrate Retyc transfers into your scripts, pipelines and workflows — no browser required.


Installation

npm install @retyc/sdk
# or
pnpm add @retyc/sdk
# or
yarn add @retyc/sdk

Usage

Initialize the client

import { RetycSDK, FileTokenStore } from '@retyc/sdk'

const sdk = new RetycSDK({
  apiUrl: 'https://api.retyc.com',
  // Persist tokens across restarts (optional, defaults to in-memory)
  tokenStore: new FileTokenStore('/home/user/.retyc/tokens.json'),
})

Authentication (Device Flow)

Retyc uses the OAuth 2.0 Device Authorization Grant. The user authenticates in their browser while your script polls for the token.

// Start the device flow
const flow = await sdk.auth.startDeviceFlow()

// Show the user where to authenticate
console.log(`Open ${flow.verificationUri} and enter code: ${flow.userCode}`)
// Or use the direct link if available:
// console.log(`Or visit: ${flow.verificationUriComplete}`)

// Wait until the user completes authentication
const tokens = await flow.poll()

console.log('Authenticated! Access token expires at:', tokens.expiresAt)

Reloading an existing session

If tokens were persisted (e.g. via FileTokenStore), the SDK auto-refreshes them on the first request — no extra setup needed.

const tokens = await sdk.auth.getTokens()
if (!tokens) {
  // Run device flow...
}

Optionally, call preload() once on startup to pre-fetch the OIDC config and avoid latency on the first refresh:

await sdk.preload()

Manual refresh

The SDK refreshes tokens automatically when needed (on expiry or on a 401). You can also force a refresh manually:

const tokens = await sdk.auth.refresh()

Logout

await sdk.auth.logout()

User

// Fetch the authenticated user's profile
const { user, extra_data, roles } = await sdk.user.getMe()
console.log(user.email, user.full_name, roles)

// Fetch the active age keypair (encrypted private key + public key)
const key = await sdk.user.getActiveKey()
console.log(key.public_key, key.status) // status: 'active' | 'pending' | 'revoked'

Transfers

Upload

import { readFileSync, statSync } from 'node:fs'

const result = await sdk.transfers.upload({
  recipients: ['[email protected]', '[email protected]'],
  title: 'Q1 Report',
  expires: 7, // days
  files: [
    {
      name: 'report.pdf',
      mimeType: 'application/pdf',
      data: readFileSync('./report.pdf'),
      size: statSync('./report.pdf').size,
    },
  ],
})

console.log('Transfer created:', result.transferId)
console.log('Share link: https://retyc.com/share/' + result.slug)

Download

Downloading requires two steps: resolve the transfer session key, then download the files.

With a Retyc account (private key)

import { writeFileSync } from 'node:fs'
import { decryptStringWithPassphrase } from '@retyc/sdk'

// 1. Fetch your encrypted private key and unlock it with your key password
const { private_key_enc } = await sdk.user.getActiveKey()
const privateKey = await decryptStringWithPassphrase(private_key_enc!, 'your-key-password')

// 2. Resolve the transfer session key
const sessionKey = await sdk.transfers.resolveSessionKey('transfer-id', { privateKey })

// 3. Download and decrypt files
const files = await sdk.transfers.download('transfer-id', sessionKey)

for (const file of files) {
  writeFileSync(file.name, file.data!)
}

Without an account (transfer passphrase)

When the sender protected the transfer with a passphrase, no account key is needed.

const sessionKey = await sdk.transfers.resolveSessionKey('transfer-id', {
  transferPassphrase: 'the-passphrase-shared-by-the-sender',
})

const files = await sdk.transfers.download('transfer-id', sessionKey)

Streaming to disk (large files)

By default files are buffered in memory (file.data: Buffer). For large transfers, pass outputPath to stream directly to disk — file.data will be null.

const files = await sdk.transfers.download('transfer-id', sessionKey, {
  outputPath: '/tmp/retyc-downloads',
})

for (const file of files) {
  console.log(`Saved ${file.name} (${file.size} bytes)`)
}

The output directory is created automatically. File names containing .. or starting with / are rejected.

Manage transfers

// Disable a transfer (recipients can no longer access it)
await sdk.transfers.disable('transfer-id')

// Permanently delete a transfer and all its files
await sdk.transfers.forceDelete('transfer-id')

API Reference

new RetycSDK(config)

| Option | Type | Default | Description | | --- | --- | --- | --- | | apiUrl | string | — | Retyc API base URL | | tokenStore | TokenStore | InMemoryTokenStore | Where to persist OAuth tokens | | chunkSize | number | 8388608 (8 MB) | Upload chunk size in bytes | | uploadConcurrency | number | 4 | Max concurrent chunk uploads | | downloadConcurrency | number | 4 | Max concurrent chunk downloads |

sdk.auth

| Method | Returns | Description | | --- | --- | --- | | startDeviceFlow() | DeviceFlowResult | Initiate the OAuth 2.0 Device Authorization Grant. Call .poll() on the result to wait for the user. | | refresh() | TokenSet | Force a token refresh using the stored refresh token. Refreshes are otherwise triggered automatically. | | getTokens() | TokenSet \| null | Read the currently stored tokens (or null if not authenticated). | | logout() | void | Clear stored tokens. |

sdk.user

| Method | Returns | Description | | --- | --- | --- | | getMe() | UserApiResponse | Authenticated user profile + OIDC extra data + roles | | getActiveKey() | UserKeyApiResponse | Active age keypair (public_key, private_key_enc, status) |

Token stores

| Class | Description | | --- | --- | | InMemoryTokenStore | Default. Tokens are lost when the process exits. | | FileTokenStore(path) | Persists tokens to a JSON file on disk. |

You can implement the TokenStore interface to use any custom storage backend (keychain, database, etc.).


License

MIT — © Retyc / TripleStack SAS