peachsim 0.1.648 → 0.1.649

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.
Files changed (97) hide show
  1. package/dist-lib/agent-daemon-client.cjs +1 -1
  2. package/dist-lib/agent-events.cjs +1 -1
  3. package/dist-lib/agent-identity.cjs +1 -1
  4. package/dist-lib/agent-sessions.cjs +1 -1
  5. package/dist-lib/attached-projects.cjs +1 -1
  6. package/dist-lib/auth/shared-session.cjs +1 -1
  7. package/dist-lib/backend-origin.cjs +1 -1
  8. package/dist-lib/beta.cjs +1 -1
  9. package/dist-lib/beta.mjs +1 -1
  10. package/dist-lib/bridge-constants.cjs +1 -1
  11. package/dist-lib/bridge-contract-input.cjs +1 -1
  12. package/dist-lib/bridge-contract-input.mjs +1 -1
  13. package/dist-lib/bridge-contract.cjs +1 -1
  14. package/dist-lib/bridge-contract.mjs +1 -1
  15. package/dist-lib/capture-contract.cjs +1 -1
  16. package/dist-lib/capture-contract.mjs +1 -1
  17. package/dist-lib/cli-constants.cjs +1 -1
  18. package/dist-lib/cloud-contract.cjs +1 -1
  19. package/dist-lib/cloud-contract.mjs +1 -1
  20. package/dist-lib/cloud-test-args.cjs +1 -1
  21. package/dist-lib/cloud-test-args.mjs +1 -1
  22. package/dist-lib/cloud.cjs +1 -1
  23. package/dist-lib/cloud.mjs +1 -1
  24. package/dist-lib/config.cjs +1 -1
  25. package/dist-lib/detox/index.cjs +1 -1
  26. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  27. package/dist-lib/home-paths.cjs +1 -1
  28. package/dist-lib/host/bridge-host.cjs +1 -1
  29. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  30. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  31. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  32. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  33. package/dist-lib/host/websocket-proxy.cjs +1 -1
  34. package/dist-lib/index.cjs +1 -1
  35. package/dist-lib/jump-to-source-babel.cjs +1 -1
  36. package/dist-lib/jump-to-source-native.cjs +1 -1
  37. package/dist-lib/kotlin-host.cjs +21 -5
  38. package/dist-lib/menu.cjs +1 -1
  39. package/dist-lib/menu.mjs +1 -1
  40. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  41. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  42. package/dist-lib/metro-production-bundle.cjs +1 -1
  43. package/dist-lib/metro-production-bundle.mjs +1 -1
  44. package/dist-lib/metro.cjs +1 -1
  45. package/dist-lib/native-app-identity.cjs +1 -1
  46. package/dist-lib/native-app-identity.mjs +1 -1
  47. package/dist-lib/profiles.cjs +1 -1
  48. package/dist-lib/public-brand.cjs +1 -1
  49. package/dist-lib/react-native-host-modules.cjs +1 -1
  50. package/dist-lib/react-native-host-modules.mjs +1 -1
  51. package/dist-lib/render-mode.cjs +1 -1
  52. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  53. package/dist-lib/sdk.cjs +1 -1
  54. package/dist-lib/sdk.mjs +1 -1
  55. package/dist-lib/skills.cjs +14 -14
  56. package/dist-lib/swift-compile.cjs +1 -1
  57. package/dist-lib/swift-compile.mjs +1 -1
  58. package/dist-lib/swift-package.cjs +1 -1
  59. package/dist-lib/swift-package.mjs +1 -1
  60. package/dist-lib/swift-submit.cjs +1 -1
  61. package/dist-lib/swift-submit.mjs +1 -1
  62. package/dist-lib/swift.cjs +1 -1
  63. package/dist-lib/vite-swift.cjs +1 -1
  64. package/dist-lib/vite.cjs +1 -1
  65. package/kotlin/ComposeSources/PeachComposeHost.kt +295 -0
  66. package/kotlin/Sources/dev/onejs/one/OneNativeSourceViewDispatch.kt +13 -0
  67. package/kotlin/Sources/org/json/JSON.kt +6 -0
  68. package/kotlin/fixtures/counter/Counter.d.kt.ts +16 -0
  69. package/kotlin/fixtures/counter/Counter.kt +18 -0
  70. package/kotlin/fixtures/counter/CounterApp.native.tsx +34 -0
  71. package/kotlin/fixtures/counter/CounterApp.tsx +3 -0
  72. package/kotlin/fixtures/counter/CounterScreen.d.kt.ts +7 -0
  73. package/kotlin/fixtures/counter/CounterScreen.kt +18 -3
  74. package/kotlin/fixtures/counter/app/_layout.tsx +4 -0
  75. package/kotlin/fixtures/counter/app/index+spa.tsx +1 -0
  76. package/kotlin/fixtures/counter/app/routes.d.ts +18 -0
  77. package/kotlin/fixtures/counter/package.json +7 -0
  78. package/kotlin/fixtures/counter/tsconfig.json +19 -0
  79. package/kotlin/fixtures/counter/vite.config.ts +10 -0
  80. package/kotlin/fixtures/headless-counter/Headless.kt +5 -0
  81. package/kotlin/fixtures/kotlin-app/app/build.gradle.kts +30 -0
  82. package/kotlin/fixtures/kotlin-app/app/src/main/AndroidManifest.xml +13 -0
  83. package/kotlin/fixtures/kotlin-app/app/src/main/java/dev/contrast/kotlinapp/MainActivity.kt +60 -0
  84. package/kotlin/fixtures/kotlin-app/app/src/main/java/dev/contrast/kotlinapp/ProbeApplication.kt +18 -0
  85. package/kotlin/fixtures/kotlin-app/build.gradle.kts +5 -0
  86. package/kotlin/fixtures/kotlin-app/gradle.properties +4 -0
  87. package/kotlin/fixtures/kotlin-app/settings.gradle.kts +4 -0
  88. package/kotlin/fork/NOTICE +7 -5
  89. package/kotlin/fork/README.md +41 -49
  90. package/kotlin/fork/build.sh +3 -2
  91. package/kotlin/fork/compose-worker-globals.patch +22 -11
  92. package/kotlin/fork/fork.json +2 -2
  93. package/kotlin/fork/publish.ts +30 -15
  94. package/kotlin/fork/skiko-worker-clock.patch +38 -0
  95. package/kotlin/toolchain.json +9 -9
  96. package/package.json +1 -1
  97. package/src/kotlin-host.ts +20 -4
