@blinkk/root 3.0.1-alpha.0 → 3.0.1-beta.2

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.
@@ -0,0 +1,854 @@
1
+ import {
2
+ getVitePlugins
3
+ } from "./chunk-XSNCF7WU.js";
4
+
5
+ // src/node/monorepo.ts
6
+ import path2 from "path";
7
+ import { getWorkspaces, getWorkspaceRoot } from "workspace-tools";
8
+
9
+ // src/utils/fsutils.ts
10
+ import fs from "fs";
11
+ import path from "path";
12
+ import fsExtra from "fs-extra";
13
+ import glob from "tiny-glob";
14
+ function isJsFile(filename) {
15
+ return !!filename.match(/\.(j|t)sx?$/);
16
+ }
17
+ async function writeFile(filepath, content) {
18
+ const dirPath = path.dirname(filepath);
19
+ await makeDir(dirPath);
20
+ await fs.promises.writeFile(filepath, content);
21
+ }
22
+ async function makeDir(dirpath) {
23
+ try {
24
+ await fs.promises.access(dirpath);
25
+ } catch (e) {
26
+ await fs.promises.mkdir(dirpath, { recursive: true });
27
+ }
28
+ }
29
+ async function copyDir(srcdir, dstdir) {
30
+ if (!fsExtra.existsSync(srcdir)) {
31
+ return;
32
+ }
33
+ fsExtra.copySync(srcdir, dstdir, { overwrite: true });
34
+ }
35
+ async function copyGlob(pattern, srcdir, dstdir) {
36
+ const files = await glob(pattern, { cwd: srcdir });
37
+ if (files.length > 0) {
38
+ await makeDir(dstdir);
39
+ }
40
+ files.forEach((file) => {
41
+ fsExtra.copySync(path.resolve(srcdir, file), path.resolve(dstdir, file));
42
+ });
43
+ }
44
+ async function rmDir(dirpath) {
45
+ await fs.promises.rm(dirpath, { recursive: true, force: true });
46
+ }
47
+ async function loadJson(filepath) {
48
+ const content = await fs.promises.readFile(filepath, "utf-8");
49
+ return JSON.parse(content);
50
+ }
51
+ function loadJsonSync(filepath) {
52
+ const content = fs.readFileSync(filepath, "utf-8");
53
+ return JSON.parse(content);
54
+ }
55
+ async function writeJson(filepath, data) {
56
+ const content = JSON.stringify(data, null, 2);
57
+ await writeFile(filepath, content);
58
+ }
59
+ async function isDirectory(dirpath) {
60
+ return fs.promises.stat(dirpath).then((fsStat) => {
61
+ return fsStat.isDirectory();
62
+ }).catch((err) => {
63
+ if (err.code === "ENOENT") {
64
+ return false;
65
+ }
66
+ throw err;
67
+ });
68
+ }
69
+ function fileExists(filepath) {
70
+ return fs.promises.access(filepath).then(() => true).catch(() => false);
71
+ }
72
+ function fileExistsSync(filepath) {
73
+ try {
74
+ fs.accessSync(filepath);
75
+ return true;
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+ async function dirExists(dirpath) {
81
+ try {
82
+ const stat = await fs.promises.stat(dirpath);
83
+ return stat.isDirectory();
84
+ } catch (error) {
85
+ if (error.code === "ENOENT") {
86
+ return false;
87
+ }
88
+ throw error;
89
+ }
90
+ }
91
+ async function directoryContains(dirpath, subpath) {
92
+ const outer = await fs.promises.realpath(dirpath);
93
+ const inner = await fs.promises.realpath(subpath);
94
+ const rel = path.relative(outer, inner);
95
+ return !rel.startsWith("..");
96
+ }
97
+
98
+ // src/node/monorepo.ts
99
+ function loadPackageJson(filepath) {
100
+ if (!fileExistsSync(filepath)) {
101
+ return null;
102
+ }
103
+ return loadJsonSync(filepath);
104
+ }
105
+ function getMonorepoPackages(rootDir) {
106
+ const monorepoRoot = getWorkspaceRoot(rootDir);
107
+ if (!monorepoRoot) {
108
+ return {};
109
+ }
110
+ const workspaces = getWorkspaces(monorepoRoot);
111
+ const packages = {};
112
+ workspaces.forEach((workspaceInfo) => {
113
+ packages[workspaceInfo.name] = workspaceInfo;
114
+ });
115
+ return packages;
116
+ }
117
+ function getMonorepoPackageDeps(rootDir) {
118
+ const monorepoRoot = getWorkspaceRoot(rootDir);
119
+ if (!monorepoRoot) {
120
+ return {};
121
+ }
122
+ const packageJsonPath = path2.join(monorepoRoot, "package.json");
123
+ const packageJson = loadPackageJson(packageJsonPath);
124
+ return packageJson?.dependencies || {};
125
+ }
126
+ function flattenPackageDepsFromMonorepo(rootDir, options) {
127
+ const packageJsonPath = path2.resolve(rootDir, "package.json");
128
+ const packageJson = loadPackageJson(packageJsonPath);
129
+ const monorepoDeps = getMonorepoPackageDeps(rootDir);
130
+ const projectDeps = {
131
+ ...packageJson?.peerDependencies,
132
+ ...packageJson?.dependencies
133
+ };
134
+ const allDeps = {};
135
+ const workspacePackages = getMonorepoPackages(rootDir);
136
+ const ignore = options?.ignore || /* @__PURE__ */ new Set();
137
+ Object.entries(projectDeps).forEach(([depName, depVersion]) => {
138
+ if (depName.startsWith("@blinkk/root") && depVersion.startsWith("workspace:")) {
139
+ const packageInfo = workspacePackages[depName];
140
+ if (packageInfo) {
141
+ allDeps[depName] = packageInfo.packageJson.version;
142
+ }
143
+ } else if (depVersion.startsWith("workspace:")) {
144
+ if (ignore.has(depName)) {
145
+ return;
146
+ }
147
+ ignore.add(depName);
148
+ const packageInfo = workspacePackages[depName];
149
+ if (packageInfo) {
150
+ const workspacePackageDir = packageInfo.path;
151
+ const deps = flattenPackageDepsFromMonorepo(workspacePackageDir, {
152
+ ignore
153
+ });
154
+ for (const key in deps) {
155
+ const currentValue = allDeps[key];
156
+ if (deps[key] && deps[key] !== "*" && (!currentValue || currentValue === "*")) {
157
+ allDeps[key] = deps[key];
158
+ }
159
+ }
160
+ }
161
+ } else if (depVersion === "*" && monorepoDeps[depName]) {
162
+ allDeps[depName] = monorepoDeps[depName];
163
+ } else {
164
+ allDeps[depName] = depVersion;
165
+ }
166
+ });
167
+ return sortDeps(allDeps);
168
+ }
169
+ function sortDeps(deps) {
170
+ const keys = Object.keys(deps).sort();
171
+ const sortedDeps = {};
172
+ for (const key of keys) {
173
+ sortedDeps[key] = deps[key];
174
+ }
175
+ return sortedDeps;
176
+ }
177
+
178
+ // src/node/load-config.ts
179
+ import path3 from "path";
180
+ import { bundleRequire } from "bundle-require";
181
+ import { build } from "esbuild";
182
+ async function loadRootConfig(rootDir, options) {
183
+ const { rootConfig } = await loadRootConfigWithDeps(rootDir, options);
184
+ return rootConfig;
185
+ }
186
+ async function loadRootConfigWithDeps(rootDir, options) {
187
+ const configPath = path3.resolve(rootDir, "root.config.ts");
188
+ const exists = await fileExists(configPath);
189
+ if (!exists) {
190
+ throw new Error(`${configPath} does not exist`);
191
+ }
192
+ const configBundle = await bundleRequire({
193
+ filepath: configPath,
194
+ esbuildOptions: { plugins: [esbuildExternalsPlugin({ rootDir })] }
195
+ });
196
+ let config = configBundle.mod.default || {};
197
+ if (typeof config === "function") {
198
+ config = await config(options) || {};
199
+ }
200
+ const rootConfig = Object.assign({}, config, { rootDir });
201
+ validateRootconfig(rootConfig);
202
+ return { rootConfig, dependencies: configBundle.dependencies };
203
+ }
204
+ function validateRootconfig(rootConfig) {
205
+ const scss = rootConfig.vite?.css?.preprocessorOptions?.scss;
206
+ if (scss?.includePaths) {
207
+ console.warn(
208
+ '[deprecation warning] root.config.ts: vite.css.preprocessorOptions.scss.includePaths is deprecated. rename "includePaths" -> "loadPaths"'
209
+ );
210
+ scss.loadPaths = scss.includePaths;
211
+ }
212
+ }
213
+ async function bundleRootConfig(rootDir, outPath) {
214
+ const configPath = path3.resolve(rootDir, "root.config.ts");
215
+ const configExists = await fileExists(configPath);
216
+ if (!configExists) {
217
+ throw new Error(`${configPath} does not exist`);
218
+ }
219
+ await build({
220
+ entryPoints: [configPath],
221
+ bundle: true,
222
+ minify: true,
223
+ platform: "node",
224
+ outfile: outPath,
225
+ sourcemap: "inline",
226
+ metafile: true,
227
+ format: "esm",
228
+ plugins: [esbuildExternalsPlugin({ rootDir })]
229
+ });
230
+ }
231
+ async function loadBundledConfig(rootDir, options) {
232
+ const configPath = path3.resolve(rootDir, "dist/root.config.js");
233
+ const exists = await fileExists(configPath);
234
+ if (!exists) {
235
+ throw new Error(`${configPath} does not exist`);
236
+ }
237
+ const module = await import(configPath);
238
+ let config = module.default || {};
239
+ if (typeof config === "function") {
240
+ config = await config(options) || {};
241
+ }
242
+ return Object.assign({}, config, { rootDir });
243
+ }
244
+ function esbuildExternalsPlugin(options) {
245
+ const rootDir = options.rootDir;
246
+ const allDeps = flattenPackageDepsFromMonorepo(rootDir);
247
+ function getPackageName(id) {
248
+ const segments = id.split("/");
249
+ if (segments.length > 1) {
250
+ if (segments[0].startsWith("@") && segments[0].length > 1) {
251
+ return `${segments[0]}/${segments[1]}`;
252
+ }
253
+ return segments[0];
254
+ }
255
+ return id;
256
+ }
257
+ return {
258
+ name: "root-externals-plugin",
259
+ setup(build2) {
260
+ build2.onResolve({ filter: /.*/ }, (args) => {
261
+ const id = args.path;
262
+ if (id[0] !== "." && !id.startsWith("@/")) {
263
+ const packageName = getPackageName(id);
264
+ if (packageName in allDeps) {
265
+ return {
266
+ external: true
267
+ };
268
+ }
269
+ }
270
+ return null;
271
+ });
272
+ }
273
+ };
274
+ }
275
+
276
+ // src/node/pod-collector.ts
277
+ import path4 from "path";
278
+ import glob2 from "tiny-glob";
279
+ var cachedPods = null;
280
+ function invalidatePodCache() {
281
+ cachedPods = null;
282
+ }
283
+ async function collectPods(rootConfig) {
284
+ if (cachedPods) {
285
+ return cachedPods;
286
+ }
287
+ const plugins = rootConfig.plugins || [];
288
+ const userPodConfigs = rootConfig.pods || {};
289
+ const rawPods = await resolvePluginPods(plugins, rootConfig);
290
+ const resolved = [];
291
+ const seenNames = /* @__PURE__ */ new Set();
292
+ for (const pod of rawPods) {
293
+ if (seenNames.has(pod.name)) {
294
+ throw new Error(
295
+ `Duplicate pod name: "${pod.name}". Each pod must have a unique name.`
296
+ );
297
+ }
298
+ seenNames.add(pod.name);
299
+ const userConfig = userPodConfigs[pod.name] || {};
300
+ if (userConfig.enabled === false) {
301
+ continue;
302
+ }
303
+ const resolvedPod = await resolvePod(pod, userConfig, rootConfig);
304
+ resolved.push(resolvedPod);
305
+ }
306
+ validateCollectionIds(resolved, rootConfig);
307
+ cachedPods = resolved;
308
+ return resolved;
309
+ }
310
+ async function resolvePluginPods(plugins, rootConfig) {
311
+ const pods = [];
312
+ for (const plugin of plugins) {
313
+ if (!plugin.pod) {
314
+ continue;
315
+ }
316
+ if (typeof plugin.pod === "function") {
317
+ const result = await plugin.pod({ rootConfig });
318
+ pods.push(result);
319
+ } else if (Array.isArray(plugin.pod)) {
320
+ pods.push(...plugin.pod);
321
+ } else {
322
+ pods.push(plugin.pod);
323
+ }
324
+ }
325
+ return pods;
326
+ }
327
+ async function resolvePod(pod, userConfig, rootConfig) {
328
+ const mount = normalizeMountPath(userConfig.mount ?? pod.mount ?? "/");
329
+ const priority = userConfig.priority ?? pod.priority ?? 0;
330
+ const routeFiles = pod.routesDir ? await scanRouteFiles(pod.routesDir, mount, userConfig, rootConfig) : [];
331
+ const bundleFiles = pod.bundlesDir ? await scanBundleFiles(pod.bundlesDir) : [];
332
+ const collectionFiles = pod.collectionsDir ? await scanCollectionFiles(pod.collectionsDir, userConfig) : [];
333
+ const translationFiles = pod.translationsDir ? await scanTranslationFiles(pod.translationsDir) : [];
334
+ return {
335
+ name: pod.name,
336
+ enabled: true,
337
+ mount,
338
+ priority,
339
+ routesDir: pod.routesDir,
340
+ elementsDirs: pod.elementsDirs || [],
341
+ bundlesDir: pod.bundlesDir,
342
+ collectionsDir: pod.collectionsDir,
343
+ translationsDir: pod.translationsDir,
344
+ routeFiles,
345
+ bundleFiles,
346
+ collectionFiles,
347
+ translationFiles,
348
+ config: userConfig
349
+ };
350
+ }
351
+ async function scanRouteFiles(routesDir, mount, userConfig, rootConfig) {
352
+ if (!await isDirectory(routesDir)) {
353
+ return [];
354
+ }
355
+ const files = await glob2("**/*", { cwd: routesDir });
356
+ const routes = [];
357
+ const excludePatterns = userConfig.routes?.exclude || [];
358
+ for (const file of files) {
359
+ const parts = path4.parse(file);
360
+ if (parts.name.startsWith("_") || !isJsFile(parts.base)) {
361
+ continue;
362
+ }
363
+ if (shouldExclude(file, excludePatterns)) {
364
+ continue;
365
+ }
366
+ const filePath = path4.join(routesDir, file);
367
+ let relativeRoutePath = "/" + file.replace(/\\/g, "/");
368
+ const routeParts = path4.parse(relativeRoutePath);
369
+ if (routeParts.name === "index") {
370
+ relativeRoutePath = routeParts.dir;
371
+ } else {
372
+ relativeRoutePath = path4.join(routeParts.dir, routeParts.name);
373
+ }
374
+ relativeRoutePath = relativeRoutePath.replace(/\\/g, "/");
375
+ const routePath = normalizeRoutePath(mount, relativeRoutePath, rootConfig);
376
+ routes.push({ filePath, relPath: file, routePath });
377
+ }
378
+ return routes;
379
+ }
380
+ async function scanBundleFiles(bundlesDir) {
381
+ if (!await isDirectory(bundlesDir)) {
382
+ return [];
383
+ }
384
+ const files = await glob2("*", { cwd: bundlesDir });
385
+ return files.filter((file) => isJsFile(path4.parse(file).base)).map((file) => path4.join(bundlesDir, file));
386
+ }
387
+ async function scanCollectionFiles(collectionsDir, userConfig) {
388
+ if (!await isDirectory(collectionsDir)) {
389
+ return [];
390
+ }
391
+ const files = await glob2("**/*.schema.ts", { cwd: collectionsDir });
392
+ const excludeIds = new Set(userConfig.collections?.exclude || []);
393
+ const renameMap = userConfig.collections?.rename || {};
394
+ const collections = [];
395
+ for (const file of files) {
396
+ const parts = path4.parse(file);
397
+ const rawId = parts.name.replace(".schema", "");
398
+ if (excludeIds.has(rawId)) {
399
+ continue;
400
+ }
401
+ const id = renameMap[rawId] || rawId;
402
+ collections.push({
403
+ filePath: path4.join(collectionsDir, file),
404
+ relPath: file,
405
+ id
406
+ });
407
+ }
408
+ return collections;
409
+ }
410
+ async function scanTranslationFiles(translationsDir) {
411
+ if (!await isDirectory(translationsDir)) {
412
+ return [];
413
+ }
414
+ const files = await glob2("*.json", { cwd: translationsDir });
415
+ return files.map((file) => ({
416
+ locale: path4.parse(file).name,
417
+ filePath: path4.join(translationsDir, file)
418
+ }));
419
+ }
420
+ function validateCollectionIds(pods, rootConfig) {
421
+ const seenIds = /* @__PURE__ */ new Map();
422
+ for (const pod of pods) {
423
+ for (const col of pod.collectionFiles) {
424
+ const existing = seenIds.get(col.id);
425
+ if (existing) {
426
+ throw new Error(
427
+ `Collection "${col.id}" is defined by both "${existing}" and "${pod.name}". Use rootConfig.pods['${pod.name}'].collections.rename to disambiguate.`
428
+ );
429
+ }
430
+ seenIds.set(col.id, pod.name);
431
+ }
432
+ }
433
+ }
434
+ function normalizeMountPath(mount) {
435
+ if (!mount.startsWith("/")) {
436
+ mount = "/" + mount;
437
+ }
438
+ if (mount.endsWith("/") && mount.length > 1) {
439
+ mount = mount.slice(0, -1);
440
+ }
441
+ return mount;
442
+ }
443
+ function normalizeRoutePath(mount, relativeRoutePath, rootConfig) {
444
+ const basePath = rootConfig.base || "/";
445
+ let fullPath;
446
+ if (mount === "/") {
447
+ fullPath = relativeRoutePath || "/";
448
+ } else {
449
+ fullPath = mount + (relativeRoutePath || "");
450
+ }
451
+ if (basePath !== "/") {
452
+ const base = basePath.replace(/^\/|\/$/g, "");
453
+ fullPath = `/${base}${fullPath}`;
454
+ }
455
+ fullPath = fullPath.replace(/\/+/g, "/");
456
+ if (!fullPath.startsWith("/")) {
457
+ fullPath = "/" + fullPath;
458
+ }
459
+ return fullPath || "/";
460
+ }
461
+ function shouldExclude(filePath, patterns) {
462
+ for (const pattern of patterns) {
463
+ if (typeof pattern === "string") {
464
+ if (filePath.includes(pattern)) {
465
+ return true;
466
+ }
467
+ } else {
468
+ if (pattern.test(filePath)) {
469
+ return true;
470
+ }
471
+ }
472
+ }
473
+ return false;
474
+ }
475
+
476
+ // src/node/vite.ts
477
+ import { createServer } from "vite";
478
+
479
+ // src/node/pods-vite-plugin.ts
480
+ import path5 from "path";
481
+ import glob3 from "tiny-glob";
482
+ var VIRTUAL_ROUTES_ID = "virtual:root/routes";
483
+ var VIRTUAL_SCHEMAS_ID = "virtual:root/schemas";
484
+ var VIRTUAL_TRANSLATIONS_ID = "virtual:root/translations";
485
+ var RESOLVED_VIRTUAL_ROUTES = "\0" + VIRTUAL_ROUTES_ID;
486
+ var RESOLVED_VIRTUAL_SCHEMAS = "\0" + VIRTUAL_SCHEMAS_ID;
487
+ var RESOLVED_VIRTUAL_TRANSLATIONS = "\0" + VIRTUAL_TRANSLATIONS_ID;
488
+ function rootPodsVitePlugin(rootConfig) {
489
+ let podsPromise = null;
490
+ const getPods = () => {
491
+ if (!podsPromise) {
492
+ podsPromise = collectPods(rootConfig);
493
+ }
494
+ return podsPromise;
495
+ };
496
+ return {
497
+ name: "root:pods",
498
+ enforce: "pre",
499
+ resolveId(id) {
500
+ if (id === VIRTUAL_ROUTES_ID) return RESOLVED_VIRTUAL_ROUTES;
501
+ if (id === VIRTUAL_SCHEMAS_ID) return RESOLVED_VIRTUAL_SCHEMAS;
502
+ if (id === VIRTUAL_TRANSLATIONS_ID) return RESOLVED_VIRTUAL_TRANSLATIONS;
503
+ return null;
504
+ },
505
+ async load(id) {
506
+ if (id === RESOLVED_VIRTUAL_ROUTES) {
507
+ return buildRoutesModule(rootConfig, await getPods());
508
+ }
509
+ if (id === RESOLVED_VIRTUAL_SCHEMAS) {
510
+ return buildSchemasModule(rootConfig, await getPods());
511
+ }
512
+ if (id === RESOLVED_VIRTUAL_TRANSLATIONS) {
513
+ return buildTranslationsModule(rootConfig, await getPods());
514
+ }
515
+ return null;
516
+ },
517
+ configureServer(server) {
518
+ const watchDirs = [];
519
+ getPods().then((pods) => {
520
+ for (const pod of pods) {
521
+ if (pod.routesDir) watchDirs.push(pod.routesDir);
522
+ if (pod.collectionsDir) watchDirs.push(pod.collectionsDir);
523
+ if (pod.translationsDir) watchDirs.push(pod.translationsDir);
524
+ if (pod.bundlesDir) watchDirs.push(pod.bundlesDir);
525
+ for (const dir of pod.elementsDirs) {
526
+ watchDirs.push(dir);
527
+ }
528
+ }
529
+ for (const dir of watchDirs) {
530
+ server.watcher.add(dir);
531
+ }
532
+ });
533
+ const invalidateVirtualModules = () => {
534
+ invalidatePodCache();
535
+ podsPromise = null;
536
+ const mods = [
537
+ RESOLVED_VIRTUAL_ROUTES,
538
+ RESOLVED_VIRTUAL_SCHEMAS,
539
+ RESOLVED_VIRTUAL_TRANSLATIONS
540
+ ];
541
+ for (const modId of mods) {
542
+ const mod = server.moduleGraph.getModuleById(modId);
543
+ if (mod) {
544
+ server.moduleGraph.invalidateModule(mod);
545
+ }
546
+ }
547
+ server.ws.send({ type: "full-reload" });
548
+ };
549
+ server.watcher.on("add", (filePath) => {
550
+ if (isInPodDir(filePath, watchDirs)) {
551
+ invalidateVirtualModules();
552
+ }
553
+ });
554
+ server.watcher.on("unlink", (filePath) => {
555
+ if (isInPodDir(filePath, watchDirs)) {
556
+ invalidateVirtualModules();
557
+ }
558
+ });
559
+ }
560
+ };
561
+ }
562
+ function isInPodDir(filePath, watchDirs) {
563
+ for (const dir of watchDirs) {
564
+ if (filePath.startsWith(dir)) {
565
+ return true;
566
+ }
567
+ }
568
+ return false;
569
+ }
570
+ async function buildRoutesModule(rootConfig, pods) {
571
+ const rootDir = rootConfig.rootDir;
572
+ const imports = [];
573
+ const userEntries = [];
574
+ const podEntries = [];
575
+ let idx = 0;
576
+ const routesDir = path5.join(rootDir, "routes");
577
+ if (await isDirectory(routesDir)) {
578
+ const files = await glob3("**/*", { cwd: routesDir });
579
+ for (const file of files) {
580
+ const parts = path5.parse(file);
581
+ if (parts.name.startsWith("_") || !isJsFile(parts.base)) {
582
+ continue;
583
+ }
584
+ const modulePath = `/routes/${file.replace(/\\/g, "/")}`;
585
+ const varName = `_r${idx++}`;
586
+ imports.push(`import * as ${varName} from '${modulePath}';`);
587
+ userEntries.push(` '${modulePath}': ${varName},`);
588
+ }
589
+ }
590
+ for (const pod of pods) {
591
+ for (const route of pod.routeFiles) {
592
+ const varName = `_r${idx++}`;
593
+ imports.push(`import * as ${varName} from '${route.filePath}';`);
594
+ podEntries.push(
595
+ ` '${route.filePath}': {module: ${varName}, podName: ${JSON.stringify(pod.name)}, routePath: ${JSON.stringify(route.routePath)}, src: ${JSON.stringify(`pod/${pod.name}/${route.relPath}`)}},`
596
+ );
597
+ }
598
+ }
599
+ return [
600
+ ...imports,
601
+ "",
602
+ "export const ROUTE_MODULES = {",
603
+ ...userEntries,
604
+ "};",
605
+ "",
606
+ "export const POD_ROUTE_MODULES = {",
607
+ ...podEntries,
608
+ "};"
609
+ ].join("\n");
610
+ }
611
+ async function buildSchemasModule(rootConfig, pods) {
612
+ const rootDir = rootConfig.rootDir;
613
+ const imports = [];
614
+ const entries = [];
615
+ let idx = 0;
616
+ const userCollectionIds = /* @__PURE__ */ new Set();
617
+ const collectionsDir = path5.join(rootDir, "collections");
618
+ if (await isDirectory(collectionsDir)) {
619
+ const files = await glob3("**/*.schema.ts", { cwd: collectionsDir });
620
+ for (const file of files) {
621
+ const parts = path5.parse(file);
622
+ const id = parts.name.replace(".schema", "");
623
+ userCollectionIds.add(id);
624
+ const modulePath = `/collections/${file.replace(/\\/g, "/")}`;
625
+ const varName = `_s${idx++}`;
626
+ imports.push(`import * as ${varName} from '${modulePath}';`);
627
+ entries.push(` '${modulePath}': ${varName},`);
628
+ }
629
+ }
630
+ const rootSchemaFiles = await scanRootSchemaFiles(rootDir);
631
+ for (const file of rootSchemaFiles) {
632
+ const modulePath = `/${file.replace(/\\/g, "/")}`;
633
+ if (modulePath.startsWith("/collections/")) continue;
634
+ const varName = `_s${idx++}`;
635
+ imports.push(`import * as ${varName} from '${modulePath}';`);
636
+ entries.push(` '${modulePath}': ${varName},`);
637
+ }
638
+ for (const pod of pods) {
639
+ for (const col of pod.collectionFiles) {
640
+ if (userCollectionIds.has(col.id)) {
641
+ continue;
642
+ }
643
+ const varName = `_s${idx++}`;
644
+ imports.push(`import * as ${varName} from '${col.filePath}';`);
645
+ const key = `/collections/${col.id}.schema.ts`;
646
+ entries.push(` '${key}': ${varName},`);
647
+ }
648
+ }
649
+ return [
650
+ ...imports,
651
+ "",
652
+ "export const SCHEMA_MODULES = {",
653
+ ...entries,
654
+ "};"
655
+ ].join("\n");
656
+ }
657
+ async function scanRootSchemaFiles(rootDir) {
658
+ const excludeDirs = ["appengine", "functions", "gae", "node_modules", "dist"];
659
+ let files;
660
+ try {
661
+ files = await glob3("**/*.schema.ts", { cwd: rootDir });
662
+ } catch {
663
+ return [];
664
+ }
665
+ return files.filter((file) => {
666
+ const normalized = file.replace(/\\/g, "/");
667
+ return !excludeDirs.some((dir) => normalized.startsWith(dir + "/"));
668
+ });
669
+ }
670
+ async function buildTranslationsModule(rootConfig, pods) {
671
+ const rootDir = rootConfig.rootDir;
672
+ const imports = [];
673
+ const entries = [];
674
+ let idx = 0;
675
+ const userLocales = /* @__PURE__ */ new Set();
676
+ const translationsDir = path5.join(rootDir, "translations");
677
+ if (await isDirectory(translationsDir)) {
678
+ const files = await glob3("*.json", { cwd: translationsDir });
679
+ for (const file of files) {
680
+ const locale = path5.parse(file).name;
681
+ userLocales.add(locale);
682
+ const modulePath = `/translations/${file}`;
683
+ const varName = `_t${idx++}`;
684
+ imports.push(`import ${varName} from '${modulePath}';`);
685
+ entries.push(` '${modulePath}': {default: ${varName}},`);
686
+ }
687
+ }
688
+ for (const pod of pods) {
689
+ for (const t of pod.translationFiles) {
690
+ const varName = `_t${idx++}`;
691
+ imports.push(`import ${varName} from '${t.filePath}';`);
692
+ const key = `/translations/pod:${pod.name}:${t.locale}.json`;
693
+ entries.push(` '${key}': {default: ${varName}},`);
694
+ }
695
+ }
696
+ return [
697
+ ...imports,
698
+ "",
699
+ "export const TRANSLATION_MODULES = {",
700
+ ...entries,
701
+ "};"
702
+ ].join("\n");
703
+ }
704
+
705
+ // src/node/vite-plugin-root-jsx-virtual.ts
706
+ function preactToRootJsxPlugin(options) {
707
+ const useRootJsx = options?.useRootJsx ?? false;
708
+ const SSR_REDIRECTS = {
709
+ preact: "@blinkk/root/jsx",
710
+ "preact/hooks": "@blinkk/root/jsx",
711
+ "preact/jsx-runtime": "@blinkk/root/jsx/jsx-runtime",
712
+ "preact/jsx-dev-runtime": "@blinkk/root/jsx/jsx-dev-runtime"
713
+ };
714
+ return {
715
+ name: "root:preact-to-jsx",
716
+ async resolveId(id, importer, resolveOptions) {
717
+ if (!useRootJsx) {
718
+ return null;
719
+ }
720
+ const ssrTarget = SSR_REDIRECTS[id];
721
+ if (!ssrTarget) {
722
+ return null;
723
+ }
724
+ const isSSR = this.environment?.name === "ssr";
725
+ if (!isSSR) {
726
+ return null;
727
+ }
728
+ const resolved = await this.resolve(ssrTarget, importer, {
729
+ ...resolveOptions,
730
+ skipSelf: true
731
+ });
732
+ return resolved;
733
+ }
734
+ };
735
+ }
736
+
737
+ // src/node/vite.ts
738
+ async function createViteServer(rootConfig, options) {
739
+ const rootDir = rootConfig.rootDir;
740
+ const viteConfig = rootConfig.vite || {};
741
+ let hmrOptions = viteConfig.server?.hmr;
742
+ if (options?.hmr === false) {
743
+ hmrOptions = false;
744
+ } else if (typeof hmrOptions === "undefined" && options?.port) {
745
+ hmrOptions = { port: options.port + 10 };
746
+ }
747
+ const viteServer = await createServer({
748
+ ...viteConfig,
749
+ mode: "development",
750
+ root: rootDir,
751
+ // publicDir is disabled from the vite dev server since it's handled by the
752
+ // root dev server directly, which allows user middlewares to override
753
+ // files in the public dir.
754
+ publicDir: false,
755
+ server: {
756
+ ...viteConfig.server || {},
757
+ middlewareMode: true,
758
+ hmr: hmrOptions
759
+ },
760
+ appType: "custom",
761
+ optimizeDeps: {
762
+ ...viteConfig.optimizeDeps || {},
763
+ include: [
764
+ ...options?.optimizeDeps || [],
765
+ ...viteConfig.optimizeDeps?.include || []
766
+ ],
767
+ extensions: [...viteConfig.optimizeDeps?.extensions || [], ".tsx"]
768
+ },
769
+ ssr: {
770
+ ...viteConfig.ssr || {},
771
+ noExternal: ["@blinkk/root", "@blinkk/root-cms/richtext", /^virtual:/]
772
+ },
773
+ plugins: [
774
+ rootPodsVitePlugin(rootConfig),
775
+ hmrSSRReload(),
776
+ preactToRootJsxPlugin({ useRootJsx: !!rootConfig.jsxRenderer?.mode }),
777
+ ...viteConfig.plugins || [],
778
+ ...getVitePlugins(rootConfig.plugins || [])
779
+ ]
780
+ });
781
+ return viteServer;
782
+ }
783
+ async function viteSsrLoadModule(rootConfig, file) {
784
+ const viteServer = await createViteServer(rootConfig, { hmr: false });
785
+ const module = await viteServer.ssrLoadModule(file);
786
+ await viteServer.close();
787
+ return module;
788
+ }
789
+ function hmrSSRReload() {
790
+ return {
791
+ name: "hmr-ssr-reload",
792
+ enforce: "post",
793
+ hotUpdate: {
794
+ order: "post",
795
+ handler({ modules, server, timestamp }) {
796
+ if (this.environment.name !== "ssr") {
797
+ return;
798
+ }
799
+ let hasSsrOnlyModules = false;
800
+ const invalidatedModules = /* @__PURE__ */ new Set();
801
+ for (const mod of modules) {
802
+ if (mod.id === null) {
803
+ continue;
804
+ }
805
+ const clientModule = server.environments.client.moduleGraph.getModuleById(mod.id);
806
+ if (clientModule) {
807
+ continue;
808
+ }
809
+ hasSsrOnlyModules = true;
810
+ this.environment.moduleGraph.invalidateModule(
811
+ mod,
812
+ invalidatedModules,
813
+ timestamp,
814
+ true
815
+ );
816
+ }
817
+ if (hasSsrOnlyModules) {
818
+ server.ws.send({ type: "full-reload" });
819
+ return [];
820
+ }
821
+ return;
822
+ }
823
+ }
824
+ };
825
+ }
826
+
827
+ export {
828
+ isJsFile,
829
+ writeFile,
830
+ makeDir,
831
+ copyDir,
832
+ copyGlob,
833
+ rmDir,
834
+ loadJson,
835
+ writeJson,
836
+ isDirectory,
837
+ fileExists,
838
+ dirExists,
839
+ directoryContains,
840
+ loadPackageJson,
841
+ getMonorepoPackageDeps,
842
+ flattenPackageDepsFromMonorepo,
843
+ loadRootConfig,
844
+ loadRootConfigWithDeps,
845
+ bundleRootConfig,
846
+ loadBundledConfig,
847
+ invalidatePodCache,
848
+ collectPods,
849
+ rootPodsVitePlugin,
850
+ preactToRootJsxPlugin,
851
+ createViteServer,
852
+ viteSsrLoadModule
853
+ };
854
+ //# sourceMappingURL=chunk-PVBPP5LN.js.map