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

@xemahq/object-projection-nest

v0.6.3

Published

Shared NestJS building blocks for the XSI plane-1 object projection surface (`GET /describe-objects` + the `xema.object-registry.projection.published.v1` CloudEvent) that every XemaObject-owning service implements.

Readme

@xemahq/object-projection-nest

This package belongs to Layer 1 — it is a kernel-side NestJS SDK with zero domain knowledge and no dependency on any Xema service.

It ships the shared implementation of the XSI plane-1 object projection surface that every XemaObject-owning service exposes so object-registry-api can build the platform-wide object index:

| piece | export | | --- | --- | | GET /describe-objects wire DTOs | DescribeObjectsResponseDto, XemaObjectResponseDto, XemaSpaceRefDto, XemaSubjectRefDto | | CloudEvent descriptor factory | defineObjectProjectionEvents(serviceName) | | change-driven publisher with reconcile-on-boot | ObjectProjectionPublisherService | | the slice content digest it compares | projectionEnvelopeDigest(envelope) |

Freshness model: reconcile on boot, publish on change

The publisher pushes the COMPLETE slice unconditionally at boot and thereafter only when the slice has actually changed.

  • boot — always publishes. A fresh process knows nothing about what the registry currently holds for its source, so this is what repairs a slice whose publish was dropped or failed before the last restart.
  • every PROJECTION_REFRESH_INTERVAL_MS — builds the envelope, digests it locally, and publishes only if the digest differs from the last successfully published one. In a quiet hour this puts nothing on the bus.
  • scheduleRepublish() — an optional per-write hook that collapses detection latency from one interval to PROJECTION_DEBOUNCE_MS. It passes the same digest gate, so a write that projects to identical content still publishes nothing. Wiring one can only ever make a producer more responsive, never noisier.
  • publishProjection(Manual) — forced, like boot. "Force a resync" that silently did nothing would be worse than the republish it saves.

The interval is a POLL, not a heartbeat, and it is deliberately still here: most producers in the fleet wire no per-write hook, so for them it is the change signal. Deleting it would leave them publishing at boot and never again — the registry's cache would go stale on every write with nothing anywhere reporting a failure.

The baseline is per PROCESS and in memory. Two replicas each publish once per real change instead of once a minute each; the consumer applies an idempotent REPLACE, so the duplicate costs nothing.

Producer shape

A producing service adds one describe-objects/ folder:

// projection-events.registry.ts
export const { descriptor: ObjectRegistryProjectionPublishedEvent, descriptors } =
  defineObjectProjectionEvents('knowledge-base-api');

// describe-objects.service.ts — builds the COMPLETE current slice
@Injectable()
export class DescribeObjectsService {
  async buildEnvelope(): Promise<DescribeObjectsResponseDto> { /* … */ }
}

// projection-publisher.service.ts — PUSH path (optional; PULL alone is valid)
@Injectable()
export class ProjectionPublisherService extends ObjectProjectionPublisherService {
  constructor(
    publisher: DescriptorEventPublisherService,
    describeObjects: DescribeObjectsService,
  ) {
    super(publisher, {
      source: KNOWLEDGE_BASE_PROJECTION_SOURCE,
      descriptor: ObjectRegistryProjectionPublishedEvent,
      buildEnvelope: () => describeObjects.buildEnvelope(),
    });
  }
}

Layout note

Sources live under src/projection/ (not src/lib/) and the package declares a ./* subpath export. This is load-bearing, not cosmetic: the @nestjs/swagger CLI plugin emits a require() of a DTO's physical declaration path, which tooling/codegen/scrub-swagger-plugin-paths.mjs rewrites to @xemahq/<pkg>/<first-dir-under-dist>. If that directory is not a resolvable subpath export, every consuming pod crashes at boot with ERR_PACKAGE_PATH_NOT_EXPORTED. Same convention as @xemahq/kernel-contracts. Consumers import from the package root.

Invariants

  • A projection is always the COMPLETE slice. The registry REPLACES its cache slice keyed by source atomically; there is no delta primitive.
  • payload is opaque on the wire. The per-kind payload schema is owned by the producing service's domain contract; plane 1 carries it through and plane 3 (Capability) is the validation point.
  • A row that cannot be projected (missing scope qualifier, missing version) MUST throw a typed error carrying the row id. Never skip it silently.
  • The publisher logs and does not rethrow on transport failure — a cache-refresh push must not crash its host. The next tick retries because the baseline advances only after publish resolves, and the consumer can always recover the same slice over the pull path.
  • An ABSENT key and an EMPTY collection are different slices. The digest uses the kernel's canonicalJsonStringify, which drops an undefined property and keeps [], so a producer that starts emitting an empty collection where it previously omitted the key republishes once. That is correct, and it costs nothing across a deploy because the boot publish re-seeds the baseline anyway.