@swiftbrowser/swift 0.0.0-stage → 0.2.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 (400) hide show
  1. package/Package.swift +214 -0
  2. package/README.md +10 -2
  3. package/Sources/AVFoundation/AVFoundation.swift +131 -0
  4. package/Sources/AVFoundation/Asset.swift +487 -0
  5. package/Sources/AVFoundation/AudioSession.swift +144 -0
  6. package/Sources/AVFoundation/CMTime.swift +303 -0
  7. package/Sources/AVFoundation/Capture.swift +688 -0
  8. package/Sources/AVFoundation/Player.swift +749 -0
  9. package/Sources/AVFoundation/PlayerView.swift +117 -0
  10. package/Sources/AVKit/AVKit.swift +132 -0
  11. package/Sources/Accelerate/Accelerate.swift +122 -0
  12. package/Sources/AppIntents/AppIntents.swift +144 -0
  13. package/Sources/AppIntents/Parameters.swift +220 -0
  14. package/Sources/AppIntents/Shortcuts.swift +159 -0
  15. package/Sources/AudioToolbox/AudioToolbox.swift +55 -0
  16. package/Sources/AuthenticationServices/AuthenticationServices.swift +257 -0
  17. package/Sources/AuthenticationServices/Authorization.swift +251 -0
  18. package/Sources/Charts/Charts.swift +61 -0
  19. package/Sources/Combine/AnyCancellable.swift +65 -0
  20. package/Sources/Combine/AnyPublisher.swift +148 -0
  21. package/Sources/Combine/AnySubscriber.swift +230 -0
  22. package/Sources/Combine/Cancellable.swift +35 -0
  23. package/Sources/Combine/Codable.swift +29 -0
  24. package/Sources/Combine/CombineIdentifier.swift +45 -0
  25. package/Sources/Combine/Concurrency/ConcurrencyHelpers.swift +24 -0
  26. package/Sources/Combine/Concurrency/Future+Concurrency.swift +136 -0
  27. package/Sources/Combine/Concurrency/GENERATED-Publisher+Concurrency.swift +397 -0
  28. package/Sources/Combine/CurrentValueSubject.swift +252 -0
  29. package/Sources/Combine/CustomCombineIdentifierConvertible.swift +28 -0
  30. package/Sources/Combine/Future.swift +228 -0
  31. package/Sources/Combine/GENERATED-RootProtocols.swift +426 -0
  32. package/Sources/Combine/Helpers/ConduitBase.swift +40 -0
  33. package/Sources/Combine/Helpers/ConduitList.swift +59 -0
  34. package/Sources/Combine/Helpers/DebugHook.swift +177 -0
  35. package/Sources/Combine/Helpers/FilterProducer.swift +174 -0
  36. package/Sources/Combine/Helpers/Locking.swift +30 -0
  37. package/Sources/Combine/Helpers/PartialCompletion.swift +26 -0
  38. package/Sources/Combine/Helpers/ReduceProducer.swift +249 -0
  39. package/Sources/Combine/Helpers/SubjectSubscriber.swift +96 -0
  40. package/Sources/Combine/Helpers/SubscriberTap.swift +69 -0
  41. package/Sources/Combine/Helpers/SubscriptionStatus.swift +33 -0
  42. package/Sources/Combine/Helpers/SubscriptionTap.swift +33 -0
  43. package/Sources/Combine/Helpers/Utils.swift +30 -0
  44. package/Sources/Combine/Helpers/Violations.swift +33 -0
  45. package/Sources/Combine/ImmediateScheduler.swift +178 -0
  46. package/Sources/Combine/LICENSE +21 -0
  47. package/Sources/Combine/NotificationPublisher.swift +48 -0
  48. package/Sources/Combine/ObjectWillChange.swift +46 -0
  49. package/Sources/Combine/PassthroughSubject.swift +222 -0
  50. package/Sources/Combine/Publisher+Subscribe.swift +53 -0
  51. package/Sources/Combine/Publishers/Deferred.swift +48 -0
  52. package/Sources/Combine/Publishers/Empty.swift +54 -0
  53. package/Sources/Combine/Publishers/Fail.swift +42 -0
  54. package/Sources/Combine/Publishers/GENERATED-Publishers.Catch.swift +673 -0
  55. package/Sources/Combine/Publishers/GENERATED-Publishers.Encode.swift +388 -0
  56. package/Sources/Combine/Publishers/GENERATED-Publishers.MapKeyPath.swift +384 -0
  57. package/Sources/Combine/Publishers/Just.swift +313 -0
  58. package/Sources/Combine/Publishers/Optional.Publisher.swift +315 -0
  59. package/Sources/Combine/Publishers/Publishers.AllSatisfy.swift +217 -0
  60. package/Sources/Combine/Publishers/Publishers.AssertNoFailure.swift +158 -0
  61. package/Sources/Combine/Publishers/Publishers.Autoconnect.swift +193 -0
  62. package/Sources/Combine/Publishers/Publishers.Breakpoint.swift +231 -0
  63. package/Sources/Combine/Publishers/Publishers.Buffer.swift +356 -0
  64. package/Sources/Combine/Publishers/Publishers.Collect.swift +102 -0
  65. package/Sources/Combine/Publishers/Publishers.CollectByCount.swift +195 -0
  66. package/Sources/Combine/Publishers/Publishers.CompactMap.swift +241 -0
  67. package/Sources/Combine/Publishers/Publishers.Comparison.swift +371 -0
  68. package/Sources/Combine/Publishers/Publishers.Concatenate.swift +474 -0
  69. package/Sources/Combine/Publishers/Publishers.Contains.swift +293 -0
  70. package/Sources/Combine/Publishers/Publishers.Count.swift +87 -0
  71. package/Sources/Combine/Publishers/Publishers.Debounce.swift +332 -0
  72. package/Sources/Combine/Publishers/Publishers.Delay.swift +269 -0
  73. package/Sources/Combine/Publishers/Publishers.Drop.swift +155 -0
  74. package/Sources/Combine/Publishers/Publishers.DropUntilOutput.swift +283 -0
  75. package/Sources/Combine/Publishers/Publishers.DropWhile.swift +378 -0
  76. package/Sources/Combine/Publishers/Publishers.Filter.swift +248 -0
  77. package/Sources/Combine/Publishers/Publishers.First.swift +261 -0
  78. package/Sources/Combine/Publishers/Publishers.FlatMap.swift +533 -0
  79. package/Sources/Combine/Publishers/Publishers.HandleEvents.swift +260 -0
  80. package/Sources/Combine/Publishers/Publishers.IgnoreOutput.swift +109 -0
  81. package/Sources/Combine/Publishers/Publishers.Last.swift +252 -0
  82. package/Sources/Combine/Publishers/Publishers.MakeConnectable.swift +82 -0
  83. package/Sources/Combine/Publishers/Publishers.Map.swift +351 -0
  84. package/Sources/Combine/Publishers/Publishers.MapError.swift +140 -0
  85. package/Sources/Combine/Publishers/Publishers.MeasureInterval.swift +187 -0
  86. package/Sources/Combine/Publishers/Publishers.Multicast.swift +284 -0
  87. package/Sources/Combine/Publishers/Publishers.Output.swift +241 -0
  88. package/Sources/Combine/Publishers/Publishers.PrefixUntilOutput.swift +197 -0
  89. package/Sources/Combine/Publishers/Publishers.PrefixWhile.swift +176 -0
  90. package/Sources/Combine/Publishers/Publishers.Print.swift +206 -0
  91. package/Sources/Combine/Publishers/Publishers.ReceiveOn.swift +227 -0
  92. package/Sources/Combine/Publishers/Publishers.Reduce.swift +204 -0
  93. package/Sources/Combine/Publishers/Publishers.RemoveDuplicates.swift +264 -0
  94. package/Sources/Combine/Publishers/Publishers.ReplaceEmpty.swift +201 -0
  95. package/Sources/Combine/Publishers/Publishers.ReplaceError.swift +211 -0
  96. package/Sources/Combine/Publishers/Publishers.Retry.swift +274 -0
  97. package/Sources/Combine/Publishers/Publishers.Scan.swift +331 -0
  98. package/Sources/Combine/Publishers/Publishers.Sequence.swift +437 -0
  99. package/Sources/Combine/Publishers/Publishers.SetFailureType.swift +120 -0
  100. package/Sources/Combine/Publishers/Publishers.Share.swift +104 -0
  101. package/Sources/Combine/Publishers/Publishers.SubscribeOn.swift +197 -0
  102. package/Sources/Combine/Publishers/Publishers.SwitchToLatest.swift +444 -0
  103. package/Sources/Combine/Publishers/Publishers.Throttle.swift +359 -0
  104. package/Sources/Combine/Publishers/Publishers.Timeout.swift +301 -0
  105. package/Sources/Combine/Publishers/Publishers.Zip.swift +720 -0
  106. package/Sources/Combine/Publishers/Publishers.swift +13 -0
  107. package/Sources/Combine/Publishers/Record.swift +237 -0
  108. package/Sources/Combine/Publishers/Result.Publisher.swift +337 -0
  109. package/Sources/Combine/Result.swift +46 -0
  110. package/Sources/Combine/Scheduler.swift +89 -0
  111. package/Sources/Combine/Schedulers.swift +211 -0
  112. package/Sources/Combine/Subject+Void.swift +17 -0
  113. package/Sources/Combine/Subscriber+Void.swift +20 -0
  114. package/Sources/Combine/Subscribers/Subscribers.Assign.swift +175 -0
  115. package/Sources/Combine/Subscribers/Subscribers.Completion.swift +90 -0
  116. package/Sources/Combine/Subscribers/Subscribers.Demand.swift +476 -0
  117. package/Sources/Combine/Subscribers/Subscribers.Sink.swift +206 -0
  118. package/Sources/Combine/Subscribers/Subscribers.swift +9 -0
  119. package/Sources/Combine/Subscription.swift +22 -0
  120. package/Sources/Combine/Subscriptions.swift +42 -0
  121. package/Sources/Combine/SwiftUIObservation.swift +10 -0
  122. package/Sources/Combine/_Introspection.swift +107 -0
  123. package/Sources/CommonCrypto/CommonCrypto.swift +80 -0
  124. package/Sources/Compression/Compression.swift +365 -0
  125. package/Sources/Compression/Deflate.swift +407 -0
  126. package/Sources/Compression/Zlib.swift +179 -0
  127. package/Sources/CoreFoundationTypes/CoreFoundationTypes.swift +101 -0
  128. package/Sources/CoreGraphics/CoreGraphics.swift +411 -0
  129. package/Sources/CoreGraphics/ProjectionTransforms.swift +28 -0
  130. package/Sources/CoreHaptics/CoreHaptics.swift +399 -0
  131. package/Sources/CoreImage/CIColor.swift +41 -0
  132. package/Sources/CoreImage/CIContext.swift +31 -0
  133. package/Sources/CoreImage/CIDetector.swift +57 -0
  134. package/Sources/CoreImage/CIFilter.swift +243 -0
  135. package/Sources/CoreImage/CIFilterBuiltins.swift +136 -0
  136. package/Sources/CoreImage/CIImage.swift +162 -0
  137. package/Sources/CoreImage/QRCode.swift +393 -0
  138. package/Sources/CoreLocation/Coordinate.swift +30 -0
  139. package/Sources/CoreLocation/Location.swift +65 -0
  140. package/Sources/CoreML/Evaluation.swift +414 -0
  141. package/Sources/CoreML/FeatureValue.swift +266 -0
  142. package/Sources/CoreML/Model.swift +269 -0
  143. package/Sources/CoreML/MultiArray.swift +92 -0
  144. package/Sources/CoreML/Specification.swift +233 -0
  145. package/Sources/CoreText/CoreText.swift +64 -0
  146. package/Sources/CoreTransferable/CoreTransferable.swift +606 -0
  147. package/Sources/CryptoKit/ChaChaPoly.swift +258 -0
  148. package/Sources/CryptoKit/CryptoKit.swift +375 -0
  149. package/Sources/CryptoKit/Curve25519.swift +317 -0
  150. package/Sources/CryptoKit/P256.swift +321 -0
  151. package/Sources/FoundationBridge/AppStorage.swift +165 -0
  152. package/Sources/FoundationBridge/AssetResources.swift +90 -0
  153. package/Sources/FoundationBridge/AsyncBytes.swift +128 -0
  154. package/Sources/FoundationBridge/AsyncImage.swift +116 -0
  155. package/Sources/FoundationBridge/AttributedStrings.swift +16 -0
  156. package/Sources/FoundationBridge/Bundle.swift +119 -0
  157. package/Sources/FoundationBridge/CombineExports.swift +8 -0
  158. package/Sources/FoundationBridge/CoreFoundation.swift +77 -0
  159. package/Sources/FoundationBridge/Dispatch.swift +458 -0
  160. package/Sources/FoundationBridge/EnvironmentFoundation.swift +41 -0
  161. package/Sources/FoundationBridge/FileImporter.swift +128 -0
  162. package/Sources/FoundationBridge/FileSystem.swift +68 -0
  163. package/Sources/FoundationBridge/FoundationBridge.swift +29 -0
  164. package/Sources/FoundationBridge/HostResolution.swift +31 -0
  165. package/Sources/FoundationBridge/ItemProvider.swift +655 -0
  166. package/Sources/FoundationBridge/KeyValueObserving.swift +138 -0
  167. package/Sources/FoundationBridge/Links.swift +127 -0
  168. package/Sources/FoundationBridge/ListFormatter.swift +32 -0
  169. package/Sources/FoundationBridge/Locale.swift +86 -0
  170. package/Sources/FoundationBridge/Localization.swift +149 -0
  171. package/Sources/FoundationBridge/Locks.swift +50 -0
  172. package/Sources/FoundationBridge/Markdown.swift +527 -0
  173. package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
  174. package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
  175. package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
  176. package/Sources/FoundationBridge/Operation.swift +195 -0
  177. package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
  178. package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
  179. package/Sources/FoundationBridge/SceneStorage.swift +78 -0
  180. package/Sources/FoundationBridge/SecurityExports.swift +8 -0
  181. package/Sources/FoundationBridge/Selector.swift +226 -0
  182. package/Sources/FoundationBridge/StringComparators.swift +17 -0
  183. package/Sources/FoundationBridge/Table.swift +211 -0
  184. package/Sources/FoundationBridge/TextAttributes.swift +42 -0
  185. package/Sources/FoundationBridge/Timer.swift +53 -0
  186. package/Sources/FoundationBridge/UITextChecker.swift +30 -0
  187. package/Sources/FoundationBridge/URLSession.swift +718 -0
  188. package/Sources/FoundationBridge/UserDefaults.swift +183 -0
  189. package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
  190. package/Sources/FoundationBridge/WebSocket.swift +187 -0
  191. package/Sources/FoundationModels/FoundationModels.swift +1098 -0
  192. package/Sources/ImageIO/GIF.swift +72 -0
  193. package/Sources/ImageIO/ImageIO.swift +248 -0
  194. package/Sources/ImageIO/ImageTypes.swift +28 -0
  195. package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
  196. package/Sources/LocalAuthentication/LAContext.swift +86 -0
  197. package/Sources/MapKit/Geometry.swift +223 -0
  198. package/Sources/MapKit/Map.swift +638 -0
  199. package/Sources/MapKit/MapView.swift +229 -0
  200. package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
  201. package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
  202. package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
  203. package/Sources/OSLog/OSLog.swift +6 -0
  204. package/Sources/Photos/Photos.swift +572 -0
  205. package/Sources/PhotosUI/PhotosPicker.swift +248 -0
  206. package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
  207. package/Sources/QuickLook/QuickLook.swift +168 -0
  208. package/Sources/SafariServices/SafariServices.swift +106 -0
  209. package/Sources/Security/Security.swift +332 -0
  210. package/Sources/StoreKit/AppStore.swift +207 -0
  211. package/Sources/StoreKit/Products.swift +280 -0
  212. package/Sources/StoreKit/RequestReview.swift +28 -0
  213. package/Sources/StoreKit/StoreKit1.swift +486 -0
  214. package/Sources/StoreKit/StoreViews.swift +428 -0
  215. package/Sources/StoreKit/Transactions.swift +197 -0
  216. package/Sources/SwiftData/Macros.swift +58 -0
  217. package/Sources/SwiftData/ModelActor.swift +38 -0
  218. package/Sources/SwiftData/ModelContainer.swift +129 -0
  219. package/Sources/SwiftData/ModelContext.swift +451 -0
  220. package/Sources/SwiftData/PersistentModel.swift +238 -0
  221. package/Sources/SwiftData/Properties.swift +261 -0
  222. package/Sources/SwiftData/Query.swift +256 -0
  223. package/Sources/SwiftData/Schema.swift +192 -0
  224. package/Sources/SwiftData/Store.swift +146 -0
  225. package/Sources/SwiftData/StringPredicates.swift +125 -0
  226. package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
  227. package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
  228. package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
  229. package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
  230. package/Sources/SwiftDataMacros/Plugin.swift +18 -0
  231. package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
  232. package/Sources/SwiftUI/API/Accessibility.swift +181 -0
  233. package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
  234. package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
  235. package/Sources/SwiftUI/API/Alert.swift +221 -0
  236. package/Sources/SwiftUI/API/AlignmentGuides.swift +65 -0
  237. package/Sources/SwiftUI/API/Animation.swift +285 -0
  238. package/Sources/SwiftUI/API/App.swift +87 -0
  239. package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
  240. package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
  241. package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
  242. package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
  243. package/Sources/SwiftUI/API/Canvas.swift +337 -0
  244. package/Sources/SwiftUI/API/Color.swift +237 -0
  245. package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
  246. package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
  247. package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
  248. package/Sources/SwiftUI/API/Commands.swift +106 -0
  249. package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
  250. package/Sources/SwiftUI/API/ContentShape.swift +33 -0
  251. package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
  252. package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
  253. package/Sources/SwiftUI/API/Controls.swift +300 -0
  254. package/Sources/SwiftUI/API/CustomLayout.swift +442 -0
  255. package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
  256. package/Sources/SwiftUI/API/Decorations.swift +92 -0
  257. package/Sources/SwiftUI/API/EditMode.swift +212 -0
  258. package/Sources/SwiftUI/API/Effects.swift +388 -0
  259. package/Sources/SwiftUI/API/Entry.swift +8 -0
  260. package/Sources/SwiftUI/API/Environment.swift +439 -0
  261. package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
  262. package/Sources/SwiftUI/API/Focus.swift +137 -0
  263. package/Sources/SwiftUI/API/Font.swift +131 -0
  264. package/Sources/SwiftUI/API/Gauge.swift +290 -0
  265. package/Sources/SwiftUI/API/Geometry.swift +89 -0
  266. package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
  267. package/Sources/SwiftUI/API/GeometryReader.swift +135 -0
  268. package/Sources/SwiftUI/API/GestureState.swift +65 -0
  269. package/Sources/SwiftUI/API/Gestures.swift +342 -0
  270. package/Sources/SwiftUI/API/Glass.swift +127 -0
  271. package/Sources/SwiftUI/API/Grid.swift +188 -0
  272. package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
  273. package/Sources/SwiftUI/API/KeyPress.swift +54 -0
  274. package/Sources/SwiftUI/API/LabelStyle.swift +124 -0
  275. package/Sources/SwiftUI/API/Layout.swift +220 -0
  276. package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
  277. package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
  278. package/Sources/SwiftUI/API/Lists.swift +331 -0
  279. package/Sources/SwiftUI/API/Menu.swift +58 -0
  280. package/Sources/SwiftUI/API/Modifiers.swift +313 -0
  281. package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
  282. package/Sources/SwiftUI/API/Namespace.swift +44 -0
  283. package/Sources/SwiftUI/API/Navigation.swift +386 -0
  284. package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
  285. package/Sources/SwiftUI/API/ObservableObject.swift +293 -0
  286. package/Sources/SwiftUI/API/OnChange.swift +48 -0
  287. package/Sources/SwiftUI/API/Path.swift +543 -0
  288. package/Sources/SwiftUI/API/Phase8Controls.swift +411 -0
  289. package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
  290. package/Sources/SwiftUI/API/Picker.swift +185 -0
  291. package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
  292. package/Sources/SwiftUI/API/Popover.swift +41 -0
  293. package/Sources/SwiftUI/API/Preferences.swift +262 -0
  294. package/Sources/SwiftUI/API/Presentation.swift +122 -0
  295. package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
  296. package/Sources/SwiftUI/API/Primitives.swift +517 -0
  297. package/Sources/SwiftUI/API/Publishers.swift +107 -0
  298. package/Sources/SwiftUI/API/Redaction.swift +75 -0
  299. package/Sources/SwiftUI/API/RowActions.swift +84 -0
  300. package/Sources/SwiftUI/API/Scenes.swift +131 -0
  301. package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
  302. package/Sources/SwiftUI/API/ScrollTargets.swift +104 -0
  303. package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
  304. package/Sources/SwiftUI/API/SectionSupplements.swift +96 -0
  305. package/Sources/SwiftUI/API/Shape.swift +214 -0
  306. package/Sources/SwiftUI/API/ShapeStyle.swift +409 -0
  307. package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
  308. package/Sources/SwiftUI/API/Sharing.swift +193 -0
  309. package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
  310. package/Sources/SwiftUI/API/State.swift +144 -0
  311. package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
  312. package/Sources/SwiftUI/API/StrokeStyle.swift +30 -0
  313. package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
  314. package/Sources/SwiftUI/API/TabContent.swift +841 -0
  315. package/Sources/SwiftUI/API/Table.swift +382 -0
  316. package/Sources/SwiftUI/API/Tabs.swift +263 -0
  317. package/Sources/SwiftUI/API/Tasks.swift +35 -0
  318. package/Sources/SwiftUI/API/Text.swift +386 -0
  319. package/Sources/SwiftUI/API/TextDates.swift +61 -0
  320. package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
  321. package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
  322. package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
  323. package/Sources/SwiftUI/API/Timeline.swift +212 -0
  324. package/Sources/SwiftUI/API/Toolbar.swift +251 -0
  325. package/Sources/SwiftUI/API/Transfer.swift +145 -0
  326. package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
  327. package/Sources/SwiftUI/API/Video.swift +64 -0
  328. package/Sources/SwiftUI/API/View.swift +215 -0
  329. package/Sources/SwiftUI/API/ViewModifier.swift +43 -0
  330. package/Sources/SwiftUI/API/VisualEffect.swift +155 -0
  331. package/Sources/SwiftUI/API/Windows.swift +25 -0
  332. package/Sources/SwiftUI/Charts/Axis.swift +325 -0
  333. package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
  334. package/Sources/SwiftUI/Charts/Chart.swift +660 -0
  335. package/Sources/SwiftUI/Charts/ChartContent.swift +376 -0
  336. package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
  337. package/Sources/SwiftUI/Charts/Marks.swift +204 -0
  338. package/Sources/SwiftUI/Charts/Plottable.swift +99 -0
  339. package/Sources/SwiftUI/Charts/Scales.swift +326 -0
  340. package/Sources/SwiftUI/Localization/Localization.swift +498 -0
  341. package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
  342. package/Sources/SwiftUI/Runtime/Executor.swift +85 -0
  343. package/Sources/SwiftUI/Runtime/Exports.swift +101 -0
  344. package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
  345. package/Sources/SwiftUI/Runtime/JSON.swift +143 -0
  346. package/Sources/SwiftUI/Runtime/JSONParser.swift +443 -0
  347. package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
  348. package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
  349. package/Sources/SwiftUI/Runtime/Ops.swift +152 -0
  350. package/Sources/SwiftUI/Runtime/Reconciler.swift +219 -0
  351. package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
  352. package/Sources/SwiftUI/Runtime/Runtime.swift +2146 -0
  353. package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
  354. package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
  355. package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
  356. package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
  357. package/Sources/Symbols/Symbols.swift +25 -0
  358. package/Sources/Translation/Translation.swift +423 -0
  359. package/Sources/UIKit/Activity.swift +213 -0
  360. package/Sources/UIKit/Alerts.swift +69 -0
  361. package/Sources/UIKit/AppDelegate.swift +222 -0
  362. package/Sources/UIKit/Appearance.swift +84 -0
  363. package/Sources/UIKit/ColorConversions.swift +70 -0
  364. package/Sources/UIKit/Controls.swift +225 -0
  365. package/Sources/UIKit/Device.swift +200 -0
  366. package/Sources/UIKit/Feedback.swift +65 -0
  367. package/Sources/UIKit/Font.swift +307 -0
  368. package/Sources/UIKit/Graphics.swift +204 -0
  369. package/Sources/UIKit/HostingController.swift +185 -0
  370. package/Sources/UIKit/Identity.swift +24 -0
  371. package/Sources/UIKit/Introspectable.swift +510 -0
  372. package/Sources/UIKit/Pasteboard.swift +363 -0
  373. package/Sources/UIKit/PhotoAlbum.swift +81 -0
  374. package/Sources/UIKit/RemoteNotifications.swift +15 -0
  375. package/Sources/UIKit/Representable.swift +288 -0
  376. package/Sources/UIKit/SafeArea.swift +12 -0
  377. package/Sources/UIKit/SceneDelegates.swift +132 -0
  378. package/Sources/UIKit/Scenes.swift +40 -0
  379. package/Sources/UIKit/ScrollView.swift +157 -0
  380. package/Sources/UIKit/ShortcutItems.swift +67 -0
  381. package/Sources/UIKit/SymbolConfiguration.swift +124 -0
  382. package/Sources/UIKit/TargetAction.swift +123 -0
  383. package/Sources/UIKit/TextPaste.swift +161 -0
  384. package/Sources/UIKit/TextView.swift +538 -0
  385. package/Sources/UIKit/UIKit.swift +292 -0
  386. package/Sources/UIKit/UIView.swift +855 -0
  387. package/Sources/UIKit/ViewTranslation.swift +311 -0
  388. package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
  389. package/Sources/UserNotifications/Content.swift +370 -0
  390. package/Sources/UserNotifications/NotificationCenter.swift +309 -0
  391. package/Sources/WeatherKit/WeatherKit.swift +228 -0
  392. package/Sources/WebKit/WebKit.swift +245 -0
  393. package/Sources/os/os.swift +376 -0
  394. package/Sources/zlib/zlib.swift +6 -0
  395. package/index.d.ts +2 -0
  396. package/index.mjs +16 -0
  397. package/manifest.d.mts +2 -0
  398. package/manifest.mjs +39 -0
  399. package/package.json +30 -4
  400. package/sync-sources.mjs +33 -0
