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

@tschk/moonshine-astro

v0.4.49

Published

Native signal bridges and rendering with optional legacy astro entries

Readme

@tschk/moonshine-astro

The root provides native Moonshine signal bridges and a lazy native renderer. At runtime, root imports need neither Astro, React, parser WASM nor the optional framework peer. Legacy host APIs remain explicit on their existing subpaths.

Strict TypeScript checking of the root entry requires installing @tschk/moonshine-framework, even when importing only a bridge: the root also exports crepusRenderer with the framework's Renderer contract. The framework remains optional for runtime imports and bridge-only browser/Bun/Node bundles. This requirement does not apply to the signal-only @tschk/moonshine core entry.

import { fromMoonshineSignal, crepusRenderer } from "@tschk/moonshine-astro";

| Entry | Provides | | ------------ | ---------------------------------------------- | | . | Native signal bridges and lazy native renderer | | ./compiler | Legacy Astro compiler re-exports | | ./ssr | Independent synchronous Astro source factories |

crepusRenderer preserves its compatibility name but renders native server factories, escaped metadata, API JSON and SPA shells. Install @tschk/moonshine-framework when invoking this source-file compatibility facade under Bun. Bundled deployments use @tschk/moonshine-dom/framework-native explicitly; the facade intentionally keeps source loading outside the static bundle graph. Legacy React/View IR page outputs reject; native island hydration is unsupported. The renderer loads only when called, so signal bridge consumers do not load server rendering.

Legacy entries require their optional host peers: astro. They cannot be aliased over arbitrary host-compiled output to remove the host.

The compiler entry still requires Astro. The independent /ssr entry supplies factories for Crepuscularity-authored server modules; it does not implement Astro's compiled component ABI. It preserves HTML attributes, normalizes class:list and style objects, escapes ordinary children and keeps component props independent of any host runtime.

Local Crepuscularity integration now lowers fenced .astro frontmatter into per-render synchronous factories, including typed Props, Astro.props, static imports, imported children, conditionals and simple maps. This compiler work is not yet published. Scriptless entry files retain the older scope-based template path. Parsing and lowering stay in Crepuscularity.

This remains a bounded source slice: top-level await, dynamic imports, client directives, script/style blocks, runtime exports, async children, and Astro globals other than Astro.props are unsupported. Hydration and arbitrary host-compiled output are unsupported. Use the legacy compiler explicitly for applications requiring the full Astro compiler contract.

Run the authored-source regression with an explicitly supplied local compiler:

MOONSHINE_CREPUS_COMPILER=/absolute/path/to/crepus bun test packages/adapter-astro/test/standalone.test.ts

It checks prop/interpolation capture, deferred component setup, short-circuit values, optional maps, slots and component prop identity in isolated Bun and Node consumers. Without the variable, that compiler integration case is explicitly skipped; runtime cases still run.

The local authored compiler retains whitespace in pre/textarea, including nested elements and expression boundaries, and keeps same-line root sibling separators. These factories serialize initial newlines using literal HTML rules; the browser consumes the first newline after pre/textarea. Ordinary native DOM factories keep their existing textarea property-value behavior.

Conditional and mapped markup retains text punctuation, including apostrophes, colons, question marks and operator-like text. Nested template substitutions work in child and attribute expressions, while quoted attribute braces stay literal. Authored regex/division boundaries use Crepuscularity's existing JavaScript parser, including nested templates, attributes and JavaScript groups. Astro void tags stay in the markup frontend; no host runtime or parser enters the SDK. Namespace/directive attributes, generic Props, and map callbacks with index/destructuring/block bodies are not yet supported. These parser limits remain work in Crepuscularity.

Local component prop spreads now preserve ordinary JavaScript override order, getter evaluation and own string/symbol keys. Forwarding Astro.props works through imported components; ordinary children/slots props remain separate from projected slots. Spread class:list normalizes against the final class after overrides. Nullish spreads contribute no props. Slot outlet spreads remain rejected. Compiler lowering is local and unpublished.