@@ -0,0 +1,18 @@
1
+ package dev.contrast.kotlinapp
2
+
3
+ import android.app.Application
4
+
5
+ // process globals the probe reads back: the cold-start order and a value only
6
+ // the application sets before any activity exists.
7
+ object Probe {
8
+ val log = mutableListOf<String>()
9
+ var greeting = "unset"
10
+ }
11
+
12
+ class ProbeApplication : Application() {
13
+ override fun onCreate() {
14
+ super.onCreate()
15
+ Probe.log += "app.onCreate"
16
+ Probe.greeting = "set by application"
17
+ }
18
+ }
@@ -0,0 +1,5 @@
1
+ plugins {
2
+ id("com.android.application") version "9.2.1" apply false
3
+ id("org.jetbrains.kotlin.android") version "2.2.0" apply false
4
+ id("org.jetbrains.kotlin.plugin.compose") version "2.2.0" apply false
5
+ }
@@ -0,0 +1,4 @@
1
+ android.useAndroidX=true
2
+ android.builtInKotlin=false
3
+ android.newDsl=false
4
+ org.gradle.jvmargs=-Xmx2g
@@ -0,0 +1,4 @@
1
+ pluginManagement { repositories { google(); mavenCentral(); gradlePluginPortal() } }
2
+ dependencyResolutionManagement { repositories { google(); mavenCentral() } }
3
+ rootProject.name = "KotlinApp"
4
+ include(":app")
@@ -17,9 +17,11 @@ The license text is in LICENSE beside this file.
17
17
  https://android.googlesource.com/platform/frameworks/base
18
18
 
19
19
  Modifications: compose-worker-globals.patch and skiko-worker-clock.patch
20
- change four upstream source files so their web code reads globalThis instead
21
- of window (performance.now, isSecureContext, navigator.clipboard,
22
- navigator.languages). Each modified file carries a notice saying so. No other
23
- upstream file changes; the built klibs are ui-wasm-js and ui-text-wasm-js
20
+ change clock and clipboard reads to globalThis rather than window, and add an
21
+ explicit ui-text locale provider and Skiko host OS provider whose defaults
22
+ retain upstream navigator behavior. Each modified file carries a notice saying so. The Skiko
23
+ loader build also reads import.meta.url instead of self.location.href, which
24
+ React Native tenants do not expose. The built klibs are ui-wasm-js and ui-text-wasm-js
24
25
  1.13.0-alpha01 and skiko-wasm-js 0.152.0-alpha02 compiled from the patched
