@stacksjs/server 0.74.29 → 0.74.31

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/imports.d.ts CHANGED
@@ -70,12 +70,7 @@ export declare function autoImportSourceDirs(): string[];
70
70
  * is a no-op and the loop cannot start.
71
71
  */
72
72
  export declare function autoImportsAreStale(): boolean;
73
- /**
74
- * Generate runtime auto-import files for Bun runtime execution.
75
- * This creates index files that can be imported to get all auto-imports,
76
- * including defineModel()-based model definitions and resource functions.
77
- */
78
- export declare function generateAutoImportFiles(): Promise<void>;
73
+ export declare function generateAutoImportFiles(options?: GenerateAutoImportOptions): Promise<void>;
79
74
  /**
80
75
  * Initialize auto-imports for both bundler and runtime.
81
76
  *
@@ -117,6 +112,14 @@ export declare function pruneBrowserAutoImportTypes(): Promise<string[]>;
117
112
  * "no imports needed" ergonomics of framework default actions.
118
113
  */
119
114
  export declare function injectGlobalAutoImports(): Promise<void>;
115
+ /**
116
+ * Generate runtime auto-import files for Bun runtime execution.
117
+ * This creates index files that can be imported to get all auto-imports,
118
+ * including defineModel()-based model definitions and resource functions.
119
+ */
120
+ export declare interface GenerateAutoImportOptions {
121
+ declarations?: boolean
122
+ }
120
123
  /**
121
124
  * Generate a runtime index file for defineModel() models.
122
125
  * These use `export default defineModel(...)`, so we re-export each default as a named export.
package/dist/imports.js CHANGED
@@ -1,15 +1,15 @@
1
- var {require}=import.meta;import{existsSync,readFileSync,statSync}from"node:fs";import{dirname,relative,resolve as resolvePath}from"node:path";import{fileURLToPath}from"node:url";import{plugin}from"bun";import{log}from"@stacksjs/logging";import{path}from"@stacksjs/path";import{autoImports,generateRuntimeIndex,generateGlobalsScript}from"bun-plugin-auto-imports";import{globSync}from"@stacksjs/storage";import{primitiveAutoImportEntries,primitiveModules}from"./primitive-imports";const OPTIONAL_MODEL_MODULES={commerce:["config/commerce.ts"],Content:["config/cms.ts","config/blog.ts"],Forms:["config/forms.ts"],realtime:["config/realtime.ts"]};function configEnabled(configRelPaths){if(process.env.STACKS_CANONICAL_FEATURES==="1")return!0;return configRelPaths.some((rel)=>existsSync(path.projectPath(rel)))}export function frameworkDefaultsDir(sub){const vendored=path.storagePath(`framework/defaults/${sub}`);return resolveDefaultsDir(existsSync(vendored)?vendored:void 0,packagedDefaultsDir(sub),vendoredDefaultsAreStale())}export function resolveDefaultsDir(vendored,packaged,vendoredIsStale){if(packaged&&vendoredIsStale)return packaged;return vendored??packaged}function packagedDefaultsDir(sub){try{const packaged=`${dirname(fileURLToPath(import.meta.resolve("@stacksjs/defaults/package.json")))}/${sub}`;return existsSync(packaged)?packaged:void 0}catch{return}}let defaultsAreStale;function vendoredDefaultsAreStale(){if(defaultsAreStale===void 0)defaultsAreStale=path.inspectDefaultsProvenance().status==="stale";return defaultsAreStale}function existingDirs(dirs){return dirs.filter((dir)=>Boolean(dir)&&existsSync(dir))}function packageModelDirs(){try{const{packageModelRoots}=require("@stacksjs/config");return packageModelRoots().map((root)=>root.dir)}catch{return[]}}function packageJobDirs(){try{const{packageJobRoots}=require("@stacksjs/config");return packageJobRoots().map((root)=>root.dir)}catch{return[]}}function resolveDefaultModelDirs(){const root=frameworkDefaultsDir("app/Models");if(!root)return[];const dirs=[root];for(const[subdir,configPaths]of Object.entries(OPTIONAL_MODEL_MODULES))if(configEnabled(configPaths))dirs.push(`${root}/${subdir}`);return dirs}function scanDirTopLevel(dir){try{return globSync(`${dir}/*.ts`,{ignore:["**/*.d.ts","**/index.ts","**/README*"]}).sort()}catch{return[]}}function scanDefineModelExports(dir,opts={}){const{recursive=!0}=opts;let files=[];try{const pattern=recursive?`${dir}/**/*.ts`:`${dir}/*.ts`;files=globSync(pattern,{ignore:["**/*.d.ts","**/index.ts","**/README*"]}).sort()}catch{return[]}const exports=[],seen=new Set;for(const file of files){const basename=file.split("/").pop()?.replace(".ts","")||"";if(basename&&!seen.has(basename)){seen.add(basename);exports.push({name:basename,file,isDefault:!0})}}return exports}const GLOBAL_SHADOW_BLOCKLIST=new Set(["Error","Request","Response","URL","Map","Set","Object","Array","Number","String","Date","Promise","Symbol"]);async function generateDefineModelIndex(entries,outputPath){const lines=["// Generated by bun-plugin-auto-imports"],seen=new Set;for(const entry of entries){const dir=typeof entry==="string"?entry:entry.dir,recursive=typeof entry==="string"?!0:entry.recursive;let files=[];try{const pattern=recursive?`${dir}/**/*.ts`:`${dir}/*.ts`;files=globSync(pattern,{ignore:["**/*.d.ts","**/index.ts","**/README*"]}).sort()}catch{continue}for(const file of files){const basename=file.split("/").pop()?.replace(".ts","")||"";if(!basename||seen.has(basename))continue;seen.add(basename);const relativePath=relative(dirname(outputPath),file).replace(/\.ts$/,"");if(GLOBAL_SHADOW_BLOCKLIST.has(basename)){lines.push(`// Skipped '${basename}' - would shadow a built-in global. Import directly if needed.`);lines.push(`// export { default as ${basename} } from '${relativePath}'`);continue}lines.push(`export { default as ${basename} } from '${relativePath}'`)}}await Bun.write(outputPath,lines.join(`
2
- `)+`
3
- `)}async function generatePathIndex(entries,outputPath,options){const prefix=options.prefix??"",extensions=options.extensions??[".ts"],found=new Map;for(const entry of entries){const dir=typeof entry==="string"?entry:entry.dir,recursive=typeof entry==="string"?!0:entry.recursive;let files=[];try{for(const extension of extensions){const pattern=recursive?`${dir}/**/*${extension}`:`${dir}/*${extension}`;files.push(...globSync(pattern).sort())}}catch{continue}const rank=(file)=>extensions.findIndex((extension)=>file.endsWith(extension));files=files.sort((left,right)=>{const byRank=rank(left)-rank(right);if(byRank!==0)return byRank;return left<right?-1:left>right?1:0});for(const file of files){const basename=file.split("/").pop()??"";if(basename.endsWith(".d.ts")||basename.endsWith(".test.ts")||basename.endsWith(".spec.ts")||basename==="index.ts")continue;const extension=extensions.find((candidate)=>file.endsWith(candidate))??"",key=prefix+relative(dir,file).slice(0,extension.length?-extension.length:void 0);if(found.has(key))continue;found.set(key,relative(dirname(outputPath),file))}}const lines=["// Generated by bun-plugin-auto-imports","//","// Name to file, relative to this file. The resolvers read it, and the name","// types are `keyof` over it - so a name that type-checks is a name that","// resolves. Values are paths rather than import thunks on purpose: thunks","// would make every compilation that touches a name resolve every module.",`export const ${options.exportName} = {`,...[...found.entries()].map(([key,file])=>` '${key}': '${file}',`),"} as const",""];await Bun.write(outputPath,lines.join(`
4
- `))}export function autoImportSourceDirs(){return existingDirs([path.resourcesPath("functions"),frameworkDefaultsDir("functions"),path.userModelsPath(),...resolveDefaultModelDirs(),path.userJobsPath(),frameworkDefaultsDir("app/Jobs"),...packageJobDirs(),path.userControllersPath(),frameworkDefaultsDir("app/Controllers"),path.appPath("Actions"),frameworkDefaultsDir("app/Actions"),path.appPath("Listeners"),frameworkDefaultsDir("app/Listeners"),path.appPath("Policies"),frameworkDefaultsDir("app/Policies"),path.appPath("Middleware"),frameworkDefaultsDir("app/Middleware"),path.resourcesPath("emails"),frameworkDefaultsDir("resources/emails")])}export function autoImportsAreStale(){const manifest=path.storagePath("framework/auto-imports/functions.ts");if(!existsSync(manifest))return!0;let manifestTime;try{manifestTime=statSync(manifest).mtimeMs}catch{return!0}const discovered=path.storagePath("framework/discovered-packages.json");try{if(existsSync(discovered)&&statSync(discovered).mtimeMs>manifestTime)return!0}catch{}for(const dir of autoImportSourceDirs()){if(!existsSync(dir))continue;try{if(statSync(dir).mtimeMs>manifestTime)return!0;for(const file of globSync(`${dir}/**/*.ts`,{ignore:["**/*.d.ts"]}))if(statSync(file).mtimeMs>manifestTime)return!0}catch{continue}}return!1}export async function generateAutoImportFiles(){const userFunctionsPath=path.resourcesPath("functions"),defaultFunctionsPath=frameworkDefaultsDir("functions"),functionsPath=userFunctionsPath,outputDir=path.storagePath("framework/auto-imports"),userModelsPath=path.userModelsPath(),defaultModelDirs=resolveDefaultModelDirs(),[defaultsRoot,...enabledSubdirs]=defaultModelDirs,userJobsPath=path.userJobsPath(),userControllersPath=path.userControllersPath(),defaultControllersPath=frameworkDefaultsDir("app/Controllers");await Bun.write(`${outputDir}/.gitkeep`,"");const functionsIndexPath=`${outputDir}/functions.ts`;await generateRuntimeIndex(existingDirs([userFunctionsPath,defaultFunctionsPath]),functionsIndexPath);const modelsIndexPath=`${outputDir}/models.ts`,modelScan=[userModelsPath,...packageModelDirs().map((dir)=>({dir,recursive:!0})),...defaultsRoot?[{dir:defaultsRoot,recursive:!1}]:[],...defaultModelDirs.slice(1).map((d)=>({dir:d,recursive:!0}))];await generateDefineModelIndex(modelScan,modelsIndexPath);const jobsIndexPath=`${outputDir}/jobs.ts`;await generateDefineModelIndex(existingDirs([userJobsPath,frameworkDefaultsDir("app/Jobs"),...packageJobDirs()]),jobsIndexPath);await generatePathIndex(existingDirs([path.appPath("Actions"),frameworkDefaultsDir("app/Actions")]),`${outputDir}/actions.ts`,{exportName:"actions",prefix:"Actions/"});await generatePathIndex(existingDirs([path.appPath("Listeners"),frameworkDefaultsDir("app/Listeners")]),`${outputDir}/listeners.ts`,{exportName:"listeners"});await generatePathIndex(existingDirs([path.appPath("Policies"),frameworkDefaultsDir("app/Policies")]),`${outputDir}/policies.ts`,{exportName:"policies"});await generatePathIndex(existingDirs([path.appPath("Middleware"),frameworkDefaultsDir("app/Middleware")]),`${outputDir}/middleware.ts`,{exportName:"middleware"});await generatePathIndex(existingDirs([path.resourcesPath("emails"),frameworkDefaultsDir("resources/emails")]),`${outputDir}/emails.ts`,{exportName:"emails",extensions:[".stx",".html"]});const controllersIndexPath=`${outputDir}/controllers.ts`;await generateDefineModelIndex(existingDirs([userControllersPath,defaultControllersPath]),controllersIndexPath);const combinedContent=`// Generated by bun-plugin-auto-imports
1
+ var {require}=import.meta;import{existsSync,readFileSync,renameSync,statSync,unlinkSync}from"node:fs";import{dirname,relative,resolve as resolvePath}from"node:path";import{fileURLToPath}from"node:url";import{plugin}from"bun";import{log}from"@stacksjs/logging";import{path}from"@stacksjs/path";import{autoImports,generateRuntimeIndex,generateGlobalsScript}from"bun-plugin-auto-imports";import{globSync}from"@stacksjs/storage";import{primitiveAutoImportEntries,primitiveModules}from"./primitive-imports";const OPTIONAL_MODEL_MODULES={commerce:["config/commerce.ts"],Content:["config/cms.ts","config/blog.ts"],Forms:["config/forms.ts"],realtime:["config/realtime.ts"]};function configEnabled(configRelPaths){if(process.env.STACKS_CANONICAL_FEATURES==="1")return!0;return configRelPaths.some((rel)=>existsSync(path.projectPath(rel)))}export function frameworkDefaultsDir(sub){const vendored=path.storagePath(`framework/defaults/${sub}`);return resolveDefaultsDir(existsSync(vendored)?vendored:void 0,packagedDefaultsDir(sub),vendoredDefaultsAreStale())}export function resolveDefaultsDir(vendored,packaged,vendoredIsStale){if(packaged&&vendoredIsStale)return packaged;return vendored??packaged}function packagedDefaultsDir(sub){try{const packaged=`${dirname(fileURLToPath(import.meta.resolve("@stacksjs/defaults/package.json")))}/${sub}`;return existsSync(packaged)?packaged:void 0}catch{return}}let defaultsAreStale;function vendoredDefaultsAreStale(){if(defaultsAreStale===void 0)defaultsAreStale=path.inspectDefaultsProvenance().status==="stale";return defaultsAreStale}function existingDirs(dirs){return dirs.filter((dir)=>Boolean(dir)&&existsSync(dir))}function packageModelDirs(){try{const{packageModelRoots}=require("@stacksjs/config");return packageModelRoots().map((root)=>root.dir)}catch{return[]}}async function writeGeneratedFile(outputPath,contents){const temp=`${outputPath}.${process.pid}.tmp`;try{await Bun.write(temp,contents);renameSync(temp,outputPath)}catch(error){try{unlinkSync(temp)}catch{}throw error}}function packageJobDirs(){try{const{packageJobRoots}=require("@stacksjs/config");return packageJobRoots().map((root)=>root.dir)}catch{return[]}}function resolveDefaultModelDirs(){const root=frameworkDefaultsDir("app/Models");if(!root)return[];const dirs=[root];for(const[subdir,configPaths]of Object.entries(OPTIONAL_MODEL_MODULES))if(configEnabled(configPaths))dirs.push(`${root}/${subdir}`);return dirs}function scanDirTopLevel(dir){try{return globSync(`${dir}/*.ts`,{ignore:["**/*.d.ts","**/index.ts","**/README*"]}).sort()}catch{return[]}}function scanDefineModelExports(dir,opts={}){const{recursive=!0}=opts;let files=[];try{const pattern=recursive?`${dir}/**/*.ts`:`${dir}/*.ts`;files=globSync(pattern,{ignore:["**/*.d.ts","**/index.ts","**/README*"]}).sort()}catch{return[]}const exports=[],seen=new Set;for(const file of files){const basename=file.split("/").pop()?.replace(".ts","")||"";if(basename&&!seen.has(basename)){seen.add(basename);exports.push({name:basename,file,isDefault:!0})}}return exports}const GLOBAL_SHADOW_BLOCKLIST=new Set(["Error","Request","Response","URL","Map","Set","Object","Array","Number","String","Date","Promise","Symbol"]);async function generateDefineModelIndex(entries,outputPath){const lines=["// Generated by bun-plugin-auto-imports"],seen=new Set;for(const entry of entries){const dir=typeof entry==="string"?entry:entry.dir,recursive=typeof entry==="string"?!0:entry.recursive;let files=[];try{const pattern=recursive?`${dir}/**/*.ts`:`${dir}/*.ts`;files=globSync(pattern,{ignore:["**/*.d.ts","**/index.ts","**/README*"]}).sort()}catch{continue}for(const file of files){const basename=file.split("/").pop()?.replace(".ts","")||"";if(!basename||seen.has(basename))continue;seen.add(basename);const relativePath=relative(dirname(outputPath),file).replace(/\.ts$/,"");if(GLOBAL_SHADOW_BLOCKLIST.has(basename)){lines.push(`// Skipped '${basename}' - would shadow a built-in global. Import directly if needed.`);lines.push(`// export { default as ${basename} } from '${relativePath}'`);continue}lines.push(`export { default as ${basename} } from '${relativePath}'`)}}await writeGeneratedFile(outputPath,`${lines.join(`
2
+ `)}
3
+ `)}async function generatePathIndex(entries,outputPath,options){const prefix=options.prefix??"",extensions=options.extensions??[".ts"],found=new Map;for(const entry of entries){const dir=typeof entry==="string"?entry:entry.dir,recursive=typeof entry==="string"?!0:entry.recursive;let files=[];try{for(const extension of extensions){const pattern=recursive?`${dir}/**/*${extension}`:`${dir}/*${extension}`;files.push(...globSync(pattern).sort())}}catch{continue}const rank=(file)=>extensions.findIndex((extension)=>file.endsWith(extension));files=files.sort((left,right)=>{const byRank=rank(left)-rank(right);if(byRank!==0)return byRank;return left<right?-1:left>right?1:0});for(const file of files){const basename=file.split("/").pop()??"";if(basename.endsWith(".d.ts")||basename.endsWith(".test.ts")||basename.endsWith(".spec.ts")||basename==="index.ts")continue;const extension=extensions.find((candidate)=>file.endsWith(candidate))??"",key=prefix+relative(dir,file).slice(0,extension.length?-extension.length:void 0);if(found.has(key))continue;found.set(key,relative(dirname(outputPath),file))}}const lines=["// Generated by bun-plugin-auto-imports","//","// Name to file, relative to this file. The resolvers read it, and the name","// types are `keyof` over it - so a name that type-checks is a name that","// resolves. Values are paths rather than import thunks on purpose: thunks","// would make every compilation that touches a name resolve every module.",`export const ${options.exportName} = {`,...[...found.entries()].map(([key,file])=>` '${key}': '${file}',`),"} as const",""];await writeGeneratedFile(outputPath,lines.join(`
4
+ `))}export function autoImportSourceDirs(){return existingDirs([path.resourcesPath("functions"),frameworkDefaultsDir("functions"),path.userModelsPath(),...resolveDefaultModelDirs(),path.userJobsPath(),frameworkDefaultsDir("app/Jobs"),...packageJobDirs(),path.userControllersPath(),frameworkDefaultsDir("app/Controllers"),path.appPath("Actions"),frameworkDefaultsDir("app/Actions"),path.appPath("Listeners"),frameworkDefaultsDir("app/Listeners"),path.appPath("Policies"),frameworkDefaultsDir("app/Policies"),path.appPath("Middleware"),frameworkDefaultsDir("app/Middleware"),path.resourcesPath("emails"),frameworkDefaultsDir("resources/emails")])}export function autoImportsAreStale(){const manifest=path.storagePath("framework/auto-imports/functions.ts");if(!existsSync(manifest))return!0;let manifestTime;try{manifestTime=statSync(manifest).mtimeMs}catch{return!0}const discovered=path.storagePath("framework/discovered-packages.json");try{if(existsSync(discovered)&&statSync(discovered).mtimeMs>manifestTime)return!0}catch{}for(const dir of autoImportSourceDirs()){if(!existsSync(dir))continue;try{if(statSync(dir).mtimeMs>manifestTime)return!0;for(const file of globSync(`${dir}/**/*.ts`,{ignore:["**/*.d.ts"]}))if(statSync(file).mtimeMs>manifestTime)return!0}catch{continue}}return!1}export async function generateAutoImportFiles(options={}){const userFunctionsPath=path.resourcesPath("functions"),defaultFunctionsPath=frameworkDefaultsDir("functions"),functionsPath=userFunctionsPath,outputDir=path.storagePath("framework/auto-imports"),userModelsPath=path.userModelsPath(),defaultModelDirs=resolveDefaultModelDirs(),[defaultsRoot,...enabledSubdirs]=defaultModelDirs,userJobsPath=path.userJobsPath(),userControllersPath=path.userControllersPath(),defaultControllersPath=frameworkDefaultsDir("app/Controllers");await Bun.write(`${outputDir}/.gitkeep`,"");const functionsIndexPath=`${outputDir}/functions.ts`;await generateRuntimeIndex(existingDirs([userFunctionsPath,defaultFunctionsPath]),functionsIndexPath);const modelsIndexPath=`${outputDir}/models.ts`,modelScan=[userModelsPath,...packageModelDirs().map((dir)=>({dir,recursive:!0})),...defaultsRoot?[{dir:defaultsRoot,recursive:!1}]:[],...defaultModelDirs.slice(1).map((d)=>({dir:d,recursive:!0}))];await generateDefineModelIndex(modelScan,modelsIndexPath);const jobsIndexPath=`${outputDir}/jobs.ts`;await generateDefineModelIndex(existingDirs([userJobsPath,frameworkDefaultsDir("app/Jobs"),...packageJobDirs()]),jobsIndexPath);await generatePathIndex(existingDirs([path.appPath("Actions"),frameworkDefaultsDir("app/Actions")]),`${outputDir}/actions.ts`,{exportName:"actions",prefix:"Actions/"});await generatePathIndex(existingDirs([path.appPath("Listeners"),frameworkDefaultsDir("app/Listeners")]),`${outputDir}/listeners.ts`,{exportName:"listeners"});await generatePathIndex(existingDirs([path.appPath("Policies"),frameworkDefaultsDir("app/Policies")]),`${outputDir}/policies.ts`,{exportName:"policies"});await generatePathIndex(existingDirs([path.appPath("Middleware"),frameworkDefaultsDir("app/Middleware")]),`${outputDir}/middleware.ts`,{exportName:"middleware"});await generatePathIndex(existingDirs([path.resourcesPath("emails"),frameworkDefaultsDir("resources/emails")]),`${outputDir}/emails.ts`,{exportName:"emails",extensions:[".stx",".html"]});const controllersIndexPath=`${outputDir}/controllers.ts`;await generateDefineModelIndex(existingDirs([userControllersPath,defaultControllersPath]),controllersIndexPath);const combinedContent=`// Generated by bun-plugin-auto-imports
5
5
  export * from './functions'
6
6
  export * from './models'
7
7
  export * from './jobs'
8
8
  export * from './controllers'
9
- `;await Bun.write(`${outputDir}/index.ts`,combinedContent);const globalsPath=`${outputDir}/globals.ts`;await generateGlobalsScript([functionsPath],globalsPath,`${outputDir}/index.ts`);await generateServerAutoImportTypes();const pruned=await pruneBrowserAutoImportTypes();if(pruned.length>0)log.debug(`[auto-imports] dropped ${pruned.length} browser globals that resolve to nothing`);await invalidateTypeScriptBuildInfo();log.debug("Auto-import files generated successfully")}async function invalidateTypeScriptBuildInfo(){const cacheDir=path.storagePath("framework/.cache/typescript");try{const{readdirSync,rmSync}=await import("node:fs");for(const entry of readdirSync(cacheDir)){if(!entry.endsWith(".tsbuildinfo"))continue;rmSync(`${cacheDir}/${entry}`,{force:!0});log.debug(`[auto-imports] dropped stale ${entry}`)}}catch{}}export function initiateImports(){const functionsPath=path.resourcesPath("functions"),defaultFunctionsPath=frameworkDefaultsDir("functions"),userModelsPath=path.userModelsPath(),defaultModelDirs=resolveDefaultModelDirs(),[defaultsRoot,...enabledSubdirs]=defaultModelDirs,userJobsPath=path.userJobsPath(),userControllersPath=path.userControllersPath(),defaultControllersPath=frameworkDefaultsDir("app/Controllers"),defineModelExports=[...scanDefineModelExports(userModelsPath),...packageModelDirs().flatMap((dir)=>scanDefineModelExports(dir)),...defaultsRoot?scanDefineModelExports(defaultsRoot,{recursive:!1}):[],...enabledSubdirs.flatMap((d)=>scanDefineModelExports(d))],seenJobs=new Set,jobExports=[...scanDefineModelExports(userJobsPath),...packageJobDirs().flatMap((dir)=>scanDefineModelExports(dir))].filter((exp)=>{if(seenJobs.has(exp.name))return!1;seenJobs.add(exp.name);return!0}),seen=new Set,uniqueDefineModelExports=defineModelExports.filter((exp)=>{if(seen.has(exp.name))return!1;seen.add(exp.name);return!0}),dtsDir=dirname(path.storagePath("framework/types/server-auto-imports.d.ts")),defineModelImports=uniqueDefineModelExports.map((exp)=>({from:`./${relative(dtsDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,"")}`,name:"default",as:exp.name})),jobImports=jobExports.map((exp)=>({from:`./${relative(dtsDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,"")}`,name:"default",as:exp.name})),controllerExports=[...scanDefineModelExports(userControllersPath),...defaultControllersPath?scanDefineModelExports(defaultControllersPath):[]],seenControllers=new Set,controllerImports=controllerExports.filter((exp)=>{if(seenControllers.has(exp.name))return!1;seenControllers.add(exp.name);return!0}).map((exp)=>({from:`./${relative(dtsDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,"")}`,name:"default",as:exp.name})),options={dts:path.storagePath("framework/types/server-auto-imports.d.ts"),imports:[...primitiveAutoImportEntries(),...defineModelImports,...jobImports,...controllerImports],dirs:existingDirs([functionsPath,defaultFunctionsPath]),eslint:{enabled:!0,filepath:path.storagePath("framework/server-auto-imports.json")}};plugin(autoImports(options));generateAutoImportFiles().catch((err)=>{console.error("[Server] Failed to generate auto-import files:",err)})}export async function generateServerAutoImportTypes(){const seen=new Set,valueExports=[...barrelExports("models"),...barrelExports("jobs"),...barrelExports("controllers"),...await ormModelGlobals()].filter((exp)=>!GLOBAL_SHADOW_BLOCKLIST.has(exp.name)).filter((exp)=>{if(seen.has(exp.name))return!1;seen.add(exp.name);return!0}),outputPath=path.storagePath("framework/types/server-auto-imports.d.ts"),outputDir=dirname(outputPath),declaredValues=new Set(valueExports.map((exp)=>exp.name)),lines=["// Generated by Stacks server auto-imports","// This file is regenerated automatically when the API starts.","export {}","declare global {"];for(const{from,name,as}of primitiveAutoImportEntries())if(!declaredValues.has(as))lines.push(` const ${as}: typeof import('${from}')['${name}']`);for(const exp of valueExports){if(!exp.isDefault){lines.push(` const ${exp.name}: typeof import('${exp.file}')['${exp.name}']`);continue}const importPath=relative(outputDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,""),relativePath=importPath.startsWith(".")?importPath:`./${importPath}`;lines.push(` const ${exp.name}: typeof import('${relativePath}')['default']`)}lines.push("}","");await Bun.write(outputPath,lines.join(`
9
+ `;await writeGeneratedFile(`${outputDir}/index.ts`,combinedContent);const globalsPath=`${outputDir}/globals.ts`;await generateGlobalsScript([functionsPath],globalsPath,`${outputDir}/index.ts`);if(options.declarations!==!1){await generateServerAutoImportTypes();const pruned=await pruneBrowserAutoImportTypes();if(pruned.length>0)log.debug(`[auto-imports] dropped ${pruned.length} browser globals that resolve to nothing`);await invalidateTypeScriptBuildInfo()}log.debug("Auto-import files generated successfully")}async function invalidateTypeScriptBuildInfo(){const cacheDir=path.storagePath("framework/.cache/typescript");try{const{readdirSync,rmSync}=await import("node:fs");for(const entry of readdirSync(cacheDir)){if(!entry.endsWith(".tsbuildinfo"))continue;rmSync(`${cacheDir}/${entry}`,{force:!0});log.debug(`[auto-imports] dropped stale ${entry}`)}}catch{}}export function initiateImports(){const functionsPath=path.resourcesPath("functions"),defaultFunctionsPath=frameworkDefaultsDir("functions"),userModelsPath=path.userModelsPath(),defaultModelDirs=resolveDefaultModelDirs(),[defaultsRoot,...enabledSubdirs]=defaultModelDirs,userJobsPath=path.userJobsPath(),userControllersPath=path.userControllersPath(),defaultControllersPath=frameworkDefaultsDir("app/Controllers"),defineModelExports=[...scanDefineModelExports(userModelsPath),...packageModelDirs().flatMap((dir)=>scanDefineModelExports(dir)),...defaultsRoot?scanDefineModelExports(defaultsRoot,{recursive:!1}):[],...enabledSubdirs.flatMap((d)=>scanDefineModelExports(d))],seenJobs=new Set,jobExports=[...scanDefineModelExports(userJobsPath),...packageJobDirs().flatMap((dir)=>scanDefineModelExports(dir))].filter((exp)=>{if(seenJobs.has(exp.name))return!1;seenJobs.add(exp.name);return!0}),seen=new Set,uniqueDefineModelExports=defineModelExports.filter((exp)=>{if(seen.has(exp.name))return!1;seen.add(exp.name);return!0}),dtsDir=dirname(path.storagePath("framework/types/server-auto-imports.d.ts")),defineModelImports=uniqueDefineModelExports.map((exp)=>({from:`./${relative(dtsDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,"")}`,name:"default",as:exp.name})),jobImports=jobExports.map((exp)=>({from:`./${relative(dtsDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,"")}`,name:"default",as:exp.name})),controllerExports=[...scanDefineModelExports(userControllersPath),...defaultControllersPath?scanDefineModelExports(defaultControllersPath):[]],seenControllers=new Set,controllerImports=controllerExports.filter((exp)=>{if(seenControllers.has(exp.name))return!1;seenControllers.add(exp.name);return!0}).map((exp)=>({from:`./${relative(dtsDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,"")}`,name:"default",as:exp.name})),options={dts:path.storagePath("framework/types/server-auto-imports.d.ts"),imports:[...primitiveAutoImportEntries(),...defineModelImports,...jobImports,...controllerImports],dirs:existingDirs([functionsPath,defaultFunctionsPath]),eslint:{enabled:!0,filepath:path.storagePath("framework/server-auto-imports.json")}};plugin(autoImports(options));generateAutoImportFiles().catch((err)=>{console.error("[Server] Failed to generate auto-import files:",err)})}export async function generateServerAutoImportTypes(){const seen=new Set,valueExports=[...barrelExports("models"),...barrelExports("jobs"),...barrelExports("controllers"),...await ormModelGlobals()].filter((exp)=>!GLOBAL_SHADOW_BLOCKLIST.has(exp.name)).filter((exp)=>{if(seen.has(exp.name))return!1;seen.add(exp.name);return!0}),outputPath=path.storagePath("framework/types/server-auto-imports.d.ts"),outputDir=dirname(outputPath),declaredValues=new Set(valueExports.map((exp)=>exp.name)),lines=["// Generated by Stacks server auto-imports","// This file is regenerated automatically when the API starts.","export {}","declare global {"];for(const{from,name,as}of primitiveAutoImportEntries())if(!declaredValues.has(as))lines.push(` const ${as}: typeof import('${from}')['${name}']`);for(const exp of valueExports){if(!exp.isDefault){lines.push(` const ${exp.name}: typeof import('${exp.file}')['${exp.name}']`);continue}const importPath=relative(outputDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,""),relativePath=importPath.startsWith(".")?importPath:`./${importPath}`;lines.push(` const ${exp.name}: typeof import('${relativePath}')['default']`)}lines.push("}","");await writeGeneratedFile(outputPath,lines.join(`
10
10
  `));const globals={};for(const{as}of primitiveAutoImportEntries())if(!declaredValues.has(as))globals[as]=!0;for(const exp of valueExports)globals[exp.name]=!0;await Bun.write(path.storagePath("framework/server-auto-imports.json"),`${JSON.stringify({globals:Object.fromEntries(Object.keys(globals).sort().map((k)=>[k,!0]))},null,2)}
11
11
  `)}function barrelExports(barrel){const file=path.storagePath(`framework/auto-imports/${barrel}.ts`);if(!existsSync(file))return[];const source=readFileSync(file,"utf8"),outputDir=dirname(file),found=[];for(const line of source.split(`
12
12
  `)){const match=/^export \{ default as (\w+) \} from '([^']+)'/.exec(line.trim());if(!match)continue;const[,name,relativePath]=match;found.push({name,file:resolvePath(outputDir,`${relativePath}.ts`),isDefault:!0})}return found}export async function pruneBrowserAutoImportTypes(){const outputPath=path.storagePath("framework/types/browser-auto-imports.d.ts");if(!existsSync(outputPath))return[];const source=readFileSync(outputPath,"utf8"),outputDir=dirname(outputPath),exportsOf=new Map;async function moduleExports(specifier){const cached=exportsOf.get(specifier);if(cached!==void 0)return cached;let names;try{const resolved=specifier.startsWith(".")?resolvePath(outputDir,specifier):specifier;names=new Set(Object.keys(await import(resolved)))}catch{names=null}exportsOf.set(specifier,names);return names}const removed=[],kept=[];for(const line of source.split(`
13
13
  `)){const match=/^ {2}const (\w+): typeof import\('([^']+)'\)\['(\w+)'\]/.exec(line);if(!match){kept.push(line);continue}const[,declaredAs,specifier,exported]=match;if(specifier==="@stacksjs/stx"){removed.push(declaredAs);continue}const names=await moduleExports(specifier);if(names&&!names.has(exported)){removed.push(declaredAs);continue}kept.push(line)}if(removed.length===0)return[];const pruned=kept.filter((line)=>line.trim()!=="// @ts-nocheck").map((line)=>line.trim()==="// Generated by unplugin-auto-import"?"// Pruned by Stacks: every name below is exported by the module beside it.":line).join(`
14
14
  `);await Bun.write(outputPath,pruned);const globals=[...pruned.matchAll(/^ {2}const (\w+):/gm)].map((match)=>match[1]).sort();await Bun.write(path.storagePath("framework/browser-auto-imports.json"),`${JSON.stringify({globals:Object.fromEntries(globals.map((name)=>[name,!0]))},null,2)}
15
- `);return removed}async function ormModelGlobals(){try{const{modelGlobalNames}=await import("@stacksjs/orm");return(modelGlobalNames??[]).map((name)=>({name,file:"@stacksjs/orm",isDefault:!1}))}catch{return[]}}export async function injectGlobalAutoImports(){if(globalThis.__stacksAutoImportsInjected)return;globalThis.__stacksAutoImportsInjected=!0;const errors=[],importWithTimeout=async(pkg)=>{return Promise.race([import(pkg),new Promise((_,reject)=>setTimeout(()=>reject(Error(`auto-import timed out: ${pkg}`)),4000))])};await Promise.all(primitiveModules.map(async([pkg,names])=>{try{const mod=await importWithTimeout(pkg);for(const name of names)if(mod[name]!==void 0)globalThis[name]=mod[name]}catch(err){errors.push(err)}}));try{const{ensureLocalesLoaded}=await import("@stacksjs/i18n");await ensureLocalesLoaded()}catch(err){errors.push(err)}const barrels=["functions","models","jobs","controllers"],injected=[];for(const barrel of barrels){const barrelPath=path.storagePath(`framework/auto-imports/${barrel}.ts`);if(!existsSync(barrelPath))continue;try{const mod=await import(barrelPath);Object.assign(globalThis,mod);injected.push(barrel)}catch(err){log.warn(`[auto-imports] ${barrel}.ts failed to load, so nothing it exports is available. Views and actions referencing them will throw "is not defined". Cause: ${err.message}`)}}if(!injected.includes("models")&&existsSync(path.storagePath("framework/auto-imports/models.ts")))log.warn("[auto-imports] No models were injected. Every model reference in stx views and actions will be undefined.");try{const{registerAppListeners}=await import("@stacksjs/events");await registerAppListeners()}catch(err){errors.push(err)}try{const{initializeAuthorization}=await import("@stacksjs/auth");await initializeAuthorization()}catch(err){errors.push(err)}if(errors.length)for(const err of errors)console.warn("[auto-imports]",err.message)}
15
+ `);return removed}async function ormModelGlobals(){try{const{modelGlobalNames}=await import("@stacksjs/orm");return(modelGlobalNames??[]).map((name)=>({name,file:"@stacksjs/orm",isDefault:!1}))}catch{return[]}}export async function injectGlobalAutoImports(){if(globalThis.__stacksAutoImportsInjected)return;globalThis.__stacksAutoImportsInjected=!0;const errors=[],importWithTimeout=async(pkg)=>{let timer;try{return await Promise.race([import(pkg),new Promise((_,reject)=>{timer=setTimeout(()=>reject(Error(`auto-import timed out: ${pkg}`)),4000)})])}finally{if(timer!==void 0)clearTimeout(timer)}};await Promise.all(primitiveModules.map(async([pkg,names])=>{try{const mod=await importWithTimeout(pkg);for(const name of names)if(mod[name]!==void 0)globalThis[name]=mod[name]}catch(err){errors.push(err)}}));try{const{ensureLocalesLoaded}=await import("@stacksjs/i18n");await ensureLocalesLoaded()}catch(err){errors.push(err)}const barrels=["functions","models","jobs","controllers"],injected=[];for(const barrel of barrels){const barrelPath=path.storagePath(`framework/auto-imports/${barrel}.ts`);if(!existsSync(barrelPath))continue;try{const mod=await import(barrelPath);Object.assign(globalThis,mod);injected.push(barrel)}catch(err){log.warn(`[auto-imports] ${barrel}.ts failed to load, so nothing it exports is available. Views and actions referencing them will throw "is not defined". Cause: ${err.message}`)}}if(!injected.includes("models")&&existsSync(path.storagePath("framework/auto-imports/models.ts")))log.warn("[auto-imports] No models were injected. Every model reference in stx views and actions will be undefined.");try{const{registerAppListeners}=await import("@stacksjs/events");await registerAppListeners()}catch(err){errors.push(err)}try{const{initializeAuthorization}=await import("@stacksjs/auth");await initializeAuthorization()}catch(err){errors.push(err)}if(errors.length)for(const err of errors)console.warn("[auto-imports]",err.message)}
@@ -1,4 +1,4 @@
1
- import{log}from"@stacksjs/logging";import*as p from"@stacksjs/path";const DEFAULT_MAINTENANCE_PAYLOAD={mode:"maintenance",status:503,message:"We are currently performing maintenance. Please check back soon."},DEFAULT_COMING_SOON_PAYLOAD={mode:"coming-soon",status:200,message:"Stacks is setting up camp. Check back soon for the public launch.",redirect:"/coming-soon"};function defaultsForMode(mode){return mode==="coming-soon"?DEFAULT_COMING_SOON_PAYLOAD:DEFAULT_MAINTENANCE_PAYLOAD}export function maintenanceFilePath(){return p.storagePath("framework/down")}export function comingSoonFilePath(){return p.storagePath("framework/coming-soon")}export function siteModeFilePath(mode){return mode==="coming-soon"?comingSoonFilePath():maintenanceFilePath()}export async function isDownForMaintenance(){try{return await Bun.file(maintenanceFilePath()).exists()}catch{return!1}}export async function isComingSoon(){try{return await Bun.file(comingSoonFilePath()).exists()}catch{return!1}}export async function maintenancePayload(){return siteModePayload("maintenance")}export async function comingSoonPayload(){return siteModePayload("coming-soon")}export async function siteModePayload(mode){try{const file=Bun.file(siteModeFilePath(mode));if(!await file.exists())return null;const content=await file.text();return{...defaultsForMode(mode),...JSON.parse(content),mode}}catch{return null}}export async function activeSiteModePayload(){return await maintenancePayload()??await comingSoonPayload()??envSiteModePayload()}function envSiteModePayload(){if(isTruthy(process.env.APP_MAINTENANCE))return{...DEFAULT_MAINTENANCE_PAYLOAD,mode:"maintenance",time:Date.now(),secret:process.env.APP_MAINTENANCE_SECRET||void 0};if(isTruthy(process.env.APP_COMING_SOON))return{...DEFAULT_COMING_SOON_PAYLOAD,mode:"coming-soon",time:Date.now(),secret:process.env.APP_COMING_SOON_SECRET||void 0};return null}function isTruthy(value){return["1","true","yes","on"].includes(String(value||"").toLowerCase())}export async function down(options={}){const payload={...DEFAULT_MAINTENANCE_PAYLOAD,...options,mode:"maintenance",time:Date.now()},frameworkDir=p.storagePath("framework"),{mkdirSync,existsSync}=await import("@stacksjs/storage");if(!existsSync(frameworkDir))mkdirSync(frameworkDir,{recursive:!0});await Bun.write(maintenanceFilePath(),JSON.stringify(payload,null,2));log.info("Application is now in maintenance mode.");if(payload.secret)log.info("Maintenance bypass secret has been configured")}export async function comingSoon(options={}){const payload={...DEFAULT_COMING_SOON_PAYLOAD,...options,mode:"coming-soon",time:Date.now()},frameworkDir=p.storagePath("framework"),{mkdirSync,existsSync}=await import("@stacksjs/storage");if(!existsSync(frameworkDir))mkdirSync(frameworkDir,{recursive:!0});await Bun.write(comingSoonFilePath(),JSON.stringify(payload,null,2));log.info("Application is now in coming soon mode.");if(payload.secret)log.info("Coming soon bypass secret has been configured")}export async function up(){const{unlinkSync,existsSync}=await import("node:fs"),filePath=maintenanceFilePath();if(existsSync(filePath)){unlinkSync(filePath);log.info("Application is now live.")}else log.info("Application is already live.")}export async function launch(){const{unlinkSync,existsSync}=await import("node:fs"),filePath=comingSoonFilePath();if(existsSync(filePath)){unlinkSync(filePath);log.info("Application is out of coming soon mode.")}else log.info("Application is not in coming soon mode.")}export function isAllowedIp(ip,allowed=[],trustLocalhost=!0){if(trustLocalhost&&["127.0.0.1","::1","localhost"].includes(ip))return!0;if(allowed.length===0)return!1;return allowed.includes(ip)}export function bypassCookieName(mode="maintenance"){return mode==="coming-soon"?"stacks_coming_soon_bypass":"stacks_maintenance_bypass"}export function hasValidBypassCookie(cookies,secret,mode="maintenance"){return cookies[bypassCookieName(mode)]===secret}export function isSecretPath(path,secret){return path===`/${secret}`||path.startsWith(`/${secret}/`)}export function maintenanceHtml(payload){const mode=payload.mode??"maintenance",defaults=defaultsForMode(mode),message=escapeHtml(payload.message||defaults.message||""),title=escapeHtml(payload.title||(mode==="coming-soon"?"Opening Soon":"Trail Maintenance"));return`<!DOCTYPE html>
1
+ import{log}from"@stacksjs/logging";import*as p from"@stacksjs/path";const DEFAULT_MAINTENANCE_PAYLOAD={mode:"maintenance",status:503,message:"We are currently performing maintenance. Please check back soon."},DEFAULT_COMING_SOON_PAYLOAD={mode:"coming-soon",status:200,message:"Stacks is setting up camp. Check back soon for the public launch.",redirect:"/coming-soon"};function defaultsForMode(mode){return mode==="coming-soon"?DEFAULT_COMING_SOON_PAYLOAD:DEFAULT_MAINTENANCE_PAYLOAD}let siteModePaths;function currentSiteModePaths(){const cwd=process.cwd();if(siteModePaths?.cwd!==cwd)siteModePaths={cwd};return siteModePaths}export function maintenanceFilePath(){return currentSiteModePaths().maintenance??=p.storagePath("framework/down")}export function comingSoonFilePath(){return currentSiteModePaths().comingSoon??=p.storagePath("framework/coming-soon")}export function siteModeFilePath(mode){return mode==="coming-soon"?comingSoonFilePath():maintenanceFilePath()}export async function isDownForMaintenance(){try{return await Bun.file(maintenanceFilePath()).exists()}catch{return!1}}export async function isComingSoon(){try{return await Bun.file(comingSoonFilePath()).exists()}catch{return!1}}export async function maintenancePayload(){return siteModePayload("maintenance")}export async function comingSoonPayload(){return siteModePayload("coming-soon")}export async function siteModePayload(mode){try{const file=Bun.file(siteModeFilePath(mode));if(!await file.exists())return null;const content=await file.text();return{...defaultsForMode(mode),...JSON.parse(content),mode}}catch{return null}}export async function activeSiteModePayload(){return await maintenancePayload()??await comingSoonPayload()??envSiteModePayload()}function envSiteModePayload(){if(isTruthy(process.env.APP_MAINTENANCE))return{...DEFAULT_MAINTENANCE_PAYLOAD,mode:"maintenance",time:Date.now(),secret:process.env.APP_MAINTENANCE_SECRET||void 0};if(isTruthy(process.env.APP_COMING_SOON))return{...DEFAULT_COMING_SOON_PAYLOAD,mode:"coming-soon",time:Date.now(),secret:process.env.APP_COMING_SOON_SECRET||void 0};return null}function isTruthy(value){return["1","true","yes","on"].includes(String(value||"").toLowerCase())}export async function down(options={}){const payload={...DEFAULT_MAINTENANCE_PAYLOAD,...options,mode:"maintenance",time:Date.now()},frameworkDir=p.storagePath("framework"),{mkdirSync,existsSync}=await import("@stacksjs/storage");if(!existsSync(frameworkDir))mkdirSync(frameworkDir,{recursive:!0});await Bun.write(maintenanceFilePath(),JSON.stringify(payload,null,2));log.info("Application is now in maintenance mode.");if(payload.secret)log.info("Maintenance bypass secret has been configured")}export async function comingSoon(options={}){const payload={...DEFAULT_COMING_SOON_PAYLOAD,...options,mode:"coming-soon",time:Date.now()},frameworkDir=p.storagePath("framework"),{mkdirSync,existsSync}=await import("@stacksjs/storage");if(!existsSync(frameworkDir))mkdirSync(frameworkDir,{recursive:!0});await Bun.write(comingSoonFilePath(),JSON.stringify(payload,null,2));log.info("Application is now in coming soon mode.");if(payload.secret)log.info("Coming soon bypass secret has been configured")}export async function up(){const{unlinkSync,existsSync}=await import("node:fs"),filePath=maintenanceFilePath();if(existsSync(filePath)){unlinkSync(filePath);log.info("Application is now live.")}else log.info("Application is already live.")}export async function launch(){const{unlinkSync,existsSync}=await import("node:fs"),filePath=comingSoonFilePath();if(existsSync(filePath)){unlinkSync(filePath);log.info("Application is out of coming soon mode.")}else log.info("Application is not in coming soon mode.")}export function isAllowedIp(ip,allowed=[],trustLocalhost=!0){if(trustLocalhost&&["127.0.0.1","::1","localhost"].includes(ip))return!0;if(allowed.length===0)return!1;return allowed.includes(ip)}export function bypassCookieName(mode="maintenance"){return mode==="coming-soon"?"stacks_coming_soon_bypass":"stacks_maintenance_bypass"}export function hasValidBypassCookie(cookies,secret,mode="maintenance"){return cookies[bypassCookieName(mode)]===secret}export function isSecretPath(path,secret){return path===`/${secret}`||path.startsWith(`/${secret}/`)}export function maintenanceHtml(payload){const mode=payload.mode??"maintenance",defaults=defaultsForMode(mode),message=escapeHtml(payload.message||defaults.message||""),title=escapeHtml(payload.title||(mode==="coming-soon"?"Opening Soon":"Trail Maintenance"));return`<!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8">
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/server",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.74.29",
5
+ "version": "0.74.31",
6
6
  "description": "Local development and production-ready.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -58,19 +58,19 @@
58
58
  "prepublishOnly": "bun run build"
59
59
  },
