@junejs/server 0.1.0-dev.4 → 0.1.0-dev.7

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.
Files changed (105) hide show
  1. package/dist/adapter.d.ts +56 -0
  2. package/dist/adapter.js +211 -0
  3. package/dist/agent-discover.d.ts +5 -0
  4. package/dist/agent-discover.js +75 -0
  5. package/dist/agent-durable.d.ts +72 -0
  6. package/dist/agent-durable.js +141 -0
  7. package/dist/agent-native.d.ts +40 -0
  8. package/dist/agent-native.js +179 -0
  9. package/dist/app.d.ts +15 -0
  10. package/dist/app.js +252 -0
  11. package/dist/blob.d.ts +23 -0
  12. package/dist/blob.js +78 -0
  13. package/dist/build.d.ts +40 -0
  14. package/dist/build.js +582 -0
  15. package/dist/client-bundle.d.ts +15 -0
  16. package/dist/client-bundle.js +91 -0
  17. package/dist/config-loader.d.ts +9 -0
  18. package/dist/config-loader.js +25 -0
  19. package/dist/content.d.ts +39 -0
  20. package/dist/content.js +201 -0
  21. package/dist/css-modules-ambient.d.ts +10 -0
  22. package/dist/css-modules.d.ts +24 -0
  23. package/dist/css-modules.js +127 -0
  24. package/dist/css.d.ts +14 -0
  25. package/dist/css.js +114 -0
  26. package/dist/d1-BkdUg9kg.d.ts +24 -0
  27. package/dist/d1-migrate.d.ts +31 -0
  28. package/dist/d1-migrate.js +156 -0
  29. package/dist/d1.d.ts +2 -0
  30. package/dist/d1.js +32 -0
  31. package/dist/db.d.ts +11 -0
  32. package/dist/db.js +20 -0
  33. package/dist/deploy.d.ts +25 -0
  34. package/dist/deploy.js +158 -0
  35. package/dist/dev-reload.d.ts +5 -0
  36. package/dist/dev-reload.js +123 -0
  37. package/dist/dev.d.ts +13 -0
  38. package/dist/dev.js +55 -0
  39. package/dist/host.d.ts +25 -0
  40. package/dist/host.js +107 -0
  41. package/dist/index.d.ts +26 -0
  42. package/dist/index.js +26 -0
  43. package/dist/instrumentation.d.ts +4 -0
  44. package/dist/instrumentation.js +15 -0
  45. package/dist/island-registry.d.ts +8 -0
  46. package/dist/island-registry.js +117 -0
  47. package/dist/kv.d.ts +8 -0
  48. package/dist/kv.js +35 -0
  49. package/dist/migrate-BbWt-PuB.d.ts +32 -0
  50. package/dist/migrate.d.ts +2 -0
  51. package/dist/migrate.js +115 -0
  52. package/dist/mysql-driver-BsrWVqbp.d.ts +12 -0
  53. package/dist/mysql-driver.d.ts +2 -0
  54. package/dist/mysql-driver.js +52 -0
  55. package/dist/negotiate.d.ts +11 -0
  56. package/dist/negotiate.js +39 -0
  57. package/dist/pipeline-B2V6tKfO.d.ts +49 -0
  58. package/dist/pipeline.d.ts +2 -0
  59. package/dist/pipeline.js +235 -0
  60. package/dist/postgres-driver-DkkBFikA.d.ts +15 -0
  61. package/dist/postgres-driver.d.ts +2 -0
  62. package/dist/postgres-driver.js +50 -0
  63. package/dist/resources.d.ts +15 -0
  64. package/dist/resources.js +31 -0
  65. package/dist/router.d.ts +32 -0
  66. package/dist/router.js +183 -0
  67. package/dist/rsc-build.d.ts +17 -0
  68. package/dist/rsc-build.js +68 -0
  69. package/dist/rsc-bundle.d.ts +8 -0
  70. package/dist/rsc-bundle.js +39 -0
  71. package/dist/rsc-manifest.d.ts +8 -0
  72. package/dist/rsc-manifest.js +67 -0
  73. package/dist/rsc-runtime/flight-render-routes.d.ts +5 -0
  74. package/dist/rsc-runtime/flight-render-routes.js +26 -0
  75. package/dist/rsc-runtime/flight-render.d.ts +4 -0
  76. package/dist/rsc-runtime/flight-render.js +21 -0
  77. package/dist/rsc-runtime/flight-to-html.d.ts +4 -0
  78. package/dist/rsc-runtime/flight-to-html.js +32 -0
  79. package/dist/rsc-runtime/rsc-worker.d.ts +6 -0
  80. package/dist/rsc-runtime/rsc-worker.js +46 -0
  81. package/dist/rsc-runtime/rsdw-shims.d.ts +42 -0
  82. package/dist/segment.d.ts +14 -0
  83. package/dist/segment.js +33 -0
  84. package/dist/sqlite-driver.d.ts +25 -0
  85. package/dist/sqlite-driver.js +102 -0
  86. package/dist/static-files.d.ts +6 -0
  87. package/dist/static-files.js +56 -0
  88. package/dist/tsconfig-jsx.d.ts +15 -0
  89. package/dist/tsconfig-jsx.js +35 -0
  90. package/dist/turso-driver-C1wEigMZ.d.ts +22 -0
  91. package/dist/turso-driver.d.ts +2 -0
  92. package/dist/turso-driver.js +68 -0
  93. package/dist/worker.d.ts +55 -0
  94. package/dist/worker.js +211 -0
  95. package/package.json +115 -23
  96. package/src/adapter.ts +20 -7
  97. package/src/agent-discover.ts +5 -2
  98. package/src/agent-durable.ts +108 -4
  99. package/src/app.ts +74 -2
  100. package/src/build.ts +52 -3
  101. package/src/client-bundle.ts +3 -1
  102. package/src/index.ts +4 -0
  103. package/src/rsc-bundle.ts +3 -2
  104. package/src/static-files.ts +84 -0
  105. package/src/worker.ts +46 -29
