@use-voltra/ios-client 2.1.1 → 2.3.0

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 (365) hide show
  1. package/README.md +61 -8
  2. package/Voltra.podspec +1 -0
  3. package/build/commonjs/dynamic-widget/api.js +15 -0
  4. package/build/commonjs/dynamic-widget/api.js.map +1 -0
  5. package/build/commonjs/events.js +23 -0
  6. package/build/commonjs/events.js.map +1 -1
  7. package/build/commonjs/index.js +74 -7
  8. package/build/commonjs/index.js.map +1 -1
  9. package/build/commonjs/live-activity/api.js +3 -1
  10. package/build/commonjs/live-activity/api.js.map +1 -1
  11. package/build/commonjs/live-activity/dynamic-api.js +173 -0
  12. package/build/commonjs/live-activity/dynamic-api.js.map +1 -0
  13. package/build/commonjs/native/NativeVoltra.js.map +1 -1
  14. package/build/commonjs/utils/enableDynamicLiveActivityHotReload.js +47 -0
  15. package/build/commonjs/utils/enableDynamicLiveActivityHotReload.js.map +1 -0
  16. package/build/commonjs/utils/enableWidgetHotReload.js +8 -11
  17. package/build/commonjs/utils/enableWidgetHotReload.js.map +1 -1
  18. package/build/commonjs/utils/useUpdateOnHMR.js +3 -7
  19. package/build/commonjs/utils/useUpdateOnHMR.js.map +1 -1
  20. package/build/commonjs/widgets/server-credentials.js +9 -0
  21. package/build/commonjs/widgets/server-credentials.js.map +1 -1
  22. package/build/commonjs/widgets/server-update.js +78 -0
  23. package/build/commonjs/widgets/server-update.js.map +1 -0
  24. package/build/module/dynamic-widget/api.js +10 -0
  25. package/build/module/dynamic-widget/api.js.map +1 -0
  26. package/build/module/events.js +23 -0
  27. package/build/module/events.js.map +1 -1
  28. package/build/module/index.js +4 -0
  29. package/build/module/index.js.map +1 -1
  30. package/build/module/live-activity/api.js +2 -2
  31. package/build/module/live-activity/api.js.map +1 -1
  32. package/build/module/live-activity/dynamic-api.js +167 -0
  33. package/build/module/live-activity/dynamic-api.js.map +1 -0
  34. package/build/module/native/NativeVoltra.js.map +1 -1
  35. package/build/module/utils/enableDynamicLiveActivityHotReload.js +43 -0
  36. package/build/module/utils/enableDynamicLiveActivityHotReload.js.map +1 -0
  37. package/build/module/utils/enableWidgetHotReload.js +9 -11
  38. package/build/module/utils/enableWidgetHotReload.js.map +1 -1
  39. package/build/module/utils/useUpdateOnHMR.js +3 -7
  40. package/build/module/utils/useUpdateOnHMR.js.map +1 -1
  41. package/build/module/widgets/server-credentials.js +9 -0
  42. package/build/module/widgets/server-credentials.js.map +1 -1
  43. package/build/module/widgets/server-update.js +72 -0
  44. package/build/module/widgets/server-update.js.map +1 -0
  45. package/build/typescript/commonjs/dynamic-widget/api.d.ts +8 -0
  46. package/build/typescript/commonjs/dynamic-widget/api.d.ts.map +1 -0
  47. package/build/typescript/commonjs/events.d.ts +7 -0
  48. package/build/typescript/commonjs/events.d.ts.map +1 -1
  49. package/build/typescript/commonjs/index.d.ts +4 -0
  50. package/build/typescript/commonjs/index.d.ts.map +1 -1
  51. package/build/typescript/commonjs/live-activity/api.d.ts +7 -0
  52. package/build/typescript/commonjs/live-activity/api.d.ts.map +1 -1
  53. package/build/typescript/commonjs/live-activity/dynamic-api.d.ts +54 -0
  54. package/build/typescript/commonjs/live-activity/dynamic-api.d.ts.map +1 -0
  55. package/build/typescript/commonjs/native/NativeVoltra.d.ts +21 -0
  56. package/build/typescript/commonjs/native/NativeVoltra.d.ts.map +1 -1
  57. package/build/typescript/commonjs/types.d.ts +1 -1
  58. package/build/typescript/commonjs/types.d.ts.map +1 -1
  59. package/build/typescript/commonjs/utils/enableDynamicLiveActivityHotReload.d.ts +15 -0
  60. package/build/typescript/commonjs/utils/enableDynamicLiveActivityHotReload.d.ts.map +1 -0
  61. package/build/typescript/commonjs/utils/enableWidgetHotReload.d.ts +5 -7
  62. package/build/typescript/commonjs/utils/enableWidgetHotReload.d.ts.map +1 -1
  63. package/build/typescript/commonjs/utils/useUpdateOnHMR.d.ts +0 -3
  64. package/build/typescript/commonjs/utils/useUpdateOnHMR.d.ts.map +1 -1
  65. package/build/typescript/commonjs/widgets/server-credentials.d.ts +8 -0
  66. package/build/typescript/commonjs/widgets/server-credentials.d.ts.map +1 -1
  67. package/build/typescript/commonjs/widgets/server-update.d.ts +64 -0
  68. package/build/typescript/commonjs/widgets/server-update.d.ts.map +1 -0
  69. package/build/typescript/module/dynamic-widget/api.d.ts +8 -0
  70. package/build/typescript/module/dynamic-widget/api.d.ts.map +1 -0
  71. package/build/typescript/module/events.d.ts +7 -0
  72. package/build/typescript/module/events.d.ts.map +1 -1
  73. package/build/typescript/module/index.d.ts +4 -0
  74. package/build/typescript/module/index.d.ts.map +1 -1
  75. package/build/typescript/module/live-activity/api.d.ts +7 -0
  76. package/build/typescript/module/live-activity/api.d.ts.map +1 -1
  77. package/build/typescript/module/live-activity/dynamic-api.d.ts +54 -0
  78. package/build/typescript/module/live-activity/dynamic-api.d.ts.map +1 -0
  79. package/build/typescript/module/native/NativeVoltra.d.ts +21 -0
  80. package/build/typescript/module/native/NativeVoltra.d.ts.map +1 -1
  81. package/build/typescript/module/types.d.ts +1 -1
  82. package/build/typescript/module/types.d.ts.map +1 -1
  83. package/build/typescript/module/utils/enableDynamicLiveActivityHotReload.d.ts +15 -0
  84. package/build/typescript/module/utils/enableDynamicLiveActivityHotReload.d.ts.map +1 -0
  85. package/build/typescript/module/utils/enableWidgetHotReload.d.ts +5 -7
  86. package/build/typescript/module/utils/enableWidgetHotReload.d.ts.map +1 -1
  87. package/build/typescript/module/utils/useUpdateOnHMR.d.ts +0 -3
  88. package/build/typescript/module/utils/useUpdateOnHMR.d.ts.map +1 -1
  89. package/build/typescript/module/widgets/server-credentials.d.ts +8 -0
  90. package/build/typescript/module/widgets/server-credentials.d.ts.map +1 -1
  91. package/build/typescript/module/widgets/server-update.d.ts +64 -0
  92. package/build/typescript/module/widgets/server-update.d.ts.map +1 -0
  93. package/expo-plugin/build/cjs/constants.js +20 -1
  94. package/expo-plugin/build/cjs/constants.js.map +1 -1
  95. package/expo-plugin/build/cjs/index.js +9 -1
  96. package/expo-plugin/build/cjs/index.js.map +1 -1
  97. package/expo-plugin/build/cjs/ios/index.js +1 -0
  98. package/expo-plugin/build/cjs/ios/index.js.map +1 -1
  99. package/expo-plugin/build/cjs/ios/infoPlist.js +28 -5
  100. package/expo-plugin/build/cjs/ios/infoPlist.js.map +1 -1
  101. package/expo-plugin/build/cjs/ios/serverUpdate.js +25 -0
  102. package/expo-plugin/build/cjs/ios/serverUpdate.js.map +1 -0
  103. package/expo-plugin/build/cjs/ios-widget/clientRendered.js +4 -4
  104. package/expo-plugin/build/cjs/ios-widget/clientRendered.js.map +1 -1
  105. package/expo-plugin/build/cjs/ios-widget/clientRenderedPrerender.js +5 -5
  106. package/expo-plugin/build/cjs/ios-widget/clientRenderedPrerender.js.map +1 -1
  107. package/expo-plugin/build/cjs/ios-widget/dynamic-live-activity/swift.js +130 -0
  108. package/expo-plugin/build/cjs/ios-widget/dynamic-live-activity/swift.js.map +1 -0
  109. package/expo-plugin/build/cjs/ios-widget/files/index.js +9 -2
  110. package/expo-plugin/build/cjs/ios-widget/files/index.js.map +1 -1
  111. package/expo-plugin/build/cjs/ios-widget/files/infoPlist.js +6 -3
  112. package/expo-plugin/build/cjs/ios-widget/files/infoPlist.js.map +1 -1
  113. package/expo-plugin/build/cjs/ios-widget/files/manifest.js +24 -0
  114. package/expo-plugin/build/cjs/ios-widget/files/manifest.js.map +1 -1
  115. package/expo-plugin/build/cjs/ios-widget/files/swift-utils.js +7 -0
  116. package/expo-plugin/build/cjs/ios-widget/files/swift-utils.js.map +1 -0
  117. package/expo-plugin/build/cjs/ios-widget/files/swift.js +56 -26
  118. package/expo-plugin/build/cjs/ios-widget/files/swift.js.map +1 -1
  119. package/expo-plugin/build/cjs/ios-widget/index.js +9 -3
  120. package/expo-plugin/build/cjs/ios-widget/index.js.map +1 -1
  121. package/expo-plugin/build/cjs/ios-widget/podfile.js +38 -12
  122. package/expo-plugin/build/cjs/ios-widget/podfile.js.map +1 -1
  123. package/expo-plugin/build/cjs/ios-widget/widgetPlist.js +34 -22
  124. package/expo-plugin/build/cjs/ios-widget/widgetPlist.js.map +1 -1
  125. package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js +194 -118
  126. package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js.map +1 -1
  127. package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js +30 -22
  128. package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js.map +1 -1
  129. package/expo-plugin/build/cjs/ios-widget/xcode/fileReferences.js +50 -0
  130. package/expo-plugin/build/cjs/ios-widget/xcode/fileReferences.js.map +1 -0
  131. package/expo-plugin/build/cjs/ios-widget/xcode/groups.js +45 -43
  132. package/expo-plugin/build/cjs/ios-widget/xcode/groups.js.map +1 -1
  133. package/expo-plugin/build/cjs/ios-widget/xcode/index.js +93 -91
  134. package/expo-plugin/build/cjs/ios-widget/xcode/index.js.map +1 -1
  135. package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js +41 -39
  136. package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js.map +1 -1
  137. package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js +2 -2
  138. package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js.map +1 -1
  139. package/expo-plugin/build/cjs/ios-widget/xcode/target.js +29 -63
  140. package/expo-plugin/build/cjs/ios-widget/xcode/target.js.map +1 -1
  141. package/expo-plugin/build/cjs/utils/urlScheme.js +36 -14
  142. package/expo-plugin/build/cjs/utils/urlScheme.js.map +1 -1
  143. package/expo-plugin/build/cjs/validation.js +54 -0
  144. package/expo-plugin/build/cjs/validation.js.map +1 -1
  145. package/expo-plugin/build/esm/constants.js +17 -0
  146. package/expo-plugin/build/esm/constants.js.map +1 -1
  147. package/expo-plugin/build/esm/index.js +9 -1
  148. package/expo-plugin/build/esm/index.js.map +1 -1
  149. package/expo-plugin/build/esm/ios/index.js +1 -0
  150. package/expo-plugin/build/esm/ios/index.js.map +1 -1
  151. package/expo-plugin/build/esm/ios/infoPlist.js +28 -5
  152. package/expo-plugin/build/esm/ios/infoPlist.js.map +1 -1
  153. package/expo-plugin/build/esm/ios/serverUpdate.js +21 -0
  154. package/expo-plugin/build/esm/ios/serverUpdate.js.map +1 -0
  155. package/expo-plugin/build/esm/ios-widget/clientRendered.js +5 -5
  156. package/expo-plugin/build/esm/ios-widget/clientRendered.js.map +1 -1
  157. package/expo-plugin/build/esm/ios-widget/clientRenderedPrerender.js +6 -6
  158. package/expo-plugin/build/esm/ios-widget/clientRenderedPrerender.js.map +1 -1
  159. package/expo-plugin/build/esm/ios-widget/dynamic-live-activity/swift.js +122 -0
  160. package/expo-plugin/build/esm/ios-widget/dynamic-live-activity/swift.js.map +1 -0
  161. package/expo-plugin/build/esm/ios-widget/files/index.js +10 -3
  162. package/expo-plugin/build/esm/ios-widget/files/index.js.map +1 -1
  163. package/expo-plugin/build/esm/ios-widget/files/infoPlist.js +6 -3
  164. package/expo-plugin/build/esm/ios-widget/files/infoPlist.js.map +1 -1
  165. package/expo-plugin/build/esm/ios-widget/files/manifest.js +23 -1
  166. package/expo-plugin/build/esm/ios-widget/files/manifest.js.map +1 -1
  167. package/expo-plugin/build/esm/ios-widget/files/swift-utils.js +4 -0
  168. package/expo-plugin/build/esm/ios-widget/files/swift-utils.js.map +1 -0
  169. package/expo-plugin/build/esm/ios-widget/files/swift.js +50 -20
  170. package/expo-plugin/build/esm/ios-widget/files/swift.js.map +1 -1
  171. package/expo-plugin/build/esm/ios-widget/index.js +9 -3
  172. package/expo-plugin/build/esm/ios-widget/index.js.map +1 -1
  173. package/expo-plugin/build/esm/ios-widget/podfile.js +36 -11
  174. package/expo-plugin/build/esm/ios-widget/podfile.js.map +1 -1
  175. package/expo-plugin/build/esm/ios-widget/widgetPlist.js +34 -22
  176. package/expo-plugin/build/esm/ios-widget/widgetPlist.js.map +1 -1
  177. package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js +194 -117
  178. package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js.map +1 -1
  179. package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js +31 -22
  180. package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js.map +1 -1
  181. package/expo-plugin/build/esm/ios-widget/xcode/fileReferences.js +45 -0
  182. package/expo-plugin/build/esm/ios-widget/xcode/fileReferences.js.map +1 -0
  183. package/expo-plugin/build/esm/ios-widget/xcode/groups.js +45 -42
  184. package/expo-plugin/build/esm/ios-widget/xcode/groups.js.map +1 -1
  185. package/expo-plugin/build/esm/ios-widget/xcode/index.js +97 -96
  186. package/expo-plugin/build/esm/ios-widget/xcode/index.js.map +1 -1
  187. package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js +41 -39
  188. package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js.map +1 -1
  189. package/expo-plugin/build/esm/ios-widget/xcode/productFile.js +3 -2
  190. package/expo-plugin/build/esm/ios-widget/xcode/productFile.js.map +1 -1
  191. package/expo-plugin/build/esm/ios-widget/xcode/target.js +28 -62
  192. package/expo-plugin/build/esm/ios-widget/xcode/target.js.map +1 -1
  193. package/expo-plugin/build/esm/utils/urlScheme.js +34 -14
  194. package/expo-plugin/build/esm/utils/urlScheme.js.map +1 -1
  195. package/expo-plugin/build/esm/validation.js +54 -1
  196. package/expo-plugin/build/esm/validation.js.map +1 -1
  197. package/expo-plugin/build/types/constants.d.ts +10 -1
  198. package/expo-plugin/build/types/constants.d.ts.map +1 -1
  199. package/expo-plugin/build/types/index.d.ts +1 -1
  200. package/expo-plugin/build/types/index.d.ts.map +1 -1
  201. package/expo-plugin/build/types/ios/index.d.ts +2 -0
  202. package/expo-plugin/build/types/ios/index.d.ts.map +1 -1
  203. package/expo-plugin/build/types/ios/infoPlist.d.ts +2 -0
  204. package/expo-plugin/build/types/ios/infoPlist.d.ts.map +1 -1
  205. package/expo-plugin/build/types/ios/serverUpdate.d.ts +11 -0
  206. package/expo-plugin/build/types/ios/serverUpdate.d.ts.map +1 -0
  207. package/expo-plugin/build/types/ios-widget/clientRendered.d.ts.map +1 -1
  208. package/expo-plugin/build/types/ios-widget/clientRenderedPrerender.d.ts.map +1 -1
  209. package/expo-plugin/build/types/ios-widget/dynamic-live-activity/swift.d.ts +7 -0
  210. package/expo-plugin/build/types/ios-widget/dynamic-live-activity/swift.d.ts.map +1 -0
  211. package/expo-plugin/build/types/ios-widget/files/index.d.ts +3 -1
  212. package/expo-plugin/build/types/ios-widget/files/index.d.ts.map +1 -1
  213. package/expo-plugin/build/types/ios-widget/files/infoPlist.d.ts +2 -1
  214. package/expo-plugin/build/types/ios-widget/files/infoPlist.d.ts.map +1 -1
  215. package/expo-plugin/build/types/ios-widget/files/manifest.d.ts +9 -2
  216. package/expo-plugin/build/types/ios-widget/files/manifest.d.ts.map +1 -1
  217. package/expo-plugin/build/types/ios-widget/files/swift-utils.d.ts +2 -0
  218. package/expo-plugin/build/types/ios-widget/files/swift-utils.d.ts.map +1 -0
  219. package/expo-plugin/build/types/ios-widget/files/swift.d.ts +6 -2
  220. package/expo-plugin/build/types/ios-widget/files/swift.d.ts.map +1 -1
  221. package/expo-plugin/build/types/ios-widget/index.d.ts +3 -1
  222. package/expo-plugin/build/types/ios-widget/index.d.ts.map +1 -1
  223. package/expo-plugin/build/types/ios-widget/podfile.d.ts +19 -1
  224. package/expo-plugin/build/types/ios-widget/podfile.d.ts.map +1 -1
  225. package/expo-plugin/build/types/ios-widget/widgetPlist.d.ts.map +1 -1
  226. package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts +6 -8
  227. package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts.map +1 -1
  228. package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts +15 -10
  229. package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts.map +1 -1
  230. package/expo-plugin/build/types/ios-widget/xcode/fileReferences.d.ts +16 -0
  231. package/expo-plugin/build/types/ios-widget/xcode/fileReferences.d.ts.map +1 -0
  232. package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts +0 -4
  233. package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts.map +1 -1
  234. package/expo-plugin/build/types/ios-widget/xcode/index.d.ts +23 -3
  235. package/expo-plugin/build/types/ios-widget/xcode/index.d.ts.map +1 -1
  236. package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts +16 -4
  237. package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts.map +1 -1
  238. package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts +0 -4
  239. package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts.map +1 -1
  240. package/expo-plugin/build/types/ios-widget/xcode/target.d.ts +11 -26
  241. package/expo-plugin/build/types/ios-widget/xcode/target.d.ts.map +1 -1
  242. package/expo-plugin/build/types/types.d.ts +23 -4
  243. package/expo-plugin/build/types/types.d.ts.map +1 -1
  244. package/expo-plugin/build/types/utils/urlScheme.d.ts +16 -0
  245. package/expo-plugin/build/types/utils/urlScheme.d.ts.map +1 -1
  246. package/expo-plugin/build/types/validation.d.ts +2 -1
  247. package/expo-plugin/build/types/validation.d.ts.map +1 -1
  248. package/expo-plugin/src/constants.ts +24 -1
  249. package/expo-plugin/src/index.ts +14 -1
  250. package/expo-plugin/src/ios/index.ts +3 -0
  251. package/expo-plugin/src/ios/infoPlist.ts +33 -5
  252. package/expo-plugin/src/ios/serverUpdate.ts +29 -0
  253. package/expo-plugin/src/ios-widget/clientRendered.ts +9 -5
  254. package/expo-plugin/src/ios-widget/clientRenderedPrerender.ts +11 -6
  255. package/expo-plugin/src/ios-widget/dynamic-live-activity/swift.ts +138 -0
  256. package/expo-plugin/src/ios-widget/files/index.ts +15 -4
  257. package/expo-plugin/src/ios-widget/files/infoPlist.ts +17 -3
  258. package/expo-plugin/src/ios-widget/files/manifest.ts +42 -2
  259. package/expo-plugin/src/ios-widget/files/swift-utils.ts +3 -0
  260. package/expo-plugin/src/ios-widget/files/swift.ts +69 -22
  261. package/expo-plugin/src/ios-widget/index.ts +13 -3
  262. package/expo-plugin/src/ios-widget/podfile.ts +46 -13
  263. package/expo-plugin/src/ios-widget/widgetPlist.ts +37 -23
  264. package/expo-plugin/src/ios-widget/xcode/__fixtures__/fresh.pbxproj +197 -0
  265. package/expo-plugin/src/ios-widget/xcode/__fixtures__/with-existing-extension.pbxproj +321 -0
  266. package/expo-plugin/src/ios-widget/xcode/__fixtures__/with-per-config-signing.pbxproj +203 -0
  267. package/expo-plugin/src/ios-widget/xcode/__snapshots__/applyXcodeChanges.node.test.ts.snap +363 -0
  268. package/expo-plugin/src/ios-widget/xcode/__tests__/pbxConsistency.ts +130 -0
  269. package/expo-plugin/src/ios-widget/xcode/buildPhases.ts +210 -164
  270. package/expo-plugin/src/ios-widget/xcode/configurationList.ts +52 -35
  271. package/expo-plugin/src/ios-widget/xcode/fileReferences.ts +51 -0
  272. package/expo-plugin/src/ios-widget/xcode/groups.ts +52 -54
  273. package/expo-plugin/src/ios-widget/xcode/index.ts +124 -119
  274. package/expo-plugin/src/ios-widget/xcode/mainAppSettings.ts +59 -54
  275. package/expo-plugin/src/ios-widget/xcode/productFile.ts +3 -2
  276. package/expo-plugin/src/ios-widget/xcode/target.ts +31 -83
  277. package/expo-plugin/src/types.ts +28 -4
  278. package/expo-plugin/src/utils/urlScheme.ts +47 -17
  279. package/expo-plugin/src/validation.ts +76 -1
  280. package/ios/Package.swift +39 -4
  281. package/ios/VoltraWidget.podspec +1 -0
  282. package/ios/app/NativeVoltra.mm +126 -7
  283. package/ios/app/VoltraLiveActivityManager.swift +30 -0
  284. package/ios/app/VoltraLiveActivityService.swift +77 -5
  285. package/ios/app/VoltraModule.swift +117 -1
  286. package/ios/app/VoltraModuleImpl.swift +116 -2
  287. package/ios/app/VoltraViewComponentView.mm +3 -3
  288. package/ios/app/VoltraWidgetService.swift +147 -12
  289. package/ios/app/dynamic-live-activity/VoltraDynamicLiveActivityService.swift +97 -0
  290. package/ios/app/dynamic-live-activity/VoltraLiveActivityChronology.swift +68 -0
  291. package/ios/shared/DynamicWidgetPropsCodec.swift +51 -0
  292. package/ios/shared/DynamicWidgetPropsStorage.swift +53 -0
  293. package/ios/shared/DynamicWidgetPropsStore.swift +117 -0
  294. package/ios/shared/DynamicWidgetRenderCoordinator.swift +31 -0
  295. package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerFetchResolver.swift +34 -0
  296. package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerProps.swift +55 -0
  297. package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerPropsStore.swift +146 -0
  298. package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerUpdateRunner.swift +193 -0
  299. package/ios/shared/DynamicWidgetUpdater.swift +30 -0
  300. package/ios/shared/ServerWidgetContentResolver.swift +60 -0
  301. package/ios/shared/ServerWidgetResponseStore.swift +25 -0
  302. package/ios/shared/ShortNames.swift +6 -0
  303. package/ios/shared/VoltraConfig.swift +41 -0
  304. package/ios/shared/VoltraConstants.swift +19 -0
  305. package/ios/shared/VoltraElement.swift +127 -43
  306. package/ios/shared/VoltraEventBus.swift +52 -7
  307. package/ios/shared/VoltraJSRenderer.swift +93 -23
  308. package/ios/shared/VoltraNode.swift +7 -111
  309. package/ios/shared/VoltraRefreshIntent.swift +1 -1
  310. package/ios/shared/VoltraWidgetDefaults.swift +9 -1
  311. package/ios/shared/VoltraWidgetKind.swift +41 -0
  312. package/ios/shared/VoltraWidgetServerFetcher.swift +52 -107
  313. package/ios/shared/WidgetServer/VoltraWidgetAppearance.swift +17 -0
  314. package/ios/shared/WidgetServer/VoltraWidgetServer.swift +138 -0
  315. package/ios/shared/WidgetServer/WidgetCanonicalConfiguration.swift +77 -0
  316. package/ios/shared/WidgetServer/WidgetScope.swift +55 -0
  317. package/ios/shared/WidgetServer/WidgetServerEtagStore.swift +55 -0
  318. package/ios/shared/WidgetServer/WidgetServerFetcher.swift +179 -0
  319. package/ios/shared/WidgetServer/WidgetServerRequestBuilder.swift +114 -0
  320. package/ios/shared/WidgetServer/WidgetServerSettingsCodec.swift +47 -0
  321. package/ios/shared/WidgetServer/WidgetServerSettingsResolver.swift +129 -0
  322. package/ios/shared/WidgetServer/WidgetServerSettingsStore.swift +170 -0
  323. package/ios/shared/WidgetServer/WidgetServerSettingsValidator.swift +73 -0
  324. package/ios/shared/WidgetServer/WidgetServerUpdateSettings.swift +123 -0
  325. package/ios/shared/WidgetServer/WidgetServerUpdateSettingsJson.swift +115 -0
  326. package/ios/shared/dynamic-live-activity/DynamicLiveActivityPropsCodec.swift +13 -0
  327. package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityBundleSource.swift +156 -0
  328. package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityObserver.swift +97 -0
  329. package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityOperations.swift +105 -0
  330. package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityPayloadValidator.swift +55 -0
  331. package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRegistry.swift +143 -0
  332. package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRenderFailureQueue.swift +158 -0
  333. package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRenderFailureReporter.swift +120 -0
  334. package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRenderer.swift +370 -0
  335. package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityTypes.swift +87 -0
  336. package/ios/shared/dynamic-live-activity/VoltraLiveActivityOrder.swift +19 -0
  337. package/ios/target/VoltraClientWidgetRuntime.swift +60 -10
  338. package/ios/target/VoltraDynamicWidgetServerUpdateProvider.swift +204 -0
  339. package/ios/target/VoltraHomeWidget.swift +91 -92
  340. package/ios/target/VoltraWidget.swift +3 -1
  341. package/ios/ui/Extensions/VoltraNode+View.swift +113 -0
  342. package/ios/ui/Generated/Parameters/ChartParameters.swift +3 -0
  343. package/ios/ui/Helpers/VoltraDeepLinkResolver.swift +5 -3
  344. package/ios/ui/Helpers/VoltraProgressDriver.swift +6 -2
  345. package/ios/ui/Layout/VoltraFlexStackLayout.swift +9 -3
  346. package/ios/ui/Style/JSColorParser.swift +24 -8
  347. package/ios/ui/Style/JSGradientParser.swift +36 -12
  348. package/ios/ui/Style/JSStyleParser.swift +36 -12
  349. package/ios/ui/Style/LayoutStyle.swift +12 -4
  350. package/ios/ui/Views/VoltraChart.swift +160 -16
  351. package/ios/ui/Views/VoltraLinearGradient.swift +6 -2
  352. package/package.json +5 -5
  353. package/src/dynamic-widget/api.ts +25 -0
  354. package/src/events.ts +34 -0
  355. package/src/index.ts +23 -0
  356. package/src/live-activity/api.ts +2 -2
  357. package/src/live-activity/dynamic-api.ts +240 -0
  358. package/src/native/NativeVoltra.ts +22 -0
  359. package/src/types.ts +4 -0
  360. package/src/utils/enableDynamicLiveActivityHotReload.ts +50 -0
  361. package/src/utils/enableWidgetHotReload.ts +9 -16
  362. package/src/utils/useUpdateOnHMR.ts +3 -12
  363. package/src/widgets/server-credentials.ts +8 -0
  364. package/src/widgets/server-update.ts +84 -0
  365. /package/ios/shared/{VoltraKeychainHelper.swift → WidgetServer/VoltraKeychainHelper.swift} +0 -0
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ export {
5
5
  } from './components/VoltraLiveActivityPreview.js'