25
- sources.
26
+ sources; skiko-wasm-0.152.0-alpha02.jar contains that worker-safe loader and
27
+ Skiko's own wasm runtime.
@@ -1,59 +1,51 @@
1
1
  # Peach's JetBrains web fork
2
2
 
3
- Peach runs Compose in a tenant worker, which has no `window`, like any browser
4
- worker. Three web functions in Compose UI 1.13.0-alpha01 and one in Skiko
5
- 0.152.0-alpha02 name `window` anyway, so a Compose scene throws
6
- `window is not defined` before its first frame. Peach carries patched builds
7
- of those modules until upstream supports workers.
3
+ Peach runs Compose in a React Native tenant worker, with no `window`,
4
+ `document`, `location`, or browser navigator language/platform fields. The official
5
+ Compose UI 1.13.0-alpha01 and Skiko 0.152.0-alpha02 platform actuals assume
6
+ browser globals that this native host does not publish. Peach carries patched
7
+ builds until upstream supplies equivalent worker and native host hooks.
8
8
 
9
- The patches replace `window` with `globalThis` and nothing else:
10
-
11
- | module | file | read |
9
+ | module | file | native host binding |
12
10
  | --- | --- | --- |
13
- | `org.jetbrains.compose.ui:ui` | `Actuals.wasm.kt` | `currentTimeMillis()` from `globalThis.performance.now()` |
14
- | `org.jetbrains.compose.ui:ui` | `PlatformClipboard.web.kt` | `globalThis.isSecureContext`, `globalThis.navigator.clipboard` |
15
- | `org.jetbrains.compose.ui:ui-text` | `PlatformLocale.web.kt` | `globalThis.navigator.languages` |
16
- | `org.jetbrains.skiko:skiko` | `Actuals.web.kt` | `currentNanoTime()` from `globalThis.performance.now()` |
17
-
18
- In a document `globalThis` is the window, so behavior there is unchanged. In a
19
- worker each read returns the worker's real value: its clock, its secure
20
- context, its languages, and no clipboard API. Nothing defines a `window`.
21
-
22
- ## files
23
-
24
- - `fork.json`: upstream repositories, tags and commits, patch sha256s, and the
25
- builder's pinned JDK and Android command-line tools.
26
- - `compose-worker-globals.patch`, `skiko-worker-clock.patch`: the whole fork.
27
- Every modified file carries a notice saying it was modified.
28
- - `LICENSE` (Apache 2.0, both upstreams) and `NOTICE`.
29
- - `build.sh`: fetches each upstream at its commit, applies its patch and runs
30
- the upstream Gradle build for the changed modules only.
31
-
32
- `packages/peachsim/kotlin/toolchain.json` names each built klib by its sha256
33
- at `https://r2.rnxsim.com/peach-kotlin-fork/<sha256>/<file>`, beside a copy of
34
- the patches, `fork.json`, `LICENSE` and `NOTICE`. Every other Compose library
35
- is the official Maven artifact. The klibs load only for an app whose Kotlin
36
- imports Compose, like the rest of the Compose closure.
37
-
38
- ## rebuilding
11
+ | Compose `ui` | `Actuals.wasm.kt` | clock reads `globalThis.performance.now()` |
12
+ | Compose `ui` | `PlatformClipboard.web.kt` | worker-safe secure-context and clipboard reads |
13
+ | Compose `ui-text` | `PlatformLocale.web.kt` | explicit `setPlatformLocaleProvider`; its default keeps upstream navigator behavior |
14
+ | Skiko | `OsArch.web.kt` | explicit `setHostOsProvider`; its default lazily retains upstream OS detection |
15
+ | Skiko | `Actuals.web.kt` | nanosecond clock reads `globalThis.performance.now()` |
16
+ | Skiko loader build | `OptimizeSkikoWasmTask.kt` | script directory reads `import.meta.url`, without `self.location` |
17
+
18
+ The Compose host installs the locale provider once before any scene, from the
19
+ same device locale it passes to `PlatformContext`, and installs `OS.Android`
20
+ through Skiko’s host OS provider before any scene. Browser navigator fields
21
+ stay absent in guest JS. Changes to device language after launch are outside
22
+ this contract.
23
+
24
+ `fork.json` pins repositories, commits, patch hashes, JDK and Android tools.
25
+ Every changed upstream file carries a modification notice. `LICENSE` and
26
+ `NOTICE` travel with the patches. `build.sh` builds the changed KLIBs and Skiko
27
+ runtime jar with the upstream Gradle builds on the Linux builder.
39
28
 
