peachsim 0.1.2208 → 0.1.2209

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 (121) 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 +448 -22
  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 +436 -16
  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 +448 -22
  31. package/dist-lib/host/fetch-proxy-handler.cjs +4 -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 +4 -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 +4 -4
  47. package/dist-lib/native-app-identity-project.cjs +2 -2
  48. package/dist-lib/native-app-identity-project.mjs +2 -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 +59 -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 +5482 -381
  68. package/dist-lib/swift-compile.cjs +98 -6
  69. package/dist-lib/swift-compile.mjs +98 -6
  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 +351 -13
  77. package/dist-lib/vite.cjs +4 -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/UIKit.framework/Headers/UIFeedbackGenerator.h +1 -1
  101. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UIImpactFeedbackGenerator.h +1 -1
  102. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UINibLoading.h +1 -1
  103. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UINotificationFeedbackGenerator.h +1 -1
  104. package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UISelectionFeedbackGenerator.h +1 -1
  105. package/sdk/ios/usr/include/ObjectiveC.apinotes +7 -0
  106. package/src/android-theme.ts +136 -2
  107. package/src/expo-swift-host.ts +90 -1
  108. package/src/generated/android-framework-text.json +4566 -0
  109. package/src/generated/android-framework-themes.json +11 -0
  110. package/src/kotlin-app.ts +24 -4
  111. package/src/kotlin-host.ts +9 -0
  112. package/src/nitro-adapter.lock.json +246 -246
  113. package/src/nitro-superset.lock.json +4 -4
  114. package/src/swift-compile.ts +120 -2
  115. package/src/swift-distribution.lock.json +8 -8
  116. package/src/swift-objc-standin.ts +9 -2
  117. package/src/swift-shared-sdk.ts +2 -1
  118. package/src/swift-standin-builtin-behavior.ts +248 -0
  119. package/src/swift-standin-emit.ts +2 -0
  120. package/src/swift-standins.ts +17 -5
  121. package/src/turbo-runtime.lock.json +17 -17
@@ -1373,6 +1373,104 @@ export function swiftSystemLibraryExclusions(
1373
1373
  )
1374
1374
  }
1375
1375
 
