mikser-io 7.10.2 → 7.12.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/README.md +20 -3
- package/index.js +1 -0
- package/package.json +4 -3
- package/src/engine.js +14 -2
- package/src/plugins/api.js +347 -41
- package/src/plugins/assets.js +52 -2
- package/src/plugins/layouts.js +18 -0
- package/src/plugins/preview.js +168 -1
- package/src/plugins/render/hbs.js +5 -4
- package/src/refs.js +620 -0
- package/src/utils.js +349 -1
- package/src/plugins/post/pdf.js +0 -117
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
**Mikser is the content layer of your application.** Business logic, user accounts, transactions live in their own services; mikser handles the parts that *are* content — pages, docs, the published catalog, multi-format outputs. [Vue](https://github.com/almero-digital-marketing/mikser-io-sdk-vue), [React](https://github.com/almero-digital-marketing/mikser-io-sdk-react), and [Svelte](https://github.com/almero-digital-marketing/mikser-io-sdk-svelte) SDKs are the seam between them — same surface across all three (`useDocument`, `useDocuments`, multilingual `useHref`, live SSE updates), each in its framework's idiomatic shape.
|
|
8
8
|
|
|
9
|
+
**An AI-native file-based content engine with live graph queries.** Content lives as plain text files you can read, search, and version-control like code. Mikser knows how those files reference each other — who an article's author is, which images a landing page uses, who else mentions a given product. When you fetch an article, you can pull its author and that author's organization along with it in one round-trip. When the author's bio changes, every page subscribed to a reference touching them updates live, without polling. AI agents talk to mikser through the same calls a frontend developer uses — there's no separate "AI API" to keep in sync. The whole graph is queryable from both sides at once.
|
|
10
|
+
|
|
9
11
|
Built for Node.js around a strict lifecycle and a composable plugin system. Every document, asset, and template flows through the same pipeline; plugins hook in at any phase. The same engine runs a single markdown blog and a multi-language publishing platform with PDF / email / AI-augmented asset pipelines — same lifecycle, more plugins.
|
|
10
12
|
|
|
11
13
|
It's MIT-licensed, runs on Node 18+, has zero hosted dependencies, and the entire content tree it manages is a folder of `.md` and `.yml` files you can copy, diff, and version-control. **The portability promise is the architecture, not a feature.**
|
|
@@ -82,6 +84,7 @@ Add `--mcp` to your mikser command and any MCP-speaking client — Claude Deskto
|
|
|
82
84
|
- read every entity in the catalog
|
|
83
85
|
- write new content files (markdown, layouts, configuration) — writes land on disk and the next cycle picks them up
|
|
84
86
|
- render any layout for preview without touching the output folder
|
|
87
|
+
- **surface rendered UI inline in the conversation** — `mikser_preview_ui` runs an entity through a layout that declares `mcpUi` frontmatter and returns the HTML as a UI block the host can show; an approve/reject button on that block sends the result straight back to the agent
|
|
85
88
|
- watch every build log as it streams past
|
|
86
89
|
- introspect engine state — current lifecycle phase, effective config, recent log buffer
|
|
87
90
|
|
|
@@ -91,7 +94,20 @@ Plugins extend the tool surface the same way they mount HTTP routes; install the
|
|
|
91
94
|
mikser --server --mcp # mounts MCP at /mcp on the same port as --server
|
|
92
95
|
```
|
|
93
96
|
|
|
94
|
-
What that feels like in practice: *"draft three hero-section variants and show me previews"* — three layouts written, three previews returned inline, one chat turn. *"Why did the build break?"* — the agent reads the rolling log buffer and answers from the same view your terminal sees. Operator, AI, and any observer dashboard share the same engine because mikser is single-tenant by design.
|
|
97
|
+
What that feels like in practice: *"draft three hero-section variants and show me previews"* — three layouts written, three previews returned inline, one chat turn. *"Why did the build break?"* — the agent reads the rolling log buffer and answers from the same view your terminal sees. *"Update this article's tone and show me the preview"* — the agent edits the file and surfaces the rendered article inline; you click Approve or Reject, the agent acts on your choice. Operator, AI, and any observer dashboard share the same engine because mikser is single-tenant by design.
|
|
98
|
+
|
|
99
|
+
### Editing is the easy part — verification is where it pays off
|
|
100
|
+
|
|
101
|
+
When an AI agent edits ten files, the next question is: *did it do what I asked?* When it edits two hundred, you can't read them all yourself — and that's exactly the scale where AI editing starts being interesting. Most content systems leave verification to the human (read the diff, check the preview, hope you caught the issues). Mikser turns the questions a reviewer would ask into things the agent can answer for itself:
|
|
102
|
+
|
|
103
|
+
- **"Did I update every article that needed it?"** — semantic search finds anything that still matches the old tone or phrasing the agent was supposed to change.
|
|
104
|
+
- **"What else mentions this person, product, or topic?"** — mikser knows how content references content. "Show me every page that mentions Dick" returns the list instantly, no full-tree scan.
|
|
105
|
+
- **"Did anything break?"** — if a reference points at something that no longer exists, mikser surfaces it as a warning. The build either completes cleanly or doesn't.
|
|
106
|
+
- **"Can I see what this looks like before publishing?"** — render any single page or section on demand, no full rebuild, no staging deploy.
|
|
107
|
+
- **"What changed since I last looked?"** — `git diff`. The catalog is plain files, so the audit trail is the same one your engineers already use for code.
|
|
108
|
+
- **"Roll back this batch?"** — `git checkout`. Atomic. No database migration to undo, no version-history-feature to learn.
|
|
109
|
+
|
|
110
|
+
The shift this enables: AI review stops being *"read every change"* and becomes *"spot-check the agent's confidence."* The agent verifies its own work; the human samples and approves. That's the workflow that lets a content team actually use AI at scale — change the tone across the entire site in a morning, ship it after a coffee.
|
|
95
111
|
|
|
96
112
|
Full tool reference and twelve worked scenarios in [MCP — talking to mikser from AI](./documentation/mcp.md).
|
|
97
113
|
|
|
@@ -123,7 +139,7 @@ The engine is what stays stable — the lifecycle, the catalog, the file-based c
|
|
|
123
139
|
| Plugin | What it does |
|
|
124
140
|
|---|---|
|
|
125
141
|
| [`mikser-io-vector`](https://github.com/almero-digital-marketing/mikser-io-vector) | OpenAI embeddings + semantic search (sqlite-vec or pgvector) |
|
|
126
|
-
| [`mikser-io-plugin-schemas`](https://github.com/almero-digital-marketing/mikser-io-plugin-schemas) | Zod-backed entity validation + auto-generated TypeScript declarations for the SDK |
|
|
142
|
+
| [`mikser-io-plugin-schemas`](https://github.com/almero-digital-marketing/mikser-io-plugin-schemas) | Zod-backed entity validation + auto-generated TypeScript declarations for the SDK. Auto-detects `$`-keyed references and warns on broken ones — see [ADR-0007](./documentation/decisions/0007-references-declaration-and-expansion.md) |
|
|
127
143
|
| [`mikser-io-archive`](https://github.com/almero-digital-marketing/mikser-io-archive) | Persist matching entities to YAML — audit trail, versioned content history, downstream export |
|
|
128
144
|
| `mapper` | Run config-supplied transforms over matched entities each cycle (in-core, generic transformation layer) |
|
|
129
145
|
| [`mikser-io-live`](https://github.com/almero-digital-marketing/mikser-io-live) | Lightweight dev server with browser auto-refresh — pair with `--watch` for the classic save→reload loop |
|
|
@@ -143,7 +159,7 @@ The `api`, `vector`, and `schemas` plugins are paired with client-side SDKs so a
|
|
|
143
159
|
|
|
144
160
|
| Package | For the plugin | What you get |
|
|
145
161
|
|---|---|---|
|
|
146
|
-
| [`mikser-io-sdk-api`](https://github.com/almero-digital-marketing/mikser-io-sdk-api) | `api` | `entities(name).list / query / urlFor / pages / update / delete / render / live` — Mongo-style filter operators backed by sift, sort, projection, pagination, SSE-driven live subscriptions |
|
|
162
|
+
| [`mikser-io-sdk-api`](https://github.com/almero-digital-marketing/mikser-io-sdk-api) | `api` | `entities(name).list / query / urlFor / pages / update / delete / render / live` — Mongo-style filter operators backed by sift, sort, projection, pagination, SSE-driven live subscriptions, and `expand: [...]` to inline-resolve `$`-keyed references in one round-trip (multi-hop chains, `*` array iteration) |
|
|
147
163
|
| [`mikser-io-sdk-vector`](https://github.com/almero-digital-marketing/mikser-io-sdk-vector) | `vector` | `vector(storeName).findSimilar(text, { limit })` — semantic search hits with the original mapped object attached |
|
|
148
164
|
|
|
149
165
|
**Framework integrations** — all three wrap `mikser-io-sdk-api` in framework-idiomatic shapes. Same surface: `useDocument` / `useDocuments` live data, multilingual `useHref` / `useAlternates`, asset resolution via `useAsset`, generic on entity type so `mikser-io-plugin-schemas`-emitted types compose:
|
|
@@ -174,6 +190,7 @@ For a working starter — config with a real plugin set, sample `documents/`, ex
|
|
|
174
190
|
|
|
175
191
|
- **Lifecycle** — Processing runs through fixed phases: initialize → load → import → process → persist → render → finalize. Plugins hook into any phase.
|
|
176
192
|
- **Entities** — Everything is an entity (document, file, layout, asset). Entities flow through the journal and are tracked in the catalog.
|
|
193
|
+
- **References between entities** — Front-matter keys starting with `$` (e.g. `$author: /authors/dick`) are references. The engine projects them to plain keys (`meta.author`) for templates and SDK consumers; the schemas plugin auto-validates them; the api can `expand` them inline for one-trip graph fetches. The engine also maintains an inverse-reference index at `runtime.refs.*` (graph queries, rename cascade, live-expand subscriptions, MCP tools `mikser_refs_inbound` / `_outbound` / `_broken` / `_rename`). See [ADR-0007](./documentation/decisions/0007-references-declaration-and-expansion.md).
|
|
177
194
|
- **Plugins** — Functionality is delivered via plugins. Built-in plugins handle common sources (documents, files, layouts, assets). Custom plugins can be added to any project.
|
|
178
195
|
- **Runtime Singleton** — A plain module-level object holds all global state and coordinates the lifecycle. The ES module cache guarantees every importer gets the same instance.
|
|
179
196
|
- **Watch Mode** — In watch mode, file changes trigger incremental re-processing without restarting.
|
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './src/utils.js'
|
|
|
4
4
|
export * from './src/journal.js'
|
|
5
5
|
export * from './src/lifecycle.js'
|
|
6
6
|
export * from './src/catalog.js'
|
|
7
|
+
export * from './src/refs.js'
|
|
7
8
|
export * from './src/config.js'
|
|
8
9
|
export * from './src/plugins.js'
|
|
9
10
|
export * from './src/manager.js'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mikser-io",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.12.0",
|
|
4
4
|
"description": "<p align=\"center\"> <img src=\"mikser-lockup-stacked.svg\" alt=\"mikser\" width=\"198\" /> </p>",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -53,18 +53,19 @@
|
|
|
53
53
|
"yaml": "^2.9.0"
|
|
54
54
|
},
|
|
55
55
|
"optionalDependencies": {
|
|
56
|
-
"express": "^5.2.1"
|
|
57
|
-
"puppeteer": "^25.1.0"
|
|
56
|
+
"express": "^5.2.1"
|
|
58
57
|
},
|
|
59
58
|
"devDependencies": {
|
|
60
59
|
"fluent-ffmpeg": "^2.1.3",
|
|
61
60
|
"mikser-io-decap": "file:../mikser-io-decap",
|
|
62
61
|
"mikser-io-post-mjml": "file:../mikser-io-post-mjml",
|
|
62
|
+
"mikser-io-post-pdf": "file:../mikser-io-post-pdf",
|
|
63
63
|
"mikser-io-render-eta": "file:../mikser-io-render-eta",
|
|
64
64
|
"mikser-io-render-liquid": "file:../mikser-io-render-liquid",
|
|
65
65
|
"mikser-io-render-markdown": "file:../mikser-io-render-markdown",
|
|
66
66
|
"mikser-io-schemas": "file:../mikser-io-schemas",
|
|
67
67
|
"mikser-io-vector": "file:../mikser-io-vector",
|
|
68
|
+
"puppeteer": "^25.1.0",
|
|
68
69
|
"sharp": "^0.34.5",
|
|
69
70
|
"zod": "^4.4.3"
|
|
70
71
|
},
|
package/src/engine.js
CHANGED
|
@@ -10,7 +10,7 @@ import { onInitialize, onInitialized, onLoad, onRender, onCancel, onCancelled, o
|
|
|
10
10
|
import { useJournal, updateEntry } from './journal.js'
|
|
11
11
|
import { globby } from 'globby'
|
|
12
12
|
import { OPERATION, TASKS } from './constants.js'
|
|
13
|
-
import { changeExtension, formatErrorContext } from './utils.js'
|
|
13
|
+
import { changeExtension, formatErrorContext, projectMeta } from './utils.js'
|
|
14
14
|
import render from './render.js'
|
|
15
15
|
import postprocess, { loadPlugin as loadPostPlugin } from './postprocess.js'
|
|
16
16
|
import map from 'p-map'
|
|
@@ -294,8 +294,20 @@ export async function setup(options) {
|
|
|
294
294
|
const jobId = entity.id + ':' + entity.destination
|
|
295
295
|
if (!renderJobs.has(jobId) && !options.ignore) {
|
|
296
296
|
renderJobs.add(jobId)
|
|
297
|
+
// Project reference-marker keys (`$author`, `$hero`, …)
|
|
298
|
+
// into their normalized form (`author`, `hero`) before
|
|
299
|
+
// the entity crosses into the renderer — applies whether
|
|
300
|
+
// the render runs in-process or on a worker thread.
|
|
301
|
+
// Templates and renderer plugins see plain field names;
|
|
302
|
+
// the canonical `$`-keyed form stays in the catalog entry
|
|
303
|
+
// where the schemas and refs plugins consume it.
|
|
304
|
+
// Per ADR-0007 A4, on collision the `$`-version wins
|
|
305
|
+
// deterministically in the projection.
|
|
306
|
+
const renderEntity = entity?.meta
|
|
307
|
+
? { ...entity, meta: projectMeta(entity.meta) }
|
|
308
|
+
: entity
|
|
297
309
|
const renderOptions = {
|
|
298
|
-
entity,
|
|
310
|
+
entity: renderEntity,
|
|
299
311
|
options: {
|
|
300
312
|
tasks: TASKS.POOL,
|
|
301
313
|
...runtime.options,
|