@swiftbrowser/swift 0.1.0 → 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 (393) hide show
  1. package/Package.swift +200 -9
  2. package/README.md +7 -9
  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 +0 -4
  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/{_FoundationCommon → FoundationBridge}/Bundle.swift +41 -4
  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 +24 -72
  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/Localization.swift +149 -0
  170. package/Sources/FoundationBridge/Locks.swift +50 -0
  171. package/Sources/FoundationBridge/Markdown.swift +527 -0
  172. package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
  173. package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
  174. package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
  175. package/Sources/FoundationBridge/Operation.swift +195 -0
  176. package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
  177. package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
  178. package/Sources/FoundationBridge/SceneStorage.swift +78 -0
  179. package/Sources/FoundationBridge/SecurityExports.swift +8 -0
  180. package/Sources/FoundationBridge/Selector.swift +226 -0
  181. package/Sources/FoundationBridge/StringComparators.swift +17 -0
  182. package/Sources/FoundationBridge/Table.swift +211 -0
  183. package/Sources/FoundationBridge/TextAttributes.swift +42 -0
  184. package/Sources/FoundationBridge/Timer.swift +6 -1
  185. package/Sources/FoundationBridge/URLSession.swift +718 -0
  186. package/Sources/{_FoundationCommon → FoundationBridge}/UserDefaults.swift +17 -4
  187. package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
  188. package/Sources/FoundationBridge/WebSocket.swift +187 -0
  189. package/Sources/FoundationModels/FoundationModels.swift +1098 -0
  190. package/Sources/ImageIO/GIF.swift +72 -0
  191. package/Sources/ImageIO/ImageIO.swift +248 -0
  192. package/Sources/ImageIO/ImageTypes.swift +28 -0
  193. package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
  194. package/Sources/LocalAuthentication/LAContext.swift +86 -0
  195. package/Sources/MapKit/Geometry.swift +223 -0
  196. package/Sources/MapKit/Map.swift +638 -0
  197. package/Sources/MapKit/MapView.swift +229 -0
  198. package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
  199. package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
  200. package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
  201. package/Sources/OSLog/OSLog.swift +6 -0
  202. package/Sources/Photos/Photos.swift +572 -0
  203. package/Sources/PhotosUI/PhotosPicker.swift +248 -0
  204. package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
  205. package/Sources/QuickLook/QuickLook.swift +168 -0
  206. package/Sources/SafariServices/SafariServices.swift +106 -0
  207. package/Sources/Security/Security.swift +332 -0
  208. package/Sources/StoreKit/AppStore.swift +207 -0
  209. package/Sources/StoreKit/Products.swift +280 -0
  210. package/Sources/StoreKit/RequestReview.swift +28 -0
  211. package/Sources/StoreKit/StoreKit1.swift +486 -0
  212. package/Sources/StoreKit/StoreViews.swift +428 -0
  213. package/Sources/StoreKit/Transactions.swift +197 -0
  214. package/Sources/SwiftData/Macros.swift +58 -0
  215. package/Sources/SwiftData/ModelActor.swift +38 -0
  216. package/Sources/SwiftData/ModelContainer.swift +129 -0
  217. package/Sources/SwiftData/ModelContext.swift +451 -0
  218. package/Sources/SwiftData/PersistentModel.swift +238 -0
  219. package/Sources/SwiftData/Properties.swift +261 -0
  220. package/Sources/SwiftData/Query.swift +256 -0
  221. package/Sources/SwiftData/Schema.swift +192 -0
  222. package/Sources/SwiftData/Store.swift +146 -0
  223. package/Sources/SwiftData/StringPredicates.swift +125 -0
  224. package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
  225. package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
  226. package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
  227. package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
  228. package/Sources/SwiftDataMacros/Plugin.swift +18 -0
  229. package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
  230. package/Sources/SwiftUI/API/Accessibility.swift +55 -6
  231. package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
  232. package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
  233. package/Sources/SwiftUI/API/Alert.swift +1 -1
  234. package/Sources/SwiftUI/API/AlignmentGuides.swift +65 -0
  235. package/Sources/SwiftUI/API/Animation.swift +37 -5
  236. package/Sources/SwiftUI/API/App.swift +31 -1
  237. package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
  238. package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
  239. package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
  240. package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
  241. package/Sources/SwiftUI/API/Canvas.swift +337 -0
  242. package/Sources/SwiftUI/API/Color.swift +104 -28
  243. package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
  244. package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
  245. package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
  246. package/Sources/SwiftUI/API/Commands.swift +106 -0
  247. package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
  248. package/Sources/SwiftUI/API/ContentShape.swift +33 -0
  249. package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
  250. package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
  251. package/Sources/SwiftUI/API/Controls.swift +59 -27
  252. package/Sources/SwiftUI/API/CustomLayout.swift +49 -10
  253. package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
  254. package/Sources/SwiftUI/API/Decorations.swift +1 -1
  255. package/Sources/SwiftUI/API/EditMode.swift +25 -82
  256. package/Sources/SwiftUI/API/Effects.swift +105 -7
  257. package/Sources/SwiftUI/API/Entry.swift +8 -0
  258. package/Sources/SwiftUI/API/Environment.swift +93 -9
  259. package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
  260. package/Sources/SwiftUI/API/Focus.swift +11 -3
  261. package/Sources/SwiftUI/API/Gauge.swift +3 -2
  262. package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
  263. package/Sources/SwiftUI/API/GeometryReader.swift +13 -2
  264. package/Sources/SwiftUI/API/GestureState.swift +65 -0
  265. package/Sources/SwiftUI/API/Gestures.swift +1 -1
  266. package/Sources/SwiftUI/API/Glass.swift +127 -0
  267. package/Sources/SwiftUI/API/Grid.swift +1 -1
  268. package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
  269. package/Sources/SwiftUI/API/KeyPress.swift +54 -0
  270. package/Sources/SwiftUI/API/LabelStyle.swift +13 -6
  271. package/Sources/SwiftUI/API/Layout.swift +67 -12
  272. package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
  273. package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
  274. package/Sources/SwiftUI/API/Lists.swift +61 -6
  275. package/Sources/SwiftUI/API/Menu.swift +8 -1
  276. package/Sources/SwiftUI/API/Modifiers.swift +80 -10
  277. package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
  278. package/Sources/SwiftUI/API/Namespace.swift +44 -0
  279. package/Sources/SwiftUI/API/Navigation.swift +24 -9
  280. package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
  281. package/Sources/SwiftUI/API/ObservableObject.swift +16 -2
  282. package/Sources/SwiftUI/API/Path.swift +543 -0
  283. package/Sources/SwiftUI/API/Phase8Controls.swift +48 -31
  284. package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
  285. package/Sources/SwiftUI/API/Picker.swift +11 -2
  286. package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
  287. package/Sources/SwiftUI/API/Popover.swift +41 -0
  288. package/Sources/SwiftUI/API/Preferences.swift +262 -0
  289. package/Sources/SwiftUI/API/Presentation.swift +17 -4
  290. package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
  291. package/Sources/SwiftUI/API/Primitives.swift +164 -37
  292. package/Sources/SwiftUI/API/Publishers.swift +4 -4
  293. package/Sources/SwiftUI/API/Redaction.swift +75 -0
  294. package/Sources/SwiftUI/API/RowActions.swift +3 -2
  295. package/Sources/SwiftUI/API/Scenes.swift +131 -0
  296. package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
  297. package/Sources/SwiftUI/API/ScrollTargets.swift +3 -3
  298. package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
  299. package/Sources/SwiftUI/API/SectionSupplements.swift +96 -0
  300. package/Sources/SwiftUI/API/Shape.swift +214 -0
  301. package/Sources/SwiftUI/API/ShapeStyle.swift +105 -7
  302. package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
  303. package/Sources/SwiftUI/API/Sharing.swift +193 -0
  304. package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
  305. package/Sources/SwiftUI/API/State.swift +18 -1
  306. package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
  307. package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
  308. package/Sources/SwiftUI/API/TabContent.swift +841 -0
  309. package/Sources/SwiftUI/API/Table.swift +382 -0
  310. package/Sources/SwiftUI/API/Tabs.swift +148 -4
  311. package/Sources/SwiftUI/API/Tasks.swift +2 -2
  312. package/Sources/SwiftUI/API/Text.swift +386 -0
  313. package/Sources/SwiftUI/API/TextDates.swift +61 -0
  314. package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
  315. package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
  316. package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
  317. package/Sources/SwiftUI/API/Toolbar.swift +52 -16
  318. package/Sources/SwiftUI/API/Transfer.swift +145 -0
  319. package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
  320. package/Sources/SwiftUI/API/Video.swift +64 -0
  321. package/Sources/SwiftUI/API/View.swift +10 -2
  322. package/Sources/SwiftUI/API/ViewModifier.swift +4 -1
  323. package/Sources/SwiftUI/API/VisualEffect.swift +74 -1
  324. package/Sources/SwiftUI/API/Windows.swift +25 -0
  325. package/Sources/SwiftUI/Charts/Axis.swift +7 -1
  326. package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
  327. package/Sources/SwiftUI/Charts/Chart.swift +17 -3
  328. package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
  329. package/Sources/SwiftUI/Localization/Localization.swift +498 -0
  330. package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
  331. package/Sources/SwiftUI/Runtime/Executor.swift +2 -0
  332. package/Sources/SwiftUI/Runtime/Exports.swift +37 -1
  333. package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
  334. package/Sources/SwiftUI/Runtime/JSON.swift +76 -4
  335. package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
  336. package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
  337. package/Sources/SwiftUI/Runtime/Ops.swift +58 -12
  338. package/Sources/SwiftUI/Runtime/Reconciler.swift +10 -1
  339. package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
  340. package/Sources/SwiftUI/Runtime/Runtime.swift +977 -198
  341. package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
  342. package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
  343. package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
  344. package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
  345. package/Sources/Symbols/Symbols.swift +25 -0
  346. package/Sources/Translation/Translation.swift +423 -0
  347. package/Sources/UIKit/Activity.swift +213 -0
  348. package/Sources/UIKit/Alerts.swift +69 -0
  349. package/Sources/UIKit/AppDelegate.swift +222 -0
  350. package/Sources/UIKit/Appearance.swift +84 -0
  351. package/Sources/UIKit/ColorConversions.swift +70 -0
  352. package/Sources/UIKit/Controls.swift +225 -0
  353. package/Sources/UIKit/Device.swift +200 -0
  354. package/Sources/UIKit/Feedback.swift +65 -0
  355. package/Sources/UIKit/Font.swift +307 -0
  356. package/Sources/UIKit/Graphics.swift +204 -0
  357. package/Sources/UIKit/HostingController.swift +185 -0
  358. package/Sources/UIKit/Identity.swift +24 -0
  359. package/Sources/UIKit/Introspectable.swift +510 -0
  360. package/Sources/UIKit/Pasteboard.swift +363 -0
  361. package/Sources/UIKit/PhotoAlbum.swift +81 -0
  362. package/Sources/UIKit/RemoteNotifications.swift +15 -0
  363. package/Sources/UIKit/Representable.swift +288 -0
  364. package/Sources/UIKit/SafeArea.swift +12 -0
  365. package/Sources/UIKit/SceneDelegates.swift +132 -0
  366. package/Sources/UIKit/Scenes.swift +40 -0
  367. package/Sources/UIKit/ScrollView.swift +157 -0
  368. package/Sources/UIKit/ShortcutItems.swift +67 -0
  369. package/Sources/UIKit/SymbolConfiguration.swift +124 -0
  370. package/Sources/UIKit/TargetAction.swift +123 -0
  371. package/Sources/UIKit/TextPaste.swift +161 -0
  372. package/Sources/UIKit/TextView.swift +538 -0
  373. package/Sources/UIKit/UIKit.swift +292 -0
  374. package/Sources/UIKit/UIView.swift +855 -0
  375. package/Sources/UIKit/ViewTranslation.swift +311 -0
  376. package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
  377. package/Sources/UserNotifications/Content.swift +370 -0
  378. package/Sources/UserNotifications/NotificationCenter.swift +309 -0
  379. package/Sources/WeatherKit/WeatherKit.swift +228 -0
  380. package/Sources/WebKit/WebKit.swift +245 -0
  381. package/Sources/os/os.swift +376 -0
  382. package/Sources/zlib/zlib.swift +6 -0
  383. package/index.d.ts +1 -1
  384. package/index.mjs +2 -2
  385. package/manifest.d.mts +2 -0
  386. package/manifest.mjs +39 -0
  387. package/package.json +5 -3
  388. package/sync-sources.mjs +21 -7
  389. package/Sources/FoundationLite/Common.swift +0 -3
  390. package/Sources/FoundationLite/FoundationLite.swift +0 -171
  391. package/Sources/FoundationLite/Interaction.swift +0 -146
  392. package/Sources/FoundationLite/Timer.swift +0 -48
  393. package/Sources/_FoundationCommon/_FoundationCommon.swift +0 -10
