Skip to main content

Static assets and helpers for the BlockWriteAI JSON-first editor with free core blocks and license-gated premium plugins.

Project description

BlockWriteAI

BlockWriteAI is a JSON-first block editor for web apps. It works with a script tag, npm, PHP/Composer, and Python static-file workflows.

Use the free core editor for normal documents. Serve premium tools such as AI, Mermaid, Drawing, Signature, and Signature Flow only through your licensed server endpoint.

Quick Start With Local Files

Add the stylesheet, editor script, and free plugin bundle:

<link rel="stylesheet" href="dist/blockwriteai.min.css">

<div id="editor"></div>

<script src="dist/blockwriteai.min.js"></script>
<script src="dist/plugins/blockwriteai-code-assist.min.js"></script>
<script src="dist/plugins/blockwriteai-advanced-blocks.min.js"></script>
<script>
  const editor = new BlockWriteAI({
    holder: "#editor",
    placeholder: "Write something, or press / for blocks",
    async onSave(data) {
      await fetch("/api/documents", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data)
      });
    }
  });
</script>

Use these local files for production:

dist/blockwriteai.min.css
dist/blockwriteai.min.js
dist/plugins/blockwriteai-code-assist.min.js
dist/plugins/blockwriteai-advanced-blocks.min.js

Premium integrations should load licensed plugins and verify usage through the production BlockWriteAI Platform:

await BlockWriteAI.loadPremiumPlugins({
  licenseKey: "bwai_live_xxxxx",
  endpoint: BlockWriteAI.platformEndpoints.premiumPlugins,
  features: ["drawing", "mermaid", "signature", "signature_flow", "letterhead", "ai"]
});

Install With Node

npm install @blockwriteaileaf/blockwriteai

The npm package is self-contained for normal production use. Import the editor and CSS from the package; do not copy vendor folders or logo files into your public web root.

import BlockWriteAI from "@blockwriteaileaf/blockwriteai";
import "@blockwriteaileaf/blockwriteai/css";
import "@blockwriteaileaf/blockwriteai/plugins/code-assist/min";
import "@blockwriteaileaf/blockwriteai/plugins/advanced/min";

const editor = new BlockWriteAI({
  holder: "#editor",
  premium: {
    licenseKey: "bwai_live_xxxxx",
    verifyEndpoint: BlockWriteAI.platformEndpoints.licenseVerify,
    usageEndpoint: BlockWriteAI.platformEndpoints.aiUsage,
    featureUsageEndpoint: BlockWriteAI.platformEndpoints.premiumUsage,
    eventEndpoint: BlockWriteAI.platformEndpoints.premiumEvent,
    signatureEventEndpoint: BlockWriteAI.platformEndpoints.signatureEvent
  },
  async onSave(data) {
    await fetch("/api/documents", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data)
    });
  }
});

Install With PHP

composer require qarakash/blockwriteai

Publish the package dist assets into a public asset directory in your app, then print the tags:

<?php

use QarAkash\BlockWriteAI\BlockWriteAIAssets;

echo BlockWriteAIAssets::stylesheetTag('/assets/blockwriteai');
echo BlockWriteAIAssets::scriptTags('/assets/blockwriteai');

$platform = BlockWriteAIAssets::platformEndpoints();

Create the editor:

<div id="editor"></div>
<script>
  const editor = new BlockWriteAI({
    holder: "#editor",
    async onSave(data) {
      await fetch("/api/documents/save.php", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data)
      });
    }
  });
</script>

Install With Python

pip install blockwriteai-editor

Copy the packaged assets into your app static directory:

from blockwriteai_editor import copy_static

copy_static("static/blockwriteai")

Generate tags in Flask, Django, or any Python web app:

from blockwriteai_editor import platform_endpoints, stylesheet_tag, script_tags

print(stylesheet_tag("/static/blockwriteai"))
print(script_tags("/static/blockwriteai"))

platform = platform_endpoints()

Then mount the editor in your template:

<div id="editor"></div>
<script>
  const editor = new BlockWriteAI({
    holder: "#editor",
    async onSave(data) {
      await fetch("/api/documents", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data)
      });
    }
  });
</script>

Editor Configuration

Create an editor with new BlockWriteAI(options). The only required option is holder.