40
29
  ```sh
41
30
  bun remote bash packages/peachsim/kotlin/fork/build.sh
42
31
  bun packages/peachsim/kotlin/fork/publish.ts .remote-out/kotlin-fork
43
32
  ```
44
33
 
45
- The build runs on the Linux builder under its idle scheduling and memory
46
- bound; a warm rebuild takes a few minutes. The build delivers the klibs with
47
- the record it used (`fork.json`, patches, LICENSE, NOTICE, `klibs.sha256`).
48
- `publish.ts` uploads exactly that delivery under each klib's sha256, refuses to
49
- replace an existing object with other bytes, and prints the `toolchain.json`
50
- entries. Moving a pin means a new tag, commit, regenerated patch and patch
51
- sha256 in `fork.json`, then a rebuild.
52
-
53
- ## exit
54
-
55
- Delete this directory and point `toolchain.json` back at Maven Central when
56
- official Compose Multiplatform and Skiko releases read worker-safe globals in
57
- all four places, and those releases match the Android pin table in
58
- `plans/peach/kotlin-everywhere.md`. The upstream issue text lives with that
59
- plan's owner until it is filed.
34
+ The delivery includes `artifacts.sha256` and its exact fork record. Publication
35
+ stores each binary at `peach-kotlin-fork/<binary-sha256>/<file>` and its record
36
+ at `peach-kotlin-fork/<binary-sha256>/records/<record-sha256>/`. It refuses to
37
+ replace existing bytes. A metadata change cannot overwrite a previous record
38
+ when a binary is unchanged. `toolchain.json` pins these immutable binary URLs;
39
+ all other Compose libraries remain official Maven artifacts. Everything stays
40
+ lazy for Kotlin/Compose apps.
41
+
42
+ The isolated worker probe cannot certify the native tenant's absent globals.
43
+ `scripts/debug/peach-compose-mount/tenant-run.ts` boots the actual capture tenant
44
+ with the imported `.kt` component, asserts those globals stay absent, and
45
+ checks `Locale.current` and `LocalLocaleList` against an ar-EG device setting
46
+ with an en-US browser.
47
+
48
+ Delete the fork when official releases provide worker-safe clocks/clipboard,
49
+ a location-independent loader and equivalent native locale/host OS provider hooks,
50
+ then rematch the Android pins in `plans/peach/kotlin-everywhere.md`. The prepared
51
+ upstream issue names these hooks and the full guest regression vehicle.
@@ -115,7 +115,8 @@ checkout 1
115
115
  cd "${SOURCE}/skiko"
116
116
  gradle -Pdeploy.version=0.152.0-alpha02 -Pdeploy.release=true \
117
117
  -Pskiko.wasm.enabled=true -Pskiko.awt.enabled=false \
118
- :publishWasmJsPublicationToMavenLocal
118
+ :publishWasmJsPublicationToMavenLocal :skikoWasmJar
119
+ cp build/libs/skiko-wasm-0.152.0-alpha02.jar "${DELIVER}/"
119
120
  )
120
121
 
121
122
  cp "${M2}/org/jetbrains/compose/ui/ui-wasm-js/1.13.0-alpha01/ui-wasm-js-1.13.0-alpha01.klib" \
@@ -125,4 +126,4 @@ cp "${M2}/org/jetbrains/compose/ui/ui-wasm-js/1.13.0-alpha01/ui-wasm-js-1.13.0-a
125
126
  # the record travels with the klibs it describes, so publishing attaches what
126
127
  # this build used, not whatever the checkout holds later
