@stacksjs/actions 0.75.169 → 0.75.171
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/craft-entry.d.ts +11 -0
- package/dist/build/craft-entry.js +1 -1
- package/dist/build/ios-config.d.ts +68 -0
- package/dist/build/ios-config.js +1 -1
- package/dist/build/ios.js +1 -1
- package/package.json +40 -40
|
@@ -14,3 +14,14 @@
|
|
|
14
14
|
* Falls back to the bare specifier when @stacksjs/mobile is not installed.
|
|
15
15
|
*/
|
|
16
16
|
export declare function craftBuilderSpecifier(builder: 'ios' | 'android', root: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* The version of the Craft a builder entry belongs to, read from the nearest
|
|
19
|
+
* enclosing `package.json` that is Craft's own.
|
|
20
|
+
*
|
|
21
|
+
* Takes the builder's file path or `file:` URL (what `craftBuilderSpecifier`
|
|
22
|
+
* returns, or `CRAFT_IOS_SRC`); a bare specifier is resolved from `root`.
|
|
23
|
+
* `craft-native` does not export its `package.json`, so the manifest is found
|
|
24
|
+
* by walking up from the entry rather than resolved by name. Returns
|
|
25
|
+
* undefined when no Craft manifest encloses the entry.
|
|
26
|
+
*/
|
|
27
|
+
export declare function craftBuilderVersion(entry: string, root: string): { version: string, manifest: string } | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname}from"node:path";import{pathToFileURL}from"node:url";export function craftBuilderSpecifier(builder,root){try{const mobile=Bun.resolveSync("@stacksjs/mobile/package.json",root);return pathToFileURL(Bun.resolveSync(`craft-native/${builder}`,dirname(mobile))).href}catch{return`craft-native/${builder}`}}
|
|
1
|
+
import{existsSync,readFileSync}from"node:fs";import{dirname,join}from"node:path";import{fileURLToPath,pathToFileURL}from"node:url";export function craftBuilderSpecifier(builder,root){try{const mobile=Bun.resolveSync("@stacksjs/mobile/package.json",root);return pathToFileURL(Bun.resolveSync(`craft-native/${builder}`,dirname(mobile))).href}catch{return`craft-native/${builder}`}}const CRAFT_PACKAGES=new Set(["craft-native","@craft-native/ios","@craft-native/android"]);export function craftBuilderVersion(entry,root){let file;try{file=entry.startsWith("file:")?fileURLToPath(entry):entry.startsWith("/")?entry:Bun.resolveSync(entry,root)}catch{return}for(let dir=dirname(file);;dir=dirname(dir)){const manifest=join(dir,"package.json");if(existsSync(manifest))try{const pkg=JSON.parse(readFileSync(manifest,"utf8"));if(pkg.name&&CRAFT_PACKAGES.has(pkg.name)&&pkg.version)return{version:pkg.version,manifest}}catch{}if(dirname(dir)===dir)return}}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import type { IosMobileConfig, MobileConfig } from '@stacksjs/types';
|
|
2
|
+
/** The capabilities `config/mobile.ts` turns on that a Craft of `version` would leave out of the app. */
|
|
3
|
+
export declare function unsupportedCraftCapabilities(capabilities: IosMobileConfig['capabilities'], version: string): UnsupportedCraftCapability[];
|
|
4
|
+
/**
|
|
5
|
+
* Refuse to generate an app that would silently lack a capability it asks for.
|
|
6
|
+
*
|
|
7
|
+
* `version` is the craft-native the builder came from and `source` where it
|
|
8
|
+
* was found, both named in the error so the stale copy can be traced in the
|
|
9
|
+
* lockfile.
|
|
10
|
+
*/
|
|
11
|
+
export declare function assertCraftSupportsCapabilities(capabilities: IosMobileConfig['capabilities'], version: string, source: string): void;
|
|
2
12
|
export declare function normalizeMobileUrl(value: string | undefined): string | undefined;
|
|
3
13
|
/**
|
|
4
14
|
* The generated project's records (craft.config.json, stacks-mobile.json)
|
|
@@ -33,6 +43,60 @@ export declare function withActivityTypes(plist: string, types: readonly string[
|
|
|
33
43
|
export declare function writeIosActivityTypes(output: string, config: MobileConfig): string[] | null;
|
|
34
44
|
/** The route stx's bundle runs the app script under (`compileNativeBundle`'s `app`). */
|
|
35
45
|
export declare const NATIVE_APP_ROUTE: '__app';
|
|
46
|
+
declare const CAPABILITY_KEYS: {
|
|
47
|
+
speechRecognition: 'enableSpeechRecognition';
|
|
48
|
+
haptics: 'enableHaptics';
|
|
49
|
+
share: 'enableShare';
|
|
50
|
+
camera: 'enableCamera';
|
|
51
|
+
biometric: 'enableBiometric';
|
|
52
|
+
pushNotifications: 'enablePushNotifications';
|
|
53
|
+
secureStorage: 'enableSecureStorage';
|
|
54
|
+
geolocation: 'enableGeolocation';
|
|
55
|
+
backgroundLocation: 'enableBackgroundLocation';
|
|
56
|
+
clipboard: 'enableClipboard';
|
|
57
|
+
contacts: 'enableContacts';
|
|
58
|
+
calendar: 'enableCalendar';
|
|
59
|
+
localNotifications: 'enableLocalNotifications';
|
|
60
|
+
inAppPurchase: 'enableInAppPurchase';
|
|
61
|
+
keepAwake: 'enableKeepAwake';
|
|
62
|
+
orientationLock: 'enableOrientationLock';
|
|
63
|
+
deepLinks: 'enableDeepLinks';
|
|
64
|
+
qrScanner: 'enableQRScanner';
|
|
65
|
+
localNetwork: 'enableLocalNetwork';
|
|
66
|
+
filePicker: 'enableFilePicker';
|
|
67
|
+
fileDownload: 'enableFileDownload';
|
|
68
|
+
socialAuth: 'enableSocialAuth';
|
|
69
|
+
audioRecording: 'enableAudioRecording';
|
|
70
|
+
videoRecording: 'enableVideoRecording';
|
|
71
|
+
motionSensors: 'enableMotionSensors';
|
|
72
|
+
localDatabase: 'enableLocalDatabase';
|
|
73
|
+
bluetooth: 'enableBluetooth';
|
|
74
|
+
nfc: 'enableNFC';
|
|
75
|
+
healthKit: 'enableHealthKit';
|
|
76
|
+
appleMusic: 'enableAppleMusic';
|
|
77
|
+
heartRate: 'enableHeartRate';
|
|
78
|
+
backgroundAudio: 'enableBackgroundAudio';
|
|
79
|
+
scheduledWorkouts: 'enableScheduledWorkouts';
|
|
80
|
+
liveActivities: 'enableLiveActivities';
|
|
81
|
+
watchApp: 'enableWatchApp';
|
|
82
|
+
backgroundTasks: 'enableBackgroundTasks';
|
|
83
|
+
screenCapture: 'enableScreenCapture';
|
|
84
|
+
pdfViewer: 'enablePDFViewer';
|
|
85
|
+
augmentedReality: 'enableAR';
|
|
86
|
+
machineLearning: 'enableMLKit'
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* The first craft-native release whose iOS template honours a capability.
|
|
90
|
+
*
|
|
91
|
+
* Craft copies every `enable…` key into craft.config.json, and an older
|
|
92
|
+
* template simply has no Swift reading the new one: the build succeeds and
|
|
93
|
+
* the app ships without the entitlement, the Info.plist keys and the bridge,
|
|
94
|
+
* while the pages still call it. HQ.training's Apple Watch workouts went
|
|
95
|
+
* missing that way, built by a craft-native 0.0.162 nested under
|
|
96
|
+
* @stacksjs/mobile. Capabilities older than every craft-native Stacks has
|
|
97
|
+
* accepted are not listed.
|
|
98
|
+
*/
|
|
99
|
+
export declare const CRAFT_CAPABILITY_FLOORS: Partial<Record<keyof typeof CAPABILITY_KEYS, string>>;
|
|
36
100
|
export declare interface CraftIosConfig {
|
|
37
101
|
[key: string]: unknown
|
|
38
102
|
appName: string
|
|
@@ -74,3 +138,7 @@ export declare interface CraftIosConfig {
|
|
|
74
138
|
orientations?: IosMobileConfig['orientations']
|
|
75
139
|
deviceFamilies?: IosMobileConfig['deviceFamilies']
|
|
76
140
|
}
|
|
141
|
+
export declare interface UnsupportedCraftCapability {
|
|
142
|
+
capability: keyof typeof CRAFT_CAPABILITY_FLOORS
|
|
143
|
+
needs: string
|
|
144
|
+
}
|
package/dist/build/ios-config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync,readFileSync,writeFileSync}from"node:fs";import{isAbsolute,join,relative,resolve}from"node:path";import{spotlightActivityTypes}from"@stacksjs/mobile";export const NATIVE_APP_ROUTE="__app";const CAPABILITY_KEYS={speechRecognition:"enableSpeechRecognition",haptics:"enableHaptics",share:"enableShare",camera:"enableCamera",biometric:"enableBiometric",pushNotifications:"enablePushNotifications",secureStorage:"enableSecureStorage",geolocation:"enableGeolocation",backgroundLocation:"enableBackgroundLocation",clipboard:"enableClipboard",contacts:"enableContacts",calendar:"enableCalendar",localNotifications:"enableLocalNotifications",inAppPurchase:"enableInAppPurchase",keepAwake:"enableKeepAwake",orientationLock:"enableOrientationLock",deepLinks:"enableDeepLinks",qrScanner:"enableQRScanner",localNetwork:"enableLocalNetwork",filePicker:"enableFilePicker",fileDownload:"enableFileDownload",socialAuth:"enableSocialAuth",audioRecording:"enableAudioRecording",videoRecording:"enableVideoRecording",motionSensors:"enableMotionSensors",localDatabase:"enableLocalDatabase",bluetooth:"enableBluetooth",nfc:"enableNFC",healthKit:"enableHealthKit",appleMusic:"enableAppleMusic",heartRate:"enableHeartRate",backgroundAudio:"enableBackgroundAudio",scheduledWorkouts:"enableScheduledWorkouts",liveActivities:"enableLiveActivities",watchApp:"enableWatchApp",backgroundTasks:"enableBackgroundTasks",screenCapture:"enableScreenCapture",pdfViewer:"enablePDFViewer",augmentedReality:"enableAR",machineLearning:"enableMLKit"};export function normalizeMobileUrl(value){const input=value?.trim();if(!input)return;return new URL(/^https?:\/\//i.test(input)?input:`https://${input}`).toString().replace(/\/$/,"")}export function portablePaths(value,projectDir,appRoot){if(typeof value==="string")return isAbsolute(value)&&!relative(appRoot,value).startsWith("..")?relative(projectDir,value)||".":value;if(Array.isArray(value))return value.map((item)=>portablePaths(item,projectDir,appRoot));if(value&&typeof value==="object"){const out={};for(const[key,item]of Object.entries(value))out[key]=typeof item==="string"&&!/(?:path(?:dark)?|bundle)$/i.test(key)?item:portablePaths(item,projectDir,appRoot);return out}return value}export function resolveMobilePath(root,value){if(!value)return;return isAbsolute(value)?value:resolve(root,value)}export function resolveSwipeNavigation(config){if(config.swipeNavigation!==void 0)return config.swipeNavigation;return config.swipeBack==="webview"}export function toCraftIosConfig(config){const devServerURL=normalizeMobileUrl(config.url),trustedOrigins=new Set(config.trustedOrigins??[]);if(devServerURL)trustedOrigins.add(new URL(devServerURL).origin);const declaresAppBoundDomains=(config.appBoundDomains?.length??0)>0,craft={appName:config.appName,bundleId:config.bundleId,version:config.version,buildNumber:config.buildNumber,darkMode:config.darkMode,appearance:config.appearance,backgroundColor:config.backgroundColor,backgroundColorDark:config.backgroundColorDark,swipeNavigation:resolveSwipeNavigation(config),allowsLinkPreview:config.allowsLinkPreview,keyboardAccessory:config.keyboardAccessory,disableZoom:config.disableZoom,splashMaxSeconds:config.splashMaxSeconds,requestTimeoutSeconds:config.requestTimeoutSeconds,backgroundRefresh:config.backgroundRefresh,iosVersion:config.deploymentTarget,watchosVersion:config.watchDeploymentTarget,teamId:config.teamId,devServerURL,urlSchemes:config.urlSchemes,trustedOrigins:[...trustedOrigins],appBoundDomains:config.appBoundDomains,limitNavigationsToAppBoundDomains:config.limitNavigationsToAppBoundDomains??(declaresAppBoundDomains||void 0),associatedDomains:config.associatedDomains,renderer:config.renderer,nativeScreens:config.nativeScreens,nativeApp:config.nativeApp?NATIVE_APP_ROUTE:void 0,tabs:config.tabs,shareStorage:config.shareStorage,appGroups:config.appGroups,appIconPath:config.appIcon,privacy:config.privacy,usageDescriptions:config.usageDescriptions,orientations:config.orientations,deviceFamilies:config.deviceFamilies};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 validateIosMobileConfig(config){if(!config.appName?.trim())throw Error("config/mobile.ts must define ios.appName");if(!/^[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/.test(config.bundleId))throw Error(`Invalid iOS bundle identifier: ${config.bundleId}`);if(config.url&&config.webAssets)throw Error("Choose either ios.url or ios.webAssets in config/mobile.ts, not both");if(!config.url&&!config.webAssets)throw Error("config/mobile.ts must define ios.url or ios.webAssets");if(config.renderer!==void 0&&config.renderer!=="web"&&config.renderer!=="native")throw Error(`ios.renderer must be 'web' or 'native', not ${String(config.renderer)}`);if(config.renderer==="native"){if(!Object.keys(config.nativeScreens??{}).length)throw Error("ios.renderer 'native' draws every screen natively: list them in ios.nativeScreens");if(config.webAssets)throw Error("ios.renderer 'native' has no web view to show ios.webAssets in: set ios.url to the app's site instead");if(config.fallbackWebAssets)throw Error("ios.fallbackWebAssets is the web view's offline page; ios.renderer 'native' has no web view")}if(config.fallbackWebAssets&&!config.url)throw Error("ios.fallbackWebAssets requires ios.url");if(config.deviceFamilies&&(config.deviceFamilies.length===0||config.deviceFamilies.some((family)=>family!=="iphone"&&family!=="ipad")))throw Error("ios.deviceFamilies must contain iphone and/or ipad");if(config.url){const url=new URL(normalizeMobileUrl(config.url)),isLocal=["localhost","127.0.0.1","::1"].includes(url.hostname);if(url.protocol!=="https:"&&!isLocal)throw Error("ios.url must use HTTPS outside local development")}for(const domain of config.associatedDomains??[])if(!/^(applinks|webcredentials|activitycontinuation):[^/\s]+$/.test(domain))throw Error(`Invalid iOS associated domain: ${domain}`);for(const key of["splashMaxSeconds","requestTimeoutSeconds"]){const value=config[key];if(value!==void 0&&(!Number.isFinite(value)||value<=0))throw Error(`ios.${key} must be a positive number of seconds`)}const refresh=config.backgroundRefresh;if(refresh){if(refresh.identifier!==void 0&&!/^[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/.test(refresh.identifier))throw Error(`Invalid iOS background refresh identifier: ${refresh.identifier}`);if(refresh.minimumIntervalMinutes!==void 0&&(!Number.isFinite(refresh.minimumIntervalMinutes)||refresh.minimumIntervalMinutes<=0))throw Error("ios.backgroundRefresh.minimumIntervalMinutes must be a positive number of minutes")}if(config.capabilities?.watchApp){const target=Number.parseFloat(config.watchDeploymentTarget??"9.0");if(!Number.isFinite(target)||target<9)throw Error("ios.watchDeploymentTarget must be watchOS 9.0 or newer")}}const ACTIVITY_TYPES_BLOCK=/[ \t]*<key>NSUserActivityTypes<\/key>\s*<array>[\s\S]*?<\/array>\n?/;export function withActivityTypes(plist,types){const entries=types.map((type)=>` <string>${escapeXml(type)}</string>`).join(`
|
|
1
|
+
import{existsSync,readFileSync,writeFileSync}from"node:fs";import{isAbsolute,join,relative,resolve}from"node:path";import{spotlightActivityTypes}from"@stacksjs/mobile";export const NATIVE_APP_ROUTE="__app";const CAPABILITY_KEYS={speechRecognition:"enableSpeechRecognition",haptics:"enableHaptics",share:"enableShare",camera:"enableCamera",biometric:"enableBiometric",pushNotifications:"enablePushNotifications",secureStorage:"enableSecureStorage",geolocation:"enableGeolocation",backgroundLocation:"enableBackgroundLocation",clipboard:"enableClipboard",contacts:"enableContacts",calendar:"enableCalendar",localNotifications:"enableLocalNotifications",inAppPurchase:"enableInAppPurchase",keepAwake:"enableKeepAwake",orientationLock:"enableOrientationLock",deepLinks:"enableDeepLinks",qrScanner:"enableQRScanner",localNetwork:"enableLocalNetwork",filePicker:"enableFilePicker",fileDownload:"enableFileDownload",socialAuth:"enableSocialAuth",audioRecording:"enableAudioRecording",videoRecording:"enableVideoRecording",motionSensors:"enableMotionSensors",localDatabase:"enableLocalDatabase",bluetooth:"enableBluetooth",nfc:"enableNFC",healthKit:"enableHealthKit",appleMusic:"enableAppleMusic",heartRate:"enableHeartRate",backgroundAudio:"enableBackgroundAudio",scheduledWorkouts:"enableScheduledWorkouts",liveActivities:"enableLiveActivities",watchApp:"enableWatchApp",backgroundTasks:"enableBackgroundTasks",screenCapture:"enableScreenCapture",pdfViewer:"enablePDFViewer",augmentedReality:"enableAR",machineLearning:"enableMLKit"};export const CRAFT_CAPABILITY_FLOORS={appleMusic:"0.0.144",heartRate:"0.0.152",backgroundAudio:"0.0.162",scheduledWorkouts:"0.0.163"};export function unsupportedCraftCapabilities(capabilities,version){const missing=[];for(const[capability,needs]of Object.entries(CRAFT_CAPABILITY_FLOORS))if(capabilities?.[capability]&&!Bun.semver.satisfies(version,`>=${needs}`))missing.push({capability,needs});return missing}export function assertCraftSupportsCapabilities(capabilities,version,source){const missing=unsupportedCraftCapabilities(capabilities,version);if(missing.length===0)return;const needed=missing.reduce((max,{needs})=>Bun.semver.order(needs,max)>0?needs:max,"0.0.0");throw Error(`The Craft iOS builder is craft-native ${version} (${source}), which would build the app without ${missing.map(({capability,needs})=>`ios.capabilities.${capability} (needs >= ${needs})`).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 normalizeMobileUrl(value){const input=value?.trim();if(!input)return;return new URL(/^https?:\/\//i.test(input)?input:`https://${input}`).toString().replace(/\/$/,"")}export function portablePaths(value,projectDir,appRoot){if(typeof value==="string")return isAbsolute(value)&&!relative(appRoot,value).startsWith("..")?relative(projectDir,value)||".":value;if(Array.isArray(value))return value.map((item)=>portablePaths(item,projectDir,appRoot));if(value&&typeof value==="object"){const out={};for(const[key,item]of Object.entries(value))out[key]=typeof item==="string"&&!/(?:path(?:dark)?|bundle)$/i.test(key)?item:portablePaths(item,projectDir,appRoot);return out}return value}export function resolveMobilePath(root,value){if(!value)return;return isAbsolute(value)?value:resolve(root,value)}export function resolveSwipeNavigation(config){if(config.swipeNavigation!==void 0)return config.swipeNavigation;return config.swipeBack==="webview"}export function toCraftIosConfig(config){const devServerURL=normalizeMobileUrl(config.url),trustedOrigins=new Set(config.trustedOrigins??[]);if(devServerURL)trustedOrigins.add(new URL(devServerURL).origin);const declaresAppBoundDomains=(config.appBoundDomains?.length??0)>0,craft={appName:config.appName,bundleId:config.bundleId,version:config.version,buildNumber:config.buildNumber,darkMode:config.darkMode,appearance:config.appearance,backgroundColor:config.backgroundColor,backgroundColorDark:config.backgroundColorDark,swipeNavigation:resolveSwipeNavigation(config),allowsLinkPreview:config.allowsLinkPreview,keyboardAccessory:config.keyboardAccessory,disableZoom:config.disableZoom,splashMaxSeconds:config.splashMaxSeconds,requestTimeoutSeconds:config.requestTimeoutSeconds,backgroundRefresh:config.backgroundRefresh,iosVersion:config.deploymentTarget,watchosVersion:config.watchDeploymentTarget,teamId:config.teamId,devServerURL,urlSchemes:config.urlSchemes,trustedOrigins:[...trustedOrigins],appBoundDomains:config.appBoundDomains,limitNavigationsToAppBoundDomains:config.limitNavigationsToAppBoundDomains??(declaresAppBoundDomains||void 0),associatedDomains:config.associatedDomains,renderer:config.renderer,nativeScreens:config.nativeScreens,nativeApp:config.nativeApp?NATIVE_APP_ROUTE:void 0,tabs:config.tabs,shareStorage:config.shareStorage,appGroups:config.appGroups,appIconPath:config.appIcon,privacy:config.privacy,usageDescriptions:config.usageDescriptions,orientations:config.orientations,deviceFamilies:config.deviceFamilies};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 validateIosMobileConfig(config){if(!config.appName?.trim())throw Error("config/mobile.ts must define ios.appName");if(!/^[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/.test(config.bundleId))throw Error(`Invalid iOS bundle identifier: ${config.bundleId}`);if(config.url&&config.webAssets)throw Error("Choose either ios.url or ios.webAssets in config/mobile.ts, not both");if(!config.url&&!config.webAssets)throw Error("config/mobile.ts must define ios.url or ios.webAssets");if(config.renderer!==void 0&&config.renderer!=="web"&&config.renderer!=="native")throw Error(`ios.renderer must be 'web' or 'native', not ${String(config.renderer)}`);if(config.renderer==="native"){if(!Object.keys(config.nativeScreens??{}).length)throw Error("ios.renderer 'native' draws every screen natively: list them in ios.nativeScreens");if(config.webAssets)throw Error("ios.renderer 'native' has no web view to show ios.webAssets in: set ios.url to the app's site instead");if(config.fallbackWebAssets)throw Error("ios.fallbackWebAssets is the web view's offline page; ios.renderer 'native' has no web view")}if(config.fallbackWebAssets&&!config.url)throw Error("ios.fallbackWebAssets requires ios.url");if(config.deviceFamilies&&(config.deviceFamilies.length===0||config.deviceFamilies.some((family)=>family!=="iphone"&&family!=="ipad")))throw Error("ios.deviceFamilies must contain iphone and/or ipad");if(config.url){const url=new URL(normalizeMobileUrl(config.url)),isLocal=["localhost","127.0.0.1","::1"].includes(url.hostname);if(url.protocol!=="https:"&&!isLocal)throw Error("ios.url must use HTTPS outside local development")}for(const domain of config.associatedDomains??[])if(!/^(applinks|webcredentials|activitycontinuation):[^/\s]+$/.test(domain))throw Error(`Invalid iOS associated domain: ${domain}`);for(const key of["splashMaxSeconds","requestTimeoutSeconds"]){const value=config[key];if(value!==void 0&&(!Number.isFinite(value)||value<=0))throw Error(`ios.${key} must be a positive number of seconds`)}const refresh=config.backgroundRefresh;if(refresh){if(refresh.identifier!==void 0&&!/^[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/.test(refresh.identifier))throw Error(`Invalid iOS background refresh identifier: ${refresh.identifier}`);if(refresh.minimumIntervalMinutes!==void 0&&(!Number.isFinite(refresh.minimumIntervalMinutes)||refresh.minimumIntervalMinutes<=0))throw Error("ios.backgroundRefresh.minimumIntervalMinutes must be a positive number of minutes")}if(config.capabilities?.watchApp){const target=Number.parseFloat(config.watchDeploymentTarget??"9.0");if(!Number.isFinite(target)||target<9)throw Error("ios.watchDeploymentTarget must be watchOS 9.0 or newer")}}const ACTIVITY_TYPES_BLOCK=/[ \t]*<key>NSUserActivityTypes<\/key>\s*<array>[\s\S]*?<\/array>\n?/;export function withActivityTypes(plist,types){const entries=types.map((type)=>` <string>${escapeXml(type)}</string>`).join(`
|
|
2
2
|
`),block=types.length===0?"":` <key>NSUserActivityTypes</key>
|
|
3
3
|
<array>
|
|
4
4
|
${entries}
|
package/dist/build/ios.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{existsSync,readFileSync,writeFileSync}from"node:fs";import{pathToFileURL}from"node:url";import process from"node:process";import{log}from"@stacksjs/cli";import{projectPath,storagePath}from"@stacksjs/path";import{craftBuilderSpecifier}from"./craft-entry";import{resolveCraftBuilderProvenance}from"./craft-provenance";import{portablePaths,resolveMobilePath,toCraftIosConfig,validateIosMobileConfig,writeIosActivityTypes}from"./ios-config";import{compileNativeScreens}from"./native-screens";import{writeIosShellSupport}from"./ios-shell";process.exitCode=1;
|
|
1
|
+
import{existsSync,readFileSync,writeFileSync}from"node:fs";import{pathToFileURL}from"node:url";import process from"node:process";import{log}from"@stacksjs/cli";import{projectPath,storagePath}from"@stacksjs/path";import{craftBuilderSpecifier,craftBuilderVersion}from"./craft-entry";import{resolveCraftBuilderProvenance}from"./craft-provenance";import{assertCraftSupportsCapabilities,portablePaths,resolveMobilePath,toCraftIosConfig,validateIosMobileConfig,writeIosActivityTypes}from"./ios-config";import{compileNativeScreens}from"./native-screens";import{writeIosShellSupport}from"./ios-shell";process.exitCode=1;function craftIosEntry(){const explicit=process.env.CRAFT_IOS_SRC;return explicit?pathToFileURL(explicit).href:craftBuilderSpecifier("ios",projectPath())}async function loadCraftIosBuilder(){try{return await import(craftIosEntry())}catch(error){throw Error("Craft iOS builder is unavailable. Install the current craft-native package or set CRAFT_IOS_SRC to packages/ios/src/index.ts in a Craft checkout.",{cause:error})}}const configPath=projectPath("config/mobile.ts");if(!existsSync(configPath))throw Error("Missing config/mobile.ts. Add an ios section before running `buddy build:ios`.");const configModule=await import(`${pathToFileURL(configPath).href}?t=${Date.now()}`),mobile=configModule.default,config=mobile.ios;validateIosMobileConfig(config);if(config.swipeNavigation===!0&&config.swipeBack!=="webview")log.warn("ios.swipeNavigation turns on WebKit's edge swipe alongside the stx router's own. Remove it, or set ios.swipeBack: 'webview' for an app not on the router.");const output=resolveMobilePath(projectPath(),config.output)??storagePath("framework/mobile/ios"),webAssets=resolveMobilePath(projectPath(),config.webAssets),fallbackWebAssets=resolveMobilePath(projectPath(),config.fallbackWebAssets),craftConfig=toCraftIosConfig(config);craftConfig.appIconPath=resolveMobilePath(projectPath(),config.appIcon);craftConfig.splashImagePath=resolveMobilePath(projectPath(),config.splash?.image);craftConfig.splashImagePathDark=resolveMobilePath(projectPath(),config.splash?.imageDark);const nativeBundle=await compileNativeScreens(config,projectPath(),output);if(nativeBundle){craftConfig.nativeBundle=nativeBundle.outFile;for(const diagnostic of nativeBundle.diagnostics??[])log.warn(`${diagnostic.file?`${diagnostic.file}: `:""}${diagnostic.message}`);log.info(`Compiled ${Object.keys(config.nativeScreens??{}).length} native screen path(s) into ${nativeBundle.outFile}`)}const builder=await loadCraftIosBuilder(),craftVersion=craftBuilderVersion(craftIosEntry(),projectPath());if(craftVersion)assertCraftSupportsCapabilities(config.capabilities,craftVersion.version,craftVersion.manifest);else log.warn(`Could not read the craft-native version behind ${craftIosEntry()}, so the build cannot check that it supports every capability config/mobile.ts turns on.`);await builder.init({name:config.appName,bundleId:config.bundleId,teamId:config.teamId,output,config:craftConfig});const native=config.renderer==="native";if(native&&!nativeBundle)throw Error("ios.renderer 'native' needs native screens to draw: list them in ios.nativeScreens");await builder.build(native?{output,nativeBundlePath:nativeBundle.outFile,generateProject:process.env.STACKS_IOS_SKIP_XCODEGEN!=="1"}:{output,htmlPath:webAssets??fallbackWebAssets,devServer:craftConfig.devServerURL,generateProject:process.env.STACKS_IOS_SKIP_XCODEGEN!=="1"});writeIosShellSupport(output,config);const activityTypes=writeIosActivityTypes(output,mobile);if(activityTypes)log.info(`Declared ${activityTypes.length} activity types, so a tapped Spotlight or Siri entry reaches the app`);const sourceRevision=Bun.spawnSync(["git","rev-parse","HEAD"],{cwd:projectPath()}).stdout.toString().trim(),craftConfigPath=`${output}/craft.config.json`,generatedConfig=portablePaths(JSON.parse(readFileSync(craftConfigPath,"utf8")),output,projectPath());writeFileSync(craftConfigPath,`${JSON.stringify(generatedConfig,null,2)}
|
|
2
2
|
`);writeFileSync(`${output}/stacks-mobile.json`,`${JSON.stringify(portablePaths({schemaVersion:"1.0.0",platform:"ios",sourceRevision,source:native?{kind:"native",site:craftConfig.devServerURL}:webAssets?{kind:"bundled",path:webAssets}:{kind:"remote",url:craftConfig.devServerURL,fallback:fallbackWebAssets?{kind:"bundled",path:fallbackWebAssets}:void 0},capabilities:config.capabilities??{},builder:resolveCraftBuilderProvenance(process.env.CRAFT_IOS_SRC),craft:generatedConfig},output,projectPath()),null,2)}
|
|
3
3
|
`);log.success(`Built the Craft iOS project in ${output}`);await log.flush();process.exitCode=0;
|
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.
|
|
5
|
+
"version": "0.75.171",
|
|
6
6
|
"description": "The Stacks actions.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -66,57 +66,57 @@
|
|
|
66
66
|
"prepublishOnly": "bun run build"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@stacksjs/action-runner": "0.75.
|
|
70
|
-
"@stacksjs/ai": "0.75.
|
|
71
|
-
"@stacksjs/analytics": "0.75.
|
|
72
|
-
"@stacksjs/api": "0.75.
|
|
73
|
-
"@stacksjs/auth": "0.75.
|
|
74
|
-
"@stacksjs/build": "0.75.
|
|
69
|
+
"@stacksjs/action-runner": "0.75.171",
|
|
70
|
+
"@stacksjs/ai": "0.75.171",
|
|
71
|
+
"@stacksjs/analytics": "0.75.171",
|
|
72
|
+
"@stacksjs/api": "0.75.171",
|
|
73
|
+
"@stacksjs/auth": "0.75.171",
|
|
74
|
+
"@stacksjs/build": "0.75.171",
|
|
75
75
|
"@stacksjs/bumpx": "^0.2.21",
|
|
76
76
|
"@stacksjs/bunpress": "^0.2.15",
|
|
77
|
-
"@stacksjs/cli": "0.75.
|
|
78
|
-
"@stacksjs/cloud": "0.75.
|
|
79
|
-
"@stacksjs/cms": "0.75.
|
|
77
|
+
"@stacksjs/cli": "0.75.171",
|
|
78
|
+
"@stacksjs/cloud": "0.75.171",
|
|
79
|
+
"@stacksjs/cms": "0.75.171",
|
|
80
80
|
"@stacksjs/components": "^0.2.483",
|
|
81
|
-
"@stacksjs/config": "0.75.
|
|
82
|
-
"@stacksjs/database": "0.75.
|
|
83
|
-
"@stacksjs/desktop-build": "0.75.
|
|
84
|
-
"@stacksjs/dns": "0.75.
|
|
85
|
-
"@stacksjs/enums": "0.75.
|
|
86
|
-
"@stacksjs/env": "0.75.
|
|
87
|
-
"@stacksjs/error-handling": "0.75.
|
|
81
|
+
"@stacksjs/config": "0.75.171",
|
|
82
|
+
"@stacksjs/database": "0.75.171",
|
|
83
|
+
"@stacksjs/desktop-build": "0.75.171",
|
|
84
|
+
"@stacksjs/dns": "0.75.171",
|
|
85
|
+
"@stacksjs/enums": "0.75.171",
|
|
86
|
+
"@stacksjs/env": "0.75.171",
|
|
87
|
+
"@stacksjs/error-handling": "0.75.171",
|
|
88
88
|
"@stacksjs/gitit": "^0.2.5",
|
|
89
|
-
"@stacksjs/i18n": "0.75.
|
|
90
|
-
"@stacksjs/image": "0.75.
|
|
91
|
-
"@stacksjs/logging": "0.75.
|
|
89
|
+
"@stacksjs/i18n": "0.75.171",
|
|
90
|
+
"@stacksjs/image": "0.75.171",
|
|
91
|
+
"@stacksjs/logging": "0.75.171",
|
|
92
92
|
"@stacksjs/logsmith": "^0.2.11",
|
|
93
|
-
"@stacksjs/mobile": "0.75.
|
|
94
|
-
"@stacksjs/orm": "0.75.
|
|
95
|
-
"@stacksjs/path": "0.75.
|
|
96
|
-
"@stacksjs/payments": "0.75.
|
|
97
|
-
"@stacksjs/queue": "0.75.
|
|
98
|
-
"@stacksjs/registry": "0.75.
|
|
99
|
-
"@stacksjs/router": "0.75.
|
|
93
|
+
"@stacksjs/mobile": "0.75.171",
|
|
94
|
+
"@stacksjs/orm": "0.75.171",
|
|
95
|
+
"@stacksjs/path": "0.75.171",
|
|
96
|
+
"@stacksjs/payments": "0.75.171",
|
|
97
|
+
"@stacksjs/queue": "0.75.171",
|
|
98
|
+
"@stacksjs/registry": "0.75.171",
|
|
99
|
+
"@stacksjs/router": "0.75.171",
|
|
100
100
|
"@stacksjs/rpx": "^0.11.54",
|
|
101
|
-
"@stacksjs/scheduler": "0.75.
|
|
102
|
-
"@stacksjs/search-engine": "0.75.
|
|
103
|
-
"@stacksjs/security": "0.75.
|
|
104
|
-
"@stacksjs/server": "0.75.
|
|
105
|
-
"@stacksjs/sites": "0.75.
|
|
106
|
-
"@stacksjs/storage": "0.75.
|
|
107
|
-
"@stacksjs/strings": "0.75.
|
|
101
|
+
"@stacksjs/scheduler": "0.75.171",
|
|
102
|
+
"@stacksjs/search-engine": "0.75.171",
|
|
103
|
+
"@stacksjs/security": "0.75.171",
|
|
104
|
+
"@stacksjs/server": "0.75.171",
|
|
105
|
+
"@stacksjs/sites": "0.75.171",
|
|
106
|
+
"@stacksjs/storage": "0.75.171",
|
|
107
|
+
"@stacksjs/strings": "0.75.171",
|
|
108
108
|
"@stacksjs/stx": "^0.2.483",
|
|
109
109
|
"@stacksjs/tlsx": "^0.13.19",
|
|
110
110
|
"@stacksjs/ts-cloud": "^0.16.52",
|
|
111
111
|
"@stacksjs/ts-md": "^0.1.1",
|
|
112
|
-
"@stacksjs/tunnel": "0.75.
|
|
113
|
-
"@stacksjs/types": "0.75.
|
|
114
|
-
"@stacksjs/utils": "0.75.
|
|
115
|
-
"@stacksjs/whois": "0.75.
|
|
112
|
+
"@stacksjs/tunnel": "0.75.171",
|
|
113
|
+
"@stacksjs/types": "0.75.171",
|
|
114
|
+
"@stacksjs/utils": "0.75.171",
|
|
115
|
+
"@stacksjs/whois": "0.75.171",
|
|
116
116
|
"bun-plugin-stx": "^0.2.483"
|
|
117
117
|
},
|
|
118
118
|
"peerDependencies": {
|
|
119
|
-
"craft-native": ">=0.0.
|
|
119
|
+
"craft-native": ">=0.0.163",
|
|
120
120
|
"pickier": "^0.1.70"
|
|
121
121
|
},
|
|
122
122
|
"peerDependenciesMeta": {
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
}
|
|
129
129
|
},
|
|
130
130
|
"devDependencies": {
|
|
131
|
-
"@stacksjs/validation": "0.75.
|
|
131
|
+
"@stacksjs/validation": "0.75.171",
|
|
132
132
|
"better-dx": "^0.2.24"
|
|
133
133
|
}
|
|
134
134
|
}
|