peachsim 0.1.2208 → 0.1.2210

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 (139) 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/attached-projects.cjs +1 -1
  4. package/dist-lib/auth/shared-session.cjs +1 -1
  5. package/dist-lib/backend-origin.cjs +1 -1
  6. package/dist-lib/beta.cjs +1 -1
  7. package/dist-lib/beta.mjs +1 -1
  8. package/dist-lib/bridge-constants.cjs +1 -1
  9. package/dist-lib/bridge-contract-input.cjs +1 -1
  10. package/dist-lib/bridge-contract-input.mjs +1 -1
  11. package/dist-lib/bridge-contract.cjs +1 -1
  12. package/dist-lib/bridge-contract.mjs +1 -1
  13. package/dist-lib/bundle-channel.cjs +712 -66
  14. package/dist-lib/capture-contract.cjs +1 -1
  15. package/dist-lib/capture-contract.mjs +1 -1
  16. package/dist-lib/cloud-contract.cjs +1 -1
  17. package/dist-lib/cloud-contract.mjs +1 -1
  18. package/dist-lib/cloud-test-args.cjs +1 -1
  19. package/dist-lib/cloud-test-args.mjs +1 -1
  20. package/dist-lib/cloud.cjs +1 -1
  21. package/dist-lib/cloud.mjs +1 -1
  22. package/dist-lib/config.cjs +1 -1
  23. package/dist-lib/config.mjs +1 -1
  24. package/dist-lib/detox/index.cjs +2 -2
  25. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  26. package/dist-lib/expo-swift-bundle.cjs +700 -60
  27. package/dist-lib/expo-swift-metadata.cjs +1 -1
  28. package/dist-lib/expo-swift-metadata.mjs +1 -1
  29. package/dist-lib/home-paths.cjs +1 -1
  30. package/dist-lib/host/bridge-host.cjs +712 -66
  31. package/dist-lib/host/fetch-proxy-handler.cjs +17 -4
  32. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  33. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  34. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  35. package/dist-lib/host/websocket-proxy.cjs +1 -1
  36. package/dist-lib/index.cjs +17 -4
  37. package/dist-lib/jump-to-source-babel.cjs +1 -1
  38. package/dist-lib/jump-to-source-native.cjs +1 -1
  39. package/dist-lib/kotlin-host.cjs +7 -1
  40. package/dist-lib/menu.cjs +1 -1
  41. package/dist-lib/menu.mjs +1 -1
  42. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  43. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  44. package/dist-lib/metro-production-bundle.cjs +1 -1
  45. package/dist-lib/metro-production-bundle.mjs +1 -1
  46. package/dist-lib/metro.cjs +17 -4
  47. package/dist-lib/native-app-identity-project.cjs +15 -2
  48. package/dist-lib/native-app-identity-project.mjs +15 -2
  49. package/dist-lib/native-app-identity.cjs +1 -1
  50. package/dist-lib/native-app-identity.mjs +1 -1
  51. package/dist-lib/native-firebase-metadata.cjs +1 -1
  52. package/dist-lib/native-firebase-metadata.mjs +1 -1
  53. package/dist-lib/pdfium-raster.cjs +1 -1
  54. package/dist-lib/pdfium-raster.mjs +1 -1
  55. package/dist-lib/plist.cjs +1 -1
  56. package/dist-lib/plist.mjs +1 -1
  57. package/dist-lib/profiles.cjs +1 -1
  58. package/dist-lib/public-brand.cjs +1 -1
  59. package/dist-lib/public-origins-lib-esm.json +24 -24
  60. package/dist-lib/public-origins-lib.json +69 -53
  61. package/dist-lib/react-native-host-modules.cjs +1 -1
  62. package/dist-lib/react-native-host-modules.mjs +1 -1
  63. package/dist-lib/reap-browser.cjs +1 -1
  64. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  65. package/dist-lib/sdk.cjs +1 -1
  66. package/dist-lib/sdk.mjs +1 -1
  67. package/dist-lib/skills.cjs +5679 -358
  68. package/dist-lib/swift-compile.cjs +154 -16
  69. package/dist-lib/swift-compile.mjs +153 -16
  70. package/dist-lib/swift-package.cjs +1 -1
  71. package/dist-lib/swift-package.mjs +1 -1
  72. package/dist-lib/swift-submit.cjs +1 -1
  73. package/dist-lib/swift-submit.mjs +1 -1
  74. package/dist-lib/swift-toolchain.cjs +1 -1
  75. package/dist-lib/swift.cjs +1 -1
  76. package/dist-lib/vite-swift.cjs +600 -55
  77. package/dist-lib/vite.cjs +17 -4
  78. package/dist-lib/worklet-executable.cjs +1 -1
  79. package/dist-lib/worklet-executable.mjs +1 -1
  80. package/dist-types/packages/peach-engine/src/engine/animated.d.ts +2 -1
  81. package/dist-types/packages/peach-engine/src/engine/animation-graph.d.ts +1 -0
  82. package/dist-types/packages/peach-engine/src/engine/liquid-glass.d.ts +6 -0
  83. package/dist-types/packages/peach-engine/src/engine/node.d.ts +1 -0
  84. package/dist-types/packages/peach-engine/src/engine/types.d.ts +1 -0
  85. package/dist-types/packages/peach-engine/src/render-worker/canvaskit-webgpu.d.ts +8 -0
  86. package/dist-types/packages/peach-engine/src/render-worker/compositor-gpu.d.ts +3 -0
  87. package/dist-types/packages/peach-engine/src/render-worker/compositor-protocol.d.ts +14 -0
  88. package/dist-types/packages/peach-engine/src/render-worker/compositor-runtime/render-tree.d.ts +18 -0
  89. package/kotlin/sdk.tar.gz +0 -0
  90. package/package.json +1 -1
  91. package/runtime-companion.json +1 -1
  92. package/sdk/ios/System/Library/Frameworks/Foundation.framework/Headers/NSCompoundPredicate.h +1 -1
  93. package/sdk/ios/System/Library/Frameworks/Foundation.framework/Headers/NSExpression.h +1 -1
  94. package/sdk/ios/System/Library/Frameworks/Foundation.framework/Headers/NSISO8601DateFormatter.h +1 -1
  95. package/sdk/ios/System/Library/Frameworks/Foundation.framework/Headers/NSMeasurementFormatter.h +1 -1
  96. package/sdk/ios/System/Library/Frameworks/Intents.framework/Headers/INObjectCollection.h +27 -0
  97. package/sdk/ios/System/Library/Frameworks/Intents.framework/Headers/INObjectSection.h +24 -0
  98. package/sdk/ios/System/Library/Frameworks/Intents.framework/Headers/Intents.h +9 -0
  99. package/sdk/ios/System/Library/Frameworks/Intents.framework/Modules/module.modulemap +5 -0
  100. package/sdk/ios/System/Library/Frameworks/QuartzCore.framework/Headers/CoreAnimation.h +2 -0
  101. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UIFeedbackGenerator.h +1 -1
  102. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UIImpactFeedbackGenerator.h +1 -1
  103. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UIKit.apinotes +21 -0
  104. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UINibLoading.h +1 -1
  105. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UINotificationFeedbackGenerator.h +1 -1
  106. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UISelectionFeedbackGenerator.h +1 -1
  107. package/sdk/ios/usr/include/ObjectiveC.apinotes +7 -0
  108. package/sdk/ios/usr/lib/swift/Combine.swiftmodule/arm64-apple-ios-simulator.swiftinterface +18 -0
  109. package/sdk/ios/usr/lib/swift/Foundation.swiftmodule/arm64-apple-ios-simulator.swiftinterface +1 -0
  110. package/sdk/ios/usr/lib/swift/SwiftUI.swiftmodule/arm64-apple-ios-simulator.swiftinterface +19 -0
  111. package/sdk/ios/usr/lib/swift/SwiftUICore.swiftmodule/arm64-apple-ios-simulator.swiftinterface +4 -0
  112. package/sdk/ios/usr/lib/swift/UIKit.swiftmodule/arm64-apple-ios-simulator.swiftinterface +4 -0
  113. package/sdk/ios/wasm/include/pthread.h +1 -0
  114. package/sdk/ios/wasm/include/signal.h +2 -2
  115. package/sdk/native-hashes.json +3 -3
  116. package/src/android-theme.ts +136 -2
  117. package/src/expo-swift-host.ts +90 -1
  118. package/src/generated/android-framework-text.json +4566 -0
  119. package/src/generated/android-framework-themes.json +11 -0
  120. package/src/kotlin-app.ts +24 -4
  121. package/src/kotlin-host.ts +9 -0
  122. package/src/native-static-libraries.ts +7 -0
  123. package/src/nitro-adapter.lock.json +246 -246
  124. package/src/nitro-superset.lock.json +4 -4
  125. package/src/swift-compile.ts +168 -12
  126. package/src/swift-distribution.lock.json +8 -8
  127. package/src/swift-host.ts +22 -3
  128. package/src/swift-objc-compile.ts +1 -1
  129. package/src/swift-objc-import.ts +32 -2
  130. package/src/swift-objc-standin.ts +10 -3
  131. package/src/swift-packages.ts +53 -28
  132. package/src/swift-pdf-raster.ts +60 -4
  133. package/src/swift-shared-sdk.ts +2 -1
  134. package/src/swift-shipped-archives.json +44 -0
  135. package/src/swift-shipped-binaries.ts +12 -0
  136. package/src/swift-standin-builtin-behavior.ts +248 -0
  137. package/src/swift-standin-emit.ts +11 -3
  138. package/src/swift-standins.ts +92 -13
  139. package/src/turbo-runtime.lock.json +17 -17