const editor = new BlockWriteAI({
  holder: "#editor",
  data: initialData,
  placeholder: "Write something, or press / for blocks",
  minHeight: "620px",
  autofocus: true,
  theme: "light",
  themeToggle: true,
  saveButton: true,
  exportHtmlButton: true,
  uploadOutput: ["upload", "base64"],
  autosave: {
    key: "rbe-demo-document",
    load: true
  },
  upload: {
    image: async (file) => {
      const uploaded = await uploadToServer(file, "image");
      return { ...uploaded, alt: file.name, caption: file.name };
    },
    file: async (file) => uploadToServer(file, "file")
  },
  ai: {
    endpoint: "/api/blockwriteai-premium.php?action=ai_generate"
  },
  premium: {
    mode: "server",
    endpoint: "/api/blockwriteai-premium.php",
    autoLoadPlugins: true,
    features: ["drawing", "mermaid", "signature", "signature_flow", "letterhead", "ai"]
  },
  exportFilename: "blockwriteai-preview",
  onReady(editor) {
    console.log("BlockWriteAI ready", editor);
  },
  onChange(data) {
    queueJsonSync(data);
  },
  async onSave(data) {
    const payload = await sendJsonToApi(data);
    return payload.data || data;
  }
});

Core Options

Option Default Description
holder null Required. CSS selector or DOM element where the editor mounts.
data null Initial BlockWriteAI JSON document. Use { time, version, blocks }.
placeholder "Type / for blocks" Placeholder shown in empty text blocks.
minHeight "320px" Minimum editor canvas height.
autofocus false Focus the first editable block after render.
readOnly false Render the document without editing controls.
tools null Optional allow-list/order for block tools. null enables registered tools.
upload null Upload adapter object. Supports image(file) and file(file).
uploadOutput ["base64"] Output modes for uploads. Use ["upload"], ["base64"], or both.
mentions [] Mention suggestions used by inline mention/comment UI.
autosave null Local autosave settings. Example: { key: "doc-key", load: true }.
persistence null Advanced persistence adapter for document, comments, and signatures.
documentId null Your app's document id, passed into persistence callbacks.
userName "Current user" Name used in comments, review actions, and metadata.
select2 false Set true to enhance selects with Select2 when available.
shell true Wrap editor in the built-in shell/header layout.
theme "light" Initial theme. Use "light" or "dark".
themeToggle false Show a light/dark theme toggle button.
maxWidth null Optional max width for the editor layout.
saveButton false Show built-in save button. Calls onSave.
exportButton false Show built-in export menu button.
exportHtmlButton false Show direct HTML export button.
exportFilename "blockwriteai-document" Base filename for exported files.
onReady null Callback after the editor is mounted.
onChange null Callback after document changes. Receives current JSON.
onSave null Callback used by save button and save workflow. Can return updated JSON.

You can also configure export buttons with an export object:

export: {
  buttons: true,
  html: true
}

Free Blocks

The core editor includes common writing and layout blocks:

  • paragraph: normal rich text.
  • heading: section headings.
  • quote: quote with optional caption.
  • list: ordered or unordered lists.
  • checklist: task list with checked state.
  • code: code block.
  • image: image upload, paste, base64, or server URL.
  • table: editable table.
  • embed: YouTube, Vimeo, maps, iframe-style URLs.
  • callout: highlighted note.
  • delimiter: horizontal divider.
  • button: linked CTA button.
  • toggle: collapsible content.
  • signatureRow: shown as Multiple blocks in a row; places up to 3 blocks in one row.
  • linkPreview: rich link card.
  • raw: trusted raw HTML block.
  • attaches: file attachment card.

The free advanced plugin adds extra tools such as chart, LaTeX, audio, and columns when blockwriteai-advanced-blocks.min.js is loaded.

Upload Adapter

Use upload.image and upload.file when you want files to go to your server:

const editor = new BlockWriteAI({
  holder: "#editor",
  uploadOutput: ["upload", "base64"],
  upload: {
    async image(file) {
      return uploadToServer(file, "image");
    },
    async file(file) {
      return uploadToServer(file, "file");
    }
  }
});

Return shape:

{
  url: "https://cdn.example.com/file.png",
  name: "file.png",
  type: "image/png",
  size: 12345
}

Use uploadOutput: ["base64"] for local/demo documents. Use uploadOutput: ["upload"] for production storage.

Editor API

After initialization, use the editor instance to read, render, save, insert, export, or destroy the editor.

