@stacksjs/actions 0.74.26 → 0.74.28
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/bump.js +3 -3
- package/dist/dev/views.js +1 -1
- package/package.json +40 -40
package/dist/bump.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{execSync,log,parseOptions}from"@stacksjs/cli";import{path as p}from"@stacksjs/path";import{versionBump}from"@stacksjs/bumpx";import{generateChangelog,loadLogsmithConfig}from"@stacksjs/logsmith";import{existsSync,readdirSync,readFileSync,unlinkSync,writeFileSync}from"node:fs";import{join,relative}from"node:path";const options=parseOptions(),allowedBumps=new Set(["patch","minor","major","prepatch","preminor","premajor","prerelease"]),rawBump=options?.bump?.toString(),bumpArg=rawBump?allowedBumps.has(rawBump)||/^\d+\.\d+\.\d+(?:-[\w.]+)?$/.test(rawBump)?rawBump:null:null;if(rawBump&&!bumpArg)log.warn(`Ignoring invalid --bump "${rawBump}"; expected one of patch|minor|major or x.y.z`);const isDryRun=options?.dryRun===!0,isVerbose=options?.verbose===!0;async function readPackage(file){if(!existsSync(file))return;return await Bun.file(file).json()}const rootManifest=p.projectPath("package.json"),rootPkg=await readPackage(rootManifest),isFrameworkRelease=rootPkg?.name==="stacks"&&existsSync(p.frameworkPath("core/package.json")),bumpCwd=isFrameworkRelease?p.frameworkPath("core"):p.projectPath(),primaryManifest=isFrameworkRelease?p.frameworkPath("core/package.json"):rootManifest;async function resolveBumpArg(bump){if(!bump||/^\d+\.\d+\.\d+(?:-[\w.]+)?$/.test(bump))return bump;if(!["patch","minor","major"].includes(bump))return bump;const match=(await readPackage(primaryManifest))?.version?.match(/^(\d+)\.(\d+)\.(\d+)$/);if(!match)return bump;const major=Number(match[1]),minor=Number(match[2]),patch=Number(match[3]);if(bump==="major")return`${major+1}.0.0`;if(bump==="minor")return`${major}.${minor+1}.0`;return`${major}.${minor}.${patch+1}`}const resolvedBumpArg=await resolveBumpArg(bumpArg);async function git(args,cwd=p.projectPath(),options={}){return await execSync(["git",...args],{cwd,stdin:"inherit",stderr:"pipe",throwOnError:options.throwOnError??!0})}async function readVersion(file){const pkg=await readPackage(file);if(!pkg?.version||!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(pkg.version))throw Error(`Invalid version in ${file}: ${pkg?.version??"<missing>"}`);return pkg.version}function lockfileVersion(contents){const match=contents.match(/"lockfileVersion"\s*:\s*(\d+)/);return match?Number(match[1]):null}async function packageFilesFor(pattern,cwd){const glob=new Bun.Glob(pattern),files=[];for await(const file of glob.scan({cwd,absolute:!0,onlyFiles:!0})){if(file.includes("/node_modules/")||file.includes("/dist/")||file.includes("/pantry/"))continue;files.push(`./${relative(bumpCwd,file)}`)}return files}async function existingPackageFiles(files){const existing=[];for(const file of files){const absolutePath=join(bumpCwd,file);if(await Bun.file(absolutePath).exists())existing.push(file)}return existing}async function frameworkBumpFiles(){return Array.from(new Set([...await packageFilesFor("package.json",bumpCwd),...await packageFilesFor("*/package.json",bumpCwd),...await packageFilesFor("*/*/package.json",bumpCwd),...await existingPackageFiles(["../package.json","../defaults/ide/vscode/package.json","../api/package.json","../cloud/package.json","../docs/package.json","../orm/package.json","../server/package.json"]),...await packageFilesFor("../libs/**/package.json",bumpCwd)]))}const bumpFiles=isFrameworkRelease?await frameworkBumpFiles():["./package.json"];log.debug(`Release mode: ${isFrameworkRelease?"framework monorepo":"consumer app"} (${rootPkg?.name??"unknown"})`);log.debug(`Bumping ${bumpFiles.length} package manifest(s) in ${bumpCwd}`);await versionBump({release:resolvedBumpArg??void 0,files:bumpFiles,cwd:bumpCwd,recursive:!1,commit:!1,tag:!1,push:!1,changelog:!1,noGitCheck:!0,dryRun:isDryRun,yes:Boolean(resolvedBumpArg),verbose:isVerbose});const nextVersion=isDryRun&&resolvedBumpArg&&/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(resolvedBumpArg)?resolvedBumpArg:await readVersion(primaryManifest),latestTag=(await git(["describe","--abbrev=0","--tags"],p.projectPath(),{throwOnError:!1}).catch(()=>"")).trim();async function writeChangelog(){const config=await loadLogsmithConfig({dir:p.projectPath(),from:latestTag||void 0,to:"HEAD",output:isDryRun?!1:"CHANGELOG.md",theme:"github",verbose:isVerbose}),result=await generateChangelog(config);if(isDryRun){log.info(result.content);return}const changelogPath=p.projectPath("CHANGELOG.md");if(!existsSync(changelogPath))return;let content=readFileSync(changelogPath,"utf-8");const versionSeen=new RegExp(`\\bv?${nextVersion.replace(/\./g,"\\.")}\\b`);if(/\/compare\/[^)\s]+\.\.\.HEAD\)/.test(content))content=content.replace(/(\/compare\/[^)\s]+\.\.\.)HEAD(\))/,`$1v${nextVersion}$2`);else if(!versionSeen.test(content.split(`
|
|
1
|
+
import{execSync,log,parseOptions}from"@stacksjs/cli";import{path as p}from"@stacksjs/path";import{versionBump}from"@stacksjs/bumpx";import{generateChangelog,loadLogsmithConfig}from"@stacksjs/logsmith";import{existsSync,readdirSync,readFileSync,unlinkSync,writeFileSync}from"node:fs";import{join,relative}from"node:path";const options=parseOptions(),allowedBumps=new Set(["patch","minor","major","prepatch","preminor","premajor","prerelease"]),rawBump=options?.bump?.toString(),bumpArg=rawBump?allowedBumps.has(rawBump)||/^\d+\.\d+\.\d+(?:-[\w.]+)?$/.test(rawBump)?rawBump:null:null;if(rawBump&&!bumpArg)log.warn(`Ignoring invalid --bump "${rawBump}"; expected one of patch|minor|major or x.y.z`);const isDryRun=options?.dryRun===!0,isVerbose=options?.verbose===!0;async function readPackage(file){if(!existsSync(file))return;return await Bun.file(file).json()}const rootManifest=p.projectPath("package.json"),rootPkg=await readPackage(rootManifest),isFrameworkRelease=rootPkg?.name==="stacks"&&existsSync(p.frameworkPath("core/package.json")),bumpCwd=isFrameworkRelease?p.frameworkPath("core"):p.projectPath(),primaryManifest=isFrameworkRelease?p.frameworkPath("core/package.json"):rootManifest;async function resolveBumpArg(bump){if(!bump||/^\d+\.\d+\.\d+(?:-[\w.]+)?$/.test(bump))return bump;if(!["patch","minor","major"].includes(bump))return bump;const match=(await readPackage(primaryManifest))?.version?.match(/^(\d+)\.(\d+)\.(\d+)$/);if(!match)return bump;const major=Number(match[1]),minor=Number(match[2]),patch=Number(match[3]);if(bump==="major")return`${major+1}.0.0`;if(bump==="minor")return`${major}.${minor+1}.0`;return`${major}.${minor}.${patch+1}`}const resolvedBumpArg=await resolveBumpArg(bumpArg);async function git(args,cwd=p.projectPath(),options={}){return await execSync(["git",...args],{cwd,stdin:"inherit",stderr:"pipe",throwOnError:options.throwOnError??!0})}async function isGitIgnored(file){return(await git(["check-ignore","--",file],p.projectPath(),{throwOnError:!1})).trim().length>0}async function readVersion(file){const pkg=await readPackage(file);if(!pkg?.version||!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(pkg.version))throw Error(`Invalid version in ${file}: ${pkg?.version??"<missing>"}`);return pkg.version}function lockfileVersion(contents){const match=contents.match(/"lockfileVersion"\s*:\s*(\d+)/);return match?Number(match[1]):null}async function packageFilesFor(pattern,cwd){const glob=new Bun.Glob(pattern),files=[];for await(const file of glob.scan({cwd,absolute:!0,onlyFiles:!0})){if(file.includes("/node_modules/")||file.includes("/dist/")||file.includes("/pantry/"))continue;files.push(`./${relative(bumpCwd,file)}`)}return files}async function existingPackageFiles(files){const existing=[];for(const file of files){const absolutePath=join(bumpCwd,file);if(await Bun.file(absolutePath).exists())existing.push(file)}return existing}async function frameworkBumpFiles(){return Array.from(new Set([...await packageFilesFor("package.json",bumpCwd),...await packageFilesFor("*/package.json",bumpCwd),...await packageFilesFor("*/*/package.json",bumpCwd),...await existingPackageFiles(["../package.json","../defaults/ide/vscode/package.json","../api/package.json","../cloud/package.json","../docs/package.json","../orm/package.json","../server/package.json"]),...await packageFilesFor("../libs/**/package.json",bumpCwd)]))}const bumpFiles=isFrameworkRelease?await frameworkBumpFiles():["./package.json"];log.debug(`Release mode: ${isFrameworkRelease?"framework monorepo":"consumer app"} (${rootPkg?.name??"unknown"})`);log.debug(`Bumping ${bumpFiles.length} package manifest(s) in ${bumpCwd}`);await versionBump({release:resolvedBumpArg??void 0,files:bumpFiles,cwd:bumpCwd,recursive:!1,commit:!1,tag:!1,push:!1,changelog:!1,noGitCheck:!0,dryRun:isDryRun,yes:Boolean(resolvedBumpArg),verbose:isVerbose});const nextVersion=isDryRun&&resolvedBumpArg&&/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(resolvedBumpArg)?resolvedBumpArg:await readVersion(primaryManifest),latestTag=(await git(["describe","--abbrev=0","--tags"],p.projectPath(),{throwOnError:!1}).catch(()=>"")).trim();async function writeChangelog(){const config=await loadLogsmithConfig({dir:p.projectPath(),from:latestTag||void 0,to:"HEAD",output:isDryRun?!1:"CHANGELOG.md",theme:"github",verbose:isVerbose}),result=await generateChangelog(config);if(isDryRun){log.info(result.content);return}const changelogPath=p.projectPath("CHANGELOG.md");if(!existsSync(changelogPath))return;let content=readFileSync(changelogPath,"utf-8");const versionSeen=new RegExp(`\\bv?${nextVersion.replace(/\./g,"\\.")}\\b`);if(/\/compare\/[^)\s]+\.\.\.HEAD\)/.test(content))content=content.replace(/(\/compare\/[^)\s]+\.\.\.)HEAD(\))/,`$1v${nextVersion}$2`);else if(!versionSeen.test(content.split(`
|
|
2
2
|
`).slice(0,4).join(`
|
|
3
3
|
`)))content=content.replace(/^(#\s.*\n+)?/,(match)=>`${match??""}## v${nextVersion}
|
|
4
4
|
|
|
5
|
-
`);writeFileSync(changelogPath,content)}await writeChangelog();if(!isDryRun&&isFrameworkRelease)pinLockstepDeps(nextVersion);async function refreshPantryLock(){const lockPath=p.projectPath("pantry.lock");if(!existsSync(lockPath))return;const previousLock=readFileSync(lockPath);try{await execSync(["pantry","install","--ignore-scripts","--quiet"],{cwd:p.projectPath(),stdin:"inherit"});if(!existsSync(lockPath))throw Error("Pantry completed without writing pantry.lock")}catch(error){writeFileSync(lockPath,previousLock);throw Error("Release aborted: Pantry could not refresh pantry.lock without lifecycle scripts. The previous lockfile was restored.",{cause:error})}}if(!isDryRun)await refreshPantryLock();if(!isDryRun&&existsSync(p.projectPath("bun.lock"))){const lockPath=p.projectPath("bun.lock"),previousLock=readFileSync(lockPath);unlinkSync(lockPath);try{await execSync(["bun","install","--lockfile-only"],{cwd:p.projectPath(),stdin:"inherit"})}catch(error){writeFileSync(lockPath,previousLock);throw error}if(!existsSync(lockPath)){writeFileSync(lockPath,previousLock);throw Error("Release aborted: `bun install --lockfile-only` wrote no lockfile, so the previous one has been restored. This usually means a dependency range this bump just raised names a version that is not published yet - release that package first, then re-run.")}const expectedLockfileVersion=lockfileVersion(previousLock.toString("utf8")),regeneratedLock=readFileSync(lockPath,"utf8"),producedVersion=lockfileVersion(regeneratedLock);if(expectedLockfileVersion==null||producedVersion!==expectedLockfileVersion){writeFileSync(lockPath,previousLock);
|
|
6
|
-
`)}if(pinned>0)log.debug(`Pinned ${pinned} lockstep core dep(s) to ^${version}`)}async function stageReleaseArtifacts(){const pathspecs=isFrameworkRelease?[":(glob)storage/framework/**/package.json","package.json"]:["package.json"];for(const file of["CHANGELOG.md","bun.lock","pantry.lock"])if(existsSync(p.projectPath(file)))pathspecs.push(file)
|
|
5
|
+
`);writeFileSync(changelogPath,content)}await writeChangelog();if(!isDryRun&&isFrameworkRelease)pinLockstepDeps(nextVersion);async function refreshPantryLock(){const lockPath=p.projectPath("pantry.lock");if(!existsSync(lockPath))return;const previousLock=readFileSync(lockPath);try{await execSync(["pantry","install","--ignore-scripts","--quiet"],{cwd:p.projectPath(),stdin:"inherit"});if(!existsSync(lockPath))throw Error("Pantry completed without writing pantry.lock")}catch(error){writeFileSync(lockPath,previousLock);throw Error("Release aborted: Pantry could not refresh pantry.lock without lifecycle scripts. The previous lockfile was restored.",{cause:error})}}if(!isDryRun)await refreshPantryLock();if(!isDryRun&&existsSync(p.projectPath("bun.lock"))){const lockPath=p.projectPath("bun.lock"),previousLock=readFileSync(lockPath);unlinkSync(lockPath);try{await execSync(["bun","install","--lockfile-only"],{cwd:p.projectPath(),stdin:"inherit"})}catch(error){writeFileSync(lockPath,previousLock);throw error}if(!existsSync(lockPath)){writeFileSync(lockPath,previousLock);throw Error("Release aborted: `bun install --lockfile-only` wrote no lockfile, so the previous one has been restored. This usually means a dependency range this bump just raised names a version that is not published yet - release that package first, then re-run.")}const expectedLockfileVersion=lockfileVersion(previousLock.toString("utf8")),regeneratedLock=readFileSync(lockPath,"utf8"),producedVersion=lockfileVersion(regeneratedLock);if(expectedLockfileVersion==null||producedVersion!==expectedLockfileVersion){writeFileSync(lockPath,previousLock);const remedy=producedVersion!=null&&expectedLockfileVersion!=null&&producedVersion>expectedLockfileVersion?"the committed lockfile predates the Bun this repository declares. Regenerate it once with that toolchain (`bun install --lockfile-only`) and commit the result as its own change, then re-run the release.":"this machine's Bun is older than the one that wrote the committed lockfile. Re-run the release with the repository's declared Bun toolchain through `pantry install`.";throw Error(`Release aborted: regenerating bun.lock produced lockfileVersion ${producedVersion??"unknown"}, but the committed one is v${expectedLockfileVersion??"unknown"} \u2014 ${remedy}`)}}function lockstepPackages(version){const names=new Set;for(const entry of readdirSync(p.frameworkPath("core"),{withFileTypes:!0})){if(!entry.isDirectory())continue;const manifest=p.frameworkPath(`core/${entry.name}/package.json`);if(!existsSync(manifest))continue;const pkg=JSON.parse(readFileSync(manifest,"utf-8"));if(pkg.name?.startsWith("@stacksjs/")&&pkg.version===version)names.add(pkg.name)}return names}function pinLockstepDeps(version){const lockstep=lockstepPackages(version),next=`^${version}`,manifests=[p.frameworkPath("core/package.json"),...readdirSync(p.frameworkPath("core"),{withFileTypes:!0}).filter((entry)=>entry.isDirectory()).map((entry)=>p.frameworkPath(`core/${entry.name}/package.json`)).filter((path)=>existsSync(path))];let pinned=0;for(const manifestPath of manifests){const manifest=JSON.parse(readFileSync(manifestPath,"utf-8"));let changed=!1;for(const field of["dependencies","devDependencies"]){const deps=manifest[field];if(!deps)continue;for(const name of Object.keys(deps)){if(!lockstep.has(name)||deps[name].startsWith("workspace:")||deps[name]===next)continue;deps[name]=next;changed=!0;pinned++}}if(changed)writeFileSync(manifestPath,`${JSON.stringify(manifest,null,2)}
|
|
6
|
+
`)}if(pinned>0)log.debug(`Pinned ${pinned} lockstep core dep(s) to ^${version}`)}async function stageReleaseArtifacts(){const pathspecs=isFrameworkRelease?[":(glob)storage/framework/**/package.json","package.json"]:["package.json"];for(const file of["CHANGELOG.md","bun.lock","pantry.lock"]){if(!existsSync(p.projectPath(file)))continue;if(await isGitIgnored(file))continue;pathspecs.push(file)}await git(["add","--",...pathspecs]);const leftover=(await git(["status","--porcelain"])).split(`
|
|
7
7
|
`).map((line)=>line.trimEnd()).filter((line)=>line&&!line.startsWith("A ")&&!line.startsWith("M "));if(leftover.length)log.warn(`Kept ${leftover.length} change(s) out of the release commit:
|
|
8
8
|
${leftover.slice(0,20).join(`
|
|
9
9
|
`)}${leftover.length>20?`
|
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"),authCookie=authCookieName(),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:stxPageAuthMiddleware({cookieName:authCookie,redirectTo:"/login"}),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,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{}}
|
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.
|
|
5
|
+
"version": "0.74.28",
|
|
6
6
|
"description": "The Stacks actions.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -60,52 +60,52 @@
|
|
|
60
60
|
"prepublishOnly": "bun run build"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@stacksjs/action-runner": "0.74.
|
|
64
|
-
"@stacksjs/ai": "0.74.
|
|
65
|
-
"@stacksjs/analytics": "0.74.
|
|
66
|
-
"@stacksjs/api": "0.74.
|
|
67
|
-
"@stacksjs/auth": "0.74.
|
|
68
|
-
"@stacksjs/build": "0.74.
|
|
63
|
+
"@stacksjs/action-runner": "0.74.28",
|
|
64
|
+
"@stacksjs/ai": "0.74.28",
|
|
65
|
+
"@stacksjs/analytics": "0.74.28",
|
|
66
|
+
"@stacksjs/api": "0.74.28",
|
|
67
|
+
"@stacksjs/auth": "0.74.28",
|
|
68
|
+
"@stacksjs/build": "0.74.28",
|
|
69
69
|
"@stacksjs/bumpx": "^0.2.6",
|
|
70
70
|
"@stacksjs/bunpress": "^0.2.8",
|
|
71
|
-
"@stacksjs/cli": "0.74.
|
|
72
|
-
"@stacksjs/cloud": "0.74.
|
|
73
|
-
"@stacksjs/cms": "0.74.
|
|
74
|
-
"@stacksjs/config": "0.74.
|
|
75
|
-
"@stacksjs/database": "0.74.
|
|
76
|
-
"@stacksjs/desktop-build": "0.74.
|
|
77
|
-
"@stacksjs/dns": "0.74.
|
|
78
|
-
"@stacksjs/enums": "0.74.
|
|
79
|
-
"@stacksjs/env": "0.74.
|
|
80
|
-
"@stacksjs/error-handling": "0.74.
|
|
71
|
+
"@stacksjs/cli": "0.74.28",
|
|
72
|
+
"@stacksjs/cloud": "0.74.28",
|
|
73
|
+
"@stacksjs/cms": "0.74.28",
|
|
74
|
+
"@stacksjs/config": "0.74.28",
|
|
75
|
+
"@stacksjs/database": "0.74.28",
|
|
76
|
+
"@stacksjs/desktop-build": "0.74.28",
|
|
77
|
+
"@stacksjs/dns": "0.74.28",
|
|
78
|
+
"@stacksjs/enums": "0.74.28",
|
|
79
|
+
"@stacksjs/env": "0.74.28",
|
|
80
|
+
"@stacksjs/error-handling": "0.74.28",
|
|
81
81
|
"@stacksjs/gitit": "^0.2.5",
|
|
82
|
-
"@stacksjs/i18n": "0.74.
|
|
83
|
-
"@stacksjs/image": "0.74.
|
|
84
|
-
"@stacksjs/logging": "0.74.
|
|
82
|
+
"@stacksjs/i18n": "0.74.28",
|
|
83
|
+
"@stacksjs/image": "0.74.28",
|
|
84
|
+
"@stacksjs/logging": "0.74.28",
|
|
85
85
|
"@stacksjs/logsmith": "^0.2.3",
|
|
86
|
-
"@stacksjs/orm": "0.74.
|
|
87
|
-
"@stacksjs/path": "0.74.
|
|
88
|
-
"@stacksjs/payments": "0.74.
|
|
89
|
-
"@stacksjs/queue": "0.74.
|
|
90
|
-
"@stacksjs/registry": "0.74.
|
|
91
|
-
"@stacksjs/router": "0.74.
|
|
86
|
+
"@stacksjs/orm": "0.74.28",
|
|
87
|
+
"@stacksjs/path": "0.74.28",
|
|
88
|
+
"@stacksjs/payments": "0.74.28",
|
|
89
|
+
"@stacksjs/queue": "0.74.28",
|
|
90
|
+
"@stacksjs/registry": "0.74.28",
|
|
91
|
+
"@stacksjs/router": "0.74.28",
|
|
92
92
|
"@stacksjs/rpx": "^0.11.42",
|
|
93
|
-
"@stacksjs/scheduler": "0.74.
|
|
94
|
-
"@stacksjs/search-engine": "0.74.
|
|
95
|
-
"@stacksjs/security": "0.74.
|
|
96
|
-
"@stacksjs/server": "0.74.
|
|
97
|
-
"@stacksjs/sites": "0.74.
|
|
98
|
-
"@stacksjs/storage": "0.74.
|
|
99
|
-
"@stacksjs/strings": "0.74.
|
|
93
|
+
"@stacksjs/scheduler": "0.74.28",
|
|
94
|
+
"@stacksjs/search-engine": "0.74.28",
|
|
95
|
+
"@stacksjs/security": "0.74.28",
|
|
96
|
+
"@stacksjs/server": "0.74.28",
|
|
97
|
+
"@stacksjs/sites": "0.74.28",
|
|
98
|
+
"@stacksjs/storage": "0.74.28",
|
|
99
|
+
"@stacksjs/strings": "0.74.28",
|
|
100
100
|
"@stacksjs/stx": "^0.2.274",
|
|
101
101
|
"@stacksjs/tlsx": "^0.13.19",
|
|
102
|
-
"@stacksjs/ts-cloud": "^0.12.
|
|
102
|
+
"@stacksjs/ts-cloud": "^0.12.15",
|
|
103
103
|
"@stacksjs/ts-md": "^0.1.1",
|
|
104
|
-
"@stacksjs/tunnel": "0.74.
|
|
105
|
-
"@stacksjs/types": "0.74.
|
|
106
|
-
"@stacksjs/utils": "0.74.
|
|
107
|
-
"@stacksjs/whois": "0.74.
|
|
108
|
-
"bun-plugin-stx": "^0.2.
|
|
104
|
+
"@stacksjs/tunnel": "0.74.28",
|
|
105
|
+
"@stacksjs/types": "0.74.28",
|
|
106
|
+
"@stacksjs/utils": "0.74.28",
|
|
107
|
+
"@stacksjs/whois": "0.74.28",
|
|
108
|
+
"bun-plugin-stx": "^0.2.279"
|
|
109
109
|
},
|
|
110
110
|
"peerDependencies": {
|
|
111
111
|
"craft-native": ">=0.0.72",
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
}
|
|
121
121
|
},
|
|
122
122
|
"devDependencies": {
|
|
123
|
-
"@stacksjs/validation": "0.74.
|
|
123
|
+
"@stacksjs/validation": "0.74.28",
|
|
124
124
|
"better-dx": "^0.2.24"
|
|
125
125
|
}
|
|
126
126
|
}
|