@shortkitsdk/react-native 0.2.28 → 0.2.29

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 (25) hide show
  1. package/android/libs/shortkit-release.aar +0 -0
  2. package/ios/ReactVideoCarouselOverlayHost.swift +6 -0
  3. package/ios/ShortKitBridge.swift +134 -35
  4. package/ios/ShortKitFeedView.swift +43 -44
  5. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Info.plist +2 -2
  6. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +696 -55
  7. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +20 -1
  8. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  9. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +20 -1
  10. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
  11. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources +9 -9
  12. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Info.plist +2 -2
  13. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +696 -55
  14. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +20 -1
  15. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  16. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +20 -1
  17. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +696 -55
  18. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +20 -1
  19. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  20. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +20 -1
  21. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
  22. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/_CodeSignature/CodeResources +17 -17
  23. package/package.json +1 -1
  24. package/src/ShortKitFeed.tsx +31 -0
  25. package/src/specs/NativeShortKitModule.ts +6 -0
@@ -442,6 +442,15 @@ public enum ShortKitDownloadError : Swift.Error {
442
442
  public typealias Body = Swift.Never
443
443
  public typealias UIViewControllerType = ShortKitSDK.ShortKitFeedViewController
444
444
  }
445
+ public enum ShortKitFeedLifecycle {
446
+ case automatic
447
+ case manual
448
+ public static func == (a: ShortKitSDK.ShortKitFeedLifecycle, b: ShortKitSDK.ShortKitFeedLifecycle) -> Swift.Bool
449
+ public func hash(into hasher: inout Swift.Hasher)
450
+ public var hashValue: Swift.Int {
451
+ get
452
+ }
453
+ }
445
454
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency public class ShortKitFeedViewController : UIKit.UIViewController {
446
455
  @_Concurrency.MainActor @preconcurrency public var debugPanelFactory: ((_ active: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>, _ prev: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>, _ next: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>) -> UIKit.UIView)?
447
456
  @_Concurrency.MainActor @preconcurrency public var onDismiss: (() -> Swift.Void)?
@@ -454,8 +463,12 @@ public enum ShortKitDownloadError : Swift.Error {
454
463
  }
455
464
  @_Concurrency.MainActor @preconcurrency public var onVideoCarouselCellTap: ((ShortKitSDK.ShortKitFeedViewController.VideoCarouselCellTapPayload) -> Swift.Void)?
456
465
  @_Concurrency.MainActor @preconcurrency public var onRefreshStateChanged: ((ShortKitSDK.ShortKitRefreshState) -> Swift.Void)?
466
+ @_Concurrency.MainActor @preconcurrency public var onFeedTransition: ((ShortKitSDK.FeedTransitionEvent) -> Swift.Void)?
467
+ @_Concurrency.MainActor @preconcurrency public var isActiveSurface: Swift.Bool {
468
+ get
469
+ }
457
470
  @_Concurrency.MainActor @preconcurrency public var seedThumbnail: UIKit.UIImage?
458
- @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.FeedConfig, startAtItemId: Swift.String? = nil)
471
+ @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.FeedConfig, startAtItemId: Swift.String? = nil, lifecycle: ShortKitSDK.ShortKitFeedLifecycle = .automatic)
459
472
  @_Concurrency.MainActor public func setFeedItems(_ items: [ShortKitSDK.FeedInput], startAtId: Swift.String? = nil)
460
473
  @_Concurrency.MainActor public func scrollToItem(id: Swift.String, animated: Swift.Bool)
461
474
  @_Concurrency.MainActor public func appendFeedItems(_ items: [ShortKitSDK.FeedInput])