127
128
  cp "${FORK}/fork.json" "${FORK}/LICENSE" "${FORK}/NOTICE" "${FORK}"/*.patch "${DELIVER}/"
128
- (cd "${DELIVER}" && sha256sum -- *.klib > klibs.sha256 && cat klibs.sha256)
129
+ (cd "${DELIVER}" && sha256sum -- *.klib *.jar > artifacts.sha256 && cat artifacts.sha256)
@@ -1,5 +1,4 @@
1
1
  diff --git a/compose/ui/ui-text/src/webMain/kotlin/androidx/compose/ui/text/intl/PlatformLocale.web.kt b/compose/ui/ui-text/src/webMain/kotlin/androidx/compose/ui/text/intl/PlatformLocale.web.kt
2
- index 6e80e51..28f1de1 100644
3
2
  --- a/compose/ui/ui-text/src/webMain/kotlin/androidx/compose/ui/text/intl/PlatformLocale.web.kt
4
3
  +++ b/compose/ui/ui-text/src/webMain/kotlin/androidx/compose/ui/text/intl/PlatformLocale.web.kt
5
4
  @@ -12,6 +12,10 @@
@@ -7,20 +6,32 @@ index 6e80e51..28f1de1 100644
7
6
  * See the License for the specific language governing permissions and
8
7
  * limitations under the License.
9
8
  + *
10
- + * Modified for Peach (https://peachsim.com): reads worker-safe globals through
11
- + * globalThis instead of window, so this code runs in a Web Worker as well as a
12
- + * document. See the Peach fork record for the patch and upstream revision.
9
+ + * modified for Peach: an explicit locale provider lets a native host supply
10
+ + * device languages without exposing browser navigator fields to guest code.
11
+ + * see the fork record for the patch and upstream revision.
13
12
  */
14
13
 
15
14
  package androidx.compose.ui.text.intl
16
- @@ -127,4 +131,4 @@ private fun userPreferredLanguages(): List<String> {
15
+ @@ -64,8 +68,18 @@
16
+ // The locale code en-001 denotes the English language spoken in the World.
17
+ private const val FALLBACK_LANGUAGE_TAG = "en-001"
17
18
 
18
- @OptIn(ExperimentalWasmJsInterop::class)
19
- private fun getUserPreferredLanguagesAsArray(): JsArray<JsString> =
20
- - js("window.navigator.languages")
21
-
22
- + js("globalThis.navigator.languages")
23
-
19
+ +private var currentLocaleProvider: () -> LocaleList = {
20
+ + localeListFromLanguageTags(userPreferredLanguages())
21
+ +}
22
+ +
23
+ +// the host installs the device provider before constructing its first scene.
24
+ +@InternalComposeUiApi
25
+ +fun setPlatformLocaleProvider(provider: () -> LocaleList) {
26
+ + currentLocaleProvider = provider
27
+ +}
28
+ +
29
+ internal actual fun createPlatformLocaleDelegate(): PlatformLocaleDelegate =
30
+ object : PlatformLocaleDelegate {
31
+ override val current: LocaleList
32
+ - get() = localeListFromLanguageTags(userPreferredLanguages())
33
+ + get() = currentLocaleProvider()
34
+ }
24
35
  diff --git a/compose/ui/ui/src/wasmJsMain/kotlin/androidx/compose/ui/Actuals.wasm.kt b/compose/ui/ui/src/wasmJsMain/kotlin/androidx/compose/ui/Actuals.wasm.kt
25
36
  index 26aa8ea..aa4f6d4 100644
26
37
  --- a/compose/ui/ui/src/wasmJsMain/kotlin/androidx/compose/ui/Actuals.wasm.kt
@@ -18,7 +18,7 @@
18
18
  "tag": "v1.13.0-alpha01",
19
19
  "commit": "a9e47e8aa04c95cfe572ab4297c770f3cbfb234e",
20
20
  "patch": "compose-worker-globals.patch",
21
- "patchSha256": "7f7df0788145b8d44c32a9ca7746cf254c363beca816922f84d73faa0effed5a"
21
+ "patchSha256": "51fa45bda1e0aae7db2eab1b056def406352958257e1d3b899c5c3d8aa5edddb"
22
22
  },
23
23
  {
24
24
  "name": "skiko",
@@ -27,7 +27,7 @@
27
27
  "tag": "v0.152.0-alpha02",
28
28
  "commit": "96378296bb23c23c5f30cd2b0d42d6f8fdeff730",
29
29
  "patch": "skiko-worker-clock.patch",
30
- "patchSha256": "d55007f3aa4c2b61e44f036bdb43f37ab38455bf800664fdb6598955874d10da"
30
+ "patchSha256": "735a42f7a9d3be1ab288f4d67bef44924ec2b6bbcd59f5a5f76edf22f912c347"
31
31
  }
32
32
  ]
33
33
  }
@@ -1,6 +1,6 @@
1
- // uploads the klibs one build.sh run delivered to R2, each under its sha256
1
+ // uploads the artifacts one build.sh run delivered to R2, each under its sha256
2
2
  // beside the record that run copied (patches, fork.json, LICENSE, NOTICE,
3
- // klibs.sha256), and prints the toolchain.json entries that name them. keys
3
+ // artifacts.sha256), and prints the toolchain.json entries that name them. keys
4
4
  // are immutable: an existing object with other bytes stops the publish. needs
