best-email-builder 0.6.0 → 0.8.0
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 +59 -0
- package/README.md +127 -698
- package/dist/ai-server.js +116 -3
- package/dist/ai-server.js.map +1 -1
- package/dist/ai.js +507 -172
- package/dist/ai.js.map +1 -1
- package/dist/builder.js +8 -8
- package/dist/chunk-62HBUBBI.js +3866 -0
- package/dist/chunk-62HBUBBI.js.map +1 -0
- package/dist/{chunk-NC2YDZSP.js → chunk-6W3QUZR7.js} +8 -8
- package/dist/{chunk-W424KPCR.js → chunk-AXIM6E7T.js} +2 -2
- package/dist/{chunk-JU3OUO6X.js → chunk-DXWIVGHP.js} +3 -3
- package/dist/{chunk-QPAZLCPO.js → chunk-FAEVYSIF.js} +3 -3
- package/dist/{chunk-QPAZLCPO.js.map → chunk-FAEVYSIF.js.map} +1 -1
- package/dist/{chunk-4U7L2NYQ.js → chunk-G4U6PSF6.js} +2 -2
- package/dist/{chunk-5W4TUUPD.js → chunk-ITIG5NTJ.js} +4 -4
- package/dist/{chunk-CNJZLZRH.js → chunk-LUM7J5FF.js} +2 -2
- package/dist/{chunk-SAIW46IC.js → chunk-P7ABBLX6.js} +2 -2
- package/dist/chunk-SHHHYRPC.js +2829 -0
- package/dist/chunk-SHHHYRPC.js.map +1 -0
- package/dist/{chunk-XEFBPP5Y.js → chunk-WM2EEV4Q.js} +4 -4
- package/dist/index.js +10 -10
- package/dist/library.js +5 -5
- package/dist/server.js +8 -8
- package/dist/server.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/ai/ConnectAi.d.ts +2 -1
- package/dist/types/ai/ModelPicker.d.ts +34 -0
- package/dist/types/ai/agent.d.ts +31 -0
- package/dist/types/ai/agentEndpoint.d.ts +69 -0
- package/dist/types/ai/claude.d.ts +2 -1
- package/dist/types/ai/draft.d.ts +10 -4
- package/dist/types/ai/generator.d.ts +10 -4
- package/dist/types/ai/i18n/de.d.ts +2 -0
- package/dist/types/ai/i18n/es.d.ts +2 -0
- package/dist/types/ai/i18n/pt.d.ts +2 -0
- package/dist/types/ai/i18n/ru.d.ts +2 -0
- package/dist/types/ai/i18n/zh.d.ts +2 -0
- package/dist/types/ai/index.d.ts +2 -1
- package/dist/types/ai/keys.d.ts +14 -1
- package/dist/types/ai/providers.d.ts +48 -5
- package/dist/types/ai/rewrite.d.ts +2 -1
- package/dist/types/ai/server.d.ts +3 -1
- package/dist/types/ai/subjects.d.ts +2 -1
- package/dist/types/core/constants.d.ts +1 -1
- package/dist/types/engine/NativeAdapter.d.ts +1 -1
- package/dist/types/i18n/de.d.ts +2 -0
- package/dist/types/i18n/es.d.ts +2 -0
- package/dist/types/i18n/pt.d.ts +2 -0
- package/dist/types/i18n/ru.d.ts +2 -0
- package/dist/types/i18n/zh.d.ts +2 -0
- package/dist/types/server/handler.d.ts +3 -0
- package/package.json +2 -2
- package/dist/chunk-JI36FNWE.js +0 -1361
- package/dist/chunk-JI36FNWE.js.map +0 -1
- package/dist/chunk-NZIQF7IW.js +0 -1830
- package/dist/chunk-NZIQF7IW.js.map +0 -1
- /package/dist/{chunk-NC2YDZSP.js.map → chunk-6W3QUZR7.js.map} +0 -0
- /package/dist/{chunk-W424KPCR.js.map → chunk-AXIM6E7T.js.map} +0 -0
- /package/dist/{chunk-JU3OUO6X.js.map → chunk-DXWIVGHP.js.map} +0 -0
- /package/dist/{chunk-4U7L2NYQ.js.map → chunk-G4U6PSF6.js.map} +0 -0
- /package/dist/{chunk-5W4TUUPD.js.map → chunk-ITIG5NTJ.js.map} +0 -0
- /package/dist/{chunk-CNJZLZRH.js.map → chunk-LUM7J5FF.js.map} +0 -0
- /package/dist/{chunk-SAIW46IC.js.map → chunk-P7ABBLX6.js.map} +0 -0
- /package/dist/{chunk-XEFBPP5Y.js.map → chunk-WM2EEV4Q.js.map} +0 -0
package/dist/ai-server.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AGENT_ERROR_CODES,
|
|
3
|
+
AGENT_PROTOCOL,
|
|
2
4
|
AI_MESSAGES,
|
|
3
5
|
AI_PROVIDERS,
|
|
4
6
|
DEFAULT_CLAUDE_MODEL,
|
|
@@ -13,6 +15,7 @@ import {
|
|
|
13
15
|
REWRITE_SYSTEM_PROMPT,
|
|
14
16
|
SUBJECTS_SYSTEM_PROMPT,
|
|
15
17
|
SYSTEM_PROMPT,
|
|
18
|
+
agentEmailModel,
|
|
16
19
|
buildUserPrompt,
|
|
17
20
|
claudeEmailModel,
|
|
18
21
|
cleanGenerateInput,
|
|
@@ -21,6 +24,7 @@ import {
|
|
|
21
24
|
createSubjectSuggester,
|
|
22
25
|
emailWords,
|
|
23
26
|
failureCode,
|
|
27
|
+
listProviderModels,
|
|
24
28
|
normalizeGeneratedMjml,
|
|
25
29
|
parseDraft,
|
|
26
30
|
providerEmailModel,
|
|
@@ -30,11 +34,116 @@ import {
|
|
|
30
34
|
reviewDraft,
|
|
31
35
|
reviewRewrite,
|
|
32
36
|
reviewSubjects
|
|
33
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-SHHHYRPC.js";
|
|
34
38
|
import "./chunk-OWVXKMLI.js";
|
|
35
|
-
import "./chunk-
|
|
36
|
-
import "./chunk-
|
|
39
|
+
import "./chunk-AXIM6E7T.js";
|
|
40
|
+
import "./chunk-62HBUBBI.js";
|
|
41
|
+
|
|
42
|
+
// src/ai/agentEndpoint.js
|
|
43
|
+
var TASKS = ["generate", "rewrite", "subjects"];
|
|
44
|
+
var MAX_BODY_BYTES = 2 * 1024 * 1024;
|
|
45
|
+
var MAX_MESSAGES = 20;
|
|
46
|
+
var json = (body, status = 200) => new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" } });
|
|
47
|
+
var refuse = (error, code, status) => json({ error, code }, status);
|
|
48
|
+
function problemOf(body) {
|
|
49
|
+
if (!body || typeof body !== "object") return "The body is not a JSON object";
|
|
50
|
+
if (body.protocol !== AGENT_PROTOCOL) return `Unsupported protocol ${JSON.stringify(body.protocol)} \u2014 this endpoint speaks ${AGENT_PROTOCOL}`;
|
|
51
|
+
if (!TASKS.includes(body.task)) return `Unknown task ${JSON.stringify(body.task)}`;
|
|
52
|
+
if (typeof body.system !== "string") return "`system` must be a string";
|
|
53
|
+
if (!body.schema || typeof body.schema !== "object") return "`schema` must be an object";
|
|
54
|
+
const { messages } = body;
|
|
55
|
+
if (!Array.isArray(messages) || !messages.length || messages.length > MAX_MESSAGES) return `\`messages\` must hold 1 to ${MAX_MESSAGES} messages`;
|
|
56
|
+
for (const message of messages) {
|
|
57
|
+
if (!message || message.role !== "user" && message.role !== "assistant" || typeof message.content !== "string") {
|
|
58
|
+
return 'Each message is { role: "user"|"assistant", content: string }';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
function createAgentEndpoint({ complete, onError = (error) => console.error("[agent]", error) } = (
|
|
64
|
+
/** @type {any} */
|
|
65
|
+
{}
|
|
66
|
+
)) {
|
|
67
|
+
if (typeof complete !== "function") throw new TypeError("createAgentEndpoint: `complete` must be a function \u2014 your agent");
|
|
68
|
+
return async function agentEndpoint(request) {
|
|
69
|
+
if (request.method.toUpperCase() !== "POST") return refuse("POST only", "METHOD_NOT_ALLOWED", 405);
|
|
70
|
+
const length = Number(request.headers.get("content-length") || 0);
|
|
71
|
+
if (length > MAX_BODY_BYTES) return refuse("Request too large", "TOO_LARGE", 413);
|
|
72
|
+
const raw = await request.text();
|
|
73
|
+
if (raw.length > MAX_BODY_BYTES) return refuse("Request too large", "TOO_LARGE", 413);
|
|
74
|
+
let body;
|
|
75
|
+
try {
|
|
76
|
+
body = JSON.parse(raw);
|
|
77
|
+
} catch {
|
|
78
|
+
return refuse("Invalid JSON", "INVALID_JSON", 400);
|
|
79
|
+
}
|
|
80
|
+
const problem = problemOf(body);
|
|
81
|
+
if (problem) return refuse(problem, "INVALID_REQUEST", 400);
|
|
82
|
+
try {
|
|
83
|
+
const answer = await complete({
|
|
84
|
+
task: body.task,
|
|
85
|
+
system: body.system,
|
|
86
|
+
messages: body.messages.map((m) => ({ role: m.role, content: m.content })),
|
|
87
|
+
schema: body.schema,
|
|
88
|
+
request,
|
|
89
|
+
signal: request.signal
|
|
90
|
+
});
|
|
91
|
+
if (typeof answer === "string") return json({ text: answer });
|
|
92
|
+
if (answer && typeof answer === "object") return json({ output: answer });
|
|
93
|
+
return refuse("The agent gave no answer", "MODEL_ERROR", 502);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
const code = (
|
|
96
|
+
/** @type {any} */
|
|
97
|
+
error?.code
|
|
98
|
+
);
|
|
99
|
+
if (AGENT_ERROR_CODES.includes(code)) {
|
|
100
|
+
const known = GENERATION_ERRORS[
|
|
101
|
+
/** @type {keyof typeof GENERATION_ERRORS} */
|
|
102
|
+
code
|
|
103
|
+
];
|
|
104
|
+
return refuse(String(
|
|
105
|
+
/** @type {any} */
|
|
106
|
+
error?.detail || /** @type {any} */
|
|
107
|
+
error?.message || known.message
|
|
108
|
+
), code, known.status);
|
|
109
|
+
}
|
|
110
|
+
onError(error, request);
|
|
111
|
+
return refuse("The agent could not answer", "MODEL_ERROR", 502);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
var SAMPLE_TEXT = '<p>Our summer sale starts on Monday: 30% off everything in store, for three days only. It ends on Wednesday at midnight. <a href="https://example.com/sale">See the offers</a>.</p>';
|
|
116
|
+
async function checkAgent({ url, headers, user, fetch: fetchImpl, timeout, compile, language = "en" }) {
|
|
117
|
+
const model = agentEmailModel({ url, headers, fetch: fetchImpl, timeout });
|
|
118
|
+
const generator = createEmailGenerator({ model, compile });
|
|
119
|
+
const steps = [
|
|
120
|
+
["generate", () => generator.generate({ purpose: "welcome", language }, { user }), (r) => ({ subject: r.subject, warnings: r.warnings })],
|
|
121
|
+
["rewrite", () => generator.rewrite({ action: "shorter", text: SAMPLE_TEXT, format: "html" }, { user }), (r) => r.text],
|
|
122
|
+
[
|
|
123
|
+
"subjects",
|
|
124
|
+
() => generator.suggestSubjects({ subject: "Summer sale: 30% off", text: "Our summer sale starts on Monday: 30% off everything in store, for three days only.", language }, { user }),
|
|
125
|
+
(r) => r.subjects
|
|
126
|
+
]
|
|
127
|
+
];
|
|
128
|
+
const results = [];
|
|
129
|
+
for (const [task, run, sampleOf] of steps) {
|
|
130
|
+
const started = Date.now();
|
|
131
|
+
try {
|
|
132
|
+
const result = await run();
|
|
133
|
+
results.push({ task, ok: true, ms: Date.now() - started, attempts: result.attempts, sample: sampleOf(result) });
|
|
134
|
+
} catch (error) {
|
|
135
|
+
const failure = (
|
|
136
|
+
/** @type {any} */
|
|
137
|
+
error
|
|
138
|
+
);
|
|
139
|
+
results.push({ task, ok: false, ms: Date.now() - started, code: failure?.code || "ERROR", error: String(failure?.detail || failure?.message || error) });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { ok: results.every((result) => result.ok), results };
|
|
143
|
+
}
|
|
37
144
|
export {
|
|
145
|
+
AGENT_ERROR_CODES,
|
|
146
|
+
AGENT_PROTOCOL,
|
|
38
147
|
AI_MESSAGES,
|
|
39
148
|
AI_PROVIDERS,
|
|
40
149
|
DEFAULT_CLAUDE_MODEL,
|
|
@@ -49,14 +158,18 @@ export {
|
|
|
49
158
|
REWRITE_SYSTEM_PROMPT,
|
|
50
159
|
SUBJECTS_SYSTEM_PROMPT,
|
|
51
160
|
SYSTEM_PROMPT,
|
|
161
|
+
agentEmailModel,
|
|
52
162
|
buildUserPrompt,
|
|
163
|
+
checkAgent,
|
|
53
164
|
claudeEmailModel,
|
|
54
165
|
cleanGenerateInput,
|
|
166
|
+
createAgentEndpoint,
|
|
55
167
|
createEmailGenerator,
|
|
56
168
|
createRewriter,
|
|
57
169
|
createSubjectSuggester,
|
|
58
170
|
emailWords,
|
|
59
171
|
failureCode,
|
|
172
|
+
listProviderModels,
|
|
60
173
|
normalizeGeneratedMjml,
|
|
61
174
|
parseDraft,
|
|
62
175
|
providerEmailModel,
|
package/dist/ai-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/ai/agentEndpoint.js"],"sourcesContent":["// @ts-check\n/**\n * THE AGENT'S SIDE of `best-email-builder/agent@1` (see agent.js), for an\n * agent written in JavaScript — and `checkAgent`, to try any agent with the\n * builder's own checks before plugging it in.\n *\n * const endpoint = createAgentEndpoint({\n * complete: async ({ task, system, messages, schema, request }) => {\n * const who = await sessionOf(request); // your rights\n * return myAgent.answer({ system, messages, who }); // text, or the answer as an object\n * },\n * });\n * // Next.js: export const POST = endpoint; Express: app.post('/email-builder', toNodeListener(endpoint))\n *\n * const report = await checkAgent({ url: 'http://localhost:8800/email-builder', headers, compile: compileMjml });\n * // { ok, results: [{ task: 'generate', ok, ms, attempts, sample }, …] }\n */\n\nimport { AGENT_ERROR_CODES, AGENT_PROTOCOL, agentEmailModel } from './agent.js';\nimport { GENERATION_ERRORS } from './draft.js';\nimport { createEmailGenerator } from './generator.js';\n\nconst TASKS = ['generate', 'rewrite', 'subjects'];\n/** A repair turn carries the last answer: a whole email at most. */\nconst MAX_BODY_BYTES = 2 * 1024 * 1024;\nconst MAX_MESSAGES = 20;\n\n/**\n * @typedef {{\n * task: 'generate'|'rewrite'|'subjects',\n * system: string,\n * messages: {role: 'user'|'assistant', content: string}[],\n * schema: object,\n * request: Request,\n * signal: AbortSignal,\n * }} AgentTask\n */\n\n/** @param {unknown} body @param {number} status */\nconst json = (body, status = 200) =>\n new Response(JSON.stringify(body), { status, headers: { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-store' } });\n\n/** @param {string} error @param {string} code @param {number} status */\nconst refuse = (error, code, status) => json({ error, code }, status);\n\n/**\n * What the builder sent, checked; or why not.\n * @param {any} body\n * @returns {string|null} the problem\n */\nfunction problemOf(body) {\n if (!body || typeof body !== 'object') return 'The body is not a JSON object';\n if (body.protocol !== AGENT_PROTOCOL) return `Unsupported protocol ${JSON.stringify(body.protocol)} — this endpoint speaks ${AGENT_PROTOCOL}`;\n if (!TASKS.includes(body.task)) return `Unknown task ${JSON.stringify(body.task)}`;\n if (typeof body.system !== 'string') return '`system` must be a string';\n if (!body.schema || typeof body.schema !== 'object') return '`schema` must be an object';\n const { messages } = body;\n if (!Array.isArray(messages) || !messages.length || messages.length > MAX_MESSAGES) return `\\`messages\\` must hold 1 to ${MAX_MESSAGES} messages`;\n for (const message of messages) {\n if (!message || (message.role !== 'user' && message.role !== 'assistant') || typeof message.content !== 'string') {\n return 'Each message is { role: \"user\"|\"assistant\", content: string }';\n }\n }\n return null;\n}\n\n/**\n * @param {{\n * complete: (task: AgentTask) => Promise<string | object> | string | object,\n * onError?: (error: unknown, request: Request) => void,\n * }} options\n * `complete`: your agent. It answers with the text of its model, or with\n * the answer as an object. To fail with a reason the builder explains, throw\n * an error whose `code` is one of AGENT_ERROR_CODES ('REFUSED',\n * 'MODEL_BUSY'…); any other error is logged with `onError` and answered as\n * MODEL_ERROR, its message kept out of the response.\n * @returns {(request: Request) => Promise<Response>}\n */\nexport function createAgentEndpoint({ complete, onError = (error) => console.error('[agent]', error) } = /** @type {any} */ ({})) {\n if (typeof complete !== 'function') throw new TypeError('createAgentEndpoint: `complete` must be a function — your agent');\n\n return async function agentEndpoint(request) {\n if (request.method.toUpperCase() !== 'POST') return refuse('POST only', 'METHOD_NOT_ALLOWED', 405);\n const length = Number(request.headers.get('content-length') || 0);\n if (length > MAX_BODY_BYTES) return refuse('Request too large', 'TOO_LARGE', 413);\n const raw = await request.text();\n if (raw.length > MAX_BODY_BYTES) return refuse('Request too large', 'TOO_LARGE', 413);\n /** @type {any} */\n let body;\n try {\n body = JSON.parse(raw);\n } catch {\n return refuse('Invalid JSON', 'INVALID_JSON', 400);\n }\n const problem = problemOf(body);\n if (problem) return refuse(problem, 'INVALID_REQUEST', 400);\n\n try {\n const answer = await complete({\n task: body.task,\n system: body.system,\n messages: body.messages.map((/** @type {any} */ m) => ({ role: m.role, content: m.content })),\n schema: body.schema,\n request,\n signal: request.signal,\n });\n if (typeof answer === 'string') return json({ text: answer });\n if (answer && typeof answer === 'object') return json({ output: answer });\n return refuse('The agent gave no answer', 'MODEL_ERROR', 502);\n } catch (error) {\n const code = /** @type {any} */ (error)?.code;\n if (AGENT_ERROR_CODES.includes(code)) {\n const known = GENERATION_ERRORS[/** @type {keyof typeof GENERATION_ERRORS} */ (code)];\n return refuse(String(/** @type {any} */ (error)?.detail || /** @type {any} */ (error)?.message || known.message), code, known.status);\n }\n onError(error, request);\n return refuse('The agent could not answer', 'MODEL_ERROR', 502);\n }\n };\n}\n\nconst SAMPLE_TEXT =\n '<p>Our summer sale starts on Monday: 30% off everything in store, for three days only. ' +\n 'It ends on Wednesday at midnight. <a href=\"https://example.com/sale\">See the offers</a>.</p>';\n\n/**\n * Tries an agent with the builder's own checks: one email written, one text\n * rewritten, subject ideas — in turn, each as the builder would ask it (with\n * its repair turn). Three to six calls to the agent.\n * @param {{\n * url: string,\n * headers?: import('./agent.js').AgentHeaders,\n * user?: any,\n * fetch?: typeof fetch,\n * timeout?: number,\n * compile?: (mjml: string) => Promise<{warnings?: {message: string}[]}>,\n * language?: string,\n * }} options\n * `user`: what `headers` gets, as the handler's `authorize` would give it.\n * `compile`: `compileMjml` (best-email-builder/server), for MJML's own\n * warnings as on the server.\n * @returns {Promise<{ok: boolean, results: {task: string, ok: boolean, ms: number, attempts?: number, sample?: unknown, code?: string, error?: string}[]}>}\n */\nexport async function checkAgent({ url, headers, user, fetch: fetchImpl, timeout, compile, language = 'en' }) {\n const model = agentEmailModel({ url, headers, fetch: fetchImpl, timeout });\n const generator = createEmailGenerator({ model, compile });\n /** @type {[string, () => Promise<any>, (result: any) => unknown][]} */\n const steps = [\n ['generate', () => generator.generate({ purpose: 'welcome', language }, { user }), (r) => ({ subject: r.subject, warnings: r.warnings })],\n ['rewrite', () => generator.rewrite({ action: 'shorter', text: SAMPLE_TEXT, format: 'html' }, { user }), (r) => r.text],\n [\n 'subjects',\n () => generator.suggestSubjects({ subject: 'Summer sale: 30% off', text: 'Our summer sale starts on Monday: 30% off everything in store, for three days only.', language }, { user }),\n (r) => r.subjects,\n ],\n ];\n const results = [];\n for (const [task, run, sampleOf] of steps) {\n const started = Date.now();\n try {\n const result = await run();\n results.push({ task, ok: true, ms: Date.now() - started, attempts: result.attempts, sample: sampleOf(result) });\n } catch (error) {\n const failure = /** @type {any} */ (error);\n results.push({ task, ok: false, ms: Date.now() - started, code: failure?.code || 'ERROR', error: String(failure?.detail || failure?.message || error) });\n }\n }\n return { ok: results.every((result) => result.ok), results };\n}\n"],"mappings":"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","names":[]}
|