@@ -465,6 +478,7 @@ public enum ShortKitDownloadError : Swift.Error {
465
478
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewWillAppear(_ animated: Swift.Bool)
466
479
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewDidAppear(_ animated: Swift.Bool)
467
480
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewWillDisappear(_ animated: Swift.Bool)
481
+ @available(*, deprecated, message: "Pass lifecycle: .manual to ShortKitFeedViewController's initializer instead.")
468
482
  @_Concurrency.MainActor @preconcurrency public func setBridgeManaged()
469
483
  @_Concurrency.MainActor @preconcurrency public func activate()
470
484
  @_Concurrency.MainActor @preconcurrency public func deactivate()
@@ -940,6 +954,9 @@ public struct FeedTransitionEvent : Swift.Equatable, Swift.Sendable {
940
954
  public let from: ShortKitSDK.ContentItem?
941
955
  public let to: ShortKitSDK.ContentItem?
942
956
  public let direction: ShortKitSDK.FeedTransitionEvent.Direction
957
+ public let fromFeedItem: ShortKitSDK.FeedItem?
958
+ public let toFeedItem: ShortKitSDK.FeedItem?
959
+ public init(phase: ShortKitSDK.FeedTransitionEvent.Phase, from: ShortKitSDK.ContentItem?, to: ShortKitSDK.ContentItem?, direction: ShortKitSDK.FeedTransitionEvent.Direction, fromFeedItem: ShortKitSDK.FeedItem? = nil, toFeedItem: ShortKitSDK.FeedItem? = nil)
943
960
  public static func == (a: ShortKitSDK.FeedTransitionEvent, b: ShortKitSDK.FeedTransitionEvent) -> Swift.Bool
944
961
  }
945
962
  public struct FormatChangeEvent : Swift.Equatable, Swift.Sendable {
@@ -1191,6 +1208,8 @@ extension ShortKitSDK.SwipeCurve : Swift.RawRepresentable {}
1191
1208
  extension ShortKitSDK.DownloadMode : Swift.Equatable {}
1192
1209
  extension ShortKitSDK.DownloadMode : Swift.Hashable {}
1193
1210
  extension ShortKitSDK.ShortKitFeedView : Swift.Sendable {}
1211
+ extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Equatable {}
1212
+ extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Hashable {}
1194
1213
  extension ShortKitSDK.CaptionSource : Swift.Equatable {}
1195
1214
  extension ShortKitSDK.CaptionSource : Swift.Hashable {}
1196
1215
  extension ShortKitSDK.CaptionSource : Swift.RawRepresentable {}
@@ -442,6 +442,15 @@ public enum ShortKitDownloadError : Swift.Error {
442
442
  public typealias Body = Swift.Never
443
443
  public typealias UIViewControllerType = ShortKitSDK.ShortKitFeedViewController
444
444
  }
445
+ public enum ShortKitFeedLifecycle {
446
+ case automatic
447
+ case manual
448
+ public static func == (a: ShortKitSDK.ShortKitFeedLifecycle, b: ShortKitSDK.ShortKitFeedLifecycle) -> Swift.Bool
449
+ public func hash(into hasher: inout Swift.Hasher)
450
+ public var hashValue: Swift.Int {
451
+ get
452
+ }
453
+ }
445
454
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency public class ShortKitFeedViewController : UIKit.UIViewController {
446
455
  @_Concurrency.MainActor @preconcurrency public var debugPanelFactory: ((_ active: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>, _ prev: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>, _ next: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>) -> UIKit.UIView)?
447
456
  @_Concurrency.MainActor @preconcurrency public var onDismiss: (() -> Swift.Void)?
@@ -454,8 +463,12 @@ public enum ShortKitDownloadError : Swift.Error {
454
463
  }
455
464
  @_Concurrency.MainActor @preconcurrency public var onVideoCarouselCellTap: ((ShortKitSDK.ShortKitFeedViewController.VideoCarouselCellTapPayload) -> Swift.Void)?
456
465
  @_Concurrency.MainActor @preconcurrency public var onRefreshStateChanged: ((ShortKitSDK.ShortKitRefreshState) -> Swift.Void)?
466
+ @_Concurrency.MainActor @preconcurrency public var onFeedTransition: ((ShortKitSDK.FeedTransitionEvent) -> Swift.Void)?
467
+ @_Concurrency.MainActor @preconcurrency public var isActiveSurface: Swift.Bool {
468
+ get
469
+ }
457
470
  @_Concurrency.MainActor @preconcurrency public var seedThumbnail: UIKit.UIImage?
458
- @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.FeedConfig, startAtItemId: Swift.String? = nil)
471
+ @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.FeedConfig, startAtItemId: Swift.String? = nil, lifecycle: ShortKitSDK.ShortKitFeedLifecycle = .automatic)
459
472
  @_Concurrency.MainActor public func setFeedItems(_ items: [ShortKitSDK.FeedInput], startAtId: Swift.String? = nil)
460
473
  @_Concurrency.MainActor public func scrollToItem(id: Swift.String, animated: Swift.Bool)
461
474
  @_Concurrency.MainActor public func appendFeedItems(_ items: [ShortKitSDK.FeedInput])
@@ -465,6 +478,7 @@ public enum ShortKitDownloadError : Swift.Error {
465
478
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewWillAppear(_ animated: Swift.Bool)
466
479
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewDidAppear(_ animated: Swift.Bool)
467
480
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewWillDisappear(_ animated: Swift.Bool)
481
+ @available(*, deprecated, message: "Pass lifecycle: .manual to ShortKitFeedViewController's initializer instead.")
468
482
  @_Concurrency.MainActor @preconcurrency public func setBridgeManaged()
469
483
  @_Concurrency.MainActor @preconcurrency public func activate()
470
484
  @_Concurrency.MainActor @preconcurrency public func deactivate()
@@ -940,6 +954,9 @@ public struct FeedTransitionEvent : Swift.Equatable, Swift.Sendable {
940
954
  public let from: ShortKitSDK.ContentItem?
941
955
  public let to: ShortKitSDK.ContentItem?
942
956
  public let direction: ShortKitSDK.FeedTransitionEvent.Direction
957
+ public let fromFeedItem: ShortKitSDK.FeedItem?
958
+ public let toFeedItem: ShortKitSDK.FeedItem?
959
+ public init(phase: ShortKitSDK.FeedTransitionEvent.Phase, from: ShortKitSDK.ContentItem?, to: ShortKitSDK.ContentItem?, direction: ShortKitSDK.FeedTransitionEvent.Direction, fromFeedItem: ShortKitSDK.FeedItem? = nil, toFeedItem: ShortKitSDK.FeedItem? = nil)
943
960
  public static func == (a: ShortKitSDK.FeedTransitionEvent, b: ShortKitSDK.FeedTransitionEvent) -> Swift.Bool
944
961
  }
945
962
  public struct FormatChangeEvent : Swift.Equatable, Swift.Sendable {
@@ -1191,6 +1208,8 @@ extension ShortKitSDK.SwipeCurve : Swift.RawRepresentable {}
1191
1208
  extension ShortKitSDK.DownloadMode : Swift.Equatable {}
1192
1209
  extension ShortKitSDK.DownloadMode : Swift.Hashable {}
1193
1210
  extension ShortKitSDK.ShortKitFeedView : Swift.Sendable {}
1211
+ extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Equatable {}
1212
+ extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Hashable {}
1194
1213
  extension ShortKitSDK.CaptionSource : Swift.Equatable {}
1195
1214
  extension ShortKitSDK.CaptionSource : Swift.Hashable {}
1196
1215
  extension ShortKitSDK.CaptionSource : Swift.RawRepresentable {}
@@ -10,39 +10,39 @@
10
10
  </data>
11
11
  <key>Info.plist</key>
12
12
  <data>
13
- ojzrG3Ap08GJYamHkQPBUeXk/l0=
13
+ SGnC4k70E9DgpOqahVfG8CzDvZA=
14
14
  </data>
15
15
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json</key>
16
16
  <data>
17
- 21myiENnbm60Ispq3tQ5ew19FSk=
17
+ BO1VUECw+jNellCun0jhxv3t30k=
18
18
  </data>
19
19
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
20
20
  <data>
21
- zPo7oMw2NLtjLxfYCxXyViI9stM=
21
+ CBxkj0soc11JQFMNAKh03fEskOQ=
22
22
  </data>
23
23
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc</key>
24
24
  <data>
25
- 40YCNN9uv8BRz93OzhGUKoz3RAA=
25
+ Egfd+TPgbG9XhezyyhpOkJ9bZWs=
26
26
  </data>
27
27
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface</key>
28
28
  <data>
29
- zPo7oMw2NLtjLxfYCxXyViI9stM=
29
+ CBxkj0soc11JQFMNAKh03fEskOQ=
30
30
  </data>
31
31
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
32
32
  <data>
33
- 21myiENnbm60Ispq3tQ5ew19FSk=
33
+ BO1VUECw+jNellCun0jhxv3t30k=
34
34
  </data>
35
35
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
36
36
  <data>
37
- vcLubVZzFhhcaxIe+CkCl0boQWs=
37
+ KDzWlPhZbTYIibjJVtICWSKv9cs=
38
38
  </data>
39
39
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
40
40
  <data>
41
- /2fiMms53INV4XQrQbZvM6gqOEg=
41
+ CbLKbJe6jCpRFjhJ5MJ7F7Um93M=
42
42
  </data>
43
43
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
44
44
  <data>
45
- vcLubVZzFhhcaxIe+CkCl0boQWs=
45
+ KDzWlPhZbTYIibjJVtICWSKv9cs=
46
46
  </data>
47
47
  <key>Modules/module.modulemap</key>
48
48
  <data>
@@ -66,56 +66,56 @@
66
66
  <dict>
67
67
  <key>hash2</key>
68
68
  <data>
69
- Dsiu+M+BzZQooc8siWOeQ+tS8azZJ7BfE+71duXglXs=
69
+ fHbFQio59u+N64dapbLRpLdCd4VatCDVkbn5qTzHCxc=
70
70
  </data>
71
71
  </dict>
72
72
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
73
73
  <dict>
74
74
  <key>hash2</key>
75
75
  <data>
76
- FMAJh9SjpqLB6134JfHMNDpUINiMPb9TP4YXvhZEUug=
76
+ Ct1MN9BrXD/Rkc+lJb6iANMaf9f+RwWB4+pYW/i+3Ek=
77
77
  </data>
78
78
  </dict>
79
79
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc</key>
80
80
  <dict>
81
81
  <key>hash2</key>
82
82
  <data>
83
- Cw1QZDVkmMiaSLxpl7OxGadGNlHAFn08jn1ClL2XN6s=
83
+ aLVo05BXMvhibMAdWTtKpK4Ezm91V9IJz/GAm9WDhLw=
84
84
  </data>
85
85
  </dict>
86
86
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface</key>
87
87
  <dict>
88
88
  <key>hash2</key>
89
89
  <data>
90
- FMAJh9SjpqLB6134JfHMNDpUINiMPb9TP4YXvhZEUug=
90
+ Ct1MN9BrXD/Rkc+lJb6iANMaf9f+RwWB4+pYW/i+3Ek=
91
91
  </data>
92
92
  </dict>
93
93
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
94
94
  <dict>
95
95
  <key>hash2</key>
96
96
  <data>
97
- Dsiu+M+BzZQooc8siWOeQ+tS8azZJ7BfE+71duXglXs=
97
+ fHbFQio59u+N64dapbLRpLdCd4VatCDVkbn5qTzHCxc=
98
98
  </data>
99
99
  </dict>
100
100
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
101
101
  <dict>
102
102
  <key>hash2</key>
103
103
  <data>
104
- 2I1oGbLXn9JJAJEdBxgRR/gyfKA2c1l0bFbNOsCRUNY=
104
+ 4rQvWmFNy7cluozJQCGW3y7OdbgvVQco8KNNJ5gFrhc=
105
105
  </data>
106
106
  </dict>
107
107
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
108
108
  <dict>
109
109
  <key>hash2</key>
110
110
  <data>
111
- E73Dx8SYkIk9zbpx6V2HLAdRZAIFitk3aKJVzM2p95g=
111
+ mVc5JWN6Fy34JoJsotmdTST52bcYpwdaOl1WZGL42xs=
112
112
  </data>
113
113
  </dict>
114
114
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
115
115
  <dict>
116
116
  <key>hash2</key>
117
117
  <data>
118
- 2I1oGbLXn9JJAJEdBxgRR/gyfKA2c1l0bFbNOsCRUNY=
118
+ 4rQvWmFNy7cluozJQCGW3y7OdbgvVQco8KNNJ5gFrhc=
119
119
  </data>
120
120
  </dict>
121
121
  <key>Modules/module.modulemap</key>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shortkitsdk/react-native",
3
- "version": "0.2.28",
3
+ "version": "0.2.29",
4
4
  "description": "ShortKit React Native SDK — short-form video feed",
5
5
  "react-native": "src/index",
6
6
  "source": "src/index",
@@ -163,6 +163,11 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
163
163
  if (onLoop) {
164
164
  subscriptions.push(
165
165
  NativeShortKitModule.onDidLoop((event) => {
166
+ // Filter to this feed instance — onDidLoop is fired from the
167
+ // shared player's global Combine publisher. The native bridge
168
+ // tags the emit with the active surface's feedId; reject events
169
+ // that don't match. Accept empty feedId for forward-compat.
170
+ if (event.feedId !== feedId && event.feedId !== '') return;
166
171
  onLoop({ contentId: event.contentId, loopCount: event.loopCount });
167
172
  }),
168
173
  );
@@ -171,6 +176,16 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
171
176
  if (onFeedTransition) {
172
177
  subscriptions.push(
173
178
  NativeShortKitModule.onFeedTransition((event) => {
179
+ // Filter to this feed instance — `player.feedTransition` is a
180
+ // singleton publisher on the shared player; the native bridge now
181
+ // tags the emit with the active surface's feedId. Without this
182
+ // filter, every <ShortKitFeed> consumer receives every transition,
183
+ // which caused cross-tab state pollution (e.g., sibling tabs'
184
+ // onCurrentItemIdChange handlers firing on the active tab's
185
+ // scroll, leaking that item ID into their own startAtItemId).
186
+ // Accept empty feedId as a fallback for older native builds that
187
+ // don't tag the emit yet — same pattern as other callbacks here.
188
+ if (event.feedId !== feedId && event.feedId !== '') return;
174
189
  onFeedTransition({
175
190
  phase: event.phase as 'began' | 'ended',
176
191
  from: deserializeContentItem(event.fromItem ?? null),
@@ -184,6 +199,10 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
184
199
  if (onFormatChange) {
185
200
  subscriptions.push(
186
201
  NativeShortKitModule.onFormatChange((event) => {
202
+ // Filter to this feed instance — onFormatChange fires from the
203
+ // shared player's global publisher; bridge tags with active
204
+ // surface's feedId. Reject events addressed to other feeds.
205
+ if (event.feedId !== feedId && event.feedId !== '') return;
187
206
  onFormatChange({
188
207
  contentId: event.contentId,
189
208
  fromBitrate: event.fromBitrate,
@@ -198,6 +217,9 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
198
217
  if (onContentTapped) {
199
218
  subscriptions.push(
200
219
  NativeShortKitModule.onContentTapped((event) => {
220
+ // Filter to this feed instance — ShortKitDelegate is a singleton
221
+ // (bridge); native side tags with active surface's feedId.
222
+ if (event.feedId !== feedId && event.feedId !== '') return;
201
223
  onContentTapped(event.contentId, event.index);
202
224
  }),
203
225
  );
@@ -229,6 +251,10 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
229
251
  if (onDidFetchContentItems) {
230
252
  subscriptions.push(
231
253
  NativeShortKitModule.onDidFetchContentItems((event) => {
254
+ // Filter to this feed instance — ShortKitDelegate is a singleton
255
+ // (bridge); native side tags with active surface's feedId (at
256
+ // delegate call time, before any Task/await suspension).
257
+ if (event.feedId !== feedId && event.feedId !== '') return;
232
258
  try {
233
259
  const items = JSON.parse(event.items);
234
260
  onDidFetchContentItems(items);
@@ -242,6 +268,11 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
242
268
  if (onCarouselActiveVideoCompleted) {
243
269
  subscriptions.push(
244
270
  NativeShortKitModule.onCarouselActiveVideoCompleted((event) => {
271
+ // Filter to this feed instance — overlay events were previously
272
+ // unscoped per-feed; native side now tags with active surface's
273
+ // feedId. surfaceId continues to identify the React overlay host
274
+ // (separate concern from feedId).
275
+ if (event.feedId !== feedId && event.feedId !== '') return;
245
276
  try {
246
277
  onCarouselActiveVideoCompleted({
247
278
  surfaceId: event.surfaceId,
@@ -56,11 +56,13 @@ type CueEvent = Readonly<{
56
56
  }>;
57
57
 
58
58
  type LoopEvent = Readonly<{
59
+ feedId: string;
59
60
  contentId: string;
60
61
  loopCount: Int32;
61
62
  }>;
62
63
 
63
64
  type FeedTransitionEvent = Readonly<{
65
+ feedId: string;
64
66
  phase: string;
65
67
  fromItem?: string; // JSON-serialized ContentItem
66
68
  toItem?: string; // JSON-serialized ContentItem
@@ -73,6 +75,7 @@ type FeedScrollPhaseEvent = Readonly<{
73
75
  }>;
74
76
 
75
77
  type FormatChangeEvent = Readonly<{
78
+ feedId: string;
76
79
  contentId: string;
77
80
  fromBitrate: Double;
78
81
  toBitrate: Double;
@@ -103,10 +106,12 @@ type RefreshStateChangedPerFeedEvent = Readonly<{
103
106
  }>;
104
107
 
105
108
  type DidFetchContentItemsEvent = Readonly<{
109
+ feedId: string;
106
110
  items: string; // JSON-serialized ContentItem[]
107
111
  }>;
108
112
 
109
113
  type ContentTappedEvent = Readonly<{
114
+ feedId: string;
110
115
  contentId: string;
111
116
  index: Int32;
112
117
  }>;
@@ -214,6 +219,7 @@ type VideoCarouselItemChangedEvent = Readonly<{
214
219
  }>;
215
220
 
216
221
  type CarouselActiveVideoCompletedEvent = Readonly<{
222
+ feedId: string;
217
223
  surfaceId: string;
218
224
  contentItem: string; // JSON-serialized ContentItem
219
225
  indexInCarousel: Int32;