expo-modules-core 57.0.3 → 57.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,25 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 57.0.5 — 2026-07-15
14
+
15
+ _This version does not introduce any user-facing changes._
16
+
17
+ ## 57.0.4 — 2026-07-15
18
+
19
+ ### 🎉 New features
20
+
21
+ - [iOS] `@SharedObject` now binds `@JS` methods, properties and the `@JS init` directly onto the class prototype, so they no longer need `Function(…)` / `Property(…)` / `Constructor { … }` definition entries. ([#47107](https://github.com/expo/expo/pull/47107) by [@tsapeta](https://github.com/tsapeta))
22
+
23
+ ### 🐛 Bug fixes
24
+
25
+ - [iOS] Fixed a crash when the runtime is reloaded while async function calls are still suspended in their native body. Concurrent functions now decode `this` and the arguments buffer synchronously inside the host call and schedule only converted native values, so no JSI-owned wrappers are destroyed off the JS thread after the runtime is torn down. ([#47716](https://github.com/expo/expo/issues/47716), [#47717](https://github.com/expo/expo/pull/47717) by [@AlirezaHadjar](https://github.com/AlirezaHadjar))
26
+ - [Android] Support `android.graphics.Color` arguments and props on Android below API 26 by adding a `ColorCompat` wrapper, since the class-based `Color` API (`Color.valueOf` and the float accessors) only exists on API 26 and above. ([#47546](https://github.com/expo/expo/issues/47546) by [@anasvemmully](https://github.com/anasvemmully)) ([#47575](https://github.com/expo/expo/pull/47575) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
27
+ - [iOS] Fix a `SIGABRT` crash when unmounting a SwiftUI view tree that still holds a focused field nested inside a container (e.g. an `@expo/ui` `TextField` inside an `HStack` or `LabeledContent` in a `Form`), such as dismissing a modal from a native header button. Resigning the first responder on unmount now recurses through the removed subtree instead of only handling a top-level focusable view. ([#47682](https://github.com/expo/expo/issues/47682) by [@andreavrr](https://github.com/andreavrr)) ([#47709](https://github.com/expo/expo/pull/47709) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
28
+ - [iOS] Pair a native shared object with one JavaScript object per runtime, so a shared object exposed to several runtimes (e.g. the main and UI runtimes, or worklet contexts) keeps a live pairing in each instead of only the one paired last. ([#47238](https://github.com/expo/expo/pull/47238) by [@tsapeta](https://github.com/tsapeta))
29
+ - [iOS] Fix `hsl()`/`hsla()` color strings failing to parse on some OS versions (observed on the iOS 27.0 beta), caused by regex-literal fragments composed in `RegexBuilder` blocks. The CSS color patterns are now built from `RegexBuilder` primitives only. ([#47543](https://github.com/expo/expo/pull/47543) by [@tsapeta](https://github.com/tsapeta))
30
+ - [iOS] Fixed a potential use-after-free when native code scheduled work onto the JS thread (e.g. settling an async function's promise from a background queue) while the React instance was concurrently tearing down the runtime scheduler on reload. The dispatch trampoline now references the scheduler weakly and drops the task once the scheduler is gone. ([#47492](https://github.com/expo/expo/pull/47492) by [@tsapeta](https://github.com/tsapeta))
31
+
13
32
  ## 57.0.3 — 2026-07-07
14
33
 
15
34
  _This version does not introduce any user-facing changes._
@@ -37,7 +56,6 @@ _This version does not introduce any user-facing changes._
37
56
 
38
57
  ### 🐛 Bug fixes
39
58
 
40
- - [iOS] Pair a native shared object with one JavaScript object per runtime, so a shared object exposed to several runtimes (e.g. the main and UI runtimes, or worklet contexts) keeps a live pairing in each instead of only the one paired last. ([#47238](https://github.com/expo/expo/pull/47238) by [@tsapeta](https://github.com/tsapeta))
41
59
  - [Android][compose] Guard `onLayout` against detached window to prevent `LayoutNode should be attached to an owner` crash. ([#47085](https://github.com/expo/expo/pull/47085) by [@roitium](https://github.com/roitium))
42
60
  - [Android] Fix Jetpack Compose `Host` content disappearing before a react-native-screens pop animation finishes, by deferring composition disposal to window detach while the view is still on-screen for a transition. ([#45914](https://github.com/expo/expo/issues/45914), [#47086](https://github.com/expo/expo/issues/47086) by [@aubrey-wodonga](https://github.com/aubrey-wodonga)) ([#47099](https://github.com/expo/expo/pull/47099) by [@nishan](https://github.com/intergalacticspacehighway))
43
61
  - [iOS] Fix a crash on `Updates.reloadAsync()` where the previous `AppContext` could deallocate before the old runtime finished tearing down, releasing cached JSI objects against a dying runtime on the wrong thread. Its lifetime is now tied to the runtime via native state attached to the `global.expo` object. ([#47051](https://github.com/expo/expo/issues/47051) by [@HaiyiMei](https://github.com/HaiyiMei)) ([#47080](https://github.com/expo/expo/pull/47080), [#47098](https://github.com/expo/expo/pull/47098) by [@tsapeta](https://github.com/tsapeta))
@@ -127,14 +127,22 @@ Pod::Spec.new do |s|
127
127
  s.test_spec 'Tests' do |test_spec|
128
128
  test_spec.dependency 'ExpoModulesTestCore'
129
129
 
130
- test_spec.source_files = 'ios/Tests/**/*.{m,swift}'
131
-
132
- # The library's -lc++ lives in `user_target_xcconfig` (for consuming apps), which a
133
- # test_spec target doesn't inherit. The test bundle links libExpoModulesCore.a (C++)
134
- # but has no C++/Obj-C++ source of its own, so the linker driver is clang, not clang++,
135
- # and libc++ isn't linked implicitly. Link it explicitly here.
130
+ test_spec.source_files = 'ios/Tests/**/*.{h,m,mm,swift}'
131
+
132
+ # The Obj-C++ tests include React renderer headers, which need the library's folly
133
+ # config. It reaches them through the library's `compiler_flags`, which test specs
134
+ # inherit and CocoaPods applies per-file to C-family sources.
135
+ #
136
+ # OTHER_LDFLAGS: the library's -lc++ lives in `user_target_xcconfig` (for consuming
137
+ # apps), which a test_spec target doesn't inherit. The test bundle links
138
+ # libExpoModulesCore.a (C++), so link libc++ explicitly.
139
+ #
140
+ # SWIFT_OBJC_BRIDGING_HEADER: a test target has no module for its own Obj-C sources,
141
+ # so the Swift tests see the Obj-C test doubles (`ios/Tests/Mocks`) through the
142
+ # bridging header.
136
143
  test_spec.pod_target_xcconfig = {
137
- 'OTHER_LDFLAGS' => '$(inherited) -lc++'
144
+ 'OTHER_LDFLAGS' => '$(inherited) -lc++',
145
+ 'SWIFT_OBJC_BRIDGING_HEADER' => '$(PODS_TARGET_SRCROOT)/ios/Tests/Tests-Bridging-Header.h'
138
146
  }
139
147
  end
140
148
  end
@@ -27,7 +27,7 @@ if (shouldIncludeCompose) {
27
27
  }
28
28
 
29
29
  group = 'host.exp.exponent'
30
- version = '57.0.3'
30
+ version = '57.0.5'
31
31
 
32
32
  def isExpoModulesCoreTests = {
33
33
  Gradle gradle = getGradle()
@@ -94,7 +94,7 @@ android {
94
94
  defaultConfig {
95
95
  consumerProguardFiles 'proguard-rules.pro'
96
96
  versionCode 1
97
- versionName "57.0.3"
97
+ versionName "57.0.5"
98
98
  buildConfigField "String", "EXPO_MODULES_CORE_VERSION", "\"${versionName}\""
99
99
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", "true"
100
100
 
@@ -0,0 +1,148 @@
1
+ package expo.modules.kotlin.types
2
+
3
+ import android.graphics.Color
4
+ import android.os.Build
5
+ import androidx.annotation.ColorInt
6
+ import androidx.annotation.RequiresApi
7
+
8
+ /**
9
+ * Compatibility wrapper for [Color] instance APIs added in API 26.
10
+ *
11
+ * Remove this class when expo-modules-core minSdkVersion is 26 or higher. Android Lint's
12
+ * ObsoleteSdkInt check should flag these version gates after that bump.
13
+ */
14
+ class ColorCompat private constructor() {
15
+ companion object {
16
+ private val defaultLegacyColor = LegacyColor(
17
+ red = 0f,
18
+ green = 0f,
19
+ blue = 0f,
20
+ alpha = 1f,
21
+ argb = Color.BLACK
22
+ )
23
+
24
+ @JvmStatic
25
+ fun valueOf(@ColorInt color: Int): Color {
26
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
27
+ return Api26Impl.valueOf(color)
28
+ }
29
+ return LegacyColor(
30
+ red = Color.red(color) / 255f,
31
+ green = Color.green(color) / 255f,
32
+ blue = Color.blue(color) / 255f,
33
+ alpha = Color.alpha(color) / 255f,
34
+ argb = color
35
+ )
36
+ }
37
+
38
+ @JvmStatic
39
+ fun valueOf(red: Float, green: Float, blue: Float, alpha: Float): Color {
40
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
41
+ return Api26Impl.valueOf(red, green, blue, alpha)
42
+ }
43
+ val saturatedRed = red.coerceIn(0f, 1f)
44
+ val saturatedGreen = green.coerceIn(0f, 1f)
45
+ val saturatedBlue = blue.coerceIn(0f, 1f)
46
+ val saturatedAlpha = alpha.coerceIn(0f, 1f)
47
+ return LegacyColor(
48
+ red = saturatedRed,
49
+ green = saturatedGreen,
50
+ blue = saturatedBlue,
51
+ alpha = saturatedAlpha,
52
+ argb = Color.argb(
53
+ toColorComponent(saturatedAlpha),
54
+ toColorComponent(saturatedRed),
55
+ toColorComponent(saturatedGreen),
56
+ toColorComponent(saturatedBlue)
57
+ )
58
+ )
59
+ }
60
+
61
+ @JvmStatic
62
+ fun toArgb(color: Color): Int {
63
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
64
+ return Api26Impl.toArgb(color)
65
+ }
66
+ return legacyColor(color).argb
67
+ }
68
+
69
+ @JvmStatic
70
+ fun alpha(color: Color): Float {
71
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
72
+ return Api26Impl.alpha(color)
73
+ }
74
+ return legacyColor(color).alpha
75
+ }
76
+
77
+ @JvmStatic
78
+ fun red(color: Color): Float {
79
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
80
+ return Api26Impl.red(color)
81
+ }
82
+ return legacyColor(color).red
83
+ }
84
+
85
+ @JvmStatic
86
+ fun green(color: Color): Float {
87
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
88
+ return Api26Impl.green(color)
89
+ }
90
+ return legacyColor(color).green
91
+ }
92
+
93
+ @JvmStatic
94
+ fun blue(color: Color): Float {
95
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
96
+ return Api26Impl.blue(color)
97
+ }
98
+ return legacyColor(color).blue
99
+ }
100
+
101
+ private fun legacyColor(color: Color): LegacyColor {
102
+ return color as? LegacyColor ?: defaultLegacyColor
103
+ }
104
+
105
+ private fun toColorComponent(component: Float): Int {
106
+ return (component * 255f + 0.5f).toInt()
107
+ }
108
+ }
109
+
110
+ private class LegacyColor(
111
+ val red: Float,
112
+ val green: Float,
113
+ val blue: Float,
114
+ val alpha: Float,
115
+ @ColorInt val argb: Int
116
+ ) : Color()
117
+
118
+ @RequiresApi(Build.VERSION_CODES.O)
119
+ private object Api26Impl {
120
+ fun valueOf(@ColorInt color: Int): Color {
121
+ return Color.valueOf(color)
122
+ }
123
+
124
+ fun valueOf(red: Float, green: Float, blue: Float, alpha: Float): Color {
125
+ return Color.valueOf(red, green, blue, alpha)
126
+ }
127
+
128
+ fun toArgb(color: Color): Int {
129
+ return color.toArgb()
130
+ }
131
+
132
+ fun alpha(color: Color): Float {
133
+ return color.alpha()
134
+ }
135
+
136
+ fun red(color: Color): Float {
137
+ return color.red()
138
+ }
139
+
140
+ fun green(color: Color): Float {
141
+ return color.green()
142
+ }
143
+
144
+ fun blue(color: Color): Float {
145
+ return color.blue()
146
+ }
147
+ }
148
+ }
@@ -1,8 +1,6 @@
1
1
  package expo.modules.kotlin.types
2
2
 
3
3
  import android.graphics.Color
4
- import android.os.Build
5
- import androidx.annotation.RequiresApi
6
4
  import com.facebook.react.bridge.Dynamic
7
5
  import com.facebook.react.bridge.ReadableType
8
6
  import expo.modules.kotlin.AppContext
@@ -262,7 +260,7 @@ private fun hslToColor(h: Float, s: Float, l: Float, a: Float): Color {
262
260
  g = hueToRgb(p, q, hue)
263
261
  b = hueToRgb(p, q, hue - 1f / 3f)
264
262
  }
265
- return Color.valueOf(r.coerceIn(0f, 1f), g.coerceIn(0f, 1f), b.coerceIn(0f, 1f), a)
263
+ return ColorCompat.valueOf(r.coerceIn(0f, 1f), g.coerceIn(0f, 1f), b.coerceIn(0f, 1f), a)
266
264
  }
267
265
 
268
266
  private fun hwbToColor(h: Float, w: Float, b: Float, a: Float): Color {
@@ -272,10 +270,10 @@ private fun hwbToColor(h: Float, w: Float, b: Float, a: Float): Color {
272
270
  val white = if (sum > 1f) ww / sum else ww
273
271
  val black = if (sum > 1f) bb / sum else bb
274
272
  val rgb = hslToColor(h, 1f, 0.5f, 1f)
275
- val r = rgb.red() * (1f - white - black) + white
276
- val g = rgb.green() * (1f - white - black) + white
277
- val bl = rgb.blue() * (1f - white - black) + white
278
- return Color.valueOf(r.coerceIn(0f, 1f), g.coerceIn(0f, 1f), bl.coerceIn(0f, 1f), a)
273
+ val r = ColorCompat.red(rgb) * (1f - white - black) + white
274
+ val g = ColorCompat.green(rgb) * (1f - white - black) + white
275
+ val bl = ColorCompat.blue(rgb) * (1f - white - black) + white
276
+ return ColorCompat.valueOf(r.coerceIn(0f, 1f), g.coerceIn(0f, 1f), bl.coerceIn(0f, 1f), a)
279
277
  }
280
278
 
281
279
  /**
@@ -292,7 +290,7 @@ private fun parseHexColor(value: String): Color? {
292
290
  val r = match.groupValues[1].repeat(2).toInt(16)
293
291
  val g = match.groupValues[2].repeat(2).toInt(16)
294
292
  val b = match.groupValues[3].repeat(2).toInt(16)
295
- return Color.valueOf(r / 255f, g / 255f, b / 255f, 1f)
293
+ return ColorCompat.valueOf(r / 255f, g / 255f, b / 255f, 1f)
296
294
  }
297
295
 
298
296
  // #RGBA → #RRGGBBAA
@@ -301,7 +299,7 @@ private fun parseHexColor(value: String): Color? {
301
299
  val g = match.groupValues[2].repeat(2).toInt(16)
302
300
  val b = match.groupValues[3].repeat(2).toInt(16)
303
301
  val a = match.groupValues[4].repeat(2).toInt(16)
304
- return Color.valueOf(r / 255f, g / 255f, b / 255f, a / 255f)
302
+ return ColorCompat.valueOf(r / 255f, g / 255f, b / 255f, a / 255f)
305
303
  }
306
304
 
307
305
  // #RRGGBBAA (CSS byte order: alpha is last, unlike Android's #AARRGGBB)
@@ -311,7 +309,7 @@ private fun parseHexColor(value: String): Color? {
311
309
  val g = ((hex shr 16) and 0xFF).toInt()
312
310
  val b = ((hex shr 8) and 0xFF).toInt()
313
311
  val a = (hex and 0xFF).toInt()
314
- return Color.valueOf(r / 255f, g / 255f, b / 255f, a / 255f)
312
+ return ColorCompat.valueOf(r / 255f, g / 255f, b / 255f, a / 255f)
315
313
  }
316
314
 
317
315
  return null
@@ -329,7 +327,7 @@ private fun parseCssColorFunction(value: String): Color? {
329
327
  val g = parseRgbComponent(match.groupValues[2])
330
328
  val b = parseRgbComponent(match.groupValues[3])
331
329
  val a = parseAlpha(match.groupValues[4].ifEmpty { null })
332
- return Color.valueOf(r, g, b, a)
330
+ return ColorCompat.valueOf(r, g, b, a)
333
331
  }
334
332
 
335
333
  // hsl/hsla
@@ -355,7 +353,6 @@ private fun parseCssColorFunction(value: String): Color? {
355
353
 
356
354
  // endregion
357
355
 
358
- @RequiresApi(Build.VERSION_CODES.O)
359
356
  class ColorTypeConverter : DynamicAwareTypeConverters<Color>() {
360
357
  override fun convertFromDynamic(value: Dynamic, context: AppContext?, forceConversion: Boolean): Color {
361
358
  return when (value.type) {
@@ -389,18 +386,18 @@ class ColorTypeConverter : DynamicAwareTypeConverters<Color>() {
389
386
  throw InvalidColorComponentsException(value.size)
390
387
  }
391
388
  val alpha = value.getOrNull(3) ?: 1.0
392
- return Color.valueOf(value[0].toFloat(), value[1].toFloat(), value[2].toFloat(), alpha.toFloat())
389
+ return ColorCompat.valueOf(value[0].toFloat(), value[1].toFloat(), value[2].toFloat(), alpha.toFloat())
393
390
  }
394
391
 
395
392
  private fun colorFromInt(value: Int): Color {
396
- return Color.valueOf(value)
393
+ return ColorCompat.valueOf(value)
397
394
  }
398
395
 
399
396
  private fun colorFromString(value: String): Color {
400
397
  val normalizedValue = value.trim().lowercase()
401
398
  val colorFromString = namedColors[normalizedValue]
402
399
  if (colorFromString != null) {
403
- return Color.valueOf(
400
+ return ColorCompat.valueOf(
404
401
  colorFromString[0],
405
402
  colorFromString[1],
406
403
  colorFromString[2],
@@ -411,12 +408,12 @@ class ColorTypeConverter : DynamicAwareTypeConverters<Color>() {
411
408
  if (normalizedValue.startsWith('#')) {
412
409
  parseHexColor(normalizedValue)?.let { return it }
413
410
  // Fall through to toColorInt() for standard #RRGGBB / #AARRGGBB
414
- return Color.valueOf(normalizedValue.toColorInt())
411
+ return ColorCompat.valueOf(normalizedValue.toColorInt())
415
412
  }
416
413
 
417
414
  parseCssColorFunction(normalizedValue)?.let { return it }
418
415
 
419
- return Color.valueOf(normalizedValue.toColorInt())
416
+ return ColorCompat.valueOf(normalizedValue.toColorInt())
420
417
  }
421
418
 
422
419
  override fun getCppRequiredTypes(): ExpectedType =
@@ -275,6 +275,8 @@ object TypeConverterProviderImpl : TypeConverterProvider {
275
275
 
276
276
  Any::class.java to AnyTypeConverter(),
277
277
 
278
+ Color::class.java to ColorTypeConverter(),
279
+
278
280
  // Unit converter doesn't care about nullability.
279
281
  // It will always return Unit
280
282
  Unit::class.java to UnitTypeConverter(),
@@ -285,7 +287,6 @@ object TypeConverterProviderImpl : TypeConverterProvider {
285
287
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
286
288
  return converters + mapOf(
287
289
  Path::class.java to PathTypeConverter(),
288
- Color::class.java to ColorTypeConverter(),
289
290
  LocalDate::class.java to DateTypeConverter()
290
291
  )
291
292
  }
@@ -436,6 +436,10 @@ public final class AppContext: NSObject, EXAppContextProtocol, @unchecked Sendab
436
436
  to a synchronous no-op scheduler — callers can detect this via
437
437
  `JavaScriptRuntime.supportsAsyncScheduling`.
438
438
 
439
+ `scheduler` is an opaque handle that `dispatch` understands; the factories pass
440
+ a handle created by `expo::createReactSchedulerHandle` that references the React
441
+ runtime scheduler weakly (see `EXReactSchedulerDispatch.h`).
442
+
439
443
  `dispatch` is a raw pointer to a C function with signature
440
444
  `void (*)(void *scheduler, int priority, void (^callback)())` — cast back
441
445
  to the typed pointer inside `ExpoModulesJSI`. It's typed as `UnsafeRawPointer`
@@ -51,17 +51,20 @@ public final class ClassDefinition: ObjectDefinition {
51
51
 
52
52
  @JavaScriptActor
53
53
  public override func build(appContext: AppContext) throws -> JavaScriptObject {
54
+ // The concrete `SharedObject` subclass backing this class, used to dispatch to the
55
+ // `@SharedObject` macro's `_constructSharedObject` / `_decorateSharedObject` overrides.
56
+ let sharedObjectType = ((associatedType as? DynamicSharedObjectType)?.innerType) as? SharedObject.Type
57
+
54
58
  let constructorClosure: JavaScriptRuntime.SyncFunctionClosure = { [weak self, weak appContext] this, arguments in
55
59
  guard let self, let appContext else {
56
60
  throw Exceptions.AppContextLost()
57
61
  }
58
- // Call the native constructor when defined. Any thrown `Exception` (which
59
- // conforms to `JavaScriptThrowable`) propagates to the host function closure,
60
- // which converts it to a JS `Error` preserving `message` and `code`.
61
- if let constructor {
62
- // Run the body natively so we can pair a returned `SharedObject` with `this`
63
- // directly. `this` was created by `new` with the correct class prototype; returning
64
- // a different JS object would replace `this` and drop that prototype chain.
62
+ // Build the native instance and pair it with `this` (returning a different object would drop
63
+ // the prototype chain `new` set up). Prefer the macro-synthesized `_constructSharedObject`,
64
+ // falling back to the DSL `Constructor` body.
65
+ if let sharedObject = try sharedObjectType?._constructSharedObject(this: this, arguments: arguments, in: appContext.runtime) {
66
+ appContext.sharedObjectRegistry.add(native: sharedObject, javaScript: this.getObject())
67
+ } else if let constructor {
65
68
  let result = try constructor.runBody(appContext, in: appContext.runtime, this: this, arguments: arguments)
66
69
 
67
70
  if let sharedObject = result as? SharedObject {
@@ -75,6 +78,12 @@ public final class ClassDefinition: ObjectDefinition {
75
78
 
76
79
  try decorate(object: klass, appContext: appContext)
77
80
 
81
+ // Bind the macro's `@JS` members onto the prototype.
82
+ if let sharedObjectType {
83
+ let prototype = klass.getProperty("prototype").getObject()
84
+ try sharedObjectType._decorateSharedObject(prototype: prototype, in: appContext.runtime)
85
+ }
86
+
78
87
  // Register the JS class and its associated native type.
79
88
  if let sharedObjectType = associatedType as? DynamicSharedObjectType {
80
89
  appContext.classRegistry.register(nativeClassId: sharedObjectType.typeIdentifier, javaScriptClass: klass)
@@ -122,6 +131,10 @@ public final class ClassDefinition: ObjectDefinition {
122
131
  proto.setProperty(fn.name, value: try syncFn.build(appContext: appContext, in: runtime))
123
132
  }
124
133
  }
134
+ // Bind the macro's `@JS` members, which aren't in the DSL `properties`/`functions` dictionaries.
135
+ if let sharedObjectType = (associatedType as? DynamicSharedObjectType)?.innerType as? SharedObject.Type {
136
+ try sharedObjectType._decorateSharedObject(prototype: proto, in: runtime)
137
+ }
125
138
  return proto
126
139
  }
127
140
  }