@applicaster/zapp-react-native-utils 15.1.0-rc.9 → 16.0.0-alpha.1011304583

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 (177) hide show
  1. package/README.md +0 -6
  2. package/actionUtils/index.ts +7 -0
  3. package/actionsExecutor/ActionExecutorContext.tsx +67 -14
  4. package/actionsExecutor/feedDecorator.ts +6 -6
  5. package/adsUtils/__tests__/createVMAP.test.ts +419 -0
  6. package/adsUtils/index.ts +2 -2
  7. package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +2 -2
  8. package/analyticsUtils/PlayerAnalyticsManager.ts +11 -1
  9. package/analyticsUtils/README.md +1 -1
  10. package/analyticsUtils/__tests__/analyticsMapper.test.ts +35 -0
  11. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testACP_events.json +1 -1
  12. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testBlockUnlistedParams_rules.json +1 -1
  13. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_events.json +4 -0
  14. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_rules.json +6 -0
  15. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEventRegex_events.json +3 -9
  16. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_events.json +18 -0
  17. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_rules.json +16 -0
  18. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_events.json +4 -0
  19. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_rules.json +6 -0
  20. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_events.json +4 -0
  21. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_rules.json +6 -0
  22. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_events.json +4 -0
  23. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_rules.json +6 -0
  24. package/analyticsUtils/__tests__/fixtures/index.js +20 -0
  25. package/analyticsUtils/analyticsMapper.ts +4 -1
  26. package/analyticsUtils/playerAnalyticsTracker.ts +26 -3
  27. package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
  28. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
  29. package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
  30. package/appUtils/HooksManager/index.ts +12 -18
  31. package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
  32. package/appUtils/accessibilityManager/const.ts +4 -0
  33. package/appUtils/accessibilityManager/utils.ts +0 -1
  34. package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
  35. package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
  36. package/appUtils/contextKeysManager/contextResolver.ts +51 -22
  37. package/appUtils/contextKeysManager/index.ts +65 -10
  38. package/appUtils/contextKeysManager/utils/index.ts +38 -25
  39. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -0
  40. package/appUtils/focusManager/index.ios.ts +43 -4
  41. package/appUtils/focusManager/treeDataStructure/Tree/__tests__/Tree.test.js +46 -0
  42. package/appUtils/focusManager/treeDataStructure/Tree/index.js +18 -18
  43. package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
  44. package/appUtils/focusManagerAux/utils/index.ts +11 -3
  45. package/appUtils/focusManagerAux/utils/utils.ios.ts +202 -3
  46. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  47. package/appUtils/orientationHelper.ts +2 -4
  48. package/appUtils/platform/platformUtils.ts +12 -1
  49. package/appUtils/playerManager/player.ts +4 -0
  50. package/appUtils/playerManager/playerNative.ts +30 -21
  51. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  52. package/cellUtils/index.ts +3 -5
  53. package/cloudEventsUtils/__tests__/index.test.ts +529 -0
  54. package/cloudEventsUtils/index.ts +65 -1
  55. package/colorUtils/__tests__/isTransparentColor.test.ts +76 -0
  56. package/colorUtils/__tests__/isValidColor.test.ts +70 -0
  57. package/colorUtils/index.ts +50 -0
  58. package/componentsUtils/index.ts +8 -0
  59. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  60. package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
  61. package/errorUtils/__tests__/GeneralError.test.ts +97 -0
  62. package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
  63. package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
  64. package/errorUtils/__tests__/NetworkError.test.ts +202 -0
  65. package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
  66. package/errorUtils/__tests__/invariant.test.ts +112 -0
  67. package/focusManager/aux/index.ts +1 -1
  68. package/headersUtils/__tests__/headersUtils.test.js +11 -1
  69. package/headersUtils/index.ts +2 -1
  70. package/manifestUtils/_internals/__tests__/index.test.js +41 -0
  71. package/manifestUtils/_internals/index.js +33 -0
  72. package/manifestUtils/defaultManifestConfigurations/generalContent.js +35 -0
  73. package/manifestUtils/defaultManifestConfigurations/player.js +59 -1
  74. package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +49 -0
  75. package/manifestUtils/fieldUtils/index.js +54 -0
  76. package/manifestUtils/index.js +3 -1
  77. package/manifestUtils/keys.js +229 -0
  78. package/manifestUtils/mobileAction/button/__tests__/mobileActionButton.test.js +168 -0
  79. package/manifestUtils/mobileAction/button/index.js +140 -0
  80. package/manifestUtils/mobileAction/container/__tests__/mobileActionButtonsContainer.test.js +102 -0
  81. package/manifestUtils/mobileAction/container/index.js +73 -0
  82. package/manifestUtils/mobileAction/groups/__tests__/buildMobileActionButtonGroups.test.js +127 -0
  83. package/manifestUtils/mobileAction/groups/defaults.js +76 -0
  84. package/manifestUtils/mobileAction/groups/index.js +80 -0
  85. package/manifestUtils/platformIsTV.js +1 -0
  86. package/manifestUtils/tvAction/container/index.js +1 -1
  87. package/numberUtils/__tests__/toNumber.test.ts +27 -0
  88. package/numberUtils/__tests__/toPositiveNumber.test.ts +193 -0
  89. package/numberUtils/index.ts +23 -1
  90. package/package.json +4 -4
  91. package/pipesUtils/__tests__/buildUrlWithQuery.test.ts +33 -0
  92. package/pipesUtils/__tests__/withPipesEndpoint.test.tsx +56 -0
  93. package/pipesUtils/index.ts +1 -0
  94. package/pipesUtils/withPipesEndpoint.tsx +54 -0
  95. package/pluginUtils/index.ts +4 -0
  96. package/reactHooks/advertising/index.ts +2 -2
  97. package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
  98. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  99. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  100. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  101. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  102. package/reactHooks/cell-click/index.ts +15 -6
  103. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  104. package/reactHooks/connection/__tests__/index.test.js +1 -1
  105. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  106. package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
  107. package/reactHooks/device/useIsTablet.tsx +14 -19
  108. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  109. package/reactHooks/feed/__mocks__/useMarkPipesDataStale.ts +4 -0
  110. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  111. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  112. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
  113. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  114. package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +1 -1
  115. package/reactHooks/feed/index.ts +5 -3
  116. package/reactHooks/feed/useBatchLoading.ts +17 -3
  117. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  118. package/reactHooks/feed/{usePipesCacheReset.ts → useMarkPipesDataStale.ts} +14 -4
  119. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  120. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  121. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  122. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  123. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  124. package/reactHooks/navigation/__tests__/index.test.tsx +2 -4
  125. package/reactHooks/navigation/index.ts +7 -6
  126. package/reactHooks/navigation/useRoute.ts +8 -6
  127. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  128. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  129. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  130. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  131. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  132. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  133. package/reactHooks/resolvers/useComponentResolver.ts +8 -2
  134. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
  135. package/reactHooks/screen/__tests__/useIsStandaloneFullscreen.test.ts +114 -0
  136. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  137. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  138. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
  139. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  140. package/reactHooks/state/useRivers.ts +1 -1
  141. package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
  142. package/reactHooks/usePluginConfiguration.ts +2 -2
  143. package/reactHooks/utils/__tests__/index.test.js +1 -1
  144. package/reactHooks/utils/index.ts +3 -2
  145. package/rectUtils/__tests__/index.test.ts +549 -0
  146. package/rectUtils/index.ts +2 -2
  147. package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +206 -0
  148. package/refreshUtils/RefreshCoordinator/index.ts +245 -0
  149. package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
  150. package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
  151. package/riverComponetsMeasurementProvider/index.tsx +12 -8
  152. package/screenPickerUtils/__tests__/index.test.ts +333 -0
  153. package/screenState/__tests__/index.test.ts +1 -1
  154. package/screenUtils/index.ts +3 -0
  155. package/searchUtils/const.ts +7 -0
  156. package/searchUtils/index.ts +3 -0
  157. package/stringUtils/index.ts +1 -1
  158. package/testUtils/index.tsx +30 -21
  159. package/time/__tests__/BackgroundTimer.test.ts +156 -0
  160. package/time/__tests__/Timer.test.ts +236 -0
  161. package/typeGuards/__tests__/isString.test.ts +21 -0
  162. package/typeGuards/index.ts +4 -0
  163. package/utils/__tests__/mergeRight.test.ts +48 -0
  164. package/utils/__tests__/path.test.ts +7 -0
  165. package/utils/__tests__/selectors.test.ts +124 -0
  166. package/utils/index.ts +13 -0
  167. package/utils/mergeRight.ts +5 -0
  168. package/utils/path.ts +6 -3
  169. package/utils/pathOr.ts +5 -1
  170. package/utils/selectors.ts +46 -0
  171. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +1 -1
  172. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
  173. package/zappFrameworkUtils/loginPluginUtils.ts +1 -1
  174. package/reactHooks/componentsMap/index.ts +0 -55
  175. package/reactHooks/feed/__mocks__/usePipesCacheReset.ts +0 -1
  176. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
  177. package/reactHooks/feed/useFeedRefresh.tsx +0 -65
