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

@ue-shed/unreal-assets

v0.8.0

Published

Validated, read-only inspection of saved Unreal Engine asset packages.

Readme

@ue-shed/unreal-assets

Project Index aggregate queries return a count and its committed generation without loading all candidate headers. countProjectIndex({ projectId, expectedGeneration, filters }) accepts 1–16 ProjectIndexFilter values: Maps, ExactClasses, ClassPrefixes, ClassNameSuffixes, or SerializedNames. Each filter except Maps requires a values array of 1–64 non-empty strings. Empty filter lists are rejected. A package matching any filter counts once, even when several filters match. The production binary Catalog reads checked snapshot postings; SQLite is used only for explicit oracle tests.

The CLI translates repeatable selector flags into these filters. With no selector flags, it returns zero for the committed generation without invoking the count API:

pnpm ue-shed project-index count 'C:/Projects/Game' 'C:/Caches/Game' --exact-class '/Script/Engine.StringTable' --serialized-name 'TextProperty'

Run project-index refresh first if the catalog is absent or needs to discover disk changes.

The process and compatibility boundary for read-only inspection of saved Unreal asset packages. It discovers a compatible uasset executable, validates its versioned CLI JSON output, and returns normalized package evidence with explicit partial and unsupported results.

npm install --save-exact @ue-shed/unreal-assets @ue-shed/uasset

Node.js 22.14 or newer is required. The package exposes one stable entry point:

import {
	AssetReader,
	AssetReaderLive,
	discoverSavedAssets,
	readSavedAsset,
	readSavedBlueprint,
	readSavedWorld,
	readSavedTable,
	scanSavedProject
} from "@ue-shed/unreal-assets";

Reading one saved Blueprint graph

readSavedBlueprint opens one uncooked .uasset in the supported UE 5.7 saved-revision window and returns a schema-1 saved-graph projection together with the protocol outcome and diagnostics. The projection includes graph and node identity, saved node positions, pin types and defaults, pin hierarchy, canonical links, arbitrary tagged node properties, and explicit coverage gaps. Graph and node discovery follows saved membership rather than an engine class allowlist, so engine, plugin, and project subclasses share the same topology path. It neither starts Unreal nor compiles the Blueprint.

const { blueprint, diagnostics, outcome } = yield * readSavedBlueprint({ assetPath });
const eventGraph = blueprint.graphs.find((graph) => graph.name === "EventGraph");

The operation is intentionally read-only and currently targets UE4 522 packages with UE5 saved revisions 1012, 1013, 1017, or 1018. Cooked/editor-filtered packages, Control Rig's separate RigVM model, referenced-package loading, bytecode reconstruction, and package mutation are outside this boundary. A non-empty coverage_gaps array means the topology remains useful but a reference, native property payload, or node-subclass tail was not fully projected.

Reading one saved map

readSavedWorld invokes the map-targeted uasset saved-world operation. Unlike a project scan, it reads a conventional level's single .umap or, for World Partition, only the selected map's __ExternalActors__ subtree. The returned catalog carries saved-package authority, actor package/object identity, class and label evidence, plus a transform-resolution status. It can be partial when unrelated exports fail to decode while actor transforms remain usable. Contract v2 exposes finite effective location, quaternion rotation, and scale plus direct root-component attachment paths without inferring parent actor ownership.

const world =
	yield *
	readSavedWorld({
		mapPath: "Content/Maps/L_Example.umap",
		projectRoot
	});

const transformedActors = world.actors.filter((actor) => actor.transform.status === "resolved");

This is saved disk state, not a live Observatory snapshot: bounds, Focus in Unreal, Follow, and camera framing still require a connected editor authority. maximumAssets is a pre-decode safety limit (100,000 by default in the native reader); exceeding it returns AssetReaderError with kind: "resource_limit".

SavedWorld is one authority-tagged current read, not a historical corpus. Cross-run actor identity, daily observation lifecycle, diff policy, persistence, retention, and capture correlation belong to the consuming product.

Scanning a whole project

For routine project opening and repeated candidate queries, prefer the headless ProjectIndex over a whole-project scan. Its refresh operation performs one Content traversal and publishes a committed Generation to a disposable Catalog; maps and header-evidence queries return stable pages capped at 1,024 items. Callers configure the cache root, but never depend on SQLite tables or filenames.

const events = refreshProjectIndex({ projectRoot });
const page =
	yield *
	queryProjectIndex(
		ProjectIndexQuery.cases.ExactClasses.make({
			expectedGeneration,
			limit: 100,
			projectId,
			values: ["/Script/Engine.Texture2D"]
		})
	);

