├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── ci.yml │ ├── initiate_release.yml │ ├── release.yml │ ├── reviewdog.yml │ └── scheduled_test.yml ├── .gitignore ├── .rubocop.yml ├── .versionrc.js ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── Rakefile ├── SECURITY.md ├── assets └── logo.svg ├── lib ├── stream-chat.rb └── stream-chat │ ├── channel.rb │ ├── client.rb │ ├── errors.rb │ ├── moderation.rb │ ├── stream_rate_limits.rb │ ├── stream_response.rb │ ├── types.rb │ ├── util.rb │ └── version.rb ├── scripts └── get_changelog_diff.js ├── sorbet ├── config └── rbi │ ├── gems │ ├── coderay.rbi │ ├── connection_pool.rbi │ ├── docile.rbi │ ├── faraday-em_http.rbi │ ├── faraday-em_synchrony.rbi │ ├── faraday-excon.rbi │ ├── faraday-httpclient.rbi │ ├── faraday-multipart.rbi │ ├── faraday-net_http.rbi │ ├── faraday-net_http_persistent.rbi │ ├── faraday-patron.rbi │ ├── faraday-rack.rbi │ ├── faraday.rbi │ ├── jwt.rbi │ ├── method_source.rbi │ ├── multipart-post.rbi │ ├── net-http-persistent.rbi │ ├── pry-doc.rbi │ ├── pry.rbi │ ├── rack.rbi │ ├── rake.rbi │ ├── rspec-core.rbi │ ├── rspec-expectations.rbi │ ├── rspec-mocks.rbi │ ├── rspec-support.rbi │ ├── rspec.rbi │ ├── simplecov-html.rbi │ ├── simplecov.rbi │ ├── simplecov_json_formatter.rbi │ └── yard.rbi │ ├── hidden-definitions │ ├── errors.txt │ └── hidden.rbi │ ├── sorbet-typed │ └── lib │ │ ├── faraday │ │ └── all │ │ │ └── faraday.rbi │ │ ├── rainbow │ │ └── all │ │ │ └── rainbow.rbi │ │ ├── rake │ │ └── all │ │ │ └── rake.rbi │ │ ├── rspec-core │ │ └── all │ │ │ └── rspec-core.rbi │ │ ├── rubocop │ │ └── >=1.8 │ │ │ └── rubocop.rbi │ │ └── yard │ │ └── all │ │ └── yard.rbi │ └── todo.rbi ├── spec ├── channel_spec.rb ├── client_spec.rb ├── data │ ├── helloworld.jpg │ └── helloworld.txt ├── moderation_spec.rb └── spec_helper.rb └── stream-chat.gemspec /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @totalimmersion @akupila @guerinoni @JimmyPettersson85 @shaljam @vishalnarkhede @nijeesh-stream 2 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Submit a pull request 2 | 3 | ## CLA 4 | 5 | - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required). 6 | - [ ] The code changes follow best practices 7 | - [ ] Code changes are tested (add some information if not applicable) 8 | 9 | ## Description of the pull request 10 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | max-parallel: 1 10 | matrix: 11 | ruby: ["3.0", "3.1", "3.4"] 12 | name: 💎 Ruby ${{ matrix.ruby }} 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 # gives the commit linter access to previous commits 17 | 18 | - uses: ruby/setup-ruby@v1 19 | with: 20 | ruby-version: ${{ matrix.ruby }} 21 | bundler-cache: true 22 | 23 | - run: bundle exec rake rubocop 24 | if: ${{ matrix.ruby == '3.4' }} 25 | 26 | - run: bundle exec srb tc 27 | if: ${{ matrix.ruby == '3.4' }} 28 | 29 | - run: bundle exec rspec ./spec --require spec_helper 30 | env: 31 | STREAM_KEY: ${{ secrets.STREAM_CHAT_API_KEY }} 32 | STREAM_SECRET: ${{ secrets.STREAM_CHAT_API_SECRET }} 33 | -------------------------------------------------------------------------------- /.github/workflows/initiate_release.yml: -------------------------------------------------------------------------------- 1 | name: Create release PR 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: "The new version number with 'v' prefix. Example: v1.40.1" 8 | required: true 9 | 10 | jobs: 11 | init_release: 12 | name: 🚀 Create release PR 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 # gives the changelog generator access to all previous commits 18 | 19 | - name: Update CHANGELOG.md, version.rb and push release branch 20 | env: 21 | VERSION: ${{ github.event.inputs.version }} 22 | run: | 23 | npx --yes standard-version@9.3.2 --release-as "$VERSION" --skip.tag --skip.commit --tag-prefix=v 24 | git config --global user.name 'github-actions' 25 | git config --global user.email 'release@getstream.io' 26 | git checkout -q -b "release-$VERSION" 27 | git commit -am "chore(release): $VERSION" 28 | git push -q -u origin "release-$VERSION" 29 | 30 | - name: Get changelog diff 31 | uses: actions/github-script@v6 32 | with: 33 | script: | 34 | const get_change_log_diff = require('./scripts/get_changelog_diff.js') 35 | core.exportVariable('CHANGELOG', get_change_log_diff()) 36 | 37 | - name: Open pull request 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | run: | 41 | gh pr create \ 42 | -t "Release ${{ github.event.inputs.version }}" \ 43 | -b "# :rocket: ${{ github.event.inputs.version }} 44 | Make sure to use squash & merge when merging! 45 | Once this is merged, another job will kick off automatically and publish the package. 46 | # :memo: Changelog 47 | ${{ env.CHANGELOG }}" 48 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | pull_request: 5 | types: [closed] 6 | branches: 7 | - master 8 | 9 | jobs: 10 | Release: 11 | name: 🚀 Release 12 | if: github.event.pull_request.merged && startsWith(github.head_ref, 'release-') 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | 19 | - uses: actions/github-script@v6 20 | with: 21 | script: | 22 | const get_change_log_diff = require('./scripts/get_changelog_diff.js') 23 | core.exportVariable('CHANGELOG', get_change_log_diff()) 24 | 25 | // Getting the release version from the PR source branch 26 | // Source branch looks like this: release-1.0.0 27 | const version = context.payload.pull_request.head.ref.split('-')[1] 28 | core.exportVariable('VERSION', version) 29 | 30 | - name: Publish gem 31 | uses: dawidd6/action-publish-gem@v1 32 | with: 33 | api_key: ${{secrets.RUBYGEMS_API_KEY}} 34 | 35 | - name: Create release on GitHub 36 | uses: ncipollo/release-action@v1 37 | with: 38 | body: ${{ env.CHANGELOG }} 39 | tag: ${{ env.VERSION }} 40 | token: ${{ secrets.GITHUB_TOKEN }} 41 | -------------------------------------------------------------------------------- /.github/workflows/reviewdog.yml: -------------------------------------------------------------------------------- 1 | name: reviewdog 2 | 3 | on: [pull_request] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.head_ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | rubocop: 11 | name: 🐶 Reviewdog 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Check out code 15 | uses: actions/checkout@v4 16 | 17 | - uses: ruby/setup-ruby@v1 18 | with: 19 | ruby-version: 3 20 | 21 | - name: rubocop 22 | uses: reviewdog/action-rubocop@v2 23 | with: 24 | rubocop_version: gemfile 25 | reporter: github-pr-review 26 | -------------------------------------------------------------------------------- /.github/workflows/scheduled_test.yml: -------------------------------------------------------------------------------- 1 | name: Scheduled tests 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | # Monday at 9:00 UTC 7 | - cron: '0 9 * * 1' 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | 15 | - uses: ruby/setup-ruby@v1 16 | with: 17 | ruby-version: '3.1' 18 | bundler-cache: true 19 | 20 | - name: Test 21 | env: 22 | STREAM_KEY: ${{ secrets.STREAM_CHAT_API_KEY }} 23 | STREAM_SECRET: ${{ secrets.STREAM_CHAT_API_SECRET }} 24 | run: | 25 | # Retry 3 times because tests can be flaky 26 | for _ in 1 2 3; 27 | do 28 | bundle exec rspec ./spec --require spec_helper && break 29 | done 30 | 31 | - name: Notify Slack if failed 32 | uses: voxmedia/github-action-slack-notify-build@v1 33 | if: failure() 34 | with: 35 | channel_id: C02RPDF7T63 36 | color: danger 37 | status: FAILED 38 | env: 39 | SLACK_BOT_TOKEN: ${{ secrets.SLACK_NOTIFICATIONS_BOT_TOKEN }} 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | .vscode 13 | .idea 14 | .DS_Store 15 | 16 | # Used by dotenv library to load environment variables. 17 | # .env 18 | 19 | ## Specific to RubyMotion: 20 | .dat* 21 | .repl_history 22 | build/ 23 | *.bridgesupport 24 | build-iPhoneOS/ 25 | build-iPhoneSimulator/ 26 | 27 | ## Specific to RubyMotion (use of CocoaPods): 28 | # 29 | # We recommend against adding the Pods directory to your .gitignore. However 30 | # you should judge for yourself, the pros and cons are mentioned at: 31 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 32 | # 33 | # vendor/Pods/ 34 | 35 | ## Documentation cache and generated files: 36 | /.yardoc/ 37 | /_yardoc/ 38 | /doc/ 39 | /rdoc/ 40 | 41 | ## Environment normalization: 42 | /.bundle/ 43 | /vendor/bundle 44 | /lib/bundler/man/ 45 | 46 | # for a library or gem, you might want to ignore these files since the code is 47 | # intended to run in multiple environments; otherwise, check them in: 48 | # See https://github.com/rubygems/rubygems/issues/3372 for more info 49 | Gemfile.lock 50 | .ruby-version 51 | # .ruby-gemset 52 | 53 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 54 | .rvmrc 55 | .envrc 56 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | DisabledByDefault: false 3 | NewCops: enable 4 | TargetRubyVersion: 3.0 5 | Exclude: 6 | - sorbet/**/*.rbi 7 | - vendor/bundle/**/* 8 | 9 | Layout/LineLength: 10 | Enabled: false 11 | 12 | Lint/RedundantCopDisableDirective: 13 | Enabled: false 14 | 15 | Metrics/AbcSize: 16 | Enabled: false 17 | Metrics/BlockLength: 18 | Enabled: false 19 | Metrics/ClassLength: 20 | Enabled: false 21 | Metrics/MethodLength: 22 | Enabled: false 23 | 24 | Naming/AccessorMethodName: 25 | Enabled: false 26 | 27 | Style/AccessorGrouping: 28 | Enabled: false 29 | Style/Documentation: 30 | Enabled: false 31 | Style/DoubleCopDisableDirective: 32 | Enabled: false 33 | Style/FrozenStringLiteralComment: 34 | Enabled: false 35 | 36 | Gemspec/RequireMFA: 37 | Enabled: false 38 | Naming/PredicateMethod: 39 | Enabled: false 40 | -------------------------------------------------------------------------------- /.versionrc.js: -------------------------------------------------------------------------------- 1 | const versionFileUpdater = { 2 | VERSION_REGEX: /VERSION = '(.+)'/, 3 | 4 | readVersion: function (contents) { 5 | const version = this.VERSION_REGEX.exec(contents)[1]; 6 | return version; 7 | }, 8 | 9 | writeVersion: function (contents, version) { 10 | return contents.replace(this.VERSION_REGEX.exec(contents)[0], `VERSION = '${version}'`); 11 | } 12 | } 13 | 14 | module.exports = { 15 | bumpFiles: [{ filename: './lib/stream-chat/version.rb', updater: versionFileUpdater }], 16 | types: [ 17 | {"type": "feat", "section": "Features"}, 18 | {"type": "fix", "section": "Bug Fixes"}, 19 | {"type": "chore", "section": "Other", "hidden": false}, 20 | {"type": "docs", "section": "Other", "hidden": false}, 21 | {"type": "style", "section": "Other", "hidden": false}, 22 | {"type": "refactor", "section": "Other", "hidden": false}, 23 | {"type": "perf", "section": "Other", "hidden": false}, 24 | {"type": "test", "section": "Other", "hidden": false} 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## [3.15.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.14.0...v3.15.0) (2025-06-06) 6 | 7 | ## [3.14.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.13.0...v3.14.0) (2025-04-07) 8 | 9 | ## [3.13.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.12.0...v3.13.0) (2025-04-04) 10 | 11 | 12 | ### Features 13 | 14 | * deactivate users ([#162](https://github.com/GetStream/stream-chat-ruby/issues/162)) ([12bf4d1](https://github.com/GetStream/stream-chat-ruby/commit/12bf4d19846b5100f1886929b74c7ad05d753be4)) 15 | * draft messages ([#161](https://github.com/GetStream/stream-chat-ruby/pull/161)) ([1719104](https://github.com/GetStream/stream-chat-ruby/commit/c7bccb3ad30721a20f32fd60eb13ab6d97a08208)) 16 | 17 | ### Other 18 | 19 | * added nijeesh to code owners ([#156](https://github.com/GetStream/stream-chat-ruby/issues/156)) ([7cd4e54](https://github.com/GetStream/stream-chat-ruby/commit/7cd4e5443a8f283596b8eadc873030d737cd621c)) 20 | * **release:** v3.12.0 ([#157](https://github.com/GetStream/stream-chat-ruby/issues/157)) ([993b7a3](https://github.com/GetStream/stream-chat-ruby/commit/993b7a30bd2222ee328ca7a862384c7baf7d53e1)) 21 | 22 | ## [3.11.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.9.0...v3.11.0) (2025-03-21) 23 | 24 | 25 | ### Other 26 | 27 | * **release:** 3.10.0 ([#151](https://github.com/GetStream/stream-chat-ruby/issues/151)) ([ac11fc1](https://github.com/GetStream/stream-chat-ruby/commit/ac11fc122ec97ffd1b2bce820efe55925e96277f)) 28 | 29 | ## [3.10.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.9.0...v3.10.0) (2025-02-24) 30 | 31 | ## [3.9.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.7.0...v3.9.0) (2025-02-11) 32 | 33 | 34 | ### Other 35 | 36 | * added tests using the restricted visibility feature ([#144](https://github.com/GetStream/stream-chat-ruby/issues/144)) ([b13cc92](https://github.com/GetStream/stream-chat-ruby/commit/b13cc92cd91aeb1f6e1a25f5c6d22efb41339f49)) 37 | * **release:** 3.8.0 ([#146](https://github.com/GetStream/stream-chat-ruby/issues/146)) ([e2e7673](https://github.com/GetStream/stream-chat-ruby/commit/e2e7673f6b93a248e870f060e719c6ef16886129)) 38 | 39 | ## [3.8.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.7.0...v3.8.0) (2025-02-11) 40 | 41 | 42 | ### Other 43 | 44 | * added tests using the restricted visibility feature ([#144](https://github.com/GetStream/stream-chat-ruby/issues/144)) ([b13cc92](https://github.com/GetStream/stream-chat-ruby/commit/b13cc92cd91aeb1f6e1a25f5c6d22efb41339f49)) 45 | 46 | ## [3.7.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.6.0...v3.7.0) (2024-12-09) 47 | 48 | ## [3.6.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.5.1...v3.6.0) (2024-05-22) 49 | 50 | 51 | ### Features 52 | 53 | * add test for `notifications_muted` as filter in `query_members` ([#140](https://github.com/GetStream/stream-chat-ruby/issues/140)) ([61102ac](https://github.com/GetStream/stream-chat-ruby/commit/61102ac16783ecfc502d8f7d21435ec64af28436)) 54 | 55 | ### [3.5.1](https://github.com/GetStream/stream-chat-ruby/compare/v3.5.0...v3.5.1) (2024-04-18) 56 | 57 | ## [3.5.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.4.0...v3.5.0) (2023-10-30) 58 | 59 | 60 | ### Features 61 | 62 | * add check sns point ([#134](https://github.com/GetStream/stream-chat-ruby/issues/134)) ([532ae7e](https://github.com/GetStream/stream-chat-ruby/commit/532ae7e9f2e0879f679dc3cd2c5afb27987d4e88)) 63 | 64 | ## [3.4.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.3.0...v3.4.0) (2023-07-19) 65 | 66 | 67 | ### Features 68 | 69 | * commit message endpoint ([#129](https://github.com/GetStream/stream-chat-ruby/issues/129)) ([09eabb3](https://github.com/GetStream/stream-chat-ruby/commit/09eabb33f4bcfa6f8881dc545060bc5bdd51374e)) 70 | 71 | 72 | ### Bug Fixes 73 | 74 | * sorbet type for mark_read function signature ([#130](https://github.com/GetStream/stream-chat-ruby/issues/130)) ([7ea0f51](https://github.com/GetStream/stream-chat-ruby/commit/7ea0f517592c1819e223a65eedb53caa85a92817)) 75 | 76 | ## [3.3.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.2.0...v3.3.0) (2022-11-17) 77 | 78 | 79 | ### Features 80 | 81 | * add campaign support ([#124](https://github.com/GetStream/stream-chat-ruby/issues/124)) ([d7a935f](https://github.com/GetStream/stream-chat-ruby/commit/d7a935f7b4459399b82db1d51a541388caeb5e68)) 82 | 83 | ## [3.2.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.1.0...v3.2.0) (2022-11-17) 84 | 85 | 86 | ### Features 87 | 88 | * **send_message:** add options argument ([#107](https://github.com/GetStream/stream-chat-ruby/issues/107)) ([8e5bf89](https://github.com/GetStream/stream-chat-ruby/commit/8e5bf8977f899d3e5a259efd38d7bcf3962cd999)) 89 | 90 | 91 | ### Bug Fixes 92 | 93 | * do not ship lock ([#118](https://github.com/GetStream/stream-chat-ruby/issues/118)) ([4cd4f25](https://github.com/GetStream/stream-chat-ruby/commit/4cd4f251a575ec8b010543d0277914463028cf2b)) 94 | * relax dependency versions ([#116](https://github.com/GetStream/stream-chat-ruby/issues/116)) ([2b87af6](https://github.com/GetStream/stream-chat-ruby/commit/2b87af624856c403ffaf8c9b69982832f169df70)) 95 | 96 | 97 | ### Other 98 | 99 | * add ignored sections into changelog ([#120](https://github.com/GetStream/stream-chat-ruby/issues/120)) ([191ea82](https://github.com/GetStream/stream-chat-ruby/commit/191ea825c4ad68473568da6c801819d6a8fec827)) 100 | * **deps-dev:** bump rack from 2.2.3 to 2.2.4 ([#110](https://github.com/GetStream/stream-chat-ruby/issues/110)) ([2ab646b](https://github.com/GetStream/stream-chat-ruby/commit/2ab646b4f6cdcb016203075a94a77437739b69d0)) 101 | * drop old rubies ([#122](https://github.com/GetStream/stream-chat-ruby/issues/122)) ([77ddb1f](https://github.com/GetStream/stream-chat-ruby/commit/77ddb1f4917611a6579c177dd617358bdbde6bbc)) 102 | * move pr template into github ([#119](https://github.com/GetStream/stream-chat-ruby/issues/119)) ([99cd178](https://github.com/GetStream/stream-chat-ruby/commit/99cd178571cfdf6b6828ef60f4eca57890f14e18)) 103 | 104 | ## [3.1.0](https://github.com/GetStream/stream-chat-ruby/compare/v3.0.0...v3.1.0) (2022-08-26) 105 | 106 | 107 | ### Chore 108 | 109 | * chore: pin dependencies versions ([#109](https://github.com/GetStream/stream-chat-ruby/pull/109)) ([66dc80b](https://github.com/GetStream/stream-chat-ruby/commit/66dc80bb3f5e3698450517e94238e28fa7bd9d9c)) 110 | 111 | ## [3.0.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.23.0...v3.0.0) (2022-05-24) 112 | 113 | 114 | ### ⚠ BREAKING CHANGES 115 | 116 | * **sorbet:** enable runtime typecheck (#104) 117 | 118 | > In this release we have enabled runtime level typechecking for Sorbet. This means that if you input parameters 119 | are invalid **your code will throw an error during runtime**. Please ensure that your code is properly tested 120 | before continuing with v3.0.0 of this library. 121 | 122 | ### Features 123 | 124 | * **sorbet:** enable runtime typecheck ([#104](https://github.com/GetStream/stream-chat-ruby/issues/104)) ([97d5f29](https://github.com/GetStream/stream-chat-ruby/commit/97d5f299b652e8328af6e76d0d605c59f05a5cc3)) 125 | 126 | ## [2.23.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.22.2...v2.23.0) (2022-05-19) 127 | 128 | 129 | ### Features 130 | 131 | * **campaign:** add campaign endpoints ([c8c698b](https://github.com/GetStream/stream-chat-ruby/commit/c8c698b51ee2c9f54819c2b9407a3fff7808efd5)) 132 | * **import:** add import endpoints ([#102](https://github.com/GetStream/stream-chat-ruby/issues/102)) ([4d7358d](https://github.com/GetStream/stream-chat-ruby/commit/4d7358d39615c5346f9fdcb2b0dfbffa3c2ae79c)) 133 | 134 | ### [2.22.2](https://github.com/GetStream/stream-chat-ruby/compare/v2.22.1...v2.22.2) (2022-04-21) 135 | 136 | 137 | ### Bug Fixes 138 | 139 | * **sorbet:** turn off runtime checks properly ([#98](https://github.com/GetStream/stream-chat-ruby/issues/98)) ([29e9e73](https://github.com/GetStream/stream-chat-ruby/commit/29e9e73ac07d163e8c1ca7b24516cb7ac61e93cd)) 140 | 141 | ### [2.22.1](https://github.com/GetStream/stream-chat-ruby/compare/v2.22.0...v2.22.1) (2022-04-20) 142 | 143 | ### Features 144 | 145 | * added comments to public methods ([#93](https://github.com/GetStream/stream-chat-ruby/issues/93)) ([3843fe4](https://github.com/GetStream/stream-chat-ruby/commit/3843fe41ea7716d2b6a787d695bbe54981b2b35e)) 146 | 147 | ## [2.22.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.21.0...v2.22.0) (2022-04-01) 148 | 149 | 150 | ### Features 151 | 152 | * add new device field ([#90](https://github.com/GetStream/stream-chat-ruby/issues/90)) ([aa6723c](https://github.com/GetStream/stream-chat-ruby/commit/aa6723cd54e58aab0f1b8c55bc4e54211ab39f3c)) 153 | * add new moderation apis ([#88](https://github.com/GetStream/stream-chat-ruby/issues/88)) ([573c586](https://github.com/GetStream/stream-chat-ruby/commit/573c58650392eaa5a6d38b4423e170e30b3e98df)) 154 | * add push provider apis ([#89](https://github.com/GetStream/stream-chat-ruby/issues/89)) ([d592fba](https://github.com/GetStream/stream-chat-ruby/commit/d592fba4c0041102fa18d0fee11961f881414337)) 155 | * **update_user:** deprecate update in favor of upsert ([#91](https://github.com/GetStream/stream-chat-ruby/issues/91)) ([74d3163](https://github.com/GetStream/stream-chat-ruby/commit/74d316339b277b0f9cf0f94f40f11aae30fd7644)) 156 | 157 | ## [2.21.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.20.0...v2.21.0) (2022-03-03) 158 | 159 | 160 | ### Features 161 | 162 | * add options to delete message ([#80](https://github.com/GetStream/stream-chat-ruby/issues/80)) ([6a343e9](https://github.com/GetStream/stream-chat-ruby/commit/6a343e9fa9409150c27afc4246765f07bb12e571)) 163 | * add sorbet type checker ([#83](https://github.com/GetStream/stream-chat-ruby/issues/83)) ([f2fcee5](https://github.com/GetStream/stream-chat-ruby/commit/f2fcee58ecc0c3b4016721e997c42c44753bba9a)) 164 | 165 | 166 | ### Bug Fixes 167 | 168 | * update app settings ([#86](https://github.com/GetStream/stream-chat-ruby/issues/86)) ([3f88185](https://github.com/GetStream/stream-chat-ruby/commit/3f88185117c5710e0b3e66f7f402f2c8969dec2f)) 169 | 170 | ## [2.20.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.19.0...v2.20.0) (2022-02-04) 171 | 172 | 173 | ### Features 174 | 175 | * add helper for invitation acceptance and rejection ([#78](https://github.com/GetStream/stream-chat-ruby/issues/78)) ([c950694](https://github.com/GetStream/stream-chat-ruby/commit/c950694a0ac2b0906d7bedb4ebc9a1af00eea606)) 176 | 177 | ## [2.19.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.18.0...v2.19.0) (2022-02-02) 178 | 179 | 180 | ### Features 181 | 182 | * ability to provide custom http client ([#75](https://github.com/GetStream/stream-chat-ruby/issues/75)) ([bfff20d](https://github.com/GetStream/stream-chat-ruby/commit/bfff20d06232c49a1a8d0eee255a718bfffbb351)) 183 | * add connection pooling and idle timeout ([#74](https://github.com/GetStream/stream-chat-ruby/issues/74)) ([7891005](https://github.com/GetStream/stream-chat-ruby/commit/78910053b3a15b1efa3183a71299068e63b128e3)) 184 | * env var handling enhancement ([#76](https://github.com/GetStream/stream-chat-ruby/issues/76)) ([0cdc38a](https://github.com/GetStream/stream-chat-ruby/commit/0cdc38abd671bfaa8cefa7f403b9e2ac8b642272)) 185 | > 🚨 Note: if you used `STREAM_CHAT_URL` env var, you'll need to provide it manually in the `**options` as `base_url`. See the initializer of `Client` class for more information. 186 | 187 | ## [2.18.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.17.2...v2.18.0) (2022-01-26) 188 | 189 | 190 | ### Features 191 | 192 | * expose rate limits ([#72](https://github.com/GetStream/stream-chat-ruby/issues/72)) ([3f1ad5c](https://github.com/GetStream/stream-chat-ruby/commit/3f1ad5c8f43263424e934055d0ac283cdcce9376)) 193 | * full feature parity ([#71](https://github.com/GetStream/stream-chat-ruby/issues/71)) ([a25a1b6](https://github.com/GetStream/stream-chat-ruby/commit/a25a1b66f9eadd77d09b99d5c3cfba27bba52f17)) 194 | 195 | ### [2.17.2](https://github.com/GetStream/stream-chat-ruby/compare/v2.17.1...v2.17.2) (2022-01-17) 196 | 197 | ### Features 198 | * added some new metadata to the gemspec ([#69](https://github.com/GetStream/stream-chat-ruby/issues/69)) ([3e747bc](https://github.com/GetStream/stream-chat-ruby/commit/3e747bcd6aa338b08e136febfb0cf06f29d366b5)) 199 | 200 | ### [2.17.1](https://github.com/GetStream/stream-chat-ruby/compare/v2.17.0...v2.17.1) (2022-01-17) 201 | 202 | 203 | ### Bug Fixes 204 | 205 | * load faraday-mutipart error ([#67](https://github.com/GetStream/stream-chat-ruby/issues/67)) ([55ec107](https://github.com/GetStream/stream-chat-ruby/commit/55ec107fb4d6af887aa562c1e04d90a669c630cb)) 206 | 207 | ## [2.17.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.16.0...v2.17.0) (2022-01-14) 208 | 209 | 210 | ### Features 211 | 212 | * add options to add members ([#63](https://github.com/GetStream/stream-chat-ruby/issues/63)) ([89c9fa9](https://github.com/GetStream/stream-chat-ruby/commit/89c9fa98e19565c4b5353077523a1d407e1f10c9)) 213 | 214 | ## [2.16.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.15.0...v2.16.0) (2021-12-01) 215 | 216 | - Add permissions v2 APIs by @ffenix113 in #62 217 | 218 | ## [2.15.0](https://github.com/GetStream/stream-chat-ruby/compare/v2.14.0...v2.15.0) (2021-11-25) 219 | 220 | - Add configuration support for channel truncate 221 | - truncated_at: to truncate channel up to given time 222 | - message: a system message to be added via truncation 223 | - skip_push: don't send a push notification for system message 224 | - hard_delete: true if truncation should delete messages instead of hiding 225 | 226 | ## November 24th, 2021 - 2.14.0 227 | 228 | - Add new flags for export channels 229 | - clear_deleted_message_text (default: false) 230 | - include_truncated_messages (default: false) 231 | 232 | ## November 17th, 2021 - 2.13.0 233 | 234 | - Add support for shadow banning user 235 | - shadow_ban 236 | - remove_shadow_ban 237 | - Add support for pinning messages 238 | - pin_message 239 | - unpin_message 240 | - Add support for partial updating messages 241 | - update_message_partial 242 | - Add support for updating channel ownership for Deleted Users 243 | 244 | ## November 1st, 2021 - 2.12.0 245 | 246 | - Add support for async endpoints 247 | - get_task 248 | - delete_channels 249 | - delete_users 250 | 251 | ## October 22nd, 2021 - 2.11.3 252 | 253 | - Don't log the entire response when creating exception 254 | - Access error details through StreamAPIException class attr_readers 255 | 256 | ## October 5th, 2021 - 2.11.2 257 | 258 | - Add Codeowners file 259 | - Fix StreamChannelException raises 260 | - Fix rubocop linting error 261 | - Fix channel export test 262 | - Update Github action 263 | 264 | ## August 23rd, 2021 - 2.11.1 265 | 266 | - Use edge as base url 267 | 268 | ## June 25th, 2021 - 2.11.0 269 | 270 | - Add support for improved search 271 | 272 | ## June 4th, 2021 - 2.10.0 273 | 274 | - Add custom command CRUD support 275 | 276 | ## May 31st, 2021 - 2.9.0 277 | 278 | - Add support for app and user level token revoke 279 | 280 | ## May 21st, 2021 - 2.8.0 281 | 282 | - Add query message flags support 283 | 284 | ## March 17th, 2021 - 2.7.0 285 | 286 | - Add Ruby 3.x support 287 | - Update CI to run all tests for all versions 288 | 289 | ## March 9th, 2021 - 2.6.0 290 | 291 | - Add get_rate_limits endpoint 292 | 293 | ## February 3rd, 2021 - 2.5.0 294 | 295 | - Add channel partial update 296 | - Increase convenience in query members 297 | - Improve internal symbol conversions 298 | 299 | ## January 20th, 2021 - 2.4.0 300 | 301 | - Add query_members to channel 302 | - Use post endpoint for query channels instead of get 303 | - Extract common code for sorting into a helper for query calls 304 | 305 | ## January 5th, 2021 - 2.3.0 306 | 307 | - Add check SQS helper 308 | 309 | ## January 4th, 2021 - 2.2.0 310 | 311 | - Add support for export channels 312 | - Improve readme for blocklist and export channels 313 | - Improve running tests for multiple versions of ruby 314 | - Fix issues from the latest version of rubocop 315 | - Move to GitHub Actions 316 | 317 | ## October 5th, 2020 - 2.1.0 318 | 319 | - Add support for blocklist 320 | 321 | ## October 2nd, 2020 - 2.0.0 322 | 323 | - Drop EOL Ruby versions: 2.3 && 2.4 324 | - Setup Rubocop and mark string literals as frozen 325 | 326 | ## August 3rd, 2020 - 1.1.3 327 | 328 | - Fixed Argument Error on delete_user 329 | 330 | ## April 23th, 2020 - 1.1.2 331 | 332 | - Fixed ArgumentError when no users was passed 333 | 334 | ## March 30th, 2020 - 1.1.1 335 | 336 | - Fixed few minor issues 337 | 338 | ## Oct 27th, 2019 - 1.1.0 339 | 340 | - Mark gems use for testing as development dependencies 341 | - Added `send_file`, `send_image`, `delete_file`, `delete_image` 342 | - Added `invite_members` 343 | 344 | ## Oct 19th, 2019 - 1.0.0 345 | 346 | - Added `channel.hide` and `channel.show` 347 | - Added `client.flag_message` and `client.unflag_message` 348 | - Added `client.flag_user` and `client.unflag_user` 349 | - Added `client.get_message` 350 | - Added `client.search` 351 | - Added `client.update_users_partial` 352 | - Added `client.update_user_partial` 353 | - Added `client.reactivate_user` 354 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | # :recycle: Contributing 3 | 4 | We welcome code changes that improve this library or fix a problem, please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github. We are very happy to merge your code in the official repository. Make sure to sign our [Contributor License Agreement (CLA)](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) first. See our license file for more details. 5 | 6 | ## Getting started 7 | 8 | ### Install dependencies 9 | 10 | ```shell 11 | $ bundle install --path vendor/bundle 12 | ``` 13 | 14 | ### Run tests 15 | 16 | ```shell 17 | $ STREAM_KEY=my_api_key STREAM_SECRET=my_api_secret bundle exec rspec spec 18 | ``` 19 | 20 | ### Run specific test 21 | 22 | Add :focus tag on target test: 23 | 24 | ```rb 25 | it 'can mark messages as read', :focus do 26 | # test something 27 | end 28 | ``` 29 | 30 | And then run as following: 31 | 32 | ```shell 33 | $ STREAM_KEY=myapi_key STREAM_SECRET=my_secret STREAM_CHAT_URL=http://127.0.0.1:3030 bundle exec rspec spec --tag focus 34 | ``` 35 | 36 | ### Linters and type check 37 | 38 | We use [Rubocop](https://github.com/rubocop/rubocop) for linting and [Sorbet](https://sorbet.org/) for type checking. 39 | 40 | To run them: 41 | ```shell 42 | $ bundle exec rake rubocop 43 | $ bundle exec srb tc 44 | ``` 45 | 46 | These linters can be easily integrated into IDEs such as RubyMine or VS Code. 47 | 48 | For VS Code, just install the basic Ruby extension which handles Rubocop ([`rebornix.ruby`](https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby)) and the official Sorbet one ([`sorbet.sorbet-vscode-extension`](https://marketplace.visualstudio.com/items?itemName=sorbet.sorbet-vscode-extension)). 49 | 50 | Recommended settings: 51 | ```json 52 | { 53 | "editor.formatOnSave": true, 54 | "ruby.useBundler": true, 55 | "ruby.lint": { 56 | "rubocop": { 57 | "useBundler": true, // enable rubocop via bundler 58 | } 59 | }, 60 | "ruby.format": "rubocop", 61 | "ruby.useLanguageServer": true, 62 | "sorbet.enabled": true 63 | } 64 | ``` 65 | 66 | ### Commit message convention 67 | 68 | This repository follows a commit message convention in order to automatically generate the [CHANGELOG](./CHANGELOG.md). Make sure you follow the rules of [conventional commits](https://www.conventionalcommits.org/) when opening a pull request. 69 | 70 | ### Releasing a new version (for Stream developers) 71 | 72 | In order to release new version you need to be a maintainer of the library. 73 | 74 | - Kick off a job called `initiate_release` ([link](https://github.com/GetStream/stream-chat-ruby/actions/workflows/initiate_release.yml)). 75 | 76 | The job creates a pull request with the changelog. Check if it looks good. 77 | 78 | - Merge the pull request. 79 | 80 | Once the PR is merged, it automatically kicks off another job which will upload the Gem to RubyGems.org and creates a GitHub release. -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gemspec 6 | 7 | group :dev do 8 | gem 'method_source', '~> 1.0' 9 | gem 'pry', '~> 0.14' 10 | gem 'pry-doc', '~> 1.3' 11 | gem 'rake', '~> 13.0' 12 | gem 'rspec', '~> 3.12' 13 | gem 'rubocop', '~> 1.38', require: false 14 | gem 'rubocop-ast', '~> 1.23', require: false 15 | gem 'simplecov', '~> 0.21.2' 16 | gem 'simplecov-console', '~> 0.9.1' 17 | gem 'sorbet', '~> 0.5.10539' 18 | end 19 | 20 | group :test do 21 | gem 'rack', '~> 2.2.4' 22 | end 23 | 24 | ruby '>= 3.0.0' 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | SOURCE CODE LICENSE AGREEMENT 2 | 3 | IMPORTANT - READ THIS CAREFULLY BEFORE DOWNLOADING, INSTALLING, USING OR 4 | ELECTRONICALLY ACCESSING THIS PROPRIETARY PRODUCT. 5 | 6 | THIS IS A LEGAL AGREEMENT BETWEEN STREAM.IO, INC. (“STREAM.IO”) AND THE 7 | BUSINESS ENTITY OR PERSON FOR WHOM YOU (“YOU”) ARE ACTING (“CUSTOMER”) AS THE 8 | LICENSEE OF THE PROPRIETARY SOFTWARE INTO WHICH THIS AGREEMENT HAS BEEN 9 | INCLUDED (THE “AGREEMENT”). YOU AGREE THAT YOU ARE THE CUSTOMER, OR YOU ARE AN 10 | EMPLOYEE OR AGENT OF CUSTOMER AND ARE ENTERING INTO THIS AGREEMENT FOR LICENSE 11 | OF THE SOFTWARE BY CUSTOMER FOR CUSTOMER’S BUSINESS PURPOSES AS DESCRIBED IN 12 | AND IN ACCORDANCE WITH THIS AGREEMENT. YOU HEREBY AGREE THAT YOU ENTER INTO 13 | THIS AGREEMENT ON BEHALF OF CUSTOMER AND THAT YOU HAVE THE AUTHORITY TO BIND 14 | CUSTOMER TO THIS AGREEMENT. 15 | 16 | STREAM.IO IS WILLING TO LICENSE THE SOFTWARE TO CUSTOMER ONLY ON THE FOLLOWING 17 | CONDITIONS: (1) YOU ARE A CURRENT CUSTOMER OF STREAM.IO; (2) YOU ARE NOT A 18 | COMPETITOR OF STREAM.IO; AND (3) THAT YOU ACCEPT ALL THE TERMS IN THIS 19 | AGREEMENT. BY DOWNLOADING, INSTALLING, CONFIGURING, ACCESSING OR OTHERWISE 20 | USING THE SOFTWARE, INCLUDING ANY UPDATES, UPGRADES, OR NEWER VERSIONS, YOU 21 | REPRESENT, WARRANT AND ACKNOWLEDGE THAT (A) CUSTOMER IS A CURRENT CUSTOMER OF 22 | STREAM.IO; (B) CUSTOMER IS NOT A COMPETITOR OF STREAM.IO; AND THAT (C) YOU HAVE 23 | READ THIS AGREEMENT, UNDERSTAND THIS AGREEMENT, AND THAT CUSTOMER AGREES TO BE 24 | BOUND BY ALL THE TERMS OF THIS AGREEMENT. 25 | 26 | IF YOU DO NOT AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT, 27 | STREAM.IO IS UNWILLING TO LICENSE THE SOFTWARE TO CUSTOMER, AND THEREFORE, DO 28 | NOT COMPLETE THE DOWNLOAD PROCESS, ACCESS OR OTHERWISE USE THE SOFTWARE, AND 29 | CUSTOMER SHOULD IMMEDIATELY RETURN THE SOFTWARE AND CEASE ANY USE OF THE 30 | SOFTWARE. 31 | 32 | 1. SOFTWARE. The Stream.io software accompanying this Agreement, may include 33 | Source Code, Executable Object Code, associated media, printed materials and 34 | documentation (collectively, the “Software”). The Software also includes any 35 | updates or upgrades to or new versions of the original Software, if and when 36 | made available to you by Stream.io. “Source Code” means computer programming 37 | code in human readable form that is not suitable for machine execution without 38 | the intervening steps of interpretation or compilation. “Executable Object 39 | Code" means the computer programming code in any other form than Source Code 40 | that is not readily perceivable by humans and suitable for machine execution 41 | without the intervening steps of interpretation or compilation. “Site” means a 42 | Customer location controlled by Customer. “Authorized User” means any employee 43 | or contractor of Customer working at the Site, who has signed a written 44 | confidentiality agreement with Customer or is otherwise bound in writing by 45 | confidentiality and use obligations at least as restrictive as those imposed 46 | under this Agreement. 47 | 48 | 2. LICENSE GRANT. Subject to the terms and conditions of this Agreement, in 49 | consideration for the representations, warranties, and covenants made by 50 | Customer in this Agreement, Stream.io grants to Customer, during the term of 51 | this Agreement, a personal, non-exclusive, non-transferable, non-sublicensable 52 | license to: 53 | 54 | a. install and use Software Source Code on password protected computers at a Site, 55 | restricted to Authorized Users; 56 | 57 | b. create derivative works, improvements (whether or not patentable), extensions 58 | and other modifications to the Software Source Code (“Modifications”) to build 59 | unique scalable newsfeeds, activity streams, and in-app messaging via Stream’s 60 | application program interface (“API”); 61 | 62 | c. compile the Software Source Code to create Executable Object Code versions of 63 | the Software Source Code and Modifications to build such newsfeeds, activity 64 | streams, and in-app messaging via the API; 65 | 66 | d. install, execute and use such Executable Object Code versions solely for 67 | Customer’s internal business use (including development of websites through 68 | which data generated by Stream services will be streamed (“Apps”)); 69 | 70 | e. use and distribute such Executable Object Code as part of Customer’s Apps; and 71 | 72 | f. make electronic copies of the Software and Modifications as required for backup 73 | or archival purposes. 74 | 75 | 3. RESTRICTIONS. Customer is responsible for all activities that occur in 76 | connection with the Software. Customer will not, and will not attempt to: (a) 77 | sublicense or transfer the Software or any Source Code related to the Software 78 | or any of Customer’s rights under this Agreement, except as otherwise provided 79 | in this Agreement, (b) use the Software Source Code for the benefit of a third 80 | party or to operate a service; (c) allow any third party to access or use the 81 | Software Source Code; (d) sublicense or distribute the Software Source Code or 82 | any Modifications in Source Code or other derivative works based on any part of 83 | the Software Source Code; (e) use the Software in any manner that competes with 84 | Stream.io or its business; or (e) otherwise use the Software in any manner that 85 | exceeds the scope of use permitted in this Agreement. Customer shall use the 86 | Software in compliance with any accompanying documentation any laws applicable 87 | to Customer. 88 | 89 | 4. OPEN SOURCE. Customer and its Authorized Users shall not use any software or 90 | software components that are open source in conjunction with the Software 91 | Source Code or any Modifications in Source Code or in any way that could 92 | subject the Software to any open source licenses. 93 | 94 | 5. CONTRACTORS. Under the rights granted to Customer under this Agreement, 95 | Customer may permit its employees, contractors, and agencies of Customer to 96 | become Authorized Users to exercise the rights to the Software granted to 97 | Customer in accordance with this Agreement solely on behalf of Customer to 98 | provide services to Customer; provided that Customer shall be liable for the 99 | acts and omissions of all Authorized Users to the extent any of such acts or 100 | omissions, if performed by Customer, would constitute a breach of, or otherwise 101 | give rise to liability to Customer under, this Agreement. Customer shall not 102 | and shall not permit any Authorized User to use the Software except as 103 | expressly permitted in this Agreement. 104 | 105 | 6. COMPETITIVE PRODUCT DEVELOPMENT. Customer shall not use the Software in any way 106 | to engage in the development of products or services which could be reasonably 107 | construed to provide a complete or partial functional or commercial alternative 108 | to Stream.io’s products or services (a “Competitive Product”). Customer shall 109 | ensure that there is no direct or indirect use of, or sharing of, Software 110 | source code, or other information based upon or derived from the Software to 111 | develop such products or services. Without derogating from the generality of 112 | the foregoing, development of Competitive Products shall include having direct 113 | or indirect access to, supervising, consulting or assisting in the development 114 | of, or producing any specifications, documentation, object code or source code 115 | for, all or part of a Competitive Product. 116 | 117 | 7. LIMITATION ON MODIFICATIONS. Notwithstanding any provision in this Agreement, 118 | Modifications may only be created and used by Customer as permitted by this 119 | Agreement and Modification Source Code may not be distributed to third parties. 120 | Customer will not assert against Stream.io, its affiliates, or their customers, 121 | direct or indirect, agents and contractors, in any way, any patent rights that 122 | Customer may obtain relating to any Modifications for Stream.io, its 123 | affiliates’, or their customers’, direct or indirect, agents’ and contractors’ 124 | manufacture, use, import, offer for sale or sale of any Stream.io products or 125 | services. 126 | 127 | 8. DELIVERY AND ACCEPTANCE. The Software will be delivered electronically pursuant 128 | to Stream.io standard download procedures. The Software is deemed accepted upon 129 | delivery. 130 | 131 | 9. IMPLEMENTATION AND SUPPORT. Stream.io has no obligation under this Agreement to 132 | provide any support or consultation concerning the Software. 133 | 134 | 10. TERM AND TERMINATION. The term of this Agreement begins when the Software is 135 | downloaded or accessed and shall continue until terminated. Either party may 136 | terminate this Agreement upon written notice. This Agreement shall 137 | automatically terminate if Customer is or becomes a competitor of Stream.io or 138 | makes or sells any Competitive Products. Upon termination of this Agreement for 139 | any reason, (a) all rights granted to Customer in this Agreement immediately 140 | cease to exist, (b) Customer must promptly discontinue all use of the Software 141 | and return to Stream.io or destroy all copies of the Software in Customer’s 142 | possession or control. Any continued use of the Software by Customer or attempt 143 | by Customer to exercise any rights under this Agreement after this Agreement 144 | has terminated shall be considered copyright infringement and subject Customer 145 | to applicable remedies for copyright infringement. Sections 2, 5, 6, 8 and 9 146 | shall survive expiration or termination of this Agreement for any reason. 147 | 148 | 11. OWNERSHIP. As between the parties, the Software and all worldwide intellectual 149 | property rights and proprietary rights relating thereto or embodied therein, 150 | are the exclusive property of Stream.io and its suppliers. Stream.io and its 151 | suppliers reserve all rights in and to the Software not expressly granted to 152 | Customer in this Agreement, and no other licenses or rights are granted by 153 | implication, estoppel or otherwise. 154 | 155 | 12. WARRANTY DISCLAIMER. USE OF THIS SOFTWARE IS ENTIRELY AT YOURS AND CUSTOMER’S 156 | OWN RISK. THE SOFTWARE IS PROVIDED “AS IS” WITHOUT ANY WARRANTY OF ANY KIND 157 | WHATSOEVER. STREAM.IO DOES NOT MAKE, AND HEREBY DISCLAIMS, ANY WARRANTY OF ANY 158 | KIND, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT 159 | LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 160 | PURPOSE, TITLE, NON-INFRINGEMENT OF THIRD-PARTY RIGHTS, RESULTS, EFFORTS, 161 | QUALITY OR QUIET ENJOYMENT. STREAM.IO DOES NOT WARRANT THAT THE SOFTWARE IS 162 | ERROR-FREE, WILL FUNCTION WITHOUT INTERRUPTION, WILL MEET ANY SPECIFIC NEED 163 | THAT CUSTOMER HAS, THAT ALL DEFECTS WILL BE CORRECTED OR THAT IT IS 164 | SUFFICIENTLY DOCUMENTED TO BE USABLE BY CUSTOMER. TO THE EXTENT THAT STREAM.IO 165 | MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW, THE SCOPE AND 166 | DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW. 167 | CUSTOMER ACKNOWLEDGES THAT IT HAS RELIED ON NO WARRANTIES OTHER THAN THE 168 | EXPRESS WARRANTIES IN THIS AGREEMENT. 169 | 170 | 13. LIMITATION OF LIABILITY. TO THE FULLEST EXTENT PERMISSIBLE BY LAW, STREAM.IO’S 171 | TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR RELATED TO THE SOFTWARE OR 172 | THIS AGREEMENT, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, 173 | SHALL NOT EXCEED $100. IN NO EVENT WILL STREAM.IO BE LIABLE FOR ANY INDIRECT, 174 | CONSEQUENTIAL, EXEMPLARY, PUNITIVE, SPECIAL OR INCIDENTAL DAMAGES OF ANY KIND 175 | WHATSOEVER, INCLUDING ANY LOST DATA AND LOST PROFITS, ARISING FROM OR RELATING 176 | TO THE SOFTWARE EVEN IF STREAM.IO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 177 | DAMAGES. CUSTOMER ACKNOWLEDGES THAT THIS PROVISION REFLECTS THE AGREED UPON 178 | ALLOCATION OF RISK FOR THIS AGREEMENT AND THAT STREAM.IO WOULD NOT ENTER INTO 179 | THIS AGREEMENT WITHOUT THESE LIMITATIONS ON ITS LIABILITY. 180 | 181 | 14. General. Customer may not assign or transfer this Agreement, by operation of 182 | law or otherwise, or any of its rights under this Agreement (including the 183 | license rights granted to Customer) to any third party without Stream.io’s 184 | prior written consent, which consent will not be unreasonably withheld or 185 | delayed. Stream.io may assign this Agreement, without consent, including, but 186 | limited to, affiliate or any successor to all or substantially all its business 187 | or assets to which this Agreement relates, whether by merger, sale of assets, 188 | sale of stock, reorganization or otherwise. Any attempted assignment or 189 | transfer in violation of the foregoing will be null and void. Stream.io shall 190 | not be liable hereunder by reason of any failure or delay in the performance of 191 | its obligations hereunder for any cause which is beyond the reasonable control. 192 | All notices, consents, and approvals under this Agreement must be delivered in 193 | writing by courier, by electronic mail, or by certified or registered mail, 194 | (postage prepaid and return receipt requested) to the other party at the 195 | address set forth in the customer agreement between Stream.io and Customer and 196 | will be effective upon receipt or when delivery is refused. This Agreement will 197 | be governed by and interpreted in accordance with the laws of the State of 198 | Colorado, without reference to its choice of laws rules. The United Nations 199 | Convention on Contracts for the International Sale of Goods does not apply to 200 | this Agreement. Any action or proceeding arising from or relating to this 201 | Agreement shall be brought in a federal or state court in Denver, Colorado, and 202 | each party irrevocably submits to the jurisdiction and venue of any such court 203 | in any such action or proceeding. All waivers must be in writing. Any waiver or 204 | failure to enforce any provision of this Agreement on one occasion will not be 205 | deemed a waiver of any other provision or of such provision on any other 206 | occasion. If any provision of this Agreement is unenforceable, such provision 207 | will be changed and interpreted to accomplish the objectives of such provision 208 | to the greatest extent possible under applicable law and the remaining 209 | provisions will continue in full force and effect. Customer shall not violate 210 | any applicable law, rule or regulation, including those regarding the export of 211 | technical data. The headings of Sections of this Agreement are for convenience 212 | and are not to be used in interpreting this Agreement. As used in this 213 | Agreement, the word “including” means “including but not limited to.” This 214 | Agreement (including all exhibits and attachments) constitutes the entire 215 | agreement between the parties regarding the subject hereof and supersedes all 216 | prior or contemporaneous agreements, understandings and communication, whether 217 | written or oral. This Agreement may be amended only by a written document 218 | signed by both parties. The terms of any purchase order or similar document 219 | submitted by Customer to Stream.io will have no effect. 220 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Submit a pull request 2 | 3 | ## CLA 4 | 5 | - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required). 6 | - [ ] The code changes follow best practices 7 | - [ ] Code changes are tested (add some information if not applicable) 8 | 9 | ## Description of the pull request 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Official Ruby SDK for [Stream Chat](https://getstream.io/chat/) 2 | 3 | [![build](https://github.com/GetStream/stream-chat-ruby/workflows/build/badge.svg)](https://github.com/GetStream/stream-chat-ruby/actions) [![Gem Version](https://badge.fury.io/rb/stream-chat-ruby.svg)](http://badge.fury.io/rb/stream-chat-ruby) 4 | 5 |

