@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.
