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

ug-file

v0.3.1

Published

Unofficial SDK for UGOS Pro file management APIs.

Downloads

734

Readme

ug-file

Unofficial TypeScript SDK for UGOS Pro / UGREEN NAS file management APIs.

ug-file provides a small ESM client for authenticating with UGOS, resolving UGREENlink aliases, listing directories, reading and uploading files, and performing common file operations such as copy, move, rename, trash, and delete.

Features

  • Authenticate against UGOS Pro with RSA-encrypted credentials.
  • Reuse exported sessions without storing passwords in the client.
  • Connect by direct UGOS URL or by UGREENlink ID.
  • List root folders and directory contents with file/directory helpers.
  • Read, download, and upload files.
  • Create folders and manage files with copy, move, rename, trash, and permanent delete operations.
  • Use native fetch, or inject a custom fetch implementation.
  • Fully typed TypeScript API.

Requirements

  • A runtime with fetch, FormData, and Blob support. Node.js 18+ works out of the box.
  • Network access to your UGOS Pro / UGREEN NAS instance.

Installation

npm install ug-file

Or with other package managers:

yarn add ug-file
pnpm add ug-file

Development

This library is developed with Bun ([email protected]). Use Bun for local development workflows.

bun install
bun run typecheck
bun run build

Quick Start

import { UgosClient } from "ug-file";

const client = new UgosClient({
  url: "https://your-nas.example.com"
});

let login = await client.login({ username: "admin", password: "your-password", keepalive: true });

if (login.requiresCode) {
  login = await login.verifyCode("123456", true);
}

if (!login.success) {
  throw new Error(login.message ?? `Login failed: ${login.code}`);
}

const entries = await client.list("/Documents");
for (const entry of entries) {
  console.log(entry.name, entry.isDirectory() ? "directory" : "file");
}

Connecting

Direct URL

Use url when you already know the UGOS base URL.

const client = new UgosClient({
  url: "https://your-nas.example.com"
});

UGREENlink ID

Use uglinkid to resolve a UGREENlink alias automatically through the public UGREENlink API.

const client = new UgosClient({
  uglinkid: "your-alias"
});

You can also resolve an alias directly:

const url = await UgosClient.resolveUgreenLinkUrl("your-alias");

Custom Fetch

Pass fetch when your runtime does not provide globalThis.fetch, or when you need custom transport behavior.

const client = new UgosClient({
  url: "https://your-nas.example.com",
  trustInfo: {
    client_type: "sdk",
    system: "node",
    dev_name: "backup-worker"
  },
  fetch: customFetch
});

Usage

Call login() before using authenticated file APIs. Credentials are passed to login() and are not stored in the client.

const result = await client.login({ username: "admin", password: "your-password", keepalive: true });

if (result.success) {
  console.log(result.session.uid);
}

When UGOS requires OTP, login() returns an interactive challenge result. Pass keepalive: true to create a session that can be exported and reused later (see Session export). Pass true to verifyCode() to trust this device, or false to avoid adding a trusted device.

let result = await client.login({ username: "admin", password: "your-password", keepalive: true });

if (result.requiresCode) {
  result = await result.verifyCode("123456", true);
}

if (!result.success) {
  throw new Error(result.message ?? `Login failed: ${result.code}`);
}

Use checkLogin() to verify whether the current in-memory token is still valid:

if (!(await client.checkLogin())) {
  const result = await client.login({ username: "admin", password: "your-password", keepalive: true });
  if (!result.success) {
    throw new Error(result.message ?? `Login failed: ${result.code}`);
  }
}

Session export

Only sessions created with keepalive: true can be exported. If you logged in without keepalive (or with keepalive: false), exportSession() returns undefined.

const exportedSession = client.exportSession();

if (exportedSession) {
  await anotherClient.login(exportedSession);
}

List Files

const entries = await client.list("/Documents", { page: 1, limit: 100 });