6 | 7 |

8 |

9 | Official Ruby API client for Stream Chat, a service for building chat applications. 10 |
11 | Explore the docs » 12 |
13 |
14 | Code Samples 15 | · 16 | Report Bug 17 | · 18 | Request Feature 19 |

20 | 21 | ## 📝 About Stream 22 | 23 | You can sign up for a Stream account at our [Get Started](https://getstream.io/chat/get_started/) page. 24 | 25 | You can use this library to access chat API endpoints server-side. 26 | 27 | For the client-side integrations (web and mobile) have a look at the JavaScript, iOS and Android SDK libraries ([docs](https://getstream.io/chat/)). 28 | 29 | ## ⚙️ Installation 30 | 31 | [`stream-chat-ruby`](https://rubygems.org/gems/stream-chat-ruby) supports Ruby version `3.0` and greater. We test against Ruby versions `3.0`, `3.1` and `3.4`. 32 | 33 | ```bash 34 | $ gem install stream-chat-ruby 35 | ``` 36 | 37 | ## ✨ Getting started 38 | 39 | ```ruby 40 | require 'stream-chat' 41 | 42 | client = StreamChat::Client.new('STREAM_KEY', 'STREAM_SECRET') 43 | ``` 44 | 45 | > 💡 Note: since v2.21.0 we implemented [Sorbet](https://sorbet.org/) type checker. As of v2.x.x we only use it for static type checks and you won't notice any difference, but from v3.0.0 **we will enable runtime checks** 🚨 🚨 🚨. 46 | 47 | > What this means, is that you'll receive an error during runtime if you pass an invalid type to our methods. To prepare for that, just make sure whatever you pass in, matches the method signature (`sig { ... }`). 48 | 49 | > **Update (2022-May-24)**: we have relased [v3.0.0](https://github.com/GetStream/stream-chat-ruby/releases/tag/v3.0.0) with enabled runtime checks. 50 | 51 | --- 52 | 53 | > Additionally, in a future major version, we would like to enforce symbol hash keys during runtime to conform to Ruby best practises. It's a good idea to prepare your application for that. 54 | > 55 | > ```ruby 56 | > # Wrong: 57 | > user = { "user" => { "id" => "bob-1"}} 58 | > # Correct: 59 | > user = { user: { id: "bob-1" }} 60 | > ``` 61 | 62 | ### Generate a token for client-side usage: 63 | 64 | ```ruby 65 | client.create_token('bob-1') 66 | ``` 67 | 68 | ### Create/Update users 69 | 70 | ```ruby 71 | client.upsert_user({ 72 | id: 'bob-1', 73 | role: 'admin', 74 | name: 'Robert Tables' 75 | }) 76 | 77 | # Batch update is also supported 78 | jane = {id: 'jane-1'} 79 | june = {id: 'june-1'} 80 | client.upsert_users([jane, june]) 81 | ``` 82 | 83 | ### Channel types 84 | 85 | ```ruby 86 | client.create_channel_type({ 87 | name: 'livechat', 88 | automod: 'disabled', 89 | commands: ['ban'], 90 | mutes: true 91 | }) 92 | 93 | channel_types = client.list_channel_types() 94 | ``` 95 | 96 | ### Channels 97 | 98 | ```ruby 99 | # Create a channel with members from the start 100 | chan = client.channel("messaging", channel_id: "bob-and-jane", data: {:members => ['bob-1', 'jane-77']}) 101 | chan.create('bob-1') 102 | 103 | # Create a channel and then add members 104 | chan = client.channel("messaging", channel_id: "bob-and-jane") 105 | chan.create('bob-1') 106 | chan.add_members(['bob-1', 'jane-77']) 107 | ``` 108 | 109 | ### Reactions 110 | 111 | ```ruby 112 | chan.send_reaction(m1['id'], {type: 'like'}, 'bob-1') 113 | ``` 114 | 115 | ### Moderation 116 | 117 | ```ruby 118 | chan.add_moderators(['jane-77']) 119 | chan.demote_moderators(['bob-1']) 120 | 121 | chan.ban_user('bob-1', timeout: 30) 122 | 123 | chan.unban_user('bob-1') 124 | ``` 125 | 126 | ### Messages 127 | 128 | ```ruby 129 | m1 = chan.send_message({text: 'Hi Jane!'}, 'bob-1') 130 | 131 | deleted_message = client.delete_message(m1['message']['id']) 132 | 133 | ``` 134 | 135 | ### Devices 136 | 137 | ```ruby 138 | jane_phone = client.add_device({:id => 'iOS Device Token', :push_provider => push_provider.apn, :user_id => 'jane-77'}) 139 | 140 | client.get_devices('jane-77') 141 | 142 | client.remove_device(jane_phone['id'], jane_phone['user_id']) 143 | ``` 144 | 145 | ### Blocklists 146 | 147 | ```ruby 148 | client.create_blocklist('my_blocker', %w[fudge cream sugar]) 149 | 150 | # Enable it on 'messaging' channel type 151 | client.update_channel_type('messaging', blocklist: 'my_blocker', blocklist_behavior: 'block') 152 | 153 | client.get_blocklist('my_blocker') 154 | 155 | client.delete_blocklist('my_blocker') 156 | ``` 157 | 158 | ### Export Channels 159 | 160 | ```ruby 161 | # Register an export 162 | response = client.export_channels({type: 'messaging', id: 'jane'}) 163 | 164 | # Check completion 165 | status_response = client.get_export_channel_status(response['task_id']) 166 | # status_response['status'] == 'pending', 'completed' 167 | ``` 168 | 169 | ### Rate limits 170 | 171 | ```ruby 172 | # Get all rate limits 173 | limits = client.get_rate_limits 174 | 175 | # Get rate limits for specific platform(s) 176 | limits = client.get_rate_limits(server_side: true) 177 | 178 | # Get rate limits for specific platforms and endpoints 179 | limits = client.get_rate_limits(android: true, ios: true, endpoints: ['QueryChannels', 'SendMessage']) 180 | ``` 181 | 182 | ## ✍️ Contributing 183 | 184 | We welcome code changes that improve this library or fix a problem, please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github. We are very happy to merge your code in the official repository. Make sure to sign our [Contributor License Agreement (CLA)](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) first. See our [license file](./LICENSE) for more details. 185 | 186 | Head over to [CONTRIBUTING.md](./CONTRIBUTING.md) for some development tips. 187 | 188 | ## 🧑‍💻 We are hiring! 189 | 190 | We've recently closed a [$38 million Series B funding round](https://techcrunch.com/2021/03/04/stream-raises-38m-as-its-chat-and-activity-feed-apis-power-communications-for-1b-users/) and we keep actively growing. 191 | Our APIs are used by more than a billion end-users, and you'll have a chance to make a huge impact on the product within a team of the strongest engineers all over the world. 192 | 193 | Check out our current openings and apply via [Stream's website](https://getstream.io/team/#jobs). 194 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/gem_tasks' 4 | # rake spec 5 | require 'rspec/core/rake_task' 6 | RSpec::Core::RakeTask.new(:spec) { |t| t.verbose = false } 7 | 8 | # rake console 9 | task :console do 10 | require 'pry' 11 | require 'stream-chat' 12 | ARGV.clear 13 | Pry.start 14 | end 15 | 16 | require 'rubocop/rake_task' 17 | RuboCop::RakeTask.new(:rubocop) do |t| 18 | t.options = ['--display-cop-names'] 19 | end 20 | 21 | task default: [:spec] 22 | task test: [:spec] 23 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting a Vulnerability 2 | At Stream we are committed to the security of our Software. We appreciate your efforts in disclosing vulnerabilities responsibly and we will make every effort to acknowledge your contributions. 3 | 4 | Report security vulnerabilities at the following email address: 5 | ``` 6 | [security@getstream.io](mailto:security@getstream.io) 7 | ``` 8 | Alternatively it is also possible to open a new issue in the affected repository, tagging it with the `security` tag. 9 | 10 | A team member will acknowledge the vulnerability and will follow-up with more detailed information. A representative of the security team will be in touch if more information is needed. 11 | 12 | # Information to include in a report 13 | While we appreciate any information that you are willing to provide, please make sure to include the following: 14 | * Which repository is affected 15 | * Which branch, if relevant 16 | * Be as descriptive as possible, the team will replicate the vulnerability before working on a fix. 17 | -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | STREAM MARK 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /lib/stream-chat.rb: -------------------------------------------------------------------------------- 1 | # typed: strict # rubocop:todo Naming/FileName 2 | # frozen_string_literal: true 3 | 4 | require 'stream-chat/client' 5 | -------------------------------------------------------------------------------- /lib/stream-chat/channel.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | require 'stream-chat/client' 5 | require 'stream-chat/errors' 6 | require 'stream-chat/util' 7 | require 'stream-chat/types' 8 | 9 | module StreamChat 10 | class Channel 11 | extend T::Sig 12 | 13 | sig { returns(T.nilable(String)) } 14 | attr_reader :id 15 | 16 | sig { returns(String) } 17 | attr_reader :channel_type 18 | 19 | sig { returns(String) } 20 | attr_reader :cid 21 | 22 | sig { returns(StringKeyHash) } 23 | attr_reader :custom_data 24 | 25 | sig { returns(T::Array[StringKeyHash]) } 26 | attr_reader :members 27 | 28 | sig { params(client: StreamChat::Client, channel_type: String, channel_id: T.nilable(String), custom_data: T.nilable(StringKeyHash)).void } 29 | def initialize(client, channel_type, channel_id = nil, custom_data = nil) 30 | @channel_type = channel_type 31 | @id = channel_id 32 | @cid = T.let("#{@channel_type}:#{@id}", String) 33 | @client = client 34 | @custom_data = T.let(custom_data || {}, StringKeyHash) 35 | @members = T.let([], T::Array[StringKeyHash]) 36 | end 37 | 38 | sig { returns(String) } 39 | def url 40 | raise StreamChannelException, 'channel does not have an id' if @id.nil? 41 | 42 | "channels/#{@channel_type}/#{@id}" 43 | end 44 | 45 | # Gets multiple messages from the channel. 46 | sig { params(message_ids: T::Array[String]).returns(StreamChat::StreamResponse) } 47 | def get_messages(message_ids) 48 | @client.get("#{url}/messages", params: { 'ids' => message_ids.join(',') }) 49 | end 50 | 51 | # Sends a message to this channel. 52 | sig { params(message: StringKeyHash, user_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 53 | def send_message(message, user_id, **options) 54 | payload = options.merge({ message: add_user_id(message, user_id) }) 55 | @client.post("#{url}/message", data: payload) 56 | end 57 | 58 | # Sends an event on this channel. 59 | sig { params(event: StringKeyHash, user_id: String).returns(StreamChat::StreamResponse) } 60 | def send_event(event, user_id) 61 | payload = { 'event' => add_user_id(event, user_id) } 62 | @client.post("#{url}/event", data: payload) 63 | end 64 | 65 | # Sends a new reaction to a given message. 66 | sig { params(message_id: String, reaction: StringKeyHash, user_id: String).returns(StreamChat::StreamResponse) } 67 | def send_reaction(message_id, reaction, user_id) 68 | payload = { reaction: add_user_id(reaction, user_id) } 69 | @client.post("messages/#{message_id}/reaction", data: payload) 70 | end 71 | 72 | # Delete a reaction from a message. 73 | sig { params(message_id: String, reaction_type: String, user_id: String).returns(StreamChat::StreamResponse) } 74 | def delete_reaction(message_id, reaction_type, user_id) 75 | @client.delete( 76 | "messages/#{message_id}/reaction/#{reaction_type}", 77 | params: { user_id: user_id } 78 | ) 79 | end 80 | 81 | # Creates a channel with the given creator user. 82 | sig { params(user_id: String).returns(StreamChat::StreamResponse) } 83 | def create(user_id) 84 | @custom_data['created_by'] = { id: user_id } 85 | query(watch: false, state: false, presence: false) 86 | end 87 | 88 | # Creates or returns a channel. 89 | sig { params(options: T.untyped).returns(StreamChat::StreamResponse) } 90 | def query(**options) 91 | payload = { state: true, data: @custom_data }.merge(options) 92 | url = "channels/#{@channel_type}" 93 | url = "#{url}/#{@id}" unless @id.nil? 94 | 95 | state = @client.post("#{url}/query", data: payload) 96 | @id = state['channel']['id'] if @id.nil? 97 | state 98 | end 99 | 100 | # Queries members of a channel. 101 | # 102 | # The queryMembers endpoint allows you to list and paginate members from a channel. The 103 | # endpoint supports filtering on numerous criteria to efficiently return members information. 104 | # This endpoint is useful for channels that have large lists of members and 105 | # you want to search members or if you want to display the full list of members for a channel. 106 | sig { params(filter_conditions: StringKeyHash, sort: T.nilable(T::Hash[String, Integer]), options: T.untyped).returns(StreamChat::StreamResponse) } 107 | def query_members(filter_conditions = {}, sort: nil, **options) 108 | params = {}.merge(options).merge({ 109 | id: @id, 110 | type: @channel_type, 111 | filter_conditions: filter_conditions, 112 | sort: StreamChat.get_sort_fields(sort) 113 | }) 114 | 115 | if @id == '' && @members.length.positive? 116 | params['members'] = [] 117 | @members.each do |m| 118 | params['members'] << m['user'].nil? ? m['user_id'] : m['user']['id'] 119 | end 120 | end 121 | 122 | @client.get('members', params: { payload: params.to_json }) 123 | end 124 | 125 | # Updates a channel. 126 | sig { params(channel_data: T.nilable(StringKeyHash), update_message: T.nilable(StringKeyHash), options: T.untyped).returns(StreamChat::StreamResponse) } 127 | def update(channel_data, update_message = nil, **options) 128 | payload = { data: channel_data, message: update_message }.merge(options) 129 | @client.post(url, data: payload) 130 | end 131 | 132 | # Updates a channel partially. 133 | sig { params(set: T.nilable(StringKeyHash), unset: T.nilable(T::Array[String])).returns(StreamChat::StreamResponse) } 134 | def update_partial(set = nil, unset = nil) 135 | raise StreamChannelException, 'set or unset is needed' if set.nil? && unset.nil? 136 | 137 | payload = { set: set, unset: unset } 138 | @client.patch(url, data: payload) 139 | end 140 | 141 | # Deletes a channel. 142 | sig { returns(StreamChat::StreamResponse) } 143 | def delete 144 | @client.delete(url) 145 | end 146 | 147 | # Removes all messages from the channel. 148 | sig { params(options: T.untyped).returns(StreamChat::StreamResponse) } 149 | def truncate(**options) 150 | @client.post("#{url}/truncate", data: options) 151 | end 152 | 153 | # Mutes a channel. 154 | # 155 | # Messages added to a muted channel will not trigger push notifications, nor change the 156 | # unread count for the users that muted it. By default, mutes stay in place indefinitely 157 | # until the user removes it; however, you can optionally set an expiration time. The list 158 | # of muted channels and their expiration time is returned when the user connects. 159 | sig { params(user_id: String, expiration: T.nilable(Integer)).returns(StreamChat::StreamResponse) } 160 | def mute(user_id, expiration = nil) 161 | data = { user_id: user_id, channel_cid: @cid } 162 | data['expiration'] = expiration if expiration 163 | @client.post('moderation/mute/channel', data: data) 164 | end 165 | 166 | # Unmutes a channel. 167 | sig { params(user_id: String).returns(StreamChat::StreamResponse) } 168 | def unmute(user_id) 169 | @client.post('moderation/unmute/channel', data: { 'user_id' => user_id, 'channel_cid' => @cid }) 170 | end 171 | 172 | # Pins a channel for a user. 173 | sig { params(user_id: String).returns(StreamChat::StreamResponse) } 174 | def pin(user_id) 175 | raise StreamChannelException, 'user ID must not be empty' if user_id.empty? 176 | 177 | payload = { 178 | set: { 179 | pinned: true 180 | } 181 | } 182 | @client.patch("#{url}/member/#{CGI.escape(user_id)}", data: payload) 183 | end 184 | 185 | # Unins a channel for a user. 186 | sig { params(user_id: String).returns(StreamChat::StreamResponse) } 187 | def unpin(user_id) 188 | raise StreamChannelException, 'user ID must not be empty' if user_id.empty? 189 | 190 | payload = { 191 | set: { 192 | pinned: false 193 | } 194 | } 195 | @client.patch("#{url}/member/#{CGI.escape(user_id)}", data: payload) 196 | end 197 | 198 | # Archives a channel for a user. 199 | sig { params(user_id: String).returns(StreamChat::StreamResponse) } 200 | def archive(user_id) 201 | raise StreamChannelException, 'user ID must not be empty' if user_id.empty? 202 | 203 | payload = { 204 | set: { 205 | archived: true 206 | } 207 | } 208 | @client.patch("#{url}/member/#{CGI.escape(user_id)}", data: payload) 209 | end 210 | 211 | # Archives a channel for a user. 212 | sig { params(user_id: String).returns(StreamChat::StreamResponse) } 213 | def unarchive(user_id) 214 | raise StreamChannelException, 'user ID must not be empty' if user_id.empty? 215 | 216 | payload = { 217 | set: { 218 | archived: false 219 | } 220 | } 221 | @client.patch("#{url}/member/#{CGI.escape(user_id)}", data: payload) 222 | end 223 | 224 | # Updates a member partially in the channel. 225 | sig { params(user_id: String, set: T.nilable(StringKeyHash), unset: T.nilable(T::Array[String])).returns(StreamChat::StreamResponse) } 226 | def update_member_partial(user_id, set: nil, unset: nil) 227 | raise StreamChannelException, 'user ID must not be empty' if user_id.empty? 228 | raise StreamChannelException, 'set or unset is required' if set.nil? && unset.nil? 229 | 230 | payload = { set: set, unset: unset } 231 | @client.patch("#{url}/member/#{CGI.escape(user_id)}", data: payload) 232 | end 233 | 234 | # Adds members to the channel. 235 | sig { params(user_ids: T::Array[String], options: T.untyped).returns(StreamChat::StreamResponse) } 236 | def add_members(user_ids, **options) 237 | payload = options.merge({ add_members: user_ids }) 238 | update(nil, nil, **payload) 239 | end 240 | 241 | # Invites users to the channel. 242 | sig { params(user_ids: T::Array[String], options: T.untyped).returns(StreamChat::StreamResponse) } 243 | def invite_members(user_ids, **options) 244 | payload = options.merge({ invites: user_ids }) 245 | update(nil, nil, **payload) 246 | end 247 | 248 | # Accepts an invitation to the channel. 249 | sig { params(user_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 250 | def accept_invite(user_id, **options) 251 | payload = options.merge({ user_id: user_id, accept_invite: true }) 252 | update(nil, nil, **payload) 253 | end 254 | 255 | # Rejects an invitation to the channel. 256 | sig { params(user_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 257 | def reject_invite(user_id, **options) 258 | payload = options.merge({ user_id: user_id, reject_invite: true }) 259 | update(nil, nil, **payload) 260 | end 261 | 262 | # Adds moderators to the channel. 263 | sig { params(user_ids: T::Array[String]).returns(StreamChat::StreamResponse) } 264 | def add_moderators(user_ids) 265 | update(nil, nil, add_moderators: user_ids) 266 | end 267 | 268 | # Removes members from the channel. 269 | sig { params(user_ids: T::Array[String]).returns(StreamChat::StreamResponse) } 270 | def remove_members(user_ids) 271 | update(nil, nil, remove_members: user_ids) 272 | end 273 | 274 | # Assigns roles to members in the channel. 275 | sig { params(members: T::Array[StringKeyHash], message: T.nilable(StringKeyHash)).returns(StreamChat::StreamResponse) } 276 | def assign_roles(members, message = nil) 277 | update(nil, message, assign_roles: members) 278 | end 279 | 280 | # Demotes moderators in the channel. 281 | sig { params(user_ids: T::Array[String]).returns(StreamChat::StreamResponse) } 282 | def demote_moderators(user_ids) 283 | update(nil, nil, demote_moderators: user_ids) 284 | end 285 | 286 | # Sends the mark read event for this user, only works if the `read_events` setting is enabled. 287 | sig { params(user_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 288 | def mark_read(user_id, **options) 289 | payload = add_user_id(options, user_id) 290 | @client.post("#{url}/read", data: payload) 291 | end 292 | 293 | # List the message replies for a parent message. 294 | sig { params(parent_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 295 | def get_replies(parent_id, **options) 296 | @client.get("messages/#{parent_id}/replies", params: options) 297 | end 298 | 299 | # List the reactions, supports pagination. 300 | sig { params(message_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 301 | def get_reactions(message_id, **options) 302 | @client.get("messages/#{message_id}/reactions", params: options) 303 | end 304 | 305 | # Bans a user from this channel. 306 | sig { params(user_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 307 | def ban_user(user_id, **options) 308 | @client.ban_user(user_id, type: @channel_type, id: @id, **options) 309 | end 310 | 311 | # Removes the ban for a user on this channel. 312 | sig { params(user_id: String).returns(StreamChat::StreamResponse) } 313 | def unban_user(user_id) 314 | @client.unban_user(user_id, type: @channel_type, id: @id) 315 | end 316 | 317 | # Removes a channel from query channel requests for that user until a new message is added. 318 | # Use `show` to cancel this operation. 319 | sig { params(user_id: String).returns(StreamChat::StreamResponse) } 320 | def hide(user_id) 321 | @client.post("#{url}/hide", data: { user_id: user_id }) 322 | end 323 | 324 | # Shows a previously hidden channel. 325 | # Use `hide` to hide a channel. 326 | sig { params(user_id: String).returns(StreamChat::StreamResponse) } 327 | def show(user_id) 328 | @client.post("#{url}/show", data: { user_id: user_id }) 329 | end 330 | 331 | # Uploads a file. 332 | # 333 | # This functionality defaults to using the Stream CDN. If you would like, you can 334 | # easily change the logic to upload to your own CDN of choice. 335 | sig { params(url: String, user: StringKeyHash, content_type: T.nilable(String)).returns(StreamChat::StreamResponse) } 336 | def send_file(url, user, content_type = nil) 337 | @client.send_file("#{self.url}/file", url, user, content_type) 338 | end 339 | 340 | # Uploads an image. 341 | # 342 | # Stream supported image types are: image/bmp, image/gif, image/jpeg, image/png, image/webp, 343 | # image/heic, image/heic-sequence, image/heif, image/heif-sequence, image/svg+xml. 344 | # You can set a more restrictive list for your application if needed. 345 | # The maximum file size is 100MB. 346 | sig { params(url: String, user: StringKeyHash, content_type: T.nilable(String)).returns(StreamChat::StreamResponse) } 347 | def send_image(url, user, content_type = nil) 348 | @client.send_file("#{self.url}/image", url, user, content_type) 349 | end 350 | 351 | # Deletes a file by file url. 352 | sig { params(url: String).returns(StreamChat::StreamResponse) } 353 | def delete_file(url) 354 | @client.delete("#{self.url}/file", params: { url: url }) 355 | end 356 | 357 | # Deletes an image by image url. 358 | sig { params(url: String).returns(StreamChat::StreamResponse) } 359 | def delete_image(url) 360 | @client.delete("#{self.url}/image", params: { url: url }) 361 | end 362 | 363 | # Creates or updates a draft message for this channel. 364 | # 365 | # @param [StringKeyHash] message The draft message content 366 | # @param [String] user_id The ID of the user creating/updating the draft 367 | # @return [StreamChat::StreamResponse] 368 | sig { params(message: StringKeyHash, user_id: String).returns(StreamChat::StreamResponse) } 369 | def create_draft(message, user_id) 370 | payload = { message: add_user_id(message, user_id) } 371 | @client.post("#{url}/draft", data: payload) 372 | end 373 | 374 | # Deletes a draft message for this channel. 375 | # 376 | # @param [String] user_id The ID of the user deleting the draft 377 | # @param [String] parent_id Optional parent message ID for thread drafts 378 | # @return [StreamChat::StreamResponse] 379 | sig { params(user_id: String, parent_id: T.nilable(String)).returns(StreamChat::StreamResponse) } 380 | def delete_draft(user_id, parent_id: nil) 381 | params = { user_id: user_id } 382 | params[:parent_id] = parent_id if parent_id 383 | @client.delete("#{url}/draft", params: params) 384 | end 385 | 386 | # Gets a draft message for this channel. 387 | # 388 | # @param [String] user_id The ID of the user getting the draft 389 | # @param [String] parent_id Optional parent message ID for thread drafts 390 | # @return [StreamChat::StreamResponse] 391 | sig { params(user_id: String, parent_id: T.nilable(String)).returns(StreamChat::StreamResponse) } 392 | def get_draft(user_id, parent_id: nil) 393 | params = { user_id: user_id } 394 | params[:parent_id] = parent_id if parent_id 395 | @client.get("#{url}/draft", params: params) 396 | end 397 | 398 | private 399 | 400 | sig { params(payload: StringKeyHash, user_id: String).returns(StringKeyHash) } 401 | def add_user_id(payload, user_id) 402 | payload.merge({ user: { id: user_id } }) 403 | end 404 | end 405 | end 406 | -------------------------------------------------------------------------------- /lib/stream-chat/errors.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module StreamChat 5 | class StreamAPIException < StandardError 6 | extend T::Sig 7 | 8 | sig { returns(Integer) } 9 | attr_reader :error_code 10 | 11 | sig { returns(String) } 12 | attr_reader :error_message 13 | 14 | sig { returns(T::Boolean) } 15 | attr_reader :json_response 16 | 17 | sig { returns(Faraday::Response) } 18 | attr_reader :response 19 | 20 | sig { params(response: Faraday::Response).void } 21 | def initialize(response) 22 | super() 23 | @response = response 24 | begin 25 | parsed_response = JSON.parse(response.body) 26 | @json_response = T.let(true, T::Boolean) 27 | @error_code = T.let(parsed_response.fetch('code', 'unknown'), Integer) 28 | @error_message = T.let(parsed_response.fetch('message', 'unknown'), String) 29 | rescue JSON::ParserError 30 | @json_response = false 31 | end 32 | end 33 | 34 | sig { returns(String) } 35 | def message 36 | if @json_response 37 | "StreamChat error code #{@error_code}: #{@error_message}" 38 | else 39 | "StreamChat error HTTP code: #{@response.status}" 40 | end 41 | end 42 | 43 | sig { returns(String) } 44 | def to_s 45 | message 46 | end 47 | end 48 | 49 | class StreamChannelException < StandardError; end 50 | end 51 | -------------------------------------------------------------------------------- /lib/stream-chat/moderation.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | require 'stream-chat/client' 5 | require 'stream-chat/errors' 6 | require 'stream-chat/util' 7 | require 'stream-chat/types' 8 | 9 | module StreamChat 10 | # Moderation class provides all the endpoints related to moderation v2 11 | class Moderation 12 | extend T::Sig 13 | 14 | MODERATION_ENTITY_TYPES = T.let( 15 | { 16 | user: 'stream:user', 17 | message: 'stream:chat:v1:message', 18 | userprofile: 'stream:v1:user_profile' 19 | }.freeze, 20 | T::Hash[Symbol, String] 21 | ) 22 | 23 | sig { params(client: Client).void } 24 | def initialize(client) 25 | @client = client 26 | end 27 | 28 | # Experimental: Check user profile 29 | # 30 | # Warning: This is an experimental feature and the API is subject to change. 31 | # 32 | # This function is used to check a user profile for moderation. 33 | # This will not create any review queue items for the user profile. 34 | # You can just use this to check whether to allow a certain user profile to be created or not. 35 | # 36 | # @param [string] user_id User ID to be checked 37 | # @param [Hash] profile Profile data to be checked 38 | # @option profile [String] :username Username to be checked 39 | # @option profile [String] :image Image URL to be checked 40 | # @return [StreamChat::StreamResponse] 41 | # 42 | # example: 43 | # client.moderation.check_user_profile('user-id', {username: 'bad_username', image: 'https://example.com/profile.jpg'}) 44 | sig do 45 | params( 46 | user_id: String, 47 | profile: T::Hash[Symbol, T.nilable(String)] 48 | ).returns(StreamChat::StreamResponse) 49 | end 50 | def check_user_profile(user_id, profile) 51 | raise ArgumentError, 'Either username or image must be provided' if profile[:username].nil? && profile[:image].nil? 52 | 53 | moderation_payload = {} 54 | moderation_payload[:texts] = [profile[:username]] if profile[:username] 55 | moderation_payload[:images] = [profile[:image]] if profile[:image] 56 | 57 | check( 58 | T.must(MODERATION_ENTITY_TYPES[:userprofile]), 59 | user_id, 60 | moderation_payload, 61 | 'user_profile:default', 62 | entity_creator_id: user_id, 63 | options: { 64 | force_sync: true, 65 | test_mode: true 66 | } 67 | ) 68 | end 69 | 70 | # Flags a user with a reason 71 | # 72 | # @param [string] flagged_user_id User ID to be flagged 73 | # @param [string] reason Reason for flagging the user 74 | # @param [Hash] options Additional options for flagging the user 75 | # @option options [String] :user_id User ID of the user who is flagging the target user 76 | # @option options [Hash] :custom Additional data to be stored with the flag 77 | sig { params(flagged_user_id: String, reason: String, options: T.untyped).returns(StreamChat::StreamResponse) } 78 | def flag_user(flagged_user_id, reason, **options) 79 | flag(T.must(MODERATION_ENTITY_TYPES[:user]), flagged_user_id, reason, **options) 80 | end 81 | 82 | # Flags a message with a reason 83 | # 84 | # @param [string] message_id Message ID to be flagged 85 | # @param [string] reason Reason for flagging the message 86 | # @param [Hash] options Additional options for flagging the message 87 | # @option options [String] :user_id User ID of the user who is flagging the target message 88 | # @option options [Hash] :custom Additional data to be stored with the flag 89 | sig { params(message_id: String, reason: String, options: T.untyped).returns(StreamChat::StreamResponse) } 90 | def flag_message(message_id, reason, **options) 91 | flag(T.must(MODERATION_ENTITY_TYPES[:message]), message_id, reason, **options) 92 | end 93 | 94 | # Flags an entity with a reason 95 | # 96 | # @param [string] entity_type Entity type to be flagged 97 | # @param [string] entity_id Entity ID to be flagged 98 | # @param [string] reason Reason for flagging the entity 99 | # @param [string] entity_creator_id User ID of the entity creator (optional) 100 | # @param [Hash] options Additional options for flagging the entity 101 | # @option options [String] :user_id User ID of the user who is flagging the target entity 102 | # @option options [Hash] :moderation_payload Content to be flagged 103 | # @option options [Hash] :custom Additional data to be stored with the flag 104 | sig { params(entity_type: String, entity_id: String, reason: String, entity_creator_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 105 | def flag(entity_type, entity_id, reason, entity_creator_id: '', **options) 106 | @client.post('api/v2/moderation/flag', data: { 107 | entity_type: entity_type, 108 | entity_id: entity_id, 109 | entity_creator_id: entity_creator_id, 110 | reason: reason, 111 | **options 112 | }) 113 | end 114 | 115 | # Mutes a user 116 | # 117 | # @param [string] target_id User ID to be muted 118 | # @param [Hash] options Additional options for muting the user 119 | # @option options [String] :user_id User ID of the user who is muting the target user 120 | # @option options [Integer] :timeout Timeout for the mute in minutes 121 | sig { params(target_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 122 | def mute_user(target_id, **options) 123 | @client.post('api/v2/moderation/mute', data: { 124 | target_ids: [target_id], 125 | **options 126 | }) 127 | end 128 | 129 | # Unmutes a user 130 | # 131 | # @param [string] target_id User ID to be unmuted 132 | # @param [Hash] options Additional options for unmuting the user 133 | # @option options [String] :user_id User ID of the user who is unmuting the target user 134 | sig { params(target_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 135 | def unmute_user(target_id, **options) 136 | @client.post('api/v2/moderation/unmute', data: { 137 | target_ids: [target_id], 138 | **options 139 | }) 140 | end 141 | 142 | # Gets moderation report for a user 143 | # 144 | # @param [string] user_id User ID for which moderation report is to be fetched 145 | # @param [Hash] options Additional options for fetching the moderation report 146 | # @option options [Boolean] :create_user_if_not_exists Create user if not exists 147 | # @option options [Boolean] :include_user_blocks Include user blocks 148 | # @option options [Boolean] :include_user_mutes Include user mutes 149 | sig { params(user_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 150 | def get_user_moderation_report(user_id, **options) 151 | @client.get('api/v2/moderation/user_report', params: { 152 | user_id: user_id, 153 | **options 154 | }) 155 | end 156 | 157 | # Queries review queue 158 | # 159 | # @param [Hash] filter_conditions Filter conditions for querying review queue 160 | # @param [Array] sort Sort conditions for querying review queue 161 | # @param [Hash] options Pagination options for querying review queue 162 | sig { params(filter_conditions: T.untyped, sort: T.untyped, options: T.untyped).returns(StreamChat::StreamResponse) } 163 | def query_review_queue(filter_conditions = {}, sort = [], **options) 164 | @client.post('api/v2/moderation/review_queue', data: { 165 | filter: filter_conditions, 166 | sort: StreamChat.get_sort_fields(sort), 167 | **options 168 | }) 169 | end 170 | 171 | # Upserts moderation config 172 | # 173 | # @param [Hash] config Moderation config to be upserted 174 | sig { params(config: T.untyped).returns(StreamChat::StreamResponse) } 175 | def upsert_config(config) 176 | @client.post('api/v2/moderation/config', data: config) 177 | end 178 | 179 | # Gets moderation config 180 | # 181 | # @param [string] key Key for which moderation config is to be fetched 182 | # @param [Hash] data Additional data 183 | # @option data [String] :team Team name 184 | sig { params(key: String, data: T.untyped).returns(StreamChat::StreamResponse) } 185 | def get_config(key, data = {}) 186 | @client.get("api/v2/moderation/config/#{key}", params: data) 187 | end 188 | 189 | # Deletes moderation config 190 | # 191 | # @param [string] key Key for which moderation config is to be deleted 192 | # @param [Hash] data Additional data 193 | # @option data [String] :team Team name 194 | sig { params(key: String, data: T.untyped).returns(StreamChat::StreamResponse) } 195 | def delete_config(key, data = {}) 196 | @client.delete("api/v2/moderation/config/#{key}", params: data) 197 | end 198 | 199 | # Queries moderation configs 200 | # 201 | # @param [Hash] filter_conditions Filter conditions for querying moderation configs 202 | # @param [Array] sort Sort conditions for querying moderation configs 203 | # @param [Hash] options Additional options for querying moderation configs 204 | sig { params(filter_conditions: T.untyped, sort: T.untyped, options: T.untyped).returns(StreamChat::StreamResponse) } 205 | def query_configs(filter_conditions, sort, **options) 206 | @client.post('api/v2/moderation/configs', data: { 207 | filter: filter_conditions, 208 | sort: sort, 209 | **options 210 | }) 211 | end 212 | 213 | # Submits a moderation action 214 | # 215 | # @param [string] action_type Type of action to submit 216 | # @param [string] item_id ID of the item to submit action for 217 | # @param [Hash] options Additional options for submitting the action 218 | sig { params(action_type: String, item_id: String, options: T.untyped).returns(StreamChat::StreamResponse) } 219 | def submit_action(action_type, item_id, **options) 220 | @client.post('api/v2/moderation/submit_action', data: { 221 | action_type: action_type, 222 | item_id: item_id, 223 | **options 224 | }) 225 | end 226 | 227 | # rubocop:disable Metrics/ParameterLists 228 | # Checks content for moderation 229 | # 230 | # @param [string] entity_type Type of entity to be checked E.g., stream:user, stream:chat:v1:message, or any custom string 231 | # @param [string] entity_id ID of the entity to be checked. This is mainly for tracking purposes 232 | # @param [string] entity_creator_id ID of the entity creator 233 | # @param [Hash] moderation_payload Content to be checked for moderation 234 | # @option moderation_payload [Array] :texts Array of texts to be checked for moderation 235 | # @option moderation_payload [Array] :images Array of images to be checked for moderation 236 | # @option moderation_payload [Array] :videos Array of videos to be checked for moderation 237 | # @option moderation_payload [Hash] :custom Additional custom data 238 | # @param [string] config_key Key of the moderation config to use 239 | # @param [Hash] options Additional options 240 | # @option options [Boolean] :force_sync Force synchronous check 241 | sig do 242 | params( 243 | entity_type: String, 244 | entity_id: String, 245 | moderation_payload: T::Hash[Symbol, T.any(T::Array[String], T::Hash[String, T.untyped])], 246 | config_key: String, 247 | entity_creator_id: String, 248 | options: T::Hash[Symbol, T::Boolean] 249 | ).returns(StreamChat::StreamResponse) 250 | end 251 | def check(entity_type, entity_id, moderation_payload, config_key, entity_creator_id: '', options: {}) 252 | @client.post('api/v2/moderation/check', data: { 253 | entity_type: entity_type, 254 | entity_id: entity_id, 255 | entity_creator_id: entity_creator_id, 256 | moderation_payload: moderation_payload, 257 | config_key: config_key, 258 | options: options 259 | }) 260 | end 261 | # rubocop:enable Metrics/ParameterLists 262 | # Adds custom flags to an entity 263 | # 264 | # @param [string] entity_type Type of entity to be checked 265 | # @param [string] entity_id ID of the entity to be checked 266 | # @param [string] entity_creator_id ID of the entity creator 267 | # @param [Hash] moderation_payload Content to be checked for moderation 268 | # @param [Array] flags Array of custom flags to add 269 | sig { params(entity_type: String, entity_id: String, moderation_payload: T.untyped, flags: T::Array[T.untyped], entity_creator_id: String).returns(StreamChat::StreamResponse) } 270 | def add_custom_flags(entity_type, entity_id, moderation_payload, flags, entity_creator_id: '') 271 | @client.post('api/v2/moderation/custom_check', data: { 272 | entity_type: entity_type, 273 | entity_id: entity_id, 274 | entity_creator_id: entity_creator_id, 275 | moderation_payload: moderation_payload, 276 | flags: flags 277 | }) 278 | end 279 | 280 | # Adds custom flags to a message 281 | # 282 | # @param [string] message_id Message ID to be flagged 283 | # @param [Array] flags Array of custom flags to add 284 | sig { params(message_id: String, flags: T::Array[T.untyped]).returns(StreamChat::StreamResponse) } 285 | def add_custom_message_flags(message_id, flags) 286 | add_custom_flags(T.must(MODERATION_ENTITY_TYPES[:message]), message_id, {}, flags) 287 | end 288 | end 289 | end 290 | -------------------------------------------------------------------------------- /lib/stream-chat/stream_rate_limits.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module StreamChat 5 | class StreamRateLimits 6 | extend T::Sig 7 | 8 | sig { returns(Integer) } 9 | attr_reader :limit 10 | 11 | sig { returns(Integer) } 12 | attr_reader :remaining 13 | 14 | sig { returns(Time) } 15 | attr_reader :reset 16 | 17 | sig { params(limit: String, remaining: String, reset: String).void } 18 | def initialize(limit, remaining, reset) 19 | @limit = T.let(limit.to_i, Integer) 20 | @remaining = T.let(remaining.to_i, Integer) 21 | @reset = T.let(Time.at(reset.to_i), Time) 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/stream-chat/stream_response.rb: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | require 'stream-chat/stream_rate_limits' 5 | require 'stream-chat/types' 6 | 7 | module StreamChat 8 | class StreamResponse < Hash 9 | extend T::Sig 10 | 11 | sig { returns(StreamRateLimits) } 12 | attr_reader :rate_limit 13 | 14 | sig { returns(Integer) } 15 | attr_reader :status_code 16 | 17 | sig { returns(StringKeyHash) } 18 | attr_reader :headers 19 | 20 | sig { params(hash: T::Hash[T.untyped, T.untyped], response: Faraday::Response).void } 21 | def initialize(hash, response) 22 | super(nil) 23 | merge!(hash) 24 | 25 | if response.headers.key?('X-Ratelimit-Limit') 26 | @rate_limit = T.let(StreamRateLimits.new( 27 | T.must(response.headers['X-Ratelimit-Limit']), 28 | T.must(response.headers['X-Ratelimit-Remaining']), 29 | T.must(response.headers['X-Ratelimit-Reset']) 30 | ), StreamRateLimits) 31 | end 32 | 33 | @status_code = T.let(response.status, Integer) 34 | @headers = T.let(response.headers, StringKeyHash) 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/stream-chat/types.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module StreamChat 5 | extend T::Sig 6 | 7 | StringKeyHash = T.type_alias { T::Hash[T.any(String, Symbol), T.untyped] } 8 | SortArray = T.type_alias { T::Array[{ field: String, direction: Integer }] } 9 | end 10 | -------------------------------------------------------------------------------- /lib/stream-chat/util.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | require 'stream-chat/types' 5 | 6 | module StreamChat 7 | extend T::Sig 8 | 9 | sig { params(sort: T.nilable(T::Hash[String, Integer])).returns(SortArray) } 10 | def self.get_sort_fields(sort) 11 | sort_fields = T.let([], SortArray) 12 | sort&.each do |k, v| 13 | sort_fields << { field: k, direction: v } 14 | end 15 | sort_fields 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/stream-chat/version.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module StreamChat 5 | VERSION = '3.15.0' 6 | end 7 | -------------------------------------------------------------------------------- /scripts/get_changelog_diff.js: -------------------------------------------------------------------------------- 1 | /* 2 | Here we're trying to parse the latest changes from CHANGELOG.md file. 3 | The changelog looks like this: 4 | 5 | ## 0.0.3 6 | - Something #3 7 | ## 0.0.2 8 | - Something #2 9 | ## 0.0.1 10 | - Something #1 11 | 12 | In this case we're trying to extract "- Something #3" since that's the latest change. 13 | */ 14 | module.exports = () => { 15 | const fs = require('fs') 16 | 17 | changelog = fs.readFileSync('CHANGELOG.md', 'utf8') 18 | releases = changelog.match(/## [?[0-9](.+)/g) 19 | 20 | current_release = changelog.indexOf(releases[0]) 21 | previous_release = changelog.indexOf(releases[1]) 22 | 23 | latest_changes = changelog.substr(current_release, previous_release - current_release) 24 | 25 | return latest_changes 26 | } 27 | -------------------------------------------------------------------------------- /sorbet/config: -------------------------------------------------------------------------------- 1 | --dir 2 | . 3 | --ignore=vendor/bundle,spec 4 | --disable-watchman -------------------------------------------------------------------------------- /sorbet/rbi/gems/coderay.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: true 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/coderay/all/coderay.rbi 9 | # 10 | # coderay-1.1.3 11 | 12 | module CodeRay 13 | def self.coderay_path(*path); end 14 | def self.encode(code, lang, format, options = nil); end 15 | def self.encode_file(filename, format, options = nil); end 16 | def self.encode_tokens(tokens, format, options = nil); end 17 | def self.encoder(format, options = nil); end 18 | def self.get_scanner_options(options); end 19 | def self.highlight(code, lang, options = nil, format = nil); end 20 | def self.highlight_file(filename, options = nil, format = nil); end 21 | def self.scan(code, lang, options = nil, &block); end 22 | def self.scan_file(filename, lang = nil, options = nil, &block); end 23 | def self.scanner(lang, options = nil, &block); end 24 | end 25 | module CodeRay::FileType 26 | def self.[](filename, read_shebang = nil); end 27 | def self.fetch(filename, default = nil, read_shebang = nil); end 28 | def self.type_from_shebang(filename); end 29 | end 30 | class CodeRay::FileType::UnknownFileType < Exception 31 | end 32 | class CodeRay::Tokens < Array 33 | def begin_group(kind); end 34 | def begin_line(kind); end 35 | def count; end 36 | def encode(encoder, options = nil); end 37 | def end_group(kind); end 38 | def end_line(kind); end 39 | def method_missing(meth, options = nil); end 40 | def scanner; end 41 | def scanner=(arg0); end 42 | def split_into_parts(*sizes); end 43 | def text_token(*arg0); end 44 | def to_s; end 45 | def tokens(*arg0); end 46 | end 47 | class CodeRay::TokensProxy 48 | def block; end 49 | def block=(arg0); end 50 | def each(*args, &blk); end 51 | def encode(encoder, options = nil); end 52 | def initialize(input, lang, options = nil, block = nil); end 53 | def input; end 54 | def input=(arg0); end 55 | def lang; end 56 | def lang=(arg0); end 57 | def method_missing(method, *args, &blk); end 58 | def options; end 59 | def options=(arg0); end 60 | def scanner; end 61 | def tokens; end 62 | end 63 | module CodeRay::PluginHost 64 | def [](id, *args, &blk); end 65 | def all_plugins; end 66 | def const_missing(const); end 67 | def default(id = nil); end 68 | def list; end 69 | def load(id, *args, &blk); end 70 | def load_all; end 71 | def load_plugin_map; end 72 | def make_plugin_hash; end 73 | def map(hash); end 74 | def path_to(plugin_id); end 75 | def plugin_hash; end 76 | def plugin_path(*args); end 77 | def register(plugin, id); end 78 | def self.extended(mod); end 79 | def validate_id(id); end 80 | end 81 | class CodeRay::PluginHost::PluginNotFound < LoadError 82 | end 83 | class CodeRay::PluginHost::HostNotFound < LoadError 84 | end 85 | module CodeRay::Plugin 86 | def aliases; end 87 | def plugin_host(host = nil); end 88 | def plugin_id; end 89 | def register_for(id); end 90 | def title(title = nil); end 91 | end 92 | module CodeRay::Scanners 93 | extend CodeRay::PluginHost 94 | end 95 | class CodeRay::Scanners::Scanner < StringScanner 96 | def binary_string; end 97 | def column(pos = nil); end 98 | def each(&block); end 99 | def file_extension; end 100 | def initialize(code = nil, options = nil); end 101 | def lang; end 102 | def line(pos = nil); end 103 | def raise_inspect(message, tokens, state = nil, ambit = nil, backtrace = nil); end 104 | def raise_inspect_arguments(message, tokens, state, ambit); end 105 | def reset; end 106 | def reset_instance; end 107 | def scan_rest; end 108 | def scan_tokens(tokens, options); end 109 | def scanner_state_info(state); end 110 | def self.encode_with_encoding(code, target_encoding); end 111 | def self.encoding(name = nil); end 112 | def self.file_extension(extension = nil); end 113 | def self.guess_encoding(s); end 114 | def self.lang; end 115 | def self.normalize(code); end 116 | def self.to_unix(code); end 117 | def set_string_from_source(source); end 118 | def set_tokens_from_options(options); end 119 | def setup; end 120 | def state; end 121 | def state=(arg0); end 122 | def string=(code); end 123 | def tokenize(source = nil, options = nil); end 124 | def tokens; end 125 | def tokens_last(tokens, n); end 126 | def tokens_size(tokens); end 127 | extend CodeRay::Plugin 128 | include Enumerable 129 | end 130 | class CodeRay::Scanners::Scanner::ScanError < StandardError 131 | end 132 | class CodeRay::WordList < Hash 133 | def add(words, value = nil); end 134 | def initialize(default = nil); end 135 | end 136 | class CodeRay::WordList::CaseIgnoring < CodeRay::WordList 137 | def [](key); end 138 | def []=(key, value); end 139 | end 140 | module CodeRay::Scanners::Java::BuiltinTypes 141 | end 142 | class CodeRay::Scanners::Java < CodeRay::Scanners::Scanner 143 | def scan_tokens(encoder, options); end 144 | end 145 | class CodeRay::Scanners::Ruby < CodeRay::Scanners::Scanner 146 | def interpreted_string_state; end 147 | def scan_tokens(encoder, options); end 148 | def setup; end 149 | end 150 | module CodeRay::Scanners::Ruby::Patterns 151 | end 152 | class Anonymous_Struct_1 < Struct 153 | def delim; end 154 | def delim=(_); end 155 | def heredoc; end 156 | def heredoc=(_); end 157 | def interpreted; end 158 | def interpreted=(_); end 159 | def next_state; end 160 | def next_state=(_); end 161 | def opening_paren; end 162 | def opening_paren=(_); end 163 | def paren_depth; end 164 | def paren_depth=(_); end 165 | def pattern; end 166 | def pattern=(_); end 167 | def self.[](*arg0); end 168 | def self.inspect; end 169 | def self.members; end 170 | def self.new(*arg0); end 171 | def type; end 172 | def type=(_); end 173 | end 174 | class CodeRay::Scanners::Ruby::StringState < Anonymous_Struct_1 175 | def heredoc_pattern(delim, interpreted, indented); end 176 | def initialize(kind, interpreted, delim, heredoc = nil); end 177 | def self.simple_key_pattern(delim); end 178 | end 179 | module CodeRay::Encoders 180 | extend CodeRay::PluginHost 181 | end 182 | class CodeRay::Encoders::Encoder 183 | def <<(token); end 184 | def begin_group(kind); end 185 | def begin_line(kind); end 186 | def compile(tokens, options = nil); end 187 | def encode(code, lang, options = nil); end 188 | def encode_tokens(tokens, options = nil); end 189 | def end_group(kind); end 190 | def end_line(kind); end 191 | def file_extension; end 192 | def finish(options); end 193 | def get_output(options); end 194 | def highlight(code, lang, options = nil); end 195 | def initialize(options = nil); end 196 | def options; end 197 | def options=(arg0); end 198 | def output(data); end 199 | def scanner; end 200 | def scanner=(arg0); end 201 | def self.const_missing(sym); end 202 | def self.file_extension; end 203 | def setup(options); end 204 | def text_token(text, kind); end 205 | def token(content, kind); end 206 | def tokens(tokens, options = nil); end 207 | extend CodeRay::Plugin 208 | end 209 | class CodeRay::Encoders::HTML < CodeRay::Encoders::Encoder 210 | def begin_group(kind); end 211 | def begin_line(kind); end 212 | def break_lines(text, style); end 213 | def check_group_nesting(name, kind); end 214 | def check_options!(options); end 215 | def close_span; end 216 | def css; end 217 | def css_class_for_kinds(kinds); end 218 | def end_group(kind); end 219 | def end_line(kind); end 220 | def finish(options); end 221 | def make_span_for_kinds(method, hint); end 222 | def self.make_html_escape_hash; end 223 | def self.token_path_to_hint(hint, kinds); end 224 | def setup(options); end 225 | def style_for_kinds(kinds); end 226 | def text_token(text, kind); end 227 | end 228 | module CodeRay::Encoders::HTML::Output 229 | def apply_title!(title); end 230 | def css; end 231 | def css=(arg0); end 232 | def self.extended(o); end 233 | def self.make_stylesheet(css, in_tag = nil); end 234 | def self.page_template_for_css(css); end 235 | def stylesheet(in_tag = nil); end 236 | def wrap!(element, *args); end 237 | def wrap_in!(template); end 238 | def wrapped_in; end 239 | def wrapped_in=(arg0); end 240 | def wrapped_in?(element); end 241 | end 242 | class CodeRay::Encoders::HTML::Output::Template < String 243 | def apply(target, replacement); end 244 | def self.wrap!(str, template, target); end 245 | end 246 | class CodeRay::Encoders::HTML::CSS 247 | def get_style_for_css_classes(css_classes); end 248 | def initialize(style = nil); end 249 | def parse(stylesheet); end 250 | def self.load_stylesheet(style = nil); end 251 | def stylesheet; end 252 | end 253 | module CodeRay::Encoders::HTML::Numbering 254 | def self.number!(output, mode = nil, options = nil); end 255 | end 256 | module CodeRay::Styles 257 | extend CodeRay::PluginHost 258 | end 259 | class CodeRay::Styles::Style 260 | extend CodeRay::Plugin 261 | end 262 | class CodeRay::Duo 263 | def call(code, options = nil); end 264 | def encode(code, options = nil); end 265 | def encoder; end 266 | def format; end 267 | def format=(arg0); end 268 | def highlight(code, options = nil); end 269 | def initialize(lang = nil, format = nil, options = nil); end 270 | def lang; end 271 | def lang=(arg0); end 272 | def options; end 273 | def options=(arg0); end 274 | def scanner; end 275 | def self.[](*arg0); end 276 | end 277 | class CodeRay::Encoders::Terminal < CodeRay::Encoders::Encoder 278 | def begin_group(kind); end 279 | def begin_line(kind); end 280 | def end_group(kind); end 281 | def end_line(kind); end 282 | def open_token(kind); end 283 | def setup(options); end 284 | def text_token(text, kind); end 285 | end 286 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/connection_pool.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/connection_pool/all/connection_pool.rbi 9 | # 10 | # connection_pool-2.2.5 11 | 12 | class ConnectionPool 13 | def available; end 14 | def checkin; end 15 | def checkout(options = nil); end 16 | def initialize(options = nil, &block); end 17 | def reload(&block); end 18 | def self.wrap(options, &block); end 19 | def shutdown(&block); end 20 | def size; end 21 | def then(options = nil); end 22 | def with(options = nil); end 23 | end 24 | class ConnectionPool::TimedStack 25 | def <<(obj, options = nil); end 26 | def connection_stored?(options = nil); end 27 | def current_time; end 28 | def empty?; end 29 | def fetch_connection(options = nil); end 30 | def initialize(size = nil, &block); end 31 | def length; end 32 | def max; end 33 | def pop(timeout = nil, options = nil); end 34 | def push(obj, options = nil); end 35 | def shutdown(reload: nil, &block); end 36 | def shutdown_connections(options = nil); end 37 | def store_connection(obj, options = nil); end 38 | def try_create(options = nil); end 39 | end 40 | class ConnectionPool::Wrapper < BasicObject 41 | def initialize(options = nil, &block); end 42 | def method_missing(name, *args, &block); end 43 | def pool_available; end 44 | def pool_shutdown(&block); end 45 | def pool_size; end 46 | def respond_to?(id, *args); end 47 | def with(&block); end 48 | def wrapped_pool; end 49 | end 50 | class ConnectionPool::Error < RuntimeError 51 | end 52 | class ConnectionPool::PoolShuttingDownError < ConnectionPool::Error 53 | end 54 | class ConnectionPool::TimeoutError < Timeout::Error 55 | end 56 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/docile.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/docile/all/docile.rbi 9 | # 10 | # docile-1.4.0 11 | 12 | module Docile 13 | def dsl_eval(dsl, *args, &block); end 14 | def dsl_eval_immutable(dsl, *args, &block); end 15 | def dsl_eval_with_block_return(dsl, *args, &block); end 16 | def self.dsl_eval(dsl, *args, &block); end 17 | def self.dsl_eval_immutable(dsl, *args, &block); end 18 | def self.dsl_eval_with_block_return(dsl, *args, &block); end 19 | extend Docile::Execution 20 | end 21 | module Docile::Execution 22 | def exec_in_proxy_context(dsl, proxy_type, *args, &block); end 23 | def self.exec_in_proxy_context(dsl, proxy_type, *args, &block); end 24 | end 25 | class Docile::FallbackContextProxy 26 | def initialize(receiver, fallback); end 27 | def instance_variables; end 28 | def method_missing(method, *args, &block); end 29 | end 30 | class Docile::ChainingFallbackContextProxy < Docile::FallbackContextProxy 31 | def method_missing(method, *args, &block); end 32 | end 33 | module Docile::BacktraceFilter 34 | def backtrace; end 35 | def backtrace_locations; end 36 | end 37 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/faraday-em_http.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/faraday-em_http/all/faraday-em_http.rbi 9 | # 10 | # faraday-em_http-1.0.0 11 | 12 | module Faraday 13 | end 14 | class Faraday::Adapter 15 | end 16 | class Faraday::Adapter::EMHttp < Faraday::Adapter 17 | def call(env); end 18 | def create_request(env); end 19 | def error_message(client); end 20 | def parallel?(env); end 21 | def perform_request(env); end 22 | def perform_single_request(env); end 23 | def raise_error(msg); end 24 | def self.setup_parallel_manager(_options = nil); end 25 | def timeout_message?(msg); end 26 | include Faraday::Adapter::EMHttp::Options 27 | end 28 | module Faraday::Adapter::EMHttp::Options 29 | def configure_compression(options, env); end 30 | def configure_proxy(options, env); end 31 | def configure_socket(options, env); end 32 | def configure_ssl(options, env); end 33 | def configure_timeout(options, env); end 34 | def connection_config(env); end 35 | def read_body(env); end 36 | def request_config(env); end 37 | def request_options(env); end 38 | end 39 | class Faraday::Adapter::EMHttp::Manager 40 | def add(&block); end 41 | def check_finished; end 42 | def initialize; end 43 | def perform_request; end 44 | def reset; end 45 | def run; end 46 | def running?; end 47 | end 48 | module Faraday::EmHttp 49 | end 50 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/faraday-em_synchrony.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/faraday-em_synchrony/all/faraday-em_synchrony.rbi 9 | # 10 | # faraday-em_synchrony-1.0.0 11 | 12 | module Faraday 13 | end 14 | class Faraday::Adapter 15 | end 16 | class Faraday::Adapter::EMSynchrony < Faraday::Adapter 17 | def call(env); end 18 | def call_block(block); end 19 | def create_request(env); end 20 | def execute_parallel_request(env, request, http_method); end 21 | def execute_single_request(env, request, http_method); end 22 | def self.setup_parallel_manager(_options = nil); end 23 | include Faraday::Adapter::EMHttp::Options 24 | end 25 | module Faraday::EmSynchrony 26 | end 27 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/faraday-excon.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/faraday-excon/all/faraday-excon.rbi 9 | # 10 | # faraday-excon-1.1.0 11 | 12 | module Faraday 13 | end 14 | class Faraday::Adapter 15 | end 16 | class Faraday::Adapter::Excon < Faraday::Adapter 17 | def amend_opts_with_proxy_settings!(opts, req); end 18 | def amend_opts_with_ssl!(opts, ssl); end 19 | def amend_opts_with_timeouts!(opts, req); end 20 | def build_connection(env); end 21 | def call(env); end 22 | def needs_ssl_settings?(env); end 23 | def opts_from_env(env); end 24 | def proxy_settings_for_opts(proxy); end 25 | def read_body(env); end 26 | end 27 | module Faraday::Excon 28 | end 29 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/faraday-httpclient.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/faraday-httpclient/all/faraday-httpclient.rbi 9 | # 10 | # faraday-httpclient-1.0.1 11 | 12 | module Faraday 13 | end 14 | class Faraday::Adapter 15 | end 16 | class Faraday::Adapter::HTTPClient < Faraday::Adapter 17 | def build_connection(env); end 18 | def call(env); end 19 | def configure_client(client); end 20 | def configure_proxy(client, proxy); end 21 | def configure_socket(client, bind); end 22 | def configure_ssl(client, ssl); end 23 | def configure_timeouts(client, req); end 24 | def ssl_cert_store(ssl); end 25 | def ssl_verify_mode(ssl); end 26 | end 27 | module Faraday::HTTPClient 28 | end 29 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/faraday-multipart.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/faraday-multipart/all/faraday-multipart.rbi 9 | # 10 | # faraday-multipart-1.0.3 11 | 12 | module Faraday 13 | end 14 | module Faraday::Multipart 15 | end 16 | class Faraday::Multipart::CompositeReadIO 17 | def advance_io; end 18 | def close; end 19 | def current_io; end 20 | def ensure_open_and_readable; end 21 | def initialize(*parts); end 22 | def length; end 23 | def read(length = nil, outbuf = nil); end 24 | def rewind; end 25 | end 26 | class Faraday::Multipart::ParamPart 27 | def content_id; end 28 | def content_type; end 29 | def headers; end 30 | def initialize(value, content_type, content_id = nil); end 31 | def to_part(boundary, key); end 32 | def value; end 33 | end 34 | class Faraday::Multipart::Middleware < Faraday::Request::UrlEncoded 35 | def call(env); end 36 | def create_multipart(env, params); end 37 | def has_multipart?(obj); end 38 | def initialize(app = nil, options = nil); end 39 | def part(boundary, key, value); end 40 | def process_params(params, prefix = nil, pieces = nil, &block); end 41 | def process_request?(env); end 42 | def unique_boundary; end 43 | end 44 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/faraday-net_http.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/faraday-net_http/all/faraday-net_http.rbi 9 | # 10 | # faraday-net_http-1.0.1 11 | 12 | module Faraday 13 | end 14 | class Faraday::Adapter 15 | end 16 | class Faraday::Adapter::NetHttp < Faraday::Adapter 17 | def build_connection(env); end 18 | def call(env); end 19 | def configure_request(http, req); end 20 | def configure_ssl(http, ssl); end 21 | def create_request(env); end 22 | def initialize(app = nil, opts = nil, &block); end 23 | def net_http_connection(env); end 24 | def perform_request(http, env); end 25 | def request_via_get_method(http, env, &block); end 26 | def request_via_request_method(http, env, &block); end 27 | def request_with_wrapped_block(http, env, &block); end 28 | def ssl_cert_store(ssl); end 29 | def ssl_verify_mode(ssl); end 30 | end 31 | module Faraday::NetHttp 32 | end 33 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/faraday-net_http_persistent.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/faraday-net_http_persistent/all/faraday-net_http_persistent.rbi 9 | # 10 | # faraday-net_http_persistent-1.2.0 11 | 12 | module Faraday 13 | end 14 | class Faraday::Adapter 15 | end 16 | class Faraday::Adapter::NetHttpPersistent < Faraday::Adapter::NetHttp 17 | def configure_ssl(http, ssl); end 18 | def http_set(http, attr, value); end 19 | def net_http_connection(env); end 20 | def perform_request(http, env); end 21 | def proxy_uri(env); end 22 | end 23 | module Faraday::NetHttpPersistent 24 | end 25 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/faraday-patron.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/faraday-patron/all/faraday-patron.rbi 9 | # 10 | # faraday-patron-1.0.0 11 | 12 | module Faraday 13 | end 14 | class Faraday::Adapter 15 | end 16 | class Faraday::Adapter::Patron < Faraday::Adapter 17 | def build_connection(env); end 18 | def call(env); end 19 | def configure_proxy(session, proxy); end 20 | def configure_ssl(session, ssl); end 21 | def configure_timeouts(session, req); end 22 | def connection_timed_out_message?(message); end 23 | end 24 | module Faraday::Patron 25 | end 26 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/faraday-rack.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/faraday-rack/all/faraday-rack.rbi 9 | # 10 | # faraday-rack-1.0.0 11 | 12 | module Faraday 13 | end 14 | class Faraday::Adapter 15 | end 16 | class Faraday::Adapter::Rack < Faraday::Adapter 17 | def build_rack_env(env); end 18 | def call(env); end 19 | def execute_request(env, rack_env); end 20 | def initialize(faraday_app, rack_app); end 21 | end 22 | module Faraday::Rack 23 | end 24 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/jwt.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: true 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/jwt/all/jwt.rbi 9 | # 10 | # jwt-2.3.0 11 | 12 | module JWT 13 | def decode(jwt, key = nil, verify = nil, options = nil, &keyfinder); end 14 | def encode(payload, key, algorithm = nil, header_fields = nil); end 15 | def self.decode(jwt, key = nil, verify = nil, options = nil, &keyfinder); end 16 | def self.encode(payload, key, algorithm = nil, header_fields = nil); end 17 | include JWT::DefaultOptions 18 | end 19 | class JWT::Base64 20 | def self.url_decode(str); end 21 | def self.url_encode(str); end 22 | end 23 | class JWT::JSON 24 | def self.generate(data); end 25 | def self.parse(data); end 26 | end 27 | module JWT::SecurityUtils 28 | def asn1_to_raw(signature, public_key); end 29 | def raw_to_asn1(signature, private_key); end 30 | def rbnacl_fixup(algorithm, key); end 31 | def secure_compare(left, right); end 32 | def self.asn1_to_raw(signature, public_key); end 33 | def self.raw_to_asn1(signature, private_key); end 34 | def self.rbnacl_fixup(algorithm, key); end 35 | def self.secure_compare(left, right); end 36 | def self.verify_ps(algorithm, public_key, signing_input, signature); end 37 | def self.verify_rsa(algorithm, public_key, signing_input, signature); end 38 | def verify_ps(algorithm, public_key, signing_input, signature); end 39 | def verify_rsa(algorithm, public_key, signing_input, signature); end 40 | end 41 | module JWT::Algos 42 | def find(algorithm); end 43 | def indexed; end 44 | extend JWT::Algos 45 | end 46 | module JWT::Algos::Hmac 47 | def self.sign(to_sign); end 48 | def self.verify(to_verify); end 49 | def sign(to_sign); end 50 | def verify(to_verify); end 51 | end 52 | module JWT::Algos::Eddsa 53 | def self.sign(to_sign); end 54 | def self.verify(to_verify); end 55 | def sign(to_sign); end 56 | def verify(to_verify); end 57 | end 58 | module JWT::Algos::Ecdsa 59 | def self.sign(to_sign); end 60 | def self.verify(to_verify); end 61 | def sign(to_sign); end 62 | def verify(to_verify); end 63 | end 64 | module JWT::Algos::Rsa 65 | def self.sign(to_sign); end 66 | def self.verify(to_verify); end 67 | def sign(to_sign); end 68 | def verify(to_verify); end 69 | end 70 | module JWT::Algos::Ps 71 | def require_openssl!; end 72 | def self.require_openssl!; end 73 | def self.sign(to_sign); end 74 | def self.verify(to_verify); end 75 | def sign(to_sign); end 76 | def verify(to_verify); end 77 | end 78 | module JWT::Algos::None 79 | def self.sign(*arg0); end 80 | def self.verify(*arg0); end 81 | def sign(*arg0); end 82 | def verify(*arg0); end 83 | end 84 | module JWT::Algos::Unsupported 85 | def self.sign(*arg0); end 86 | def self.verify(*arg0); end 87 | def sign(*arg0); end 88 | def verify(*arg0); end 89 | end 90 | module JWT::Signature 91 | def sign(algorithm, msg, key); end 92 | def verify(algorithm, key, signing_input, signature); end 93 | extend JWT::Signature 94 | end 95 | class JWT::Signature::ToSign < Struct 96 | def algorithm; end 97 | def algorithm=(_); end 98 | def key; end 99 | def key=(_); end 100 | def msg; end 101 | def msg=(_); end 102 | def self.[](*arg0); end 103 | def self.inspect; end 104 | def self.members; end 105 | def self.new(*arg0); end 106 | end 107 | class JWT::Signature::ToVerify < Struct 108 | def algorithm; end 109 | def algorithm=(_); end 110 | def public_key; end 111 | def public_key=(_); end 112 | def self.[](*arg0); end 113 | def self.inspect; end 114 | def self.members; end 115 | def self.new(*arg0); end 116 | def signature; end 117 | def signature=(_); end 118 | def signing_input; end 119 | def signing_input=(_); end 120 | end 121 | class JWT::EncodeError < StandardError 122 | end 123 | class JWT::DecodeError < StandardError 124 | end 125 | class JWT::RequiredDependencyError < StandardError 126 | end 127 | class JWT::VerificationError < JWT::DecodeError 128 | end 129 | class JWT::ExpiredSignature < JWT::DecodeError 130 | end 131 | class JWT::IncorrectAlgorithm < JWT::DecodeError 132 | end 133 | class JWT::ImmatureSignature < JWT::DecodeError 134 | end 135 | class JWT::InvalidIssuerError < JWT::DecodeError 136 | end 137 | class JWT::InvalidIatError < JWT::DecodeError 138 | end 139 | class JWT::InvalidAudError < JWT::DecodeError 140 | end 141 | class JWT::InvalidSubError < JWT::DecodeError 142 | end 143 | class JWT::InvalidJtiError < JWT::DecodeError 144 | end 145 | class JWT::InvalidPayload < JWT::DecodeError 146 | end 147 | class JWT::MissingRequiredClaim < JWT::DecodeError 148 | end 149 | class JWT::JWKError < JWT::DecodeError 150 | end 151 | class JWT::Verify 152 | def exp_leeway; end 153 | def global_leeway; end 154 | def initialize(payload, options); end 155 | def nbf_leeway; end 156 | def self.verify_aud(payload, options); end 157 | def self.verify_claims(payload, options); end 158 | def self.verify_expiration(payload, options); end 159 | def self.verify_iat(payload, options); end 160 | def self.verify_iss(payload, options); end 161 | def self.verify_jti(payload, options); end 162 | def self.verify_not_before(payload, options); end 163 | def self.verify_required_claims(payload, options); end 164 | def self.verify_sub(payload, options); end 165 | def verify_aud; end 166 | def verify_expiration; end 167 | def verify_iat; end 168 | def verify_iss; end 169 | def verify_jti; end 170 | def verify_not_before; end 171 | def verify_required_claims; end 172 | def verify_sub; end 173 | end 174 | class JWT::Decode 175 | def allowed_algorithms; end 176 | def decode_crypto; end 177 | def decode_segments; end 178 | def find_key(&keyfinder); end 179 | def header; end 180 | def initialize(jwt, key, verify, options, &keyfinder); end 181 | def options_includes_algo_in_header?; end 182 | def parse_and_decode(segment); end 183 | def payload; end 184 | def segment_length; end 185 | def signing_input; end 186 | def validate_segment_count!; end 187 | def verify_claims; end 188 | def verify_signature; end 189 | end 190 | module JWT::DefaultOptions 191 | end 192 | class JWT::ClaimsValidator 193 | def initialize(payload); end 194 | def validate!; end 195 | def validate_is_numeric(claim); end 196 | def validate_numeric_claims; end 197 | end 198 | class JWT::Encode 199 | def combine(*parts); end 200 | def encode(data); end 201 | def encode_header; end 202 | def encode_payload; end 203 | def encode_signature; end 204 | def encoded_header; end 205 | def encoded_header_and_payload; end 206 | def encoded_payload; end 207 | def encoded_signature; end 208 | def initialize(options); end 209 | def segments; end 210 | end 211 | module JWT::JWK 212 | def self.classes; end 213 | def self.create_from(keypair, kid = nil); end 214 | def self.generate_mappings; end 215 | def self.import(jwk_data); end 216 | def self.mappings; end 217 | def self.new(keypair, kid = nil); end 218 | end 219 | class JWT::JWK::KeyFinder 220 | def find_key(kid); end 221 | def initialize(options); end 222 | def jwks; end 223 | def jwks_keys; end 224 | def key_for(kid); end 225 | def load_keys(opts = nil); end 226 | def reloadable?; end 227 | def resolve_key(kid); end 228 | end 229 | class JWT::JWK::KeyBase 230 | def initialize(keypair, kid = nil); end 231 | def keypair; end 232 | def kid; end 233 | def self.inherited(klass); end 234 | end 235 | class JWT::JWK::EC < JWT::JWK::KeyBase 236 | def append_private_parts(the_hash); end 237 | def encode_octets(octets); end 238 | def encode_open_ssl_bn(key_part); end 239 | def export(options = nil); end 240 | def generate_kid(ec_keypair); end 241 | def initialize(keypair, kid = nil); end 242 | def keypair_components(ec_keypair); end 243 | def private?; end 244 | def public_key(*args, &block); end 245 | def self.decode_octets(jwk_data); end 246 | def self.decode_open_ssl_bn(jwk_data); end 247 | def self.ec_pkey(jwk_crv, jwk_x, jwk_y, jwk_d); end 248 | def self.import(jwk_data); end 249 | def self.jwk_attrs(jwk_data, attrs); end 250 | def self.to_openssl_curve(crv); end 251 | extend Forwardable 252 | end 253 | class JWT::JWK::RSA < JWT::JWK::KeyBase 254 | def append_private_parts(the_hash); end 255 | def encode_open_ssl_bn(key_part); end 256 | def export(options = nil); end 257 | def generate_kid(public_key); end 258 | def initialize(keypair, kid = nil); end 259 | def private?; end 260 | def public_key; end 261 | def self.decode_open_ssl_bn(jwk_data); end 262 | def self.import(jwk_data); end 263 | def self.jwk_attributes(jwk_data, *attributes); end 264 | def self.populate_key(rsa_key, rsa_parameters); end 265 | def self.rsa_pkey(rsa_parameters); end 266 | end 267 | class JWT::JWK::HMAC < JWT::JWK::KeyBase 268 | def export(options = nil); end 269 | def generate_kid; end 270 | def initialize(keypair, kid = nil); end 271 | def private?; end 272 | def public_key; end 273 | def self.import(jwk_data); end 274 | end 275 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/method_source.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/method_source/all/method_source.rbi 9 | # 10 | # method_source-1.0.0 11 | 12 | module MethodSource 13 | def self.comment_helper(source_location, name = nil); end 14 | def self.extract_code(source_location); end 15 | def self.lines_for(file_name, name = nil); end 16 | def self.source_helper(source_location, name = nil); end 17 | def self.valid_expression?(str); end 18 | extend MethodSource::CodeHelpers 19 | end 20 | module MethodSource::ReeSourceLocation 21 | def source_location; end 22 | end 23 | module MethodSource::SourceLocation 24 | end 25 | module MethodSource::SourceLocation::MethodExtensions 26 | def source_location; end 27 | def trace_func(event, file, line, id, binding, classname); end 28 | end 29 | module MethodSource::SourceLocation::ProcExtensions 30 | def source_location; end 31 | end 32 | module MethodSource::SourceLocation::UnboundMethodExtensions 33 | def source_location; end 34 | end 35 | module MethodSource::CodeHelpers 36 | def comment_describing(file, line_number); end 37 | def complete_expression?(str); end 38 | def expression_at(file, line_number, options = nil); end 39 | def extract_first_expression(lines, consume = nil, &block); end 40 | def extract_last_comment(lines); end 41 | end 42 | module MethodSource::CodeHelpers::IncompleteExpression 43 | def self.===(ex); end 44 | def self.rbx?; end 45 | end 46 | class MethodSource::SourceNotFoundError < StandardError 47 | end 48 | module MethodSource::MethodExtensions 49 | def comment; end 50 | def self.included(klass); end 51 | def source; end 52 | end 53 | class Method 54 | include MethodSource::MethodExtensions 55 | include MethodSource::SourceLocation::MethodExtensions 56 | end 57 | class UnboundMethod 58 | include MethodSource::MethodExtensions 59 | include MethodSource::SourceLocation::UnboundMethodExtensions 60 | end 61 | class Proc 62 | include MethodSource::MethodExtensions 63 | include MethodSource::SourceLocation::ProcExtensions 64 | end 65 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/multipart-post.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/multipart-post/all/multipart-post.rbi 9 | # 10 | # multipart-post-2.1.1 11 | 12 | class CompositeReadIO 13 | def advance_io; end 14 | def current_io; end 15 | def initialize(*ios); end 16 | def read(length = nil, outbuf = nil); end 17 | def rewind; end 18 | end 19 | class UploadIO 20 | def content_type; end 21 | def initialize(filename_or_io, content_type, filename = nil, opts = nil); end 22 | def io; end 23 | def local_path; end 24 | def method_missing(*args); end 25 | def opts; end 26 | def original_filename; end 27 | def respond_to?(meth, include_all = nil); end 28 | def self.convert!(io, content_type, original_filename, local_path); end 29 | end 30 | module Parts 31 | end 32 | module Parts::Part 33 | def length; end 34 | def self.file?(value); end 35 | def self.new(boundary, name, value, headers = nil); end 36 | def to_io; end 37 | end 38 | class Parts::ParamPart 39 | def build_part(boundary, name, value, headers = nil); end 40 | def initialize(boundary, name, value, headers = nil); end 41 | def length; end 42 | include Parts::Part 43 | end 44 | class Parts::FilePart 45 | def build_head(boundary, name, filename, type, content_len, opts = nil); end 46 | def initialize(boundary, name, io, headers = nil); end 47 | def length; end 48 | include Parts::Part 49 | end 50 | class Parts::EpiloguePart 51 | def initialize(boundary); end 52 | include Parts::Part 53 | end 54 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/net-http-persistent.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/net-http-persistent/all/net-http-persistent.rbi 9 | # 10 | # net-http-persistent-4.0.1 11 | 12 | class Net::HTTP::Persistent::Connection 13 | def finish; end 14 | def http; end 15 | def http=(arg0); end 16 | def initialize(http_class, http_args, ssl_generation); end 17 | def last_use; end 18 | def last_use=(arg0); end 19 | def requests; end 20 | def requests=(arg0); end 21 | def reset; end 22 | def ressl(ssl_generation); end 23 | def ssl_generation; end 24 | def ssl_generation=(arg0); end 25 | end 26 | class Net::HTTP::Persistent::TimedStackMulti < ConnectionPool::TimedStack 27 | def connection_stored?(options = nil); end 28 | def empty?; end 29 | def fetch_connection(options = nil); end 30 | def initialize(size = nil, &block); end 31 | def length; end 32 | def lru_update(connection_args); end 33 | def self.hash_of_arrays; end 34 | def shutdown_connections; end 35 | def store_connection(obj, options = nil); end 36 | def try_create(options = nil); end 37 | end 38 | class Net::HTTP::Persistent::Pool < ConnectionPool 39 | def available; end 40 | def checkin(net_http_args); end 41 | def checkout(net_http_args); end 42 | def initialize(options = nil, &block); end 43 | def key; end 44 | def shutdown; end 45 | end 46 | class Net::HTTP::Persistent 47 | def ca_file; end 48 | def ca_file=(file); end 49 | def ca_path; end 50 | def ca_path=(path); end 51 | def cert; end 52 | def cert=(certificate); end 53 | def cert_store; end 54 | def cert_store=(store); end 55 | def certificate; end 56 | def certificate=(certificate); end 57 | def ciphers; end 58 | def ciphers=(ciphers); end 59 | def connection_for(uri); end 60 | def debug_output; end 61 | def debug_output=(arg0); end 62 | def escape(str); end 63 | def expired?(connection); end 64 | def finish(connection); end 65 | def generation; end 66 | def headers; end 67 | def http_version(uri); end 68 | def http_versions; end 69 | def idle_timeout; end 70 | def idle_timeout=(arg0); end 71 | def initialize(name: nil, proxy: nil, pool_size: nil); end 72 | def keep_alive; end 73 | def keep_alive=(arg0); end 74 | def key; end 75 | def key=(key); end 76 | def max_requests; end 77 | def max_requests=(arg0); end 78 | def max_retries; end 79 | def max_retries=(retries); end 80 | def max_version; end 81 | def max_version=(max_version); end 82 | def min_version; end 83 | def min_version=(min_version); end 84 | def name; end 85 | def no_proxy; end 86 | def normalize_uri(uri); end 87 | def open_timeout; end 88 | def open_timeout=(arg0); end 89 | def override_headers; end 90 | def pipeline(uri, requests, &block); end 91 | def pool; end 92 | def private_key; end 93 | def private_key=(key); end 94 | def proxy=(proxy); end 95 | def proxy_bypass?(host, port); end 96 | def proxy_from_env; end 97 | def proxy_uri; end 98 | def read_timeout; end 99 | def read_timeout=(arg0); end 100 | def reconnect; end 101 | def reconnect_ssl; end 102 | def request(uri, req = nil, &block); end 103 | def request_setup(req_or_uri); end 104 | def reset(connection); end 105 | def reuse_ssl_sessions; end 106 | def reuse_ssl_sessions=(arg0); end 107 | def self.detect_idle_timeout(uri, max = nil); end 108 | def shutdown; end 109 | def socket_options; end 110 | def ssl(connection); end 111 | def ssl_generation; end 112 | def ssl_timeout; end 113 | def ssl_timeout=(ssl_timeout); end 114 | def ssl_version; end 115 | def ssl_version=(ssl_version); end 116 | def start(http); end 117 | def timeout_key; end 118 | def unescape(str); end 119 | def verify_callback; end 120 | def verify_callback=(callback); end 121 | def verify_depth; end 122 | def verify_depth=(verify_depth); end 123 | def verify_mode; end 124 | def verify_mode=(verify_mode); end 125 | def write_timeout; end 126 | def write_timeout=(arg0); end 127 | end 128 | class Net::HTTP::Persistent::Error < StandardError 129 | end 130 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/pry-doc.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: true 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/pry-doc/all/pry-doc.rbi 9 | # 10 | # pry-doc-1.2.0 11 | 12 | module PryDoc 13 | def self.load_yardoc(version); end 14 | def self.root; end 15 | end 16 | module Pry::CInternals 17 | end 18 | class Pry::CInternals::SymbolExtractor 19 | def balanced?(str); end 20 | def complete_function_signature?(str); end 21 | def extract(info); end 22 | def extract_code(info, offset: nil, start_line: nil, direction: nil, &block); end 23 | def extract_function(info); end 24 | def extract_macro(info); end 25 | def extract_oneliner(info); end 26 | def extract_struct(info); end 27 | def extract_typedef_struct(info); end 28 | def function_return_type?(str); end 29 | def initialize(ruby_source_folder); end 30 | def self.file_cache; end 31 | def self.file_cache=(arg0); end 32 | def source_from_file(file); end 33 | def token_count(tokens, token); end 34 | end 35 | class Pry::CInternals::ETagParser 36 | def clean_file_name(file_name); end 37 | def file_name_and_content_for(c_file_section); end 38 | def initialize(tags_path, ruby_source_folder); end 39 | def parse_tagfile; end 40 | def ruby_source_folder; end 41 | def self.symbol_map_for(tags_path, ruby_source_folder); end 42 | def symbol_map; end 43 | def tagfile; end 44 | def tags_path; end 45 | end 46 | class Pry::CInternals::ETagParser::CFile 47 | def cleanup_linenumber(line_number); end 48 | def cleanup_symbol(symbol); end 49 | def file_name; end 50 | def file_name=(arg0); end 51 | def full_path_for(file_name); end 52 | def initialize(file_name: nil, content: nil, ruby_source_folder: nil); end 53 | def ruby_source_folder; end 54 | def source_location_for(symbol, line_number); end 55 | def symbol_map; end 56 | def symbol_type_for(symbol); end 57 | def windows?; end 58 | end 59 | class Pry::CInternals::ETagParser::SourceLocation < Struct 60 | def file; end 61 | def file=(_); end 62 | def line; end 63 | def line=(_); end 64 | def self.[](*arg0); end 65 | def self.inspect; end 66 | def self.members; end 67 | def self.new(*arg0); end 68 | def symbol_type; end 69 | def symbol_type=(_); end 70 | end 71 | class Pry::CInternals::RubySourceInstaller 72 | def arch; end 73 | def ask_for_install; end 74 | def check_for_error(message, &block); end 75 | def curl_cmd; end 76 | def curl_cmd=(arg0); end 77 | def download_ruby; end 78 | def etag_binary; end 79 | def etag_binary=(arg0); end 80 | def etag_cmd; end 81 | def etag_cmd=(arg0); end 82 | def generate_tagfile; end 83 | def initialize(ruby_version, ruby_source_folder); end 84 | def install; end 85 | def linux?; end 86 | def ruby_source_folder; end 87 | def ruby_version; end 88 | def set_platform_specific_commands; end 89 | def windows?; end 90 | end 91 | class Pry::CInternals::CodeFetcher 92 | def fetch_all_definitions(symbol); end 93 | def fetch_first_definition(symbol, index = nil); end 94 | def initialize(line_number_style: nil); end 95 | def line_number_style; end 96 | def self.ruby_source_folder; end 97 | def self.ruby_source_folder=(arg0); end 98 | def self.ruby_source_installer; end 99 | def self.ruby_source_installer=(arg0); end 100 | def self.ruby_version; end 101 | def self.symbol_map; end 102 | def self.symbol_map=(arg0); end 103 | def start_line_for(line); end 104 | def symbol_extractor; end 105 | def use_line_numbers?; end 106 | include Pry::Helpers::Text 107 | end 108 | class Pry::CInternals::ShowSourceWithCInternals < Pry::Command::ShowSource 109 | def line_number_style; end 110 | def options(opt); end 111 | def process; end 112 | def show_c_source; end 113 | end 114 | class Pry 115 | end 116 | module Pry::MethodInfo 117 | def self.aliases(meth); end 118 | def self.cache(meth); end 119 | def self.find_gem_dir(meth); end 120 | def self.gem_dir_from_method(meth); end 121 | def self.gem_root(dir); end 122 | def self.guess_gem_name(name); end 123 | def self.info_for(meth); end 124 | def self.is_singleton?(meth); end 125 | def self.method_host(meth); end 126 | def self.namespace_name(host); end 127 | def self.parse_and_cache_if_gem_cext(meth); end 128 | def self.receiver_notation_for(meth); end 129 | def self.registry_lookup(meth); end 130 | end 131 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/rspec-support.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: true 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/rspec-support/all/rspec-support.rbi 9 | # 10 | # rspec-support-3.10.3 11 | 12 | module RSpec 13 | extend RSpec::Support::Warnings 14 | end 15 | module RSpec::Support 16 | def self.class_of(object); end 17 | def self.define_optimized_require_for_rspec(lib, &require_relative); end 18 | def self.deregister_matcher_definition(&block); end 19 | def self.failure_notifier; end 20 | def self.failure_notifier=(callable); end 21 | def self.is_a_matcher?(object); end 22 | def self.matcher_definitions; end 23 | def self.method_handle_for(object, method_name); end 24 | def self.notify_failure(failure, options = nil); end 25 | def self.register_matcher_definition(&block); end 26 | def self.require_rspec_support(f); end 27 | def self.rspec_description_for_object(object); end 28 | def self.thread_local_data; end 29 | def self.warning_notifier; end 30 | def self.warning_notifier=(arg0); end 31 | def self.with_failure_notifier(callable); end 32 | end 33 | module RSpec::Support::Version 34 | end 35 | class RSpec::Support::ComparableVersion 36 | def <=>(other); end 37 | def initialize(string); end 38 | def segments; end 39 | def string; end 40 | include Comparable 41 | end 42 | module RSpec::Support::OS 43 | def self.windows?; end 44 | def self.windows_file_path?; end 45 | def windows?; end 46 | def windows_file_path?; end 47 | end 48 | module RSpec::Support::Ruby 49 | def jruby?; end 50 | def jruby_9000?; end 51 | def jruby_version; end 52 | def mri?; end 53 | def non_mri?; end 54 | def rbx?; end 55 | def self.jruby?; end 56 | def self.jruby_9000?; end 57 | def self.jruby_version; end 58 | def self.mri?; end 59 | def self.non_mri?; end 60 | def self.rbx?; end 61 | def self.truffleruby?; end 62 | def truffleruby?; end 63 | end 64 | module RSpec::Support::RubyFeatures 65 | def caller_locations_supported?; end 66 | def fork_supported?; end 67 | def kw_args_supported?; end 68 | def module_prepends_supported?; end 69 | def module_refinement_supported?; end 70 | def optional_and_splat_args_supported?; end 71 | def required_kw_args_supported?; end 72 | def ripper_supported?; end 73 | def self.caller_locations_supported?; end 74 | def self.fork_supported?; end 75 | def self.kw_args_supported?; end 76 | def self.module_prepends_supported?; end 77 | def self.module_refinement_supported?; end 78 | def self.optional_and_splat_args_supported?; end 79 | def self.required_kw_args_supported?; end 80 | def self.ripper_supported?; end 81 | def self.supports_exception_cause?; end 82 | def self.supports_rebinding_module_methods?; end 83 | def self.supports_taint?; end 84 | def supports_exception_cause?; end 85 | def supports_rebinding_module_methods?; end 86 | def supports_taint?; end 87 | end 88 | module RSpec::Support::AllExceptionsExceptOnesWeMustNotRescue 89 | def self.===(exception); end 90 | end 91 | class RSpec::CallerFilter 92 | def self.first_non_rspec_line(skip_frames = nil, increment = nil); end 93 | end 94 | module RSpec::Support::Warnings 95 | def deprecate(deprecated, options = nil); end 96 | def warn_deprecation(message, options = nil); end 97 | def warn_with(message, options = nil); end 98 | def warning(text, options = nil); end 99 | end 100 | class RSpec::Support::EncodedString 101 | def <<(string); end 102 | def ==(*args, &block); end 103 | def detect_source_encoding(string); end 104 | def empty?(*args, &block); end 105 | def encoding(*args, &block); end 106 | def eql?(*args, &block); end 107 | def initialize(string, encoding = nil); end 108 | def lines(*args, &block); end 109 | def matching_encoding(string); end 110 | def remove_invalid_bytes(string); end 111 | def self.pick_encoding(source_a, source_b); end 112 | def source_encoding; end 113 | def split(regex_or_string); end 114 | def to_s; end 115 | def to_str; end 116 | end 117 | class RSpec::Support::ReentrantMutex 118 | def enter; end 119 | def exit; end 120 | def initialize; end 121 | def synchronize; end 122 | end 123 | class RSpec::Support::Mutex < Thread::Mutex 124 | def self.new; end 125 | end 126 | class RSpec::Support::DirectoryMaker 127 | def self.directory_exists?(dirname); end 128 | def self.generate_path(stack, part); end 129 | def self.generate_stack(path); end 130 | def self.mkdir_p(path); end 131 | end 132 | class RSpec::Support::MethodSignature 133 | def arbitrary_kw_args?; end 134 | def classify_arity(arity = nil); end 135 | def classify_parameters; end 136 | def could_contain_kw_args?(args); end 137 | def description; end 138 | def has_kw_args_in?(args); end 139 | def initialize(method); end 140 | def invalid_kw_args_from(given_kw_args); end 141 | def max_non_kw_args; end 142 | def min_non_kw_args; end 143 | def missing_kw_args_from(given_kw_args); end 144 | def non_kw_args_arity_description; end 145 | def optional_kw_args; end 146 | def required_kw_args; end 147 | def unlimited_args?; end 148 | def valid_non_kw_args?(positional_arg_count, optional_max_arg_count = nil); end 149 | end 150 | class RSpec::Support::MethodSignatureExpectation 151 | def empty?; end 152 | def expect_arbitrary_keywords; end 153 | def expect_arbitrary_keywords=(arg0); end 154 | def expect_unlimited_arguments; end 155 | def expect_unlimited_arguments=(arg0); end 156 | def initialize; end 157 | def keywords; end 158 | def keywords=(values); end 159 | def max_count; end 160 | def max_count=(number); end 161 | def min_count; end 162 | def min_count=(number); end 163 | end 164 | class RSpec::Support::BlockSignature < RSpec::Support::MethodSignature 165 | def classify_parameters; end 166 | end 167 | class RSpec::Support::MethodSignatureVerifier 168 | def arbitrary_kw_args?; end 169 | def error_message; end 170 | def initialize(signature, args = nil); end 171 | def invalid_kw_args; end 172 | def kw_args; end 173 | def max_non_kw_args; end 174 | def min_non_kw_args; end 175 | def missing_kw_args; end 176 | def non_kw_args; end 177 | def split_args(*args); end 178 | def unlimited_args?; end 179 | def valid?; end 180 | def valid_non_kw_args?; end 181 | def with_expectation(expectation); end 182 | end 183 | class RSpec::Support::LooseSignatureVerifier < RSpec::Support::MethodSignatureVerifier 184 | def split_args(*args); end 185 | end 186 | class RSpec::Support::LooseSignatureVerifier::SignatureWithKeywordArgumentsMatcher 187 | def has_kw_args_in?(args); end 188 | def initialize(signature); end 189 | def invalid_kw_args_from(_kw_args); end 190 | def missing_kw_args_from(_kw_args); end 191 | def non_kw_args_arity_description; end 192 | def valid_non_kw_args?(*args); end 193 | end 194 | module RSpec::Support::WithKeywordsWhenNeeded 195 | def class_exec(klass, *args, &block); end 196 | def self.class_exec(klass, *args, &block); end 197 | end 198 | module RSpec::Support::RecursiveConstMethods 199 | def const_defined_on?(mod, const_name); end 200 | def constants_defined_on(mod); end 201 | def get_const_defined_on(mod, const_name); end 202 | def normalize_const_name(const_name); end 203 | def recursive_const_defined?(const_name); end 204 | def recursive_const_get(const_name); end 205 | end 206 | class RSpec::Support::ObjectFormatter 207 | def format(object); end 208 | def initialize(max_formatted_output_length = nil); end 209 | def max_formatted_output_length; end 210 | def max_formatted_output_length=(arg0); end 211 | def prepare_array(array); end 212 | def prepare_element(element); end 213 | def prepare_for_inspection(object); end 214 | def prepare_hash(input_hash); end 215 | def recursive_structure?(object); end 216 | def self.default_instance; end 217 | def self.format(object); end 218 | def self.prepare_for_inspection(object); end 219 | def sort_hash_keys(input_hash); end 220 | def truncate_string(str, start_index, end_index); end 221 | def with_entering_structure(structure); end 222 | end 223 | class RSpec::Support::ObjectFormatter::InspectableItem < Struct 224 | def inspect; end 225 | def pretty_print(pp); end 226 | def self.[](*arg0); end 227 | def self.inspect; end 228 | def self.members; end 229 | def self.new(*arg0); end 230 | def text; end 231 | def text=(_); end 232 | end 233 | class RSpec::Support::ObjectFormatter::BaseInspector < Struct 234 | def formatter; end 235 | def formatter=(_); end 236 | def inspect; end 237 | def object; end 238 | def object=(_); end 239 | def pretty_print(pp); end 240 | def self.[](*arg0); end 241 | def self.can_inspect?(_object); end 242 | def self.inspect; end 243 | def self.members; end 244 | def self.new(*arg0); end 245 | end 246 | class RSpec::Support::ObjectFormatter::TimeInspector < RSpec::Support::ObjectFormatter::BaseInspector 247 | def inspect; end 248 | def self.can_inspect?(object); end 249 | end 250 | class RSpec::Support::ObjectFormatter::DateTimeInspector < RSpec::Support::ObjectFormatter::BaseInspector 251 | def inspect; end 252 | def self.can_inspect?(object); end 253 | end 254 | class RSpec::Support::ObjectFormatter::BigDecimalInspector < RSpec::Support::ObjectFormatter::BaseInspector 255 | def inspect; end 256 | def self.can_inspect?(object); end 257 | end 258 | class RSpec::Support::ObjectFormatter::DescribableMatcherInspector < RSpec::Support::ObjectFormatter::BaseInspector 259 | def inspect; end 260 | def self.can_inspect?(object); end 261 | end 262 | class RSpec::Support::ObjectFormatter::UninspectableObjectInspector < RSpec::Support::ObjectFormatter::BaseInspector 263 | def inspect; end 264 | def klass; end 265 | def native_object_id; end 266 | def self.can_inspect?(object); end 267 | end 268 | class RSpec::Support::ObjectFormatter::DelegatorInspector < RSpec::Support::ObjectFormatter::BaseInspector 269 | def inspect; end 270 | def self.can_inspect?(object); end 271 | end 272 | class RSpec::Support::ObjectFormatter::InspectableObjectInspector < RSpec::Support::ObjectFormatter::BaseInspector 273 | def inspect; end 274 | def self.can_inspect?(object); end 275 | end 276 | module RSpec::Support::FuzzyMatcher 277 | def self.arrays_match?(expected_list, actual_list); end 278 | def self.hashes_match?(expected_hash, actual_hash); end 279 | def self.values_match?(expected, actual); end 280 | end 281 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/rspec.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/rspec/all/rspec.rbi 9 | # 10 | # rspec-3.10.0 11 | 12 | module RSpec 13 | end 14 | module RSpec::Version 15 | end 16 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/simplecov-html.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/simplecov-html/all/simplecov-html.rbi 9 | # 10 | # simplecov-html-0.12.3 11 | 12 | module SimpleCov 13 | end 14 | module SimpleCov::Formatter 15 | end 16 | class SimpleCov::Formatter::HTMLFormatter 17 | def asset_output_path; end 18 | def assets_path(name); end 19 | def branchable_result?; end 20 | def coverage_css_class(covered_percent); end 21 | def covered_percent(percent); end 22 | def format(result); end 23 | def formatted_file_list(title, source_files); end 24 | def formatted_source_file(source_file); end 25 | def id(source_file); end 26 | def initialize; end 27 | def line_status?(source_file, line); end 28 | def link_to_source_file(source_file); end 29 | def output_message(result); end 30 | def output_path; end 31 | def shortened_filename(source_file); end 32 | def strength_css_class(covered_strength); end 33 | def template(name); end 34 | def timeago(time); end 35 | end 36 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/simplecov.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: true 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/simplecov/all/simplecov.rbi 9 | # 10 | # simplecov-0.21.2 11 | 12 | module SimpleCov 13 | def self.adapt_coverage_result; end 14 | def self.add_not_loaded_files(result); end 15 | def self.at_exit_behavior; end 16 | def self.clear_result; end 17 | def self.collate(result_filenames, profile = nil, ignore_timeout: nil, &block); end 18 | def self.exit_and_report_previous_error(exit_status); end 19 | def self.exit_status_from_exception; end 20 | def self.external_at_exit; end 21 | def self.external_at_exit=(arg0); end 22 | def self.external_at_exit?; end 23 | def self.filtered(files); end 24 | def self.final_result_process?; end 25 | def self.grouped(files); end 26 | def self.initial_setup(profile, &block); end 27 | def self.load_adapter(name); end 28 | def self.load_profile(name); end 29 | def self.lookup_corresponding_ruby_coverage_name(criterion); end 30 | def self.make_parallel_tests_available; end 31 | def self.pid; end 32 | def self.pid=(arg0); end 33 | def self.previous_error?(error_exit_status); end 34 | def self.probably_running_parallel_tests?; end 35 | def self.process_coverage_result; end 36 | def self.process_result(result); end 37 | def self.process_results_and_report_error; end 38 | def self.ready_to_process_results?; end 39 | def self.remove_useless_results; end 40 | def self.result; end 41 | def self.result?; end 42 | def self.result_exit_status(result); end 43 | def self.result_with_not_loaded_files; end 44 | def self.round_coverage(coverage); end 45 | def self.run_exit_tasks!; end 46 | def self.running; end 47 | def self.running=(arg0); end 48 | def self.start(profile = nil, &block); end 49 | def self.start_coverage_measurement; end 50 | def self.start_coverage_with_criteria; end 51 | def self.wait_for_other_processes; end 52 | def self.write_last_run(result); end 53 | extend SimpleCov::Configuration 54 | end 55 | module SimpleCov::Formatter 56 | def self.from_env(env); end 57 | end 58 | class SimpleCov::Formatter::MultiFormatter 59 | def self.[](*args); end 60 | def self.new(formatters = nil); end 61 | end 62 | module SimpleCov::Formatter::MultiFormatter::InstanceMethods 63 | def format(result); end 64 | end 65 | module SimpleCov::Configuration 66 | def adapters; end 67 | def add_filter(filter_argument = nil, &filter_proc); end 68 | def add_group(group_name, filter_argument = nil, &filter_proc); end 69 | def at_exit(&block); end 70 | def at_fork(&block); end 71 | def branch_coverage?; end 72 | def branch_coverage_supported?; end 73 | def clear_coverage_criteria; end 74 | def command_name(name = nil); end 75 | def configure(&block); end 76 | def coverage_criteria; end 77 | def coverage_criterion(criterion = nil); end 78 | def coverage_criterion_enabled?(criterion); end 79 | def coverage_dir(dir = nil); end 80 | def coverage_path; end 81 | def coverage_start_arguments_supported?; end 82 | def enable_coverage(criterion); end 83 | def enable_for_subprocesses(value = nil); end 84 | def enabled_for_subprocesses?; end 85 | def filters; end 86 | def filters=(arg0); end 87 | def formatter(formatter = nil); end 88 | def formatter=(arg0); end 89 | def formatters; end 90 | def formatters=(formatters); end 91 | def groups; end 92 | def groups=(arg0); end 93 | def maximum_coverage_drop(coverage_drop = nil); end 94 | def merge_timeout(seconds = nil); end 95 | def minimum_coverage(coverage = nil); end 96 | def minimum_coverage_by_file(coverage = nil); end 97 | def minimum_possible_coverage_exceeded(coverage_option); end 98 | def nocov_token(nocov_token = nil); end 99 | def parse_filter(filter_argument = nil, &filter_proc); end 100 | def primary_coverage(criterion = nil); end 101 | def print_error_status; end 102 | def print_error_status=(arg0); end 103 | def profiles; end 104 | def project_name(new_name = nil); end 105 | def raise_if_criterion_disabled(criterion); end 106 | def raise_if_criterion_unsupported(criterion); end 107 | def raise_on_invalid_coverage(coverage, coverage_setting); end 108 | def refuse_coverage_drop(*criteria); end 109 | def root(root = nil); end 110 | def skip_token(nocov_token = nil); end 111 | def track_files(glob); end 112 | def tracked_files; end 113 | def use_merging(use = nil); end 114 | end 115 | class SimpleCov::CoverageStatistics 116 | def compute_percent(covered, missed, total); end 117 | def compute_strength(total_strength, total); end 118 | def covered; end 119 | def initialize(covered:, missed:, total_strength: nil); end 120 | def missed; end 121 | def percent; end 122 | def self.from(coverage_statistics); end 123 | def strength; end 124 | def total; end 125 | end 126 | module SimpleCov::ExitCodes 127 | end 128 | module SimpleCov::ExitCodes::ExitCodeHandling 129 | def call(result, coverage_limits:); end 130 | def coverage_checks(result, coverage_limits); end 131 | def self.call(result, coverage_limits:); end 132 | def self.coverage_checks(result, coverage_limits); end 133 | end 134 | class SimpleCov::ExitCodes::MaximumCoverageDropCheck 135 | def compute_coverage_drop_data; end 136 | def coverage_drop_violations; end 137 | def drop_percent(criterion); end 138 | def exit_code; end 139 | def failing?; end 140 | def initialize(result, maximum_coverage_drop); end 141 | def last_coverage(criterion); end 142 | def last_run; end 143 | def maximum_coverage_drop; end 144 | def report; end 145 | def result; end 146 | end 147 | class SimpleCov::ExitCodes::MinimumCoverageByFileCheck 148 | def compute_minimum_coverage_data; end 149 | def exit_code; end 150 | def failing?; end 151 | def initialize(result, minimum_coverage_by_file); end 152 | def minimum_coverage_by_file; end 153 | def minimum_violations; end 154 | def report; end 155 | def result; end 156 | end 157 | class SimpleCov::ExitCodes::MinimumOverallCoverageCheck 158 | def calculate_minimum_violations; end 159 | def exit_code; end 160 | def failing?; end 161 | def initialize(result, minimum_coverage); end 162 | def minimum_coverage; end 163 | def minimum_violations; end 164 | def report; end 165 | def result; end 166 | end 167 | class SimpleCov::Profiles < Hash 168 | def define(name, &blk); end 169 | def load(name); end 170 | end 171 | class SimpleCov::SourceFile 172 | def branch_coverage_statistics; end 173 | def branches; end 174 | def branches_coverage_percent; end 175 | def branches_for_line(line_number); end 176 | def branches_report; end 177 | def build_branch(branch_data, hit_count, condition_start_line); end 178 | def build_branches; end 179 | def build_branches_from(condition, branches); end 180 | def build_branches_report; end 181 | def build_lines; end 182 | def build_no_cov_chunks; end 183 | def coverage_data; end 184 | def coverage_exceeding_source_warn; end 185 | def coverage_statistics; end 186 | def covered_branches; end 187 | def covered_lines; end 188 | def covered_percent; end 189 | def covered_strength; end 190 | def ensure_remove_undefs(file_lines); end 191 | def filename; end 192 | def initialize(filename, coverage_data); end 193 | def line(number); end 194 | def line_coverage_statistics; end 195 | def line_with_missed_branch?(line_number); end 196 | def lines; end 197 | def lines_of_code; end 198 | def lines_strength; end 199 | def load_source; end 200 | def missed_branches; end 201 | def missed_lines; end 202 | def never_lines; end 203 | def no_branches?; end 204 | def no_cov_chunks; end 205 | def no_lines?; end 206 | def process_skipped_branches(branches); end 207 | def process_skipped_lines(lines); end 208 | def project_filename; end 209 | def read_lines(file, lines, current_line); end 210 | def relevant_lines; end 211 | def restore_ruby_data_structure(structure); end 212 | def set_encoding_based_on_magic_comment(file, line); end 213 | def shebang?(line); end 214 | def skipped_lines; end 215 | def source; end 216 | def source_lines; end 217 | def src; end 218 | def total_branches; end 219 | end 220 | class SimpleCov::SourceFile::Line 221 | def coverage; end 222 | def covered?; end 223 | def initialize(src, line_number, coverage); end 224 | def line; end 225 | def line_number; end 226 | def missed?; end 227 | def never?; end 228 | def number; end 229 | def skipped!; end 230 | def skipped; end 231 | def skipped?; end 232 | def source; end 233 | def src; end 234 | def status; end 235 | end 236 | class SimpleCov::SourceFile::Branch 237 | def coverage; end 238 | def covered?; end 239 | def end_line; end 240 | def initialize(start_line:, end_line:, coverage:, inline:, type:); end 241 | def inline?; end 242 | def missed?; end 243 | def overlaps_with?(line_range); end 244 | def report; end 245 | def report_line; end 246 | def skipped!; end 247 | def skipped?; end 248 | def start_line; end 249 | def type; end 250 | end 251 | class SimpleCov::FileList 252 | def branch_covered_percent; end 253 | def compute_coverage_statistics; end 254 | def compute_coverage_statistics_by_file; end 255 | def count(*args, &block); end 256 | def coverage_statistics; end 257 | def coverage_statistics_by_file; end 258 | def covered_branches; end 259 | def covered_lines; end 260 | def covered_percent; end 261 | def covered_percentages; end 262 | def covered_strength; end 263 | def each(*args, &block); end 264 | def empty?(*args, &block); end 265 | def initialize(files); end 266 | def least_covered_file; end 267 | def length(*args, &block); end 268 | def lines_of_code; end 269 | def map(*args, &block); end 270 | def missed_branches; end 271 | def missed_lines; end 272 | def never_lines; end 273 | def size(*args, &block); end 274 | def skipped_lines; end 275 | def to_a(*args, &block); end 276 | def to_ary(*args, &block); end 277 | def total_branches; end 278 | extend Forwardable 279 | include Enumerable 280 | end 281 | class SimpleCov::Result 282 | def command_name; end 283 | def command_name=(arg0); end 284 | def coverage; end 285 | def coverage_statistics(*args, &block); end 286 | def coverage_statistics_by_file(*args, &block); end 287 | def covered_branches(*args, &block); end 288 | def covered_lines(*args, &block); end 289 | def covered_percent(*args, &block); end 290 | def covered_percentages(*args, &block); end 291 | def covered_strength(*args, &block); end 292 | def created_at; end 293 | def created_at=(arg0); end 294 | def filenames; end 295 | def files; end 296 | def filter!; end 297 | def format!; end 298 | def groups; end 299 | def initialize(original_result, command_name: nil, created_at: nil); end 300 | def least_covered_file(*args, &block); end 301 | def missed_branches(*args, &block); end 302 | def missed_lines(*args, &block); end 303 | def original_result; end 304 | def self.from_hash(hash); end 305 | def source_files; end 306 | def to_hash; end 307 | def total_branches(*args, &block); end 308 | def total_lines(*args, &block); end 309 | extend Forwardable 310 | end 311 | class SimpleCov::Filter 312 | def filter_argument; end 313 | def initialize(filter_argument); end 314 | def matches?(_source_file); end 315 | def passes?(source_file); end 316 | def self.build_filter(filter_argument); end 317 | def self.class_for_argument(filter_argument); end 318 | end 319 | class SimpleCov::StringFilter < SimpleCov::Filter 320 | def matches?(source_file); end 321 | end 322 | class SimpleCov::RegexFilter < SimpleCov::Filter 323 | def matches?(source_file); end 324 | end 325 | class SimpleCov::BlockFilter < SimpleCov::Filter 326 | def matches?(source_file); end 327 | end 328 | class SimpleCov::ArrayFilter < SimpleCov::Filter 329 | def initialize(filter_argument); end 330 | def matches?(source_files_list); end 331 | end 332 | class SimpleCov::Formatter::SimpleFormatter 333 | def format(result); end 334 | end 335 | module SimpleCov::LastRun 336 | def self.last_run_path; end 337 | def self.read; end 338 | def self.write(json); end 339 | end 340 | class SimpleCov::LinesClassifier 341 | def classify(lines); end 342 | def self.no_cov_line; end 343 | def self.no_cov_line?(line); end 344 | def self.whitespace_line?(line); end 345 | end 346 | module SimpleCov::ResultMerger 347 | def self.adapt_pre_simplecov_0_18_result(result); end 348 | def self.adapt_result(result); end 349 | def self.create_result(command_names, coverage); end 350 | def self.merge_and_store(*file_paths, ignore_timeout: nil); end 351 | def self.merge_coverage(*results); end 352 | def self.merge_results(*file_paths, ignore_timeout: nil); end 353 | def self.merge_valid_results(results, ignore_timeout: nil); end 354 | def self.merged_result; end 355 | def self.parse_file(path); end 356 | def self.parse_json(content); end 357 | def self.pre_simplecov_0_18_result?(result); end 358 | def self.read_file(path); end 359 | def self.read_resultset; end 360 | def self.resultset_path; end 361 | def self.resultset_writelock; end 362 | def self.store_result(result); end 363 | def self.synchronize_resultset; end 364 | def self.time_since_result_creation(data); end 365 | def self.valid_results(file_path, ignore_timeout: nil); end 366 | def self.within_merge_timeout?(data); end 367 | end 368 | module SimpleCov::CommandGuesser 369 | def self.from_command_line_options; end 370 | def self.from_defined_constants; end 371 | def self.from_env; end 372 | def self.guess; end 373 | def self.original_run_command; end 374 | def self.original_run_command=(arg0); end 375 | end 376 | class SimpleCov::ResultAdapter 377 | def adapt; end 378 | def initialize(result); end 379 | def result; end 380 | def self.call(*args); end 381 | end 382 | module SimpleCov::Combine 383 | def combine(combiner_module, coverage_a, coverage_b); end 384 | def empty_coverage?(coverage_a, coverage_b); end 385 | def existing_coverage(coverage_a, coverage_b); end 386 | def self.combine(combiner_module, coverage_a, coverage_b); end 387 | def self.empty_coverage?(coverage_a, coverage_b); end 388 | def self.existing_coverage(coverage_a, coverage_b); end 389 | end 390 | module SimpleCov::Combine::BranchesCombiner 391 | def combine(coverage_a, coverage_b); end 392 | def self.combine(coverage_a, coverage_b); end 393 | end 394 | module SimpleCov::Combine::FilesCombiner 395 | def combine(coverage_a, coverage_b); end 396 | def self.combine(coverage_a, coverage_b); end 397 | end 398 | module SimpleCov::Combine::LinesCombiner 399 | def combine(coverage_a, coverage_b); end 400 | def merge_line_coverage(first_val, second_val); end 401 | def self.combine(coverage_a, coverage_b); end 402 | def self.merge_line_coverage(first_val, second_val); end 403 | end 404 | module SimpleCov::Combine::ResultsCombiner 405 | def combine(*results); end 406 | def combine_file_coverage(coverage_a, coverage_b); end 407 | def combine_result_sets(combined_results, result); end 408 | def self.combine(*results); end 409 | def self.combine_file_coverage(coverage_a, coverage_b); end 410 | def self.combine_result_sets(combined_results, result); end 411 | end 412 | module SimpleCov::UselessResultsRemover 413 | def self.call(coverage_result); end 414 | def self.root_regx; end 415 | end 416 | module SimpleCov::SimulateCoverage 417 | def call(absolute_path); end 418 | def self.call(absolute_path); end 419 | end 420 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/simplecov_json_formatter.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi gems 3 | 4 | # typed: strict 5 | # 6 | # If you would like to make changes to this file, great! Please create the gem's shim here: 7 | # 8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/simplecov_json_formatter/all/simplecov_json_formatter.rbi 9 | # 10 | # simplecov_json_formatter-0.1.3 11 | 12 | module SimpleCovJSONFormatter 13 | end 14 | class SimpleCovJSONFormatter::SourceFileFormatter 15 | def branch_coverage; end 16 | def branches; end 17 | def format; end 18 | def initialize(source_file); end 19 | def line_coverage; end 20 | def lines; end 21 | def parse_branch(branch); end 22 | def parse_line(line); end 23 | end 24 | class SimpleCovJSONFormatter::ResultHashFormatter 25 | def format; end 26 | def format_source_file(source_file); end 27 | def formatted_result; end 28 | def initialize(result); end 29 | end 30 | class SimpleCovJSONFormatter::ResultExporter 31 | def export; end 32 | def export_path; end 33 | def initialize(result_hash); end 34 | def json_result; end 35 | end 36 | module SimpleCov 37 | end 38 | module SimpleCov::Formatter 39 | end 40 | class SimpleCov::Formatter::JSONFormatter 41 | def export_formatted_result(result_hash); end 42 | def format(result); end 43 | def format_result(result); end 44 | def output_message(result); end 45 | end 46 | -------------------------------------------------------------------------------- /sorbet/rbi/sorbet-typed/lib/faraday/all/faraday.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi sorbet-typed 3 | # 4 | # If you would like to make changes to this file, great! Please upstream any changes you make here: 5 | # 6 | # https://github.com/sorbet/sorbet-typed/edit/master/lib/faraday/all/faraday.rbi 7 | # 8 | # typed: strict 9 | 10 | module Faraday 11 | def self.new(url = nil, options = nil, &block); end 12 | 13 | # HTTP verb methods. These are proxied to Faraday::Connecation, 14 | # which should have corresponding sigs 15 | 16 | # Query methods 17 | sig do 18 | params( 19 | url: String, 20 | params: T.nilable(T::Hash[Object, Object]), 21 | headers: T.nilable(T::Hash[Object, String]), 22 | block: T.nilable(T.proc.params(req: Faraday::Request).void), 23 | ).returns(Faraday::Response) 24 | end 25 | def self.get(url, params = nil, headers = nil, &block); end 26 | sig do 27 | params( 28 | url: String, 29 | params: T.nilable(T::Hash[Object, Object]), 30 | headers: T.nilable(T::Hash[Object, String]), 31 | block: T.nilable(T.proc.params(req: Faraday::Request).void), 32 | ).returns(Faraday::Response) 33 | end 34 | def self.head(url, params = nil, headers = nil, &block); end 35 | sig do 36 | params( 37 | url: String, 38 | params: T.nilable(T::Hash[Object, Object]), 39 | headers: T.nilable(T::Hash[Object, String]), 40 | block: T.nilable(T.proc.params(req: Faraday::Request).void), 41 | ).returns(Faraday::Response) 42 | end 43 | def self.delete(url, params = nil, headers = nil, &block); end 44 | sig do 45 | params( 46 | url: String, 47 | params: T.nilable(T::Hash[Object, Object]), 48 | headers: T.nilable(T::Hash[Object, String]), 49 | block: T.nilable(T.proc.params(req: Faraday::Request).void), 50 | ).returns(Faraday::Response) 51 | end 52 | def self.trace(url, params = nil, headers = nil, &block); end 53 | 54 | # Body methods 55 | sig do 56 | params( 57 | url: String, 58 | body: T.any(String, T.nilable(T::Hash[Object, Object])), 59 | headers: T.nilable(T::Hash[Object, String]), 60 | block: T.nilable(T.proc.params(req: Faraday::Request).void), 61 | ).returns(Faraday::Response) 62 | end 63 | def self.post(url, body = nil, headers = nil, &block); end 64 | sig do 65 | params( 66 | url: String, 67 | body: T.any(String, T.nilable(T::Hash[Object, Object])), 68 | headers: T.nilable(T::Hash[Object, String]), 69 | block: T.nilable(T.proc.params(req: Faraday::Request).void), 70 | ).returns(Faraday::Response) 71 | end 72 | def self.put(url, body = nil, headers = nil, &block); end 73 | sig do 74 | params( 75 | url: String, 76 | body: T.any(String, T.nilable(T::Hash[Object, Object])), 77 | headers: T.nilable(T::Hash[Object, String]), 78 | block: T.nilable(T.proc.params(req: Faraday::Request).void), 79 | ).returns(Faraday::Response) 80 | end 81 | def self.patch(url, body = nil, headers = nil, &block); end 82 | end 83 | -------------------------------------------------------------------------------- /sorbet/rbi/sorbet-typed/lib/rainbow/all/rainbow.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi sorbet-typed 3 | # 4 | # If you would like to make changes to this file, great! Please upstream any changes you make here: 5 | # 6 | # https://github.com/sorbet/sorbet-typed/edit/master/lib/rainbow/all/rainbow.rbi 7 | # 8 | # typed: strong 9 | 10 | module Rainbow 11 | sig { returns(T::Boolean) } 12 | attr_accessor :enabled 13 | 14 | class Color 15 | sig { returns(Symbol) } 16 | attr_reader :ground 17 | 18 | sig do 19 | params( 20 | ground: Symbol, 21 | values: T.any([Integer], [Integer, Integer, Integer]) 22 | ).returns(Color) 23 | end 24 | def self.build(ground, values); end 25 | 26 | sig { params(hex: String).returns([Integer, Integer, Integer]) } 27 | def self.parse_hex_color(hex); end 28 | 29 | class Indexed < Color 30 | sig { returns(Integer) } 31 | attr_reader :num 32 | 33 | sig { params(ground: Symbol, num: Integer).void } 34 | def initialize(ground, num); end 35 | 36 | sig { returns(T::Array[Integer]) } 37 | def codes; end 38 | end 39 | 40 | class Named < Indexed 41 | NAMES = T.let(nil, T::Hash[Symbol, Integer]) 42 | 43 | sig { returns(T::Array[Symbol]) } 44 | def self.color_names; end 45 | 46 | sig { returns(String) } 47 | def self.valid_names; end 48 | 49 | sig { params(ground: Symbol, name: Symbol).void } 50 | def initialize(ground, name); end 51 | end 52 | 53 | class RGB < Indexed 54 | sig { returns(Integer) } 55 | attr_accessor :r, :g, :b 56 | 57 | sig { params(value: Numeric).returns(Integer) } 58 | def to_ansi_domain(value); end 59 | 60 | sig { params(ground: Symbol, values: Integer).void } 61 | def initialize(ground, *values); end 62 | 63 | sig { returns(T::Array[Integer]) } 64 | def codes; end 65 | end 66 | 67 | class X11Named < RGB 68 | include X11ColorNames 69 | 70 | sig { returns(T::Array[Symbol]) } 71 | def self.color_names; end 72 | 73 | sig { returns(String) } 74 | def self.valid_names; end 75 | 76 | sig { params(ground: Symbol, name: Symbol).void } 77 | def initialize(ground, name); end 78 | end 79 | end 80 | 81 | sig { returns(Wrapper) } 82 | def self.global; end 83 | 84 | sig { returns(T::Boolean) } 85 | def self.enabled; end 86 | 87 | sig { params(value: T::Boolean).returns(T::Boolean) } 88 | def self.enabled=(value); end 89 | 90 | sig { params(string: String).returns(String) } 91 | def self.uncolor(string); end 92 | 93 | class NullPresenter < String 94 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 95 | def color(*values); end 96 | 97 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 98 | def foreground(*values); end 99 | 100 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 101 | def fg(*values); end 102 | 103 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 104 | def background(*values); end 105 | 106 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 107 | def bg(*values); end 108 | 109 | sig { returns(NullPresenter) } 110 | def reset; end 111 | 112 | sig { returns(NullPresenter) } 113 | def bright; end 114 | 115 | sig { returns(NullPresenter) } 116 | def faint; end 117 | 118 | sig { returns(NullPresenter) } 119 | def italic; end 120 | 121 | sig { returns(NullPresenter) } 122 | def underline; end 123 | 124 | sig { returns(NullPresenter) } 125 | def blink; end 126 | 127 | sig { returns(NullPresenter) } 128 | def inverse; end 129 | 130 | sig { returns(NullPresenter) } 131 | def hide; end 132 | 133 | sig { returns(NullPresenter) } 134 | def cross_out; end 135 | 136 | sig { returns(NullPresenter) } 137 | def black; end 138 | 139 | sig { returns(NullPresenter) } 140 | def red; end 141 | 142 | sig { returns(NullPresenter) } 143 | def green; end 144 | 145 | sig { returns(NullPresenter) } 146 | def yellow; end 147 | 148 | sig { returns(NullPresenter) } 149 | def blue; end 150 | 151 | sig { returns(NullPresenter) } 152 | def magenta; end 153 | 154 | sig { returns(NullPresenter) } 155 | def cyan; end 156 | 157 | sig { returns(NullPresenter) } 158 | def white; end 159 | 160 | sig { returns(NullPresenter) } 161 | def bold; end 162 | 163 | sig { returns(NullPresenter) } 164 | def dark; end 165 | 166 | sig { returns(NullPresenter) } 167 | def strike; end 168 | end 169 | 170 | class Presenter < String 171 | TERM_EFFECTS = T.let(nil, T::Hash[Symbol, Integer]) 172 | 173 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 174 | def color(*values); end 175 | 176 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 177 | def foreground(*values); end 178 | 179 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 180 | def fg(*values); end 181 | 182 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 183 | def background(*values); end 184 | 185 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 186 | def bg(*values); end 187 | 188 | sig { returns(Presenter) } 189 | def reset; end 190 | 191 | sig { returns(Presenter) } 192 | def bright; end 193 | 194 | sig { returns(Presenter) } 195 | def faint; end 196 | 197 | sig { returns(Presenter) } 198 | def italic; end 199 | 200 | sig { returns(Presenter) } 201 | def underline; end 202 | 203 | sig { returns(Presenter) } 204 | def blink; end 205 | 206 | sig { returns(Presenter) } 207 | def inverse; end 208 | 209 | sig { returns(Presenter) } 210 | def hide; end 211 | 212 | sig { returns(Presenter) } 213 | def cross_out; end 214 | 215 | sig { returns(Presenter) } 216 | def black; end 217 | 218 | sig { returns(Presenter) } 219 | def red; end 220 | 221 | sig { returns(Presenter) } 222 | def green; end 223 | 224 | sig { returns(Presenter) } 225 | def yellow; end 226 | 227 | sig { returns(Presenter) } 228 | def blue; end 229 | 230 | sig { returns(Presenter) } 231 | def magenta; end 232 | 233 | sig { returns(Presenter) } 234 | def cyan; end 235 | 236 | sig { returns(Presenter) } 237 | def white; end 238 | 239 | sig { returns(Presenter) } 240 | def bold; end 241 | 242 | sig { returns(Presenter) } 243 | def dark; end 244 | 245 | sig { returns(Presenter) } 246 | def strike; end 247 | end 248 | 249 | class StringUtils 250 | sig { params(string: String, codes: T::Array[Integer]).returns(String) } 251 | def self.wrap_with_sgr(string, codes); end 252 | 253 | sig { params(string: String).returns(String) } 254 | def uncolor(string); end 255 | end 256 | 257 | VERSION = T.let(nil, String) 258 | 259 | class Wrapper 260 | sig { returns(T::Boolean) } 261 | attr_accessor :enabled 262 | 263 | sig { params(enabled: T::Boolean).void } 264 | def initialize(enabled = true); end 265 | 266 | sig { params(string: String).returns(T.any(Rainbow::Presenter, Rainbow::NullPresenter)) } 267 | def wrap(string); end 268 | end 269 | 270 | module X11ColorNames 271 | NAMES = T.let(nil, T::Hash[Symbol, [Integer, Integer, Integer]]) 272 | end 273 | end 274 | 275 | sig { params(string: String).returns(Rainbow::Presenter) } 276 | def Rainbow(string); end 277 | -------------------------------------------------------------------------------- /sorbet/rbi/sorbet-typed/lib/rspec-core/all/rspec-core.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi sorbet-typed 3 | # 4 | # If you would like to make changes to this file, great! Please upstream any changes you make here: 5 | # 6 | # https://github.com/sorbet/sorbet-typed/edit/master/lib/rspec-core/all/rspec-core.rbi 7 | # 8 | # typed: strict 9 | 10 | module RSpec::Core::ShellEscape 11 | def conditionally_quote(id); end 12 | def escape(shell_command); end 13 | def quote(argument); end 14 | def self.conditionally_quote(id); end 15 | def self.escape(shell_command); end 16 | def self.quote(argument); end 17 | def self.shell_allows_unquoted_ids?; end 18 | def shell_allows_unquoted_ids?; end 19 | end 20 | class RSpec::Core::RakeTask < ::Rake::TaskLib 21 | include ::Rake::DSL 22 | include RSpec::Core::ShellEscape 23 | def initialize(*args, &task_block); end 24 | end 25 | -------------------------------------------------------------------------------- /sorbet/rbi/sorbet-typed/lib/rubocop/>=1.8/rubocop.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi sorbet-typed 3 | # 4 | # If you would like to make changes to this file, great! Please upstream any changes you make here: 5 | # 6 | # https://github.com/sorbet/sorbet-typed/edit/master/lib/rubocop/>=1.8/rubocop.rbi 7 | # 8 | # typed: strict 9 | 10 | class RuboCop::RakeTask < ::Rake::TaskLib 11 | def initialize(name = :rubocop, *args, &task_block); end 12 | end 13 | -------------------------------------------------------------------------------- /sorbet/rbi/sorbet-typed/lib/yard/all/yard.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi sorbet-typed 3 | # 4 | # If you would like to make changes to this file, great! Please upstream any changes you make here: 5 | # 6 | # https://github.com/sorbet/sorbet-typed/edit/master/lib/yard/all/yard.rbi 7 | # 8 | # typed: strict 9 | 10 | class YARD::CodeObjects::Base 11 | def initialize(namespace, name, *arg2); end 12 | end 13 | class YARD::CodeObjects::NamespaceObject < YARD::CodeObjects::Base 14 | def mixins(*scopes); end 15 | end 16 | class YARD::CodeObjects::ClassObject < YARD::CodeObjects::NamespaceObject 17 | end 18 | class YARD::CodeObjects::ConstantObject < YARD::CodeObjects::Base 19 | end 20 | class YARD::CodeObjects::Proxy 21 | def initialize(namespace, name, type = nil); end 22 | end 23 | class YARD::Handlers::Base 24 | def handlers; end 25 | def self.handlers; end 26 | end 27 | class YARD::Handlers::Ruby::Base < YARD::Handlers::Base 28 | end 29 | class YARD::Handlers::Ruby::AttributeHandler < YARD::Handlers::Ruby::Base 30 | end 31 | class YARD::Handlers::Ruby::MethodHandler < YARD::Handlers::Ruby::Base 32 | end 33 | -------------------------------------------------------------------------------- /sorbet/rbi/todo.rbi: -------------------------------------------------------------------------------- 1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with: 2 | # srb rbi todo 3 | 4 | # typed: strong 5 | module Rack::QueryParser::InvalidParameterError; end 6 | module Rack::QueryParser::ParameterTypeError; end 7 | module T::CompatibilityPatches::RSpecCompatibility::MethodDoubleExtensions; end 8 | module T::CompatibilityPatches::RSpecCompatibility::RecorderExtensions; end 9 | module T::Private::Methods::MethodHooks; end 10 | module T::Private::Methods::SingletonMethodHooks; end 11 | class Prism::LexCompat::Result; end -------------------------------------------------------------------------------- /spec/channel_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'securerandom' 4 | require 'stream-chat' 5 | 6 | describe StreamChat::Channel do 7 | def loop_times(times) 8 | loop do 9 | begin 10 | yield() 11 | return 12 | rescue StandardError, RSpec::Expectations::ExpectationNotMetError 13 | raise if times.zero? 14 | end 15 | 16 | sleep(1) 17 | times -= 1 18 | end 19 | end 20 | 21 | before(:all) do 22 | @client = StreamChat::Client.from_env 23 | @created_users = [] 24 | end 25 | 26 | before(:each) do 27 | @random_users = [{ id: SecureRandom.uuid, name: 'b' }, { id: SecureRandom.uuid, name: 'a' }] 28 | @random_user = { id: SecureRandom.uuid } 29 | 30 | users_to_insert = [@random_users[0], @random_users[1], @random_user] 31 | 32 | @created_users.push(*users_to_insert.map { |u| u[:id] }) 33 | @client.upsert_users(users_to_insert) 34 | 35 | @channel = @client.channel('messaging', channel_id: SecureRandom.uuid, data: { test: true, language: 'ruby' }) 36 | @channel.create(@random_user[:id]) 37 | end 38 | 39 | after(:each) do 40 | @channel.delete 41 | rescue StreamChat::StreamAPIException 42 | # if the channel is already deleted by the test, we can ignore the error 43 | end 44 | 45 | after(:all) do 46 | curr_idx = 0 47 | batch_size = 25 48 | 49 | slice = @created_users.slice(0, batch_size) 50 | 51 | while !slice.nil? && !slice.empty? 52 | @client.delete_users(slice, user: StreamChat::HARD_DELETE, messages: StreamChat::HARD_DELETE) 53 | 54 | curr_idx += batch_size 55 | slice = @created_users.slice(curr_idx, batch_size) 56 | end 57 | end 58 | 59 | it 'can create channel without id' do 60 | channel = @client.channel('messaging', data: { 'members' => @random_users.map { |u| u[:id] } }) 61 | expect(channel.id).to eq nil 62 | 63 | channel.create(@random_users[0][:id]) 64 | expect(channel.id).not_to eq nil 65 | end 66 | 67 | it 'can send events' do 68 | response = @channel.send_event({ 'type' => 'typing.start' }, @random_user[:id]) 69 | expect(response).to include 'event' 70 | expect(response['event']['type']).to eq 'typing.start' 71 | end 72 | 73 | it 'can get many messages' do 74 | msg = @channel.send_message({ text: 'hi' }, @random_user[:id]) 75 | response = @channel.get_messages([msg['message']['id']]) 76 | expect(response['messages']).not_to be_empty 77 | end 78 | 79 | it 'can send reactions' do 80 | msg = @channel.send_message({ 'text' => 'hi' }, @random_user[:id]) 81 | response = @channel.send_reaction(msg['message']['id'], { 'type' => 'love' }, @random_user[:id]) 82 | expect(response).to include 'message' 83 | expect(response['message']['latest_reactions'].length).to eq 1 84 | expect(response['message']['latest_reactions'][0]['type']).to eq 'love' 85 | end 86 | 87 | it 'can delete a reaction' do 88 | msg = @channel.send_message({ 'text' => 'hi' }, @random_user[:id]) 89 | @channel.send_reaction(msg['message']['id'], { 'type' => 'love' }, @random_user[:id]) 90 | response = @channel.delete_reaction(msg['message']['id'], 'love', @random_user[:id]) 91 | expect(response).to include 'message' 92 | expect(response['message']['latest_reactions'].length).to eq 0 93 | end 94 | 95 | it 'can mute and unmute a channel' do 96 | response = @channel.mute(@random_user[:id]) 97 | expect(response['channel_mute']['channel']['cid']).not_to be_empty 98 | 99 | @channel.unmute(@random_user[:id]) 100 | end 101 | 102 | it 'can update metadata' do 103 | response = @channel.update({ 'motd' => 'one apple a day...' }) 104 | expect(response).to include 'channel' 105 | expect(response['channel']['motd']).to eq 'one apple a day...' 106 | end 107 | 108 | it 'can update metadata partial' do 109 | @channel.update_partial({ color: 'blue', age: 30 }, ['motd']) 110 | response = @channel.query 111 | expect(response['channel']['color']).to eq 'blue' 112 | expect(response['channel']['age']).to eq 30 113 | expect(response['channel']).not_to include 'motd' 114 | 115 | @channel.update_partial({ color: 'red' }, ['age']) 116 | response = @channel.query 117 | expect(response['channel']['color']).to eq 'red' 118 | expect(response['channel']).not_to include 'age' 119 | expect(response['channel']).not_to include 'motd' 120 | end 121 | 122 | it 'can delete' do 123 | response = @channel.delete 124 | expect(response).to include 'channel' 125 | expect(response['channel'].fetch('deleted_at')).not_to eq nil 126 | end 127 | 128 | it 'can truncate' do 129 | response = @channel.truncate 130 | expect(response).to include 'channel' 131 | end 132 | 133 | it 'can truncate with message' do 134 | text = SecureRandom.uuid.to_s 135 | @channel.truncate(message: { text: text, user_id: @random_user[:id] }) 136 | 137 | loop_times 60 do 138 | channel_state = @channel.query 139 | expect(channel_state).to include 'messages' 140 | expect(channel_state['messages'][0]['text']).to eq(text) 141 | end 142 | end 143 | 144 | it 'can add members' do 145 | response = @channel.remove_members([@random_users[0][:id], @random_users[1][:id]]) 146 | expect(response['members'].length).to eq 0 147 | 148 | @channel.add_members([@random_users[0][:id]]) 149 | response = @channel.add_members([@random_users[1][:id]], hide_history: true) 150 | expect(response['members'].length).to eq 2 151 | response['members']&.each do |m| 152 | expect(m.fetch('is_moderator', false)).to be false 153 | end 154 | end 155 | 156 | it 'can invite members' do 157 | response = @channel.remove_members([@random_user[:id]]) 158 | expect(response['members'].length).to eq 0 159 | 160 | response = @channel.invite_members([@random_user[:id]]) 161 | expect(response['members'].length).to eq 1 162 | expect(response['members'][0].fetch('invited', false)).to be true 163 | end 164 | 165 | it 'can accept invitation' do 166 | @channel.remove_members([@random_user[:id]]) 167 | @channel.invite_members([@random_user[:id]]) 168 | 169 | @channel.accept_invite(@random_user[:id]) 170 | end 171 | 172 | it 'can reject invitation' do 173 | @channel.remove_members([@random_user[:id]]) 174 | @channel.invite_members([@random_user[:id]]) 175 | 176 | @channel.reject_invite(@random_user[:id]) 177 | end 178 | 179 | it 'can add moderators' do 180 | response = @channel.add_moderators([@random_user[:id]]) 181 | expect(response['members'][0]['is_moderator']).to be true 182 | 183 | response = @channel.demote_moderators([@random_user[:id]]) 184 | expect(response['members'][0].fetch('is_moderator', false)).to be false 185 | end 186 | 187 | it 'can mark messages as read' do 188 | response = @channel.mark_read(@random_user[:id]) 189 | expect(response).to include 'event' 190 | expect(response['event']['type']).to eq 'message.read' 191 | end 192 | 193 | it 'can get replies' do 194 | msg = @channel.send_message({ 'text' => 'hi' }, @random_user[:id]) 195 | response = @channel.get_replies(msg['message']['id']) 196 | expect(response).to include 'messages' 197 | expect(response['messages'].length).to eq 0 198 | (1..10).each do |i| 199 | @channel.send_message( 200 | { 'text' => 'hi', 'index' => i, 'parent_id' => msg['message']['id'] }, 201 | @random_user[:id] 202 | ) 203 | end 204 | response = @channel.get_replies(msg['message']['id']) 205 | expect(response).to include 'messages' 206 | expect(response['messages'].length).to eq 10 207 | end 208 | 209 | it 'can get reactions' do 210 | msg = @channel.send_message({ 'text' => 'hi' }, @random_user[:id]) 211 | response = @channel.get_reactions(msg['message']['id']) 212 | expect(response).to include 'reactions' 213 | expect(response['reactions'].length).to eq 0 214 | 215 | @channel.send_reaction(msg['message']['id'], { 'type' => 'love', 'count' => 42 }, @random_user[:id]) 216 | @channel.send_reaction(msg['message']['id'], { 'type' => 'clap' }, @random_user[:id]) 217 | 218 | response = @channel.get_reactions(msg['message']['id']) 219 | expect(response['reactions'].length).to eq 2 220 | 221 | response = @channel.get_reactions(msg['message']['id'], offset: 1) 222 | expect(response['reactions'].length).to eq 1 223 | expect(response['reactions'][0]['count']).to eq 42 224 | end 225 | 226 | it 'send message with pending metadata' do 227 | options = { 228 | is_pending_message: true, 229 | pending_message_metadata: { 230 | metadata: 'some_data' 231 | } 232 | } 233 | msg = @channel.send_message({ text: 'hi' }, @random_user[:id], **options) 234 | response = @client.get_message(msg['message']['id']) 235 | expect(response['message']).not_to be_empty 236 | expect(response['pending_message_metadata']['metadata']).to eq 'some_data' 237 | end 238 | 239 | it 'hides\shows channel for user' do 240 | @channel.hide(@random_user[:id]) 241 | @channel.show(@random_user[:id]) 242 | end 243 | 244 | file = '' 245 | it 'can send file' do 246 | response = @channel.send_file("#{__dir__}/data/helloworld.txt", @random_user, 'text/plain') 247 | expect(response).to have_key('file') 248 | file = response['file'] 249 | end 250 | 251 | it 'delete file' do 252 | @channel.delete_file(file) 253 | end 254 | 255 | image = '' 256 | it 'can send image' do 257 | response = @channel.send_image("#{__dir__}/data/helloworld.jpg", @random_user, 'image/jpeg') 258 | expect(response).to have_key('file') 259 | image = response['file'] 260 | end 261 | 262 | it 'delete image' do 263 | @channel.delete_image(image) 264 | end 265 | 266 | it 'query members' do 267 | response = @channel.query_members 268 | expect(response['members'].length).to eq 0 269 | 270 | members = [] 271 | @random_users&.each do |u| 272 | members << u[:id] 273 | end 274 | @channel.add_members(members) 275 | 276 | response = @channel.query_members(sort: { name: 1 }) 277 | expect(response['members'].length).to eq 2 278 | 279 | got_members = [] 280 | response['members']&.each do |m| 281 | got_members << m['user']['id'] 282 | end 283 | expect(got_members).to eq members.reverse 284 | 285 | response = @channel.query_members(limit: 1) 286 | expect(response['members'].length).to eq 1 287 | 288 | response = @channel.query_members(filter_conditions: { notifications_muted: true }) 289 | expect(response['members'].length).to eq 2 290 | end 291 | 292 | it 'can pin and unpin a channel' do 293 | @channel.add_members([@random_users[0][:id]]) 294 | @channel.add_members([@random_users[1][:id]]) 295 | 296 | # Pin the channel 297 | now = Time.now 298 | response = @channel.pin(@random_users[0][:id]) 299 | expect(response['channel_member']['pinned_at']).not_to be_nil 300 | expect(Time.parse(response['channel_member']['pinned_at']).to_i).to be >= now.to_i 301 | 302 | # Query for pinned channel 303 | response = @client.query_channels({ 'pinned' => true, 'cid' => @channel.cid }, sort: nil, user_id: @random_users[0][:id]) 304 | expect(response['channels'].length).to eq 1 305 | expect(response['channels'][0]['channel']['cid']).to eq @channel.cid 306 | 307 | # Unpin the channel 308 | response = @channel.unpin(@random_users[0][:id]) 309 | expect(response['channel_member']).not_to have_key('pinned_at') 310 | 311 | # Query for unpinned channel 312 | response = @client.query_channels({ 'pinned' => false, 'cid' => @channel.cid }, sort: nil, user_id: @random_users[0][:id]) 313 | expect(response['channels'].length).to eq 1 314 | expect(response['channels'][0]['channel']['cid']).to eq @channel.cid 315 | end 316 | 317 | it 'can archive and unarchive a channel' do 318 | @channel.add_members([@random_users[0][:id]]) 319 | @channel.add_members([@random_users[1][:id]]) 320 | 321 | # Pin the channel 322 | now = Time.now 323 | response = @channel.archive(@random_users[0][:id]) 324 | expect(response['channel_member']['archived_at']).not_to be_nil 325 | expect(Time.parse(response['channel_member']['archived_at']).to_i).to be >= now.to_i 326 | 327 | # Query for archived channel 328 | response = @client.query_channels({ 'archived' => true, 'cid' => @channel.cid }, sort: nil, user_id: @random_users[0][:id]) 329 | expect(response['channels'].length).to eq 1 330 | expect(response['channels'][0]['channel']['cid']).to eq @channel.cid 331 | 332 | # Unarchive the channel 333 | response = @channel.unarchive(@random_users[0][:id]) 334 | expect(response['channel_member']).not_to have_key('archived_at') 335 | 336 | # Query for unarchived channel 337 | response = @client.query_channels({ 'archived' => false, 'cid' => @channel.cid }, sort: nil, user_id: @random_users[0][:id]) 338 | expect(response['channels'].length).to eq 1 339 | expect(response['channels'][0]['channel']['cid']).to eq @channel.cid 340 | end 341 | 342 | it 'can update channel member partially' do 343 | @channel.add_members([@random_users[0][:id]]) 344 | 345 | # Test setting a field 346 | response = @channel.update_member_partial(@random_users[0][:id], set: { 'hat' => 'blue' }) 347 | expect(response['channel_member']['hat']).to eq 'blue' 348 | 349 | # Test setting and unsetting fields 350 | response = @channel.update_member_partial(@random_users[0][:id], set: { 'color' => 'red' }, unset: ['hat']) 351 | expect(response['channel_member']['color']).to eq 'red' 352 | expect(response['channel_member']).not_to have_key('hat') 353 | end 354 | 355 | it 'can send message with restricted visibility' do 356 | # Send a message that's only visible to specific users 357 | msg = @channel.send_message( 358 | { 359 | 'text' => 'secret message', 360 | 'restricted_visibility' => [@random_users[0][:id], @random_users[1][:id]] 361 | }, 362 | @random_user[:id] 363 | ) 364 | 365 | # Verify the message was sent successfully 366 | expect(msg).to include 'message' 367 | expect(msg['message']['text']).to eq 'secret message' 368 | 369 | # Verify the restricted visibility 370 | expect(msg['message']['restricted_visibility']).to match_array([@random_users[0][:id], @random_users[1][:id]]) 371 | end 372 | 373 | it 'can update message with restricted visibility' do 374 | # First send a regular message 375 | msg = @channel.send_message( 376 | { 377 | 'text' => 'original message' 378 | }, 379 | @random_user[:id] 380 | ) 381 | 382 | # Update the message with restricted visibility 383 | updated_msg = @client.update_message( 384 | { 385 | 'id' => msg['message']['id'], 386 | 'text' => 'updated secret message', 387 | 'restricted_visibility' => [@random_users[0][:id], @random_users[1][:id]], 388 | 'user' => { 'id' => @random_user[:id] } 389 | } 390 | ) 391 | 392 | # Verify the message was updated successfully 393 | expect(updated_msg).to include 'message' 394 | expect(updated_msg['message']['text']).to eq 'updated secret message' 395 | 396 | # Verify the restricted visibility 397 | expect(updated_msg['message']['restricted_visibility']).to match_array([@random_users[0][:id], @random_users[1][:id]]) 398 | end 399 | 400 | it 'can update message partially with restricted visibility' do 401 | # First send a regular message 402 | msg = @channel.send_message( 403 | { 404 | 'text' => 'original message', 405 | 'custom_field' => 'original value' 406 | }, 407 | @random_user[:id] 408 | ) 409 | 410 | # Partially update the message with restricted visibility 411 | updated_msg = @client.update_message_partial( 412 | msg['message']['id'], 413 | { 414 | set: { 415 | text: 'partially updated secret message', 416 | restricted_visibility: [@random_users[0][:id], @random_users[1][:id]] 417 | }, 418 | unset: ['custom_field'] 419 | }, 420 | user_id: @random_user[:id] 421 | ) 422 | 423 | # Verify the message was updated successfully 424 | expect(updated_msg).to include 'message' 425 | expect(updated_msg['message']['text']).to eq 'partially updated secret message' 426 | 427 | # Verify the restricted visibility was set 428 | expect(updated_msg['message']['restricted_visibility']).to match_array([@random_users[0][:id], @random_users[1][:id]]) 429 | 430 | # Verify the custom field was unset 431 | expect(updated_msg['message']).not_to include 'custom_field' 432 | end 433 | 434 | it 'can create draft message' do 435 | draft_message = { 'text' => 'This is a draft message' } 436 | response = @channel.create_draft(draft_message, @random_user[:id]) 437 | 438 | expect(response).to include 'draft' 439 | expect(response['draft']['message']['text']).to eq 'This is a draft message' 440 | expect(response['draft']['channel_cid']).to eq @channel.cid 441 | end 442 | 443 | it 'can get draft message' do 444 | # First create a draft 445 | draft_message = { 'text' => 'This is a draft to retrieve' } 446 | @channel.create_draft(draft_message, @random_user[:id]) 447 | 448 | # Then get the draft 449 | response = @channel.get_draft(@random_user[:id]) 450 | 451 | expect(response).to include 'draft' 452 | expect(response['draft']['message']['text']).to eq 'This is a draft to retrieve' 453 | expect(response['draft']['channel_cid']).to eq @channel.cid 454 | end 455 | 456 | it 'can delete draft message' do 457 | # First create a draft 458 | draft_message = { 'text' => 'This is a draft to delete' } 459 | @channel.create_draft(draft_message, @random_user[:id]) 460 | 461 | # Then delete the draft 462 | @channel.delete_draft(@random_user[:id]) 463 | 464 | # Verify it's deleted by trying to get it 465 | expect { @channel.get_draft(@random_user[:id]) }.to raise_error(StreamChat::StreamAPIException) 466 | end 467 | 468 | it 'can create and manage thread draft' do 469 | # First create a parent message 470 | msg = @channel.send_message({ 'text' => 'Parent message' }, @random_user[:id]) 471 | parent_id = msg['message']['id'] 472 | 473 | # Create a draft reply 474 | draft_reply = { 'text' => 'This is a draft reply', 'parent_id' => parent_id } 475 | response = @channel.create_draft(draft_reply, @random_user[:id]) 476 | 477 | expect(response).to include 'draft' 478 | expect(response['draft']['message']['text']).to eq 'This is a draft reply' 479 | expect(response['draft']['parent_id']).to eq parent_id 480 | 481 | # Get the draft reply 482 | response = @channel.get_draft(@random_user[:id], parent_id: parent_id) 483 | 484 | expect(response).to include 'draft' 485 | expect(response['draft']['message']['text']).to eq 'This is a draft reply' 486 | expect(response['draft']['parent_id']).to eq parent_id 487 | 488 | # Delete the draft reply 489 | @channel.delete_draft(@random_user[:id], parent_id: parent_id) 490 | 491 | # Verify it's deleted 492 | expect { @channel.get_draft(@random_user[:id], parent_id: parent_id) }.to raise_error(StreamChat::StreamAPIException) 493 | end 494 | end 495 | -------------------------------------------------------------------------------- /spec/data/helloworld.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GetStream/stream-chat-ruby/79aa72a75063498490866400e6e027f4f7fa8c72/spec/data/helloworld.jpg -------------------------------------------------------------------------------- /spec/data/helloworld.txt: -------------------------------------------------------------------------------- 1 | Hello World! 2 | -------------------------------------------------------------------------------- /spec/moderation_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'jwt' 4 | require 'securerandom' 5 | require 'stream-chat' 6 | require 'faraday' 7 | 8 | describe StreamChat::Moderation do 9 | def loop_times(times) 10 | loop do 11 | begin 12 | yield() 13 | return 14 | rescue StandardError, RSpec::Expectations::ExpectationNotMetError 15 | raise if times.zero? 16 | end 17 | 18 | sleep(1) 19 | times -= 1 20 | end 21 | end 22 | 23 | before(:all) do 24 | @client = StreamChat::Client.from_env 25 | 26 | @created_users = [] 27 | 28 | @fellowship_of_the_ring = [ 29 | { id: 'frodo-baggins', name: 'Frodo Baggins', race: 'Hobbit', age: 50 }, 30 | { id: 'sam-gamgee', name: 'Samwise Gamgee', race: 'Hobbit', age: 38 }, 31 | { id: 'gandalf', name: 'Gandalf the Grey', race: 'Istari' }, 32 | { id: 'legolas', name: 'Legolas', race: 'Elf', age: 500 } 33 | ] 34 | @client.upsert_users(@fellowship_of_the_ring) 35 | @channel = @client.channel('team', channel_id: 'fellowship-of-the-ring', 36 | data: { members: @fellowship_of_the_ring.map { |fellow| fellow[:id] } }) 37 | @channel.create('gandalf') 38 | end 39 | 40 | before(:each) do 41 | @random_users = [{ id: SecureRandom.uuid }, { id: SecureRandom.uuid }] 42 | @random_user = { id: SecureRandom.uuid } 43 | users_to_insert = [@random_users[0], @random_users[1], @random_user] 44 | 45 | @created_users.push(*users_to_insert.map { |u| u[:id] }) 46 | 47 | @client.upsert_users(users_to_insert) 48 | end 49 | 50 | after(:all) do 51 | curr_idx = 0 52 | batch_size = 25 53 | 54 | slice = @created_users.slice(0, batch_size) 55 | 56 | while !slice.nil? && !slice.empty? 57 | @client.delete_users(slice, user: StreamChat::HARD_DELETE, messages: StreamChat::HARD_DELETE) 58 | 59 | curr_idx += batch_size 60 | slice = @created_users.slice(curr_idx, batch_size) 61 | end 62 | end 63 | 64 | it 'properly sets up a new client' do 65 | client = StreamChat::Client.from_env 66 | 67 | client.set_http_client(Faraday.new(url: 'https://getstream.io')) 68 | expect { client.get_app_settings }.to raise_error(StreamChat::StreamAPIException) 69 | 70 | client.set_http_client(Faraday.new(url: 'https://chat.stream-io-api.com')) 71 | response = client.get_app_settings 72 | expect(response).to include 'app' 73 | end 74 | 75 | it 'raises ArgumentError if no api_key is provided' do 76 | expect { StreamChat::Client.new(nil, nil) }.to raise_error(TypeError) 77 | end 78 | 79 | it 'properly handles stream response class' do 80 | response = @client.get_app_settings 81 | expect(response.rate_limit.limit).to be > 0 82 | expect(response.rate_limit.remaining).to be > 0 83 | expect(response.rate_limit.reset).to be_within(120).of Time.now.utc 84 | expect(response.status_code).to be 200 85 | expect(response.to_json).not_to include 'rate_limit' 86 | expect(response.to_json).not_to include 'status_code' 87 | end 88 | 89 | describe 'moderation' do 90 | before(:each) do 91 | @moderation = @client.moderation 92 | @test_user_id = SecureRandom.uuid 93 | @test_message_id = SecureRandom.uuid 94 | @test_config_key = SecureRandom.uuid 95 | end 96 | 97 | it 'flagging a user and message' do 98 | msg_response = @channel.send_message({ id: @test_message_id, text: 'Test message' }, @test_user_id) 99 | expect(msg_response['message']['id']).to eq(@test_message_id) 100 | expect(msg_response['message']['user']['id']).to eq(@test_user_id) 101 | response = @moderation.flag_user( 102 | @test_user_id, 103 | 'inappropriate_behavior', 104 | user_id: @random_user[:id], 105 | custom: { severity: 'high' } 106 | ) 107 | expect(response['duration']).not_to be_nil 108 | response = @moderation.flag_message( 109 | @test_message_id, 110 | 'inappropriate_content', 111 | user_id: @random_user[:id], 112 | custom: { category: 'spam' } 113 | ) 114 | expect(response['duration']).not_to be_nil 115 | end 116 | 117 | it 'mute a user and unmute a user' do 118 | @channel.send_message({ id: @test_message_id, text: 'Test message' }, @test_user_id) 119 | testuserid1 = @random_user[:id] 120 | response = @moderation.mute_user( 121 | @test_user_id, 122 | user_id: testuserid1, 123 | timeout: 60 124 | ) 125 | expect(response['duration']).not_to be_nil 126 | expect(response['mutes'][0]['user']['id']).to eq(testuserid1) 127 | response = @moderation.unmute_user( 128 | @test_user_id, 129 | user_id: @random_user[:id] 130 | ) 131 | expect(response['duration']).not_to be_nil 132 | 133 | response = @moderation.get_user_moderation_report( 134 | @test_user_id, 135 | include_user_blocks: true, 136 | include_user_mutes: true 137 | ) 138 | expect(response['duration']).not_to be_nil 139 | end 140 | 141 | it 'adds custom flags to an entity' do 142 | testuserid1 = @random_user[:id] 143 | testmsgid1 = SecureRandom.uuid 144 | @channel.send_message({ id: testmsgid1, text: 'Test message' }, testuserid1) 145 | entity_type = 'stream:chat:v1:message' 146 | entity_id = testmsgid1 147 | moderation_payload = { 148 | 'texts' => ['Test message'], 149 | 'custom' => { 'original_message_type' => 'regular' } 150 | } 151 | flags = [{ type: 'custom_check_text', value: 'test_flag' }] 152 | 153 | response = @moderation.add_custom_flags(entity_type, entity_id, moderation_payload, flags, entity_creator_id: testuserid1) 154 | expect(response['duration']).not_to be_nil 155 | response = @moderation.add_custom_message_flags( 156 | testmsgid1, 157 | [{ type: 'custom_check_text', value: 'test_flag' }] 158 | ) 159 | expect(response['duration']).not_to be_nil 160 | end 161 | 162 | it 'check user profile' do 163 | response = @moderation.check_user_profile( 164 | @test_user_id, 165 | { username: 'fuck_you_123' } 166 | ) 167 | expect(response['duration']).not_to be_nil 168 | expect(response['status']).to eq('complete') 169 | expect(response['recommended_action']).to eq('remove') 170 | 171 | response = @moderation.check_user_profile( 172 | @test_user_id, 173 | { username: 'hi' } 174 | ) 175 | expect(response['duration']).not_to be_nil 176 | expect(response['status']).to eq('complete') 177 | expect(response['recommended_action']).to eq('keep') 178 | end 179 | 180 | it 'config test' do 181 | # Create moderation config 182 | moderation_config = { 183 | key: "chat:team:#{@channel.id}", 184 | block_list_config: { 185 | enabled: true, 186 | rules: [ 187 | { 188 | name: 'profanity_en_2020_v1', 189 | action: 'flag' 190 | } 191 | ] 192 | } 193 | } 194 | @moderation.upsert_config(moderation_config) 195 | response = @moderation.get_config("chat:team:#{@channel.id}") 196 | expect(response['config']['key']).to eq("chat:team:#{@channel.id}") 197 | 198 | response = @moderation.query_configs( 199 | { key: "chat:messaging:#{@channel.id}" }, 200 | [] 201 | ) 202 | expect(response).not_to be_nil 203 | 204 | # Send message that should be blocked 205 | response = @channel.send_message( 206 | { text: 'damn' }, 207 | @random_user[:id], 208 | force_moderation: true 209 | ) 210 | 211 | # Verify message appears in review queue 212 | queue_response = @moderation.query_review_queue( 213 | { entity_type: 'stream:chat:v1:message' }, 214 | { created_at: -1 }, 215 | limit: 1 216 | ) 217 | expect(queue_response['items'][0]['entity_id']).to eq(response['message']['id']) 218 | 219 | response = @moderation.delete_config("chat:team:#{@channel.id}") 220 | expect(response['duration']).not_to be_nil 221 | end 222 | end 223 | end 224 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'simplecov' 2 | require 'simplecov-console' 3 | 4 | SimpleCov.start do 5 | formatter SimpleCov::Formatter::Console 6 | add_filter '/spec/' 7 | end 8 | -------------------------------------------------------------------------------- /stream-chat.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path('lib', __dir__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require 'stream-chat/version' 6 | 7 | Gem::Specification.new do |gem| 8 | gem.name = 'stream-chat-ruby' 9 | gem.description = 'Ruby client for Stream Chat.' 10 | gem.version = StreamChat::VERSION 11 | gem.platform = Gem::Platform::RUBY 12 | gem.summary = 'The low level client for serverside calls for Stream Chat.' 13 | gem.email = 'support@getstream.io' 14 | gem.homepage = 'http://github.com/GetStream/stream-chat-ruby' 15 | gem.authors = ['getstream.io'] 16 | gem.files = Dir.chdir(File.expand_path(__dir__)) do 17 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|sorbet|spec|\.github|scripts|assets)/}) } 18 | end 19 | gem.required_ruby_version = '>=3.0.0' 20 | gem.metadata = { 21 | 'rubygems_mfa_required' => 'false', 22 | 'homepage_uri' => 'https://getstream.io/chat/docs/', 23 | 'bug_tracker_uri' => 'https://github.com/GetStream/stream-chat-ruby/issues', 24 | 'documentation_uri' => 'https://getstream.io/chat/docs/ruby/?language=ruby', 25 | 'changelog_uri' => 'https://github.com/GetStream/stream-chat-ruby/blob/master/CHANGELOG.md', 26 | 'source_code_uri' => 'https://github.com/GetStream/stream-chat-ruby' 27 | } 28 | 29 | gem.add_dependency 'faraday', '~> 2.12.2' 30 | gem.add_dependency 'faraday-multipart', '~> 1.1.0' 31 | gem.add_dependency 'faraday-net_http_persistent', '~> 2.3.0' 32 | gem.add_dependency 'jwt', '~> 2.10' 33 | gem.add_dependency 'net-http-persistent', '~> 4.0' 34 | gem.add_dependency 'sorbet-runtime', '~> 0.5.11820' 35 | end 36 | --------------------------------------------------------------------------------