@@ -0,0 +1,183 @@
1
+ // `UserDefaults` that survives reloads (corelibs Foundation's cannot persist on
2
+ // WASI; the CLI's generated file aliases this one in the app). Values live in memory and are mirrored
3
+ // to the host: every change is sent as a `defaults` op (the whole dictionary
4
+ // as JSON), which the browser stores per app in localStorage and hands back at
5
+ // the next launch through the `SB_DEFAULTS` environment variable. Headless
6
+ // runs print the op like any other, so a snapshot shows what an app saves.
7
+ //
8
+ // JSON cannot tell an Int from a Double or carry Data and Date; integers
9
+ // travel as whole numbers (and come back as Int), `Data` as `{"$data": base64}`,
10
+ // `Date` as `{"$date": seconds}`, `URL` as `{"$url": string}`.
11
+
12
+ import Foundation
13
+ import SwiftUI
14
+
15
+ /// Equal and hashed by identity, as an `NSObject` is on Apple platforms.
16
+ public final class UserDefaults: Hashable, @unchecked Sendable {
17
+ nonisolated(unsafe) public static let standard = UserDefaults(persistent: true)
18
+
19
+ private var storage: [String: Any] = [:]
20
+ private var registered: [String: Any] = [:]
21
+ private let persistent: Bool
22
+
23
+ init(persistent: Bool) {
24
+ self.persistent = persistent
25
+ if persistent, let text = _environment("SB_DEFAULTS"), let json = try? _JSON.parse(text), case .object(let values) = json {
26
+ for (key, value) in values { storage[key] = _defaultsValue(fromJSON: value) }
27
+ }
28
+ }
29
+
30
+ public convenience init() { self.init(persistent: false) }
31
+ /// Suites are not separated: every suite is the standard defaults.
32
+ public convenience init?(suiteName: String?) { self.init(persistent: true) }
33
+
34
+ // MARK: Reading
35
+
36
+ public func object(forKey key: String) -> Any? { storage[key] ?? registered[key] }
37
+ /// Key-value coding's read, which answers the default for the key.
38
+ public func value(forKey key: String) -> Any? { object(forKey: key) }
39
+ public func string(forKey key: String) -> String? {
40
+ switch object(forKey: key) {
41
+ case let s as String: s
42
+ case let n as Int: String(n)
43
+ case let n as Double: String(n)
44
+ default: nil
45
+ }
46
+ }
47
+ public func array(forKey key: String) -> [Any]? { object(forKey: key) as? [Any] }
48
+ public func dictionary(forKey key: String) -> [String: Any]? { object(forKey: key) as? [String: Any] }
49
+ public func data(forKey key: String) -> Data? { object(forKey: key) as? Data }
50
+ public func stringArray(forKey key: String) -> [String]? {
51
+ guard let array = object(forKey: key) as? [Any] else { return nil }
52
+ let strings = array.compactMap { $0 as? String }
53
+ return strings.count == array.count ? strings : nil
54
+ }
55
+ public func url(forKey key: String) -> URL? {
56
+ switch object(forKey: key) {
57
+ case let url as URL: url
58
+ case let s as String: URL(string: s)
59
+ default: nil
60
+ }
61
+ }
62
+ public func integer(forKey key: String) -> Int {
63
+ switch object(forKey: key) {
64
+ case let n as Int: n
65
+ case let n as Double: Int(n)
66
+ case let s as String: Int(s) ?? 0
67
+ case let b as Bool: b ? 1 : 0
68
+ default: 0
69
+ }
70
+ }
71
+ public func float(forKey key: String) -> Float { Float(double(forKey: key)) }
72
+ public func double(forKey key: String) -> Double {
73
+ switch object(forKey: key) {
74
+ case let n as Double: n
75
+ case let n as Int: Double(n)
76
+ case let s as String: Double(s) ?? 0
77
+ case let b as Bool: b ? 1 : 0
78
+ default: 0
79
+ }
80
+ }
81
+ public func bool(forKey key: String) -> Bool {
82
+ switch object(forKey: key) {
83
+ case let b as Bool: b
84
+ case let n as Int: n != 0
85
+ case let n as Double: n != 0
86
+ case let s as String: s == "true" || s == "YES" || s == "1"
87
+ default: false
88
+ }
89
+ }
90
+
91
+ // MARK: Writing
92
+
93
+ public func set(_ value: Any?, forKey key: String) {
94
+ if let value { storage[key] = value } else { storage[key] = nil }
95
+ persist()
96
+ _DefaultsKey.named(key).changed()
97
+ }
98
+ public func set(_ value: Int, forKey key: String) { set(value as Any, forKey: key) }
99
+ public func set(_ value: Double, forKey key: String) { set(value as Any, forKey: key) }
100
+ public func set(_ value: Float, forKey key: String) { set(Double(value) as Any, forKey: key) }
101
+ public func set(_ value: Bool, forKey key: String) { set(value as Any, forKey: key) }
102
+ public func set(_ url: URL?, forKey key: String) { set(url as Any?, forKey: key) }
103
+ public func removeObject(forKey key: String) { set(nil, forKey: key) }
104
+
105
+ /// Fallback values, read when nothing was set; never persisted.
106
+ public func register(defaults: [String: Any]) {
107
+ for (key, value) in defaults {
108
+ registered[key] = value
109
+ _DefaultsKey.named(key).changed()
110
+ }
111
+ }
112
+ public func dictionaryRepresentation() -> [String: Any] {
113
+ var all = registered
114
+ for (key, value) in storage { all[key] = value }
115
+ return all
116
+ }
117
+ public func removePersistentDomain(forName domainName: String) {
118
+ storage.removeAll()
119
+ persist()
120
+ for key in _DefaultsKey.all { key.changed() }
121
+ }
122
+ @discardableResult public func synchronize() -> Bool { true }
123
+
124
+ /// The saved values as the host stores them.
125
+ public var _json: _JSON {
126
+ var fields: [String: _JSON] = [:]
127
+ for (key, value) in storage {
128
+ if let json = _defaultsJSON(from: value) { fields[key] = json }
129
+ }
130
+ return .object(fields)
131
+ }
132
+
133
+ private func persist() {
134
+ guard persistent else { return }
135
+ let json = _json
136
+ MainActor.assumeIsolated { _Runtime.shared.storeDefaults(json) }
137
+ }
138
+
139
+ public static func == (lhs: UserDefaults, rhs: UserDefaults) -> Bool { lhs === rhs }
140
+ public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) }
141
+ }
142
+
143
+ /// A defaults value as JSON; nil for a type the store cannot carry.
144
+ func _defaultsJSON(from value: Any) -> _JSON? {
145
+ switch value {
146
+ case let v as String: return .string(v)
147
+ case let v as Bool: return .bool(v)
148
+ case let v as Int: return .number(Double(v))
149
+ case let v as Double: return .number(v)
150
+ case let v as Float: return .number(Double(v))
151
+ case let v as Data: return .object(["$data": .string(v.base64EncodedString())])
152
+ case let v as Date: return .object(["$date": .number(v.timeIntervalSince1970)])
153
+ case let v as URL: return .object(["$url": .string(v.absoluteString)])
154
+ case let v as [Any]: return .array(v.compactMap(_defaultsJSON(from:)))
155
+ case let v as [String: Any]:
156
+ var fields: [String: _JSON] = [:]
157
+ for (key, item) in v { if let json = _defaultsJSON(from: item) { fields[key] = json } }
158
+ return .object(fields)
159
+ default:
160
+ print("[UserDefaults] cannot save a value of type \(type(of: value)); use a property-list type")
161
+ return nil
162
+ }
163
+ }
164
+
165
+ func _defaultsValue(fromJSON json: _JSON) -> Any? {
166
+ switch json {
167
+ case .null: return nil
168
+ case .bool(let b): return b
169
+ case .string(let s): return s
170
+ case .number(let n): return n == n.rounded() && abs(n) < 9_007_199_254_740_992 ? Int(n) as Any : n
171
+ case .bytes(let bytes): return Data(bytes)
172
+ case .array(let items): return items.compactMap(_defaultsValue(fromJSON:))
173
+ case .object(let fields):
174
+ if fields.count == 1 {
175
+ if case .string(let b64)? = fields["$data"], let data = Data(base64Encoded: b64) { return data }
176
+ if case .number(let seconds)? = fields["$date"] { return Date(timeIntervalSince1970: seconds) }
177
+ if case .string(let text)? = fields["$url"], let url = URL(string: text) { return url }
178
+ }
179
+ var out: [String: Any] = [:]
180
+ for (key, item) in fields { if let value = _defaultsValue(fromJSON: item) { out[key] = value } }
181
+ return out
182
+ }
183
+ }
@@ -0,0 +1,227 @@
1
+ // OAuth redirects to the app's own URL scheme, in the browser. An iOS app
2
+ // signs in by registering `myapp://…` as its OAuth redirect URI and letting
3
+ // `ASWebAuthenticationSession` catch the provider's redirect to it. A web
4
+ // page cannot receive a redirect to a custom scheme: the browser would hand
5
+ // it to another app, or fail. So the page serves a callback page at its own
6
+ // origin (Web/public/app/oauth-callback.html), and wherever one of the app's
7
+ // schemes appears as an OAuth redirect, the shim puts that page's URL in its
8
+ // place, with the original scheme (and what followed it) in the query so the
9
+ // app's URL can be rebuilt:
10
+ //
11
+ // icecubesapp:// → <page>/app/oauth-callback.html?sb_scheme=icecubesapp
12
+ // myapp://auth/done?x=1 → <page>/app/oauth-callback.html?sb_scheme=myapp&sb_target=%2F%2Fauth%2Fdone%3Fx%3D1
13
+ //
14
+ // The swap is narrow. Only the app's own schemes: those it declares
15
+ // (CFBundleURLTypes in its Info.plist; the CLI hands them to the page, and
16
+ // the page to the app as `SB_URL_SCHEMES`), plus the `callbackURLScheme` of
17
+ // a session once it starts. Only the redirect parameters, `redirect_uri` and
18
+ // `redirect_uris`: in the query of a URLSession request, in a form or JSON
19
+ // body (top-level keys; bodies up to 64 KiB), and in the authorize URL a
20
+ // web authentication session opens. The app's registration, the authorize
21
+ // request and the token exchange so all carry the same page URL, and the
22
+ // provider sees one consistent redirect URI. The provider redirects the
23
+ // sign-in window to the callback page, which hands its URL back to the app's
24
+ // page; `appURL(fromCallback:)` rebuilds `icecubesapp://?code=…` for the app
25
+ // (docs/ops-protocol.md, "Signing in").
26
+
27
+ import Foundation
28
+ import SwiftUI
29
+
30
+ public enum _WebAuthRedirects {
31
+ /// The parameters whose values are redirect URIs (OAuth 2's `redirect_uri`,
32
+ /// and `redirect_uris` of dynamic client registration and Mastodon's apps API).
33
+ public static let parameterNames: Set<String> = ["redirect_uri", "redirect_uris"]
34
+
35
+ /// The query items that carry the app's redirect on the callback page.
36
+ static let schemeItem = "sb_scheme"
37
+ static let targetItem = "sb_target"
38
+
39
+ /// Where the page serves its callback page when it does not say
40
+ /// (`SB_WEB_AUTH_CALLBACK` unset: headless runs).
41
+ public static let defaultCallbackPage = "http://localhost/app/oauth-callback.html"
42
+
43
+ /// Bodies larger than this are uploads, not OAuth forms; they are not examined.
44
+ static let bodyLimit = 64 * 1024
45
+
46
+ /// Schemes sessions registered. Only ever added to; one thread on WASI.
47
+ nonisolated(unsafe) static var sessionSchemes: Set<String> = []
48
+
49
+ /// The app's URL schemes, lower-cased: `SB_URL_SCHEMES`, plus those
50
+ /// sessions registered.
51
+ public static var schemes: Set<String> {
52
+ parseSchemes(_environment("SB_URL_SCHEMES") ?? "").union(sessionSchemes)
53
+ }
54
+
55
+ /// `SB_URL_SCHEMES`: schemes separated by commas or spaces.
56
+ static func parseSchemes(_ text: String) -> Set<String> {
57
+ Set(text.split(whereSeparator: { $0 == "," || $0 == " " || $0 == "\n" }).map { $0.lowercased() })
58
+ }
59
+
60
+ /// Adds a scheme for the rest of the run (a session's `callbackURLScheme`).
61
+ public static func register(scheme: String) {
62
+ let scheme = scheme.lowercased()
63
+ guard !scheme.isEmpty, scheme != "http", scheme != "https" else { return }
64
+ sessionSchemes.insert(scheme)
65
+ }
66
+
67
+ /// The page's callback page (`SB_WEB_AUTH_CALLBACK`, which the page sets).
68
+ public static var callbackPage: String {
69
+ _environment("SB_WEB_AUTH_CALLBACK") ?? defaultCallbackPage
70
+ }
71
+
72
+ // MARK: Redirect URIs
73
+
74
+ /// Whether `value` is a URI in one of the app's schemes.
75
+ public static func isAppRedirect(_ value: String) -> Bool {
76
+ guard let colon = value.firstIndex(of: ":") else { return false }
77
+ let scheme = value[..<colon].lowercased()
78
+ guard !scheme.isEmpty, scheme != "http", scheme != "https" else { return false }
79
+ return schemes.contains(scheme)
80
+ }
81
+
82
+ /// The callback page URL that stands for the app's redirect `value`, or
83
+ /// nil when `value` is not in one of the app's schemes.
84
+ public static func pageURL(forAppRedirect value: String) -> String? {
85
+ guard isAppRedirect(value), let colon = value.firstIndex(of: ":") else { return nil }
86
+ let scheme = String(value[..<colon])
87
+ let target = String(value[value.index(after: colon)...])
88
+ var url = callbackPage
89
+ url += url.contains("?") ? "&" : "?"
90
+ url += "\(schemeItem)=\(encode(scheme))"
91
+ // `myapp://` is the common case; its `//` is implied.
92
+ if target != "//" { url += "&\(targetItem)=\(encode(target))" }
93
+ return url
94
+ }
95
+
96
+ /// The app's URL for a URL the callback page was opened at: its scheme and
97
+ /// target back in front, the provider's query items (`code`, `state`, …)
98
+ /// added to the target's query, and the fragment kept. Nil when `url` is
99
+ /// not a callback page URL.
100
+ public static func appURL(fromCallback url: String) -> String? {
101
+ guard let components = URLComponents(string: url),
102
+ let items = components.percentEncodedQueryItems,
103
+ let scheme = items.first(where: { $0.name == schemeItem })?.value?.removingPercentEncoding,
104
+ !scheme.isEmpty
105
+ else { return nil }
106
+ let target = items.first(where: { $0.name == targetItem })?.value?.removingPercentEncoding ?? "//"
107
+ var result = "\(scheme):\(target)"
108
+ let rest = items.filter { $0.name != schemeItem && $0.name != targetItem }
109
+ if !rest.isEmpty {
110
+ result += result.contains("?") ? "&" : "?"
111
+ result += rest.map { item in item.value.map { "\(item.name)=\($0)" } ?? item.name }.joined(separator: "&")
112
+ }
113
+ if let fragment = components.percentEncodedFragment { result += "#\(fragment)" }
114
+ return result
115
+ }
116
+
117
+ /// A redirect parameter's value with each of the app's URIs replaced; a
118
+ /// space- or newline-separated list (`redirect_uris`) is rewritten item by item.
119
+ public static func rewriteRedirectValue(_ value: String) -> String {
120
+ let separator: Character = value.contains("\n") ? "\n" : " "
121
+ guard value.contains(separator) else { return pageURL(forAppRedirect: value) ?? value }
122
+ return value.split(separator: separator, omittingEmptySubsequences: false)
123
+ .map { pageURL(forAppRedirect: String($0)) ?? String($0) }
124
+ .joined(separator: String(separator))
125
+ }
126
+
127
+ // MARK: Requests
128
+
129
+ /// `url` with the app's URIs in its redirect query items replaced (the
130
+ /// URL itself when there are none).
131
+ public static func rewriting(url: URL) -> URL {
132
+ guard !schemes.isEmpty, let query = url.query, query.contains("redirect_uri"),
133
+ var components = URLComponents(url: url, resolvingAgainstBaseURL: false),
134
+ let items = components.percentEncodedQueryItems
135
+ else { return url }
136
+ var changed = false
137
+ let rewritten = items.map { item -> URLQueryItem in
138
+ guard parameterNames.contains(item.name), let value = item.value?.removingPercentEncoding else { return item }
139
+ let new = rewriteRedirectValue(value)
140
+ guard new != value else { return item }
141
+ changed = true
142
+ return URLQueryItem(name: item.name, value: encode(new))
143
+ }
144
+ guard changed else { return url }
145
+ components.percentEncodedQueryItems = rewritten
146
+ return components.url ?? url
147
+ }
148
+
149
+ /// `body` with the app's URIs in its redirect parameters replaced: the
150
+ /// top-level keys of a JSON object, or the fields of a form
151
+ /// (`application/x-www-form-urlencoded`). Other bodies come back as they were.
152
+ public static func rewriting(body: Data?, contentType: String?) -> Data? {
153
+ guard let body, !body.isEmpty, body.count <= bodyLimit, !schemes.isEmpty else { return body }
154
+ let text = String(decoding: body, as: UTF8.self)
155
+ guard text.contains("redirect_uri") else { return body }
156
+ let type = contentType?.lowercased() ?? ""
157
+ if type.contains("json") || (type.isEmpty && text.first(where: { !$0.isWhitespace }) == "{") {
158
+ return rewritingJSON(text).map { Data($0.utf8) } ?? body
159
+ }
160
+ if type.contains("x-www-form-urlencoded") || type.isEmpty {
161
+ return rewritingForm(text).map { Data($0.utf8) } ?? body
162
+ }
163
+ return body
164
+ }
165
+
166
+ /// The JSON object with its redirect keys rewritten; nil when nothing changed.
167
+ static func rewritingJSON(_ text: String) -> String? {
168
+ guard case .object(var object)? = try? _JSON.parse(text) else { return nil }
169
+ var changed = false
170
+ for name in parameterNames {
171
+ switch object[name] {
172
+ case .string(let value)?:
173
+ let new = rewriteRedirectValue(value)
174
+ if new != value { object[name] = .string(new); changed = true }
175
+ case .array(let values)?:
176
+ let new = values.map { item -> _JSON in
177
+ if case .string(let value) = item { return .string(rewriteRedirectValue(value)) }
178
+ return item
179
+ }
180
+ if new != values { object[name] = .array(new); changed = true }
181
+ default:
182
+ break
183
+ }
184
+ }
185
+ return changed ? _JSON.object(object).serialized : nil
186
+ }
187
+
188
+ /// The form with its redirect fields rewritten; nil when nothing changed.
189
+ static func rewritingForm(_ text: String) -> String? {
190
+ var changed = false
191
+ let fields = text.split(separator: "&", omittingEmptySubsequences: false).map { field -> String in
192
+ guard let equals = field.firstIndex(of: "=") else { return String(field) }
193
+ let name = formDecode(field[..<equals])
194
+ guard parameterNames.contains(name) else { return String(field) }
195
+ let value = formDecode(field[field.index(after: equals)...])
196
+ let new = rewriteRedirectValue(value)
197
+ guard new != value else { return String(field) }
198
+ changed = true
199
+ return "\(field[..<equals])=\(encode(new))"
200
+ }
201
+ return changed ? fields.joined(separator: "&") : nil
202
+ }
203
+
204
+ // MARK: Encoding
205
+
206
+ /// RFC 3986's unreserved characters stay; everything else is percent-encoded.
207
+ static func encode(_ text: String) -> String {
208
+ var out = ""
209
+ for byte in text.utf8 {
210
+ switch byte {
211
+ case UInt8(ascii: "A")...UInt8(ascii: "Z"), UInt8(ascii: "a")...UInt8(ascii: "z"),
212
+ UInt8(ascii: "0")...UInt8(ascii: "9"), UInt8(ascii: "-"), UInt8(ascii: "."),
213
+ UInt8(ascii: "_"), UInt8(ascii: "~"):
214
+ out.unicodeScalars.append(UnicodeScalar(byte))
215
+ default:
216
+ let hex = Array("0123456789ABCDEF")
217
+ out += "%\(hex[Int(byte >> 4)])\(hex[Int(byte & 15)])"
218
+ }
219
+ }
220
+ return out
221
+ }
222
+
223
+ static func formDecode(_ text: Substring) -> String {
224
+ let spaced = text.replacingOccurrences(of: "+", with: " ")
225
+ return spaced.removingPercentEncoding ?? spaced
226
+ }
227
+ }
@@ -0,0 +1,187 @@
1
+ // `URLSessionWebSocketTask` over the browser's WebSocket. Each call is a host
2
+ // request of kind `websocket` (docs/ops-protocol.md, "WebSockets"):
3
+ // `open` connects and answers the socket's id once it is open, `send` sends a
4
+ // message, `receive` answers the next message (queued by the page as it
5
+ // arrives), and `close` closes. The pull model matches the task's own: an
6
+ // app calls `receive` again for every message.
7
+
8
+ import Foundation
9
+ import SwiftUI
10
+
11
+ open class URLSessionWebSocketTask: URLSessionTask, @unchecked Sendable {
12
+ public enum Message: Sendable {
13
+ case data(Data)
14
+ case string(String)
15
+ }
16
+
17
+ public enum CloseCode: Int, Sendable {
18
+ case invalid = 0
19
+ case normalClosure = 1000
20
+ case goingAway = 1001
21
+ case protocolError = 1002
22
+ case unsupportedData = 1003
23
+ case noStatusReceived = 1005
24
+ case abnormalClosure = 1006
25
+ case invalidFramePayloadData = 1007
26
+ case policyViolation = 1008
27
+ case messageTooBig = 1009
28
+ case mandatoryExtensionMissing = 1010
29
+ case internalServerError = 1011
30
+ case tlsHandshakeFailure = 1015
31
+ }
32
+
33
+ public var maximumMessageSize = 1_048_576
34
+ public private(set) var closeCode: CloseCode = .invalid
35
+ public private(set) var closeReason: Data?
36
+
37
+ let url: URL
38
+ let protocols: [String]
39
+ /// The connection, opened on `resume()` (or the first send or receive).
40
+ private var connection: Task<Int, any Error>?
41
+
42
+ init(identifier: Int, request: URLRequest, url: URL, protocols: [String]) {
43
+ self.url = url
44
+ self.protocols = protocols
45
+ super.init(identifier: identifier, request: request) { task in
46
+ _ = try? await (task as! URLSessionWebSocketTask).socket()
47
+ }
48
+ }
49
+
50
+ /// The page's id for the open socket.
51
+ @MainActor func socket() async throws -> Int {
52
+ if connection == nil {
53
+ let params: _JSON = .object([
54
+ "action": .string("open"),
55
+ "url": .string(url.absoluteString),
56
+ "protocols": .array(protocols.map { .string($0) }),
57
+ ])
58
+ let url = self.url
59
+ connection = Task { @MainActor in
60
+ let value = try await Self.host(params, url: url)
61
+ guard case .object(let fields) = value, case .number(let id)? = fields["socket"] else {
62
+ throw URLError(.badServerResponse, userInfo: ["NSErrorFailingURLKey": url])
63
+ }
64
+ return Int(id)
65
+ }
66
+ }
67
+ return try await connection!.value
68
+ }
69
+
70
+ @MainActor static func host(_ params: _JSON, url: URL) async throws -> _JSON {
71
+ do {
72
+ return try await _Runtime.shared._hostRequest(kind: "websocket", params: params)
73
+ } catch let failure as _HostRequestError {
74
+ throw URLSession.urlError(from: failure.message, url: url)
75
+ }
76
+ }
77
+
78
+ // MARK: Messages
79
+
80
+ @MainActor public func send(_ message: Message) async throws {
81
+ let id = try await socket()
82
+ var params: [String: _JSON] = ["action": .string("send"), "socket": .number(Double(id))]
83
+ switch message {
84
+ case .string(let text): params["string"] = .string(text)
85
+ case .data(let data): params["data"] = .string(data.base64EncodedString())
86
+ }
87
+ _ = try await Self.host(.object(params), url: url)
88
+ }
89
+
90
+ public func send(_ message: Message, completionHandler: @escaping @Sendable ((any Error)?) -> Void) {
91
+ Task { @MainActor in
92
+ do {
93
+ try await self.send(message)
94
+ completionHandler(nil)
95
+ } catch {
96
+ completionHandler(error)
97
+ }
98
+ }
99
+ }
100
+
101
+ /// The next message; fails once the socket is closed.
102
+ @MainActor public func receive() async throws -> Message {
103
+ let id = try await socket()
104
+ let value = try await Self.host(.object(["action": .string("receive"), "socket": .number(Double(id))]), url: url)
105
+ guard case .object(let fields) = value else { throw URLError(.badServerResponse) }
106
+ if case .string(let text)? = fields["string"] { return .string(text) }
107
+ if case .string(let encoded)? = fields["data"], let data = Data(base64Encoded: encoded) { return .data(data) }
108
+ if case .number(let code)? = fields["closeCode"] {
109
+ closeCode = CloseCode(rawValue: Int(code)) ?? .abnormalClosure
110
+ if case .string(let reason)? = fields["reason"], !reason.isEmpty { closeReason = Data(reason.utf8) }
111
+ finish(response: response, error: URLError(.networkConnectionLost))
112
+ }
113
+ throw URLError(.networkConnectionLost, userInfo: ["NSErrorFailingURLKey": url])
114
+ }
115
+
116
+ public func receive(completionHandler: @escaping @Sendable (Result<Message, any Error>) -> Void) {
117
+ Task { @MainActor in
118
+ do {
119
+ completionHandler(.success(try await self.receive()))
120
+ } catch {
121
+ completionHandler(.failure(error))
122
+ }
123
+ }
124
+ }
125
+
126
+ /// Browsers send pings themselves and do not expose them: the handler is called once the socket is open.
127
+ public func sendPing(pongReceiveHandler: @escaping @Sendable ((any Error)?) -> Void) {
128
+ Task { @MainActor in
129
+ do {
130
+ _ = try await self.socket()
131
+ pongReceiveHandler(nil)
132
+ } catch {
133
+ pongReceiveHandler(error)
134
+ }
135
+ }
136
+ }
137
+
138
+ public func cancel(with closeCode: CloseCode, reason: Data?) {
139
+ self.closeCode = closeCode
140
+ closeReason = reason
141
+ close(code: closeCode == .invalid ? .normalClosure : closeCode, reason: reason)
142
+ }
143
+
144
+ public override func cancel() {
145
+ close(code: .normalClosure, reason: nil)
146
+ }
147
+
148
+ private func close(code: CloseCode, reason: Data?) {
149
+ let connection = self.connection
150
+ let url = self.url
151
+ finish(response: response, error: URLError(.cancelled))
152
+ guard let connection else { return }
153
+ Task { @MainActor in
154
+ guard let id = try? await connection.value else { return }
155
+ var params: [String: _JSON] = ["action": .string("close"), "socket": .number(Double(id)), "code": .number(Double(code.rawValue))]
156
+ if let reason { params["reason"] = .string(String(decoding: reason, as: UTF8.self)) }
157
+ _ = try? await Self.host(.object(params), url: url)
158
+ }
159
+ }
160
+ }
161
+
162
+ public protocol URLSessionWebSocketDelegate: URLSessionTaskDelegate {
163
+ func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?)
164
+ func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?)
165
+ }
166
+
167
+ extension URLSessionWebSocketDelegate {
168
+ public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {}
169
+ public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {}
170
+ }
171
+
172
+ extension URLSession {
173
+ public func webSocketTask(with url: URL) -> URLSessionWebSocketTask {
174
+ webSocketTask(with: url, protocols: [])
175
+ }
176
+
177
+ public func webSocketTask(with url: URL, protocols: [String]) -> URLSessionWebSocketTask {
178
+ URLSessionWebSocketTask(identifier: takeIdentifier(), request: URLRequest(url: url), url: url, protocols: protocols)
179
+ }
180
+
181
+ public func webSocketTask(with request: URLRequest) -> URLSessionWebSocketTask {
182
+ let url = request.url ?? URL(string: "about:blank")!
183
+ let protocols = request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol")?
184
+ .split(separator: ",").map { $0.trimmingCharacters(in: .whitespaces) } ?? []
185
+ return URLSessionWebSocketTask(identifier: takeIdentifier(), request: request, url: url, protocols: protocols)
186
+ }
187
+ }