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

@shoplifter/presentation-sdk

v0.3.4

Published

Portable Astro rendering and authoring integration for Shoplifter presentations

Readme

Shoplifter presentation SDK

Apache-2.0 for Shoplifter-owned code; bundled components retain their own licenses. See LICENSE, NOTICE, THIRD_PARTY_NOTICES and vendor/THIRD_PARTY_NOTICES. The license covers this package, not the private Shoplifter backend or customer content.

Runtime and installation

Authored Markdown renderers (0.3.1)

HEN-355's presentation renderer map is available in standalone publications. Add an optional src/markdown.ts exporting markdownRenderers:

import type { MarkdownRenderers } from '@shoplifter/presentation-sdk/markdown';
export const markdownRenderers: MarkdownRenderers = {
  '/': ({ values, text }) => `# ${text(values.title)}`,
};

MarkdownContext, MarkdownRenderer and MarkdownRenderers retain the HEN-355 route patterns and host-provided text, html and link helpers. Context comes from the same captured language, published records and resolved data as HTML. The map runs only during rendering, supports async functions, and must include / when supplied. Other routes use the shared content/blog fallbacks. Projects without a map remain supported.

Both static and reusable builds emit /index.md, /contact-us.md, /pages/<slug>.md and /blogs/<blog>/<article>.md, including blog pagination. The support shell has no Markdown representation. HTML advertises its alternate; the public gateway also negotiates explicit Accept: text/markdown on public page URLs. Markdown remains uncached and canonicalizes to HTML. Preview access and immutable revision-asset restrictions apply to Markdown documents too.

YouTube thumbnails and external images (0.3.0)

---
import YouTubeThumbnail from '@shoplifter/presentation-sdk/YouTubeThumbnail.astro';
import ExternalImage from '@shoplifter/presentation-sdk/ExternalImage.astro';
import { parseYouTubeUrl, youtubeEmbedUrl } from '@shoplifter/presentation-sdk/youtube';
---
<YouTubeThumbnail url="https://youtu.be/dQw4w9WgXcQ?t=90" alt="Video" />
<ExternalImage src="https://images.example/photo.jpg" alt="Photo" width={640} height={480} />

YouTubeThumbnail accepts watch, shortened, Shorts, live and embed URLs (including scheme-less links), validates the video ID and generates the exact YouTube thumbnail. Its dimensions default to 480×360. Both components require alt (an empty string is valid for decorative content), default to lazy loading and asynchronous decoding, and accept styling and loading attributes. Protected URLs and SDK markers cannot be overridden. ExternalImage requires positive numeric dimensions and an absolute HTTPS URL without credentials; it does not download, proxy or optimize the image.

Using ExternalImage is explicit consent to third-party requests. CLI validation, builds and publication logs warn without blocking: visitors contact external hosts, and images may change or disappear. There is no owner toggle or domain allowlist. YouTube thumbnails are allowed directly without that warning. Raw image tags and external CSS image URLs remain restricted; use Picture for channel-owned assets.

parseYouTubeUrl(url) returns { videoId, startSeconds? } or null. Timestamp precedence is t, start, then #t; malformed timestamps are ignored. youtubeEmbedUrl(parsed, { autoplay: true }) creates a privacy-enhanced player URL and preserves the timestamp. youtubeThumbnailUrl(videoId) generates the thumbnail URL. Carousel layout, timers and player overlays remain presentation code.

Use Node 24 and Astro 7.4.4 or a compatible later 7.x release. The matching CLI, SDK and contract release versions are distributed together. Install the CLI with npm install --global @shoplifter/cli after the prepared release is published.

shoplifter init ./my-site my-site downloads the CLI's matching public SDK/contract versions and verifies their npm SHA-512 integrity. It stores them in vendor/, so generated projects have no workspace links. Explicit local SDK and contract archive arguments remain supported for offline setup.

Run npm install, shoplifter fixtures generate, shoplifter types, and npm run dev. Fixture development and static builds do not require Vendure. Run shoplifter fixtures reset only when existing fixture edits should be replaced. Authored homepage, header, footer and CSS are never regenerated implicitly.

Public exports

@shoplifter/presentation-sdk exports runtime data resolution and its TypeScript interfaces. /integration supplies the managed Astro integration. /Picture.astro renders responsive channel images, /Decorative.astro renders decorative vectors, /InquiryForm.astro provides inquiries, /theme exposes existing theme helpers, /links exposes link helpers, and /live provides trusted-server live API handlers. Do not bundle /live into browser code or pass server credentials to components.

The SDK owns document metadata, language/direction, public editorial/contact routes and the private support shell. Projects own homepage/header/footer components and styling. Additional routes and replacement shared templates are unsupported. Use Picture for raster images. Decorative SVG and local fonts are exceptions; SVGs must not embed raster images. Published images must use channel-owned assets.

