craft-native 0.0.304 → 0.0.328
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/android/src/index.d.ts +3 -5
- package/dist/android/src/index.js +50 -7
- package/dist/android/templates/CraftBridge.kt.template +0 -90
- package/dist/android/templates/CraftNative.kt.template +3 -0
- package/dist/android/templates/CraftNativeBackground.kt.template +8 -2
- package/dist/android/templates/CraftNativeServices.kt.template +100 -1
- package/dist/android/templates/CraftNativeShell.kt.template +26 -8
- package/dist/android/templates/CraftPermissionPolicy.kt.template +96 -0
- package/dist/android/templates/MainActivityNative.kt.template +120 -6
- package/dist/android/templates/build.gradle.kts.app.template +1 -5
- package/dist/api/mobile.d.ts +9 -0
- package/dist/cli.js +63 -20
- package/dist/index.cjs +67 -20
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +67 -20
- package/dist/ios/src/index.d.ts +2 -5
- package/dist/ios/src/index.js +26 -1
- package/dist/ios/src/testing.d.ts +6 -0
- package/dist/ios/templates/CraftActivityAttributes.swift +29 -2
- package/dist/ios/templates/CraftApp.swift +45 -7
- package/dist/ios/templates/CraftHealth.swift +14 -0
- package/dist/ios/templates/CraftHybrid.swift +6 -0
- package/dist/ios/templates/CraftLiveActivities.swift +106 -2
- package/dist/ios/templates/CraftLiveActivityWidget.swift.template +1 -1
- package/dist/ios/templates/CraftNativeActions.swift +10 -1
- package/dist/ios/templates/CraftNativeScreen.swift +170 -9
- package/dist/ios/templates/CraftVoiceRecording.swift +75 -0
- package/dist/ios/templates/project.yml.template +6 -0
- package/dist/ios/templates/testing/DriverTests.swift.template +38 -0
- package/dist/package.d.ts +15 -4
- package/dist/types.d.ts +11 -4
- package/package.json +1 -1
|
@@ -864,6 +864,7 @@ internal class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
864
864
|
super.onWindowVisibilityChanged(visibility)
|
|
865
865
|
if (visibility != View.VISIBLE) celebration?.stop()
|
|
866
866
|
}
|
|
867
|
+
var pageViewport: Pair<Int, Int>? = null
|
|
867
868
|
var onLayoutChanged: (() -> Unit)? = null
|
|
868
869
|
private val styles = mutableMapOf<View, CraftNativeLayoutStyle>()
|
|
869
870
|
private var wrap = false
|
|
@@ -1839,6 +1840,12 @@ internal class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
1839
1840
|
}
|
|
1840
1841
|
|
|
1841
1842
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
|
1843
|
+
pageViewport?.let { (pageWidth, pageHeight) ->
|
|
1844
|
+
val pages = (0 until childCount).map { getChildAt(it) }.filter { it.visibility != View.GONE }
|
|
1845
|
+
pages.forEach { it.measure(MeasureSpec.makeMeasureSpec(pageWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(pageHeight, MeasureSpec.EXACTLY)) }
|
|
1846
|
+
setMeasuredDimension(pageWidth * pages.size, pageHeight)
|
|
1847
|
+
return
|
|
1848
|
+
}
|
|
1842
1849
|
val unboundedHorizontal = unboundedWidth && orientation == HORIZONTAL
|
|
1843
1850
|
val widthMode = if (unboundedHorizontal) View.MeasureSpec.UNSPECIFIED else View.MeasureSpec.getMode(widthMeasureSpec)
|
|
1844
1851
|
widthDefinite = widthMode == View.MeasureSpec.EXACTLY
|
|
@@ -1875,6 +1882,12 @@ internal class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
1875
1882
|
|
|
1876
1883
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
1877
1884
|
celebration?.layout()
|
|
1885
|
+
pageViewport?.let { (pageWidth, pageHeight) ->
|
|
1886
|
+
val pages = (0 until childCount).map { getChildAt(it) }.filter { it.visibility != View.GONE }
|
|
1887
|
+
pages.forEachIndexed { index, child -> child.layout(index * pageWidth, 0, (index + 1) * pageWidth, pageHeight) }
|
|
1888
|
+
onLayoutChanged?.invoke()
|
|
1889
|
+
return
|
|
1890
|
+
}
|
|
1878
1891
|
widthDefinite = true
|
|
1879
1892
|
if (grid) {
|
|
1880
1893
|
val layout = gridLayout(width, height)
|
|
@@ -2237,15 +2250,92 @@ private class CraftNativeKeyboardAvoidingView(context: Context) : FrameLayout(co
|
|
|
2237
2250
|
}
|
|
2238
2251
|
}
|
|
2239
2252
|
|
|
2240
|
-
|
|
2253
|
+
/** CSS family fallback order, using bundled app fonts before platform families. */
|
|
2254
|
+
internal fun craftNativeFontFamily(family: String?, bundledFonts: Map<String, Typeface> = emptyMap()): Typeface =
|
|
2255
|
+
family?.split(',')?.asSequence()?.map { it.trim().trim('"', '\'') }?.mapNotNull { name ->
|
|
2256
|
+
bundledFonts[name] ?: when (name.lowercase()) {
|
|
2257
|
+
"monospace", "ui-monospace" -> Typeface.MONOSPACE
|
|
2258
|
+
"serif", "ui-serif" -> Typeface.SERIF
|
|
2259
|
+
"sans-serif", "ui-sans-serif", "system-ui", "-apple-system" -> Typeface.SANS_SERIF
|
|
2260
|
+
else -> Typeface.create(name, Typeface.NORMAL).takeUnless { it == Typeface.DEFAULT }
|
|
2261
|
+
}
|
|
2262
|
+
}?.firstOrNull() ?: Typeface.DEFAULT
|
|
2263
|
+
|
|
2264
|
+
internal class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(context) {
|
|
2241
2265
|
val content = CraftNativeFlexLayout(context)
|
|
2242
2266
|
// Keep one refresh target across axis changes. Replacing all children of
|
|
2243
2267
|
// SwipeRefreshLayout would also detach its own animated indicator.
|
|
2244
2268
|
private val scrollContainer = FrameLayout(context)
|
|
2245
|
-
private val vertical = ScrollView(context)
|
|
2246
|
-
|
|
2269
|
+
private val vertical = object : ScrollView(context) {
|
|
2270
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean = isEnabled && super.onInterceptTouchEvent(event)
|
|
2271
|
+
override fun onTouchEvent(event: MotionEvent): Boolean = isEnabled && super.onTouchEvent(event)
|
|
2272
|
+
}
|
|
2273
|
+
private val horizontal = object : HorizontalScrollView(context) {
|
|
2274
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean = isEnabled && super.onInterceptTouchEvent(event)
|
|
2275
|
+
override fun onTouchEvent(event: MotionEvent): Boolean = isEnabled && super.onTouchEvent(event)
|
|
2276
|
+
}
|
|
2247
2277
|
private var horizontalMode: Boolean? = null
|
|
2248
2278
|
private var pagingEnabled = false
|
|
2279
|
+
private var authoredPageIndex: Int? = null
|
|
2280
|
+
private var pendingPageIndex: Int? = null
|
|
2281
|
+
private var currentPageIndex = 0
|
|
2282
|
+
private var reportedPage: Pair<Int, Int>? = null
|
|
2283
|
+
private var pageHandler: ((Int, Int) -> Unit)? = null
|
|
2284
|
+
private var pageSettleGeneration = 0
|
|
2285
|
+
private var pageDragging = false
|
|
2286
|
+
private var pageInMotion = false
|
|
2287
|
+
|
|
2288
|
+
private fun schedulePageSettle(scroller: View) {
|
|
2289
|
+
val generation = ++pageSettleGeneration
|
|
2290
|
+
scroller.postDelayed({
|
|
2291
|
+
if (generation == pageSettleGeneration && !pageDragging) {
|
|
2292
|
+
pageInMotion = false
|
|
2293
|
+
settlePage()
|
|
2294
|
+
}
|
|
2295
|
+
}, 80L)
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
fun configurePager(value: Any?, onSelect: ((Int, Int) -> Unit)?) {
|
|
2299
|
+
val next = (value as? Number)?.toDouble()?.takeIf { it.isFinite() }?.coerceIn(0.0, (Int.MAX_VALUE / 2).toDouble())?.toInt()
|
|
2300
|
+
if (next != authoredPageIndex) pendingPageIndex = next
|
|
2301
|
+
authoredPageIndex = next
|
|
2302
|
+
pageHandler = onSelect
|
|
2303
|
+
if (next == null) { content.pageViewport = null; reportedPage = null }
|
|
2304
|
+
requestLayout()
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
private fun settlePage() {
|
|
2308
|
+
if (authoredPageIndex == null || horizontal.width <= 0 || pageDragging || pageInMotion) return
|
|
2309
|
+
val pages = (0 until content.childCount).map { content.getChildAt(it) }.filter { it.visibility != View.GONE }
|
|
2310
|
+
val index = (horizontal.scrollX.toFloat() / horizontal.width).roundToInt().coerceIn(0, max(0, pages.size - 1))
|
|
2311
|
+
val target = index * horizontal.width
|
|
2312
|
+
if (horizontal.scrollX != target) {
|
|
2313
|
+
// ACTION_UP can start native motion after our touch listener's snap.
|
|
2314
|
+
// A rounded index is not settled until that viewport is fully shown.
|
|
2315
|
+
pageInMotion = true
|
|
2316
|
+
horizontal.smoothScrollTo(target, 0)
|
|
2317
|
+
schedulePageSettle(horizontal)
|
|
2318
|
+
return
|
|
2319
|
+
}
|
|
2320
|
+
currentPageIndex = index
|
|
2321
|
+
pages.forEachIndexed { i, page -> page.importantForAccessibility = if (i == index) View.IMPORTANT_FOR_ACCESSIBILITY_AUTO else View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS }
|
|
2322
|
+
val report = index to pages.size
|
|
2323
|
+
if (report != reportedPage) { reportedPage = report; pageHandler?.invoke(index, pages.size) }
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
2327
|
+
val oldWidth = horizontal.width
|
|
2328
|
+
super.onLayout(changed, left, top, right, bottom)
|
|
2329
|
+
if (authoredPageIndex != null && horizontalMode == true && horizontal.width > 0) {
|
|
2330
|
+
val count = (0 until content.childCount).count { content.getChildAt(it).visibility != View.GONE }
|
|
2331
|
+
val index = (pendingPageIndex ?: currentPageIndex).coerceIn(0, max(0, count - 1))
|
|
2332
|
+
if (pendingPageIndex != null || oldWidth != horizontal.width || index != currentPageIndex) horizontal.scrollTo(index * horizontal.width, 0)
|
|
2333
|
+
pendingPageIndex = null
|
|
2334
|
+
currentPageIndex = index
|
|
2335
|
+
settlePage()
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2249
2339
|
private var bounces = true
|
|
2250
2340
|
private var alwaysBounceVertical = true
|
|
2251
2341
|
private var alwaysBounceHorizontal = true
|
|
@@ -2273,6 +2363,10 @@ private class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(conte
|
|
|
2273
2363
|
// configured. Interception is gated below instead.
|
|
2274
2364
|
isEnabled = true
|
|
2275
2365
|
setHorizontal(false)
|
|
2366
|
+
// Paging is owned by this native control even before an Activity
|
|
2367
|
+
// supplies optional bridge callbacks. Its normal configuration may
|
|
2368
|
+
// replace these listeners without changing gesture ownership.
|
|
2369
|
+
setScrollListeners(null, null, null, null, null, "none", null)
|
|
2276
2370
|
}
|
|
2277
2371
|
|
|
2278
2372
|
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
|
@@ -2301,6 +2395,7 @@ private class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(conte
|
|
|
2301
2395
|
val unspecified = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
|
|
2302
2396
|
val horizontalPadding = paddingLeft + paddingRight
|
|
2303
2397
|
val verticalPadding = paddingTop + paddingBottom
|
|
2398
|
+
content.pageViewport = if (authoredPageIndex != null && sideways) max(0, widthSize - horizontalPadding) to max(0, heightSize - verticalPadding) else null
|
|
2304
2399
|
content.measure(
|
|
2305
2400
|
if (sideways || widthMode == MeasureSpec.UNSPECIFIED) unspecified
|
|
2306
2401
|
else MeasureSpec.makeMeasureSpec(max(0, widthSize - horizontalPadding), MeasureSpec.EXACTLY),
|
|
@@ -2316,7 +2411,7 @@ private class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(conte
|
|
|
2316
2411
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
2317
2412
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
2318
2413
|
)
|
|
2319
|
-
params.width = max(params.width, content.measuredWidth)
|
|
2414
|
+
params.width = if (authoredPageIndex != null) content.measuredWidth else max(params.width, content.measuredWidth)
|
|
2320
2415
|
content.layoutParams = params
|
|
2321
2416
|
}
|
|
2322
2417
|
fun fit(mode: Int, size: Int, wanted: Int): Int = when (mode) {
|
|
@@ -2648,11 +2743,18 @@ private class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(conte
|
|
|
2648
2743
|
|
|
2649
2744
|
scroller.setOnScrollChangeListener { _, x, y, _, _ ->
|
|
2650
2745
|
if (horizontalMode != true) updateStickyHeaders()
|
|
2746
|
+
if (authoredPageIndex != null) {
|
|
2747
|
+
pageInMotion = true
|
|
2748
|
+
schedulePageSettle(scroller)
|
|
2749
|
+
}
|
|
2651
2750
|
onScroll?.invoke(x, y)
|
|
2652
2751
|
}
|
|
2653
2752
|
scroller.setOnTouchListener { _, event ->
|
|
2654
2753
|
when (event.actionMasked) {
|
|
2655
2754
|
android.view.MotionEvent.ACTION_DOWN -> {
|
|
2755
|
+
pageDragging = true
|
|
2756
|
+
pageInMotion = false
|
|
2757
|
+
pageSettleGeneration += 1
|
|
2656
2758
|
if (momentumActive) {
|
|
2657
2759
|
momentumActive = false
|
|
2658
2760
|
onMomentumEnd?.invoke()
|
|
@@ -2674,6 +2776,8 @@ private class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(conte
|
|
|
2674
2776
|
}
|
|
2675
2777
|
onEndDrag?.invoke()
|
|
2676
2778
|
if (pagingEnabled) snapToPage(scroller)
|
|
2779
|
+
pageDragging = false
|
|
2780
|
+
if (authoredPageIndex != null) schedulePageSettle(scroller)
|
|
2677
2781
|
if (moved && !momentumActive) {
|
|
2678
2782
|
momentumActive = true
|
|
2679
2783
|
lastX = scroller.scrollX
|
|
@@ -2692,6 +2796,10 @@ private class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(conte
|
|
|
2692
2796
|
|
|
2693
2797
|
fun clearScrollListeners() {
|
|
2694
2798
|
scrollListenerGeneration += 1
|
|
2799
|
+
pageSettleGeneration += 1
|
|
2800
|
+
pageDragging = false
|
|
2801
|
+
pageInMotion = false
|
|
2802
|
+
pageHandler = null
|
|
2695
2803
|
vertical.setOnScrollChangeListener(null)
|
|
2696
2804
|
vertical.setOnTouchListener(null)
|
|
2697
2805
|
horizontal.setOnScrollChangeListener(null)
|
|
@@ -4868,7 +4976,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
4868
4976
|
val bars = chrome ?: return
|
|
4869
4977
|
val depth = screens.indexOf(screen).coerceAtLeast(0)
|
|
4870
4978
|
val fallback = if (depth == 0) routes.tabs.getOrNull(currentTab)?.title else null
|
|
4871
|
-
bars.apply(screen.options, depth, fallback)
|
|
4979
|
+
bars.apply(screen.options, depth, fallback, screen.path)
|
|
4872
4980
|
}
|
|
4873
4981
|
|
|
4874
4982
|
/** Applies a screen-specific background, falling back to the dynamic app colour. */
|
|
@@ -4932,6 +5040,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
4932
5040
|
put("viewReparent")
|
|
4933
5041
|
put("viewNonModalPresentation")
|
|
4934
5042
|
put("nativePlatformControls")
|
|
5043
|
+
put("nativePager")
|
|
4935
5044
|
}
|
|
4936
5045
|
|
|
4937
5046
|
private fun appVersion(): Pair<String, String> = runCatching {
|
|
@@ -6095,6 +6204,10 @@ class MainActivity : AppCompatActivity() {
|
|
|
6095
6204
|
craftNativeBoolean(props.opt("alwaysBounceHorizontal"), horizontal),
|
|
6096
6205
|
)
|
|
6097
6206
|
setPagingEnabled(craftNativeBoolean(props.opt("pagingEnabled")))
|
|
6207
|
+
val pageHandler = craftNativeEventName(events, "onPageSelected").takeIf { it.isNotBlank() }
|
|
6208
|
+
configurePager(props.opt("pageIndex"), pageHandler?.let { handler ->
|
|
6209
|
+
{ index, count -> send(screen, "EVENT", JSONObject().put("handlerName", handler).put("nativeEvent", JSONObject().put("index", index).put("count", count))) }
|
|
6210
|
+
})
|
|
6098
6211
|
val refreshNode = (0 until children.length()).asSequence()
|
|
6099
6212
|
.mapNotNull { children.optJSONObject(it) }
|
|
6100
6213
|
.firstOrNull { canonicalType(it.optString("type")) == "RefreshControl" }
|
|
@@ -6916,7 +7029,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6916
7029
|
}
|
|
6917
7030
|
val italic = craftNativeOptionalString(style.opt("fontStyle")) == "italic"
|
|
6918
7031
|
val family = craftNativeOptionalString(style.opt("fontFamily"))?.takeIf { it.isNotBlank() }
|
|
6919
|
-
val base =
|
|
7032
|
+
val base = craftNativeFontFamily(family, bundledFonts)
|
|
6920
7033
|
view.typeface = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
6921
7034
|
Typeface.create(base, weight, italic)
|
|
6922
7035
|
} else Typeface.create(base, (if (weight >= 600) Typeface.BOLD else Typeface.NORMAL) or
|
|
@@ -7555,6 +7668,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
7555
7668
|
}
|
|
7556
7669
|
|
|
7557
7670
|
override fun onPause() {
|
|
7671
|
+
if (::services.isInitialized) services.pauseVoice()
|
|
7558
7672
|
nativeAppState = "inactive"
|
|
7559
7673
|
publish("APP_STATE", JSONObject().put("state", nativeAppState))
|
|
7560
7674
|
super.onPause()
|
|
@@ -116,11 +116,7 @@ dependencies {
|
|
|
116
116
|
|
|
117
117
|
{{WALLET_DEPENDENCY}}
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
implementation("com.google.mlkit:barcode-scanning:17.3.0")
|
|
121
|
-
implementation("com.google.mlkit:image-labeling:17.0.9")
|
|
122
|
-
implementation("com.google.mlkit:object-detection:17.0.2")
|
|
123
|
-
implementation("com.google.mlkit:text-recognition:16.0.1")
|
|
119
|
+
{{MACHINE_LEARNING_DEPENDENCIES}}
|
|
124
120
|
|
|
125
121
|
// Google Play Billing (In-App Purchase)
|
|
126
122
|
implementation("com.android.billingclient:billing:6.1.0")
|
package/dist/api/mobile.d.ts
CHANGED
|
@@ -1844,6 +1844,15 @@ export declare const health: {
|
|
|
1844
1844
|
onHeartRate(callback: (samples: HealthHeartRateSample[]) => void): () => void;
|
|
1845
1845
|
};
|
|
1846
1846
|
export interface LiveActivityState {
|
|
1847
|
+
/** Native step boundaries retained on device; at most 1000, with detail limited to 96 characters. Only the current state is sent to the widget. */
|
|
1848
|
+
transitions?: Array<{
|
|
1849
|
+
at: number;
|
|
1850
|
+
detail: string;
|
|
1851
|
+
duration?: number | null;
|
|
1852
|
+
}>;
|
|
1853
|
+
/** An actual HealthKit workout (iOS 26+, already authorised) owns background updates. */
|
|
1854
|
+
workoutType?: string;
|
|
1855
|
+
sessionStartedAt?: number;
|
|
1847
1856
|
/** What to show once staleAt passes without fresh app state. */
|
|
1848
1857
|
staleStatus?: string;
|
|
1849
1858
|
/** Current step, interval or session detail. */
|
package/dist/cli.js
CHANGED
|
@@ -262,6 +262,7 @@ async function packageMacOS(config, outDir) {
|
|
|
262
262
|
iconPath: config.iconPath,
|
|
263
263
|
provisioningProfile: opts.provisioningProfile,
|
|
264
264
|
additionalExecutables: opts.additionalExecutables,
|
|
265
|
+
nativeRuntimePath: opts.nativeRuntimePath,
|
|
265
266
|
outputPath: appBundlePath
|
|
266
267
|
});
|
|
267
268
|
if (!appBundle.success) {
|
|
@@ -310,6 +311,12 @@ async function packageMacOS(config, outDir) {
|
|
|
310
311
|
} catch (error) {
|
|
311
312
|
return [{ success: false, platform: "macos", format: "app", error: error.message }];
|
|
312
313
|
}
|
|
314
|
+
if (opts.notarize && !opts.appStore) {
|
|
315
|
+
const notarized = await notarizeIfRequested(opts, appBundlePath, "app");
|
|
316
|
+
results.push(...notarized);
|
|
317
|
+
if (notarized.some((result) => !result.success))
|
|
318
|
+
return results;
|
|
319
|
+
}
|
|
313
320
|
results.push({ success: true, platform: "macos", format: "app", outputPath: appBundlePath });
|
|
314
321
|
if (opts.dmg !== false) {
|
|
315
322
|
const outputPath = join2(outDir, `${name}-${version}.dmg`);
|
|
@@ -358,24 +365,36 @@ async function notarizeIfRequested(opts, artifactPath, format) {
|
|
|
358
365
|
error: "Notarization requires a keychain profile, API key, or Apple ID/password/team ID"
|
|
359
366
|
}];
|
|
360
367
|
}
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
368
|
+
const scratch = format === "app" ? createTempDir("craft-notarize-") : undefined;
|
|
369
|
+
try {
|
|
370
|
+
const submission = scratch ? join2(scratch, "app.zip") : artifactPath;
|
|
371
|
+
if (scratch) {
|
|
372
|
+
const zipped = await runTool("ditto", ["-c", "-k", "--keepParent", artifactPath, submission]);
|
|
373
|
+
if (!zipped.success)
|
|
374
|
+
return [{ success: false, platform: "macos", format: `${format} (notarize)`, error: zipped.error }];
|
|
375
|
+
}
|
|
376
|
+
const submitted = await runTool("xcrun", notarytoolArguments({
|
|
377
|
+
artifactPath: submission,
|
|
378
|
+
appleId: opts.appleId,
|
|
379
|
+
applePassword: opts.applePassword,
|
|
380
|
+
teamId: opts.teamId,
|
|
381
|
+
keychainProfile: opts.notaryKeychainProfile,
|
|
382
|
+
apiKey: opts.notaryApiKey
|
|
383
|
+
}));
|
|
384
|
+
if (!submitted.success)
|
|
385
|
+
return [{ success: false, platform: "macos", format: `${format} (notarize)`, error: submitted.error }];
|
|
386
|
+
const stapled = await runTool("xcrun", ["stapler", "staple", artifactPath]);
|
|
387
|
+
return [{
|
|
388
|
+
success: stapled.success,
|
|
389
|
+
platform: "macos",
|
|
390
|
+
format: `${format} (notarize)`,
|
|
391
|
+
outputPath: stapled.success ? artifactPath : undefined,
|
|
392
|
+
error: stapled.success ? undefined : stapled.error
|
|
393
|
+
}];
|
|
394
|
+
} finally {
|
|
395
|
+
if (scratch)
|
|
396
|
+
removeTempDir(scratch);
|
|
397
|
+
}
|
|
379
398
|
}
|
|
380
399
|
async function packageWindows(config, outDir) {
|
|
381
400
|
const results = [];
|
|
@@ -543,7 +562,7 @@ ${schemes.length ? `MimeType=${schemes.map((scheme) => `x-scheme-handler/${schem
|
|
|
543
562
|
}
|
|
544
563
|
function macOSInfoPlist(metadata) {
|
|
545
564
|
const entries = [
|
|
546
|
-
["CFBundleExecutable", metadata.name],
|
|
565
|
+
["CFBundleExecutable", metadata.executableName || metadata.name],
|
|
547
566
|
["CFBundleIdentifier", metadata.bundleId],
|
|
548
567
|
["CFBundleName", metadata.name],
|
|
549
568
|
["CFBundleShortVersionString", metadata.version],
|
|
@@ -686,6 +705,9 @@ function copyMacOSAppBundle(source, destination) {
|
|
|
686
705
|
return { success: false, error: error.message };
|
|
687
706
|
}
|
|
688
707
|
}
|
|
708
|
+
function macOSRuntimeExecutablePath(appBundlePath) {
|
|
709
|
+
return join2(appBundlePath, "Contents", "Helpers", "CraftRuntime.app", "Contents", "MacOS", "craft");
|
|
710
|
+
}
|
|
689
711
|
function createMacOSAppBundle(opts) {
|
|
690
712
|
try {
|
|
691
713
|
const { name, binaryPath, iconPath, provisioningProfile, additionalExecutables, outputPath } = opts;
|
|
@@ -702,6 +724,27 @@ function createMacOSAppBundle(opts) {
|
|
|
702
724
|
copyFileSync(executable, destination);
|
|
703
725
|
chmodSync(destination, 493);
|
|
704
726
|
}
|
|
727
|
+
if (opts.nativeRuntimePath) {
|
|
728
|
+
const helper = macOSRuntimeExecutablePath(outputPath);
|
|
729
|
+
const helperContents = resolve(helper, "..", "..");
|
|
730
|
+
mkdirSync(join2(helperContents, "MacOS"), { recursive: true });
|
|
731
|
+
copyFileSync(opts.nativeRuntimePath, helper);
|
|
732
|
+
chmodSync(helper, 493);
|
|
733
|
+
if (iconPath) {
|
|
734
|
+
mkdirSync(join2(helperContents, "Resources"), { recursive: true });
|
|
735
|
+
copyFileSync(iconPath, join2(helperContents, "Resources", "icon.icns"));
|
|
736
|
+
}
|
|
737
|
+
writeFileSync3(join2(helperContents, "Info.plist"), macOSInfoPlist({
|
|
738
|
+
name,
|
|
739
|
+
executableName: "craft",
|
|
740
|
+
version: opts.version,
|
|
741
|
+
bundleId: `${opts.bundleId}.runtime`,
|
|
742
|
+
buildNumber: opts.buildNumber,
|
|
743
|
+
minimumSystemVersion: opts.minimumSystemVersion,
|
|
744
|
+
menuBarOnly: true,
|
|
745
|
+
iconName: iconPath ? "icon" : undefined
|
|
746
|
+
}));
|
|
747
|
+
}
|
|
705
748
|
let iconName;
|
|
706
749
|
if (iconPath) {
|
|
707
750
|
if (!existsSync4(iconPath))
|
|
@@ -2945,7 +2988,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
|
|
|
2945
2988
|
`);
|
|
2946
2989
|
}
|
|
2947
2990
|
// package.json
|
|
2948
|
-
var version = "0.0.
|
|
2991
|
+
var version = "0.0.328";
|
|
2949
2992
|
|
|
2950
2993
|
// bin/cli.ts
|
|
2951
2994
|
var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
|
package/dist/index.cjs
CHANGED
|
@@ -158,6 +158,7 @@ __export(exports_src, {
|
|
|
158
158
|
liveActivities: () => liveActivities,
|
|
159
159
|
loadURL: () => loadURL,
|
|
160
160
|
location: () => location,
|
|
161
|
+
macOSRuntimeExecutablePath: () => macOSRuntimeExecutablePath,
|
|
161
162
|
materialYou: () => materialYou,
|
|
162
163
|
media: () => media,
|
|
163
164
|
menuItem: () => menuItem,
|
|
@@ -374,7 +375,7 @@ function craftBinaryNotFoundMessage(triedPath) {
|
|
|
374
375
|
`);
|
|
375
376
|
}
|
|
376
377
|
// package.json
|
|
377
|
-
var version = "0.0.
|
|
378
|
+
var version = "0.0.328";
|
|
378
379
|
|
|
379
380
|
// src/sdk-version.ts
|
|
380
381
|
var SDK_VERSION = version;
|
|
@@ -627,6 +628,7 @@ async function packageMacOS(config, outDir) {
|
|
|
627
628
|
iconPath: config.iconPath,
|
|
628
629
|
provisioningProfile: opts.provisioningProfile,
|
|
629
630
|
additionalExecutables: opts.additionalExecutables,
|
|
631
|
+
nativeRuntimePath: opts.nativeRuntimePath,
|
|
630
632
|
outputPath: appBundlePath
|
|
631
633
|
});
|
|
632
634
|
if (!appBundle.success) {
|
|
@@ -675,6 +677,12 @@ async function packageMacOS(config, outDir) {
|
|
|
675
677
|
} catch (error) {
|
|
676
678
|
return [{ success: false, platform: "macos", format: "app", error: error.message }];
|
|
677
679
|
}
|
|
680
|
+
if (opts.notarize && !opts.appStore) {
|
|
681
|
+
const notarized = await notarizeIfRequested(opts, appBundlePath, "app");
|
|
682
|
+
results.push(...notarized);
|
|
683
|
+
if (notarized.some((result) => !result.success))
|
|
684
|
+
return results;
|
|
685
|
+
}
|
|
678
686
|
results.push({ success: true, platform: "macos", format: "app", outputPath: appBundlePath });
|
|
679
687
|
if (opts.dmg !== false) {
|
|
680
688
|
const outputPath = import_path.join(outDir, `${name}-${version}.dmg`);
|
|
@@ -723,24 +731,36 @@ async function notarizeIfRequested(opts, artifactPath, format) {
|
|
|
723
731
|
error: "Notarization requires a keychain profile, API key, or Apple ID/password/team ID"
|
|
724
732
|
}];
|
|
725
733
|
}
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
734
|
+
const scratch = format === "app" ? createTempDir("craft-notarize-") : undefined;
|
|
735
|
+
try {
|
|
736
|
+
const submission = scratch ? import_path.join(scratch, "app.zip") : artifactPath;
|
|
737
|
+
if (scratch) {
|
|
738
|
+
const zipped = await runTool("ditto", ["-c", "-k", "--keepParent", artifactPath, submission]);
|
|
739
|
+
if (!zipped.success)
|
|
740
|
+
return [{ success: false, platform: "macos", format: `${format} (notarize)`, error: zipped.error }];
|
|
741
|
+
}
|
|
742
|
+
const submitted = await runTool("xcrun", notarytoolArguments({
|
|
743
|
+
artifactPath: submission,
|
|
744
|
+
appleId: opts.appleId,
|
|
745
|
+
applePassword: opts.applePassword,
|
|
746
|
+
teamId: opts.teamId,
|
|
747
|
+
keychainProfile: opts.notaryKeychainProfile,
|
|
748
|
+
apiKey: opts.notaryApiKey
|
|
749
|
+
}));
|
|
750
|
+
if (!submitted.success)
|
|
751
|
+
return [{ success: false, platform: "macos", format: `${format} (notarize)`, error: submitted.error }];
|
|
752
|
+
const stapled = await runTool("xcrun", ["stapler", "staple", artifactPath]);
|
|
753
|
+
return [{
|
|
754
|
+
success: stapled.success,
|
|
755
|
+
platform: "macos",
|
|
756
|
+
format: `${format} (notarize)`,
|
|
757
|
+
outputPath: stapled.success ? artifactPath : undefined,
|
|
758
|
+
error: stapled.success ? undefined : stapled.error
|
|
759
|
+
}];
|
|
760
|
+
} finally {
|
|
761
|
+
if (scratch)
|
|
762
|
+
removeTempDir(scratch);
|
|
763
|
+
}
|
|
744
764
|
}
|
|
745
765
|
async function packageWindows(config, outDir) {
|
|
746
766
|
const results = [];
|
|
@@ -909,7 +929,7 @@ ${schemes.length ? `MimeType=${schemes.map((scheme) => `x-scheme-handler/${schem
|
|
|
909
929
|
}
|
|
910
930
|
function macOSInfoPlist(metadata) {
|
|
911
931
|
const entries = [
|
|
912
|
-
["CFBundleExecutable", metadata.name],
|
|
932
|
+
["CFBundleExecutable", metadata.executableName || metadata.name],
|
|
913
933
|
["CFBundleIdentifier", metadata.bundleId],
|
|
914
934
|
["CFBundleName", metadata.name],
|
|
915
935
|
["CFBundleShortVersionString", metadata.version],
|
|
@@ -1052,6 +1072,9 @@ function copyMacOSAppBundle(source, destination) {
|
|
|
1052
1072
|
return { success: false, error: error.message };
|
|
1053
1073
|
}
|
|
1054
1074
|
}
|
|
1075
|
+
function macOSRuntimeExecutablePath(appBundlePath) {
|
|
1076
|
+
return import_path.join(appBundlePath, "Contents", "Helpers", "CraftRuntime.app", "Contents", "MacOS", "craft");
|
|
1077
|
+
}
|
|
1055
1078
|
function createMacOSAppBundle(opts) {
|
|
1056
1079
|
try {
|
|
1057
1080
|
const { name, binaryPath, iconPath, provisioningProfile, additionalExecutables, outputPath } = opts;
|
|
@@ -1068,6 +1091,27 @@ function createMacOSAppBundle(opts) {
|
|
|
1068
1091
|
import_fs.copyFileSync(executable, destination);
|
|
1069
1092
|
import_fs.chmodSync(destination, 493);
|
|
1070
1093
|
}
|
|
1094
|
+
if (opts.nativeRuntimePath) {
|
|
1095
|
+
const helper = macOSRuntimeExecutablePath(outputPath);
|
|
1096
|
+
const helperContents = import_path.resolve(helper, "..", "..");
|
|
1097
|
+
import_fs.mkdirSync(import_path.join(helperContents, "MacOS"), { recursive: true });
|
|
1098
|
+
import_fs.copyFileSync(opts.nativeRuntimePath, helper);
|
|
1099
|
+
import_fs.chmodSync(helper, 493);
|
|
1100
|
+
if (iconPath) {
|
|
1101
|
+
import_fs.mkdirSync(import_path.join(helperContents, "Resources"), { recursive: true });
|
|
1102
|
+
import_fs.copyFileSync(iconPath, import_path.join(helperContents, "Resources", "icon.icns"));
|
|
1103
|
+
}
|
|
1104
|
+
import_fs.writeFileSync(import_path.join(helperContents, "Info.plist"), macOSInfoPlist({
|
|
1105
|
+
name,
|
|
1106
|
+
executableName: "craft",
|
|
1107
|
+
version: opts.version,
|
|
1108
|
+
bundleId: `${opts.bundleId}.runtime`,
|
|
1109
|
+
buildNumber: opts.buildNumber,
|
|
1110
|
+
minimumSystemVersion: opts.minimumSystemVersion,
|
|
1111
|
+
menuBarOnly: true,
|
|
1112
|
+
iconName: iconPath ? "icon" : undefined
|
|
1113
|
+
}));
|
|
1114
|
+
}
|
|
1071
1115
|
let iconName;
|
|
1072
1116
|
if (iconPath) {
|
|
1073
1117
|
if (!import_fs.existsSync(iconPath))
|
|
@@ -10884,6 +10928,9 @@ class AutoUpdater extends import_events3.EventEmitter {
|
|
|
10884
10928
|
if (this.isNewerVersion(this.cachedManifest.version, this.config.currentVersion)) {
|
|
10885
10929
|
this.updateInfo = this.cachedManifest;
|
|
10886
10930
|
this.emit("update-available", this.cachedManifest);
|
|
10931
|
+
if (this.config.autoDownload) {
|
|
10932
|
+
await this.downloadUpdate();
|
|
10933
|
+
}
|
|
10887
10934
|
return this.cachedManifest;
|
|
10888
10935
|
}
|
|
10889
10936
|
this.emit("update-not-available");
|
package/dist/index.d.cts
CHANGED
|
@@ -24,7 +24,7 @@ export declare function parseCraftVersionOutput(output: string): string;
|
|
|
24
24
|
* (#236).
|
|
25
25
|
*/
|
|
26
26
|
export declare function craftProcessFailedMessage(code: number | null, stderr: string, quiet: boolean): string;
|
|
27
|
-
export { packageApp, pack, type PackageConfig, type PackageResult } from './package.js';
|
|
27
|
+
export { packageApp, pack, macOSRuntimeExecutablePath, type PackageConfig, type PackageResult } from './package.js';
|
|
28
28
|
export { craftBinaryNotFoundMessage, resolveCraftBinary } from './binary-resolver.js';
|
|
29
29
|
export * from './utils/index.js';
|
|
30
30
|
export * from './api/index.js';
|
|
@@ -85,4 +85,4 @@ export declare function show(html: string, options?: WindowOptions): Promise<voi
|
|
|
85
85
|
* Quick helper to load a URL
|
|
86
86
|
*/
|
|
87
87
|
export declare function loadURL(url: string, options?: WindowOptions): Promise<void>;
|
|
88
|
-
export type { WindowOptions, CraftSidebarAPI, CraftNativeUIAPI, CraftContextMenuItem, CraftContextMenuResult, AppConfig, CraftTrayAPI, CraftWindowAPI, CraftAppAPI, CraftBridgeAPI, MenubarState, CraftTimersAPI, Permission, HapticType, CraftHapticsAPI, CameraOptions, PhotoPickerOptions, CraftMobileAPI, CraftFileSystemAPI, CraftFsWatchEvent, CraftFsWatchHandle, CraftDatabaseAPI, CraftHttpAPI, CraftCryptoAPI, CraftCapabilities, CapabilityNamespace, CapabilityNamespaceStatus, CapabilityAction, CraftPreferencesAPI, CraftPreferencesInfo, CraftSettingsAPI, PreferenceValue, CraftEventType, CraftEventMap, CraftEventHandler, CraftEventEmitter, IOSConfig, AndroidConfig, MacOSConfig, WindowsConfig, LinuxConfig, CraftAppConfig, } from './types.js';
|
|
88
|
+
export type { WindowOptions, CraftSidebarAPI, CraftNativeUIAPI, CraftContextMenuItem, CraftContextMenuResult, AppConfig, CraftTrayAPI, CraftWindowAPI, CraftAppAPI, CraftBridgeAPI, MenubarState, MenubarInitOptions, CraftTimersAPI, Permission, HapticType, CraftHapticsAPI, CameraOptions, PhotoPickerOptions, CraftMobileAPI, CraftFileSystemAPI, CraftFsWatchEvent, CraftFsWatchHandle, CraftDatabaseAPI, CraftHttpAPI, CraftCryptoAPI, CraftCapabilities, CapabilityNamespace, CapabilityNamespaceStatus, CapabilityAction, CraftPreferencesAPI, CraftPreferencesInfo, CraftSettingsAPI, PreferenceValue, CraftEventType, CraftEventMap, CraftEventHandler, CraftEventEmitter, IOSConfig, AndroidConfig, MacOSConfig, WindowsConfig, LinuxConfig, CraftAppConfig, } from './types.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export declare function parseCraftVersionOutput(output: string): string;
|
|
|
24
24
|
* (#236).
|
|
25
25
|
*/
|
|
26
26
|
export declare function craftProcessFailedMessage(code: number | null, stderr: string, quiet: boolean): string;
|
|
27
|
-
export { packageApp, pack, type PackageConfig, type PackageResult } from './package.js';
|
|
27
|
+
export { packageApp, pack, macOSRuntimeExecutablePath, type PackageConfig, type PackageResult } from './package.js';
|
|
28
28
|
export { craftBinaryNotFoundMessage, resolveCraftBinary } from './binary-resolver.js';
|
|
29
29
|
export * from './utils/index.js';
|
|
30
30
|
export * from './api/index.js';
|
|
@@ -85,4 +85,4 @@ export declare function show(html: string, options?: WindowOptions): Promise<voi
|
|
|
85
85
|
* Quick helper to load a URL
|
|
86
86
|
*/
|
|
87
87
|
export declare function loadURL(url: string, options?: WindowOptions): Promise<void>;
|
|
88
|
-
export type { WindowOptions, CraftSidebarAPI, CraftNativeUIAPI, CraftContextMenuItem, CraftContextMenuResult, AppConfig, CraftTrayAPI, CraftWindowAPI, CraftAppAPI, CraftBridgeAPI, MenubarState, CraftTimersAPI, Permission, HapticType, CraftHapticsAPI, CameraOptions, PhotoPickerOptions, CraftMobileAPI, CraftFileSystemAPI, CraftFsWatchEvent, CraftFsWatchHandle, CraftDatabaseAPI, CraftHttpAPI, CraftCryptoAPI, CraftCapabilities, CapabilityNamespace, CapabilityNamespaceStatus, CapabilityAction, CraftPreferencesAPI, CraftPreferencesInfo, CraftSettingsAPI, PreferenceValue, CraftEventType, CraftEventMap, CraftEventHandler, CraftEventEmitter, IOSConfig, AndroidConfig, MacOSConfig, WindowsConfig, LinuxConfig, CraftAppConfig, } from './types.js';
|
|
88
|
+
export type { WindowOptions, CraftSidebarAPI, CraftNativeUIAPI, CraftContextMenuItem, CraftContextMenuResult, AppConfig, CraftTrayAPI, CraftWindowAPI, CraftAppAPI, CraftBridgeAPI, MenubarState, MenubarInitOptions, CraftTimersAPI, Permission, HapticType, CraftHapticsAPI, CameraOptions, PhotoPickerOptions, CraftMobileAPI, CraftFileSystemAPI, CraftFsWatchEvent, CraftFsWatchHandle, CraftDatabaseAPI, CraftHttpAPI, CraftCryptoAPI, CraftCapabilities, CapabilityNamespace, CapabilityNamespaceStatus, CapabilityAction, CraftPreferencesAPI, CraftPreferencesInfo, CraftSettingsAPI, PreferenceValue, CraftEventType, CraftEventMap, CraftEventHandler, CraftEventEmitter, IOSConfig, AndroidConfig, MacOSConfig, WindowsConfig, LinuxConfig, CraftAppConfig, } from './types.js';
|