for (const entry of entries) {
  if (entry.isFile()) {
    console.log(entry.path, entry.size);
  }
}

Root Folders

const { personal, shared } = await client.root();

console.log("Personal roots", personal.map((entry) => entry.name));
console.log("Shared roots", shared.map((entry) => entry.name));

File Metadata and Existence

if (await client.exists("/Documents/report.pdf")) {
  const stat = await client.stat("/Documents/report.pdf");
  console.log(stat.name, stat.size, new Date(stat.mtime));
}

Read and Download Files

const text = await client.readFile("/Documents/notes.txt", "utf8");
const bytes = await client.readFile("/Documents/archive.bin");

const response = await client.download("/Documents/report.pdf");
const arrayBuffer = await response.arrayBuffer();

Upload Files

await client.upload("/Documents/hello.txt", "Hello from ug-file");

const bytes = new TextEncoder().encode("binary content");
await client.upload("/Documents/data.bin", bytes);

Upload content can be a string, Blob, ArrayBuffer, ArrayBufferView, or ReadableStream<Uint8Array>.

Manage Files and Folders

await client.mkdir("/Documents/Projects", true);

await client.copy("/Documents/file.txt", "/Backup/", "skip");
await client.move(["/Downloads/a.txt", "/Downloads/b.txt"], "/Documents/", "overwrite");
await client.rename("/Documents/old-name.txt", "new-name.txt");

await client.trash("/Documents/old-file.txt");
await client.delete("/Documents/remove-forever.txt");

Conflict actions for copy and move are:

  • "skip" or 0: skip conflicting items.
  • "overwrite" or 1: replace conflicting items.
  • "keep-both" or 3: keep both files by allowing UGOS to rename the copied or moved entry.

API Overview

Main exports:

  • UgosClient
  • UgosApiError
  • UgosHttpError
  • Type exports including UgosClientConfig, UgosLoginCredentials, UgosLoginResult, UgosLoginCodeOptions, UgosDirent, UgosFileEntry, UgosRoot, SessionContainer, LoginResponse, and ConflictAction.

UgosClient methods:

  • UgosClient.resolveUgreenLinkUrl(ugreenLinkId, fetchImpl?)
  • client.login(username, password)
  • client.login({ username, password, keepalive? })
  • client.login(credentialsOrSession)
  • loginResult.verifyCode(code, trustOrOptions?)
  • client.checkLogin()
  • client.currentSession
  • client.exportSession() — returns session only when logged in with keepalive: true
  • client.list(path?, options?)
  • client.exists(path)
  • client.root()
  • client.stat(path)
  • client.mkdir(path, recursive?)
  • client.copy(src, dst, action?)
  • client.move(src, dst, action?)
  • client.rename(path, newName)
  • client.download(path)
  • client.readFile(path, encoding?)
  • client.upload(path, content)
  • client.trash(path)
  • client.delete(path)

Error Handling

import { UgosApiError, UgosHttpError } from "ug-file";

try {
  const result = await client.login({ username: "admin", password: "your-password", keepalive: true });
  if (!result.success) {
    throw new Error(result.message ?? `Login failed: ${result.code}`);
  }
  await client.list("/Documents");
} catch (error) {
  if (error instanceof UgosApiError) {
    console.error("UGOS API error", error.code, error.body);
  } else if (error instanceof UgosHttpError) {
    console.error("HTTP error", error.status, error.body);
  } else {
    throw error;
  }
}

Development

bun install
bun run typecheck
bun run build

Available scripts:

  • bun run build: generate declaration files and bundle the package into dist.
  • bun run build:types: emit TypeScript declaration files only.
  • bun run build:bundle: bundle src/index.ts into dist.
  • bun run typecheck: run TypeScript without emitting files.

Notes

  • This is an unofficial SDK and is not affiliated with UGREEN or UGOS.
  • File operations run against your NAS account and may modify or permanently delete remote files.
  • delete() permanently removes files. Use trash() when you want UGOS recycle-bin recovery behavior.