@one-million-lines/email-builder 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +38 -0
- package/dist/ai/AIChatPanel.d.ts +3 -0
- package/dist/ai/applyResponse.d.ts +20 -0
- package/dist/ai/catalog.d.ts +15 -0
- package/dist/ai/index.d.ts +22 -0
- package/dist/ai/provider.d.ts +23 -0
- package/dist/ai/state.d.ts +11 -0
- package/dist/email-builder.cjs +12 -10
- package/dist/email-builder.cjs.map +1 -1
- package/dist/email-builder.js +2556 -2057
- package/dist/email-builder.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,24 @@ This project adheres to [Semantic Versioning](https://semver.org/) and the
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
### Added
|
|
10
|
+
- **AI assistant module** (`src/ai/`) — optional chat-driven editing. When an AI
|
|
11
|
+
provider is configured an **AI** tab appears in the left sidebar. The client
|
|
12
|
+
sends a catalog of real modules so the assistant only ever assembles valid,
|
|
13
|
+
renderable emails; every response is validated with `documentSchema` and gets
|
|
14
|
+
fresh ids before being applied. New exports: `aiAssistantPlugin`,
|
|
15
|
+
`createHttpAIProvider`, `buildCatalog`, `applyAIResponse`, `mockAIProvider`,
|
|
16
|
+
`applyAIActions`, `validateAIDocument`, and the related types. New `aiEndpoint`
|
|
17
|
+
prop on `<EmailBuilder>`. See `src/ai/README.md`.
|
|
18
|
+
- **Python AI backend** (`backend/`) — a small Flask service (`app.py`,
|
|
19
|
+
`ai_service.py`) exposing `GET /health` and `POST /ai/generate`. Works with any
|
|
20
|
+
OpenAI-compatible endpoint and falls back to a deterministic offline planner
|
|
21
|
+
when no API key is set. See `backend/README.md`.
|
|
22
|
+
- **Feature module additions** — five new blocks added to the Feature category:
|
|
23
|
+
`feature.gradient_hero` (launch CTA hero), `feature.pull_quote`,
|
|
24
|
+
`feature.stat_row`, `feature.single_product_spotlight`, `feature.pill_nav`.
|
|
25
|
+
|
|
26
|
+
|
|
9
27
|
## [0.1.4] — 2026-07-02
|
|
10
28
|
|
|
11
29
|
### Changed
|
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ Marketing teams often need a reusable editor that produces email-safe HTML witho
|
|
|
15
15
|
- Visual editor with top bar, left sidebar, canvas, and right sidebar
|
|
16
16
|
- JSON-first email document model
|
|
17
17
|
- Built-in modules, templates, and themes
|
|
18
|
+
- **AI assistant module** — optional chat-driven editing backed by a simple
|
|
19
|
+
Python service
|
|
18
20
|
- Table-based HTML rendering for email output
|
|
19
21
|
- Local autosave via Zustand store
|
|
20
22
|
- React component API and vanilla JS factory
|
|
@@ -45,12 +47,14 @@ src/
|
|
|
45
47
|
core/ document types, renderer, validation, AI actions, plugins
|
|
46
48
|
editor/ top bar, sidebars, canvas
|
|
47
49
|
modules/ module registry and built-in modules
|
|
50
|
+
ai/ AI assistant module: provider, catalog, chat panel (see ai/README.md)
|
|
48
51
|
recommendations/ recommendation and fallback logic
|
|
49
52
|
store/ editor state and persistence
|
|
50
53
|
templates/ built-in email templates
|
|
51
54
|
themes/ theme definitions
|
|
52
55
|
plugins/ extension points, including image uploader helpers
|
|
53
56
|
index.ts public API for embedding
|
|
57
|
+
backend/ Python (Flask) AI service (see backend/README.md)
|
|
54
58
|
```
|
|
55
59
|
|
|
56
60
|
## Install
|
|
@@ -131,6 +135,26 @@ Vue and Angular mount the React-based editor through the framework-neutral
|
|
|
131
135
|
`createEmailBuilder()` factory (`getDocument` / `exportHtml` / `exportJson` /
|
|
132
136
|
`destroy`). React and ReactDOM remain peer dependencies in all cases.
|
|
133
137
|
|
|
138
|
+
### AI assistant module
|
|
139
|
+
|
|
140
|
+
Enable chat-driven editing by pointing the builder at the Python AI service in
|
|
141
|
+
[`backend/`](./backend). When configured, an **AI** tab appears in the left
|
|
142
|
+
sidebar.
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
<EmailBuilder aiEndpoint="http://localhost:3001/ai/generate" />
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import { registerPlugin, aiAssistantPlugin } from "@one-million-lines/email-builder";
|
|
150
|
+
registerPlugin(aiAssistantPlugin({ endpoint: "http://localhost:3001/ai/generate" }));
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The assistant only ever assembles emails from real, renderable modules, and every
|
|
154
|
+
response is validated with Zod before it is applied. See
|
|
155
|
+
[`src/ai/README.md`](./src/ai/README.md) and
|
|
156
|
+
[`backend/README.md`](./backend/README.md).
|
|
157
|
+
|
|
134
158
|
### Styling & isolation
|
|
135
159
|
|
|
136
160
|
The stylesheet at `@one-million-lines/email-builder/styles.css` is designed to
|
|
@@ -212,6 +236,20 @@ npm run validate:pack # build + npm pack --dry-run
|
|
|
212
236
|
npm run build:demo # build the standalone demo app
|
|
213
237
|
```
|
|
214
238
|
|
|
239
|
+
### AI backend (optional)
|
|
240
|
+
|
|
241
|
+
The AI assistant needs the Python service in [`backend/`](./backend):
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
cd backend
|
|
245
|
+
python -m venv .venv && source .venv/bin/activate
|
|
246
|
+
pip install -r requirements.txt
|
|
247
|
+
python app.py # offline heuristic mode; set AI_API_KEY for a real model
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Then set `VITE_AI_ENDPOINT=http://localhost:3001/ai/generate` in a root `.env`
|
|
251
|
+
to enable the AI tab in `npm run dev`.
|
|
252
|
+
|
|
215
253
|
## Building & publishing
|
|
216
254
|
|
|
217
255
|
```bash
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EmailDocument } from '../core/types';
|
|
2
|
+
import { AIResponse } from '../core/aiActions';
|
|
3
|
+
export interface ApplyResult {
|
|
4
|
+
document: EmailDocument;
|
|
5
|
+
/** Assistant chat text, if any. */
|
|
6
|
+
text?: string;
|
|
7
|
+
/** Short human summary of what changed, for the chat log. */
|
|
8
|
+
summary: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Apply an {@link AIResponse} to `doc`. Returns the next document plus a summary,
|
|
12
|
+
* or an error string when the result fails validation.
|
|
13
|
+
*/
|
|
14
|
+
export declare function applyAIResponse(doc: EmailDocument, res: AIResponse): {
|
|
15
|
+
ok: true;
|
|
16
|
+
result: ApplyResult;
|
|
17
|
+
} | {
|
|
18
|
+
ok: false;
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { EmailModule } from '../core/types';
|
|
2
|
+
export interface CatalogEntry {
|
|
3
|
+
type: string;
|
|
4
|
+
category: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
tags: string[];
|
|
8
|
+
source: "module";
|
|
9
|
+
/** A concrete, renderable instance of the module (ids included). */
|
|
10
|
+
sample: EmailModule;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Build the catalog sent to the AI backend.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildCatalog(): CatalogEntry[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Plugin } from '../core/plugins';
|
|
2
|
+
import { HttpAIProviderOptions } from './provider';
|
|
3
|
+
export { createHttpAIProvider } from './provider';
|
|
4
|
+
export type { HttpAIProviderOptions } from './provider';
|
|
5
|
+
export { buildCatalog } from './catalog';
|
|
6
|
+
export type { CatalogEntry } from './catalog';
|
|
7
|
+
export { applyAIResponse } from './applyResponse';
|
|
8
|
+
export type { ApplyResult } from './applyResponse';
|
|
9
|
+
export { AIChatPanel, useAIAvailable } from './AIChatPanel';
|
|
10
|
+
export { getAIProvider as getActiveAIProvider, setAIProvider as setActiveAIProvider, } from './state';
|
|
11
|
+
export interface AIAssistantOptions extends HttpAIProviderOptions {
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Plugin factory that wires an HTTP-backed AI provider into the builder and
|
|
15
|
+
* enables the chat panel.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* import { registerPlugin } from "@one-million-lines/email-builder";
|
|
19
|
+
* import { aiAssistantPlugin } from "@one-million-lines/email-builder";
|
|
20
|
+
* registerPlugin(aiAssistantPlugin({ endpoint: "http://localhost:3001/ai/generate" }));
|
|
21
|
+
*/
|
|
22
|
+
export declare function aiAssistantPlugin(opts: AIAssistantOptions): Plugin;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AIProvider, AIResponse } from '../core/aiActions';
|
|
2
|
+
export interface HttpAIProviderOptions {
|
|
3
|
+
/** Absolute or same-origin URL that implements POST /ai/generate. Required. */
|
|
4
|
+
endpoint: string;
|
|
5
|
+
/** Extra headers (e.g. Authorization). */
|
|
6
|
+
headers?: Record<string, string>;
|
|
7
|
+
/** Send cookies with the request. Default: false. */
|
|
8
|
+
withCredentials?: boolean;
|
|
9
|
+
/** Abort the request after this many ms. Default: 60000. */
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
/**
|
|
12
|
+
* Map a raw server JSON body to an `AIResponse`.
|
|
13
|
+
* Default expects the body to already be an `AIResponse`.
|
|
14
|
+
*/
|
|
15
|
+
transformResponse?: (body: unknown) => AIResponse;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create an {@link AIProvider} backed by an HTTP endpoint.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* const provider = createHttpAIProvider({ endpoint: "http://localhost:3001/ai/generate" });
|
|
22
|
+
*/
|
|
23
|
+
export declare function createHttpAIProvider(opts: HttpAIProviderOptions): AIProvider;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AIProvider } from '../core/aiActions';
|
|
2
|
+
type Listener = () => void;
|
|
3
|
+
/** Set (or clear) the active AI provider. Notifies subscribers. */
|
|
4
|
+
export declare function setAIProvider(next: AIProvider | null): void;
|
|
5
|
+
/** The active AI provider, or null when AI is not configured. */
|
|
6
|
+
export declare function getAIProvider(): AIProvider | null;
|
|
7
|
+
/** Subscribe to provider changes (for `useSyncExternalStore`). */
|
|
8
|
+
export declare const subscribeAIProvider: (listener: Listener) => (() => void);
|
|
9
|
+
/** Monotonic version; changes whenever the provider is set or cleared. */
|
|
10
|
+
export declare const getAIProviderVersion: () => number;
|
|
11
|
+
export {};
|