@stacksjs/buddy 0.70.259 → 0.70.261

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.
@@ -97,6 +97,7 @@ jobs:
97
97
  `));if(!skipBuild)await buildDesktop();const desktopDist=storagePath("framework/desktop-dist"),launcher=join(desktopDist,"stacks-desktop"),runtime=join(desktopDist,"craft-runtime"),manifest=join(desktopDist,"desktop.json");for(const path of[launcher,runtime,manifest])if(!existsSync(path))throw Error(`Desktop build artifact is missing: ${path}`);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"));copyFileSync(manifest,join(macosDir,"desktop.json"));copyFileSync(config.provisioningProfile,join(contents,"embedded.provisionprofile"));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]);command(["codesign","--force","--timestamp","--options","runtime","--entitlements",helperEntitlements,"--sign",config.appSigningIdentity,join(macosDir,"craft-runtime")]);command(["codesign","--force","--timestamp","--options","runtime","--entitlements",appEntitlements,"--sign",config.appSigningIdentity,appPath]);command(["codesign","--verify","--deep","--strict","--verbose=2",appPath]);command(["codesign","-d","--entitlements",":-",appPath]);const packagePath=join(appleDir,`${config.appName}-${config.version}-${config.buildNumber}.pkg`);command(["productbuild","--component",appPath,"/Applications","--sign",config.installerSigningIdentity,packagePath]);command(["pkgutil","--check-signature",packagePath]);const packageHash=sha256(packagePath);writeFileSync(join(appleDir,"checksums.sha256"),`${packageHash} ${basename(packagePath)}
98
98
  `);writeFileSync(join(appleDir,"apple-provenance.json"),`${JSON.stringify({schemaVersion:"1.0.0",appName:config.appName,bundleId:config.bundleId,teamId:config.teamId,version:config.version,buildNumber:config.buildNumber,minimumMacos:config.minimumMacos,package:{name:basename(packagePath),sha256:packageHash},sourceRevision:Bun.spawnSync(["git","rev-parse","HEAD"],{cwd:projectPath()}).stdout.toString().trim(),craft:{sha256:sha256(join(macosDir,"craft-runtime"))}},null,2)}
99
99
  `);return packagePath}function validateOrUpload(packagePath,config,validateOnly){const errors=validateAppleDesktopConfig(config,!0);if(errors.length)throw Error(errors.join(`
100
- `));const common=["--type","macos","--file",packagePath,"--apiKey",config.apiKeyId,"--apiIssuer",config.apiIssuerId];process.env.API_PRIVATE_KEYS_DIR=resolve(config.apiKeyPath,"..");command(["xcrun","altool","--validate-app",...common]);if(!validateOnly)command(["xcrun","altool","--upload-app",...common])}function fail(error){log.error(error instanceof Error?error.message:String(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=resolveAppleDesktopConfig(options);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)}
100
+ `));const common=["--type","macos","--file",packagePath,"--apiKey",config.apiKeyId,"--apiIssuer",config.apiIssuerId];process.env.API_PRIVATE_KEYS_DIR=resolve(config.apiKeyPath,"..");command(["xcrun","altool","--validate-app",...common]);if(!validateOnly)command(["xcrun","altool","--upload-app",...common])}function fail(error){const message=error instanceof Error?error.message:String(error);process.stderr.write(`${message}
101
+ `);log.error(message);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=resolveAppleDesktopConfig(options);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)}
101
102
  `,{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").action((options)=>{try{const config=resolveAppleDesktopConfig(options),errors=validateAppleDesktopConfig(config,!0);if(!signingIdentityExists(config.appSigningIdentity))errors.push(`App signing identity is not installed: ${config.appSigningIdentity}`);if(!signingIdentityExists(config.installerSigningIdentity))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(`
102
103
  `));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").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");addSharedOptions(buddy.command("desktop:apple:package","Build, sandbox, sign, and package a Mac App Store desktop app")).action(async(options)=>{try{const packagePath=await packageAppleDesktop(resolveAppleDesktopConfig(options),Boolean(options.skipBuild));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").action(async(options)=>{try{const config=resolveAppleDesktopConfig(options),packagePath=await packageAppleDesktop(config,Boolean(options.skipBuild));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`)}catch(error){fail(error)}})}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/buddy",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.259",
5
+ "version": "0.70.261",
6
6
  "description": "Meet Buddy. The Stacks runtime.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -95,53 +95,53 @@
95
95
  "prepublishOnly": "bun run build"
96
96
  },
