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

@open-xchange/app-suite-ui-sdk

v0.1.7

Published

Shared build, lint and test tooling for OX App Suite UI projects

Readme

@open-xchange/app-suite-ui-sdk

Shared build, lint and test tooling for OX App Suite UI projects: core ui, plugins, customer plugins and services with a UI build.

A project depends on this one package instead of vite, eslint, stylelint, vitest, lefthook and their plugins. A tool bump or a security fix becomes one SDK release. Renovate then rolls it out to every project with one automerged MR.

Setup

pnpm add -D @open-xchange/app-suite-ui-sdk
pnpm exec ui-sdk doctor --fix
pnpm install

doctor --fix removes the tooling the SDK provides from package.json, points the scripts at ui-sdk, and writes the pnpm settings the SDK needs into pnpm-workspace.yaml. docs/migration.md walks through moving an existing project, including what doctor leaves to you.

For renovate, the project's renovate.json only extends the SDK preset:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["local>openxchange/appsuite/web-foundation/renovate:app-suite-ui-sdk"]
}

The preset automerges updates, and after an SDK bump it runs ui-sdk doctor --fix in the same MR. SDK minor releases below 1.0.0 and SDK majors wait for review.

Commands

| Command | Runs | Default arguments | |---|---|---| | ui-sdk dev | vite dev server | | | ui-sdk build | vite build | | | ui-sdk test | vitest | --run | | ui-sdk lint | eslint | . --cache | | ui-sdk stylelint | stylelint | src/**/*.{scss,css} --allow-empty-input | | ui-sdk msgmerge [po] [pot] | gettext msgmerge for each po file | src/i18n/*.po dist/ox.pot | | ui-sdk doctor [--fix] | checks the project setup, --fix writes the changes | | | ui-sdk audit [--fix] | pnpm audit, --fix first writes only the SDK security overrides into pnpm-workspace.yaml and reinstalls | |

Arguments after the command replace the defaults and go straight to the tool, for example ui-sdk lint src spec --fix. msgmerge needs gettext installed.

The tools come from the SDK's own dependencies. After ui-sdk doctor --fix, the publicHoistPattern makes pnpm link vite, vitest, eslint, stylelint and tsc into node_modules/.bin, so pnpm exec vite works too. Scripts use ui-sdk, which falls back to the SDK config when the project has none; plain vite does not.

Configs

Without a config file in the project, ui-sdk uses the SDK defaults. To change them, add the file and start from the SDK export:

// vite.config.js
import { defineConfig } from '@open-xchange/app-suite-ui-sdk/vite'

export default defineConfig({
  id: 'gpg-ui',
  name: 'GPG UI',
  tailwind: true,
  gettext: { poFiles: 'src/i18n/*.po', outFile: 'ox.pot', defaultDictionary: 'io.ox/gpg/i18n', defaultLanguage: 'en_US' },
  vite: { build: { sourcemap: true } }
})

To copy files into place when vite starts, for example assets from node_modules into public/, pass copy targets. Each match of src lands in dest under its own name, folders are copied as folders, and rename and transform change the file name and content:

defineConfig({
  copy: [
    { src: 'node_modules/pdfjs-dist/cmaps', dest: 'public/pdfjs' },
    { src: 'node_modules/flag-icons/flags/4x3/*', dest: 'public/flags', rename: name => `${name}.webp`, transform: svg => toWebp(svg) }
  ]
})

With an own vite config, import copyPlugin from '@open-xchange/app-suite-ui-sdk/vite-plugin-copy' gives the same plugin.

defineConfig builds the usual plugin setup: src as root and dist as output, the dev proxy to SERVER from .env, manifests, $ externals, css and po2json. Vitest runs with jsdom on spec/**/*_test.{js,mjs} and src/**/*.test.{js,mjs}. options.vite and options.test are merged over the defaults.

// eslint.config.js
import config from '@open-xchange/app-suite-ui-sdk/eslint'

export default [...config]
// stylelint.config.js
import config from '@open-xchange/app-suite-ui-sdk/stylelint'

export default { ...config, rules: { ...config.rules } }
# lefthook.yml
extends:
  - node_modules/@open-xchange/app-suite-ui-sdk/configs/lefthook.yml