@@ -0,0 +1,193 @@
1
+ import { toPositiveNumber } from "..";
2
+
3
+ describe("toPositiveNumber", () => {
4
+ describe("valid positive numbers", () => {
5
+ it("returns the number for positive integers", () => {
6
+ expect(toPositiveNumber(5)).toBe(5);
7
+ expect(toPositiveNumber(1000)).toBe(1000);
8
+ });
9
+
10
+ it("returns the number for positive floats", () => {
11
+ expect(toPositiveNumber(0.1)).toBe(0.1);
12
+ expect(toPositiveNumber(3.14159)).toBe(3.14159);
13
+ });
14
+
15
+ it("returns the number for very small positive numbers", () => {
16
+ expect(toPositiveNumber(1e-300)).toBe(1e-300);
17
+ });
18
+
19
+ it("returns the number for very large positive numbers", () => {
20
+ expect(toPositiveNumber(1e300)).toBe(1e300);
21
+ });
22
+
23
+ it("returns Infinity for positive infinity", () => {
24
+ expect(toPositiveNumber(Infinity)).toBe(Infinity);
25
+ });
26
+
27
+ it("converts valid positive strings to numbers", () => {
28
+ expect(toPositiveNumber("5")).toBe(5);
29
+ expect(toPositiveNumber("3.14")).toBe(3.14);
30
+ expect(toPositiveNumber(" 100 ")).toBe(100);
31
+ });
32
+
33
+ it("converts boolean true to undefined", () => {
34
+ expect(toPositiveNumber(true)).toBeUndefined();
35
+ });
36
+
37
+ it("converts single-element arrays to undefined", () => {
38
+ expect(toPositiveNumber([5])).toBeUndefined();
39
+ expect(toPositiveNumber(["10"])).toBeUndefined();
40
+ });
41
+ });
42
+
43
+ describe("invalid cases (return undefined)", () => {
44
+ describe("zero values", () => {
45
+ it("returns undefined for zero", () => {
46
+ expect(toPositiveNumber(0)).toBeUndefined();
47
+ expect(toPositiveNumber(-0)).toBeUndefined();
48
+ });
49
+
50
+ it("returns undefined for string zero", () => {
51
+ expect(toPositiveNumber("0")).toBeUndefined();
52
+ expect(toPositiveNumber(" 0 ")).toBeUndefined();
53
+ });
54
+
55
+ it("returns undefined for boolean false", () => {
56
+ expect(toPositiveNumber(false)).toBeUndefined();
57
+ });
58
+
59
+ it("returns undefined for empty arrays", () => {
60
+ expect(toPositiveNumber([])).toBeUndefined();
61
+ });
62
+
63
+ it("returns undefined for empty strings", () => {
64
+ expect(toPositiveNumber("")).toBeUndefined();
65
+ expect(toPositiveNumber(" ")).toBeUndefined();
66
+ });
67
+ });
68
+
69
+ describe("negative values", () => {
70
+ it("returns undefined for negative numbers", () => {
71
+ expect(toPositiveNumber(-5)).toBeUndefined();
72
+ expect(toPositiveNumber(-0.1)).toBeUndefined();
73
+ });
74
+
75
+ it("returns undefined for negative strings", () => {
76
+ expect(toPositiveNumber("-5")).toBeUndefined();
77
+ expect(toPositiveNumber(" -10 ")).toBeUndefined();
78
+ });
79
+
80
+ it("returns undefined for negative infinity", () => {
81
+ expect(toPositiveNumber(-Infinity)).toBeUndefined();
82
+ });
83
+ });
84
+
85
+ describe("non-convertible values", () => {
86
+ it("returns undefined for null", () => {
87
+ expect(toPositiveNumber(null)).toBeUndefined();
88
+ });
89
+
90
+ it("returns undefined for undefined", () => {
91
+ expect(toPositiveNumber(undefined)).toBeUndefined();
92
+ });
93
+
94
+ it("returns undefined for objects", () => {
95
+ expect(toPositiveNumber({})).toBeUndefined();
96
+ expect(toPositiveNumber({ a: 1 })).toBeUndefined();
97
+ });
98
+
99
+ it("returns undefined for multi-element arrays", () => {
100
+ expect(toPositiveNumber([1, 2])).toBeUndefined();
101
+ expect(toPositiveNumber(["a", "b"])).toBeUndefined();
102
+ });
103
+
104
+ it("returns undefined for non-numeric strings", () => {
105
+ expect(toPositiveNumber("abc")).toBeUndefined();
106
+ expect(toPositiveNumber("5px")).toBeUndefined();
107
+ expect(toPositiveNumber("123.45.67")).toBeUndefined();
108
+ });
109
+
110
+ it("returns undefined for NaN", () => {
111
+ expect(toPositiveNumber(NaN)).toBeUndefined();
112
+ expect(toPositiveNumber(Number("abc"))).toBeUndefined();
113
+ });
114
+ });
115
+ });
116
+
117
+ describe("special cases", () => {
118
+ it("handles exponential notation correctly", () => {
119
+ expect(toPositiveNumber("1e5")).toBe(100000);
120
+ expect(toPositiveNumber("1e-5")).toBe(0.00001);
121
+ expect(toPositiveNumber("-1e5")).toBeUndefined();
122
+ });
123
+
124
+ it("preserves precision for decimal numbers", () => {
125
+ expect(toPositiveNumber(0.1 + 0.2)).toBeCloseTo(0.3);
126
+ expect(toPositiveNumber("0.1")).toBe(0.1);
127
+ });
128
+
129
+ it("handles numeric strings with leading zeros", () => {
130
+ expect(toPositiveNumber("005")).toBe(5);
131
+ expect(toPositiveNumber("0.5")).toBe(0.5);
132
+ });
133
+
134
+ it("returns undefined for numeric strings with trailing non-numeric characters", () => {
135
+ expect(toPositiveNumber("5px")).toBeUndefined();
136
+ expect(toPositiveNumber("10%")).toBeUndefined();
137
+ });
138
+
139
+ it("handles scientific notation correctly", () => {
140
+ expect(toPositiveNumber("1.5e2")).toBe(150);
141
+ expect(toPositiveNumber("-2.5e3")).toBeUndefined();
142
+ });
143
+ });
144
+
145
+ describe("type conversion behavior", () => {
146
+ it("converts Date objects correctly", () => {
147
+ const date = new Date(2026, 1, 17);
148
+ expect(toPositiveNumber(date)).toBeUndefined();
149
+ });
150
+
151
+ it("converts functions to NaN (returns undefined)", () => {
152
+ expect(toPositiveNumber(() => {})).toBeUndefined();
153
+ expect(toPositiveNumber(Math.sqrt)).toBeUndefined();
154
+ });
155
+
156
+ it("handles Symbol values", () => {
157
+ expect(toPositiveNumber(Symbol("test"))).toBeUndefined();
158
+ });
159
+ });
160
+
161
+ describe("BigInt support", () => {
162
+ // Conditional test based on BigInt availability
163
+ const isBigIntSupported = typeof BigInt !== "undefined";
164
+
165
+ if (isBigIntSupported) {
166
+ it("converts positive BigInt values to numbers when BigInt is supported", () => {
167
+ expect(toPositiveNumber(BigInt(5))).toBe(5);
168
+ expect(toPositiveNumber(BigInt(100))).toBe(100);
169
+ expect(toPositiveNumber(BigInt(1000))).toBe(1000);
170
+ });
171
+
172
+ it("returns undefined for zero BigInt", () => {
173
+ expect(toPositiveNumber(BigInt(0))).toBeUndefined();
174
+ });
175
+
176
+ it("returns undefined for negative BigInt values", () => {
177
+ expect(toPositiveNumber(BigInt(-5))).toBeUndefined();
178
+ expect(toPositiveNumber(BigInt(-100))).toBeUndefined();
179
+ });
180
+
181
+ it("handles large positive BigInt values", () => {
182
+ const largeBigInt = BigInt(Number.MAX_SAFE_INTEGER);
183
+ const result = toPositiveNumber(largeBigInt);
184
+ expect(result).toBe(Number(largeBigInt));
185
+ });
186
+ } else {
187
+ it("skips BigInt tests when BigInt is not supported", () => {
188
+ // Placeholder test to indicate BigInt is not available
189
+ expect(typeof BigInt).toBe("undefined");
190
+ });
191
+ }
192
+ });
193
+ });
@@ -8,7 +8,11 @@ export const toNumber = (value: unknown): number | undefined => {
8
8
  return undefined;
9
9
  }