97
97
  "dependencies": {
98
- "@stacksjs/actions": "^0.70.259",
99
- "@stacksjs/ai": "^0.70.259",
100
- "@stacksjs/alias": "^0.70.259",
101
- "@stacksjs/arrays": "^0.70.259",
102
- "@stacksjs/auth": "^0.70.259",
103
- "@stacksjs/build": "^0.70.259",
104
- "@stacksjs/cache": "^0.70.259",
105
- "@stacksjs/cli": "^0.70.259",
98
+ "@stacksjs/actions": "^0.70.261",
99
+ "@stacksjs/ai": "^0.70.261",
100
+ "@stacksjs/alias": "^0.70.261",
101
+ "@stacksjs/arrays": "^0.70.261",
102
+ "@stacksjs/auth": "^0.70.261",
103
+ "@stacksjs/build": "^0.70.261",
104
+ "@stacksjs/cache": "^0.70.261",
105
+ "@stacksjs/cli": "^0.70.261",
106
106
  "@stacksjs/clapp": "^0.2.12",
107
- "@stacksjs/cloud": "^0.70.259",
108
- "@stacksjs/collections": "^0.70.259",
109
- "@stacksjs/config": "^0.70.259",
110
- "@stacksjs/database": "^0.70.259",
111
- "@stacksjs/desktop-build": "^0.70.259",
112
- "@stacksjs/dns": "^0.70.259",
113
- "@stacksjs/email": "^0.70.259",
114
- "@stacksjs/enums": "^0.70.259",
115
- "@stacksjs/error-handling": "^0.70.259",
116
- "@stacksjs/events": "^0.70.259",
117
- "@stacksjs/git": "^0.70.259",
107
+ "@stacksjs/cloud": "^0.70.261",
108
+ "@stacksjs/collections": "^0.70.261",
109
+ "@stacksjs/config": "^0.70.261",
110
+ "@stacksjs/database": "^0.70.261",
111
+ "@stacksjs/desktop-build": "^0.70.261",
112
+ "@stacksjs/dns": "^0.70.261",
113
+ "@stacksjs/email": "^0.70.261",
114
+ "@stacksjs/enums": "^0.70.261",
115
+ "@stacksjs/error-handling": "^0.70.261",
116
+ "@stacksjs/events": "^0.70.261",
117
+ "@stacksjs/git": "^0.70.261",
118
118
  "@stacksjs/gitit": "^0.2.5",
119
- "@stacksjs/health": "^0.70.259",
119
+ "@stacksjs/health": "^0.70.261",
120
120
  "@stacksjs/dnsx": "^0.2.3",
121
121
  "@stacksjs/httx": "^0.1.10",
122
- "@stacksjs/image": "^0.70.259",
123
- "@stacksjs/lint": "^0.70.259",
124
- "@stacksjs/logging": "^0.70.259",
125
- "@stacksjs/notifications": "^0.70.259",
126
- "@stacksjs/objects": "^0.70.259",
127
- "@stacksjs/orm": "^0.70.259",
128
- "@stacksjs/path": "^0.70.259",
129
- "@stacksjs/skills": "^0.70.259",
130
- "@stacksjs/payments": "^0.70.259",
131
- "@stacksjs/realtime": "^0.70.259",
132
- "@stacksjs/router": "^0.70.259",
122
+ "@stacksjs/image": "^0.70.261",
123
+ "@stacksjs/lint": "^0.70.261",
124
+ "@stacksjs/logging": "^0.70.261",
125
+ "@stacksjs/notifications": "^0.70.261",
126
+ "@stacksjs/objects": "^0.70.261",
127
+ "@stacksjs/orm": "^0.70.261",
128
+ "@stacksjs/path": "^0.70.261",
129
+ "@stacksjs/skills": "^0.70.261",
130
+ "@stacksjs/payments": "^0.70.261",
131
+ "@stacksjs/realtime": "^0.70.261",
132
+ "@stacksjs/router": "^0.70.261",
133
133
  "@stacksjs/rpx": "^0.11.42",
134
- "@stacksjs/search-engine": "^0.70.259",
135
- "@stacksjs/security": "^0.70.259",
136
- "@stacksjs/server": "^0.70.259",
137
- "@stacksjs/storage": "^0.70.259",
138
- "@stacksjs/strings": "^0.70.259",
139
- "@stacksjs/testing": "^0.70.259",
140
- "@stacksjs/tunnel": "^0.70.259",
141
- "@stacksjs/types": "^0.70.259",
142
- "@stacksjs/ui": "^0.70.259",
143
- "@stacksjs/utils": "^0.70.259",
144
- "@stacksjs/validation": "^0.70.259",
134
+ "@stacksjs/search-engine": "^0.70.261",
135
+ "@stacksjs/security": "^0.70.261",
136
+ "@stacksjs/server": "^0.70.261",
137
+ "@stacksjs/storage": "^0.70.261",
138
+ "@stacksjs/strings": "^0.70.261",
139
+ "@stacksjs/testing": "^0.70.261",
140
+ "@stacksjs/tunnel": "^0.70.261",
141
+ "@stacksjs/types": "^0.70.261",
142
+ "@stacksjs/ui": "^0.70.261",
143
+ "@stacksjs/utils": "^0.70.261",
144
+ "@stacksjs/validation": "^0.70.261",
145
145
  "@stacksjs/ts-cloud": "^0.7.94",
146
146
  "ajv": "^8.20.0",
147
147
  "ajv-formats": "^3.0.1",