@moku-labs/core 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +315 -0
- package/dist/index.cjs +715 -0
- package/dist/index.d.cts +900 -0
- package/dist/index.d.mts +900 -0
- package/dist/index.mjs +713 -0
- package/package.json +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 moku-labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# Moku Core
|
|
2
|
+
|
|
3
|
+
**Micro-kernel plugin framework for TypeScript. Three layers of isolation. Built for LLM-scale development.**
|
|
4
|
+
|
|
5
|
+
One runtime export. Bundle < 5KB. Zero dependencies. The type system does the heavy lifting.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
bun add @moku-labs/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## The Problem
|
|
14
|
+
|
|
15
|
+
LLMs are writing more of our code. But they generate spaghetti — they invent structure, mix concerns, bypass APIs, and scatter logic across files. The bigger the codebase, the worse it gets.
|
|
16
|
+
|
|
17
|
+
Every framework tries to solve scaling with conventions. Conventions don't work for LLMs. LLMs approximate conventions. They hallucinate when the API surface is too large to hold in context.
|
|
18
|
+
|
|
19
|
+
**You need constraints, not conventions.**
|
|
20
|
+
|
|
21
|
+
## The Solution
|
|
22
|
+
|
|
23
|
+
Moku enforces a 3-layer architecture where each layer physically constrains the layer above it. LLM-generated code is confined to plugins, integrated only through typed public APIs, and cannot touch the core.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
┌─────────────────────────────────────────────────────────┐
|
|
27
|
+
│ Layer 3: Consumer / LLM-generated code │
|
|
28
|
+
│ Can only: configure, compose plugins, use typed APIs │
|
|
29
|
+
│ Cannot: modify the framework, bypass plugin boundaries │
|
|
30
|
+
├─────────────────────────────────────────────────────────┤
|
|
31
|
+
│ Layer 2: Framework │
|
|
32
|
+
│ Defines: config shape, event contract, default plugins │
|
|
33
|
+
│ Cannot: modify the kernel │
|
|
34
|
+
├─────────────────────────────────────────────────────────┤
|
|
35
|
+
│ Layer 1: @moku-labs/core │
|
|
36
|
+
│ One function. Zero domain knowledge. Pure machinery. │
|
|
37
|
+
└─────────────────────────────────────────────────────────┘
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Slop doesn't spread.** An LLM writing a plugin cannot break the framework. An LLM writing consumer code cannot break a plugin. The architecture is the guardrail.
|
|
41
|
+
|
|
42
|
+
## Why It Works for LLMs
|
|
43
|
+
|
|
44
|
+
| Problem | How Moku solves it |
|
|
45
|
+
|---|---|
|
|
46
|
+
| LLMs hallucinate framework structure | Entire API learnable in ~1000 tokens |
|
|
47
|
+
| Code drifts across files and modules | Each feature is one plugin, one boundary |
|
|
48
|
+
| Generated code bypasses intended APIs | `emit` is strictly typed, no escape hatch |
|
|
49
|
+
| Quality degrades at scale | Frozen configs, phantom types, compile-time enforcement |
|
|
50
|
+
| Adding features breaks existing code | Horizontal scaling — add plugins, don't modify |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
### 1. Define your framework (Layer 2)
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// my-framework/config.ts
|
|
60
|
+
import { createCoreConfig } from '@moku-labs/core';
|
|
61
|
+
|
|
62
|
+
type Config = { siteName: string; mode: 'development' | 'production' };
|
|
63
|
+
type Events = {
|
|
64
|
+
'page:render': { path: string; html: string };
|
|
65
|
+
'router:navigate': { from: string; to: string };
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const coreConfig = createCoreConfig<Config, Events>('my-site', {
|
|
69
|
+
config: { siteName: 'Untitled', mode: 'development' },
|
|
70
|
+
});
|
|
71
|
+
export const { createPlugin, createCore } = coreConfig;
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Write plugins
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// my-framework/plugins/router.ts
|
|
78
|
+
import { createPlugin } from '../config';
|
|
79
|
+
|
|
80
|
+
export const routerPlugin = createPlugin('router', {
|
|
81
|
+
config: { basePath: '/' },
|
|
82
|
+
createState: () => ({ currentPath: '/', history: [] as string[] }),
|
|
83
|
+
api: ctx => ({
|
|
84
|
+
navigate: (path: string) => {
|
|
85
|
+
const from = ctx.state.currentPath;
|
|
86
|
+
ctx.state.currentPath = path;
|
|
87
|
+
ctx.emit('router:navigate', { from, to: path });
|
|
88
|
+
},
|
|
89
|
+
current: () => ctx.state.currentPath,
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. Wire the framework
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// my-framework/index.ts
|
|
98
|
+
import { coreConfig, createCore } from './config';
|
|
99
|
+
import { routerPlugin } from './plugins/router';
|
|
100
|
+
|
|
101
|
+
const framework = createCore(coreConfig, {
|
|
102
|
+
plugins: [routerPlugin],
|
|
103
|
+
});
|
|
104
|
+
export const { createApp, createPlugin } = framework;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 4. Ship the product (Layer 3)
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// my-app/main.ts
|
|
111
|
+
import { createApp } from 'my-framework';
|
|
112
|
+
|
|
113
|
+
const app = await createApp({
|
|
114
|
+
plugins: [blogPlugin],
|
|
115
|
+
config: { siteName: 'My Blog', mode: 'production' },
|
|
116
|
+
pluginConfigs: { router: { basePath: '/blog' } },
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await app.start();
|
|
120
|
+
app.router.navigate('/about'); // fully typed
|
|
121
|
+
app.blog.listPosts(); // fully typed
|
|
122
|
+
await app.stop();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**That's the entire API.** `createCoreConfig` → `createCore` → `createApp`. Three functions, three layers.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## How It Scales
|
|
130
|
+
|
|
131
|
+
Every feature is a plugin. Plugins are isolated by design:
|
|
132
|
+
|
|
133
|
+
- **Own config** — declared in the plugin, resolved by the kernel
|
|
134
|
+
- **Own state** — mutable escape hatch, invisible to other plugins
|
|
135
|
+
- **Own API** — mounted on the app object, fully typed
|
|
136
|
+
- **Own events** — declared via register callback, strictly typed payloads
|
|
137
|
+
- **Explicit dependencies** — `depends: [otherPlugin]`, validated at init
|
|
138
|
+
|
|
139
|
+
Adding a feature = adding a plugin to the array. No framework modifications. No global state pollution. No import spaghetti.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// Team A ships auth
|
|
143
|
+
const authPlugin = createPlugin('auth', {
|
|
144
|
+
events: register => ({
|
|
145
|
+
'auth:login': register<{ userId: string }>('User logged in'),
|
|
146
|
+
}),
|
|
147
|
+
api: ctx => ({
|
|
148
|
+
login: (id: string) => ctx.emit('auth:login', { userId: id }),
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Team B ships analytics, depends on auth events
|
|
153
|
+
const analyticsPlugin = createPlugin('analytics', {
|
|
154
|
+
depends: [authPlugin],
|
|
155
|
+
createState: () => ({ events: [] as string[] }),
|
|
156
|
+
hooks: ctx => ({
|
|
157
|
+
'auth:login': ({ userId }) => { ctx.state.events.push(`login:${userId}`); },
|
|
158
|
+
}),
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Teams work independently. Plugins compose through typed events. The kernel enforces the boundaries.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Quality Enforcement
|
|
167
|
+
|
|
168
|
+
Moku is designed for a world where LLMs write plugins and CI enforces quality. The framework provides structural guarantees, and the toolchain catches everything else.
|
|
169
|
+
|
|
170
|
+
### Compile-time guarantees
|
|
171
|
+
|
|
172
|
+
- **Strict emit** — only known event names compile. Wrong payloads are type errors. No `any`, no escape hatch.
|
|
173
|
+
- **Phantom types** — plugin APIs, configs, and events flow through the type system without runtime cost.
|
|
174
|
+
- **Required configs** — if a plugin needs config and you don't provide it, TypeScript tells you.
|
|
175
|
+
- **Context tiers** — `createState` can't call `emit` (other plugins don't exist yet). `onStop` can't access other plugins (they may already be stopped). The type system prevents temporal bugs.
|
|
176
|
+
|
|
177
|
+
### Runtime guarantees
|
|
178
|
+
|
|
179
|
+
- **Frozen configs** — `Object.freeze` on all configs and the app object. No accidental mutation.
|
|
180
|
+
- **No duplicate plugins** — caught at init with an actionable error message.
|
|
181
|
+
- **Dependency validation** — dependencies must appear before dependents. No implicit reordering.
|
|
182
|
+
- **Sequential execution** — lifecycle phases run one plugin at a time. No race conditions.
|
|
183
|
+
- **Single start/stop** — calling `start()` twice throws. Calling `stop()` before `start()` throws.
|
|
184
|
+
|
|
185
|
+
### Recommended toolchain
|
|
186
|
+
|
|
187
|
+
The kernel provides structure. Pair it with:
|
|
188
|
+
|
|
189
|
+
- **[Biome](https://biomejs.dev/)** — fast formatting + linting, zero-config
|
|
190
|
+
- **[ESLint](https://eslint.org/)** — JSDoc enforcement, code quality rules
|
|
191
|
+
- **[Vitest](https://vitest.dev/)** — test coverage thresholds per plugin
|
|
192
|
+
- **TypeScript strict mode** — `exactOptionalPropertyTypes`, `noUncheckedIndexedAccess`
|
|
193
|
+
|
|
194
|
+
LLMs generate the code. The toolchain gates it. The kernel contains it.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## The Kernel
|
|
199
|
+
|
|
200
|
+
Six responsibilities. Nothing else.
|
|
201
|
+
|
|
202
|
+
| # | Responsibility | Mechanism |
|
|
203
|
+
|---|---|---|
|
|
204
|
+
| 1 | Collect plugins | Ordered array, framework defaults + consumer extras |
|
|
205
|
+
| 2 | Validate | Reserved names, duplicates, dependency order |
|
|
206
|
+
| 3 | Resolve config | Shallow merge: plugin defaults → framework → consumer |
|
|
207
|
+
| 4 | Lifecycle | 3 phases: `onInit` → `onStart` → `onStop` (reverse) |
|
|
208
|
+
| 5 | Events | `emit` dispatches to typed hooks. Fire-and-forget. |
|
|
209
|
+
| 6 | Freeze | `Object.freeze` on app and configs. State stays mutable. |
|
|
210
|
+
|
|
211
|
+
### Plugin spec shape
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
createPlugin('name', {
|
|
215
|
+
config: { /* defaults */ },
|
|
216
|
+
events: register => ({ 'name:event': register<Payload>('description') }),
|
|
217
|
+
depends: [otherPlugin],
|
|
218
|
+
createState: ctx => ({ /* mutable state */ }),
|
|
219
|
+
api: ctx => ({ /* public methods, mounted on app.name */ }),
|
|
220
|
+
hooks: ctx => ({ 'event:name': handler }),
|
|
221
|
+
onInit: async ctx => { /* all plugins exist */ },
|
|
222
|
+
onStart: async ctx => { /* app is running */ },
|
|
223
|
+
onStop: async ctx => { /* teardown, reverse order */ },
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Every field is optional. A plugin with only `api` works. A plugin with only `hooks` works.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Design Principles
|
|
232
|
+
|
|
233
|
+
**Brutal simplicity.** No classes. No decorators. No dependency injection. No inheritance. Every function is a pure factory: input → output.
|
|
234
|
+
|
|
235
|
+
**Types over runtime.** Most of the codebase is type definitions and JSDoc. The type system provides autocomplete, compile-time validation, and documentation simultaneously.
|
|
236
|
+
|
|
237
|
+
**Explicit over implicit.** Plugin order is the array order. No topological sort. No magic reordering. If B depends on A, A comes first.
|
|
238
|
+
|
|
239
|
+
**Functional composition.** Plugins are plain objects. Dependencies use `ctx.require(plugin)`. APIs are closures over state. No `this`, no prototypes.
|
|
240
|
+
|
|
241
|
+
**Minimum description length.** Define parts (plugins), compose them (createApp), let them communicate (events + APIs), manage lifecycle (init/start/stop). Nothing else.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## API Reference
|
|
246
|
+
|
|
247
|
+
### Exports
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Runtime
|
|
251
|
+
import { createCoreConfig } from '@moku-labs/core';
|
|
252
|
+
|
|
253
|
+
// Type utilities for plugin authors
|
|
254
|
+
import type { PluginCtx, EmitFn } from '@moku-labs/core';
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### createCoreConfig\<Config, Events\>(id, options)
|
|
258
|
+
|
|
259
|
+
Creates a bound factory chain for a framework. Returns `{ createPlugin, createCore }`, both locked to `Config` and `Events`.
|
|
260
|
+
|
|
261
|
+
### createCore(coreConfig, options)
|
|
262
|
+
|
|
263
|
+
Captures framework defaults: plugins, plugin configs, `onReady`, `onError`. Returns `{ createApp, createPlugin }`.
|
|
264
|
+
|
|
265
|
+
### createPlugin(name, spec)
|
|
266
|
+
|
|
267
|
+
Creates a plugin instance. Zero explicit generics — everything inferred from the spec. Returns `PluginInstance` with phantom types.
|
|
268
|
+
|
|
269
|
+
### createApp(options?)
|
|
270
|
+
|
|
271
|
+
Merges framework defaults with consumer options. Validates, resolves config, runs `onInit`. Returns `Promise<App>` — a frozen object with plugin APIs mounted as properties.
|
|
272
|
+
|
|
273
|
+
### App
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
await app.start(); // onStart (forward order)
|
|
277
|
+
await app.stop(); // onStop (reverse order)
|
|
278
|
+
app.emit('event', payload); // strictly typed, fire-and-forget
|
|
279
|
+
app.require(plugin); // returns typed API or throws
|
|
280
|
+
app.has('name'); // boolean, never throws
|
|
281
|
+
app.pluginName.method(); // fully typed API access
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Specification
|
|
287
|
+
|
|
288
|
+
The full specification lives in [`specification/`](specification/):
|
|
289
|
+
|
|
290
|
+
| Document | Covers |
|
|
291
|
+
|---|---|
|
|
292
|
+
| [01 Architecture](specification/01-ARCHITECTURE.md) | Three-layer model, design philosophy, LLM motivation |
|
|
293
|
+
| [02 Core API](specification/02-CORE-API.md) | All function signatures |
|
|
294
|
+
| [03 Plugin System](specification/03-PLUGIN-SYSTEM.md) | PluginSpec, PluginInstance, depends |
|
|
295
|
+
| [04 Factory Chain](specification/04-FACTORY-CHAIN.md) | 3-step factory chain: why and how |
|
|
296
|
+
| [05 Config System](specification/05-CONFIG-SYSTEM.md) | Config resolution, shallow merge rules |
|
|
297
|
+
| [06 Lifecycle](specification/06-LIFECYCLE.md) | init → start → stop phases |
|
|
298
|
+
| [07 Communication](specification/07-COMMUNICATION.md) | emit, hooks, event dispatch |
|
|
299
|
+
| [08 Context](specification/08-CONTEXT.md) | Three context tiers |
|
|
300
|
+
| [09 Type System](specification/09-TYPE-SYSTEM.md) | Phantom types, type flow, BuildPluginApis |
|
|
301
|
+
| [11 Invariants](specification/11-INVARIANTS.md) | Guarantees, error format, anti-patterns |
|
|
302
|
+
| [12 Plugin Patterns](specification/12-PLUGIN-PATTERNS.md) | File structure conventions |
|
|
303
|
+
| [13 Kernel Pseudocode](specification/13-KERNEL-PSEUDOCODE.md) | Reference implementation with rationale |
|
|
304
|
+
| [14 Event Registration](specification/14-EVENT-REGISTRATION.md) | Register callback pattern |
|
|
305
|
+
| [15 Plugin Structure](specification/15-PLUGIN-STRUCTURE.md) | Plugin file organization |
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Status
|
|
310
|
+
|
|
311
|
+
Alpha. API is stabilizing. Not yet published to npm.
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
MIT
|