What doctor checks

  • packageManager and engines.node match the SDK.
  • devDependencies lists no tooling that the SDK or @open-xchange/lint provides, and none of the tools the SDK replaced (release-it, lint-staged, simple-git-hooks, husky, eslint-config-standard). The same packages in dependencies only get a warning, because the project may need them at runtime.
  • Workspace packages from the packages list in pnpm-workspace.yaml get the same dependency check. Their scripts only get warnings, because the SDK is a dependency of the workspace root. A package without "private": true is published and builds on its own, so it keeps its tooling and only gets warnings.
  • Scripts call ui-sdk instead of the tools. --fix rewrites single commands like vite build or eslint src and keeps their arguments. Scripts that chain commands, pipe or redirect get a warning and need a manual change.
  • pnpm-workspace.yaml has publicHoistPattern (so editors and test files find eslint, stylelint, typescript, vite and vitest, and the project's own configs still find every SDK package doctor removed from package.json), allowBuilds, minimumReleaseAgeExclude for @open-xchange/* (pnpm otherwise refuses a freshly released SDK version, which blocks the renovate bump), and the SDK security overrides.
  • lefthook.yml (or .lefthook.yml) extends the SDK config.
  • renovate.json (or .renovaterc.json, renovate.json5 and the other names renovate reads) extends the app-suite-ui-sdk preset. --fix creates the file when it is missing. An existing file without the preset only gets a warning, because projects keep their own rules there.
  • rlsy is installed globally, unless the project has its own release script. That is a warning only.

ui-sdk doctor exits non-zero while errors remain, so a CI job that runs it fails on drift. Add that job to the project's pipeline.

Security overrides

pnpm reads overrides only from the project root, so the SDK cannot pin a patched transitive version for its consumers by itself. Instead, security-overrides.json lists the overrides, and doctor --fix writes them into the project's pnpm-workspace.yaml with a # managed by ui-sdk comment. Managed overrides that the SDK no longer lists are removed again. An override the project set itself always wins, and doctor only warns about it.

A daily scheduled pipeline (with SECURITY_OVERRIDES=true) finds the overrides itself: it installs the packed SDK into a temporary project, runs pnpm audit --fix there and adds every new override to the list. If it finds one, it opens an MR with a Security: commit that merges once its pipeline passes, test projects included.

To add an override by hand, add it here and commit it with the Security: prefix. A push to main with such a commit releases right away instead of waiting for the weekly release. The renovate SDK bump in each project then runs ui-sdk doctor --fix as a post-upgrade task and automerges. For an urgent fix in one project, run pnpm exec ui-sdk audit --fix.

Releasing

Releasing stays out of the SDK. Projects release with a globally installed rlsy (pnpm add -g rlsy) and get no release script.

The SDK itself releases once a week. A scheduled pipeline on main runs rlsy --yes, which picks the version from the commits since the last release and counts renovate's "Update dependency" commits as changes. A security change does not wait: when a push to main brings a commit with [SECURITY] (renovate's security updates) or a Security: commit, the release job releases right away. Running a pipeline on main by hand also releases, from the GitLab UI or with glab ci run -b main. The tag the release job pushes starts the publish job.

Decisions

Agreed on 2026-11-03.

  • One package with everything. Projects without a vite build install the build tooling too. One version to bump matters more than install size.
  • Tooling only. Runtime libraries stay in the projects or come from core ui as $ externals.
  • Exact pins, no SDK lockfile. pnpm ignores a dependency's lockfile, and bundling the dependencies fails on platform-specific binaries (rolldown, sass, lefthook). Each project's own lockfile keeps its build reproducible.
  • One CLI. ui-sdk wraps every tool, so all projects run the same scripts. It has no release command.
  • Config factories with overrides. Projects keep only what differs from the defaults.
  • doctor --fix writes visible settings into package.json and pnpm-workspace.yaml instead of injecting them at install time.
  • Same tools everywhere. lefthook, the SDK's pnpm and Node version, enforced by ui-sdk doctor in CI.
  • @open-xchange/lint stays its own package. The SDK pins it and re-exports it.
  • Semver, released weekly. Security changes release right away. A tool bump that breaks consumers is a major. Consumers automerge minor and patch updates and review majors.
  • Test projects gate releases. Every SDK pipeline installs the packed SDK into the projects in test-projects and runs doctor --fix, lint, stylelint, test, build and audit there. A core ui pipeline per SDK MR was too heavy for every dependency bump.
  • Renovate everywhere through the app-suite-ui-sdk preset in web-foundation/renovate. Every project has the short renovate.json from Setup.
  • e2e is out of scope and gets its own SDK.
  • Rollout: core ui first, then the other vite projects, then the customer plugins.

Development

pnpm test            # unit tests
pnpm test:projects   # packs the SDK and runs it in each test project
pnpm test:projects vite-vue   # only one project

pnpm test:projects copies each project from test-projects into a temporary directory, installs the packed SDK there, and deletes the directory afterwards. It needs network access for the install and the audit. The test projects:

  • customer-plugin: a drifted customer plugin with eslint 8, release-it and no build.
  • vite-vue: vite with Vue, scss, po files and a unit test.
  • vite-tailwind: vite with Tailwind.
  • ui-like: shaped like core ui, with a workspace package, its own lefthook and renovate files, a chained build script, a runtime dependency and no vite config.

License

MIT