Method Description
editor.getData() Returns the current BlockWriteAI JSON document.
editor.save() Runs the save workflow and calls onSave when provided.
editor.render(data) Replaces the current document with new JSON data.
editor.insertBlock(type, data, index) Inserts a block programmatically.
editor.exportHTML() Converts the current document to HTML.
editor.exportMarkdown() Converts the current document to Markdown.
editor.loadPremiumPlugins(features) Loads premium plugins for this editor instance.
editor.destroy() Removes listeners and editor DOM references.

Static helpers:

Helper Description
BlockWriteAI.platformEndpoints Default BlockWriteAI Platform endpoint map.
BlockWriteAI.loadPremiumPlugins(options) Loads licensed premium plugin JavaScript.
BlockWriteAI.toHTML(data, options) Converts a JSON document to HTML without mounting a visible editor.
BlockWriteAI.renderPreview(holder, data, options) Renders a read-only preview into a holder.
BlockWriteAI.mountPreviews(options) Auto-mounts preview containers such as .blockwriteai-preview.

Example:

const data = editor.getData();
const html = editor.exportHTML();
await editor.save();
editor.insertBlock("heading", { level: 2, text: "Next section" });

Simple Persistence API

For most projects, store the full BlockWriteAI JSON document in your own database. Comments, replies, approvals, reject reasons, and document content stay inside the same JSON payload.

<div id="editor"></div>
<script>
  const editor = new BlockWriteAI({
    holder: "#editor",
    documentId: "doc-123",
    data: initialDocument,
    persistence: {
      localStorageKey: "rbe-demo-document",
      async save({ documentId, data, type, action }) {
        await fetch("/api/blockwriteai/document", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ documentId, data, type, action })
        });
      }
    }
  });
</script>

Use the same adapter on preview pages. Set previewRuntime: true when you want preview-side comment approval, reject, reply, and signature actions to work without writing custom DOM patching code.

<div id="preview" class="blockwriteai-preview"></div>
<script>
  BlockWriteAI.renderPreview("#preview", initialDocument, {
    documentId: "doc-123",
    previewRuntime: true,
    persistence: {
      localStorageKey: "rbe-demo-document",
      async save({ documentId, data, type, action }) {
        await fetch("/api/blockwriteai/document", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ documentId, data, type, action })
        });
      }
    }
  });
</script>

For larger apps, split storage by feature:

persistence: {
  save: ({ documentId, data }) => saveDocument(documentId, data),
  comments: {
    save: ({ documentId, comment, data }) => saveCommentTrail(documentId, comment, data)
  },
  signatures: {
    save: ({ documentId, signatureType, signatureKey, signature }) => {
      return saveSignature(documentId, signatureType, signatureKey, signature);
    }
  }
}

Read Saved Documents

BlockWriteAI saves JSON. Store that JSON in your database, then render it later with a preview container:

<link rel="stylesheet" href="/assets/blockwriteai/blockwriteai.min.css">

<div class="blockwriteai-preview" data-source="/api/documents/123.json"></div>

<script src="/assets/blockwriteai/blockwriteai.min.js"></script>
<script src="/assets/blockwriteai/plugins/blockwriteai-advanced-blocks.min.js"></script>
<script>
  BlockWriteAI.mountPreviews();
</script>

The JSON endpoint can return a document directly:

{
  "time": 1779540000000,
  "version": "1.4.2",
  "blocks": []
}

It can also return a wrapper:

{
  "ok": true,
  "data": {
    "time": 1779540000000,
    "version": "1.4.2",
    "blocks": []
  }
}

Premium Plugins

Premium tools are not loaded as public scripts. Your backend should verify the license and proxy premium requests to the BlockWriteAI Platform. This keeps license keys, OpenAI keys, billing checks, and usage limits out of the browser.

Premium features currently include:

  • ai: AI writing/generation.
  • drawing: drawing canvas.
  • mermaid: Mermaid diagrams.
  • signature: single digital signature field.
  • signature_flow: sequential multi-signer signature flow.
  • letterhead: organization letterhead/A4 company header.

Step 1: Create A Server Proxy

The example proxy is api/blockwriteai-premium.php. It reads BLOCKWRITEAI_LICENSE_KEY from .env, adds it server-side, and forwards requests to the platform.

BLOCKWRITEAI_LICENSE_KEY=bwai_live_xxxxx
BLOCKWRITEAI_PLATFORM_API_BASE=https://blockwriteai.in/api

