@stacksjs/actions 0.72.101 → 0.72.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/build/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 launcherName="stacks-desktop",bundledFiles=readdirSync(desktopDist).filter((name)=>statSync(join(desktopDist,name)).isFile());for(const file of bundledFiles)await runCommand(["cp",join(desktopDist,file),join(macosDir,file)],{cwd:projectPath()});if(!existsSync(join(macosDir,launcherName)))throw Error(`build:desktop did not produce ${launcherName}`);const userlandResources=appPath("Desktop/Resources");if(existsSync(userlandResources))cpSync(userlandResources,resourcesDir,{recursive:!0});async function buildIcon(){const source=[resourcesPath("assets/images/app-icon.png"),publicPath("images/app-icon.png"),publicPath("apple-touch-icon.png")].find((candidate)=>existsSync(candidate));if(!source)return;const iconset=join(scratch,"icon.iconset");mkdirSync(iconset,{recursive:!0});for(const size of[16,32,128,256,512]){await runCommand(["sips","-z",String(size),String(size),source,"--out",join(iconset,`icon_${size}x${size}.png`)],{cwd:scratch,silent:!0});await runCommand(["sips","-z",String(size*2),String(size*2),source,"--out",join(iconset,`icon_${size}x${size}@2x.png`)],{cwd:scratch,silent:!0})}const icns=join(resourcesDir,"AppIcon.icns");if((await runCommand(["iconutil","-c","icns",iconset,"-o",icns],{cwd:scratch})).isErr||!existsSync(icns))return;return"AppIcon"}const iconFile=await buildIcon();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{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"?>
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>
@@ -28,4 +28,4 @@ ${overriddenByApp("LSMinimumSystemVersion")?"":` <key>LSMinimumSystemVersion</k
28
28
  <key>CFBundleIconFile</key><string>${iconFile}</string>`:""}${extraPlistEntries}
29
29
  </dict>
30
30
  </plist>
31
- `);if(signingIdentity){const nested=bundledFiles.filter((name)=>name!==launcherName&&!name.endsWith(".json")&&!name.endsWith(".sha256")).map((name)=>join(macosDir,name));for(const target of[...nested,join(macosDir,launcherName),appDir])await runCommand(["codesign","--force","--options","runtime","--sign",signingIdentity,target],{cwd:staging})}symlinkSync("/Applications",join(staging,"Applications"));const dmgPath=join(outputDir,`${appName}-${version}.dmg`),created=await runCommand(["hdiutil","create","-volname",appName,"-srcfolder",staging,"-ov","-format","UDZO",dmgPath],{cwd:staging});if(created.isErr)throw Error(`hdiutil failed to create ${dmgPath}`);rmSync(staging,{recursive:!0,force:!0});rmSync(scratch,{recursive:!0,force:!0});log.success(`Built ${dmgPath}`);if(!signingIdentity)log.info("Unsigned build: Gatekeeper blocks the first launch. Right-click the app and choose Open, or set DESKTOP_SIGNING_IDENTITY and notarize before distributing.");
31
+ `);if(signingIdentity){const nested=bundledFiles.filter((name)=>name!==builtLauncher&&!name.endsWith(".json")&&!name.endsWith(".sha256")).map((name)=>join(macosDir,name));for(const target of[...nested,join(macosDir,launcherName),appDir])await runCommand(["codesign","--force","--options","runtime","--sign",signingIdentity,target],{cwd:staging})}symlinkSync("/Applications",join(staging,"Applications"));const dmgPath=join(outputDir,`${appName}-${version}.dmg`),created=await runCommand(["hdiutil","create","-volname",appName,"-srcfolder",staging,"-ov","-format","UDZO",dmgPath],{cwd:staging});if(created.isErr)throw Error(`hdiutil failed to create ${dmgPath}`);rmSync(staging,{recursive:!0,force:!0});rmSync(scratch,{recursive:!0,force:!0});log.success(`Built ${dmgPath}`);if(!signingIdentity)log.info("Unsigned build: Gatekeeper blocks the first launch. Right-click the app and choose Open, or set DESKTOP_SIGNING_IDENTITY and notarize before distributing.");
@@ -31,6 +31,37 @@ export declare function runActions(actions: Action[], options?: ActionOptions):
31
31
  export declare function runActionSequence(actions: Action[], options: ActionOptions | undefined, runner?: typeof runAction): Promise<any>;
32
32
  // looks in most common locations
33
33
  export declare function hasAction(action: Action): boolean;
