@stacksjs/actions 0.75.230 → 0.75.236

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.
@@ -30,6 +30,8 @@ export declare const CRAFT_ANDROID_FLOORS: {
30
30
  /** Verified HTTPS hosts and ordered website path exclusions. */
31
31
  appLinks: '0.0.201';
32
32
  bluetooth: '0.0.178';
33
+ /** CraftHeartRate.kt: Bluetooth heart-rate straps, the same `craft.heartRate` as iOS. */
34
+ heartRate: '0.0.247';
33
35
  /** Health Connect for native screens (workouts, sleep, heart rate, mindful, nutrition). */
34
36
  healthConnect: '0.0.169';
35
37
  /** WorkManager background refresh for the app script. */
@@ -65,6 +67,7 @@ export declare interface CraftAndroidConfig {
65
67
  googleServicesFile?: string
66
68
  mapsApiKey?: string
67
69
  enableBluetooth?: boolean
70
+ enableHeartRate?: boolean
68
71
  enableHealthConnect?: boolean
69
72
  renderer?: AndroidMobileConfig['renderer']
70
73
  nativeScreens?: Record<string, string>
@@ -1 +1 @@
1
- import{NATIVE_APP_ROUTE,normalizeMobileUrl,toCraftCrashReporting}from"./ios-config";const CAPABILITY_KEYS={speechRecognition:"enableSpeechRecognition",haptics:"enableHaptics",share:"enableShare",camera:"enableCamera",biometric:"enableBiometric",pushNotifications:"enablePushNotifications",secureStorage:"enableSecureStorage",geolocation:"enableGeolocation",backgroundLocation:"enableBackgroundLocation",keepAwake:"enableKeepAwake",deepLinks:"enableDeepLinks",healthConnect:"enableHealthConnect",bluetooth:"enableBluetooth",localNetwork:"enableLocalNetwork",localDatabase:"enableLocalDatabase",localNotifications:"enableLocalNotifications"};export const CRAFT_ANDROID_FLOORS={nativeShell:"0.0.169",appLinks:"0.0.201",bluetooth:"0.0.178",healthConnect:"0.0.169",backgroundRefresh:"0.0.169",appBundle:"0.0.169",crashReporting:"0.0.179",notificationIcon:"0.0.241"};export function assertCraftSupportsAndroidMapProvider(config,providers){if(config.mapProvider&&!providers?.includes(config.mapProvider))throw Error(`The resolved Craft Android builder does not advertise native map provider '${config.mapProvider}'. Upgrade craft-native to a published SDK supporting that provider before building this app.`)}export function androidCraftFeatures(config,options={}){const features=[];if(config.renderer==="native"&&Object.keys(config.nativeScreens??{}).length)features.push("nativeShell");if(config.appLinks?.length&&config.capabilities?.deepLinks)features.push("appLinks");if(config.capabilities?.bluetooth)features.push("bluetooth");if(config.capabilities?.healthConnect&&config.renderer==="native")features.push("healthConnect");if(config.backgroundRefresh?.enabled)features.push("backgroundRefresh");if(options.appBundle)features.push("appBundle");if(config.crashReporting?.key)features.push("crashReporting");if(config.notificationIcon||config.notificationColor)features.push("notificationIcon");return features}export function assertCraftSupportsAndroid(config,version,source,options={}){const missing=androidCraftFeatures(config,options).filter((feature)=>!Bun.semver.satisfies(version,`>=${CRAFT_ANDROID_FLOORS[feature]}`));if(!missing.length)return;const needed=missing.map((feature)=>CRAFT_ANDROID_FLOORS[feature]).reduce((max,next)=>Bun.semver.order(next,max)>0?next:max,"0.0.0");throw Error(`The Craft Android builder is craft-native ${version} (${source}), which would build the app without ${missing.map((feature)=>`${feature} (needs >= ${CRAFT_ANDROID_FLOORS[feature]})`).join(", ")}. Install craft-native >= ${needed}: look for an older copy nested under @stacksjs/mobile in bun.lock, or raise the app's own craft-native pin.`)}export function toCraftAndroidConfig(config){const devServerURL=normalizeMobileUrl(config.url),trustedOrigins=new Set(config.trustedOrigins??[]);if(devServerURL)trustedOrigins.add(new URL(devServerURL).origin);const native=config.renderer==="native",craft={mapProvider:config.mapProvider,nativeFonts:config.nativeFonts,appName:config.appName,packageName:config.packageName,version:config.version,versionCode:config.versionCode,minSdk:config.minSdk,targetSdk:config.targetSdk,darkMode:config.darkMode,appearance:config.appearance,backgroundColor:config.backgroundColor,backgroundColorDark:config.backgroundColorDark,devServerURL,trustedOrigins:[...trustedOrigins],urlSchemes:config.urlSchemes,appLinks:config.appLinks,appIconPath:config.appIcon,notificationColor:config.notificationColor,googleServicesFile:config.googleServicesFile,mapsApiKey:config.mapsApiKey,renderer:config.renderer,nativeScreens:native?config.nativeScreens:void 0,nativeApp:native&&config.nativeApp?NATIVE_APP_ROUTE:void 0,tabs:native?config.tabs:void 0,backgroundRefresh:native?config.backgroundRefresh:void 0,healthConnect:config.capabilities?.healthConnect?config.healthConnect:void 0,privacyPolicyURL:config.privacyPolicyUrl,crashReporting:toCraftCrashReporting(config.crashReporting)};for(const[key,nativeKey]of Object.entries(CAPABILITY_KEYS)){const enabled=config.capabilities?.[key];if(enabled!==void 0)craft[nativeKey]=enabled}if(config.capabilities?.backgroundLocation)craft.enableGeolocation=!0;for(const key of Object.keys(craft))if(craft[key]===void 0)delete craft[key];return craft}export function validateAndroidMobileConfig(config){if(config.mapProvider!==void 0&&config.mapProvider!=="google"&&config.mapProvider!=="maplibre")throw Error(`android.mapProvider must be 'google' or 'maplibre', not ${String(config.mapProvider)}`);if(config.mapProvider&&config.renderer!=="native")throw Error("android.mapProvider configures native map views: set android.renderer to 'native'");if(!config.appName?.trim())throw Error("config/mobile.ts must define android.appName");if(!/^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z][A-Za-z0-9_]*)+$/.test(config.packageName))throw Error(`Invalid Android package name: ${config.packageName}`);if(config.notificationColor!==void 0&&!/^#[0-9a-f]{6}$/i.test(config.notificationColor))throw Error(`android.notificationColor must be #RRGGBB, not ${String(config.notificationColor)}`);if(config.notificationIcon!==void 0&&!/\.(png|xml)$/i.test(config.notificationIcon))throw Error("android.notificationIcon must be an Android vector drawable (.xml) or a white-on-transparent .png");if(config.mapsApiKey!==void 0&&(typeof config.mapsApiKey!=="string"||!config.mapsApiKey.trim()))throw Error("android.mapsApiKey must be a non-empty Google Maps Android SDK key");if(config.renderer!==void 0&&config.renderer!=="web"&&config.renderer!=="native")throw Error(`android.renderer must be 'web' or 'native', not ${String(config.renderer)}`);if(config.renderer==="native"){if(!Object.keys(config.nativeScreens??{}).length)throw Error("android.renderer 'native' draws every screen natively: list them in android.nativeScreens");if(config.webAssets)throw Error("android.renderer 'native' has no web view to show android.webAssets in: set android.url to the app's site instead");if(config.fallbackWebAssets)throw Error("android.fallbackWebAssets is the web view's offline page; android.renderer 'native' has no web view");if(!config.url)throw Error("android.renderer 'native' needs android.url: the app's site, where its API answers")}else{if(config.url&&config.webAssets)throw Error("Choose either android.url or android.webAssets in config/mobile.ts, not both");if(!config.url&&!config.webAssets)throw Error("config/mobile.ts must define android.url or android.webAssets");if(config.fallbackWebAssets&&!config.url)throw Error("android.fallbackWebAssets requires android.url")}if(config.nativeApp&&config.renderer!=="native")throw Error("android.nativeApp runs beside native screens: set android.renderer to 'native'");for(const tab of config.tabs??[])if(!tab.id?.startsWith("/"))throw Error(`An android.tabs entry needs an id that is an app path, like /m (got ${String(tab.id)})`);if(config.url){const normalized=normalizeMobileUrl(config.url),url=new URL(normalized),isLocal=["localhost","127.0.0.1","10.0.2.2"].includes(url.hostname);if(url.protocol!=="https:"&&!isLocal)throw Error("android.url must use HTTPS outside local development")}if(config.capabilities?.healthConnect&&(config.minSdk??26)<26)throw Error("Android Health Connect requires android.minSdk 26 or newer");if(config.healthConnect&&!config.capabilities?.healthConnect)throw Error("android.healthConnect lists Health Connect data, but android.capabilities.healthConnect is off");const minutes=config.backgroundRefresh?.minimumIntervalMinutes;if(minutes!==void 0&&(!Number.isFinite(minutes)||minutes<15))throw Error("android.backgroundRefresh.minimumIntervalMinutes is at least 15 (WorkManager's shortest period)");for(const scheme of config.urlSchemes??[])if(!/^[a-z][a-z0-9+.-]*$/i.test(scheme))throw Error(`Invalid Android URL scheme: ${scheme}`)}export function androidRelease(config){if(config.crashReporting?.release)return config.crashReporting.release;return`${config.version||"1.0.0"}+${config.versionCode||1}`}export async function uploadAndroidMapping(mappingPath,host,release,token,send=fetch){if(!token)return{ok:!1,message:"BUGHQ_UPLOAD_TOKEN is not set, so the R8 mapping was not uploaded and this build's Android crashes will show obfuscated names."};const file=Bun.file(mappingPath);if(!await file.exists())return{ok:!1,message:`No R8 mapping at ${mappingPath}, so nothing was uploaded.`};try{const body=Bun.gzipSync(new Uint8Array(await file.arrayBuffer())),response=await send(`${host.replace(/\/$/,"")}/api/debug-files?kind=proguard&release=${encodeURIComponent(release)}`,{method:"POST",headers:{Authorization:`Bearer ${token}`,"Content-Type":"application/octet-stream"},body});if(!response.ok)return{ok:!1,message:`bughq refused the R8 mapping (${response.status}): ${(await response.text()).slice(0,200)}`};return{ok:!0,message:`Uploaded the R8 mapping for ${release} to bughq.`}}catch(error){return{ok:!1,message:`Could not upload the R8 mapping: ${error instanceof Error?error.message:String(error)}`}}}
1
+ import{NATIVE_APP_ROUTE,normalizeMobileUrl,toCraftCrashReporting}from"./ios-config";const CAPABILITY_KEYS={speechRecognition:"enableSpeechRecognition",haptics:"enableHaptics",share:"enableShare",camera:"enableCamera",biometric:"enableBiometric",pushNotifications:"enablePushNotifications",secureStorage:"enableSecureStorage",geolocation:"enableGeolocation",backgroundLocation:"enableBackgroundLocation",keepAwake:"enableKeepAwake",deepLinks:"enableDeepLinks",healthConnect:"enableHealthConnect",bluetooth:"enableBluetooth",heartRate:"enableHeartRate",localNetwork:"enableLocalNetwork",localDatabase:"enableLocalDatabase",localNotifications:"enableLocalNotifications"};export const CRAFT_ANDROID_FLOORS={nativeShell:"0.0.169",appLinks:"0.0.201",bluetooth:"0.0.178",heartRate:"0.0.247",healthConnect:"0.0.169",backgroundRefresh:"0.0.169",appBundle:"0.0.169",crashReporting:"0.0.179",notificationIcon:"0.0.241"};export function assertCraftSupportsAndroidMapProvider(config,providers){if(config.mapProvider&&!providers?.includes(config.mapProvider))throw Error(`The resolved Craft Android builder does not advertise native map provider '${config.mapProvider}'. Upgrade craft-native to a published SDK supporting that provider before building this app.`)}export function androidCraftFeatures(config,options={}){const features=[];if(config.renderer==="native"&&Object.keys(config.nativeScreens??{}).length)features.push("nativeShell");if(config.appLinks?.length&&config.capabilities?.deepLinks)features.push("appLinks");if(config.capabilities?.bluetooth)features.push("bluetooth");if(config.capabilities?.heartRate)features.push("heartRate");if(config.capabilities?.healthConnect&&config.renderer==="native")features.push("healthConnect");if(config.backgroundRefresh?.enabled)features.push("backgroundRefresh");if(options.appBundle)features.push("appBundle");if(config.crashReporting?.key)features.push("crashReporting");if(config.notificationIcon||config.notificationColor)features.push("notificationIcon");return features}export function assertCraftSupportsAndroid(config,version,source,options={}){const missing=androidCraftFeatures(config,options).filter((feature)=>!Bun.semver.satisfies(version,`>=${CRAFT_ANDROID_FLOORS[feature]}`));if(!missing.length)return;const needed=missing.map((feature)=>CRAFT_ANDROID_FLOORS[feature]).reduce((max,next)=>Bun.semver.order(next,max)>0?next:max,"0.0.0");throw Error(`The Craft Android builder is craft-native ${version} (${source}), which would build the app without ${missing.map((feature)=>`${feature} (needs >= ${CRAFT_ANDROID_FLOORS[feature]})`).join(", ")}. Install craft-native >= ${needed}: look for an older copy nested under @stacksjs/mobile in bun.lock, or raise the app's own craft-native pin.`)}export function toCraftAndroidConfig(config){const devServerURL=normalizeMobileUrl(config.url),trustedOrigins=new Set(config.trustedOrigins??[]);if(devServerURL)trustedOrigins.add(new URL(devServerURL).origin);const native=config.renderer==="native",craft={mapProvider:config.mapProvider,nativeFonts:config.nativeFonts,appName:config.appName,packageName:config.packageName,version:config.version,versionCode:config.versionCode,minSdk:config.minSdk,targetSdk:config.targetSdk,darkMode:config.darkMode,appearance:config.appearance,backgroundColor:config.backgroundColor,backgroundColorDark:config.backgroundColorDark,devServerURL,trustedOrigins:[...trustedOrigins],urlSchemes:config.urlSchemes,appLinks:config.appLinks,appIconPath:config.appIcon,notificationColor:config.notificationColor,googleServicesFile:config.googleServicesFile,mapsApiKey:config.mapsApiKey,renderer:config.renderer,nativeScreens:native?config.nativeScreens:void 0,nativeApp:native&&config.nativeApp?NATIVE_APP_ROUTE:void 0,tabs:native?config.tabs:void 0,backgroundRefresh:native?config.backgroundRefresh:void 0,healthConnect:config.capabilities?.healthConnect?config.healthConnect:void 0,privacyPolicyURL:config.privacyPolicyUrl,crashReporting:toCraftCrashReporting(config.crashReporting)};for(const[key,nativeKey]of Object.entries(CAPABILITY_KEYS)){const enabled=config.capabilities?.[key];if(enabled!==void 0)craft[nativeKey]=enabled}if(config.capabilities?.backgroundLocation)craft.enableGeolocation=!0;for(const key of Object.keys(craft))if(craft[key]===void 0)delete craft[key];return craft}export function validateAndroidMobileConfig(config){if(config.mapProvider!==void 0&&config.mapProvider!=="google"&&config.mapProvider!=="maplibre")throw Error(`android.mapProvider must be 'google' or 'maplibre', not ${String(config.mapProvider)}`);if(config.mapProvider&&config.renderer!=="native")throw Error("android.mapProvider configures native map views: set android.renderer to 'native'");if(!config.appName?.trim())throw Error("config/mobile.ts must define android.appName");if(!/^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z][A-Za-z0-9_]*)+$/.test(config.packageName))throw Error(`Invalid Android package name: ${config.packageName}`);if(config.notificationColor!==void 0&&!/^#[0-9a-f]{6}$/i.test(config.notificationColor))throw Error(`android.notificationColor must be #RRGGBB, not ${String(config.notificationColor)}`);if(config.notificationIcon!==void 0&&!/\.(png|xml)$/i.test(config.notificationIcon))throw Error("android.notificationIcon must be an Android vector drawable (.xml) or a white-on-transparent .png");if(config.mapsApiKey!==void 0&&(typeof config.mapsApiKey!=="string"||!config.mapsApiKey.trim()))throw Error("android.mapsApiKey must be a non-empty Google Maps Android SDK key");if(config.renderer!==void 0&&config.renderer!=="web"&&config.renderer!=="native")throw Error(`android.renderer must be 'web' or 'native', not ${String(config.renderer)}`);if(config.renderer==="native"){if(!Object.keys(config.nativeScreens??{}).length)throw Error("android.renderer 'native' draws every screen natively: list them in android.nativeScreens");if(config.webAssets)throw Error("android.renderer 'native' has no web view to show android.webAssets in: set android.url to the app's site instead");if(config.fallbackWebAssets)throw Error("android.fallbackWebAssets is the web view's offline page; android.renderer 'native' has no web view");if(!config.url)throw Error("android.renderer 'native' needs android.url: the app's site, where its API answers")}else{if(config.url&&config.webAssets)throw Error("Choose either android.url or android.webAssets in config/mobile.ts, not both");if(!config.url&&!config.webAssets)throw Error("config/mobile.ts must define android.url or android.webAssets");if(config.fallbackWebAssets&&!config.url)throw Error("android.fallbackWebAssets requires android.url")}if(config.nativeApp&&config.renderer!=="native")throw Error("android.nativeApp runs beside native screens: set android.renderer to 'native'");for(const tab of config.tabs??[])if(!tab.id?.startsWith("/"))throw Error(`An android.tabs entry needs an id that is an app path, like /m (got ${String(tab.id)})`);if(config.url){const normalized=normalizeMobileUrl(config.url),url=new URL(normalized),isLocal=["localhost","127.0.0.1","10.0.2.2"].includes(url.hostname);if(url.protocol!=="https:"&&!isLocal)throw Error("android.url must use HTTPS outside local development")}if(config.capabilities?.healthConnect&&(config.minSdk??26)<26)throw Error("Android Health Connect requires android.minSdk 26 or newer");if(config.healthConnect&&!config.capabilities?.healthConnect)throw Error("android.healthConnect lists Health Connect data, but android.capabilities.healthConnect is off");const minutes=config.backgroundRefresh?.minimumIntervalMinutes;if(minutes!==void 0&&(!Number.isFinite(minutes)||minutes<15))throw Error("android.backgroundRefresh.minimumIntervalMinutes is at least 15 (WorkManager's shortest period)");for(const scheme of config.urlSchemes??[])if(!/^[a-z][a-z0-9+.-]*$/i.test(scheme))throw Error(`Invalid Android URL scheme: ${scheme}`)}export function androidRelease(config){if(config.crashReporting?.release)return config.crashReporting.release;return`${config.version||"1.0.0"}+${config.versionCode||1}`}export async function uploadAndroidMapping(mappingPath,host,release,token,send=fetch){if(!token)return{ok:!1,message:"BUGHQ_UPLOAD_TOKEN is not set, so the R8 mapping was not uploaded and this build's Android crashes will show obfuscated names."};const file=Bun.file(mappingPath);if(!await file.exists())return{ok:!1,message:`No R8 mapping at ${mappingPath}, so nothing was uploaded.`};try{const body=Bun.gzipSync(new Uint8Array(await file.arrayBuffer())),response=await send(`${host.replace(/\/$/,"")}/api/debug-files?kind=proguard&release=${encodeURIComponent(release)}`,{method:"POST",headers:{Authorization:`Bearer ${token}`,"Content-Type":"application/octet-stream"},body});if(!response.ok)return{ok:!1,message:`bughq refused the R8 mapping (${response.status}): ${(await response.text()).slice(0,200)}`};return{ok:!0,message:`Uploaded the R8 mapping for ${release} to bughq.`}}catch(error){return{ok:!1,message:`Could not upload the R8 mapping: ${error instanceof Error?error.message:String(error)}`}}}
@@ -1 +1 @@
1
- import{library}from"@stacksjs/config";import{log}from"@stacksjs/logging";import{generateLibraryPackages}from"../library/build";export async function generateLibEntries(){if(library?.releaseable===!1){log.info("library.releaseable is false. Skipping library entry points.");return}log.info("Generating library entry points...");const reports=await generateLibraryPackages({allowEmpty:!0});for(const report of reports)log.success(`Generated ${report.name} (${report.kind}, ${report.sources} sources)`)}await generateLibEntries();
1
+ import{awaitConfig,library}from"@stacksjs/config";import{log}from"@stacksjs/logging";import{generateLibraryPackages}from"../library/build";export async function generateLibEntries(){await awaitConfig();if(library?.releaseable===!1){log.info("library.releaseable is false. Skipping library entry points.");return}log.info("Generating library entry points...");const reports=await generateLibraryPackages({allowEmpty:!0});for(const report of reports)log.success(`Generated ${report.name} (${report.kind}, ${report.sources} sources)`)}await generateLibEntries();
@@ -1,4 +1,4 @@
1
- import{mkdir,rm}from"node:fs/promises";import{dirname,relative,resolve}from"node:path";import{transpilePackage,validateDeclarations,validateRuntimeExports}from"@stacksjs/build";import{library}from"@stacksjs/config";import{log}from"@stacksjs/logging";import{projectPath}from"@stacksjs/path";import{buildComponentLibrary}from"@stacksjs/stx";import{functionEntryData}from"./entries";import{ambientGlobalsUsed,stxAmbientGlobals}from"./globals";import{libraryManifest,serializeManifest}from"./manifest";import{LibraryConfigError,resolveLibraryPackages}from"./packages";export async function buildLibraryPackages(options={}){const config=options.config??library,kinds=options.kinds,compile=options.compile??!0,all=await resolveLibraryPackages(config,{onUnmatched:options.allowEmpty?"skip":"error"}),packages=kinds?all.filter((pkg)=>kinds.includes(pkg.kind)):all;if(!packages.length){if(options.allowEmpty){log.info("No library packages are configured. Nothing to build.");return[]}throw new LibraryConfigError(kinds?`No ${kinds.join("/")} packages are configured. Add one to \`packages\` in config/library.ts.`:"No library packages are configured. Add one to `packages` in config/library.ts.")}const version=await projectVersion(),reports=[];for(const pkg of packages){const verb=compile?"Building":"Generating";log.info(`${verb} ${pkg.name} (${pkg.kind}, ${pkg.sources.length} source${pkg.sources.length===1?"":"s"})...`);if(compile)await rm(resolve(pkg.dir,"dist"),{recursive:!0,force:!0});await mkdir(pkg.dir,{recursive:!0});if(pkg.kind==="functions")await buildFunctionPackage(pkg,config,version,compile);else await buildComponentPackage(pkg,config,version,compile);reports.push({name:pkg.name,kind:pkg.kind,dir:pkg.dir,sources:pkg.sources.length});if(compile)log.success(`Built ${pkg.name} \u2192 ${relative(projectPath(),pkg.dir)}/dist`)}return reports}export async function generateLibraryPackages(options={}){return buildLibraryPackages({...options,compile:!1})}async function buildFunctionPackage(pkg,config,version,compile){await assertPublishable(pkg);const srcDir=resolve(pkg.dir,"src");await rm(srcDir,{recursive:!0,force:!0});const staged=[];for(const source of pkg.sources){const destination=resolve(srcDir,relative(pkg.sourceDir,source));await mkdir(dirname(destination),{recursive:!0});await Bun.write(destination,await Bun.file(source).text());staged.push(destination)}const entry=resolve(srcDir,"index.ts");if(staged.includes(entry))throw new LibraryConfigError(`Package "${pkg.name}" claims resources/functions/index.ts, which collides with the generated barrel. Rename it or exclude it.`);await Bun.write(entry,functionEntryData(pkg,staged));await writeManifest(pkg,config,version);if(!compile)return;await transpilePackage({dir:pkg.dir,pkgName:pkg.name,external:["@stacksjs/*","bun",...Object.keys(pkg.dependencies),...Object.keys(pkg.peerDependencies)]});await validateDeclarations(pkg.dir);await validateRuntimeExports(pkg.dir)}async function buildComponentPackage(pkg,config,version,compile){if(!compile){await writeManifest(pkg,config,version);return}const result=await buildComponentLibrary({inputDir:pkg.sourceDir,outputDir:resolve(pkg.dir,"dist"),prefix:pkg.prefix,components:pkg.sources.map((source)=>{const file=relative(pkg.sourceDir,source),stem=file.replace(/\.stx$/,"").split("/").at(-1);return pkg.names[stem]?{file,name:pkg.names[stem]}:{file}}),progressive:!0,manifest:!0,declarations:!0,css:!0,bundle:!0,minify:!0,sourcemap:pkg.sourcemap?"external":!1});log.debug(`${pkg.name}: compiled ${result.components.length} components (${result.totalBytes} bytes)`);await writeManifest(pkg,config,version)}async function assertPublishable(pkg){if(pkg.runtime==="stx")return;const globals=await stxAmbientGlobals();if(!globals.size)return;const offenders=[];for(const source of pkg.sources){const used=ambientGlobalsUsed(await Bun.file(source).text(),globals);if(used.length)offenders.push(` ${relative(projectPath(),source)} \u2192 ${used.join(", ")}`)}if(!offenders.length)return;throw new LibraryConfigError(`Package "${pkg.name}" uses stx's ambient globals, which no module exports:
1
+ import{mkdir,rm}from"node:fs/promises";import{dirname,relative,resolve}from"node:path";import{transpilePackage,validateDeclarations,validateRuntimeExports}from"@stacksjs/build";import{awaitConfig,library}from"@stacksjs/config";import{log}from"@stacksjs/logging";import{projectPath}from"@stacksjs/path";import{buildComponentLibrary}from"@stacksjs/stx";import{functionEntryData}from"./entries";import{ambientGlobalsUsed,stxAmbientGlobals}from"./globals";import{libraryManifest,serializeManifest}from"./manifest";import{LibraryConfigError,resolveLibraryPackages}from"./packages";export async function buildLibraryPackages(options={}){if(!options.config)await awaitConfig();const config=options.config??library,kinds=options.kinds,compile=options.compile??!0,all=await resolveLibraryPackages(config,{onUnmatched:options.allowEmpty?"skip":"error"}),packages=kinds?all.filter((pkg)=>kinds.includes(pkg.kind)):all;if(!packages.length){if(options.allowEmpty){log.info("No library packages are configured. Nothing to build.");return[]}throw new LibraryConfigError(kinds?`No ${kinds.join("/")} packages are configured. Add one to \`packages\` in config/library.ts.`:"No library packages are configured. Add one to `packages` in config/library.ts.")}const version=await projectVersion(),reports=[];for(const pkg of packages){const verb=compile?"Building":"Generating";log.info(`${verb} ${pkg.name} (${pkg.kind}, ${pkg.sources.length} source${pkg.sources.length===1?"":"s"})...`);if(compile)await rm(resolve(pkg.dir,"dist"),{recursive:!0,force:!0});await mkdir(pkg.dir,{recursive:!0});if(pkg.kind==="functions")await buildFunctionPackage(pkg,config,version,compile);else await buildComponentPackage(pkg,config,version,compile);reports.push({name:pkg.name,kind:pkg.kind,dir:pkg.dir,sources:pkg.sources.length});if(compile)log.success(`Built ${pkg.name} \u2192 ${relative(projectPath(),pkg.dir)}/dist`)}return reports}export async function generateLibraryPackages(options={}){return buildLibraryPackages({...options,compile:!1})}async function buildFunctionPackage(pkg,config,version,compile){await assertPublishable(pkg);const srcDir=resolve(pkg.dir,"src");await rm(srcDir,{recursive:!0,force:!0});const staged=[];for(const source of pkg.sources){const destination=resolve(srcDir,relative(pkg.sourceDir,source));await mkdir(dirname(destination),{recursive:!0});await Bun.write(destination,await Bun.file(source).text());staged.push(destination)}const entry=resolve(srcDir,"index.ts");if(staged.includes(entry))throw new LibraryConfigError(`Package "${pkg.name}" claims resources/functions/index.ts, which collides with the generated barrel. Rename it or exclude it.`);await Bun.write(entry,functionEntryData(pkg,staged));await writeManifest(pkg,config,version);if(!compile)return;await transpilePackage({dir:pkg.dir,pkgName:pkg.name,external:["@stacksjs/*","bun",...Object.keys(pkg.dependencies),...Object.keys(pkg.peerDependencies)]});await validateDeclarations(pkg.dir);await validateRuntimeExports(pkg.dir)}async function buildComponentPackage(pkg,config,version,compile){if(!compile){await writeManifest(pkg,config,version);return}const result=await buildComponentLibrary({inputDir:pkg.sourceDir,outputDir:resolve(pkg.dir,"dist"),prefix:pkg.prefix,components:pkg.sources.map((source)=>{const file=relative(pkg.sourceDir,source),stem=file.replace(/\.stx$/,"").split("/").at(-1);return pkg.names[stem]?{file,name:pkg.names[stem]}:{file}}),progressive:!0,manifest:!0,declarations:!0,css:!0,bundle:!0,minify:!0,sourcemap:pkg.sourcemap?"external":!1});log.debug(`${pkg.name}: compiled ${result.components.length} components (${result.totalBytes} bytes)`);await writeManifest(pkg,config,version)}async function assertPublishable(pkg){if(pkg.runtime==="stx")return;const globals=await stxAmbientGlobals();if(!globals.size)return;const offenders=[];for(const source of pkg.sources){const used=ambientGlobalsUsed(await Bun.file(source).text(),globals);if(used.length)offenders.push(` ${relative(projectPath(),source)} \u2192 ${used.join(", ")}`)}if(!offenders.length)return;throw new LibraryConfigError(`Package "${pkg.name}" uses stx's ambient globals, which no module exports:
2
2
  ${offenders.join(`
3
3
  `)}
4
4
 
package/dist/release.js CHANGED
@@ -1 +1 @@
1
- import{parseOptions}from"@stacksjs/cli";import{app}from"@stacksjs/config";import{Action}from"@stacksjs/enums";import{log}from"@stacksjs/logging";import{projectPath}from"@stacksjs/path";import{runActions}from".";import{BYPASS_ENV,formatPreflightFailure,runPinnedChecks}from"./release-preflight";const raw=parseOptions()??{},passthrough={};for(const[k,v]of Object.entries(raw)){if(k==="--"||k==="_")continue;passthrough[k]=v}const isDryRun=passthrough.dryRun===!0||passthrough.dryRun==="true",actions=[Action.GenerateLibraryEntries,Action.Bump],preflight=await runPinnedChecks({cwd:projectPath()});if(preflight.bypassed)log.warn(`${BYPASS_ENV} is set, so the pinned checks were skipped for this release.`);else if(preflight.failures.length>0){await log.flush();await log.exit(formatPreflightFailure(preflight.failures),1)}const result=await runActions(actions,{cwd:projectPath(),...passthrough});if(result&&result.isErr)await log.exit(`Release failed: ${result.error?.message??String(result.error)}`,1);log.success(isDryRun?`Dry run complete for ${app.name}. Nothing was committed, tagged or pushed.`:`Successfully released ${app.name}`);
1
+ import{parseOptions}from"@stacksjs/cli";import{app}from"@stacksjs/config";import{Action}from"@stacksjs/enums";import{log}from"@stacksjs/logging";import{projectPath}from"@stacksjs/path";import{runActions}from"./helpers/utils";import{BYPASS_ENV,formatPreflightFailure,runPinnedChecks}from"./release-preflight";const raw=parseOptions()??{},passthrough={};for(const[k,v]of Object.entries(raw)){if(k==="--"||k==="_")continue;passthrough[k]=v}const isDryRun=passthrough.dryRun===!0||passthrough.dryRun==="true",actions=[Action.GenerateLibraryEntries,Action.Bump],preflight=await runPinnedChecks({cwd:projectPath()});if(preflight.bypassed)log.warn(`${BYPASS_ENV} is set, so the pinned checks were skipped for this release.`);else if(preflight.failures.length>0){await log.flush();await log.exit(formatPreflightFailure(preflight.failures),1)}const result=await runActions(actions,{cwd:projectPath(),...passthrough});if(result&&result.isErr)await log.exit(`Release failed: ${result.error?.message??String(result.error)}`,1);log.success(isDryRun?`Dry run complete for ${app.name}. Nothing was committed, tagged or pushed.`:`Successfully released ${app.name}`);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/actions",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.230",
5
+ "version": "0.75.236",
6
6
  "description": "The Stacks actions.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -66,54 +66,54 @@
66
66
  "prepublishOnly": "bun run build"
67
67
  },
68
68
  "dependencies": {
69
- "@stacksjs/action-runner": "0.75.230",
70
- "@stacksjs/ai": "0.75.230",
71
- "@stacksjs/analytics": "0.75.230",
72
- "@stacksjs/api": "0.75.230",
73
- "@stacksjs/auth": "0.75.230",
74
- "@stacksjs/build": "0.75.230",
75
- "@stacksjs/bumpx": "^0.2.21",
69
+ "@stacksjs/action-runner": "0.75.236",
70
+ "@stacksjs/ai": "0.75.236",
71
+ "@stacksjs/analytics": "0.75.236",
72
+ "@stacksjs/api": "0.75.236",
73
+ "@stacksjs/auth": "0.75.236",
74
+ "@stacksjs/build": "0.75.236",
75
+ "@stacksjs/bumpx": "^0.2.24",
76
76
  "@stacksjs/bunpress": "^0.2.15",
77
- "@stacksjs/cli": "0.75.230",
78
- "@stacksjs/cloud": "0.75.230",
79
- "@stacksjs/cms": "0.75.230",
77
+ "@stacksjs/cli": "0.75.236",
78
+ "@stacksjs/cloud": "0.75.236",
79
+ "@stacksjs/cms": "0.75.236",
80
80
  "@stacksjs/components": "^0.2.574",
81
- "@stacksjs/config": "0.75.230",
82
- "@stacksjs/database": "0.75.230",
83
- "@stacksjs/desktop-build": "0.75.230",
84
- "@stacksjs/dns": "0.75.230",
85
- "@stacksjs/enums": "0.75.230",
86
- "@stacksjs/env": "0.75.230",
87
- "@stacksjs/error-handling": "0.75.230",
88
- "@stacksjs/github": "0.75.230",
81
+ "@stacksjs/config": "0.75.236",
82
+ "@stacksjs/database": "0.75.236",
83
+ "@stacksjs/desktop-build": "0.75.236",
84
+ "@stacksjs/dns": "0.75.236",
85
+ "@stacksjs/enums": "0.75.236",
86
+ "@stacksjs/env": "0.75.236",
87
+ "@stacksjs/error-handling": "0.75.236",
88
+ "@stacksjs/github": "0.75.236",
89
89
  "@stacksjs/gitit": "^0.2.5",
90
- "@stacksjs/i18n": "0.75.230",
91
- "@stacksjs/image": "0.75.230",
92
- "@stacksjs/logging": "0.75.230",
90
+ "@stacksjs/i18n": "0.75.236",
91
+ "@stacksjs/image": "0.75.236",
92
+ "@stacksjs/logging": "0.75.236",
93
93
  "@stacksjs/logsmith": "^0.2.11",
94
- "@stacksjs/mobile": "0.75.230",
95
- "@stacksjs/orm": "0.75.230",
96
- "@stacksjs/path": "0.75.230",
97
- "@stacksjs/payments": "0.75.230",
98
- "@stacksjs/queue": "0.75.230",
99
- "@stacksjs/registry": "0.75.230",
100
- "@stacksjs/router": "0.75.230",
94
+ "@stacksjs/mobile": "0.75.236",
95
+ "@stacksjs/orm": "0.75.236",
96
+ "@stacksjs/path": "0.75.236",
97
+ "@stacksjs/payments": "0.75.236",
98
+ "@stacksjs/queue": "0.75.236",
99
+ "@stacksjs/registry": "0.75.236",
100
+ "@stacksjs/router": "0.75.236",
101
101
  "@stacksjs/rpx": "^0.11.54",
102
- "@stacksjs/scheduler": "0.75.230",
103
- "@stacksjs/search-engine": "0.75.230",
104
- "@stacksjs/security": "0.75.230",
105
- "@stacksjs/server": "0.75.230",
106
- "@stacksjs/sites": "0.75.230",
107
- "@stacksjs/storage": "0.75.230",
108
- "@stacksjs/strings": "0.75.230",
102
+ "@stacksjs/scheduler": "0.75.236",
103
+ "@stacksjs/search-engine": "0.75.236",
104
+ "@stacksjs/security": "0.75.236",
105
+ "@stacksjs/server": "0.75.236",
106
+ "@stacksjs/sites": "0.75.236",
107
+ "@stacksjs/storage": "0.75.236",
108
+ "@stacksjs/strings": "0.75.236",
109
109
  "@stacksjs/stx": "^0.2.574",
110
110
  "@stacksjs/tlsx": "^0.13.19",
111
111
  "@stacksjs/ts-cloud": "^0.16.58",
112
112
  "@stacksjs/ts-md": "^0.1.1",
113
- "@stacksjs/tunnel": "0.75.230",
114
- "@stacksjs/types": "0.75.230",
115
- "@stacksjs/utils": "0.75.230",
116
- "@stacksjs/whois": "0.75.230",
113
+ "@stacksjs/tunnel": "0.75.236",
114
+ "@stacksjs/types": "0.75.236",
115
+ "@stacksjs/utils": "0.75.236",
116
+ "@stacksjs/whois": "0.75.236",
117
117
  "bun-plugin-stx": "^0.2.574"
118
118
  },
119
119
  "peerDependencies": {
@@ -129,7 +129,7 @@
129
129
  }
130
130
  },
131
131
  "devDependencies": {
132
- "@stacksjs/validation": "0.75.230",
132
+ "@stacksjs/validation": "0.75.236",
133
133
  "better-dx": "^0.2.24"
134
134
  }
135
135
  }