@@ -0,0 +1,9 @@
1
+ import { JuneConfig } from "@junejs/core/config";
2
+ //#region src/config-loader.d.ts
3
+ /** The config file loadJuneConfig would import, or null. Exported so callers that need a FRESH
4
+ * load (a subprocess probe — see generateContent's bootstrap retry) target the same file the
5
+ * in-process loader would. */
6
+ declare function findJuneConfigPath(appDir: string): string | null;
7
+ declare function loadJuneConfig(appDir: string): Promise<JuneConfig>;
8
+ //#endregion
9
+ export { findJuneConfigPath, loadJuneConfig };
@@ -0,0 +1,25 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ //#region src/config-loader.ts
5
+ /** The config file loadJuneConfig would import, or null. Exported so callers that need a FRESH
6
+ * load (a subprocess probe — see generateContent's bootstrap retry) target the same file the
7
+ * in-process loader would. */
8
+ function findJuneConfigPath(appDir) {
9
+ for (const dir of [appDir, join(appDir, "..")]) for (const name of [
10
+ "june.config.ts",
11
+ "june.config.js",
12
+ ".june/config.ts"
13
+ ]) {
14
+ const path = join(dir, name);
15
+ if (existsSync(path)) return path;
16
+ }
17
+ return null;
18
+ }
19
+ async function loadJuneConfig(appDir) {
20
+ const path = findJuneConfigPath(appDir);
21
+ if (!path) return {};
22
+ return (await import(pathToFileURL(path).href)).default ?? {};
23
+ }
24
+ //#endregion
25
+ export { findJuneConfigPath, loadJuneConfig };
@@ -0,0 +1,39 @@
1
+ import { ContentSource } from "@junejs/core/config";
2
+ //#region src/content.d.ts
3
+ type ContentEntry = {
4
+ slug: string;
5
+ file: string;
6
+ /** Parsed frontmatter (string values; `tags`-style lists become string[]). */
7
+ data: Record<string, string | string[]>;
8
+ /** The markdown body (frontmatter stripped). */
9
+ body: string;
10
+ /** The authored file, verbatim — the agent-facing .md projection. */
11
+ original: string;
12
+ /** The body rendered to HTML (CommonMark + GFM, via @momiji-rs/sparkdown/gfm wasm). */
13
+ html: string;
14
+ /** The locale this entry was authored in — set for files under a `<locale>/`
15
+ * subdir, undefined for the flat (default-locale) files. */
16
+ locale?: string;
17
+ };
18
+ type ScannedCollection = {
19
+ default: ContentEntry[];
20
+ byLocale: Record<string, ContentEntry[]>;
21
+ };
22
+ declare function scanCollection(dir: string, knownLocales?: readonly string[]): ScannedCollection;
23
+ /** All entries in a content directory, newest-first by `date` (then slug). With
24
+ * a `locale`, each entry is its locale variant when present, else the default
25
+ * (so a reader sees the whole collection, localized where available). */
26
+ declare function collection(dir: string, locale?: string): ContentEntry[];
27
+ /** One entry by slug, or null. With a `locale`, prefer `<dir>/<locale>/<slug>`,
28
+ * falling back to the flat default (a dev-warn flags a partial translation).
29
+ * `fallback: false` is STRICT — a missing variant returns null (so a route can
30
+ * 404 rather than serve default-language content). */
31
+ declare function entry(dir: string, slug: string, locale?: string, opts?: {
32
+ fallback?: boolean;
33
+ }): ContentEntry | null;
34
+ declare function generateContentModule(contentDir: string, knownLocales?: readonly string[], sources?: readonly ContentSource[]): {
35
+ code: string;
36
+ names: string[];
37
+ };
38
+ //#endregion
39
+ export { ContentEntry, ScannedCollection, collection, entry, generateContentModule, scanCollection };
@@ -0,0 +1,201 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { initSync, toHtmlSync } from "@momiji-rs/sparkdown/gfm";
4
+ //#region src/content.ts
5
+ let wasmReady = false;
6
+ const ensureWasm = () => {
7
+ if (!wasmReady) {
8
+ initSync();
9
+ wasmReady = true;
10
+ }
11
+ };
12
+ function parseFrontmatter(raw) {
13
+ if (!raw.startsWith("---")) return {
14
+ data: {},
15
+ body: raw
16
+ };
17
+ const end = raw.indexOf("\n---", 3);
18
+ if (end === -1) return {
19
+ data: {},
20
+ body: raw
21
+ };
22
+ const data = {};
23
+ for (const line of raw.slice(3, end).split("\n")) {
24
+ const i = line.indexOf(":");
25
+ if (i === -1) continue;
26
+ const key = line.slice(0, i).trim();
27
+ const value = line.slice(i + 1).trim();
28
+ if (!key) continue;
29
+ if (value.startsWith("[") && value.endsWith("]")) data[key] = value.slice(1, -1).split(",").map((s) => s.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
30
+ else data[key] = value.replace(/^["']|["']$/g, "");
31
+ }
32
+ return {
33
+ data,
34
+ body: raw.slice(end + 4).replace(/^\n+/, "")
35
+ };
36
+ }
37
+ const memo = /* @__PURE__ */ new Map();
38
+ const memoKey = (file, slug, locale) => `${file}\u0000${slug}\u0000${locale ?? ""}`;
39
+ function loadEntry(file, slug, locale) {
40
+ const mtime = statSync(file).mtimeMs;
41
+ const key = memoKey(file, slug, locale);
42
+ const hit = memo.get(key);
43
+ if (hit && hit.mtime === mtime) return hit.entry;
44
+ const original = readFileSync(file, "utf8");
45
+ const { data, body } = parseFrontmatter(original);
46
+ if (data.title === void 0) {
47
+ const h1 = body.match(/^#[ \t]+(.+?)[ \t]*$/m);
48
+ if (h1?.[1]) data.title = h1[1];
49
+ }
50
+ ensureWasm();
51
+ const entry = {
52
+ slug,
53
+ file,
54
+ data,
55
+ body,
56
+ original,
57
+ html: toHtmlSync(body),
58
+ ...locale ? { locale } : {}
59
+ };
60
+ memo.set(key, {
61
+ mtime,
62
+ entry
63
+ });
64
+ return entry;
65
+ }
66
+ const isMd = (f) => f.endsWith(".md") || f.endsWith(".mdx");
67
+ const slugOf = (f) => f.replace(/\.(md|mdx)$/, "").replace(/(^|\/)(index|README)$/i, "");
68
+ const byDate = (a, b) => String(b.data.date ?? "").localeCompare(String(a.data.date ?? "")) || a.slug.localeCompare(b.slug);
69
+ const LOCALE_DIR = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
70
+ function isLocaleDir(name, known) {
71
+ return known ? known.includes(name) : LOCALE_DIR.test(name);
72
+ }
73
+ function collectMd(root, knownLocales, skipTopLocales, sub = "") {
74
+ const out = [];
75
+ for (const ent of readdirSync(join(root, sub), { withFileTypes: true })) {
76
+ const rel = sub ? `${sub}/${ent.name}` : ent.name;
77
+ if (ent.isDirectory()) {
78
+ if (skipTopLocales && sub === "" && isLocaleDir(ent.name, knownLocales)) continue;
79
+ out.push(...collectMd(root, knownLocales, skipTopLocales, rel));
80
+ } else if (isMd(ent.name)) out.push({
81
+ file: join(root, rel),
82
+ slug: slugOf(rel)
83
+ });
84
+ }
85
+ return out;
86
+ }
87
+ function scanCollection(dir, knownLocales) {
88
+ const def = collectMd(dir, knownLocales, true).map(({ file, slug }) => loadEntry(file, slug)).sort(byDate);
89
+ const byLocale = {};
90
+ for (const ent of readdirSync(dir, { withFileTypes: true })) if (ent.isDirectory() && isLocaleDir(ent.name, knownLocales)) {
91
+ const locale = ent.name;
92
+ byLocale[locale] = collectMd(join(dir, locale), knownLocales, false).map(({ file, slug }) => loadEntry(file, slug, locale)).sort(byDate);
93
+ }
94
+ return {
95
+ default: def,
96
+ byLocale
97
+ };
98
+ }
99
+ /** All entries in a content directory, newest-first by `date` (then slug). With
100
+ * a `locale`, each entry is its locale variant when present, else the default
101
+ * (so a reader sees the whole collection, localized where available). */
102
+ function collection(dir, locale) {
103
+ const { default: def, byLocale } = scanCollection(dir);
104
+ if (!locale || !byLocale[locale]) return def;
105
+ const variants = new Map(byLocale[locale].map((e) => [e.slug, e]));
106
+ return def.map((e) => variants.get(e.slug) ?? e).sort(byDate);
107
+ }
108
+ function probe(dir, slug, locale) {
109
+ for (const ext of [".md", ".mdx"]) try {
110
+ return loadEntry(join(dir, slug + ext), slug, locale);
111
+ } catch {}
112
+ return null;
113
+ }
114
+ /** One entry by slug, or null. With a `locale`, prefer `<dir>/<locale>/<slug>`,
115
+ * falling back to the flat default (a dev-warn flags a partial translation).
116
+ * `fallback: false` is STRICT — a missing variant returns null (so a route can
117
+ * 404 rather than serve default-language content). */
118
+ function entry(dir, slug, locale, opts) {
119
+ if (!/^[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*$/.test(slug) || slug.includes("..")) return null;
120
+ if (!locale) return probe(dir, slug);
121
+ const variant = probe(join(dir, locale), slug, locale);
122
+ if (variant) return variant;
123
+ if (opts?.fallback === false) return null;
124
+ const fallback = probe(dir, slug);
125
+ if (fallback && existsSync(join(dir, locale))) console.warn(`[june content] ${slug}: no "${locale}" variant — served default`);
126
+ return fallback;
127
+ }
128
+ function mountScanned(s, mount) {
129
+ if (!mount) return s;
130
+ const re = (e) => ({
131
+ ...e,
132
+ slug: e.slug ? `${mount}/${e.slug}` : mount
133
+ });
134
+ return {
135
+ default: s.default.map(re),
136
+ byLocale: Object.fromEntries(Object.entries(s.byLocale).map(([l, es]) => [l, es.map(re)]))
137
+ };
138
+ }
139
+ function mergeScanned(into, add, label) {
140
+ const mergeEntries = (a, b, bucket) => {
141
+ const seen = new Map(a.map((e) => [e.slug, e.file]));
142
+ for (const e of b) {
143
+ const other = seen.get(e.slug);
144
+ if (other !== void 0) throw new Error(`[june content] slug collision in collection "${label}"${bucket ? ` (${bucket})` : ""}: "${e.slug}" is authored by both\n ${other}\n ${e.file}\nGive the source a distinct mount, or rename one file.`);
145
+ seen.set(e.slug, e.file);
146
+ }
147
+ return [...a, ...b].sort(byDate);
148
+ };
149
+ const byLocale = { ...into.byLocale };
150
+ for (const [locale, entries] of Object.entries(add.byLocale)) byLocale[locale] = mergeEntries(byLocale[locale] ?? [], entries, locale);
151
+ return {
152
+ default: mergeEntries(into.default, add.default, ""),
153
+ byLocale
154
+ };
155
+ }
156
+ function generateContentModule(contentDir, knownLocales, sources) {
157
+ const strip = (e) => ({
158
+ slug: e.slug,
159
+ data: e.data,
160
+ body: e.body,
161
+ original: e.original,
162
+ html: e.html,
163
+ ...e.locale ? { locale: e.locale } : {}
164
+ });
165
+ const collections = /* @__PURE__ */ new Map();
166
+ if (existsSync(contentDir)) {
167
+ for (const d of readdirSync(contentDir, { withFileTypes: true })) if (d.isDirectory()) collections.set(d.name, scanCollection(join(contentDir, d.name), knownLocales));
168
+ }
169
+ for (const s of sources ?? []) {
170
+ if (!existsSync(s.dir)) throw new Error(`[june content] content source "${s.dir}" (collection "${s.collection}") does not exist`);
171
+ const scanned = mountScanned(scanCollection(s.dir, knownLocales), s.mount);
172
+ const base = collections.get(s.collection);
173
+ collections.set(s.collection, base ? mergeScanned(base, scanned, s.collection) : scanned);
174
+ }
175
+ const names = [];
176
+ let anyLocale = false;
177
+ let body = "";
178
+ for (const [name, { default: def, byLocale }] of collections) {
179
+ const CONST = name.replace(/[^A-Za-z0-9]/g, "_").toUpperCase();
180
+ const finder = name.endsWith("s") ? name.slice(0, -1) : `${name}Entry`;
181
+ body += `export const ${CONST}: ContentEntry[] = ${JSON.stringify(def.map(strip), null, 2)};\n`;
182
+ if (Object.keys(byLocale).length === 0) {
183
+ body += `export const ${finder} = (slug: string): ContentEntry | null => ${CONST}.find((p) => p.slug === slug) ?? null;\n`;
184
+ body += `export const ${name} = (_locale?: string): ContentEntry[] => ${CONST};\n`;
185
+ } else {
186
+ anyLocale = true;
187
+ const map = {};
188
+ for (const [loc, entries] of Object.entries(byLocale)) for (const e of entries) (map[loc] ??= {})[e.slug] = strip(e);
189
+ body += `const ${CONST}_L: Record<string, Record<string, ContentEntry>> = ${JSON.stringify(map, null, 2)};\n`;
190
+ body += `export const ${finder} = (slug: string, locale?: string, opts?: { fallback?: boolean }): ContentEntry | null => {\n const v = locale ? ${CONST}_L[locale]?.[slug] : undefined;\n if (v) return v;\n if (opts?.fallback === false) return null;\n const d = ${CONST}.find((p) => p.slug === slug) ?? null;\n if (process.env.NODE_ENV !== "production" && locale && ${CONST}_L[locale] && d) console.warn(\`[june content] ${name}/\${slug}: no "\${locale}" variant — served default\`);\n return d;\n};\n`;
191
+ body += `export const ${name} = (locale?: string): ContentEntry[] => locale && ${CONST}_L[locale] ? ${CONST}.map((p) => ${CONST}_L[locale]![p.slug] ?? p) : ${CONST};\n`;
192
+ }
193
+ names.push(name);
194
+ }
195
+ return {
196
+ code: "// AUTO-GENERATED by `june build` — edit content/**/*.md, not this file.\n" + (anyLocale ? "export type ContentEntry = { slug: string; data: Record<string, string | string[]>; body: string; original: string; html: string; locale?: string };\n" : "export type ContentEntry = { slug: string; data: Record<string, string | string[]>; body: string; original: string; html: string };\n") + body,
197
+ names
198
+ };
199
+ }
200
+ //#endregion
201
+ export { collection, entry, generateContentModule, scanCollection };
@@ -0,0 +1,10 @@
1
+ //#region src/css-modules-ambient.d.ts
2
+ // Ambient types for CSS Modules: `import styles from "./X.module.css"` resolves
3
+ // to a map of local class name → scoped name. June ships this so app code (and
4
+ // these tests/fixtures) typecheck; the create-june template references an
5
+ // equivalent june-env.d.ts. (No top-level import/export → this is a GLOBAL
6
+ // declaration, so the ambient module applies everywhere.)
7
+ declare module "*.module.css" {
8
+ const classes: Record<string, string>;
9
+ export default classes;
10
+ }
@@ -0,0 +1,24 @@
1
+ //#region src/css-modules.d.ts
2
+ declare const MODULE_STYLES_URL = "/_june/modules.css";
3
+ declare const isModuleCss: (id: string) => boolean;
4
+ declare function stableKey(appRoot: string, file: string): string;
5
+ declare function transformCssModule(file: string, appRoot: string): Promise<{
6
+ map: Record<string, string>;
7
+ css: string;
8
+ }>;
9
+ declare const moduleJs: (map: Record<string, string>) => string;
10
+ type ModuleMaps = Record<string, Record<string, string>>;
11
+ declare function buildModuleCss(appDir: string, appRoot: string): Promise<{
12
+ maps: ModuleMaps;
13
+ css: string | null;
14
+ }>;
15
+ declare function rolldownCssModulesPlugin(maps: ModuleMaps): {
16
+ name: string;
17
+ load(id: string): {
18
+ code: string;
19
+ moduleType: "js";
20
+ } | null;
21
+ };
22
+ declare function registerCssModules(maps: ModuleMaps): Promise<void>;
23
+ //#endregion
24
+ export { MODULE_STYLES_URL, ModuleMaps, buildModuleCss, isModuleCss, moduleJs, registerCssModules, rolldownCssModulesPlugin, stableKey, transformCssModule };
@@ -0,0 +1,127 @@
1
+ import { readFile, readdir } from "node:fs/promises";
2
+ import { dirname, join, relative, resolve, sep } from "node:path";
3
+ //#region src/css-modules.ts
4
+ const MODULE_STYLES_URL = "/_june/modules.css";
5
+ const isModuleCss = (id) => id.endsWith(".module.css");
6
+ function stableKey(appRoot, file) {
7
+ return relative(appRoot, file).split(sep).join("/");
8
+ }
9
+ async function transformOne(file, appRoot) {
10
+ const { transform } = await import("lightningcss");
11
+ const { code, exports } = transform({
12
+ filename: stableKey(appRoot, file),
13
+ code: Buffer.from(await readFile(file, "utf8")),
14
+ cssModules: { pattern: "[local]_[hash]" }
15
+ });
16
+ return {
17
+ css: code.toString(),
18
+ exports: exports ?? {}
19
+ };
20
+ }
21
+ async function transformGraph(entry, appRoot, all = {}) {
22
+ if (all[entry]) return all;
23
+ const t = await transformOne(entry, appRoot);
24
+ all[entry] = t;
25
+ for (const exp of Object.values(t.exports)) for (const c of exp.composes) if (c.type === "dependency") await transformGraph(resolve(dirname(entry), c.specifier), appRoot, all);
26
+ return all;
27
+ }
28
+ function resolveName(file, local, all, seen = /* @__PURE__ */ new Set()) {
29
+ const exp = all[file]?.[local];
30
+ if (!exp) return local;
31
+ const parts = [exp.name];
32
+ for (const c of exp.composes) if (c.type === "dependency") {
33
+ const target = resolve(dirname(file), c.specifier);
34
+ const k = `${target}::${c.name}`;
35
+ if (seen.has(k)) continue;
36
+ seen.add(k);
37
+ parts.push(resolveName(target, c.name, all, seen));
38
+ } else parts.push(c.name);
39
+ return parts.join(" ");
40
+ }
41
+ const exportsOnly = (all) => Object.fromEntries(Object.entries(all).map(([f, t]) => [f, t.exports]));
42
+ async function transformCssModule(file, appRoot) {
43
+ const all = await transformGraph(file, appRoot);
44
+ const exports = exportsOnly(all);
45
+ const map = {};
46
+ for (const local of Object.keys(all[file].exports)) map[local] = resolveName(file, local, exports);
47
+ return {
48
+ map,
49
+ css: all[file].css
50
+ };
51
+ }
52
+ const moduleJs = (map) => `export default ${JSON.stringify(map)};`;
53
+ async function findModuleCss(dir) {
54
+ const out = [];
55
+ const walk = async (d) => {
56
+ let entries;
57
+ try {
58
+ entries = await readdir(d, { withFileTypes: true });
59
+ } catch {
60
+ return;
61
+ }
62
+ for (const e of entries) {
63
+ const full = join(d, e.name);
64
+ if (e.isDirectory()) await walk(full);
65
+ else if (e.name.endsWith(".module.css")) out.push(full);
66
+ }
67
+ };
68
+ await walk(dir);
69
+ return out.sort();
70
+ }
71
+ async function buildModuleCss(appDir, appRoot) {
72
+ const files = await findModuleCss(appDir);
73
+ if (!files.length) return {
74
+ maps: {},
75
+ css: null
76
+ };
77
+ const all = {};
78
+ for (const file of files) await transformGraph(file, appRoot, all);
79
+ const exports = exportsOnly(all);
80
+ const maps = {};
81
+ for (const file of files) {
82
+ maps[file] = {};
83
+ for (const local of Object.keys(all[file].exports)) maps[file][local] = resolveName(file, local, exports);
84
+ }
85
+ return {
86
+ maps,
87
+ css: Object.keys(all).sort().map((f) => all[f].css).join("\n")
88
+ };
89
+ }
90
+ function rolldownCssModulesPlugin(maps) {
91
+ return {
92
+ name: "june-css-modules",
93
+ load(id) {
94
+ if (!isModuleCss(id)) return null;
95
+ return {
96
+ code: moduleJs(maps[id] ?? {}),
97
+ moduleType: "js"
98
+ };
99
+ }
100
+ };
101
+ }
102
+ let activeMaps = {};
103
+ let runtimeRegistered = false;
104
+ function registerBunCssModules() {
105
+ globalThis.Bun.plugin({
106
+ name: "june-css-modules",
107
+ setup(build) {
108
+ build.onLoad({ filter: /\.module\.css$/ }, (args) => ({
109
+ loader: "js",
110
+ contents: moduleJs(activeMaps[args.path] ?? {})
111
+ }));
112
+ }
113
+ });
114
+ }
115
+ async function registerNodeCssModules(maps) {
116
+ const { register } = await import("node:module");
117
+ register(new URL("./css-modules-loader.mjs", import.meta.url), { data: { maps } });
118
+ }
119
+ async function registerCssModules(maps) {
120
+ activeMaps = maps;
121
+ if (runtimeRegistered || !Object.keys(maps).length) return;
122
+ runtimeRegistered = true;
123
+ if (typeof globalThis.Bun !== "undefined") registerBunCssModules();
124
+ else await registerNodeCssModules(maps);
125
+ }
126
+ //#endregion
127
+ export { MODULE_STYLES_URL, buildModuleCss, isModuleCss, moduleJs, registerCssModules, rolldownCssModulesPlugin, stableKey, transformCssModule };
package/dist/css.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { Targets } from "lightningcss";
2
+ //#region src/css.d.ts
3
+ declare const STYLES_URL = "/_june/global.css";
4
+ declare function findGlobalCss(appDir: string): string | null;
5
+ declare function globalCssUsesTailwind(appDir: string): boolean;
6
+ declare function cssTargets(appDir: string): Promise<Targets>;
7
+ declare function processCssCached(appDir: string): Promise<string | null>;
8
+ declare function invalidateCss(): void;
9
+ declare function minifyCss(css: string, filename?: string, targets?: Targets): Promise<string>;
10
+ declare function processCss(appDir: string, opts?: {
11
+ minify?: boolean;
12
+ }): Promise<string | null>;
13
+ //#endregion
14
+ export { STYLES_URL, cssTargets, findGlobalCss, globalCssUsesTailwind, invalidateCss, minifyCss, processCss, processCssCached };
package/dist/css.js ADDED
@@ -0,0 +1,114 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { createRequire } from "node:module";
6
+ //#region src/css.ts
7
+ const STYLES_URL = "/_june/global.css";
8
+ const GLOBAL_CSS = "global.css";
9
+ function findGlobalCss(appDir) {
10
+ const p = join(appDir, GLOBAL_CSS);
11
+ return existsSync(p) ? p : null;
12
+ }
13
+ const usesTailwind = (css) => /@import\s+["']tailwindcss["']|@tailwind\b/.test(css);
14
+ function globalCssUsesTailwind(appDir) {
15
+ const p = join(appDir, GLOBAL_CSS);
16
+ try {
17
+ return existsSync(p) && usesTailwind(readFileSync(p, "utf8"));
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+ function resolveFromApp(specifier, appDir) {
23
+ try {
24
+ return createRequire(pathToFileURL(join(appDir, "package.json"))).resolve(specifier);
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+ const v = (major, minor = 0) => major << 16 | minor << 8;
30
+ const DEFAULT_TARGETS = {
31
+ chrome: v(107),
32
+ edge: v(107),
33
+ firefox: v(104),
34
+ safari: v(16)
35
+ };
36
+ let targetsCache = null;
37
+ async function cssTargets(appDir) {
38
+ if (targetsCache?.appDir === appDir) return targetsCache.targets;
39
+ let targets = DEFAULT_TARGETS;
40
+ const blPath = resolveFromApp("browserslist", appDir);
41
+ if (blPath) try {
42
+ const browserslist = (await import(blPath)).default;
43
+ const { browserslistToTargets } = await import("lightningcss");
44
+ targets = browserslistToTargets(browserslist(void 0, { path: appDir }));
45
+ } catch {}
46
+ targetsCache = {
47
+ appDir,
48
+ targets
49
+ };
50
+ return targets;
51
+ }
52
+ async function compileTailwind(css, file, appDir, minify) {
53
+ const nodePath = resolveFromApp("@tailwindcss/node", appDir);
54
+ const oxidePath = resolveFromApp("@tailwindcss/oxide", appDir);
55
+ if (!nodePath || !oxidePath) return null;
56
+ const { compile, optimize, Features } = await import(nodePath);
57
+ const { Scanner } = await import(oxidePath);
58
+ const compiler = await compile(css, {
59
+ base: dirname(file),
60
+ onDependency: () => {}
61
+ });
62
+ const sources = [{
63
+ base: dirname(appDir),
64
+ pattern: "**/*",
65
+ negated: false
66
+ }, ...compiler.sources];
67
+ const candidates = compiler.features & Features.Utilities ? new Scanner({ sources }).scan() : [];
68
+ const out = compiler.build(candidates);
69
+ return minify ? optimize(out, { minify: true }).code : out;
70
+ }
71
+ let devCache = null;
72
+ async function processCssCached(appDir) {
73
+ if (devCache?.appDir === appDir) return devCache.css;
74
+ const css = await processCss(appDir);
75
+ devCache = {
76
+ appDir,
77
+ css
78
+ };
79
+ return css;
80
+ }
81
+ function invalidateCss() {
82
+ devCache = null;
83
+ }
84
+ async function minifyCss(css, filename = "input.css", targets) {
85
+ try {
86
+ const { transform } = await import("lightningcss");
87
+ const { code } = transform({
88
+ filename,
89
+ code: Buffer.from(css),
90
+ minify: true,
91
+ targets
92
+ });
93
+ return code.toString();
94
+ } catch (e) {
95
+ console.warn("[june] CSS minify failed; emitting unminified:", e);
96
+ return css;
97
+ }
98
+ }
99
+ async function processCss(appDir, opts = {}) {
100
+ const file = findGlobalCss(appDir);
101
+ if (!file) return null;
102
+ const css = await readFile(file, "utf8");
103
+ if (usesTailwind(css)) {
104
+ const compiled = await compileTailwind(css, file, appDir, !!opts.minify).catch((e) => {
105
+ console.warn("[june] Tailwind compile failed; serving raw CSS:", e);
106
+ return null;
107
+ });
108
+ if (compiled !== null) return compiled;
109
+ console.warn("[june] global.css uses Tailwind but @tailwindcss/node + @tailwindcss/oxide aren't installed — serving raw CSS.");
110
+ }
111
+ return opts.minify ? await minifyCss(css, file, await cssTargets(appDir)) : css;
112
+ }
113
+ //#endregion
114
+ export { STYLES_URL, cssTargets, findGlobalCss, globalCssUsesTailwind, invalidateCss, minifyCss, processCss, processCssCached };
@@ -0,0 +1,24 @@
1
+ import { DbFactory } from "@junejs/core/resources";
2
+ //#region src/d1.d.ts
3
+ type D1Result<T> = {
4
+ results: T[];
5
+ };
6
+ type D1Meta = {
7
+ changes?: number;
8
+ last_row_id?: number;
9
+ };
10
+ interface D1PreparedStatement {
11
+ bind(...values: unknown[]): D1PreparedStatement;
12
+ all<T = unknown>(): Promise<D1Result<T>>;
13
+ first<T = unknown>(): Promise<T | null>;
14
+ run(): Promise<{
15
+ meta: D1Meta;
16
+ }>;
17
+ }
18
+ interface D1Database {
19
+ prepare(sql: string): D1PreparedStatement;
20
+ exec(sql: string): Promise<unknown>;
21
+ }
22
+ declare function d1(binding: D1Database): DbFactory;
23
+ //#endregion
24
+ export { d1 as n, D1Database as t };
@@ -0,0 +1,31 @@
1
+ import { n as MigrateResult } from "./migrate-BbWt-PuB.js";
2
+ import { JuneDb } from "@junejs/core/resources";
3
+ //#region src/d1-migrate.d.ts
4
+ type D1Exec = (req: {
5
+ sql: string;
6
+ mode: "command" | "file";
7
+ json: boolean;
8
+ }) => Promise<{
9
+ stdout: string;
10
+ stderr: string;
11
+ exitCode: number;
12
+ }>;
13
+ declare function inlineParams(sql: string, params: readonly unknown[]): string;
14
+ declare function wranglerD1(opts: {
15
+ database: string;
16
+ configPath: string;
17
+ cwd: string;
18
+ wranglerVersion?: string;
19
+ exec?: D1Exec;
20
+ }): JuneDb;
21
+ declare function resolveD1Database(appRoot: string, configPath: string): Promise<string | null>;
22
+ declare function migrateD1(opts: {
23
+ appRoot: string;
24
+ database: string;
25
+ configPath: string;
26
+ allowDestructive?: boolean;
27
+ exec?: D1Exec;
28
+ now?: string;
29
+ }): Promise<MigrateResult>;
30
+ //#endregion
31
+ export { D1Exec, inlineParams, migrateD1, resolveD1Database, wranglerD1 };