Typed lead forms

Import type, defineLeadForm, fetchLeadContext and submitLead from @shoplifter/presentation-sdk/leads. Define flat ArkType schemas in src/leads.ts and export leadForms = [{ form, component: 'src/LeadForm.astro' }] and defaultFormId. Set persist: true to retain submissions; the default is forwarding only, which requires a configured webhook.

Set leads.source in shoplifter.json to src/leads.ts. Running shoplifter types, validation or upload compiles the portable definitions into the manifest locally. The server validates this data without executing author TypeScript. Form IDs and versions are immutable, and publication activates them. Each registration provides its own Astro component; the default also renders at /contact-us. Preserve preview restrictions with disabled controls when preview is true or mode is not published.

For static publications, obtain a fresh context with fetchLeadContext(form.id) before submitLead(form, context, values, idempotencyKey). Reuse the key for unchanged retries. Contexts are bound to the resolved site, form and hostname; never provide a tenant ID from the browser. Keep secrets and lead payloads out of presentation source. SDK LeadSubmittedEvent describes the outgoing webhook.

Browser transport (0.3.2)

The @shoplifter/presentation-sdk/leads/browser entry exports fetchLeadContext(formId, fetcher?) and submitLead(context, values, idempotencyKey, fetcher?) without importing form definitions or ArkType. This entry is available starting with SDK 0.3.2. Use it in browser code that only submits values; keep schema definitions in the authoring module. The existing /leads entry retains its form argument and client validation. Both entries use the same endpoints, payloads, errors and server validation. Preserve preview restrictions and reuse the idempotency key for unchanged retries.

import { fetchLeadContext, submitLead } from '@shoplifter/presentation-sdk/leads/browser';

const context = await fetchLeadContext('inquiry');
await submitLead(context, { name, phone }, idempotencyKey);

Production publishing

Set SHOPLIFTER_API_URL to the platform HTTPS origin. shoplifter dependencies sync downloads the platform-approved public runtime without logging in and explicitly updates the project's dependency lock. Package visibility grants no deployment access. Use shoplifter login for upload, stage, preview, publication, activation and rollback. Production still validates exact runtime bytes, lock integrity and returned build output. Snapshots retain the approved runtime archives; public package availability cannot silently change an existing revision. Preview and published content remain separate.

Reusable private rendering

The integration accepts { mode: 'renderer' }, or the isolated compiler sets SHOPLIFTER_BUILD_MODE=renderer. This compiles project components and managed routes using the pinned official Node adapter, without capturing publication data. The platform retains dist/, .shoplifter/renderer-project.json, package metadata and locked runtime dependencies privately.

@shoplifter/presentation-sdk/renderer exports renderPublication, which accepts a fresh materialized compiled directory, an empty output directory, one immutable snapshot, and language-to-origin/asset-base maps. It enumerates managed routes from that snapshot and writes a complete language tree of static HTML and assets. Run this interface only in the isolated execution environment. Returned files still require trusted output validation. The private Node renderer is never a public SSR service.

Ordinary astro build remains static. Runtime upgrades require explicit shoplifter dependencies sync; retained source archives remain unchanged.

Instant browser preview

Set shoplifter({ browserPreview: 'src/editor-preview.ts' }) to opt in. Export renderPreview(root, state, select) from that module. The dashboard passes the home page path (state.page), language (state.language), current draft (state.values), and authorized asset previews (state.assets). Call select('services.0.title') to focus a field in the dashboard.

The SDK bundles the entry once during renderer compilation. Use browser JavaScript or TypeScript and keep the bundle under 512 KiB. Use inline styles and approved HTTPS asset previews. Render from the provided state on every call and share rendering logic with the Astro components where possible. Generate a standard protected preview after staging a new source to prepare its private bundle and delivery origin. Subsequent edits render in the browser. Publish still validates the draft and runs the static build.

Inspect shoplifter files before upload. Do not put credentials or private records into presentation source. Ignore rules and exclusions prevent common accidental uploads, but cannot identify all secrets embedded in otherwise legitimate source.

User-selected article sections

Article-list requirements may set allowUserSelection: true in data.json. The Website content editor then offers Automatic and Manual modes for that requirement. The developer's blog source and take maximum remain fixed; owners can select fewer articles and control their order. Omitted or false flags keep the existing automatic ordering. Components receive the same article arrays.

Selections are platform metadata saved and published with each language's content, rather than editable definition fields. Manual lists never fill missing slots automatically: unpublished, deleted or moved articles are omitted, and an empty list stays empty. Draft selections affect authenticated previews only. Changing the full blog order does not change a manually selected homepage list.

Before publishing an unreleased SDK, synchronize explicitly packed local archives: shoplifter dependencies sync /absolute/path/sdk.tgz /absolute/path/contract.tgz. Without archive arguments, synchronization continues to use the platform or npm.