vrchatapi-async 1.20.8.dev1__tar.gz → 1.20.8.dev2__tar.gz

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 (371) hide show
  1. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/PKG-INFO +47 -1
  2. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/README.md +46 -0
  3. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/setup.py +93 -1
  4. vrchatapi_async-1.20.8.dev2/tests/test_websocket.py +450 -0
  5. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/__init__.py +1 -1
  6. vrchatapi_async-1.20.8.dev2/vrchatapi/websocket.py +650 -0
  7. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi_async.egg-info/PKG-INFO +47 -1
  8. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi_async.egg-info/SOURCES.txt +2 -0
  9. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/LICENSE +0 -0
  10. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/pyproject.toml +0 -0
  11. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/setup.cfg +0 -0
  12. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/tests/test_async_sdk.py +0 -0
  13. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/__init__.py +0 -0
  14. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/authentication_api.py +0 -0
  15. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/avatars_api.py +0 -0
  16. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/calendar_api.py +0 -0
  17. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/economy_api.py +0 -0
  18. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/favorites_api.py +0 -0
  19. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/files_api.py +0 -0
  20. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/friends_api.py +0 -0
  21. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/groups_api.py +0 -0
  22. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/instances_api.py +0 -0
  23. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/inventory_api.py +0 -0
  24. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/invite_api.py +0 -0
  25. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/jams_api.py +0 -0
  26. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/miscellaneous_api.py +0 -0
  27. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/notifications_api.py +0 -0
  28. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/playermoderation_api.py +0 -0
  29. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/prints_api.py +0 -0
  30. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/props_api.py +0 -0
  31. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/users_api.py +0 -0
  32. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api/worlds_api.py +0 -0
  33. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api_client.py +0 -0
  34. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/api_response.py +0 -0
  35. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/configuration.py +0 -0
  36. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/exceptions.py +0 -0
  37. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/__init__.py +0 -0
  38. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/account_deletion_log.py +0 -0
  39. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/add_favorite_request.py +0 -0
  40. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/add_group_gallery_image_request.py +0 -0
  41. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/admin_asset_bundle.py +0 -0
  42. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/admin_unity_package.py +0 -0
  43. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/age_verification_status.py +0 -0
  44. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/agreement.py +0 -0
  45. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/agreement_code.py +0 -0
  46. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/agreement_request.py +0 -0
  47. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/agreement_status.py +0 -0
  48. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config.py +0 -0
  49. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_access_logs_urls.py +0 -0
  50. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_announcement.py +0 -0
  51. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_audio_config.py +0 -0
  52. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_avatar_perf_limiter.py +0 -0
  53. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_constants.py +0 -0
  54. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_constants_groups.py +0 -0
  55. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_constants_instance.py +0 -0
  56. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_constants_instancepopulationbrackets.py +0 -0
  57. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_constants_instancepopulationbracketscrowded.py +0 -0
  58. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_constants_instancepopulationbracketsfew.py +0 -0
  59. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_constants_instancepopulationbracketsmany.py +0 -0
  60. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_constants_language.py +0 -0
  61. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_download_url_list.py +0 -0
  62. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_events.py +0 -0
  63. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_ios_version.py +0 -0
  64. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_min_supported_client_build_number.py +0 -0
  65. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_config_offline_analysis.py +0 -0
  66. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/api_health.py +0 -0
  67. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/avatar.py +0 -0
  68. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/avatar_moderation.py +0 -0
  69. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/avatar_moderation_created.py +0 -0
  70. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/avatar_moderation_type.py +0 -0
  71. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/avatar_performance.py +0 -0
  72. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/avatar_published_listings_inner.py +0 -0
  73. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/avatar_style.py +0 -0
  74. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/avatar_styles.py +0 -0
  75. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/avatar_unity_package_url_object.py +0 -0
  76. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/badge.py +0 -0
  77. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/balance.py +0 -0
  78. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/ban_group_member_request.py +0 -0
  79. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/boop_request.py +0 -0
  80. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_day_of_week.py +0 -0
  81. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event.py +0 -0
  82. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_access.py +0 -0
  83. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_category.py +0 -0
  84. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_discovery.py +0 -0
  85. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_discovery_inclusion.py +0 -0
  86. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_discovery_scope.py +0 -0
  87. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_frequency.py +0 -0
  88. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_occurrence_kind.py +0 -0
  89. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_platform.py +0 -0
  90. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_recurrence.py +0 -0
  91. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_recurrence_end.py +0 -0
  92. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_recurrence_end_type.py +0 -0
  93. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/calendar_event_user_interest.py +0 -0
  94. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/change_user_tags_request.py +0 -0
  95. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/change_world_tags_request.py +0 -0
  96. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/content_filter.py +0 -0
  97. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_avatar_moderation_request.py +0 -0
  98. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_avatar_request.py +0 -0
  99. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_calendar_event_request.py +0 -0
  100. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_file_request.py +0 -0
  101. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_file_version_request.py +0 -0
  102. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_group_announcement_request.py +0 -0
  103. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_group_gallery_request.py +0 -0
  104. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_group_invite_request.py +0 -0
  105. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_group_post_request.py +0 -0
  106. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_group_request.py +0 -0
  107. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_group_role_request.py +0 -0
  108. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_instance_request.py +0 -0
  109. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_jam_submission_request.py +0 -0
  110. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_listing_request.py +0 -0
  111. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_product_request.py +0 -0
  112. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_prop_request.py +0 -0
  113. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/create_world_request.py +0 -0
  114. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/current_user.py +0 -0
  115. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/current_user_platform_history_inner.py +0 -0
  116. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/current_user_presence.py +0 -0
  117. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/decline_group_invite_request.py +0 -0
  118. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/developer_type.py +0 -0
  119. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/disable2_fa_result.py +0 -0
  120. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/discord_details.py +0 -0
  121. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/dynamic_content_row.py +0 -0
  122. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/earnings_metrics.py +0 -0
  123. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/earnings_metrics_totals.py +0 -0
  124. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/economy_account.py +0 -0
  125. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/economy_balances.py +0 -0
  126. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/economy_payout.py +0 -0
  127. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/economy_payout_eligibility.py +0 -0
  128. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/economy_payout_list.py +0 -0
  129. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/economy_payout_status.py +0 -0
  130. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/equip_inventory_item_request.py +0 -0
  131. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/error.py +0 -0
  132. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/favorite.py +0 -0
  133. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/favorite_group.py +0 -0
  134. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/favorite_group_limits.py +0 -0
  135. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/favorite_group_visibility.py +0 -0
  136. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/favorite_limits.py +0 -0
  137. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/favorite_type.py +0 -0
  138. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/favorited_world.py +0 -0
  139. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/feedback.py +0 -0
  140. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/file.py +0 -0
  141. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/file_analysis.py +0 -0
  142. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/file_analysis_avatar_stats.py +0 -0
  143. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/file_data.py +0 -0
  144. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/file_status.py +0 -0
  145. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/file_upload_url.py +0 -0
  146. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/file_version.py +0 -0
  147. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/file_version_upload_status.py +0 -0
  148. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/finish_file_data_upload_request.py +0 -0
  149. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/follow_calendar_event_request.py +0 -0
  150. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/friend_status.py +0 -0
  151. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/get_group_posts200_response.py +0 -0
  152. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/get_user_group_instances200_response.py +0 -0
  153. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group.py +0 -0
  154. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_access_type.py +0 -0
  155. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_announcement.py +0 -0
  156. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_audit_log_entry.py +0 -0
  157. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_gallery.py +0 -0
  158. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_gallery_file_order.py +0 -0
  159. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_gallery_file_order_request.py +0 -0
  160. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_gallery_image.py +0 -0
  161. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_instance.py +0 -0
  162. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_join_request_action.py +0 -0
  163. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_join_state.py +0 -0
  164. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_member.py +0 -0
  165. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_member_limited_user.py +0 -0
  166. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_member_status.py +0 -0
  167. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_my_member.py +0 -0
  168. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_permission.py +0 -0
  169. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_permissions.py +0 -0
  170. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_post.py +0 -0
  171. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_post_visibility.py +0 -0
  172. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_privacy.py +0 -0
  173. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_role.py +0 -0
  174. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_role_template.py +0 -0
  175. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_role_template_values.py +0 -0
  176. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_role_template_values_roles.py +0 -0
  177. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_search_sort.py +0 -0
  178. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_transferable.py +0 -0
  179. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_transferable_requirements.py +0 -0
  180. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/group_user_visibility.py +0 -0
  181. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/image_animation_style.py +0 -0
  182. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/image_loop_style.py +0 -0
  183. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/image_mask.py +0 -0
  184. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/image_purpose.py +0 -0
  185. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/info_push.py +0 -0
  186. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/info_push_data.py +0 -0
  187. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/info_push_data_article.py +0 -0
  188. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/info_push_data_article_content.py +0 -0
  189. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/info_push_data_clickable.py +0 -0
  190. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/instance.py +0 -0
  191. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/instance_content_settings.py +0 -0
  192. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/instance_platforms.py +0 -0
  193. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/instance_region.py +0 -0
  194. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/instance_short_name_response.py +0 -0
  195. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/instance_type.py +0 -0
  196. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory.py +0 -0
  197. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_consumption_results.py +0 -0
  198. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_default_attributes_value.py +0 -0
  199. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_default_attributes_value_validator.py +0 -0
  200. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_drop.py +0 -0
  201. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_equip_slot.py +0 -0
  202. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_flag.py +0 -0
  203. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_item.py +0 -0
  204. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_item_type.py +0 -0
  205. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_metadata.py +0 -0
  206. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_notification_details.py +0 -0
  207. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_spawn.py +0 -0
  208. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_template.py +0 -0
  209. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/inventory_user_attributes.py +0 -0
  210. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/invite_message.py +0 -0
  211. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/invite_message_type.py +0 -0
  212. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/invite_request.py +0 -0
  213. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/invite_response.py +0 -0
  214. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/jam.py +0 -0
  215. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/jam_state_change_dates.py +0 -0
  216. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/jam_submission.py +0 -0
  217. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/join_group_request.py +0 -0
  218. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/license.py +0 -0
  219. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/license_action.py +0 -0
  220. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/license_group.py +0 -0
  221. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/license_type.py +0 -0
  222. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/limited_group.py +0 -0
  223. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/limited_unity_package.py +0 -0
  224. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/limited_user_friend.py +0 -0
  225. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/limited_user_groups.py +0 -0
  226. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/limited_user_instance.py +0 -0
  227. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/limited_user_search.py +0 -0
  228. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/limited_world.py +0 -0
  229. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/mime_type.py +0 -0
  230. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/model_print.py +0 -0
  231. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/moderate_user_request.py +0 -0
  232. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/moderation_report.py +0 -0
  233. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/mutual_friend.py +0 -0
  234. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/mutuals.py +0 -0
  235. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification.py +0 -0
  236. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_detail_invite.py +0 -0
  237. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_detail_invite_response.py +0 -0
  238. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_detail_request_invite.py +0 -0
  239. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_detail_request_invite_response.py +0 -0
  240. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_detail_vote_to_kick.py +0 -0
  241. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_type.py +0 -0
  242. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_v2.py +0 -0
  243. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_v2_details_boop.py +0 -0
  244. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_v2_response.py +0 -0
  245. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/notification_v2_type.py +0 -0
  246. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/ok_status.py +0 -0
  247. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/ok_status2.py +0 -0
  248. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/order_option.py +0 -0
  249. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/order_option_short.py +0 -0
  250. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/paginated_calendar_event_list.py +0 -0
  251. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/paginated_group_audit_log_entry_list.py +0 -0
  252. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/paginated_moderation_report_list.py +0 -0
  253. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/past_display_name.py +0 -0
  254. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/pending2_fa_result.py +0 -0
  255. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/performance_limiter_info.py +0 -0
  256. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/performance_ratings.py +0 -0
  257. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/permission.py +0 -0
  258. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/permission_data.py +0 -0
  259. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/platform_build_info.py +0 -0
  260. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/player_moderation.py +0 -0
  261. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/player_moderation_type.py +0 -0
  262. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/print_files.py +0 -0
  263. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/private_profile.py +0 -0
  264. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/private_profile_activity.py +0 -0
  265. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product.py +0 -0
  266. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_listing.py +0 -0
  267. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_listing_type.py +0 -0
  268. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_listing_variant.py +0 -0
  269. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_purchase.py +0 -0
  270. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_purchase_history.py +0 -0
  271. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_purchase_location_type.py +0 -0
  272. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_purchase_product.py +0 -0
  273. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_purchase_purchase_context.py +0 -0
  274. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_purchase_record.py +0 -0
  275. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/product_type.py +0 -0
  276. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/profile_represented_group.py +0 -0
  277. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/prop.py +0 -0
  278. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/prop_publish_status.py +0 -0
  279. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/prop_unity_package.py +0 -0
  280. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/public_profile.py +0 -0
  281. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/purchase_context_data.py +0 -0
  282. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/purchase_product_listing_request.py +0 -0
  283. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/region.py +0 -0
  284. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/register_user_account_request.py +0 -0
  285. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/release_status.py +0 -0
  286. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/report_category.py +0 -0
  287. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/report_reason.py +0 -0
  288. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/represented_group.py +0 -0
  289. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/request_invite_request.py +0 -0
  290. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/respond_group_join_request.py +0 -0
  291. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/respond_notification_v2_request.py +0 -0
  292. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/response.py +0 -0
  293. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/reward_badge.py +0 -0
  294. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/reward_redemption.py +0 -0
  295. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/reward_redemption_data.py +0 -0
  296. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/reward_redemption_request.py +0 -0
  297. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/reward_redemption_result.py +0 -0
  298. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/search_group_members200_response.py +0 -0
  299. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/seller_eligibility.py +0 -0
  300. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/sent_notification.py +0 -0
  301. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/service_queue_stats.py +0 -0
  302. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/service_status.py +0 -0
  303. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/share_inventory_item_direct_request.py +0 -0
  304. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/sort_option.py +0 -0
  305. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/sort_option_product_purchase.py +0 -0
  306. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/store.py +0 -0
  307. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/store_context.py +0 -0
  308. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/store_shelf.py +0 -0
  309. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/store_type.py +0 -0
  310. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/store_view.py +0 -0
  311. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/submit_moderation_report_request.py +0 -0
  312. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/submit_moderation_report_request_details.py +0 -0
  313. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/subscription.py +0 -0
  314. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/subscription_period.py +0 -0
  315. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/success.py +0 -0
  316. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/success_flag.py +0 -0
  317. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/tilia_kyc.py +0 -0
  318. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/tilia_status.py +0 -0
  319. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/tilia_tos.py +0 -0
  320. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/token_bundle.py +0 -0
  321. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/transaction.py +0 -0
  322. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/transaction_agreement.py +0 -0
  323. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/transaction_status.py +0 -0
  324. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/transaction_steam_info.py +0 -0
  325. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/transaction_steam_wallet_info.py +0 -0
  326. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/transfer_group_request.py +0 -0
  327. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/tutorial_status.py +0 -0
  328. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/two_factor_auth_code.py +0 -0
  329. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/two_factor_email_code.py +0 -0
  330. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/two_factor_recovery_codes.py +0 -0
  331. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/two_factor_recovery_codes_otp_inner.py +0 -0
  332. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/unity_package.py +0 -0
  333. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_asset_review_notes_request.py +0 -0
  334. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_avatar_request.py +0 -0
  335. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_calendar_event_request.py +0 -0
  336. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_favorite_group_request.py +0 -0
  337. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_group_gallery_request.py +0 -0
  338. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_group_member_request.py +0 -0
  339. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_group_representation_request.py +0 -0
  340. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_group_request.py +0 -0
  341. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_group_role_request.py +0 -0
  342. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_inventory_item_request.py +0 -0
  343. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_invite_message_request.py +0 -0
  344. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_listing_request.py +0 -0
  345. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_product_request.py +0 -0
  346. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_prop_request.py +0 -0
  347. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_tilia_tos_request.py +0 -0
  348. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_user_badge_request.py +0 -0
  349. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_user_note_request.py +0 -0
  350. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_user_request.py +0 -0
  351. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/update_world_request.py +0 -0
  352. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/user.py +0 -0
  353. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/user_credits_eligible.py +0 -0
  354. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/user_exists.py +0 -0
  355. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/user_note.py +0 -0
  356. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/user_note_target_user.py +0 -0
  357. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/user_state.py +0 -0
  358. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/user_status.py +0 -0
  359. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/user_subscription.py +0 -0
  360. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/user_subscription_eligible.py +0 -0
  361. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/verify2_fa_email_code_result.py +0 -0
  362. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/verify2_fa_result.py +0 -0
  363. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/verify_auth_token_result.py +0 -0
  364. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/world.py +0 -0
  365. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/world_metadata.py +0 -0
  366. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/models/world_publish_status.py +0 -0
  367. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/py.typed +0 -0
  368. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi/rest.py +0 -0
  369. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi_async.egg-info/dependency_links.txt +0 -0
  370. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi_async.egg-info/requires.txt +0 -0
  371. {vrchatapi_async-1.20.8.dev1 → vrchatapi_async-1.20.8.dev2}/vrchatapi_async.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vrchatapi-async