10
10
 
11
- if (R.is(Number, value) || R.is(String, value)) {
11
+ // Feature-detect BigInt support to avoid ReferenceError on older runtimes
12
+ const isBigIntSupported = typeof BigInt !== "undefined";
13
+ const isBigIntValue = isBigIntSupported && R.is(BigInt, value);
14
+
15
+ if (R.is(Number, value) || isBigIntValue || R.is(String, value)) {
12
16
  const numberOrNan = Number(value);
13
17
 
14
18
  return Number.isNaN(numberOrNan) ? undefined : numberOrNan;
@@ -69,6 +73,24 @@ export const isMinusZero = (value: number) => {
69
73
  return 1 / value === -Infinity;
70
74
  };
71
75
 
76
+ export const toPositiveNumber = (value: unknown): number | undefined => {
77
+ const possibleNumber = toNumber(value);
78
+
79
+ if (R.isNil(possibleNumber)) {
80
+ return undefined;
81
+ }
82
+
83
+ if (possibleNumber < 0) {
84
+ return undefined;
85
+ }
86
+
87
+ if (isZero(possibleNumber)) {
88
+ return undefined;
89
+ }
90
+
91
+ return possibleNumber;
92
+ };
93
+
72
94
  export const toPositiveNumberWithDefault = (
73
95
  defaultValue: number,
74
96
  value: unknown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "15.1.0-rc.9",
3
+ "version": "16.0.0-alpha.1011304583",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,13 +27,13 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "15.1.0-rc.9",
30
+ "@applicaster/applicaster-types": "16.0.0-alpha.1011304583",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
34
+ "handlebars": "4.7.9",
34
35
  "memoizee": "0.4.15",
35
- "prop-types": "^15.0.0",
36
- "react-native-handlebars": "^5.0.0-alpha.1"
36
+ "prop-types": "^15.0.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@applicaster/zapp-pipes-v2-client": "*",
@@ -0,0 +1,33 @@
1
+ import { buildUrlWithQuery } from "../withPipesEndpoint";
2
+
3
+ describe("buildUrlWithQuery", () => {
4
+ it("returns the url unchanged when requestParams is null", () => {
5
+ expect(buildUrlWithQuery("https://foo.com/path", null)).toBe(
6
+ "https://foo.com/path"
7
+ );
8
+ });
9
+
10
+ it("returns the url unchanged when requestParams has no params", () => {
11
+ expect(buildUrlWithQuery("https://foo.com/path", { headers: {} })).toBe(
12
+ "https://foo.com/path"
13
+ );
14
+ });
15
+
16
+ it("returns the url unchanged when url is empty", () => {
17
+ expect(buildUrlWithQuery("", { params: { a: "1" } })).toBe("");
18
+ });
19
+
20
+ it("appends params to a url with no existing query", () => {
21
+ expect(
22
+ buildUrlWithQuery("https://foo.com/path", { params: { token: "abc" } })
23
+ ).toBe("https://foo.com/path?token=abc");
24
+ });
25
+
26
+ it("merges params with an existing query string", () => {
27
+ expect(
28
+ buildUrlWithQuery("https://foo.com/path?existing=1", {
29
+ params: { token: "abc" },
30
+ })
31
+ ).toBe("https://foo.com/path?existing=1&token=abc");
32
+ });
33
+ });
@@ -0,0 +1,56 @@
1
+ import * as React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+ import { Text } from "react-native";
4
+
5
+ const mockedUseBuildPipesUrl = jest.fn();
6
+
7
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/feed", () => ({
8
+ useBuildPipesUrl: (args) => mockedUseBuildPipesUrl(args),
9
+ }));
10
+
11
+ const { withPipesEndpoint } = require("../withPipesEndpoint");
12
+
13
+ // eslint-disable-next-line react/display-name
14
+ const Wrapped = React.forwardRef((props: any, _ref) => (
15
+ <Text testID="wrapped">{`${props.uri}|${JSON.stringify(props.headers)}`}</Text>
16
+ ));
17
+
18
+ describe("withPipesEndpoint", () => {
19
+ afterEach(() => jest.clearAllMocks());
20
+
21
+ it("renders nothing while the endpoint context is resolving", () => {
22
+ mockedUseBuildPipesUrl.mockReturnValue({ requestParams: null });
23
+
24
+ const Decorated = withPipesEndpoint(Wrapped);
25
+ const { queryByTestId } = render(<Decorated uri="https://foo.com" />);
26
+
27
+ expect(queryByTestId("wrapped")).toBeNull();
28
+ });
29
+
30
+ it("passes the uri through unchanged when there are no params", () => {
31
+ mockedUseBuildPipesUrl.mockReturnValue({ requestParams: {} });
32
+
33
+ const Decorated = withPipesEndpoint(Wrapped);
34
+ const { getByTestId } = render(<Decorated uri="https://foo.com/path" />);
35
+
36
+ expect(getByTestId("wrapped").props.children).toBe(
37
+ "https://foo.com/path|{}"
38
+ );
39
+ });
40
+
41
+ it("merges resolved params into the uri and forwards headers", () => {
42
+ mockedUseBuildPipesUrl.mockReturnValue({
43
+ requestParams: {
44
+ params: { token: "abc" },
45
+ headers: { Authorization: "Bearer xyz" },
46
+ },
47
+ });
48
+
49
+ const Decorated = withPipesEndpoint(Wrapped);
50
+ const { getByTestId } = render(<Decorated uri="https://foo.com/path" />);
51
+
52
+ expect(getByTestId("wrapped").props.children).toBe(
53
+ 'https://foo.com/path?token=abc|{"Authorization":"Bearer xyz"}'
54
+ );
55
+ });
56
+ });
@@ -0,0 +1 @@
1
+ export { withPipesEndpoint, buildUrlWithQuery } from "./withPipesEndpoint";
@@ -0,0 +1,54 @@
1
+ import React, { forwardRef, RefObject } from "react";
2
+ import URL from "url";
3
+
4
+ import { useBuildPipesUrl } from "@applicaster/zapp-react-native-utils/reactHooks/feed";
5
+
6
+ /**
7
+ * Merges the query params resolved from a pipes endpoint context into the url.
8
+ * Returns the url unchanged when there is nothing to merge.
9
+ */
10
+ export function buildUrlWithQuery(url: string, requestParams): string {
11
+ if (!url || !requestParams?.params) {
12
+ return url;
13
+ }
14
+
15
+ const parsedURL = URL.parse(url, true);
16
+
17
+ parsedURL.query = { ...parsedURL.query, ...requestParams.params };
18
+ parsedURL.search = null;
19
+
20
+ return URL.format(parsedURL);
21
+ }
22
+
23
+ type Props = {
24
+ uri: string;
25
+ } & Record<string, unknown>;
26
+
27
+ /**
28
+ * HOC that resolves the wrapped component's `uri` against its matching Zapp
29
+ * Pipes endpoint. Endpoint context keys are added as query params (merged into
30
+ * the uri) and as request `headers`. Rendering is deferred until the context
31
+ * has been resolved so the component never loads without its required headers.
32
+ */
33
+ export function withPipesEndpoint(Component) {
34
+ function WithPipesEndpoint(props: Props, ref: RefObject<unknown>) {
35
+ const { requestParams } = useBuildPipesUrl({ url: props.uri });
36
+
37
+ if (requestParams !== null) {
38
+ const urlWithQuery = buildUrlWithQuery(props.uri, requestParams);
39
+
40
+ return (
41
+ <Component
42
+ ref={ref}
43
+ {...props}
44
+ uri={urlWithQuery}
45
+ headers={requestParams.headers || {}}
46
+ />
47
+ );
48
+ }
49
+
50
+ return null;
51
+ }
52
+
53
+ return forwardRef(WithPipesEndpoint);
54
+ }
@@ -6,6 +6,7 @@ import { deprecationMessage } from "../appUtils";
6
6
 