1376
+ // EXUpdates publicly imports these C targets. The distribution links their
1377
+ // objects and ships no clang module, so a later `import EXUpdates` fails
1378
+ // with missing required modules EXStructuredHeaders and EXUpdatesBSPatch.
1379
+ // Headers match packages/sootsim-swift/Sources for those targets.
1380
+ const DISTRIBUTION_CLANG_MODULES: {
1381
+ name: string
1382
+ header: string
1383
+ source: string
1384
+ }[] = [
1385
+ {
1386
+ name: 'EXStructuredHeaders',
1387
+ header: 'EXStructuredHeaders/EXStructuredHeadersParser.h',
1388
+ source: `// Copyright © 2021 650 Industries. All rights reserved.
1389
+
1390
+ #import <Foundation/Foundation.h>
1391
+
1392
+ NS_ASSUME_NONNULL_BEGIN
1393
+
1394
+ typedef NS_ENUM(NSInteger, EXStructuredHeadersParserFieldType) {
1395
+ EXStructuredHeadersParserFieldTypeDictionary,
1396
+ EXStructuredHeadersParserFieldTypeList,
1397
+ EXStructuredHeadersParserFieldTypeItem
1398
+ };
1399
+
1400
+ @interface EXStructuredHeadersParser : NSObject
1401
+
1402
+ - (instancetype)initWithRawInput:(NSString *)raw
1403
+ fieldType:(EXStructuredHeadersParserFieldType)fieldType;
1404
+
1405
+ - (instancetype)initWithRawInput:(NSString *)raw
1406
+ fieldType:(EXStructuredHeadersParserFieldType)fieldType
1407
+ ignoringParameters:(BOOL)shouldIgnoreParameters;
1408
+
1409
+ - (nullable id)parseStructuredFieldsWithError:(NSError ** _Nullable)error;
1410
+
1411
+ @end
1412
+
1413
+ NS_ASSUME_NONNULL_END
1414
+ `,
1415
+ },
1416
+ {
1417
+ name: 'EXUpdatesBSPatch',
1418
+ header: 'EXUpdatesBSPatch.h',
1419
+ source: `// Copyright 2015-present 650 Industries. All rights reserved.
1420
+
1421
+ #pragma once
1422
+
1423
+ #import <Foundation/Foundation.h>
1424
+
1425
+ int EXUpdatesApplyBSDiffPatch(const char * _Nonnull oldFilePath,
1426
+ const char * _Nonnull newFilePath,
1427
+ const char * _Nonnull patchFilePath);
1428
+ `,
1429
+ },
1430
+ ]
1431
+
1432
+ function distributionClangModulePresent(modules: string, name: string): boolean {
1433
+ return (
1434
+ existsSync(path.join(modules, `${name}.swiftmodule`)) ||
1435
+ existsSync(path.join(modules, name, 'module.modulemap'))
1436
+ )
1437
+ }
1438
+
1439
+ /** module map for distribution C targets the archive omitted, or null when
1440
+ * the archive already provides them. */
1441
+ function distributionClangModuleMap(root: string, modules: string): string | null {
1442
+ const missing = DISTRIBUTION_CLANG_MODULES.filter(
1443
+ (mod) => !distributionClangModulePresent(modules, mod.name),
1444
+ )
1445
+ if (missing.length === 0) return null
1446
+ const key = createHash('sha256')
1447
+ .update(modules)
1448
+ .update(missing.map((mod) => `${mod.name}\0${mod.source}`).join('\0'))
1449
+ .digest('hex')
1450
+ .slice(0, 16)
1451
+ const directory = path.join(root, `.peach-clang-modules-${key}`)
1452
+ const mapPath = path.join(directory, 'module.modulemap')
1453
+ if (!existsSync(mapPath)) {
1454
+ mkdirSync(directory, { recursive: true })
1455
+ const parts: string[] = []
1456
+ for (const mod of missing) {
1457
+ const destination = path.join(directory, mod.header)
1458
+ mkdirSync(path.dirname(destination), { recursive: true })
1459
+ writeFileSync(destination, mod.source)
1460
+ parts.push(
1461
+ `module ${mod.name} {\n requires objc\n header "${mod.header}"\n export *\n}\n`,
1462
+ )
1463
+ }
1464
+ writeFileSync(mapPath, parts.join('\n'))
1465
+ }
1466
+ return mapPath
1467
+ }
1468
+
1469
+ function distributionClangModuleOptions(root: string, modules: string): string[] {
1470
+ const map = distributionClangModuleMap(root, modules)
1471
+ return map === null ? [] : ['-Xcc', `-fmodule-map-file=${map}`]
1472
+ }
1473
+
1376
1474
  /** prebuilt modules without interfaces owned by the compiling source graph. */
1377
1475
  function providedModulesPath(
1378
1476
  root: string,
@@ -2038,7 +2136,9 @@ export function emitSwiftPackageManifest(args: {
2038
2136
  path.join(moduleRoot, 'modules'),
2039
2137
  args.moduleExcludes,
2040
2138
  ),
2041
- )}`
2139
+ )}${distributionClangModuleOptions(args.root, path.join(moduleRoot, 'modules'))
2140
+ .map((flag) => `, ${JSON.stringify(flag)}`)
2141
+ .join('')}`
2042
2142
  : prebuilt