6
6
  export { VoltraView, type VoltraViewProps } from './components/VoltraView.js'
7
7
  export { VoltraWidgetPreview, type VoltraWidgetPreviewProps } from './components/VoltraWidgetPreview.js'
8
+ export { type DynamicWidgetProps, type DynamicWidgetPropsValue, updateDynamicWidget } from './dynamic-widget/api.js'
8
9
  export * from './events.js'
9
10
  export { isGlassSupported, isHeadless, useIsHeadless } from './helpers.js'
10
11
  export { logger, type VoltraLogLevel } from './logger.js'
@@ -22,6 +23,18 @@ export {
22
23
  type UseLiveActivityOptions,
23
24
  type UseLiveActivityResult,
24
25
  } from './live-activity/api.js'
26
+ export {
27
+ getDynamicLiveActivityDefinitionIds,
28
+ startDynamicLiveActivity,
29
+ type StartDynamicLiveActivityOptions,
30
+ updateDynamicLiveActivity,
31
+ type UpdateDynamicLiveActivityOptions,
32
+ useDynamicLiveActivity,
33
+ type UseDynamicLiveActivityOptions,
34
+ type UseDynamicLiveActivityResult,
35
+ type DynamicLiveActivityProps,
36
+ type DynamicLiveActivityPropsValue,
37
+ } from './live-activity/dynamic-api.js'
25
38
  export type { DismissalPolicy, LiveActivityVariants } from '@use-voltra/ios'
