@use-voltra/ios-client 1.4.1 → 2.0.0-rc.2

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 (577) hide show
  1. package/README.md +113 -0
  2. package/Voltra.podspec +28 -0
  3. package/build/commonjs/VoltraModule.js +13 -0
  4. package/build/commonjs/VoltraModule.js.map +1 -0
  5. package/build/commonjs/components/VoltraLiveActivityPreview.js +30 -0
  6. package/build/commonjs/components/VoltraLiveActivityPreview.js.map +1 -0
  7. package/build/commonjs/components/VoltraView.js +50 -0
  8. package/build/commonjs/components/VoltraView.js.map +1 -0
  9. package/build/commonjs/components/VoltraWidgetPreview.js +58 -0
  10. package/build/commonjs/components/VoltraWidgetPreview.js.map +1 -0
  11. package/build/commonjs/events.js +32 -0
  12. package/build/commonjs/events.js.map +1 -0
  13. package/build/commonjs/helpers.js +26 -0
  14. package/build/commonjs/helpers.js.map +1 -0
  15. package/build/commonjs/index.js +226 -0
  16. package/build/commonjs/index.js.map +1 -0
  17. package/build/commonjs/live-activity/api.js +168 -0
  18. package/build/commonjs/live-activity/api.js.map +1 -0
  19. package/build/commonjs/logger.js +39 -0
  20. package/build/commonjs/logger.js.map +1 -0
  21. package/build/commonjs/native/NativeVoltra.js +15 -0
  22. package/build/commonjs/native/NativeVoltra.js.map +1 -0
  23. package/build/commonjs/native/VoltraRNNativeComponent.ts +9 -0
  24. package/build/commonjs/package.json +1 -0
  25. package/build/commonjs/preload.js +54 -0
  26. package/build/commonjs/preload.js.map +1 -0
  27. package/build/commonjs/types.js +2 -0
  28. package/build/commonjs/types.js.map +1 -0
  29. package/build/commonjs/utils/assertRunningOnApple.js +16 -0
  30. package/build/commonjs/utils/assertRunningOnApple.js.map +1 -0
  31. package/build/commonjs/utils/helpers.js +19 -0
  32. package/build/commonjs/utils/helpers.js.map +1 -0
  33. package/build/commonjs/utils/index.js +28 -0
  34. package/build/commonjs/utils/index.js.map +1 -0
  35. package/build/commonjs/utils/useUpdateOnHMR.js +25 -0
  36. package/build/commonjs/utils/useUpdateOnHMR.js.map +1 -0
  37. package/build/commonjs/widgets/server-credentials.js +18 -0
  38. package/build/commonjs/widgets/server-credentials.js.map +1 -0
  39. package/build/commonjs/widgets/widget-api.js +55 -0
  40. package/build/commonjs/widgets/widget-api.js.map +1 -0
  41. package/build/module/VoltraModule.js +4 -0
  42. package/build/module/VoltraModule.js.map +1 -0
  43. package/build/module/components/VoltraLiveActivityPreview.js +25 -0
  44. package/build/module/components/VoltraLiveActivityPreview.js.map +1 -0
  45. package/build/module/components/VoltraView.js +44 -0
  46. package/build/module/components/VoltraView.js.map +1 -0
  47. package/build/module/components/VoltraWidgetPreview.js +53 -0
  48. package/build/module/components/VoltraWidgetPreview.js.map +1 -0
  49. package/build/module/events.js +28 -0
  50. package/build/module/events.js.map +1 -0
  51. package/build/module/helpers.js +21 -0
  52. package/build/module/helpers.js.map +1 -0
  53. package/build/module/index.js +17 -0
  54. package/build/module/index.js.map +1 -0
  55. package/build/module/live-activity/api.js +158 -0
  56. package/build/module/live-activity/api.js.map +1 -0
  57. package/build/module/logger.js +35 -0
  58. package/build/module/logger.js.map +1 -0
  59. package/build/module/native/NativeVoltra.js +11 -0
  60. package/build/module/native/NativeVoltra.js.map +1 -0
  61. package/build/module/native/VoltraRNNativeComponent.ts +9 -0
  62. package/build/module/package.json +1 -0
  63. package/build/module/preload.js +48 -0
  64. package/build/module/preload.js.map +1 -0
  65. package/build/module/types.js +2 -0
  66. package/build/module/types.js.map +1 -0
  67. package/build/module/utils/assertRunningOnApple.js +11 -0
  68. package/build/module/utils/assertRunningOnApple.js.map +1 -0
  69. package/build/module/utils/helpers.js +4 -0
  70. package/build/module/utils/helpers.js.map +1 -0
  71. package/build/module/utils/index.js +5 -0
  72. package/build/module/utils/index.js.map +1 -0
  73. package/build/module/utils/useUpdateOnHMR.js +20 -0
  74. package/build/module/utils/useUpdateOnHMR.js.map +1 -0
  75. package/build/module/widgets/server-credentials.js +13 -0
  76. package/build/module/widgets/server-credentials.js.map +1 -0
  77. package/build/module/widgets/widget-api.js +45 -0
  78. package/build/module/widgets/widget-api.js.map +1 -0
  79. package/build/typescript/commonjs/VoltraModule.d.ts +3 -0
  80. package/build/typescript/commonjs/VoltraModule.d.ts.map +1 -0
  81. package/build/typescript/commonjs/components/VoltraLiveActivityPreview.d.ts.map +1 -0
  82. package/build/typescript/commonjs/components/VoltraView.d.ts.map +1 -0
  83. package/build/typescript/commonjs/components/VoltraWidgetPreview.d.ts.map +1 -0
  84. package/build/typescript/commonjs/events.d.ts.map +1 -0
  85. package/build/typescript/commonjs/helpers.d.ts.map +1 -0
  86. package/build/{types → typescript/commonjs}/index.d.ts +5 -0
  87. package/build/typescript/commonjs/index.d.ts.map +1 -0
  88. package/build/typescript/commonjs/live-activity/api.d.ts.map +1 -0
  89. package/build/typescript/commonjs/logger.d.ts.map +1 -0
  90. package/build/typescript/commonjs/native/NativeVoltra.d.ts +100 -0
  91. package/build/typescript/commonjs/native/NativeVoltra.d.ts.map +1 -0
  92. package/build/typescript/commonjs/native/VoltraRNNativeComponent.d.ts +8 -0
  93. package/build/typescript/commonjs/native/VoltraRNNativeComponent.d.ts.map +1 -0
  94. package/build/typescript/commonjs/package.json +1 -0
  95. package/build/typescript/commonjs/preload.d.ts.map +1 -0
  96. package/build/typescript/commonjs/types.d.ts.map +1 -0
  97. package/build/typescript/commonjs/utils/assertRunningOnApple.d.ts.map +1 -0
  98. package/build/typescript/commonjs/utils/helpers.d.ts.map +1 -0
  99. package/build/typescript/commonjs/utils/index.d.ts.map +1 -0
  100. package/build/typescript/commonjs/utils/useUpdateOnHMR.d.ts.map +1 -0
  101. package/build/typescript/commonjs/widgets/server-credentials.d.ts.map +1 -0
  102. package/build/typescript/commonjs/widgets/widget-api.d.ts.map +1 -0
  103. package/build/typescript/module/VoltraModule.d.ts +3 -0
  104. package/build/typescript/module/VoltraModule.d.ts.map +1 -0
  105. package/build/typescript/module/components/VoltraLiveActivityPreview.d.ts +7 -0
  106. package/build/typescript/module/components/VoltraLiveActivityPreview.d.ts.map +1 -0
  107. package/build/typescript/module/components/VoltraView.d.ts +12 -0
  108. package/build/typescript/module/components/VoltraView.d.ts.map +1 -0
  109. package/build/typescript/module/components/VoltraWidgetPreview.d.ts +9 -0
  110. package/build/typescript/module/components/VoltraWidgetPreview.d.ts.map +1 -0
  111. package/build/typescript/module/events.d.ts +33 -0
  112. package/build/typescript/module/events.d.ts.map +1 -0
  113. package/build/typescript/module/helpers.d.ts +3 -0
  114. package/build/typescript/module/helpers.d.ts.map +1 -0
  115. package/build/typescript/module/index.d.ts +18 -0
  116. package/build/typescript/module/index.d.ts.map +1 -0
  117. package/build/typescript/module/live-activity/api.d.ts +35 -0
  118. package/build/typescript/module/live-activity/api.d.ts.map +1 -0
  119. package/build/typescript/module/logger.d.ts +16 -0
  120. package/build/typescript/module/logger.d.ts.map +1 -0
  121. package/build/typescript/module/native/NativeVoltra.d.ts +100 -0
  122. package/build/typescript/module/native/NativeVoltra.d.ts.map +1 -0
  123. package/build/typescript/module/native/VoltraRNNativeComponent.d.ts +8 -0
  124. package/build/typescript/module/native/VoltraRNNativeComponent.d.ts.map +1 -0
  125. package/build/typescript/module/package.json +1 -0
  126. package/build/typescript/module/preload.d.ts +6 -0
  127. package/build/typescript/module/preload.d.ts.map +1 -0
  128. package/build/typescript/module/types.d.ts +2 -0
  129. package/build/typescript/module/types.d.ts.map +1 -0
  130. package/build/typescript/module/utils/assertRunningOnApple.d.ts +2 -0
  131. package/build/typescript/module/utils/assertRunningOnApple.d.ts.map +1 -0
  132. package/build/{esm/utils/helpers.js → typescript/module/utils/helpers.d.ts} +1 -1
  133. package/build/typescript/module/utils/helpers.d.ts.map +1 -0
  134. package/build/{esm/utils/index.js → typescript/module/utils/index.d.ts} +1 -1
  135. package/build/typescript/module/utils/index.d.ts.map +1 -0
  136. package/build/typescript/module/utils/useUpdateOnHMR.d.ts +5 -0
  137. package/build/typescript/module/utils/useUpdateOnHMR.d.ts.map +1 -0
  138. package/build/typescript/module/widgets/server-credentials.d.ts +5 -0
  139. package/build/typescript/module/widgets/server-credentials.d.ts.map +1 -0
  140. package/build/typescript/module/widgets/widget-api.d.ts +11 -0
  141. package/build/typescript/module/widgets/widget-api.d.ts.map +1 -0
  142. package/expo-plugin/app.plugin.js +3 -0
  143. package/expo-plugin/build/cjs/constants.js +23 -0
  144. package/expo-plugin/build/cjs/constants.js.map +1 -0
  145. package/expo-plugin/build/cjs/index.js +51 -0
  146. package/expo-plugin/build/cjs/index.js.map +1 -0
  147. package/expo-plugin/build/cjs/ios/eas.js +28 -0
  148. package/expo-plugin/build/cjs/ios/eas.js.map +1 -0
  149. package/expo-plugin/build/cjs/ios/entitlements.js +46 -0
  150. package/expo-plugin/build/cjs/ios/entitlements.js.map +1 -0
  151. package/expo-plugin/build/cjs/ios/index.js +39 -0
  152. package/expo-plugin/build/cjs/ios/index.js.map +1 -0
  153. package/expo-plugin/build/cjs/ios/infoPlist.js +51 -0
  154. package/expo-plugin/build/cjs/ios/infoPlist.js.map +1 -0
  155. package/expo-plugin/build/cjs/ios/pushNotifications.js +22 -0
  156. package/expo-plugin/build/cjs/ios/pushNotifications.js.map +1 -0
  157. package/expo-plugin/build/cjs/ios-widget/eas.js +66 -0
  158. package/expo-plugin/build/cjs/ios-widget/eas.js.map +1 -0
  159. package/expo-plugin/build/cjs/ios-widget/files/assets.js +199 -0
  160. package/expo-plugin/build/cjs/ios-widget/files/assets.js.map +1 -0
  161. package/expo-plugin/build/cjs/ios-widget/files/entitlements.js +77 -0
  162. package/expo-plugin/build/cjs/ios-widget/files/entitlements.js.map +1 -0
  163. package/expo-plugin/build/cjs/ios-widget/files/index.js +92 -0
  164. package/expo-plugin/build/cjs/ios-widget/files/index.js.map +1 -0
  165. package/expo-plugin/build/cjs/ios-widget/files/infoPlist.js +91 -0
  166. package/expo-plugin/build/cjs/ios-widget/files/infoPlist.js.map +1 -0
  167. package/expo-plugin/build/cjs/ios-widget/files/swift.js +443 -0
  168. package/expo-plugin/build/cjs/ios-widget/files/swift.js.map +1 -0
  169. package/expo-plugin/build/cjs/ios-widget/fonts.js +151 -0
  170. package/expo-plugin/build/cjs/ios-widget/fonts.js.map +1 -0
  171. package/expo-plugin/build/cjs/ios-widget/index.js +46 -0
  172. package/expo-plugin/build/cjs/ios-widget/index.js.map +1 -0
  173. package/expo-plugin/build/cjs/ios-widget/podfile.js +41 -0
  174. package/expo-plugin/build/cjs/ios-widget/podfile.js.map +1 -0
  175. package/expo-plugin/build/cjs/ios-widget/widgetPlist.js +99 -0
  176. package/expo-plugin/build/cjs/ios-widget/widgetPlist.js.map +1 -0
  177. package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js +247 -0
  178. package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js.map +1 -0
  179. package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js +91 -0
  180. package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js.map +1 -0
  181. package/expo-plugin/build/cjs/ios-widget/xcode/groups.js +79 -0
  182. package/expo-plugin/build/cjs/ios-widget/xcode/groups.js.map +1 -0
  183. package/expo-plugin/build/cjs/ios-widget/xcode/index.js +155 -0
  184. package/expo-plugin/build/cjs/ios-widget/xcode/index.js.map +1 -0
  185. package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js +71 -0
  186. package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js.map +1 -0
  187. package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js +74 -0
  188. package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js.map +1 -0
  189. package/expo-plugin/build/cjs/ios-widget/xcode/target.js +113 -0
  190. package/expo-plugin/build/cjs/ios-widget/xcode/target.js.map +1 -0
  191. package/expo-plugin/build/cjs/utils/fileDiscovery.js +120 -0
  192. package/expo-plugin/build/cjs/utils/fileDiscovery.js.map +1 -0
  193. package/expo-plugin/build/cjs/utils/urlScheme.js +40 -0
  194. package/expo-plugin/build/cjs/utils/urlScheme.js.map +1 -0
  195. package/expo-plugin/build/cjs/validation.js +55 -0
  196. package/expo-plugin/build/cjs/validation.js.map +1 -0
  197. package/expo-plugin/build/esm/constants.js +20 -0
  198. package/expo-plugin/build/esm/constants.js.map +1 -0
  199. package/expo-plugin/build/esm/index.js +49 -0
  200. package/expo-plugin/build/esm/index.js.map +1 -0
  201. package/expo-plugin/build/esm/ios/eas.js +24 -0
  202. package/expo-plugin/build/esm/ios/eas.js.map +1 -0
  203. package/expo-plugin/build/esm/ios/entitlements.js +42 -0
  204. package/expo-plugin/build/esm/ios/entitlements.js.map +1 -0
  205. package/expo-plugin/build/esm/ios/index.js +34 -0
  206. package/expo-plugin/build/esm/ios/index.js.map +1 -0
  207. package/expo-plugin/build/esm/ios/infoPlist.js +47 -0
  208. package/expo-plugin/build/esm/ios/infoPlist.js.map +1 -0
  209. package/expo-plugin/build/esm/ios/pushNotifications.js +18 -0
  210. package/expo-plugin/build/esm/ios/pushNotifications.js.map +1 -0
  211. package/expo-plugin/build/esm/ios-widget/eas.js +62 -0
  212. package/expo-plugin/build/esm/ios-widget/eas.js.map +1 -0
  213. package/expo-plugin/build/esm/ios-widget/files/assets.js +163 -0
  214. package/expo-plugin/build/esm/ios-widget/files/assets.js.map +1 -0
  215. package/expo-plugin/build/esm/ios-widget/files/entitlements.js +37 -0
  216. package/expo-plugin/build/esm/ios-widget/files/entitlements.js.map +1 -0
  217. package/expo-plugin/build/esm/ios-widget/files/index.js +55 -0
  218. package/expo-plugin/build/esm/ios-widget/files/index.js.map +1 -0
  219. package/expo-plugin/build/esm/ios-widget/files/infoPlist.js +55 -0
  220. package/expo-plugin/build/esm/ios-widget/files/infoPlist.js.map +1 -0
  221. package/expo-plugin/build/esm/ios-widget/files/swift.js +403 -0
  222. package/expo-plugin/build/esm/ios-widget/files/swift.js.map +1 -0
  223. package/expo-plugin/build/esm/ios-widget/fonts.js +111 -0
  224. package/expo-plugin/build/esm/ios-widget/fonts.js.map +1 -0
  225. package/expo-plugin/build/esm/ios-widget/index.js +42 -0
  226. package/expo-plugin/build/esm/ios-widget/index.js.map +1 -0
  227. package/expo-plugin/build/esm/ios-widget/podfile.js +37 -0
  228. package/expo-plugin/build/esm/ios-widget/podfile.js.map +1 -0
  229. package/expo-plugin/build/esm/ios-widget/widgetPlist.js +92 -0
  230. package/expo-plugin/build/esm/ios-widget/widgetPlist.js.map +1 -0
  231. package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js +210 -0
  232. package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js.map +1 -0
  233. package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js +87 -0
  234. package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js.map +1 -0
  235. package/expo-plugin/build/esm/ios-widget/xcode/groups.js +75 -0
  236. package/expo-plugin/build/esm/ios-widget/xcode/groups.js.map +1 -0
  237. package/expo-plugin/build/esm/ios-widget/xcode/index.js +118 -0
  238. package/expo-plugin/build/esm/ios-widget/xcode/index.js.map +1 -0
  239. package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js +68 -0
  240. package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js.map +1 -0
  241. package/expo-plugin/build/esm/ios-widget/xcode/productFile.js +70 -0
  242. package/expo-plugin/build/esm/ios-widget/xcode/productFile.js.map +1 -0
  243. package/expo-plugin/build/esm/ios-widget/xcode/target.js +108 -0
  244. package/expo-plugin/build/esm/ios-widget/xcode/target.js.map +1 -0
  245. package/expo-plugin/build/esm/utils/fileDiscovery.js +83 -0
  246. package/expo-plugin/build/esm/utils/fileDiscovery.js.map +1 -0
  247. package/expo-plugin/build/esm/utils/urlScheme.js +37 -0
  248. package/expo-plugin/build/esm/utils/urlScheme.js.map +1 -0
  249. package/expo-plugin/build/esm/validation.js +51 -0
  250. package/expo-plugin/build/esm/validation.js.map +1 -0
  251. package/expo-plugin/build/types/constants.d.ts +13 -0
  252. package/expo-plugin/build/types/constants.d.ts.map +1 -0
  253. package/expo-plugin/build/types/index.d.ts +10 -0
  254. package/expo-plugin/build/types/index.d.ts.map +1 -0
  255. package/expo-plugin/build/types/ios/eas.d.ts +12 -0
  256. package/expo-plugin/build/types/ios/eas.d.ts.map +1 -0
  257. package/expo-plugin/build/types/ios/entitlements.d.ts +14 -0
  258. package/expo-plugin/build/types/ios/entitlements.d.ts.map +1 -0
  259. package/expo-plugin/build/types/ios/index.d.ts +19 -0
  260. package/expo-plugin/build/types/ios/index.d.ts.map +1 -0
  261. package/expo-plugin/build/types/ios/infoPlist.d.ts +21 -0
  262. package/expo-plugin/build/types/ios/infoPlist.d.ts.map +1 -0
  263. package/expo-plugin/build/types/ios/pushNotifications.d.ts +10 -0
  264. package/expo-plugin/build/types/ios/pushNotifications.d.ts.map +1 -0
  265. package/expo-plugin/build/types/ios-widget/eas.d.ts +15 -0
  266. package/expo-plugin/build/types/ios-widget/eas.d.ts.map +1 -0
  267. package/expo-plugin/build/types/ios-widget/files/assets.d.ts +13 -0
  268. package/expo-plugin/build/types/ios-widget/files/assets.d.ts.map +1 -0
  269. package/expo-plugin/build/types/ios-widget/files/entitlements.d.ts +17 -0
  270. package/expo-plugin/build/types/ios-widget/files/entitlements.d.ts.map +1 -0
  271. package/expo-plugin/build/types/ios-widget/files/index.d.ts +24 -0
  272. package/expo-plugin/build/types/ios-widget/files/index.d.ts.map +1 -0
  273. package/expo-plugin/build/types/ios-widget/files/infoPlist.d.ts +10 -0
  274. package/expo-plugin/build/types/ios-widget/files/infoPlist.d.ts.map +1 -0
  275. package/expo-plugin/build/types/ios-widget/files/swift.d.ts +24 -0
  276. package/expo-plugin/build/types/ios-widget/files/swift.d.ts.map +1 -0
  277. package/expo-plugin/build/types/ios-widget/fonts.d.ts +22 -0
  278. package/expo-plugin/build/types/ios-widget/fonts.d.ts.map +1 -0
  279. package/expo-plugin/build/types/ios-widget/index.d.ts +31 -0
  280. package/expo-plugin/build/types/ios-widget/index.d.ts.map +1 -0
  281. package/expo-plugin/build/types/ios-widget/podfile.d.ts +9 -0
  282. package/expo-plugin/build/types/ios-widget/podfile.d.ts.map +1 -0
  283. package/expo-plugin/build/types/ios-widget/widgetPlist.d.ts +20 -0
  284. package/expo-plugin/build/types/ios-widget/widgetPlist.d.ts.map +1 -0
  285. package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts +25 -0
  286. package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts.map +1 -0
  287. package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts +20 -0
  288. package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts.map +1 -0
  289. package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts +15 -0
  290. package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts.map +1 -0
  291. package/expo-plugin/build/types/ios-widget/xcode/index.d.ts +20 -0
  292. package/expo-plugin/build/types/ios-widget/xcode/index.d.ts.map +1 -0
  293. package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts +15 -0
  294. package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts.map +1 -0
  295. package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts +14 -0
  296. package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts.map +1 -0
  297. package/expo-plugin/build/types/ios-widget/xcode/target.d.ts +42 -0
  298. package/expo-plugin/build/types/ios-widget/xcode/target.d.ts.map +1 -0
  299. package/expo-plugin/build/types/types.d.ts +74 -0
  300. package/expo-plugin/build/types/types.d.ts.map +1 -0
  301. package/expo-plugin/build/types/utils/fileDiscovery.d.ts +15 -0
  302. package/expo-plugin/build/types/utils/fileDiscovery.d.ts.map +1 -0
  303. package/expo-plugin/build/types/utils/urlScheme.d.ts +10 -0
  304. package/expo-plugin/build/types/utils/urlScheme.d.ts.map +1 -0
  305. package/expo-plugin/build/types/validation.d.ts +4 -0
  306. package/expo-plugin/build/types/validation.d.ts.map +1 -0
  307. package/expo-plugin/jest.config.js +18 -0
  308. package/expo-plugin/src/constants.ts +25 -0
  309. package/expo-plugin/src/index.ts +72 -0
  310. package/expo-plugin/src/ios/eas.ts +33 -0
  311. package/expo-plugin/src/ios/entitlements.ts +59 -0
  312. package/expo-plugin/src/ios/index.ts +47 -0
  313. package/expo-plugin/src/ios/infoPlist.ts +63 -0
  314. package/expo-plugin/src/ios/pushNotifications.ts +22 -0
  315. package/expo-plugin/src/ios-widget/eas.ts +79 -0
  316. package/expo-plugin/src/ios-widget/files/assets.ts +201 -0
  317. package/expo-plugin/src/ios-widget/files/entitlements.ts +48 -0
  318. package/expo-plugin/src/ios-widget/files/index.ts +74 -0
  319. package/expo-plugin/src/ios-widget/files/infoPlist.ts +57 -0
  320. package/expo-plugin/src/ios-widget/files/swift.node.test.ts +22 -0
  321. package/expo-plugin/src/ios-widget/files/swift.ts +476 -0
  322. package/expo-plugin/src/ios-widget/fonts.ts +132 -0
  323. package/expo-plugin/src/ios-widget/index.ts +73 -0
  324. package/expo-plugin/src/ios-widget/podfile.ts +44 -0
  325. package/expo-plugin/src/ios-widget/widgetPlist.ts +115 -0
  326. package/expo-plugin/src/ios-widget/xcode/buildPhases.ts +301 -0
  327. package/expo-plugin/src/ios-widget/xcode/configurationList.ts +127 -0
  328. package/expo-plugin/src/ios-widget/xcode/groups.ts +101 -0
  329. package/expo-plugin/src/ios-widget/xcode/index.ts +149 -0
  330. package/expo-plugin/src/ios-widget/xcode/mainAppSettings.ts +95 -0
  331. package/expo-plugin/src/ios-widget/xcode/productFile.ts +91 -0
  332. package/expo-plugin/src/ios-widget/xcode/target.ts +148 -0
  333. package/expo-plugin/src/types.ts +89 -0
  334. package/expo-plugin/src/utils/fileDiscovery.ts +96 -0
  335. package/expo-plugin/src/utils/urlScheme.ts +45 -0
  336. package/expo-plugin/src/validation.node.test.ts +19 -0
  337. package/expo-plugin/src/validation.ts +63 -0
  338. package/expo-plugin/tsconfig.base.json +17 -0
  339. package/expo-plugin/tsconfig.cjs.json +9 -0
  340. package/expo-plugin/tsconfig.esm.json +9 -0
  341. package/expo-plugin/tsconfig.jest.json +8 -0
  342. package/expo-plugin/tsconfig.typecheck.json +12 -0
  343. package/expo-plugin/tsconfig.types.json +10 -0
  344. package/ios/Package.swift +68 -0
  345. package/ios/Tests/JSGradientParserTests.swift +201 -0
  346. package/ios/Tests/VoltraSharedTests/SmokeTests.swift +8 -0
  347. package/ios/VoltraWidget.podspec +30 -0
  348. package/ios/app/NativeVoltra.h +5 -0
  349. package/ios/app/NativeVoltra.mm +211 -0
  350. package/ios/app/VoltraActivity.swift +5 -0
  351. package/ios/app/VoltraImagePreload.swift +154 -0
  352. package/ios/app/VoltraLiveActivityManager.swift +228 -0
  353. package/ios/app/VoltraLiveActivityService.swift +306 -0
  354. package/ios/app/VoltraModule.swift +215 -0
  355. package/ios/app/VoltraModuleImpl.swift +331 -0
  356. package/ios/app/VoltraOptions.swift +27 -0
  357. package/ios/app/VoltraViewComponentView.h +10 -0
  358. package/ios/app/VoltraViewComponentView.mm +67 -0
  359. package/ios/app/VoltraViewRoot.swift +63 -0
  360. package/ios/app/VoltraWidgetService.swift +154 -0
  361. package/ios/shared/BrotliCompression.swift +81 -0
  362. package/ios/shared/ComponentTypeID.swift +117 -0
  363. package/ios/shared/Data+hexString.swift +8 -0
  364. package/ios/shared/Date+toTimerInterval.swift +25 -0
  365. package/ios/shared/JSONValue.swift +128 -0
  366. package/ios/shared/ShortNames.swift +180 -0
  367. package/ios/shared/VoltraAttributes.swift +58 -0
  368. package/ios/shared/VoltraConfig.swift +18 -0
  369. package/ios/shared/VoltraConstants.swift +45 -0
  370. package/ios/shared/VoltraElement.swift +153 -0
  371. package/ios/shared/VoltraEvent.swift +72 -0
  372. package/ios/shared/VoltraEventBus.swift +80 -0
  373. package/ios/shared/VoltraImageStore.swift +119 -0
  374. package/ios/shared/VoltraInitialStateLocale.swift +54 -0
  375. package/ios/shared/VoltraInteractionIntent.swift +39 -0
  376. package/ios/shared/VoltraKeychainHelper.swift +178 -0
  377. package/ios/shared/VoltraLiveActivityPayload.swift +113 -0
  378. package/ios/shared/VoltraLogger.swift +30 -0
  379. package/ios/shared/VoltraNode.swift +194 -0
  380. package/ios/shared/VoltraPayloadMigrator.swift +63 -0
  381. package/ios/shared/VoltraPersistentEventQueue.swift +67 -0
  382. package/ios/shared/VoltraRefreshIntent.swift +29 -0
  383. package/ios/shared/VoltraRegion.swift +37 -0
  384. package/ios/shared/VoltraWidgetDefaults.swift +114 -0
  385. package/ios/shared/VoltraWidgetServerFetcher.swift +166 -0
  386. package/ios/target/VoltraHomeWidget.swift +508 -0
  387. package/ios/target/VoltraWidget.swift +158 -0
  388. package/ios/ui/Extensions/View.modifiers.swift +28 -0
  389. package/ios/ui/Extensions/VoltraNode+Parameters.swift +18 -0
  390. package/ios/ui/Generated/Parameters/ButtonParameters.swift +15 -0
  391. package/ios/ui/Generated/Parameters/ChartParameters.swift +33 -0
  392. package/ios/ui/Generated/Parameters/CircularProgressViewParameters.swift +59 -0
  393. package/ios/ui/Generated/Parameters/ComponentParameters.swift +12 -0
  394. package/ios/ui/Generated/Parameters/DividerParameters.swift +12 -0
  395. package/ios/ui/Generated/Parameters/GaugeParameters.swift +54 -0
  396. package/ios/ui/Generated/Parameters/GlassContainerParameters.swift +15 -0
  397. package/ios/ui/Generated/Parameters/GroupBoxParameters.swift +12 -0
  398. package/ios/ui/Generated/Parameters/HStackParameters.swift +34 -0
  399. package/ios/ui/Generated/Parameters/ImageParameters.swift +29 -0
  400. package/ios/ui/Generated/Parameters/LabelParameters.swift +18 -0
  401. package/ios/ui/Generated/Parameters/LinearGradientParameters.swift +27 -0
  402. package/ios/ui/Generated/Parameters/LinearProgressViewParameters.swift +64 -0
  403. package/ios/ui/Generated/Parameters/LinkParameters.swift +15 -0
  404. package/ios/ui/Generated/Parameters/MaskParameters.swift +12 -0
  405. package/ios/ui/Generated/Parameters/SpacerParameters.swift +15 -0
  406. package/ios/ui/Generated/Parameters/SymbolParameters.swift +59 -0
  407. package/ios/ui/Generated/Parameters/TextParameters.swift +18 -0
  408. package/ios/ui/Generated/Parameters/TimerParameters.swift +54 -0
  409. package/ios/ui/Generated/Parameters/ToggleParameters.swift +24 -0
  410. package/ios/ui/Generated/Parameters/VStackParameters.swift +34 -0
  411. package/ios/ui/Generated/Parameters/ViewParameters.swift +12 -0
  412. package/ios/ui/Generated/Parameters/ZStackParameters.swift +15 -0
  413. package/ios/ui/Helpers/VoltraDeepLinkResolver.swift +43 -0
  414. package/ios/ui/Helpers/VoltraProgressDriver.swift +52 -0
  415. package/ios/ui/Layout/FlexContainerHelper.swift +114 -0
  416. package/ios/ui/Layout/VoltraFlexStackLayout.swift +417 -0
  417. package/ios/ui/Protocols/VoltraView.swift +29 -0
  418. package/ios/ui/Style/BackgroundValue.swift +27 -0
  419. package/ios/ui/Style/CompositeStyle.swift +81 -0
  420. package/ios/ui/Style/DecorationStyle.swift +207 -0
  421. package/ios/ui/Style/FlexEnvironment.swift +35 -0
  422. package/ios/ui/Style/FontVariant.swift +4 -0
  423. package/ios/ui/Style/GlassEffect.swift +6 -0
  424. package/ios/ui/Style/JSColorParser.swift +517 -0
  425. package/ios/ui/Style/JSGradientParser.swift +674 -0
  426. package/ios/ui/Style/JSStyleParser.swift +223 -0
  427. package/ios/ui/Style/LayoutStyle.swift +184 -0
  428. package/ios/ui/Style/Overflow.swift +4 -0
  429. package/ios/ui/Style/RenderingStyle.swift +33 -0
  430. package/ios/ui/Style/StyleConverter.swift +202 -0
  431. package/ios/ui/Style/TextDecoration.swift +6 -0
  432. package/ios/ui/Style/TextStyle.swift +50 -0
  433. package/ios/ui/Style/View+applyStyle.swift +38 -0
  434. package/ios/ui/Views/VoltraButton.swift +57 -0
  435. package/ios/ui/Views/VoltraChart.swift +840 -0
  436. package/ios/ui/Views/VoltraCircularProgressView.swift +103 -0
  437. package/ios/ui/Views/VoltraDivider.swift +16 -0
  438. package/ios/ui/Views/VoltraFlexView.swift +33 -0
  439. package/ios/ui/Views/VoltraGauge.swift +65 -0
  440. package/ios/ui/Views/VoltraGlassContainer.swift +29 -0
  441. package/ios/ui/Views/VoltraGroupBox.swift +26 -0
  442. package/ios/ui/Views/VoltraHStack.swift +70 -0
  443. package/ios/ui/Views/VoltraImage.swift +109 -0
  444. package/ios/ui/Views/VoltraLabel.swift +24 -0
  445. package/ios/ui/Views/VoltraLinearGradient.swift +115 -0
  446. package/ios/ui/Views/VoltraLinearProgressView.swift +118 -0
  447. package/ios/ui/Views/VoltraLink.swift +25 -0
  448. package/ios/ui/Views/VoltraMask.swift +23 -0
  449. package/ios/ui/Views/VoltraSpacer.swift +16 -0
  450. package/ios/ui/Views/VoltraSymbol.swift +160 -0
  451. package/ios/ui/Views/VoltraText.swift +87 -0
  452. package/ios/ui/Views/VoltraTimer.swift +131 -0
  453. package/ios/ui/Views/VoltraToggle.swift +39 -0
  454. package/ios/ui/Views/VoltraVStack.swift +68 -0
  455. package/ios/ui/Views/VoltraZStack.swift +33 -0
  456. package/ios/ui/Voltra.swift +86 -0
  457. package/package.json +105 -19
  458. package/src/VoltraModule.ts +2 -0
  459. package/src/components/VoltraLiveActivityPreview.tsx +29 -0
  460. package/src/components/VoltraView.tsx +49 -0
  461. package/src/components/VoltraWidgetPreview.tsx +38 -0
  462. package/src/events.ts +70 -0
  463. package/src/helpers.ts +21 -0
  464. package/src/index.ts +52 -0
  465. package/src/live-activity/api.ts +224 -0
  466. package/src/logger.ts +35 -0
  467. package/src/native/NativeVoltra.ts +118 -0
  468. package/src/native/VoltraRNNativeComponent.ts +9 -0
  469. package/src/preload.ts +50 -0
  470. package/src/types.ts +12 -0
  471. package/src/utils/assertRunningOnApple.ts +10 -0
  472. package/src/utils/helpers.ts +1 -0
  473. package/src/utils/index.ts +2 -0
  474. package/src/utils/useUpdateOnHMR.ts +25 -0
  475. package/src/widgets/server-credentials.ts +16 -0
  476. package/src/widgets/widget-api.ts +65 -0
  477. package/build/cjs/VoltraModule.js +0 -6
  478. package/build/cjs/VoltraModule.js.map +0 -1
  479. package/build/cjs/components/VoltraLiveActivityPreview.js +0 -20
  480. package/build/cjs/components/VoltraLiveActivityPreview.js.map +0 -1
  481. package/build/cjs/components/VoltraView.js +0 -37
  482. package/build/cjs/components/VoltraView.js.map +0 -1
  483. package/build/cjs/components/VoltraWidgetPreview.js +0 -26
  484. package/build/cjs/components/VoltraWidgetPreview.js.map +0 -1
  485. package/build/cjs/events.js +0 -19
  486. package/build/cjs/events.js.map +0 -1
  487. package/build/cjs/helpers.js +0 -30
  488. package/build/cjs/helpers.js.map +0 -1
  489. package/build/cjs/index.js +0 -49
  490. package/build/cjs/index.js.map +0 -1
  491. package/build/cjs/live-activity/api.js +0 -158
  492. package/build/cjs/live-activity/api.js.map +0 -1
  493. package/build/cjs/logger.js +0 -36
  494. package/build/cjs/logger.js.map +0 -1
  495. package/build/cjs/preload.js +0 -54
  496. package/build/cjs/preload.js.map +0 -1
  497. package/build/cjs/utils/assertRunningOnApple.js +0 -13
  498. package/build/cjs/utils/assertRunningOnApple.js.map +0 -1
  499. package/build/cjs/utils/helpers.js +0 -7
  500. package/build/cjs/utils/helpers.js.map +0 -1
  501. package/build/cjs/utils/index.js +0 -19
  502. package/build/cjs/utils/index.js.map +0 -1
  503. package/build/cjs/utils/useUpdateOnHMR.js +0 -22
  504. package/build/cjs/utils/useUpdateOnHMR.js.map +0 -1
  505. package/build/cjs/widgets/server-credentials.js +0 -18
  506. package/build/cjs/widgets/server-credentials.js.map +0 -1
  507. package/build/cjs/widgets/widget-api.js +0 -59
  508. package/build/cjs/widgets/widget-api.js.map +0 -1
  509. package/build/esm/VoltraModule.js +0 -4
  510. package/build/esm/VoltraModule.js.map +0 -1
  511. package/build/esm/components/VoltraLiveActivityPreview.js +0 -17
  512. package/build/esm/components/VoltraLiveActivityPreview.js.map +0 -1
  513. package/build/esm/components/VoltraView.js +0 -34
  514. package/build/esm/components/VoltraView.js.map +0 -1
  515. package/build/esm/components/VoltraWidgetPreview.js +0 -23
  516. package/build/esm/components/VoltraWidgetPreview.js.map +0 -1
  517. package/build/esm/events.js +0 -13
  518. package/build/esm/events.js.map +0 -1
  519. package/build/esm/helpers.js +0 -23
  520. package/build/esm/helpers.js.map +0 -1
  521. package/build/esm/index.js +0 -10
  522. package/build/esm/index.js.map +0 -1
  523. package/build/esm/live-activity/api.js +0 -146
  524. package/build/esm/live-activity/api.js.map +0 -1
  525. package/build/esm/logger.js +0 -33
  526. package/build/esm/logger.js.map +0 -1
  527. package/build/esm/preload.js +0 -46
  528. package/build/esm/preload.js.map +0 -1
  529. package/build/esm/utils/assertRunningOnApple.js +0 -9
  530. package/build/esm/utils/assertRunningOnApple.js.map +0 -1
  531. package/build/esm/utils/helpers.js.map +0 -1
  532. package/build/esm/utils/index.js.map +0 -1
  533. package/build/esm/utils/useUpdateOnHMR.js +0 -18
  534. package/build/esm/utils/useUpdateOnHMR.js.map +0 -1
  535. package/build/esm/widgets/server-credentials.js +0 -11
  536. package/build/esm/widgets/server-credentials.js.map +0 -1
  537. package/build/esm/widgets/widget-api.js +0 -47
  538. package/build/esm/widgets/widget-api.js.map +0 -1
  539. package/build/types/VoltraModule.d.ts +0 -44
  540. package/build/types/VoltraModule.d.ts.map +0 -1
  541. package/build/types/components/VoltraLiveActivityPreview.d.ts.map +0 -1
  542. package/build/types/components/VoltraView.d.ts.map +0 -1
  543. package/build/types/components/VoltraWidgetPreview.d.ts.map +0 -1
  544. package/build/types/events.d.ts.map +0 -1
  545. package/build/types/helpers.d.ts.map +0 -1
  546. package/build/types/index.d.ts.map +0 -1
  547. package/build/types/live-activity/api.d.ts.map +0 -1
  548. package/build/types/logger.d.ts.map +0 -1
  549. package/build/types/preload.d.ts.map +0 -1
  550. package/build/types/types.d.ts.map +0 -1
  551. package/build/types/utils/assertRunningOnApple.d.ts.map +0 -1
  552. package/build/types/utils/helpers.d.ts.map +0 -1
  553. package/build/types/utils/index.d.ts.map +0 -1
  554. package/build/types/utils/useUpdateOnHMR.d.ts.map +0 -1
  555. package/build/types/widgets/server-credentials.d.ts.map +0 -1
  556. package/build/types/widgets/widget-api.d.ts.map +0 -1
  557. /package/build/{types → typescript/commonjs}/components/VoltraLiveActivityPreview.d.ts +0 -0
  558. /package/build/{types → typescript/commonjs}/components/VoltraView.d.ts +0 -0
  559. /package/build/{types → typescript/commonjs}/components/VoltraWidgetPreview.d.ts +0 -0
  560. /package/build/{types → typescript/commonjs}/events.d.ts +0 -0
  561. /package/build/{types → typescript/commonjs}/helpers.d.ts +0 -0
  562. /package/build/{types → typescript/commonjs}/live-activity/api.d.ts +0 -0
  563. /package/build/{types → typescript/commonjs}/logger.d.ts +0 -0
  564. /package/build/{types → typescript/commonjs}/preload.d.ts +0 -0
  565. /package/build/{types → typescript/commonjs}/types.d.ts +0 -0
  566. /package/build/{types → typescript/commonjs}/utils/assertRunningOnApple.d.ts +0 -0
  567. /package/build/{types → typescript/commonjs}/utils/helpers.d.ts +0 -0
  568. /package/build/{types → typescript/commonjs}/utils/index.d.ts +0 -0
  569. /package/build/{types → typescript/commonjs}/utils/useUpdateOnHMR.d.ts +0 -0
  570. /package/build/{types → typescript/commonjs}/widgets/server-credentials.d.ts +0 -0
  571. /package/build/{types → typescript/commonjs}/widgets/widget-api.d.ts +0 -0
  572. /package/{build → expo-plugin/build}/cjs/package.json +0 -0
  573. /package/{build → expo-plugin/build}/cjs/types.js +0 -0
  574. /package/{build → expo-plugin/build}/cjs/types.js.map +0 -0
  575. /package/{build → expo-plugin/build}/esm/package.json +0 -0
  576. /package/{build → expo-plugin/build}/esm/types.js +0 -0
  577. /package/{build → expo-plugin/build}/esm/types.js.map +0 -0