5
5
  // R2 credentials; reads are public.
6
6
  //
@@ -22,27 +22,32 @@ const files = readdirSync(delivered)
22
22
  const record = files.filter(
23
23
  (name) =>
24
24
  name.endsWith('.patch') ||
25
- ['fork.json', 'LICENSE', 'NOTICE', 'klibs.sha256'].includes(name),
25
+ ['fork.json', 'LICENSE', 'NOTICE', 'artifacts.sha256'].includes(name),
26
+ )
27
+ if (
28
+ record.length !==
29
+ files.filter((name) => !name.endsWith('.klib') && !name.endsWith('.jar')).length
26
30
  )
27
- if (record.length !== files.filter((name) => !name.endsWith('.klib')).length)
28
31
  throw new Error(`${delivered} holds files build.sh does not deliver`)
29
- if (!record.includes('klibs.sha256') || !record.includes('fork.json'))
32
+ if (!record.includes('artifacts.sha256') || !record.includes('fork.json'))
30
33
  throw new Error(`${delivered} is not a build.sh delivery`)
31
34
 
32
- // the klibs are exactly the ones the build hashed
35
+ // the artifacts are exactly the ones the build hashed
33
36
  const built = new Map(
34
- readFileSync(path.join(delivered, 'klibs.sha256'), 'utf8')
37
+ readFileSync(path.join(delivered, 'artifacts.sha256'), 'utf8')
35
38
  .trim()
36
39
  .split('\n')
37
40
  .map((line) => {
38
41
  const [hash, name] = line.split(/\s+/)
39
- if (!hash || !name) throw new Error(`malformed klibs.sha256 line: ${line}`)
42
+ if (!hash || !name) throw new Error(`malformed artifacts.sha256 line: ${line}`)
40
43
  return [name, hash]
41
44
  }),
42
45
  )
43
- const klibs = files.filter((name) => name.endsWith('.klib')).sort()
44
- if (klibs.length === 0 || klibs.length !== built.size)
45
- throw new Error(`${delivered} klibs do not match klibs.sha256`)
46
+ const artifacts = files
47
+ .filter((name) => name.endsWith('.klib') || name.endsWith('.jar'))
48
+ .sort()
49
+ if (artifacts.length === 0 || artifacts.length !== built.size)
50
+ throw new Error(`${delivered} artifacts do not match artifacts.sha256`)
46
51
 