26
39
  export {
27
40
  clearPreloadedImages,
@@ -32,9 +45,19 @@ export {
32
45
  } from './preload.js'
33
46
  export { assertRunningOnApple } from './utils/assertRunningOnApple.js'
34
47
  export { enableWidgetHotReload } from './utils/enableWidgetHotReload.js'
48
+ export { enableDynamicLiveActivityHotReload } from './utils/enableDynamicLiveActivityHotReload.js'
35
49
  export { useUpdateOnHMR } from './utils/useUpdateOnHMR.js'
36
50
  export * from './utils/helpers.js'
37
51
  export type { VoltraElementJson, VoltraNodeJson } from './types.js'
52
+ export {
53
+ clearWidgetServerUpdate,
54
+ getWidgetServerUpdate,
55
+ setWidgetServerUpdate,
56
+ type WidgetServerUpdateBody,
57
+ type WidgetServerUpdateOptions,
58
+ type WidgetServerUpdateSettings,
59
+ type WidgetServerUpdateSnapshot,
60
+ } from './widgets/server-update.js'
38
61
  export {
39
62
  clearWidgetServerCredentials,
40
63
  setWidgetServerCredentials,
@@ -40,7 +40,7 @@ export type UseLiveActivityResult = {
40
40
  isActive: boolean
41
41
  }
42
42
 
43
- const normalizeSharedLiveActivityOptions = (
43
+ export const normalizeSharedLiveActivityOptions = (
44
44
  options?: SharedLiveActivityOptions
45
45
  ): SharedLiveActivityOptions | undefined => {
46
46
  if (!options) return undefined
@@ -66,7 +66,7 @@ const normalizeSharedLiveActivityOptions = (
66
66
  return Object.keys(normalizedOptions).length > 0 ? normalizedOptions : undefined
67
67
  }
68
68
 
69
- const normalizeEndLiveActivityOptions = (
69
+ export const normalizeEndLiveActivityOptions = (
70
70
  options?: EndLiveActivityOptions
71
71
  ): { dismissalPolicy?: { type: 'immediate' | 'after'; date?: number } } | undefined => {
72
72
  if (!options?.dismissalPolicy) return undefined
@@ -0,0 +1,240 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react'
2
+
3
+ import { addVoltraListener } from '../events.js'
4
+ import { assertRunningOnApple, useUpdateOnHMR } from '../utils/index.js'
5
+ import { getNativeVoltra } from '../VoltraModule.js'
6
+ import {
7
+ isLiveActivityActive,
8
+ normalizeSharedLiveActivityOptions,
9
+ stopLiveActivity,
10
+ type EndLiveActivityOptions,
11
+ type SharedLiveActivityOptions,
12
+ } from './api.js'
13
+
14
+ /** @experimental A JSON-compatible value accepted as Dynamic Live Activity props. */
15
+ export type DynamicLiveActivityPropsValue =
16
+ | string
17
+ | number
18
+ | boolean
19
+ | null
20
+ | ReadonlyArray<DynamicLiveActivityPropsValue>
21
+ | Readonly<{ [key: string]: DynamicLiveActivityPropsValue }>
22
+
23
+ /** @experimental A complete JSON-compatible props record for a Dynamic Live Activity update. */
24
+ export type DynamicLiveActivityProps = Readonly<{ [key: string]: DynamicLiveActivityPropsValue }>
25
+
26
+ /** @experimental Options used to start a Dynamic Live Activity. */
27
+ export type StartDynamicLiveActivityOptions = {
28
+ activityName?: string
29
+ deepLinkUrl?: string
30
+ channelId?: string
31
+ } & SharedLiveActivityOptions
32
+
33
+ /** @experimental Options used to update a Dynamic Live Activity. */
34
+ export type UpdateDynamicLiveActivityOptions = SharedLiveActivityOptions
35
+
36
+ /** @experimental Options for `useDynamicLiveActivity`. */
37
+ export type UseDynamicLiveActivityOptions = StartDynamicLiveActivityOptions & {
38
+ autoStart?: boolean
39
+ autoUpdate?: boolean
40
+ }
41
+
42
+ /** @experimental Lifecycle controls returned by `useDynamicLiveActivity`. */
43
+ export type UseDynamicLiveActivityResult = {
44
+ start: (options?: StartDynamicLiveActivityOptions) => Promise<void>
45
+ update: (options?: UpdateDynamicLiveActivityOptions) => Promise<void>
46
+ end: (options?: EndLiveActivityOptions) => Promise<void>
47
+ isActive: boolean
48
+ }
49
+
50
+ function serializeDynamicLiveActivityProps(props: DynamicLiveActivityProps): string {
51
+ const ancestors = new Set<object>()
52
+
53
+ const validate = (value: unknown, path: string): void => {
54
+ if (value === null || typeof value === 'string' || typeof value === 'boolean') return
55
+
56
+ if (typeof value === 'number') {
57
+ if (!Number.isFinite(value)) {
58
+ throw new TypeError(`Dynamic Live Activity props must be JSON-compatible; ${path} is not a finite number.`)
59
+ }
60
+ return
61
+ }
62
+
63
+ if (Array.isArray(value)) {
64
+ if (ancestors.has(value)) {
65
+ throw new TypeError(
66
+ `Dynamic Live Activity props must be JSON-compatible; ${path} contains a circular reference.`
67
+ )
68
+ }
69
+ ancestors.add(value)
70
+ value.forEach((item, index) => validate(item, `${path}[${index}]`))
71
+ ancestors.delete(value)
72
+ return
73
+ }
74
+
75
+ if (typeof value === 'object') {
76
+ const prototype = Object.getPrototypeOf(value)
77
+ if (prototype !== Object.prototype && prototype !== null) {
78
+ throw new TypeError(`Dynamic Live Activity props must be JSON-compatible; ${path} must be a plain object.`)
79
+ }
80
+ if (ancestors.has(value)) {
81
+ throw new TypeError(
82
+ `Dynamic Live Activity props must be JSON-compatible; ${path} contains a circular reference.`
83
+ )
84
+ }
85
+ ancestors.add(value)
86
+ for (const [key, item] of Object.entries(value as Record<string, unknown>)) {
87
+ validate(item, `${path}.${key}`)
88
+ }
89
+ ancestors.delete(value)
90
+ return
91
+ }
92
+
93
+ throw new TypeError(
94
+ `Dynamic Live Activity props must be JSON-compatible; ${path} has unsupported type ${typeof value}.`
95
+ )
96
+ }
97
+
98
+ if (props === null || Array.isArray(props) || typeof props !== 'object') {
99
+ throw new TypeError('Dynamic Live Activity props must be a JSON-compatible record.')
100
+ }
101
+
102
+ validate(props, 'props')
103
+ return JSON.stringify(props)
104
+ }
105
+
106
+ /**
107
+ * Starts a bundled Dynamic Live Activity with a complete opaque props record.
108
+ * @experimental
109
+ */
110
+ export async function startDynamicLiveActivity(
111
+ definitionId: string,
112
+ props: DynamicLiveActivityProps,
113
+ options?: StartDynamicLiveActivityOptions
114
+ ): Promise<string> {
115
+ if (!assertRunningOnApple()) return ''
116
+
117
+ const propsJson = serializeDynamicLiveActivityProps(props)
118
+ const normalizedSharedOptions = normalizeSharedLiveActivityOptions(options)
119
+ return getNativeVoltra().startDynamicLiveActivity(definitionId, propsJson, {
120
+ target: 'liveActivity',
121
+ deepLinkUrl: options?.deepLinkUrl,
122
+ activityName: options?.activityName,
123
+ channelId: options?.channelId,
124
+ ...normalizedSharedOptions,
125
+ })
126
+ }
127
+
128
+ /**
129
+ * Replaces a Dynamic Live Activity's complete opaque props record.
130
+ * @experimental
131
+ */
132
+ export async function updateDynamicLiveActivity(
133
+ activityName: string,
134
+ props: DynamicLiveActivityProps,
135
+ options?: UpdateDynamicLiveActivityOptions
136
+ ): Promise<void> {
137
+ if (!assertRunningOnApple()) return
138
+
139
+ const propsJson = serializeDynamicLiveActivityProps(props)
140
+ return getNativeVoltra().updateDynamicLiveActivity(
141
+ activityName,
142
+ propsJson,
143
+ normalizeSharedLiveActivityOptions(options) ?? {}
144
+ )
145
+ }
146
+
147
+ /**
148
+ * Returns the Dynamic Live Activity definition IDs bundled in the installed app.
149
+ * @experimental
150
+ */
151
+ export async function getDynamicLiveActivityDefinitionIds(): Promise<string[]> {
152
+ if (!assertRunningOnApple()) return []
153
+ return getNativeVoltra().getDynamicLiveActivityDefinitionIds()
154
+ }
155
+
156
+ /**
157
+ * Manages the lifecycle of one Dynamic Live Activity definition.
158
+ *
159
+ * Complete props are sent on every update. In development, call
160
+ * `enableDynamicLiveActivityHotReload()` once in the app host to reload only
161
+ * the definition changed by Fast Refresh.
162
+ * @experimental
163
+ */
164
+ export function useDynamicLiveActivity<Props extends DynamicLiveActivityProps = DynamicLiveActivityProps>(
165
+ definitionId: string,
166
+ props: Props,
167
+ options?: UseDynamicLiveActivityOptions
168
+ ): UseDynamicLiveActivityResult {
169
+ const [activityName, setActivityName] = useState<string | null>(() => {
170
+ if (options?.activityName) {
171
+ return isLiveActivityActive(options.activityName) ? options.activityName : null
172
+ }
173
+ return null
174
+ })
175
+ const propsRef = useRef(props)
176
+ const optionsRef = useRef(options)
177
+ const lastUpdateOptionsRef = useRef<UpdateDynamicLiveActivityOptions | undefined>(undefined)
178
+
179
+ useEffect(() => {
180
+ propsRef.current = props
181
+ }, [props])
182
+
183
+ useEffect(() => {
184
+ optionsRef.current = options
185
+ }, [options])
186
+
187
+ useUpdateOnHMR()
188
+
189
+ const start = useCallback(
190
+ async (startOptions?: StartDynamicLiveActivityOptions) => {
191
+ const id = await startDynamicLiveActivity(definitionId, propsRef.current, {
192
+ ...optionsRef.current,
193
+ ...startOptions,
194
+ })
195
+ setActivityName(id)
196
+ },
197
+ [definitionId]
198
+ )
199
+
200
+ const update = useCallback(
201
+ async (updateOptions?: UpdateDynamicLiveActivityOptions) => {
202
+ if (!activityName) return
203
+
204
+ const mergedOptions = { ...optionsRef.current, ...updateOptions }
205
+ lastUpdateOptionsRef.current = mergedOptions
206
+ await updateDynamicLiveActivity(activityName, propsRef.current, mergedOptions)
207
+ },
208
+ [activityName]
209
+ )
210
+
211
+ const end = useCallback(
212
+ async (endOptions?: EndLiveActivityOptions) => {
213
+ if (!activityName) return
214
+
215
+ await stopLiveActivity(activityName, endOptions)
216
+ setActivityName(null)
217
+ },
218
+ [activityName]
219
+ )
220
+
221
+ useEffect(() => {
222
+ if (options?.autoStart) void start()
223
+ }, [options?.autoStart, start])
224
+
225
+ useEffect(() => {
226
+ if (options?.autoUpdate) void update(lastUpdateOptionsRef.current)
227
+ }, [options?.autoUpdate, props, update])
228
+
229
+ useEffect(() => {
230
+ if (!activityName) return
231
+
232
+ const subscription = addVoltraListener('stateChange', (event) => {
233
+ if (event.activityName !== activityName) return
234
+ if (event.activityState === 'dismissed' || event.activityState === 'ended') setActivityName(null)
235
+ })
236
+ return () => subscription.remove()
237
+ }, [activityName])
238
+
239
+ return { start, update, end, isActive: activityName !== null }
240
+ }
@@ -32,6 +32,15 @@ type VoltraInteractionEvent = Readonly<{
32
32
  payload: string
33
33
  }>
34
34
 
35
+ type VoltraDynamicLiveActivityRenderFailedEvent = Readonly<{
36
+ source: string
37
+ timestamp: number
38
+ type: 'dynamicLiveActivityRenderFailed'
39
+ activityName: string
40
+ definitionId: string
41
+ message: string
42
+ }>
43
+
35
44
  type StartVoltraOptions = Readonly<{
36
45
  target?: string
37
46
  deepLinkUrl?: string
@@ -86,26 +95,39 @@ type WidgetServerCredentials = Readonly<{
86
95
 
87
96
  export interface Spec extends TurboModule {
88
97
  readonly onInteraction: CodegenTypes.EventEmitter<VoltraInteractionEvent>
98
+ readonly onDynamicLiveActivityRenderFailed: CodegenTypes.EventEmitter<VoltraDynamicLiveActivityRenderFailedEvent>
89
99
  readonly onStateChanged: CodegenTypes.EventEmitter<VoltraActivityUpdateEvent>
90
100
  readonly onActivityTokenReceived: CodegenTypes.EventEmitter<VoltraActivityTokenReceivedEvent>
91
101
  readonly onActivityPushToStartTokenReceived: CodegenTypes.EventEmitter<VoltraActivityPushToStartTokenReceivedEvent>
102
+ drainDynamicLiveActivityRenderFailures(): void
103
+ setDynamicLiveActivityRenderFailureListenerActive(active: boolean): void
92
104
  startLiveActivity(jsonString: string, options: StartVoltraOptions): Promise<string>
93
105
  updateLiveActivity(activityId: string, jsonString: string, options: UpdateVoltraOptions): Promise<void>
106
+ startDynamicLiveActivity(definitionId: string, propsJson: string, options: StartVoltraOptions): Promise<string>
107
+ updateDynamicLiveActivity(activityId: string, propsJson: string, options: UpdateVoltraOptions): Promise<void>
94
108
  endLiveActivity(activityId: string, options: EndVoltraOptions): Promise<void>
95
109
  endAllLiveActivities(): Promise<void>
96
110
  getLatestVoltraActivityId(): Promise<string | null>
97
111
  listVoltraActivityIds(): Promise<string[]>
112
+ getDynamicLiveActivityDefinitionIds(): Promise<string[]>
98
113
  isLiveActivityActive(activityName: string): boolean
99
114
  isHeadless(): boolean
100
115
  preloadImages(images: PreloadImageOptions[]): Promise<PreloadImagesResult>
101
116
  reloadLiveActivities(activityNames?: string[] | null): Promise<void>
117
+ reloadDynamicLiveActivities(definitionIds?: string[] | null): Promise<void>
102
118
  clearPreloadedImages(keys?: string[] | null): Promise<void>
119
+ updateDynamicWidget(dynamicWidgetId: string, dynamicWidgetPropsJson: string): Promise<void>
103
120
  updateWidget(widgetId: string, jsonString: string, options: UpdateWidgetOptions): Promise<void>
104
121
  scheduleWidget(widgetId: string, timelineJson: string): Promise<void>
105
122
  reloadWidgets(widgetIds?: string[] | null): Promise<void>
106
123
  clearWidget(widgetId: string): Promise<void>
107
124
  clearAllWidgets(): Promise<void>
108
125
  getActiveWidgets<T = unknown>(): Promise<T[]>
126
+ /** Settings are passed as JSON so an arbitrary `body` survives the bridge unchanged. */
127
+ setWidgetServerUpdate(settingsJson: string, widgetId?: string | null): Promise<void>
128
+ clearWidgetServerUpdate(widgetId?: string | null): Promise<void>
129
+ /** Result is JSON so an arbitrary `body` survives the bridge unchanged, or null. */
130
+ getWidgetServerUpdate(widgetId?: string | null): Promise<string | null>
109
131
  setWidgetServerCredentials(credentials: WidgetServerCredentials): Promise<void>
110
132
  clearWidgetServerCredentials(): Promise<void>
111
133
  }
package/src/types.ts CHANGED
@@ -9,4 +9,8 @@ export type {
9
9
  VoltraNodeJson,
10
10
  VoltraPropValue,
11
11
  WidgetServerCredentials,
12
+ WidgetServerUpdateBody,
13
+ WidgetServerUpdateOptions,
14
+ WidgetServerUpdateSettings,
15
+ WidgetServerUpdateSnapshot,
12
16
  } from '@use-voltra/ios'
@@ -0,0 +1,50 @@
1
+ import { getFastRefreshHub } from '@use-voltra/ios'
2
+
3
+ import { getNativeVoltra } from '../VoltraModule.js'
4
+
5
+ declare global {
6
+ var __voltraDynamicLiveActivityDefinitionUpdated: ((definitionId: string) => void) | undefined
7
+ }
8
+
9
+ /**
10
+ * Reload Dynamic Live Activities after a Metro Fast Refresh patch. When Metro
11
+ * re-evaluates a generated definition entry, only that definition is reloaded.
12
+ * Component-only refresh boundaries do not re-evaluate their importer, so those
13
+ * patches fall back to reloading every Dynamic Live Activity definition.
14
+ * Legacy activities and Dynamic Widgets are unaffected.
15
+ *
16
+ * Subscribes to the shared {@link getFastRefreshHub} so multiple `__accept`
17
+ * calls from one save collapse into a single native reload.
18
+ */
19
+ export function enableDynamicLiveActivityHotReload(): () => void {
20
+ if (!__DEV__) return () => {}
21
+
22
+ const hub = getFastRefreshHub()
23
+ const previousDefinitionUpdated = global.__voltraDynamicLiveActivityDefinitionUpdated
24
+ const updatedDefinitionIds = new Set<string>()
25
+
26
+ global.__voltraDynamicLiveActivityDefinitionUpdated = (definitionId) => {
27
+ // A generated entry re-evaluated inside a patch: batch it so the debounced
28
+ // flush reloads each changed definition exactly once. A signal that arrives
29
+ // outside a patch (the first require of a definition) has no flush coming,
30
+ // so reload it immediately.
31
+ if (hub.isAccepting) {
32
+ updatedDefinitionIds.add(definitionId)
33
+ return
34
+ }
35
+ void getNativeVoltra().reloadDynamicLiveActivities([definitionId])
36
+ }
37
+
38
+ const unsubscribe = hub.onPatch(() => {
39
+ const definitionIds = Array.from(updatedDefinitionIds)
40
+ updatedDefinitionIds.clear()
41
+ // No definition re-evaluated during this patch: a component-only boundary
42
+ // changed, so fall back to reloading every definition (null).
43
+ void getNativeVoltra().reloadDynamicLiveActivities(definitionIds.length > 0 ? definitionIds : null)
44
+ })
45
+
46
+ return () => {
47
+ unsubscribe()
48
+ global.__voltraDynamicLiveActivityDefinitionUpdated = previousDefinitionUpdated
49
+ }
50
+ }
@@ -1,14 +1,13 @@
1
- import { reloadWidgets } from '../widgets/widget-api.js'
1
+ import { getFastRefreshHub } from '@use-voltra/ios'
2
2
 
3
- declare global {
4
- var __accept: (...args: unknown[]) => void
5
- }
3
+ import { reloadWidgets } from '../widgets/widget-api.js'
6
4
 
7
5
  /**
8
6
  * Trigger `reloadWidgets()` on every Metro Fast Refresh patch (DEV only).
9
7
  *
10
- * Hooks the global `__accept` callback Metro fires when a Fast Refresh patch
11
- * lands in the host app's JS runtime. When fired, calls
8
+ * Subscribes to the shared {@link getFastRefreshHub}, which wraps the global
9
+ * `__accept` callback Metro fires when a Fast Refresh patch lands in the host
10
+ * app's JS runtime. On each debounced patch it calls
12
11
  * `WidgetCenter.shared.reloadAllTimelines()` so WidgetKit re-invokes each widget
13
12
  * Provider, which re-fetches the freshest bundle from Metro and renders the
14
13
  * updated UI.
@@ -19,21 +18,15 @@ declare global {
19
18
  * workflow the dev still relies on WidgetKit's natural lifecycle refresh on
20
19
  * app foreground.
21
20
  *
22
- * Call once at app startup. Returns `dispose()` to restore the prior
23
- * `__accept` (rarely needed in practice). No-op in release builds.
21
+ * Call once at app startup. Returns `dispose()` to unsubscribe (rarely needed
22
+ * in practice). No-op in release builds.
24
23
  */
25
24
  export function enableWidgetHotReload(): () => void {
26
25
  if (!__DEV__) {
27
26
  return () => {}
28
27
  }
29
28
 
30
- const oldAccept = global['__accept']
31
- global['__accept'] = (...args) => {
29
+ return getFastRefreshHub().onPatch(() => {
32
30
  void reloadWidgets()
33
- oldAccept?.(...args)
34
- }
35
-
36
- return () => {
37
- global['__accept'] = oldAccept
38
- }
31
+ })
39
32
  }
@@ -1,9 +1,6 @@
1
+ import { getFastRefreshHub } from '@use-voltra/ios'
1
2
  import { useEffect, useState } from 'react'
2
3
 
3
- declare global {
4
- var __accept: (...args: unknown[]) => void
5
- }
6
-
7
4
  export const useUpdateOnHMR = () => {
8
5
  const [, forceUpdate] = useState(0)
9
6
 
@@ -12,14 +9,8 @@ export const useUpdateOnHMR = () => {
12
9
  return
13
10
  }
14
11
 
15
- const oldAccept = global['__accept']
16
- global['__accept'] = (...args) => {
12
+ return getFastRefreshHub().onPatch(() => {
17
13
  forceUpdate((prev) => prev + 1)
18
- oldAccept?.(...args)
19
- }
20
-
21
- return () => {
22
- global['__accept'] = oldAccept
23
- }
14
+ })
24
15
  }, [])
25
16
  }
@@ -3,6 +3,11 @@ import { getNativeVoltra } from '../VoltraModule.js'
3
3
 
4
4
  export type { WidgetServerCredentials } from '../types.js'
5
5
 
6
+ /**
7
+ * @deprecated Use {@link setWidgetServerUpdate} with an `Authorization` header. This writes the
8
+ * same stored credentials and keeps the same replace-everything semantics, so migrating is a
9
+ * one-line change; it will be removed in a future major.
10
+ */
6
11
  export async function setWidgetServerCredentials(credentials: WidgetServerCredentials): Promise<void> {
7
12
  if (!credentials.token) {
8
13
  throw new Error('[Voltra][iOS] setWidgetServerCredentials: token is required')
@@ -11,6 +16,9 @@ export async function setWidgetServerCredentials(credentials: WidgetServerCreden
11
16
  return getNativeVoltra().setWidgetServerCredentials(credentials)
12
17
  }
13
18
 
19
+ /**
20
+ * @deprecated Use {@link clearWidgetServerUpdate} instead.
21
+ */
14
22
  export async function clearWidgetServerCredentials(): Promise<void> {
15
23
  return getNativeVoltra().clearWidgetServerCredentials()
16
24
  }
@@ -0,0 +1,84 @@
1
+ import type { WidgetServerUpdateOptions, WidgetServerUpdateSettings, WidgetServerUpdateSnapshot } from '../types.js'
2
+ import { getNativeVoltra } from '../VoltraModule.js'
3
+
4
+ export type {
5
+ WidgetServerUpdateBody,
6
+ WidgetServerUpdateOptions,
7
+ WidgetServerUpdateSettings,
8
+ WidgetServerUpdateSnapshot,
9
+ } from '../types.js'
10
+
11
+ /**
12
+ * Overrides a server-driven widget's `serverUpdate` settings at runtime.
13
+ *
14
+ * The `serverUpdate` entry in app.json supplies the defaults; this replaces any of them for one
15
+ * widget, or for every server-driven widget when no `widgetId` is given. A widget-scoped call wins
16
+ * over a global one, and `headers` and `query` merge per key across the two.
17
+ *
18
+ * Each call replaces the whole layer it writes, so pass every field you want to keep. Setting
19
+ * anything reschedules the widgets it affects and fetches once immediately.
20
+ *
21
+ * @example Point a widget at the tenant's own backend once the user has logged in.
22
+ * ```ts
23
+ * await setWidgetServerUpdate(
24
+ * { url: `https://${tenant}.example.com/widgets/portfolio`, headers: { Authorization: `Bearer ${token}` } },
25
+ * { widgetId: 'portfolio' }
26
+ * )
27
+ * ```
28
+ *
29
+ * @example Take a widget over and drive it from the app until you hand it back.
30
+ * ```ts
31
+ * await setWidgetServerUpdate({ enabled: false }, { widgetId: 'portfolio' })
32
+ * await updateDynamicWidget('portfolio', localProps)
33
+ * ```
34
+ *
35
+ * @throws if the widget has no `serverUpdate` in app.json, if the URL is not https (plain http is
36
+ * allowed only in a debug build, and only for a local dev host), or if `query` names one of the
37
+ * parameters Voltra already sends.
38
+ */
39
+ export async function setWidgetServerUpdate(
40
+ settings: WidgetServerUpdateSettings,
41
+ options?: WidgetServerUpdateOptions
42
+ ): Promise<void> {
43
+ return getNativeVoltra().setWidgetServerUpdate(JSON.stringify(settings ?? {}), options?.widgetId ?? null)
44
+ }
45
+
46
+ /**
47
+ * Drops the runtime settings for one widget, or the global ones when no `widgetId` is given, so
48
+ * the widget falls back to what app.json configured.
49
+ *
50
+ * Clearing the global settings is the logout gesture: along with the settings it drops what the
51
+ * server last sent for every server-driven widget, so a Dynamic Widget goes back to `{}` with
52
+ * `env.serverUpdate.status` of `never` rather than showing the previous account's data. Credentials
53
+ * set with the deprecated `setWidgetServerCredentials` are stored separately — clear those with
54
+ * `clearWidgetServerCredentials`.
55
+ */
56
+ export async function clearWidgetServerUpdate(options?: WidgetServerUpdateOptions): Promise<void> {
57
+ return getNativeVoltra().clearWidgetServerUpdate(options?.widgetId ?? null)
58
+ }
59
+
60
+ /**
61
+ * Reads a widget's `serverUpdate` settings back, without reasoning about what was set where.
62
+ *
63
+ * With a `widgetId`, this is the fully resolved settings that widget would fetch with right now:
64
+ * every layer flattened and app.json's defaults applied — `null` if the widget is not
65
+ * server-driven. Without one, this is the raw contents of the global layer only — what the last
66
+ * `setWidgetServerUpdate(settings)` call (with no `widgetId`) wrote, with no defaults applied and
67
+ * every field optional — `null` if nothing has been set globally.
68
+ *
69
+ * @example Check what a widget is about to fetch from.
70
+ * ```ts
71
+ * const snapshot = await getWidgetServerUpdate({ widgetId: 'portfolio' })
72
+ * if (snapshot?.enabled) {
73
+ * console.log(`portfolio fetches ${snapshot.url} every ${snapshot.intervalMinutes}m`)
74
+ * }
75
+ * ```
76
+ */
77
+ export async function getWidgetServerUpdate(options: { widgetId: string }): Promise<WidgetServerUpdateSnapshot | null>
78
+ export async function getWidgetServerUpdate(options?: undefined): Promise<WidgetServerUpdateSettings | null>
79
+ export async function getWidgetServerUpdate(
80
+ options?: WidgetServerUpdateOptions
81
+ ): Promise<WidgetServerUpdateSnapshot | WidgetServerUpdateSettings | null> {
82
+ const json = await getNativeVoltra().getWidgetServerUpdate(options?.widgetId ?? null)
83
+ return json == null ? null : JSON.parse(json)
84
+ }