@stacksjs/actions 0.74.37 → 0.74.38

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/dev/views.js CHANGED
@@ -1 +1 @@
1
- import{AsyncLocalStorage}from"node:async_hooks";import{existsSync}from"node:fs";import{join}from"node:path";import{config,installRequestContext,overridesReady,parseCookieHeader,resolveViewPatterns}from"@stacksjs/config";import{log}from"@stacksjs/logging";import{projectPath,siteConfigPath}from"@stacksjs/path";import{seedCsrfPageResponse}from"./csrf";import{resolveDefaultsResources}from"./defaults-resources";import{exitWithParent}from"./exit-with-parent";const requestStore=new AsyncLocalStorage;function currentRequestContext(){return requestStore.getStore()??globalThis.__stxServeContext}installRequestContext(currentRequestContext);exitWithParent();const projectServe=projectPath("serve.ts");try{if(await Bun.file(projectServe).exists())await import(projectServe);else await startDefaultServer()}catch{await startDefaultServer()}function parseCookies(req){return parseCookieHeader(req.headers.get("cookie"))}async function startDefaultServer(){await overridesReady;const{applyViewSecurityHeaders,describeApiProxyRules,describeRedirectRules,injectGlobalAutoImports,isApiBoundRequest,proxyToBackend,resolveApiProxyRules,resolveEmbeddableRules,resolveRedirect,resolveRedirectRules}=await import("@stacksjs/server"),{applyRequestLocale}=await import("@stacksjs/i18n");await injectGlobalAutoImports();const{serve}=await import("bun-plugin-stx/serve"),{site:siteConfig,i18n:i18nConfig}=await loadStxSiteConfig(),defaultsResources=resolveDefaultsResources(),userViewsPath="resources/views",defaultViewsPath=join(defaultsResources,"views"),userComponentsPath=await firstExistingPath(["resources/components","components"])??"resources/components",userLayoutsPath=await firstExistingPath(["resources/views/layouts","resources/layouts"])??"resources/views/layouts",defaultLayoutsPath=join(defaultsResources,"layouts"),userPartialsPath=await firstExistingPath(["resources/partials","resources/views/partials","partials","resources/components"]),preferredPort=Number(process.env.PORT)||3000,apiPort=Number(process.env.PORT_API)||3008,docsPort=Number(process.env.PORT_DOCS)||config.ports?.docs||3006,apiBase=`http://127.0.0.1:${apiPort}`,docsBase=`http://127.0.0.1:${docsPort}`,apiProxyRules=resolveApiProxyRules(config.server?.proxy),redirectRules=resolveRedirectRules(config.server?.redirects),embeddableRules=resolveEmbeddableRules(config.server?.security?.embeddable);if(apiProxyRules.paths.length>0||apiProxyRules.prefixes.length>1)console.log(` API proxy: ${describeApiProxyRules(apiProxyRules)}`);if(embeddableRules.paths.length>0||embeddableRules.prefixes.length>0)console.log(` Frameable by other origins: ${[...embeddableRules.paths,...embeddableRules.prefixes].join(" ")}`);if(redirectRules.size>0)console.log(` Redirects: ${describeRedirectRules(redirectRules)}`);const hasUserDocsView=["docs.stx","docs/index.stx"].some((rel)=>existsSync(projectPath(`${userViewsPath}/${rel}`))),hasDocsSite=existsSync(projectPath("docs")),docsProxyEnabled=!hasUserDocsView&&hasDocsSite,{authCookieName,stxPageAuthMiddleware}=await import("@stacksjs/auth"),{enhanceRequest,loadMiddlewareHandlers}=await import("@stacksjs/router"),authCookie=authCookieName(),pageMiddleware=await loadMiddlewareHandlers(),viewPatterns=resolveViewPatterns(userViewsPath,defaultViewsPath,config?.ui?.defaultViews,(path)=>existsSync(projectPath(path)));for(const name of viewPatterns.missing)log.warn(`ui.defaultViews lists "${name}", which does not exist under ${defaultViewsPath} - ignoring.`);await serve({patterns:viewPatterns.patterns,port:preferredPort,componentsDir:userComponentsPath,fallbackComponentsDir:join(defaultsResources,"components"),layoutsDir:userLayoutsPath,...userPartialsPath&&{partialsDir:userPartialsPath},fallbackLayoutsDir:defaultLayoutsPath,fallbackPartialsDir:defaultViewsPath,quiet:!0,openPath:process.env.STACKS_DEV_ENTRY_PATH||"/",...i18nConfig&&{i18n:i18nConfig},...siteConfig?.url&&{site:siteConfig},auth:{cookieName:authCookie,redirectTo:"/login"},middleware:{...pageMiddleware,...stxPageAuthMiddleware({cookieName:authCookie,redirectTo:"/login"})},prepareMiddlewareRequest:(request)=>enhanceRequest(request),onRequest:async(req)=>{const url=new URL(req.url),{maintenanceGate}=await import("@stacksjs/server"),gated=await maintenanceGate(req);if(gated)return gated;const redirected=resolveRedirect(url,redirectRules);if(redirected)return redirected;if(existsSync(projectPath("resources/views/blog.stx"))){const{renderBlogFeed}=await import("../blog"),feed=await renderBlogFeed(req);if(feed)return feed}else{const{renderBlog}=await import("../blog"),blogResponse=await renderBlog(req);if(blogResponse)return blogResponse}if(docsProxyEnabled&&(url.pathname==="/docs"||url.pathname.startsWith("/docs/")))return proxyToBackend(req,docsBase,"/docs");if(isApiBoundRequest(req,url.pathname,apiProxyRules))return proxyToBackend(req,apiBase);if(i18nConfig&&req.method==="GET"){const localeSwitch=url.pathname.match(/^\/locale\/([a-z]{2}(?:-[a-z]{2})?)\/?$/i);if(localeSwitch){const{createLocaleSwitchResponse}=await import("@stacksjs/i18n");return createLocaleSwitchResponse(req,localeSwitch[1],i18nConfig)}}const locale=await applyRequestLocale(req);let site=null;if(config.sites?.enabled){const sites=await import("@stacksjs/sites"),resolved=await sites.resolveSiteByHost(sites.requestHost(req.headers,sites.sitesOptions()));sites.setCurrentSite(resolved);site=sites.toSiteSnapshot(resolved)}const ctx={cookies:parseCookies(req),url:req.url,path:url.pathname,search:url.search,host:url.host,locale,site};globalThis.__stxServeSearch=url.search;globalThis.__stxServeContext=ctx;if(config.analytics?.capturePageviews)import("@stacksjs/analytics").then(({recordPageview})=>recordPageview(req)).catch(()=>{});requestStore.enterWith(ctx);return null},onResponse:async(req,response)=>{const secured=applyViewSecurityHeaders(req,response,embeddableRules),baseline=secured??response;let current=baseline;if(current.status===404&&config.sites?.enabled)try{const{cmsNotFoundFallback}=await import("@stacksjs/cms"),cmsResponse=await cmsNotFoundFallback(req);if(cmsResponse)current=cmsResponse}catch(error){log.debug(`CMS fallback skipped: ${error.message}`)}return await seedCsrfPageResponse(req,current)??(current===baseline?secured:current)}})}async function firstExistingPath(candidates){const existing=candidates.filter((candidate)=>existsSync(projectPath(candidate)));if(existing.length===0)return null;for(const candidate of existing)if(containsTemplates(projectPath(candidate)))return candidate;return existing[0]}function containsTemplates(dir){try{return[...new Bun.Glob("**/*.stx").scanSync({cwd:dir,onlyFiles:!0})].length>0}catch{return!1}}function fallbackI18nFromSite(site){const locales=site.i18n.locales,defaultLocale=site.i18n.defaultLocale??locales[0];return{locales,defaultLocale,labels:site.i18n.labels??Object.fromEntries(locales.map((c)=>[c,c.toUpperCase()])),translations:{},pickerSelector:site.i18n.pickerSelector??"#lang-picker"}}async function resolveSiteI18n(site){try{const{resolveI18n}=await import("@stacksjs/stx");if(typeof resolveI18n==="function"){const i18n=resolveI18n(site,projectPath());if(i18n)return i18n}}catch{}return fallbackI18nFromSite(site)}async function loadStxSiteConfig(){const sitePath=siteConfigPath();if(!existsSync(sitePath))return{};try{const mod=await import(sitePath),site=mod.default??mod.site??mod.config;if(!site)return{};if(!site.i18n)return{site};const i18n=await resolveSiteI18n(site);return{site,i18n}}catch{}return{}}
1
+ import{AsyncLocalStorage}from"node:async_hooks";import{existsSync}from"node:fs";import{join}from"node:path";import{config,installRequestContext,overridesReady,parseCookieHeader,resolveViewPatterns}from"@stacksjs/config";import{log}from"@stacksjs/logging";import{projectPath,siteConfigPath}from"@stacksjs/path";import{seedCsrfPageResponse}from"./csrf";import{resolveDefaultsResources}from"./defaults-resources";import{exitWithParent}from"./exit-with-parent";const requestStore=new AsyncLocalStorage;function currentRequestContext(){return requestStore.getStore()??globalThis.__stxServeContext}installRequestContext(currentRequestContext);exitWithParent();const projectServe=projectPath("serve.ts");try{if(await Bun.file(projectServe).exists())await import(projectServe);else await startDefaultServer()}catch{await startDefaultServer()}function parseCookies(req){return parseCookieHeader(req.headers.get("cookie"))}async function startDefaultServer(){await overridesReady;const{applyViewSecurityHeaders,describeApiProxyRules,describeRedirectRules,describeRewriteRules,injectGlobalAutoImports,isApiBoundRequest,proxyToBackend,resolveApiProxyRules,resolveEmbeddableRules,resolveRedirect,resolveRedirectRules,resolveRewrite,resolveRewriteRules}=await import("@stacksjs/server"),{applyRequestLocale}=await import("@stacksjs/i18n");await injectGlobalAutoImports();const{serve}=await import("bun-plugin-stx/serve"),{site:siteConfig,i18n:i18nConfig}=await loadStxSiteConfig(),defaultsResources=resolveDefaultsResources(),userViewsPath="resources/views",defaultViewsPath=join(defaultsResources,"views"),userComponentsPath=await firstExistingPath(["resources/components","components"])??"resources/components",userLayoutsPath=await firstExistingPath(["resources/views/layouts","resources/layouts"])??"resources/views/layouts",defaultLayoutsPath=join(defaultsResources,"layouts"),userPartialsPath=await firstExistingPath(["resources/partials","resources/views/partials","partials","resources/components"]),preferredPort=Number(process.env.PORT)||3000,apiPort=Number(process.env.PORT_API)||3008,docsPort=Number(process.env.PORT_DOCS)||config.ports?.docs||3006,apiBase=`http://127.0.0.1:${apiPort}`,docsBase=`http://127.0.0.1:${docsPort}`,apiProxyRules=resolveApiProxyRules(config.server?.proxy),redirectRules=resolveRedirectRules(config.server?.redirects),rewriteRules=resolveRewriteRules(config.server?.rewrites),embeddableRules=resolveEmbeddableRules(config.server?.security?.embeddable);if(apiProxyRules.paths.length>0||apiProxyRules.prefixes.length>1)console.log(` API proxy: ${describeApiProxyRules(apiProxyRules)}`);if(embeddableRules.paths.length>0||embeddableRules.prefixes.length>0)console.log(` Frameable by other origins: ${[...embeddableRules.paths,...embeddableRules.prefixes].join(" ")}`);if(redirectRules.size>0){console.log(` Redirects: ${describeRedirectRules(redirectRules)}`);if(rewriteRules.size>0)console.log(` Rewrites: ${describeRewriteRules(rewriteRules)}`)}const hasUserDocsView=["docs.stx","docs/index.stx"].some((rel)=>existsSync(projectPath(`${userViewsPath}/${rel}`))),hasDocsSite=existsSync(projectPath("docs")),docsProxyEnabled=!hasUserDocsView&&hasDocsSite,{authCookieName,stxPageAuthMiddleware}=await import("@stacksjs/auth"),{enhanceRequest,loadMiddlewareHandlers}=await import("@stacksjs/router"),authCookie=authCookieName(),pageMiddleware=await loadMiddlewareHandlers(),viewPatterns=resolveViewPatterns(userViewsPath,defaultViewsPath,config?.ui?.defaultViews,(path)=>existsSync(projectPath(path)));for(const name of viewPatterns.missing)log.warn(`ui.defaultViews lists "${name}", which does not exist under ${defaultViewsPath} - ignoring.`);await serve({patterns:viewPatterns.patterns,port:preferredPort,componentsDir:userComponentsPath,fallbackComponentsDir:join(defaultsResources,"components"),layoutsDir:userLayoutsPath,...userPartialsPath&&{partialsDir:userPartialsPath},fallbackLayoutsDir:defaultLayoutsPath,fallbackPartialsDir:defaultViewsPath,quiet:!0,openPath:process.env.STACKS_DEV_ENTRY_PATH||"/",...i18nConfig&&{i18n:i18nConfig},...siteConfig?.url&&{site:siteConfig},auth:{cookieName:authCookie,redirectTo:"/login"},middleware:{...pageMiddleware,...stxPageAuthMiddleware({cookieName:authCookie,redirectTo:"/login"})},prepareMiddlewareRequest:(request)=>enhanceRequest(request),onRequest:async(req)=>{const url=new URL(req.url),{maintenanceGate}=await import("@stacksjs/server"),gated=await maintenanceGate(req);if(gated)return gated;const redirected=resolveRedirect(url,redirectRules);if(redirected)return redirected;const rewritten=resolveRewrite(url.pathname,rewriteRules);if(rewritten){const target=new URL(`${rewritten}${url.search}`,url.origin);return proxyToBackend(new Request(target,req),apiBase)}if(existsSync(projectPath("resources/views/blog.stx"))){const{renderBlogFeed}=await import("../blog"),feed=await renderBlogFeed(req);if(feed)return feed}else{const{renderBlog}=await import("../blog"),blogResponse=await renderBlog(req);if(blogResponse)return blogResponse}if(docsProxyEnabled&&(url.pathname==="/docs"||url.pathname.startsWith("/docs/")))return proxyToBackend(req,docsBase,"/docs");if(isApiBoundRequest(req,url.pathname,apiProxyRules))return proxyToBackend(req,apiBase);if(i18nConfig&&req.method==="GET"){const localeSwitch=url.pathname.match(/^\/locale\/([a-z]{2}(?:-[a-z]{2})?)\/?$/i);if(localeSwitch){const{createLocaleSwitchResponse}=await import("@stacksjs/i18n");return createLocaleSwitchResponse(req,localeSwitch[1],i18nConfig)}}const locale=await applyRequestLocale(req);let site=null;if(config.sites?.enabled){const sites=await import("@stacksjs/sites"),resolved=await sites.resolveSiteByHost(sites.requestHost(req.headers,sites.sitesOptions()));sites.setCurrentSite(resolved);site=sites.toSiteSnapshot(resolved)}const ctx={cookies:parseCookies(req),url:req.url,path:url.pathname,search:url.search,host:url.host,locale,site};globalThis.__stxServeSearch=url.search;globalThis.__stxServeContext=ctx;if(config.analytics?.capturePageviews)import("@stacksjs/analytics").then(({recordPageview})=>recordPageview(req)).catch(()=>{});requestStore.enterWith(ctx);return null},onResponse:async(req,response)=>{const secured=applyViewSecurityHeaders(req,response,embeddableRules),baseline=secured??response;let current=baseline;if(current.status===404&&config.sites?.enabled)try{const{cmsNotFoundFallback}=await import("@stacksjs/cms"),cmsResponse=await cmsNotFoundFallback(req);if(cmsResponse)current=cmsResponse}catch(error){log.debug(`CMS fallback skipped: ${error.message}`)}return await seedCsrfPageResponse(req,current)??(current===baseline?secured:current)}})}async function firstExistingPath(candidates){const existing=candidates.filter((candidate)=>existsSync(projectPath(candidate)));if(existing.length===0)return null;for(const candidate of existing)if(containsTemplates(projectPath(candidate)))return candidate;return existing[0]}function containsTemplates(dir){try{return[...new Bun.Glob("**/*.stx").scanSync({cwd:dir,onlyFiles:!0})].length>0}catch{return!1}}function fallbackI18nFromSite(site){const locales=site.i18n.locales,defaultLocale=site.i18n.defaultLocale??locales[0];return{locales,defaultLocale,labels:site.i18n.labels??Object.fromEntries(locales.map((c)=>[c,c.toUpperCase()])),translations:{},pickerSelector:site.i18n.pickerSelector??"#lang-picker"}}async function resolveSiteI18n(site){try{const{resolveI18n}=await import("@stacksjs/stx");if(typeof resolveI18n==="function"){const i18n=resolveI18n(site,projectPath());if(i18n)return i18n}}catch{}return fallbackI18nFromSite(site)}async function loadStxSiteConfig(){const sitePath=siteConfigPath();if(!existsSync(sitePath))return{};try{const mod=await import(sitePath),site=mod.default??mod.site??mod.config;if(!site)return{};if(!site.i18n)return{site};const i18n=await resolveSiteI18n(site);return{site,i18n}}catch{}return{}}
@@ -0,0 +1,19 @@
1
+ import { path } from '@stacksjs/path';
2
+ /**
3
+ * Wrap the diagram in a fenced Mermaid block when the target is markdown.
4
+ *
5
+ * A `.md` file holding a bare `erDiagram` renders as a paragraph of broken
6
+ * text; a `.mmd` file holding a fence is not a Mermaid file. The extension is
7
+ * the only signal available, and getting it wrong is visible immediately, so
8
+ * this decides rather than asking.
9
+ */
10
+ export declare function wrapForTarget(diagram: string, outPath: string): string;
11
+ export declare function generateErd(options?: GenerateErdOptions): Promise<GenerateErdResult>;
12
+ export declare interface GenerateErdOptions {
13
+ dryRun?: boolean
14
+ out?: string
15
+ noColumns?: boolean
16
+ only?: string[]
17
+ }
18
+ export type GenerateErdResult = | { ok: false, error: string }
19
+ | { ok: true, diagram: string, path: string, modelCount: number, skipped: string[] }
@@ -0,0 +1,9 @@
1
+ import{dirname}from"node:path";import{renderErd,resolveModelSources,toDiagrammableModel}from"@stacksjs/database";import{log}from"@stacksjs/logging";import{path}from"@stacksjs/path";import{fs}from"@stacksjs/storage";function tableNameFor(definition,fileName){if(definition?.table)return definition.table;const snake=(definition?.name??fileName).replace(/([a-z0-9])([A-Z])/g,"$1_$2").toLowerCase();if(/(?:s|x|z|ch|sh)$/.test(snake))return`${snake}es`;if(/[^aeiou]y$/.test(snake))return`${snake.slice(0,-1)}ies`;return`${snake}s`}export function wrapForTarget(diagram,outPath){return outPath.endsWith(".md")?`# Entity Relationships
2
+
3
+ <!-- Generated by \`buddy generate:erd\`. Edit your models, not this. -->
4
+
5
+ \`\`\`mermaid
6
+ ${diagram}
7
+ \`\`\`
8
+ `:`${diagram}
9
+ `}export async function generateErd(options={}){const sources=resolveModelSources();if(!sources||sources.models.length===0)return{ok:!1,error:"No models found. The diagram is derived from your models, so there is nothing to generate."};const models=[],skipped=[];for(const source of sources.models)try{const definition=(await import(source.file)).default;if(!definition)continue;models.push(toDiagrammableModel(definition,tableNameFor(definition,source.name)))}catch(error){skipped.push(`${source.name}: ${error.message}`)}for(const failure of skipped)log.warn(`[generate:erd] skipped ${failure}`);if(models.length===0)return{ok:!1,error:"Every model failed to load; nothing to diagram."};const diagram=renderErd(models,{columns:!options.noColumns,...options.only&&options.only.length>0?{only:options.only}:{}}),outPath=path.projectPath(options.out??"docs/erd.md");if(!options.dryRun){fs.mkdirSync(dirname(outPath),{recursive:!0});await Bun.write(outPath,wrapForTarget(diagram,outPath))}return{ok:!0,diagram,path:outPath,modelCount:models.length,skipped}}
@@ -1,6 +1,7 @@
1
1
  import { generateProjectImages } from './images';