Queries do not silently refresh. If the expected Generation is stale, refresh and restart paging; if the disposable Catalog is corrupt or incompatible, use rebuildProjectIndex. scanSavedProject remains the explicit compatibility API for callers that genuinely need a generic scan.

Query results are deeply frozen after domain validation. The same validated page can pass through the process adapter and public helper without rechecking every name; arbitrary inputs still run the complete schema. Copy a result if a consumer needs a mutable working model. The paired native adapter requests protocol v1.3 dictionary pages, which share repeated strings during transport and expand to the existing public string arrays. Older workers require an upgrade; callers of the native v1.1 query format can still omit pageEncoding to receive ordinary pages.

countProjectIndex({ projectId, expectedGeneration, filters }) counts distinct package paths matching any of 1–16 ProjectIndexFilter values. Overlapping filters count each package once. The native v1.4 operation reads checked postings without loading header evidence. It shares the query session and stale-generation behavior. Use it for badges and summaries that only need a count; ordinary queries still return complete evidence. The memory adapter computes the same union from pages and remains usable without the native worker.

scanSavedProject invokes uasset scan <project-root> once and streams newline-delimited results back, so a project-wide scan costs one process instead of one per package. Prefer it over discoverSavedAssets plus readSavedAsset per path.

classes, classPrefixes, and names are selection rules the reader evaluates against each package header, so packages that cannot hold what you are looking for are never fully read or decoded. A package is selected when it matches any rule; with no rules every package is selected. names matches the package name table, which selects by serialized property type — a package holding any FText names TextProperty in its header.

// Every Texture2D in the project.
scanSavedProject({ classes: ["Texture2D"], projectRoot });

// Everything under one folder, plus one specific package.
scanSavedProject({
	paths: ["Content/Characters", "Content/UI/T_Icon.uasset"],
	projectRoot
});

paths narrows enumeration to directories or individual .uasset files, relative to the project root or absolute, and must resolve inside it. It defaults to Content. maximumAssets refuses a scan during enumeration, before any package is decoded, and surfaces as an AssetReaderError of kind resource_limit.

Pass inventory: true when a caller needs a persisted project signature. The same native scan then streams the path, size, and modified time of every package and .uexp, .ubulk, or .uptnl sidecar beneath the selected roots. This inventory is independent of class filters, so a client can derive maps and validate its own cached projections without a second Node filesystem walk.

resolveScanTarget turns any user-supplied path into the projectRoot and paths pair a scan needs, so callers accepting a path from a person do not each reimplement the walk:

// A project root or .uproject scans all of Content; anything else scopes to itself.
const target = yield * resolveScanTarget("Fixture/Content/Characters");
yield * scanSavedProject({ ...target, projectRoot: target.projectRoot });

It walks up to the owning .uproject and fails when there is none, because object paths are only meaningful relative to a project root.

Its authoring payload is derived from the same language-neutral schema and snapshot contract emitted by UEShedAuthoring; it is not a second package-reader-specific authoring model.

This package owns process execution, schema-version negotiation, limits, and diagnostics. It does not own DataTable authoring policy, live editor state, mutation, or Save.

readSavedTable sends one uasset-io protocol request and validates every streamed result against the shared runtime contract. readSavedTable and readSavedAsset share one lazily started native protocol session for the lifetime of their AssetReader layer. Calls are serialized through that bounded worker; interruption terminates it, and closing the layer closes the process. Project scans remain explicit batched operations in fresh workers. Protocol validation rejects excess fields on every frame; measured large frames use the schema's exact type-side parser, while smaller frames use the normal decoder. The executable keeps the human authoring command for compatibility. Callers can pass an explicit executable, set UE_SHED_UASSET_EXECUTABLE, or provide uasset on PATH. The UE Shed source-checkout launchers incrementally build crates/uasset-io and configure its executable automatically; this package does not depend on a monorepo-relative path. Expected partial outcomes are typed terminal protocol events; the legacy human command retains exit code 6 for compatibility.

The reader currently normalizes DataTables and the parser's supported saved-asset inspection models. Unsupported classes, parser versions, malformed output, process failures, and configured limits are represented explicitly by the exported schemas or AssetReaderError; untrusted parser output is always validated. This library does not mutate or save packages.

@ue-shed/uasset is the separately published executable launcher. The library never downloads a binary and never falls back to a source checkout. Use assetReaderLayer to configure an explicit executable when embedding another compatible producer.

License

MIT. Unreal Engine is a trademark of Epic Games, Inc. This project is not affiliated with or endorsed by Epic Games.