Local intrinsic spreads use ordered attribute segments rather than merged props. Own enumerable string getters run once, in order, with coercion before the next getter/expression; inherited and symbol keys are ignored. Function values stringify without invocation. Literal and dynamic boolean values retain their separate rules. Repeated attributes (including spread classes) remain separate; HTML parsing keeps the first. Authored class plus class:list combines at the directive position. The opt-in /ssr compiler helpers are sourceAttribute, sourceSpread and sourceElement; ordinary no-spread factories retain their existing path.

Moonshine retains its server constraints: event attributes are filtered, invalid names throw, script/style elements and spread directives/namespaces reject. These differ from Astro's more permissive spread handling. Nullish spreads are empty; string/array index keys fail attribute-name validation. Raw-content-looking names remain escaped ordinary attributes, not HTML injection instructions.

An authored fixture passes three fresh SSR requests in Bun and minified Node, plus Chromium parsing, input editing and form reset with no client script. Six parsed cases match actual Astro 7.4.0 attribute helpers, with event filtering recorded separately. The reference uses compiler 4.0.0 segment output and runtime helpers separately, not a complete host compilation/rendering comparison. The fixture is 5,860 gzip bytes; an ordinary no-spread control stays 12,844 raw bytes and changes from 4,902 to 4,903 gzip bytes. No host bundle or speed claim.

Without prop spreads, combined class and class:list use the existing helper. The ordinary class evaluates first at the directive position. Empty HTML classes are omitted. Component factories omit an empty normalized class-list prop while retaining an explicitly supplied empty ordinary class prop.

Local authored slot lowering now supports default and nonempty literal named slots, grouping of same-name children, named Fragments and forwarding through imported layouts. An explicit empty slot suppresses fallback; whitespace-only ordinary component content supplies no slot. Projected HTML loses the marker, while projected components retain their ordinary slot prop. Dynamic/empty outlet names and misplaced markers reject explicitly. Astro.slots.render, the slot bag, method extraction, computed/optional access and unrelated Astro globals remain unsupported.

Local source now supports ordinary Astro.slots.has(nameExpression) calls in frontmatter and template expressions, including dynamic strings and nested Astro.props reads. For example:

---
interface Props { lookup?: string }
const present = Astro.slots.has(Astro.props.lookup ?? "head");
---
<section data-present={String(present)}><slot name="head">fallback</slot></section>

Presence uses the existing native own-slot protocol: an explicitly empty supplied slot counts, missing/inherited names do not. The query never renders content or reads its value. It works without a slot outlet; an unused child that would throw stays unevaluated. Shadowed local Astro bindings remain ordinary JavaScript. Native own-slot behavior differs from Astro's inherited-name and reserved-member quirks; it does not implement the host Slots instance ABI.

The real Astro 7.4.0 Slots class and @astrojs/compiler 4.0.0 were checked separately for presence values and emitted slot shapes. Six native source cases pass repeated fresh Bun/minified Node SSR, with dynamic argument evaluation once and no Astro/React/parser WASM in the runtime graph. Both source/declaration type lanes pass. The native fixture is 5,592 gzip bytes; there is no full host bundle or timing comparison. A no-slot control bundle is byte-identical before/after the helper addition. Compiler changes remain local and unpublished.

Generated calls use the compiler-facing sourceComponent / sourceSlot / sourceHasSlot contract. Slot values stay outside ordinary props, including children and slots. Props and template interpolations capture when the parent constructs its template; component frontmatter runs during serialization, once per invocation. Unused slot content stays lazy, repeated outlets render it again, and fallback interpolations capture eagerly while fallback components defer. Deferred content retains its caller's native SSR owner. Construct these helpers inside renderToString(() => ...); ordinary public h invocation is unchanged. This compiler integration is local and unpublished. The companion runtime helpers are available in SDK 0.4.22. This is not Astro's compiled component ABI; async rendering, hydration and full slot/source coverage remain incomplete.