bloggen
v1.0.4
Published
tool for autogenerating blogs
Readme
instruqt
A TypeScript ESM module for AI agents and context engineering. This tool provides structured development workflows, configuration management, and utilities for building maintainable, scalable applications with comprehensive error handling.
Features
- Context Engineering: Structured approach to AI-assisted development
- TypeScript ESM Module: Modern module architecture with tree-shaking support
- Single Responsibility Principle: One function per file for maintainability
- Comprehensive Error Handling: Built with
qerrorsfor robust error management - Testing Framework: Integrated testing with
qtestsrunner - Configuration Management: Centralized constants and environment variables
- Universal I/O: All callable helpers accept a single
dataobject and return objects
Quick Start
npm install
npm test
npm run buildRequirements
- Node.js 20+ recommended when using Google Gen AI SDK features (per @google/genai requirements). Core utilities that do not call the SDK work on earlier Node versions, but generating content/images requires Node 20+.
Migration Guide (Breaking Changes)
The following helper functions now follow the Universal I/O convention: they accept a single data object as input and return results as an object.
buildTextPrompt- Before:
buildTextPrompt(opts)→string - Now:
buildTextPrompt({ opts })→{ prompt: string } - Example:
- Before:
const s = buildTextPrompt({ topic, author, minLinks, maxLinks, tone }); - Now:
const { prompt } = buildTextPrompt({ opts: { topic, author, minLinks, maxLinks, tone } });
- Before:
- Before:
buildImagePrompt- Before:
buildImagePrompt(title, topic)→string - Now:
buildImagePrompt({ title, topic, style? })→{ prompt: string } - Example:
- Before:
const s = buildImagePrompt(title, topic); - Now:
const { prompt } = buildImagePrompt({ title, topic, style: 'photo-realistic' });
- Before:
- Before:
countLinks- Before:
countLinks(html)→number - Now:
countLinks({ html })→{ count: number } - Example:
- Before:
const n = countLinks(html); - Now:
const { count } = countLinks({ html });
- Before:
- Before:
extractImageFromParts- Before:
extractImageFromParts(parts)→{ mimeType, base64 } | null - Now:
extractImageFromParts({ parts })→{ mimeType, base64 } | null
- Before:
generateStructuredPost- Before:
generateStructuredPost(ai, model, prompt)→object - Now:
generateStructuredPost({ ai, model, prompt })→object
- Before:
generateHeroImage- Before:
generateHeroImage(ai, model, prompt)→object - Now:
generateHeroImage({ ai, model, prompt })→object
- Before:
Unchanged APIs
buildBlogSchema()returns a JSON schema object.getLogger()returns an object withinfo,warn,errormethods.
Rationale
- Aligns all public helpers with the repo’s Universal I/O pattern.
- Improves future extensibility and call-site clarity.
Architecture
/lib- Core functionality with single-responsibility functions/config- Configuration files and environment management/tests- Integration tests and test setup/agentRecords- AI agent work records and documentation
Public API
- Functions:
generateBlog(data)→Promise<BlogPost>createGenerateBlog(deps)→(data) => Promise<BlogPost>(factory for DI + reuse)buildTextPrompt({ opts })→{ prompt: string }buildImagePrompt({ title, topic, style? })→{ prompt: string }countLinks({ html })→{ count: number }extractImageFromParts({ parts })→{ mimeType: string; base64: string } | nullbuildBlogSchema()→ schema objectgetLogger()→{ info, warn, error }generateStructuredPost({ ai, model, prompt })→ objectgenerateHeroImage({ ai, model, prompt })→{ mimeType, base64 }
Privacy & Logging
- This module does not persist or transmit user data beyond returning results to the caller. However, the high‑level
generateBlogfunction performs informational logging by default (e.g., topic and author) through theqerrorslogger. - For compliance‑sensitive use cases (GDPR/CCPA, internal privacy policies), prefer
generateBlogCoreand inject a logger that redacts or suppresses PII. Example:{ logger: { info: () => {}, warn: () => {}, error: console.error } }. - Consumers are responsible for consent, data subject requests, and log retention policies in their applications.
Error Handling Guidance
- Library functions may throw errors with descriptive messages (e.g., missing configuration). Treat these as server‑side diagnostics. Do not pass raw error messages directly to end users.
- Recommended pattern:
- Catch errors, log details server‑side with a correlation ID, and return a generic error message to clients.
- For advanced control, use
generateBlogCoreand inject a logger and error wrapper that align with your organization’s standards.
Runtime Dependencies
- Published artifacts are limited to
dist/(seeexportsandfilesinpackage.json). Demo/server code is not published. - Runtime dependencies for consumers are kept minimal (e.g.,
@google/genai,qerrors). Demo/server tooling (e.g.,express,winston) lives indevDependenciesto reduce supply‑chain surface for module users.
Configuration & Environment
The module can infer provider configuration from environment variables if cfg is omitted in generateBlog({ opts, cfg }):
GOOGLE_GENAI_USE_VERTEXAI:'true' | 'false'— when'true', Vertex AI is used; otherwise AI Studio API key is used.GOOGLE_CLOUD_PROJECT: GCP project ID for Vertex AI.GOOGLE_CLOUD_LOCATION: GCP region (defaults to'us-central1').GEMINI_API_KEY: AI Studio API key (server-side only).
Defaults used when not specified via opts/env:
- Text model:
'gemini-2.5-flash' - Image model:
'gemini-2.5-flash-image-preview' - Author:
'Anonymous' - Min/Max links:
3/5
Usage
import {
generateBlog,
buildTextPrompt,
buildImagePrompt,
countLinks,
extractImageFromParts
} from 'bloggen';
// Generate a full blog post
const post = await generateBlog({
opts: { topic: 'X', author: 'A', minLinks: 3, maxLinks: 5, tone: 'friendly', style: 'photo-realistic' },
cfg: { useVertexAI: false, apiKey: process.env.GEMINI_API_KEY! }
});
// Use helpers directly
const { prompt: textPrompt } = buildTextPrompt({
opts: { topic: 'X', author: 'A', minLinks: 3, maxLinks: 5 }
});
const { prompt: imagePrompt } = buildImagePrompt({ title: 'T', topic: 'X', style: 'watercolor' });
const { count } = countLinks({ html: post.html });Demo Server
A simple demo server is included to exercise the API from a browser UI.
Run:
node server.jsOpen: http://localhost:5000/ (default port 5000)
Endpoints exposed and used by the demo UI:
POST /api/generate-blog- Optional: set
returnImageUrl=true(query or body) to returnimageUrlinstead of inline base64 image
- Optional: set
POST /api/util/build-text-promptPOST /api/util/build-image-promptPOST /api/util/count-linksGET /api/util/build-blog-schemaPOST /api/util/extract-image-from-partsPOST /api/util/generate-structured-postPOST /api/util/generate-hero-imageGET /api/util/generate-hero-image-binary(binary streaming variant)GET /health
Static assets are served from public/ (demo HTML/JS lives there) with ETag and Cache-Control: max-age=3600; / redirects to /demo.html.
Transport options for images (Demo only)
- Default response from
/api/generate-blogincludes{ image: { mimeType, base64, alt } }. - For lower payload size and better performance in the demo, use
returnImageUrl=trueto receive animageUrlpointing toGET /api/util/generate-hero-image-binary?model=...&prompt=..., which streamsimage/*bytes with cache headers.- Note: These HTTP endpoints are part of the demo server only; the npm module does not expose HTTP routes.
Performance Notes
- The GenAI SDK is lazy‑loaded only when needed by
generateBlog, reducing cold‑start time and baseline memory when consumers import this package but only use pure helpers.
HTTP Meta (.meta)
- Each exported endpoint function carries a
.metaobject for host frameworks to auto‑wire routes, auth, and validation. - Highlights:
POST /api/generate-blog→ requiresuserrole,apiKeyRequired: truewith Zod schema for{ opts, cfg }.POST /api/util/generate-structured-post→user+ API key;{ model, prompt }schema.POST /api/util/generate-hero-image→user+ API key;{ model, prompt }schema.POST /api/util/build-text-prompt→ public;{ opts }schema.POST /api/util/build-image-prompt→ public;{ title, topic, style? }schema.POST /api/util/count-links→ public;{ html }schema.GET /api/util/build-blog-schema→ public; no input schema.
Hosts that support .meta can use these to enforce role checks, validate inputs via Zod, and generate API docs automatically.
Context Engineering
The rules folders for Cline Code & Kilocode are symlinked to the folder for Roo Code rules. 00-general.md in Roo Code rules is symlinked to AGENTS.md
ln -s "$(pwd)/.roo/rules" "$(pwd)/.kilocode/rules"
ln -s "$(pwd)/.roo/rules" "$(pwd)/.clinerules/"
ln -s "$(pwd)/AGENTS.md" "$(pwd)/.roo/rules/00-general.md"Replacement Installation of other apps (only to over-write this project entirely, in order to get them Replit Agent)
git remote set-url origin https://github.com/yourusername/yourrepo.git
git remote -v
git fetch
git reset origin/main --hard