47
52
  async function put(key: string, bytes: Buffer, contentType: string) {
48
53
  const existing = await readR2Object(key, 120000)
@@ -53,23 +58,33 @@ async function put(key: string, bytes: Buffer, contentType: string) {
53
58
  await uploadToR2(key, bytes, contentType, IMMUTABLE)
54
59
  }
55
60
 
61
+ const recordHash = sha256(
62
+ Buffer.concat(
63
+ record
64
+ .sort()
65
+ .flatMap((file) => [
66
+ Buffer.from(file + '\0'),
67
+ readFileSync(path.join(delivered, file)),
68
+ ]),
69
+ ),
70
+ )
56
71
  const entries = []
57
- for (const name of klibs) {
72
+ for (const name of artifacts) {
58
73
  const bytes = readFileSync(path.join(delivered, name))
59
74
  const hash = sha256(bytes)
60
75
  if (built.get(name) !== hash)
61
- throw new Error(`${name} is not the klib the build hashed`)
76
+ throw new Error(`${name} is not the artifact the build hashed`)
62
77
  const prefix = `peach-kotlin-fork/${hash}`
63
78
  await put(`${prefix}/${name}`, bytes, 'application/octet-stream')
64
79
  for (const file of record)
65
80
  await put(
66
- `${prefix}/${file}`,
81
+ `${prefix}/records/${recordHash}/${file}`,
67
82
  readFileSync(path.join(delivered, file)),
68
83
  'text/plain; charset=utf-8',
69
84
  )
70
85
  // the loader caches a library by its name, so the name carries the hash
71
86
  entries.push({
72
- name: name.replace(/\.klib$/, `-peach-${hash.slice(0, 12)}.klib`),
87
+ name: name.replace(/\.(klib|jar)$/, `-peach-${hash.slice(0, 12)}.$1`),
73
88
  url: `${RNX_PUBLIC.publicR2Origin}/${prefix}/${name}`,
74
89
  sha256: hash,
75
90
  })
@@ -31,3 +31,41 @@ index 366ed37..d56c267 100644
31
31
  + js("globalThis.performance.now() * 1000000")
32
32
 
33
33
  annotation class WebImport(val name : String)
34
+ diff --git a/skiko/buildSrc/src/main/kotlin/OptimizeSkikoWasmTask.kt b/skiko/buildSrc/src/main/kotlin/OptimizeSkikoWasmTask.kt
35
+ --- a/skiko/buildSrc/src/main/kotlin/OptimizeSkikoWasmTask.kt
36
+ +++ b/skiko/buildSrc/src/main/kotlin/OptimizeSkikoWasmTask.kt
37
+ @@ -65,6 +65,12 @@ abstract class OptimizeSkikoWasmTask : AbstractSkikoNativeToolTask() {
38
+ "${inputFile.nameWithoutExtension}.wasm",
39
+ "${libOutputFileName.get()}.wasm"
40
+ )
41
+ + // peach tenants hide location from react native;
42
+ + // emscripten already uses this module url below.
43
+ + .replace(
44
+ + "scriptDirectory=self.location.href",
45
+ + "scriptDirectory=import.meta.url"
46
+ + )
47
+ )
48
+ }
49
+ }
50
+ diff --git a/skiko/src/webMain/kotlin/org/jetbrains/skiko/OsArch.web.kt b/skiko/src/webMain/kotlin/org/jetbrains/skiko/OsArch.web.kt
51
+ --- a/skiko/src/webMain/kotlin/org/jetbrains/skiko/OsArch.web.kt
52
+ +++ b/skiko/src/webMain/kotlin/org/jetbrains/skiko/OsArch.web.kt
53
+ @@ -3,6 +3,15 @@
54
+ import kotlinx.browser.window
55
+ import kotlin.js.js
56
+ -
57
+ +
58
+ -actual val hostOs: OS = detectHostOs()
59
+ +private val defaultHostOs: OS by lazy { detectHostOs() }
60
+ +private var hostOsProvider: () -> OS = { defaultHostOs }
61
+ +
62
+ +// modified for Peach: native hosts install their device's platform before
63
+ +// any compose scene. see the fork record for the patch and upstream revision.
64
+ +fun setHostOsProvider(provider: () -> OS) {
65
+ + hostOsProvider = provider
66
+ +}
67
+ +
68
+ +actual val hostOs: OS get() = hostOsProvider()
69
+ -
70
+ +
71
+ actual val hostArch: Arch = Arch.Unknown
@@ -33,9 +33,9 @@
33
33
  "sha256": "6187e199922b061cffa16fd9ae2ed920d6a59f0b0f7c3207e829b983ff132d38"
34
34
  },
35
35
  {
36
- "name": "skiko-wasm-js-0.152.0-alpha02-peach-a480f0730dab.klib",
37
- "url": "https://r2.rnxsim.com/peach-kotlin-fork/a480f0730dabea887e2fa22f5f5683454d3594445557a8d8149647af90d3d312/skiko-wasm-js-0.152.0-alpha02.klib",
38
- "sha256": "a480f0730dabea887e2fa22f5f5683454d3594445557a8d8149647af90d3d312"
36
+ "name": "skiko-wasm-js-0.152.0-alpha02-peach-3834433e1790.klib",
37
+ "url": "https://r2.rnxsim.com/peach-kotlin-fork/3834433e17902a3d86dc973abb245b7af5aae0012ca29e1ac9668d74335f3115/skiko-wasm-js-0.152.0-alpha02.klib",
38
+ "sha256": "3834433e17902a3d86dc973abb245b7af5aae0012ca29e1ac9668d74335f3115"
39
39
  },
40
40
  {
41
41
  "name": "annotation-wasm-js-1.9.1.klib",
@@ -73,9 +73,9 @@
73
73
  "sha256": "dab0b337dd99ec99e8a3cc4efd365d8101db050971490eff6839fc566aeadc6c"
74
74
  },
75
75
  {
76
- "name": "ui-text-wasm-js-1.13.0-alpha01-peach-a2c25f211136.klib",
77
- "url": "https://r2.rnxsim.com/peach-kotlin-fork/a2c25f2111369c638e785f192312934a78fcacc15186da681429b580b143ddd7/ui-text-wasm-js-1.13.0-alpha01.klib",
78
- "sha256": "a2c25f2111369c638e785f192312934a78fcacc15186da681429b580b143ddd7"
76
+ "name": "ui-text-wasm-js-1.13.0-alpha01-peach-10c54ff0fa5f.klib",
77
+ "url": "https://r2.rnxsim.com/peach-kotlin-fork/10c54ff0fa5fc0ff066fb4561e2d5ca9d5c41fedcb32a61414016ef215b035ba/ui-text-wasm-js-1.13.0-alpha01.klib",
78
+ "sha256": "10c54ff0fa5fc0ff066fb4561e2d5ca9d5c41fedcb32a61414016ef215b035ba"
79
79
  },