@@ -46,9 +46,9 @@ CGImageDestinationAddImage(dest, image, nil)
46
46
  guard CGImageDestinationFinalize(dest) else { exit(7) }
47
47
  `
48
48
 
49
- function rasterBinary(): string {
50
- const tag = createHash('sha256').update(RASTER_SWIFT).digest('hex').slice(0, 16)
51
- const binary = path.join(cacheDir(), `swift-pdf-raster-${tag}`)
49
+ function rasterBinary(swift = RASTER_SWIFT, name = 'swift-pdf-raster'): string {
50
+ const tag = createHash('sha256').update(swift).digest('hex').slice(0, 16)
51
+ const binary = path.join(cacheDir(), `${name}-${tag}`)
52
52
  try {
53
53
  fs.accessSync(binary, fs.constants.X_OK)
54
54
  return binary
@@ -61,7 +61,7 @@ function rasterBinary(): string {
61
61
  fs.mkdtempSync(path.join(os.tmpdir(), 'swift-pdf-raster-')),
62
62
  'raster.swift',
63
63
  )
64
- fs.writeFileSync(source, RASTER_SWIFT)
64
+ fs.writeFileSync(source, swift)
65
65
  try {
66
66
  // runner-toolchain-platform: darwin
67
67
  execFileSync('xcrun', ['swiftc', '-o', binary, source], { stdio: 'pipe' })
@@ -135,3 +135,59 @@ export function rasterizePdfFile(diskPath: string, pdfSha256: string): { bytes:
135
135
  fs.rmSync(path.dirname(out), { recursive: true, force: true })
136
136
  }
137
137
  }
138
+
139
+ // actool compiles an svg imageset to a vector rendition. the engine decodes
140
+ // rasters only, so an svg imageset travels as its 3x png like a pdf one.
141
+ // AppKit draws svg on macOS; other hosts have no svg renderer here and keep
142
+ // serving the file as it is.
143
+ const RASTER_SVG_SWIFT = `import AppKit
144
+ guard CommandLine.arguments.count == 4 else { exit(1) }
145
+ let input = URL(fileURLWithPath: CommandLine.arguments[1])
146
+ let scale = CGFloat(Double(CommandLine.arguments[2]) ?? 3.0)
147
+ let output = URL(fileURLWithPath: CommandLine.arguments[3])
148
+ guard let image = NSImage(contentsOf: input), image.size.width > 0, image.size.height > 0 else { exit(2) }
149
+ let width = Int(ceil(image.size.width * scale))
150
+ let height = Int(ceil(image.size.height * scale))
151
+ if width > 12000 || height > 12000 { exit(3) }
152
+ guard let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: width, pixelsHigh: height, bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0) else { exit(4) }
153
+ guard let context = NSGraphicsContext(bitmapImageRep: rep) else { exit(5) }
154
+ NSGraphicsContext.saveGraphicsState()
155
+ NSGraphicsContext.current = context
156
+ context.imageInterpolation = .high
157
+ image.draw(in: NSRect(x: 0, y: 0, width: width, height: height), from: .zero, operation: .copy, fraction: 1)
158
+ NSGraphicsContext.restoreGraphicsState()
159
+ guard let data = rep.representation(using: .png, properties: [:]) else { exit(6) }
160
+ do { try data.write(to: output) } catch { exit(7) }
161
+ `
162
+
163
+ /**
164
+ * the svg file as 3x png bytes, cached by the svg's sha256, or null off macOS.
165
+ * throws when the svg cannot rasterize, like actool failing the build.
166
+ */
167
+ export function rasterizeSvgFile(
168
+ diskPath: string,
169
+ svgSha256: string,
170
+ ): { bytes: Buffer } | null {
171
+ if (process.platform !== 'darwin') return null
172
+ const binary = rasterBinary(RASTER_SVG_SWIFT, 'swift-svg-raster')
173
+ const tag = createHash('sha256').update(RASTER_SVG_SWIFT).digest('hex').slice(0, 16)
174
+ const cached = path.join(cacheDir(), `swift-svg-png-${tag}-${svgSha256}.png`)
175
+ if (fs.existsSync(cached)) return { bytes: fs.readFileSync(cached) }
176
+ const out = path.join(
177
+ fs.mkdtempSync(path.join(os.tmpdir(), 'swift-svg-png-')),
178
+ 'out.png',
179
+ )
180
+ try {
181
+ execFileSync(binary, [diskPath, '3', out], { stdio: 'pipe' })
182
+ const bytes = fs.readFileSync(out)
183
+ fs.mkdirSync(cacheDir(), { recursive: true })
184
+ fs.copyFileSync(out, cached)
185
+ return { bytes: Buffer.from(bytes) }
186
+ } catch (error) {
187
+ throw new Error(
188
+ `swift svg asset ${diskPath} did not rasterize: ${error instanceof Error ? error.message : String(error)}`,
189
+ )
190
+ } finally {
191
+ fs.rmSync(path.dirname(out), { recursive: true, force: true })
192
+ }
193
+ }
@@ -260,7 +260,7 @@ export function swiftSharedSdkViewOptions(
260
260
  .map((entry) => path.join(entry.parentPath, entry.name))
261
261
  .sort()
262
262
  const key = JSON.stringify([
263
- 'v22',
263
+ 'v23',
264
264
  toolchainBin,
265
265
  sdk,
266
266
  frameworks,
@@ -333,6 +333,7 @@ export function swiftSharedSdkViewOptions(
333
333
  ...[
334
334
  'MacTypes.h',
335
335
  'objc/NSObject.h',
336
+ 'ObjectiveC.apinotes',
336
337
  'net/if.h',
337
338
  'notify.h',
338
339
  'notify.modulemap',
@@ -0,0 +1,44 @@
1
+ {
2
+ "AppCheckCore": "a18d4e5aff27ff4b9bce8d6e73e55ccf1d11515311e219aa4473319cdff3187b",
3
+ "AppLovinSDK": "c00f052c4b15766a6a2734e2b3685234e6bd28dbc47fbe7cbc3edbf56f701d5c",
4
+ "AppsFlyerLib": "13bae495e63e22579dd9525a1c9e88d8eedc78b4586979b7e2d492cfd3efbe1f",
5
+ "FBAEMKit": "ceaf685683c6a23ae4893150d0d770aeeaec34811ac8c146b3aa351beade5fa0",
6
+ "FBAudienceNetwork": "4d84bf1e404a83852a93af2ae73e22e45bb2b11e0a9a445c3b461173a5d6aec3",
7
+ "FBLPromises": "3544fb457e7f60c69740cdd26617a75bdd613943e948becca643022c7edd76c0",
8
+ "FBSDKCoreKit": "1577edd62ec0c172928befed3b309dc59ae8915d2aaad091460d9d1be5ddc13d",
9
+ "FBSDKCoreKit_Basics": "c780833f204f9ec6eab70a3758a45c5c78bfb6f4e590289ccf395497f204cac1",
10
+ "FirebaseAnalytics": "e3253a494375c5174d20cb81925e20afa1ff6b1419125cb608d39b092b53ff2a",
11
+ "FirebaseAppCheck": "af82d72727d55d14f65eee96845d4d9495e4e603b4673709d6f3448b9595cc63",
12
+ "FirebaseAppCheckInterop": "7ffd54e6fe187bf8cd714e3d863e0095f7cbbb0fb802adb87a40c552de7cffcc",
13
+ "FirebaseAuth": "fcde09db8d45ffba67802e81c17b8046db6b56568226ace3fca898983b08c968",
14
+ "FirebaseAuthInterop": "e8e6f4fb42b3fa76c2bade7a522ab0f224558d27d2321175c791d307541787a8",
15
+ "FirebaseCore": "30e3505c715e17682c1dc20bb26ba475e99e6981a9a0dba3cf9352eea632fc1d",
16
+ "FirebaseCoreExtension": "e37ce2abcd4c218ab5426da78cbe7ab41f79ee7eba1d02dd4b0cde952ed2c4a0",
17
+ "FirebaseCoreInternal": "72a15c0c63585faf93e9ffa91e8a8c1c50b24749405804ffae19a29ec05b07ab",
18
+ "FirebaseCrashlytics": "e03c71913efd97678b895abb1e968c83e58b3fbd7955a81ec6e6581b95db16e3",
19
+ "FirebaseFirestore": "f7a1bb7fc4a2fb09298b514114d6aaca9a4f00fd8868667524a05bc4563bf1fd",
20
+ "FirebaseFirestoreInternal": "d9595a1784beaf5cd4a8e0dda0f4364ddfa6b536ad60f82746d81d14dce037a3",
21
+ "FirebaseInstallations": "141e313325bab001f2dbb79dc8a433f884f4c4a12a5feb665e6958098d637f7b",
22
+ "FirebaseRemoteConfig": "e0ae6d626a423d535bc67216f9f0cd66f98f1c0fb4b5bf88074d4496733e2db1",
23
+ "FirebaseRemoteConfigInterop": "794f599eb4232058715b606fa671639c8cc5d821655a0f739651d17c5ef65c37",
24
+ "FirebaseSessions": "1781d72e47dac0fc7a532412641021730bd5b659135633cd9ef7b97ccd31b0ce",
25
+ "FirebaseSharedSwift": "8d63b09a517733ef3a58390bf1e8cf054f058bdd618bb4f19a1f4b5a0b4f09e5",
26
+ "FirebaseStorage": "636b33180dd5ad60b4878357691fe6472cf3bd57ec691e9d661c5444f523df66",
27
+ "GTMSessionFetcher": "f58dc2bd9db39defd73f0f67e7a11893a0c6e6f0ba45cd83cf420b2b3c15f1bd",
28
+ "GoogleAdsOnDeviceConversion": "31a5a1f5204f4844a480d3889b6ebe2e69473ef32b868935c51812c0483cb08b",
29
+ "GoogleAppMeasurement": "5741e6334392e0345f1b5896111ffef4d5a78859970f5e197fa0b7d881165305",
30
+ "GoogleAppMeasurementIdentitySupport": "b70cb033eeb002ed1c5a8140953ccb3be0221ca754c05fe450ed9c9c6547f274",
31
+ "GoogleDataTransport": "7d08050419e0906f13039cc4d2dd69be075234c0bf5bbb34df9dd4891e48831d",
32
+ "GoogleMobileAds": "f2c09c60ee331ce029f563304ad73a481d57ace0d4bc11ce33a2bf59497c59bf",
33
+ "GoogleUtilities": "37a9d3d3810dad763a8a79bd4c7cc4c37b386240725aca07f45dba1826676c8c",
34
+ "Intercom": "fc8251f24b305b91f83304d4dffaf1a90c424a7bc37be8b595dd1fc5cff566ea",
35
+ "Promises": "6d8f1a4b3d561d67adfc2026834779b05685d1cdacea6e83c70d0641c39f24de",
36
+ "RecaptchaInterop": "cf5cc62ebc237b34d5267c1190d18f33b424dbc7f81713f127108d0ad8a592cf",
37
+ "RiveRuntime": "72b6ff5c5a1d153c9cdbea9a917c09be557cfcb1fafa02853fa06b0268551710",
38
+ "absl": "fff0388cf074c69a2da4bc197a005da0b8e5c23ebdcfa383600c540a342f9df1",
39
+ "grpc": "918737c9f8f93e14127b3894e31c7a0522475f2247b74f87d8166dff3a6bafb0",
40
+ "grpcpp": "b83f85e0256cf06df00cf0ed728b5c0d68373ca401742877935771447450b90a",
41
+ "leveldb": "5521a6e6e4cd01b2e31b099d4341f1bccae7e8ba43de648b028928573daf8bb4",
42
+ "nanopb": "a7fafe2e4e16d99de4c58f72e22dcc53221885aa6d678d1270123e4b01badfa3",
43
+ "openssl_grpc": "b2aaede82457cdd15915762a4f57b38e28ba0f47b9b48556a7e0c46881973096"
44
+ }
@@ -0,0 +1,12 @@
1
+ import archives from './swift-shipped-archives.json'
2
+
3
+ // the archive checksum of each vendor binary whose surface peach ships as a module
4
+ // (scripts/debug/swift-binary-standin-generate.ts writes the table). a package pinning a
5
+ // different archive gets its own stand-in, since the shipped module declares another version's API.
6
+ const SHIPPED_ARCHIVES = new Map<string, string>(Object.entries(archives))
7
+
8
+ /** true when `target` is a binary peach ships and the app's pinned archive is another one. */
9
+ export function shippedBinaryDiffers(target: string, checksum: string | null): boolean {
10
+ const shipped = SHIPPED_ARCHIVES.get(target)
11
+ return shipped !== undefined && checksum !== null && checksum !== shipped
12
+ }
@@ -0,0 +1,248 @@
1
+ import type { SwiftStandinBehaviors } from './swift-standin-emit'
2
+
3
+ // behavior the stand-in generator gives a closed binary framework in every
4
+ // app. an app's own configured behavior for the same declaration replaces it.
5
+ //
6
+ // GoogleCast: Peach has no local network to browse, so a Cast context
7
+ // initializes, discovery runs and finds no receiver, and no session can
8
+ // start. the values below are what the iOS framework reports in that state;
9
+ // the receiver-facing and UI members stay trapping stand-ins.
10
+ const BUILTIN_STANDIN_BEHAVIOR: SwiftStandinBehaviors = {
11
+ GoogleCast: {
12
+ kGCKCastDeviceCategory: { body: 'return "com.google.cast.CastDevice"' },
13
+ kGCKDefaultMediaReceiverApplicationID: { body: 'return "CC1AD845"' },
14
+ kGCKErrorDomain: { body: 'return "com.google.cast.GCKError"' },
15
+ 'GCKError.init(code:)': {
16
+ body: 'super.init(domain: kGCKErrorDomain, code: code.rawValue, userInfo: nil)',
17
+ },
18
+
19
+ 'GCKDiscoveryCriteria.applicationIDs': { stored: '' },
20
+ 'GCKDiscoveryCriteria.namespaces': { stored: '' },
21
+ 'GCKDiscoveryCriteria.hasApplicationIDs': { body: 'return applicationIDs != nil' },
22
+ 'GCKDiscoveryCriteria.hasNamespaces': { body: 'return namespaces != nil' },
23
+ 'GCKDiscoveryCriteria.init(applicationID:)': {
24
+ body: 'super.init(); applicationIDs = NSOrderedSet(object: applicationID)',
25
+ },
26
+ 'GCKDiscoveryCriteria.init(namespaces:)': {
27
+ body: 'super.init(); self.namespaces = namespaces',
28
+ },
29
+
30
+ GCKLaunchOptions: {
31
+ members: `
32
+ private static var peachDeviceLanguageCode: String? { Locale.preferredLanguages.first }
33
+ `,
34
+ },
35
+ 'GCKLaunchOptions.languageCode': { stored: '' },
36
+ 'GCKLaunchOptions.relaunchIfRunning': { stored: 'false' },
37
+ 'GCKLaunchOptions.androidReceiverCompatible': { stored: 'false' },
38
+ 'GCKLaunchOptions.init()': {
39
+ body: 'super.init(); languageCode = GCKLaunchOptions.peachDeviceLanguageCode',
40
+ },
41
+ 'GCKLaunchOptions.init(relaunchIfRunning:)': {
42
+ body: `
43
+ super.init()
44
+ languageCode = GCKLaunchOptions.peachDeviceLanguageCode
45
+ self.relaunchIfRunning = relaunchIfRunning
46
+ `,
47
+ },
48
+ 'GCKLaunchOptions.init(languageCode:relaunchIfRunning:)': {
49
+ body: `
50
+ super.init()
51
+ self.languageCode = languageCode
52
+ self.relaunchIfRunning = relaunchIfRunning
53
+ `,
54
+ },
55
+ 'GCKLaunchOptions.init(relaunchIfRunning:androidReceiverCompatible:)': {
56
+ body: `
57
+ super.init()
58
+ languageCode = GCKLaunchOptions.peachDeviceLanguageCode
59
+ self.relaunchIfRunning = relaunchIfRunning
60
+ self.androidReceiverCompatible = androidReceiverCompatible
61
+ `,
62
+ },
63
+ 'GCKLaunchOptions.init(relaunchIfRunning:languageCode:androidReceiverCompatible:)': {
64
+ body: `
65
+ super.init()
66
+ self.languageCode = languageCode
67
+ self.relaunchIfRunning = relaunchIfRunning
68
+ self.androidReceiverCompatible = androidReceiverCompatible
69
+ `,
70
+ },
71
+
72
+ GCKCastOptions: {
73
+ members: 'fileprivate var peachDiscoveryCriteria: GCKDiscoveryCriteria?',
74
+ },
75
+ 'GCKCastOptions.init(discoveryCriteria:)': {
76
+ body: 'super.init(); peachDiscoveryCriteria = discoveryCriteria',
77
+ },
78
+ 'GCKCastOptions.init(receiverApplicationID:)': {
79
+ body: 'super.init(); peachDiscoveryCriteria = GCKDiscoveryCriteria(applicationID: applicationID)',
80
+ },
81
+ 'GCKCastOptions.init(supportedNamespaces:)': {
82
+ body: 'super.init(); peachDiscoveryCriteria = GCKDiscoveryCriteria(namespaces: Set(namespaces))',
83
+ },
84
+ 'GCKCastOptions.physicalVolumeButtonsWillControlDeviceVolume': { stored: 'false' },
85
+ 'GCKCastOptions.disableDiscoveryAutostart': { stored: 'false' },
86
+ 'GCKCastOptions.disableAnalyticsLogging': { stored: 'false' },
87
+ 'GCKCastOptions.launchOptions': { stored: '' },
88
+ 'GCKCastOptions.sharedContainerIdentifier': { stored: '' },
89
+ 'GCKCastOptions.suspendSessionsWhenBackgrounded': { stored: 'true' },
90
+ 'GCKCastOptions.stopReceiverApplicationWhenEndingSession': { stored: 'false' },
91
+ 'GCKCastOptions.startDiscoveryAfterFirstTapOnCastButton': { stored: 'true' },
92
+
93
+ GCKCastContext: {
94
+ members: `
95
+ nonisolated(unsafe) fileprivate static var peachShared: GCKCastContext?
96
+ fileprivate let peachDiscoveryManager = GCKDiscoveryManager()
97
+ fileprivate let peachSessionManager = GCKSessionManager()
98
+ fileprivate var peachCredentialsData: GCKCredentialsData?
99
+ fileprivate static func peachInitialize(_ options: GCKCastOptions) {
100
+ let context = GCKCastContext()
101
+ peachShared = context
102
+ if !options.disableDiscoveryAutostart && !options.startDiscoveryAfterFirstTapOnCastButton {
103
+ context.peachDiscoveryManager.startDiscovery()
104
+ }
105
+ }
106
+ `,
107
+ },
108
+ 'GCKCastContext.imageCache': { stored: '' },
109
+ 'GCKCastContext.imagePicker': { stored: '' },
110
+ 'GCKCastContext.useDefaultExpandedMediaControls': { stored: 'false' },
111
+ 'GCKCastContext.castState': { body: 'return .noDevicesAvailable' },
112
+ 'GCKCastContext.discoveryManager': { body: 'return peachDiscoveryManager' },
113
+ 'GCKCastContext.sessionManager': { body: 'return peachSessionManager' },
114
+ 'GCKCastContext.setLaunch(_:)': { body: 'peachCredentialsData = credentialsData' },
115
+ 'GCKCastContext.isSharedInstanceInitialized()': {
116
+ body: 'return peachShared != nil',
117
+ },
118
+ 'GCKCastContext.sharedInstance()': {
119
+ body: `
120
+ guard let shared = peachShared else {
121
+ fatalError("GCKCastContext.sharedInstance() was called before the shared instance was initialized")
122
+ }
123
+ return unsafeDowncast(shared, to: Self.self)
124
+ `,
125
+ },
126
+ 'GCKCastContext.setSharedInstanceWith(_:)': {
127
+ body: `
128
+ if peachShared != nil {
129
+ fatalError("GCKCastContext.setSharedInstanceWith(_:) was called when the shared instance was already initialized")
130
+ }
131
+ peachInitialize(options)
132
+ `,
133
+ },
134
+ 'GCKCastContext.setSharedInstanceWith(_:error:)': {
135
+ body: `
136
+ if peachShared != nil {
137
+ error?.pointee = GCKError(code: .alreadyInitialized)
138
+ return false
139
+ }
140
+ peachInitialize(options)
141
+ return true
142
+ `,
143
+ },
144
+
145
+ GCKDiscoveryManager: {
146
+ members: `
147
+ private final class PeachListener {
148
+ weak var listener: (any GCKDiscoveryManagerListener)?
149
+ init(_ listener: any GCKDiscoveryManagerListener) { self.listener = listener }
150
+ }
151
+ private var peachListeners: [PeachListener] = []
152
+ private var peachState: GCKDiscoveryState = .stopped
153
+ `,
154
+ },
155
+ 'GCKDiscoveryManager.discoveryState': { body: 'return peachState' },
156
+ 'GCKDiscoveryManager.hasDiscoveredDevices': { body: 'return false' },
157
+ 'GCKDiscoveryManager.passiveScan': { stored: 'false' },
158
+ 'GCKDiscoveryManager.discoveryActive': { body: 'return peachState == .running' },
159
+ 'GCKDiscoveryManager.deviceCount': { body: 'return 0' },
160
+ 'GCKDiscoveryManager.add(_:)': {
161
+ body: `
162
+ peachListeners.removeAll { $0.listener == nil }
163
+ if !peachListeners.contains(where: { $0.listener === listener }) {
164
+ peachListeners.append(PeachListener(listener))
165
+ }
166
+ `,
167
+ },
168
+ 'GCKDiscoveryManager.remove(_:)': {
169
+ body: 'peachListeners.removeAll { $0.listener == nil || $0.listener === listener }',
170
+ },
171
+ 'GCKDiscoveryManager.startDiscovery()': {
172
+ body: `
173
+ if peachState == .running { return }
174
+ peachState = .running
175
+ for entry in peachListeners {
176
+ entry.listener?.didStartDiscovery(forDeviceCategory: kGCKCastDeviceCategory)
177
+ }
178
+ `,
179
+ },
180
+ 'GCKDiscoveryManager.stopDiscovery()': { body: 'peachState = .stopped' },
181
+ 'GCKDiscoveryManager.isDiscoveryActive(forDeviceCategory:)': {
182
+ body: 'return peachState == .running && deviceCategory == kGCKCastDeviceCategory',
183
+ },
184
+ 'GCKDiscoveryManager.device(at:)': {
185
+ body: 'fatalError("GCKDiscoveryManager.device(at:) index \\(index) is out of range: no Cast device is discovered")',
186
+ },
187
+ 'GCKDiscoveryManager.device(withUniqueID:)': { body: 'return nil' },
188
+ 'GCKDiscoveryManager.cancelFindOperation()': { body: '' },
189
+
190
+ GCKSessionManager: {
191
+ members: `
192
+ private var peachListeners: [any GCKSessionManagerListener] = []
193
+ private var peachDefaultSessionOptions: [String: [String: any NSCoding & NSObjectProtocol]] = [:]
194
+ `,
195
+ },
196
+ 'GCKSessionManager.currentSession': { body: 'return nil' },
197
+ 'GCKSessionManager.currentCastSession': { body: 'return nil' },
198
+ 'GCKSessionManager.connectionState': { body: 'return .disconnected' },
199
+ 'GCKSessionManager.hasConnectedSession()': { body: 'return false' },
200
+ 'GCKSessionManager.hasConnectedCastSession()': { body: 'return false' },
201
+ 'GCKSessionManager.startSession(with:)': { body: 'return false' },
202
+ 'GCKSessionManager.startSession(with:sessionOptions:)': { body: 'return false' },
203
+ 'GCKSessionManager.suspendSession(with:)': { body: 'return false' },
204
+ 'GCKSessionManager.endSession()': { body: 'return false' },
205
+ 'GCKSessionManager.endSessionAndStopCasting(_:)': { body: 'return false' },
206
+ 'GCKSessionManager.setDefaultSessionOptions(_:forDeviceCategory:)': {
207
+ body: 'peachDefaultSessionOptions[category] = sessionOptions',
208
+ },
209
+ 'GCKSessionManager.defaultSessionOptions(forDeviceCategory:)': {
210
+ body: 'return peachDefaultSessionOptions[category]',
211
+ },
212
+ 'GCKSessionManager.add(_:)': {
213
+ body: `
214
+ if !peachListeners.contains(where: { $0 === listener }) { peachListeners.append(listener) }
215
+ `,
216
+ },
217
+ 'GCKSessionManager.remove(_:)': {
218
+ body: 'peachListeners.removeAll { $0 === listener }',
219
+ },
220
+
221
+ GCKLogger: {
222
+ members: 'nonisolated(unsafe) fileprivate static let peachShared = GCKLogger()',
223
+ },
224
+ 'GCKLogger.sharedInstance()': { body: 'return peachShared' },
225
+ 'GCKLogger.delegate': { stored: '' },
226
+ 'GCKLogger.filter': { stored: '' },
227
+ 'GCKLogger.loggingEnabled': { stored: 'true' },
228
+ 'GCKLogger.fileLoggingEnabled': { stored: 'false' },
229
+ 'GCKLogger.consoleLoggingEnabled': { stored: 'false' },
230
+ },
231
+ }
232
+
233
+ export function withBuiltinStandinBehavior(
234
+ behavior: SwiftStandinBehaviors,
235
+ ): SwiftStandinBehaviors {
236
+ const merged: SwiftStandinBehaviors = { ...behavior }
237
+ for (const [module, members] of Object.entries(BUILTIN_STANDIN_BEHAVIOR))
238
+ merged[module] = {
239
+ ...Object.fromEntries(
240
+ Object.entries(members).map(([path, entry]) => [
241
+ path,
242
+ { ...entry, builtin: true },
243
+ ]),
244
+ ),
245
+ ...behavior[module],
246
+ }
247
+ return merged
248
+ }
@@ -178,6 +178,8 @@ export type StandinOptions = {
178
178
  plain?: ReadonlySet<string>
179
179
  /** paths whose type the guest cannot represent in objective-c: emitted without @objc */
180
180
  unobjc?: ReadonlySet<string>
181
+ /** classes whose superclass declares init(coder:) non-failable: the compiler rejected the failable one */
182
+ coderNonfailable?: ReadonlySet<string>
181
183
  /** class path → objective-c protocols the compiler found its witnesses mismatch (nullability a swift protocol checks); the class drops the conformance */
182
184
  unconformed?: ReadonlyMap<string, ReadonlySet<string>>
183
185
  /** paths the compiler says must be marked override */
@@ -207,6 +209,8 @@ export type StandinBehavior = {
207
209
  set?: string
208
210
  /** a stored property instead of a computed one, with this initial value */
209
211
  stored?: string
212
+ /** generator-owned behavior, skipped where a framework version lacks the declaration */
213
+ builtin?: true
210
214
  }
211
215
 
212
216
  export type SwiftStandinBehaviors = Record<string, Record<string, StandinBehavior>>
@@ -1642,7 +1646,7 @@ export function emitSwiftStandin(
1642
1646
  externalRoot(id) !== null
1643
1647
  )
1644
1648
  emit(
1645
- `${inner}public required init?(coder: NSCoder) { ${options.inert ? 'return nil' : trap(`${path}.init(coder:)`)} }`,
1649
+ `${inner}public required init${options.coderNonfailable?.has(path) ? '' : '?'}(coder: NSCoder) { ${options.inert && !options.coderNonfailable?.has(path) ? 'return nil' : trap(`${path}.init(coder:)`)} }`,
1646
1650
  )
1647
1651
  // a designated init drops the inherited required init(), so a
1648
1652
  // subclass restates it
@@ -1888,6 +1892,8 @@ export function emitSwiftStandin(
1888
1892
  .replace(/^(?:weak |unowned )/, '')
1889
1893
  .replace(/^((?:static )?)let /, '$1var ')
1890
1894
  const witness = `${owner}.${leaf(member)}`
1895
+ // a superclass the graph cannot see already declares what the compiler says must override
1896
+ if (options.forcedOverride?.has(witness)) return
1891
1897
  const body = options.inert ? inertBody(member) : trap(witness)
1892
1898
  if (
1893
1899
  member.kind.identifier === 'swift.property' ||
@@ -1897,11 +1903,13 @@ export function emitSwiftStandin(
1897
1903
  const setter = parsed.settable
1898
1904
  ? ` ${parsed.nonmutating ? 'nonmutating ' : ''}set { ${body} }`
1899
1905
  : ''
1900
- emit(
1906
+ emitAt(
1907
+ witness,
1901
1908
  `${indent}${visibility} ${parsed.decl} { get${parsed.effects} { ${body} }${setter} }`,
1902
1909
  )
1903
1910
  } else
1904
- emit(
1911
+ emitAt(
1912
+ witness,
1905
1913
  `${indent}${member.kind.identifier === 'swift.init' ? 'public required ' : visibility + ' '}${stripDefaults(decl)} { ${body} }`,
1906
1914
  )
1907
1915
  }