davaux 0.8.0 → 0.8.1
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/package.json +6 -2
- package/BASELINE.md +0 -169
- package/CLAUDE.md +0 -518
- package/ROADMAP.md +0 -198
- package/build.mjs +0 -101
- package/client/control.ts +0 -247
- package/client/hydrate.ts +0 -37
- package/client/index.ts +0 -19
- package/client/jsx-runtime.ts +0 -209
- package/client/resource.ts +0 -122
- package/client/signal.ts +0 -211
- package/client/store.ts +0 -110
- package/client/useHead.ts +0 -63
- package/pka.config.json +0 -32
- package/src/build/config.ts +0 -42
- package/src/build/index.ts +0 -6
- package/src/build/plugins.ts +0 -118
- package/src/cli.ts +0 -502
- package/src/config.ts +0 -197
- package/src/create-multisite.ts +0 -310
- package/src/create.ts +0 -194
- package/src/dev/blueprints.ts +0 -75
- package/src/dev/components.ts +0 -108
- package/src/dev/insert.ts +0 -221
- package/src/dev/remove.ts +0 -677
- package/src/dev/watch.ts +0 -3098
- package/src/errors.ts +0 -64
- package/src/generate.ts +0 -228
- package/src/index.ts +0 -67
- package/src/island.ts +0 -47
- package/src/jsx-runtime.d.ts +0 -408
- package/src/jsx-runtime.d.ts.map +0 -1
- package/src/jsx-runtime.ts +0 -536
- package/src/link.ts +0 -49
- package/src/oml/fragment.ts +0 -54
- package/src/oml/index.ts +0 -21
- package/src/oml/jsx-runtime.ts +0 -121
- package/src/oml/jsx.ts +0 -151
- package/src/oml/page.ts +0 -13
- package/src/oml/render.ts +0 -181
- package/src/oml/types.ts +0 -159
- package/src/router/handler.ts +0 -515
- package/src/router/matcher.ts +0 -52
- package/src/router/scanner.ts +0 -272
- package/src/server/index.ts +0 -49
- package/src/signal.ts +0 -39
- package/src/ssg.ts +0 -253
- package/src/test/actions.test.ts +0 -40
- package/src/test/body-limits.test.ts +0 -83
- package/src/test/errors.test.ts +0 -53
- package/src/test/fixtures/routes/[id].page.ts +0 -3
- package/src/test/fixtures/routes/_error.ts +0 -6
- package/src/test/fixtures/routes/_global.ts +0 -8
- package/src/test/fixtures/routes/_layout-template.ts +0 -7
- package/src/test/fixtures/routes/_layout.ts +0 -7
- package/src/test/fixtures/routes/_layout_scripts.ts +0 -8
- package/src/test/fixtures/routes/_middleware.ts +0 -8
- package/src/test/fixtures/routes/_redirect301_mw.ts +0 -5
- package/src/test/fixtures/routes/_redirect_mw.ts +0 -5
- package/src/test/fixtures/routes/about.page.ts +0 -6
- package/src/test/fixtures/routes/action.page.ts +0 -11
- package/src/test/fixtures/routes/api/form-all.post.ts +0 -5
- package/src/test/fixtures/routes/api/form-limited.post.ts +0 -6
- package/src/test/fixtures/routes/api/response-obj.get.ts +0 -17
- package/src/test/fixtures/routes/api/upload.post.ts +0 -14
- package/src/test/fixtures/routes/api/users.get.ts +0 -3
- package/src/test/fixtures/routes/api/xml.get.ts +0 -5
- package/src/test/fixtures/routes/auth/_middleware.ts +0 -11
- package/src/test/fixtures/routes/auth/protected.page.ts +0 -3
- package/src/test/fixtures/routes/index.page.ts +0 -3
- package/src/test/fixtures/routes/oml.page.ts +0 -7
- package/src/test/fixtures/routes/redirect.page.ts +0 -3
- package/src/test/fixtures/routes/ssg/[slug].page.ts +0 -8
- package/src/test/fixtures/routes/ssg/server.page.ts +0 -5
- package/src/test/fixtures/routes/state.page.ts +0 -4
- package/src/test/fixtures/routes/throw.page.ts +0 -5
- package/src/test/fixtures/routes/wiki/[...slug].page.ts +0 -3
- package/src/test/helpers.ts +0 -132
- package/src/test/layouts.test.ts +0 -76
- package/src/test/middleware.test.ts +0 -69
- package/src/test/multipart.test.ts +0 -91
- package/src/test/oml-routing.test.ts +0 -59
- package/src/test/oml.test.ts +0 -429
- package/src/test/redirects.test.ts +0 -32
- package/src/test/routing.test.ts +0 -118
- package/src/test/ssg.test.ts +0 -273
- package/src/test/web-response.test.ts +0 -33
- package/src/types.ts +0 -670
- package/tsconfig.client.json +0 -17
- package/tsconfig.json +0 -20
package/client/useHead.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { createEffect, onCleanup } from './signal.js'
|
|
2
|
-
|
|
3
|
-
export interface MetaDescriptor {
|
|
4
|
-
/** `<meta name="...">` value. Mutually exclusive with `property`. */
|
|
5
|
-
name?: string
|
|
6
|
-
/** `<meta property="...">` value (Open Graph, etc.). Mutually exclusive with `name`. */
|
|
7
|
-
property?: string
|
|
8
|
-
content: string | (() => string)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface UseHeadOptions {
|
|
12
|
-
/** Reactive document title. A function re-runs whenever its signals change. */
|
|
13
|
-
title?: string | (() => string)
|
|
14
|
-
/** Meta tags to add/update in `<head>`. Existing tags are updated in place. */
|
|
15
|
-
meta?: MetaDescriptor[]
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Update `document.title` and `<meta>` tags from inside a client island.
|
|
20
|
-
* String values are set once; function values are wrapped in `createEffect`
|
|
21
|
-
* and update reactively whenever their signals change.
|
|
22
|
-
*
|
|
23
|
-
* No-op on the server — use `ctx.head` from the page handler for initial SSR values.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* useHead({
|
|
27
|
-
* title: () => `${article()} — My Site`,
|
|
28
|
-
* meta: [{ name: 'description', content: () => article().summary }],
|
|
29
|
-
* })
|
|
30
|
-
*/
|
|
31
|
-
export function useHead(options: UseHeadOptions): void {
|
|
32
|
-
if (typeof document === 'undefined') return
|
|
33
|
-
|
|
34
|
-
if (options.title !== undefined) {
|
|
35
|
-
const title = options.title
|
|
36
|
-
createEffect(() => {
|
|
37
|
-
document.title = typeof title === 'function' ? title() : title
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
for (const descriptor of options.meta ?? []) {
|
|
42
|
-
const attr = descriptor.name !== undefined ? 'name' : 'property'
|
|
43
|
-
const attrValue = (descriptor.name ?? descriptor.property) as string
|
|
44
|
-
|
|
45
|
-
let el = document.querySelector(`meta[${attr}="${attrValue}"]`) as HTMLMetaElement | null
|
|
46
|
-
const created = !el
|
|
47
|
-
if (!el) {
|
|
48
|
-
el = document.createElement('meta')
|
|
49
|
-
el.setAttribute(attr, attrValue)
|
|
50
|
-
document.head.appendChild(el)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const metaEl = el
|
|
54
|
-
const content = descriptor.content
|
|
55
|
-
createEffect(() => {
|
|
56
|
-
metaEl.content = typeof content === 'function' ? content() : content
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
if (created) {
|
|
60
|
-
onCleanup(() => metaEl.remove())
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
package/pka.config.json
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"configVersion": 2,
|
|
3
|
-
"_pkaGenerated": true,
|
|
4
|
-
"mode": "claude-code",
|
|
5
|
-
"outputDir": "./.pka",
|
|
6
|
-
"maxFileSize": 1048576,
|
|
7
|
-
"noGit": false,
|
|
8
|
-
"noContext": false,
|
|
9
|
-
"noConcat": false,
|
|
10
|
-
"noFlatten": false,
|
|
11
|
-
"install": false,
|
|
12
|
-
"noGitignore": false,
|
|
13
|
-
"xml": false,
|
|
14
|
-
"agentsMd": null,
|
|
15
|
-
"copilot": null,
|
|
16
|
-
"cursorRules": null,
|
|
17
|
-
"hierarchical": false,
|
|
18
|
-
"scaffoldCommands": false,
|
|
19
|
-
"compact": false,
|
|
20
|
-
"compactTokens": 0,
|
|
21
|
-
"compactOmit": false,
|
|
22
|
-
"compactKeep": [],
|
|
23
|
-
"compactPreview": false,
|
|
24
|
-
"diff": false,
|
|
25
|
-
"force": false,
|
|
26
|
-
"watch": false,
|
|
27
|
-
"since": null,
|
|
28
|
-
"includeExt": [],
|
|
29
|
-
"excludeDir": [],
|
|
30
|
-
"description": "",
|
|
31
|
-
"instructions": ""
|
|
32
|
-
}
|
package/src/build/config.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs'
|
|
2
|
-
import { mkdir, rm } from 'node:fs/promises'
|
|
3
|
-
import { join, resolve } from 'node:path'
|
|
4
|
-
import type { DavauxConfig } from '../config.js'
|
|
5
|
-
|
|
6
|
-
const CONFIG_FILES = ['davaux.config.ts', 'davaux.config.js', 'davaux.config.mjs']
|
|
7
|
-
|
|
8
|
-
// Compile and import the project's davaux.config.* file.
|
|
9
|
-
// Returns an empty object if no config file is found.
|
|
10
|
-
export async function loadConfig(cwd: string): Promise<DavauxConfig> {
|
|
11
|
-
for (const name of CONFIG_FILES) {
|
|
12
|
-
const configPath = resolve(cwd, name)
|
|
13
|
-
if (!existsSync(configPath)) continue
|
|
14
|
-
|
|
15
|
-
// Write to node_modules/.cache/davaux/ so Node.js resolves externals
|
|
16
|
-
// (esbuild, davaux, etc.) via the project's own node_modules tree.
|
|
17
|
-
const cacheDir = resolve(cwd, 'node_modules', '.cache', 'davaux')
|
|
18
|
-
await mkdir(cacheDir, { recursive: true })
|
|
19
|
-
const outfile = join(cacheDir, `config-${Date.now()}.mjs`)
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const { build } = await import('esbuild')
|
|
23
|
-
await build({
|
|
24
|
-
entryPoints: [configPath],
|
|
25
|
-
outfile,
|
|
26
|
-
format: 'esm',
|
|
27
|
-
platform: 'node',
|
|
28
|
-
target: 'node22',
|
|
29
|
-
bundle: true,
|
|
30
|
-
// Keep node built-ins and framework packages as external imports;
|
|
31
|
-
// everything else (user plugin deps) is bundled in.
|
|
32
|
-
external: ['node:*', 'esbuild', 'davaux', 'davaux/*'],
|
|
33
|
-
logLevel: 'silent',
|
|
34
|
-
})
|
|
35
|
-
const mod = await import(outfile)
|
|
36
|
-
return (mod.default ?? {}) as DavauxConfig
|
|
37
|
-
} finally {
|
|
38
|
-
await rm(outfile, { force: true }).catch(() => {})
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return {}
|
|
42
|
-
}
|
package/src/build/index.ts
DELETED
package/src/build/plugins.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises'
|
|
2
|
-
import { basename, dirname, join } from 'node:path'
|
|
3
|
-
import { type Plugin, transform } from 'esbuild'
|
|
4
|
-
import type { IslandFile } from '../types.js'
|
|
5
|
-
|
|
6
|
-
// ─── Island server plugin ─────────────────────────────────────────────────────
|
|
7
|
-
//
|
|
8
|
-
// When the routes bundle imports a file from the islands directory, this plugin
|
|
9
|
-
// intercepts at load time and returns a thin server wrapper instead of the raw
|
|
10
|
-
// source. The wrapper re-exports the component wrapped with island() so the
|
|
11
|
-
// route gets back a function that renders SSR HTML + serialized props.
|
|
12
|
-
//
|
|
13
|
-
// The actual island source is loaded under the 'island-raw' namespace, which:
|
|
14
|
-
// 1. Strips any @jsxImportSource pragma (server context sets its own)
|
|
15
|
-
// 2. Allows the route context's jsxImportSource:'davaux' + alias to apply
|
|
16
|
-
|
|
17
|
-
export function islandServerPlugin(islandsDirs: string | string[]): Plugin {
|
|
18
|
-
const dirs = Array.isArray(islandsDirs) ? islandsDirs : [islandsDirs]
|
|
19
|
-
return {
|
|
20
|
-
name: 'davaux-island-server',
|
|
21
|
-
setup(build) {
|
|
22
|
-
// Intercept file-namespace loads of island source files
|
|
23
|
-
build.onLoad({ filter: /\.(tsx?|jsx?)$/ }, async (args) => {
|
|
24
|
-
if (args.namespace !== 'file') return
|
|
25
|
-
if (!dirs.some((d) => args.path.startsWith(d))) return
|
|
26
|
-
|
|
27
|
-
const id = basename(args.path).replace(/\.(tsx?|jsx?)$/, '')
|
|
28
|
-
return {
|
|
29
|
-
contents: [
|
|
30
|
-
`import Component from ${JSON.stringify(`${args.path}?island-raw`)};`,
|
|
31
|
-
`import { island } from 'davaux/island';`,
|
|
32
|
-
`export default island(Component, ${JSON.stringify(id)});`,
|
|
33
|
-
].join('\n'),
|
|
34
|
-
loader: 'js',
|
|
35
|
-
resolveDir: dirname(args.path),
|
|
36
|
-
}
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
// Resolve the ?island-raw marker → island-raw namespace (bypasses the wrapper)
|
|
40
|
-
build.onResolve({ filter: /\?island-raw$/ }, (args) => ({
|
|
41
|
-
path: args.path.replace(/\?island-raw$/, ''),
|
|
42
|
-
namespace: 'island-raw',
|
|
43
|
-
}))
|
|
44
|
-
|
|
45
|
-
// Load the raw island source, stripping any file-level @jsxImportSource pragma
|
|
46
|
-
// and replacing it with the standard 'davaux' runtime so the island renders to
|
|
47
|
-
// HTML strings on the server (OML is only needed at the route/page level).
|
|
48
|
-
build.onLoad({ filter: /.*/, namespace: 'island-raw' }, async (args) => {
|
|
49
|
-
let source = await readFile(args.path, 'utf8')
|
|
50
|
-
source = source.replace(/\/\*\*?\s*@jsxImportSource\s+\S+\s*\*\//g, '')
|
|
51
|
-
source = `/** @jsxImportSource davaux */\n${source}`
|
|
52
|
-
const ext = (args.path.match(/\.(tsx?|jsx?)$/)?.[1] ?? 'ts') as 'tsx' | 'ts' | 'jsx' | 'js'
|
|
53
|
-
return { contents: source, loader: ext, resolveDir: dirname(args.path) }
|
|
54
|
-
})
|
|
55
|
-
},
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// ─── CSS collector ────────────────────────────────────────────────────────────
|
|
60
|
-
//
|
|
61
|
-
// Scans a directory recursively for all *.css files produced by esbuild
|
|
62
|
-
// (side-effect CSS imports in routes and islands) and concatenates them into a
|
|
63
|
-
// single stylesheet. Returns true if CSS was found and written, false otherwise.
|
|
64
|
-
|
|
65
|
-
export async function collectCss(
|
|
66
|
-
scanDir: string,
|
|
67
|
-
stylesOutFile: string,
|
|
68
|
-
minify = false,
|
|
69
|
-
): Promise<boolean> {
|
|
70
|
-
const cssFiles: string[] = []
|
|
71
|
-
async function walk(dir: string): Promise<void> {
|
|
72
|
-
const entries = await readdir(dir, { withFileTypes: true }).catch(() => [])
|
|
73
|
-
for (const e of entries) {
|
|
74
|
-
const full = join(dir, e.name)
|
|
75
|
-
if (e.isDirectory()) await walk(full)
|
|
76
|
-
else if (e.name.endsWith('.css') && full !== stylesOutFile) cssFiles.push(full)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
await walk(scanDir)
|
|
80
|
-
if (cssFiles.length === 0) return false
|
|
81
|
-
let css = (await Promise.all(cssFiles.map((f) => readFile(f, 'utf8')))).join('\n')
|
|
82
|
-
if (minify) {
|
|
83
|
-
const result = await transform(css, { loader: 'css', minify: true })
|
|
84
|
-
css = result.code
|
|
85
|
-
}
|
|
86
|
-
await mkdir(dirname(stylesOutFile), { recursive: true })
|
|
87
|
-
await writeFile(stylesOutFile, css)
|
|
88
|
-
return true
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// ─── CSS collector plugin ─────────────────────────────────────────────────────
|
|
92
|
-
//
|
|
93
|
-
// Wraps collectCss as an esbuild onEnd plugin. Added to both the routes and
|
|
94
|
-
// islands contexts so either rebuild updates the combined stylesheet.
|
|
95
|
-
|
|
96
|
-
export function cssCollectorPlugin(dauxDir: string, stylesOutFile: string): Plugin {
|
|
97
|
-
return {
|
|
98
|
-
name: 'davaux-css-collector',
|
|
99
|
-
setup(build) {
|
|
100
|
-
build.onEnd(() => void collectCss(dauxDir, stylesOutFile))
|
|
101
|
-
},
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ─── Island client bundle entry ───────────────────────────────────────────────
|
|
106
|
-
|
|
107
|
-
export function generateIslandsEntry(islands: IslandFile[]): string {
|
|
108
|
-
return [
|
|
109
|
-
`import { hydrate } from 'davaux/client'`,
|
|
110
|
-
...islands.map((isle, i) => `import __island_${i} from ${JSON.stringify(isle.filePath)}`),
|
|
111
|
-
'',
|
|
112
|
-
'hydrate({',
|
|
113
|
-
...islands.map(
|
|
114
|
-
(isle, i) => ` ${JSON.stringify(isle.id)}: async () => ({ default: __island_${i} }),`,
|
|
115
|
-
),
|
|
116
|
-
'})',
|
|
117
|
-
].join('\n')
|
|
118
|
-
}
|