80
80
  {
81
81
  "name": "ui-unit-wasm-js-1.13.0-alpha01.klib",
@@ -290,9 +290,9 @@
290
290
  "skiko": "0.152.0-alpha02"
291
291
  },
292
292
  "composeRuntime": {
293
- "name": "skiko-wasm-0.152.0-alpha02.jar",
294
- "url": "https://repo1.maven.org/maven2/org/jetbrains/skiko/skiko-wasm-js/0.152.0-alpha02/skiko-wasm-js-0.152.0-alpha02-skiko-runtime.jar",
295
- "sha256": "14e37c567f10d906a10a74df80b44ee5a5dd5e3a75929f351a32d5b123dad643"
293
+ "name": "skiko-wasm-0.152.0-alpha02-peach-4814686165d0.jar",
294
+ "url": "https://r2.rnxsim.com/peach-kotlin-fork/4814686165d0ba869e605e661d0fb261ecc79f5e984ed6ae78dfe20300923c98/skiko-wasm-0.152.0-alpha02.jar",
295
+ "sha256": "4814686165d0ba869e605e661d0fb261ecc79f5e984ed6ae78dfe20300923c98"
296
296
  },
297
297
  "composeJsLibraries": [
298
298
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peachsim",
3
- "version": "0.1.648",
3
+ "version": "0.1.649",
4
4
  "description": "Vite and Metro plugins, testing drivers, and SDK exports for peach.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -256,7 +256,7 @@ function entrySource(ids: string[]): string {
256
256
  ].join('\n')
257
257
  }
258
258
 
259
- const BUILD_FORMAT = 4
259
+ const BUILD_FORMAT = 5
260
260
  const builds = new Map<string, Promise<KotlinArtifact>>()
261
261
 
262
262
  function buildsDir(): string {
@@ -278,18 +278,34 @@ export async function kotlinArtifact(
278
278
  if (sources.length === 0) throw new Error(`${root} holds no Kotlin sources`)
279
279
  const generated: Record<string, string> = {}
280
280
  const ids: string[] = []
281
+ const viewIds: string[] = []
281
282
  let usesCompose = false
282
283
  for (const file of sources) {
283
284
  const source = fs.readFileSync(file, 'utf8')
284
285
  if (/\bandroidx\.compose\./.test(source)) usesCompose = true
285
286
  const contract = nativeSourceContract(file, source)
286
- if (contract.modules.length === 0) continue
287
+ if (contract.modules.length === 0 && contract.views.length === 0) continue
287
288
  const id = kotlinSourceId(root, file)
288
- ids.push(id)
289
+ if (contract.modules.length > 0) ids.push(id)
290
+ if (contract.views.length > 0) viewIds.push(id)
289
291
  generated[`OneNativeSource_${id}.kt`] = renderKotlinSourceGlue(id, contract).source
290
292
  }
291
293
  generated['PeachEntry.kt'] = entrySource(ids)
292
- const shims = kotlinSources(path.join(moduleRoot, 'Sources'))
294
+ if (viewIds.length > 0) {
295
+ generated['PeachViews.kt'] = [
296
+ 'import dev.onejs.one.OneNativeSourceViewDispatch',
297
+ '',
298
+ 'fun peachViewDispatcher(source: String): OneNativeSourceViewDispatch = when (source) {',
299
+ ...viewIds.map((id) => ` ${JSON.stringify(id)} -> OneNativeSourceViews_${id}()`),
300
+ ' else -> error("composable source $source is not linked; rebuild the app")',
301
+ '}',
302
+ ].join('\n')
303
+ }
304
+ const shims = kotlinSources(path.join(moduleRoot, 'Sources')).filter(
305
+ (file) => usesCompose || !file.endsWith('/OneNativeSourceViewDispatch.kt'),
306
+ )
307
+ if (viewIds.length > 0)
308
+ shims.push(...kotlinSources(path.join(moduleRoot, 'ComposeSources')))
293
309
  const digest = createHash('sha256')
294
310
  // BUILD_FORMAT moves when this host changes what it does to a build
295
311
  digest.update(JSON.stringify({ format: BUILD_FORMAT, toolchain, language }))