7
7
  import { pluginUtilsLogger } from "./logger";
8
8
  import { platformSelect } from "../reactUtils";
9
+ import { get } from "../utils";
9
10
 
10
11
  type PluginModule = any;
11
12
  type Plugin = {
@@ -253,3 +254,6 @@ const getPluginType = R.pathOr("unknown_plugin_type", [
253
254
 
254
255
  export const isPlayerPlugin = (routeState): boolean =>
255
256
  getPluginType(routeState) === "player";
257
+
258
+ export const getPluginModuleUrlScheme = (plugin) =>
259
+ get(plugin, ["module", "urlScheme"]);
@@ -3,7 +3,7 @@ import { View } from "react-native";
3
3
  import * as R from "ramda";
4
4
 
5
5
  import { useNavigation } from "../navigation";
6
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
+ import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
7
7
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
8
8
  import { dismissModal, openModal } from "../../modalState";
9
9
 
@@ -16,7 +16,7 @@ const ModalContainer = platformSelect({
16
16
 
17
17
  export function useAdvertisingInterstitial() {
18
18
  const { screenData, currentRoute } = useNavigation();
19
- const { plugins } = usePickFromState();
19
+ const plugins = usePlugins();
20
20
 
21
21
  return useEffect(() => {
22
22
  // TODD: typing problem: fix any type