@stacksjs/desktop-build 0.75.407 → 0.75.409

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -132,6 +132,8 @@ export declare function desktopAppVersion(options?: DesktopAppVersionOptions): s
132
132
  * somebody typed is how a build becomes unpredictable.
133
133
  */
134
134
  export declare function dmgVolumeName(options: DmgVolumeOptions): string;
135
+ /** The arguments that sign `notarytool` in. A key held as PEM text has to be written to `keyPath` first. */
136
+ export declare function notarytoolAuthArgs(credentials: { profile: string } | { keyId: string, issuerId: string, keyPath: string }): string[];
135
137
  /**
136
138
  * Everything `build:dmg` needs to name and sign a bundle, from flags first and
137
139
  * the environment second.
@@ -301,6 +303,10 @@ export declare interface DmgPackagingFlags {
301
303
  bundleId?: unknown
302
304
  signingIdentity?: unknown
303
305
  notaryProfile?: unknown
306
+ notarize?: unknown
307
+ apiKeyId?: unknown
308
+ apiIssuerId?: unknown
309
+ apiKeyPath?: unknown
304
310
  volumeName?: unknown
305
311
  [flag: string]: unknown
306
312
  }
@@ -317,6 +323,7 @@ export declare interface DmgPackaging {
317
323
  volumeName: string
318
324
  signingIdentity?: string
319
325
  notaryProfile?: string
326
+ notary?: NotaryCredentials
320
327
  }
321
328
  export declare interface CodesignOptions {
322
329
  identity: string
@@ -325,6 +332,15 @@ export declare interface CodesignOptions {
325
332
  }
326
333
  export type CraftLauncher = (command: string[]) => void | Promise<void>;
327
334
  export type CraftBinaryLocator = (binary: string) => string | null;
335
+ /**
336
+ * How `notarytool` signs in: a keychain profile saved by `xcrun notarytool
337
+ * store-credentials`, or an App Store Connect API key, which needs no keychain
338
+ * and is what CI and the Mac App Store path (`desktop:apple`) already hold.
339
+ * The key is a `.p8` file or, from an encrypted `.env.production`, its PEM text.
340
+ */
341
+ export type NotaryCredentials = | { profile: string }
342
+ | { keyId: string, issuerId: string, keyPath: string }
343
+ | { keyId: string, issuerId: string, keyPem: string }
328
344
  export * from './agent';
329
345
  export * from './agent-launcher';
330
346
  export * from './invites';
