@jay-framework/compiler-jay-stack 0.10.0 → 0.12.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 +88 -1
- package/dist/index.js +166 -23
- package/package.json +7 -6
package/dist/index.d.ts
CHANGED
|
@@ -108,6 +108,93 @@ declare function transformActionImports(code: string, id: string, resolveActionM
|
|
|
108
108
|
code: string;
|
|
109
109
|
} | null>): Promise<TransformResult | null>;
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Plugin Client Import Resolver
|
|
113
|
+
*
|
|
114
|
+
* Transforms imports from Jay plugin packages to use their /client subpath
|
|
115
|
+
* when in client build mode.
|
|
116
|
+
*
|
|
117
|
+
* This handles transitive plugin dependencies: when wix-stores imports from
|
|
118
|
+
* wix-server-client, the import should be rewritten to wix-server-client/client
|
|
119
|
+
* in client builds.
|
|
120
|
+
*
|
|
121
|
+
* Uses a `transform` hook instead of `resolveId` to ensure the rewrite happens
|
|
122
|
+
* before rollup's `external` option is evaluated.
|
|
123
|
+
*
|
|
124
|
+
* Detection:
|
|
125
|
+
* 1. Check if the imported package has a plugin.yaml (is a Jay plugin)
|
|
126
|
+
* 2. Check if the package exports a /client subpath
|
|
127
|
+
* 3. If both true, rewrite the import to use /client
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Interface for detecting if a package is a Jay plugin with /client export.
|
|
132
|
+
* Extracted to allow mocking in tests.
|
|
133
|
+
*/
|
|
134
|
+
interface PluginDetector {
|
|
135
|
+
/**
|
|
136
|
+
* Checks if a package is a Jay plugin with a /client export.
|
|
137
|
+
* @param packageName - The package name (e.g., '@jay-framework/wix-stores')
|
|
138
|
+
* @param projectRoot - The project root for resolution
|
|
139
|
+
* @returns true if the package should be rewritten to /client
|
|
140
|
+
*/
|
|
141
|
+
isJayPluginWithClientExport(packageName: string, projectRoot: string): boolean;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Default implementation using Node's require.resolve.
|
|
145
|
+
*/
|
|
146
|
+
declare function createDefaultPluginDetector(): PluginDetector;
|
|
147
|
+
/**
|
|
148
|
+
* Extracts the package name from an import source.
|
|
149
|
+
* Handles scoped packages like @jay-framework/wix-stores.
|
|
150
|
+
*/
|
|
151
|
+
declare function extractPackageName(source: string): string | null;
|
|
152
|
+
/**
|
|
153
|
+
* Checks if the import is already using a subpath (not just the main entry).
|
|
154
|
+
*/
|
|
155
|
+
declare function isSubpathImport(source: string, packageName: string): boolean;
|
|
156
|
+
interface TransformImportsOptions {
|
|
157
|
+
/** The source code to transform */
|
|
158
|
+
code: string;
|
|
159
|
+
/** Project root for plugin detection */
|
|
160
|
+
projectRoot: string;
|
|
161
|
+
/** File path for logging */
|
|
162
|
+
filePath: string;
|
|
163
|
+
/** Plugin detector (injectable for testing) */
|
|
164
|
+
pluginDetector: PluginDetector;
|
|
165
|
+
/** Enable verbose logging */
|
|
166
|
+
verbose?: boolean;
|
|
167
|
+
}
|
|
168
|
+
interface TransformImportsResult {
|
|
169
|
+
/** The transformed code */
|
|
170
|
+
code: string;
|
|
171
|
+
/** Whether any changes were made */
|
|
172
|
+
hasChanges: boolean;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Transforms import/export declarations in source code.
|
|
176
|
+
* Rewrites plugin package imports to use /client subpath.
|
|
177
|
+
*
|
|
178
|
+
* This is a pure function - all IO is handled by the pluginDetector.
|
|
179
|
+
*/
|
|
180
|
+
declare function transformImports(options: TransformImportsOptions): TransformImportsResult;
|
|
181
|
+
interface PluginClientImportResolverOptions {
|
|
182
|
+
/** Project root directory for resolution */
|
|
183
|
+
projectRoot?: string;
|
|
184
|
+
/** Enable verbose logging */
|
|
185
|
+
verbose?: boolean;
|
|
186
|
+
/** Custom plugin detector (for testing) */
|
|
187
|
+
pluginDetector?: PluginDetector;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Creates a Vite plugin that transforms plugin package imports to /client
|
|
191
|
+
* in client builds.
|
|
192
|
+
*
|
|
193
|
+
* Uses the `transform` hook to rewrite import declarations before rollup's
|
|
194
|
+
* external option is evaluated.
|
|
195
|
+
*/
|
|
196
|
+
declare function createPluginClientImportResolver(options?: PluginClientImportResolverOptions): Plugin;
|
|
197
|
+
|
|
111
198
|
interface JayStackCompilerOptions extends JayRollupConfig {
|
|
112
199
|
/**
|
|
113
200
|
* Enable import chain tracking for debugging server code leaking into client builds.
|
|
@@ -156,4 +243,4 @@ interface JayStackCompilerOptions extends JayRollupConfig {
|
|
|
156
243
|
*/
|
|
157
244
|
declare function jayStackCompiler(options?: JayStackCompilerOptions): Plugin[];
|
|
158
245
|
|
|
159
|
-
export { type ActionMetadata, type BuildEnvironment, type ExtractedActions, type ImportChainTrackerOptions, type JayStackCompilerOptions, clearActionMetadataCache, createImportChainTracker, extractActionsFromSource, isActionImport, jayStackCompiler, transformActionImports, transformJayStackBuilder };
|
|
246
|
+
export { type ActionMetadata, type BuildEnvironment, type ExtractedActions, type ImportChainTrackerOptions, type JayStackCompilerOptions, type PluginClientImportResolverOptions, type PluginDetector, type TransformImportsOptions, type TransformImportsResult, clearActionMetadataCache, createDefaultPluginDetector, createImportChainTracker, createPluginClientImportResolver, extractActionsFromSource, extractPackageName, isActionImport, isSubpathImport, jayStackCompiler, transformActionImports, transformImports, transformJayStackBuilder };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jayRuntime } from "@jay-framework/vite-plugin";
|
|
2
2
|
import tsBridge from "@jay-framework/typescript-bridge";
|
|
3
3
|
import { flattenVariable, isImportModuleVariableRoot, mkTransformer, SourceFileBindingResolver, areFlattenedAccessChainsEqual } from "@jay-framework/compiler";
|
|
4
|
-
import
|
|
4
|
+
import { getLogger } from "@jay-framework/logger";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import * as fs from "node:fs";
|
|
6
8
|
const COMPONENT_SERVER_METHODS = /* @__PURE__ */ new Set([
|
|
7
9
|
"withServices",
|
|
8
10
|
"withLoadParams",
|
|
@@ -387,7 +389,7 @@ async function transformActionImports(code, id, resolveActionModule) {
|
|
|
387
389
|
for (const imp of actionImports) {
|
|
388
390
|
const resolved = await resolveActionModule(imp.source, id);
|
|
389
391
|
if (!resolved) {
|
|
390
|
-
|
|
392
|
+
getLogger().warn(`[action-transform] Could not resolve action module: ${imp.source}`);
|
|
391
393
|
continue;
|
|
392
394
|
}
|
|
393
395
|
const actions = extractActionsFromSource(resolved.code, resolved.path);
|
|
@@ -400,7 +402,7 @@ async function transformActionImports(code, id, resolveActionModule) {
|
|
|
400
402
|
);
|
|
401
403
|
needsCreateActionCallerImport = true;
|
|
402
404
|
} else {
|
|
403
|
-
|
|
405
|
+
getLogger().warn(
|
|
404
406
|
`[action-transform] Export '${importName}' from ${imp.source} is not a recognized action`
|
|
405
407
|
);
|
|
406
408
|
}
|
|
@@ -504,7 +506,7 @@ function createImportChainTracker(options = {}) {
|
|
|
504
506
|
importChain.clear();
|
|
505
507
|
detectedServerModules.clear();
|
|
506
508
|
if (verbose) {
|
|
507
|
-
|
|
509
|
+
getLogger().info("[import-chain-tracker] Build started, tracking imports...");
|
|
508
510
|
}
|
|
509
511
|
},
|
|
510
512
|
resolveId(source, importer, options2) {
|
|
@@ -516,7 +518,7 @@ function createImportChainTracker(options = {}) {
|
|
|
516
518
|
}
|
|
517
519
|
if (importer) {
|
|
518
520
|
if (verbose) {
|
|
519
|
-
|
|
521
|
+
getLogger().info(
|
|
520
522
|
`[import-chain-tracker] ${shortenPath(importer)} imports ${source}`
|
|
521
523
|
);
|
|
522
524
|
}
|
|
@@ -533,14 +535,14 @@ function createImportChainTracker(options = {}) {
|
|
|
533
535
|
if (isServerOnlyModule(id)) {
|
|
534
536
|
detectedServerModules.add(id);
|
|
535
537
|
const chain = buildImportChain(id);
|
|
536
|
-
|
|
538
|
+
getLogger().error(
|
|
537
539
|
`
|
|
538
540
|
[import-chain-tracker] ⚠️ Server-only module detected in client build!`
|
|
539
541
|
);
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
542
|
+
getLogger().error(`Module: ${shortenPath(id)}`);
|
|
543
|
+
getLogger().error(`Import chain:`);
|
|
544
|
+
getLogger().error(formatChain(chain));
|
|
545
|
+
getLogger().error("");
|
|
544
546
|
}
|
|
545
547
|
const importRegex = /import\s+(?:(?:\{[^}]*\}|[^{}\s,]+)\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
546
548
|
let match;
|
|
@@ -550,16 +552,18 @@ function createImportChainTracker(options = {}) {
|
|
|
550
552
|
if (isServerOnlyModule(importedModule)) {
|
|
551
553
|
if (!detectedServerModules.has(importedModule)) {
|
|
552
554
|
detectedServerModules.add(importedModule);
|
|
553
|
-
|
|
555
|
+
getLogger().error(
|
|
554
556
|
`
|
|
555
557
|
[import-chain-tracker] ⚠️ Server-only import detected in client build!`
|
|
556
558
|
);
|
|
557
|
-
|
|
559
|
+
getLogger().error(
|
|
560
|
+
`Module "${importedModule}" imported by: ${shortenPath(id)}`
|
|
561
|
+
);
|
|
558
562
|
const chain = buildImportChain(id);
|
|
559
563
|
chain.push(importedModule);
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
564
|
+
getLogger().error(`Import chain:`);
|
|
565
|
+
getLogger().error(formatChain(chain));
|
|
566
|
+
getLogger().error("");
|
|
563
567
|
}
|
|
564
568
|
}
|
|
565
569
|
}
|
|
@@ -567,27 +571,151 @@ function createImportChainTracker(options = {}) {
|
|
|
567
571
|
},
|
|
568
572
|
buildEnd() {
|
|
569
573
|
if (detectedServerModules.size > 0) {
|
|
570
|
-
|
|
574
|
+
getLogger().warn(
|
|
571
575
|
`
|
|
572
576
|
[import-chain-tracker] ⚠️ ${detectedServerModules.size} server-only module(s) detected during transform:`
|
|
573
577
|
);
|
|
574
578
|
for (const mod of detectedServerModules) {
|
|
575
|
-
|
|
579
|
+
getLogger().warn(` - ${mod}`);
|
|
576
580
|
}
|
|
577
|
-
|
|
581
|
+
getLogger().warn(
|
|
578
582
|
"\nNote: These may be stripped by the code-split transform if only used in .withServer()."
|
|
579
583
|
);
|
|
580
|
-
|
|
584
|
+
getLogger().warn(
|
|
581
585
|
'If build fails with "not exported" errors, check the import chains above.\n'
|
|
582
586
|
);
|
|
583
587
|
} else if (verbose) {
|
|
584
|
-
|
|
588
|
+
getLogger().info(
|
|
585
589
|
"[import-chain-tracker] ✅ No server-only modules detected in client build"
|
|
586
590
|
);
|
|
587
591
|
}
|
|
588
592
|
}
|
|
589
593
|
};
|
|
590
594
|
}
|
|
595
|
+
const require2 = createRequire(import.meta.url);
|
|
596
|
+
function createDefaultPluginDetector() {
|
|
597
|
+
const cache = /* @__PURE__ */ new Map();
|
|
598
|
+
return {
|
|
599
|
+
isJayPluginWithClientExport(packageName, projectRoot) {
|
|
600
|
+
const cacheKey = `${packageName}:${projectRoot}`;
|
|
601
|
+
if (cache.has(cacheKey)) {
|
|
602
|
+
return cache.get(cacheKey);
|
|
603
|
+
}
|
|
604
|
+
let result = false;
|
|
605
|
+
try {
|
|
606
|
+
require2.resolve(`${packageName}/plugin.yaml`, { paths: [projectRoot] });
|
|
607
|
+
try {
|
|
608
|
+
require2.resolve(`${packageName}/client`, { paths: [projectRoot] });
|
|
609
|
+
result = true;
|
|
610
|
+
} catch {
|
|
611
|
+
result = false;
|
|
612
|
+
}
|
|
613
|
+
} catch {
|
|
614
|
+
result = false;
|
|
615
|
+
}
|
|
616
|
+
cache.set(cacheKey, result);
|
|
617
|
+
return result;
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
function extractPackageName(source) {
|
|
622
|
+
if (source.startsWith(".") || source.startsWith("/")) {
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
if (source.startsWith("@")) {
|
|
626
|
+
const parts2 = source.split("/");
|
|
627
|
+
if (parts2.length >= 2) {
|
|
628
|
+
return `${parts2[0]}/${parts2[1]}`;
|
|
629
|
+
}
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
const parts = source.split("/");
|
|
633
|
+
return parts[0];
|
|
634
|
+
}
|
|
635
|
+
function isSubpathImport(source, packageName) {
|
|
636
|
+
return source.length > packageName.length && source[packageName.length] === "/";
|
|
637
|
+
}
|
|
638
|
+
const IMPORT_REGEX = /import\s+(.+?)\s+from\s+(['"])([^'"]+)\2/g;
|
|
639
|
+
const EXPORT_FROM_REGEX = /export\s+(.+?)\s+from\s+(['"])([^'"]+)\2/g;
|
|
640
|
+
function transformImports(options) {
|
|
641
|
+
const { code, projectRoot, filePath, pluginDetector, verbose = false } = options;
|
|
642
|
+
let hasChanges = false;
|
|
643
|
+
let result = code;
|
|
644
|
+
result = result.replace(IMPORT_REGEX, (match, clause, quote, source) => {
|
|
645
|
+
const packageName = extractPackageName(source);
|
|
646
|
+
if (!packageName)
|
|
647
|
+
return match;
|
|
648
|
+
if (isSubpathImport(source, packageName))
|
|
649
|
+
return match;
|
|
650
|
+
if (!pluginDetector.isJayPluginWithClientExport(packageName, projectRoot))
|
|
651
|
+
return match;
|
|
652
|
+
hasChanges = true;
|
|
653
|
+
const newSource = `${packageName}/client`;
|
|
654
|
+
if (verbose) {
|
|
655
|
+
getLogger().info(
|
|
656
|
+
`[plugin-client-import] Rewriting import ${source} -> ${newSource} (in ${path.basename(filePath)})`
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
return `import ${clause} from ${quote}${newSource}${quote}`;
|
|
660
|
+
});
|
|
661
|
+
result = result.replace(EXPORT_FROM_REGEX, (match, clause, quote, source) => {
|
|
662
|
+
const packageName = extractPackageName(source);
|
|
663
|
+
if (!packageName)
|
|
664
|
+
return match;
|
|
665
|
+
if (isSubpathImport(source, packageName))
|
|
666
|
+
return match;
|
|
667
|
+
if (!pluginDetector.isJayPluginWithClientExport(packageName, projectRoot))
|
|
668
|
+
return match;
|
|
669
|
+
hasChanges = true;
|
|
670
|
+
const newSource = `${packageName}/client`;
|
|
671
|
+
if (verbose) {
|
|
672
|
+
getLogger().info(
|
|
673
|
+
`[plugin-client-import] Rewriting export ${source} -> ${newSource} (in ${path.basename(filePath)})`
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
return `export ${clause} from ${quote}${newSource}${quote}`;
|
|
677
|
+
});
|
|
678
|
+
return { code: result, hasChanges };
|
|
679
|
+
}
|
|
680
|
+
function createPluginClientImportResolver(options = {}) {
|
|
681
|
+
const { verbose = false } = options;
|
|
682
|
+
let projectRoot = options.projectRoot || process.cwd();
|
|
683
|
+
let isSSRBuild = false;
|
|
684
|
+
const pluginDetector = options.pluginDetector || createDefaultPluginDetector();
|
|
685
|
+
return {
|
|
686
|
+
name: "jay-stack:plugin-client-import",
|
|
687
|
+
enforce: "pre",
|
|
688
|
+
configResolved(config) {
|
|
689
|
+
projectRoot = config.root || projectRoot;
|
|
690
|
+
isSSRBuild = !!config.build?.ssr;
|
|
691
|
+
},
|
|
692
|
+
transform(code, id, transformOptions) {
|
|
693
|
+
if (transformOptions?.ssr || isSSRBuild) {
|
|
694
|
+
return null;
|
|
695
|
+
}
|
|
696
|
+
if (!id.endsWith(".ts") && !id.endsWith(".js") && !id.includes(".ts?") && !id.includes(".js?")) {
|
|
697
|
+
return null;
|
|
698
|
+
}
|
|
699
|
+
if (id.includes("node_modules") && !id.includes("@jay-framework")) {
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
if (!code.includes("@jay-framework/") && !code.includes("from '@") && !code.includes('from "@')) {
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
const result = transformImports({
|
|
706
|
+
code,
|
|
707
|
+
projectRoot,
|
|
708
|
+
filePath: id,
|
|
709
|
+
pluginDetector,
|
|
710
|
+
verbose
|
|
711
|
+
});
|
|
712
|
+
if (!result.hasChanges) {
|
|
713
|
+
return null;
|
|
714
|
+
}
|
|
715
|
+
return { code: result.code };
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
}
|
|
591
719
|
function jayStackCompiler(options = {}) {
|
|
592
720
|
const { trackImports, ...jayOptions } = options;
|
|
593
721
|
const moduleCache = /* @__PURE__ */ new Map();
|
|
@@ -597,6 +725,7 @@ function jayStackCompiler(options = {}) {
|
|
|
597
725
|
if (shouldTrackImports) {
|
|
598
726
|
plugins.push(createImportChainTracker(trackerOptions));
|
|
599
727
|
}
|
|
728
|
+
plugins.push(createPluginClientImportResolver({ verbose: !!shouldTrackImports }));
|
|
600
729
|
plugins.push(
|
|
601
730
|
// First: Jay Stack code splitting transformation
|
|
602
731
|
{
|
|
@@ -616,7 +745,7 @@ function jayStackCompiler(options = {}) {
|
|
|
616
745
|
try {
|
|
617
746
|
return transformJayStackBuilder(code, id, environment);
|
|
618
747
|
} catch (error) {
|
|
619
|
-
|
|
748
|
+
getLogger().error(`[jay-stack:code-split] Error transforming ${id}: ${error}`);
|
|
620
749
|
return null;
|
|
621
750
|
}
|
|
622
751
|
}
|
|
@@ -657,6 +786,13 @@ function jayStackCompiler(options = {}) {
|
|
|
657
786
|
} else {
|
|
658
787
|
return null;
|
|
659
788
|
}
|
|
789
|
+
} else if (resolvedPath.endsWith(".js") && !fs.existsSync(resolvedPath)) {
|
|
790
|
+
const tsPath = resolvedPath.slice(0, -3) + ".ts";
|
|
791
|
+
if (fs.existsSync(tsPath)) {
|
|
792
|
+
resolvedPath = tsPath;
|
|
793
|
+
} else {
|
|
794
|
+
return null;
|
|
795
|
+
}
|
|
660
796
|
}
|
|
661
797
|
return `\0jay-action:${resolvedPath}`;
|
|
662
798
|
},
|
|
@@ -669,12 +805,14 @@ function jayStackCompiler(options = {}) {
|
|
|
669
805
|
try {
|
|
670
806
|
code = await fs.promises.readFile(actualPath, "utf-8");
|
|
671
807
|
} catch (err) {
|
|
672
|
-
|
|
808
|
+
getLogger().error(
|
|
809
|
+
`[action-transform] Could not read ${actualPath}: ${err}`
|
|
810
|
+
);
|
|
673
811
|
return null;
|
|
674
812
|
}
|
|
675
813
|
const actions = extractActionsFromSource(code, actualPath);
|
|
676
814
|
if (actions.length === 0) {
|
|
677
|
-
|
|
815
|
+
getLogger().warn(`[action-transform] No actions found in ${actualPath}`);
|
|
678
816
|
return null;
|
|
679
817
|
}
|
|
680
818
|
const lines = [
|
|
@@ -703,10 +841,15 @@ function jayStackCompiler(options = {}) {
|
|
|
703
841
|
}
|
|
704
842
|
export {
|
|
705
843
|
clearActionMetadataCache,
|
|
844
|
+
createDefaultPluginDetector,
|
|
706
845
|
createImportChainTracker,
|
|
846
|
+
createPluginClientImportResolver,
|
|
707
847
|
extractActionsFromSource,
|
|
848
|
+
extractPackageName,
|
|
708
849
|
isActionImport,
|
|
850
|
+
isSubpathImport,
|
|
709
851
|
jayStackCompiler,
|
|
710
852
|
transformActionImports,
|
|
853
|
+
transformImports,
|
|
711
854
|
transformJayStackBuilder
|
|
712
855
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/compiler-jay-stack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -27,15 +27,16 @@
|
|
|
27
27
|
"test:watch": "vitest"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@jay-framework/compiler": "^0.
|
|
31
|
-
"@jay-framework/compiler-shared": "^0.
|
|
32
|
-
"@jay-framework/
|
|
33
|
-
"@jay-framework/
|
|
30
|
+
"@jay-framework/compiler": "^0.12.0",
|
|
31
|
+
"@jay-framework/compiler-shared": "^0.12.0",
|
|
32
|
+
"@jay-framework/logger": "^0.12.0",
|
|
33
|
+
"@jay-framework/typescript-bridge": "^0.7.0",
|
|
34
|
+
"@jay-framework/vite-plugin": "^0.12.0",
|
|
34
35
|
"typescript": "^5.3.3",
|
|
35
36
|
"vite": "^5.0.11"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
|
-
"@jay-framework/dev-environment": "^0.
|
|
39
|
+
"@jay-framework/dev-environment": "^0.12.0",
|
|
39
40
|
"rimraf": "^5.0.5",
|
|
40
41
|
"tsup": "^8.0.1",
|
|
41
42
|
"vitest": "^1.2.1"
|