@@ -0,0 +1,166 @@
1
+ import Foundation
2
+ import UIKit
3
+
4
+ /// Handles fetching widget content from a remote Voltra SSR server.
5
+ /// Used by the TimelineProvider to pull server-driven widget updates.
6
+ public enum VoltraWidgetServerFetcher {
7
+ /// Errors that can occur during server fetch
8
+ public enum FetchError: Error, LocalizedError {
9
+ case noServerUrl
10
+ case invalidUrl(String)
11
+ case networkError(Error)
12
+ case httpError(statusCode: Int)
13
+ case invalidResponse
14
+ case emptyResponse
15
+
16
+ public var errorDescription: String? {
17
+ switch self {
18
+ case .noServerUrl:
19
+ return "No server URL configured for this widget"
20
+ case let .invalidUrl(url):
21
+ return "Invalid server URL: \(url)"
22
+ case let .networkError(error):
23
+ return "Network error: \(error.localizedDescription)"
24
+ case let .httpError(statusCode):
25
+ return "HTTP error: \(statusCode)"
26
+ case .invalidResponse:
27
+ return "Invalid response from server"
28
+ case .emptyResponse:
29
+ return "Empty response from server"
30
+ }
31
+ }
32
+ }
33
+
34
+ /// Read the server update URL for a widget from Info.plist / UserDefaults config.
35
+ public static func serverUrl(for widgetId: String) -> String? {
36
+ // Check Info.plist first (set at build time by config plugin)
37
+ if let urls = Bundle.main.object(forInfoDictionaryKey: VoltraStorageKeys.widgetServerUrls) as? [String: String],
38
+ let url = urls[widgetId]
39
+ {
40
+ return url
41
+ }
42
+
43
+ // Fallback to UserDefaults (can be set at runtime)
44
+ if let group = VoltraConfig.groupIdentifier(),
45
+ let defaults = UserDefaults(suiteName: group)
46
+ {
47
+ return defaults.string(forKey: VoltraStorageKeys.widgetServerUrl(widgetId))
48
+ }
49
+
50
+ return nil
51
+ }
52
+
53
+ /// Read the update interval (in minutes) for a widget.
54
+ public static func updateInterval(for widgetId: String) -> Int {
55
+ if let intervals = Bundle.main.object(forInfoDictionaryKey: VoltraStorageKeys.widgetServerIntervals) as? [String: Int],
56
+ let interval = intervals[widgetId]
57
+ {
58
+ return interval
59
+ }
60
+ return 60 // default: 1 hour
61
+ }
62
+
63
+ public static func isRefreshEnabled(for widgetId: String) -> Bool {
64
+ if let refreshDict = Bundle.main.object(forInfoDictionaryKey: VoltraStorageKeys.widgetServerRefresh) as? [String: Bool],
65
+ let enabled = refreshDict[widgetId]
66
+ {
67
+ return enabled
68
+ }
69
+ return false
70
+ }
71
+
72
+ private static func currentColorScheme() -> String {
73
+ if #available(iOSApplicationExtension 13.0, *) {
74
+ switch UITraitCollection.current.userInterfaceStyle {
75
+ case .dark:
76
+ return "dark"
77
+ case .light:
78
+ return "light"
79
+ default:
80
+ return "light"
81
+ }
82
+ }
83
+ return "light"
84
+ }
85
+
86
+ /// Fetch widget content from the remote Voltra SSR server.
87
+ ///
88
+ /// The request includes:
89
+ /// - `widgetId` query parameter
90
+ /// - `family` query parameter (e.g., "systemSmall")
91
+ /// - `platform` query parameter (`ios`)
92
+ /// - `theme` query parameter (`light` or `dark`)
93
+ /// - `Authorization: Bearer <token>` header (if credentials stored in Keychain)
94
+ /// - Any custom headers stored in Keychain
95
+ ///
96
+ /// Returns the raw JSON data from the server, ready to be parsed by VoltraNode.
97
+ public static func fetchWidgetContent(
98
+ widgetId: String,
99
+ family: String
100
+ ) async throws -> Data {
101
+ guard let baseUrl = serverUrl(for: widgetId) else {
102
+ throw FetchError.noServerUrl
103
+ }
104
+
105
+ // Build URL with query parameters
106
+ guard var components = URLComponents(string: baseUrl) else {
107
+ throw FetchError.invalidUrl(baseUrl)
108
+ }
109
+
110
+ let theme = currentColorScheme()
111
+
112
+ var queryItems = components.queryItems ?? []
113
+ queryItems.append(URLQueryItem(name: "widgetId", value: widgetId))
114
+ queryItems.append(URLQueryItem(name: "family", value: family))
115
+ queryItems.append(URLQueryItem(name: "platform", value: "ios"))
116
+ queryItems.append(URLQueryItem(name: "theme", value: theme))
117
+ components.queryItems = queryItems
118
+
119
+ guard let url = components.url else {
120
+ throw FetchError.invalidUrl(baseUrl)
121
+ }
122
+
123
+ var request = URLRequest(url: url)
124
+ request.httpMethod = "GET"
125
+ request.timeoutInterval = 15 // Widgets have limited execution time
126
+
127
+ // Add auth token from Keychain if available
128
+ if let token = VoltraKeychainHelper.readToken() {
129
+ request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
130
+ }
131
+
132
+ // Add custom headers from Keychain if available
133
+ if let headers = VoltraKeychainHelper.readHeaders() {
134
+ for (key, value) in headers {
135
+ request.setValue(value, forHTTPHeaderField: key)
136
+ }
137
+ }
138
+
139
+ // Add Voltra-specific headers
140
+ let systemVersion = UIDevice.current.systemVersion
141
+ request.setValue("application/json", forHTTPHeaderField: "Accept")
142
+ request.setValue("VoltraWidget/1.0 (iOS/\(systemVersion))", forHTTPHeaderField: "User-Agent")
143
+
144
+ do {
145
+ let (data, response) = try await URLSession.shared.data(for: request)
146
+
147
+ guard let httpResponse = response as? HTTPURLResponse else {
148
+ throw FetchError.invalidResponse
149
+ }
150
+
151
+ guard (200 ... 299).contains(httpResponse.statusCode) else {
152
+ throw FetchError.httpError(statusCode: httpResponse.statusCode)
153
+ }
154
+
155
+ guard !data.isEmpty else {
156
+ throw FetchError.emptyResponse
157
+ }
158
+
159
+ return data
160
+ } catch let error as FetchError {
161
+ throw error
162
+ } catch {
163
+ throw FetchError.networkError(error)
164
+ }
165
+ }
166
+ }
@@ -0,0 +1,508 @@
1
+ //
2
+ // VoltraHomeWidget.swift
3
+ //
4
+ // Generic home screen widget infrastructure for Voltra.
5
+ // Widget definitions are generated dynamically by the config plugin.
6
+ //
7
+
8
+ import Foundation
9
+ import os
10
+ import SwiftUI
11
+ import WidgetKit
12
+
13
+ // MARK: - Shared storage helpers
14
+
15
+ public enum VoltraHomeWidgetStore {
16
+ public static func readJson(widgetId: String) -> Data? {
17
+ VoltraWidgetDefaults.widgetJson(for: widgetId).flatMap { $0.data(using: .utf8) }
18
+ }
19
+
20
+ public static func readDeepLinkUrl(widgetId: String) -> String? {
21
+ VoltraWidgetDefaults.deepLinkUrl(for: widgetId)
22
+ }
23
+
24
+ public static func readTimeline(widgetId: String) -> WidgetTimeline? {
25
+ guard let timelineString = VoltraWidgetDefaults.timelineString(for: widgetId),
26
+ let timelineData = timelineString.data(using: .utf8),
27
+ let json = try? JSONSerialization.jsonObject(with: timelineData) as? [String: Any],
28
+ let entriesJson = json["entries"] as? [[String: Any]]
29
+ else {
30
+ return nil
31
+ }
32
+
33
+ let entries = entriesJson.compactMap { entryJson -> WidgetTimelineEntry? in
34
+ guard let timestampNumber = entryJson["date"] as? NSNumber,
35
+ let jsonString = entryJson["json"] as? String,
36
+ let jsonData = jsonString.data(using: .utf8)
37
+ else {
38
+ return nil
39
+ }
40
+
41
+ let timestampMs = timestampNumber.doubleValue
42
+ let date = Date(timeIntervalSince1970: timestampMs / 1000.0)
43
+ let deepLinkUrl = entryJson["deepLinkUrl"] as? String
44
+
45
+ return WidgetTimelineEntry(date: date, json: jsonData, deepLinkUrl: deepLinkUrl)
46
+ }
47
+
48
+ let sortedEntries = entries.sorted { $0.date < $1.date }
49
+ return WidgetTimeline(entries: sortedEntries)
50
+ }
51
+
52
+ public static func pruneExpiredEntries(widgetId: String) -> Int {
53
+ guard let timelineString = VoltraWidgetDefaults.timelineString(for: widgetId),
54
+ let timelineData = timelineString.data(using: .utf8),
55
+ var json = try? JSONSerialization.jsonObject(with: timelineData) as? [String: Any],
56
+ let entriesJson = json["entries"] as? [[String: Any]]
57
+ else {
58
+ return 0
59
+ }
60
+
61
+ let now = Date()
62
+ let parsedEntries: [(date: Date, json: [String: Any])] = entriesJson.compactMap { entry in
63
+ guard let timestamp = entry["date"] as? NSNumber else { return nil }
64
+ let date = Date(timeIntervalSince1970: timestamp.doubleValue / 1000.0)
65
+ return (date: date, json: entry)
66
+ }
67
+
68
+ // Keep all future entries, plus the most recent past entry (current state).
69
+ let pastEntries = parsedEntries.filter { $0.date <= now }.sorted { $0.date < $1.date }
70
+ let latestPastEntry = pastEntries.last?.json
71
+ let futureEntries = parsedEntries.filter { $0.date > now }.map(\.json)
72
+
73
+ var validEntries = futureEntries
74
+ if let latestPastEntry {
75
+ validEntries.insert(latestPastEntry, at: 0)
76
+ }
77
+
78
+ let prunedCount = entriesJson.count - validEntries.count
79
+ guard prunedCount > 0 else { return 0 }
80
+
81
+ json["entries"] = validEntries
82
+ if let updatedData = try? JSONSerialization.data(withJSONObject: json),
83
+ let updatedString = String(data: updatedData, encoding: .utf8)
84
+ {
85
+ try? VoltraWidgetDefaults.setTimeline(updatedString, for: widgetId)
86
+ VoltraLogger.widget.debug("Pruned \(prunedCount) expired timeline entries for '\(widgetId)'")
87
+ }
88
+
89
+ return prunedCount
90
+ }
91
+ }
92
+
93
+ /// Timeline data structures (intermediate storage - still uses Data for flexibility)
94
+ public struct WidgetTimelineEntry {
95
+ let date: Date
96
+ let json: Data
97
+ let deepLinkUrl: String?
98
+ }
99
+
100
+ public struct WidgetTimeline {
101
+ let entries: [WidgetTimelineEntry]
102
+ }
103
+
104
+ // MARK: - Timeline + entries
105
+
106
+ /// The entry holds a pre-parsed VoltraNode (AST) instead of raw JSON.
107
+ public struct VoltraHomeWidgetEntry: TimelineEntry, Equatable {
108
+ public let date: Date
109
+ public let rootNode: VoltraNode?
110
+ public let widgetId: String
111
+ public let deepLinkUrl: String?
112
+
113
+ public init(date: Date, rootNode: VoltraNode?, widgetId: String, deepLinkUrl: String? = nil) {
114
+ self.date = date
115
+ self.rootNode = rootNode
116
+ self.widgetId = widgetId
117
+ self.deepLinkUrl = deepLinkUrl
118
+ }
119
+ }
120
+
121
+ public struct VoltraHomeWidgetProvider: TimelineProvider {
122
+ public let widgetId: String
123
+ public let initialState: Data?
124
+
125
+ public init(widgetId: String, initialState: Data? = nil) {
126
+ self.widgetId = widgetId
127
+ self.initialState = initialState
128
+ }
129
+
130
+ public func placeholder(in _: Context) -> VoltraHomeWidgetEntry {
131
+ VoltraHomeWidgetEntry(date: Date(), rootNode: nil, widgetId: widgetId)
132
+ }
133
+
134
+ public func getSnapshot(in context: Context, completion: @escaping (VoltraHomeWidgetEntry) -> Void) {
135
+ // Prioritize timeline data for consistency with getTimeline
136
+ if let timeline = VoltraHomeWidgetStore.readTimeline(widgetId: widgetId),
137
+ let firstEntry = timeline.entries.first
138
+ {
139
+ let node = parseJsonToNode(data: firstEntry.json, family: context.family)
140
+ completion(VoltraHomeWidgetEntry(
141
+ date: Date(),
142
+ rootNode: node,
143
+ widgetId: widgetId,
144
+ deepLinkUrl: firstEntry.deepLinkUrl
145
+ ))
146
+ return
147
+ }
148
+
149
+ // Fallback to single-entry data
150
+ let data = VoltraHomeWidgetStore.readJson(widgetId: widgetId) ?? initialState
151
+ let node = data.flatMap { parseJsonToNode(data: $0, family: context.family) }
152
+ completion(VoltraHomeWidgetEntry(date: Date(), rootNode: node, widgetId: widgetId))
153
+ }
154
+
155
+ public func getTimeline(in context: Context, completion: @escaping (Timeline<VoltraHomeWidgetEntry>) -> Void) {
156
+ // Prune expired timeline entries if any exist
157
+ VoltraHomeWidgetStore.pruneExpiredEntries(widgetId: widgetId)
158
+
159
+ // Check if server-driven updates are configured for this widget
160
+ if VoltraWidgetServerFetcher.serverUrl(for: widgetId) != nil {
161
+ getServerDrivenTimeline(in: context, completion: completion)
162
+ return
163
+ }
164
+
165
+ // Local-only mode: use existing data from UserDefaults
166
+ getLocalTimeline(in: context, completion: completion)
167
+ }
168
+
169
+ // MARK: - Server-Driven Timeline
170
+
171
+ private static var lastFetchTimes: [String: Date] = [:]
172
+ private static let coalesceInterval: TimeInterval = 3 // seconds
173
+
174
+ /// Fetch widget content from a remote Voltra SSR server and build a timeline.
175
+ private func getServerDrivenTimeline(in context: Context, completion: @escaping (Timeline<VoltraHomeWidgetEntry>) -> Void) {
176
+ let familyKey = familyToKey(context.family)
177
+ let intervalMinutes = VoltraWidgetServerFetcher.updateInterval(for: widgetId)
178
+
179
+ // Coalesce: if we fetched for this widget very recently, use cached data.
180
+ // The server returns all families in every response, so subsequent getTimeline
181
+ // calls for different families can safely use the just-cached response —
182
+ // selectContentForFamily will pick the correct family-specific content.
183
+ if let lastFetch = Self.lastFetchTimes[widgetId],
184
+ Date().timeIntervalSince(lastFetch) < Self.coalesceInterval
185
+ {
186
+ VoltraLogger.widget.info("Coalescing fetch for '\(widgetId)' family '\(familyKey)' (last fetch \(Date().timeIntervalSince(lastFetch))s ago)")
187
+ getLocalTimeline(in: context, completion: completion)
188
+ return
189
+ }
190
+
191
+ Task {
192
+ do {
193
+ let data = try await VoltraWidgetServerFetcher.fetchWidgetContent(
194
+ widgetId: widgetId,
195
+ family: familyKey
196
+ )
197
+
198
+ // Record that we just fetched successfully
199
+ Self.lastFetchTimes[widgetId] = Date()
200
+
201
+ let node = parseJsonToNode(data: data, family: context.family)
202
+
203
+ // Only cache the data after successful parsing to avoid overwriting
204
+ // good cached content with unparseable responses
205
+ if node != nil, let jsonString = String(data: data, encoding: .utf8) {
206
+ try? VoltraWidgetDefaults.setWidgetJson(jsonString, for: widgetId, deepLinkUrl: nil)
207
+ }
208
+
209
+ let entry = VoltraHomeWidgetEntry(date: Date(), rootNode: node, widgetId: widgetId)
210
+
211
+ // Schedule next update based on configured interval
212
+ let nextUpdate = Calendar.current.date(byAdding: .minute, value: intervalMinutes, to: Date()) ?? Date().addingTimeInterval(900)
213
+ completion(Timeline(entries: [entry], policy: .after(nextUpdate)))
214
+
215
+ VoltraLogger.widget.info("Server-driven update succeeded for '\(widgetId)', next update in \(intervalMinutes)m")
216
+ } catch {
217
+ VoltraLogger.widget.error("Server-driven update failed for '\(widgetId)': \(error.localizedDescription)")
218
+
219
+ // Fall back to local data on network failure
220
+ getLocalTimeline(in: context, completion: completion)
221
+ }
222
+ }
223
+ }
224
+
225
+ // MARK: - Local Timeline
226
+
227
+ /// Build a timeline from locally stored data (UserDefaults / initial state).
228
+ private func getLocalTimeline(in context: Context, completion: @escaping (Timeline<VoltraHomeWidgetEntry>) -> Void) {
229
+ if let timeline = VoltraHomeWidgetStore.readTimeline(widgetId: widgetId), !timeline.entries.isEmpty {
230
+ let entries = timeline.entries.map { timelineEntry in
231
+ let node = parseJsonToNode(data: timelineEntry.json, family: context.family)
232
+ return VoltraHomeWidgetEntry(
233
+ date: timelineEntry.date,
234
+ rootNode: node,
235
+ widgetId: widgetId,
236
+ deepLinkUrl: timelineEntry.deepLinkUrl
237
+ )
238
+ }
239
+ completion(Timeline(entries: entries, policy: .never))
240
+ return
241
+ }
242
+
243
+ // Fallback to single-entry behavior
244
+ let data = VoltraHomeWidgetStore.readJson(widgetId: widgetId) ?? initialState
245
+ let node = data.flatMap { parseJsonToNode(data: $0, family: context.family) }
246
+ let entry = VoltraHomeWidgetEntry(date: Date(), rootNode: node, widgetId: widgetId)
247
+
248
+ // If server updates are configured but we're in fallback, retry sooner
249
+ if VoltraWidgetServerFetcher.serverUrl(for: widgetId) != nil {
250
+ let retryDate = Date().addingTimeInterval(900) // Retry in 15 minutes
251
+ completion(Timeline(entries: [entry], policy: .after(retryDate)))
252
+ } else {
253
+ completion(Timeline(entries: [entry], policy: .never))
254
+ }
255
+ }
256
+
257
+ /// Parse JSON data into a VoltraNode for the given widget family.
258
+ /// This moves all parsing work to the Provider (background thread).
259
+ private func parseJsonToNode(data: Data, family: WidgetFamily) -> VoltraNode? {
260
+ // 1. Select content for the target family
261
+ let selectedData = selectContentForFamily(data, family: family)
262
+
263
+ // 2. Normalize the JSON
264
+ guard let normalized = normalizeJsonData(selectedData),
265
+ let jsonString = String(data: normalized, encoding: .utf8),
266
+ let json = try? JSONValue.parse(from: jsonString)
267
+ else {
268
+ return nil
269
+ }
270
+
271
+ // 3. Parse into VoltraNode AST
272
+ return VoltraNode.parse(from: json)
273
+ }
274
+ }
275
+
276
+ public struct VoltraHomeWidgetView: View {
277
+ public var entry: VoltraHomeWidgetEntry
278
+
279
+ @Environment(\.showsWidgetContainerBackground) private var showsWidgetContainerBackground
280
+ @Environment(\.widgetRenderingMode) private var widgetRenderingMode
281
+
282
+ public init(entry: VoltraHomeWidgetEntry) {
283
+ self.entry = entry
284
+ }
285
+
286
+ private var showRefreshButton: Bool {
287
+ VoltraWidgetServerFetcher.isRefreshEnabled(for: entry.widgetId)
288
+ }
289
+
290
+ public var body: some View {
291
+ let mappedRenderingMode = mapWidgetRenderingMode(widgetRenderingMode)
292
+
293
+ Group {
294
+ if let root = entry.rootNode {
295
+ // No parsing here - just render the pre-parsed AST
296
+ let content = Voltra(
297
+ root: root,
298
+ activityId: "widget",
299
+ widget: VoltraWidgetEnvironment(
300
+ isHomeScreenWidget: true,
301
+ renderingMode: mappedRenderingMode,
302
+ showsContainerBackground: showsWidgetContainerBackground
303
+ )
304
+ )
305
+ .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
306
+ .widgetURL(resolveDeepLinkURL(entry))
307
+
308
+ if showRefreshButton {
309
+ content.overlay(alignment: .topTrailing) {
310
+ refreshButton
311
+ }
312
+ } else {
313
+ content
314
+ }
315
+ } else {
316
+ placeholderView(widgetId: entry.widgetId)
317
+ }
318
+ }
319
+ .disableWidgetMarginsIfAvailable()
320
+ }
321
+
322
+ private func mapWidgetRenderingMode(_ mode: WidgetRenderingMode) -> VoltraWidgetRenderingMode {
323
+ switch mode {
324
+ case .fullColor:
325
+ return .fullColor
326
+ case .accented:
327
+ return .accented
328
+ case .vibrant:
329
+ return .vibrant
330
+ default:
331
+ return .unknown
332
+ }
333
+ }
334
+
335
+ @ViewBuilder
336
+ private var refreshButton: some View {
337
+ if #available(iOSApplicationExtension 17.0, *) {
338
+ Button(intent: VoltraRefreshIntent(widgetId: entry.widgetId)) {
339
+ Image(systemName: "arrow.clockwise")
340
+ .font(.system(size: 12, weight: .semibold))
341
+ .foregroundStyle(.secondary)
342
+ .padding(6)
343
+ .background(.ultraThinMaterial, in: Circle())
344
+ }
345
+ .buttonStyle(.plain)
346
+ .padding(12)
347
+ }
348
+ }
349
+
350
+ private func placeholderView(widgetId _: String) -> some View {
351
+ ZStack {
352
+ RoundedRectangle(cornerRadius: 18, style: .continuous)
353
+ .fill(Color(UIColor.secondarySystemBackground))
354
+ ProgressView()
355
+ .progressViewStyle(.circular)
356
+ }
357
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
358
+ .padding(16)
359
+ }
360
+ }
361
+
362
+ // MARK: - Family-aware content selection
363
+
364
+ /// Maps WidgetFamily to the JSON key
365
+ private func familyToKey(_ family: WidgetFamily) -> String {
366
+ switch family {
367
+ case .systemSmall: return "systemSmall"
368
+ case .systemMedium: return "systemMedium"
369
+ case .systemLarge: return "systemLarge"
370
+ case .systemExtraLarge: return "systemExtraLarge"
371
+ case .accessoryCircular: return "accessoryCircular"
372
+ case .accessoryRectangular: return "accessoryRectangular"
373
+ case .accessoryInline: return "accessoryInline"
374
+ @unknown default: return "systemMedium"
375
+ }
376
+ }
377
+
378
+ /// Select content appropriate for the current widget family.
379
+ /// Uses the flat structure like live activities (e.g., "systemSmall", "systemMedium").
380
+ private func selectContentForFamily(_ data: Data, family: WidgetFamily) -> Data {
381
+ guard let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
382
+ // Not valid JSON, return empty
383
+ return Data("[]".utf8)
384
+ }
385
+
386
+ let familyKey = familyToKey(family)
387
+
388
+ // Try to get content for the specific family
389
+ if let familyContent = root[familyKey] {
390
+ return reconstructWithSharedData(content: familyContent, root: root)
391
+ }
392
+
393
+ // Fallback: try families in order of preference
394
+ let fallbackOrder = ["systemMedium", "systemSmall", "systemLarge", "systemExtraLarge",
395
+ "accessoryRectangular", "accessoryCircular", "accessoryInline"]
396
+ for fallbackKey in fallbackOrder {
397
+ if let fallbackContent = root[fallbackKey] {
398
+ return reconstructWithSharedData(content: fallbackContent, root: root)
399
+ }
400
+ }
401
+
402
+ // No content found, return empty
403
+ return Data("[]".utf8)
404
+ }
405
+
406
+ /// Reconstruct JSON with family-specific content plus shared stylesheet and elements.
407
+ /// This ensures VoltraNode.parse can resolve style references and element deduplication.
408
+ private func reconstructWithSharedData(content: Any, root: [String: Any]) -> Data {
409
+ var result: [String: Any] = [:]
410
+
411
+ // If content is a dictionary (single component), wrap it in the result
412
+ // If content is an array or other type, it will be returned as-is below
413
+ if let contentDict = content as? [String: Any] {
414
+ // Copy all keys from the component
415
+ result = contentDict
416
+ }
417
+
418
+ // Add shared stylesheet if present (key "s")
419
+ if let stylesheet = root["s"] {
420
+ result["s"] = stylesheet
421
+ }
422
+
423
+ // Add shared elements if present (key "e")
424
+ if let sharedElements = root["e"] {
425
+ result["e"] = sharedElements
426
+ }
427
+
428
+ // If we built a result dict with shared data, serialize it
429
+ if !result.isEmpty {
430
+ if JSONSerialization.isValidJSONObject(result),
431
+ let data = try? JSONSerialization.data(withJSONObject: result)
432
+ {
433
+ return data
434
+ }
435
+ }
436
+
437
+ // Fallback: return content as-is if it's serializable
438
+ if JSONSerialization.isValidJSONObject(content),
439
+ let data = try? JSONSerialization.data(withJSONObject: content)
440
+ {
441
+ return data
442
+ }
443
+
444
+ // Final fallback: empty array
445
+ return Data("[]".utf8)
446
+ }
447
+
448
+ // MARK: - Deep link helpers
449
+
450
+ private extension View {
451
+ @ViewBuilder
452
+ func disableWidgetMarginsIfAvailable() -> some View {
453
+ if #available(iOSApplicationExtension 17.0, *) {
454
+ containerBackground(.clear, for: .widget)
455
+ } else {
456
+ self
457
+ }
458
+ }
459
+ }
460
+
461
+ private func resolveDeepLinkURL(_ entry: VoltraHomeWidgetEntry) -> URL? {
462
+ // Prefer the timeline entry's deep link URL if available
463
+ if let entryUrl = entry.deepLinkUrl, !entryUrl.isEmpty {
464
+ if entryUrl.contains("://"), let url = URL(string: entryUrl) { return url }
465
+ if let scheme = VoltraDeepLinkResolver.deepLinkScheme() {
466
+ let path = entryUrl.hasPrefix("/") ? entryUrl : "/\(entryUrl)"
467
+ return URL(string: "\(scheme)://\(path.trimmingCharacters(in: CharacterSet(charactersIn: "/")))")
468
+ }
469
+ }
470
+
471
+ // Fallback to static deep link URL from UserDefaults
472
+ if let raw = VoltraHomeWidgetStore.readDeepLinkUrl(widgetId: entry.widgetId), !raw.isEmpty {
473
+ if raw.contains("://"), let url = URL(string: raw) { return url }
474
+ if let scheme = VoltraDeepLinkResolver.deepLinkScheme() {
475
+ let path = raw.hasPrefix("/") ? raw : "/\(raw)"
476
+ return URL(string: "\(scheme)://\(path.trimmingCharacters(in: CharacterSet(charactersIn: "/")))")
477
+ }
478
+ }
479
+
480
+ // Default deep link with widget info
481
+ guard let scheme = VoltraDeepLinkResolver.deepLinkScheme() else { return nil }
482
+
483
+ var tag = "unknown"
484
+ if let root = entry.rootNode, case let .element(element) = root {
485
+ tag = element.id ?? element.type
486
+ }
487
+
488
+ return URL(string: "\(scheme)://voltraui?kind=widget&source=home_widget&tag=\(tag)")
489
+ }
490
+
491
+ private func normalizeJsonData(_ data: Data) -> Data? {
492
+ guard let obj = try? JSONSerialization.jsonObject(with: data) else { return nil }
493
+
494
+ // If it's already an array, use it as-is
495
+ if obj is [Any] {
496
+ return data
497
+ }
498
+
499
+ // If it's a single component (dictionary), return as-is
500
+ // Don't wrap in array - VoltraNode.parse handles single objects and needs
501
+ // to find "s" (stylesheet) and "e" (elements) at the root level
502
+ if obj is [String: Any] {
503
+ return data
504
+ }
505
+
506
+ // Invalid input (string, number, boolean, null) - return nil to indicate error
507
+ return nil
508
+ }