@stacksjs/actions 0.72.97 → 0.72.99
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/build/desktop.js +2 -2
- package/dist/build/dmg.js +15 -4
- package/dist/generate/action-types.d.ts +21 -6
- package/dist/generate/action-types.js +10 -44
- package/dist/generate/index.js +1 -1
- package/package.json +22 -22
- package/dist/generate/env-files.d.ts +0 -23
- package/dist/generate/env-files.js +0 -46
package/dist/build/desktop.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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,runCommand}from"@stacksjs/cli";import{corePath,projectPath,storagePath}from"@stacksjs/path";import{assertDesktopReleaseChannel,resolveCraftExecutable,resolveDesktopLauncher}from"@stacksjs/desktop-build";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);if(!appUrl)throw Error("Desktop builds require APP_URL or DESKTOP_URL so the native app knows which Stacks application to open");const url=new URL(/^https?:\/\//.test(appUrl)?appUrl:`https://${appUrl}`),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 runCommand("bun run build",{cwd:desktopSource});const launcherEntry=resolveDesktopLauncher();await runCommand(["bun","build","--compile",launcherEntry,"--outfile",join(outputDir,launcherName)],{cwd:projectPath()});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.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},null,2)}
|
|
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,runCommand}from"@stacksjs/cli";import{corePath,projectPath,storagePath}from"@stacksjs/path";import{assertDesktopReleaseChannel,hasUserlandDesktopLauncher,resolveCraftExecutable,resolveDesktopLauncher}from"@stacksjs/desktop-build";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 runCommand("bun run build",{cwd:desktopSource});const launcherEntry=resolveDesktopLauncher(projectPath());await runCommand(["bun","build","--compile",launcherEntry,"--outfile",join(outputDir,launcherName)],{cwd:projectPath()});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
|
`)}
|
|
5
|
-
`);log.success(`Built Craft desktop application in ${outputDir}`);
|
|
5
|
+
`);log.success(`Built Craft desktop application in ${outputDir}`);if(ownsLauncher)log.info(`Using this application's own launcher (${launcherEntry}).`);
|
package/dist/build/dmg.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync,mkdirSync,mkdtempSync,readFileSync,rmSync,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{projectPath,publicPath,resourcesPath,storagePath}from"@stacksjs/path";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")),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 launcherName="stacks-desktop";for(const file of
|
|
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";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 launcherName="stacks-desktop",bundledFiles=readdirSync(desktopDist).filter((name)=>statSync(join(desktopDist,name)).isFile());for(const file of bundledFiles)await runCommand(["cp",join(desktopDist,file),join(macosDir,file)],{cwd:projectPath()});if(!existsSync(join(macosDir,launcherName)))throw Error(`build:desktop did not produce ${launcherName}`);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))return;return"AppIcon"}const iconFile=await buildIcon();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>
|
|
@@ -12,9 +12,20 @@ import{existsSync,mkdirSync,mkdtempSync,readFileSync,rmSync,symlinkSync,writeFil
|
|
|
12
12
|
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
|
|
13
13
|
<key>LSMinimumSystemVersion</key><string>11.0</string>
|
|
14
14
|
<key>NSHighResolutionCapable</key><true/>
|
|
15
|
-
<!-- The window
|
|
16
|
-
|
|
15
|
+
${ownsLauncher?` <!-- The window talks to something this app started on loopback, so an
|
|
16
|
+
exception for 127.0.0.1 is all it needs. NSAllowsArbitraryLoads would
|
|
17
|
+
additionally permit every unencrypted host on the internet. -->
|
|
18
|
+
<key>NSAppTransportSecurity</key>
|
|
19
|
+
<dict>
|
|
20
|
+
<key>NSAllowsLocalNetworking</key><true/>
|
|
21
|
+
<key>NSExceptionDomains</key>
|
|
22
|
+
<dict>
|
|
23
|
+
<key>127.0.0.1</key>
|
|
24
|
+
<dict><key>NSExceptionAllowsInsecureHTTPLoads</key><true/></dict>
|
|
25
|
+
</dict>
|
|
26
|
+
</dict>`:` <!-- The window loads a remote URL, so the app has to be allowed to reach it. -->
|
|
27
|
+
<key>NSAppTransportSecurity</key><dict><key>NSAllowsArbitraryLoads</key><true/></dict>`}${iconFile?`
|
|
17
28
|
<key>CFBundleIconFile</key><string>${iconFile}</string>`:""}
|
|
18
29
|
</dict>
|
|
19
30
|
</plist>
|
|
20
|
-
`);if(signingIdentity)for(const target of[
|
|
31
|
+
`);if(signingIdentity){const nested=bundledFiles.filter((name)=>name!==launcherName&&!name.endsWith(".json")&&!name.endsWith(".sha256")).map((name)=>join(macosDir,name));for(const target of[...nested,join(macosDir,launcherName),appDir])await runCommand(["codesign","--force","--options","runtime","--sign",signingIdentity,target],{cwd:staging})}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.");
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Write `storage/framework/
|
|
2
|
+
* Write `storage/framework/auto-imports/routes.ts`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* A RUNTIME map, not a declaration file. Every other name in the framework -
|
|
5
|
+
* actions, listeners, policies, middleware classes, jobs, models, tables - is
|
|
6
|
+
* derived from a map the resolver reads, so `keyof` and the resolution can
|
|
7
|
+
* never disagree. Route names could not join them, because a route name is
|
|
8
|
+
* produced by RUNNING code: it is attached by a chained `.name()` whose path
|
|
9
|
+
* may have come from a group prefix, and no static read of the source can know
|
|
10
|
+
* what `/users/{id}` a given `.name('users.show')` actually got.
|
|
11
|
+
*
|
|
12
|
+
* So this loads the route table, exactly as the OpenAPI generator does, and
|
|
13
|
+
* writes what it finds as a runtime value. `storage/framework/types/registries.d.ts`
|
|
14
|
+
* reads it with `typeof import(...)`. The list is still produced by a
|
|
15
|
+
* generator; what changed is that it is no longer a type nobody can check
|
|
16
|
+
* against anything - the router can resolve a name out of the same map.
|
|
17
|
+
*
|
|
18
|
+
* Best-effort on purpose. A route registry that fails to load writes an empty
|
|
19
|
+
* map, which the router reads as "no declaration" and falls back to accepting
|
|
20
|
+
* any name - the behaviour before any of this existed. Refusing to generate
|
|
21
|
+
* because one route file threw would be a much worse trade than an unchecked
|
|
22
|
+
* `url()`.
|
|
8
23
|
*/
|
|
9
|
-
export declare function
|
|
24
|
+
export declare function generateRouteNames(): Promise<void>;
|
|
@@ -1,46 +1,12 @@
|
|
|
1
|
-
import{existsSync}from"node:fs";import{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
//
|
|
1
|
+
import{existsSync}from"node:fs";import{log}from"@stacksjs/logging";import{path as p}from"@stacksjs/path";import{storage}from"@stacksjs/storage";async function collectNamedRoutes(){const registryFile=p.appPath("Routes.ts");if(!existsSync(registryFile))return{};try{const{listNamedRoutes,loadRoutes}=await import("@stacksjs/router"),{default:routeRegistry}=await import(registryFile);await loadRoutes(routeRegistry);return listNamedRoutes()}catch(error){log.debug("[generate:types] Could not load routes for named-route types",{error});return{}}}export async function generateRouteNames(){log.info("Generating route names...");const namedRoutes=await collectNamedRoutes(),entries=Object.entries(namedRoutes).sort(([left],[right])=>left.localeCompare(right)).map(([name,routePath])=>`
|
|
2
|
+
'${name}': '${routePath}',`).join(""),contents=`// This file is auto-generated by Stacks. Do not edit this file manually.
|
|
3
|
+
//
|
|
4
|
+
// Every named route, and the path it resolves to. Read as a type by
|
|
5
|
+
// \`storage/framework/types/registries.d.ts\`, so \`url('users.show')\` is checked
|
|
6
|
+
// against the routes this application registers - and readable at runtime by
|
|
7
|
+
// anything that needs to resolve a name without loading the route table.
|
|
7
8
|
//
|
|
8
9
|
// For more information, please visit: https://stacksjs.com/docs
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* defaults it has not overridden.
|
|
13
|
-
*/
|
|
14
|
-
export type ActionPath =${union}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Every middleware alias this application registers, and its negated form.
|
|
18
|
-
*/
|
|
19
|
-
export type MiddlewareAlias =${middlewareUnion||`
|
|
20
|
-
| string`}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Every named route, and the path it resolves to.
|
|
24
|
-
*
|
|
25
|
-
* A type alias, NOT an interface: only aliases of object literals get an
|
|
26
|
-
* implicit index signature, so an interface here fails the router's
|
|
27
|
-
* \`extends Record<string, string>\` shape check and the whole map is quietly
|
|
28
|
-
* ignored.
|
|
29
|
-
*/
|
|
30
|
-
export type NamedRoutes = {${routeEntries?`${routeEntries}
|
|
31
|
-
`:""}}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Handed to the router, so \`route.get(path, 'Actions/\u2026')\` and
|
|
35
|
-
* \`.middleware('auth')\` are checked against the lists above rather than
|
|
36
|
-
* against a string. A controller reference stays a pattern - the method half is
|
|
37
|
-
* a member name, not a filename.
|
|
38
|
-
*/
|
|
39
|
-
declare module '@stacksjs/bun-router' {
|
|
40
|
-
interface RouterTypeRegistry {
|
|
41
|
-
actions: ActionPath | \`\${string}Controller@\${string}\`
|
|
42
|
-
middleware: MiddlewareAlias
|
|
43
|
-
routes: NamedRoutes
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
`;await storage.writeFile(p.frameworkPath("types/actions.d.ts"),contents);log.debug(`[generate:types] Wrote ${actions.length} action paths, ${aliases.length} middleware aliases and ${Object.keys(namedRoutes).length} named routes`)}
|
|
10
|
+
export const routeNames = {${entries?`${entries}
|
|
11
|
+
`:""}} as const
|
|
12
|
+
`;await storage.writeFile(p.storagePath("framework/auto-imports/routes.ts"),contents);log.debug(`[generate:types] Wrote ${Object.keys(namedRoutes).length} named routes`)}
|
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
|
|
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(options);else if(options?.customData)await generateVsCodeCustomData();else if(options?.ideHelpers)await generateIdeHelpers(options);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})}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(options){const result=await runNpmScript(NpmScript.GenerateWebTypes,options);if(result.isErr){log.error("There was an error generating the web-types.json file.",result.error);process.exit(ExitCode.FatalError)}log.success("Successfully generated the web-types.json file")}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(options){const result=await runNpmScript(NpmScript.GenerateIdeHelpers,options);if(result.isErr){log.error("There was an error generating IDE helpers.",result.error);process.exit(ExitCode.FatalError)}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")}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/actions",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.72.
|
|
5
|
+
"version": "0.72.99",
|
|
6
6
|
"description": "The Stacks actions.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -60,36 +60,36 @@
|
|
|
60
60
|
"prepublishOnly": "bun run build"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@stacksjs/config": "0.72.
|
|
63
|
+
"@stacksjs/config": "0.72.99",
|
|
64
64
|
"@stacksjs/bumpx": "^0.2.6",
|
|
65
65
|
"@stacksjs/bunpress": "^0.2.8",
|
|
66
66
|
"@stacksjs/logsmith": "^0.2.3",
|
|
67
|
-
"@stacksjs/registry": "0.72.
|
|
68
|
-
"@stacksjs/stx": "^0.2.
|
|
67
|
+
"@stacksjs/registry": "0.72.99",
|
|
68
|
+
"@stacksjs/stx": "^0.2.245",
|
|
69
69
|
"@stacksjs/ts-cloud": "^0.12.7",
|
|
70
70
|
"@stacksjs/ts-md": "^0.1.1"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
|
-
"@stacksjs/api": "0.72.
|
|
74
|
-
"@stacksjs/cli": "0.72.
|
|
75
|
-
"@stacksjs/database": "0.72.
|
|
73
|
+
"@stacksjs/api": "0.72.99",
|
|
74
|
+
"@stacksjs/cli": "0.72.99",
|
|
75
|
+
"@stacksjs/database": "0.72.99",
|
|
76
76
|
"@stacksjs/tlsx": "^0.13.2",
|
|
77
77
|
"better-dx": "^0.2.24",
|
|
78
|
-
"@stacksjs/dns": "0.72.
|
|
79
|
-
"@stacksjs/enums": "0.72.
|
|
80
|
-
"@stacksjs/env": "0.72.
|
|
81
|
-
"@stacksjs/error-handling": "0.72.
|
|
82
|
-
"@stacksjs/image": "0.72.
|
|
83
|
-
"@stacksjs/logging": "0.72.
|
|
84
|
-
"@stacksjs/path": "0.72.
|
|
85
|
-
"@stacksjs/security": "0.72.
|
|
86
|
-
"@stacksjs/server": "0.72.
|
|
87
|
-
"@stacksjs/cms": "0.72.
|
|
88
|
-
"@stacksjs/sites": "0.72.
|
|
89
|
-
"@stacksjs/storage": "0.72.
|
|
90
|
-
"@stacksjs/strings": "0.72.
|
|
91
|
-
"@stacksjs/utils": "0.72.
|
|
92
|
-
"@stacksjs/validation": "0.72.
|
|
78
|
+
"@stacksjs/dns": "0.72.99",
|
|
79
|
+
"@stacksjs/enums": "0.72.99",
|
|
80
|
+
"@stacksjs/env": "0.72.99",
|
|
81
|
+
"@stacksjs/error-handling": "0.72.99",
|
|
82
|
+
"@stacksjs/image": "0.72.99",
|
|
83
|
+
"@stacksjs/logging": "0.72.99",
|
|
84
|
+
"@stacksjs/path": "0.72.99",
|
|
85
|
+
"@stacksjs/security": "0.72.99",
|
|
86
|
+
"@stacksjs/server": "0.72.99",
|
|
87
|
+
"@stacksjs/cms": "0.72.99",
|
|
88
|
+
"@stacksjs/sites": "0.72.99",
|
|
89
|
+
"@stacksjs/storage": "0.72.99",
|
|
90
|
+
"@stacksjs/strings": "0.72.99",
|
|
91
|
+
"@stacksjs/utils": "0.72.99",
|
|
92
|
+
"@stacksjs/validation": "0.72.99"
|
|
93
93
|
},
|
|
94
94
|
"peerDependencies": {
|
|
95
95
|
"pickier": "^0.1.58",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The text of `storage/framework/types/env.d.ts`.
|
|
3
|
-
*
|
|
4
|
-
* Bun's `env` namespace only. The `env` exported by '@stacksjs/env' used to be
|
|
5
|
-
* augmented from here too, and that was the wrong source: the key set came
|
|
6
|
-
* from whichever `.env` was on the machine running the generator, so a
|
|
7
|
-
* variable set only in deploy secrets could never be typed, and each type was
|
|
8
|
-
* read off the variable's live value, so the same variable could be `number`
|
|
9
|
-
* here and `string` on a colleague's checkout. `StacksEnv` is now extended
|
|
10
|
-
* from `config/env.ts`, which declares those variables anyway and is committed.
|
|
11
|
-
*
|
|
12
|
-
* Pure, so the shape can be asserted without writing into the framework.
|
|
13
|
-
*/
|
|
14
|
-
export declare function renderEnvTypes(keys: string[], typeOf: (key: string) => string): string;
|
|
15
|
-
/**
|
|
16
|
-
* Write `storage/framework/types/env.d.ts` and `storage/framework/env.ts`.
|
|
17
|
-
*
|
|
18
|
-
* This was a top-level script with nothing importing it — no command, no
|
|
19
|
-
* build step, no test referenced the file — so the declarations it owns were
|
|
20
|
-
* whatever the last person to run it by hand had produced. `generateTypes()`
|
|
21
|
-
* calls it now.
|
|
22
|
-
*/
|
|
23
|
-
export declare function generateEnvFiles(): Promise<void>;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import{env as e,envEnum,parse}from"@stacksjs/env";import{log}from"@stacksjs/logging";import{path as p}from"@stacksjs/path";import{storage}from"@stacksjs/storage";import{existsSync,readFileSync}from"node:fs";function previouslyDeclaredKeys(){const file=p.frameworkPath("env.ts");if(!existsSync(file))return[];return[...(readFileSync(file,"utf8").match(/export const envKeys = \[([^\]]*)\]/)?.[1]??"").matchAll(/'([A-Z0-9_]+)'/g)].map((match)=>match[1])}function resolveEnvKeys(){const keys=new Set(previouslyDeclaredKeys());for(const file of[".env",".env.example"]){const path=p.projectPath(file);if(!existsSync(path))continue;for(const key of Object.keys(parse(readFileSync(path,"utf8")).parsed))keys.add(key)}return[...keys].sort()}export function renderEnvTypes(keys,typeOf){return`
|
|
2
|
-
// This file is auto-generated by Stacks. Do not edit this file manually.
|
|
3
|
-
// If you want to change the environment variables, please edit the .env file.
|
|
4
|
-
//
|
|
5
|
-
// This types \`Bun.env.SOMETHING\`. The \`env\` exported by '@stacksjs/env' is
|
|
6
|
-
// typed from your \`config/env.ts\` instead - declare a variable there and it
|
|
7
|
-
// is typed everywhere, with no generation step:
|
|
8
|
-
//
|
|
9
|
-
// const envSchema = defineEnv({
|
|
10
|
-
// STRIPE_WEBHOOK_SECRET: { validation: schema.string(), default: '' },
|
|
11
|
-
// })
|
|
12
|
-
//
|
|
13
|
-
// declare module '@stacksjs/env' {
|
|
14
|
-
// interface StacksEnv extends InferEnv<typeof envSchema> {}
|
|
15
|
-
// }
|
|
16
|
-
//
|
|
17
|
-
// export default envSchema
|
|
18
|
-
//
|
|
19
|
-
// For more information, please visit: https://stacksjs.com/docs
|
|
20
|
-
|
|
21
|
-
// Marks this file as a module, which is what makes the block below an
|
|
22
|
-
// augmentation. In a global script file \`declare module 'x'\` declares an
|
|
23
|
-
// ambient module instead, shadowing the real one \u2014 which took '@stacksjs/env'
|
|
24
|
-
// down to only the members named here and broke every \`import { env }\` in
|
|
25
|
-
// config/ with "has no exported member 'env'".
|
|
26
|
-
export {}
|
|
27
|
-
|
|
28
|
-
declare module 'bun' {
|
|
29
|
-
namespace env {
|
|
30
|
-
${keys.map((key)=>`const ${key}: ${typeOf(key)}`).join(`
|
|
31
|
-
`)}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
`}export async function generateEnvFiles(){log.info("Generating type env files...");const resolvedKeys=resolveEnvKeys();function typeOf(key){let type=typeof e[key],value=e[key];if(!value)if(envEnum[key]){type=envEnum[key]?.map((item)=>`'${item}'`).join(" | ");value=envEnum[key]?.[0]}else switch(type){case"number":value="0";break;case"boolean":value=!1;break;default:value=""}type="string";if(typeof value==="string"){if(value.toLowerCase()==="true"||value.toLowerCase()==="false")type="boolean";else if(!Number.isNaN(Number.parseFloat(value))&&Number.isFinite(Number(value)))type="number";else if(envEnum[key])type=envEnum[key].map((item)=>`'${item}'`).join(" | ")}else if(typeof value==="number")type="number";else if(typeof value==="boolean")type="boolean";return type}const envTypes=renderEnvTypes(resolvedKeys,typeOf);await storage.writeFile(p.frameworkPath("types/env.d.ts"),envTypes);log.info(" - ./storage/framework/env.ts");const env=`
|
|
35
|
-
// This file is auto-generated by Stacks. Do not edit this file manually.
|
|
36
|
-
// If you want to change the environment variables, please edit the .env file.
|
|
37
|
-
//
|
|
38
|
-
// For more information, please visit: https://stacksjs.com/docs
|
|
39
|
-
|
|
40
|
-
export const envKeys = [
|
|
41
|
-
${resolvedKeys.map((key)=>`'${key}'`).join(`,
|
|
42
|
-
`)}
|
|
43
|
-
] as const
|
|
44
|
-
|
|
45
|
-
export type EnvKey = typeof envKeys[number]
|
|
46
|
-
`;await storage.writeFile(p.frameworkPath("env.ts"),env);log.info(" - ./storage/framework/env.d.ts")}
|