@llm-newsletter-kit/core 2.0.2 → 2.0.4

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/README.md CHANGED
@@ -3,10 +3,10 @@
3
3
  > **Automate domain-expert newsletters powered by AI**
4
4
 
5
5
  [
6
- ![CI](https://github.com/heripo-lab/llm-newsletter-kit-core/actions/workflows/ci.yml/badge.svg)
6
+ ![CI](https://github.com/heripo-lab/llm-newsletter-kit-core/actions/workflows/ci.yml/badge.svg)
7
7
  ](https://github.com/heripo-lab/llm-newsletter-kit-core/actions/workflows/ci.yml)
8
8
  [
9
- ![npm version](https://img.shields.io/npm/v/%40llm-newsletter-kit/core?logo=npm&color=cb0000)
9
+ ![npm version](https://img.shields.io/npm/v/%40llm-newsletter-kit/core?logo=npm&color=cb0000)
10
10
  ](https://www.npmjs.com/package/@llm-newsletter-kit/core)
11
11
  ![coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)
12
12
  ![license](https://img.shields.io/github/license/heripo-lab/llm-newsletter-kit-core)
@@ -27,11 +27,12 @@ A type‑first, extensible toolkit that automates LLM‑based newsletter creatio
27
27
 
28
28
  This project originated from a **Korean cultural heritage newsletter service** called “Research Radar.”
29
29
 
30
- It was architected by **Kim Hongyeon**, a unique **archaeologist-turned-software engineer**. Driven by a question he held for over a decade—***"Why must research be such grueling manual labor?"***—he combined his domain expertise with 10+ years of engineering experience to solve this problem.
30
+ It was architected by **Kim Hongyeon**, a unique **archaeologist-turned-software engineer**. Driven by a question he held for over a decade—**_"Why must research be such grueling manual labor?"_**—he combined his domain expertise with 10+ years of engineering experience to solve this problem.
31
31
 
32
32
  After completing an academic research project on [A Study on Archaeological Informatization Using Large Language Models (LLMs)](https://poc.heripo.org), a personal automation script created to keep up with academic trends evolved into a service with a high engagement rate (15% CTR) and near-zero maintenance cost.
33
33
 
34
34
  **Real-world production metrics:**
35
+
35
36
  - **LLM API cost:** $0.2-1 USD per issue with optimized model usage
36
37
  - **Operational overhead:** Truly hands-off automation—runs 24/7 without human intervention; the only ongoing work is occasional code maintenance
37
38
  - **Time investment:** Set it up once, let it run indefinitely; it operates while you sleep
@@ -44,6 +45,7 @@ His design philosophy: **"Logic in code, reasoning in AI, connections in archite
44
45
  - **Research Radar (Reference Implementation):** A real-world application built with this Core. It serves as a live demo and a "preset" for how to implement the providers.
45
46
 
46
47
  **Quick Links**
48
+
47
49
  - Research Radar (Live Service): https://heripo.app/research-radar/subscribe
48
50
  - Source Code (Usage Example): https://github.com/heripo-lab/heripo-research-radar
49
51
 
@@ -52,6 +54,7 @@ His design philosophy: **"Logic in code, reasoning in AI, connections in archite
52
54
  Newsletter automation generally falls into two approaches: no-code and code-based. **This kit takes the code-based approach because it produces significantly better output quality.**
53
55
 
54
56
  **Key advantages:**
57
+
55
58
  - **Advanced AI workflows**: Implement sophisticated techniques like self-reflection, chain-of-thought reasoning, and multi-step verification—impossible or prohibitively expensive in no-code platforms
56
59
  - **Cost control**: Use different models per stage, cap tokens, control retries, and prevent runaway costs with granular configuration
57
60
  - **Full customization**: Swap any component (crawlers, LLMs, databases, email) via Provider interfaces without vendor lock-in
@@ -73,9 +76,10 @@ npm i @llm-newsletter-kit/core
73
76
  ## Quick Start
74
77
 
75
78
  ```ts
76
- import { GenerateNewsletter } from '@llm-newsletter-kit/core';
77
79
  import type { GenerateNewsletterConfig } from '@llm-newsletter-kit/core';
80
+
78
81
  import { createOpenAI } from '@ai-sdk/openai';
82
+ import { GenerateNewsletter } from '@llm-newsletter-kit/core';
79
83
 
80
84
  const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });
81
85
 
@@ -88,7 +92,8 @@ const config: GenerateNewsletterConfig<string> = {
88
92
  },
89
93
  dateService: {
90
94
  getPublicationISODateString: () => new Date().toISOString().split('T')[0],
91
- getPublicationDisplayDateString: () => new Date().toLocaleDateString('en-US'),
95
+ getPublicationDisplayDateString: () =>
96
+ new Date().toLocaleDateString('en-US'),
92
97
  },
93
98
  taskService: {
94
99
  start: async () => `task-${Date.now()}`,
@@ -96,8 +101,12 @@ const config: GenerateNewsletterConfig<string> = {
96
101
  },
97
102
  crawlingProvider: {
98
103
  // customFetch: myProxyFetch, // Optional: custom fetch for proxy support
99
- crawlingTargetGroups: [/* ... */],
100
- fetchExistingArticlesByUrls: async (urls) => [/* ... */],
104
+ crawlingTargetGroups: [
105
+ /* ... */
106
+ ],
107
+ fetchExistingArticlesByUrls: async (urls) => [
108
+ /* ... */
109
+ ],
101
110
  saveCrawledArticles: async (articles, context) => articles.length,
102
111
  },
103
112
  analysisProvider: {
@@ -105,8 +114,12 @@ const config: GenerateNewsletterConfig<string> = {
105
114
  classifyTagOptions: { model: openai('gpt-5-mini') },
106
115
  analyzeImagesOptions: { model: openai('gpt-5.1') },
107
116
  determineScoreOptions: { model: openai('gpt-5.1') },
108
- fetchUnscoredArticles: async () => [/* ... */],
109
- fetchTags: async () => [/* ... */],
117
+ fetchUnscoredArticles: async () => [
118
+ /* ... */
119
+ ],
120
+ fetchTags: async () => [
121
+ /* ... */
122
+ ],
110
123
  update: async (article) => {},
111
124
  },
112
125
  contentGenerateProvider: {
@@ -115,7 +128,9 @@ const config: GenerateNewsletterConfig<string> = {
115
128
  issueOrder: 1,
116
129
  newsletterBrandName: 'Tech Insight Weekly',
117
130
  publicationCriteria: { minimumArticleCountForIssue: 5 },
118
- fetchArticleCandidates: async () => [/* ... */],
131
+ fetchArticleCandidates: async () => [
132
+ /* ... */
133
+ ],
119
134
  htmlTemplate: ({ content }) => `<html>...</html>`,
120
135
  saveNewsletter: async ({ newsletter }) => ({ id: 1 }),
121
136
  },
@@ -126,6 +141,7 @@ const newsletterId = await generator.generate();
126
141
  ```
127
142
 
128
143
  **⚠️ This is a minimal example showing the structure. For a complete, production-ready implementation with:**
144
+
129
145
  - Real database integration (Prisma/Drizzle)
130
146
  - Actual crawling targets and parsing logic
131
147
  - HTML email templates
@@ -153,10 +169,10 @@ For detailed field descriptions, see `src/generate-newsletter/models/interfaces.
153
169
 
154
170
  ## Architecture & Flow
155
171
 
156
- 1) CrawlingChain: Collect/parse/save articles from targets
157
- 2) AnalysisChain: Tagging/image analysis/importance scoring and update
158
- 3) ContentGenerateChain: Select candidates → generate Markdown via LLM → apply template (HTML) → save → return id
159
- 4) If previewNewsletter option is present, send a preview email
172
+ 1. CrawlingChain: Collect/parse/save articles from targets
173
+ 2. AnalysisChain: Tagging/image analysis/importance scoring and update
174
+ 3. ContentGenerateChain: Select candidates → generate Markdown via LLM → apply template (HTML) → save → return id
175
+ 4. If previewNewsletter option is present, send a preview email
160
176
 
161
177
  All chains are composed as a single pipeline using `@langchain/core/runnables` sequence.
162
178
 
@@ -177,11 +193,13 @@ Playground scripts let you run individual LLM query classes in isolation — no
177
193
  ### Setup
178
194
 
179
195
  1. Install playground dependencies:
196
+
180
197
  ```bash
181
198
  npm install -D tsx @ai-sdk/openai
182
199
  ```
183
200
 
184
201
  2. Copy example data files and customize:
202
+
185
203
  ```bash
186
204
  mkdir -p playground/data
187
205
  cp playground/data-examples/config.example.json playground/data/config.json
@@ -202,16 +220,17 @@ npm run playground:generate-newsletter
202
220
  ### Output
203
221
 
204
222
  Results are saved to `playground/output/` (git-ignored):
223
+
205
224
  - `newsletter.md` — Generated markdown with title in frontmatter
206
225
  - `newsletter.html` — Rendered HTML with CSS inlined (juice)
207
226
 
208
227
  ### Data Management
209
228
 
210
- | Directory | Git | Purpose |
211
- |---|---|---|
212
- | `playground/data-examples/` | Tracked | Format reference files (`.example.*`) |
213
- | `playground/data/` | Ignored | Your actual config, articles, templates |
214
- | `playground/output/` | Ignored | Generated results |
229
+ | Directory | Git | Purpose |
230
+ | --------------------------- | ------- | --------------------------------------- |
231
+ | `playground/data-examples/` | Tracked | Format reference files (`.example.*`) |
232
+ | `playground/data/` | Ignored | Your actual config, articles, templates |
233
+ | `playground/output/` | Ignored | Generated results |
215
234
 
216
235
  ## Development / Build / Test / CI
217
236
 
@@ -220,6 +239,7 @@ For the full developer guide (environment, scripts, testing/coverage, and CI), s
220
239
  ## Contributing & Policies
221
240
 
222
241
  Please refer to [CONTRIBUTING.md](./CONTRIBUTING.md) for all contribution guidelines and project policies, including:
242
+
223
243
  - Issue labels and triage
224
244
  - Branch strategy and PR process
225
245
  - Versioning and release policy
package/dist/index.cjs CHANGED
@@ -5,7 +5,6 @@ var esToolkit = require('es-toolkit');
5
5
  var zod = require('zod');
6
6
  var ai = require('ai');
7
7
  var jsdom = require('jsdom');
8
- var juice = require('juice');
9
8
  var safeMarkdown2Html = require('safe-markdown2html');
10
9
  var node_crypto = require('node:crypto');
11
10
 
@@ -1195,6 +1194,10 @@ function addUsage(a, b) {
1195
1194
  };
1196
1195
  }
1197
1196
 
1197
+ async function inlineCss(html) {
1198
+ const { default: juice } = await import('juice');
1199
+ return juice(html);
1200
+ }
1198
1201
  class ContentGenerateChain extends Chain {
1199
1202
  dateService;
1200
1203
  minimumArticleCountForIssue;
@@ -1324,7 +1327,7 @@ class ContentGenerateChain extends Chain {
1324
1327
  const { id } = await this.provider.saveNewsletter({
1325
1328
  newsletter: {
1326
1329
  ...coreContent,
1327
- htmlBody: juice(html),
1330
+ htmlBody: await inlineCss(html),
1328
1331
  issueOrder: this.provider.issueOrder,
1329
1332
  date: this.dateService.getPublicationISODateString(),
1330
1333
  },
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.js CHANGED
@@ -3,7 +3,6 @@ import { pick, omit } from 'es-toolkit';
3
3
  import { z } from 'zod';
4
4
  import { generateText, Output } from 'ai';
5
5
  import { JSDOM } from 'jsdom';
6
- import juice from 'juice';
7
6
  import safeMarkdown2Html from 'safe-markdown2html';
8
7
  import { randomUUID } from 'node:crypto';
9
8
 
@@ -1193,6 +1192,10 @@ function addUsage(a, b) {
1193
1192
  };
1194
1193
  }
1195
1194
 
1195
+ async function inlineCss(html) {
1196
+ const { default: juice } = await import('juice');
1197
+ return juice(html);
1198
+ }
1196
1199
  class ContentGenerateChain extends Chain {
1197
1200
  dateService;
1198
1201
  minimumArticleCountForIssue;
@@ -1322,7 +1325,7 @@ class ContentGenerateChain extends Chain {
1322
1325
  const { id } = await this.provider.saveNewsletter({
1323
1326
  newsletter: {
1324
1327
  ...coreContent,
1325
- htmlBody: juice(html),
1328
+ htmlBody: await inlineCss(html),
1326
1329
  issueOrder: this.provider.issueOrder,
1327
1330
  date: this.dateService.getPublicationISODateString(),
1328
1331
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@llm-newsletter-kit/core",
3
3
  "private": false,
4
4
  "type": "module",
5
- "version": "2.0.2",
5
+ "version": "2.0.4",
6
6
  "description": "An extensible framework to automate your entire newsletter workflow. Handles data collection, LLM-based content analysis, and email generation, letting you focus on your unique domain logic.",
7
7
  "main": "dist/index.cjs",
8
8
  "module": "dist/index.js",
@@ -41,43 +41,44 @@
41
41
  "lint:fix": "eslint --fix ./src",
42
42
  "lint:ci": "eslint --quiet ./src",
43
43
  "typecheck": "tsc --noEmit",
44
- "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md,mdx}\"",
44
+ "format": "prettier --write \"**/*.{ts,tsx,js,jsx,mjs,json,md,mdx}\"",
45
+ "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,mjs,json,md,mdx}\"",
45
46
  "playground": "tsx",
46
47
  "playground:generate-newsletter": "tsx playground/generate-newsletter.ts"
47
48
  },
48
49
  "author": "kimhongyeon",
49
50
  "license": "Apache-2.0",
50
51
  "dependencies": {
51
- "@langchain/core": "^1.1.46",
52
- "ai": "^6.0.184",
53
- "es-toolkit": "^1.46.1",
52
+ "@langchain/core": "^1.1.48",
53
+ "ai": "^6.0.197",
54
+ "es-toolkit": "^1.47.0",
54
55
  "jsdom": "^29.1.1",
55
- "juice": "^11.1.1",
56
- "safe-markdown2html": "^1.0.4",
56
+ "juice": "^12.1.0",
57
+ "safe-markdown2html": "^1.0.6",
57
58
  "zod": "^4.4.3"
58
59
  },
59
60
  "devDependencies": {
60
- "@ai-sdk/anthropic": "^3.0.78",
61
- "@ai-sdk/google": "^3.0.75",
62
- "@ai-sdk/openai": "^3.0.64",
63
- "@ai-sdk/togetherai": "^2.0.51",
61
+ "@ai-sdk/anthropic": "^3.0.81",
62
+ "@ai-sdk/google": "^3.0.80",
63
+ "@ai-sdk/openai": "^3.0.68",
64
+ "@ai-sdk/togetherai": "^2.0.53",
64
65
  "@eslint/js": "^10.0.1",
65
66
  "@trivago/prettier-plugin-sort-imports": "^6.0.2",
66
67
  "@types/jsdom": "^28.0.3",
67
- "@types/node": "^25.8.0",
68
- "@vitest/coverage-v8": "^4.1.6",
69
- "@vitest/expect": "^4.1.6",
70
- "eslint": "^10.4.0",
68
+ "@types/node": "^25.9.2",
69
+ "@vitest/coverage-v8": "^4.1.8",
70
+ "@vitest/expect": "^4.1.8",
71
+ "eslint": "^10.4.1",
71
72
  "eslint-plugin-unused-imports": "^4.4.1",
72
73
  "prettier": "^3.8.3",
73
74
  "rimraf": "^6.1.3",
74
- "rollup": "^4.60.4",
75
+ "rollup": "^4.61.1",
75
76
  "rollup-plugin-dts": "^6.4.1",
76
77
  "rollup-plugin-typescript2": "^0.37.0",
77
- "tsx": "^4.22.1",
78
+ "tsx": "^4.22.4",
78
79
  "typescript": "^6.0.3",
79
- "typescript-eslint": "^8.59.3",
80
- "vitest": "^4.1.6"
80
+ "typescript-eslint": "^8.60.1",
81
+ "vitest": "^4.1.8"
81
82
  },
82
83
  "repository": {
83
84
  "type": "git",