package/dist/index.js CHANGED
@@ -36,4 +36,5 @@ ${kept.map(([key,value])=>` <key>${xmlEscape(key)}</key>${plistValue(value," "
36
36
  ${minimumSystem}${highResolution}${transportSecurity}${icon}${extra}
37
37
  </dict>
38
38
  </plist>
39
- `,ignored}}export function resolveDevWindowUrl(port,options={}){if(!Number.isInteger(port)||port<1||port>65535)throw RangeError(`Invalid desktop development port: ${port}`);const configured=options.url||process.env.APP_URL;if(!configured)return"https://stacks.test";const withProtocol=/^https?:\/\//.test(configured)?configured:`https://${configured}`;return new URL(withProtocol).toString().replace(/\/$/,"")}export function craftDevCommand(port,options={}){const command=[resolveCraftBinary(options.craftBin),resolveDevWindowUrl(port,options),"--title",options.title||"Stacks","--width",String(options.width||1400),"--height",String(options.height||900)];if(options.hotReload!==!1)command.push("--hot-reload");if(options.devTools===!1)command.push("--no-devtools");if(options.darkMode)command.push("--dark");if(options.systemTray)command.push("--system-tray");if(options.hideDockIcon)command.push("--hide-dock-icon");if(options.menubarOnly)command.push("--menubar-only");return command}export function createUpdateManifestUrl(baseUrl,channel="stable"){if(!/^[a-z0-9-]+$/i.test(channel))throw Error("Update channel may only contain letters, numbers, and hyphens");return new URL(`/desktop/updates/${channel}.json`,/^https?:\/\//.test(baseUrl)?baseUrl:`https://${baseUrl}`).toString()}async function launchCraft(command){Bun.spawn(command,{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).unref()}export async function openDevWindow(port,options={},launcher=launchCraft){await launcher(craftDevCommand(port,options));return!0}export const BUN_EXECUTABLE_MARKER="---- Bun!";const MARKER_SEARCH_BYTES=8388608,RUNTIME_SIZE_FLOOR=41943040,MACH_O_MAGIC=new Set([4277009102,3472551422,4277009103,3489328638,3405691582,3199925962]);export function isMachO(path){try{const fd=openSync(path,"r");try{const head=Buffer.alloc(4);if(readSync(fd,head,0,4,0)<4)return!1;return MACH_O_MAGIC.has(head.readUInt32BE(0))}finally{closeSync(fd)}}catch{return!1}}export function bundleDirectoryFor(path){return isMachO(path)?"MacOS":"Resources"}export function desktopAppVersion(options={}){const override=options.override?.trim();if(override)return override;return(typeof options.declared==="string"?options.declared.trim():"")||"0.0.0"}export function dmgVolumeName(options){const override=options.override?.trim();if(override)return override;const appName=options.appName.trim(),version=options.version?.trim();return version?`${appName} ${version}`:`${appName} Installer`}function supplied(value){if(typeof value!=="string")return;return value.trim()||void 0}export function resolveDmgPackaging(inputs={}){const flags=inputs.flags??{},env=inputs.env??{},appName=supplied(flags.appName)??supplied(env.DESKTOP_APP_NAME)??supplied(inputs.manifestTitle)??supplied(env.APP_NAME)??"Stacks",version=desktopAppVersion({override:supplied(flags.appVersion)??supplied(env.DESKTOP_APP_VERSION),declared:inputs.declaredVersion}),bundleId=supplied(flags.bundleId)??supplied(env.DESKTOP_BUNDLE_ID)??`sh.stacks.${appName.toLowerCase().replace(/[^a-z0-9]+/g,"-")}`;return{appName,bundleId,version,volumeName:dmgVolumeName({appName,version,override:supplied(flags.volumeName)??supplied(env.DESKTOP_VOLUME_NAME)}),signingIdentity:supplied(flags.signingIdentity)??supplied(env.DESKTOP_SIGNING_IDENTITY),notaryProfile:supplied(flags.notaryProfile)??supplied(env.DESKTOP_NOTARY_PROFILE)}}export function codesignArgs(options){return["codesign","--force",options.identity==="-"?"--timestamp=none":"--timestamp","--options","runtime",...options.entitlements?["--entitlements",options.entitlements]:[],"--sign",options.identity,options.target]}export function looksLikeBunExecutable(path,read=readTail){const file=read(path);if(!file||file.size<RUNTIME_SIZE_FLOOR)return!1;return file.tail.includes(BUN_EXECUTABLE_MARKER)}function readTail(path){try{const{size}=statSync(path);if(size<RUNTIME_SIZE_FLOOR)return{size,tail:""};const fd=openSync(path,"r");try{const length=Math.min(MARKER_SEARCH_BYTES,size),buffer=Buffer.alloc(length);readSync(fd,buffer,0,length,size-length);return{size,tail:buffer.toString("latin1")}}finally{closeSync(fd)}}catch{return null}}export function describeRuntimeDuplication(runtimes){if(runtimes.length<2)return null;const sorted=[...runtimes].sort((a,b)=>b.bytes-a.bytes),wasted=sorted.slice(1).length*RUNTIME_SIZE_FLOOR,names=sorted.map((r)=>`${r.name} (${(r.bytes/1024/1024).toFixed(1)} MB)`).join(", ");return`This bundle ships ${runtimes.length} Bun-compiled executables: ${names}. Each embeds a full copy of the Bun runtime, so at least ${(wasted/1024/1024).toFixed(0)} MB of the bundle is the same runtime repeated. `+"Compiling one binary that dispatches on a subcommand \u2014 `MyApp agent`, `MyApp worker` \u2014 keeps the helpers as separate processes and pays for the runtime once."}
39
+ `,ignored}}export function resolveDevWindowUrl(port,options={}){if(!Number.isInteger(port)||port<1||port>65535)throw RangeError(`Invalid desktop development port: ${port}`);const configured=options.url||process.env.APP_URL;if(!configured)return"https://stacks.test";const withProtocol=/^https?:\/\//.test(configured)?configured:`https://${configured}`;return new URL(withProtocol).toString().replace(/\/$/,"")}export function craftDevCommand(port,options={}){const command=[resolveCraftBinary(options.craftBin),resolveDevWindowUrl(port,options),"--title",options.title||"Stacks","--width",String(options.width||1400),"--height",String(options.height||900)];if(options.hotReload!==!1)command.push("--hot-reload");if(options.devTools===!1)command.push("--no-devtools");if(options.darkMode)command.push("--dark");if(options.systemTray)command.push("--system-tray");if(options.hideDockIcon)command.push("--hide-dock-icon");if(options.menubarOnly)command.push("--menubar-only");return command}export function createUpdateManifestUrl(baseUrl,channel="stable"){if(!/^[a-z0-9-]+$/i.test(channel))throw Error("Update channel may only contain letters, numbers, and hyphens");return new URL(`/desktop/updates/${channel}.json`,/^https?:\/\//.test(baseUrl)?baseUrl:`https://${baseUrl}`).toString()}async function launchCraft(command){Bun.spawn(command,{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).unref()}export async function openDevWindow(port,options={},launcher=launchCraft){await launcher(craftDevCommand(port,options));return!0}export const BUN_EXECUTABLE_MARKER="---- Bun!";const MARKER_SEARCH_BYTES=8388608,RUNTIME_SIZE_FLOOR=41943040,MACH_O_MAGIC=new Set([4277009102,3472551422,4277009103,3489328638,3405691582,3199925962]);export function isMachO(path){try{const fd=openSync(path,"r");try{const head=Buffer.alloc(4);if(readSync(fd,head,0,4,0)<4)return!1;return MACH_O_MAGIC.has(head.readUInt32BE(0))}finally{closeSync(fd)}}catch{return!1}}export function bundleDirectoryFor(path){return isMachO(path)?"MacOS":"Resources"}export function desktopAppVersion(options={}){const override=options.override?.trim();if(override)return override;return(typeof options.declared==="string"?options.declared.trim():"")||"0.0.0"}export function dmgVolumeName(options){const override=options.override?.trim();if(override)return override;const appName=options.appName.trim(),version=options.version?.trim();return version?`${appName} ${version}`:`${appName} Installer`}export function notarytoolAuthArgs(credentials){return"profile"in credentials?["--keychain-profile",credentials.profile]:["--key",credentials.keyPath,"--key-id",credentials.keyId,"--issuer",credentials.issuerId]}function resolveNotary(flags,env){const profile=supplied(flags.notaryProfile)??supplied(env.DESKTOP_NOTARY_PROFILE);if(profile)return{profile};if(!(flags.notarize===!0||["1","true","yes"].includes(supplied(env.DESKTOP_NOTARIZE)?.toLowerCase()??"")))return;const keyId=supplied(flags.apiKeyId)??supplied(env.APP_STORE_CONNECT_API_KEY_ID),issuerId=supplied(flags.apiIssuerId)??supplied(env.APP_STORE_CONNECT_API_ISSUER_ID),keyPath=supplied(flags.apiKeyPath)??supplied(env.APP_STORE_CONNECT_API_KEY_PATH),keyPem=supplied(env.APP_STORE_CONNECT_API_KEY)?.replaceAll("\\n",`
40
+ `),missing=[!keyId&&"APP_STORE_CONNECT_API_KEY_ID (--api-key-id)",!issuerId&&"APP_STORE_CONNECT_API_ISSUER_ID (--api-issuer-id)",!keyPath&&!keyPem&&"APP_STORE_CONNECT_API_KEY_PATH (--api-key-path) or APP_STORE_CONNECT_API_KEY"].filter(Boolean);if(missing.length||!keyId||!issuerId)throw Error(`Notarizing needs a keychain profile (--notary-profile or DESKTOP_NOTARY_PROFILE) or an App Store Connect API key. Missing: ${missing.join(", ")}.`);if(keyPath)return{keyId,issuerId,keyPath};if(!keyPem.includes("-----BEGIN PRIVATE KEY-----"))throw Error("APP_STORE_CONNECT_API_KEY must hold the PEM text of the .p8 key.");return{keyId,issuerId,keyPem}}function supplied(value){if(typeof value!=="string")return;return value.trim()||void 0}export function resolveDmgPackaging(inputs={}){const flags=inputs.flags??{},env=inputs.env??{},appName=supplied(flags.appName)??supplied(env.DESKTOP_APP_NAME)??supplied(inputs.manifestTitle)??supplied(env.APP_NAME)??"Stacks",version=desktopAppVersion({override:supplied(flags.appVersion)??supplied(env.DESKTOP_APP_VERSION),declared:inputs.declaredVersion}),bundleId=supplied(flags.bundleId)??supplied(env.DESKTOP_BUNDLE_ID)??`sh.stacks.${appName.toLowerCase().replace(/[^a-z0-9]+/g,"-")}`;return{appName,bundleId,version,volumeName:dmgVolumeName({appName,version,override:supplied(flags.volumeName)??supplied(env.DESKTOP_VOLUME_NAME)}),signingIdentity:supplied(flags.signingIdentity)??supplied(env.DESKTOP_SIGNING_IDENTITY),notaryProfile:supplied(flags.notaryProfile)??supplied(env.DESKTOP_NOTARY_PROFILE),notary:resolveNotary(flags,env)}}export function codesignArgs(options){return["codesign","--force",options.identity==="-"?"--timestamp=none":"--timestamp","--options","runtime",...options.entitlements?["--entitlements",options.entitlements]:[],"--sign",options.identity,options.target]}export function looksLikeBunExecutable(path,read=readTail){const file=read(path);if(!file||file.size<RUNTIME_SIZE_FLOOR)return!1;return file.tail.includes(BUN_EXECUTABLE_MARKER)}function readTail(path){try{const{size}=statSync(path);if(size<RUNTIME_SIZE_FLOOR)return{size,tail:""};const fd=openSync(path,"r");try{const length=Math.min(MARKER_SEARCH_BYTES,size),buffer=Buffer.alloc(length);readSync(fd,buffer,0,length,size-length);return{size,tail:buffer.toString("latin1")}}finally{closeSync(fd)}}catch{return null}}export function describeRuntimeDuplication(runtimes){if(runtimes.length<2)return null;const sorted=[...runtimes].sort((a,b)=>b.bytes-a.bytes),wasted=sorted.slice(1).length*RUNTIME_SIZE_FLOOR,names=sorted.map((r)=>`${r.name} (${(r.bytes/1024/1024).toFixed(1)} MB)`).join(", ");return`This bundle ships ${runtimes.length} Bun-compiled executables: ${names}. Each embeds a full copy of the Bun runtime, so at least ${(wasted/1024/1024).toFixed(0)} MB of the bundle is the same runtime repeated. `+"Compiling one binary that dispatches on a subcommand \u2014 `MyApp agent`, `MyApp worker` \u2014 keeps the helpers as separate processes and pays for the runtime once."}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/desktop-build",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.407",
5
+ "version": "0.75.409",
6
6
  "description": "Build and launch Craft desktop applications for Stacks",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -73,15 +73,15 @@
73
73
  "prepublishOnly": "bun run build"
74
74
  },
75
75
  "dependencies": {
76
- "@stacksjs/config": "0.75.407",
77
- "@stacksjs/router": "0.75.407",
78
- "@stacksjs/server": "0.75.407",
79
- "craft-native": ">=0.0.416"
76
+ "@stacksjs/config": "0.75.409",
77
+ "@stacksjs/router": "0.75.409",
78
+ "@stacksjs/server": "0.75.409",
79
+ "craft-native": ">=0.0.420"
80
80
  },
81
81
  "peerDependencies": {
82
- "@stacksjs/config": "0.75.407",
83
- "@stacksjs/router": "0.75.407",
84
- "@stacksjs/server": "0.75.407"
82
+ "@stacksjs/config": "0.75.409",
83
+ "@stacksjs/router": "0.75.409",
84
+ "@stacksjs/server": "0.75.409"
85
85
  },
86
86
  "peerDependenciesMeta": {
87
87
  "@stacksjs/config": {
@@ -95,7 +95,7 @@
95
95
  }
96
96
  },
97
97
  "devDependencies": {
98
- "@stacksjs/build": "0.75.407",
98
+ "@stacksjs/build": "0.75.409",
99
99
  "better-dx": "^0.2.24"
100
100
  }
101
101
  }