3
- Version: 1.20.8.dev1
3
+ Version: 1.20.8.dev2
4
4
  Summary: VRChat API Library for Python (async version)
5
5
  Home-page: https://github.com/hi94740/vrchatapi-python-async
6
6
  Author: hi94740
@@ -134,4 +134,50 @@ Compared to [the synchronous SDK](https://github.com/vrchatapi/vrchatapi-python)
134
134
  ## Contributing
135
135
 
136
136
  Contributions are welcome, but do not add features that should be handled by the OpenAPI specification.
137
+
138
+ ## Websocket (Pipeline) API
139
+
140
+ The SDK also ships a hand-written async client for VRChat's real-time
141
+ WebSocket (Pipeline) API (`wss://pipeline.vrchat.cloud`), which pushes invites,
142
+ friend requests, friend online/offline events, user and group updates to the
143
+ authenticated client. The connection is receive-only; every message's
144
+ double-encoded `content` field is automatically unpacked into a plain dict.
145
+
146
+ ```python
147
+ import asyncio
148
+
149
+ import vrchatapi
150
+ from vrchatapi.api import authentication_api
151
+ from vrchatapi.websocket import VRChatWebSocket
152
+
153
+
154
+ async def main():
155
+ configuration = vrchatapi.Configuration(username="username", password="password")
156
+ async with vrchatapi.ApiClient(configuration) as api_client:
157
+ api_client.user_agent = "ExampleProgram/0.0.1 my@email.com"
158
+ await authentication_api.AuthenticationApi(api_client).get_current_user()
159
+
160
+ # Reads the auth cookie + User-Agent from the logged-in client.
161
+ ws = VRChatWebSocket.from_client(api_client)
162
+
163
+ @ws.on("friend-online")
164
+ async def on_friend_online(event):
165
+ print("online:", event.content["user"]["displayName"])
166
+
167
+ # Or consume the same stream as an async iterator:
168
+ # async for event in ws:
169
+ # print(event.type, event.content)
170
+
171
+ await ws.run() # blocks; reconnects automatically by default
172
+ ```
173
+
174
+ `VRChatWebSocket` supports callback registration (`ws.on("friend-online", ...)`
175
+ / `@ws.on(...)`, a catch-all `ws.on_event(...)`), an async iterator over the
176
+ same event stream, error/connect/disconnect/reconnect hooks, automatic
177
+ reconnection with exponential backoff (`auto_reconnect=False` disables it), and
178
+ a configurable application-level heartbeat (default 30s;
179
+ `heartbeat_interval=None` disables it). See
180
+ [examples/examples-source/websocket.py](examples/examples-source/websocket.py)
181
+ and the [Websocket API reference](https://vrchat.community/websocket) for
182
+ details.
137
183
 
@@ -103,3 +103,49 @@ Compared to [the synchronous SDK](https://github.com/vrchatapi/vrchatapi-python)
103
103
  ## Contributing
104
104
 
105
105
  Contributions are welcome, but do not add features that should be handled by the OpenAPI specification.
106
+
107
+ ## Websocket (Pipeline) API
108
+
109
+ The SDK also ships a hand-written async client for VRChat's real-time
110
+ WebSocket (Pipeline) API (`wss://pipeline.vrchat.cloud`), which pushes invites,
111
+ friend requests, friend online/offline events, user and group updates to the
112
+ authenticated client. The connection is receive-only; every message's
113
+ double-encoded `content` field is automatically unpacked into a plain dict.
114
+
115
+ ```python
116
+ import asyncio
117
+
118
+ import vrchatapi
119
+ from vrchatapi.api import authentication_api
120
+ from vrchatapi.websocket import VRChatWebSocket
121
+
122
+
123
+ async def main():
124
+ configuration = vrchatapi.Configuration(username="username", password="password")
125
+ async with vrchatapi.ApiClient(configuration) as api_client:
126
+ api_client.user_agent = "ExampleProgram/0.0.1 my@email.com"
127
+ await authentication_api.AuthenticationApi(api_client).get_current_user()
128
+
129
+ # Reads the auth cookie + User-Agent from the logged-in client.
130
+ ws = VRChatWebSocket.from_client(api_client)
131
+
132
+ @ws.on("friend-online")
133
+ async def on_friend_online(event):
134
+ print("online:", event.content["user"]["displayName"])
135
+
136
+ # Or consume the same stream as an async iterator:
137
+ # async for event in ws:
138
+ # print(event.type, event.content)
139
+
140
+ await ws.run() # blocks; reconnects automatically by default
141
+ ```
142
+
143
+ `VRChatWebSocket` supports callback registration (`ws.on("friend-online", ...)`
144
+ / `@ws.on(...)`, a catch-all `ws.on_event(...)`), an async iterator over the
145
+ same event stream, error/connect/disconnect/reconnect hooks, automatic
146
+ reconnection with exponential backoff (`auto_reconnect=False` disables it), and
147
+ a configurable application-level heartbeat (default 30s;
148
+ `heartbeat_interval=None` disables it). See
149
+ [examples/examples-source/websocket.py](examples/examples-source/websocket.py)
150
+ and the [Websocket API reference](https://vrchat.community/websocket) for
151
+ details.
@@ -107,6 +107,52 @@ Compared to [the synchronous SDK](https://github.com/vrchatapi/vrchatapi-python)
107
107
 
108
108
  Contributions are welcome, but do not add features that should be handled by the OpenAPI specification.
109
109
 
110
+ ## Websocket (Pipeline) API
111
+
112
+ The SDK also ships a hand-written async client for VRChat's real-time
113
+ WebSocket (Pipeline) API (`wss://pipeline.vrchat.cloud`), which pushes invites,
114
+ friend requests, friend online/offline events, user and group updates to the
115
+ authenticated client. The connection is receive-only; every message's
116
+ double-encoded `content` field is automatically unpacked into a plain dict.
117
+
118
+ ```python
119
+ import asyncio
120
+
121
+ import vrchatapi
122
+ from vrchatapi.api import authentication_api
123
+ from vrchatapi.websocket import VRChatWebSocket
124
+
125
+
126
+ async def main():
127
+ configuration = vrchatapi.Configuration(username="username", password="password")
128
+ async with vrchatapi.ApiClient(configuration) as api_client:
129
+ api_client.user_agent = "ExampleProgram/0.0.1 my@email.com"
130
+ await authentication_api.AuthenticationApi(api_client).get_current_user()
131
+
132
+ # Reads the auth cookie + User-Agent from the logged-in client.
133
+ ws = VRChatWebSocket.from_client(api_client)
134
+
135
+ @ws.on("friend-online")
136
+ async def on_friend_online(event):
137
+ print("online:", event.content["user"]["displayName"])
138
+
139
+ # Or consume the same stream as an async iterator:
140
+ # async for event in ws:
141
+ # print(event.type, event.content)
142
+
143
+ await ws.run() # blocks; reconnects automatically by default
144
+ ```
145
+
146
+ `VRChatWebSocket` supports callback registration (`ws.on("friend-online", ...)`
147
+ / `@ws.on(...)`, a catch-all `ws.on_event(...)`), an async iterator over the
148
+ same event stream, error/connect/disconnect/reconnect hooks, automatic
149
+ reconnection with exponential backoff (`auto_reconnect=False` disables it), and
150
+ a configurable application-level heartbeat (default 30s;
151
+ `heartbeat_interval=None` disables it). See
152
+ [examples/examples-source/websocket.py](examples/examples-source/websocket.py)
153
+ and the [Websocket API reference](https://vrchat.community/websocket) for
154
+ details.
155
+
110
156
  The version of the OpenAPI document: 1.20.8
111
157
  Contact: vrchatapi.lpv0t@aries.fyi
112
158
  Generated by OpenAPI Generator (https://openapi-generator.tech)
@@ -124,7 +170,7 @@ from setuptools import setup, find_packages # noqa: H301
124
170
  # prerequisite: setuptools
125
171
  # http://pypi.python.org/pypi/setuptools
126
172
  NAME = "vrchatapi-async"
127
- VERSION = "1.20.8dev1"
173
+ VERSION = "1.20.8dev2"
128
174
  PYTHON_REQUIRES = ">= 3.10"
129
175
  REQUIRES = [
130
176
  "python-dateutil >= 2.8.2",
@@ -254,6 +300,52 @@ Compared to [the synchronous SDK](https://github.com/vrchatapi/vrchatapi-python)
254
300
  ## Contributing
255
301
 
256
302
  Contributions are welcome, but do not add features that should be handled by the OpenAPI specification.
303
+
304
+ ## Websocket (Pipeline) API
305
+
306
+ The SDK also ships a hand-written async client for VRChat's real-time
307
+ WebSocket (Pipeline) API (`wss://pipeline.vrchat.cloud`), which pushes invites,
308
+ friend requests, friend online/offline events, user and group updates to the
309
+ authenticated client. The connection is receive-only; every message's
310
+ double-encoded `content` field is automatically unpacked into a plain dict.
311
+
312
+ ```python
313
+ import asyncio
314
+
315
+ import vrchatapi
316
+ from vrchatapi.api import authentication_api
317
+ from vrchatapi.websocket import VRChatWebSocket
318
+
319
+
320
+ async def main():
321
+ configuration = vrchatapi.Configuration(username="username", password="password")
322
+ async with vrchatapi.ApiClient(configuration) as api_client:
323
+ api_client.user_agent = "ExampleProgram/0.0.1 my@email.com"
324
+ await authentication_api.AuthenticationApi(api_client).get_current_user()
325
+
326
+ # Reads the auth cookie + User-Agent from the logged-in client.
327
+ ws = VRChatWebSocket.from_client(api_client)
328
+
329
+ @ws.on("friend-online")
330
+ async def on_friend_online(event):
331
+ print("online:", event.content["user"]["displayName"])
332
+
333
+ # Or consume the same stream as an async iterator:
334
+ # async for event in ws:
335
+ # print(event.type, event.content)
336
+
337
+ await ws.run() # blocks; reconnects automatically by default
338
+ ```
339
+
340
+ `VRChatWebSocket` supports callback registration (`ws.on("friend-online", ...)`
341
+ / `@ws.on(...)`, a catch-all `ws.on_event(...)`), an async iterator over the
342
+ same event stream, error/connect/disconnect/reconnect hooks, automatic
343
+ reconnection with exponential backoff (`auto_reconnect=False` disables it), and
344
+ a configurable application-level heartbeat (default 30s;
345
+ `heartbeat_interval=None` disables it). See
346
+ [examples/examples-source/websocket.py](examples/examples-source/websocket.py)
347
+ and the [Websocket API reference](https://vrchat.community/websocket) for
348
+ details.
257
349
  """, # noqa: E501
258
350
  package_data={"vrchatapi": ["py.typed"]},
259
351
  )
@@ -0,0 +1,450 @@
1
+ """Tests for the hand-written VRChat WebSocket (Pipeline) client.
2
+
3
+ The pipeline is emulated with a real local aiohttp websocket server so the
4
+ tests exercise the actual transport (handshake, query authToken, User-Agent,
5
+ heartbeat frames, close handling) end to end.
6
+ """
7
+
8
+ import asyncio
9
+ import json
10
+ import time
11
+ from types import SimpleNamespace
12
+
13
+ import aiohttp
14
+ import pytest
15
+ from aiohttp import web
16
+
17
+ from vrchatapi.websocket import (
18
+ VRChatEvent,
19
+ VRChatWebSocket,
20
+ VRChatWebSocketError,
21
+ get_auth_cookie,
22
+ )
23
+
24
+
25
+ def friend_online_frame(user_id="usr_x", display_name="Alice"):
26
+ return json.dumps(
27
+ {
28
+ "type": "friend-online",
29
+ "content": json.dumps(
30
+ {
31
+ "user": {
32
+ "id": user_id,
33
+ "displayName": display_name,
34
+ "location": "offline",
35
+ }
36
+ }
37
+ ),
38
+ }
39
+ )
40
+
41
+
42
+ def notification_frame():
43
+ return json.dumps(
44
+ {
45
+ "type": "notification",
46
+ "content": json.dumps(
47
+ {"type": "friendRequest", "senderUserId": "usr_y"}
48
+ ),
49
+ }
50
+ )
51
+
52
+
53
+ class MockPipelineServer:
54
+ """Tiny aiohttp server mimicking the VRChat pipeline websocket."""
55
+
56
+ def __init__(self):
57
+ self.connections = [] # (query, headers) per connection
58
+ self.received = [] # text frames sent by the client
59
+ self.frames = [] # frames sent on unscripted connections
60
+ self.close_after_frames = False
61
+ self.script = {} # connection index -> (frames, close_after_send)
62
+ self.app = web.Application()
63
+ self.app.router.add_get("/", self._ws_handler)
64
+
65
+ def set_script(self, conn_index, frames, close_after_send=True):
66
+ self.script[conn_index] = (frames, close_after_send)
67
+
68
+ async def start(self):
69
+ self.runner = web.AppRunner(self.app)
70
+ await self.runner.setup()
71
+ self.site = web.TCPSite(self.runner, "127.0.0.1", 0)
72
+ await self.site.start()
73
+ port = self.site._server.sockets[0].getsockname()[1]
74
+ self.base_url = f"http://127.0.0.1:{port}"
75
+
76
+ async def stop(self):
77
+ await self.runner.cleanup()
78
+
79
+ async def _ws_handler(self, request):
80
+ self.connections.append((dict(request.query), request.headers))
81
+ index = len(self.connections) - 1
82
+ frames, close_after = self.script.get(
83
+ index, (self.frames, self.close_after_frames)
84
+ )
85
+ ws = web.WebSocketResponse()
86
+ await ws.prepare(request)
87
+ for frame in frames:
88
+ await ws.send_str(frame)
89
+ if close_after:
90
+ await ws.close()
91
+ return ws
92
+ async for msg in ws:
93
+ if msg.type == aiohttp.WSMsgType.TEXT:
94
+ self.received.append(msg.data)
95
+ elif msg.type == aiohttp.WSMsgType.ERROR:
96
+ break
97
+ elif msg.type in (aiohttp.WSMsgType.CLOSE, aiohttp.WSMsgType.CLOSED):
98
+ break
99
+ return ws
100
+
101
+
102
+ @pytest.fixture
103
+ async def pipeline_server():
104
+ srv = MockPipelineServer()
105
+ await srv.start()
106
+ yield srv
107
+ await srv.stop()
108
+
109
+
110
+ def make_ws(server, **kwargs):
111
+ defaults = dict(
112
+ auth_token="authcookie_test",
113
+ endpoint=server.base_url,
114
+ auto_reconnect=False,
115
+ heartbeat_interval=None,
116
+ )
117
+ defaults.update(kwargs)
118
+ return VRChatWebSocket(**defaults)
119
+
120
+
121
+ # ---------------------------------------------------------------------------
122
+ # Connection
123
+ # ---------------------------------------------------------------------------
124
+
125
+
126
+ @pytest.mark.asyncio
127
+ async def test_connect_sends_auth_token_and_user_agent(pipeline_server):
128
+ pipeline_server.set_script(0, [], close_after_send=True)
129
+ ws = VRChatWebSocket(
130
+ auth_token="authcookie_test",
131
+ user_agent="TestApp/1.0 me@example.com",
132
+ endpoint=pipeline_server.base_url,
133
+ auto_reconnect=False,
134
+ heartbeat_interval=None,
135
+ )
136
+ await ws.run()
137
+
138
+ query, headers = pipeline_server.connections[0]
139
+ assert query["authToken"] == "authcookie_test"
140
+ assert headers.get("User-Agent") == "TestApp/1.0 me@example.com"
141
+
142
+
143
+ @pytest.mark.asyncio
144
+ async def test_auth_token_is_url_encoded(pipeline_server):
145
+ pipeline_server.set_script(0, [], close_after_send=True)
146
+ token = "authcookie_a b&c=d"
147
+ ws = VRChatWebSocket(
148
+ auth_token=token,
149
+ endpoint=pipeline_server.base_url,
150
+ auto_reconnect=False,
151
+ heartbeat_interval=None,
152
+ )
153
+ await ws.run()
154
+
155
+ # The server sees the decoded original token; without URL encoding the
156
+ # unquoted "&" / "=" would have split the query string.
157
+ query, _ = pipeline_server.connections[0]
158
+ assert query["authToken"] == token
159
+
160
+
161
+ # ---------------------------------------------------------------------------
162
+ # Decoding
163
+ # ---------------------------------------------------------------------------
164
+
165
+
166
+ @pytest.mark.asyncio
167
+ async def test_content_decoding_matrix():
168
+ ws = VRChatWebSocket(auth_token="x", heartbeat_interval=None)
169
+ seen = []
170
+
171
+ @ws.on_event
172
+ async def on_event(event):
173
+ seen.append(event)
174
+
175
+ def frame(msg_type, content=None):
176
+ payload = {"type": msg_type}
177
+ if content is not None:
178
+ payload["content"] = content
179
+ return json.dumps(payload)
180
+
181
+ assert (
182
+ await ws._dispatch_message(
183
+ frame("notification", json.dumps({"type": "friendRequest", "senderUserId": "usr_x"}))
184
+ )
185
+ is True
186
+ )
187
+ assert await ws._dispatch_message(frame("see-notification", "not_abc")) is True
188
+ assert await ws._dispatch_message(frame("clear-notification")) is True
189
+ assert (
190
+ await ws._dispatch_message(
191
+ frame("notification-v2-delete", json.dumps({"notificationIds": ["n1", "n2"]}))
192
+ )
193
+ is True
194
+ )
195
+
196
+ assert [e.type for e in seen] == [
197
+ "notification",
198
+ "see-notification",
199
+ "clear-notification",
200
+ "notification-v2-delete",
201
+ ]
202
+ assert seen[0].content == {"type": "friendRequest", "senderUserId": "usr_x"}
203
+ assert isinstance(seen[0], VRChatEvent)
204
+ assert seen[1].content == "not_abc"
205
+ assert seen[1].raw_content == "not_abc"
206
+ assert seen[2].content is None
207
+ assert seen[2].raw_content is None
208
+ assert seen[3].content == {"notificationIds": ["n1", "n2"]}
209
+
210
+
211
+ @pytest.mark.asyncio
212
+ async def test_malformed_content_reports_error_and_keeps_connection():
213
+ ws = VRChatWebSocket(auth_token="x", heartbeat_interval=None)
214
+ errors = []
215
+
216
+ @ws.on_error
217
+ async def on_error(exc):
218
+ errors.append(exc)
219
+
220
+ # content is not valid JSON but the connection itself stays up.
221
+ assert await ws._dispatch_message('{"type":"notification","content":"nope"}') is True
222
+ assert len(errors) == 1
223
+ assert isinstance(errors[0], VRChatWebSocketError)
224
+
225
+
226
+ @pytest.mark.asyncio
227
+ async def test_server_error_message_closes_connection():
228
+ ws = VRChatWebSocket(auth_token="x", heartbeat_interval=None)
229
+ errors = []
230
+
231
+ @ws.on_error
232
+ async def on_error(exc):
233
+ errors.append(exc)
234
+
235
+ assert await ws._dispatch_message('{"err":"Error finding user usr_x"}') is False
236
+ assert len(errors) == 1
237
+ assert isinstance(errors[0], VRChatWebSocketError)
238
+ assert "Error finding user" in str(errors[0])
239
+ assert errors[0].raw == '{"err":"Error finding user usr_x"}'
240
+
241
+
242
+ # ---------------------------------------------------------------------------
243
+ # Callbacks
244
+ # ---------------------------------------------------------------------------
245
+
246
+
247
+ @pytest.mark.asyncio
248
+ async def test_callback_dispatch_and_catch_all(pipeline_server):
249
+ pipeline_server.set_script(
250
+ 0, [friend_online_frame(), notification_frame()], close_after_send=True
251
+ )
252
+ ws = make_ws(pipeline_server)
253
+ typed, catch_all = [], []
254
+
255
+ @ws.on("friend-online")
256
+ async def on_friend_online(event):
257
+ typed.append(event.content["user"]["displayName"])
258
+
259
+ @ws.on_event
260
+ async def on_event(event):
261
+ catch_all.append(event.type)
262
+
263
+ await ws.run()
264
+
265
+ assert typed == ["Alice"]
266
+ assert catch_all == ["friend-online", "notification"]
267
+
268
+
269
+ @pytest.mark.asyncio
270
+ async def test_off_removes_handler(pipeline_server):
271
+ pipeline_server.set_script(0, [friend_online_frame()], close_after_send=True)
272
+ ws = make_ws(pipeline_server)
273
+ calls = []
274
+
275
+ @ws.on("friend-online")
276
+ async def handler(event):
277
+ calls.append(event)
278
+
279
+ ws.off("friend-online", handler)
280
+ await ws.run()
281
+
282
+ assert calls == []
283
+
284
+
285
+ # ---------------------------------------------------------------------------
286
+ # Async iterator
287
+ # ---------------------------------------------------------------------------
288
+
289
+
290
+ @pytest.mark.asyncio
291
+ async def test_async_iterator_yields_events(pipeline_server):
292
+ pipeline_server.set_script(
293
+ 0, [friend_online_frame(), notification_frame()], close_after_send=False
294
+ )
295
+ ws = make_ws(pipeline_server)
296
+ await ws.connect()
297
+
298
+ collected = []
299
+
300
+ async def consume():
301
+ async for event in ws:
302
+ collected.append(event.type)
303
+ if len(collected) == 2:
304
+ await ws.close()
305
+
306
+ await consume()
307
+
308
+ assert collected == ["friend-online", "notification"]
309
+
310
+
311
+ # ---------------------------------------------------------------------------
312
+ # Errors / lifecycle
313
+ # ---------------------------------------------------------------------------
314
+
315
+
316
+ @pytest.mark.asyncio
317
+ async def test_server_error_ends_run(pipeline_server):
318
+ pipeline_server.set_script(
319
+ 0, ['{"err":"Error finding user usr_x"}'], close_after_send=True
320
+ )
321
+ ws = make_ws(pipeline_server)
322
+ errors = []
323
+
324
+ @ws.on_error
325
+ async def on_error(exc):
326
+ errors.append(exc)
327
+
328
+ await ws.run()
329
+
330
+ assert len(errors) == 1
331
+ assert isinstance(errors[0], VRChatWebSocketError)
332
+ assert not ws.is_connected
333
+
334
+
335
+ # ---------------------------------------------------------------------------
336
+ # Heartbeat
337
+ # ---------------------------------------------------------------------------
338
+
339
+
340
+ @pytest.mark.asyncio
341
+ async def test_heartbeat_frames_are_sent(pipeline_server):
342
+ pipeline_server.set_script(0, [], close_after_send=False)
343
+ ws = make_ws(pipeline_server, heartbeat_interval=0.05)
344
+
345
+ task = asyncio.create_task(ws.run())
346
+ try:
347
+ deadline = time.monotonic() + 10
348
+ while not pipeline_server.received and time.monotonic() < deadline:
349
+ await asyncio.sleep(0.02)
350
+ finally:
351
+ await ws.close()
352
+ await task
353
+
354
+ assert pipeline_server.received, "server never received a heartbeat frame"
355
+ heartbeats = [
356
+ json.loads(frame)
357
+ for frame in pipeline_server.received
358
+ if json.loads(frame).get("type") == "heartbeat"
359
+ ]
360
+ assert heartbeats, pipeline_server.received
361
+ assert heartbeats[0]["connected"] is True
362
+ assert heartbeats[0]["nonce"]
363
+
364
+
365
+ # ---------------------------------------------------------------------------
366
+ # Reconnect
367
+ # ---------------------------------------------------------------------------
368
+
369
+
370
+ @pytest.mark.asyncio
371
+ async def test_auto_reconnect_after_drop(pipeline_server):
372
+ # First connection drops immediately; the client must reconnect and
373
+ # receive the event sent on the second connection.
374
+ pipeline_server.set_script(0, [], close_after_send=True)
375
+ pipeline_server.set_script(1, [friend_online_frame()], close_after_send=False)
376
+
377
+ ws = make_ws(
378
+ pipeline_server,
379
+ auto_reconnect=True,
380
+ reconnect_max_delay=0.05,
381
+ )
382
+ received = []
383
+ got = asyncio.Event()
384
+ reconnects = []
385
+
386
+ @ws.on("friend-online")
387
+ async def on_friend_online(event):
388
+ received.append(event.content["user"]["displayName"])
389
+ got.set()
390
+
391
+ @ws.on_reconnect
392
+ async def on_reconnect(delay):
393
+ reconnects.append(delay)
394
+
395
+ task = asyncio.create_task(ws.run())
396
+ try:
397
+ await asyncio.wait_for(got.wait(), timeout=10)
398
+ finally:
399
+ await ws.close()
400
+ await task
401
+
402
+ assert len(pipeline_server.connections) >= 2
403
+ assert received == ["Alice"]
404
+ assert reconnects
405
+
406
+
407
+ # ---------------------------------------------------------------------------
408
+ # from_client / auth cookie
409
+ # ---------------------------------------------------------------------------
410
+
411
+
412
+ class _FakeCookieJar:
413
+ def __init__(self, cookies):
414
+ self._cookies = cookies
415
+
416
+ def __iter__(self):
417
+ return iter(self._cookies)
418
+
419
+
420
+ class _FakeApiClient:
421
+ def __init__(self, cookies, user_agent="MyApp/1.0 me@example.com"):
422
+ self.rest_client = SimpleNamespace(cookie_jar=_FakeCookieJar(cookies))
423
+ self.user_agent = user_agent
424
+
425
+
426
+ def test_from_client_reads_auth_cookie_and_user_agent():
427
+ client = _FakeApiClient(
428
+ [
429
+ SimpleNamespace(name="twoFactorAuth", value="2fa-value"),
430
+ SimpleNamespace(name="auth", value="authcookie_123"),
431
+ ]
432
+ )
433
+ ws = VRChatWebSocket.from_client(client)
434
+ assert ws._auth_token == "authcookie_123"
435
+ assert ws._user_agent == "MyApp/1.0 me@example.com"
436
+
437
+
438
+ def test_from_client_raises_without_auth_cookie():
439
+ client = _FakeApiClient([])
440
+ with pytest.raises(ValueError, match="auth"):
441
+ VRChatWebSocket.from_client(client)
442
+
443
+
444
+ def test_get_auth_cookie_returns_none_without_rest_client():
445
+ assert get_auth_cookie(SimpleNamespace()) is None
446
+
447
+
448
+ def test_constructor_requires_auth_token():
449
+ with pytest.raises(ValueError, match="auth_token"):
450
+ VRChatWebSocket(auth_token="")
@@ -14,7 +14,7 @@
14
14
  """ # noqa: E501
15
15
 
16
16
 
17
- __version__ = "1.20.8dev1"
17
+ __version__ = "1.20.8dev2"
18
18
 
19
19
  # Define package exports
20
20
  __all__ = [