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

lightweight-dms-core

v1.0.0

Published

`lightweight-dms-core` is a stable, embeddable TypeScript library for tenant-scoped document storage. It provides PostgreSQL row-level security (RLS), document metadata, durable processing boundaries, webhooks, exports, and tenant deletion workflows. The

Readme

lightweight-dms-core

lightweight-dms-core is a stable, embeddable TypeScript library for tenant-scoped document storage. It provides PostgreSQL row-level security (RLS), document metadata, durable processing boundaries, webhooks, exports, and tenant deletion workflows. The host application owns its database roles, storage, workers, and external services.

Requirements

  • Node.js 22.14 or later
  • PostgreSQL with separate application and migration-owner roles in production
  • A durable StorageAdapter; LocalFsAdapter is suitable only for local development

Installation

npm install lightweight-dms-core

The package is ESM-only. Use TypeScript with Node's ESM resolution and import from lightweight-dms-core rather than its internal paths.

Database roles and migrations

Use the application role for tenant-scoped requests. Use a distinct owner role for migrations and other owner-only maintenance. Run migrations before serving traffic:

const dms = createDms({
  database: {
    connectionString: process.env.DATABASE_URL!,
    ownerConnectionString: process.env.OWNER_DATABASE_URL!,
  },
  storage: new LocalFsAdapter('/var/lib/lightweight-dms'),
  maxUploadBytes: 64 * 1024 * 1024,
});

await dms.migrate();

With connection-string configuration, migrate() uses ownerConnectionString when it is set and otherwise falls back to connectionString. Use a distinct owner connection in production; the fallback supports a single-role local setup. A pool-based configuration has no connection string for migrate(), so run migrations through a connection-string-configured instance.

Create a DMS instance

import { randomUUID } from 'node:crypto';
import { Readable } from 'node:stream';
import { createDms, LocalFsAdapter } from 'lightweight-dms-core';

const dms = createDms({
  database: {
    connectionString: process.env.DATABASE_URL!,
    ownerConnectionString: process.env.OWNER_DATABASE_URL!,
  },
  storage: new LocalFsAdapter('/var/lib/lightweight-dms'),
  maxUploadBytes: 64 * 1024 * 1024,
});

await dms.migrate();
const tenant = await dms.tenants.provision({
  name: 'Example tenant',
  ocrLanguages: ['de'],
  searchLanguage: 'german',
});

const png = Buffer.from('...');
const document = await dms.documents.upload(
  { tenantId: tenant.id, actorId: randomUUID() },
  {
    filename: 'document.png',
    mimeType: 'image/png',
    content: Readable.from(png),
    contentLength: png.length,
  },
);

await dms.close();

The checked repository quickstart uses the same public API. It needs DATABASE_URL and OWNER_DATABASE_URL and is typechecked by npm run docs:example:check from this package directory.

Provision OCR and search languages

Tenant provisioning requires both independent language settings. ocrLanguages is a non-empty array of OCR engine language codes. searchLanguage controls PostgreSQL full-text indexing and must be one of simple, english, or german; it is not inferred from OCR configuration.

await dms.tenants.provision({
  name: 'German documents',
  ocrLanguages: ['de'],
  searchLanguage: 'german',
});

Upload limits and streaming

maxUploadBytes is required and must be a positive safe integer. It is the application-level ceiling used by document ingestion. Supply contentLength when the upload size is known; the library checks it against the measured stream and the configured ceiling. The upload content is a Node Readable, so the host must avoid buffering untrusted uploads in memory before calling documents.upload.

StorageAdapter contract

StorageAdapter.put(key, body, options) is create-only: a key must be fresh and an adapter must reject rather than overwrite an existing object. options can include an AbortSignal and an optional contentLength. On cancellation, put, get, and delete must not settle until local work that could still affect the object has quiesced. Implementations must keep durable cleanup and ambiguity handling appropriate for their object store.

LocalFsAdapter stores canonical library-generated keys below a local root. S3Adapter supports S3-compatible object storage and bounded multipart writes. Its defaults are an 8 MiB small-object threshold, 8 MiB multipart parts, and multipart concurrency of 2; multipart parts cannot be below 5 MiB and concurrency must be between 1 and 8. Multipart cleanup requires the S3 principal to allow s3:ListBucketMultipartUploads and s3:AbortMultipartUpload. When using S3Adapter directly, serialize put and delete calls for the same key; DMS-managed write and purge paths already do so.

Workers and external services

createDms() opens database resources but does not start a queue or workers. The embedding host must configure the queue, start startWorkers, and monitor worker health separately. Production also needs durable storage, malware scanning, OCR, Redis when queues are configured, process supervision, and a graceful shutdown path. Do not use a request-serving process as a substitute for durable worker operation.

Shutdown

Stop accepting host traffic, quiesce worker activity under host control, then call:

await dms.close();

This destroys the Kysely database instances and ends every distinct underlying pool used by the instance, including caller-supplied pools as well. Do not share a supplied pool with other live components unless the host coordinates their shutdown around dms.close(). The host remains responsible for closing queues, storage clients it created, and external service connections.

Public API and SemVer

The root export of lightweight-dms-core is the public API. Public names, type contracts, and runtime behavior follow semantic versioning from 1.0.0 onward. Import only root exports, including createDms, DmsConfig, DmsContext, StorageAdapter, LocalFsAdapter, S3Adapter, ProvisionInput, SearchLanguage, queue and worker seams, and documented error classes. Internal source paths and the private HTTP service are not part of this npm package contract.

Security reporting

Report vulnerabilities privately using the GitHub security advisory form. Do not include production credentials or personal data.

License

Apache-2.0. Third-party attributions are in NOTICE.