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

@weblakecms/cli

v0.1.2

Published

WebLake CLI — init, schemas, and content management

Readme

@weblakecms/cli

The official WebLake command-line tool. Use it to scaffold projects, export and import content schemas and items, and generate typed React block renderer components from your CMS schema definitions.

weblake <command> [sub-command] [options]

Table of Contents


Installation

Global (recommended for local development)

npm install -g @weblakecms/cli
# or
pnpm add -g @weblakecms/cli

Monorepo / project-local

npm install --save-dev @weblakecms/cli
# then run via
npx weblake <command>

From source (development)

cd packages/cli
npm run build
node dist/index.js --help

Configuration

The CLI reads two files from the current working directory (or any ancestor directory):

| File | Purpose | |---|---| | .weblake.json | Management API credentials (apiUrl, token) | | .env.local | Delivery API credentials (WEBLAKE_API_KEY) |

Run weblake init to create both interactively. Add both files to .gitignore — they contain secrets.

.weblake.json format

{
  "apiUrl": "http://localhost:3000",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
  • apiUrl — Base URL of your CMS instance (no trailing slash).
  • token — Management JWT. Obtain it from your browser's localStorage (authToken) after logging into the CMS, or from the Platform UI API key section.

.env.local format

WEBLAKE_API_URL=http://localhost:3000
WEBLAKE_API_KEY=wl_live_...

Only required when you also use @weblakecms/sdk in the same project.


Commands

weblake init

Interactively configures the CLI for the current workspace.

weblake init

What it does:

  1. Prompts for CMS API URL (default: http://localhost:3000).
  2. Prompts for your Management JWT token.
  3. Prompts for your Delivery API Key (wl_live_…).
  4. Writes .weblake.json with the management credentials.
  5. Writes or patches .env.local with the delivery credentials.
  6. Patches .gitignore to exclude both files.

Example session:

$ weblake init

WebLake CLI — workspace setup
──────────────────────────────────────────
? CMS API URL: http://localhost:3000
? Management JWT (from browser localStorage > authToken): eyJ...
? Delivery API Key (wl_live_...): wl_live_abc123

✅  Written .weblake.json
✅  Written .env.local
✅  .gitignore updated

weblake schemas export

Downloads all schemas for the configured tenant as a JSON bundle.

weblake schemas export [options]

Options:

| Flag | Default | Description | |---|---|---| | -o, --output <file> | schemas.json | Path to write the bundle |

Example:

# Export all schemas to the default file
weblake schemas export

# Export to a custom location
weblake schemas export -o ./backups/schemas-2025-01-15.json

Bundle format:

{
  "version": "1.0",
  "type": "weblake-schema-bundle",
  "exportedAt": "2026-06-16T12:00:00.000Z",
  "schemas": [
    {
      "slug": "blog-post",
      "name": "Blog Post",
      "tier": "content_type",
      "currentSchema": {
        "fields": [...],
        "$refs": {
          "link": { "name": "Link", "fields": [...] },
          "button": { "name": "Button", "fields": [...] }
        }
      }
    }
  ]
}
  • Every schema entry nests its field definitions and cross-schema references inside currentSchema.
  • $refs is populated automatically by the export endpoint — it inlines all schemas referenced by field types (e.g. type: "banner") plus the built-in composite types (link, button, menu_item) so the CLI has full type information without needing a live API connection.
  • The bundle is suitable for version control and for importing into another WebLake instance.

Tip: The CMS Copy JSON button (on the Schemas page) emits the same bundle envelope even for a single schema — so you can always pipe its output directly to weblake generate.


weblake schemas import

Uploads a previously exported schema bundle back into the CMS. Existing schemas with matching slugs are updated; new slugs are created.

weblake schemas import [options]

Options:

| Flag | Default | Description | |---|---|---| | -f, --file <file> | schemas.json | Path to the bundle file |

Example:

# Import from the default file
weblake schemas import

# Import from a specific bundle
weblake schemas import -f ./backups/schemas-2025-01-15.json

Notes:

  • Field order within a schema is preserved from the bundle.
  • Importing does not delete schemas that are absent from the bundle.
  • The API applies upsert semantics: slug is the unique key.

weblake content export

Downloads published content items as a JSON bundle.

weblake content export [options]

Options:

| Flag | Default | Description | |---|---|---| | -o, --output <file> | content.json | Path to write the bundle | | -s, --schema <slug> | (all schemas) | Export only items of this schema type | | --ids <id,...> | (all items) | Export only specific item IDs (comma-separated) |

Examples:

# Export all content
weblake content export

# Export only blog posts
weblake content export --schema blog-post -o blog-posts.json

# Export specific items
weblake content export --ids abc123,def456 -o selected.json

Bundle format:

{
  "exportedAt": "2025-01-15T12:00:00.000Z",
  "tenantId": "acme",
  "items": [
    {
      "id": "abc123",
      "schemaSlug": "blog-post",
      "slug": "my-first-post",
      "status": "published",
      "data": { "title": "My First Post", ... },
      "publishedAt": "2025-01-10T09:00:00.000Z"
    }
  ]
}

weblake content import

Uploads a content bundle to the CMS. Items are upserted by id; missing items are created; existing items are updated.

weblake content import [options]

Options:

| Flag | Default | Description | |---|---|---| | -f, --file <file> | content.json | Path to the bundle file |

Example:

# Import from the default file
weblake content import

# Import from a specific bundle
weblake content import -f ./blog-posts.json

Notes:

  • The status field in the bundle is respected. Items that were published in the export will be published after import.
  • Importing does not delete content that is absent from the bundle.
  • Referenced media assets must already exist in the target tenant.

weblake generate

Generates fully-typed TypeScript/TSX block renderer components from a WebLake schema JSON definition or bundle.

weblake generate [schema-file] [options]

Arguments / options:

| Argument / flag | Default | Description | |---|---|---| | [schema-file] | (stdin) | Path to a schema JSON file or bundle. If omitted, JSON is read from stdin. | | -n, --name <name> | (derived from slug) | Override the display name — single-schema mode only | | -o, --out <path> | (cwd) | Output file (single schema) or directory (bundle). See behaviour table below. | | --no-register | (auto-register) | Skip auto-patching registry.tsx |

Accepted input formats

The command auto-detects the input format:

| JSON shape | Behaviour | |---|---| | { "type": "weblake-schema-bundle", "schemas": [...] } | Bundle mode — one .tsx file per schema entry | | { "slug": "...", "fields": [...] } | Single-schema mode — one .tsx file | | [{ "name": "...", "type": "..." }, ...] | Raw fields array — one .tsx file (slug required separately) |

-o output path behaviour

| Condition | Result | |---|---| | Bundle + multiple schemas + -o src/blocks/ | Writes {ComponentName}.tsx per schema into src/blocks/ | | Bundle + one schema + -o src/blocks/Hero.tsx | Writes to that exact file (single-schema mode forwarded) | | Single schema + -o src/blocks/Hero.tsx | Writes to that exact file | | Single schema + no -o | Writes {ComponentName}.tsx in the current directory | | Bundle + no -o | Writes one {ComponentName}.tsx per schema in the current directory |

Getting the schema JSON

Option A — Copy JSON from the CMS UI (recommended):

  1. In the CMS, go to Schemas.
  2. Click the 📜 Copy JSON button next to any schema — or click Export to download all schemas as a bundle.
  3. The clipboard always contains a weblake-schema-bundle envelope, even for a single schema. Paste directly into a file or pipe to weblake generate.
# macOS — paste clipboard directly to the generator
pbpaste | weblake generate -o src/blocks/Hero.tsx

# Save first, then generate
pbpaste > hero-bundle.json
weblake generate hero-bundle.json -o src/blocks/Hero.tsx

Option B — Generate all blocks from a full CMS export:

# Export all schemas from the CMS
weblake schemas export -o schemas.json

# Generate a component for every schema in the bundle
weblake generate schemas.json --out src/blocks/

Examples

# Single-schema bundle from the CMS → explicit output path
weblake generate hero-bundle.json -o src/blocks/Hero.tsx

# Multi-schema bundle → one file per schema in src/blocks/
weblake generate schemas-export.json --out src/blocks/

# Read from stdin
pbpaste | weblake generate --out src/blocks/

# Override the display name in the generated file header
weblake generate hero-bundle.json -n "Hero Section" -o src/blocks/Hero.tsx

# Skip registry.tsx auto-patching
weblake generate hero-bundle.json -o src/blocks/Hero.tsx --no-register

Generated file structure

For a schema with slug hero, the command produces Hero.tsx:

/**
 * Block renderer for "Hero" (schema slug: hero)
 *
 * Generated by: weblake generate hero-bundle.json
 *
 * Register this component in your app:
 *
 *   import { createRegistry } from '@weblakecms/client';
 *   import { Hero } from './components/Hero';
 *
 *   const registry = createRegistry({
 *     overrides: { blockRenderers: { 'hero': Hero } },
 *   });
 *   <ContentRenderer content={content} registry={registry} />
 */

import React from 'react';
import type { BlockRendererProps } from '@weblakecms/client';
import { resolveStyles, themeToCssVars, themeToWrapperStyle, layoutToCssVars, layoutToContainerStyle } from '@weblakecms/client';
import { MediaValue, LinkValue } from '@weblakecms/ui';

// ── Typed data interface ──────────────────────────────────────────────────────

export interface HeroData {
  /** Title */
  title?: string;
  /** Subtitle */
  subtitle?: string;
  /** Background Image */
  image?: string;
  /** CTA Variant */
  cta_variant?: 'primary' | 'outline';
  /** Primary CTA */
  cta?: LinkData;
}

// ── Component ─────────────────────────────────────────────────────────────────

export function Hero({ data: rawData, schema }: BlockRendererProps) {
  const data = rawData as HeroData;

  const { theme, layout } = resolveStyles(rawData);
  // themeToCssVars declares --color-* and --theme-* custom properties;
  // themeToWrapperStyle binds them to actual CSS attributes (background-color, color, font-family…)
  const wrapperStyle = {
    ...themeToCssVars(theme),
    ...layoutToCssVars(layout),
    ...themeToWrapperStyle(theme),
  } as React.CSSProperties;
  const containerStyle = layoutToContainerStyle(layout);

  return (
    <div data-block="hero" data-schema={schema.slug} style={wrapperStyle}>
      <div style={containerStyle}>
        {/* Title */}
        {data.title && <span>{String(data.title)}</span>}

        {/* Subtitle */}
        {data.subtitle && <span>{String(data.subtitle)}</span>}

        {/* Background Image */}
        <MediaValue value={data.image} name="Background Image" />

        {/* Primary CTA */}
        <LinkValue value={data.cta} />
      </div>
    </div>
  );
}

Field type → TypeScript type and JSX

| Field type | TypeScript type | JSX (single value) | JSX (array — isArray: true) | |---|---|---|---| | text, slug, email, url, color, code, date, reference | string | {data.f && <span>{String(data.f)}</span>} | {data.f?.map((item, i) => <span key={i}>{String(item)}</span>)} | | number | number | {data.f && <span>{String(data.f)}</span>} | {data.f?.map((item, i) => <span key={i}>{String(item)}</span>)} | | boolean | boolean | {typeof data.f === 'boolean' && <span>{data.f ? 'Yes' : 'No'}</span>} | {data.f?.map((item, i) => <span key={i}>{item ? 'Yes' : 'No'}</span>)} | | select | Union of choice values e.g. 'sm' \| 'lg' | {data.f && <span>{String(data.f)}</span>} | {data.f?.map((item, i) => <span key={i}>{String(item)}</span>)} | | richtext | string | <RichTextValue value={data.f} /> | {data.f?.map((item, i) => <RichTextValue key={i} value={item} />)} | | media | string | <MediaValue value={data.f} name="..." /> | {data.f?.map((item, i) => <MediaValue key={i} value={item} name="..." />)} | | link | LinkData | <LinkValue value={data.f} /> | {data.f?.map((item, i) => <LinkValue key={i} value={item} />)} | | button | ButtonData | <ButtonValue value={data.f} /> | {data.f?.map((item, i) => <ButtonValue key={i} value={item} />)} | | menu | MenuItem[] | <MenuValue value={data.f} /> | (not applicable) | | menu_item | MenuItemData | {data.f && <MenuValue value={[data.f]} />} | <MenuValue value={data.f} /> | | blocks (with $ref) | {RefName}Data or {RefName}Data[] | {/* TODO: render block */} | {/* TODO: render block */} | | datasource | never (resolved into __datasource) | typed sub-component (see below) | (not applicable) |

All @weblakecms/ui components (RichTextValue, MediaValue, LinkValue, ButtonValue, MenuValue) are imported automatically — only the ones actually needed by the schema's fields are included.

$refs — cross-schema references

When a schema field references another schema (e.g. type: "banner" or blockRef: "link"), the CMS export inlines the referenced schema's field definitions into currentSchema.$refs. The generator turns each entry in $refs into a named TypeScript interface:

/** Link (schema: link) */
export interface LinkData {
  label?: string;
  icon_name?: string;
  url_type?: 'url' | 'ref';
  href?: string;
  ref_schema?: string;
  ref_id?: string;
  target?: '_self' | '_blank';
}

When a $ref slug matches a block already implemented in @weblakecms/client (e.g. banner, hero, sliding_banner), an informational comment is added above the interface:

// ℹ️  Banner renderer is already available in '@weblakecms/client' — import it directly.
export interface BannerData { ... }

Built-in composite types

Three composite types are recognised by name and injected automatically into the $refs map even when not present in the exported bundle:

| Type | Interface name | Key fields | |---|---|---| | menu_item | MenuItemData | label, icon_name, url_type, url, ref_schema, ref_id, children (recursive) | | link | LinkData | label, icon_name, url_type, href, ref_schema, ref_id, target | | button | ButtonData | label, icon_name, url_type, href, ref_schema, ref_id, variant, target |

datasource fields

Fields with type: "datasource" are resolved server-side by the Delivery API and delivered to the component under data.__datasource.<fieldName>[]. The generator:

  1. Emits a typed __datasource block in the main data interface.
  2. Generates a {FieldName}Item interface for each item (using the schema fields from $refs when the source is an internal schema).
  3. Generates a {FieldName}Item sub-component that renders a single item.
  4. Emits a .map() loop in the main component body calling the sub-component.
// Generated interface (partial)
export interface ArticleListData {
  __datasource?: {
    articles?: ArticlesItem[];
  };
}

// Generated sub-component
function ArticlesItem({ item }: { item: ArticlesItem }) {
  return (
    <div>
      {/* title */}
      {item.title !== undefined && <span>{String(item.title)}</span>}
      {/* CTA — links to the content item's path */}
      {item._meta?.path && (
        <a href={item._meta.path} className="...">View →</a>
      )}
    </div>
  );
}

registry.tsx auto-patching

When a registry.tsx file exists one directory above the output file (../registry.tsx), the command automatically:

  1. Adds an import line for the new component (with .js extension for ESM compatibility).
  2. Inserts an entry into DEFAULT_BLOCK_RENDERERS.

Example — before:

const DEFAULT_BLOCK_RENDERERS: Record<string, BlockRendererComponent> = {
  'feature-grid': FeatureGrid,
};

After running weblake generate hero-bundle.json -o blocks/Hero.tsx:

import { Hero } from './blocks/Hero.js';

const DEFAULT_BLOCK_RENDERERS: Record<string, BlockRendererComponent> = {
  'feature-grid': FeatureGrid,
  'hero': Hero,
};

If the component is already registered the command prints an info message and skips the patch. Pass --no-register to skip this step entirely (e.g. when the registry lives in a non-standard location or you prefer manual wiring).


weblake clientapp

Scaffolds a brand-new Next.js client site by copying the live apps/client template from the monorepo into apps/<slug>.

Because the template is read at runtime — not embedded in the CLI package — every improvement you make to apps/client is automatically available the next time the command is run.

The generated app is a full monorepo workspace member so all @weblakecms/* workspace dependencies resolve automatically without any extra configuration.

weblake clientapp <name> [options]

Arguments

| Argument | Description | |---|---| | <name> | Display name for the new app (slugified automatically, e.g. "My Shop"my-shop) |

Options

| Option | Default | Description | |---|---|---| | --api-url <url> | http://localhost:3000 | CMS / Delivery API base URL | | --api-key <key> | (prompted) | Delivery API key (wl_live_...) — written to .env.local | | --port <port> | 3004 | Dev-server port for the new app | | --out <dir> | apps/<slug> in monorepo root | Override the output directory (absolute or relative to CWD) |

Examples

# Scaffold with all options — no prompts
weblake clientapp "Acme Store" \
  --api-url https://cms.acme.com \
  --api-key wl_live_abc123 \
  --port 3010

# Scaffold with an explicit output directory
weblake clientapp my-blog --out ../projects/my-blog

# Minimal — prompts for API key, defaults to port 3004
weblake clientapp "Shore Demo"

What gets created

apps/shore-demo/
├── src/
│   ├── app/                   # Next.js App Router pages
│   │   ├── [[...slug]]/       # Catch-all CMS page renderer
│   │   ├── api/revalidate/    # ISR revalidation webhook
│   │   └── globals.css
│   ├── components/            # Icon + block renderer stubs
│   └── lib/weblake.ts         # createWebLakeClient + createRegistry() setup
├── public/                    # Static assets + SVG icon library
├── package.json               # name: @weblakecms/shore-demo, port: 3004
├── next.config.ts
├── tailwind.config.ts
├── tsconfig.json
├── .env.local                 # WEBLAKE_API_URL + WEBLAKE_API_KEY  ← gitignored
└── .gitignore

Files never copied from the template: node_modules, .next, .turbo, .env, .env.local, tsconfig.tsbuildinfo.

After scaffolding

# 1. Register the new workspace and install deps (from the monorepo root)
cd /path/to/weblake.shore.pt
npm install

# 2. Start the dev server
npx turbo dev --filter=@weblakecms/shore-demo
# or
cd apps/shore-demo && npx next dev --port 3004

# 3. Add custom block renderers in src/components/blocks/
weblake generate my-schema.json -o apps/shore-demo/src/components/blocks/MyBlock.tsx

# 4. Register the block in src/lib/weblake.ts using createRegistry()

Typical workflow

New client site from scratch

# 1. Scaffold a new client app from the live template
weblake clientapp "My Site" --api-url http://localhost:3000 --port 3004

# 2. Install the new workspace
cd /path/to/weblake.shore.pt && npm install

# 3. Export all schemas and generate all block renderers in one step
weblake schemas export -o schemas.json
weblake generate schemas.json --out apps/my-site/src/components/blocks/

# 4. Start the dev server
npx turbo dev --filter=@weblakecms/my-site

Existing project — schema + content management

# 1. Configure the CLI for a project
cd my-weblake-project
weblake init

# 2. Export all schemas to keep them in version control
weblake schemas export -o cms/schemas.json

# 3a. Generate a single block renderer
#     (use the CMS "Copy JSON" button, then paste the bundle)
pbpaste | weblake generate -o src/components/blocks/Hero.tsx

# 3b. Or generate all blocks from the export bundle at once
weblake generate cms/schemas.json --out src/components/blocks/

# 4. The component(s) are ready — customise the JSX to match your design

# 5. Export content for seeding a staging environment
weblake content export --schema blog-post -o cms/blog-posts.json

# 6. Import content into staging
WEBLAKE_TOKEN=... weblake content import -f cms/blog-posts.json