@elurjs/kit 2.4.4
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/CHANGELOG.md +874 -0
- package/LICENSE +21 -0
- package/README.md +1330 -0
- package/bin/elur-kit.js +54 -0
- package/dist/lib/action/define.d.cts +72 -0
- package/dist/lib/action/define.d.ts +72 -0
- package/dist/lib/action/error-store.d.cts +29 -0
- package/dist/lib/action/error-store.d.ts +29 -0
- package/dist/lib/action/index.cjs +1 -0
- package/dist/lib/action/index.d.cts +64 -0
- package/dist/lib/action/index.d.ts +64 -0
- package/dist/lib/action/index.js +2 -0
- package/dist/lib/action/origin.d.cts +20 -0
- package/dist/lib/action/origin.d.ts +20 -0
- package/dist/lib/action/scan.d.cts +28 -0
- package/dist/lib/action/scan.d.ts +28 -0
- package/dist/lib/action/server.d.cts +30 -0
- package/dist/lib/action/server.d.ts +30 -0
- package/dist/lib/action-BB6N5yD-.js +111 -0
- package/dist/lib/action-BB6N5yD-.js.map +1 -0
- package/dist/lib/action-DZHihU3Z.cjs +2 -0
- package/dist/lib/action-DZHihU3Z.cjs.map +1 -0
- package/dist/lib/adapters/bun.cjs +30 -0
- package/dist/lib/adapters/bun.cjs.map +1 -0
- package/dist/lib/adapters/bun.d.cts +13 -0
- package/dist/lib/adapters/bun.d.ts +13 -0
- package/dist/lib/adapters/bun.js +65 -0
- package/dist/lib/adapters/bun.js.map +1 -0
- package/dist/lib/adapters/index.cjs +0 -0
- package/dist/lib/adapters/index.d.cts +30 -0
- package/dist/lib/adapters/index.d.ts +30 -0
- package/dist/lib/adapters/index.js +0 -0
- package/dist/lib/adapters/netlify.cjs +10 -0
- package/dist/lib/adapters/netlify.cjs.map +1 -0
- package/dist/lib/adapters/netlify.d.cts +13 -0
- package/dist/lib/adapters/netlify.d.ts +13 -0
- package/dist/lib/adapters/netlify.js +51 -0
- package/dist/lib/adapters/netlify.js.map +1 -0
- package/dist/lib/adapters/node.cjs +46 -0
- package/dist/lib/adapters/node.cjs.map +1 -0
- package/dist/lib/adapters/node.d.cts +13 -0
- package/dist/lib/adapters/node.d.ts +13 -0
- package/dist/lib/adapters/node.js +105 -0
- package/dist/lib/adapters/node.js.map +1 -0
- package/dist/lib/adapters/shared.d.cts +17 -0
- package/dist/lib/adapters/shared.d.ts +17 -0
- package/dist/lib/adapters/vercel.cjs +2 -0
- package/dist/lib/adapters/vercel.cjs.map +1 -0
- package/dist/lib/adapters/vercel.d.cts +9 -0
- package/dist/lib/adapters/vercel.d.ts +9 -0
- package/dist/lib/adapters/vercel.js +62 -0
- package/dist/lib/adapters/vercel.js.map +1 -0
- package/dist/lib/build/build.d.cts +83 -0
- package/dist/lib/build/build.d.ts +83 -0
- package/dist/lib/build/document-shell.d.cts +48 -0
- package/dist/lib/build/document-shell.d.ts +48 -0
- package/dist/lib/build/transform-source.d.cts +26 -0
- package/dist/lib/build/transform-source.d.ts +26 -0
- package/dist/lib/build/vite-build.d.cts +78 -0
- package/dist/lib/build/vite-build.d.ts +78 -0
- package/dist/lib/cache/policy.d.cts +25 -0
- package/dist/lib/cache/policy.d.ts +25 -0
- package/dist/lib/cache.d.cts +13 -0
- package/dist/lib/cache.d.ts +13 -0
- package/dist/lib/capabilities-C0TDQoMY.cjs +2 -0
- package/dist/lib/capabilities-C0TDQoMY.cjs.map +1 -0
- package/dist/lib/capabilities-C7txofmY.js +45 -0
- package/dist/lib/capabilities-C7txofmY.js.map +1 -0
- package/dist/lib/cli/commands.d.cts +15 -0
- package/dist/lib/cli/commands.d.ts +15 -0
- package/dist/lib/cli.cjs +5132 -0
- package/dist/lib/cli.cjs.map +1 -0
- package/dist/lib/cli.d.cts +30 -0
- package/dist/lib/cli.d.ts +30 -0
- package/dist/lib/cli.js +5131 -0
- package/dist/lib/cli.js.map +1 -0
- package/dist/lib/collections-Dbc8aRLf.js +233 -0
- package/dist/lib/collections-Dbc8aRLf.js.map +1 -0
- package/dist/lib/collections-VDy5g9p8.cjs +13 -0
- package/dist/lib/collections-VDy5g9p8.cjs.map +1 -0
- package/dist/lib/config/index.cjs +2 -0
- package/dist/lib/config/index.cjs.map +1 -0
- package/dist/lib/config/index.d.cts +100 -0
- package/dist/lib/config/index.d.ts +100 -0
- package/dist/lib/config/index.js +122 -0
- package/dist/lib/config/index.js.map +1 -0
- package/dist/lib/content/collections.d.cts +69 -0
- package/dist/lib/content/collections.d.ts +69 -0
- package/dist/lib/content/frontmatter.d.cts +20 -0
- package/dist/lib/content/frontmatter.d.ts +20 -0
- package/dist/lib/content/index.cjs +2 -0
- package/dist/lib/content/index.cjs.map +1 -0
- package/dist/lib/content/index.d.cts +5 -0
- package/dist/lib/content/index.d.ts +5 -0
- package/dist/lib/content/index.js +28 -0
- package/dist/lib/content/index.js.map +1 -0
- package/dist/lib/content/markdown.d.cts +6 -0
- package/dist/lib/content/markdown.d.ts +6 -0
- package/dist/lib/content/raw.d.cts +9 -0
- package/dist/lib/content/raw.d.ts +9 -0
- package/dist/lib/content/schema.d.cts +14 -0
- package/dist/lib/content/schema.d.ts +14 -0
- package/dist/lib/errors-0X7pCFNU.cjs +2 -0
- package/dist/lib/errors-0X7pCFNU.cjs.map +1 -0
- package/dist/lib/errors-ePYxDlhU.js +70 -0
- package/dist/lib/errors-ePYxDlhU.js.map +1 -0
- package/dist/lib/errors.d.cts +84 -0
- package/dist/lib/errors.d.ts +84 -0
- package/dist/lib/hydrate-8a3TbQbs.cjs +2 -0
- package/dist/lib/hydrate-8a3TbQbs.cjs.map +1 -0
- package/dist/lib/hydrate-CgZGrTxF.js +126 -0
- package/dist/lib/hydrate-CgZGrTxF.js.map +1 -0
- package/dist/lib/image/index.cjs +2 -0
- package/dist/lib/image/index.cjs.map +1 -0
- package/dist/lib/image/index.d.cts +37 -0
- package/dist/lib/image/index.d.ts +37 -0
- package/dist/lib/image/index.js +49 -0
- package/dist/lib/image/index.js.map +1 -0
- package/dist/lib/image/pipeline.d.cts +37 -0
- package/dist/lib/image/pipeline.d.ts +37 -0
- package/dist/lib/image/registry.cjs +2 -0
- package/dist/lib/image/registry.cjs.map +1 -0
- package/dist/lib/image/registry.d.cts +26 -0
- package/dist/lib/image/registry.d.ts +26 -0
- package/dist/lib/image/registry.js +23 -0
- package/dist/lib/image/registry.js.map +1 -0
- package/dist/lib/image/service.cjs +2 -0
- package/dist/lib/image/service.cjs.map +1 -0
- package/dist/lib/image/service.d.cts +164 -0
- package/dist/lib/image/service.d.ts +164 -0
- package/dist/lib/image/service.js +308 -0
- package/dist/lib/image/service.js.map +1 -0
- package/dist/lib/index.cjs +1 -0
- package/dist/lib/index.cjs.map +1 -0
- package/dist/lib/index.d.cts +38 -0
- package/dist/lib/index.d.ts +38 -0
- package/dist/lib/index.js +1 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/integrations/hooks.d.cts +58 -0
- package/dist/lib/integrations/hooks.d.ts +58 -0
- package/dist/lib/integrations/index.cjs +1 -0
- package/dist/lib/integrations/index.d.cts +18 -0
- package/dist/lib/integrations/index.d.ts +18 -0
- package/dist/lib/integrations/index.js +2 -0
- package/dist/lib/integrations-7dpN1RYB.js +35 -0
- package/dist/lib/integrations-7dpN1RYB.js.map +1 -0
- package/dist/lib/integrations-DDqfWjvH.cjs +2 -0
- package/dist/lib/integrations-DDqfWjvH.cjs.map +1 -0
- package/dist/lib/interpolation-plugin-Bt-KRKVY.js +365 -0
- package/dist/lib/interpolation-plugin-Bt-KRKVY.js.map +1 -0
- package/dist/lib/interpolation-plugin-CMPCDlVJ.cjs +31 -0
- package/dist/lib/interpolation-plugin-CMPCDlVJ.cjs.map +1 -0
- package/dist/lib/island/generate-entry.d.cts +27 -0
- package/dist/lib/island/generate-entry.d.ts +27 -0
- package/dist/lib/island/hydrate.d.cts +33 -0
- package/dist/lib/island/hydrate.d.ts +33 -0
- package/dist/lib/island/index.cjs +1 -0
- package/dist/lib/island/index.d.cts +2 -0
- package/dist/lib/island/index.d.ts +2 -0
- package/dist/lib/island/index.js +1 -0
- package/dist/lib/island/island.d.cts +32 -0
- package/dist/lib/island/island.d.ts +32 -0
- package/dist/lib/island/scan.d.cts +14 -0
- package/dist/lib/island/scan.d.ts +14 -0
- package/dist/lib/manifest/index.cjs +3 -0
- package/dist/lib/manifest/index.cjs.map +1 -0
- package/dist/lib/manifest/index.d.cts +18 -0
- package/dist/lib/manifest/index.d.ts +18 -0
- package/dist/lib/manifest/index.js +110 -0
- package/dist/lib/manifest/index.js.map +1 -0
- package/dist/lib/middleware/index.d.cts +56 -0
- package/dist/lib/middleware/index.d.ts +56 -0
- package/dist/lib/middleware/stream-boundary.d.cts +53 -0
- package/dist/lib/middleware/stream-boundary.d.ts +53 -0
- package/dist/lib/node-http-DRAUhO0c.js +617 -0
- package/dist/lib/node-http-DRAUhO0c.js.map +1 -0
- package/dist/lib/node-http-DhxguYyz.cjs +13 -0
- package/dist/lib/node-http-DhxguYyz.cjs.map +1 -0
- package/dist/lib/render/render-to-string.d.cts +12 -0
- package/dist/lib/render/render-to-string.d.ts +12 -0
- package/dist/lib/render/ssr-flag.d.cts +4 -0
- package/dist/lib/render/ssr-flag.d.ts +4 -0
- package/dist/lib/route-scanner-JY6YrNH5.cjs +2 -0
- package/dist/lib/route-scanner-JY6YrNH5.cjs.map +1 -0
- package/dist/lib/route-scanner-XcLId7lK.js +100 -0
- package/dist/lib/route-scanner-XcLId7lK.js.map +1 -0
- package/dist/lib/router/client.cjs +2 -0
- package/dist/lib/router/client.cjs.map +1 -0
- package/dist/lib/router/client.d.cts +47 -0
- package/dist/lib/router/client.d.ts +47 -0
- package/dist/lib/router/client.js +298 -0
- package/dist/lib/router/client.js.map +1 -0
- package/dist/lib/router/route-scanner.d.cts +50 -0
- package/dist/lib/router/route-scanner.d.ts +50 -0
- package/dist/lib/runtime/capabilities.d.cts +47 -0
- package/dist/lib/runtime/capabilities.d.ts +47 -0
- package/dist/lib/runtime/context.d.cts +140 -0
- package/dist/lib/runtime/context.d.ts +140 -0
- package/dist/lib/runtime/handler.d.cts +39 -0
- package/dist/lib/runtime/handler.d.ts +39 -0
- package/dist/lib/runtime/index.cjs +1 -0
- package/dist/lib/runtime/index.d.cts +6 -0
- package/dist/lib/runtime/index.d.ts +6 -0
- package/dist/lib/runtime/index.js +4 -0
- package/dist/lib/runtime/node-http.d.cts +2 -0
- package/dist/lib/runtime/node-http.d.ts +2 -0
- package/dist/lib/runtime/security-headers.d.cts +13 -0
- package/dist/lib/runtime/security-headers.d.ts +13 -0
- package/dist/lib/runtime/static.d.cts +1 -0
- package/dist/lib/runtime/static.d.ts +1 -0
- package/dist/lib/runtime-CrH5X-Es.cjs +2 -0
- package/dist/lib/runtime-CrH5X-Es.cjs.map +1 -0
- package/dist/lib/runtime-Ds2-wH6P.js +520 -0
- package/dist/lib/runtime-Ds2-wH6P.js.map +1 -0
- package/dist/lib/scan-CY2O9ty6.cjs +2 -0
- package/dist/lib/scan-CY2O9ty6.cjs.map +1 -0
- package/dist/lib/scan-CjMUgnsd.js +22 -0
- package/dist/lib/scan-CjMUgnsd.js.map +1 -0
- package/dist/lib/scan-DXzYtmRQ.cjs +2 -0
- package/dist/lib/scan-DXzYtmRQ.cjs.map +1 -0
- package/dist/lib/scan-Dn93ycXG.js +33 -0
- package/dist/lib/scan-Dn93ycXG.js.map +1 -0
- package/dist/lib/seo/index.cjs +10 -0
- package/dist/lib/seo/index.cjs.map +1 -0
- package/dist/lib/seo/index.d.cts +99 -0
- package/dist/lib/seo/index.d.ts +99 -0
- package/dist/lib/seo/index.js +41 -0
- package/dist/lib/seo/index.js.map +1 -0
- package/dist/lib/shared-CfqOLsKj.cjs +183 -0
- package/dist/lib/shared-CfqOLsKj.cjs.map +1 -0
- package/dist/lib/shared-DU3iQgr7.js +236 -0
- package/dist/lib/shared-DU3iQgr7.js.map +1 -0
- package/dist/lib/ssr/match.d.cts +25 -0
- package/dist/lib/ssr/match.d.ts +25 -0
- package/dist/lib/ssr/render.d.cts +62 -0
- package/dist/lib/ssr/render.d.ts +62 -0
- package/dist/lib/ssr/server.d.cts +41 -0
- package/dist/lib/ssr/server.d.ts +41 -0
- package/dist/lib/ssr/stream.d.cts +48 -0
- package/dist/lib/ssr/stream.d.ts +48 -0
- package/dist/lib/stream-CpOG052V.js +104 -0
- package/dist/lib/stream-CpOG052V.js.map +1 -0
- package/dist/lib/stream-DmZjYqHm.cjs +17 -0
- package/dist/lib/stream-DmZjYqHm.cjs.map +1 -0
- package/dist/lib/types.d.cts +97 -0
- package/dist/lib/types.d.ts +97 -0
- package/dist/lib/vite/index.cjs +2 -0
- package/dist/lib/vite/index.cjs.map +1 -0
- package/dist/lib/vite/index.d.cts +41 -0
- package/dist/lib/vite/index.d.ts +41 -0
- package/dist/lib/vite/index.js +229 -0
- package/dist/lib/vite/index.js.map +1 -0
- package/dist/lib/vite/interpolation-plugin.d.cts +64 -0
- package/dist/lib/vite/interpolation-plugin.d.ts +64 -0
- package/package.json +292 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { readFile as e, readdir as t, stat as n } from "node:fs/promises";
|
|
2
|
+
import { join as r, resolve as i } from "node:path";
|
|
3
|
+
import { AsyncLocalStorage as a } from "node:async_hooks";
|
|
4
|
+
//#region src/content/frontmatter.ts
|
|
5
|
+
function o(e) {
|
|
6
|
+
if (!e.startsWith("---")) return {
|
|
7
|
+
raw: "",
|
|
8
|
+
body: e
|
|
9
|
+
};
|
|
10
|
+
let t = e.slice(3), n = t.match(/^.*?\n---[ \t]*\r?\n?/s);
|
|
11
|
+
return n ? {
|
|
12
|
+
raw: t.slice(0, n.index + n[0].length - 4).trim(),
|
|
13
|
+
body: t.slice(n.index + n[0].length)
|
|
14
|
+
} : {
|
|
15
|
+
raw: "",
|
|
16
|
+
body: e
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function s(e) {
|
|
20
|
+
let t = {}, n = e.split(/\r?\n/), r = 0;
|
|
21
|
+
for (; r < n.length;) {
|
|
22
|
+
let e = n[r];
|
|
23
|
+
if (!e.trim() || e.trim().startsWith("#")) {
|
|
24
|
+
r++;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
let i = e.match(/^(\S[^:]*):\s*(.*)$/);
|
|
28
|
+
if (!i) {
|
|
29
|
+
r++;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
let a = i[1].trim(), o = i[2].trim();
|
|
33
|
+
if (o === "") {
|
|
34
|
+
let e = [], i = r + 1;
|
|
35
|
+
for (; i < n.length;) {
|
|
36
|
+
let t = n[i];
|
|
37
|
+
if (!t.trim()) {
|
|
38
|
+
i++;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
let r = t.match(/^\s+-\s+(.*)$/);
|
|
42
|
+
if (r) {
|
|
43
|
+
e.push(l(r[1].trim())), i++;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (/^\s+\S/.test(t) && !r) {
|
|
47
|
+
i++;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
e.length > 0 ? (t[a] = e, r = i) : (t[a] = null, r++);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
t[a] = c(o), r++;
|
|
56
|
+
}
|
|
57
|
+
return t;
|
|
58
|
+
}
|
|
59
|
+
function c(e) {
|
|
60
|
+
if (e.startsWith("[") && e.endsWith("]")) {
|
|
61
|
+
let t = e.slice(1, -1).trim();
|
|
62
|
+
return t ? t.split(",").map((e) => l(e.trim())) : [];
|
|
63
|
+
}
|
|
64
|
+
return l(e);
|
|
65
|
+
}
|
|
66
|
+
function l(e) {
|
|
67
|
+
if (!e) return null;
|
|
68
|
+
if (e.startsWith("\"") && e.endsWith("\"")) return u(e.slice(1, -1));
|
|
69
|
+
if (e.startsWith("'") && e.endsWith("'")) return e.slice(1, -1).replace(/''/g, "'");
|
|
70
|
+
let t = e.toLowerCase();
|
|
71
|
+
if (t === "true") return !0;
|
|
72
|
+
if (t === "false") return !1;
|
|
73
|
+
if (t === "null" || t === "~") return null;
|
|
74
|
+
if (/^-?\d+$/.test(e)) return parseInt(e, 10);
|
|
75
|
+
if (/^-?\d+\.\d+$/.test(e) || /^-?\d+(\.\d+)?[eE][-+]?\d+$/.test(e)) return parseFloat(e);
|
|
76
|
+
if (/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$/.test(e)) {
|
|
77
|
+
let t = new Date(e);
|
|
78
|
+
if (!isNaN(t.getTime())) return t;
|
|
79
|
+
}
|
|
80
|
+
return e;
|
|
81
|
+
}
|
|
82
|
+
function u(e) {
|
|
83
|
+
return e.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\"/g, "\"").replace(/\\\\/g, "\\");
|
|
84
|
+
}
|
|
85
|
+
function d(e) {
|
|
86
|
+
let { raw: t, body: n } = o(e);
|
|
87
|
+
return {
|
|
88
|
+
data: t ? s(t) : {},
|
|
89
|
+
body: n.trimStart()
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/content/markdown.ts
|
|
94
|
+
var f;
|
|
95
|
+
async function p() {
|
|
96
|
+
if (f === null) throw Error("[elur-kit] Markdown rendering requires the `marked` package. Install it with:\n npm install marked\n # or\n bun add marked");
|
|
97
|
+
if (f) return await f();
|
|
98
|
+
try {
|
|
99
|
+
let e = await import("marked"), t = { marked: typeof e.marked == "function" ? e.marked : e.default };
|
|
100
|
+
return f = async () => t, t;
|
|
101
|
+
} catch {
|
|
102
|
+
throw f = null, Error("[elur-kit] Markdown rendering requires the `marked` package. Install it with:\n npm install marked\n # or\n bun add marked");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function m(e) {
|
|
106
|
+
let { marked: t } = await p();
|
|
107
|
+
return t(e);
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/content/schema.ts
|
|
111
|
+
var h;
|
|
112
|
+
async function g() {
|
|
113
|
+
if (h === null) return null;
|
|
114
|
+
if (h) return h();
|
|
115
|
+
try {
|
|
116
|
+
let e = await import("zod");
|
|
117
|
+
return h = async () => e, e;
|
|
118
|
+
} catch {
|
|
119
|
+
return h = null, null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function _(e) {
|
|
123
|
+
if (e) {
|
|
124
|
+
if (e && typeof e == "object" && typeof e.parse == "function") return (t, n) => {
|
|
125
|
+
try {
|
|
126
|
+
return e.parse(t);
|
|
127
|
+
} catch (e) {
|
|
128
|
+
let t = e?.issues ?? e?.errors ?? [], r = Array.isArray(t) ? t.map((e) => ` - ${e.path?.join(".") ?? "(root)"}: ${e.message}`).join("\n") : String(e);
|
|
129
|
+
throw Error(`[elur-kit] Schema validation failed for "${n}":\n${r}`);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
if (typeof e == "function") return (t, n) => {
|
|
133
|
+
try {
|
|
134
|
+
return e(t);
|
|
135
|
+
} catch (e) {
|
|
136
|
+
throw Error(`[elur-kit] Schema validation failed for "${n}": ${e?.message ?? e}`);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function v() {
|
|
142
|
+
let e = await g();
|
|
143
|
+
if (!e) throw Error("[elur-kit] Schema validation requires the `zod` package. Install it with:\n npm install zod\n # or\n bun add zod");
|
|
144
|
+
return e;
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/content/collections.ts
|
|
148
|
+
function y(e) {
|
|
149
|
+
return e;
|
|
150
|
+
}
|
|
151
|
+
var b = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), S = 5e3, C = new a(), w = null;
|
|
152
|
+
function T(e) {
|
|
153
|
+
w = e, b.clear(), x.clear();
|
|
154
|
+
}
|
|
155
|
+
function E(e, t) {
|
|
156
|
+
return C.run(e, t);
|
|
157
|
+
}
|
|
158
|
+
function D() {
|
|
159
|
+
return C.getStore() || w || r(process.cwd(), "src", "content");
|
|
160
|
+
}
|
|
161
|
+
async function O(e) {
|
|
162
|
+
let t = e;
|
|
163
|
+
if (x.has(t)) return x.get(t) ?? null;
|
|
164
|
+
let i = r(e, "config.ts");
|
|
165
|
+
try {
|
|
166
|
+
await n(i);
|
|
167
|
+
} catch {
|
|
168
|
+
return x.set(t, null), null;
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
let e = await import(i), n = e.collections ?? e.default;
|
|
172
|
+
return x.set(t, n), n;
|
|
173
|
+
} catch (e) {
|
|
174
|
+
return console.warn("[elur-kit] Failed to load content config:", e), x.set(t, null), null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function k() {
|
|
178
|
+
b.clear(), x.clear();
|
|
179
|
+
}
|
|
180
|
+
async function A(n, i, a) {
|
|
181
|
+
let o;
|
|
182
|
+
try {
|
|
183
|
+
o = await t(i, { recursive: !0 });
|
|
184
|
+
} catch {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
let s = o.filter((e) => e.endsWith(".md")), c = [];
|
|
188
|
+
for (let t of s) {
|
|
189
|
+
let o = r(i, t), s = t.slice(0, -3).replace(/\\/g, "/"), { data: l, body: u } = d(await e(o, "utf8")), f = a ? a(l, o) : l;
|
|
190
|
+
c.push({
|
|
191
|
+
collection: n,
|
|
192
|
+
slug: s,
|
|
193
|
+
data: f,
|
|
194
|
+
body: u,
|
|
195
|
+
filePath: o
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return c.sort((e, t) => {
|
|
199
|
+
let n = e.data?.date, r = t.data?.date;
|
|
200
|
+
return n instanceof Date && r instanceof Date ? r.getTime() - n.getTime() : e.slug.localeCompare(t.slug);
|
|
201
|
+
}), c;
|
|
202
|
+
}
|
|
203
|
+
async function j(e) {
|
|
204
|
+
if (!M(e)) throw Error(`[elur-kit] Invalid collection name: "${e}". Collection names must be alphanumeric with hyphens/underscores only.`);
|
|
205
|
+
let t = D(), n = r(t, e), a = i(n), o = i(t);
|
|
206
|
+
if (!a.startsWith(o + "/") && a !== o) throw Error(`[elur-kit] Collection "${e}" escapes the content root.`);
|
|
207
|
+
let s = b.get(`${t}:${e}`);
|
|
208
|
+
if (s && Date.now() - s.loadedAt < S) return s.entries;
|
|
209
|
+
let c = (await O(t))?.[e], l = await A(e, n, c ? _(c.schema) : void 0);
|
|
210
|
+
return b.set(`${t}:${e}`, {
|
|
211
|
+
entries: l,
|
|
212
|
+
loadedAt: Date.now()
|
|
213
|
+
}), l;
|
|
214
|
+
}
|
|
215
|
+
function M(e) {
|
|
216
|
+
return !(!e || typeof e != "string" || !/^[a-zA-Z0-9_-]+$/.test(e) || e === "." || e === "..");
|
|
217
|
+
}
|
|
218
|
+
async function N(e, t) {
|
|
219
|
+
return (await j(e)).find((e) => e.slug === t);
|
|
220
|
+
}
|
|
221
|
+
async function P(e, t) {
|
|
222
|
+
let n = await j(e), r = new Set(t);
|
|
223
|
+
return n.filter((e) => r.has(e.slug));
|
|
224
|
+
}
|
|
225
|
+
async function F(e) {
|
|
226
|
+
if (e.html) return e.html;
|
|
227
|
+
let t = await m(e.body);
|
|
228
|
+
return e.html = t, t;
|
|
229
|
+
}
|
|
230
|
+
//#endregion
|
|
231
|
+
export { N as a, E as c, m as d, d as f, P as i, _ as l, o as m, y as n, F as o, s as p, j as r, T as s, k as t, v as u };
|
|
232
|
+
|
|
233
|
+
//# sourceMappingURL=collections-Dbc8aRLf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections-Dbc8aRLf.js","names":[],"sources":["../../src/content/frontmatter.ts","../../src/content/markdown.ts","../../src/content/schema.ts","../../src/content/collections.ts"],"sourcesContent":["// --- Frontmatter parser (YAML subset, zero dependencies) ---\n//\n// Parses the YAML subset that covers ~95% of real-world frontmatter:\n// - scalar key/value pairs (strings, numbers, booleans, null)\n// - dates (ISO 8601)\n// - inline arrays: [a, b, c]\n// - block arrays:\n// tags:\n// - foo\n// - bar\n// - quoted strings (single and double)\n//\n// This is NOT a full YAML parser. It deliberately rejects nested mappings and\n// complex types. If a project needs full YAML, it can install `yaml` as a peer\n// dependency and we can add a fallback later.\n\nexport interface ParsedFrontmatter {\n data: Record<string, unknown>;\n body: string;\n}\n\n/**\n * Splits a Markdown document into frontmatter and body. Returns the raw\n * frontmatter string (without the `---` fences) and the body.\n */\nexport function splitFrontmatter(source: string): { raw: string; body: string } {\n if (!source.startsWith(\"---\")) return { raw: \"\", body: source };\n\n // Find the closing `---` on its own line.\n const rest = source.slice(3);\n const closeMatch = rest.match(/^.*?\\n---[ \\t]*\\r?\\n?/s);\n if (!closeMatch) return { raw: \"\", body: source };\n\n const raw = rest.slice(0, closeMatch.index! + closeMatch[0].length - 4).trim();\n const body = rest.slice(closeMatch.index! + closeMatch[0].length);\n return { raw, body };\n}\n\n/**\n * Parses a YAML-subset frontmatter string into a JS object.\n */\nexport function parseFrontmatter(raw: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = raw.split(/\\r?\\n/);\n\n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n // Skip blank lines and comments.\n if (!line.trim() || line.trim().startsWith(\"#\")) {\n i++;\n continue;\n }\n\n const kvMatch = line.match(/^(\\S[^:]*):\\s*(.*)$/);\n if (!kvMatch) {\n i++;\n continue;\n }\n\n const key = kvMatch[1].trim();\n const value = kvMatch[2].trim();\n\n // Block array: value is empty, next lines are indented `- item`.\n if (value === \"\") {\n // Check if next lines are indented list items.\n const items: unknown[] = [];\n let j = i + 1;\n while (j < lines.length) {\n const nextLine = lines[j];\n if (!nextLine.trim()) {\n j++;\n continue;\n }\n const listItemMatch = nextLine.match(/^\\s+-\\s+(.*)$/);\n if (listItemMatch) {\n items.push(parseScalar(listItemMatch[1].trim()));\n j++;\n continue;\n }\n // Indented non-list content (nested mapping) — not supported.\n if (/^\\s+\\S/.test(nextLine) && !listItemMatch) {\n // Could be a nested map; we skip it gracefully.\n j++;\n continue;\n }\n break;\n }\n if (items.length > 0) {\n result[key] = items;\n i = j;\n } else {\n // Empty value (null).\n result[key] = null;\n i++;\n }\n continue;\n }\n\n result[key] = parseValue(value);\n i++;\n }\n\n return result;\n}\n\n/**\n * Parses a scalar value, handling inline arrays, quoted strings, numbers,\n * booleans, null and ISO dates.\n */\nfunction parseValue(value: string): unknown {\n // Inline array: [a, b, c]\n if (value.startsWith(\"[\") && value.endsWith(\"]\")) {\n const inner = value.slice(1, -1).trim();\n if (!inner) return [];\n return inner.split(\",\").map((item) => parseScalar(item.trim()));\n }\n return parseScalar(value);\n}\n\nfunction parseScalar(value: string): unknown {\n if (!value) return null;\n\n // Double-quoted string.\n if (value.startsWith('\"') && value.endsWith('\"')) {\n return unescapeQuoted(value.slice(1, -1));\n }\n // Single-quoted string.\n if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n return value.slice(1, -1).replace(/''/g, \"'\");\n }\n\n // Boolean.\n const lower = value.toLowerCase();\n if (lower === \"true\") return true;\n if (lower === \"false\") return false;\n if (lower === \"null\" || lower === \"~\") return null;\n\n // Number (int, float, negative, scientific).\n if (/^-?\\d+$/.test(value)) return parseInt(value, 10);\n if (/^-?\\d+\\.\\d+$/.test(value)) return parseFloat(value);\n if (/^-?\\d+(\\.\\d+)?[eE][-+]?\\d+$/.test(value)) return parseFloat(value);\n\n // ISO date: YYYY-MM-DD or full ISO 8601.\n if (/^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}(:\\d{2})?(\\.\\d+)?(Z|[+-]\\d{2}:?\\d{2})?)?$/.test(value)) {\n const date = new Date(value);\n if (!isNaN(date.getTime())) return date;\n }\n\n // Plain string.\n return value;\n}\n\nfunction unescapeQuoted(value: string): string {\n return value\n .replace(/\\\\n/g, \"\\n\")\n .replace(/\\\\t/g, \"\\t\")\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, \"\\\\\");\n}\n\n/**\n * Parses a full Markdown document (frontmatter + body) in one call.\n */\nexport function parseDocument(source: string): ParsedFrontmatter {\n const { raw, body } = splitFrontmatter(source);\n const data = raw ? parseFrontmatter(raw) : {};\n return { data, body: body.trimStart() };\n}\n","// --- Markdown → HTML renderer (optional `marked` peer dependency) ---\n//\n// Markdown rendering is delegated to `marked` when available. If `marked` is\n// not installed, a clear error is thrown with installation instructions.\n//\n// The resulting HTML is treated as trusted author content (same model as\n// Astro). If you render user-generated Markdown, sanitize it yourself before\n// passing it to the renderer.\n\ntype MarkedModule = { marked: (src: string) => string };\nlet markedLoader: (() => Promise<MarkedModule>) | null | undefined;\n\n/**\n * Lazily loads `marked` from the user's project. We use a dynamic import so\n * the kit itself has no hard dependency on `marked`.\n */\nasync function loadMarked(): Promise<MarkedModule> {\n if (markedLoader === null) {\n throw new Error(\n \"[elur-kit] Markdown rendering requires the `marked` package. Install it with:\\n\" +\n \" npm install marked\\n\" +\n \" # or\\n\" +\n \" bun add marked\",\n );\n }\n if (markedLoader) return await markedLoader();\n\n // Try to import `marked` from the user's project.\n try {\n // @ts-ignore — `marked` is an optional peer dependency.\n const mod = (await import(\"marked\")) as unknown as { marked?: (src: string) => string; default?: (src: string) => string };\n const fn = (typeof mod.marked === \"function\" ? mod.marked : mod.default) as (src: string) => string;\n const wrapped = { marked: fn };\n markedLoader = async () => wrapped;\n return wrapped;\n } catch {\n markedLoader = null;\n throw new Error(\n \"[elur-kit] Markdown rendering requires the `marked` package. Install it with:\\n\" +\n \" npm install marked\\n\" +\n \" # or\\n\" +\n \" bun add marked\",\n );\n }\n}\n\n/**\n * Renders a Markdown string to HTML using `marked`.\n *\n * @throws If `marked` is not installed.\n */\nexport async function renderMarkdown(source: string): Promise<string> {\n const { marked } = await loadMarked();\n return marked(source) as string;\n}\n","// --- Schema validation (optional `zod` peer dependency) ---\n//\n// Collections can define a schema for their frontmatter. When `zod` is\n// installed, schemas are validated at parse time and errors include the file\n// path and field. When `zod` is not installed, schemas are ignored (the data\n// is returned as-is) so the content layer still works without validation.\n\nexport interface SchemaValidator {\n (data: unknown, filePath: string): Record<string, unknown>;\n}\n\nlet zodLoader: (() => Promise<any>) | null | undefined;\n\nasync function loadZod(): Promise<any | null> {\n if (zodLoader === null) return null;\n if (zodLoader) return zodLoader();\n try {\n // @ts-ignore — `zod` is an optional peer dependency.\n const mod = await import(\"zod\");\n zodLoader = async () => mod;\n return mod;\n } catch {\n zodLoader = null;\n return null;\n }\n}\n\n/**\n * Creates a validator function from a schema object. If the schema is a zod\n * schema (has a `.parse` method), it is used directly. If `zod` is not\n * installed but a schema is provided, validation is skipped with a warning.\n */\nexport function createValidator(schema: unknown): SchemaValidator | undefined {\n if (!schema) return undefined;\n\n // Check if it's a zod schema (duck-typing).\n if (schema && typeof schema === \"object\" && typeof (schema as any).parse === \"function\") {\n return (data: unknown, filePath: string) => {\n try {\n return (schema as any).parse(data);\n } catch (err: any) {\n const issues = err?.issues ?? err?.errors ?? [];\n const details = Array.isArray(issues)\n ? issues.map((i: any) => ` - ${i.path?.join(\".\") ?? \"(root)\"}: ${i.message}`).join(\"\\n\")\n : String(err);\n throw new Error(\n `[elur-kit] Schema validation failed for \"${filePath}\":\\n${details}`,\n );\n }\n };\n }\n\n // Plain function validator.\n if (typeof schema === \"function\") {\n return (data: unknown, filePath: string) => {\n try {\n return (schema as Function)(data);\n } catch (err: any) {\n throw new Error(`[elur-kit] Schema validation failed for \"${filePath}\": ${err?.message ?? err}`);\n }\n };\n }\n\n return undefined;\n}\n\n/**\n * Ensures `zod` is available and re-exports it. Used by `defineCollection`\n * consumers who want to write `z.object(...)` schemas.\n */\nexport async function getZod(): Promise<any> {\n const zod = await loadZod();\n if (!zod) {\n throw new Error(\n \"[elur-kit] Schema validation requires the `zod` package. Install it with:\\n\" +\n \" npm install zod\\n\" +\n \" # or\\n\" +\n \" bun add zod\",\n );\n }\n return zod;\n}\n","// --- Content collections ---\n//\n// A collection is a directory under `src/content/<name>/` containing `.md`\n// files. Each file has YAML frontmatter (parsed by our own parser) and a\n// Markdown body (rendered via `marked` when requested).\n//\n// Collections are defined in `src/content/config.ts`:\n//\n// import { defineCollection } from \"@elurjs/kit/content\";\n// export const collections = {\n// blog: defineCollection({ schema: z.object({ title: z.string() }) }),\n// };\n//\n// At runtime, `getCollection(\"blog\")` scans the directory, parses frontmatter,\n// validates against the schema (if zod is installed), and returns typed\n// entries. `getEntry(\"blog\", \"hello\")` returns a single entry by slug.\n\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { parseDocument } from \"./frontmatter.js\";\nimport { renderMarkdown } from \"./markdown.js\";\nimport { createValidator, type SchemaValidator } from \"./schema.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nexport interface CollectionDefinition {\n /** Schema for frontmatter validation (zod schema or plain function). */\n schema?: unknown;\n}\n\nexport interface ContentEntry<TData = Record<string, unknown>> {\n /** Collection name, e.g. \"blog\". */\n collection: string;\n /** Entry slug (filename without `.md`), e.g. \"hello-world\". */\n slug: string;\n /** Parsed and validated frontmatter. */\n data: TData;\n /** Raw Markdown body (not yet rendered to HTML). */\n body: string;\n /** Rendered HTML body (lazily computed via `renderHTML()`). */\n html?: string;\n /** Absolute path to the source `.md` file. */\n filePath: string;\n}\n\n/**\n * Defines a collection with an optional schema. Used in `src/content/config.ts`.\n */\nexport function defineCollection(def: CollectionDefinition): CollectionDefinition {\n return def;\n}\n\n/** Type for the `collections` export from `src/content/config.ts`. */\nexport type CollectionsConfig = Record<string, CollectionDefinition>;\n\n// --- Internal cache ---\n\ninterface CachedCollection {\n entries: ContentEntry[];\n loadedAt: number;\n}\n\nconst collectionCache = new Map<string, CachedCollection>();\nconst configCache = new Map<string, CollectionsConfig | null>();\n\nconst CACHE_TTL_MS = 5000; // 5 seconds in dev; invalidated on HMR\n\n// Per-request content root via AsyncLocalStorage (plan §11.4).\n// Falls back to the global contentRoot set by setContentRoot().\nconst contentRootALS = new AsyncLocalStorage<string>();\n\n// Global fallback (set by CLI/Vite plugin on startup).\nlet globalContentRoot: string | null = null;\n\n/**\n * Sets the root directory for content. Called by the Vite plugin / CLI on\n * startup so `getCollection` knows where to find `src/content/`.\n */\nexport function setContentRoot(root: string): void {\n globalContentRoot = root;\n collectionCache.clear();\n configCache.clear();\n}\n\n/**\n * Runs a function with a per-request content root (plan §11.4).\n * This prevents global state leakage between concurrent requests.\n */\nexport function withContentRoot<T>(root: string, fn: () => T): T {\n return contentRootALS.run(root, fn);\n}\n\nfunction resolveContentRoot(): string {\n // Prefer per-request context.\n const alsRoot = contentRootALS.getStore();\n if (alsRoot) return alsRoot;\n // Fall back to global.\n if (globalContentRoot) return globalContentRoot;\n // Final fallback: assume CWD/src/content.\n return join(process.cwd(), \"src\", \"content\");\n}\n\n/**\n * Loads the user's `src/content/config.ts` (if it exists) and returns the\n * collections config.\n */\nasync function loadCollectionsConfig(root: string): Promise<CollectionsConfig | null> {\n const cacheKey = root;\n if (configCache.has(cacheKey)) return configCache.get(cacheKey) ?? null;\n\n const configPath = join(root, \"config.ts\");\n try {\n await stat(configPath);\n } catch {\n configCache.set(cacheKey, null);\n return null;\n }\n\n try {\n const mod = await import(configPath);\n const config = (mod.collections ?? mod.default) as CollectionsConfig;\n configCache.set(cacheKey, config);\n return config;\n } catch (err) {\n console.warn(\"[elur-kit] Failed to load content config:\", err);\n configCache.set(cacheKey, null);\n return null;\n }\n}\n\n/**\n * Clears the in-memory cache for all collections. Called by the HMR handler\n * when a `.md` file changes.\n */\nexport function clearContentCache(): void {\n collectionCache.clear();\n configCache.clear();\n}\n\n/**\n * Scans a collection directory and returns all entries. Nested directories\n * are scanned recursively; the slug of a nested file includes its relative\n * sub-path (e.g. `getting-started/intro` for `getting-started/intro.md`).\n */\nasync function scanCollection(\n name: string,\n collectionDir: string,\n validator: SchemaValidator | undefined,\n): Promise<ContentEntry[]> {\n let files: string[];\n try {\n files = await readdir(collectionDir, { recursive: true });\n } catch {\n return [];\n }\n\n const mdFiles = files.filter((f) => f.endsWith(\".md\"));\n const entries: ContentEntry[] = [];\n\n for (const file of mdFiles) {\n const filePath = join(collectionDir, file);\n const slug = file.slice(0, -3).replace(/\\\\/g, \"/\");\n const source = await readFile(filePath, \"utf8\");\n const { data: rawData, body } = parseDocument(source);\n\n const data = validator ? validator(rawData, filePath) : rawData;\n\n entries.push({\n collection: name,\n slug,\n data,\n body,\n filePath,\n });\n }\n\n // Sort by date descending if a `date` field exists, otherwise by slug.\n entries.sort((a, b) => {\n const dateA = (a.data as Record<string, unknown>)?.date;\n const dateB = (b.data as Record<string, unknown>)?.date;\n if (dateA instanceof Date && dateB instanceof Date) {\n return dateB.getTime() - dateA.getTime();\n }\n return a.slug.localeCompare(b.slug);\n });\n\n return entries;\n}\n\n/**\n * Returns all entries in a collection.\n *\n * @param name Collection name (directory under `src/content/`).\n *\n * Per plan §11.4: collection names are validated for containment — no\n * path traversal or escape from the content root is allowed.\n */\nexport async function getCollection<TData = Record<string, unknown>>(\n name: string,\n): Promise<ContentEntry<TData>[]> {\n // Containment check: reject names that could escape the content root.\n if (!isValidCollectionName(name)) {\n throw new Error(`[elur-kit] Invalid collection name: \"${name}\". Collection names must be alphanumeric with hyphens/underscores only.`);\n }\n\n const root = resolveContentRoot();\n const collectionDir = join(root, name);\n\n // Verify the resolved path is still inside the content root.\n const resolvedDir = resolve(collectionDir);\n const resolvedRoot = resolve(root);\n if (!resolvedDir.startsWith(resolvedRoot + \"/\") && resolvedDir !== resolvedRoot) {\n throw new Error(`[elur-kit] Collection \"${name}\" escapes the content root.`);\n }\n\n const cached = collectionCache.get(`${root}:${name}`);\n if (cached && Date.now() - cached.loadedAt < CACHE_TTL_MS) {\n return cached.entries as ContentEntry<TData>[];\n }\n\n const config = await loadCollectionsConfig(root);\n const def = config?.[name];\n const validator = def ? createValidator(def.schema) : undefined;\n\n const entries = await scanCollection(name, collectionDir, validator);\n collectionCache.set(`${root}:${name}`, { entries, loadedAt: Date.now() });\n return entries as ContentEntry<TData>[];\n}\n\n/**\n * Validates that a collection name is safe (no path traversal, no special chars).\n * Per plan §11.4: containment of collection names.\n */\nfunction isValidCollectionName(name: string): boolean {\n if (!name || typeof name !== \"string\") return false;\n // Only allow alphanumeric, hyphens, and underscores.\n if (!/^[a-zA-Z0-9_-]+$/.test(name)) return false;\n // Reject names that could be path segments (., .., etc).\n if (name === \".\" || name === \"..\") return false;\n return true;\n}\n\n/**\n * Returns a single entry by slug, or `undefined` if not found.\n *\n * @param collection Collection name.\n * @param slug Entry slug (filename without `.md`).\n */\nexport async function getEntry<TData = Record<string, unknown>>(\n collection: string,\n slug: string,\n): Promise<ContentEntry<TData> | undefined> {\n const entries = await getCollection<TData>(collection);\n return entries.find((e) => e.slug === slug);\n}\n\n/**\n * Returns multiple entries by slug.\n *\n * @param collection Collection name.\n * @param slugs Array of slugs.\n */\nexport async function getEntries<TData = Record<string, unknown>>(\n collection: string,\n slugs: string[],\n): Promise<ContentEntry<TData>[]> {\n const entries = await getCollection<TData>(collection);\n const slugSet = new Set(slugs);\n return entries.filter((e) => slugSet.has(e.slug));\n}\n\n/**\n * Renders the Markdown body of an entry to HTML. The result is cached on the\n * entry object so repeated calls don't re-render.\n *\n * @throws If `marked` is not installed.\n */\nexport async function renderEntryHTML(entry: ContentEntry): Promise<string> {\n if (entry.html) return entry.html;\n const html = await renderMarkdown(entry.body);\n entry.html = html;\n return html;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
let e=require("node:fs/promises"),t=require("node:path"),n=require("node:async_hooks");function r(e){if(!e.startsWith(`---`))return{raw:``,body:e};let t=e.slice(3),n=t.match(/^.*?\n---[ \t]*\r?\n?/s);return n?{raw:t.slice(0,n.index+n[0].length-4).trim(),body:t.slice(n.index+n[0].length)}:{raw:``,body:e}}function i(e){let t={},n=e.split(/\r?\n/),r=0;for(;r<n.length;){let e=n[r];if(!e.trim()||e.trim().startsWith(`#`)){r++;continue}let i=e.match(/^(\S[^:]*):\s*(.*)$/);if(!i){r++;continue}let s=i[1].trim(),c=i[2].trim();if(c===``){let e=[],i=r+1;for(;i<n.length;){let t=n[i];if(!t.trim()){i++;continue}let r=t.match(/^\s+-\s+(.*)$/);if(r){e.push(o(r[1].trim())),i++;continue}if(/^\s+\S/.test(t)&&!r){i++;continue}break}e.length>0?(t[s]=e,r=i):(t[s]=null,r++);continue}t[s]=a(c),r++}return t}function a(e){if(e.startsWith(`[`)&&e.endsWith(`]`)){let t=e.slice(1,-1).trim();return t?t.split(`,`).map(e=>o(e.trim())):[]}return o(e)}function o(e){if(!e)return null;if(e.startsWith(`"`)&&e.endsWith(`"`))return s(e.slice(1,-1));if(e.startsWith(`'`)&&e.endsWith(`'`))return e.slice(1,-1).replace(/''/g,`'`);let t=e.toLowerCase();if(t===`true`)return!0;if(t===`false`)return!1;if(t===`null`||t===`~`)return null;if(/^-?\d+$/.test(e))return parseInt(e,10);if(/^-?\d+\.\d+$/.test(e)||/^-?\d+(\.\d+)?[eE][-+]?\d+$/.test(e))return parseFloat(e);if(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$/.test(e)){let t=new Date(e);if(!isNaN(t.getTime()))return t}return e}function s(e){return e.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\t/g,` `).replace(/\\"/g,`"`).replace(/\\\\/g,`\\`)}function c(e){let{raw:t,body:n}=r(e);return{data:t?i(t):{},body:n.trimStart()}}var l;async function u(){if(l===null)throw Error(`[elur-kit] Markdown rendering requires the \`marked\` package. Install it with:
|
|
3
|
+
npm install marked
|
|
4
|
+
# or
|
|
5
|
+
bun add marked`);if(l)return await l();try{let e=await import(`marked`),t={marked:typeof e.marked==`function`?e.marked:e.default};return l=async()=>t,t}catch{throw l=null,Error(`[elur-kit] Markdown rendering requires the \`marked\` package. Install it with:
|
|
6
|
+
npm install marked
|
|
7
|
+
# or
|
|
8
|
+
bun add marked`)}}async function d(e){let{marked:t}=await u();return t(e)}var f;async function p(){if(f===null)return null;if(f)return f();try{let e=await import(`zod`);return f=async()=>e,e}catch{return f=null,null}}function m(e){if(e){if(e&&typeof e==`object`&&typeof e.parse==`function`)return(t,n)=>{try{return e.parse(t)}catch(e){let t=e?.issues??e?.errors??[],r=Array.isArray(t)?t.map(e=>` - ${e.path?.join(`.`)??`(root)`}: ${e.message}`).join(`
|
|
9
|
+
`):String(e);throw Error(`[elur-kit] Schema validation failed for "${n}":\n${r}`)}};if(typeof e==`function`)return(t,n)=>{try{return e(t)}catch(e){throw Error(`[elur-kit] Schema validation failed for "${n}": ${e?.message??e}`)}}}}async function h(){let e=await p();if(!e)throw Error(`[elur-kit] Schema validation requires the \`zod\` package. Install it with:
|
|
10
|
+
npm install zod
|
|
11
|
+
# or
|
|
12
|
+
bun add zod`);return e}function g(e){return e}var _=new Map,v=new Map,y=5e3,b=new n.AsyncLocalStorage,x=null;function S(e){x=e,_.clear(),v.clear()}function C(e,t){return b.run(e,t)}function w(){return b.getStore()||x||(0,t.join)(process.cwd(),`src`,`content`)}async function T(n){let r=n;if(v.has(r))return v.get(r)??null;let i=(0,t.join)(n,`config.ts`);try{await(0,e.stat)(i)}catch{return v.set(r,null),null}try{let e=await import(i),t=e.collections??e.default;return v.set(r,t),t}catch(e){return console.warn(`[elur-kit] Failed to load content config:`,e),v.set(r,null),null}}function E(){_.clear(),v.clear()}async function D(n,r,i){let a;try{a=await(0,e.readdir)(r,{recursive:!0})}catch{return[]}let o=a.filter(e=>e.endsWith(`.md`)),s=[];for(let a of o){let o=(0,t.join)(r,a),l=a.slice(0,-3).replace(/\\/g,`/`),{data:u,body:d}=c(await(0,e.readFile)(o,`utf8`)),f=i?i(u,o):u;s.push({collection:n,slug:l,data:f,body:d,filePath:o})}return s.sort((e,t)=>{let n=e.data?.date,r=t.data?.date;return n instanceof Date&&r instanceof Date?r.getTime()-n.getTime():e.slug.localeCompare(t.slug)}),s}async function O(e){if(!k(e))throw Error(`[elur-kit] Invalid collection name: "${e}". Collection names must be alphanumeric with hyphens/underscores only.`);let n=w(),r=(0,t.join)(n,e),i=(0,t.resolve)(r),a=(0,t.resolve)(n);if(!i.startsWith(a+`/`)&&i!==a)throw Error(`[elur-kit] Collection "${e}" escapes the content root.`);let o=_.get(`${n}:${e}`);if(o&&Date.now()-o.loadedAt<y)return o.entries;let s=(await T(n))?.[e],c=await D(e,r,s?m(s.schema):void 0);return _.set(`${n}:${e}`,{entries:c,loadedAt:Date.now()}),c}function k(e){return!(!e||typeof e!=`string`||!/^[a-zA-Z0-9_-]+$/.test(e)||e===`.`||e===`..`)}async function A(e,t){return(await O(e)).find(e=>e.slug===t)}async function j(e,t){let n=await O(e),r=new Set(t);return n.filter(e=>r.has(e.slug))}async function M(e){if(e.html)return e.html;let t=await d(e.body);return e.html=t,t}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return h}});
|
|
13
|
+
//# sourceMappingURL=collections-VDy5g9p8.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections-VDy5g9p8.cjs","names":[],"sources":["../../src/content/frontmatter.ts","../../src/content/markdown.ts","../../src/content/schema.ts","../../src/content/collections.ts"],"sourcesContent":["// --- Frontmatter parser (YAML subset, zero dependencies) ---\n//\n// Parses the YAML subset that covers ~95% of real-world frontmatter:\n// - scalar key/value pairs (strings, numbers, booleans, null)\n// - dates (ISO 8601)\n// - inline arrays: [a, b, c]\n// - block arrays:\n// tags:\n// - foo\n// - bar\n// - quoted strings (single and double)\n//\n// This is NOT a full YAML parser. It deliberately rejects nested mappings and\n// complex types. If a project needs full YAML, it can install `yaml` as a peer\n// dependency and we can add a fallback later.\n\nexport interface ParsedFrontmatter {\n data: Record<string, unknown>;\n body: string;\n}\n\n/**\n * Splits a Markdown document into frontmatter and body. Returns the raw\n * frontmatter string (without the `---` fences) and the body.\n */\nexport function splitFrontmatter(source: string): { raw: string; body: string } {\n if (!source.startsWith(\"---\")) return { raw: \"\", body: source };\n\n // Find the closing `---` on its own line.\n const rest = source.slice(3);\n const closeMatch = rest.match(/^.*?\\n---[ \\t]*\\r?\\n?/s);\n if (!closeMatch) return { raw: \"\", body: source };\n\n const raw = rest.slice(0, closeMatch.index! + closeMatch[0].length - 4).trim();\n const body = rest.slice(closeMatch.index! + closeMatch[0].length);\n return { raw, body };\n}\n\n/**\n * Parses a YAML-subset frontmatter string into a JS object.\n */\nexport function parseFrontmatter(raw: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = raw.split(/\\r?\\n/);\n\n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n // Skip blank lines and comments.\n if (!line.trim() || line.trim().startsWith(\"#\")) {\n i++;\n continue;\n }\n\n const kvMatch = line.match(/^(\\S[^:]*):\\s*(.*)$/);\n if (!kvMatch) {\n i++;\n continue;\n }\n\n const key = kvMatch[1].trim();\n const value = kvMatch[2].trim();\n\n // Block array: value is empty, next lines are indented `- item`.\n if (value === \"\") {\n // Check if next lines are indented list items.\n const items: unknown[] = [];\n let j = i + 1;\n while (j < lines.length) {\n const nextLine = lines[j];\n if (!nextLine.trim()) {\n j++;\n continue;\n }\n const listItemMatch = nextLine.match(/^\\s+-\\s+(.*)$/);\n if (listItemMatch) {\n items.push(parseScalar(listItemMatch[1].trim()));\n j++;\n continue;\n }\n // Indented non-list content (nested mapping) — not supported.\n if (/^\\s+\\S/.test(nextLine) && !listItemMatch) {\n // Could be a nested map; we skip it gracefully.\n j++;\n continue;\n }\n break;\n }\n if (items.length > 0) {\n result[key] = items;\n i = j;\n } else {\n // Empty value (null).\n result[key] = null;\n i++;\n }\n continue;\n }\n\n result[key] = parseValue(value);\n i++;\n }\n\n return result;\n}\n\n/**\n * Parses a scalar value, handling inline arrays, quoted strings, numbers,\n * booleans, null and ISO dates.\n */\nfunction parseValue(value: string): unknown {\n // Inline array: [a, b, c]\n if (value.startsWith(\"[\") && value.endsWith(\"]\")) {\n const inner = value.slice(1, -1).trim();\n if (!inner) return [];\n return inner.split(\",\").map((item) => parseScalar(item.trim()));\n }\n return parseScalar(value);\n}\n\nfunction parseScalar(value: string): unknown {\n if (!value) return null;\n\n // Double-quoted string.\n if (value.startsWith('\"') && value.endsWith('\"')) {\n return unescapeQuoted(value.slice(1, -1));\n }\n // Single-quoted string.\n if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n return value.slice(1, -1).replace(/''/g, \"'\");\n }\n\n // Boolean.\n const lower = value.toLowerCase();\n if (lower === \"true\") return true;\n if (lower === \"false\") return false;\n if (lower === \"null\" || lower === \"~\") return null;\n\n // Number (int, float, negative, scientific).\n if (/^-?\\d+$/.test(value)) return parseInt(value, 10);\n if (/^-?\\d+\\.\\d+$/.test(value)) return parseFloat(value);\n if (/^-?\\d+(\\.\\d+)?[eE][-+]?\\d+$/.test(value)) return parseFloat(value);\n\n // ISO date: YYYY-MM-DD or full ISO 8601.\n if (/^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}(:\\d{2})?(\\.\\d+)?(Z|[+-]\\d{2}:?\\d{2})?)?$/.test(value)) {\n const date = new Date(value);\n if (!isNaN(date.getTime())) return date;\n }\n\n // Plain string.\n return value;\n}\n\nfunction unescapeQuoted(value: string): string {\n return value\n .replace(/\\\\n/g, \"\\n\")\n .replace(/\\\\t/g, \"\\t\")\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, \"\\\\\");\n}\n\n/**\n * Parses a full Markdown document (frontmatter + body) in one call.\n */\nexport function parseDocument(source: string): ParsedFrontmatter {\n const { raw, body } = splitFrontmatter(source);\n const data = raw ? parseFrontmatter(raw) : {};\n return { data, body: body.trimStart() };\n}\n","// --- Markdown → HTML renderer (optional `marked` peer dependency) ---\n//\n// Markdown rendering is delegated to `marked` when available. If `marked` is\n// not installed, a clear error is thrown with installation instructions.\n//\n// The resulting HTML is treated as trusted author content (same model as\n// Astro). If you render user-generated Markdown, sanitize it yourself before\n// passing it to the renderer.\n\ntype MarkedModule = { marked: (src: string) => string };\nlet markedLoader: (() => Promise<MarkedModule>) | null | undefined;\n\n/**\n * Lazily loads `marked` from the user's project. We use a dynamic import so\n * the kit itself has no hard dependency on `marked`.\n */\nasync function loadMarked(): Promise<MarkedModule> {\n if (markedLoader === null) {\n throw new Error(\n \"[elur-kit] Markdown rendering requires the `marked` package. Install it with:\\n\" +\n \" npm install marked\\n\" +\n \" # or\\n\" +\n \" bun add marked\",\n );\n }\n if (markedLoader) return await markedLoader();\n\n // Try to import `marked` from the user's project.\n try {\n // @ts-ignore — `marked` is an optional peer dependency.\n const mod = (await import(\"marked\")) as unknown as { marked?: (src: string) => string; default?: (src: string) => string };\n const fn = (typeof mod.marked === \"function\" ? mod.marked : mod.default) as (src: string) => string;\n const wrapped = { marked: fn };\n markedLoader = async () => wrapped;\n return wrapped;\n } catch {\n markedLoader = null;\n throw new Error(\n \"[elur-kit] Markdown rendering requires the `marked` package. Install it with:\\n\" +\n \" npm install marked\\n\" +\n \" # or\\n\" +\n \" bun add marked\",\n );\n }\n}\n\n/**\n * Renders a Markdown string to HTML using `marked`.\n *\n * @throws If `marked` is not installed.\n */\nexport async function renderMarkdown(source: string): Promise<string> {\n const { marked } = await loadMarked();\n return marked(source) as string;\n}\n","// --- Schema validation (optional `zod` peer dependency) ---\n//\n// Collections can define a schema for their frontmatter. When `zod` is\n// installed, schemas are validated at parse time and errors include the file\n// path and field. When `zod` is not installed, schemas are ignored (the data\n// is returned as-is) so the content layer still works without validation.\n\nexport interface SchemaValidator {\n (data: unknown, filePath: string): Record<string, unknown>;\n}\n\nlet zodLoader: (() => Promise<any>) | null | undefined;\n\nasync function loadZod(): Promise<any | null> {\n if (zodLoader === null) return null;\n if (zodLoader) return zodLoader();\n try {\n // @ts-ignore — `zod` is an optional peer dependency.\n const mod = await import(\"zod\");\n zodLoader = async () => mod;\n return mod;\n } catch {\n zodLoader = null;\n return null;\n }\n}\n\n/**\n * Creates a validator function from a schema object. If the schema is a zod\n * schema (has a `.parse` method), it is used directly. If `zod` is not\n * installed but a schema is provided, validation is skipped with a warning.\n */\nexport function createValidator(schema: unknown): SchemaValidator | undefined {\n if (!schema) return undefined;\n\n // Check if it's a zod schema (duck-typing).\n if (schema && typeof schema === \"object\" && typeof (schema as any).parse === \"function\") {\n return (data: unknown, filePath: string) => {\n try {\n return (schema as any).parse(data);\n } catch (err: any) {\n const issues = err?.issues ?? err?.errors ?? [];\n const details = Array.isArray(issues)\n ? issues.map((i: any) => ` - ${i.path?.join(\".\") ?? \"(root)\"}: ${i.message}`).join(\"\\n\")\n : String(err);\n throw new Error(\n `[elur-kit] Schema validation failed for \"${filePath}\":\\n${details}`,\n );\n }\n };\n }\n\n // Plain function validator.\n if (typeof schema === \"function\") {\n return (data: unknown, filePath: string) => {\n try {\n return (schema as Function)(data);\n } catch (err: any) {\n throw new Error(`[elur-kit] Schema validation failed for \"${filePath}\": ${err?.message ?? err}`);\n }\n };\n }\n\n return undefined;\n}\n\n/**\n * Ensures `zod` is available and re-exports it. Used by `defineCollection`\n * consumers who want to write `z.object(...)` schemas.\n */\nexport async function getZod(): Promise<any> {\n const zod = await loadZod();\n if (!zod) {\n throw new Error(\n \"[elur-kit] Schema validation requires the `zod` package. Install it with:\\n\" +\n \" npm install zod\\n\" +\n \" # or\\n\" +\n \" bun add zod\",\n );\n }\n return zod;\n}\n","// --- Content collections ---\n//\n// A collection is a directory under `src/content/<name>/` containing `.md`\n// files. Each file has YAML frontmatter (parsed by our own parser) and a\n// Markdown body (rendered via `marked` when requested).\n//\n// Collections are defined in `src/content/config.ts`:\n//\n// import { defineCollection } from \"@elurjs/kit/content\";\n// export const collections = {\n// blog: defineCollection({ schema: z.object({ title: z.string() }) }),\n// };\n//\n// At runtime, `getCollection(\"blog\")` scans the directory, parses frontmatter,\n// validates against the schema (if zod is installed), and returns typed\n// entries. `getEntry(\"blog\", \"hello\")` returns a single entry by slug.\n\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { parseDocument } from \"./frontmatter.js\";\nimport { renderMarkdown } from \"./markdown.js\";\nimport { createValidator, type SchemaValidator } from \"./schema.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nexport interface CollectionDefinition {\n /** Schema for frontmatter validation (zod schema or plain function). */\n schema?: unknown;\n}\n\nexport interface ContentEntry<TData = Record<string, unknown>> {\n /** Collection name, e.g. \"blog\". */\n collection: string;\n /** Entry slug (filename without `.md`), e.g. \"hello-world\". */\n slug: string;\n /** Parsed and validated frontmatter. */\n data: TData;\n /** Raw Markdown body (not yet rendered to HTML). */\n body: string;\n /** Rendered HTML body (lazily computed via `renderHTML()`). */\n html?: string;\n /** Absolute path to the source `.md` file. */\n filePath: string;\n}\n\n/**\n * Defines a collection with an optional schema. Used in `src/content/config.ts`.\n */\nexport function defineCollection(def: CollectionDefinition): CollectionDefinition {\n return def;\n}\n\n/** Type for the `collections` export from `src/content/config.ts`. */\nexport type CollectionsConfig = Record<string, CollectionDefinition>;\n\n// --- Internal cache ---\n\ninterface CachedCollection {\n entries: ContentEntry[];\n loadedAt: number;\n}\n\nconst collectionCache = new Map<string, CachedCollection>();\nconst configCache = new Map<string, CollectionsConfig | null>();\n\nconst CACHE_TTL_MS = 5000; // 5 seconds in dev; invalidated on HMR\n\n// Per-request content root via AsyncLocalStorage (plan §11.4).\n// Falls back to the global contentRoot set by setContentRoot().\nconst contentRootALS = new AsyncLocalStorage<string>();\n\n// Global fallback (set by CLI/Vite plugin on startup).\nlet globalContentRoot: string | null = null;\n\n/**\n * Sets the root directory for content. Called by the Vite plugin / CLI on\n * startup so `getCollection` knows where to find `src/content/`.\n */\nexport function setContentRoot(root: string): void {\n globalContentRoot = root;\n collectionCache.clear();\n configCache.clear();\n}\n\n/**\n * Runs a function with a per-request content root (plan §11.4).\n * This prevents global state leakage between concurrent requests.\n */\nexport function withContentRoot<T>(root: string, fn: () => T): T {\n return contentRootALS.run(root, fn);\n}\n\nfunction resolveContentRoot(): string {\n // Prefer per-request context.\n const alsRoot = contentRootALS.getStore();\n if (alsRoot) return alsRoot;\n // Fall back to global.\n if (globalContentRoot) return globalContentRoot;\n // Final fallback: assume CWD/src/content.\n return join(process.cwd(), \"src\", \"content\");\n}\n\n/**\n * Loads the user's `src/content/config.ts` (if it exists) and returns the\n * collections config.\n */\nasync function loadCollectionsConfig(root: string): Promise<CollectionsConfig | null> {\n const cacheKey = root;\n if (configCache.has(cacheKey)) return configCache.get(cacheKey) ?? null;\n\n const configPath = join(root, \"config.ts\");\n try {\n await stat(configPath);\n } catch {\n configCache.set(cacheKey, null);\n return null;\n }\n\n try {\n const mod = await import(configPath);\n const config = (mod.collections ?? mod.default) as CollectionsConfig;\n configCache.set(cacheKey, config);\n return config;\n } catch (err) {\n console.warn(\"[elur-kit] Failed to load content config:\", err);\n configCache.set(cacheKey, null);\n return null;\n }\n}\n\n/**\n * Clears the in-memory cache for all collections. Called by the HMR handler\n * when a `.md` file changes.\n */\nexport function clearContentCache(): void {\n collectionCache.clear();\n configCache.clear();\n}\n\n/**\n * Scans a collection directory and returns all entries. Nested directories\n * are scanned recursively; the slug of a nested file includes its relative\n * sub-path (e.g. `getting-started/intro` for `getting-started/intro.md`).\n */\nasync function scanCollection(\n name: string,\n collectionDir: string,\n validator: SchemaValidator | undefined,\n): Promise<ContentEntry[]> {\n let files: string[];\n try {\n files = await readdir(collectionDir, { recursive: true });\n } catch {\n return [];\n }\n\n const mdFiles = files.filter((f) => f.endsWith(\".md\"));\n const entries: ContentEntry[] = [];\n\n for (const file of mdFiles) {\n const filePath = join(collectionDir, file);\n const slug = file.slice(0, -3).replace(/\\\\/g, \"/\");\n const source = await readFile(filePath, \"utf8\");\n const { data: rawData, body } = parseDocument(source);\n\n const data = validator ? validator(rawData, filePath) : rawData;\n\n entries.push({\n collection: name,\n slug,\n data,\n body,\n filePath,\n });\n }\n\n // Sort by date descending if a `date` field exists, otherwise by slug.\n entries.sort((a, b) => {\n const dateA = (a.data as Record<string, unknown>)?.date;\n const dateB = (b.data as Record<string, unknown>)?.date;\n if (dateA instanceof Date && dateB instanceof Date) {\n return dateB.getTime() - dateA.getTime();\n }\n return a.slug.localeCompare(b.slug);\n });\n\n return entries;\n}\n\n/**\n * Returns all entries in a collection.\n *\n * @param name Collection name (directory under `src/content/`).\n *\n * Per plan §11.4: collection names are validated for containment — no\n * path traversal or escape from the content root is allowed.\n */\nexport async function getCollection<TData = Record<string, unknown>>(\n name: string,\n): Promise<ContentEntry<TData>[]> {\n // Containment check: reject names that could escape the content root.\n if (!isValidCollectionName(name)) {\n throw new Error(`[elur-kit] Invalid collection name: \"${name}\". Collection names must be alphanumeric with hyphens/underscores only.`);\n }\n\n const root = resolveContentRoot();\n const collectionDir = join(root, name);\n\n // Verify the resolved path is still inside the content root.\n const resolvedDir = resolve(collectionDir);\n const resolvedRoot = resolve(root);\n if (!resolvedDir.startsWith(resolvedRoot + \"/\") && resolvedDir !== resolvedRoot) {\n throw new Error(`[elur-kit] Collection \"${name}\" escapes the content root.`);\n }\n\n const cached = collectionCache.get(`${root}:${name}`);\n if (cached && Date.now() - cached.loadedAt < CACHE_TTL_MS) {\n return cached.entries as ContentEntry<TData>[];\n }\n\n const config = await loadCollectionsConfig(root);\n const def = config?.[name];\n const validator = def ? createValidator(def.schema) : undefined;\n\n const entries = await scanCollection(name, collectionDir, validator);\n collectionCache.set(`${root}:${name}`, { entries, loadedAt: Date.now() });\n return entries as ContentEntry<TData>[];\n}\n\n/**\n * Validates that a collection name is safe (no path traversal, no special chars).\n * Per plan §11.4: containment of collection names.\n */\nfunction isValidCollectionName(name: string): boolean {\n if (!name || typeof name !== \"string\") return false;\n // Only allow alphanumeric, hyphens, and underscores.\n if (!/^[a-zA-Z0-9_-]+$/.test(name)) return false;\n // Reject names that could be path segments (., .., etc).\n if (name === \".\" || name === \"..\") return false;\n return true;\n}\n\n/**\n * Returns a single entry by slug, or `undefined` if not found.\n *\n * @param collection Collection name.\n * @param slug Entry slug (filename without `.md`).\n */\nexport async function getEntry<TData = Record<string, unknown>>(\n collection: string,\n slug: string,\n): Promise<ContentEntry<TData> | undefined> {\n const entries = await getCollection<TData>(collection);\n return entries.find((e) => e.slug === slug);\n}\n\n/**\n * Returns multiple entries by slug.\n *\n * @param collection Collection name.\n * @param slugs Array of slugs.\n */\nexport async function getEntries<TData = Record<string, unknown>>(\n collection: string,\n slugs: string[],\n): Promise<ContentEntry<TData>[]> {\n const entries = await getCollection<TData>(collection);\n const slugSet = new Set(slugs);\n return entries.filter((e) => slugSet.has(e.slug));\n}\n\n/**\n * Renders the Markdown body of an entry to HTML. The result is cached on the\n * entry object so repeated calls don't re-render.\n *\n * @throws If `marked` is not installed.\n */\nexport async function renderEntryHTML(entry: ContentEntry): Promise<string> {\n if (entry.html) return entry.html;\n const html = await renderMarkdown(entry.body);\n entry.html = html;\n return html;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../integrations-DDqfWjvH.cjs");let t=require("node:fs/promises"),n=require("node:path"),r=require("vite");function i(e){return e}async function a(t={}){let i=(0,n.resolve)(t.root??process.cwd()),a=t.configFile?(0,n.resolve)(i,t.configFile):await f(i),c={};if(a){let e=await(0,r.loadConfigFromFile)({command:t.command===`build`?`build`:`serve`,mode:t.mode??`development`},a,i);if(!e)throw Error(`[elur-kit] Could not load config: ${a}`);c=e.config}let l=s(c,t.overrides??{}),u=(0,n.resolve)(i,l.root??`.`),d=o(u,l,a);return await e.t(d.integrations,`config`,[d,{root:u,command:t.command??`dev`}]),d}function o(e,t,n){t.site&&new URL(t.site);let r=l(t.base??`/`),i=t.images?.quality??80;if(!Number.isFinite(i)||i<1||i>100)throw Error(`[elur-kit] images.quality must be between 1 and 100`);return{root:e,appDir:c(e,t.appDir??`src/app`,`appDir`),islandsDir:c(e,t.islandsDir??`src/islands`,`islandsDir`),contentDir:c(e,t.contentDir??`src/content`,`contentDir`),publicDir:c(e,t.publicDir??`public`,`publicDir`),outDir:c(e,t.outDir??`dist`,`outDir`),site:t.site,base:r,trailingSlash:t.trailingSlash??`ignore`,output:t.output??`static`,adapter:t.adapter,images:{formats:t.images?.formats??[`webp`,`avif`],quality:i,strict:t.images?.strict??!1},cache:{dir:c(e,t.cache?.dir??`.elur/cache`,`cache.dir`),defaultRevalidate:t.cache?.defaultRevalidate},security:{allowedOrigins:t.security?.allowedOrigins??[],strictOrigin:t.security?.strictOrigin??!1,bodyLimit:t.security?.bodyLimit??1048576,headers:t.security?.headers===!1?!1:t.security?.headers??{}},router:{enabled:t.router?.enabled??!0,prefetch:t.router?.prefetch??!0},integrations:t.integrations??[],configFile:n}}function s(e,t){return{...e,...t,images:{...e.images,...t.images},cache:{...e.cache,...t.cache},security:{...e.security,...t.security},router:{...e.router,...t.router},integrations:t.integrations??e.integrations}}function c(e,t,r){let i=(0,n.isAbsolute)(t)?(0,n.resolve)(t):(0,n.resolve)(e,t),a=(0,n.relative)(e,i);if(a===`..`||a.startsWith(`..${n.sep}`)||(0,n.isAbsolute)(a))throw Error(`[elur-kit] ${r} must stay inside root: ${i}`);return i}function l(e){if(!e.startsWith(`/`))throw Error(`[elur-kit] base must start with /`);return e===`/`?e:`${e.replace(/\/+$/,``)}/`}var u=[`elur.config.ts`,`elur.config.js`,`elur.config.mjs`],d=[`elur.config.ts`,`elur.config.js`,`elur.config.mjs`];async function f(e){for(let r of u){let i=(0,n.resolve)(e,r);try{return await(0,t.access)(i),i}catch{}}for(let r of d){let i=(0,n.resolve)(e,r);try{return await(0,t.access)(i),console.warn(`[elur-kit] "${r}" is deprecated and will be removed in a future release. Rename it to "elur.config.${r.split(`.`).slice(1).join(`.`)}" to keep your config working.`),i}catch{}}}exports.defineConfig=i,exports.loadElurConfig=a;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../../src/config/index.ts"],"sourcesContent":["import { access } from \"node:fs/promises\";\nimport { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { loadConfigFromFile } from \"vite\";\nimport type { Adapter } from \"../adapters/index.js\";\nimport type { ImageFormat } from \"../image/index.js\";\nimport type { ElurKitIntegration } from \"../integrations/index.js\";\nimport { runIntegrationHook } from \"../integrations/index.js\";\n\nexport type ElurOutputMode = \"static\" | \"server\" | \"hybrid\";\nexport type TrailingSlashMode = \"always\" | \"never\" | \"ignore\";\n\nexport interface ElurConfig {\n root?: string;\n appDir?: string;\n islandsDir?: string;\n contentDir?: string;\n publicDir?: string;\n outDir?: string;\n site?: string;\n base?: string;\n trailingSlash?: TrailingSlashMode;\n output?: ElurOutputMode;\n adapter?: Adapter;\n images?: {\n formats?: ImageFormat[];\n quality?: number;\n strict?: boolean;\n };\n cache?: {\n dir?: string;\n defaultRevalidate?: number;\n };\n security?: {\n allowedOrigins?: string[];\n strictOrigin?: boolean;\n bodyLimit?: number;\n /** Security response headers. Set to `false` to disable defaults. */\n headers?: SecurityHeadersConfig | false;\n };\n router?: {\n enabled?: boolean;\n prefetch?: boolean;\n };\n integrations?: ElurKitIntegration[];\n}\n\n/** Security headers configuration (runtime-security §14). */\nexport interface SecurityHeadersConfig {\n /** X-Content-Type-Options: nosniff. Default: true. */\n noSniff?: boolean;\n /** Referrer-Policy. Default: \"strict-origin-when-cross-origin\". */\n referrerPolicy?: string;\n /**\n * Content-Security-Policy. Set to a string to enable.\n * Use \"nonce\" placeholder to inject per-request nonces.\n */\n contentSecurityPolicy?: string;\n /** Strict-Transport-Security. Only applied under HTTPS. Default: unset. */\n hsts?: string | true;\n /** X-Frame-Options or CSP frame-ancestors. Default: \"SAMEORIGIN\". */\n frameAncestors?: string;\n /** Permissions-Policy. Default: unset. */\n permissionsPolicy?: string;\n}\n\nexport interface ResolvedElurConfig {\n root: string;\n appDir: string;\n islandsDir: string;\n contentDir: string;\n publicDir: string;\n outDir: string;\n site?: string;\n base: string;\n trailingSlash: TrailingSlashMode;\n output: ElurOutputMode;\n adapter?: Adapter;\n images: {\n formats: ImageFormat[];\n quality: number;\n strict: boolean;\n };\n cache: {\n dir: string;\n defaultRevalidate?: number;\n };\n security: {\n allowedOrigins: string[];\n strictOrigin: boolean;\n bodyLimit: number;\n headers: SecurityHeadersConfig | false;\n };\n router: {\n enabled: boolean;\n prefetch: boolean;\n };\n integrations: ElurKitIntegration[];\n configFile?: string;\n}\n\nexport interface LoadElurConfigOptions {\n root?: string;\n configFile?: string;\n command?: \"dev\" | \"build\" | \"preview\" | \"start\" | \"check\" | \"routes\" | \"doctor\";\n mode?: string;\n overrides?: ElurConfig;\n}\n\nexport function defineConfig(config: ElurConfig): ElurConfig {\n return config;\n}\n\nexport async function loadElurConfig(options: LoadElurConfigOptions = {}): Promise<ResolvedElurConfig> {\n const initialRoot = resolve(options.root ?? process.cwd());\n const configFile = options.configFile\n ? resolve(initialRoot, options.configFile)\n : await findConfigFile(initialRoot);\n let loaded: ElurConfig = {};\n\n if (configFile) {\n const result = await loadConfigFromFile(\n { command: options.command === \"build\" ? \"build\" : \"serve\", mode: options.mode ?? \"development\" },\n configFile,\n initialRoot,\n );\n if (!result) throw new Error(`[elur-kit] Could not load config: ${configFile}`);\n loaded = result.config as ElurConfig;\n }\n\n const merged = mergeConfig(loaded, options.overrides ?? {});\n const root = resolve(initialRoot, merged.root ?? \".\");\n const resolved = resolveConfig(root, merged, configFile);\n await runIntegrationHook(resolved.integrations, \"config\", [\n resolved as unknown as Record<string, unknown>,\n { root, command: options.command ?? \"dev\" },\n ]);\n return resolved;\n}\n\nfunction resolveConfig(root: string, config: ElurConfig, configFile?: string): ResolvedElurConfig {\n if (config.site) new URL(config.site);\n const base = normalizeBase(config.base ?? \"/\");\n const imageQuality = config.images?.quality ?? 80;\n if (!Number.isFinite(imageQuality) || imageQuality < 1 || imageQuality > 100) {\n throw new Error(\"[elur-kit] images.quality must be between 1 and 100\");\n }\n\n return {\n root,\n appDir: resolveInside(root, config.appDir ?? \"src/app\", \"appDir\"),\n islandsDir: resolveInside(root, config.islandsDir ?? \"src/islands\", \"islandsDir\"),\n contentDir: resolveInside(root, config.contentDir ?? \"src/content\", \"contentDir\"),\n publicDir: resolveInside(root, config.publicDir ?? \"public\", \"publicDir\"),\n outDir: resolveInside(root, config.outDir ?? \"dist\", \"outDir\"),\n site: config.site,\n base,\n trailingSlash: config.trailingSlash ?? \"ignore\",\n output: config.output ?? \"static\",\n adapter: config.adapter,\n images: {\n formats: config.images?.formats ?? [\"webp\", \"avif\"],\n quality: imageQuality,\n strict: config.images?.strict ?? false,\n },\n cache: {\n dir: resolveInside(root, config.cache?.dir ?? \".elur/cache\", \"cache.dir\"),\n defaultRevalidate: config.cache?.defaultRevalidate,\n },\n security: {\n allowedOrigins: config.security?.allowedOrigins ?? [],\n strictOrigin: config.security?.strictOrigin ?? false,\n bodyLimit: config.security?.bodyLimit ?? 1_048_576,\n headers: config.security?.headers === false\n ? false\n : config.security?.headers ?? {},\n },\n router: {\n enabled: config.router?.enabled ?? true,\n prefetch: config.router?.prefetch ?? true,\n },\n integrations: config.integrations ?? [],\n configFile,\n };\n}\n\nfunction mergeConfig(base: ElurConfig, override: ElurConfig): ElurConfig {\n return {\n ...base,\n ...override,\n images: { ...base.images, ...override.images },\n cache: { ...base.cache, ...override.cache },\n security: { ...base.security, ...override.security },\n router: { ...base.router, ...override.router },\n integrations: override.integrations ?? base.integrations,\n };\n}\n\nfunction resolveInside(root: string, path: string, name: string): string {\n const resolved = isAbsolute(path) ? resolve(path) : resolve(root, path);\n const rel = relative(root, resolved);\n if (rel === \"..\" || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {\n throw new Error(`[elur-kit] ${name} must stay inside root: ${resolved}`);\n }\n return resolved;\n}\n\nfunction normalizeBase(base: string): string {\n if (!base.startsWith(\"/\")) throw new Error(\"[elur-kit] base must start with /\");\n return base === \"/\" ? base : `${base.replace(/\\/+$/, \"\")}/`;\n}\n\nconst PREFERRED_CONFIG_FILES = [\"elur.config.ts\", \"elur.config.js\", \"elur.config.mjs\"];\n// Legacy names kept for backward compatibility. Emit a deprecation warning\n// when a project still uses them so authors migrate to `elur.config.*`.\nconst LEGACY_CONFIG_FILES = [\"elur.config.ts\", \"elur.config.js\", \"elur.config.mjs\"];\n\nasync function findConfigFile(root: string): Promise<string | undefined> {\n for (const name of PREFERRED_CONFIG_FILES) {\n const path = resolve(root, name);\n try {\n await access(path);\n return path;\n } catch {\n }\n }\n for (const name of LEGACY_CONFIG_FILES) {\n const path = resolve(root, name);\n try {\n await access(path);\n console.warn(\n `[elur-kit] \"${name}\" is deprecated and will be removed in a future release. ` +\n `Rename it to \"elur.config.${name.split(\".\").slice(1).join(\".\")}\" to keep your config working.`,\n );\n return path;\n } catch {\n }\n }\n return undefined;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Adapter } from "../adapters/index.js";
|
|
2
|
+
import type { ImageFormat } from "../image/index.js";
|
|
3
|
+
import type { ElurKitIntegration } from "../integrations/index.js";
|
|
4
|
+
export type ElurOutputMode = "static" | "server" | "hybrid";
|
|
5
|
+
export type TrailingSlashMode = "always" | "never" | "ignore";
|
|
6
|
+
export interface ElurConfig {
|
|
7
|
+
root?: string;
|
|
8
|
+
appDir?: string;
|
|
9
|
+
islandsDir?: string;
|
|
10
|
+
contentDir?: string;
|
|
11
|
+
publicDir?: string;
|
|
12
|
+
outDir?: string;
|
|
13
|
+
site?: string;
|
|
14
|
+
base?: string;
|
|
15
|
+
trailingSlash?: TrailingSlashMode;
|
|
16
|
+
output?: ElurOutputMode;
|
|
17
|
+
adapter?: Adapter;
|
|
18
|
+
images?: {
|
|
19
|
+
formats?: ImageFormat[];
|
|
20
|
+
quality?: number;
|
|
21
|
+
strict?: boolean;
|
|
22
|
+
};
|
|
23
|
+
cache?: {
|
|
24
|
+
dir?: string;
|
|
25
|
+
defaultRevalidate?: number;
|
|
26
|
+
};
|
|
27
|
+
security?: {
|
|
28
|
+
allowedOrigins?: string[];
|
|
29
|
+
strictOrigin?: boolean;
|
|
30
|
+
bodyLimit?: number;
|
|
31
|
+
/** Security response headers. Set to `false` to disable defaults. */
|
|
32
|
+
headers?: SecurityHeadersConfig | false;
|
|
33
|
+
};
|
|
34
|
+
router?: {
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
prefetch?: boolean;
|
|
37
|
+
};
|
|
38
|
+
integrations?: ElurKitIntegration[];
|
|
39
|
+
}
|
|
40
|
+
/** Security headers configuration (runtime-security §14). */
|
|
41
|
+
export interface SecurityHeadersConfig {
|
|
42
|
+
/** X-Content-Type-Options: nosniff. Default: true. */
|
|
43
|
+
noSniff?: boolean;
|
|
44
|
+
/** Referrer-Policy. Default: "strict-origin-when-cross-origin". */
|
|
45
|
+
referrerPolicy?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Content-Security-Policy. Set to a string to enable.
|
|
48
|
+
* Use "nonce" placeholder to inject per-request nonces.
|
|
49
|
+
*/
|
|
50
|
+
contentSecurityPolicy?: string;
|
|
51
|
+
/** Strict-Transport-Security. Only applied under HTTPS. Default: unset. */
|
|
52
|
+
hsts?: string | true;
|
|
53
|
+
/** X-Frame-Options or CSP frame-ancestors. Default: "SAMEORIGIN". */
|
|
54
|
+
frameAncestors?: string;
|
|
55
|
+
/** Permissions-Policy. Default: unset. */
|
|
56
|
+
permissionsPolicy?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ResolvedElurConfig {
|
|
59
|
+
root: string;
|
|
60
|
+
appDir: string;
|
|
61
|
+
islandsDir: string;
|
|
62
|
+
contentDir: string;
|
|
63
|
+
publicDir: string;
|
|
64
|
+
outDir: string;
|
|
65
|
+
site?: string;
|
|
66
|
+
base: string;
|
|
67
|
+
trailingSlash: TrailingSlashMode;
|
|
68
|
+
output: ElurOutputMode;
|
|
69
|
+
adapter?: Adapter;
|
|
70
|
+
images: {
|
|
71
|
+
formats: ImageFormat[];
|
|
72
|
+
quality: number;
|
|
73
|
+
strict: boolean;
|
|
74
|
+
};
|
|
75
|
+
cache: {
|
|
76
|
+
dir: string;
|
|
77
|
+
defaultRevalidate?: number;
|
|
78
|
+
};
|
|
79
|
+
security: {
|
|
80
|
+
allowedOrigins: string[];
|
|
81
|
+
strictOrigin: boolean;
|
|
82
|
+
bodyLimit: number;
|
|
83
|
+
headers: SecurityHeadersConfig | false;
|
|
84
|
+
};
|
|
85
|
+
router: {
|
|
86
|
+
enabled: boolean;
|
|
87
|
+
prefetch: boolean;
|
|
88
|
+
};
|
|
89
|
+
integrations: ElurKitIntegration[];
|
|
90
|
+
configFile?: string;
|
|
91
|
+
}
|
|
92
|
+
export interface LoadElurConfigOptions {
|
|
93
|
+
root?: string;
|
|
94
|
+
configFile?: string;
|
|
95
|
+
command?: "dev" | "build" | "preview" | "start" | "check" | "routes" | "doctor";
|
|
96
|
+
mode?: string;
|
|
97
|
+
overrides?: ElurConfig;
|
|
98
|
+
}
|
|
99
|
+
export declare function defineConfig(config: ElurConfig): ElurConfig;
|
|
100
|
+
export declare function loadElurConfig(options?: LoadElurConfigOptions): Promise<ResolvedElurConfig>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Adapter } from "../adapters/index.js";
|
|
2
|
+
import type { ImageFormat } from "../image/index.js";
|
|
3
|
+
import type { ElurKitIntegration } from "../integrations/index.js";
|
|
4
|
+
export type ElurOutputMode = "static" | "server" | "hybrid";
|
|
5
|
+
export type TrailingSlashMode = "always" | "never" | "ignore";
|
|
6
|
+
export interface ElurConfig {
|
|
7
|
+
root?: string;
|
|
8
|
+
appDir?: string;
|
|
9
|
+
islandsDir?: string;
|
|
10
|
+
contentDir?: string;
|
|
11
|
+
publicDir?: string;
|
|
12
|
+
outDir?: string;
|
|
13
|
+
site?: string;
|
|
14
|
+
base?: string;
|
|
15
|
+
trailingSlash?: TrailingSlashMode;
|
|
16
|
+
output?: ElurOutputMode;
|
|
17
|
+
adapter?: Adapter;
|
|
18
|
+
images?: {
|
|
19
|
+
formats?: ImageFormat[];
|
|
20
|
+
quality?: number;
|
|
21
|
+
strict?: boolean;
|
|
22
|
+
};
|
|
23
|
+
cache?: {
|
|
24
|
+
dir?: string;
|
|
25
|
+
defaultRevalidate?: number;
|
|
26
|
+
};
|
|
27
|
+
security?: {
|
|
28
|
+
allowedOrigins?: string[];
|
|
29
|
+
strictOrigin?: boolean;
|
|
30
|
+
bodyLimit?: number;
|
|
31
|
+
/** Security response headers. Set to `false` to disable defaults. */
|
|
32
|
+
headers?: SecurityHeadersConfig | false;
|
|
33
|
+
};
|
|
34
|
+
router?: {
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
prefetch?: boolean;
|
|
37
|
+
};
|
|
38
|
+
integrations?: ElurKitIntegration[];
|
|
39
|
+
}
|
|
40
|
+
/** Security headers configuration (runtime-security §14). */
|
|
41
|
+
export interface SecurityHeadersConfig {
|
|
42
|
+
/** X-Content-Type-Options: nosniff. Default: true. */
|
|
43
|
+
noSniff?: boolean;
|
|
44
|
+
/** Referrer-Policy. Default: "strict-origin-when-cross-origin". */
|
|
45
|
+
referrerPolicy?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Content-Security-Policy. Set to a string to enable.
|
|
48
|
+
* Use "nonce" placeholder to inject per-request nonces.
|
|
49
|
+
*/
|
|
50
|
+
contentSecurityPolicy?: string;
|
|
51
|
+
/** Strict-Transport-Security. Only applied under HTTPS. Default: unset. */
|
|
52
|
+
hsts?: string | true;
|
|
53
|
+
/** X-Frame-Options or CSP frame-ancestors. Default: "SAMEORIGIN". */
|
|
54
|
+
frameAncestors?: string;
|
|
55
|
+
/** Permissions-Policy. Default: unset. */
|
|
56
|
+
permissionsPolicy?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ResolvedElurConfig {
|
|
59
|
+
root: string;
|
|
60
|
+
appDir: string;
|
|
61
|
+
islandsDir: string;
|
|
62
|
+
contentDir: string;
|
|
63
|
+
publicDir: string;
|
|
64
|
+
outDir: string;
|
|
65
|
+
site?: string;
|
|
66
|
+
base: string;
|
|
67
|
+
trailingSlash: TrailingSlashMode;
|
|
68
|
+
output: ElurOutputMode;
|
|
69
|
+
adapter?: Adapter;
|
|
70
|
+
images: {
|
|
71
|
+
formats: ImageFormat[];
|
|
72
|
+
quality: number;
|
|
73
|
+
strict: boolean;
|
|
74
|
+
};
|
|
75
|
+
cache: {
|
|
76
|
+
dir: string;
|
|
77
|
+
defaultRevalidate?: number;
|
|
78
|
+
};
|
|
79
|
+
security: {
|
|
80
|
+
allowedOrigins: string[];
|
|
81
|
+
strictOrigin: boolean;
|
|
82
|
+
bodyLimit: number;
|
|
83
|
+
headers: SecurityHeadersConfig | false;
|
|
84
|
+
};
|
|
85
|
+
router: {
|
|
86
|
+
enabled: boolean;
|
|
87
|
+
prefetch: boolean;
|
|
88
|
+
};
|
|
89
|
+
integrations: ElurKitIntegration[];
|
|
90
|
+
configFile?: string;
|
|
91
|
+
}
|
|
92
|
+
export interface LoadElurConfigOptions {
|
|
93
|
+
root?: string;
|
|
94
|
+
configFile?: string;
|
|
95
|
+
command?: "dev" | "build" | "preview" | "start" | "check" | "routes" | "doctor";
|
|
96
|
+
mode?: string;
|
|
97
|
+
overrides?: ElurConfig;
|
|
98
|
+
}
|
|
99
|
+
export declare function defineConfig(config: ElurConfig): ElurConfig;
|
|
100
|
+
export declare function loadElurConfig(options?: LoadElurConfigOptions): Promise<ResolvedElurConfig>;
|