peachsim 0.1.2179 → 0.1.2182
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/cli/commands/package.ts +7 -2
- package/cli/commands/shell-url.ts +28 -22
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/bundle-channel.cjs +225 -85
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/config.mjs +1 -1
- package/dist-lib/detox/index.cjs +2 -2
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +140 -48
- package/dist-lib/expo-swift-metadata.cjs +1 -1
- package/dist-lib/expo-swift-metadata.mjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +201 -82
- package/dist-lib/host/fetch-proxy-handler.cjs +4 -4
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +4 -4
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +11 -3
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +4 -4
- package/dist-lib/native-app-identity-project.cjs +2 -2
- package/dist-lib/native-app-identity-project.mjs +2 -2
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/pdfium-raster.cjs +1 -1
- package/dist-lib/pdfium-raster.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/public-origins-lib-esm.json +24 -24
- package/dist-lib/public-origins-lib.json +53 -53
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/reap-browser.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +239 -176
- package/dist-lib/swift-compile.cjs +85 -16
- package/dist-lib/swift-compile.mjs +85 -16
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +2 -2
- package/dist-lib/swift-submit.mjs +2 -2
- package/dist-lib/swift-toolchain.cjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +87 -18
- package/dist-lib/vite.cjs +4 -4
- package/dist-lib/worklet-executable.cjs +1 -1
- package/dist-lib/worklet-executable.mjs +1 -1
- package/dist-types/packages/peach-engine/src/cli-companion.d.ts +1 -0
- package/dist-types/packages/peach-engine/src/ios/frame-art.d.ts +41 -0
- package/dist-types/packages/peach-engine/src/ios/frame-paint.d.ts +43 -0
- package/dist-types/packages/peach-engine/src/ios/frame-svg.d.ts +4 -0
- package/dist-types/packages/peach-engine/src/render-worker/map-command-channel.d.ts +14 -0
- package/kotlin/sdk.tar.gz +0 -0
- package/package.json +1 -1
- package/runtime-companion.json +1 -1
- package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UIScrollView.h +8 -25
- package/sdk/ios/System/Library/Frameworks/UIKitTypes.framework/Headers/UIKitTypes.h +26 -0
- package/src/expo-native-workspace.ts +17 -20
- package/src/expo-swift-bundle.ts +6 -1
- package/src/expo-swift-host.ts +35 -6
- package/src/expo-widgets-bundle.ts +12 -8
- package/src/expoSwiftContract.ts +3 -0
- package/src/kotlin-host.ts +10 -2
- package/src/native-bundles.ts +30 -10
- package/src/one-sdk/source.ts +10 -4
- package/src/one-sdk-bundle.ts +57 -24
- package/src/screenshots/frame-compose.ts +14 -109
- package/src/swift-compile.ts +105 -13
- package/src/swift-submit.ts +2 -1
- package/src/wasm-optimize.ts +13 -4
package/src/expo-swift-host.ts
CHANGED
|
@@ -1999,7 +1999,16 @@ function targetSettings(units: ExpoSwiftSourceUnit[]) {
|
|
|
1999
1999
|
return settings
|
|
2000
2000
|
}
|
|
2001
2001
|
|
|
2002
|
-
function
|
|
2002
|
+
function oneSDKStamp(oneSDK: ExpoSwiftPreparationOptions['oneSDK']): string {
|
|
2003
|
+
if (!oneSDK) return ''
|
|
2004
|
+
const hash = createHash('sha256')
|
|
2005
|
+
for (const files of [oneSDK.targets, oneSDK.entry])
|
|
2006
|
+
for (const [name, source] of [...files].sort(([a], [b]) => a.localeCompare(b)))
|
|
2007
|
+
hash.update(`${name}\0${source}\0`)
|
|
2008
|
+
return hash.digest('hex')
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
function expoEntry(units: ExpoSwiftSourceUnit[], oneSDK = false): string {
|
|
2003
2012
|
// an Objective-C bridge module registers with no Swift of its own
|
|
2004
2013
|
const namespaces = [...new Set(units.map((unit) => unit.namespace))]
|
|
2005
2014
|
.filter((namespace) => namespace !== 'PeachExpoApp')
|
|
@@ -2015,7 +2024,11 @@ function expoEntry(units: ExpoSwiftSourceUnit[]): string {
|
|
|
2015
2024
|
subscribers.length + handlers.length > 0
|
|
2016
2025
|
? `; PeachExpoRuntime.registerDelegates(subscribers: [${subscribers.join(', ')}], handlers: [${handlers.join(', ')}])`
|
|
2017
2026
|
: ''
|
|
2018
|
-
|
|
2027
|
+
// a One SDK host component marks its view; every other view is an Expo view
|
|
2028
|
+
const view = oneSDK
|
|
2029
|
+
? '@ViewBuilder func view(props: JSON) -> some View {\n if props["oneSDKHost"] != nil { OneSDKUIKitHost(props: props) } else { PeachExpoNativeView(props: props) }\n }'
|
|
2030
|
+
: 'func view(props: JSON) -> PeachExpoNativeView { PeachExpoNativeView(props: props) }'
|
|
2031
|
+
return `import SwiftUI\ninternal import ExpoModulesCore\n${bridgeModules.length ? 'import React\n' : ''}${oneSDK ? 'import One\nimport OneSDKBindings\n' : ''}${namespaces.map((namespace) => `import ${namespace}`).join('\n')}\n\n@main struct PeachExpoApp: PeachPackage {\n init() { MainActor.assumeIsolated { PeachExpoRuntime.register([${units.flatMap((unit) => unit.classes).join(', ')}])${delegates}${bridgeModules.length ? `; RCTModuleHost.register([${bridgeModules.join(', ')}])` : ''} } }\n ${view}\n}\n\n@_expose(wasm, "peach_expo_call")\n@_cdecl("peach_expo_call")\n@MainActor public func peachExpoCall(_ payload: UnsafePointer<UInt8>?, _ length: Int32) -> UnsafeMutablePointer<UInt8>? {\n PeachExpoRuntime.dispatch(payload, length)\n}\n`
|
|
2019
2032
|
}
|
|
2020
2033
|
|
|
2021
2034
|
// a compile outlives its client: a dropped open leaves the work running so the
|
|
@@ -2153,7 +2166,7 @@ export async function compileExpoSwiftModules(
|
|
|
2153
2166
|
installSwiftInputTrace()
|
|
2154
2167
|
let key: string
|
|
2155
2168
|
try {
|
|
2156
|
-
key = `${await discoveryKey(root, options.installedWorkspace, true, options.iosTarget, options.moduleRoot)}\0${options.only?.join(',') ?? ''}`
|
|
2169
|
+
key = `${await discoveryKey(root, options.installedWorkspace, true, options.iosTarget, options.moduleRoot)}\0${options.only?.join(',') ?? ''}\0${oneSDKStamp(options.oneSDK)}`
|
|
2157
2170
|
} catch {
|
|
2158
2171
|
return compileExpoSwiftModulesTraced(root, base, publishArtifact, options)
|
|
2159
2172
|
}
|
|
@@ -2406,11 +2419,23 @@ async function compileExpoSwiftModulesTraced(
|
|
|
2406
2419
|
throw new Error(`conflicting Expo Swift binary source ${name}`)
|
|
2407
2420
|
files[name] = source
|
|
2408
2421
|
}
|
|
2409
|
-
|
|
2422
|
+
const settings = targetSettings(linked)
|
|
2423
|
+
if (options.oneSDK) {
|
|
2424
|
+
for (const [name, source] of options.oneSDK.targets) files[name] = source
|
|
2425
|
+
for (const [name, source] of options.oneSDK.entry)
|
|
2426
|
+
files[`Sources/PeachExpoApp/${name}`] = source
|
|
2427
|
+
settings.set('OneSDKBindings', {
|
|
2428
|
+
languageMode: 5,
|
|
2429
|
+
mainActorIsolation: false,
|
|
2430
|
+
swiftFlags: ['-suppress-warnings'],
|
|
2431
|
+
dependencies: [{ kind: 'target', name: 'One' }],
|
|
2432
|
+
})
|
|
2433
|
+
}
|
|
2434
|
+
files[EXPO_SWIFT_ENTRY] = expoEntry(linked, options.oneSDK !== undefined)
|
|
2410
2435
|
files['Package.swift'] = expoManifest(
|
|
2411
2436
|
files,
|
|
2412
2437
|
linked.map((unit) => generations.get(unit) ?? '').join(','),
|
|
2413
|
-
|
|
2438
|
+
settings,
|
|
2414
2439
|
)
|
|
2415
2440
|
const provider = linked.some((unit) => unit.reactNativeProvider)
|
|
2416
2441
|
? reactProvider
|
|
@@ -2648,7 +2673,11 @@ async function compileExpoSwiftModulesTraced(
|
|
|
2648
2673
|
stamps.set(unit, stamp)
|
|
2649
2674
|
candidates.push(unit)
|
|
2650
2675
|
}
|
|
2651
|
-
const preparedKey = expoSwiftPreparedKey(
|
|
2676
|
+
const preparedKey = expoSwiftPreparedKey(
|
|
2677
|
+
base,
|
|
2678
|
+
units,
|
|
2679
|
+
reactProviderStamp + oneSDKStamp(options.oneSDK),
|
|
2680
|
+
)
|
|
2652
2681
|
if (!publishArtifact) {
|
|
2653
2682
|
const prepared = preparedExpoSwift.get(preparedKey)
|
|
2654
2683
|
if (prepared) {
|
|
@@ -5,6 +5,7 @@ import path from 'node:path'
|
|
|
5
5
|
import { promisify } from 'node:util'
|
|
6
6
|
import { stageExpoWidgetAssets } from './expo-widget-assets'
|
|
7
7
|
import { compiledModuleRequestHandler } from './nitro-bundle'
|
|
8
|
+
import { withSwiftRootLock } from './swift-root-lock'
|
|
8
9
|
import type { ExpoWidgetExtension } from '../../peach-engine/src/render-worker/expo-widgetContract'
|
|
9
10
|
|
|
10
11
|
export const EXPO_WIDGETS_ROUTE = '/__peach/expo-widgets'
|
|
@@ -29,18 +30,21 @@ export async function buildExpoWidgetsBundle(
|
|
|
29
30
|
// output path. 58 reads an optional platform and output and otherwise writes
|
|
30
31
|
// the same package bundle, so one root argument covers both.
|
|
31
32
|
const packageDir = path.dirname(manifest)
|
|
32
|
-
await
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const runtimeBundle = await withSwiftRootLock(
|
|
34
|
+
path.join(await fs.realpath(packageDir), 'bundle'),
|
|
35
|
+
async () => {
|
|
36
|
+
await promisify(execFile)(
|
|
37
|
+
process.env.NODE_BINARY || 'node',
|
|
38
|
+
[path.join(packageDir, 'scripts/build-bundle.mjs'), appRoot],
|
|
39
|
+
{ cwd: appRoot, maxBuffer: 16 * 1024 * 1024 },
|
|
40
|
+
)
|
|
41
|
+
return fs.readFile(path.join(packageDir, 'bundle/build/ExpoWidgets.bundle'), 'utf8')
|
|
42
|
+
},
|
|
36
43
|
)
|
|
37
44
|
const catalog = await stageExpoWidgetAssets(appRoot, origin)
|
|
38
45
|
return {
|
|
39
46
|
metadata: {
|
|
40
|
-
runtimeBundle
|
|
41
|
-
path.join(packageDir, 'bundle/build/ExpoWidgets.bundle'),
|
|
42
|
-
'utf8',
|
|
43
|
-
),
|
|
47
|
+
runtimeBundle,
|
|
44
48
|
images: catalog?.images ?? {},
|
|
45
49
|
},
|
|
46
50
|
}
|
package/src/expoSwiftContract.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
import { isRecord } from './is-record'
|
|
6
6
|
import { isNativeAppIdentity, type NativeAppIdentity } from './native-app-identity'
|
|
7
7
|
import { isSwiftResourcePath } from './swiftContract'
|
|
8
|
+
import type { OneSDKLinkSources } from './one-sdk-bundle'
|
|
8
9
|
import type {
|
|
9
10
|
SwiftNativeTarget,
|
|
10
11
|
SwiftHeaderAliases,
|
|
@@ -19,6 +20,8 @@ export interface ExpoSwiftPreparationOptions {
|
|
|
19
20
|
moduleRoot?: string
|
|
20
21
|
// compile only these Swift modules and the modules they import
|
|
21
22
|
only?: readonly string[]
|
|
23
|
+
// the app's One SDK, linked into the same executable: one process per app
|
|
24
|
+
oneSDK?: Pick<OneSDKLinkSources, 'targets' | 'entry'>
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export interface ExpoSwiftSourceOptions {
|
package/src/kotlin-host.ts
CHANGED
|
@@ -131,7 +131,11 @@ function entrySource(ids: string[]): string {
|
|
|
131
131
|
'',
|
|
132
132
|
'@OptIn(kotlin.js.ExperimentalJsExport::class)',
|
|
133
133
|
'@JsExport',
|
|
134
|
-
'fun
|
|
134
|
+
'fun peachSetAndroidDeviceInfo(model: String, release: String, apiLevel: Int, locale: String, timeZone: String) {',
|
|
135
|
+
' Build.setDevice(model, release, apiLevel)',
|
|
136
|
+
' java.util.Locale.setDefault(java.util.Locale.forLanguageTag(locale))',
|
|
137
|
+
' java.util.TimeZone.setDevice(timeZone)',
|
|
138
|
+
'}',
|
|
135
139
|
'',
|
|
136
140
|
'@OptIn(kotlin.js.ExperimentalJsExport::class, kotlinx.coroutines.DelicateCoroutinesApi::class)',
|
|
137
141
|
'@JsExport',
|
|
@@ -726,8 +730,12 @@ export async function expoKotlinArtifact(
|
|
|
726
730
|
' ))',
|
|
727
731
|
'}',
|
|
728
732
|
'',
|
|
729
|
-
'@JsExport fun
|
|
733
|
+
'@JsExport fun peachSetAndroidDeviceInfo(model: String, release: String, apiLevel: Int, locale: String, timeZone: String) {',
|
|
730
734
|
' android.os.Build.setDevice(model, release, apiLevel)',
|
|
735
|
+
' java.util.Locale.setDefault(java.util.Locale.forLanguageTag(locale))',
|
|
736
|
+
' java.util.TimeZone.setDevice(timeZone)',
|
|
737
|
+
' PeachExpoRuntime.configureProcessLocale(locale)',
|
|
738
|
+
'}',
|
|
731
739
|
'',
|
|
732
740
|
'@JsExport fun peachExpoListen(notify: () -> Unit) {',
|
|
733
741
|
' registered',
|
package/src/native-bundles.ts
CHANGED
|
@@ -47,17 +47,37 @@ export async function buildNativeBundles(
|
|
|
47
47
|
configuration: 'Debug' | 'Release',
|
|
48
48
|
): Promise<NativeBundles> {
|
|
49
49
|
return getRuntimePlatformAdapter(platform).select<() => Promise<NativeBundles>>({
|
|
50
|
-
ios: async () =>
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
ios: async () => {
|
|
51
|
+
const { appOneSDKLinkSources, buildOneSDKBundle } = await import('./one-sdk-bundle')
|
|
52
|
+
// on iOS an app is one process: its One SDK links into the Expo executable
|
|
53
|
+
// when the app has one, and its process serves both
|
|
54
|
+
const oneSDK = await appOneSDKLinkSources(projectRoot)
|
|
55
|
+
const expoSwift = await (
|
|
53
56
|
await import('./expo-swift-bundle')
|
|
54
|
-
).buildExpoSwiftBundle(projectRoot)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
).buildExpoSwiftBundle(projectRoot, oneSDK ?? undefined)
|
|
58
|
+
const linked = oneSDK && expoSwift?.metadata.modules[0]
|
|
59
|
+
return {
|
|
60
|
+
oneSDK: linked
|
|
61
|
+
? {
|
|
62
|
+
metadata: {
|
|
63
|
+
url: linked.url,
|
|
64
|
+
hash: linked.hash,
|
|
65
|
+
icuUrl: linked.icuUrl,
|
|
66
|
+
rootId: `${linked.rootId.split('/')[0]}/OneSDK`,
|
|
67
|
+
bundleFiles: linked.bundleFiles ?? {},
|
|
68
|
+
modules: oneSDK.modules,
|
|
69
|
+
},
|
|
70
|
+
assets: [],
|
|
71
|
+
}
|
|
72
|
+
: await buildOneSDKBundle(projectRoot),
|
|
73
|
+
expoSwift,
|
|
74
|
+
nitro: await (
|
|
75
|
+
await import('./nitro-bundle')
|
|
76
|
+
).buildNitroBundle(projectRoot, configuration),
|
|
77
|
+
turbo: await (await import('./turbo-bundle')).buildTurboBundle(projectRoot),
|
|
78
|
+
expoKotlin: null,
|
|
79
|
+
}
|
|
80
|
+
},
|
|
61
81
|
android: async () => ({
|
|
62
82
|
oneSDK: null,
|
|
63
83
|
expoSwift: null,
|
package/src/one-sdk/source.ts
CHANGED
|
@@ -30,12 +30,13 @@ extension OneNativeComposable {
|
|
|
30
30
|
}
|
|
31
31
|
`
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
// the view a One SDK host component mounts, in whichever executable links the
|
|
34
|
+
// app's One SDK
|
|
35
|
+
export const oneSDKHost = String.raw`import SwiftUI
|
|
34
36
|
@_spi(Peach) import UIKit
|
|
35
37
|
import One
|
|
36
|
-
import OneSDKBindings
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
struct OneSDKUIKitHost: UIViewRepresentable {
|
|
39
40
|
let props: JSON
|
|
40
41
|
func makeUIView(context: Context) -> OneNativeUIKitHostView { OneNativeUIKitHostView() }
|
|
41
42
|
func updateUIView(_ view: OneNativeUIKitHostView, context: Context) {
|
|
@@ -47,10 +48,15 @@ private struct UIKitHost: UIViewRepresentable {
|
|
|
47
48
|
}
|
|
48
49
|
static func dismantleUIView(_ view: OneNativeUIKitHostView, coordinator: Coordinator) { view.reset() }
|
|
49
50
|
}
|
|
51
|
+
`
|
|
52
|
+
|
|
53
|
+
export const oneSDKApp = String.raw`import SwiftUI
|
|
54
|
+
import One
|
|
55
|
+
import OneSDKBindings
|
|
50
56
|
|
|
51
57
|
@main
|
|
52
58
|
struct SDKGuest: PeachPackage {
|
|
53
|
-
func view(props: JSON) -> some View {
|
|
59
|
+
func view(props: JSON) -> some View { OneSDKUIKitHost(props: props) }
|
|
54
60
|
}
|
|
55
61
|
`
|
|
56
62
|
|
package/src/one-sdk-bundle.ts
CHANGED
|
@@ -4,7 +4,7 @@ import path from 'node:path'
|
|
|
4
4
|
import { prepareExpoNativeProject } from './expo-native-workspace'
|
|
5
5
|
import { compiledModuleAssets, compiledModuleRequestHandler } from './nitro-bundle'
|
|
6
6
|
import { selectOneSDK } from './one-sdk-preparation'
|
|
7
|
-
import { oneSDKApp, oneSDKModule, oneSDKTransport } from './one-sdk/source'
|
|
7
|
+
import { oneSDKApp, oneSDKHost, oneSDKModule, oneSDKTransport } from './one-sdk/source'
|
|
8
8
|
import { ONE_SDK_SOURCE_DIRECTORY, readOneSDKSourceManifest } from './oneSdkContract'
|
|
9
9
|
import { syncSwiftTree } from './swift-compile'
|
|
10
10
|
import { resolveSwiftModule } from './swift-distribution'
|
|
@@ -24,12 +24,19 @@ export async function compileOneSDKApp(
|
|
|
24
24
|
return compilePreparedOneSDKApp(appRoot, prepared.app, origin, moduleRootOverride)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
// the One and OneSDKBindings targets an executable links for the app's One SDK
|
|
28
|
+
// imports, the host view and transport its executable target adds, and the
|
|
29
|
+
// module names the bundle registers
|
|
30
|
+
export interface OneSDKLinkSources {
|
|
31
|
+
targets: Map<string, string>
|
|
32
|
+
entry: Map<string, string>
|
|
33
|
+
modules: string[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function oneSDKLinkSources(
|
|
28
37
|
appRoot: string,
|
|
29
38
|
preparedRoot: string,
|
|
30
|
-
|
|
31
|
-
moduleRootOverride?: string,
|
|
32
|
-
) {
|
|
39
|
+
): Promise<OneSDKLinkSources> {
|
|
33
40
|
const selected = await selectOneSDK(appRoot)
|
|
34
41
|
if (!selected) throw new Error('prepared app has no One SDK imports')
|
|
35
42
|
const { one, frameworks } = selected
|
|
@@ -47,6 +54,47 @@ export async function compilePreparedOneSDKApp(
|
|
|
47
54
|
throw new Error(
|
|
48
55
|
'prepared One SDK sources differ from the installed facades or app imports',
|
|
49
56
|
)
|
|
57
|
+
const targets = new Map<string, string>()
|
|
58
|
+
targets.set('Sources/One/One.swift', oneSDKModule)
|
|
59
|
+
for (const source of [
|
|
60
|
+
'SDK/OneSDKRuntime.swift',
|
|
61
|
+
'OneNativeUIKitHostView.swift',
|
|
62
|
+
'OneNativeContent.swift',
|
|
63
|
+
'OneNativeAccessibility.swift',
|
|
64
|
+
'SDKViews/OneNativeViewsTable.swift',
|
|
65
|
+
])
|
|
66
|
+
targets.set(
|
|
67
|
+
`Sources/One/${path.basename(source)}`,
|
|
68
|
+
fs.readFileSync(path.join(one, 'ios', source), 'utf8'),
|
|
69
|
+
)
|
|
70
|
+
for (const name of generated.files)
|
|
71
|
+
targets.set(
|
|
72
|
+
`Sources/OneSDKBindings/${name}`,
|
|
73
|
+
fs.readFileSync(path.join(sourceRoot, name), 'utf8'),
|
|
74
|
+
)
|
|
75
|
+
return {
|
|
76
|
+
targets,
|
|
77
|
+
entry: new Map([
|
|
78
|
+
['OneSDKHost.swift', oneSDKHost],
|
|
79
|
+
['OneSDKTransport.swift', oneSDKTransport],
|
|
80
|
+
]),
|
|
81
|
+
modules: frameworks.map((name) => `${name}_${generated.generation}`),
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// the app's One SDK sources, when it imports One's SDK
|
|
86
|
+
export async function appOneSDKLinkSources(appRoot: string) {
|
|
87
|
+
if (!(await selectOneSDK(appRoot))) return null
|
|
88
|
+
return oneSDKLinkSources(appRoot, (await prepareExpoNativeProject(appRoot)).app)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function compilePreparedOneSDKApp(
|
|
92
|
+
appRoot: string,
|
|
93
|
+
preparedRoot: string,
|
|
94
|
+
origin: string,
|
|
95
|
+
moduleRootOverride?: string,
|
|
96
|
+
) {
|
|
97
|
+
const sources = await oneSDKLinkSources(appRoot, preparedRoot)
|
|
50
98
|
const moduleRoot = moduleRootOverride ?? (await resolveSwiftModule()).root
|
|
51
99
|
const packagePath = path.join(
|
|
52
100
|
swiftCacheDir(),
|
|
@@ -66,25 +114,9 @@ let package = Package(name: "OneSDKGuest", targets: [
|
|
|
66
114
|
])
|
|
67
115
|
`,
|
|
68
116
|
)
|
|
69
|
-
files.set(
|
|
70
|
-
for (const source of
|
|
71
|
-
'SDK/OneSDKRuntime.swift',
|
|
72
|
-
'OneNativeUIKitHostView.swift',
|
|
73
|
-
'OneNativeContent.swift',
|
|
74
|
-
'OneNativeAccessibility.swift',
|
|
75
|
-
'SDKViews/OneNativeViewsTable.swift',
|
|
76
|
-
])
|
|
77
|
-
files.set(
|
|
78
|
-
`Sources/One/${path.basename(source)}`,
|
|
79
|
-
fs.readFileSync(path.join(one, 'ios', source), 'utf8'),
|
|
80
|
-
)
|
|
81
|
-
for (const name of generated.files)
|
|
82
|
-
files.set(
|
|
83
|
-
`Sources/OneSDKBindings/${name}`,
|
|
84
|
-
fs.readFileSync(path.join(sourceRoot, name), 'utf8'),
|
|
85
|
-
)
|
|
117
|
+
for (const [name, source] of sources.targets) files.set(name, source)
|
|
118
|
+
for (const [name, source] of sources.entry) files.set(`Sources/App/${name}`, source)
|
|
86
119
|
files.set('Sources/App/App.swift', oneSDKApp)
|
|
87
|
-
files.set('Sources/App/Transport.swift', oneSDKTransport)
|
|
88
120
|
fs.mkdirSync(packagePath, { recursive: true })
|
|
89
121
|
syncSwiftTree(
|
|
90
122
|
packagePath,
|
|
@@ -92,6 +124,7 @@ let package = Package(name: "OneSDKGuest", targets: [
|
|
|
92
124
|
)
|
|
93
125
|
const project = projectFor(packagePath)
|
|
94
126
|
project.oneModule = false
|
|
127
|
+
project.optimize = true
|
|
95
128
|
const artifact = await artifactFor(project, 'Sources/App/App.swift', moduleRoot)
|
|
96
129
|
const metadata: OneSDKCompilation = {
|
|
97
130
|
url: `${origin}/__peach/swift/${artifact.hash}.wasm`,
|
|
@@ -99,7 +132,7 @@ let package = Package(name: "OneSDKGuest", targets: [
|
|
|
99
132
|
icuUrl: icuUrl(origin, artifact),
|
|
100
133
|
rootId: `one-sdk-${artifact.hash.slice(0, 16)}`,
|
|
101
134
|
bundleFiles: artifact.package.bundleFiles.files,
|
|
102
|
-
modules:
|
|
135
|
+
modules: sources.modules,
|
|
103
136
|
}
|
|
104
137
|
return { metadata, artifact }
|
|
105
138
|
}
|
|
@@ -2,9 +2,8 @@ import { launchProvisionedPlaywright } from '../../cli/drivers/playwright-provis
|
|
|
2
2
|
import { getCliRuntime } from '../cli-runtime.ts'
|
|
3
3
|
import { cornerRadii, type CornerRadii, type DeviceModel } from '../device-catalog.ts'
|
|
4
4
|
import type { HousingLayer } from '#peach-cli-contract/ios/duo-housing'
|
|
5
|
+
import type { FramePaintSpec } from '#peach-cli-contract/ios/frame-paint'
|
|
5
6
|
|
|
6
|
-
const METALLIC_RING_SHADOW =
|
|
7
|
-
'inset 0 0 0 0.5px #000, inset 0 0 0 2px #757575, inset 0 0 0 5px #212121'
|
|
8
7
|
const FRAME_OUTLINE_BLEED = 1
|
|
9
8
|
|
|
10
9
|
type FrameButtonLayout = {
|
|
@@ -40,9 +39,7 @@ export interface FramedScreenshotLayout {
|
|
|
40
39
|
logicalFrameRadius: CornerRadii
|
|
41
40
|
// folding body art, painted before the screen; null draws one black body
|
|
42
41
|
housingLayers: HousingLayer[] | null
|
|
43
|
-
frameBackground: string
|
|
44
42
|
frameOutline: string
|
|
45
|
-
metallicRingShadow: string | null
|
|
46
43
|
buttons: FrameButtonLayout[]
|
|
47
44
|
legacyHomeButton: LegacyHomeButtonLayout | null
|
|
48
45
|
showHomeIndicator: boolean
|
|
@@ -149,17 +146,11 @@ export function getFramedScreenshotLayout(model: DeviceModel): FramedScreenshotL
|
|
|
149
146
|
housingLayers,
|
|
150
147
|
// the housing paints its own body layer, shadow included: its frame box is
|
|
151
148
|
// wider than the body, because the hinge barrel protrudes past the spine.
|
|
152
|
-
frameBackground: isLegacyHardware
|
|
153
|
-
? 'linear-gradient(180deg, #1b1c20 0%, #0f1012 42%, #050608 100%)'
|
|
154
|
-
: housingLayers
|
|
155
|
-
? 'transparent'
|
|
156
|
-
: '#000000',
|
|
157
149
|
frameOutline: isLegacyHardware
|
|
158
150
|
? '0 0 0 1px #1f2125'
|
|
159
151
|
: housingLayers
|
|
160
152
|
? 'none'
|
|
161
153
|
: '0 0 0 1px #333',
|
|
162
|
-
metallicRingShadow: isLegacyHardware || housingLayers ? null : METALLIC_RING_SHADOW,
|
|
163
154
|
buttons,
|
|
164
155
|
legacyHomeButton: isLegacyHardware
|
|
165
156
|
? {
|
|
@@ -182,69 +173,22 @@ export function getFramedScreenshotLayout(model: DeviceModel): FramedScreenshotL
|
|
|
182
173
|
}
|
|
183
174
|
}
|
|
184
175
|
|
|
185
|
-
function renderSideButtonHtml(button: FrameButtonLayout): string {
|
|
186
|
-
const isRight = button.side === 'right'
|
|
187
|
-
const isBottom = button.side === 'bottom'
|
|
188
|
-
const horizontal = button.side === 'top' || isBottom
|
|
189
|
-
const clip = horizontal
|
|
190
|
-
? isBottom
|
|
191
|
-
? 'inset(0 -3px -3px -3px)'
|
|
192
|
-
: 'inset(-3px -3px 0 -3px)'
|
|
193
|
-
: isRight
|
|
194
|
-
? 'inset(-3px -3px -3px 0)'
|
|
195
|
-
: 'inset(-3px 0 -3px -3px)'
|
|
196
|
-
return `
|
|
197
|
-
<div
|
|
198
|
-
aria-hidden="true"
|
|
199
|
-
style="
|
|
200
|
-
position:absolute;
|
|
201
|
-
${
|
|
202
|
-
horizontal
|
|
203
|
-
? `left:${button.top}px;${isBottom ? `bottom:-${button.width}px;` : `top:-${button.width}px;`}`
|
|
204
|
-
: `${isRight ? `right:-${button.width}px;` : `left:-${button.width}px;`}top:${button.top}px;`
|
|
205
|
-
}
|
|
206
|
-
width:${horizontal ? button.height : button.width}px;
|
|
207
|
-
height:${horizontal ? button.width : button.height}px;
|
|
208
|
-
background-color:#212121;
|
|
209
|
-
border-top-left-radius:${isRight || isBottom ? 0 : 1.5}px;
|
|
210
|
-
border-bottom-left-radius:${isRight || button.side === 'top' ? 0 : 1.5}px;
|
|
211
|
-
border-top-right-radius:${button.side === 'left' || isBottom ? 0 : 1.5}px;
|
|
212
|
-
border-bottom-right-radius:${button.side === 'left' || button.side === 'top' ? 0 : 1.5}px;
|
|
213
|
-
box-shadow:
|
|
214
|
-
inset 0 0.5px 0 #616161,
|
|
215
|
-
inset 0 -0.5px 0 #3F3F3F,
|
|
216
|
-
${isRight ? 'inset -0.5px 0 0 #3F3F3F,' : 'inset 0.5px 0 0 #3F3F3F,'}
|
|
217
|
-
0 0 0 0.5px #676767,
|
|
218
|
-
0 0 0 1.5px #000;
|
|
219
|
-
clip-path:${clip};
|
|
220
|
-
pointer-events:none;
|
|
221
|
-
z-index:2;
|
|
222
|
-
"
|
|
223
|
-
></div>
|
|
224
|
-
`
|
|
225
|
-
}
|
|
226
|
-
|
|
227
176
|
function renderFrameHtml(
|
|
228
177
|
layout: FramedScreenshotLayout,
|
|
229
178
|
rawImageDataUrl: string,
|
|
230
179
|
): string {
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
z-index:10;
|
|
244
|
-
"
|
|
245
|
-
></div>
|
|
246
|
-
`
|
|
247
|
-
: ''
|
|
180
|
+
const painter = getCliRuntime().ios_frame_svg
|
|
181
|
+
const paintSpec = {
|
|
182
|
+
width: layout.logicalFrameWidth,
|
|
183
|
+
height: layout.logicalFrameHeight,
|
|
184
|
+
radii: layout.logicalFrameRadius,
|
|
185
|
+
body: layout.legacyHomeButton ? 'legacy' : layout.housingLayers ? null : 'solid',
|
|
186
|
+
ring: layout.legacyHomeButton || layout.housingLayers ? null : painter.METALLIC_RING,
|
|
187
|
+
buttons: layout.buttons
|
|
188
|
+
.filter((button) => button.height > 0)
|
|
189
|
+
.map((button) => ({ ...button, hover: 0 })),
|
|
190
|
+
home: layout.legacyHomeButton,
|
|
191
|
+
} satisfies FramePaintSpec
|
|
248
192
|
|
|
249
193
|
// the folding body's rail, glass ring, corner art, and hinge barrel. no
|
|
250
194
|
// z-index, so the screen div after it paints on top.
|
|
@@ -252,42 +196,6 @@ function renderFrameHtml(
|
|
|
252
196
|
.map(getCliRuntime().ios_duo_housing.housingLayerHtml)
|
|
253
197
|
.join('')
|
|
254
198
|
|
|
255
|
-
const legacyHomeButtonHtml = layout.legacyHomeButton
|
|
256
|
-
? `
|
|
257
|
-
<div
|
|
258
|
-
aria-hidden="true"
|
|
259
|
-
style="
|
|
260
|
-
position:absolute;
|
|
261
|
-
top:${layout.legacyHomeButton.top}px;
|
|
262
|
-
left:${layout.legacyHomeButton.left}px;
|
|
263
|
-
width:${layout.legacyHomeButton.size}px;
|
|
264
|
-
height:${layout.legacyHomeButton.size}px;
|
|
265
|
-
border-radius:50%;
|
|
266
|
-
background:
|
|
267
|
-
radial-gradient(circle at 35% 32%, rgba(62,64,68,0.35) 0%, rgba(17,18,20,0.98) 72%, rgba(8,9,11,1) 100%);
|
|
268
|
-
box-shadow:
|
|
269
|
-
inset 0 0 0 1px rgba(255,255,255,0.06),
|
|
270
|
-
inset 0 0 0 ${layout.legacyHomeButton.ring}px rgba(184,192,204,0.45),
|
|
271
|
-
0 0 0 1px rgba(0,0,0,0.5);
|
|
272
|
-
z-index:3;
|
|
273
|
-
pointer-events:none;
|
|
274
|
-
display:flex;
|
|
275
|
-
align-items:center;
|
|
276
|
-
justify-content:center;
|
|
277
|
-
"
|
|
278
|
-
>
|
|
279
|
-
<div
|
|
280
|
-
style="
|
|
281
|
-
width:16px;
|
|
282
|
-
height:16px;
|
|
283
|
-
border-radius:4px;
|
|
284
|
-
box-shadow:inset 0 0 0 1.5px rgba(188,194,202,0.5);
|
|
285
|
-
"
|
|
286
|
-
></div>
|
|
287
|
-
</div>
|
|
288
|
-
`
|
|
289
|
-
: ''
|
|
290
|
-
|
|
291
199
|
const homeIndicatorHtml = layout.showHomeIndicator
|
|
292
200
|
? `
|
|
293
201
|
<div
|
|
@@ -374,14 +282,11 @@ function renderFrameHtml(
|
|
|
374
282
|
border-radius:${layout.housingLayers ? '0' : getCliRuntime().settings_devices.formatCornerRadii(layout.logicalFrameRadius)};
|
|
375
283
|
box-sizing:border-box;
|
|
376
284
|
overflow:visible;
|
|
377
|
-
background:${layout.frameBackground};
|
|
378
285
|
box-shadow:${layout.frameOutline};
|
|
379
286
|
"
|
|
380
287
|
>
|
|
381
|
-
${
|
|
382
|
-
${ringHtml}
|
|
288
|
+
${painter.frameSvg(paintSpec)}
|
|
383
289
|
${housingHtml}
|
|
384
|
-
${legacyHomeButtonHtml}
|
|
385
290
|
<div
|
|
386
291
|
id="screen"
|
|
387
292
|
style="
|