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:
- Enable premium features
signatureand optionallysignature_flow. - Insert the Signature block.
- The user signs once.
- The signature event is stored through
signature_event. - 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:
- Add Signature Flow.
- Add signer steps such as
Manager,Client, orApprover. - In preview/runtime mode, Step 1 is unlocked first.
- The signer enters a saved signature name or email.
- BlockWriteAI calls
signature_eventwithaction: "lookup". - The platform searches active, non-deleted signatures in the same license organization.
- If a matching signature is found, the step is marked signed.
- The next step unlocks.
- The same signature hash cannot be reused in another step of the same flow.
What is enforced:
- premium
signature_flowfeature 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-signedblockwriteai:signature-flow-signed
Release Checklist
- Run
npm run build:min. - Run
npm run check. - Publish
@blockwriteaileaf/blockwriteaito npm. - Publish
qarakash/blockwriteaito Packagist. - Publish
blockwriteai-editorto PyPI. - Serve only the public asset directory from your application.
Notes For Production
- Use the
.min.cssand.min.jsfiles 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97145303a37609e558e978fcfd8678842de79293a2b7559c4dcda20cae5ceb9e
|
|
| MD5 |
00a87b3af6090b598f1556d8e91a7442
|
|
| BLAKE2b-256 |
694d9f9764f715b9b81fbc0a6494fdaf37efe1b570cb9c5bd347302b91b05216
|
File details
Details for the file blockwriteai_editor-1.5.0-py3-none-any.whl.
File metadata
- Download URL: blockwriteai_editor-1.5.0-py3-none-any.whl
- Upload date:
- Size: 174.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3007111d115024bdea029a54f0627f0881b4cd4d9df0fccbf3e4de8d17c00861
|
|
| MD5 |
46e100b597811d3e256effb7fce1db50
|
|
| BLAKE2b-256 |
cf15d714a2b79fe876959cab119b5f6f560d95bb637a9fb692bf4fcfa79005a6
|