@@ -0,0 +1,370 @@
1
+ // UserNotifications' value types: what a notification says, when it fires,
2
+ // and what the viewer allowed. Shapes and names follow Apple's framework;
3
+ // the center that schedules and shows them is NotificationCenter.swift.
4
+
5
+ import Foundation
6
+
7
+ // MARK: Authorization
8
+
9
+ /// What an app asks permission for. The browser has one permission for all of
10
+ /// it; the options are recorded and otherwise ignored.
11
+ public struct UNAuthorizationOptions: OptionSet, Sendable, Hashable {
12
+ public let rawValue: UInt
13
+ public init(rawValue: UInt) { self.rawValue = rawValue }
14
+
15
+ public static let badge = UNAuthorizationOptions(rawValue: 1 << 0)
16
+ public static let sound = UNAuthorizationOptions(rawValue: 1 << 1)
17
+ public static let alert = UNAuthorizationOptions(rawValue: 1 << 2)
18
+ public static let carPlay = UNAuthorizationOptions(rawValue: 1 << 3)
19
+ public static let criticalAlert = UNAuthorizationOptions(rawValue: 1 << 4)
20
+ public static let providesAppNotificationSettings = UNAuthorizationOptions(rawValue: 1 << 5)
21
+ public static let provisional = UNAuthorizationOptions(rawValue: 1 << 6)
22
+ }
23
+
24
+ /// The browser's `Notification.permission`: `default` is `.notDetermined`,
25
+ /// `granted` `.authorized`, `denied` (or no Notification API) `.denied`.
26
+ public enum UNAuthorizationStatus: Int, Sendable {
27
+ case notDetermined = 0
28
+ case denied = 1
29
+ case authorized = 2
30
+ case provisional = 3
31
+ case ephemeral = 4
32
+ }
33
+
34
+ public enum UNNotificationSetting: Int, Sendable {
35
+ case notSupported = 0
36
+ case disabled = 1
37
+ case enabled = 2
38
+ }
39
+
40
+ public enum UNAlertStyle: Int, Sendable {
41
+ case none = 0
42
+ case banner = 1
43
+ case alert = 2
44
+ }
45
+
46
+ public enum UNShowPreviewsSetting: Int, Sendable {
47
+ case always = 0
48
+ case whenAuthenticated = 1
49
+ case never = 2
50
+ }
51
+
52
+ /// What `getNotificationSettings` reports. Every per-kind setting follows the
53
+ /// one browser permission: enabled when authorized, else disabled.
54
+ public final class UNNotificationSettings: NSObject, @unchecked Sendable {
55
+ public let authorizationStatus: UNAuthorizationStatus
56
+ public let soundSetting: UNNotificationSetting
57
+ public let badgeSetting: UNNotificationSetting
58
+ public let alertSetting: UNNotificationSetting
59
+ public let notificationCenterSetting: UNNotificationSetting
60
+ public let lockScreenSetting: UNNotificationSetting
61
+ public let carPlaySetting: UNNotificationSetting
62
+ public let criticalAlertSetting: UNNotificationSetting
63
+ public let timeSensitiveSetting: UNNotificationSetting
64
+ public let scheduledDeliverySetting: UNNotificationSetting
65
+ public let directMessagesSetting: UNNotificationSetting
66
+ public let announcementSetting: UNNotificationSetting
67
+ public let alertStyle: UNAlertStyle
68
+ public let showPreviewsSetting: UNShowPreviewsSetting
69
+ public let providesAppNotificationSettings: Bool
70
+
71
+ init(authorizationStatus: UNAuthorizationStatus) {
72
+ self.authorizationStatus = authorizationStatus
73
+ let shown: UNNotificationSetting = authorizationStatus == .authorized ? .enabled : .disabled
74
+ soundSetting = shown
75
+ badgeSetting = shown
76
+ alertSetting = shown
77
+ notificationCenterSetting = shown
78
+ lockScreenSetting = shown
79
+ carPlaySetting = .notSupported
80
+ criticalAlertSetting = .notSupported
81
+ timeSensitiveSetting = .notSupported
82
+ scheduledDeliverySetting = .notSupported
83
+ directMessagesSetting = .notSupported
84
+ announcementSetting = .notSupported
85
+ alertStyle = authorizationStatus == .authorized ? .banner : .none
86
+ showPreviewsSetting = .always
87
+ providesAppNotificationSettings = false
88
+ super.init()
89
+ }
90
+ }
91
+
92
+ /// Errors the center reports. In the browser: `.notificationsNotAllowed` when
93
+ /// the page has no Notification API (an iPhone browser tab that is not on the
94
+ /// Home Screen, for one).
95
+ public struct UNError: Error, Hashable, Sendable, CustomStringConvertible {
96
+ public enum Code: Int, Sendable {
97
+ case notificationsNotAllowed = 1
98
+ case attachmentInvalidURL = 100
99
+ case attachmentUnrecognizedType = 101
100
+ case attachmentInvalidFileSize = 102
101
+ case attachmentNotInDataStore = 103
102
+ case attachmentMoveIntoDataStoreFailed = 104
103
+ case attachmentCorrupt = 105
104
+ case notificationInvalidNoDate = 1400
105
+ case notificationInvalidNoContent = 1401
106
+ case contentProvidingObjectNotAllowed = 1500
107
+ case contentProvidingInvalid = 1501
108
+ case badgeInputInvalid = 1600
109
+ }
110
+
111
+ public let code: Code
112
+
113
+ public init(_ code: Code) { self.code = code }
114
+
115
+ public static let notificationsNotAllowed = Code.notificationsNotAllowed
116
+ public static let notificationInvalidNoDate = Code.notificationInvalidNoDate
117
+ public static let notificationInvalidNoContent = Code.notificationInvalidNoContent
118
+
119
+ public var description: String {
120
+ switch code {
121
+ case .notificationsNotAllowed: "Notifications are not allowed for this application"
122
+ default: "UNErrorDomain error \(code.rawValue)"
123
+ }
124
+ }
125
+
126
+ public var localizedDescription: String { description }
127
+ }
128
+
129
+ // MARK: Content
130
+
131
+ public struct UNNotificationSoundName: RawRepresentable, Hashable, Sendable {
132
+ public let rawValue: String
133
+ public init(rawValue: String) { self.rawValue = rawValue }
134
+ public init(_ rawValue: String) { self.rawValue = rawValue }
135
+ }
136
+
137
+ /// A notification's sound. The browser plays its own, or none: a notification
138
+ /// without a sound is shown `silent`.
139
+ public final class UNNotificationSound: NSObject, @unchecked Sendable {
140
+ public let name: UNNotificationSoundName?
141
+ let critical: Bool
142
+
143
+ init(name: UNNotificationSoundName?, critical: Bool = false) {
144
+ self.name = name
145
+ self.critical = critical
146
+ super.init()
147
+ }
148
+
149
+ public class var `default`: UNNotificationSound { UNNotificationSound(name: nil) }
150
+ public class var defaultCritical: UNNotificationSound { UNNotificationSound(name: nil, critical: true) }
151
+ public class var defaultRingtone: UNNotificationSound { UNNotificationSound(name: nil) }
152
+
153
+ public class func defaultCriticalSound(withAudioVolume volume: Float) -> UNNotificationSound { .defaultCritical }
154
+ public class func soundNamed(_ name: UNNotificationSoundName) -> UNNotificationSound { UNNotificationSound(name: name) }
155
+ public class func criticalSoundNamed(_ name: UNNotificationSoundName) -> UNNotificationSound { UNNotificationSound(name: name, critical: true) }
156
+ public class func criticalSoundNamed(_ name: UNNotificationSoundName, withAudioVolume volume: Float) -> UNNotificationSound {
157
+ UNNotificationSound(name: name, critical: true)
158
+ }
159
+ }
160
+
161
+ public enum UNNotificationInterruptionLevel: UInt, Sendable {
162
+ case passive = 0
163
+ case active = 1
164
+ case timeSensitive = 2
165
+ case critical = 3
166
+ }
167
+
168
+ /// What a notification says. Immutable; `UNMutableNotificationContent` is the
169
+ /// one apps fill in. The browser shows the title, and the subtitle and body
170
+ /// as the notification's text, one line each.
171
+ open class UNNotificationContent: NSObject, NSCopying, NSMutableCopying, @unchecked Sendable {
172
+ fileprivate var storedTitle = ""
173
+ fileprivate var storedSubtitle = ""
174
+ fileprivate var storedBody = ""
175
+ fileprivate var storedBadge: NSNumber?
176
+ fileprivate var storedSound: UNNotificationSound?
177
+ fileprivate var storedUserInfo: [AnyHashable: Any] = [:]
178
+ fileprivate var storedCategoryIdentifier = ""
179
+ fileprivate var storedThreadIdentifier = ""
180
+ fileprivate var storedLaunchImageName = ""
181
+ fileprivate var storedTargetContentIdentifier: String?
182
+ fileprivate var storedInterruptionLevel = UNNotificationInterruptionLevel.active
183
+ fileprivate var storedRelevanceScore = 0.0
184
+ fileprivate var storedFilterCriteria: String?
185
+
186
+ open var title: String { storedTitle }
187
+ open var subtitle: String { storedSubtitle }
188
+ open var body: String { storedBody }
189
+ open var badge: NSNumber? { storedBadge }
190
+ open var sound: UNNotificationSound? { storedSound }
191
+ open var userInfo: [AnyHashable: Any] { storedUserInfo }
192
+ open var categoryIdentifier: String { storedCategoryIdentifier }
193
+ open var threadIdentifier: String { storedThreadIdentifier }
194
+ open var launchImageName: String { storedLaunchImageName }
195
+ open var targetContentIdentifier: String? { storedTargetContentIdentifier }
196
+ open var interruptionLevel: UNNotificationInterruptionLevel { storedInterruptionLevel }
197
+ open var relevanceScore: Double { storedRelevanceScore }
198
+ open var filterCriteria: String? { storedFilterCriteria }
199
+
200
+ public override init() {
201
+ super.init()
202
+ }
203
+
204
+ fileprivate func fill(from other: UNNotificationContent) {
205
+ storedTitle = other.storedTitle
206
+ storedSubtitle = other.storedSubtitle
207
+ storedBody = other.storedBody
208
+ storedBadge = other.storedBadge
209
+ storedSound = other.storedSound
210
+ storedUserInfo = other.storedUserInfo
211
+ storedCategoryIdentifier = other.storedCategoryIdentifier
212
+ storedThreadIdentifier = other.storedThreadIdentifier
213
+ storedLaunchImageName = other.storedLaunchImageName
214
+ storedTargetContentIdentifier = other.storedTargetContentIdentifier
215
+ storedInterruptionLevel = other.storedInterruptionLevel
216
+ storedRelevanceScore = other.storedRelevanceScore
217
+ storedFilterCriteria = other.storedFilterCriteria
218
+ }
219
+
220
+ /// An immutable copy.
221
+ open func copy(with zone: NSZone? = nil) -> Any {
222
+ let copy = UNNotificationContent()
223
+ copy.fill(from: self)
224
+ return copy
225
+ }
226
+
227
+ /// A `UNMutableNotificationContent` with the same values.
228
+ open func mutableCopy(with zone: NSZone? = nil) -> Any {
229
+ let copy = UNMutableNotificationContent()
230
+ copy.fill(from: self)
231
+ return copy
232
+ }
233
+ }
234
+
235
+ open class UNMutableNotificationContent: UNNotificationContent, @unchecked Sendable {
236
+ open override var title: String { get { storedTitle } set { storedTitle = newValue } }
237
+ open override var subtitle: String { get { storedSubtitle } set { storedSubtitle = newValue } }
238
+ open override var body: String { get { storedBody } set { storedBody = newValue } }
239
+ /// Sets the app badge (`navigator.setAppBadge`, where the browser has it) when delivered; 0 clears it.
240
+ open override var badge: NSNumber? { get { storedBadge } set { storedBadge = newValue } }
241
+ open override var sound: UNNotificationSound? { get { storedSound } set { storedSound = newValue } }
242
+ open override var userInfo: [AnyHashable: Any] { get { storedUserInfo } set { storedUserInfo = newValue } }
243
+ open override var categoryIdentifier: String { get { storedCategoryIdentifier } set { storedCategoryIdentifier = newValue } }
244
+ open override var threadIdentifier: String { get { storedThreadIdentifier } set { storedThreadIdentifier = newValue } }
245
+ open override var launchImageName: String { get { storedLaunchImageName } set { storedLaunchImageName = newValue } }
246
+ open override var targetContentIdentifier: String? { get { storedTargetContentIdentifier } set { storedTargetContentIdentifier = newValue } }
247
+ open override var interruptionLevel: UNNotificationInterruptionLevel { get { storedInterruptionLevel } set { storedInterruptionLevel = newValue } }
248
+ open override var relevanceScore: Double { get { storedRelevanceScore } set { storedRelevanceScore = newValue } }
249
+ open override var filterCriteria: String? { get { storedFilterCriteria } set { storedFilterCriteria = newValue } }
250
+
251
+ public override init() {
252
+ super.init()
253
+ }
254
+ }
255
+
256
+ // MARK: Triggers
257
+
258
+ /// When a request is delivered. A request without a trigger is delivered at once.
259
+ open class UNNotificationTrigger: NSObject, @unchecked Sendable {
260
+ public let repeats: Bool
261
+
262
+ init(repeats: Bool) {
263
+ self.repeats = repeats
264
+ super.init()
265
+ }
266
+
267
+ /// The first delivery after `date` (the scheduling uses this; the
268
+ /// subclasses' `nextTriggerDate()` asks it about now).
269
+ func nextFireDate(after date: Date) -> Date? { nil }
270
+ }
271
+
272
+ /// Fires `timeInterval` seconds after the request is added, and every
273
+ /// `timeInterval` seconds after that when it repeats.
274
+ public final class UNTimeIntervalNotificationTrigger: UNNotificationTrigger, @unchecked Sendable {
275
+ public let timeInterval: TimeInterval
276
+
277
+ /// As on iOS, the interval must be positive, and at least 60 seconds when
278
+ /// the trigger repeats.
279
+ public init(timeInterval: TimeInterval, repeats: Bool) {
280
+ precondition(timeInterval > 0, "time interval must be greater than 0")
281
+ precondition(!repeats || timeInterval >= 60, "time interval must be at least 60 if repeating")
282
+ self.timeInterval = timeInterval
283
+ super.init(repeats: repeats)
284
+ }
285
+
286
+ public func nextTriggerDate() -> Date? { nextFireDate(after: Date()) }
287
+
288
+ override func nextFireDate(after date: Date) -> Date? { date.addingTimeInterval(timeInterval) }
289
+ }
290
+
291
+ /// Fires at the next date matching `dateComponents` (in their calendar and
292
+ /// time zone, else the current ones), and at each match after that when it
293
+ /// repeats: `hour = 9` is every day at 9:00, `weekday = 2, hour = 9` every
294
+ /// Monday.
295
+ public final class UNCalendarNotificationTrigger: UNNotificationTrigger, @unchecked Sendable {
296
+ public let dateComponents: DateComponents
297
+
298
+ public init(dateMatching dateComponents: DateComponents, repeats: Bool) {
299
+ self.dateComponents = dateComponents
300
+ super.init(repeats: repeats)
301
+ }
302
+
303
+ public func nextTriggerDate() -> Date? { nextFireDate(after: Date()) }
304
+
305
+ override func nextFireDate(after date: Date) -> Date? {
306
+ var calendar = dateComponents.calendar ?? Calendar.current
307
+ if let timeZone = dateComponents.timeZone { calendar.timeZone = timeZone }
308
+ var matching = dateComponents
309
+ matching.calendar = nil
310
+ matching.timeZone = nil
311
+ return calendar.nextDate(after: date, matching: matching, matchingPolicy: .nextTime)
312
+ }
313
+ }
314
+
315
+ // MARK: Requests
316
+
317
+ public final class UNNotificationRequest: NSObject, @unchecked Sendable {
318
+ public let identifier: String
319
+ public let content: UNNotificationContent
320
+ public let trigger: UNNotificationTrigger?
321
+
322
+ /// `content` is copied, as on iOS: changing it afterwards changes nothing.
323
+ public init(identifier: String, content: UNNotificationContent, trigger: UNNotificationTrigger?) {
324
+ self.identifier = identifier
325
+ self.content = content.copy() as! UNNotificationContent
326
+ self.trigger = trigger
327
+ super.init()
328
+ }
329
+ }
330
+
331
+ /// A delivered notification.
332
+ public final class UNNotification: NSObject, @unchecked Sendable {
333
+ public let date: Date
334
+ public let request: UNNotificationRequest
335
+
336
+ init(date: Date, request: UNNotificationRequest) {
337
+ self.date = date
338
+ self.request = request
339
+ super.init()
340
+ }
341
+ }
342
+
343
+ /// How to present a notification while the app is open, as a delegate's
344
+ /// `willPresent` answers.
345
+ public struct UNNotificationPresentationOptions: OptionSet, Sendable, Hashable {
346
+ public let rawValue: UInt
347
+ public init(rawValue: UInt) { self.rawValue = rawValue }
348
+
349
+ public static let badge = UNNotificationPresentationOptions(rawValue: 1 << 0)
350
+ public static let sound = UNNotificationPresentationOptions(rawValue: 1 << 1)
351
+ public static let alert = UNNotificationPresentationOptions(rawValue: 1 << 2)
352
+ public static let list = UNNotificationPresentationOptions(rawValue: 1 << 3)
353
+ public static let banner = UNNotificationPresentationOptions(rawValue: 1 << 4)
354
+ }
355
+
356
+ /// The viewer's answer to a notification. The browser never reports one (a
357
+ /// click on a notification focuses the page), so `didReceive` is not called.
358
+ public final class UNNotificationResponse: NSObject, @unchecked Sendable {
359
+ public let notification: UNNotification
360
+ public let actionIdentifier: String
361
+
362
+ init(notification: UNNotification, actionIdentifier: String) {
363
+ self.notification = notification
364
+ self.actionIdentifier = actionIdentifier
365
+ super.init()
366
+ }
367
+ }
368
+
369
+ public let UNNotificationDefaultActionIdentifier = "com.apple.UNNotificationDefaultActionIdentifier"
370
+ public let UNNotificationDismissActionIdentifier = "com.apple.UNNotificationDismissActionIdentifier"
@@ -0,0 +1,309 @@
1
+ // UserNotifications over the browser's Notification API. The center keeps
2
+ // the pending requests and schedules each with a timer of its own (the
3
+ // executor's, which the page drives with `setTimeout`); when one fires, the
4
+ // page shows it with `new Notification(…)`. Permission is the page's
5
+ // `Notification.permission`, asked for with `Notification.requestPermission()`.
6
+ //
7
+ // Every exchange with the page is a host request of kind `notification`
8
+ // (docs/ops-protocol.md, "Notifications"). Timers only run while the page is
9
+ // open: a notification scheduled for tomorrow is shown only if the app is
10
+ // still open tomorrow (in a background tab, a few seconds late at most).
11
+ // Headless runs answer deterministically: permission is "default" until the
12
+ // app asks, then "granted", and deliveries happen on the virtual clock.
13
+
14
+ import Foundation
15
+ import SwiftUI
16
+
17
+ public protocol UNUserNotificationCenterDelegate: AnyObject {
18
+ /// Asked before a notification is shown while the app is open. In the
19
+ /// browser the app is open whenever a notification can fire, so a center
20
+ /// without a delegate shows every notification (iOS would show none).
21
+ func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification,
22
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
23
+ func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions
24
+ /// Never called in the browser: the page gets no answer from a notification.
25
+ func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse,
26
+ withCompletionHandler completionHandler: @escaping () -> Void)
27
+ func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async
28
+ func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?)
29
+ }
30
+
31
+ extension UNUserNotificationCenterDelegate {
32
+ public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification,
33
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
34
+ completionHandler(UNUserNotificationCenter.showEverything)
35
+ }
36
+
37
+ public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
38
+ await withCheckedContinuation { continuation in
39
+ userNotificationCenter(center, willPresent: notification) { continuation.resume(returning: $0) }
40
+ }
41
+ }
42
+
43
+ public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse,
44
+ withCompletionHandler completionHandler: @escaping () -> Void) {
45
+ completionHandler()
46
+ }
47
+
48
+ public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {}
49
+
50
+ public func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) {}
51
+ }
52
+
53
+ open class UNUserNotificationCenter: NSObject, @unchecked Sendable {
54
+ /// Sends one `notification` request to the page; `headless` is the answer
55
+ /// a headless run gives instead. Tests substitute it.
56
+ typealias Transport = @MainActor @Sendable (_ params: _JSON, _ headless: _JSON) async throws -> _JSON
57
+
58
+ private static let shared = UNUserNotificationCenter(transport: { params, headless in
59
+ try await _Runtime.shared._hostRequest(kind: "notification", params: params, headless: headless)
60
+ })
61
+
62
+ /// The app's notification center.
63
+ open class func current() -> UNUserNotificationCenter { shared }
64
+
65
+ weak open var delegate: (any UNUserNotificationCenterDelegate)?
66
+
67
+ open var supportsContentExtensions: Bool { false }
68
+
69
+ static let showEverything: UNNotificationPresentationOptions = [.banner, .list, .sound, .badge]
70
+
71
+ /// Timers sleep at most a day at a time: the page's `setTimeout` cannot
72
+ /// wait longer than 24.8 days.
73
+ static let longestSleep: TimeInterval = 86_400
74
+
75
+ private struct Scheduled {
76
+ let request: UNNotificationRequest
77
+ /// Nil when the trigger never matches again; the request stays pending, as on iOS.
78
+ let fireDate: Date?
79
+ let token: Int
80
+ let timer: Task<Void, Never>?
81
+ }
82
+
83
+ private let transport: Transport
84
+ private let lock = NSLock()
85
+ private var pending: [Scheduled] = []
86
+ private var delivered: [UNNotification] = []
87
+ private var nextToken = 1
88
+ /// The last permission the page reported, and what a headless run answers.
89
+ private var knownPermission = "default"
90
+
91
+ init(transport: @escaping Transport) {
92
+ self.transport = transport
93
+ super.init()
94
+ }
95
+
96
+ // MARK: Authorization
97
+
98
+ open func requestAuthorization(options: UNAuthorizationOptions = [],
99
+ completionHandler: @escaping @Sendable (Bool, (any Error)?) -> Void) {
100
+ Task { @MainActor in
101
+ do {
102
+ completionHandler(try await self.requestAuthorization(options: options), nil)
103
+ } catch {
104
+ completionHandler(false, error)
105
+ }
106
+ }
107
+ }
108
+
109
+ /// Asks the page for permission (`Notification.requestPermission()`):
110
+ /// `true` when granted. Without a Notification API it throws
111
+ /// `UNError(.notificationsNotAllowed)`.
112
+ open func requestAuthorization(options: UNAuthorizationOptions = []) async throws -> Bool {
113
+ let permission = await askPermission(action: "request")
114
+ if permission == "unsupported" { throw UNError(.notificationsNotAllowed) }
115
+ return permission == "granted"
116
+ }
117
+
118
+ open func getNotificationSettings(completionHandler: @escaping @Sendable (UNNotificationSettings) -> Void) {
119
+ Task { @MainActor in completionHandler(await self.notificationSettings()) }
120
+ }
121
+
122
+ open func notificationSettings() async -> UNNotificationSettings {
123
+ UNNotificationSettings(authorizationStatus: Self.status(of: await askPermission(action: "status")))
124
+ }
125
+
126
+ static func status(of permission: String) -> UNAuthorizationStatus {
127
+ switch permission {
128
+ case "granted": .authorized
129
+ case "default": .notDetermined
130
+ default: .denied
131
+ }
132
+ }
133
+
134
+ /// `status` reads `Notification.permission`; `request` asks the viewer.
135
+ @MainActor private func askPermission(action: String) async -> String {
136
+ let headless = action == "request" ? "granted" : lock.withLock { knownPermission }
137
+ let answer = try? await transport(.object(["action": .string(action)]), .object(["permission": .string(headless)]))
138
+ guard case .object(let fields)? = answer, case .string(let permission)? = fields["permission"] else { return "unsupported" }
139
+ lock.withLock { knownPermission = permission }
140
+ return permission
141
+ }
142
+
143
+ // MARK: Scheduling
144
+
145
+ /// Schedules the request, replacing a pending one with the same identifier.
146
+ /// Delivered when its trigger fires, at once without one, if the page is
147
+ /// still open then.
148
+ open func add(_ request: UNNotificationRequest, withCompletionHandler completionHandler: (@Sendable ((any Error)?) -> Void)? = nil) {
149
+ schedule(request, now: Date())
150
+ if let completionHandler { Task { @MainActor in completionHandler(nil) } }
151
+ }
152
+
153
+ open func add(_ request: UNNotificationRequest) async throws {
154
+ schedule(request, now: Date())
155
+ }
156
+
157
+ open func getPendingNotificationRequests(completionHandler: @escaping @Sendable ([UNNotificationRequest]) -> Void) {
158
+ let requests = pendingNotificationRequestsNow()
159
+ Task { @MainActor in completionHandler(requests) }
160
+ }
161
+
162
+ open func pendingNotificationRequests() async -> [UNNotificationRequest] {
163
+ pendingNotificationRequestsNow()
164
+ }
165
+
166
+ open func removePendingNotificationRequests(withIdentifiers identifiers: [String]) {
167
+ let removed: [Scheduled] = lock.withLock {
168
+ let removed = pending.filter { identifiers.contains($0.request.identifier) }
169
+ pending.removeAll { identifiers.contains($0.request.identifier) }
170
+ return removed
171
+ }
172
+ for entry in removed { entry.timer?.cancel() }
173
+ }
174
+
175
+ open func removeAllPendingNotificationRequests() {
176
+ let removed: [Scheduled] = lock.withLock {
177
+ defer { pending.removeAll() }
178
+ return pending
179
+ }
180
+ for entry in removed { entry.timer?.cancel() }
181
+ }
182
+
183
+ /// When each pending request fires next (nil: never), for tests.
184
+ func pendingFireDates() -> [String: Date?] {
185
+ lock.withLock { Dictionary(pending.map { ($0.request.identifier, $0.fireDate) }, uniquingKeysWith: { _, last in last }) }
186
+ }
187
+
188
+ private func pendingNotificationRequestsNow() -> [UNNotificationRequest] {
189
+ lock.withLock { pending.map(\.request) }
190
+ }
191
+
192
+ private func schedule(_ request: UNNotificationRequest, now: Date) {
193
+ let fireDate: Date? = request.trigger.map { $0.nextFireDate(after: now) } ?? now
194
+ let replaced: Scheduled? = lock.withLock {
195
+ let token = nextToken
196
+ nextToken += 1
197
+ let old = pending.first { $0.request.identifier == request.identifier }
198
+ pending.removeAll { $0.request.identifier == request.identifier }
199
+ let timer = fireDate.map { startTimer(identifier: request.identifier, token: token, delay: $0.timeIntervalSince(now)) }
200
+ pending.append(Scheduled(request: request, fireDate: fireDate, token: token, timer: timer))
201
+ return old
202
+ }
203
+ replaced?.timer?.cancel()
204
+ }
205
+
206
+ private func startTimer(identifier: String, token: Int, delay: TimeInterval) -> Task<Void, Never> {
207
+ Task { @MainActor [weak self] in
208
+ var remaining = max(0, delay)
209
+ repeat {
210
+ let step = min(remaining, Self.longestSleep)
211
+ do { try await Task.sleep(for: .milliseconds(Int64((step * 1000).rounded()))) } catch { return }
212
+ remaining -= step
213
+ } while remaining > 0
214
+ await self?.fire(identifier: identifier, token: token)
215
+ }
216
+ }
217
+
218
+ /// Delivers a pending request whose timer ran out (unless it was removed
219
+ /// or replaced meanwhile), and schedules its next delivery if it repeats.
220
+ @MainActor private func fire(identifier: String, token: Int) async {
221
+ let now = Date()
222
+ let notification: UNNotification? = lock.withLock {
223
+ guard let index = pending.firstIndex(where: { $0.request.identifier == identifier && $0.token == token }) else { return nil }
224
+ let entry = pending.remove(at: index)
225
+ let notification = UNNotification(date: now, request: entry.request)
226
+ delivered.removeAll { $0.request.identifier == identifier }
227
+ delivered.append(notification)
228
+ if let trigger = entry.request.trigger, trigger.repeats {
229
+ // After the date it was due, not just now: a timer may run a
230
+ // few milliseconds early, and the same match must not fire twice.
231
+ let after = max(now, entry.fireDate ?? now)
232
+ let next = trigger.nextFireDate(after: after)
233
+ let nextToken = self.nextToken
234
+ self.nextToken += 1
235
+ let timer = next.map { startTimer(identifier: identifier, token: nextToken, delay: $0.timeIntervalSince(now)) }
236
+ pending.insert(Scheduled(request: entry.request, fireDate: next, token: nextToken, timer: timer), at: index)
237
+ }
238
+ return notification
239
+ }
240
+ guard let notification else { return }
241
+ var options = Self.showEverything
242
+ if let delegate { options = await delegate.userNotificationCenter(self, willPresent: notification) }
243
+ await present(notification, options: options)
244
+ }
245
+
246
+ @MainActor private func present(_ notification: UNNotification, options: UNNotificationPresentationOptions) async {
247
+ let content = notification.request.content
248
+ var params: [String: _JSON] = ["action": .string("show"), "id": .string(notification.request.identifier)]
249
+ if !options.isDisjoint(with: [.banner, .alert, .list]) {
250
+ params["title"] = .string(content.title)
251
+ params["subtitle"] = .string(content.subtitle)
252
+ params["body"] = .string(content.body)
253
+ params["silent"] = .bool(content.sound == nil || !options.contains(.sound))
254
+ }
255
+ if options.contains(.badge), let badge = content.badge { params["badge"] = .number(badge.doubleValue) }
256
+ guard params["title"] != nil || params["badge"] != nil else { return }
257
+ let granted = lock.withLock { knownPermission } == "granted"
258
+ _ = try? await transport(.object(params), .object(["shown": .bool(granted)]))
259
+ }
260
+
261
+ // MARK: Delivered notifications and the badge
262
+
263
+ open func getDeliveredNotifications(completionHandler: @escaping @Sendable ([UNNotification]) -> Void) {
264
+ let notifications = lock.withLock { delivered }
265
+ Task { @MainActor in completionHandler(notifications) }
266
+ }
267
+
268
+ open func deliveredNotifications() async -> [UNNotification] {
269
+ lock.withLock { delivered }
270
+ }
271
+
272
+ /// Closes the browser notifications still on screen for these identifiers.
273
+ open func removeDeliveredNotifications(withIdentifiers identifiers: [String]) {
274
+ let removed: [String] = lock.withLock {
275
+ let ids = delivered.map(\.request.identifier).filter { identifiers.contains($0) }
276
+ delivered.removeAll { identifiers.contains($0.request.identifier) }
277
+ return ids
278
+ }
279
+ close(removed)
280
+ }
281
+
282
+ open func removeAllDeliveredNotifications() {
283
+ let removed: [String] = lock.withLock {
284
+ defer { delivered.removeAll() }
285
+ return delivered.map(\.request.identifier)
286
+ }
287
+ close(removed)
288
+ }
289
+
290
+ private func close(_ identifiers: [String]) {
291
+ guard !identifiers.isEmpty else { return }
292
+ let transport = self.transport
293
+ Task { @MainActor in
294
+ _ = try? await transport(.object(["action": .string("close"), "ids": .array(identifiers.map { .string($0) })]), .object([:]))
295
+ }
296
+ }
297
+
298
+ /// The app badge (`navigator.setAppBadge`; 0 clears it), where the browser has one.
299
+ open func setBadgeCount(_ newBadgeCount: Int, withCompletionHandler completionHandler: (@Sendable ((any Error)?) -> Void)? = nil) {
300
+ Task { @MainActor in
301
+ try? await self.setBadgeCount(newBadgeCount)
302
+ completionHandler?(nil)
303
+ }
304
+ }
305
+
306
+ open func setBadgeCount(_ newBadgeCount: Int) async throws {
307
+ _ = try? await transport(.object(["action": .string("badge"), "badge": .number(Double(newBadgeCount))]), .object([:]))
308
+ }
309
+ }