@stacksjs/actions 0.73.2 → 0.74.0

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.
@@ -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,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)}
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 minify=process.env.DESKTOP_MINIFY!=="false",launcherEntry=resolveDesktopLauncher(projectPath());await runCommand(["bun","build","--compile",...minify?["--minify"]:[],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
  `)}
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{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 runCommand(["cp",join(desktopDist,file),join(macosDir,target)],{cwd:projectPath()})}if(!existsSync(join(macosDir,launcherName)))throw Error(`build:desktop did not produce ${builtLauncher}`);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();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"?>
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 runCommand(["cp",join(desktopDist,file),join(macosDir,target)],{cwd:projectPath()})}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))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>
@@ -1 +1 @@
1
- var {require}=import.meta;import{runCommand}from"@stacksjs/cli";import{projectPath}from"@stacksjs/path";function bunpressCommand(){try{const manifest=Bun.resolveSync("@stacksjs/bunpress/package.json",projectPath()),pkg=require(manifest),bin=typeof pkg.bin==="string"?pkg.bin:pkg.bin?.bunpress;if(!bin)return"bunpress";return`bun ${manifest.slice(0,manifest.lastIndexOf("/"))}/${bin.replace(/^\.\//,"")}`}catch{return"bunpress"}}await runCommand(`${bunpressCommand()} build`,{cwd:projectPath()});
1
+ var {require}=import.meta;import{projectPath}from"@stacksjs/path";import{runBuildStep}from"./run-build-step";function bunpressCommand(){try{const manifest=Bun.resolveSync("@stacksjs/bunpress/package.json",projectPath()),pkg=require(manifest),bin=typeof pkg.bin==="string"?pkg.bin:pkg.bin?.bunpress;if(!bin)return"bunpress";return`bun ${manifest.slice(0,manifest.lastIndexOf("/"))}/${bin.replace(/^\.\//,"")}`}catch{return"bunpress"}}await runBuildStep(`${bunpressCommand()} build`,{cwd:projectPath(),describe:"The documentation build"});
@@ -0,0 +1,24 @@
1
+ import type { CliOptions } from '@stacksjs/types';
2
+ /**
3
+ * Run one build subprocess and fail loudly but quietly.
4
+ *
5
+ * A build step's real diagnosis comes from the tool it spawns - a template
6
+ * parse error, a type error, a missing entry point - and that output has
7
+ * already been written to the terminal by the time control returns here. What
8
+ * happened next made it hard to find: `throw result.error` let a
9
+ * `Failed to execute command: bunx --bun @stacksjs/stx build …` error escape
10
+ * the action module uncaught, so Bun printed it with a stack through
11
+ * handleError, exec and runCommand. The last twenty lines of the build were
12
+ * then entirely about the framework's own plumbing, and the parse error that
13
+ * caused it had scrolled away.
14
+ *
15
+ * Worse for `build --views` specifically: `buddy serve` keeps serving whatever
16
+ * the previous successful build produced, so the visible symptom of a failed
17
+ * build is that newly added pages 404 while existing ones keep working. That
18
+ * is a long way from "a partial has a syntax error". stacksjs/stacks#2391.
19
+ *
20
+ * So: exit non-zero with one line that names the command and points at its
21
+ * output, and no stack. A caller that wants the framework-level trace can pass
22
+ * `--verbose`, which is already threaded through to the child.
23
+ */
24
+ export declare function runBuildStep(command: string, options: CliOptions & { describe: string }): Promise<void>;
@@ -0,0 +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: \`${command}\` exited non-zero.`);console.error(`The error it printed above is the cause - this step only relays its exit status.
3
+ `);process.exit(1)}
@@ -1 +1 @@
1
- import{runCommand}from"@stacksjs/cli";import{projectPath}from"@stacksjs/path";const projectBuild=projectPath("build.ts");if(await Bun.file(projectBuild).exists()){const result=await runCommand("bun build.ts",{cwd:projectPath()});if(result.isErr)throw result.error}else{const result=await runCommand("bunx --bun @stacksjs/stx build --pages resources/views --out dist",{cwd:projectPath()});if(result.isErr)throw result.error}
1
+ import{projectPath}from"@stacksjs/path";import{runBuildStep}from"./run-build-step";const projectBuild=projectPath("build.ts");if(await Bun.file(projectBuild).exists())await runBuildStep("bun build.ts",{cwd:projectPath(),describe:"The frontend build"});else await runBuildStep("bunx --bun @stacksjs/stx build --pages resources/views --out dist",{cwd:projectPath(),describe:"The frontend build"});
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/actions",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.73.2",
5
+ "version": "0.74.0",
6
6
  "description": "The Stacks actions.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -60,41 +60,55 @@
60
60
  "prepublishOnly": "bun run build"
61
61
  },
62
62
  "dependencies": {
63
- "@stacksjs/config": "0.73.2",
63
+ "@stacksjs/ai": "0.74.0",
64
+ "@stacksjs/analytics": "0.74.0",
65
+ "@stacksjs/api": "0.74.0",
66
+ "@stacksjs/auth": "0.74.0",
67
+ "@stacksjs/build": "0.74.0",
64
68
  "@stacksjs/bumpx": "^0.2.6",
65
69
  "@stacksjs/bunpress": "^0.2.8",
70
+ "@stacksjs/cli": "0.74.0",
71
+ "@stacksjs/cloud": "0.74.0",
72
+ "@stacksjs/cms": "0.74.0",
73
+ "@stacksjs/config": "0.74.0",
74
+ "@stacksjs/database": "0.74.0",
75
+ "@stacksjs/desktop-build": "0.74.0",
76
+ "@stacksjs/dns": "0.74.0",
77
+ "@stacksjs/enums": "0.74.0",
78
+ "@stacksjs/env": "0.74.0",
79
+ "@stacksjs/error-handling": "0.74.0",
80
+ "@stacksjs/gitit": "^0.2.5",
81
+ "@stacksjs/i18n": "0.74.0",
82
+ "@stacksjs/image": "0.74.0",
83
+ "@stacksjs/logging": "0.74.0",
66
84
  "@stacksjs/logsmith": "^0.2.3",
67
- "@stacksjs/registry": "0.73.2",
85
+ "@stacksjs/orm": "0.74.0",
86
+ "@stacksjs/path": "0.74.0",
87
+ "@stacksjs/payments": "0.74.0",
88
+ "@stacksjs/queue": "0.74.0",
89
+ "@stacksjs/registry": "0.74.0",
90
+ "@stacksjs/router": "0.74.0",
91
+ "@stacksjs/rpx": "^0.11.42",
92
+ "@stacksjs/scheduler": "0.74.0",
93
+ "@stacksjs/search-engine": "0.74.0",
94
+ "@stacksjs/security": "0.74.0",
95
+ "@stacksjs/server": "0.74.0",
96
+ "@stacksjs/sites": "0.74.0",
97
+ "@stacksjs/storage": "0.74.0",
98
+ "@stacksjs/strings": "0.74.0",
68
99
  "@stacksjs/stx": "^0.2.246",
69
- "@stacksjs/ts-cloud": "^0.12.10",
70
- "@stacksjs/ts-md": "^0.1.1"
71
- },
72
- "devDependencies": {
73
- "@stacksjs/api": "0.73.2",
74
- "@stacksjs/cli": "0.73.2",
75
- "@stacksjs/database": "0.73.2",
76
100
  "@stacksjs/tlsx": "^0.13.2",
77
- "better-dx": "^0.2.24",
78
- "@stacksjs/dns": "0.73.2",
79
- "@stacksjs/enums": "0.73.2",
80
- "@stacksjs/env": "0.73.2",
81
- "@stacksjs/error-handling": "0.73.2",
82
- "@stacksjs/image": "0.73.2",
83
- "@stacksjs/logging": "0.73.2",
84
- "@stacksjs/path": "0.73.2",
85
- "@stacksjs/security": "0.73.2",
86
- "@stacksjs/server": "0.73.2",
87
- "@stacksjs/cms": "0.73.2",
88
- "@stacksjs/sites": "0.73.2",
89
- "@stacksjs/storage": "0.73.2",
90
- "@stacksjs/strings": "0.73.2",
91
- "@stacksjs/utils": "0.73.2",
92
- "@stacksjs/validation": "0.73.2",
93
- "@stacksjs/build": "0.73.2"
101
+ "@stacksjs/ts-cloud": "^0.12.10",
102
+ "@stacksjs/ts-md": "^0.1.1",
103
+ "@stacksjs/tunnel": "0.74.0",
104
+ "@stacksjs/types": "0.74.0",
105
+ "@stacksjs/utils": "0.74.0",
106
+ "@stacksjs/whois": "0.74.0",
107
+ "bun-plugin-stx": "^0.2.246"
94
108
  },
95
109
  "peerDependencies": {
96
- "pickier": "^0.1.58",
97
- "craft-native": "^0.0.67"
110
+ "craft-native": ">=0.0.72",
111
+ "pickier": "^0.1.58"
98
112
  },
99
113
  "peerDependenciesMeta": {
100
114
  "pickier": {
@@ -103,5 +117,9 @@
103
117
  "craft-native": {
104
118
  "optional": true
105
119
  }
120
+ },
121
+ "devDependencies": {
122
+ "@stacksjs/validation": "0.74.0",
123
+ "better-dx": "^0.2.24"
106
124
  }
107
125
  }