34
- declare type ActionPath = string // TODO: narrow this by automating its generation
35
- type ActionName = string // TODO: narrow this by automating its generation
36
- type Action = ActionPath | ActionName | string;
34
+ /**
35
+ * Augmentation target: the actions this application can run.
36
+ *
37
+ * Filled by `storage/framework/types/registries.d.ts` from the same name map
38
+ * the resolver reads, so a name that typechecks is a name that resolves. Empty
39
+ * here by design - a package cannot know an application's actions.
40
+ */
41
+ // eslint-disable-next-line ts/no-empty-object-type -- augmentation target; empty by design
42
+ export declare interface RunnableActions {}
43
+ /** An action name, as narrow as the application has made it. */
44
+ export type RunnableActionName = keyof RunnableActions extends never
45
+ ? string
46
+ : Extract<keyof RunnableActions, string>;
47
+ /**
48
+ * What `runAction` accepts.
49
+ *
50
+ * This used to be
51
+ *
52
+ * type ActionPath = string // TODO: narrow this by automating its generation
53
+ * type ActionName = string // TODO: narrow this by automating its generation
54
+ * type Action = ActionPath | ActionName | string
55
+ *
56
+ * where all three members were `string`, so the union collapsed to `string`:
57
+ * no name was checked and none was offered as a completion. The registry the
58
+ * TODOs are asking for exists now, and `schedule.action()` already reads it.
59
+ *
60
+ * `(string & {})` rather than a bare `string` keeps the declared names as
61
+ * completions while still admitting the paths that are legitimately dynamic -
62
+ * `runAction('dev/views')` is a framework entry point, not an app action, and
63
+ * a `/actions/:name` route passes one straight through. A bare `string` in the
64
+ * union would erase the other members, which is the bug being fixed.
65
+ */
66
+ // eslint-disable-next-line ts/ban-types -- `string & {}` keeps literal completions alive
67
+ declare type Action = RunnableActionName | (string & {});
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/actions",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.72.101",
5
+ "version": "0.72.103",
6
6
  "description": "The Stacks actions.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -60,36 +60,36 @@
60
60
  "prepublishOnly": "bun run build"
61
61
  },
62
62
  "dependencies": {
63
- "@stacksjs/config": "0.72.101",
63
+ "@stacksjs/config": "0.72.103",
64
64
  "@stacksjs/bumpx": "^0.2.6",
65
65
  "@stacksjs/bunpress": "^0.2.8",
66
66
  "@stacksjs/logsmith": "^0.2.3",
67
- "@stacksjs/registry": "0.72.101",
67
+ "@stacksjs/registry": "0.72.103",
68
68
  "@stacksjs/stx": "^0.2.245",
69
69
  "@stacksjs/ts-cloud": "^0.12.7",
70
70
  "@stacksjs/ts-md": "^0.1.1"
71
71
  },
72
72
  "devDependencies": {
73
- "@stacksjs/api": "0.72.101",
74
- "@stacksjs/cli": "0.72.101",
75
- "@stacksjs/database": "0.72.101",
73
+ "@stacksjs/api": "0.72.103",
74
+ "@stacksjs/cli": "0.72.103",
75
+ "@stacksjs/database": "0.72.103",
76
76
  "@stacksjs/tlsx": "^0.13.2",
77
77
  "better-dx": "^0.2.24",
78
- "@stacksjs/dns": "0.72.101",
79
- "@stacksjs/enums": "0.72.101",
80
- "@stacksjs/env": "0.72.101",
81
- "@stacksjs/error-handling": "0.72.101",
82
- "@stacksjs/image": "0.72.101",
83
- "@stacksjs/logging": "0.72.101",
84
- "@stacksjs/path": "0.72.101",
85
- "@stacksjs/security": "0.72.101",
86
- "@stacksjs/server": "0.72.101",
87
- "@stacksjs/cms": "0.72.101",
88
- "@stacksjs/sites": "0.72.101",
89
- "@stacksjs/storage": "0.72.101",
90
- "@stacksjs/strings": "0.72.101",
91
- "@stacksjs/utils": "0.72.101",
92
- "@stacksjs/validation": "0.72.101"
78
+ "@stacksjs/dns": "0.72.103",
79
+ "@stacksjs/enums": "0.72.103",
80
+ "@stacksjs/env": "0.72.103",
81
+ "@stacksjs/error-handling": "0.72.103",
82
+ "@stacksjs/image": "0.72.103",
83
+ "@stacksjs/logging": "0.72.103",
84
+ "@stacksjs/path": "0.72.103",
85
+ "@stacksjs/security": "0.72.103",
86
+ "@stacksjs/server": "0.72.103",
87
+ "@stacksjs/cms": "0.72.103",
88
+ "@stacksjs/sites": "0.72.103",
89
+ "@stacksjs/storage": "0.72.103",
90
+ "@stacksjs/strings": "0.72.103",
91
+ "@stacksjs/utils": "0.72.103",
92
+ "@stacksjs/validation": "0.72.103"
93
93
  },
94
94
  "peerDependencies": {
95
95
  "pickier": "^0.1.58",