60
60
  "dependencies": {
61
- "@stacksjs/auth": "0.74.29",
62
- "@stacksjs/config": "0.74.29",
63
- "@stacksjs/events": "0.74.29",
64
- "@stacksjs/i18n": "0.74.29",
65
- "@stacksjs/logging": "0.74.29",
66
- "@stacksjs/orm": "0.74.29",
67
- "@stacksjs/path": "0.74.29",
68
- "@stacksjs/router": "0.74.29",
69
- "@stacksjs/storage": "0.74.29",
61
+ "@stacksjs/auth": "0.74.31",
62
+ "@stacksjs/config": "0.74.31",
63
+ "@stacksjs/events": "0.74.31",
64
+ "@stacksjs/i18n": "0.74.31",
65
+ "@stacksjs/logging": "0.74.31",
66
+ "@stacksjs/orm": "0.74.31",
67
+ "@stacksjs/path": "0.74.31",
68
+ "@stacksjs/router": "0.74.31",
69
+ "@stacksjs/storage": "0.74.31",
70
70
  "bun-plugin-auto-imports": "^0.4.2"
71
71
  },
72
72
  "devDependencies": {
73
- "@stacksjs/validation": "0.74.29",
73
+ "@stacksjs/validation": "0.74.31",
74
74
  "better-dx": "^0.2.24"
75
75
  }
76
76
  }