@stacksjs/buddy 0.75.431 → 0.75.439
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.
|
@@ -100,6 +100,20 @@ export declare function buildUniversalPayload(input: UniversalPayloadInput, run?
|
|
|
100
100
|
* `build:desktop` uses, plus the cross-compilation target.
|
|
101
101
|
*/
|
|
102
102
|
export declare function launcherSliceCompileArgs(base: string[], architecture: DarwinArchitecture): string[];
|
|
103
|
+
/**
|
|
104
|
+
* The team's Mac App Store signing identities in `security find-identity -v`
|
|
105
|
+
* output: the app certificate under either of the names Apple has issued it
|
|
106
|
+
* under, and the installer certificate likewise. Only the team's own: a Mac
|
|
107
|
+
* holding certificates for several teams must not sign with the wrong one.
|
|
108
|
+
*/
|
|
109
|
+
export declare function parseDistributionIdentities(output: string, teamId: string): { app?: string, installer?: string };
|
|
110
|
+
/**
|
|
111
|
+
* Fill the signing identities from the keychain when no flag or variable named
|
|
112
|
+
* them. They are certificate names, not secrets, and the keychain already says
|
|
113
|
+
* which ones this Mac can sign with, so a release from the developer's own Mac
|
|
114
|
+
* needs no Apple variables beyond the App Store Connect key.
|
|
115
|
+
*/
|
|
116
|
+
export declare function withKeychainIdentities(config: AppleDesktopConfig, read?: (keychain?: string) => string): AppleDesktopConfig;
|
|
103
117
|
/**
|
|
104
118
|
* What a failure prints, as a value.
|
|
105
119
|
*
|
|
@@ -146,6 +160,8 @@ declare interface AppleDesktopOptions {
|
|
|
146
160
|
craftArm64?: string
|
|
147
161
|
craftX64?: string
|
|
148
162
|
keychain?: string
|
|
163
|
+
testflight?: string
|
|
164
|
+
whatsNew?: string
|
|
149
165
|
}
|
|
150
166
|
export declare interface AppleDesktopConfig {
|
|
151
167
|
appName: string
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import{createHash}from"node:crypto";import{chmodSync,copyFileSync,existsSync,mkdirSync,mkdtempSync,readdirSync,readFileSync,rmSync,writeFileSync}from"node:fs";import{tmpdir}from"node:os";import{basename,join,resolve}from"node:path";import process from"node:process";import{log}from"@stacksjs/cli";import{projectPath,storagePath}from"@stacksjs/path";import{resultFailed}from"../result";const REQUIRED_TOOLS=["codesign","security","productbuild","pkgutil","xcrun"];function env(name){return process.env[name]?.trim()||""}function xml(value){return value.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}async function nativeAppleConfig(){const{loadMacosDesktop}=await import("@stacksjs/desktop-build");return loadMacosDesktop(projectPath(),packageMetadata().version)}function packageMetadata(){const packageJson=JSON.parse(readFileSync(projectPath("package.json"),"utf8"));return{name:packageJson.name||"Stacks",version:packageJson.version||"0.1.0"}}export function resolveAppleDesktopConfig(options={},native){const metadata=packageMetadata(),provisioningProfile=options.provisioningProfile||env("APPLE_PROVISIONING_PROFILE"),apiKeyPath=options.apiKeyPath||env("APP_STORE_CONNECT_API_KEY_PATH"),craftArm64=options.craftArm64||env("CRAFT_BIN_ARM64"),craftX64=options.craftX64||env("CRAFT_BIN_X64"),keychain=options.keychain||env("APPLE_KEYCHAIN");return{appName:options.appName||env("APPLE_APP_NAME")||native?.appName||env("APP_NAME")||metadata.name,bundleId:options.bundleId||env("APPLE_BUNDLE_ID")||native?.bundleId||"",teamId:options.teamId||env("APPLE_TEAM_ID")||native?.teamId||"",version:options.appVersion||env("APPLE_APP_VERSION")||native?.version||metadata.version,buildNumber:options.buildNumber||env("APPLE_BUILD_NUMBER")||(native?native.buildNumber:"")||env("GITHUB_RUN_NUMBER")||String(Math.floor(Date.now()/1000)),minimumMacos:options.minimumMacos||env("APPLE_MINIMUM_MACOS")||native?.minimumSystemVersion||"13.0",category:options.category||env("APPLE_APP_CATEGORY")||native?.category||"public.app-category.productivity",appSigningIdentity:options.appSigningIdentity||env("APPLE_APP_SIGNING_IDENTITY"),installerSigningIdentity:options.installerSigningIdentity||env("APPLE_INSTALLER_SIGNING_IDENTITY"),provisioningProfile:provisioningProfile?resolve(provisioningProfile):"",apiKeyId:options.apiKeyId||env("APP_STORE_CONNECT_API_KEY_ID"),apiIssuerId:options.apiIssuerId||env("APP_STORE_CONNECT_API_ISSUER_ID"),apiKeyPath:apiKeyPath?resolve(apiKeyPath):"",icon:options.icon||env("APPLE_APP_ICON")||(native?.icon?resolve(projectPath(),native.icon):void 0),universal:Boolean(options.universal)||env("APPLE_UNIVERSAL")==="true",craftArm64:craftArm64?resolve(craftArm64):void 0,craftX64:craftX64?resolve(craftX64):void 0,keychain:keychain?resolve(keychain):void 0}}export function withApiKeyFile(config){const pem=env("APP_STORE_CONNECT_API_KEY").replaceAll("\\n",`
|
|
2
2
|
`);if(config.apiKeyPath||!pem||!config.apiKeyId)return config;if(!pem.includes("-----BEGIN PRIVATE KEY-----"))throw Error("APP_STORE_CONNECT_API_KEY must hold the PEM text of the .p8 key");const directory=mkdtempSync(join(tmpdir(),"apple-api-key-")),apiKeyPath=join(directory,`AuthKey_${config.apiKeyId}.p8`);writeFileSync(apiKeyPath,`${pem}
|
|
3
|
-
`,{mode:384});process.on("exit",()=>rmSync(directory,{recursive:!0,force:!0}));return{...config,apiKeyPath}}export function validateAppleDesktopConfig(config,includeApi=!0){const errors=[];if(process.platform!=="darwin")errors.push("Mac App Store packaging must run on macOS");if(!config.appName)errors.push("APPLE_APP_NAME or --app-name is required");if(!/^[A-Za-z0-9][A-Za-z0-9.-]+$/.test(config.bundleId))errors.push("APPLE_BUNDLE_ID must be a reverse-DNS bundle identifier");if(!/^[A-Z0-9]{10}$/.test(config.teamId))errors.push("APPLE_TEAM_ID must be the 10-character Apple Developer team ID");if(!/^\d+(?:\.\d+){0,2}$/.test(config.version))errors.push("The marketing version must contain one to three numeric components");if(!/^[A-Za-z0-9.-]+$/.test(config.buildNumber))errors.push("The build number must contain only letters, numbers, periods, and hyphens");if(!config.appSigningIdentity)errors.push("APPLE_APP_SIGNING_IDENTITY is required");if(!config.installerSigningIdentity)errors.push("APPLE_INSTALLER_SIGNING_IDENTITY is required");if(!config.provisioningProfile||!existsSync(config.provisioningProfile))errors.push("APPLE_PROVISIONING_PROFILE must point to an existing .provisionprofile file");if(config.icon&&!existsSync(resolve(config.icon)))errors.push(`Apple app icon does not exist: ${config.icon}`);if(!/^\d+(?:\.\d+){0,2}$/.test(config.minimumMacos))errors.push("APPLE_MINIMUM_MACOS must be a macOS version such as 13.0");if(!isAppleCategory(config.category))errors.push("APPLE_APP_CATEGORY must be an Apple LSApplicationCategoryType such as public.app-category.productivity");if(includeApi){if(!config.apiKeyId)errors.push("APP_STORE_CONNECT_API_KEY_ID is required");if(!config.apiIssuerId)errors.push("APP_STORE_CONNECT_API_ISSUER_ID is required");if(!config.apiKeyPath||!existsSync(config.apiKeyPath))errors.push("APP_STORE_CONNECT_API_KEY_PATH must point to an existing .p8 file, or APP_STORE_CONNECT_API_KEY hold its text")}if(config.universal){for(const[variable,path]of[["CRAFT_BIN_ARM64",config.craftArm64],["CRAFT_BIN_X64",config.craftX64]])if(!path||!existsSync(path))errors.push(`${variable} must point to a native Craft runtime for a universal build`);else if(readFileSync(path).subarray(0,2).toString()==="#!")errors.push(`${variable} points at a script, not a native Craft runtime: ${path}`)}for(const tool of config.universal?[...REQUIRED_TOOLS,"lipo"]:REQUIRED_TOOLS)if(!Bun.which(tool))errors.push(`Required Apple command is unavailable: ${tool}`);return errors}function bundleFiles(appPath){const walk=(dir,prefix)=>readdirSync(dir,{withFileTypes:!0}).flatMap((entry)=>{const relative=prefix?`${prefix}/${entry.name}`:entry.name;return entry.isDirectory()?walk(join(dir,entry.name),relative):[relative]});return walk(appPath,"")}export function isAppleCategory(value){return/^public\.app-category\.[a-z][a-z0-9-]*$/.test(value)}export function storeRejectionFindings(paths,executable="stacks-desktop"){const findings=[],has=(path)=>paths.includes(path);for(const required of["Contents/Info.plist",`Contents/MacOS/${executable}`,"Contents/embedded.provisionprofile"])if(!has(required))findings.push(`missing required bundle file: ${required}`);for(const path of paths){const base=path.split("/").pop()??"";if(base===".DS_Store"||path.startsWith("__MACOSX/")||base.startsWith("._"))findings.push(`forbidden file in the bundle: ${path}`);if(/\.(?:dylib|so|framework|app|xpc)$/.test(path)){if(!(path.startsWith("Contents/Frameworks/")||path.startsWith("Contents/MacOS/")||path.startsWith("Contents/XPCServices/")||path.startsWith("Contents/PlugIns/")))findings.push(`nested code outside a signed location: ${path}`)}if(path.startsWith("Contents/Resources/")&&/\.(?:sh|command|dylib|so)$/.test(path))findings.push(`executable content under Resources: ${path}`)}return findings}export function renderInfoPlist(config,executable="stacks-desktop"){const iconEntry=config.icon?`
|
|
3
|
+
`,{mode:384});process.on("exit",()=>rmSync(directory,{recursive:!0,force:!0}));return{...config,apiKeyPath}}export function validateAppleDesktopConfig(config,includeApi=!0){const errors=[];if(process.platform!=="darwin")errors.push("Mac App Store packaging must run on macOS");if(!config.appName)errors.push("APPLE_APP_NAME or --app-name is required");if(!/^[A-Za-z0-9][A-Za-z0-9.-]+$/.test(config.bundleId))errors.push("APPLE_BUNDLE_ID must be a reverse-DNS bundle identifier");if(!/^[A-Z0-9]{10}$/.test(config.teamId))errors.push("APPLE_TEAM_ID must be the 10-character Apple Developer team ID");if(!/^\d+(?:\.\d+){0,2}$/.test(config.version))errors.push("The marketing version must contain one to three numeric components");if(!/^[A-Za-z0-9.-]+$/.test(config.buildNumber))errors.push("The build number must contain only letters, numbers, periods, and hyphens");if(config.buildNumber==="next")errors.push("--build-number next is resolved by desktop:apple:publish; give desktop:apple:package a number");if(!config.appSigningIdentity)errors.push("APPLE_APP_SIGNING_IDENTITY is required");if(!config.installerSigningIdentity)errors.push("APPLE_INSTALLER_SIGNING_IDENTITY is required");if(!config.provisioningProfile||!existsSync(config.provisioningProfile))errors.push("APPLE_PROVISIONING_PROFILE must point to an existing .provisionprofile file");if(config.icon&&!existsSync(resolve(config.icon)))errors.push(`Apple app icon does not exist: ${config.icon}`);if(!/^\d+(?:\.\d+){0,2}$/.test(config.minimumMacos))errors.push("APPLE_MINIMUM_MACOS must be a macOS version such as 13.0");if(!isAppleCategory(config.category))errors.push("APPLE_APP_CATEGORY must be an Apple LSApplicationCategoryType such as public.app-category.productivity");if(includeApi){if(!config.apiKeyId)errors.push("APP_STORE_CONNECT_API_KEY_ID is required");if(!config.apiIssuerId)errors.push("APP_STORE_CONNECT_API_ISSUER_ID is required");if(!config.apiKeyPath||!existsSync(config.apiKeyPath))errors.push("APP_STORE_CONNECT_API_KEY_PATH must point to an existing .p8 file, or APP_STORE_CONNECT_API_KEY hold its text")}if(config.universal){for(const[variable,path]of[["CRAFT_BIN_ARM64",config.craftArm64],["CRAFT_BIN_X64",config.craftX64]])if(!path||!existsSync(path))errors.push(`${variable} must point to a native Craft runtime for a universal build`);else if(readFileSync(path).subarray(0,2).toString()==="#!")errors.push(`${variable} points at a script, not a native Craft runtime: ${path}`)}for(const tool of config.universal?[...REQUIRED_TOOLS,"lipo"]:REQUIRED_TOOLS)if(!Bun.which(tool))errors.push(`Required Apple command is unavailable: ${tool}`);return errors}function bundleFiles(appPath){const walk=(dir,prefix)=>readdirSync(dir,{withFileTypes:!0}).flatMap((entry)=>{const relative=prefix?`${prefix}/${entry.name}`:entry.name;return entry.isDirectory()?walk(join(dir,entry.name),relative):[relative]});return walk(appPath,"")}export function isAppleCategory(value){return/^public\.app-category\.[a-z][a-z0-9-]*$/.test(value)}export function storeRejectionFindings(paths,executable="stacks-desktop"){const findings=[],has=(path)=>paths.includes(path);for(const required of["Contents/Info.plist",`Contents/MacOS/${executable}`,"Contents/embedded.provisionprofile"])if(!has(required))findings.push(`missing required bundle file: ${required}`);for(const path of paths){const base=path.split("/").pop()??"";if(base===".DS_Store"||path.startsWith("__MACOSX/")||base.startsWith("._"))findings.push(`forbidden file in the bundle: ${path}`);if(/\.(?:dylib|so|framework|app|xpc)$/.test(path)){if(!(path.startsWith("Contents/Frameworks/")||path.startsWith("Contents/MacOS/")||path.startsWith("Contents/XPCServices/")||path.startsWith("Contents/PlugIns/")))findings.push(`nested code outside a signed location: ${path}`)}if(path.startsWith("Contents/Resources/")&&/\.(?:sh|command|dylib|so)$/.test(path))findings.push(`executable content under Resources: ${path}`)}return findings}export function renderInfoPlist(config,executable="stacks-desktop"){const iconEntry=config.icon?`
|
|
4
4
|
<key>CFBundleIconFile</key>
|
|
5
5
|
<string>AppIcon</string>`:"";return`<?xml version="1.0" encoding="UTF-8"?>
|
|
6
6
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -96,7 +96,7 @@ jobs:
|
|
|
96
96
|
s3-prefix: \${{ vars.RELEASE_S3_PREFIX }}
|
|
97
97
|
s3-public-url: \${{ vars.RELEASE_S3_PUBLIC_URL }}
|
|
98
98
|
secrets: inherit
|
|
99
|
-
`}function command(args,cwd=projectPath(),extraEnv={}){const result=Bun.spawnSync(args,{cwd,env:{...process.env,...extraEnv},stdin:"inherit",stdout:"inherit",stderr:"inherit"});if(result.exitCode!==0)throw Error(`${args[0]} ${args.slice(1).join(" ")} exited with code ${result.exitCode}`)}export function signingPlan(input){const sign=(entitlements,target)=>["codesign","--force","--timestamp","--options","runtime","--entitlements",entitlements,...input.keychain?["--keychain",input.keychain]:[],"--sign",input.identity,target];return[sign(input.helperEntitlements,input.helperPath),sign(input.appEntitlements,input.appPath)]}export const captureCommand=(args)=>{const result=Bun.spawnSync(args,{cwd:projectPath(),stdin:"inherit",stdout:"pipe",stderr:"inherit"});if(result.exitCode!==0)throw Error(`${args[0]} ${args.slice(1).join(" ")} exited with code ${result.exitCode}`);return result.stdout.toString()},MACH_O_ARCHITECTURE={arm64:"arm64",x64:"x86_64"};export function parseLipoArchs(output){return output.trim().split(/\s+/).filter(Boolean).sort()}export function mergeUniversalBinary(input,run=captureCommand){for(const architecture of["arm64","x64"]){const expected=MACH_O_ARCHITECTURE[architecture],found=parseLipoArchs(run(["lipo","-archs",input[architecture]]));if(found.length!==1||found[0]!==expected)throw Error(`${input.name}: the ${architecture} input ${input[architecture]} contains ${found.join(" + ")||"no architectures"}, expected only ${expected}`)}run(["lipo","-create","-output",input.output,input.arm64,input.x64]);const merged=parseLipoArchs(run(["lipo","-archs",input.output])),expected=Object.values(MACH_O_ARCHITECTURE).sort();if(merged.join(" ")!==expected.join(" "))throw Error(`${input.name}: the universal binary ${input.output} contains ${merged.join(" + ")||"no architectures"}, expected ${expected.join(" + ")}`);return merged}export function buildUniversalPayload(input,run=captureCommand){const slice=(architecture)=>join(input.directory,architecture,"stacks-desktop");for(const architecture of["arm64","x64"]){mkdirSync(join(input.directory,architecture),{recursive:!0});run(input.launcherCompileArgs(architecture,slice(architecture)))}const launcher=join(input.directory,"stacks-desktop"),runtime=join(input.directory,"craft-runtime");mergeUniversalBinary({name:"stacks-desktop",arm64:slice("arm64"),x64:slice("x64"),output:launcher},run);const architectures=mergeUniversalBinary({name:"craft-runtime",arm64:input.craft.arm64,x64:input.craft.x64,output:runtime},run);return{launcher,runtime,architectures}}export function launcherSliceCompileArgs(base,architecture){return["bun",...base,`--target=bun-darwin-${architecture}`]}function signingIdentityExists(identity,keychain){if(!identity)return!1;const result=Bun.spawnSync(["security","find-identity","-v",...keychain?[keychain]:[]],{stdout:"pipe",stderr:"pipe"});return result.exitCode===0&&result.stdout.toString().includes(identity)}function provisioningProfileMatches(config){if(!config.provisioningProfile||!existsSync(config.provisioningProfile))return!1;const result=Bun.spawnSync(["security","cms","-D","-i",config.provisioningProfile],{stdout:"pipe",stderr:"pipe"});if(result.exitCode!==0)return!1;const profile=result.stdout.toString();return profile.includes(config.bundleId)&&profile.includes(config.teamId)}async function buildDesktop(){const{runAction}=await import("@stacksjs/actions"),{Action}=await import("@stacksjs/enums"),result=await runAction(Action.BuildDesktop);if(resultFailed(result))throw result.error}function sha256(path){return createHash("sha256").update(readFileSync(path)).digest("hex")}async function packageAppleDesktop(config,skipBuild=!1,native=null){const errors=validateAppleDesktopConfig(config,!1);if(config.keychain&&!existsSync(config.keychain))errors.push(`APPLE_KEYCHAIN does not exist: ${config.keychain}`);const where=config.keychain?` in ${config.keychain}`:"";if(!signingIdentityExists(config.appSigningIdentity,config.keychain))errors.push(`App signing identity is not installed${where}: ${config.appSigningIdentity}`);if(!signingIdentityExists(config.installerSigningIdentity,config.keychain))errors.push(`Installer signing identity is not installed${where}: ${config.installerSigningIdentity}`);if(!provisioningProfileMatches(config))errors.push(`Provisioning profile does not match ${config.teamId}.${config.bundleId}`);if(native&&config.universal)errors.push("--universal is not supported for a native macOS app yet: the AppKit host is built for this machine's architecture");if(errors.length)throw Error(errors.join(`
|
|
99
|
+
`}function command(args,cwd=projectPath(),extraEnv={}){const result=Bun.spawnSync(args,{cwd,env:{...process.env,...extraEnv},stdin:"inherit",stdout:"inherit",stderr:"inherit"});if(result.exitCode!==0)throw Error(`${args[0]} ${args.slice(1).join(" ")} exited with code ${result.exitCode}`)}export function signingPlan(input){const sign=(entitlements,target)=>["codesign","--force","--timestamp","--options","runtime","--entitlements",entitlements,...input.keychain?["--keychain",input.keychain]:[],"--sign",input.identity,target];return[sign(input.helperEntitlements,input.helperPath),sign(input.appEntitlements,input.appPath)]}export const captureCommand=(args)=>{const result=Bun.spawnSync(args,{cwd:projectPath(),stdin:"inherit",stdout:"pipe",stderr:"inherit"});if(result.exitCode!==0)throw Error(`${args[0]} ${args.slice(1).join(" ")} exited with code ${result.exitCode}`);return result.stdout.toString()},MACH_O_ARCHITECTURE={arm64:"arm64",x64:"x86_64"};export function parseLipoArchs(output){return output.trim().split(/\s+/).filter(Boolean).sort()}export function mergeUniversalBinary(input,run=captureCommand){for(const architecture of["arm64","x64"]){const expected=MACH_O_ARCHITECTURE[architecture],found=parseLipoArchs(run(["lipo","-archs",input[architecture]]));if(found.length!==1||found[0]!==expected)throw Error(`${input.name}: the ${architecture} input ${input[architecture]} contains ${found.join(" + ")||"no architectures"}, expected only ${expected}`)}run(["lipo","-create","-output",input.output,input.arm64,input.x64]);const merged=parseLipoArchs(run(["lipo","-archs",input.output])),expected=Object.values(MACH_O_ARCHITECTURE).sort();if(merged.join(" ")!==expected.join(" "))throw Error(`${input.name}: the universal binary ${input.output} contains ${merged.join(" + ")||"no architectures"}, expected ${expected.join(" + ")}`);return merged}export function buildUniversalPayload(input,run=captureCommand){const slice=(architecture)=>join(input.directory,architecture,"stacks-desktop");for(const architecture of["arm64","x64"]){mkdirSync(join(input.directory,architecture),{recursive:!0});run(input.launcherCompileArgs(architecture,slice(architecture)))}const launcher=join(input.directory,"stacks-desktop"),runtime=join(input.directory,"craft-runtime");mergeUniversalBinary({name:"stacks-desktop",arm64:slice("arm64"),x64:slice("x64"),output:launcher},run);const architectures=mergeUniversalBinary({name:"craft-runtime",arm64:input.craft.arm64,x64:input.craft.x64,output:runtime},run);return{launcher,runtime,architectures}}export function launcherSliceCompileArgs(base,architecture){return["bun",...base,`--target=bun-darwin-${architecture}`]}export function parseDistributionIdentities(output,teamId){const named=(kinds)=>new RegExp(`"((?:${kinds}): [^"]+ \\(${teamId}\\))"`).exec(output)?.[1];return{app:named("Apple Distribution|3rd Party Mac Developer Application"),installer:named("3rd Party Mac Developer Installer|Mac Installer Distribution")}}export function withKeychainIdentities(config,read=readIdentities){if(config.appSigningIdentity&&config.installerSigningIdentity||!config.teamId)return config;const found=parseDistributionIdentities(read(config.keychain),config.teamId);return{...config,appSigningIdentity:config.appSigningIdentity||found.app||"",installerSigningIdentity:config.installerSigningIdentity||found.installer||""}}function readIdentities(keychain){const result=Bun.spawnSync(["security","find-identity","-v",...keychain?[keychain]:[]],{stdout:"pipe",stderr:"pipe"});return result.exitCode===0?result.stdout.toString():""}async function appStoreClient(config){if(!config.apiKeyId||!config.apiIssuerId||!config.apiKeyPath||!existsSync(config.apiKeyPath))throw Error("App Store Connect API key ID, issuer ID, and .p8 key (APP_STORE_CONNECT_API_KEY or APP_STORE_CONNECT_API_KEY_PATH) are required");const{AppStoreConnectClient}=await import("ts-pantry");return new AppStoreConnectClient({keyId:config.apiKeyId,issuerId:config.apiIssuerId,keyPath:config.apiKeyPath})}async function appStoreAppId(client,bundleId){const app=await client.findApp(bundleId);if(!app)throw Error(`App Store Connect has no app for ${bundleId}. Create it under Apps first.`);return app.id}async function withDownloadedProfile(config){if(config.provisioningProfile||!config.bundleId)return config;const client=await appStoreClient(config),bundle=await client.findBundleId(config.bundleId);if(!bundle)throw Error(`No Apple bundle id ${config.bundleId}. Run buddy desktop:apple:provision --apply first.`);const profile=(await client.listProfiles(bundle.id)).filter((item)=>item.attributes.profileState==="ACTIVE"&&item.attributes.profileContent).sort((a,b)=>String(b.attributes.expirationDate).localeCompare(String(a.attributes.expirationDate)))[0];if(!profile)throw Error(`No active Mac App Store profile for ${config.bundleId}. Run buddy desktop:apple:provision --apply first.`);const directory=storagePath("framework/desktop-dist/apple");mkdirSync(directory,{recursive:!0});const provisioningProfile=join(directory,`${config.bundleId}.provisionprofile`);writeFileSync(provisioningProfile,Buffer.from(String(profile.attributes.profileContent),"base64"),{mode:420});log.info(`Using the Mac App Store profile "${profile.attributes.name}" from App Store Connect`);return{...config,provisioningProfile}}async function withNextBuildNumber(config){if(config.buildNumber!=="next")return config;const client=await appStoreClient(config),{nextBuildNumber}=await import("ts-pantry"),buildNumber=await nextBuildNumber(client,await appStoreAppId(client,config.bundleId));log.info(`Building ${config.version} (${buildNumber})`);return{...config,buildNumber}}async function releaseConfig(options,native){const config=withKeychainIdentities(withApiKeyFile(resolveAppleDesktopConfig(options,native)));return await withNextBuildNumber(await withDownloadedProfile(config))}async function distributeToTestFlight(config,groups,whatsNew){const client=await appStoreClient(config),{distributeTestFlightBuild}=await import("ts-pantry");log.info(`Waiting for App Store Connect to process ${config.version} (${config.buildNumber})...`);const result=await distributeTestFlightBuild(client,{appId:await appStoreAppId(client,config.bundleId),version:config.version,buildNumber:config.buildNumber,groups,whatsNew});log.success(`${config.version} (${config.buildNumber}) is on TestFlight for ${result.groups.map((group)=>group.name).join(", ")}`)}function commitsSinceLastTag(){const run=(args)=>Bun.spawnSync(args,{cwd:projectPath(),stdout:"pipe",stderr:"pipe"}),tag=run(["git","describe","--tags","--abbrev=0"]),range=tag.exitCode===0?[`${tag.stdout.toString().trim()}..HEAD`]:[];return run(["git","log","--no-merges","--format=- %s","-20",...range]).stdout.toString().trim().slice(0,4000)}function signingIdentityExists(identity,keychain){if(!identity)return!1;const result=Bun.spawnSync(["security","find-identity","-v",...keychain?[keychain]:[]],{stdout:"pipe",stderr:"pipe"});return result.exitCode===0&&result.stdout.toString().includes(identity)}function provisioningProfileMatches(config){if(!config.provisioningProfile||!existsSync(config.provisioningProfile))return!1;const result=Bun.spawnSync(["security","cms","-D","-i",config.provisioningProfile],{stdout:"pipe",stderr:"pipe"});if(result.exitCode!==0)return!1;const profile=result.stdout.toString();return profile.includes(config.bundleId)&&profile.includes(config.teamId)}async function buildDesktop(){const{runAction}=await import("@stacksjs/actions"),{Action}=await import("@stacksjs/enums"),result=await runAction(Action.BuildDesktop);if(resultFailed(result))throw result.error}function sha256(path){return createHash("sha256").update(readFileSync(path)).digest("hex")}async function packageAppleDesktop(config,skipBuild=!1,native=null){const errors=validateAppleDesktopConfig(config,!1);if(config.keychain&&!existsSync(config.keychain))errors.push(`APPLE_KEYCHAIN does not exist: ${config.keychain}`);const where=config.keychain?` in ${config.keychain}`:"";if(!signingIdentityExists(config.appSigningIdentity,config.keychain))errors.push(`App signing identity is not installed${where}: ${config.appSigningIdentity}`);if(!signingIdentityExists(config.installerSigningIdentity,config.keychain))errors.push(`Installer signing identity is not installed${where}: ${config.installerSigningIdentity}`);if(!provisioningProfileMatches(config))errors.push(`Provisioning profile does not match ${config.teamId}.${config.bundleId}`);if(native&&config.universal)errors.push("--universal is not supported for a native macOS app yet: the AppKit host is built for this machine's architecture");if(errors.length)throw Error(errors.join(`
|
|
100
100
|
`));if(native)return packageNativeApple(config,native);if(!skipBuild)await buildDesktop();const desktopDist=storagePath("framework/desktop-dist");let launcher=join(desktopDist,"stacks-desktop"),runtime=join(desktopDist,"craft-runtime");const manifest=join(desktopDist,"desktop.json");for(const path of[launcher,runtime,manifest])if(!existsSync(path))throw Error(`Desktop build artifact is missing: ${path}`);let architectures=[process.arch==="x64"?"x86_64":process.arch],craftSlices;if(config.universal){const universalDir=join(desktopDist,"universal");if(existsSync(universalDir))rmSync(universalDir,{recursive:!0});const{desktopLauncherCompileArgs,resolveDesktopLauncher}=await import("@stacksjs/desktop-build"),entry=resolveDesktopLauncher(projectPath()),minify=process.env.DESKTOP_MINIFY!=="false",payload=buildUniversalPayload({directory:universalDir,launcherCompileArgs:(architecture,outfile)=>launcherSliceCompileArgs(desktopLauncherCompileArgs({entry,outfile,minify}),architecture),craft:{arm64:config.craftArm64,x64:config.craftX64}});launcher=payload.launcher;runtime=payload.runtime;architectures=payload.architectures;craftSlices={arm64:config.craftArm64,x64:config.craftX64}}const appleDir=join(desktopDist,"apple"),appPath=join(appleDir,`${config.appName}.app`),contents=join(appPath,"Contents"),macosDir=join(contents,"MacOS"),resourcesDir=join(contents,"Resources");if(existsSync(appleDir))rmSync(appleDir,{recursive:!0});mkdirSync(macosDir,{recursive:!0});mkdirSync(resourcesDir,{recursive:!0});copyFileSync(launcher,join(macosDir,"stacks-desktop"));copyFileSync(runtime,join(macosDir,"craft-runtime"));if(config.universal){const parsed=JSON.parse(readFileSync(manifest,"utf8"));writeFileSync(join(resourcesDir,"desktop.json"),`${JSON.stringify({...parsed,architecture:"universal"},null,2)}
|
|
101
101
|
`)}else copyFileSync(manifest,join(resourcesDir,"desktop.json"));copyFileSync(config.provisioningProfile,join(contents,"embedded.provisionprofile"));chmodSync(join(contents,"embedded.provisionprofile"),420);chmodSync(join(macosDir,"stacks-desktop"),493);chmodSync(join(macosDir,"craft-runtime"),493);if(config.icon)copyFileSync(resolve(config.icon),join(resourcesDir,"AppIcon.icns"));const infoPlist=join(contents,"Info.plist"),appEntitlements=join(appleDir,"app.entitlements"),helperEntitlements=join(appleDir,"helper.entitlements");writeFileSync(infoPlist,renderInfoPlist(config));writeFileSync(appEntitlements,renderAppEntitlements(config));writeFileSync(helperEntitlements,renderHelperEntitlements());command(["plutil","-lint",infoPlist,appEntitlements,helperEntitlements]);for(const args of signingPlan({identity:config.appSigningIdentity,appPath,helperPath:join(macosDir,"craft-runtime"),appEntitlements,helperEntitlements,keychain:config.keychain}))command(args);command(["codesign","--verify","--deep","--strict","--verbose=2",appPath]);command(["codesign","-d","--entitlements","-","--xml",appPath]);const findings=storeRejectionFindings(bundleFiles(appPath));if(findings.length>0)throw Error(`The app bundle would be rejected by App Review:
|
|
102
102
|
${findings.map((finding)=>` - ${finding}`).join(`
|
|
@@ -108,4 +108,4 @@ ${findings.map((finding)=>` - ${finding}`).join(`
|
|
|
108
108
|
`));const common=["--type","macos","--file",packagePath,"--apiKey",config.apiKeyId,"--apiIssuer",config.apiIssuerId],env={API_PRIVATE_KEYS_DIR:resolve(config.apiKeyPath,"..")};command(["xcrun","altool","--validate-app",...common],projectPath(),env);if(!validateOnly)command(["xcrun","altool","--upload-app",...common],projectPath(),env)}export function renderFailure(error){return`${error instanceof Error?error.message:String(error)}
|
|
109
109
|
`}function fail(error){process.stderr.write(renderFailure(error));process.exit(1)}export function desktopApple(buddy){buddy.command("desktop:apple:csr","Generate local private keys and CSRs for Mac App Store distribution certificates").option("--common-name <name>","Certificate request common name").option("--output <path>","Directory for private keys and certificate requests").action(async(options)=>{try{const metadata=packageMetadata(),outputDirectory=resolve(options.output||storagePath("framework/desktop-dist/apple/provisioning")),{generateMacCertificateRequests}=await import("ts-pantry");generateMacCertificateRequests({outputDirectory,commonName:options.commonName||metadata.name});log.success(`Generated Apple certificate requests and private keys in ${outputDirectory}`)}catch(error){fail(error)}});buddy.command("desktop:apple:provision","Plan or reconcile Apple Bundle ID, capabilities, certificates, and profile").option("--app-name <name>","Mac App Store display name").option("--bundle-id <id>","Reverse-DNS bundle identifier").option("--api-key-id <id>","App Store Connect API key ID").option("--api-issuer-id <id>","App Store Connect API issuer ID").option("--api-key-path <path>","App Store Connect AuthKey .p8 file").option("--capabilities <types>","Comma-separated Apple capability types").option("--app-certificate-csr <path>","CSR for a missing Mac App Distribution certificate").option("--installer-certificate-csr <path>","CSR for a missing Mac Installer Distribution certificate").option("--profile-name <name>","Provisioning profile name").option("--output <path>","Directory for the plan and downloaded Apple assets").option("--plan","Report the idempotent Apple resource diff without mutating it").option("--apply","Apply the Apple resource diff without revoking existing certificates").action(async(options)=>{try{if(options.plan&&options.apply)throw Error("Choose either --plan or --apply");const config=withApiKeyFile(resolveAppleDesktopConfig(options,await nativeAppleConfig()));if(!config.bundleId)throw Error("APPLE_BUNDLE_ID or --bundle-id is required");if(!config.apiKeyId||!config.apiIssuerId||!config.apiKeyPath||!existsSync(config.apiKeyPath))throw Error("App Store Connect API key ID, issuer ID, and existing .p8 key path are required");const readCsr=(file)=>{if(!file)return;const resolved=resolve(file);if(!existsSync(resolved))throw Error(`Apple certificate CSR does not exist: ${resolved}`);return readFileSync(resolved,"utf8")},{exportAppleCertificateP12,provisionMacApp}=await import("ts-pantry"),result=await provisionMacApp({identifier:config.bundleId,name:config.appName,capabilities:options.capabilities?.split(",").map((value)=>value.trim()).filter(Boolean),appCertificateCsr:readCsr(options.appCertificateCsr),installerCertificateCsr:readCsr(options.installerCertificateCsr),profileName:options.profileName,keyId:config.apiKeyId,issuerId:config.apiIssuerId,keyPath:config.apiKeyPath,checkOnly:!options.apply}),outputDirectory=resolve(options.output||storagePath("framework/desktop-dist/apple/provisioning"));mkdirSync(outputDirectory,{recursive:!0});for(const certificate of result.certificates){if(!certificate.certificateContent)continue;const fileName=certificate.type==="MAC_APP_DISTRIBUTION"?"mac-app-distribution.cer":"mac-installer-distribution.cer";writeFileSync(join(outputDirectory,fileName),Buffer.from(certificate.certificateContent,"base64"),{mode:384})}if(result.profile.profileContent)writeFileSync(join(outputDirectory,"mac-app-store.provisionprofile"),Buffer.from(result.profile.profileContent,"base64"),{mode:384});const certificatePassword=env("APPLE_CERTIFICATE_PASSWORD"),certificateExports=[{type:"MAC_APP_DISTRIBUTION",csr:options.appCertificateCsr,certificate:"mac-app-distribution.cer",output:"mac-app-distribution.p12",name:`${config.appName} Mac App Distribution`},{type:"MAC_INSTALLER_DISTRIBUTION",csr:options.installerCertificateCsr,certificate:"mac-installer-distribution.cer",output:"mac-installer-distribution.p12",name:`${config.appName} Mac Installer Distribution`}];for(const certificateExport of certificateExports){if(!result.certificates.find((item)=>item.type===certificateExport.type)?.certificateContent||!certificateExport.csr||!certificatePassword)continue;exportAppleCertificateP12({certificatePath:join(outputDirectory,certificateExport.certificate),privateKeyPath:resolve(certificateExport.csr.replace(/\.csr$/i,".key")),outputPath:join(outputDirectory,certificateExport.output),password:certificatePassword,name:certificateExport.name})}const certificates=result.certificates.map((item)=>{const certificate={...item};delete certificate.certificateContent;return certificate}),profile={...result.profile};delete profile.profileContent;const report={...result,certificates,profile},reportPath=join(outputDirectory,"provisioning-plan.json");writeFileSync(reportPath,`${JSON.stringify(report,null,2)}
|
|
110
110
|
`,{mode:384});log.success(`${options.apply?"Applied":"Planned"} Apple provisioning: ${reportPath}`);if(!result.appRecord.exists&&result.appRecord.manualAction)log.warn(result.appRecord.manualAction)}catch(error){fail(error)}});buddy.command("desktop:apple:doctor","Validate Mac App Store tooling, credentials, certificates, and project metadata").option("--app-name <name>","Mac App Store display name").option("--bundle-id <id>","Reverse-DNS bundle identifier").option("--team-id <id>","Apple Developer team ID").option("--app-signing-identity <identity>","Mac App Distribution signing identity").option("--installer-signing-identity <identity>","Mac Installer Distribution signing identity").option("--provisioning-profile <path>","Mac App Store provisioning profile").option("--api-key-id <id>","App Store Connect API key ID").option("--api-issuer-id <id>","App Store Connect API issuer ID").option("--api-key-path <path>","App Store Connect AuthKey .p8 file").option("--keychain <path>","Look for the signing identities in this keychain file only (or APPLE_KEYCHAIN)").action(async(options)=>{try{const config=withApiKeyFile(resolveAppleDesktopConfig(options,await nativeAppleConfig())),errors=validateAppleDesktopConfig(config,!0);if(!signingIdentityExists(config.appSigningIdentity,config.keychain))errors.push(`App signing identity is not installed: ${config.appSigningIdentity}`);if(!signingIdentityExists(config.installerSigningIdentity,config.keychain))errors.push(`Installer signing identity is not installed: ${config.installerSigningIdentity}`);if(!provisioningProfileMatches(config))errors.push(`Provisioning profile does not match ${config.teamId}.${config.bundleId}`);if(errors.length)throw Error(errors.join(`
|
|
111
|
-
`));log.success(`Mac App Store prerequisites are ready for ${config.bundleId}`)}catch(error){fail(error)}});buddy.command("desktop:apple:init","Create a GitHub Actions caller for the reusable Stacks Mac App Store workflow").option("--force","Replace an existing workflow").action((options)=>{try{const workflowPath=projectPath(".github/workflows/apple-app-store.yml");if(existsSync(workflowPath)&&!options.force)throw Error(`${workflowPath} already exists. Use --force to replace it.`);mkdirSync(resolve(workflowPath,".."),{recursive:!0});writeFileSync(workflowPath,renderAppleWorkflowCaller());log.success(`Created ${workflowPath}`)}catch(error){fail(error)}});const addSharedOptions=(commandBuilder)=>commandBuilder.option("--app-name <name>","Mac App Store display name").option("--bundle-id <id>","Reverse-DNS bundle identifier").option("--team-id <id>","Apple Developer team ID").option("--app-version <version>","Marketing version").option("--build-number <number>",
|
|
111
|
+
`));log.success(`Mac App Store prerequisites are ready for ${config.bundleId}`)}catch(error){fail(error)}});buddy.command("desktop:apple:init","Create a GitHub Actions caller for the reusable Stacks Mac App Store workflow").option("--force","Replace an existing workflow").action((options)=>{try{const workflowPath=projectPath(".github/workflows/apple-app-store.yml");if(existsSync(workflowPath)&&!options.force)throw Error(`${workflowPath} already exists. Use --force to replace it.`);mkdirSync(resolve(workflowPath,".."),{recursive:!0});writeFileSync(workflowPath,renderAppleWorkflowCaller());log.success(`Created ${workflowPath}`)}catch(error){fail(error)}});const addSharedOptions=(commandBuilder)=>commandBuilder.option("--app-name <name>","Mac App Store display name").option("--bundle-id <id>","Reverse-DNS bundle identifier").option("--team-id <id>","Apple Developer team ID").option("--app-version <version>","Marketing version").option("--build-number <number>",'Unique App Store build number, or "next" for one past the highest on App Store Connect (publish only)').option("--minimum-macos <version>","Minimum supported macOS version").option("--category <category>","LSApplicationCategoryType value").option("--app-signing-identity <identity>","Mac App Distribution signing identity").option("--installer-signing-identity <identity>","Mac Installer Distribution signing identity").option("--provisioning-profile <path>","Mac App Store provisioning profile").option("--icon <path>","Optional .icns app icon").option("--skip-build","Package existing storage/framework/desktop-dist artifacts").option("--universal","Ship one arm64 + x86_64 binary, merged with lipo").option("--craft-arm64 <path>","Thin arm64 Craft runtime for --universal (or CRAFT_BIN_ARM64)").option("--craft-x64 <path>","Thin x86_64 Craft runtime for --universal (or CRAFT_BIN_X64)").option("--keychain <path>","Sign with identities from this keychain file only (or APPLE_KEYCHAIN)");addSharedOptions(buddy.command("desktop:apple:package","Build, sandbox, sign, and package a Mac App Store desktop app")).action(async(options)=>{try{const native=await nativeAppleConfig(),packagePath=await packageAppleDesktop(withKeychainIdentities(resolveAppleDesktopConfig(options,native)),Boolean(options.skipBuild),native);log.success(`Created signed Mac App Store package ${packagePath}`)}catch(error){fail(error)}});addSharedOptions(buddy.command("desktop:apple:publish","Build and validate or upload a signed Mac App Store package")).option("--api-key-id <id>","App Store Connect API key ID").option("--api-issuer-id <id>","App Store Connect API issuer ID").option("--api-key-path <path>","App Store Connect AuthKey .p8 file").option("--validate-only","Validate with App Store Connect without uploading").option("--package-only","Create the signed package without contacting App Store Connect").option("--testflight <groups>","After the upload, wait for processing and give the build to these comma-separated TestFlight groups").option("--whats-new <text>",'TestFlight "What to Test" (default: the commit subjects since the last tag)').action(async(options)=>{try{const groups=options.testflight?.split(",").map((name)=>name.trim()).filter(Boolean)??[];if(groups.length&&(options.validateOnly||options.packageOnly))throw Error("--testflight needs an upload, so it cannot be combined with --validate-only or --package-only");const native=await nativeAppleConfig(),config=await releaseConfig(options,native),packagePath=await packageAppleDesktop(config,Boolean(options.skipBuild),native);if(!options.packageOnly)validateOrUpload(packagePath,config,Boolean(options.validateOnly));log.success(options.packageOnly?`Created signed Mac App Store package ${packagePath}`:options.validateOnly?`Validated ${packagePath} with App Store Connect`:`Uploaded ${packagePath} to App Store Connect`);if(groups.length)await distributeToTestFlight(config,groups,options.whatsNew??commitsSinceLastTag())}catch(error){fail(error)}})}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{readFileSync,writeFileSync}from"node:fs";import{resolve}from"node:path";import{assertFrameworkRepo}from"./framework-repo";async function generators(){const{renderApiClient,generateOpenApi,renderOpenApiTypes}=await import("@stacksjs/api");return{renderApiClient,generateOpenApi,renderOpenApiTypes}}const root=resolve(import.meta.dir,"../../../../../../.."),openApiPath=resolve(root,"storage/framework/api/openapi.json"),apiTypesPath=resolve(root,"storage/framework/api/api-types.ts"),clientPath=resolve(root,"storage/framework/api/client.ts");export function validateOpenApi(document){const errors=[],paths=Object.entries(document.paths||{});if(paths.length<10)errors.push("OpenAPI document has fewer than 10 registered paths");const operationIds=new Set;for(const[route,item]of paths)for(const[
|
|
1
|
+
import{readFileSync,writeFileSync}from"node:fs";import{resolve}from"node:path";import{assertFrameworkRepo}from"./framework-repo";async function generators(){const{renderApiClient,generateOpenApi,renderOpenApiTypes}=await import("@stacksjs/api");return{renderApiClient,generateOpenApi,renderOpenApiTypes}}const root=resolve(import.meta.dir,"../../../../../../.."),openApiPath=resolve(root,"storage/framework/api/openapi.json"),apiTypesPath=resolve(root,"storage/framework/api/api-types.ts"),clientPath=resolve(root,"storage/framework/api/client.ts");export function validateOpenApi(document){const errors=[],paths=Object.entries(document.paths||{});if(paths.length<10)errors.push("OpenAPI document has fewer than 10 registered paths");const operationIds=new Set;for(const[route,item]of paths)for(const method of["get","put","post","delete","options","head","patch","trace"]){const operation=item[method];if(!operation)continue;if(!operation.operationId)errors.push(`${method.toUpperCase()} ${route}: operationId is missing`);else if(operationIds.has(operation.operationId))errors.push(`${method.toUpperCase()} ${route}: duplicate operationId ${operation.operationId}`);else operationIds.add(operation.operationId);for(const parameter of[...item.parameters??[],...operation.parameters??[]])if("in"in parameter&¶meter.in==="path"&&!parameter.required)errors.push(`${method.toUpperCase()} ${route}: path parameter ${parameter.name} must be required`)}return errors}async function expectedArtifacts(){const{renderApiClient,generateOpenApi,renderOpenApiTypes}=await generators(),document=await generateOpenApi({write:!1}),errors=validateOpenApi(document);if(errors.length)throw Error(errors.join(`
|
|
2
2
|
`));return{openApi:JSON.stringify(document,null,2),apiTypes:renderOpenApiTypes(document),client:renderApiClient(document,{name:document.info?.title})}}async function write(){const expected=await expectedArtifacts();writeFileSync(openApiPath,expected.openApi);writeFileSync(apiTypesPath,expected.apiTypes);writeFileSync(clientPath,expected.client);console.log("Generated OpenAPI, API type and client artifacts")}async function check(){const expected=await expectedArtifacts(),errors=[];if(readFileSync(openApiPath,"utf8")!==expected.openApi)errors.push("storage/framework/api/openapi.json is stale");if(readFileSync(apiTypesPath,"utf8")!==expected.apiTypes)errors.push("storage/framework/api/api-types.ts is stale");if(readFileSync(clientPath,"utf8")!==expected.client)errors.push("storage/framework/api/client.ts is stale");if(errors.length)throw Error(`${errors.join(`
|
|
3
3
|
`)}
|
|
4
4
|
Run bun run docs:artifacts and review the generated diff.`);console.log(`Generated API artifacts are current (${Object.keys(JSON.parse(expected.openApi).paths).length} paths)`)}export async function run(){assertFrameworkRepo(root,"docs:artifacts");try{if(process.argv.includes("--write"))await write();else if(process.argv.includes("--check"))await check();else{console.error("usage: bun storage/framework/core/buddy/src/commands/docs/generated-artifacts.ts --write | --check");process.exit(2)}}catch(error){console.error(error instanceof Error?error.message:String(error));process.exit(1)}}if(import.meta.main)await run();
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.439",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -95,73 +95,73 @@
|
|
|
95
95
|
"prepublishOnly": "bun run build"
|
|
96
96
|
},
|
|
97
97
|
"dependencies": {
|
|
98
|
-
"@stacksjs/actions": "0.75.
|
|
99
|
-
"@stacksjs/ai": "0.75.
|
|
100
|
-
"@stacksjs/alias": "0.75.
|
|
101
|
-
"@stacksjs/analytics": "0.75.
|
|
102
|
-
"@stacksjs/api": "0.75.
|
|
103
|
-
"@stacksjs/arrays": "0.75.
|
|
104
|
-
"@stacksjs/auth": "0.75.
|
|
105
|
-
"@stacksjs/browser-extension": "0.75.
|
|
106
|
-
"@stacksjs/build": "0.75.
|
|
98
|
+
"@stacksjs/actions": "0.75.439",
|
|
99
|
+
"@stacksjs/ai": "0.75.439",
|
|
100
|
+
"@stacksjs/alias": "0.75.439",
|
|
101
|
+
"@stacksjs/analytics": "0.75.439",
|
|
102
|
+
"@stacksjs/api": "0.75.439",
|
|
103
|
+
"@stacksjs/arrays": "0.75.439",
|
|
104
|
+
"@stacksjs/auth": "0.75.439",
|
|
105
|
+
"@stacksjs/browser-extension": "0.75.439",
|
|
106
|
+
"@stacksjs/build": "0.75.439",
|
|
107
107
|
"@stacksjs/bumpx": "^0.2.26",
|
|
108
|
-
"@stacksjs/cache": "0.75.
|
|
109
|
-
"@stacksjs/chat": "0.75.
|
|
108
|
+
"@stacksjs/cache": "0.75.439",
|
|
109
|
+
"@stacksjs/chat": "0.75.439",
|
|
110
110
|
"@stacksjs/clapp": "^0.2.16",
|
|
111
|
-
"@stacksjs/cli": "0.75.
|
|
112
|
-
"@stacksjs/cloud": "0.75.
|
|
113
|
-
"@stacksjs/cms": "0.75.
|
|
114
|
-
"@stacksjs/collections": "0.75.
|
|
115
|
-
"@stacksjs/commerce": "0.75.
|
|
116
|
-
"@stacksjs/config": "0.75.
|
|
117
|
-
"@stacksjs/database": "0.75.
|
|
118
|
-
"@stacksjs/desktop-build": "0.75.
|
|
119
|
-
"@stacksjs/dns": "0.75.
|
|
111
|
+
"@stacksjs/cli": "0.75.439",
|
|
112
|
+
"@stacksjs/cloud": "0.75.439",
|
|
113
|
+
"@stacksjs/cms": "0.75.439",
|
|
114
|
+
"@stacksjs/collections": "0.75.439",
|
|
115
|
+
"@stacksjs/commerce": "0.75.439",
|
|
116
|
+
"@stacksjs/config": "0.75.439",
|
|
117
|
+
"@stacksjs/database": "0.75.439",
|
|
118
|
+
"@stacksjs/desktop-build": "0.75.439",
|
|
119
|
+
"@stacksjs/dns": "0.75.439",
|
|
120
120
|
"@stacksjs/dnsx": "^0.2.3",
|
|
121
|
-
"@stacksjs/email": "0.75.
|
|
122
|
-
"@stacksjs/enums": "0.75.
|
|
123
|
-
"@stacksjs/env": "0.75.
|
|
124
|
-
"@stacksjs/error-handling": "0.75.
|
|
125
|
-
"@stacksjs/events": "0.75.
|
|
126
|
-
"@stacksjs/features": "0.75.
|
|
127
|
-
"@stacksjs/git": "0.75.
|
|
121
|
+
"@stacksjs/email": "0.75.439",
|
|
122
|
+
"@stacksjs/enums": "0.75.439",
|
|
123
|
+
"@stacksjs/env": "0.75.439",
|
|
124
|
+
"@stacksjs/error-handling": "0.75.439",
|
|
125
|
+
"@stacksjs/events": "0.75.439",
|
|
126
|
+
"@stacksjs/features": "0.75.439",
|
|
127
|
+
"@stacksjs/git": "0.75.439",
|
|
128
128
|
"@stacksjs/gitit": "^0.2.5",
|
|
129
|
-
"@stacksjs/health": "0.75.
|
|
129
|
+
"@stacksjs/health": "0.75.439",
|
|
130
130
|
"@stacksjs/httx": "^0.1.10",
|
|
131
|
-
"@stacksjs/image": "0.75.
|
|
132
|
-
"@stacksjs/lint": "0.75.
|
|
133
|
-
"@stacksjs/logging": "0.75.
|
|
134
|
-
"@stacksjs/notifications": "0.75.
|
|
135
|
-
"@stacksjs/objects": "0.75.
|
|
136
|
-
"@stacksjs/orm": "0.75.
|
|
137
|
-
"@stacksjs/path": "0.75.
|
|
138
|
-
"@stacksjs/payments": "0.75.
|
|
139
|
-
"@stacksjs/realtime": "0.75.
|
|
140
|
-
"@stacksjs/router": "0.75.
|
|
131
|
+
"@stacksjs/image": "0.75.439",
|
|
132
|
+
"@stacksjs/lint": "0.75.439",
|
|
133
|
+
"@stacksjs/logging": "0.75.439",
|
|
134
|
+
"@stacksjs/notifications": "0.75.439",
|
|
135
|
+
"@stacksjs/objects": "0.75.439",
|
|
136
|
+
"@stacksjs/orm": "0.75.439",
|
|
137
|
+
"@stacksjs/path": "0.75.439",
|
|
138
|
+
"@stacksjs/payments": "0.75.439",
|
|
139
|
+
"@stacksjs/realtime": "0.75.439",
|
|
140
|
+
"@stacksjs/router": "0.75.439",
|
|
141
141
|
"@stacksjs/rpx": "^0.11.54",
|
|
142
|
-
"@stacksjs/scheduler": "0.75.
|
|
143
|
-
"@stacksjs/search-engine": "0.75.
|
|
144
|
-
"@stacksjs/security": "0.75.
|
|
145
|
-
"@stacksjs/server": "0.75.
|
|
146
|
-
"@stacksjs/sites": "0.75.
|
|
147
|
-
"@stacksjs/skills": "0.75.
|
|
148
|
-
"@stacksjs/socials": "0.75.
|
|
149
|
-
"@stacksjs/storage": "0.75.
|
|
150
|
-
"@stacksjs/strings": "0.75.
|
|
142
|
+
"@stacksjs/scheduler": "0.75.439",
|
|
143
|
+
"@stacksjs/search-engine": "0.75.439",
|
|
144
|
+
"@stacksjs/security": "0.75.439",
|
|
145
|
+
"@stacksjs/server": "0.75.439",
|
|
146
|
+
"@stacksjs/sites": "0.75.439",
|
|
147
|
+
"@stacksjs/skills": "0.75.439",
|
|
148
|
+
"@stacksjs/socials": "0.75.439",
|
|
149
|
+
"@stacksjs/storage": "0.75.439",
|
|
150
|
+
"@stacksjs/strings": "0.75.439",
|
|
151
151
|
"@stacksjs/stx": "0.2.784",
|
|
152
|
-
"@stacksjs/testing": "0.75.
|
|
153
|
-
"@stacksjs/tinker": "0.75.
|
|
152
|
+
"@stacksjs/testing": "0.75.439",
|
|
153
|
+
"@stacksjs/tinker": "0.75.439",
|
|
154
154
|
"@stacksjs/tlsx": "^0.13.19",
|
|
155
155
|
"@stacksjs/ts-cloud": "^0.16.91",
|
|
156
|
-
"@stacksjs/tunnel": "0.75.
|
|
157
|
-
"@stacksjs/types": "0.75.
|
|
158
|
-
"@stacksjs/ui": "0.75.
|
|
159
|
-
"@stacksjs/utils": "0.75.
|
|
160
|
-
"@stacksjs/validation": "0.75.
|
|
156
|
+
"@stacksjs/tunnel": "0.75.439",
|
|
157
|
+
"@stacksjs/types": "0.75.439",
|
|
158
|
+
"@stacksjs/ui": "0.75.439",
|
|
159
|
+
"@stacksjs/utils": "0.75.439",
|
|
160
|
+
"@stacksjs/validation": "0.75.439",
|
|
161
161
|
"ajv": "^8.20.0",
|
|
162
162
|
"ajv-formats": "^3.0.1",
|
|
163
163
|
"bun-plugin-stx": "0.2.784",
|
|
164
|
-
"ts-pantry": "^0.11.
|
|
164
|
+
"ts-pantry": "^0.11.161"
|
|
165
165
|
},
|
|
166
166
|
"devDependencies": {
|
|
167
167
|
"better-dx": "^0.2.24"
|