2043
2143
  ? `, "-Isystem", ${JSON.stringify(providedModulesPath(args.root, prebuilt.modules, args.moduleExcludes))}${prebuilt.moduleMaps
2044
2144
  .map((map) => `, "-Xcc", ${JSON.stringify(`-fmodule-map-file=${map}`)}`)
@@ -2351,6 +2451,9 @@ export function syncSwiftTree(base: string, files: Map<string, string | Buffer>)
2351
2451
  dir === base &&
2352
2452
  (entry.name === '.build' ||
2353
2453
  entry.name.startsWith('.peach-modules-') ||
2454
+ // distribution clang maps are written beside the project and named
2455
+ // from the compiler flags, so a sync must not remove them.
2456
+ entry.name.startsWith('.peach-clang-modules-') ||
2354
2457
  entry.name === SWIFT_LINK_STAMP)
2355
2458
  )
2356
2459
  continue
@@ -5205,13 +5308,21 @@ export function writeSwiftProject(
5205
5308
  // swiftpm plans a build root's build once and reuses the plan until a
5206
5309
  // manifest changes, so a file added to the module would never compile
5207
5310
  // there (RAN: a broken new UIKitCore file built "complete" in 0.1s). the
5208
- // module's file list and package flags replan when either changes.
5311
+ // module's file list, the package flags, and the app package's swift
5312
+ // names replan when any changes. names only, so an edit of a file already
5313
+ // in the plan still incremental-compiles.
5209
5314
  const modulePlan = createHash('sha256').update(
5210
5315
  swiftModuleInputFiles(moduleRoot).join('\n'),
5211
5316
  )
5212
5317
  if (!distribution) {
5213
5318
  modulePlan.update(readFileSync(path.join(moduleRoot, 'Package.swift')))
5214
5319
  }
5320
+ modulePlan.update(
5321
+ Object.keys(input.files)
5322
+ .filter((file) => file.endsWith('.swift'))
5323
+ .sort()
5324
+ .join('\n'),
5325
+ )
5215
5326
  const resourcePlan = createHash('sha256')
5216
5327
  .update(
5217
5328
  JSON.stringify(
@@ -5744,6 +5855,12 @@ export function writeSwiftProject(
5744
5855
  : prebuilt
5745
5856
  ? providedModulesPath(layout.root, prebuilt.modules, moduleExcludes)
5746
5857
  : path.join(layout.root, '.build', WASM_TRIPLE, 'release', 'Modules'),
5858
+ ...(distribution
5859
+ ? distributionClangModuleOptions(
5860
+ layout.root,
5861
+ path.join(moduleRoot, 'modules'),
5862
+ )
5863
+ : []),
5747
5864
  ...(prebuilt?.moduleMaps.flatMap((map) => [
5748
5865
  '-Xcc',
5749
5866
  `-fmodule-map-file=${map}`,
@@ -6886,6 +7003,7 @@ function compileSwiftProjectOnce(
6886
7003
  if (
6887
7004
  !options.intermediates &&
6888
7005
  process.platform === 'darwin' &&
7006
+ !options.intermediates &&
6889
7007
  process.env.TM_SESSION &&
6890
7008
  !windowAdmission() &&
6891
7009
  process.env.CI !== 'true' &&
@@ -1,10 +1,10 @@
1
1
  {
2
- "id": "87fc4d2ff9d5d588",
2
+ "id": "e7ae8fdb51086f73",
3
3
  "release": "swift-6.4.0-RELEASE-custom-11345d60dca47496",
4
4
  "wasmSdkId": "swift-6.4.0-RELEASE_wasm-peach-19471d4b",
5
5
  "wasmSdkUrl": "https://r2.sootsim.com/swift-wasm-sdk/swift-6.4.0-RELEASE_wasm-peach-19471d4b.artifactbundle.tar.gz",
6
6
  "wasmSdkChecksum": "764c16e7e34156bf90d6c3372a2b77b98b9d8c3470235520d0f9619f90f33456",
7
- "source": "08519cc5f11db43a2f85f28c47ec6c8930843f93",
7
+ "source": "dbcdd2998c7a523cb5136f3731f6850cfe0bd154",
8
8
  "targets": [
9
9
  "ImagePlayground",
10
10
  "QuickLookThumbnailing",
@@ -244,16 +244,16 @@
244
244
  },
245
245
  "hosts": {
246
246
  "darwin-arm64": {
247
- "sha256": "7444ad87688bb551601a49fee6b48d15978fcd877982a25a944280f553f439b5",
248
- "size": 103297800
247
+ "sha256": "8680805789e5212d83e374bea9e4af3e3c7a86011e8ebf4921e76a8eba092761",
248
+ "size": 103496854
249
249
  },
250
250
  "linux-x64": {
251
- "sha256": "03edd8359c024c592bb53b8917d9efc59f9b76871966b41189838deb2b9c27f2",
252
- "size": 106017072
251
+ "sha256": "9d82820dfdbc857d5127c489b9c704c9e9336fe8b010256cd5b1d24ba956f454",
252
+ "size": 106214710
253
253
  },
254
254
  "linux-arm64": {
255
- "sha256": "00a89f46a581f73ea6b0343f21fa330bbe1ae444a1d29ad7251e87a86e4bc91b",
256
- "size": 105508093
255
+ "sha256": "a8e5084e14867ca9245428e51cb9435bc5b34505914fa5855950951d01b6b990",
256
+ "size": 105708986
257
257
  }
258
258
  }
259
259
  }
@@ -571,11 +571,18 @@ export function objcView(
571
571
  recursive: true,
572
572
  })
573
573
  // the swift overlay owns what the generated -Swift.h header re-imports
574
- // under swift_name, so a mixed framework's intake map drops that submodule
574
+ // under swift_name, so a mixed framework's intake map drops that submodule.
575
+ // an enum the objective-c headers only forward-declare is completed by that
576
+ // header, and without it every member naming the enum leaves the import.
575
577
  const modulemap = fs.readFileSync(surface.modulemap, 'utf8')
578
+ const forwardEnum = [...originals.values()].some((text) =>
579
+ /typedef\s+NS_(?:CLOSED_)?(?:ENUM|OPTIONS)\s*\(\s*\w+\s*,\s*\w+\s*\)\s*;/.test(
580
+ text,
581
+ ),
582
+ )
576
583
  fs.writeFileSync(
577
584
  path.join(frameworks, `${surface.module}.framework`, 'Modules', 'module.modulemap'),
578
- surface.interface
585
+ surface.interface && !forwardEnum
579
586
  ? modulemap.replace(
580
587
  new RegExp(`\\n\\s*module\\s+${surface.module}\\.Swift\\s*\\{[^}]*\\}`),
581
588
  '',
@@ -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,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
+ }
@@ -207,6 +207,8 @@ export type StandinBehavior = {
207
207
  set?: string
208
208
  /** a stored property instead of a computed one, with this initial value */
209
209
  stored?: string
210
+ /** generator-owned behavior, skipped where a framework version lacks the declaration */
211
+ builtin?: true
210
212
  }
211
213
 
212
214
  export type SwiftStandinBehaviors = Record<string, Record<string, StandinBehavior>>
@@ -52,6 +52,7 @@ import {
52
52
  } from './swift-package'
53
53
  import { swiftBinaryOnDisk, type SwiftPackageBinary } from './swift-packages'
54
54
  import { swiftSharedSdkRoot } from './swift-shared-sdk'
55
+ import { withBuiltinStandinBehavior } from './swift-standin-builtin-behavior'
55
56
  import { STANDIN_SOURCE_DIGEST, standinSourceDigest } from './swift-standin-digest'
56
57
  import {
57
58
  STANDIN_IMPORTS,
@@ -1495,7 +1496,7 @@ function graphStandin(
1495
1496
  toolchain: Toolchain,
1496
1497
  work: string,
1497
1498
  requiredInits: ReadonlySet<string>,
1498
- behavior: ReadonlyMap<string, StandinBehavior>,
1499
+ declared: ReadonlyMap<string, StandinBehavior>,
1499
1500
  imports: string[] = [],
1500
1501
  requireSwift = false,
1501
1502
  objcProperties: ReadonlyMap<string, { getter: string; setter?: string }> = new Map(),
@@ -1511,6 +1512,11 @@ function graphStandin(
1511
1512
  graph.symbols.map((symbol) => symbol.pathComponents.join('.')),
1512
1513
  ),
1513
1514
  )
1515
+ // built-in behavior written against one framework version skips a declaration
1516
+ // another version lacks; a configured entry naming one is an error
1517
+ const behavior = new Map(
1518
+ [...declared].filter(([name, entry]) => !entry.builtin || paths.has(name)),
1519
+ )
1514
1520
  const swiftPaths = new Set(
1515
1521
  requireSwift
1516
1522
  ? graphs.flatMap((graph) =>
@@ -2603,9 +2609,10 @@ const built = new Map<string, SwiftStandin[] | string>()
2603
2609
  export function standinGenerationInputs(
2604
2610
  binaries: readonly SwiftPackageBinary[],
2605
2611
  toolchain: Pick<Toolchain, 'moduleRoot' | 'release'>,
2606
- behavior: SwiftStandinBehaviors = {},
2612
+ configuredBehavior: SwiftStandinBehaviors = {},
2607
2613
  sourceDir?: string,
2608
2614
  ): string {
2615
+ const behavior = withBuiltinStandinBehavior(configuredBehavior)
2609
2616
  const { moduleRoot, release } = toolchain
2610
2617
  const sdk = swiftModuleSdk(moduleRoot)
2611
2618
  const digest =
@@ -2950,10 +2957,15 @@ export async function swiftStandins(
2950
2957
  binaries: readonly SwiftPackageBinary[],
2951
2958
  toolchain: Toolchain,
2952
2959
  provided: ReadonlySet<string> = new Set(),
2953
- behavior: SwiftStandinBehaviors = {},
2960
+ configuredBehavior: SwiftStandinBehaviors = {},
2954
2961
  options: { nativeSlices?: boolean } = {},
2955
2962
  ): Promise<SwiftStandins> {
2956
- const built = await buildStandins(binaries, toolchain, provided, behavior)
2963
+ const built = await buildStandins(
2964
+ binaries,
2965
+ toolchain,
2966
+ provided,
2967
+ withBuiltinStandinBehavior(configuredBehavior),
2968
+ )
2957
2969
  return {
2958
2970
  standins:
2959
2971
  options.nativeSlices === false
@@ -2965,7 +2977,7 @@ export async function swiftStandins(
2965
2977
  standin,
2966
2978
  toolchain.moduleRoot,
2967
2979
  STANDIN_SOURCE_DIGEST,
2968
- Object.keys(behavior[standin.module] ?? {}).length > 0,
2980
+ Object.keys(configuredBehavior[standin.module] ?? {}).length > 0,
2969
2981
  () => swiftBinaryFramework(binary).dir,
2970
2982
  )
2971
2983
  : standin
@@ -12,7 +12,7 @@
12
12
  "checksum": "764c16e7e34156bf90d6c3372a2b77b98b9d8c3470235520d0f9619f90f33456"
13
13
  },
14
14
  "framework": {
15
- "distribution": "87fc4d2ff9d5d588",
15
+ "distribution": "e7ae8fdb51086f73",
16
16
  "wireAbi": "246b8412514b644113e6a26252c8ebd6de49ab4156ac5f5c98bb9e4c2ff2568b"
17
17
  },
18
18
  "archives": [
@@ -20,70 +20,70 @@
20
20
  "headers": {
21
21
  "reactNativeJsi": "0f8c2defbca69a27a848a81ae72363073bf9602fd316e57a75811be1a0528358"
22
22
  },
23
- "sha256": "6f416d065d88a6f592f0c34dca2d898f2c1adadeeacc07c2f8f4de453715f298",
24
- "size": 25393
23
+ "sha256": "e48499ac95604409b5da4b0f113e8ec3d3e7de9bd170f2f401513c4a45c234dc",
24
+ "size": 25392
25
25
  },
26
26
  {
27
27
  "headers": {
28
28
  "reactNativeJsi": "21a624ea24fd17d56bf26832d496fc1177067f89640414c20e6486c7984dfb0a"
29
29
  },
30
- "sha256": "0c68d14139a733fa990e55fa23224589fe9a74ce82db0ce5b9b52da51211390e",
31
- "size": 26139
30
+ "sha256": "bf331e9b3d141240d9fda77dc67e1d4b584513bdc455b0c37ae6aeb1a89038ed",
31
+ "size": 26137
32
32
  },
33
33
  {
34
34
  "headers": {
35
35
  "reactNativeJsi": "324aefd8591d9ce688bce7589c4c2b516cd33ecb95d35c47239a87a8fcf6a8da"
36
36
  },
37
- "sha256": "adba5b074a4fc2d6c367de74f24aa4b6273363f8b39c9ad9d15be2775f08a2e1",
38
- "size": 25394
37
+ "sha256": "181c4fef940e164d52f0e8a6284990cfa23a19c42afb445f6945cd959f708bf9",
38
+ "size": 25392
39
39
  },
40
40
  {
41
41
  "headers": {
42
42
  "reactNativeJsi": "33596664ee7d7a6623f0796a6feb429543316c3a41b211150acda6e1d835286c"
43
43
  },
44
- "sha256": "778f943ad7fcfba7060e2f29d2bf9d3d7365c60d09b8e2fcccfe11f95920b321",
45
- "size": 25165
44
+ "sha256": "44ac75e98b6badd32e32556bfd04beab8728bbce58cf32f31528a7e17b6b3665",
45
+ "size": 25166
46
46
  },
47
47
  {
48
48
  "headers": {
49
49
  "reactNativeJsi": "66b2cd5a38511195207f6c8a76aba735f9b9cc66a52a0d00780ffe5d331623f7"
50
50
  },
51
- "sha256": "06cdf08b6f177a54dbf734f76f23ff192c4eb50238fae5207e923fa8e0cfb4bd",
51
+ "sha256": "dab069c53f92c911f1f84c7c037077c6e73df2fbd1673cb9dbbff0c6014fb9ac",
52
52
  "size": 25398
53
53
  },
54
54
  {
55
55
  "headers": {
56
56
  "reactNativeJsi": "96db4e758dd53e9320cef7cad485e00aa06e7a982cefd920f17007de8a5bd9f9"
57
57
  },
58
- "sha256": "62920d91d1805ae0df3ad0f672f6405575c04df4e66948ea37b4e165f39f8eb5",
59
- "size": 26141
58
+ "sha256": "6612544a0287c8cc231436ad31e9a45f4d824fbbc5e7da7460ac11728568c353",
59
+ "size": 26139
60
60
  },
61
61
  {
62
62
  "headers": {
63
63
  "reactNativeJsi": "aeab590ddd1218df963462242d3954ce467b0fa88f70e91429e4ffc74d230893"
64
64
  },
65
- "sha256": "fab02f584e10cee2197c10b5c488873d5203313e10f07b2940283bee3ae12a57",
65
+ "sha256": "c73fb45ff0e2037bf21c6a0e019e80c645ff141e80052b750c7d14570a4f7e72",
66
66
  "size": 26138
67
67
  },
68
68
  {
69
69
  "headers": {
70
70
  "reactNativeJsi": "b5fb260522384dd7ab07d740cdc534b529922446fcec798341c7817d9eaa49f4"
71
71
  },
72
- "sha256": "72bbd117ff2d4495f46fceecd0959e8bd2a0647fdf514bf2e2e95922514bcb66",
72
+ "sha256": "997372e6c03141640cfc3aab115b8afe9b04f6f6e806721f14f4fc0dc871d271",
73
73
  "size": 25267
74
74
  },
75
75
  {
76
76
  "headers": {
77
77
  "reactNativeJsi": "c6b391a1e870ccf7cdd534be63582862840f8245b99ebd253317deece1e6ffd5"
78
78
  },
79
- "sha256": "10e28d5ce3eb41c695bef897fa974f8919559558a2b847963047f13ce06dc6a0",
80
- "size": 26144
79
+ "sha256": "60f8e1e7da90a20ee5b112b950e264f93329014bfabdcbcd5aa1281945f2725b",
80
+ "size": 26143
81
81
  },
82
82
  {
83
83
  "headers": {
84
84
  "reactNativeJsi": "c8270f1315745ecc204c4209a4f50f58ff6f14b4a385ad6820a69800270b53c6"
85
85
  },
86
- "sha256": "52226df9610d8b5f9b47fee6bedbdbaa04df7f2f562213bd8b433a5f998d8aa3",
86
+ "sha256": "47269b8662bf147cbf9ccc011de79f0faffc30aa6b09344ad4f95dbdfae656c9",
87
87
  "size": 25105
88
88
  }
89
89
  ]