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

@itrocks/skin

v0.1.0

Published

Enables it.rocks applications to be skinned with custom templates, styles, and images

Readme

npm version npm downloads GitHub issues discord

skin

Enables it.rocks applications to be skinned with custom templates, styles, and images.

Status

The deterministic resolver validates file-specific and package-wide skin rules. The composed runtime integrations transparently replace final HTML templates, CSS stylesheets, and JPG or PNG images while preserving their public paths and native template or HTTP handling. The package is validated and ready for use; implementation evidence is tracked in the development plan.

Installation

npm i @itrocks/skin

Applications declare package-wide and file-specific replacements in the skin section of their config.yaml, or in the config.yaml of a package that contributes a skin. The framework merges package and application configuration through @itrocks/config.

YAML keys and values beginning with @ must be quoted:

skin:
  '@itrocks/home': /app/home
  '@itrocks/list/feed.html': /app/list/my-feed.html
  '@itrocks': '@my/skin'

Only final .html, .css, .jpg, and .png files used at runtime are eligible. Authoring files under src/ and SCSS sources are outside this package's responsibility.

Paths beginning with / will be relative to the application root. Paths beginning with ./ will keep the existing @itrocks/config behaviour and be resolved relative to the package that declares them.

Package skins and application overrides

A standalone skin package depends on @itrocks/skin, publishes a replacement tree, and contributes a package rule:

# @demo/blue-skin/config.yaml
skin:
  '@itrocks/home': ./content

The replacement tree keeps the published paths of the artifacts it replaces, including build directories:

content/
└── cjs/
    ├── container.html
    └── output.html

An application can keep that package skin and override one published artifact. Application configuration is loaded last by @itrocks/config, and the exact rule has priority over the package rule:

# application config.yaml
skin:
  '@itrocks/home/output.html': ./output.html

Copyable configuration layouts are available in the minimal application and the standalone skin package.

Resolver

Create the resolver from the merged skin configuration, validate it once during bootstrap, then resolve final files before reading or serving them:

import { appDir }       from '@itrocks/app-dir'
import { config }       from '@itrocks/config'
import { SkinResolver } from '@itrocks/skin'

const resolver   = new SkinResolver(config.skin ?? {}, appDir)
const validation = await resolver.validate()

if (!validation.valid) {
	throw new Error(validation.issues.map(issue => issue.message).join('\n'))
}

const resolution = resolver.resolve(templateFile, 'template')
const file        = resolution.replacement ?? resolution.original

resolve() accepts template, style, and image resources. It ignores files under src/ and unsupported extensions. Exact published paths win over build-directory aliases, which win over package rules. Package rules are partial: when the corresponding target artifact is absent, resolution silently falls back to the original artifact. An exact file rule remains strict because it explicitly promises one replacement file.

Targets and source rules containing traversal or mixed separators are rejected. Validation also resolves symbolic links and rejects any source or target that escapes its allowed package or application root.

Validation issues contain a stable code, the offending rule, and an actionable message. Applications should fail bootstrap when valid is false rather than accepting traffic with an invalid rule or target root.

Source rules and replacement layouts

The following rule forms are accepted. <relative> is the complete published path below the source package, such as cjs/views/feed.html, css/theme.css, or images/logo.png.

| Source rule | Scope | Paths searched below the target | |---------------------------------|--------------------------|----------------------------------------------------| | @itrocks/home/<relative> | One exact artifact | The configured target file | | @itrocks/home/views/feed.html | One HTML or CSS alias | The configured target file | | @itrocks/home | One package | <relative> | | @itrocks | Every package in a scope | @itrocks/home/<relative>, then home/<relative> |

HTML aliases omit one initial cjs/ or html/ directory. CSS aliases omit one initial cjs/ or css/ directory. Images have no alias. A complete exact rule takes priority over an alias, which takes priority over a package rule, which takes priority over a namespace rule.

Unscoped packages use the equivalent home/<relative> and home source forms. Namespace rules apply only to scoped packages and therefore always start with @.

Folder rules accept these target roots:

| Configured target | Resolved target root | |-------------------|-----------------------------------------| | /app/skin | <appDir>/app/skin | | @my/skin | <appDir>/node_modules/@my/skin | | @myappnamespace | <appDir>/node_modules/@myappnamespace |

For example, @itrocks: @my/skin searches a request for @itrocks/home/cjs/page.html first at node_modules/@my/skin/@itrocks/home/cjs/page.html, then at node_modules/@my/skin/home/cjs/page.html. If neither file exists, it uses the original node_modules/@itrocks/home/cjs/page.html without an error.

Diagnostics

Runtime diagnostics are disabled by default through the exported debug boolean. Enable them explicitly while investigating replacement searches:

import { debug, setDebug } from '@itrocks/skin'

console.log(debug) // false
setDebug(true)

setDebug(false) disables them again. The setter keeps the exported live debug value synchronized for both CommonJS and ES module consumers. Existing applications can alternatively enable the composed integrations through configuration:

skinDiagnostics: true

The composed template and Fastify integrations then write one console.debug entry whenever a matching rule starts a replacement search. Each entry contains the original physical file, the matching source-to-target configuration, all candidate replacement files in search order, and the selected replacement or explicitly labelled original fallback. Disable debugging after diagnosis because physical paths are intentionally included.

Library callers can collect structured events without console output:

const resolver = new SkinResolver(config.skin ?? {}, appDir, {
	diagnostic: event => audit.push(event)
})

Structured events expose rule, candidates, and final in addition to the normal resolution result.

Runtime integration

The package composes @itrocks/template:Template with its skin-aware implementation through config.yaml. It resolves the requested final template and optional container, then delegates parsing unchanged to Template. Includes inherit the composed class, relative includes use the replacement directory, and collected head dependencies keep the native template-engine behaviour.

The composed SkinFastifyServer intercepts only final .css, .jpg, and .png requests. It resolves their physical replacement, translates it back to an it.rocks static path, and delegates the response to Fastify. Public URLs, MIME types, caching statuses, missing-file responses, and unconfigured assets therefore retain the native server behaviour.

Package rules preserve the complete published path, including images referenced relative to a replaced CSS file. An exact CSS rule does not infer image replacements; each image needs its own exact rule. SCSS, JavaScript, TypeScript, SVG, WOFF2, and front-script discovery remain untouched.

The dedicated integration subpaths avoid circular facade loading.

The base configuration also seeds an empty skin object before dependent skin packages are merged. This lets @itrocks/config rebase their nested ./... target paths against the declaring package.

Compatibility

The release is validated against the package's current runtime stack:

| Component | Supported | Validated | |-----------|-----------|-----------| | Node.js | >=24 | 24.19.0 | | TypeScript | ^7.0 | 7.0.2 | | Fastify | 5.x | 5.12.0 through @itrocks/fastify 0.2.7 | | Template engine | current @itrocks/template | 0.2.3 |

Development

Run the complete resolver, template, HTTP, merged-configuration, and bootstrap suite:

npm test

Inspect the publication allow-list before publishing:

npm pack --dry-run --json

The archive contains config.yaml, the README, license, compiled JavaScript, and declarations. TypeScript sources, tests, source maps, examples, documentation sources, and caches are excluded.