Supported proxy actions:

Action Platform route Purpose
license_verify license_verify.php Validate license, organization, subscription, and feature access.
premium_plugins premium_plugins.php Return licensed premium plugin JavaScript.
ai_generate ai_generate.php Run AI generation through the licensed server.
ai_usage ai_usage.php Read AI usage summary.
ai_usage_detail ai_usage_detail.php Read detailed AI usage.
premium_usage premium_usage.php Meter trial/premium feature usage.
premium_event premium_event.php Record premium tool events.
signature_event signature_event.php Store, lookup, list, and delete signatures.
letterhead_settings letterhead_settings.php Load organization letterhead settings.

Step 2: Load Premium Plugins

Server-proxy mode is recommended:

await BlockWriteAI.loadPremiumPlugins({
  mode: "server",
  endpoint: "/api/blockwriteai-premium.php?action=premium_plugins",
  features: ["drawing", "mermaid", "signature", "signature_flow", "letterhead", "ai"]
});

Or use the editor's premium.autoLoadPlugins option:

<script>
  async function bootEditor() {
    window.editor = new BlockWriteAI({
      holder: "#editor",
      premium: {
        mode: "server",
        endpoint: "/api/blockwriteai-premium.php",
        autoLoadPlugins: true,
        features: ["drawing", "mermaid", "signature", "signature_flow", "letterhead", "ai"]
      },
      ai: {
        endpoint: "/api/blockwriteai-premium.php?action=ai_generate"
      }
    });
  }

  bootEditor();
</script>

Step 3: Configure License Verification

If you are not using mode: "server", provide explicit endpoints:

premium: {
  licenseKey: "bwai_live_xxxxx",
  verifyEndpoint: "https://blockwriteai.in/api/license_verify.php",
  pluginEndpoint: "https://blockwriteai.in/api/premium_plugins.php",
  usageEndpoint: "https://blockwriteai.in/api/ai_usage.php",
  usageDetailEndpoint: "https://blockwriteai.in/api/ai_usage_detail.php",
  featureUsageEndpoint: "https://blockwriteai.in/api/premium_usage.php",
  eventEndpoint: "https://blockwriteai.in/api/premium_event.php",
  signatureEventEndpoint: "https://blockwriteai.in/api/signature_event.php",
  features: ["drawing", "mermaid", "signature", "signature_flow", "letterhead", "ai"]
}

For production, prefer a backend proxy instead of exposing raw license keys in JavaScript.

AI

Configure AI with an endpoint that accepts your editor request and returns generated content:

ai: {
  endpoint: "/api/blockwriteai-premium.php?action=ai_generate"
}

Keep provider keys such as OpenAI keys on your server only.

Signature

The signature premium block stores one reusable signer identity. Flow signing looks up these saved signatures.

Use:

  1. Enable premium features signature and optionally signature_flow.
  2. Insert the Signature block.
  3. The user signs once.
  4. The signature event is stored through signature_event.
  5. The saved signature can later be reused by Signature Flow if name/email matches.

The signature event stores:

  • organization id
  • authenticated user id when available
  • signer name
  • signer email
  • signer role
  • IP address
  • user agent
  • signature hash
  • created timestamp
  • expiry timestamp
  • payload JSON

By default, stored signatures expire after 30 days.

Listen for signature completion:

document.addEventListener("blockwriteai:signature-signed", (event) => {
  console.log("Signature saved", event.detail);
});

Signature Flow

The signature_flow premium block creates sequential signing steps.

Current behavior:

  1. Add Signature Flow.
  2. Add signer steps such as Manager, Client, or Approver.
  3. In preview/runtime mode, Step 1 is unlocked first.
  4. The signer enters a saved signature name or email.
  5. BlockWriteAI calls signature_event with action: "lookup".
  6. The platform searches active, non-deleted signatures in the same license organization.
  7. If a matching signature is found, the step is marked signed.
  8. The next step unlocks.
  9. The same signature hash cannot be reused in another step of the same flow.

What is enforced:

  • premium signature_flow feature access
  • same organization lookup boundary
  • logged-in signer membership when a session token is used
  • sequential order in the browser UI
  • active/non-expired/non-deleted stored signatures
  • duplicate signature prevention inside one flow

What you should add in your application if required:

  • exact assigned signer email per step
  • exact assigned signer role per step
  • backend step-order enforcement
  • document status checks such as draft, active, locked, completed, cancelled
  • custom approval/rejection workflow

