@jay-framework/production-server 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +10 -3
- package/dist/index.js +107 -15
- package/dist/{init-services-BVEuyIVG.js → init-services-Dy2SiHzw.js} +4 -2
- package/dist/{serve-index-Ccw8CNDg.d.ts → serve-index-cRXZm8vQ.d.ts} +4 -0
- package/dist/serve-index.d.ts +1 -1
- package/dist/serve-index.js +1 -1
- package/package.json +12 -12
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { B as BuildOptions, R as RouteManifest, a as RouteEntry } from './serve-index-
|
|
2
|
-
export { A as ActionEntry, b as ArtifactStore, c as BuildMetadata, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, P as PageModule, d as PluginEntry, e as PreImportedPlugin, f as RouteSegment, S as ServerElementModule, g as fetchActionRequest, h as fetchPageRequest, i as fetchStaticFile, j as initializeServices, k as initializeServicesFromModules, l as isActionRequest, m as matchRequest, r as registerActionsFromManifest, n as registerActionsFromModules } from './serve-index-
|
|
1
|
+
import { B as BuildOptions, R as RouteManifest, a as RouteEntry } from './serve-index-cRXZm8vQ.js';
|
|
2
|
+
export { A as ActionEntry, b as ArtifactStore, c as BuildMetadata, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, P as PageModule, d as PluginEntry, e as PreImportedPlugin, f as RouteSegment, S as ServerElementModule, g as fetchActionRequest, h as fetchPageRequest, i as fetchStaticFile, j as initializeServices, k as initializeServicesFromModules, l as isActionRequest, m as matchRequest, r as registerActionsFromManifest, n as registerActionsFromModules } from './serve-index-cRXZm8vQ.js';
|
|
3
3
|
import '@jay-framework/ssr-runtime';
|
|
4
4
|
import '@jay-framework/compiler-shared';
|
|
5
5
|
import '@jay-framework/stack-server-runtime';
|
|
6
6
|
|
|
7
7
|
declare function buildVersion(options: BuildOptions): Promise<RouteManifest>;
|
|
8
8
|
|
|
9
|
+
declare function generateSitemap(manifest: RouteManifest, baseUrl: string, outputPath: string): Promise<number>;
|
|
10
|
+
|
|
9
11
|
interface MainServerOptions {
|
|
10
12
|
buildRoot: string;
|
|
11
13
|
version: string;
|
|
@@ -24,6 +26,8 @@ interface RendererServerOptions {
|
|
|
24
26
|
pagesRoot: string;
|
|
25
27
|
tsConfigFilePath?: string;
|
|
26
28
|
minify?: boolean;
|
|
29
|
+
/** Site base URL for sitemap regeneration on rebuild (e.g. "https://example.com"). */
|
|
30
|
+
siteBaseUrl?: string;
|
|
27
31
|
}
|
|
28
32
|
declare function startRendererServer(options: RendererServerOptions): Promise<void>;
|
|
29
33
|
|
|
@@ -47,6 +51,8 @@ interface RebuildOptions {
|
|
|
47
51
|
target: RebuildTarget;
|
|
48
52
|
tsConfigFilePath?: string;
|
|
49
53
|
minify?: boolean;
|
|
54
|
+
/** Site base URL for sitemap regeneration (e.g. "https://example.com"). */
|
|
55
|
+
siteBaseUrl?: string;
|
|
50
56
|
}
|
|
51
57
|
interface RebuildResult {
|
|
52
58
|
affected: number;
|
|
@@ -69,7 +75,8 @@ declare function rebuildContract(options: {
|
|
|
69
75
|
params?: Record<string, string>;
|
|
70
76
|
tsConfigFilePath?: string;
|
|
71
77
|
minify?: boolean;
|
|
78
|
+
siteBaseUrl?: string;
|
|
72
79
|
}): Promise<RebuildResult>;
|
|
73
80
|
declare function cleanupOrphanedFiles(buildRoot: string, version: string): Promise<number>;
|
|
74
81
|
|
|
75
|
-
export { BuildOptions, type RebuildOptions, type RebuildResult, type RebuildTarget, type RendererServerOptions, RouteEntry, RouteManifest, buildVersion, cleanupOrphanedFiles, rebuild, rebuildContract, resolveContractToRoutes, startMainServer, startRendererServer };
|
|
82
|
+
export { BuildOptions, type RebuildOptions, type RebuildResult, type RebuildTarget, type RendererServerOptions, RouteEntry, RouteManifest, buildVersion, cleanupOrphanedFiles, generateSitemap, rebuild, rebuildContract, resolveContractToRoutes, startMainServer, startRendererServer };
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ import path from "node:path";
|
|
|
6
6
|
import fs from "node:fs/promises";
|
|
7
7
|
import { createRequire } from "node:module";
|
|
8
8
|
import { DevSlowlyChangingPhase, slowRenderInstances, scanPlugins, runLoadParams, parseCookies } from "@jay-framework/stack-server-runtime";
|
|
9
|
-
import { l as loadProductionPageParts, g as buildPagePartsConfig, F as FilesystemArtifactStore, i as initializeServices, r as registerActionsFromManifest, d as isActionRequest, f as fetchActionRequest, b as fetchStaticFile, m as matchRequest, a as fetchPageRequest } from "./init-services-
|
|
10
|
-
import { c, e } from "./init-services-
|
|
9
|
+
import { l as loadProductionPageParts, g as buildPagePartsConfig, F as FilesystemArtifactStore, i as initializeServices, r as registerActionsFromManifest, d as isActionRequest, f as fetchActionRequest, b as fetchStaticFile, m as matchRequest, a as fetchPageRequest } from "./init-services-Dy2SiHzw.js";
|
|
10
|
+
import { c, e } from "./init-services-Dy2SiHzw.js";
|
|
11
11
|
import crypto, { createHash } from "node:crypto";
|
|
12
12
|
import fs$1 from "node:fs";
|
|
13
13
|
import { jayRuntime } from "@jay-framework/vite-plugin";
|
|
@@ -18,6 +18,27 @@ import { transform } from "esbuild";
|
|
|
18
18
|
import http from "node:http";
|
|
19
19
|
import { Readable } from "node:stream";
|
|
20
20
|
import { isJayWebhook } from "@jay-framework/fullstack-component";
|
|
21
|
+
function isCompilableTypeScriptFile(fileName) {
|
|
22
|
+
return fileName.endsWith(".ts") && !fileName.endsWith(".d.ts") && fileName !== "page.ts";
|
|
23
|
+
}
|
|
24
|
+
async function collectTypeScriptEntries(rootDir, entryPrefix, pages) {
|
|
25
|
+
async function walk(currentDir, relativePath) {
|
|
26
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
29
|
+
if (entry.isDirectory()) {
|
|
30
|
+
const nextRelative = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
31
|
+
await walk(fullPath, nextRelative);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (!isCompilableTypeScriptFile(entry.name)) continue;
|
|
35
|
+
const stem = entry.name.replace(/\.ts$/, "");
|
|
36
|
+
const entryName = relativePath ? `${entryPrefix}/${relativePath}/${stem}` : `${entryPrefix}/${stem}`;
|
|
37
|
+
pages[entryName] = fullPath;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
await walk(rootDir, "");
|
|
41
|
+
}
|
|
21
42
|
async function discoverServerEntries(projectRoot, pagesRoot) {
|
|
22
43
|
const logger = getLogger();
|
|
23
44
|
const routes = await scanRoutes(pagesRoot, {
|
|
@@ -47,17 +68,16 @@ async function discoverServerEntries(projectRoot, pagesRoot) {
|
|
|
47
68
|
for (const subDir of ["plugins", "components"]) {
|
|
48
69
|
const scanDir = path.join(projectRoot, "src", subDir);
|
|
49
70
|
try {
|
|
50
|
-
const
|
|
51
|
-
for (const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (file.endsWith(".ts") && !file.endsWith(".d.ts") && file !== "page.ts") {
|
|
57
|
-
const entryName = `${subDir}/${dir.name}/${file.replace(/\.ts$/, "")}`;
|
|
58
|
-
pages[entryName] = path.join(dirPath, file);
|
|
59
|
-
}
|
|
71
|
+
const entries2 = await fs.readdir(scanDir, { withFileTypes: true });
|
|
72
|
+
for (const entry of entries2) {
|
|
73
|
+
const entryPath = path.join(scanDir, entry.name);
|
|
74
|
+
if (entry.isDirectory()) {
|
|
75
|
+
await collectTypeScriptEntries(entryPath, `${subDir}/${entry.name}`, pages);
|
|
76
|
+
continue;
|
|
60
77
|
}
|
|
78
|
+
if (!isCompilableTypeScriptFile(entry.name)) continue;
|
|
79
|
+
const stem = entry.name.replace(/\.ts$/, "");
|
|
80
|
+
pages[`${subDir}/${stem}`] = entryPath;
|
|
61
81
|
}
|
|
62
82
|
} catch {
|
|
63
83
|
}
|
|
@@ -425,6 +445,47 @@ async function writeRouteManifest(manifest, buildDir) {
|
|
|
425
445
|
`[Build] Route manifest written: ${manifest.routes.length} routes, ${manifest.routes.reduce((n, r) => n + r.instances.length, 0)} instances`
|
|
426
446
|
);
|
|
427
447
|
}
|
|
448
|
+
async function generateSitemap(manifest, baseUrl, outputPath) {
|
|
449
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
450
|
+
const urls = [];
|
|
451
|
+
for (const route of manifest.routes) {
|
|
452
|
+
if (route.devOnly) continue;
|
|
453
|
+
if (route.noIndex) continue;
|
|
454
|
+
if (route.instances.length === 0) {
|
|
455
|
+
const hasDynamic = route.segments.some((s) => s.type !== "static");
|
|
456
|
+
if (!hasDynamic) {
|
|
457
|
+
const urlPath = route.pattern === "/" ? "/" : route.pattern;
|
|
458
|
+
urls.push(`${base}${urlPath}`);
|
|
459
|
+
}
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
for (const instance of route.instances) {
|
|
463
|
+
const urlPath = buildUrlFromManifest(route.pattern, instance.params);
|
|
464
|
+
urls.push(`${base}${urlPath}`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
const tmpPath = outputPath + ".tmp";
|
|
468
|
+
const handle = await fs.open(tmpPath, "w");
|
|
469
|
+
try {
|
|
470
|
+
await handle.write('<?xml version="1.0" encoding="UTF-8"?>\n');
|
|
471
|
+
await handle.write('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n');
|
|
472
|
+
for (const url of urls) {
|
|
473
|
+
await handle.write(` <url><loc>${escapeXml(url)}</loc></url>
|
|
474
|
+
`);
|
|
475
|
+
}
|
|
476
|
+
await handle.write("</urlset>\n");
|
|
477
|
+
} finally {
|
|
478
|
+
await handle.close();
|
|
479
|
+
}
|
|
480
|
+
await fs.rename(tmpPath, outputPath);
|
|
481
|
+
return urls.length;
|
|
482
|
+
}
|
|
483
|
+
function buildUrlFromManifest(pattern, params) {
|
|
484
|
+
return pattern.replace(/\[\[(\w+)\]\]/g, (_, name) => params[name] || "").replace(/\[\.\.\.(\w+)\]/g, (_, name) => params[name] || "").replace(/\[(\w+)\]/g, (_, name) => params[name] || "").replace(/\/\/+/g, "/").replace(/\/$/, "") || "/";
|
|
485
|
+
}
|
|
486
|
+
function escapeXml(str) {
|
|
487
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
488
|
+
}
|
|
428
489
|
createRequire(import.meta.url);
|
|
429
490
|
async function scanPluginRoutes(projectRoot, projectRoutes) {
|
|
430
491
|
const logger = getLogger();
|
|
@@ -973,7 +1034,19 @@ async function buildVersion(options) {
|
|
|
973
1034
|
);
|
|
974
1035
|
for (const pluginInit of pluginsWithInit) {
|
|
975
1036
|
try {
|
|
976
|
-
|
|
1037
|
+
let modulePath;
|
|
1038
|
+
if (pluginInit.isLocal) {
|
|
1039
|
+
const pluginDirName = path.basename(pluginInit.pluginPath);
|
|
1040
|
+
modulePath = path.join(
|
|
1041
|
+
serverOutputDir,
|
|
1042
|
+
"plugins",
|
|
1043
|
+
pluginDirName,
|
|
1044
|
+
`${pluginInit.initModule}.js`
|
|
1045
|
+
);
|
|
1046
|
+
} else {
|
|
1047
|
+
modulePath = pluginInit.packageName;
|
|
1048
|
+
}
|
|
1049
|
+
const pluginModule = await import(modulePath);
|
|
977
1050
|
const init = pluginModule.init || pluginModule[pluginInit.initExport || "init"];
|
|
978
1051
|
if (init?._serverInit) {
|
|
979
1052
|
logger.info(`[Build] Running plugin init: ${pluginInit.name}`);
|
|
@@ -1173,6 +1246,12 @@ async function buildVersion(options) {
|
|
|
1173
1246
|
}
|
|
1174
1247
|
if (seResult.headMeta) {
|
|
1175
1248
|
entry.headMeta = seResult.headMeta;
|
|
1249
|
+
const robotsMeta = seResult.headMeta.meta?.find(
|
|
1250
|
+
(m) => m.name === "robots" && m.content?.some((p) => p.kind === "static" && p.value.includes("noindex"))
|
|
1251
|
+
);
|
|
1252
|
+
if (robotsMeta) {
|
|
1253
|
+
entry.noIndex = true;
|
|
1254
|
+
}
|
|
1176
1255
|
}
|
|
1177
1256
|
logger.important(`[Build] Route server element: ${routeDir}`);
|
|
1178
1257
|
} catch (err) {
|
|
@@ -1308,6 +1387,11 @@ async function buildVersion(options) {
|
|
|
1308
1387
|
logger.info("[Build] Copied public/ contents to frontend/");
|
|
1309
1388
|
} catch {
|
|
1310
1389
|
}
|
|
1390
|
+
if (options.siteBaseUrl) {
|
|
1391
|
+
const sitemapPath = path.join(frontendDir, "sitemap.xml");
|
|
1392
|
+
const urlCount = await generateSitemap(manifest, options.siteBaseUrl, sitemapPath);
|
|
1393
|
+
logger.important(`[Build] Sitemap generated: ${urlCount} URLs`);
|
|
1394
|
+
}
|
|
1311
1395
|
const sourceHash = await computeBuildHash(buildDir);
|
|
1312
1396
|
const metadata = {
|
|
1313
1397
|
version: options.version,
|
|
@@ -1657,6 +1741,11 @@ async function rebuild(options) {
|
|
|
1657
1741
|
);
|
|
1658
1742
|
}
|
|
1659
1743
|
logger.important(`[Rebuild] Manifest and metadata updated`);
|
|
1744
|
+
if (options.siteBaseUrl) {
|
|
1745
|
+
const sitemapPath = path.join(frontendDir, "sitemap.xml");
|
|
1746
|
+
const urlCount = await generateSitemap(manifest, options.siteBaseUrl, sitemapPath);
|
|
1747
|
+
logger.info(`[Rebuild] Sitemap regenerated: ${urlCount} URLs`);
|
|
1748
|
+
}
|
|
1660
1749
|
if (orphanedFiles.length > 0) {
|
|
1661
1750
|
await appendCleanupManifest(buildDir, orphanedFiles);
|
|
1662
1751
|
logger.info(`[Rebuild] ${orphanedFiles.length} orphaned file(s) queued for cleanup`);
|
|
@@ -1805,7 +1894,8 @@ async function startRendererServer(options) {
|
|
|
1805
1894
|
contractName,
|
|
1806
1895
|
params,
|
|
1807
1896
|
tsConfigFilePath: options.tsConfigFilePath,
|
|
1808
|
-
minify: options.minify
|
|
1897
|
+
minify: options.minify,
|
|
1898
|
+
siteBaseUrl: options.siteBaseUrl
|
|
1809
1899
|
});
|
|
1810
1900
|
};
|
|
1811
1901
|
};
|
|
@@ -1864,7 +1954,8 @@ async function startRendererServer(options) {
|
|
|
1864
1954
|
version: options.version,
|
|
1865
1955
|
target,
|
|
1866
1956
|
tsConfigFilePath: options.tsConfigFilePath,
|
|
1867
|
-
minify: options.minify
|
|
1957
|
+
minify: options.minify,
|
|
1958
|
+
siteBaseUrl: options.siteBaseUrl
|
|
1868
1959
|
});
|
|
1869
1960
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1870
1961
|
res.end(JSON.stringify(result));
|
|
@@ -1920,6 +2011,7 @@ export {
|
|
|
1920
2011
|
fetchActionRequest,
|
|
1921
2012
|
fetchPageRequest,
|
|
1922
2013
|
fetchStaticFile,
|
|
2014
|
+
generateSitemap,
|
|
1923
2015
|
initializeServices,
|
|
1924
2016
|
c as initializeServicesFromModules,
|
|
1925
2017
|
isActionRequest,
|
|
@@ -710,7 +710,9 @@ const MIME_TYPES = {
|
|
|
710
710
|
".woff2": "font/woff2",
|
|
711
711
|
".woff": "font/woff",
|
|
712
712
|
".ttf": "font/ttf",
|
|
713
|
-
".webp": "image/webp"
|
|
713
|
+
".webp": "image/webp",
|
|
714
|
+
".xml": "application/xml",
|
|
715
|
+
".txt": "text/plain"
|
|
714
716
|
};
|
|
715
717
|
async function fetchStaticFile(pathname, frontendDir) {
|
|
716
718
|
const normalizedBase = path.resolve(frontendDir);
|
|
@@ -723,7 +725,7 @@ async function fetchStaticFile(pathname, frontendDir) {
|
|
|
723
725
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
724
726
|
const isHashed = /[-][a-zA-Z0-9_-]{6,}\./.test(path.basename(candidate));
|
|
725
727
|
const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "public, max-age=3600";
|
|
726
|
-
return new Response(content, {
|
|
728
|
+
return new Response(new Uint8Array(content), {
|
|
727
729
|
headers: {
|
|
728
730
|
"Content-Type": contentType,
|
|
729
731
|
"Content-Length": String(content.length),
|
|
@@ -33,6 +33,8 @@ interface RouteEntry {
|
|
|
33
33
|
cssImports?: string[];
|
|
34
34
|
/** Head metadata from jay-html <head> (title, meta tags). */
|
|
35
35
|
headMeta?: JayHtmlHeadMeta;
|
|
36
|
+
/** True when page has static <meta name="robots" content="noindex"> */
|
|
37
|
+
noIndex?: boolean;
|
|
36
38
|
instances: InstanceEntry[];
|
|
37
39
|
isPlugin?: boolean;
|
|
38
40
|
pluginName?: string;
|
|
@@ -75,6 +77,8 @@ interface BuildOptions {
|
|
|
75
77
|
concurrency: number;
|
|
76
78
|
tsConfigFilePath: string;
|
|
77
79
|
minify?: boolean;
|
|
80
|
+
/** Site base URL for sitemap generation (e.g. "https://example.com"). */
|
|
81
|
+
siteBaseUrl?: string;
|
|
78
82
|
}
|
|
79
83
|
interface ServerElementModule {
|
|
80
84
|
renderToStream: (vs: object, ctx: _jay_framework_ssr_runtime.ServerRenderContext) => void;
|
package/dist/serve-index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { b as ArtifactStore, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, e as PreImportedPlugin, a as RouteEntry, R as RouteManifest, S as ServerElementModule, g as fetchActionRequest, h as fetchPageRequest, i as fetchStaticFile, j as initializeServices, k as initializeServicesFromModules, l as isActionRequest, m as matchRequest, r as registerActionsFromManifest, n as registerActionsFromModules } from './serve-index-
|
|
1
|
+
export { b as ArtifactStore, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, e as PreImportedPlugin, a as RouteEntry, R as RouteManifest, S as ServerElementModule, g as fetchActionRequest, h as fetchPageRequest, i as fetchStaticFile, j as initializeServices, k as initializeServicesFromModules, l as isActionRequest, m as matchRequest, r as registerActionsFromManifest, n as registerActionsFromModules } from './serve-index-cRXZm8vQ.js';
|
|
2
2
|
import '@jay-framework/ssr-runtime';
|
|
3
3
|
import '@jay-framework/compiler-shared';
|
|
4
4
|
import '@jay-framework/stack-server-runtime';
|
package/dist/serve-index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/production-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,20 +30,20 @@
|
|
|
30
30
|
"test:watch": "vitest"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@jay-framework/compiler-jay-html": "^0.
|
|
34
|
-
"@jay-framework/compiler-jay-stack": "^0.
|
|
35
|
-
"@jay-framework/compiler-shared": "^0.
|
|
36
|
-
"@jay-framework/fullstack-component": "^0.
|
|
37
|
-
"@jay-framework/logger": "^0.
|
|
38
|
-
"@jay-framework/ssr-runtime": "^0.
|
|
39
|
-
"@jay-framework/stack-route-scanner": "^0.
|
|
40
|
-
"@jay-framework/stack-server-runtime": "^0.
|
|
41
|
-
"@jay-framework/view-state-merge": "^0.
|
|
42
|
-
"@jay-framework/vite-plugin": "^0.
|
|
33
|
+
"@jay-framework/compiler-jay-html": "^0.24.0",
|
|
34
|
+
"@jay-framework/compiler-jay-stack": "^0.24.0",
|
|
35
|
+
"@jay-framework/compiler-shared": "^0.24.0",
|
|
36
|
+
"@jay-framework/fullstack-component": "^0.24.0",
|
|
37
|
+
"@jay-framework/logger": "^0.24.0",
|
|
38
|
+
"@jay-framework/ssr-runtime": "^0.24.0",
|
|
39
|
+
"@jay-framework/stack-route-scanner": "^0.24.0",
|
|
40
|
+
"@jay-framework/stack-server-runtime": "^0.24.0",
|
|
41
|
+
"@jay-framework/view-state-merge": "^0.24.0",
|
|
42
|
+
"@jay-framework/vite-plugin": "^0.24.0",
|
|
43
43
|
"vite": "^5.0.11"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@jay-framework/dev-environment": "^0.
|
|
46
|
+
"@jay-framework/dev-environment": "^0.24.0",
|
|
47
47
|
"@types/node": "^22.15.21",
|
|
48
48
|
"rimraf": "^5.0.5",
|
|
49
49
|
"tsup": "^8.0.1",
|