@stacksjs/actions 0.74.0 → 0.74.2
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/blog-admin.js +2 -2
- package/dist/build/core.js +1 -1
- package/dist/build/desktop.js +1 -1
- package/dist/build/dmg.js +2 -2
- package/dist/build/run-build-step.d.ts +1 -1
- package/dist/build/run-build-step.js +2 -2
- package/dist/build/stacks.js +1 -1
- package/dist/deploy/index.js +1 -1
- package/dist/generate/index.d.ts +2 -2
- package/dist/generate/index.js +1 -1
- package/dist/helpers/vscode-custom-data.d.ts +6 -1
- package/dist/helpers/vscode-custom-data.js +2 -5
- package/dist/library/publish.d.ts +15 -4
- package/dist/library/publish.js +1 -1
- package/package.json +38 -38
package/dist/blog-admin.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{existsSync,mkdirSync,readdirSync,readFileSync,statSync,unlinkSync,writeFileSync}from"node:fs";import{join}from"node:path";const
|
|
1
|
+
import{existsSync,mkdirSync,readdirSync,readFileSync,statSync,unlinkSync,writeFileSync}from"node:fs";import{join}from"node:path";import process from"node:process";function contentDir(){const override=process.env.STACKS_BLOG_CONTENT_DIR;return override&&override.trim()?override:join(process.cwd(),"content/blog")}const FIELD_ORDER=["title","description","date","author","authorBio","poster","featured","draft"];export class BlogAdminError extends Error{status;constructor(message,status=422){super(message);this.status=status;this.name="BlogAdminError"}}export function slugify(input){return String(input).normalize("NFKD").replace(/[\u0300-\u036F]/g,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)}function assertSafeSlug(slug){if(!slug)throw new BlogAdminError("A slug is required.");if(!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug))throw new BlogAdminError(`Invalid slug "${slug}". Use lowercase letters, numbers, and hyphens.`);return slug}function parseFrontmatter(md){const m=md.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);if(!m)return{data:{},body:md};const data={};for(const line of(m[1]??"").split(`
|
|
2
2
|
`)){const i=line.indexOf(":");if(i===-1)continue;const key=line.slice(0,i).trim();let val=line.slice(i+1).trim();if(val.startsWith('"')&&val.endsWith('"')||val.startsWith("'")&&val.endsWith("'"))val=val.slice(1,-1);data[key]=val}return{data,body:m[2]??""}}function serialiseValue(key,value){if(/[\r\n]/.test(value))throw new BlogAdminError(`"${key}" cannot contain line breaks.`);if(!(/^["']|["']$|^\s|\s$|:\s/.test(value)||value===""))return value;if(value.includes('"'))return`'${value}'`;return`"${value}"`}function toFileContents(post){const fm=[];for(const key of FIELD_ORDER){const raw=post[key];if(typeof raw==="boolean"){if(raw)fm.push(`${key}: true`);continue}const value=String(raw??"");if(!value)continue;fm.push(`${key}: ${serialiseValue(key,value)}`)}const body=post.body.replace(/\s+$/,"");return`---
|
|
3
3
|
${fm.join(`
|
|
4
4
|
`)}
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
${body}
|
|
8
|
-
`}function readingTimeFor(body){const wordCount=body.split(/\s+/).filter(Boolean).length;return{wordCount,readingTime:Math.max(1,Math.round(wordCount/200))}}function hydrate(slug,raw,updatedAt){const{data,body}=parseFrontmatter(raw),{wordCount,readingTime}=readingTimeFor(body);return{slug,title:data.title??"",description:data.description??"",date:data.date??"",author:data.author??"",authorBio:data.authorBio??"",poster:data.poster??"",featured:data.featured==="true",draft:data.draft==="true",body:body.trim(),wordCount,readingTime,updatedAt}}function fileFor(slug){return join(
|
|
8
|
+
`}function readingTimeFor(body){const wordCount=body.split(/\s+/).filter(Boolean).length;return{wordCount,readingTime:Math.max(1,Math.round(wordCount/200))}}function hydrate(slug,raw,updatedAt){const{data,body}=parseFrontmatter(raw),{wordCount,readingTime}=readingTimeFor(body);return{slug,title:data.title??"",description:data.description??"",date:data.date??"",author:data.author??"",authorBio:data.authorBio??"",poster:data.poster??"",featured:data.featured==="true",draft:data.draft==="true",body:body.trim(),wordCount,readingTime,updatedAt}}function fileFor(slug){return join(contentDir(),`${assertSafeSlug(slug)}.md`)}export function listBlogPosts(){if(!existsSync(contentDir()))return[];return readdirSync(contentDir()).filter((f)=>f.endsWith(".md")&&!f.startsWith(".")).map((f)=>{const path=join(contentDir(),f);return hydrate(f.replace(/\.md$/,""),readFileSync(path,"utf-8"),statSync(path).mtime.toISOString())}).filter((p)=>!!p.title).sort((a,b)=>{if(a.featured!==b.featured)return a.featured?-1:1;return(b.date||"").localeCompare(a.date||"")})}export function getBlogPost(slug){const file=fileFor(slug);if(!existsSync(file))return null;return hydrate(slug,readFileSync(file,"utf-8"),statSync(file).mtime.toISOString())}export function saveBlogPost(input){const title=String(input.title??"").trim();if(!title)throw new BlogAdminError("A title is required.");const slug=assertSafeSlug(String(input.slug??"").trim()||slugify(title)),originalSlug=input.originalSlug?assertSafeSlug(input.originalSlug):"",isRename=!!originalSlug&&originalSlug!==slug;if(existsSync(fileFor(slug))&&(!originalSlug||isRename))throw new BlogAdminError(`A post with the slug "${slug}" already exists.`,409);if(originalSlug&&!existsSync(fileFor(originalSlug)))throw new BlogAdminError(`No post found with the slug "${originalSlug}".`,404);const date=String(input.date??"").trim()||new Date().toISOString().slice(0,10);if(!/^\d{4}-\d{2}-\d{2}$/.test(date))throw new BlogAdminError("Date must be in YYYY-MM-DD format.");const body=String(input.body??"").trim(),{wordCount,readingTime}=readingTimeFor(body),post={slug,title,description:String(input.description??"").trim(),date,author:String(input.author??"").trim(),authorBio:String(input.authorBio??"").trim(),poster:String(input.poster??"").trim(),featured:input.featured===!0,draft:input.draft===!0,body,wordCount,readingTime,updatedAt:new Date().toISOString()};if(!existsSync(contentDir()))mkdirSync(contentDir(),{recursive:!0});writeFileSync(fileFor(slug),toFileContents(post),"utf-8");if(isRename)unlinkSync(fileFor(originalSlug));return post}export function deleteBlogPost(slug){const file=fileFor(slug);if(!existsSync(file))return!1;unlinkSync(file);return!0}
|
package/dist/build/core.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{$}from"bun";import{existsSync,readFileSync,statSync}from"node:fs";import{basename}from"node:path";import process from"node:process";import{dim,italic,log}from"@stacksjs/cli";import{feature}from"@stacksjs/config";import{corePath}from"@stacksjs/path";import{glob}from"@stacksjs/storage";import{ExitCode}from"@stacksjs/types";log.info("Building core packages");const FEATURE_GATED_PACKAGES={cms:"cms",commerce:"commerce",queue:"queue",realtime:"realtime"},allEntries=(await glob([corePath("*")],{onlyFiles:!1})).sort(),dirs=allEntries.filter((entry)=>{if(!existsSync(entry)||!statSync(entry).isDirectory())return!1;const pkgPath=`${entry}/package.json`;if(!existsSync(pkgPath))return!1;const name=basename(entry),gate=FEATURE_GATED_PACKAGES[name];if(gate&&!feature(gate)){log.info(`Skipping ${italic(dim(entry))} - feature '${gate}' is disabled`);return!1}try{return typeof JSON.parse(readFileSync(pkgPath,"utf8")).scripts?.build==="string"}catch(error){log.warn(`Skipping ${italic(dim(entry))}: package.json could not be read`);return!1}});if(dirs.length===0){log.info("No core packages found");process.exit(ExitCode.FatalError)}const failed=[];for(const folder of dirs){log.info(`\uD83C\uDFD7\uFE0F Building ${italic(dim(folder))}`);try{$.cwd(folder);await $`bun run build`;log.success(`${italic(dim(folder))} built`)}catch(error){log.warn(`Failed to build ${italic(dim(folder))},
|
|
1
|
+
import{$}from"bun";import{existsSync,readFileSync,statSync}from"node:fs";import{basename}from"node:path";import process from"node:process";import{dim,italic,log}from"@stacksjs/cli";import{feature}from"@stacksjs/config";import{corePath}from"@stacksjs/path";import{glob}from"@stacksjs/storage";import{ExitCode}from"@stacksjs/types";log.info("Building core packages");const FEATURE_GATED_PACKAGES={cms:"cms",commerce:"commerce",queue:"queue",realtime:"realtime"},allEntries=(await glob([corePath("*")],{onlyFiles:!1})).sort(),dirs=allEntries.filter((entry)=>{if(!existsSync(entry)||!statSync(entry).isDirectory())return!1;const pkgPath=`${entry}/package.json`;if(!existsSync(pkgPath))return!1;const name=basename(entry),gate=FEATURE_GATED_PACKAGES[name];if(gate&&!feature(gate)){log.info(`Skipping ${italic(dim(entry))} - feature '${gate}' is disabled`);return!1}try{return typeof JSON.parse(readFileSync(pkgPath,"utf8")).scripts?.build==="string"}catch(error){log.warn(`Skipping ${italic(dim(entry))}: package.json could not be read`);return!1}});if(dirs.length===0){await log.info("No core packages found");process.exit(ExitCode.FatalError)}const failed=[];for(const folder of dirs){log.info(`\uD83C\uDFD7\uFE0F Building ${italic(dim(folder))}`);try{$.cwd(folder);await $`bun run build`;log.success(`${italic(dim(folder))} built`)}catch(error){log.warn(`Failed to build ${italic(dim(folder))}, continuing with the rest...`);failed.push(folder)}console.log("")}if(failed.length>0){await log.error(`${failed.length} package(s) failed to build:`);for(const f of failed)await log.error(` - ${f}`);process.exit(ExitCode.FatalError)}
|
package/dist/build/desktop.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createHash}from"node:crypto";import{chmodSync,copyFileSync,existsSync,mkdirSync,readFileSync,rmSync,writeFileSync}from"node:fs";import{join}from"node:path";import process from"node:process";import{log
|
|
1
|
+
import{createHash}from"node:crypto";import{chmodSync,copyFileSync,existsSync,mkdirSync,readFileSync,rmSync,writeFileSync}from"node:fs";import{join}from"node:path";import process from"node:process";import{log}from"@stacksjs/cli";import{corePath,projectPath,storagePath}from"@stacksjs/path";import{assertDesktopReleaseChannel,hasUserlandDesktopLauncher,resolveCraftExecutable,resolveDesktopLauncher}from"@stacksjs/desktop-build";import{runBuildStep}from"./run-build-step";const outputDir=storagePath("framework/desktop-dist"),launcherName=process.platform==="win32"?"stacks-desktop.exe":"stacks-desktop",runtimeName=process.platform==="win32"?"craft-runtime.exe":"craft-runtime",appUrl=process.env.DESKTOP_URL||process.env.APP_URL,releaseChannel=process.env.DESKTOP_RELEASE_CHANNEL==="stable"?"stable":"experimental",support=assertDesktopReleaseChannel(releaseChannel),ownsLauncher=hasUserlandDesktopLauncher(projectPath());if(!appUrl&&!ownsLauncher)throw Error("Desktop builds require APP_URL or DESKTOP_URL so the native app knows which Stacks application to open. An app that opens something local instead can supply its own app/Desktop/launcher.ts.");const url=appUrl?new URL(/^https?:\/\//.test(appUrl)?appUrl:`https://${appUrl}`):null,craftBinary=resolveCraftExecutable();if(readFileSync(craftBinary).subarray(0,2).toString()==="#!")throw Error(`CRAFT_BIN points at a script, not a native binary: ${craftBinary}. Point it at the compiled Craft executable (packages/zig/zig-out/bin/craft).`);if(existsSync(outputDir))rmSync(outputDir,{recursive:!0});mkdirSync(outputDir,{recursive:!0});const desktopSource=corePath("desktop");if(existsSync(join(desktopSource,"package.json"))&&existsSync(join(desktopSource,"src")))await runBuildStep("bun run build",{cwd:desktopSource,describe:"The desktop package build"});const minify=process.env.DESKTOP_MINIFY!=="false",launcherEntry=resolveDesktopLauncher(projectPath());await runBuildStep(["bun","build","--compile",...minify?["--minify"]:[],launcherEntry,"--outfile",join(outputDir,launcherName)],{cwd:projectPath(),describe:"Compiling the desktop launcher"});copyFileSync(craftBinary,join(outputDir,runtimeName));if(process.platform!=="win32"){chmodSync(join(outputDir,launcherName),493);chmodSync(join(outputDir,runtimeName),493)}writeFileSync(join(outputDir,"desktop.json"),`${JSON.stringify({url:url?url.toString().replace(/\/$/,""):"",title:process.env.APP_NAME||"Stacks",width:1400,height:900,darkMode:!1,systemTray:!0,hideDockIcon:!1,releaseChannel,platform:process.platform,architecture:process.arch,launcher:ownsLauncher?"userland":"framework"},null,2)}
|
|
2
2
|
`);const gitResult=Bun.spawnSync(["git","rev-parse","HEAD"],{cwd:projectPath()});if(gitResult.exitCode!==0)throw Error("Desktop builds require an exact Git source revision");const sourceRevision=gitResult.stdout.toString().trim(),remoteResult=Bun.spawnSync(["git","remote","get-url","origin"],{cwd:projectPath()}),sourceRepository=remoteResult.exitCode===0?remoteResult.stdout.toString().trim().replace(/\.git$/,""):"unknown",artifacts=[launcherName,runtimeName,"desktop.json"].map((name)=>{const contents=readFileSync(join(outputDir,name));return{name,bytes:contents.byteLength,sha256:createHash("sha256").update(contents).digest("hex")}});writeFileSync(join(outputDir,"provenance.json"),`${JSON.stringify({schemaVersion:"1.0.0",sourceRepository,sourceRevision,builtWith:{bun:Bun.version,craftSha256:artifacts.find((artifact)=>artifact.name===runtimeName)?.sha256},target:{platform:process.platform,architecture:process.arch,status:support.status,osVersions:support.osVersions},releaseChannel,artifacts},null,2)}
|
|
3
3
|
`);writeFileSync(join(outputDir,"checksums.sha256"),`${artifacts.map((artifact)=>`${artifact.sha256} ${artifact.name}`).join(`
|
|
4
4
|
`)}
|
package/dist/build/dmg.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{cpSync,existsSync,mkdirSync,mkdtempSync,readdirSync,readFileSync,rmSync,statSync,symlinkSync,writeFileSync}from"node:fs";import{tmpdir}from"node:os";import{join}from"node:path";import process from"node:process";import{log,runCommand}from"@stacksjs/cli";import{appPath,projectPath,publicPath,resourcesPath,storagePath}from"@stacksjs/path";import{describeRuntimeDuplication,looksLikeBunExecutable,renderUserlandPlistEntries}from"@stacksjs/desktop-build";if(process.platform!=="darwin")throw Error("DMG packaging only runs on macOS");const desktopDist=storagePath("framework/desktop-dist"),manifestPath=join(desktopDist,"desktop.json");if(!existsSync(manifestPath))throw Error("Run `buddy build:desktop` before packaging a DMG");const manifest=JSON.parse(readFileSync(manifestPath,"utf8")),ownsLauncher=manifest.launcher==="userland",appName=process.env.DESKTOP_APP_NAME||manifest.title||process.env.APP_NAME||"Stacks",bundleId=process.env.DESKTOP_BUNDLE_ID||`sh.stacks.${appName.toLowerCase().replace(/[^a-z0-9]+/g,"-")}`,version=process.env.DESKTOP_APP_VERSION||"0.0.0",signingIdentity=process.env.DESKTOP_SIGNING_IDENTITY,outputDir=storagePath("framework/desktop-dmg");if(existsSync(outputDir))rmSync(outputDir,{recursive:!0});mkdirSync(outputDir,{recursive:!0});const staging=mkdtempSync(join(tmpdir(),"stacks-dmg-")),scratch=mkdtempSync(join(tmpdir(),"stacks-dmg-work-")),appDir=join(staging,`${appName}.app`),macosDir=join(appDir,"Contents/MacOS"),resourcesDir=join(appDir,"Contents/Resources");mkdirSync(macosDir,{recursive:!0});mkdirSync(resourcesDir,{recursive:!0});const builtLauncher="stacks-desktop",launcherName=appName,bundledFiles=readdirSync(desktopDist).filter((name)=>statSync(join(desktopDist,name)).isFile());for(const file of bundledFiles){const target=file===builtLauncher?launcherName:file;await
|
|
1
|
+
import{cpSync,existsSync,mkdirSync,mkdtempSync,readdirSync,readFileSync,rmSync,statSync,symlinkSync,writeFileSync}from"node:fs";import{tmpdir}from"node:os";import{basename,join}from"node:path";import process from"node:process";import{log,runCommand}from"@stacksjs/cli";import{appPath,projectPath,publicPath,resourcesPath,storagePath}from"@stacksjs/path";import{describeRuntimeDuplication,looksLikeBunExecutable,renderUserlandPlistEntries}from"@stacksjs/desktop-build";import{runBuildStep}from"./run-build-step";if(process.platform!=="darwin")throw Error("DMG packaging only runs on macOS");const desktopDist=storagePath("framework/desktop-dist"),manifestPath=join(desktopDist,"desktop.json");if(!existsSync(manifestPath))throw Error("Run `buddy build:desktop` before packaging a DMG");const manifest=JSON.parse(readFileSync(manifestPath,"utf8")),ownsLauncher=manifest.launcher==="userland",appName=process.env.DESKTOP_APP_NAME||manifest.title||process.env.APP_NAME||"Stacks",bundleId=process.env.DESKTOP_BUNDLE_ID||`sh.stacks.${appName.toLowerCase().replace(/[^a-z0-9]+/g,"-")}`,version=process.env.DESKTOP_APP_VERSION||"0.0.0",signingIdentity=process.env.DESKTOP_SIGNING_IDENTITY,outputDir=storagePath("framework/desktop-dmg");if(existsSync(outputDir))rmSync(outputDir,{recursive:!0});mkdirSync(outputDir,{recursive:!0});const staging=mkdtempSync(join(tmpdir(),"stacks-dmg-")),scratch=mkdtempSync(join(tmpdir(),"stacks-dmg-work-")),appDir=join(staging,`${appName}.app`),macosDir=join(appDir,"Contents/MacOS"),resourcesDir=join(appDir,"Contents/Resources");mkdirSync(macosDir,{recursive:!0});mkdirSync(resourcesDir,{recursive:!0});const builtLauncher="stacks-desktop",launcherName=appName,bundledFiles=readdirSync(desktopDist).filter((name)=>statSync(join(desktopDist,name)).isFile());for(const file of bundledFiles){const target=file===builtLauncher?launcherName:file;await runBuildStep(["cp",join(desktopDist,file),join(macosDir,target)],{cwd:projectPath(),describe:`Copying ${file} into the bundle`})}if(!existsSync(join(macosDir,launcherName)))throw Error(`build:desktop did not produce ${builtLauncher}`);const runtimes=readdirSync(macosDir).filter((name)=>statSync(join(macosDir,name)).isFile()).filter((name)=>looksLikeBunExecutable(join(macosDir,name))).map((name)=>({name,bytes:statSync(join(macosDir,name)).size})),duplication=describeRuntimeDuplication(runtimes);if(duplication)log.warn(duplication);const userlandResources=appPath("Desktop/Resources");if(existsSync(userlandResources))cpSync(userlandResources,resourcesDir,{recursive:!0});async function buildIcon(){const source=[resourcesPath("assets/images/app-icon.png"),publicPath("images/app-icon.png"),publicPath("apple-touch-icon.png")].find((candidate)=>existsSync(candidate));if(!source)return;const iconset=join(scratch,"icon.iconset");mkdirSync(iconset,{recursive:!0});for(const size of[16,32,128,256,512]){await runCommand(["sips","-z",String(size),String(size),source,"--out",join(iconset,`icon_${size}x${size}.png`)],{cwd:scratch,silent:!0});await runCommand(["sips","-z",String(size*2),String(size*2),source,"--out",join(iconset,`icon_${size}x${size}@2x.png`)],{cwd:scratch,silent:!0})}const icns=join(resourcesDir,"AppIcon.icns");if((await runCommand(["iconutil","-c","icns",iconset,"-o",icns],{cwd:scratch})).isErr||!existsSync(icns)){log.warn(`Could not build an .icns from ${source}; the bundle will use the default icon.`);return}return"AppIcon"}const iconFile=await buildIcon();function readUserlandPlist(){const declared=appPath("Desktop/Info.plist.json");if(!existsSync(declared))return{};try{return JSON.parse(readFileSync(declared,"utf8"))}catch(error){throw Error(`app/Desktop/Info.plist.json is not valid JSON: ${error instanceof Error?error.message:error}`)}}const declaredPlist=readUserlandPlist(),{xml:extraPlistEntries,ignored:ignoredPlistKeys}=renderUserlandPlistEntries(declaredPlist);if(ignoredPlistKeys.length>0)log.info(`Ignoring reserved Info.plist keys from app/Desktop/Info.plist.json: ${ignoredPlistKeys.join(", ")}`);function overriddenByApp(key){return Object.hasOwn(declaredPlist,key)}writeFileSync(join(appDir,"Contents/Info.plist"),`<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
3
|
<plist version="1.0">
|
|
4
4
|
<dict>
|
|
@@ -28,4 +28,4 @@ ${overriddenByApp("LSMinimumSystemVersion")?"":` <key>LSMinimumSystemVersion</k
|
|
|
28
28
|
<key>CFBundleIconFile</key><string>${iconFile}</string>`:""}${extraPlistEntries}
|
|
29
29
|
</dict>
|
|
30
30
|
</plist>
|
|
31
|
-
`);if(signingIdentity){const nested=bundledFiles.filter((name)=>name!==builtLauncher&&!name.endsWith(".json")&&!name.endsWith(".sha256")).map((name)=>join(macosDir,name));for(const target of[...nested,join(macosDir,launcherName),appDir])await
|
|
31
|
+
`);if(signingIdentity){const nested=bundledFiles.filter((name)=>name!==builtLauncher&&!name.endsWith(".json")&&!name.endsWith(".sha256")).map((name)=>join(macosDir,name));for(const target of[...nested,join(macosDir,launcherName),appDir])await runBuildStep(["codesign","--force","--options","runtime","--sign",signingIdentity,target],{cwd:staging,describe:`Signing ${basename(target)}`})}symlinkSync("/Applications",join(staging,"Applications"));const dmgPath=join(outputDir,`${appName}-${version}.dmg`),created=await runCommand(["hdiutil","create","-volname",appName,"-srcfolder",staging,"-ov","-format","UDZO",dmgPath],{cwd:staging});if(created.isErr)throw Error(`hdiutil failed to create ${dmgPath}`);rmSync(staging,{recursive:!0,force:!0});rmSync(scratch,{recursive:!0,force:!0});log.success(`Built ${dmgPath}`);if(!signingIdentity)log.info("Unsigned build: Gatekeeper blocks the first launch. Right-click the app and choose Open, or set DESKTOP_SIGNING_IDENTITY and notarize before distributing.");
|
|
@@ -21,4 +21,4 @@ import type { CliOptions } from '@stacksjs/types';
|
|
|
21
21
|
* output, and no stack. A caller that wants the framework-level trace can pass
|
|
22
22
|
* `--verbose`, which is already threaded through to the child.
|
|
23
23
|
*/
|
|
24
|
-
export declare function runBuildStep(command: string, options: CliOptions & { describe: string }): Promise<void>;
|
|
24
|
+
export declare function runBuildStep(command: string | string[], options: CliOptions & { describe: string }): Promise<void>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import process from"node:process";import{runCommand}from"@stacksjs/cli";export async function runBuildStep(command,options){const{describe,...cliOptions}=options;if(!(await runCommand(command,cliOptions)).isErr)return;console.error(`
|
|
2
|
-
${describe} failed: \`${
|
|
1
|
+
import process from"node:process";import{runCommand}from"@stacksjs/cli";export async function runBuildStep(command,options){const{describe,...cliOptions}=options;if(!(await runCommand(command,cliOptions)).isErr)return;const printable=Array.isArray(command)?command.join(" "):command;console.error(`
|
|
2
|
+
${describe} failed: \`${printable}\` exited non-zero.`);console.error(`The error it printed above is the cause - this step only relays its exit status.
|
|
3
3
|
`);process.exit(1)}
|
package/dist/build/stacks.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{projectPath}from"@stacksjs/path";import{runBuildStep}from"./run-build-step";await runBuildStep("bun storage/framework/core/actions/src/build/cli.ts",{verbose:!0,cwd:projectPath(),describe:"The CLI build"});await runBuildStep("bun storage/framework/core/actions/src/build/core.ts",{verbose:!0,cwd:projectPath(),describe:"The core packages build"});
|
package/dist/deploy/index.js
CHANGED
|
@@ -6,7 +6,7 @@ ${children}${indent}</${name}>
|
|
|
6
6
|
`}return""}function buildCloudFrontDistributionConfigXml(config){return`<?xml version="1.0" encoding="UTF-8"?>
|
|
7
7
|
<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
|
|
8
8
|
${Object.entries(config).filter(([key])=>!key.startsWith("@_")).map(([key,val])=>buildCloudFrontXmlElement(key,val," ")).join("")}</DistributionConfig>
|
|
9
|
-
`}function firewallOpenCommand(ports){const uniquePorts=[...new Set(ports)].filter((port)=>Number.isFinite(port)&&port>0).sort((a,b)=>a-b);if(uniquePorts.length===0)return"true";return`if command -v firewall-cmd >/dev/null 2>&1; then firewall-cmd --permanent ${uniquePorts.map((port)=>`--add-port=${port}/tcp`).join(" ")} && firewall-cmd --reload; fi`}async function ensureSecurityGroupPort(ec2,securityGroupId,port){if(!securityGroupId)return;if(((await ec2.describeSecurityGroups({GroupIds:[securityGroupId]}))?.SecurityGroups?.[0]?.IpPermissions||[]).some((permission)=>{return permission.IpProtocol==="tcp"&&Number(permission.FromPort)<=port&&Number(permission.ToPort)>=port&&normalizeArray(permission.IpRanges).some((range)=>range.CidrIp==="0.0.0.0/0")}))return;try{await ec2.authorizeSecurityGroupIngress({GroupId:securityGroupId,IpPermissions:[{IpProtocol:"tcp",FromPort:port,ToPort:port,IpRanges:[{CidrIp:"0.0.0.0/0",Description:`Stacks API port ${port}`}]}]})}catch(error){if(!String(error?.message||"").includes("InvalidPermission.Duplicate"))throw error}}async function ensureCloudFrontApiOriginPort(awsClient,distributionId,port){if(!distributionId)return;const getResult=await awsClient.request({service:"cloudfront",region:"us-east-1",method:"GET",path:`/2020-05-31/distribution/${distributionId}/config`,returnHeaders:!0}),etag=getResult.headers?.etag||getResult.headers?.ETag||"",currentConfig=getResult.body?.DistributionConfig||getResult.DistributionConfig||getResult.body;if(!etag||!currentConfig?.Origins?.Items)return;const apiOrigin=normalizeArray(currentConfig.Origins.Items.Origin).find((origin)=>String(origin.Id||"").includes("-api"));if(!apiOrigin?.CustomOriginConfig)return;if(Number(apiOrigin.CustomOriginConfig.HTTPPort)===port)return;apiOrigin.CustomOriginConfig.HTTPPort=port;await awsClient.request({service:"cloudfront",region:"us-east-1",method:"PUT",path:`/2020-05-31/distribution/${distributionId}/config`,body:buildCloudFrontDistributionConfigXml(currentConfig),headers:{"Content-Type":"application/xml","If-Match":etag}})}const frameworkBuildSpinner=spinner("Building framework...");frameworkBuildSpinner.start();await runCommand("bun run build",{cwd:p.frameworkPath("core"),quiet:!1});frameworkBuildSpinner.succeed("Framework built");const docsDir=p.projectPath("docs"),docsBuildDir=p.projectPath("dist/docs/.bunpress");if(storage.hasFiles(docsDir)){const docsSpinner=spinner("Building documentation with BunPress...");docsSpinner.start();try{const{rm}=await import("node:fs/promises"),localBunpressCli=`${process.env.HOME}/Code/Tools/bunpress/packages/bunpress/bin/cli.ts`,installedBunpressCli=p.projectPath("node_modules/@stacksjs/bunpress/dist/bin/cli.js"),hasLocalBunpress=await Bun.file(localBunpressCli).exists(),hasInstalledBunpress=await Bun.file(installedBunpressCli).exists(),command=hasLocalBunpress?`bun ${localBunpressCli} build --dir ${docsDir} --outdir ${p.projectPath("dist/docs")}`:hasInstalledBunpress?`bun ${installedBunpressCli} build --dir ${docsDir} --outdir ${p.projectPath("dist/docs")}`:"bunx @stacksjs/bunpress@0.1.5 build --dir ./docs --outdir ./dist/docs";await rm(docsBuildDir,{recursive:!0,force:!0});await runCommand(command,{cwd:p.projectPath(),quiet:!isVerbose});docsSpinner.succeed(`Documentation built with BunPress${hasLocalBunpress?" (local checkout)":""}`)}catch(docsError){docsSpinner.stop();console.log(`\u26A0 Documentation build skipped: ${docsError.message}`);if(isVerbose)log.debug("To build docs manually: cd ~/Code/Tools/bunpress && bun packages/bunpress/bin/cli.ts build --dir /path/to/docs --outdir /path/to/dist/docs")}}else if(isVerbose)log.debug("No docs directory found, skipping documentation build");const blogDistExists=storage.hasFiles(p.projectPath("dist/blog")),blogFontAssetsExist=["CampmateScript-Regular.woff2","SequoiaSans-Regular.woff2","Switchback-Regular.woff2"].every((file)=>existsSync(p.projectPath(`dist/blog/assets/fonts/nps/${file}`))),blogImageAssetsExist=["topography.svg","park-ridge.svg"].every((file)=>existsSync(p.projectPath(`dist/blog/assets/images/${file}`))),blogIndexPath=p.projectPath("dist/blog/index.html"),blogIndexHtml=existsSync(blogIndexPath)?readFileSync(blogIndexPath,"utf8"):"",blogHtmlUsesCurrentFontFormat=blogIndexHtml.length>0&&!blogIndexHtml.includes("woff2-variations"),blogHtmlUsesCurrentParkTheme=blogIndexHtml.includes("--on-primary")&&blogIndexHtml.includes("--newsletter-bg"),blogHtmlUsesCurrentParkImages=blogIndexHtml.includes("topography.svg")&&blogIndexHtml.includes("park-ridge.svg"),blogHtmlOmitsRetiredDecorations=!blogIndexHtml.includes("stamp-trail")&&!blogIndexHtml.includes("blog-sign-tree.svg"),blogBuilderPath=p.frameworkPath("core/cms/src/build.ts"),blogConfigPath=p.projectPath("config/blog.ts"),blogHtmlIsFresh=existsSync(blogIndexPath)&&[blogBuilderPath,blogConfigPath].filter((path)=>existsSync(path)).every((path)=>statSync(blogIndexPath).mtimeMs>=statSync(path).mtimeMs);if(!blogDistExists||!blogFontAssetsExist||!blogImageAssetsExist||!blogHtmlUsesCurrentFontFormat||!blogHtmlUsesCurrentParkTheme||!blogHtmlUsesCurrentParkImages||!blogHtmlOmitsRetiredDecorations||!blogHtmlIsFresh){const blogBuildSpinner=spinner("Building blog...");blogBuildSpinner.start();try{const blogConfig=(await import(p.projectPath("config/blog"))).default,{buildBlogSite}=await import(p.frameworkPath("core/cms/src/build"));await buildBlogSite({config:blogConfig,outDir:p.projectPath("dist/blog")});blogBuildSpinner.succeed("Blog built successfully")}catch(blogBuildError){blogBuildSpinner.stop();console.log(`\u26A0 Blog build skipped: ${blogBuildError.message}`);if(isVerbose)log.debug(`Blog build error: ${blogBuildError.stack}`)}}else if(isVerbose)log.debug("Pre-built blog found at dist/blog, skipping build");if(isVerbose)log.debug("Skipping views build (vite-config not configured)");const earlyCloudConfig=await import(p.projectPath("config/cloud")),earlyDeploymentMode=earlyCloudConfig?.tsCloud?.mode||"server";if(earlyDeploymentMode==="serverless"){const serverSpinner=spinner("Building server...");serverSpinner.start();await runCommand("bun build.ts",{cwd:p.frameworkPath("server"),quiet:!isVerbose});serverSpinner.succeed("Server built");const packageSpinner=spinner("Packaging for deployment...");packageSpinner.start();await runCommand("bun zip.ts",{cwd:p.corePath("cloud"),quiet:!isVerbose});packageSpinner.succeed("Package ready")}else if(isVerbose)log.debug("Skipping server build and packaging (server mode)");if(!process.env.AWS_ACCESS_KEY_ID||!process.env.AWS_SECRET_ACCESS_KEY){const{existsSync,readFileSync}=await import("node:fs"),environment=process.env.APP_ENV||process.env.NODE_ENV||"production",envFiles=[p.projectPath(`.env.${environment}`),p.projectPath(".env")];for(const envPath of envFiles)if(existsSync(envPath)){const content=readFileSync(envPath,"utf-8");for(const line of content.split(`
|
|
9
|
+
`}function firewallOpenCommand(ports){const uniquePorts=[...new Set(ports)].filter((port)=>Number.isFinite(port)&&port>0).sort((a,b)=>a-b);if(uniquePorts.length===0)return"true";return`if command -v firewall-cmd >/dev/null 2>&1; then firewall-cmd --permanent ${uniquePorts.map((port)=>`--add-port=${port}/tcp`).join(" ")} && firewall-cmd --reload; fi`}async function ensureSecurityGroupPort(ec2,securityGroupId,port){if(!securityGroupId)return;if(((await ec2.describeSecurityGroups({GroupIds:[securityGroupId]}))?.SecurityGroups?.[0]?.IpPermissions||[]).some((permission)=>{return permission.IpProtocol==="tcp"&&Number(permission.FromPort)<=port&&Number(permission.ToPort)>=port&&normalizeArray(permission.IpRanges).some((range)=>range.CidrIp==="0.0.0.0/0")}))return;try{await ec2.authorizeSecurityGroupIngress({GroupId:securityGroupId,IpPermissions:[{IpProtocol:"tcp",FromPort:port,ToPort:port,IpRanges:[{CidrIp:"0.0.0.0/0",Description:`Stacks API port ${port}`}]}]})}catch(error){if(!String(error?.message||"").includes("InvalidPermission.Duplicate"))throw error}}async function ensureCloudFrontApiOriginPort(awsClient,distributionId,port){if(!distributionId)return;const getResult=await awsClient.request({service:"cloudfront",region:"us-east-1",method:"GET",path:`/2020-05-31/distribution/${distributionId}/config`,returnHeaders:!0}),etag=getResult.headers?.etag||getResult.headers?.ETag||"",currentConfig=getResult.body?.DistributionConfig||getResult.DistributionConfig||getResult.body;if(!etag||!currentConfig?.Origins?.Items)return;const apiOrigin=normalizeArray(currentConfig.Origins.Items.Origin).find((origin)=>String(origin.Id||"").includes("-api"));if(!apiOrigin?.CustomOriginConfig)return;if(Number(apiOrigin.CustomOriginConfig.HTTPPort)===port)return;apiOrigin.CustomOriginConfig.HTTPPort=port;await awsClient.request({service:"cloudfront",region:"us-east-1",method:"PUT",path:`/2020-05-31/distribution/${distributionId}/config`,body:buildCloudFrontDistributionConfigXml(currentConfig),headers:{"Content-Type":"application/xml","If-Match":etag}})}const frameworkBuildSpinner=spinner("Building framework...");frameworkBuildSpinner.start();const frameworkBuilt=await runCommand("bun run build",{cwd:p.frameworkPath("core"),quiet:!1});if(frameworkBuilt.isErr){frameworkBuildSpinner.fail("Framework build failed - see the output above");process.exit(ExitCode.FatalError)}frameworkBuildSpinner.succeed("Framework built");const docsDir=p.projectPath("docs"),docsBuildDir=p.projectPath("dist/docs/.bunpress");if(storage.hasFiles(docsDir)){const docsSpinner=spinner("Building documentation with BunPress...");docsSpinner.start();try{const{rm}=await import("node:fs/promises"),localBunpressCli=`${process.env.HOME}/Code/Tools/bunpress/packages/bunpress/bin/cli.ts`,installedBunpressCli=p.projectPath("node_modules/@stacksjs/bunpress/dist/bin/cli.js"),hasLocalBunpress=await Bun.file(localBunpressCli).exists(),hasInstalledBunpress=await Bun.file(installedBunpressCli).exists(),command=hasLocalBunpress?`bun ${localBunpressCli} build --dir ${docsDir} --outdir ${p.projectPath("dist/docs")}`:hasInstalledBunpress?`bun ${installedBunpressCli} build --dir ${docsDir} --outdir ${p.projectPath("dist/docs")}`:"bunx @stacksjs/bunpress@0.1.5 build --dir ./docs --outdir ./dist/docs";await rm(docsBuildDir,{recursive:!0,force:!0});await runCommand(command,{cwd:p.projectPath(),quiet:!isVerbose});docsSpinner.succeed(`Documentation built with BunPress${hasLocalBunpress?" (local checkout)":""}`)}catch(docsError){docsSpinner.stop();console.log(`\u26A0 Documentation build skipped: ${docsError.message}`);if(isVerbose)log.debug("To build docs manually: cd ~/Code/Tools/bunpress && bun packages/bunpress/bin/cli.ts build --dir /path/to/docs --outdir /path/to/dist/docs")}}else if(isVerbose)log.debug("No docs directory found, skipping documentation build");const blogDistExists=storage.hasFiles(p.projectPath("dist/blog")),blogFontAssetsExist=["CampmateScript-Regular.woff2","SequoiaSans-Regular.woff2","Switchback-Regular.woff2"].every((file)=>existsSync(p.projectPath(`dist/blog/assets/fonts/nps/${file}`))),blogImageAssetsExist=["topography.svg","park-ridge.svg"].every((file)=>existsSync(p.projectPath(`dist/blog/assets/images/${file}`))),blogIndexPath=p.projectPath("dist/blog/index.html"),blogIndexHtml=existsSync(blogIndexPath)?readFileSync(blogIndexPath,"utf8"):"",blogHtmlUsesCurrentFontFormat=blogIndexHtml.length>0&&!blogIndexHtml.includes("woff2-variations"),blogHtmlUsesCurrentParkTheme=blogIndexHtml.includes("--on-primary")&&blogIndexHtml.includes("--newsletter-bg"),blogHtmlUsesCurrentParkImages=blogIndexHtml.includes("topography.svg")&&blogIndexHtml.includes("park-ridge.svg"),blogHtmlOmitsRetiredDecorations=!blogIndexHtml.includes("stamp-trail")&&!blogIndexHtml.includes("blog-sign-tree.svg"),blogBuilderPath=p.frameworkPath("core/cms/src/build.ts"),blogConfigPath=p.projectPath("config/blog.ts"),blogHtmlIsFresh=existsSync(blogIndexPath)&&[blogBuilderPath,blogConfigPath].filter((path)=>existsSync(path)).every((path)=>statSync(blogIndexPath).mtimeMs>=statSync(path).mtimeMs);if(!blogDistExists||!blogFontAssetsExist||!blogImageAssetsExist||!blogHtmlUsesCurrentFontFormat||!blogHtmlUsesCurrentParkTheme||!blogHtmlUsesCurrentParkImages||!blogHtmlOmitsRetiredDecorations||!blogHtmlIsFresh){const blogBuildSpinner=spinner("Building blog...");blogBuildSpinner.start();try{const blogConfig=(await import(p.projectPath("config/blog"))).default,{buildBlogSite}=await import(p.frameworkPath("core/cms/src/build"));await buildBlogSite({config:blogConfig,outDir:p.projectPath("dist/blog")});blogBuildSpinner.succeed("Blog built successfully")}catch(blogBuildError){blogBuildSpinner.stop();console.log(`\u26A0 Blog build skipped: ${blogBuildError.message}`);if(isVerbose)log.debug(`Blog build error: ${blogBuildError.stack}`)}}else if(isVerbose)log.debug("Pre-built blog found at dist/blog, skipping build");if(isVerbose)log.debug("Skipping views build (vite-config not configured)");const earlyCloudConfig=await import(p.projectPath("config/cloud")),earlyDeploymentMode=earlyCloudConfig?.tsCloud?.mode||"server";if(earlyDeploymentMode==="serverless"){const serverSpinner=spinner("Building server...");serverSpinner.start();if((await runCommand("bun build.ts",{cwd:p.frameworkPath("server"),quiet:!isVerbose})).isErr){serverSpinner.fail("Server build failed - rerun with --verbose to see its output");process.exit(ExitCode.FatalError)}serverSpinner.succeed("Server built");const packageSpinner=spinner("Packaging for deployment...");packageSpinner.start();if((await runCommand("bun zip.ts",{cwd:p.corePath("cloud"),quiet:!isVerbose})).isErr){packageSpinner.fail("Packaging failed - rerun with --verbose to see its output");process.exit(ExitCode.FatalError)}packageSpinner.succeed("Package ready")}else if(isVerbose)log.debug("Skipping server build and packaging (server mode)");if(!process.env.AWS_ACCESS_KEY_ID||!process.env.AWS_SECRET_ACCESS_KEY){const{existsSync,readFileSync}=await import("node:fs"),environment=process.env.APP_ENV||process.env.NODE_ENV||"production",envFiles=[p.projectPath(`.env.${environment}`),p.projectPath(".env")];for(const envPath of envFiles)if(existsSync(envPath)){const content=readFileSync(envPath,"utf-8");for(const line of content.split(`
|
|
10
10
|
`)){const trimmed=line.trim();if(trimmed.startsWith("#")||!trimmed.includes("="))continue;const eqIndex=trimmed.indexOf("="),key=trimmed.slice(0,eqIndex).trim();let value=trimmed.slice(eqIndex+1).trim();if(value.startsWith('"')&&value.endsWith('"')||value.startsWith("'")&&value.endsWith("'"))value=value.slice(1,-1);if(key==="AWS_ACCESS_KEY_ID"&&value)process.env.AWS_ACCESS_KEY_ID=value;else if(key==="AWS_SECRET_ACCESS_KEY"&&value)process.env.AWS_SECRET_ACCESS_KEY=value;else if(key==="AWS_REGION"&&value&&!process.env.AWS_REGION)process.env.AWS_REGION=value;else if(key==="AWS_ACCOUNT_ID"&&value&&!process.env.AWS_ACCOUNT_ID)process.env.AWS_ACCOUNT_ID=value;else if(key.startsWith("MAIL_PASSWORD_")&&value&&!process.env[key])process.env[key]=value}if(isVerbose)log.debug(`Loaded AWS credentials from ${envPath}`);break}}try{const{deployStack,deployFrontend:_deployFrontend}=await import("../../deploy"),environment=process.env.APP_ENV||process.env.NODE_ENV||"production",region=process.env.AWS_REGION||"us-east-1",cloudConfigModule=await import(p.projectPath("config/cloud")),deploymentMode=cloudConfigModule?.tsCloud?.mode||"server",projectName=cloudConfigModule?.tsCloud?.project?.name||cloudConfigModule?.tsCloud?.project?.slug||"stacks";if(deploymentMode==="serverless"){console.log("");console.log("Serverless deployment mode detected");console.log("Building and pushing container image...");console.log("");const accountId=process.env.AWS_ACCOUNT_ID||await getAwsAccountId(region);if(!accountId||accountId.length<10)throw Error(`Invalid AWS Account ID: "${accountId||"(empty)"}"
|
|
11
11
|
Set AWS_ACCOUNT_ID in your .env file or ensure valid AWS credentials are configured.`);const ecrRepository=`${accountId}.dkr.ecr.${region}.amazonaws.com/${projectName}-${environment}-api`,imageTag=`${ecrRepository}:latest`;if(isVerbose)log.debug(`ECR repository: ${ecrRepository}`);if(isVerbose)log.debug("ECR credentials will be validated before push...");const buildSpinner=spinner("Building Docker image...");buildSpinner.start();try{const{exec}=await import("node:child_process"),{promisify}=await import("node:util"),execAsync=promisify(exec),buildCmd=`docker build --platform linux/amd64 -t ${imageTag} -f Dockerfile .`,{stdout,stderr}=await execAsync(buildCmd,{cwd:p.projectPath(),env:process.env,maxBuffer:10485760,timeout:900000});if(isVerbose&&stdout)log.debug(stdout);if(isVerbose&&stderr)log.debug(stderr);buildSpinner.succeed(`Docker image built: ${imageTag}`)}catch(error){buildSpinner.fail("Docker build failed");if(isVerbose)log.debug(`Docker build error: ${error.message}`);throw error}const repoSpinner=spinner("Checking ECR repository...");repoSpinner.start();try{const{ECRClient}=await import("@stacksjs/ts-cloud"),ecr=new ECRClient(region),repoName=`${projectName}-${environment}-api`;try{await ecr.describeRepositories({repositoryNames:[repoName]});repoSpinner.succeed(`ECR repository exists: ${repoName}`)}catch(err){if(err.code==="RepositoryNotFoundException"||err.message?.includes("RepositoryNotFoundException")){repoSpinner.text=`Creating ECR repository: ${repoName}...`;await ecr.createRepository({repositoryName:repoName,imageScanningConfiguration:{scanOnPush:!0},imageTagMutability:"MUTABLE"});repoSpinner.succeed(`ECR repository created: ${repoName}`)}else throw err}}catch(error){repoSpinner.fail("ECR repository check failed");if(isVerbose)log.debug(`ECR repository error: ${error.message}`);throw error}const authSpinner=spinner("Authenticating to ECR...");authSpinner.start();try{const{ECRClient}=await import("@stacksjs/ts-cloud"),token=(await new ECRClient(region).getAuthorizationToken()).authorizationData?.[0];if(!token?.authorizationToken)throw Error("No authorization token received from ECR");const decoded=Buffer.from(token.authorizationToken,"base64").toString("utf-8"),colonIndex=decoded.indexOf(":");if(colonIndex===-1)throw Error("ECR authorization token has unexpected format (missing colon separator)");const password=decoded.slice(colonIndex+1),loginResult=Bun.spawnSync(["docker","login","--username","AWS","--password-stdin",`${accountId}.dkr.ecr.${region}.amazonaws.com`],{stdin:new TextEncoder().encode(password),stdout:"pipe",stderr:"pipe"});if(loginResult.exitCode!==0){const loginError=new TextDecoder().decode(loginResult.stderr);throw Error(`Docker login failed: ${loginError}`)}authSpinner.succeed("Authenticated to ECR")}catch(error){authSpinner.fail("ECR authentication failed");if(isVerbose)log.debug(`ECR auth error: ${error.message}`);throw error}console.log("");const pushSpinner=spinner("Pushing image to ECR...");pushSpinner.start();try{const{exec}=await import("node:child_process"),{promisify}=await import("node:util"),execAsync=promisify(exec),pushCmd=`docker push ${imageTag}`;await execAsync(pushCmd,{env:process.env});pushSpinner.succeed(`Image pushed: ${imageTag}`)}catch(error){pushSpinner.fail("Docker push failed");if(isVerbose)log.debug(`Push error: ${error.message}`);throw error}console.log("");console.log("Container image ready in ECR. CloudFormation will use this image.");console.log("")}else{console.log("");console.log("Server deployment mode detected");console.log("Deploying EC2 infrastructure via CloudFormation...");console.log("")}async function getAwsAccountId(region){try{const{STSClient}=await import("@stacksjs/ts-cloud"),accountId=(await new STSClient(region).getCallerIdentity()).Account||process.env.AWS_ACCOUNT_ID||"";if(isVerbose)log.debug(`Retrieved AWS Account ID: ${accountId||"(empty)"}`);return accountId}catch(error){if(isVerbose)log.debug(`Failed to get AWS Account ID: ${error.message}`);return process.env.AWS_ACCOUNT_ID||""}}try{const deployScript=await import(p.projectPath("cloud/deploy-script"));if(typeof deployScript.beforeDeploy==="function")await deployScript.beforeDeploy({environment,region})}catch(hookError){if(hookError.code==="ERR_MODULE_NOT_FOUND"||hookError.code==="MODULE_NOT_FOUND"){if(isVerbose)log.debug("No beforeDeploy hook found (cloud/deploy-script not found)")}else{console.warn(`\u26A0 beforeDeploy hook failed: ${hookError.message}`);if(isVerbose)log.debug(`beforeDeploy error stack: ${hookError.stack}`)}}await deployStack({environment,region,waitForCompletion:!0,verbose:isVerbose});try{const deployScript=await import(p.projectPath("cloud/deploy-script"));if(typeof deployScript.afterDeploy==="function"){const{CloudFormationClient}=await import("@stacksjs/ts-cloud"),cf=new CloudFormationClient(region),stackName=`${projectName}-cloud`;let stackOutputs={};try{stackOutputs=await cf.getStackOutputs(stackName)}catch(e){if(isVerbose)log.debug(`Failed to get stack outputs: ${e instanceof Error?e.message:String(e)}`)}await deployScript.afterDeploy({environment,region,outputs:stackOutputs})}}catch(hookError){if(hookError.code==="ERR_MODULE_NOT_FOUND"||hookError.code==="MODULE_NOT_FOUND"){if(isVerbose)log.debug("No afterDeploy hook found (cloud/deploy-script not found)")}else{console.warn(`\u26A0 afterDeploy hook failed: ${hookError.message}`);if(isVerbose)log.debug(`afterDeploy error stack: ${hookError.stack}`)}}const migrateSpinner=spinner("Running database migrations...");migrateSpinner.start();try{const{generateMigrations,runDatabaseMigration}=await import("@stacksjs/database");await generateMigrations();await runDatabaseMigration();migrateSpinner.succeed("Database migrations completed")}catch(migrationError){migrateSpinner.stop();console.log(`\u26A0 Database migrations skipped: ${migrationError.message}`);if(isVerbose)log.debug(`Migration error: ${migrationError.stack}`)}const frameworkTablesSpinner=spinner("Ensuring framework tables (auth, notifications, RBAC, traits)...");frameworkTablesSpinner.start();try{const{ensureUtcDatetimeColumns,migrateAuthTables,migrateNotificationTables,migrateRbacTables,migrateTraitTables}=await import("@stacksjs/database"),failures=[],steps=[["auth",migrateAuthTables],["notification",migrateNotificationTables],["RBAC",migrateRbacTables],["trait",migrateTraitTables],["utc-datetime",ensureUtcDatetimeColumns]];for(const[name,migrateTables]of steps){const result=await migrateTables({verbose:isVerbose});if(!result.success)failures.push(`${name}: ${result.error}`)}if(failures.length>0){frameworkTablesSpinner.stop();console.log(`\u26A0 Some framework tables could not be migrated: ${failures.join("; ")}`)}else frameworkTablesSpinner.succeed("Framework tables ensured (auth, notifications, RBAC, traits)")}catch(frameworkTablesError){frameworkTablesSpinner.stop();console.log(`\u26A0 Framework table migrations skipped: ${frameworkTablesError.message}`);if(isVerbose)log.debug(`Framework table migration error: ${frameworkTablesError.stack}`)}if(deploymentMode==="server"){const serverOutputSpinner=spinner("Retrieving server instance details...");serverOutputSpinner.start();try{const{CloudFormationClient}=await import("@stacksjs/ts-cloud"),cf=new CloudFormationClient(region),stackName=`${projectName}-cloud`,outputs=await cf.getStackOutputs(stackName);serverOutputSpinner.succeed("Server instances deployed");console.log("");console.log("Server instances:");for(const[key,value]of Object.entries(outputs)){if(key.endsWith("PublicIp"))console.log(` ${key}: ${value}`);if(key.endsWith("InstanceId"))console.log(` ${key}: ${value}`)}console.log("")}catch(outputError){serverOutputSpinner.stop();console.log(`\u26A0 Could not retrieve server details: ${outputError.message}`);if(isVerbose)log.debug(`Output retrieval error: ${outputError.stack}`)}const serverDeploySpinner=spinner("Deploying API server to EC2...");serverDeploySpinner.start();try{const{S3Client,CloudFormationClient,AWSClient}=await import("@stacksjs/ts-cloud"),{readFileSync:readServerFile,existsSync:serverFileExists}=await import("node:fs"),{resolve}=await import("node:path"),s3=new S3Client(region),cf=new CloudFormationClient(region),awsClient=new AWSClient,stackName=`${projectName}-cloud`,outputs=await cf.getStackOutputs(stackName),bucketName=outputs.FrontendBucketName,apiServerPort=Number(config.ports?.api||3008);let instanceId;for(const[key,value]of Object.entries(outputs))if(key.endsWith("InstanceId")&&typeof value==="string"){instanceId=value;break}let securityGroupId;if(instanceId){const{EC2Client}=await import("@stacksjs/ts-cloud"),ec2=new EC2Client(region);securityGroupId=(await ec2.describeInstances({Filters:[{Name:"instance-id",Values:[instanceId]}]}))?.Reservations?.[0]?.Instances?.[0]?.SecurityGroups?.[0]?.GroupId;await ensureSecurityGroupPort(ec2,securityGroupId,apiServerPort)}if(!instanceId||!bucketName){serverDeploySpinner.stop();if(!instanceId)console.log("\u26A0 No EC2 instance found in stack outputs, skipping server deploy");if(!bucketName)console.log("\u26A0 No S3 bucket found for staging server artifacts")}else{const publicDistributionId=outputs.publicCloudFrontDistributionId||outputs.CloudFrontDistributionId;await ensureCloudFrontApiOriginPort(awsClient,publicDistributionId,apiServerPort);const tsCloudDistPath=resolve(p.projectPath("node_modules/@stacksjs/ts-cloud/dist/index.js"));if(serverFileExists(tsCloudDistPath)){const tsCloudDist=readServerFile(tsCloudDistPath);await withS3Retry(()=>s3.putObject({bucket:bucketName,key:"_deploy/ts-cloud-dist.js",body:tsCloudDist,contentType:"application/javascript"}),"upload ts-cloud dist");if(isVerbose)log.debug(" Uploaded ts-cloud dist to S3")}const serverCode=`import { Database } from "bun:sqlite";
|
|
12
12
|
import { SESClient } from "./ts-cloud-dist.js";
|
package/dist/generate/index.d.ts
CHANGED
|
@@ -6,9 +6,9 @@ export type { GenerateVSchemaOptions, GenerateVSchemaResult } from './vschema';
|
|
|
6
6
|
export declare function invoke(options?: GeneratorOptions): Promise<void>;
|
|
7
7
|
export declare function generate(options: GeneratorOptions): Promise<void>;
|
|
8
8
|
export declare function generateLibEntries(options: GeneratorOptions): Promise<void>;
|
|
9
|
-
export declare function generateWebTypes(
|
|
9
|
+
export declare function generateWebTypes(): Promise<void>;
|
|
10
10
|
export declare function generateVsCodeCustomData(): Promise<void>;
|
|
11
|
-
export declare function generateIdeHelpers(
|
|
11
|
+
export declare function generateIdeHelpers(): Promise<void>;
|
|
12
12
|
export declare function generateComponentMeta(): Promise<void>;
|
|
13
13
|
export declare function generateTypes(options?: GeneratorOptions): Promise<void>;
|
|
14
14
|
/**
|
package/dist/generate/index.js
CHANGED
|
@@ -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}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(
|
|
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...");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){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){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){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{generateServerAutoImportTypes}=await import("@stacksjs/server");await generateServerAutoImportTypes()}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,4 +1,9 @@
|
|
|
1
1
|
import type { Result } from '@stacksjs/error-handling';
|
|
2
2
|
export declare function generateVsCodeCustomData(): Promise<Result<void, string>>;
|
|
3
3
|
export declare function generateWebTypes(): Promise<void>;
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Same live-config read as `generateComponentInfoData` above: the snapshot has
|
|
6
|
+
* no `webComponents`, so reading it synchronously produced a valid but EMPTY
|
|
7
|
+
* web-types.json - a quieter failure than the corrupt one, and just as wrong.
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateWebTypesData(): Promise<string>;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import{
|
|
2
|
-
|
|
3
|
-
"tags": ${JSON.stringify(library.webComponents?.tags)}
|
|
4
|
-
}
|
|
5
|
-
`}export async function generateVsCodeCustomData(){try{log.info("Generating custom-elements.json...");await writeTextFile({path:customElementsDataPath(),data:generateComponentInfoData()});log.success("Generated custom-elements.json for IDEs.");return ok(void 0)}catch(e){log.error("There was an error generating the custom-elements.json file.",e);return err("There was an error generating the custom-elements.json file.")}}export async function generateWebTypes(){log.info("Generating web-types.json...");await writeTextFile({path:frameworkPath("core/web-types.json"),data:generateWebTypesData()});log.success("Generated web-types.json for IDEs.")}export function generateWebTypesData(){const tags=(library.webComponents?.tags??[]).map((tag)=>{const sourceName=Array.isArray(tag.name)?tag.name[0]:tag.name;return{name:Array.isArray(tag.name)?tag.name[1]:tag.name,description:tag.description??"",attributes:tag.attributes??[],source:{module:`../../defaults/resources/components/${sourceName}.stx`,symbol:"default"}}});return`${JSON.stringify({framework:"stx",name:library.name,contributions:{html:{"description-markup":"markdown","types-syntax":"typescript",tags}}},null,2)}
|
|
1
|
+
import{config,overridesReady}from"@stacksjs/config";import{err,ok}from"@stacksjs/error-handling";import{log}from"@stacksjs/logging";import{customElementsDataPath,frameworkPath}from"@stacksjs/path";import{writeTextFile}from"@stacksjs/storage";async function generateComponentInfoData(){await overridesReady;const tags=config.library?.webComponents?.tags??[];return`${JSON.stringify({version:1.1,tags},null,2)}
|
|
2
|
+
`}export async function generateVsCodeCustomData(){try{log.info("Generating custom-elements.json...");await writeTextFile({path:customElementsDataPath(),data:await generateComponentInfoData()});log.success("Generated custom-elements.json for IDEs.");return ok(void 0)}catch(e){log.error("There was an error generating the custom-elements.json file.",e);return err("There was an error generating the custom-elements.json file.")}}export async function generateWebTypes(){log.info("Generating web-types.json...");await writeTextFile({path:frameworkPath("core/web-types.json"),data:await generateWebTypesData()});log.success("Generated web-types.json for IDEs.")}export async function generateWebTypesData(){await overridesReady;const library=config.library??{},tags=(library.webComponents?.tags??[]).map((tag)=>{const sourceName=Array.isArray(tag.name)?tag.name[0]:tag.name;return{name:Array.isArray(tag.name)?tag.name[1]:tag.name,description:tag.description??"",attributes:tag.attributes??[],source:{module:`../../defaults/resources/components/${sourceName}.stx`,symbol:"default"}}});return`${JSON.stringify({framework:"stx",name:library.name,contributions:{html:{"description-markup":"markdown","types-syntax":"typescript",tags}}},null,2)}
|
|
6
3
|
`}
|
|
@@ -11,10 +11,21 @@ export declare function planLibraryPublish(config?: LibraryConfig | undefined):
|
|
|
11
11
|
/**
|
|
12
12
|
* The publisher to shell out to.
|
|
13
13
|
*
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* `pantry publish` first. Pantry is this project's package manager, it is what
|
|
15
|
+
* the release workflows already install, and it is the only one of the three
|
|
16
|
+
* that publishes to the Pantry registry — a release that went out through
|
|
17
|
+
* `bun publish` reached npm and nothing else, which is not where these
|
|
18
|
+
* packages are meant to live.
|
|
19
|
+
*
|
|
20
|
+
* It also takes the same flags this function's callers pass: `--access` and
|
|
21
|
+
* `--dry-run` mean what they mean everywhere else, so nothing downstream has
|
|
22
|
+
* to know which publisher was chosen. `--npm` is pantry's own escape hatch for
|
|
23
|
+
* an npm-bound package; it belongs on the package, not here.
|
|
24
|
+
*
|
|
25
|
+
* `bun` and then `npm` remain as fallbacks. Neither is guaranteed present —
|
|
26
|
+
* npm was not on the machine this was written on, and hardcoding it turned
|
|
27
|
+
* `libs:publish` into an ENOENT — so the choice is made from what is actually
|
|
28
|
+
* on PATH rather than assumed.
|
|
18
29
|
*/
|
|
19
30
|
export declare function publishCommand(): string[];
|
|
20
31
|
/**
|
package/dist/library/publish.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{existsSync}from"node:fs";import{relative,resolve}from"node:path";import{log}from"@stacksjs/logging";import{projectPath}from"@stacksjs/path";import{library}from"@stacksjs/config";import{LibraryConfigError,resolveLibraryPackages}from"./packages";export async function planLibraryPublish(config=library){const publishable=(await resolveLibraryPackages(config)).filter((pkg)=>!pkg.private);if(!publishable.length)throw new LibraryConfigError("Every configured library package is marked private. Nothing to publish.");const plans=[],missing=[];for(const pkg of publishable){const manifestPath=resolve(pkg.dir,"package.json"),distDir=resolve(pkg.dir,"dist");if(!existsSync(manifestPath)||!existsSync(distDir)){missing.push(pkg.name);continue}const built=await Array.fromAsync(new Bun.Glob("**/*.{js,css,json,d.ts}").scan({cwd:distDir}));if(!built.length){missing.push(pkg.name);continue}const manifest=await Bun.file(manifestPath).json();plans.push({name:pkg.name,version:manifest.version??"0.0.0",dir:pkg.dir,access:pkg.access,tarballFiles:built.length})}if(missing.length)throw new LibraryConfigError(`These packages have no build output: ${missing.join(", ")}.
|
|
2
|
-
Run \`buddy build:libs\` before publishing.`);return plans}export function publishCommand(){if(Bun.which("bun"))return["bun","publish"];if(Bun.which("npm"))return["npm","publish"];throw Error("
|
|
2
|
+
Run \`buddy build:libs\` before publishing.`);return plans}export function publishCommand(){if(Bun.which("pantry"))return["pantry","publish"];if(Bun.which("bun"))return["bun","publish"];if(Bun.which("npm"))return["npm","publish"];throw Error("None of `pantry`, `bun` or `npm` is on PATH, so there is nothing to publish with.")}export async function publishLibraryPackages(options={}){const plans=await planLibraryPublish(options.config??library),command=publishCommand();for(const plan of plans){const args=[...command,"--access",plan.access];if(options.dryRun)args.push("--dry-run");log.info(`${options.dryRun?"[dry run] ":""}${args.join(" ")} (${plan.name}@${plan.version}, ${relative(projectPath(),plan.dir)})`);const proc=Bun.spawnSync({cmd:args,cwd:plan.dir,stdout:"inherit",stderr:"inherit"});if(proc.exitCode!==0)throw Error(`Publishing ${plan.name}@${plan.version} failed with exit code ${proc.exitCode}.`)}return plans}
|
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.2",
|
|
6
6
|
"description": "The Stacks actions.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -60,50 +60,50 @@
|
|
|
60
60
|
"prepublishOnly": "bun run build"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@stacksjs/ai": "0.74.
|
|
64
|
-
"@stacksjs/analytics": "0.74.
|
|
65
|
-
"@stacksjs/api": "0.74.
|
|
66
|
-
"@stacksjs/auth": "0.74.
|
|
67
|
-
"@stacksjs/build": "0.74.
|
|
63
|
+
"@stacksjs/ai": "0.74.2",
|
|
64
|
+
"@stacksjs/analytics": "0.74.2",
|
|
65
|
+
"@stacksjs/api": "0.74.2",
|
|
66
|
+
"@stacksjs/auth": "0.74.2",
|
|
67
|
+
"@stacksjs/build": "0.74.2",
|
|
68
68
|
"@stacksjs/bumpx": "^0.2.6",
|
|
69
69
|
"@stacksjs/bunpress": "^0.2.8",
|
|
70
|
-
"@stacksjs/cli": "0.74.
|
|
71
|
-
"@stacksjs/cloud": "0.74.
|
|
72
|
-
"@stacksjs/cms": "0.74.
|
|
73
|
-
"@stacksjs/config": "0.74.
|
|
74
|
-
"@stacksjs/database": "0.74.
|
|
75
|
-
"@stacksjs/desktop-build": "0.74.
|
|
76
|
-
"@stacksjs/dns": "0.74.
|
|
77
|
-
"@stacksjs/enums": "0.74.
|
|
78
|
-
"@stacksjs/env": "0.74.
|
|
79
|
-
"@stacksjs/error-handling": "0.74.
|
|
70
|
+
"@stacksjs/cli": "0.74.2",
|
|
71
|
+
"@stacksjs/cloud": "0.74.2",
|
|
72
|
+
"@stacksjs/cms": "0.74.2",
|
|
73
|
+
"@stacksjs/config": "0.74.2",
|
|
74
|
+
"@stacksjs/database": "0.74.2",
|
|
75
|
+
"@stacksjs/desktop-build": "0.74.2",
|
|
76
|
+
"@stacksjs/dns": "0.74.2",
|
|
77
|
+
"@stacksjs/enums": "0.74.2",
|
|
78
|
+
"@stacksjs/env": "0.74.2",
|
|
79
|
+
"@stacksjs/error-handling": "0.74.2",
|
|
80
80
|
"@stacksjs/gitit": "^0.2.5",
|
|
81
|
-
"@stacksjs/i18n": "0.74.
|
|
82
|
-
"@stacksjs/image": "0.74.
|
|
83
|
-
"@stacksjs/logging": "0.74.
|
|
81
|
+
"@stacksjs/i18n": "0.74.2",
|
|
82
|
+
"@stacksjs/image": "0.74.2",
|
|
83
|
+
"@stacksjs/logging": "0.74.2",
|
|
84
84
|
"@stacksjs/logsmith": "^0.2.3",
|
|
85
|
-
"@stacksjs/orm": "0.74.
|
|
86
|
-
"@stacksjs/path": "0.74.
|
|
87
|
-
"@stacksjs/payments": "0.74.
|
|
88
|
-
"@stacksjs/queue": "0.74.
|
|
89
|
-
"@stacksjs/registry": "0.74.
|
|
90
|
-
"@stacksjs/router": "0.74.
|
|
85
|
+
"@stacksjs/orm": "0.74.2",
|
|
86
|
+
"@stacksjs/path": "0.74.2",
|
|
87
|
+
"@stacksjs/payments": "0.74.2",
|
|
88
|
+
"@stacksjs/queue": "0.74.2",
|
|
89
|
+
"@stacksjs/registry": "0.74.2",
|
|
90
|
+
"@stacksjs/router": "0.74.2",
|
|
91
91
|
"@stacksjs/rpx": "^0.11.42",
|
|
92
|
-
"@stacksjs/scheduler": "0.74.
|
|
93
|
-
"@stacksjs/search-engine": "0.74.
|
|
94
|
-
"@stacksjs/security": "0.74.
|
|
95
|
-
"@stacksjs/server": "0.74.
|
|
96
|
-
"@stacksjs/sites": "0.74.
|
|
97
|
-
"@stacksjs/storage": "0.74.
|
|
98
|
-
"@stacksjs/strings": "0.74.
|
|
99
|
-
"@stacksjs/stx": "^0.2.
|
|
92
|
+
"@stacksjs/scheduler": "0.74.2",
|
|
93
|
+
"@stacksjs/search-engine": "0.74.2",
|
|
94
|
+
"@stacksjs/security": "0.74.2",
|
|
95
|
+
"@stacksjs/server": "0.74.2",
|
|
96
|
+
"@stacksjs/sites": "0.74.2",
|
|
97
|
+
"@stacksjs/storage": "0.74.2",
|
|
98
|
+
"@stacksjs/strings": "0.74.2",
|
|
99
|
+
"@stacksjs/stx": "^0.2.253",
|
|
100
100
|
"@stacksjs/tlsx": "^0.13.2",
|
|
101
101
|
"@stacksjs/ts-cloud": "^0.12.10",
|
|
102
102
|
"@stacksjs/ts-md": "^0.1.1",
|
|
103
|
-
"@stacksjs/tunnel": "0.74.
|
|
104
|
-
"@stacksjs/types": "0.74.
|
|
105
|
-
"@stacksjs/utils": "0.74.
|
|
106
|
-
"@stacksjs/whois": "0.74.
|
|
103
|
+
"@stacksjs/tunnel": "0.74.2",
|
|
104
|
+
"@stacksjs/types": "0.74.2",
|
|
105
|
+
"@stacksjs/utils": "0.74.2",
|
|
106
|
+
"@stacksjs/whois": "0.74.2",
|
|
107
107
|
"bun-plugin-stx": "^0.2.246"
|
|
108
108
|
},
|
|
109
109
|
"peerDependencies": {
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
}
|
|
120
120
|
},
|
|
121
121
|
"devDependencies": {
|
|
122
|
-
"@stacksjs/validation": "0.74.
|
|
122
|
+
"@stacksjs/validation": "0.74.2",
|
|
123
123
|
"better-dx": "^0.2.24"
|
|
124
124
|
}
|
|
125
125
|
}
|