Listen for flow signing:

document.addEventListener("blockwriteai:signature-flow-signed", (event) => {
  console.log("Flow step signed", event.detail);
});

Letterhead

The letterhead premium block uses organization letterhead settings from the platform.

Load settings before premium plugins:

async function loadLetterheadSettings() {
  const response = await fetch("/api/blockwriteai-premium.php?action=letterhead_settings", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ domain: window.location.origin })
  });
  const payload = await response.json();
  window.BlockWriteAILetterHeadSettings = Object.freeze(payload.settings || {});
}

await loadLetterheadSettings();
await BlockWriteAI.loadPremiumPlugins({
  mode: "server",
  endpoint: "/api/blockwriteai-premium.php?action=premium_plugins",
  features: ["letterhead"]
});

The example helper BlockWriteAIExamplePremium.loadLetterheadSettings() already does this.

Complete Premium Example

async function bootEditor(initialData) {
  const premiumReady = await BlockWriteAIExamplePremium.loadPlugins();

  const editor = new BlockWriteAI({
    holder: "#editor",
    data: initialData,
    placeholder: "Write something, or press / for blocks",
    minHeight: "620px",
    autofocus: true,
    theme: "light",
    themeToggle: true,
    saveButton: true,
    exportHtmlButton: true,
    uploadOutput: ["upload", "base64"],
    upload: {
      image: (file) => uploadToServer(file, "image"),
      file: (file) => uploadToServer(file, "file")
    },
    ai: {
      endpoint: BlockWriteAIExamplePremium.aiEndpoint()
    },
    premium: premiumReady ? BlockWriteAIExamplePremium.premiumConfig() : false,
    exportFilename: "blockwriteai-preview",
    onChange(data) {
      queueJsonSync(data);
    },
    async onSave(data) {
      const payload = await sendJsonToApi(data);
      return payload.data || data;
    }
  });

  return editor;
}

Preview Runtime

Use preview runtime for comment actions, signatures, and signature flow interactions on read-only preview pages:

BlockWriteAI.renderPreview("#preview", savedDocument, {
  previewRuntime: true,
  documentId: "doc-123",
  persistence: {
    save: ({ documentId, data, type, action }) => {
      return saveDocument(documentId, data, type, action);
    }
  }
});

For signature audit storage in your own app, listen to:

  • blockwriteai:signature-signed
  • blockwriteai:signature-flow-signed

Release Checklist

  1. Run npm run build:min.
  2. Run npm run check.
  3. Publish @blockwriteaileaf/blockwriteai to npm.
  4. Publish qarakash/blockwriteai to Packagist.
  5. Publish blockwriteai-editor to PyPI.
  6. Serve only the public asset directory from your application.

Notes For Production

  • Use the .min.css and .min.js files in public pages.
  • Do not publish source folders, examples, build artifacts, package caches, or private configuration files.
  • Browser-delivered CSS and JavaScript can always be downloaded. Protect paid features with server-side license checks and metered premium bundle delivery.
  • Keep secret keys in backend environment variables only.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

blockwriteai_editor-1.5.0.tar.gz (172.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

blockwriteai_editor-1.5.0-py3-none-any.whl (174.5 kB view details)

Uploaded Python 3

File details

Details for the file blockwriteai_editor-1.5.0.tar.gz.

File metadata

  • Download URL: blockwriteai_editor-1.5.0.tar.gz
  • Upload date:
  • Size: 172.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for blockwriteai_editor-1.5.0.tar.gz
Algorithm Hash digest
SHA256 97145303a37609e558e978fcfd8678842de79293a2b7559c4dcda20cae5ceb9e
MD5 00a87b3af6090b598f1556d8e91a7442
BLAKE2b-256 694d9f9764f715b9b81fbc0a6494fdaf37efe1b570cb9c5bd347302b91b05216

See more details on using hashes here.

File details

Details for the file blockwriteai_editor-1.5.0-py3-none-any.whl.

File metadata

File hashes

Hashes for blockwriteai_editor-1.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3007111d115024bdea029a54f0627f0881b4cd4d9df0fccbf3e4de8d17c00861
MD5 46e100b597811d3e256effb7fce1db50
BLAKE2b-256 cf15d714a2b79fe876959cab119b5f6f560d95bb637a9fb692bf4fcfa79005a6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page