2
2
  import type { GeneratorOptions } from '@stacksjs/types';
3
3
  export type { GenerateImagesActionOptions } from './images';
4
+ export type { GenerateErdOptions, GenerateErdResult } from './erd';
4
5
  export type { GenerateVSchemaOptions, GenerateVSchemaResult } from './vschema';
5
6
  // import { files } from '@stacksjs/storage'
6
7
  export declare function invoke(options?: GeneratorOptions): Promise<void>;
@@ -46,5 +47,7 @@ export declare function generateSeeder(): Promise<void>;
46
47
  export declare function generateCoreSymlink(): Promise<void>;
47
48
  export declare function generateOpenApiSpec(): Promise<void>;
48
49
  export { generateProjectImages } from './images';
50
+ // An entity-relationship diagram, derived from the models (#439).
51
+ export { generateErd, wrapForTarget } from './erd';
49
52
  // Vitess keyspace VSchema, derived from the model relationship graph.
50
53
  export { generateVSchema } from './vschema';
@@ -1 +1 @@
1
- import*as fs from"node:fs";import process from"node:process";import{runCommand}from"@stacksjs/cli";import{Action,NpmScript}from"@stacksjs/enums";import{log}from"@stacksjs/logging";import{frameworkPath,projectPath}from"@stacksjs/path";import{ExitCode}from"@stacksjs/types";import{runNpmScript}from"@stacksjs/utils";import{runAction}from"../helpers";import{generateVsCodeCustomData as genVsCodeCustomData,generateWebTypes as genWebTypes}from"../helpers/vscode-custom-data";import{generateProjectImages}from"./images";import{generateRouteNames}from"./action-types";export{generateProjectImages}from"./images";export{generateVSchema}from"./vschema";export async function invoke(options){if(options?.types)await generateTypes(options);else if(options?.entries)await generateLibEntries(options);else if(options?.webTypes)await generateWebTypes();else if(options?.customData)await generateVsCodeCustomData();else if(options?.ideHelpers)await generateIdeHelpers();else if(options?.componentMeta)await generateComponentMeta();else if(options?.coreSymlink)await generateCoreSymlink();else if(options?.openApiSpec)await generateOpenApiSpec();else if(options?.images)await generateProjectImages({verbose:options?.verbose});else await generateEverything(options)}async function generateEverything(options){log.info("Generating types, entry points, component meta and the OpenAPI spec...");try{const{discoverPackages}=await import("../discover-packages");await discoverPackages()}catch{}await generateTypes({...options,types:!0});await generateLibEntries({...options,entries:!0});await generateOpenApiSpec();log.success("Generated")}export function generate(options){return invoke(options)}export async function generateLibEntries(options){const result=await runAction(Action.GenerateLibraryEntries,{...options,cwd:projectPath()});if(result.isErr){await log.error("There was an error generating your library entry points",result.error);process.exit(ExitCode.FatalError)}log.success("Library entry points generated successfully")}export async function generateWebTypes(){await genWebTypes()}export async function generateVsCodeCustomData(){const result=await genVsCodeCustomData();if(result.isErr){await log.error("There was an error generating the custom-elements.json file.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated the custom-elements.json file")}export async function generateIdeHelpers(){await genWebTypes();await genVsCodeCustomData();await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated IDE helpers")}export async function generateComponentMeta(){const result=await genVsCodeCustomData();if(result.isErr){await log.error("There was an error generating your component meta information.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated component meta information")}export async function generateTypes(options){try{const{generateAutoImportFiles}=await import("@stacksjs/server");await generateAutoImportFiles()}catch(error){log.debug("[generate:types] Could not refresh the auto-import registries",{error})}await generateRouteNames();try{const previous=process.env.STACKS_CANONICAL_FEATURES;process.env.STACKS_CANONICAL_FEATURES="1";try{const{generateServerAutoImportTypes}=await import("@stacksjs/server");await generateServerAutoImportTypes()}finally{if(previous===void 0)delete process.env.STACKS_CANONICAL_FEATURES;else process.env.STACKS_CANONICAL_FEATURES=previous}}catch(error){log.debug("[generate:types] Could not refresh server auto-import declarations",{error})}const entry=frameworkPath("core/actions/src/generate/types.ts");if(!fs.existsSync(entry)){await import(`./types?t=${Date.now()}`);return}const result=await runNpmScript(NpmScript.GenerateTypes,{cwd:frameworkPath(),...options});if(result.isErr){log.error("There was an error generating your types.",result.error);throw result.error instanceof Error?result.error:Error(String(result.error))}log.success("Types were generated successfully")}export async function watchTypes(options){try{const manifestPath=`${frameworkPath()}/package.json`,text=fs.existsSync(manifestPath)?fs.readFileSync(manifestPath,"utf-8"):"";if(!(text?JSON.parse(text):{})?.scripts?.["generate:types"]){log.warn("[generate:types --watch] no `generate:types` script in framework package.json - type regeneration disabled. dev:api will keep running, but type definitions won't auto-refresh on model/config changes.");return}}catch{}const watched=[...await(async()=>{try{const{autoImportSourceDirs}=await import("@stacksjs/server");return autoImportSourceDirs()}catch{return[]}})(),projectPath("config"),projectPath("database/migrations"),projectPath("app"),projectPath("routes")].filter((dir,index,all)=>all.indexOf(dir)===index);log.info(`[generate:types --watch] watching ${watched.length} directories`);let pending=null,inflight=!1;const trigger=()=>{if(pending)clearTimeout(pending);pending=setTimeout(async()=>{if(inflight)return;inflight=!0;try{log.info("[generate:types --watch] change detected, regenerating\u2026");await generateTypes(options);log.success("[generate:types --watch] types up to date")}catch(err){log.error("[generate:types --watch] regeneration failed:",err)}finally{inflight=!1}},200)},watchers=[];for(const dir of watched)try{if(!fs.existsSync(dir))continue;const w=fs.watch(dir,{recursive:!0},()=>trigger());watchers.push(w)}catch(err){log.warn(`[generate:types --watch] cannot watch ${dir}: ${err}`)}if(watchers.length===0){log.warn("[generate:types --watch] no directories to watch - exiting");return}await new Promise((resolve)=>{process.once("SIGINT",()=>{log.info("[generate:types --watch] stopping");for(const w of watchers)try{w.close()}catch{}resolve()})})}export function generatePantryConfig(){log.success("Successfully generated `./pantry.yaml` based on your config")}export async function generateSeeder(){}export async function generateCoreSymlink(){const link=projectPath(".framework");if(fs.existsSync(link))await runCommand(`rm -f ${link}`);await runCommand(`ln -s ${frameworkPath()} ${link}`)}export async function generateOpenApiSpec(){const{generateOpenApi}=await import("@stacksjs/api");await generateOpenApi();log.success("Successfully generated Open API Spec")}
1
+ import*as fs from"node:fs";import process from"node:process";import{runCommand}from"@stacksjs/cli";import{Action,NpmScript}from"@stacksjs/enums";import{log}from"@stacksjs/logging";import{frameworkPath,projectPath}from"@stacksjs/path";import{ExitCode}from"@stacksjs/types";import{runNpmScript}from"@stacksjs/utils";import{runAction}from"../helpers";import{generateVsCodeCustomData as genVsCodeCustomData,generateWebTypes as genWebTypes}from"../helpers/vscode-custom-data";import{generateProjectImages}from"./images";import{generateRouteNames}from"./action-types";export{generateProjectImages}from"./images";export{generateErd,wrapForTarget}from"./erd";export{generateVSchema}from"./vschema";export async function invoke(options){if(options?.types)await generateTypes(options);else if(options?.entries)await generateLibEntries(options);else if(options?.webTypes)await generateWebTypes();else if(options?.customData)await generateVsCodeCustomData();else if(options?.ideHelpers)await generateIdeHelpers();else if(options?.componentMeta)await generateComponentMeta();else if(options?.coreSymlink)await generateCoreSymlink();else if(options?.openApiSpec)await generateOpenApiSpec();else if(options?.images)await generateProjectImages({verbose:options?.verbose});else await generateEverything(options)}async function generateEverything(options){log.info("Generating types, entry points, component meta and the OpenAPI spec...");try{const{discoverPackages}=await import("../discover-packages");await discoverPackages()}catch{}await generateTypes({...options,types:!0});await generateLibEntries({...options,entries:!0});await generateOpenApiSpec();log.success("Generated")}export function generate(options){return invoke(options)}export async function generateLibEntries(options){const result=await runAction(Action.GenerateLibraryEntries,{...options,cwd:projectPath()});if(result.isErr){await log.error("There was an error generating your library entry points",result.error);process.exit(ExitCode.FatalError)}log.success("Library entry points generated successfully")}export async function generateWebTypes(){await genWebTypes()}export async function generateVsCodeCustomData(){const result=await genVsCodeCustomData();if(result.isErr){await log.error("There was an error generating the custom-elements.json file.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated the custom-elements.json file")}export async function generateIdeHelpers(){await genWebTypes();await genVsCodeCustomData();await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated IDE helpers")}export async function generateComponentMeta(){const result=await genVsCodeCustomData();if(result.isErr){await log.error("There was an error generating your component meta information.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated component meta information")}export async function generateTypes(options){try{const{generateAutoImportFiles}=await import("@stacksjs/server");await generateAutoImportFiles()}catch(error){log.debug("[generate:types] Could not refresh the auto-import registries",{error})}await generateRouteNames();try{const previous=process.env.STACKS_CANONICAL_FEATURES;process.env.STACKS_CANONICAL_FEATURES="1";try{const{generateServerAutoImportTypes}=await import("@stacksjs/server");await generateServerAutoImportTypes()}finally{if(previous===void 0)delete process.env.STACKS_CANONICAL_FEATURES;else process.env.STACKS_CANONICAL_FEATURES=previous}}catch(error){log.debug("[generate:types] Could not refresh server auto-import declarations",{error})}const entry=frameworkPath("core/actions/src/generate/types.ts");if(!fs.existsSync(entry)){await import(`./types?t=${Date.now()}`);return}const result=await runNpmScript(NpmScript.GenerateTypes,{cwd:frameworkPath(),...options});if(result.isErr){log.error("There was an error generating your types.",result.error);throw result.error instanceof Error?result.error:Error(String(result.error))}log.success("Types were generated successfully")}export async function watchTypes(options){try{const manifestPath=`${frameworkPath()}/package.json`,text=fs.existsSync(manifestPath)?fs.readFileSync(manifestPath,"utf-8"):"";if(!(text?JSON.parse(text):{})?.scripts?.["generate:types"]){log.warn("[generate:types --watch] no `generate:types` script in framework package.json - type regeneration disabled. dev:api will keep running, but type definitions won't auto-refresh on model/config changes.");return}}catch{}const watched=[...await(async()=>{try{const{autoImportSourceDirs}=await import("@stacksjs/server");return autoImportSourceDirs()}catch{return[]}})(),projectPath("config"),projectPath("database/migrations"),projectPath("app"),projectPath("routes")].filter((dir,index,all)=>all.indexOf(dir)===index);log.info(`[generate:types --watch] watching ${watched.length} directories`);let pending=null,inflight=!1;const trigger=()=>{if(pending)clearTimeout(pending);pending=setTimeout(async()=>{if(inflight)return;inflight=!0;try{log.info("[generate:types --watch] change detected, regenerating\u2026");await generateTypes(options);log.success("[generate:types --watch] types up to date")}catch(err){log.error("[generate:types --watch] regeneration failed:",err)}finally{inflight=!1}},200)},watchers=[];for(const dir of watched)try{if(!fs.existsSync(dir))continue;const w=fs.watch(dir,{recursive:!0},()=>trigger());watchers.push(w)}catch(err){log.warn(`[generate:types --watch] cannot watch ${dir}: ${err}`)}if(watchers.length===0){log.warn("[generate:types --watch] no directories to watch - exiting");return}await new Promise((resolve)=>{process.once("SIGINT",()=>{log.info("[generate:types --watch] stopping");for(const w of watchers)try{w.close()}catch{}resolve()})})}export function generatePantryConfig(){log.success("Successfully generated `./pantry.yaml` based on your config")}export async function generateSeeder(){}export async function generateCoreSymlink(){const link=projectPath(".framework");if(fs.existsSync(link))await runCommand(`rm -f ${link}`);await runCommand(`ln -s ${frameworkPath()} ${link}`)}export async function generateOpenApiSpec(){const{generateOpenApi}=await import("@stacksjs/api");await generateOpenApi();log.success("Successfully generated Open API Spec")}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/actions",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.74.37",
5
+ "version": "0.74.38",
6
6
  "description": "The Stacks actions.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -60,51 +60,51 @@
60
60
  "prepublishOnly": "bun run build"
61
61
  },
62
62
  "dependencies": {
63
- "@stacksjs/action-runner": "0.74.37",
64
- "@stacksjs/ai": "0.74.37",
65
- "@stacksjs/analytics": "0.74.37",
66
- "@stacksjs/api": "0.74.37",
67
- "@stacksjs/auth": "0.74.37",
68
- "@stacksjs/build": "0.74.37",
63
+ "@stacksjs/action-runner": "0.74.38",
64
+ "@stacksjs/ai": "0.74.38",
65
+ "@stacksjs/analytics": "0.74.38",
66
+ "@stacksjs/api": "0.74.38",
67
+ "@stacksjs/auth": "0.74.38",
68
+ "@stacksjs/build": "0.74.38",
69
69
  "@stacksjs/bumpx": "^0.2.6",
70
70
  "@stacksjs/bunpress": "^0.2.8",
71
- "@stacksjs/cli": "0.74.37",
72
- "@stacksjs/cloud": "0.74.37",
73
- "@stacksjs/cms": "0.74.37",
74
- "@stacksjs/config": "0.74.37",
75
- "@stacksjs/database": "0.74.37",
76
- "@stacksjs/desktop-build": "0.74.37",
77
- "@stacksjs/dns": "0.74.37",
78
- "@stacksjs/enums": "0.74.37",
79
- "@stacksjs/env": "0.74.37",
80
- "@stacksjs/error-handling": "0.74.37",
71
+ "@stacksjs/cli": "0.74.38",
72
+ "@stacksjs/cloud": "0.74.38",
73
+ "@stacksjs/cms": "0.74.38",
74
+ "@stacksjs/config": "0.74.38",
75
+ "@stacksjs/database": "0.74.38",
76
+ "@stacksjs/desktop-build": "0.74.38",
77
+ "@stacksjs/dns": "0.74.38",
78
+ "@stacksjs/enums": "0.74.38",
79
+ "@stacksjs/env": "0.74.38",
80
+ "@stacksjs/error-handling": "0.74.38",
81
81
  "@stacksjs/gitit": "^0.2.5",
82
- "@stacksjs/i18n": "0.74.37",
83
- "@stacksjs/image": "0.74.37",
84
- "@stacksjs/logging": "0.74.37",
82
+ "@stacksjs/i18n": "0.74.38",
83
+ "@stacksjs/image": "0.74.38",
84
+ "@stacksjs/logging": "0.74.38",
85
85
  "@stacksjs/logsmith": "^0.2.3",
86
- "@stacksjs/orm": "0.74.37",
87
- "@stacksjs/path": "0.74.37",
88
- "@stacksjs/payments": "0.74.37",
89
- "@stacksjs/queue": "0.74.37",
90
- "@stacksjs/registry": "0.74.37",
91
- "@stacksjs/router": "0.74.37",
86
+ "@stacksjs/orm": "0.74.38",
87
+ "@stacksjs/path": "0.74.38",
88
+ "@stacksjs/payments": "0.74.38",
89
+ "@stacksjs/queue": "0.74.38",
90
+ "@stacksjs/registry": "0.74.38",
91
+ "@stacksjs/router": "0.74.38",
92
92
  "@stacksjs/rpx": "^0.11.53",
93
- "@stacksjs/scheduler": "0.74.37",
94
- "@stacksjs/search-engine": "0.74.37",
95
- "@stacksjs/security": "0.74.37",
96
- "@stacksjs/server": "0.74.37",
97
- "@stacksjs/sites": "0.74.37",
98
- "@stacksjs/storage": "0.74.37",
99
- "@stacksjs/strings": "0.74.37",
93
+ "@stacksjs/scheduler": "0.74.38",
94
+ "@stacksjs/search-engine": "0.74.38",
95
+ "@stacksjs/security": "0.74.38",
96
+ "@stacksjs/server": "0.74.38",
97
+ "@stacksjs/sites": "0.74.38",
98
+ "@stacksjs/storage": "0.74.38",
99
+ "@stacksjs/strings": "0.74.38",
100
100
  "@stacksjs/stx": "^0.2.284",
101
101
  "@stacksjs/tlsx": "^0.13.19",
102
102
  "@stacksjs/ts-cloud": "^0.15.1",
103
103
  "@stacksjs/ts-md": "^0.1.1",
104
- "@stacksjs/tunnel": "0.74.37",
105
- "@stacksjs/types": "0.74.37",
106
- "@stacksjs/utils": "0.74.37",
107
- "@stacksjs/whois": "0.74.37",
104
+ "@stacksjs/tunnel": "0.74.38",
105
+ "@stacksjs/types": "0.74.38",
106
+ "@stacksjs/utils": "0.74.38",
107
+ "@stacksjs/whois": "0.74.38",
108
108
  "bun-plugin-stx": "^0.2.279"
109
109
  },
110
110
  "peerDependencies": {
@@ -120,7 +120,7 @@
120
120
  }
121
121
  },
122
122
  "devDependencies": {
123
- "@stacksjs/validation": "0.74.37",
123
+ "@stacksjs/validation": "0.74.38",
124
124
  "better-dx": "^0.2.24"
125
125
  }
126
126
  }