@moku-labs/web 0.1.0-alpha.4 → 0.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Alex Kucherenko
3
+ Copyright (c) 2026 moku-labs
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,73 +1,86 @@
1
1
  # @moku-labs/web
2
2
 
3
- Layer-2 static-site framework built on [`@moku-labs/core`](https://github.com/moku-labs/core). Plugin-composed, Bun-native, with built-in LLM-verifiable test trace and universal env injection.
3
+ **A content static-site generator + SPA web framework for TypeScript.** Built on
4
+ [@moku-labs/core](https://github.com/moku-labs/core) — three layers of isolation, plugins all the
5
+ way down, types doing the heavy lifting.
4
6
 
5
- **Status:** Alpha. Skeleton phase — see `.planning/` for specs.
6
-
7
- ## Quick Start
8
-
9
- ```bash
7
+ ```
10
8
  bun add @moku-labs/web
11
9
  ```
12
10
 
13
- ```ts
14
- import { createApp, route, meta, og, canonical } from '@moku-labs/web'
11
+ > Status: `0.1.0` — early. The API is settling but not yet frozen.
15
12
 
16
- const app = createApp({
17
- mode: 'production',
18
- site: { name: 'My Blog', url: 'https://example.com', author: 'Jane Doe', description: 'Personal blog' },
19
- i18n: { locales: ['en'] as const, defaultLocale: 'en', localeNames: { en: 'English' } },
20
- contentDir: '/abs/path/to/content',
21
- routes: {
22
- home: route('/').render(() => <HomePage />),
23
- },
24
- })
25
-
26
- await app.build.run()
27
- ```
13
+ ---
28
14
 
29
- ## Architecture
15
+ ## What it is
30
16
 
31
- - **10 domain-grouped plugins** (`log`, `env`, `site`, `i18n`, `content`, `router`, `head`, `build`, `spa`, `deploy`) wired via `@moku-labs/core` micro-kernel
32
- - **Bun-native bundler** (no Vite subprocess)
33
- - **Generic-preserving `createApp` wrapper** projects flat config → `pluginConfigs`
34
- - **Dev mode** lives in `bin/moku.ts dev` (NOT a plugin)
35
- - **Cloudflare Pages deploy** via the `deploy` plugin and `moku deploy` CLI (see `src/plugins/deploy/README.md`)
17
+ `@moku-labs/web` composes a small set of focused plugins into one framework: author Markdown
18
+ content, declare type-safe routes, generate SEO-complete HTML + feeds + sitemap at build time, and
19
+ optionally hydrate islands and deploy to Cloudflare Pages.
36
20
 
37
- ## Writing custom plugins
21
+ The consumer surface is one `createApp` call plus a typed routing DSL — you never import from
22
+ `@moku-labs/core` directly.
38
23
 
39
- Consumer apps can extend the framework with their own plugins using the framework-bound `createPlugin` (NOT the raw one from `@moku-labs/core`):
24
+ ## Quick start
40
25
 
41
26
  ```ts
42
- import { createApp, createPlugin, i18n, type Site } from '@moku-labs/web'
43
-
44
- const analytics = createPlugin('analytics', {
45
- depends: [i18n],
46
- config: { trackingId: '' },
47
- createState: () => ({ events: [] as string[] }),
48
- api: (ctx) => ({ track: (name: string) => { ctx.state.events.push(name) } }),
49
- })
50
-
51
- const siteConfig: Site.SiteConfig = {
52
- name: 'My Blog',
53
- url: 'https://example.com',
54
- author: 'Jane Doe',
55
- description: 'Personal blog',
56
- }
27
+ import { createApp, defineRoutes, route } from "@moku-labs/web";
28
+
29
+ const routes = defineRoutes({
30
+ home: route("/")
31
+ .render(() => <h1>My Blog</h1>)
32
+ .head(() => ({ title: "My Blog" })),
33
+ article: route("/{lang:?}/{slug}/")
34
+ .generate((locale) => listSlugs(locale).map((slug) => ({ lang: locale, slug })))
35
+ .load(({ slug }, locale) => loadArticle(slug, locale)) // widens ctx.data
36
+ .render((ctx) => <Article article={ctx.data} />)
37
+ .head((ctx) => ({ title: ctx.data.title, description: ctx.data.description }))
38
+ });
39
+
40
+ const app = createApp({
41
+ config: { mode: "production" },
42
+ pluginConfigs: {
43
+ site: { name: "My Blog", url: "https://blog.dev", author: "Me", description: "A personal blog." },
44
+ i18n: { locales: ["en", "uk"], defaultLocale: "en" },
45
+ content: { contentDir: "./content" },
46
+ router: { routes, mode: "ssg" },
47
+ head: { titleTemplate: "%s — My Blog" },
48
+ build: { outDir: "dist", feeds: true, sitemap: true }
49
+ }
50
+ });
51
+
52
+ await app.build.run(); // → static site in dist/ (HTML, feed.xml, sitemap.xml)
57
53
  ```
58
54
 
59
- All 10 plugin instances (`log, env, site, i18n, content, router, head, build, spa, deploy`) and their namespaced config types (`Log, Env, Site, I18n, Content, Router, Head, Build, Spa, Deploy`) are exported from the main entry — use them for `ctx.require(...)` access and for typing `pluginConfigs` overrides.
55
+ Content lives on disk as `content/{slug}/{locale}.md` with YAML frontmatter
56
+ (`title`, `date`, `description`, `tags`, `language`, optional `draft`/`author`). Drafts are excluded
57
+ from production builds.
60
58
 
61
- ## Test helpers (`@moku-labs/web/test`)
59
+ ## Plugins
62
60
 
63
- Framework-aware test factories for isolating plugin behavior in unit tests:
61
+ | Plugin | Responsibility |
62
+ |---|---|
63
+ | `site` | Site identity (name, URL, author) + canonical URL helper |
64
+ | `i18n` | Locales, default-locale fallback, translations, hreflang/ogLocale maps |
65
+ | `router` | Type-safe route DSL (`route`/`defineRoutes`), matching, URL/file derivation |
66
+ | `content` | Markdown pipeline → sanitized HTML, frontmatter, reading time, locale model |
67
+ | `head` | SEO `<head>` composition: title template, canonical, OG/Twitter, JSON-LD, hreflang |
68
+ | `build` | SSG orchestrator: pages, feeds (RSS/Atom/JSON), sitemap, OG images |
69
+ | `spa` | Client runtime: island hydration + intercepted navigation |
70
+ | `deploy` | Cloudflare Pages: `wrangler.jsonc` scaffolding + deploy |
71
+ | `log`, `env` | Core plugins: structured logging + validated environment access |
64
72
 
65
- ```ts
66
- import { createTestApp, createTestLog, createTestEnv } from '@moku-labs/web/test'
67
- ```
73
+ SEO primitives are exported for route `.head()` handlers: `meta`, `og`, `twitter`, `jsonLd`,
74
+ `canonical`, `hreflang`, `feedLink`, `buildArticleHead`.
68
75
 
69
- Each factory returns a FRESH instance per call — never a module-level singleton — safe for parallel vitest workers.
76
+ ## Scripts
77
+
78
+ ```
79
+ bun run build # build with tsdown
80
+ bun run test # vitest (unit + integration)
81
+ bun run lint # biome + eslint
82
+ ```
70
83
 
71
84
  ## License
72
85
 
73
- MIT
86
+ MIT © moku-labs