diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04343e0e..d6a751da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,41 +1,48 @@ name: CI on: push: - branches: - - main + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' pull_request: - branches: - - main - - next + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: + timeout-minutes: 10 name: lint - runs-on: ubuntu-latest - + runs-on: ${{ github.repository == 'stainless-sdks/prelude-ruby' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - bundler-cache: true - ruby-version: '3.1' + bundler-cache: false + - run: |- + bundle install - name: Run lints run: ./scripts/lint test: + timeout-minutes: 10 name: test - runs-on: ubuntu-latest - + runs-on: ${{ github.repository == 'stainless-sdks/prelude-ruby' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - bundler-cache: true - ruby-version: '3.1' + bundler-cache: false + - run: |- + bundle install - name: Run tests run: ./scripts/test - diff --git a/.github/workflows/publish-gem.yml b/.github/workflows/publish-gem.yml index fc60eb96..381e3009 100644 --- a/.github/workflows/publish-gem.yml +++ b/.github/workflows/publish-gem.yml @@ -1,6 +1,6 @@ # This workflow is triggered when a GitHub release is created. # It can also be run manually to re-publish to rubygems.org in case it failed for some reason. -# You can run this workflow by navigating to https://www.github.com/prelude-so/python-sdk/actions/workflows/publish-gem.yml +# You can run this workflow by navigating to https://www.github.com/prelude-so/ruby-sdk/actions/workflows/publish-gem.yml name: Publish Gem on: workflow_dispatch: @@ -19,7 +19,8 @@ jobs: uses: ruby/setup-ruby@v1 with: bundler-cache: false - ruby-version: '3.1' + - run: |- + bundle install - name: Publish to RubyGems.org run: | diff --git a/.gitignore b/.gitignore index 79fe391f..3d26ceed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ -.prism.log +*.gem .idea/ +.ignore +.prism.log .ruby-lsp/ .yardoc/ -doc/ +bin/tapioca Brewfile.lock.json -*.gem +doc/ +sorbet/tapioca/* diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ba6c3483..f14b480a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.1" + ".": "0.1.0-alpha.2" } \ No newline at end of file diff --git a/.rubocop.yml b/.rubocop.yml index c64823eb..d06397b5 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,143 +1,291 @@ -# Just to be safe, ensure nobody is mutating our internal strings. -Style/FrozenStringLiteralComment: - EnforcedStyle: always +--- +# Explicitly disable pending cops for now. This is the default behaviour but +# this avoids a large warning every time we run it. +# Stop RuboCop nagging about rubocop-rake. +# Ensure that RuboCop validates according to the lowest version of Ruby that we support. +AllCops: + Exclude: + - "bin/*" + NewCops: enable + SuggestExtensions: false + TargetRubyVersion: 3.2.0 -# And/or have confusing precedence, avoid them. -Style/AndOr: - EnforcedStyle: always +# Whether MFA is required or not should be left to the token configuration. +Gemspec/RequireMFA: + Enabled: false -# Prefer double quotes so that interpolation can be easily added. -Style/StringLiterals: - EnforcedStyle: double_quotes +# Don't require this extra line break, it can be excessive. +Layout/EmptyLineAfterGuardClause: + Enabled: false -# Most common style in Ruby. -Style/RegexpLiteral: - EnforcedStyle: slashes +# Don't leave complex assignment values hanging off to the right. +Layout/EndAlignment: + EnforcedStyleAlignWith: variable -# Prefer explicit symbols for clarity; you can search for `:the_symbol`. -Style/SymbolArray: - EnforcedStyle: brackets +Layout/FirstArrayElementLineBreak: + Enabled: true -# Prefer consistency in method calling syntax -Style/MethodCallWithArgsParentheses: +Layout/FirstHashElementLineBreak: Enabled: true + +Layout/FirstMethodArgumentLineBreak: + Enabled: true + +Layout/FirstMethodParameterLineBreak: + Enabled: true + +# Set a reasonable line length; rely on other cops to correct long lines. +Layout/LineLength: + AllowedPatterns: + - "^\\s*#.*$" + - ^require(_relative)? + - "PreludeSDK::Internal::Type::BaseModel$" + - "^\\s*[A-Z0-9_]+ = :" + - "PreludeSDK::(Models|Resources|Test)::" + Max: 110 + +Layout/MultilineArrayLineBreaks: + Enabled: true + +# Start the assignment on the same line variable is mentioned. +Layout/MultilineAssignmentLayout: + EnforcedStyle: same_line + +Layout/MultilineHashKeyLineBreaks: + Enabled: true + +Layout/MultilineMethodArgumentLineBreaks: + Enabled: true + +Layout/MultilineMethodParameterLineBreaks: + Enabled: true + +# Prefer compact hash literals. +Layout/SpaceInsideHashLiteralBraces: + EnforcedStyle: no_space Exclude: - - '**/*.gemspec' - IgnoredMethods: - - raise + - "**/*.rbi" -# Nothing wrong with inline private methods -Style/AccessModifierDeclarations: +Lint/BooleanSymbol: Enabled: false -# Nothing wrong with clear if statements. -Style/IfUnlessModifier: +# This option occasionally mangles identifier names +Lint/DeprecatedConstants: + Exclude: + - "**/*.rbi" + +# We use pattern assertion in tests to ensure correctness. +Lint/DuplicateMatchPattern: + Exclude: + - "test/**/*" + +# Fairly useful in tests for pattern assertions. +Lint/EmptyInPattern: + Exclude: + - "test/**/*" + +Lint/MissingCopEnableDirective: + Exclude: + - "examples/**/*.rb" + +Lint/MissingSuper: + Exclude: + - "**/*.rbi" + +Lint/SymbolConversion: + Exclude: + - "**/*.rbi" + +# Disabled for safety reasons, this option changes code semantics. +Lint/UnusedMethodArgument: + AutoCorrect: false + +# This option is prone to causing accidental bugs. +Lint/UselessAssignment: + AutoCorrect: false + Exclude: + - "examples/**/*.rb" + +Metrics/AbcSize: Enabled: false -# Unless is not necessarily clearer. -Style/NegatedIf: +Metrics/BlockLength: + AllowedPatterns: + - assert_pattern + - type_alias + - define_sorbet_constant! + Exclude: + - "**/*.rbi" + +Metrics/ClassLength: Enabled: false -# We use these sparingly, where we anticipate future branches for the -# inner conditional. -Style/SoleNestedConditional: +Metrics/CyclomaticComplexity: Enabled: false -# Allow explicit empty elses, for clarity. -Style/EmptyElse: +Metrics/MethodLength: Enabled: false -# Allow explicit ifs, especially for imperative use. -Style/SafeNavigation: +Metrics/ModuleLength: Enabled: false -# We commonly use ENV['KEY'], it's OK. -Style/FetchEnvVar: +Metrics/ParameterLists: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false + +Naming/AccessorMethodName: + Enabled: false + +# Need to preserve block identifier for documentation. +Naming/BlockForwarding: + Enabled: false + +# Underscores are generally useful for disambiguation. +Naming/ClassAndModuleCamelCase: + Enabled: false + +Naming/MethodParameterName: + Enabled: false + +Naming/PredicateName: + Exclude: + - "**/*.rbi" + +Naming/VariableNumber: Enabled: false +# Nothing wrong with inline private methods. +Style/AccessModifierDeclarations: + Enabled: false + +Style/AccessorGrouping: + Exclude: + - "**/*.rbi" + # Behaviour of alias_method is more predictable. Style/Alias: EnforcedStyle: prefer_alias_method +# And/or have confusing precedence, avoid them. +Style/AndOr: + EnforcedStyle: always + +Style/ArgumentsForwarding: + Enabled: false + +Style/BisectedAttrAccessor: + Exclude: + - "**/*.rbi" + # We prefer nested modules in lib/, but are currently using compact style for tests. Style/ClassAndModuleChildren: Exclude: - - test/**/* + - "test/**/*" -# Rubocop is pretty bad about mangling single line lambdas -Style/Lambda: +Style/CommentAnnotation: Enabled: false -# Set a reasonable line length; rely on other cops to correct long lines. -Layout/LineLength: - Max: 110 - AllowedPatterns: - - '^(\s*#)' # Comments for YARD docs: @param and similar. - - '= Prelude::Resources::\S+\.new\(client: (self|client)\)$' # Instantiating resources. - - '^\s*(-> { )?Prelude::Models::[a-zA-Z0-9:]+( })?$' # Line is entirely a reference to a fully-qualified Model. +# We should go back and add these docs, but ignore for now. +Style/Documentation: + Enabled: false -# Start the assignment on the same line variable is mentioned. -Layout/MultilineAssignmentLayout: - EnforcedStyle: same_line +# Allow explicit empty elses, for clarity. +Style/EmptyElse: + Enabled: false -# Don't leave complex assignment values hanging off to the right. -Layout/EndAlignment: - EnforcedStyleAlignWith: variable +Style/EmptyMethod: + Exclude: + - "**/*.rbi" -# Don't require this extra line break, it can be excessive. -Layout/EmptyLineAfterGuardClause: +# We commonly use ENV['KEY'], it's OK. +Style/FetchEnvVar: Enabled: false -# For arrays, hashes, method arguments, and method params, if they are broken onto multiple lines: -# * Should have one element per line. -# * Should have a line break before the first element. -Layout/MultilineArrayLineBreaks: - Enabled: true -Layout/FirstArrayElementLineBreak: - Enabled: true -Layout/MultilineHashKeyLineBreaks: - Enabled: true -Layout/FirstHashElementLineBreak: - Enabled: true -Layout/MultilineMethodArgumentLineBreaks: - Enabled: true -Layout/FirstMethodArgumentLineBreak: - Enabled: true -Layout/MultilineMethodParameterLineBreaks: - Enabled: true -Layout/FirstMethodParameterLineBreak: - Enabled: true +# Just to be safe, ensure nobody is mutating our internal strings. +Style/FrozenStringLiteralComment: + EnforcedStyle: always + Exclude: + - "**/*.rbi" -# Prefer compact hash literals. -Layout/SpaceInsideHashLiteralBraces: - EnforcedStyle: no_space +# Nothing wrong with clear if statements. +Style/IfUnlessModifier: + Enabled: false -# These cops are not as applicable to generated code. -Metrics/ParameterLists: +# Rubocop is pretty bad about mangling single line lambdas. +Style/Lambda: Enabled: false -Metrics/MethodLength: + +# Prefer consistency in method calling syntax. +Style/MethodCallWithArgsParentheses: + AllowedMethods: + - raise + Enabled: true + Exclude: + - "**/*.gemspec" + +Style/MultilineBlockChain: Enabled: false -Metrics/ClassLength: + +# Perfectly fine. +Style/MultipleComparison: Enabled: false -# These cops are too aggressive for us or now, but we may want to address them -# later. -Metrics/CyclomaticComplexity: +Style/MutableConstant: + Exclude: + - "**/*.rbi" + +# Not all parameters should be named. +Style/NumberedParameters: Enabled: false -Metrics/PerceivedComplexity: + +Style/NumberedParametersLimit: + Max: 2 + +# Reasonable to use brackets for errors with long messages. +Style/RaiseArgs: Enabled: false -Metrics/AbcSize: + +# Be explicit about `RuntimeError`s. +Style/RedundantException: Enabled: false -# We should go back and add these docs, but ignore for now. -Style/Documentation: +Style/RedundantInitialize: + Exclude: + - "**/*.rbi" + +Style/RedundantParentheses: + Exclude: + - "**/*.rbi" + +# Prefer slashes for regex literals. +Style/RegexpLiteral: + EnforcedStyle: slashes + +# Allow explicit ifs, especially for imperative use. +Style/SafeNavigation: Enabled: false -# Explicitly disable pending cops for now. This is the default behaviour but -# this avoids a large warning every time we run it. -# Stop RuboCop nagging about rubocop-rake. -# Ensure that RuboCop validates according to the lowest version of Ruby that we support. -AllCops: - NewCops: enable - SuggestExtensions: false - TargetRubyVersion: 3.0.0 +Style/SignalException: + Exclude: + - Rakefile + - "**/*.rake" + +# We use these sparingly, where we anticipate future branches for the +# inner conditional. +Style/SoleNestedConditional: + Enabled: false + +# Prefer double quotes so that interpolation can be easily added. +Style/StringLiterals: + EnforcedStyle: double_quotes + +# Prefer explicit symbols for clarity; you can search for `:the_symbol`. +Style/SymbolArray: + EnforcedStyle: brackets + +# This option makes examples harder to read for ruby novices. +Style/SymbolProc: + Exclude: + - "examples/**/*.rb" diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..944880fa --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.2.0 diff --git a/.solargraph.yml b/.solargraph.yml new file mode 100644 index 00000000..24c3f206 --- /dev/null +++ b/.solargraph.yml @@ -0,0 +1,11 @@ +--- +max_files: 0 +include: + - '*.gemspec' + - 'Rakefile' + - 'examples/**/*.rb' + - 'lib/**/*.rb' + - 'test/prelude_sdk/resource_namespaces.rb' + - 'test/prelude_sdk/test_helper.rb' +exclude: + - 'rbi/**/*' diff --git a/.stats.yml b/.stats.yml index 9a460fde..4e5c05c2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,4 @@ -configured_endpoints: 5 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/prelude%2Fprelude-c1f72f65743e762371400a6f36ba21d4e68ceaa351cb3ea7674cbc04a39e298c.yml +configured_endpoints: 7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/prelude%2Fprelude-8c2aed945f97bd831f3e9331ba7ab352f125e5bf1384da698d884054f2ef2211.yml +openapi_spec_hash: 5429becbaecad8ba54c45eebb4d29b11 +config_hash: 3b3da533cbc4a28dd64565b6c3fa3dd0 diff --git a/.yardopts b/.yardopts index fe9e79a1..84c12f2a 100644 --- a/.yardopts +++ b/.yardopts @@ -1,2 +1,6 @@ +--type-name-tag generic:Generic +--default-return void --markup markdown ---load .yardopts.rb +--markup-provider redcarpet +--exclude /rbi +--exclude /sig diff --git a/.yardopts.rb b/.yardopts.rb deleted file mode 100644 index 8e9b8f90..00000000 --- a/.yardopts.rb +++ /dev/null @@ -1 +0,0 @@ -# frozen_string_literal: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 2efa9720..2f265699 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,335 @@ # Changelog +## 0.1.0-alpha.2 (2025-06-27) + +Full Changelog: [v0.1.0-alpha.1...v0.1.0-alpha.2](https://github.com/prelude-so/ruby-sdk/compare/v0.1.0-alpha.1...v0.1.0-alpha.2) + +### ⚠ BREAKING CHANGES + +* bump min supported ruby version to 3.1 (oldest non-EOL) ([#222](https://github.com/prelude-so/ruby-sdk/issues/222)) +* remove top level type aliases to relocated classes ([#221](https://github.com/prelude-so/ruby-sdk/issues/221)) +* use tagged enums in sorbet type definitions ([#190](https://github.com/prelude-so/ruby-sdk/issues/190)) +* support `for item in stream` style iteration on `Stream`s ([#188](https://github.com/prelude-so/ruby-sdk/issues/188)) +* **model:** base model should recursively store coerced base models ([#178](https://github.com/prelude-so/ruby-sdk/issues/178)) +* encode objects in multipart encoding as JSON ([#97](https://github.com/prelude-so/ruby-sdk/issues/97)) +* base page should be module instead of class ([#91](https://github.com/prelude-so/ruby-sdk/issues/91)) +* breaking change - improved request options signatures ([#85](https://github.com/prelude-so/ruby-sdk/issues/85)) + +### Features + +* add deprecation notice to enum members and resources ([#133](https://github.com/prelude-so/ruby-sdk/issues/133)) ([f6f8ae3](https://github.com/prelude-so/ruby-sdk/commit/f6f8ae3237da39de7c086de4c6a8a489beb02814)) +* add jsonl support ([#148](https://github.com/prelude-so/ruby-sdk/issues/148)) ([cafe22a](https://github.com/prelude-so/ruby-sdk/commit/cafe22ac9cd043042c95ed9a5284ce3b9e336dc1)) +* add reference links in yard ([#212](https://github.com/prelude-so/ruby-sdk/issues/212)) ([aaf287c](https://github.com/prelude-so/ruby-sdk/commit/aaf287ca199b70195765c33457176aa26057b7a2)) +* add SKIP_BREW env var to ./scripts/bootstrap ([#152](https://github.com/prelude-so/ruby-sdk/issues/152)) ([7b3a590](https://github.com/prelude-so/ruby-sdk/commit/7b3a590461acee3a4189b5a2597069565a1ddf37)) +* allow all valid `JSON` types to be encoded ([#232](https://github.com/prelude-so/ruby-sdk/issues/232)) ([4e4f6fb](https://github.com/prelude-so/ruby-sdk/commit/4e4f6fb758b7a18796ea51ca9d7284dd6ffead89)) +* **api:** update via SDK Studio ([41cbb9f](https://github.com/prelude-so/ruby-sdk/commit/41cbb9f1c96f67989cb520b4d270ac4bd03e8381)) +* **api:** update via SDK Studio ([3ddcd49](https://github.com/prelude-so/ruby-sdk/commit/3ddcd4966158a8ad3e9df700b2ec2486f03f167b)) +* **api:** update via SDK Studio ([1451f92](https://github.com/prelude-so/ruby-sdk/commit/1451f92b4f8b8f6faf4b6fbab769a84729537a2f)) +* **api:** update via SDK Studio ([4ad8817](https://github.com/prelude-so/ruby-sdk/commit/4ad88170cd346d531959d23072cb303ad7258332)) +* **api:** update via SDK Studio ([#157](https://github.com/prelude-so/ruby-sdk/issues/157)) ([b71bb76](https://github.com/prelude-so/ruby-sdk/commit/b71bb76f96614b3e0a9dd3c4d389d74be87bb4c4)) +* **api:** update via SDK Studio ([#70](https://github.com/prelude-so/ruby-sdk/issues/70)) ([ca6e228](https://github.com/prelude-so/ruby-sdk/commit/ca6e22894e72a9407455a73f4dfdf22962b49b70)) +* **api:** update via SDK Studio ([#74](https://github.com/prelude-so/ruby-sdk/issues/74)) ([6a68e49](https://github.com/prelude-so/ruby-sdk/commit/6a68e49cfd09c95b4930765f5c9ebeedc134ad94)) +* **api:** update via SDK Studio ([#92](https://github.com/prelude-so/ruby-sdk/issues/92)) ([6707265](https://github.com/prelude-so/ruby-sdk/commit/6707265de2fcecbc716a50a37e5c4de43a510c62)) +* breaking change - improved request options signatures ([#85](https://github.com/prelude-so/ruby-sdk/issues/85)) ([4385257](https://github.com/prelude-so/ruby-sdk/commit/4385257e3047f1524fbdc90f714fccc9bcc78068)) +* bump default connection pool size limit to minimum of 99 ([ba2eaa9](https://github.com/prelude-so/ruby-sdk/commit/ba2eaa93a5521e90873ee9c005ec76c502f30959)) +* bump min supported ruby version to 3.1 (oldest non-EOL) ([#222](https://github.com/prelude-so/ruby-sdk/issues/222)) ([ebad6d8](https://github.com/prelude-so/ruby-sdk/commit/ebad6d8a017be26861a1cffdfa0f80635a1996da)) +* bundle typing manifests with gem release ([#108](https://github.com/prelude-so/ruby-sdk/issues/108)) ([8ba7589](https://github.com/prelude-so/ruby-sdk/commit/8ba7589eeabd5c6304887d70ada5ef34a12a7d09)) +* **client:** enable setting base URL from environment variable ([74f81c5](https://github.com/prelude-so/ruby-sdk/commit/74f81c591164077fb133d26fdfd8f641169823be)) +* **client:** send `X-Stainless-Read-Timeout` header ([#98](https://github.com/prelude-so/ruby-sdk/issues/98)) ([4917c8e](https://github.com/prelude-so/ruby-sdk/commit/4917c8ea67c77cdeda57ddcd435b2d45d2050ad5)) +* consistently accept `AnyHash` types in parameter positions in sorbet ([#195](https://github.com/prelude-so/ruby-sdk/issues/195)) ([dc28b6d](https://github.com/prelude-so/ruby-sdk/commit/dc28b6df9df9f6387b6cbf5860d1aff2c61ba1a5)) +* escape path params ([#58](https://github.com/prelude-so/ruby-sdk/issues/58)) ([770f9f3](https://github.com/prelude-so/ruby-sdk/commit/770f9f3d6b365b6c1ef4a735f268ab90d88bd2cc)) +* examples for working with discriminated unions ([#71](https://github.com/prelude-so/ruby-sdk/issues/71)) ([42d52cd](https://github.com/prelude-so/ruby-sdk/commit/42d52cdec8dbd358170e4ce50579bac55edecb9a)) +* exercise connection pool in tests ([#60](https://github.com/prelude-so/ruby-sdk/issues/60)) ([6ef2d3c](https://github.com/prelude-so/ruby-sdk/commit/6ef2d3c6e5f44e4dd6d3c9f318f836c2ee4c46ea)) +* expose base client options as read only attributes ([397ae23](https://github.com/prelude-so/ruby-sdk/commit/397ae23f3142b5bae21f0b6e3834194a44c22f75)) +* expose recursive `#to_h` conversion ([28070c1](https://github.com/prelude-so/ruby-sdk/commit/28070c1e8b9c84a8db990be89594e1b686e89274)) +* generate enum examples ([#38](https://github.com/prelude-so/ruby-sdk/issues/38)) ([7f5df13](https://github.com/prelude-so/ruby-sdk/commit/7f5df13d2baf801a06cad3439c2b27fa83fd0e8d)) +* generate enum examples ([#45](https://github.com/prelude-so/ruby-sdk/issues/45)) ([8c350e5](https://github.com/prelude-so/ruby-sdk/commit/8c350e5a7d242d532002a2655b61d1c8ba7bd91e)) +* generate enum examples ([#49](https://github.com/prelude-so/ruby-sdk/issues/49)) ([5ed025f](https://github.com/prelude-so/ruby-sdk/commit/5ed025f03750023f097fb548ebf9ab36e9f64cd7)) +* generate nested intersections classes ([#41](https://github.com/prelude-so/ruby-sdk/issues/41)) ([83eb830](https://github.com/prelude-so/ruby-sdk/commit/83eb830ee4b7e14fa6690db04922dad104c10355)) +* generate some omitted class names in doc comments ([#48](https://github.com/prelude-so/ruby-sdk/issues/48)) ([6b57ba5](https://github.com/prelude-so/ruby-sdk/commit/6b57ba544b32b76d638d548353888818dd41b824)) +* implement `#hash` for data containers ([4df687e](https://github.com/prelude-so/ruby-sdk/commit/4df687e67fe794475aa7c769397688037ab0384d)) +* implement `to_json` for base model ([#218](https://github.com/prelude-so/ruby-sdk/issues/218)) ([9186468](https://github.com/prelude-so/ruby-sdk/commit/9186468a2ed116a9b743d2c958fe9816745d4845)) +* implement subsumption operator for base classes ([#40](https://github.com/prelude-so/ruby-sdk/issues/40)) ([d01e382](https://github.com/prelude-so/ruby-sdk/commit/d01e3820ea38f2890521feb30a5d6b79be24ed01)) +* implement unions ([#57](https://github.com/prelude-so/ruby-sdk/issues/57)) ([356605b](https://github.com/prelude-so/ruby-sdk/commit/356605b7e6bc63d8e919010071c36eb8ca1aedc8)) +* improve `ArrayOf` DSL to use `:[]` instead of `.new` ([#36](https://github.com/prelude-so/ruby-sdk/issues/36)) ([38b71ce](https://github.com/prelude-so/ruby-sdk/commit/38b71cebf8efbbd5cad9f735951eb47f2a9cbc75)) +* improve `ArrayOf` DSL to use `:[]` instead of `.new` ([#39](https://github.com/prelude-so/ruby-sdk/issues/39)) ([8dcaf94](https://github.com/prelude-so/ruby-sdk/commit/8dcaf946fbf6ff4cf00da13c7b53b28426715e61)) +* improve `ArrayOf` DSL to use `:[]` instead of `.new` ([#46](https://github.com/prelude-so/ruby-sdk/issues/46)) ([f6e37e2](https://github.com/prelude-so/ruby-sdk/commit/f6e37e2445231721ae288643c3c27e62ae0126ca)) +* improve `ArrayOf` DSL to use `:[]` instead of `.new` ([#51](https://github.com/prelude-so/ruby-sdk/issues/51)) ([0e4e595](https://github.com/prelude-so/ruby-sdk/commit/0e4e595b19e96191bacb5bc554bafc229aac2b52)) +* improve interface readability, especially in `*.rbi` ([#94](https://github.com/prelude-so/ruby-sdk/issues/94)) ([8be7261](https://github.com/prelude-so/ruby-sdk/commit/8be7261a649e821eafb0969a557968a68f4e76ae)) +* inline sorbet type aliases ([#104](https://github.com/prelude-so/ruby-sdk/issues/104)) ([4338d86](https://github.com/prelude-so/ruby-sdk/commit/4338d861ad14b580f42437f5a65f135d7c8c4d60)) +* **internal:** converter interface should recurse without schema ([#203](https://github.com/prelude-so/ruby-sdk/issues/203)) ([bf88e0e](https://github.com/prelude-so/ruby-sdk/commit/bf88e0e526994dc0b5b8072571d8906860b48e40)) +* **internal:** modified tests for thread and fiber safety ([#140](https://github.com/prelude-so/ruby-sdk/issues/140)) ([c06ec6c](https://github.com/prelude-so/ruby-sdk/commit/c06ec6cc7f20d8464c64ac996bc79cf89563baa5)) +* isolate platform headers ([#134](https://github.com/prelude-so/ruby-sdk/issues/134)) ([a9b7ea2](https://github.com/prelude-so/ruby-sdk/commit/a9b7ea2dd63492aec0db5d6d26faf15e009614fd)) +* link response models to their methods in yard doc ([#214](https://github.com/prelude-so/ruby-sdk/issues/214)) ([a8af56e](https://github.com/prelude-so/ruby-sdk/commit/a8af56e4a49277a2c86a422f8e7d88a299849fb7)) +* make `build_request` overridable ([#128](https://github.com/prelude-so/ruby-sdk/issues/128)) ([726dd54](https://github.com/prelude-so/ruby-sdk/commit/726dd54f2ac020f795f30668f3b39216eb2cf388)) +* more consistent ArrayOf and HashOf DSL with re: lambda usage ([#72](https://github.com/prelude-so/ruby-sdk/issues/72)) ([f78f172](https://github.com/prelude-so/ruby-sdk/commit/f78f1723b4749eebfbc66a8727b307799ae76b72)) +* prevent tapioca from introspecting the gem internals ([#194](https://github.com/prelude-so/ruby-sdk/issues/194)) ([c72698b](https://github.com/prelude-so/ruby-sdk/commit/c72698b1c35dc27e80210bacc35e89c00183d16b)) +* remove top level type aliases to relocated classes ([#221](https://github.com/prelude-so/ruby-sdk/issues/221)) ([f39c6b3](https://github.com/prelude-so/ruby-sdk/commit/f39c6b3e74c122c5336d69fb434a333dcd35b152)) +* render yard docs with hash and nil? info ([#55](https://github.com/prelude-so/ruby-sdk/issues/55)) ([26d105e](https://github.com/prelude-so/ruby-sdk/commit/26d105e98bef71f6bdfb8e639089e0ca8f68d61c)) +* ruby add nilability annotations ([#79](https://github.com/prelude-so/ruby-sdk/issues/79)) ([5f18508](https://github.com/prelude-so/ruby-sdk/commit/5f1850870848441bd52900673a05a15084909951)) +* run rubocop in multiple processes when formatting ([#75](https://github.com/prelude-so/ruby-sdk/issues/75)) ([b93f3fe](https://github.com/prelude-so/ruby-sdk/commit/b93f3fe50c46358e5dbc248d729b145843e8a74e)) +* support `for item in stream` style iteration on `Stream`s ([#188](https://github.com/prelude-so/ruby-sdk/issues/188)) ([d146304](https://github.com/prelude-so/ruby-sdk/commit/d1463042d75b5f3244c08260c3adaf03a8e6f545)) +* support client level methods ([#155](https://github.com/prelude-so/ruby-sdk/issues/155)) ([7ff2321](https://github.com/prelude-so/ruby-sdk/commit/7ff2321ed3ed4f91bc7f613e37d3d1e510a5267c)) +* support const enums ([#84](https://github.com/prelude-so/ruby-sdk/issues/84)) ([b4787b4](https://github.com/prelude-so/ruby-sdk/commit/b4787b4a892d7e8c5e27021deceec6d30f3cd3f8)) +* support jsonl uploads ([#166](https://github.com/prelude-so/ruby-sdk/issues/166)) ([34c4709](https://github.com/prelude-so/ruby-sdk/commit/34c47091cf1b975a528b5beb226926ac332f167f)) +* support overlapping HTTP requests in same Fiber ([#119](https://github.com/prelude-so/ruby-sdk/issues/119)) ([439bca7](https://github.com/prelude-so/ruby-sdk/commit/439bca7399d583806bde009929c449c1ca0636d9)) +* support query, header, and body params that have identical names ([#231](https://github.com/prelude-so/ruby-sdk/issues/231)) ([fa64b8f](https://github.com/prelude-so/ruby-sdk/commit/fa64b8f33a835c118d42b7440e3378414b57029c)) +* support solargraph generics ([#225](https://github.com/prelude-so/ruby-sdk/issues/225)) ([1336e14](https://github.com/prelude-so/ruby-sdk/commit/1336e14ff156ec78920ce45501798858d7f32da3)) +* support sorbet aliases at the runtime ([f8a0812](https://github.com/prelude-so/ruby-sdk/commit/f8a0812a8131c6a962ebf43d637758d709966781)) +* support specifying content-type with FilePart class ([9d73a4b](https://github.com/prelude-so/ruby-sdk/commit/9d73a4ba64e17bba6b2f609b5c30be5570eca600)) +* support streaming uploads ([#160](https://github.com/prelude-so/ruby-sdk/issues/160)) ([1634acd](https://github.com/prelude-so/ruby-sdk/commit/1634acdf47a7c2014dda83a16fbfb24410f450ed)) +* support webmock for testing ([f2211db](https://github.com/prelude-so/ruby-sdk/commit/f2211db0b5530f776c549de22762b97f9921d728)) +* unify param & return types in yard ([#89](https://github.com/prelude-so/ruby-sdk/issues/89)) ([3c2fe3e](https://github.com/prelude-so/ruby-sdk/commit/3c2fe3e04c87b1391e2fc518ab6f1307c9dd4256)) +* use Pathname alongside raw IO handles for file uploads ([#245](https://github.com/prelude-so/ruby-sdk/issues/245)) ([4a896ed](https://github.com/prelude-so/ruby-sdk/commit/4a896ed8025e9c42a8ca943540bdaa923eaef341)) +* use tagged enums in sorbet type definitions ([#190](https://github.com/prelude-so/ruby-sdk/issues/190)) ([ef39c87](https://github.com/prelude-so/ruby-sdk/commit/ef39c87691e1c982d83c0c0c588c5e05d0c4ab46)) + + +### Bug Fixes + +* `to_sorbet_type` should not return branded types ([fe642ed](https://github.com/prelude-so/ruby-sdk/commit/fe642ed9fcf0bc32517632602c2634cddb236656)) +* always send idempotency header when specified as a request option ([980ae78](https://github.com/prelude-so/ruby-sdk/commit/980ae781b6515ec0992210c49aa4afaefac446a8)) +* bad documentation url for gemdocs.org ([#177](https://github.com/prelude-so/ruby-sdk/issues/177)) ([c71528f](https://github.com/prelude-so/ruby-sdk/commit/c71528f3c10aea180895ed6031e851d7cd7c969c)) +* base client type annotations ([#100](https://github.com/prelude-so/ruby-sdk/issues/100)) ([834b49a](https://github.com/prelude-so/ruby-sdk/commit/834b49a9fd4d457cf4b0b14c384a8b4745727069)) +* base page should be module instead of class ([#91](https://github.com/prelude-so/ruby-sdk/issues/91)) ([ba5d54f](https://github.com/prelude-so/ruby-sdk/commit/ba5d54f0533c5a275895d30a7d55c883fce9699f)) +* better support header parameters ([#141](https://github.com/prelude-so/ruby-sdk/issues/141)) ([dc93295](https://github.com/prelude-so/ruby-sdk/commit/dc93295278daa1361ed3364862ba499a2bc36270)) +* **ci:** release-doctor — report correct token name ([b6c02d9](https://github.com/prelude-so/ruby-sdk/commit/b6c02d9286b549378bd35199e4125fb5b5203c07)) +* **client:** send correct HTTP path ([a375a6a](https://github.com/prelude-so/ruby-sdk/commit/a375a6a617d38ad81e1cd4c18f2093c233fb772a)) +* converter should transform stringio into string where applicable ([#234](https://github.com/prelude-so/ruby-sdk/issues/234)) ([1eeb6b8](https://github.com/prelude-so/ruby-sdk/commit/1eeb6b8fb06e172327b256e6cd1145b95b0c5aec)) +* correctly annotate nil values in yard ([#63](https://github.com/prelude-so/ruby-sdk/issues/63)) ([a8c4446](https://github.com/prelude-so/ruby-sdk/commit/a8c4446cc1efd8bccd6832596e6232cfab982d4b)) +* correctly geneate array and map schemas with models ([#54](https://github.com/prelude-so/ruby-sdk/issues/54)) ([4105566](https://github.com/prelude-so/ruby-sdk/commit/4105566fd6972fd705d2027d9226d4bf090eb77c)) +* correctly instantiate sorbet type aliases for enums and unions ([f68d267](https://github.com/prelude-so/ruby-sdk/commit/f68d267258e10e16c3878a5c578978901ec5ca7e)) +* correctly mark optional arrays and hashes as nullable ([#95](https://github.com/prelude-so/ruby-sdk/issues/95)) ([753ebb9](https://github.com/prelude-so/ruby-sdk/commit/753ebb9d1e92473b4587f5a39483fbcd4e44c3f4)) +* correctly mark some error values as optional ([#67](https://github.com/prelude-so/ruby-sdk/issues/67)) ([3426e92](https://github.com/prelude-so/ruby-sdk/commit/3426e920eb58325a6ba9e18a404ff7f85825c80a)) +* default content-type for text in multi-part formdata uploads should be text/plain ([c4122bf](https://github.com/prelude-so/ruby-sdk/commit/c4122bf55fbb4de6aa18cfaa8a997487fa1223bf)) +* encode objects in multipart encoding as JSON ([#97](https://github.com/prelude-so/ruby-sdk/issues/97)) ([38350ea](https://github.com/prelude-so/ruby-sdk/commit/38350ea72be2e4511b32320564382a65c7965001)) +* ensure gem release is unaffected by renaming ([d190dad](https://github.com/prelude-so/ruby-sdk/commit/d190dad48ea81deac8fce6f03d6bda8ee915814e)) +* enums should only coerce matching symbols into strings ([#161](https://github.com/prelude-so/ruby-sdk/issues/161)) ([e65e1c9](https://github.com/prelude-so/ruby-sdk/commit/e65e1c90e751981420b919c0ab51845d97e234c4)) +* error classes did not call `.to_s` on error uri ([#61](https://github.com/prelude-so/ruby-sdk/issues/61)) ([f9798ca](https://github.com/prelude-so/ruby-sdk/commit/f9798cadbb003dad9cd95b9d3b7491ed88e50b83)) +* inaccuracies in the README.md ([493bf9b](https://github.com/prelude-so/ruby-sdk/commit/493bf9bec45a5a6d69b042aa5c30659a423dce2f)) +* **internal:** ensure formatting always uses c.utf-8 locale ([2124205](https://github.com/prelude-so/ruby-sdk/commit/21242056a47780ff9c4292bf72a3f70fdf43a573)) +* **internal:** fix formatting script for macos ([7f52102](https://github.com/prelude-so/ruby-sdk/commit/7f52102f181ecbd698b9718c22f0043989ed0872)) +* **internal:** update gemspec name ([4dab0c8](https://github.com/prelude-so/ruby-sdk/commit/4dab0c822911b8a9cf92f4f50453974a1d327b60)) +* **internal:** update release-please to use ruby strategy for README.md ([#249](https://github.com/prelude-so/ruby-sdk/issues/249)) ([b5ef517](https://github.com/prelude-so/ruby-sdk/commit/b5ef5179f0e6dee4914c9c99ce04fa884b49e8ba)) +* issue where we cannot mutate arrays on base model derivatives ([9f3b95a](https://github.com/prelude-so/ruby-sdk/commit/9f3b95a0d90ac21d66358960a70f12416d8d4a26)) +* label optional keyword arguments in *.rbs type definitions ([#186](https://github.com/prelude-so/ruby-sdk/issues/186)) ([a8a351c](https://github.com/prelude-so/ruby-sdk/commit/a8a351c8769b30aed7f0d37f271230e88008d7ff)) +* make a typo for `FilePart.content` ([de88a13](https://github.com/prelude-so/ruby-sdk/commit/de88a13840d28db004bbcea68b7426b859774a03)) +* **model:** base model should recursively store coerced base models ([#178](https://github.com/prelude-so/ruby-sdk/issues/178)) ([b0c3785](https://github.com/prelude-so/ruby-sdk/commit/b0c3785ec865e19a9c9fc4e5c7270b7d2b0be2f6)) +* path interpolation template strings ([#211](https://github.com/prelude-so/ruby-sdk/issues/211)) ([c687281](https://github.com/prelude-so/ruby-sdk/commit/c6872810c5d603636ab9b14a5c912fcf8538446d)) +* pre-release version string should match ruby, not semver conventions ([#224](https://github.com/prelude-so/ruby-sdk/issues/224)) ([d847726](https://github.com/prelude-so/ruby-sdk/commit/d847726126befe8a184f9994a4c4d0acdf5cae23)) +* prevent rubocop from mangling `===` to `is_a?` check ([34836e6](https://github.com/prelude-so/ruby-sdk/commit/34836e6207f747f02785217dc83e23f6c75a25c8)) +* raise connection error for errors that result from HTTP transports ([#246](https://github.com/prelude-so/ruby-sdk/issues/246)) ([2c0914d](https://github.com/prelude-so/ruby-sdk/commit/2c0914de47ffbbf0cf18b48f2fbcd1d50b6d3c86)) +* rectify a mistake where wrong lines were chosen during rebase ([#156](https://github.com/prelude-so/ruby-sdk/issues/156)) ([fedcda4](https://github.com/prelude-so/ruby-sdk/commit/fedcda4c27e6614cb13cb76447220e6fa3ef3cff)) +* resolve tapioca derived sorbet errors ([#189](https://github.com/prelude-so/ruby-sdk/issues/189)) ([ddb842c](https://github.com/prelude-so/ruby-sdk/commit/ddb842ca54d18c95337542ffb344240f0267761d)) +* sorbet request method signatures should support default values ([#103](https://github.com/prelude-so/ruby-sdk/issues/103)) ([0146ba5](https://github.com/prelude-so/ruby-sdk/commit/0146ba5a66479f330b6de40401bb6dbc23af22d8)) +* sorbet types for enums, and make tapioca detection ignore `tapioca dsl` ([fda883a](https://github.com/prelude-so/ruby-sdk/commit/fda883af90eafc031881e61c1c1404f4567950e6)) +* ssl timeout not required when TCP socket open timeout specified ([#120](https://github.com/prelude-so/ruby-sdk/issues/120)) ([6b0e37b](https://github.com/prelude-so/ruby-sdk/commit/6b0e37b0a18ec258b287a8f49f6ca90dd76cba52)) +* switch to github compatible markdown engine ([#208](https://github.com/prelude-so/ruby-sdk/issues/208)) ([bc81111](https://github.com/prelude-so/ruby-sdk/commit/bc811118eaa4f26e485071cd47f94bfdf2360dcf)) +* temporarily run CI without bundler cache ([#106](https://github.com/prelude-so/ruby-sdk/issues/106)) ([e1e2cc2](https://github.com/prelude-so/ruby-sdk/commit/e1e2cc2afff0876f05905e19d96eb1e01077d8e7)) +* **type signature:** remove extraneous `params` from resource methods ([#96](https://github.com/prelude-so/ruby-sdk/issues/96)) ([4005265](https://github.com/prelude-so/ruby-sdk/commit/4005265f9ee7e6d09863d49d5dba6981e8faf41b)) +* update outdated examples ([#102](https://github.com/prelude-so/ruby-sdk/issues/102)) ([b433b8a](https://github.com/prelude-so/ruby-sdk/commit/b433b8a0333be88238340768ada7c780ac0ad0c7)) +* yard example tag formatting ([#192](https://github.com/prelude-so/ruby-sdk/issues/192)) ([2653958](https://github.com/prelude-so/ruby-sdk/commit/265395868b6260166fc8de6e2a56104a0ca00ef9)) + + +### Chores + +* `BaseModel` fields that are `BaseModel` typed should also accept `Hash` ([#191](https://github.com/prelude-so/ruby-sdk/issues/191)) ([25bba5d](https://github.com/prelude-so/ruby-sdk/commit/25bba5d9bce169a2c6f370f27579e6247fc7a5d5)) +* accept all nd-json mimetype variants ([a0666cb](https://github.com/prelude-so/ruby-sdk/commit/a0666cb0ca1dea0e179a06c081443c3d53ac4e83)) +* add `[@yieldparam](https://github.com/yieldparam)` to yard doc ([#182](https://github.com/prelude-so/ruby-sdk/issues/182)) ([c9f7a9a](https://github.com/prelude-so/ruby-sdk/commit/c9f7a9a26e0f088fc8d61ac25a1b84243ee7ab8b)) +* add `sorbet` section to README ([#153](https://github.com/prelude-so/ruby-sdk/issues/153)) ([e7f096c](https://github.com/prelude-so/ruby-sdk/commit/e7f096cb80519a1944edd086f313f30ad3a83892)) +* add example directory ([#185](https://github.com/prelude-so/ruby-sdk/issues/185)) ([8383b4f](https://github.com/prelude-so/ruby-sdk/commit/8383b4f93955360f7b27671c02fef9751c626e28)) +* add generator safe directory ([41e15a6](https://github.com/prelude-so/ruby-sdk/commit/41e15a682e948b7315fff3e7ec76b786154cc67a)) +* add more examples to README.md ([#154](https://github.com/prelude-so/ruby-sdk/issues/154)) ([2a34b0f](https://github.com/prelude-so/ruby-sdk/commit/2a34b0fd4fe1df6d7df451face56c0fe1ca9db81)) +* add more private yard doc annotations ([#52](https://github.com/prelude-so/ruby-sdk/issues/52)) ([89d2c14](https://github.com/prelude-so/ruby-sdk/commit/89d2c147f746e100ecc52475f4690e0734010ede)) +* add most doc strings to rbi type definitions ([#167](https://github.com/prelude-so/ruby-sdk/issues/167)) ([fa65710](https://github.com/prelude-so/ruby-sdk/commit/fa657101d0fe02a6e0409f5aada47a4447e98b21)) +* add README docs for using solargraph when installing gem from git ([#244](https://github.com/prelude-so/ruby-sdk/issues/244)) ([a1b7cd4](https://github.com/prelude-so/ruby-sdk/commit/a1b7cd49bc3b46d4ae862387bde7042be5f435f3)) +* add type annotations for enum and union member listing methods ([#193](https://github.com/prelude-so/ruby-sdk/issues/193)) ([41f7600](https://github.com/prelude-so/ruby-sdk/commit/41f76001a8bdfa5963d430fcc23e74f2e911e5bf)) +* add type annotations for requester ([#129](https://github.com/prelude-so/ruby-sdk/issues/129)) ([a3df0bb](https://github.com/prelude-so/ruby-sdk/commit/a3df0bb5440894a46d8c7285adcd6a92f2b1e897)) +* adjust method param class position in yard doc for convenience ([#68](https://github.com/prelude-so/ruby-sdk/issues/68)) ([8253543](https://github.com/prelude-so/ruby-sdk/commit/825354354ca42da449a15f0055bd8afe7d213024)) +* adjust whitespace in comments ([#64](https://github.com/prelude-so/ruby-sdk/issues/64)) ([f3d8496](https://github.com/prelude-so/ruby-sdk/commit/f3d84960c826c93a36a1ea18a0e543c62651cacc)) +* always fold up method bodies in sorbet type definitions ([#238](https://github.com/prelude-so/ruby-sdk/issues/238)) ([1001b2b](https://github.com/prelude-so/ruby-sdk/commit/1001b2bf841569bfa5729fc0e18bd5cb2de738d9)) +* be consistent and use lower case headers everywhere ([#142](https://github.com/prelude-so/ruby-sdk/issues/142)) ([791edfa](https://github.com/prelude-so/ruby-sdk/commit/791edfa611395f61a5dc385913a4c06e61b4c6a7)) +* broadly detect json family of content-type headers ([6b605ee](https://github.com/prelude-so/ruby-sdk/commit/6b605eeb41ee645b2bd95b57cb5a139d93c9e89f)) +* bump lockfile ([#123](https://github.com/prelude-so/ruby-sdk/issues/123)) ([db0e1ac](https://github.com/prelude-so/ruby-sdk/commit/db0e1ac0768711ef779b43b4a077a0af480036da)) +* bump lockfile ([#145](https://github.com/prelude-so/ruby-sdk/issues/145)) ([e97bb56](https://github.com/prelude-so/ruby-sdk/commit/e97bb568ed58198a6693c22e59894fa5d21e4f43)) +* **ci:** add timeout thresholds for CI jobs ([e3382e8](https://github.com/prelude-so/ruby-sdk/commit/e3382e82f669532f26e5ffbc82449fa1108f5b3f)) +* **ci:** enable for pull requests ([d24a637](https://github.com/prelude-so/ruby-sdk/commit/d24a6370acbf5c34edc4f07bb96e47dec864f42d)) +* **ci:** link to correct github repo ([9de03d9](https://github.com/prelude-so/ruby-sdk/commit/9de03d9ba18d2a293cc47a9c0cc936601b469b7c)) +* **ci:** only run for pushes and fork pull requests ([7ca7f77](https://github.com/prelude-so/ruby-sdk/commit/7ca7f77a9364bd1deb56014ef4e66e543e908523)) +* **ci:** only use depot for staging repos ([e89de9b](https://github.com/prelude-so/ruby-sdk/commit/e89de9be3723256df40afcf70e6e461dee1c2f10)) +* **ci:** run on more branches and use depot runners ([0030c93](https://github.com/prelude-so/ruby-sdk/commit/0030c932c677c42cc94220cb956bb882db9fe819)) +* clamp timeout to range of positive floats ([#99](https://github.com/prelude-so/ruby-sdk/issues/99)) ([82157fb](https://github.com/prelude-so/ruby-sdk/commit/82157fbb877c425e0ca649140c172984e8e0b9c9)) +* clean up client tests ([#121](https://github.com/prelude-so/ruby-sdk/issues/121)) ([8d3e8b1](https://github.com/prelude-so/ruby-sdk/commit/8d3e8b17f385babf00fb747d3480f7670eb9cbf2)) +* consistently use string in examples, even for enums ([0bd30ee](https://github.com/prelude-so/ruby-sdk/commit/0bd30ee3b987e68661ae70eb0c81980a1110019b)) +* demonstrate how to make undocumented requests in README ([#223](https://github.com/prelude-so/ruby-sdk/issues/223)) ([ab1f60c](https://github.com/prelude-so/ruby-sdk/commit/ab1f60cc1c3b082e028cc08f070585c61fca09d2)) +* disable dangerous rubocop auto correct rule ([#199](https://github.com/prelude-so/ruby-sdk/issues/199)) ([2db2fc3](https://github.com/prelude-so/ruby-sdk/commit/2db2fc30aef614c171d9df970697e1e698da770e)) +* disable overloads in `*.rbs` definitions for readable LSP errors ([#187](https://github.com/prelude-so/ruby-sdk/issues/187)) ([499d257](https://github.com/prelude-so/ruby-sdk/commit/499d257af3f77194b57926eac6779ab3373ad7fd)) +* disable unnecessary linter rules for sorbet manifests ([#181](https://github.com/prelude-so/ruby-sdk/issues/181)) ([b46403a](https://github.com/prelude-so/ruby-sdk/commit/b46403af74660473c9c6ff4d8741275d3e9a5d00)) +* do not git ignore `bin/` ([#107](https://github.com/prelude-so/ruby-sdk/issues/107)) ([aff7a1c](https://github.com/prelude-so/ruby-sdk/commit/aff7a1c018f0f9190786ccad45bea38c00217b05)) +* do not label modules as abstract ([#176](https://github.com/prelude-so/ruby-sdk/issues/176)) ([d62b943](https://github.com/prelude-so/ruby-sdk/commit/d62b94375820be6e608bfc7707de2d1beeeb811e)) +* do not use literals for version in type definitions ([#226](https://github.com/prelude-so/ruby-sdk/issues/226)) ([0d1c0cd](https://github.com/prelude-so/ruby-sdk/commit/0d1c0cd66b51e964a7a82545e7feb8cbadb99567)) +* **docs:** grammar improvements ([1f25e66](https://github.com/prelude-so/ruby-sdk/commit/1f25e6604baf647a2f5f6c2468c3c464709fa117)) +* document Client's concurrency capability ([#180](https://github.com/prelude-so/ruby-sdk/issues/180)) ([a22ea6d](https://github.com/prelude-so/ruby-sdk/commit/a22ea6d67d5efc0d1618d83536a7dfbfa93ee4fd)) +* document LSP support in read me ([#230](https://github.com/prelude-so/ruby-sdk/issues/230)) ([e33ffad](https://github.com/prelude-so/ruby-sdk/commit/e33ffada8823ae5317a7648933ddf24b3809486e)) +* document union variants in yard doc ([#171](https://github.com/prelude-so/ruby-sdk/issues/171)) ([55ac7e7](https://github.com/prelude-so/ruby-sdk/commit/55ac7e796363a959f40936c1dd9944481d822baa)) +* documentation improvements ([f993f3c](https://github.com/prelude-so/ruby-sdk/commit/f993f3c394d1ad58288a38e287d872c15c85e587)) +* easier to read examples in README.md ([#241](https://github.com/prelude-so/ruby-sdk/issues/241)) ([9673070](https://github.com/prelude-so/ruby-sdk/commit/9673070bf340ed164858c30a48613705dd2f4f62)) +* ensure doc strings for rbi method arguments ([#168](https://github.com/prelude-so/ruby-sdk/issues/168)) ([7a08c8d](https://github.com/prelude-so/ruby-sdk/commit/7a08c8d3ad46401c7475ad2e852e6c48f5f3d8d6)) +* ensure readme.md is bumped when release please updates versions ([#248](https://github.com/prelude-so/ruby-sdk/issues/248)) ([62f0c82](https://github.com/prelude-so/ruby-sdk/commit/62f0c82138f719236d946e60bc5e94245024cbb8)) +* error fields are now mutable in keeping with rest of SDK ([#170](https://github.com/prelude-so/ruby-sdk/issues/170)) ([16a736b](https://github.com/prelude-so/ruby-sdk/commit/16a736b1ab49468bafd4606250cf8be93199c31d)) +* explicitly mark apis public under `Internal` module ([f549aac](https://github.com/prelude-so/ruby-sdk/commit/f549aaccff077e04c160f56e9f1048a99acfeb2c)) +* extract error classes into own module ([#219](https://github.com/prelude-so/ruby-sdk/issues/219)) ([5e21b4f](https://github.com/prelude-so/ruby-sdk/commit/5e21b4fa4f9d4469d6eae8092ca374cb6ec96604)) +* fix a yard doc comment ([#86](https://github.com/prelude-so/ruby-sdk/issues/86)) ([9288401](https://github.com/prelude-so/ruby-sdk/commit/9288401f3e9a173fda89a4daae362f2cfb97f99e)) +* fix lsp configuration file for local development ([f42b81e](https://github.com/prelude-so/ruby-sdk/commit/f42b81ea5bd1a248cec227458b7111fccbc9d3f0)) +* fix misc linting / minor issues ([7adf0f6](https://github.com/prelude-so/ruby-sdk/commit/7adf0f6570af69c38d621fa355401bbf4695ee6e)) +* fix misc rubocop errors ([#209](https://github.com/prelude-so/ruby-sdk/issues/209)) ([32743b9](https://github.com/prelude-so/ruby-sdk/commit/32743b99b6bc160fb016af751fb6951b07dda978)) +* force utf-8 locale via `RUBYOPT` when formatting ([aa93887](https://github.com/prelude-so/ruby-sdk/commit/aa93887b9edf8e7f47a3eb446f0e7a2736cfc7c9)) +* formatting change for `*.rbi` files ([#105](https://github.com/prelude-so/ruby-sdk/issues/105)) ([6ad8061](https://github.com/prelude-so/ruby-sdk/commit/6ad80614d3fbaa6d7d1b3537c9bf34f36ede8bea)) +* fully qualify `Array` and `Hash` in rbs files to avoid collisions ([#110](https://github.com/prelude-so/ruby-sdk/issues/110)) ([38ab4b5](https://github.com/prelude-so/ruby-sdk/commit/38ab4b5d743fc99aad85efc62ec3f1356cfdddf3)) +* fused enum should use faster internal iteration by default ([#158](https://github.com/prelude-so/ruby-sdk/issues/158)) ([192338d](https://github.com/prelude-so/ruby-sdk/commit/192338d331982fda6ee28bc9d2a8e067b7c1b21a)) +* generate better supported rbi signatures ([#150](https://github.com/prelude-so/ruby-sdk/issues/150)) ([41144d1](https://github.com/prelude-so/ruby-sdk/commit/41144d1014acf64d456aa0bb957f5e8920a57990)) +* ignore some spurious linter warnings and formatting changes ([#179](https://github.com/prelude-so/ruby-sdk/issues/179)) ([9e81ccf](https://github.com/prelude-so/ruby-sdk/commit/9e81ccf8b4b266a72a0ffc783596ed3c000b8b72)) +* improve documentation ([#159](https://github.com/prelude-so/ruby-sdk/issues/159)) ([d7b346d](https://github.com/prelude-so/ruby-sdk/commit/d7b346d09f515f934e89583a567e624f6f5066ff)) +* improve uri interpolation internals ([#73](https://github.com/prelude-so/ruby-sdk/issues/73)) ([2aa7a43](https://github.com/prelude-so/ruby-sdk/commit/2aa7a4328580b2c1e0dcbd62ded93c8892a1abef)) +* improve yard doc folding and reduce repetition ([#83](https://github.com/prelude-so/ruby-sdk/issues/83)) ([840a43a](https://github.com/prelude-so/ruby-sdk/commit/840a43a3d6ace7ea0f01c0d924d8113d78353f5b)) +* improve yard docs readability ([#213](https://github.com/prelude-so/ruby-sdk/issues/213)) ([b434e18](https://github.com/prelude-so/ruby-sdk/commit/b434e18f4d27560d4fcbb337288616e909c35dff)) +* **internal:** add sorbet config for SDK local development ([#184](https://github.com/prelude-so/ruby-sdk/issues/184)) ([03b1b56](https://github.com/prelude-so/ruby-sdk/commit/03b1b569a1d44b50ac2fe2c8b67b5cd9725cdae9)) +* **internal:** add utils methods for parsing SSE ([#143](https://github.com/prelude-so/ruby-sdk/issues/143)) ([67a6004](https://github.com/prelude-so/ruby-sdk/commit/67a600456f93d587d181bfd880c1a623bdffd534)) +* **internal:** always run post-processing when formatting when syntax_tree ([3ec78ae](https://github.com/prelude-so/ruby-sdk/commit/3ec78aee495d3226f8d4e5d2f26485fd360142c8)) +* **internal:** annotate request options with type aliases in sorbet ([a6635f1](https://github.com/prelude-so/ruby-sdk/commit/a6635f15668ecef2d3ff10d289ecfff32d696b13)) +* **internal:** codegen related update ([c5df60f](https://github.com/prelude-so/ruby-sdk/commit/c5df60f92c2bd977467e7b5451fdb53da0a339d8)) +* **internal:** codegen related update ([5978d73](https://github.com/prelude-so/ruby-sdk/commit/5978d73cd9df88d79d8ee5627c8fc112d970d23a)) +* **internal:** codegen related update ([0015460](https://github.com/prelude-so/ruby-sdk/commit/0015460e0df0d2cbc0c4aad4cdb5384aacd1d1e8)) +* **internal:** codegen related update ([#109](https://github.com/prelude-so/ruby-sdk/issues/109)) ([c1d18c0](https://github.com/prelude-so/ruby-sdk/commit/c1d18c0567eaed1f03b259d0767cb5791d4d3f34)) +* **internal:** codegen related update ([#111](https://github.com/prelude-so/ruby-sdk/issues/111)) ([18acd8a](https://github.com/prelude-so/ruby-sdk/commit/18acd8adae60d1c8738f5ec00cc3848b2bfc9612)) +* **internal:** codegen related update ([#112](https://github.com/prelude-so/ruby-sdk/issues/112)) ([ac62f9a](https://github.com/prelude-so/ruby-sdk/commit/ac62f9ae5ee2bc88f3cb5f5756fae16ca90e4aa8)) +* **internal:** codegen related update ([#113](https://github.com/prelude-so/ruby-sdk/issues/113)) ([1492625](https://github.com/prelude-so/ruby-sdk/commit/1492625a539ec4f2737af64a59e41af8e8c5ae28)) +* **internal:** codegen related update ([#115](https://github.com/prelude-so/ruby-sdk/issues/115)) ([11fa48a](https://github.com/prelude-so/ruby-sdk/commit/11fa48a1392219381cb16145e5f557eaffc44c4e)) +* **internal:** codegen related update ([#118](https://github.com/prelude-so/ruby-sdk/issues/118)) ([b823494](https://github.com/prelude-so/ruby-sdk/commit/b8234949d99a79ec126b335df9852bdf05eba0d2)) +* **internal:** codegen related update ([#137](https://github.com/prelude-so/ruby-sdk/issues/137)) ([aeb43d6](https://github.com/prelude-so/ruby-sdk/commit/aeb43d6402e67d4c005b590ad8e1bfa193b8c51d)) +* **internal:** codegen related update ([#138](https://github.com/prelude-so/ruby-sdk/issues/138)) ([63b9a6a](https://github.com/prelude-so/ruby-sdk/commit/63b9a6aac611bfb7471964df6c093f921ab7f9b8)) +* **internal:** codegen related update ([#215](https://github.com/prelude-so/ruby-sdk/issues/215)) ([18a2bf7](https://github.com/prelude-so/ruby-sdk/commit/18a2bf7d71362405627e95874f738249a7c3a44c)) +* **internal:** codegen related update ([#30](https://github.com/prelude-so/ruby-sdk/issues/30)) ([fce8e4e](https://github.com/prelude-so/ruby-sdk/commit/fce8e4ede9f1d5fd86acccc953f0cff7b9ba69bf)) +* **internal:** codegen related update ([#31](https://github.com/prelude-so/ruby-sdk/issues/31)) ([8b30e12](https://github.com/prelude-so/ruby-sdk/commit/8b30e120e0c90319e138570c53839a58795c6d53)) +* **internal:** codegen related update ([#32](https://github.com/prelude-so/ruby-sdk/issues/32)) ([08760bf](https://github.com/prelude-so/ruby-sdk/commit/08760bf824d3905c4d5bce789c826b70ccf76d6a)) +* **internal:** codegen related update ([#33](https://github.com/prelude-so/ruby-sdk/issues/33)) ([3e49b9e](https://github.com/prelude-so/ruby-sdk/commit/3e49b9ea7759648d280f23cd30fcd716d2bed265)) +* **internal:** codegen related update ([#34](https://github.com/prelude-so/ruby-sdk/issues/34)) ([e53b14d](https://github.com/prelude-so/ruby-sdk/commit/e53b14d3a3f3b4093767c0cf2a8ae9e681638837)) +* **internal:** codegen related update ([#35](https://github.com/prelude-so/ruby-sdk/issues/35)) ([c84e8fd](https://github.com/prelude-so/ruby-sdk/commit/c84e8fd5455a86fb670e392e6eafa62bc66b03a1)) +* **internal:** codegen related update ([#37](https://github.com/prelude-so/ruby-sdk/issues/37)) ([f5e2be1](https://github.com/prelude-so/ruby-sdk/commit/f5e2be1664deccd5162c0ed9ebbeb4bb91eaa71c)) +* **internal:** codegen related update ([#42](https://github.com/prelude-so/ruby-sdk/issues/42)) ([b0b9c79](https://github.com/prelude-so/ruby-sdk/commit/b0b9c790a23f3892ac74ec4ac957f88b6e4196df)) +* **internal:** codegen related update ([#43](https://github.com/prelude-so/ruby-sdk/issues/43)) ([4e0a150](https://github.com/prelude-so/ruby-sdk/commit/4e0a1508a73310f48696cc2ec318cb0c33e2d6be)) +* **internal:** codegen related update ([#44](https://github.com/prelude-so/ruby-sdk/issues/44)) ([aa4d832](https://github.com/prelude-so/ruby-sdk/commit/aa4d832530a903a0239b0cf1fa0e9d8facce70fe)) +* **internal:** codegen related update ([#47](https://github.com/prelude-so/ruby-sdk/issues/47)) ([74b1dfe](https://github.com/prelude-so/ruby-sdk/commit/74b1dfe7db2b38fdd82072f1d48d902e7d42f53f)) +* **internal:** codegen related update ([#56](https://github.com/prelude-so/ruby-sdk/issues/56)) ([0ebafe6](https://github.com/prelude-so/ruby-sdk/commit/0ebafe63182c0ff32f2ea727fdf26927a72098b0)) +* **internal:** codegen related update ([#59](https://github.com/prelude-so/ruby-sdk/issues/59)) ([5629580](https://github.com/prelude-so/ruby-sdk/commit/56295805567534074cb44cfa2f053056d464c375)) +* **internal:** codegen related update ([#62](https://github.com/prelude-so/ruby-sdk/issues/62)) ([df7042a](https://github.com/prelude-so/ruby-sdk/commit/df7042a6a7649d5d19c5e4c32ceed13c1efb9ddd)) +* **internal:** codegen related update ([#69](https://github.com/prelude-so/ruby-sdk/issues/69)) ([3212dd9](https://github.com/prelude-so/ruby-sdk/commit/3212dd9756c673853b2223fec3787d6af89837a1)) +* **internal:** codegen related update ([#87](https://github.com/prelude-so/ruby-sdk/issues/87)) ([0dce20b](https://github.com/prelude-so/ruby-sdk/commit/0dce20b573cd779318ef5112eb7f994bb0393046)) +* **internal:** codegen related update ([#93](https://github.com/prelude-so/ruby-sdk/issues/93)) ([310d0a8](https://github.com/prelude-so/ruby-sdk/commit/310d0a87ce0638be7e8ba6f32024f95377a952ba)) +* **internal:** contribute.md and contributor QoL improvements ([d7f3a0d](https://github.com/prelude-so/ruby-sdk/commit/d7f3a0df33e7a5c5ed596a2d78ce4ba899d99d58)) +* **internal:** expand CI branch coverage ([#250](https://github.com/prelude-so/ruby-sdk/issues/250)) ([263020d](https://github.com/prelude-so/ruby-sdk/commit/263020d0297a2856ce165f1188939507bbb34bb1)) +* **internal:** formatting ([#122](https://github.com/prelude-so/ruby-sdk/issues/122)) ([34a9c09](https://github.com/prelude-so/ruby-sdk/commit/34a9c0948a5fafa65969f6501432f25de28a7831)) +* **internal:** group related utils together ([#136](https://github.com/prelude-so/ruby-sdk/issues/136)) ([f5b2158](https://github.com/prelude-so/ruby-sdk/commit/f5b2158270550d6d986818d15f4aa854ae317ebd)) +* **internal:** improve response envelope unwrap functionality ([0312399](https://github.com/prelude-so/ruby-sdk/commit/031239990cf3b3c16b2837e1761f3d754f08cf09)) +* **internal:** improve sdk internal docs / types ([#66](https://github.com/prelude-so/ruby-sdk/issues/66)) ([82c6527](https://github.com/prelude-so/ruby-sdk/commit/82c65271be6efd77e48a8d7c6db2182c83317a17)) +* **internal:** loosen internal type restrictions ([aae6132](https://github.com/prelude-so/ruby-sdk/commit/aae613236b3fda2e9f9d8a9f181cd415dd920bfd)) +* **internal:** minor refactoring of utils ([#202](https://github.com/prelude-so/ruby-sdk/issues/202)) ([6ac6f5d](https://github.com/prelude-so/ruby-sdk/commit/6ac6f5d800dc146bc5b5399afb4eb5f03b8f3290)) +* **internal:** minor touch ups on sdk internals ([47370b7](https://github.com/prelude-so/ruby-sdk/commit/47370b7621a6b282925d25e85ad71c70a3162bd6)) +* **internal:** minor type annotation improvements ([34ef6c9](https://github.com/prelude-so/ruby-sdk/commit/34ef6c94b3d09b78f7eec7736c98e937b2d0f046)) +* **internal:** misc small improvements ([#235](https://github.com/prelude-so/ruby-sdk/issues/235)) ([f5419b8](https://github.com/prelude-so/ruby-sdk/commit/f5419b80e6f905a2a4f6670811916c2a068a274e)) +* **internal:** more concise handling of parameter naming conflicts ([#240](https://github.com/prelude-so/ruby-sdk/issues/240)) ([f481e73](https://github.com/prelude-so/ruby-sdk/commit/f481e73e3169e8bfe7061d64f5dccdf4e85969f8)) +* **internal:** mostly README touch ups ([e9cdcfd](https://github.com/prelude-so/ruby-sdk/commit/e9cdcfdf1da34a893f7e7eace5190519ce995ba0)) +* **internal:** protect SSE parsing pipeline from broken UTF-8 characters ([ab3d5aa](https://github.com/prelude-so/ruby-sdk/commit/ab3d5aa844e16e84b88cccac57781720569f65df)) +* **internal:** prune unused `extern` references ([#132](https://github.com/prelude-so/ruby-sdk/issues/132)) ([c4203ea](https://github.com/prelude-so/ruby-sdk/commit/c4203eac8495b829ae67ec7c83913688bfa284ef)) +* **internal:** reduce CI branch coverage ([6bec303](https://github.com/prelude-so/ruby-sdk/commit/6bec30350ed807116ea4ff5d0af0a2625b75d48f)) +* **internal:** refactor request stack ([#127](https://github.com/prelude-so/ruby-sdk/issues/127)) ([2b9660d](https://github.com/prelude-so/ruby-sdk/commit/2b9660d4975818fda19ca0c3b855231e860c6c1d)) +* **internal:** remove extra empty newlines ([#164](https://github.com/prelude-so/ruby-sdk/issues/164)) ([fa2e580](https://github.com/prelude-so/ruby-sdk/commit/fa2e580abdb2bee3eb1023e414ca5368729ab04a)) +* **internal:** remove unnecessary `rbi/lib` folder ([49f6f51](https://github.com/prelude-so/ruby-sdk/commit/49f6f519672d248d98022a088315592b9fce17dd)) +* **internal:** rubocop rules ([#237](https://github.com/prelude-so/ruby-sdk/issues/237)) ([8881008](https://github.com/prelude-so/ruby-sdk/commit/8881008d2d5817b93742b727d3b34b9f083f0e10)) +* **internal:** run rubocop linter in parallel ([#236](https://github.com/prelude-so/ruby-sdk/issues/236)) ([64f5897](https://github.com/prelude-so/ruby-sdk/commit/64f5897a79e696820cd13fc47bbca8bd6cd49474)) +* loosen const and integer coercion rules ([#247](https://github.com/prelude-so/ruby-sdk/issues/247)) ([b19ac54](https://github.com/prelude-so/ruby-sdk/commit/b19ac54096d169cdcb2d62e3b79f95a57fbe1c57)) +* loosen rubocop rules that don't always make sense ([33609a8](https://github.com/prelude-so/ruby-sdk/commit/33609a864d02e409fe25bcd84b2a621ea72e0256)) +* make client tests look prettier ([#243](https://github.com/prelude-so/ruby-sdk/issues/243)) ([691a94d](https://github.com/prelude-so/ruby-sdk/commit/691a94de176b9089bd765671e6b61e983d5b6102)) +* make internal types pretty print ([42c2540](https://github.com/prelude-so/ruby-sdk/commit/42c2540bda20c185f078793e4db90659d2dd15c3)) +* make MFA optional depending on token ([#125](https://github.com/prelude-so/ruby-sdk/issues/125)) ([7425b56](https://github.com/prelude-so/ruby-sdk/commit/7425b566a2eb4dc949b5b5f45d1ac8443c36d5b5)) +* make sorbet enums easier to read ([7f29b87](https://github.com/prelude-so/ruby-sdk/commit/7f29b87ea0204a19556247014297ef88b52dcd74)) +* mark non-inheritable SDK internal classes as final ([#173](https://github.com/prelude-so/ruby-sdk/issues/173)) ([3c22dcb](https://github.com/prelude-so/ruby-sdk/commit/3c22dcbf7620fd1ddb7ba24e51b16ceda22a1c1e)) +* migrate away from deprecated `JSON#fast_generate` ([b84e8f7](https://github.com/prelude-so/ruby-sdk/commit/b84e8f7e506b6de892864ce0b99fd7cd88f4515b)) +* migrate to pattern matching for testing ([#53](https://github.com/prelude-so/ruby-sdk/issues/53)) ([c99c3d2](https://github.com/prelude-so/ruby-sdk/commit/c99c3d29e76b3dc2a8d8a3fd23be43cb4b8dde14)) +* minor scripting improvements ([#65](https://github.com/prelude-so/ruby-sdk/issues/65)) ([9103c80](https://github.com/prelude-so/ruby-sdk/commit/9103c80aebe8118adadac8fb8519a4b2e99375e9)) +* misc sdk polish ([#229](https://github.com/prelude-so/ruby-sdk/issues/229)) ([a555344](https://github.com/prelude-so/ruby-sdk/commit/a555344a5d6cba204d242490b33665b3223fd1b1)) +* modify sorbet initializers to better support auto-completion ([#151](https://github.com/prelude-so/ruby-sdk/issues/151)) ([5ad4c86](https://github.com/prelude-so/ruby-sdk/commit/5ad4c86b4c49d598a66a368482d75256df567250)) +* more accurate type annotations and aliases ([4cf4518](https://github.com/prelude-so/ruby-sdk/commit/4cf4518d19773bdaaee5c08c4bd6277ffd9c1a3a)) +* more accurate type annotations for SDK internals ([#206](https://github.com/prelude-so/ruby-sdk/issues/206)) ([02f2bc6](https://github.com/prelude-so/ruby-sdk/commit/02f2bc68b4b62eff5ad2f1b379fffbb5a8ade7c1)) +* more aggressive tapioca detection logic for skipping compiler introspection ([#201](https://github.com/prelude-so/ruby-sdk/issues/201)) ([ff41ec4](https://github.com/prelude-so/ruby-sdk/commit/ff41ec41d0d3f9f2dc325f0aaab4eb1c34711867)) +* more detailed yard docs for base client ([#81](https://github.com/prelude-so/ruby-sdk/issues/81)) ([5ef8779](https://github.com/prelude-so/ruby-sdk/commit/5ef8779589c1715e818cc3a7c5879c751efbda2c)) +* more detailed yard docs for sdk utils ([#80](https://github.com/prelude-so/ruby-sdk/issues/80)) ([4439453](https://github.com/prelude-so/ruby-sdk/commit/44394536e395080d9359f69f06e99e931c35bf11)) +* more readable output when tests fail ([#200](https://github.com/prelude-so/ruby-sdk/issues/200)) ([f6306ad](https://github.com/prelude-so/ruby-sdk/commit/f6306ad4491f0b5a49c2cedb3dd7c90a93201bb7)) +* move basemodel examples into tests ([#126](https://github.com/prelude-so/ruby-sdk/issues/126)) ([5c3cac2](https://github.com/prelude-so/ruby-sdk/commit/5c3cac257ebf88934cc21001bbd735d2d9458660)) +* move examples into tests ([#147](https://github.com/prelude-so/ruby-sdk/issues/147)) ([3b51ecb](https://github.com/prelude-so/ruby-sdk/commit/3b51ecb0a32a163c4d782b2c08cb43ffc664793e)) +* move private classes into internal module ([#220](https://github.com/prelude-so/ruby-sdk/issues/220)) ([62e8a50](https://github.com/prelude-so/ruby-sdk/commit/62e8a5076a895d18584089b3e1d68f4e5d74278b)) +* order client variables by "importance" ([#217](https://github.com/prelude-so/ruby-sdk/issues/217)) ([33bad53](https://github.com/prelude-so/ruby-sdk/commit/33bad5375e1ca36cbdcdb342c33e01d3de7db4ac)) +* re-export top level models under library namespace ([cf4db80](https://github.com/prelude-so/ruby-sdk/commit/cf4db800d5ea6c242db032b4bc22087e7bb57f84)) +* re-order init params in accordance with their optionality ([#78](https://github.com/prelude-so/ruby-sdk/issues/78)) ([a3a23e1](https://github.com/prelude-so/ruby-sdk/commit/a3a23e18cd1a228d28cf38417c80a82c423463a7)) +* re-order resource classes constructor position ([#76](https://github.com/prelude-so/ruby-sdk/issues/76)) ([cf21aa1](https://github.com/prelude-so/ruby-sdk/commit/cf21aa1b83d5f16d9537467712ba1173fa2e6800)) +* recursively accept `AnyHash` for `BaseModel`s in arrays and hashes ([#196](https://github.com/prelude-so/ruby-sdk/issues/196)) ([2762ade](https://github.com/prelude-so/ruby-sdk/commit/2762ade46e1768da008db0a58c0e4c0c62f55cb1)) +* reduce verbosity in type declarations ([#198](https://github.com/prelude-so/ruby-sdk/issues/198)) ([61216ed](https://github.com/prelude-so/ruby-sdk/commit/61216ed91486796d422743677a2565f5b9443c83)) +* refactor BasePage to have initializer ([#163](https://github.com/prelude-so/ruby-sdk/issues/163)) ([5145d3d](https://github.com/prelude-so/ruby-sdk/commit/5145d3d468faf659449ecdc1fda20602c6f53e84)) +* refactor util method signatures ([#88](https://github.com/prelude-so/ruby-sdk/issues/88)) ([4697d4b](https://github.com/prelude-so/ruby-sdk/commit/4697d4b94541768b33bc50454b03660e803bb162)) +* **refactor:** improve requester internals ([#135](https://github.com/prelude-so/ruby-sdk/issues/135)) ([432fffa](https://github.com/prelude-so/ruby-sdk/commit/432fffa31a91c8bf713518a4187c5be5279953f9)) +* refine `#inspect` and `#to_s` for model classes ([34e8bfe](https://github.com/prelude-so/ruby-sdk/commit/34e8bfee65c9e0c47127111d54c060440d231d6f)) +* refine Yard and Sorbet types and ensure linting is turned on for examples ([9aa5442](https://github.com/prelude-so/ruby-sdk/commit/9aa54420ca4a668ebc2e90e120b02e928494f751)) +* relax sorbet enum parameters to allow `String` in addition to `Symbol` ([#216](https://github.com/prelude-so/ruby-sdk/issues/216)) ([7ca2c57](https://github.com/prelude-so/ruby-sdk/commit/7ca2c57836b1f4ffbd61bdc456d8bea78c2675b9)) +* relocate internal modules ([#205](https://github.com/prelude-so/ruby-sdk/issues/205)) ([a57c98e](https://github.com/prelude-so/ruby-sdk/commit/a57c98e4113764591e57136aa83bf85ff4d78f16)) +* remove Gemfile.lock during bootstrap ([19d742e](https://github.com/prelude-so/ruby-sdk/commit/19d742ee4a8d9b7540f25572b8cfc7210d9108ea)) +* remove stale thread local checks ([#162](https://github.com/prelude-so/ruby-sdk/issues/162)) ([54d919b](https://github.com/prelude-so/ruby-sdk/commit/54d919bb54190e54886feaf0495416db77bda139)) +* remove unnecessary & confusing module ([#204](https://github.com/prelude-so/ruby-sdk/issues/204)) ([cc6d85c](https://github.com/prelude-so/ruby-sdk/commit/cc6d85cbbc18a46e559c337eeb22f7b828b008d6)) +* rename confusing `Type::BooleanModel` to `Type::Boolean` ([#233](https://github.com/prelude-so/ruby-sdk/issues/233)) ([aa94197](https://github.com/prelude-so/ruby-sdk/commit/aa94197ff414931bb9de157801bd2ed321002387)) +* rename internal type aliases ([#124](https://github.com/prelude-so/ruby-sdk/issues/124)) ([b979ac0](https://github.com/prelude-so/ruby-sdk/commit/b979ac08f3d68b4b4756c612a9ea04cd0b960e63)) +* rename misleading variable ([#146](https://github.com/prelude-so/ruby-sdk/issues/146)) ([a5bb0a4](https://github.com/prelude-so/ruby-sdk/commit/a5bb0a4b07503f0cb03e20d936a909f36c16618f)) +* reorganize import ordering ([#130](https://github.com/prelude-so/ruby-sdk/issues/130)) ([ffcbfd8](https://github.com/prelude-so/ruby-sdk/commit/ffcbfd85ab9778e51b5dc0bd26daed02c55beb1a)) +* revert ignoring Gemfile.lock ([c36f55d](https://github.com/prelude-so/ruby-sdk/commit/c36f55db6de1bad1af573aec484742dc75d78dbf)) +* sdk client internal refactoring ([#175](https://github.com/prelude-so/ruby-sdk/issues/175)) ([3804b7d](https://github.com/prelude-so/ruby-sdk/commit/3804b7de00b87709bcbd494fff6587da6013209b)) +* sdk internal updates ([#165](https://github.com/prelude-so/ruby-sdk/issues/165)) ([413730d](https://github.com/prelude-so/ruby-sdk/commit/413730d968d1f7a2749efe5f9a8fa1c0caade95b)) +* show truncated parameter docs in yard ([26bbc66](https://github.com/prelude-so/ruby-sdk/commit/26bbc66bd3a0d263cdc2580b3447fa996ef1db7f)) +* simplify internal utils ([#228](https://github.com/prelude-so/ruby-sdk/issues/228)) ([cda302f](https://github.com/prelude-so/ruby-sdk/commit/cda302f9cd5f4be45019f84b5f90691dc0a1f3e0)) +* simplify yard annotations by removing most `@!parse` directives ([12477d1](https://github.com/prelude-so/ruby-sdk/commit/12477d1a597566a793cb04c7564ac10cae8155bf)) +* slightly more consistent type definition layout ([#172](https://github.com/prelude-so/ruby-sdk/issues/172)) ([0795e9b](https://github.com/prelude-so/ruby-sdk/commit/0795e9bf55564372d2efd7ed2023a611d54c3469)) +* sort imports via topological dependency & file path ([#131](https://github.com/prelude-so/ruby-sdk/issues/131)) ([a12f4c0](https://github.com/prelude-so/ruby-sdk/commit/a12f4c0e97452cdd4b230a42e1b9a94af89e75c2)) +* support (deprecated) ruby 3.0 as well ([#101](https://github.com/prelude-so/ruby-sdk/issues/101)) ([37adf1a](https://github.com/prelude-so/ruby-sdk/commit/37adf1af4bb9436d7e74828e2c26b83d05e5d345)) +* support different EOLs in streaming ([#149](https://github.com/prelude-so/ruby-sdk/issues/149)) ([dd6835b](https://github.com/prelude-so/ruby-sdk/commit/dd6835bcfc967a09b037800efb38194548dcc692)) +* switch to prettier looking sorbet annotations ([#197](https://github.com/prelude-so/ruby-sdk/issues/197)) ([ad156f8](https://github.com/prelude-so/ruby-sdk/commit/ad156f89d15d433ae629bb282a5699f7260d58cc)) +* touch up sdk usage examples ([#169](https://github.com/prelude-so/ruby-sdk/issues/169)) ([42ed0c6](https://github.com/prelude-so/ruby-sdk/commit/42ed0c69573e13ad7e3b9c5e96ad303eab46bcab)) +* touch up yard docs with more spec compliant syntax ([#77](https://github.com/prelude-so/ruby-sdk/issues/77)) ([0adca41](https://github.com/prelude-so/ruby-sdk/commit/0adca410a206b6f7e2f75df11d906bd62d56810b)) +* update custom timeout header name ([#144](https://github.com/prelude-so/ruby-sdk/issues/144)) ([4aa21de](https://github.com/prelude-so/ruby-sdk/commit/4aa21dea94fde02d4ec07a52b9cc4c3a0d0fe5c6)) +* update readme ([#207](https://github.com/prelude-so/ruby-sdk/issues/207)) ([6c02f85](https://github.com/prelude-so/ruby-sdk/commit/6c02f85566ddfe62472ffa57fa74de689e3de1d3)) +* update README with recommended editor plugins ([d0c9cec](https://github.com/prelude-so/ruby-sdk/commit/d0c9ceccbc7279edfa576b30daaf6072d148c0e6)) +* update SDK settings ([#117](https://github.com/prelude-so/ruby-sdk/issues/117)) ([e1ae6d2](https://github.com/prelude-so/ruby-sdk/commit/e1ae6d2fc1e984d3ef021e26e77e7853362cef9a)) +* update yard comment formatting ([#239](https://github.com/prelude-so/ruby-sdk/issues/239)) ([a705e11](https://github.com/prelude-so/ruby-sdk/commit/a705e11e0b60a3447c1e6286a01b087bfed445e4)) +* use `@!method` instead of `@!parse` for virtual method type definitions ([62586fd](https://github.com/prelude-so/ruby-sdk/commit/62586fd9ab83a46f5b330d8d6350fc753b43f65a)) +* use concise syntax for pattern matching ([#114](https://github.com/prelude-so/ruby-sdk/issues/114)) ([4e6b56b](https://github.com/prelude-so/ruby-sdk/commit/4e6b56bc5f40cd995ecd093b2a2d778b99c5de00)) +* use fully qualified name in sorbet README example ([#210](https://github.com/prelude-so/ruby-sdk/issues/210)) ([44b3f17](https://github.com/prelude-so/ruby-sdk/commit/44b3f177a2f99e0c759dd523dbb42a48199ad8de)) +* use fully qualified names for yard annotations and rbs aliases ([ff0975f](https://github.com/prelude-so/ruby-sdk/commit/ff0975f5ca87cdd626c0cc4a887d7ae672a610ee)) +* use generics instead of overloading for sorbet type definitions ([#174](https://github.com/prelude-so/ruby-sdk/issues/174)) ([edf58e2](https://github.com/prelude-so/ruby-sdk/commit/edf58e24a7b79f54d30849ef6a75bde436d36b34)) +* use more descriptive rubocop output format ([#82](https://github.com/prelude-so/ruby-sdk/issues/82)) ([b8f15eb](https://github.com/prelude-so/ruby-sdk/commit/b8f15eb58db9e5c3f10598c82160e7bfa61c7f1d)) +* use multi-line formatting style for really long lines ([#183](https://github.com/prelude-so/ruby-sdk/issues/183)) ([52dbd0a](https://github.com/prelude-so/ruby-sdk/commit/52dbd0a3a2cf899e4227c3b74038115a36988852)) +* use package name for gemspec ([#227](https://github.com/prelude-so/ruby-sdk/issues/227)) ([d3b26a2](https://github.com/prelude-so/ruby-sdk/commit/d3b26a2ba36b344120f8a9113ccb2f189c7a0428)) +* validate request option coercion correctness ([e1deedb](https://github.com/prelude-so/ruby-sdk/commit/e1deedb5a5e792c8bf87f02d547a28db17d44587)) +* whitespaces ([fa9d708](https://github.com/prelude-so/ruby-sdk/commit/fa9d708403c183051e5857241b2625008050833e)) + + +### Documentation + +* illustrate environmental defaults for auth variables ([103ac7f](https://github.com/prelude-so/ruby-sdk/commit/103ac7fe70a73edd6a305c56860744500811cdc5)) +* **readme:** fix typo ([3e0bfd6](https://github.com/prelude-so/ruby-sdk/commit/3e0bfd69f65e5eaaf84d3b9510592fcc7d19273d)) +* rewrite much of README.md for readability ([d95cef0](https://github.com/prelude-so/ruby-sdk/commit/d95cef0d1ac416f794800d5f82ea856b0ada113e)) +* update documentation links to be more uniform ([c5d3237](https://github.com/prelude-so/ruby-sdk/commit/c5d3237449ba990137d462907edf9f5bfda28c97)) +* update URLs from stainlessapi.com to stainless.com ([#139](https://github.com/prelude-so/ruby-sdk/issues/139)) ([fa2156d](https://github.com/prelude-so/ruby-sdk/commit/fa2156d3269f2558ea39c3cc7b768d87fa42ede8)) + + +### Refactors + +* **client:** impose consistent sdk internals layout ([#90](https://github.com/prelude-so/ruby-sdk/issues/90)) ([31d6386](https://github.com/prelude-so/ruby-sdk/commit/31d6386c820042710ff84a248589680ad5b0bdf4)) + ## 0.1.0-alpha.1 (2024-11-13) Full Changelog: [v0.0.1-alpha.0...v0.1.0-alpha.1](https://github.com/prelude-so/ruby-sdk/compare/v0.0.1-alpha.0...v0.1.0-alpha.1) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..729675e4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,125 @@ +## Setting up the environment + +This repository contains a `.ruby-version` file, which should work with either [rbenv](https://github.com/rbenv/rbenv) or [asdf](https://github.com/asdf-vm/asdf) with the [ruby plugin](https://github.com/asdf-vm/asdf-ruby). + +Please follow the instructions for your preferred version manager to install the Ruby version specified in the `.ruby-version` file. + +To set up the repository, run: + +```bash +$ ./scripts/bootstrap +``` + +This will install all the required dependencies. + +## Modifying/Adding code + +Most of the SDK is generated code. Modifications to code will be persisted between generations, but may result in merge conflicts between manual patches and changes from the generator. The generator will never modify the contents of `lib/prelude_sdk/helpers/` and `examples/` directory. + +## Adding and running examples + +All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. + +```ruby +#!/usr/bin/env ruby +# frozen_string_literal: true + +require_relative "../lib/prelude_sdk" + +# ... +``` + +```bash +$ chmod +x './examples/.rb' + +# run the example against your api +$ ruby './examples/.rb' +``` + +## Using the repository from source + +If you’d like to use the repository from source, you can either install from git or reference a cloned repository: + +To install via git in your `Gemfile`: + +```ruby +gem "prelude-sdk", git: "https://www.github.com/prelude-so/ruby-sdk" +``` + +Alternatively, reference local copy of the repo: + +```bash +$ git clone -- 'https://www.github.com/prelude-so/ruby-sdk' '' +``` + +```ruby +gem "prelude-sdk", path: "" +``` + +## Running commands + +Running `rake` by itself will show all runnable commands. + +```bash +$ bundle exec rake +``` + +## Running tests + +Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. + +```bash +$ npx prism mock path/to/your/openapi.yml +``` + +```bash +$ bundle exec rake test +``` + +## Linting and formatting + +This repository uses [rubocop](https://github.com/rubocop/rubocop) for linting and formatting of `*.rb` and `*.rbi` files. [syntax_tree](https://github.com/ruby-syntax-tree/syntax_tree) is used for formatting `*.rbs` files. + +There are two separate type checkers supported by this library: [sorbet](https://github.com/sorbet/sorbet) and [steep](https://github.com/soutaro/steep) are used for verifying `*.rbi` and `*.rbs` files respectively. + +To lint and typecheck: + +```bash +$ bundle exec rake lint +``` + +To format and fix all lint issues automatically: + +```bash +$ bundle exec rake format +``` + +## Editor Support + +### Ruby LSP + +[Ruby LSP](https://github.com/Shopify/ruby-lsp) has quite good support for go to definition, but not auto-completion. + +This can be installed along side Solargraph. + +### Solargraph + +[Solargraph](https://solargraph.org) has quite good support for auto-completion, but not go to definition. + +This can be installed along side Ruby LSP. + +### Sorbet + +[Sorbet](https://sorbet.org) should mostly work out of the box when editing this library directly. However, there are a some caveats due to the colocation of `*.rb` and `*.rbi` files in the same project. These issues should not otherwise manifest when this library is used as a dependency. + +1. For go to definition usages, sorbet might get confused and may not always navigate to the correct location. + +2. For each generic type in `*.rbi` files, a spurious "Duplicate type member" error is present. + +## Documentation Preview + +To preview the documentation, run: + +```bash +$ bundle exec rake docs:preview [PORT=8808] +``` diff --git a/Gemfile b/Gemfile index 4d98cfca..0d76364b 100644 --- a/Gemfile +++ b/Gemfile @@ -5,9 +5,29 @@ source "https://rubygems.org" gemspec group :development do - gem "minitest" gem "rake" + gem "rbs" gem "rubocop" + gem "sorbet" + gem "steep" + gem "syntax_tree" + # TODO: using a fork for now, the prettier below has a bug + gem "syntax_tree-rbs", github: "stainless-api/syntax_tree-rbs", branch: "main" + gem "tapioca" +end + +group :development, :test do + gem "async" + gem "minitest" + gem "minitest-focus" + gem "minitest-hooks" + gem "minitest-proveit" + gem "minitest-rg" + gem "webmock" +end + +group :development, :docs do + gem "redcarpet" gem "webrick" gem "yard" end diff --git a/Gemfile.lock b/Gemfile.lock index e4bafcc9..991940be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,52 +1,212 @@ +GIT + remote: https://github.com/stainless-api/syntax_tree-rbs.git + revision: c30b50219918be7cfe3ef803a00b59d1e77fcada + branch: main + specs: + syntax_tree-rbs (1.0.0) + prettier_print + rbs + syntax_tree (>= 2.0.1) + PATH remote: . specs: - prelude (0.1.0.pre.alpha.1) + prelude-sdk (0.1.0.pre.alpha.1) connection_pool GEM remote: https://rubygems.org/ specs: - ast (2.4.2) - connection_pool (2.4.1) - json (2.7.2) - language_server-protocol (3.17.0.3) - minitest (5.25.1) - parallel (1.26.3) - parser (3.3.5.0) + activesupport (8.0.2) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + ast (2.4.3) + async (2.24.0) + console (~> 1.29) + fiber-annotation + io-event (~> 1.9) + metrics (~> 0.12) + traces (~> 0.15) + base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.9) + concurrent-ruby (1.3.5) + connection_pool (2.5.3) + console (1.30.2) + fiber-annotation + fiber-local (~> 1.1) + json + crack (1.0.0) + bigdecimal + rexml + csv (3.3.4) + drb (2.2.1) + erubi (1.13.1) + ffi (1.17.2-x86_64-linux-gnu) + fiber-annotation (0.2.0) + fiber-local (1.1.0) + fiber-storage + fiber-storage (1.0.1) + fileutils (1.7.3) + hashdiff (1.1.2) + i18n (1.14.7) + concurrent-ruby (~> 1.0) + io-event (1.10.0) + json (2.11.3) + language_server-protocol (3.17.0.4) + lint_roller (1.1.0) + listen (3.9.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logger (1.7.0) + metrics (0.12.2) + minitest (5.25.5) + minitest-focus (1.4.0) + minitest (>= 4, < 6) + minitest-hooks (1.5.2) + minitest (> 5.3) + minitest-proveit (1.0.0) + minitest (> 5, < 7) + minitest-rg (5.3.0) + minitest (~> 5.0) + mutex_m (0.3.0) + netrc (0.11.0) + parallel (1.27.0) + parser (3.3.8.0) ast (~> 2.4.1) racc + prettier_print (1.2.1) + prism (1.4.0) + public_suffix (6.0.2) racc (1.8.1) rainbow (3.1.1) - rake (13.1.0) - regexp_parser (2.9.2) - rubocop (1.66.1) + rake (13.2.1) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) + ffi (~> 1.0) + rbi (0.3.2) + prism (~> 1.0) + rbs (>= 3.4.4) + sorbet-runtime (>= 0.5.9204) + rbs (3.9.2) + logger + redcarpet (3.6.1) + regexp_parser (2.10.0) + rexml (3.4.1) + rubocop (1.75.5) json (~> 2.3) - language_server-protocol (>= 3.17.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.4, < 3.0) - rubocop-ast (>= 1.32.2, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.44.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.2) - parser (>= 3.3.1.0) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.44.1) + parser (>= 3.3.7.2) + prism (~> 1.4) ruby-progressbar (1.13.0) - unicode-display_width (2.5.0) - webrick (1.8.2) + securerandom (0.4.1) + sorbet (0.5.12067) + sorbet-static (= 0.5.12067) + sorbet-runtime (0.5.12067) + sorbet-static (0.5.12067-x86_64-linux) + sorbet-static-and-runtime (0.5.12067) + sorbet (= 0.5.12067) + sorbet-runtime (= 0.5.12067) + spoom (1.6.1) + erubi (>= 1.10.0) + prism (>= 0.28.0) + rbi (>= 0.2.3) + sorbet-static-and-runtime (>= 0.5.10187) + thor (>= 0.19.2) + steep (1.10.0) + activesupport (>= 5.1) + concurrent-ruby (>= 1.1.10) + csv (>= 3.0.9) + fileutils (>= 1.1.0) + json (>= 2.1.0) + language_server-protocol (>= 3.17.0.4, < 4.0) + listen (~> 3.0) + logger (>= 1.3.0) + mutex_m (>= 0.3.0) + parser (>= 3.1) + rainbow (>= 2.2.2, < 4.0) + rbs (~> 3.9) + securerandom (>= 0.1) + strscan (>= 1.0.0) + terminal-table (>= 2, < 5) + uri (>= 0.12.0) + strscan (3.1.5) + syntax_tree (6.2.0) + prettier_print (>= 1.2.0) + tapioca (0.16.11) + benchmark + bundler (>= 2.2.25) + netrc (>= 0.11.0) + parallel (>= 1.21.0) + rbi (~> 0.2) + sorbet-static-and-runtime (>= 0.5.11087) + spoom (>= 1.2.0) + thor (>= 1.2.0) + yard-sorbet + terminal-table (4.0.0) + unicode-display_width (>= 1.1.1, < 4) + thor (1.3.2) + traces (0.15.2) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) + uri (1.0.3) + webmock (3.25.1) + addressable (>= 2.8.0) + crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) + webrick (1.9.1) yard (0.9.37) + yard-sorbet (0.9.0) + sorbet-runtime + yard PLATFORMS x86_64-linux DEPENDENCIES + async minitest - prelude! + minitest-focus + minitest-hooks + minitest-proveit + minitest-rg + prelude-sdk! rake + rbs + redcarpet rubocop + sorbet + steep + syntax_tree + syntax_tree-rbs! + tapioca + webmock webrick yard BUNDLED WITH - 2.4.10 + 2.4.1 diff --git a/LICENSE b/LICENSE index 157c5896..69f0a677 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 Prelude + Copyright 2025 Prelude Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 3667f3cb..b507f3d3 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,61 @@ # Prelude Ruby API library -The Prelude Ruby library provides convenient access to the Prelude REST API from any Ruby 3.0+ -application. +The Prelude Ruby library provides convenient access to the Prelude REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/prelude-so/ruby-sdk#Sorbet) for usage with Sorbet. The standard library's `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem. -It is generated with [Stainless](https://www.stainlessapi.com/). +It is generated with [Stainless](https://www.stainless.com/). ## Documentation -Documentation for the most recent version of this gem can be found [on RubyDoc](https://rubydoc.info/github/prelude-so/ruby-sdk). +Documentation for releases of this gem can be found [on RubyDoc](https://gemdocs.org/gems/prelude-sdk). -The underlying REST API documentation can be found on [docs.prelude.so](https://docs.prelude.so). +The REST API documentation can be found on [docs.prelude.so](https://docs.prelude.so). ## Installation -To use this gem during the beta, install directly from GitHub with Bundler by -adding the following to your application's `Gemfile`: +To use this gem, install via Bundler by adding the following to your application's `Gemfile`: -```ruby -gem "prelude", git: "https://github.com/prelude-so/ruby-sdk", branch: "main" -``` + -To fetch an initial copy of the gem: - -```sh -bundle install +```ruby +gem "prelude-sdk", "~> 0.1.0.pre.alpha.2" ``` -To update the version used by your application when updates are pushed to -GitHub: - -```sh -bundle update prelude -``` + ## Usage ```ruby -require "prelude" +require "bundler/setup" +require "prelude_sdk" -prelude = Prelude::Client.new( - api_token: "My API Token" # defaults to ENV["API_TOKEN"] +prelude = PreludeSDK::Client.new( + api_token: ENV["API_TOKEN"] # This is the default and can be omitted ) -verification = prelude.verification.create(target: {"type" => "phone_number", "value" => "+30123456789"}) +verification = prelude.verification.create(target: {type: "phone_number", value: "+30123456789"}) puts(verification.id) ``` -### Errors +### Handling errors -When the library is unable to connect to the API, or if the API returns a -non-success status code (i.e., 4xx or 5xx response), a subclass of -`Prelude::HTTP::Error` will be thrown: +When the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `PreludeSDK::Errors::APIError` will be thrown: ```ruby begin - verification = prelude.verification.create(target: {"type" => "phone_number", "value" => "+30123456789"}) -rescue Prelude::HTTP::Error => e - puts(e.code) # 400 + verification = prelude.verification.create(target: {type: "phone_number", value: "+30123456789"}) +rescue PreludeSDK::Errors::APIConnectionError => e + puts("The server could not be reached") + puts(e.cause) # an underlying Exception, likely raised within `net/http` +rescue PreludeSDK::Errors::RateLimitError => e + puts("A 429 status code was received; we should back off a bit.") +rescue PreludeSDK::Errors::APIStatusError => e + puts("Another non-200-range status code was received") + puts(e.status) end ``` -Error codes are as followed: +Error codes are as follows: | Cause | Error Type | | ---------------- | -------------------------- | @@ -72,54 +66,152 @@ Error codes are as followed: | HTTP 409 | `ConflictError` | | HTTP 422 | `UnprocessableEntityError` | | HTTP 429 | `RateLimitError` | -| HTTP >=500 | `InternalServerError` | +| HTTP >= 500 | `InternalServerError` | | Other HTTP error | `APIStatusError` | | Timeout | `APITimeoutError` | | Network error | `APIConnectionError` | ### Retries -Certain errors will be automatically retried 2 times by default, with a short -exponential backoff. Connection errors (for example, due to a network -connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, >=500 Internal errors, -and timeouts will all be retried by default. +Certain errors will be automatically retried 2 times by default, with a short exponential backoff. + +Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, >=500 Internal errors, and timeouts will all be retried by default. You can use the `max_retries` option to configure or disable this: ```ruby # Configure the default for all requests: -prelude = Prelude::Client.new( +prelude = PreludeSDK::Client.new( max_retries: 0 # default is 2 ) # Or, configure per-request: -prelude.verification.create(target: {"type" => "phone_number", "value" => "+30123456789"}, max_retries: 5) +prelude.verification.create( + target: {type: "phone_number", value: "+30123456789"}, + request_options: {max_retries: 5} +) ``` ### Timeouts -By default, requests will time out after 60 seconds. -Timeouts are applied separately to the initial connection and the overall request time, -so in some cases a request could wait 2\*timeout seconds before it fails. - -You can use the `timeout` option to configure or disable this: +By default, requests will time out after 60 seconds. You can use the timeout option to configure or disable this: ```ruby # Configure the default for all requests: -prelude = Prelude::Client.new( +prelude = PreludeSDK::Client.new( timeout: nil # default is 60 ) # Or, configure per-request: -prelude.verification.create(target: {"type" => "phone_number", "value" => "+30123456789"}, timeout: 5) +prelude.verification.create( + target: {type: "phone_number", value: "+30123456789"}, + request_options: {timeout: 5} +) +``` + +On timeout, `PreludeSDK::Errors::APITimeoutError` is raised. + +Note that requests that time out are retried by default. + +## Advanced concepts + +### BaseModel + +All parameter and response objects inherit from `PreludeSDK::Internal::Type::BaseModel`, which provides several conveniences, including: + +1. All fields, including unknown ones, are accessible with `obj[:prop]` syntax, and can be destructured with `obj => {prop: prop}` or pattern-matching syntax. + +2. Structural equivalence for equality; if two API calls return the same values, comparing the responses with == will return true. + +3. Both instances and the classes themselves can be pretty-printed. + +4. Helpers such as `#to_h`, `#deep_to_h`, `#to_json`, and `#to_yaml`. + +### Making custom or undocumented requests + +#### Undocumented properties + +You can send undocumented parameters to any endpoint, and read undocumented response properties, like so: + +Note: the `extra_` parameters of the same name overrides the documented parameters. + +```ruby +verification = + prelude.verification.create( + target: {type: "phone_number", value: "+30123456789"}, + request_options: { + extra_query: {my_query_parameter: value}, + extra_body: {my_body_parameter: value}, + extra_headers: {"my-header": value} + } + ) + +puts(verification[:my_undocumented_property]) +``` + +#### Undocumented request params + +If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a request, as seen in the examples above. + +#### Undocumented endpoints + +To make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on, you can make requests using `client.request`, like so: + +```ruby +response = client.request( + method: :post, + path: '/undocumented/endpoint', + query: {"dog": "woof"}, + headers: {"useful-header": "interesting-value"}, + body: {"hello": "world"} +) +``` + +### Concurrency & connection pooling + +The `PreludeSDK::Client` instances are threadsafe, but are only are fork-safe when there are no in-flight HTTP requests. + +Each instance of `PreludeSDK::Client` has its own HTTP connection pool with a default size of 99. As such, we recommend instantiating the client once per application in most settings. + +When all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout. + +Unless otherwise specified, other classes in the SDK do not have locks protecting their underlying data structure. + +## Sorbet + +This library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitions, and has no dependency on sorbet-runtime. + +You can provide typesafe request parameters like so: + +```ruby +prelude.verification.create( + target: PreludeSDK::VerificationCreateParams::Target.new(type: "phone_number", value: "+30123456789") +) +``` + +Or, equivalently: + +```ruby +# Hashes work, but are not typesafe: +prelude.verification.create(target: {type: "phone_number", value: "+30123456789"}) + +# You can also splat a full Params class: +params = PreludeSDK::VerificationCreateParams.new( + target: PreludeSDK::VerificationCreateParams::Target.new(type: "phone_number", value: "+30123456789") +) +prelude.verification.create(**params) ``` ## Versioning -This package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions. As the -library is in initial development and has a major version of `0`, APIs may change -at any time. +This package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions. As the library is in initial development and has a major version of `0`, APIs may change at any time. + +This package considers improvements to the (non-runtime) `*.rbi` and `*.rbs` type definitions to be non-breaking changes. ## Requirements -Ruby 3.0 or higher. +Ruby 3.2.0 or higher. + +## Contributing + +See [the contributing documentation](https://github.com/prelude-so/ruby-sdk/tree/main/CONTRIBUTING.md). diff --git a/Rakefile b/Rakefile index 4d8bcd64..e0714b6a 100644 --- a/Rakefile +++ b/Rakefile @@ -1,30 +1,160 @@ # frozen_string_literal: true +require "pathname" +require "securerandom" +require "shellwords" + require "minitest/test_task" +require "rake/clean" require "rubocop/rake_task" -task(default: [:test, :format]) +tapioca = "sorbet/tapioca" +examples = "examples" +ignore_file = ".ignore" + +CLEAN.push(*%w[.idea/ .ruby-lsp/ .yardoc/ doc/], *FileList["*.gem"], ignore_file) + +CLOBBER.push(*%w[sorbet/rbi/annotations/ sorbet/rbi/gems/], tapioca) + +multitask(:default) do + sh(*%w[rake --tasks]) +end + +desc("Preview docs; use `PORT=` to change the port") +multitask(:"docs:preview") do + sh(*%w[yard server --reload --quiet --bind [::] --port], ENV.fetch("PORT", "8808")) +end + +desc("Run test suites; use `TEST=path/to/test.rb` to run a specific test file") +multitask(:test) do + rb = + FileList[ENV.fetch("TEST", "./test/**/*_test.rb")] + .map { "require_relative(#{_1.dump});" } + .join + + ruby(*%w[-w -e], rb, verbose: false) { fail unless _1 } +end + +xargs = %w[xargs --no-run-if-empty --null --max-procs=0 --max-args=300 --] +ruby_opt = {"RUBYOPT" => [ENV["RUBYOPT"], "--encoding=UTF-8"].compact.join(" ")} + +desc("Lint `*.rb(i)`") +multitask(:"lint:rubocop") do + find = %w[find ./lib ./test ./rbi ./examples -type f -and ( -name *.rb -or -name *.rbi ) -print0] + + rubocop = %w[rubocop] + rubocop += %w[--format github] if ENV.key?("CI") + + # some lines cannot be shortened + rubocop += %w[--except Lint/RedundantCopDisableDirective,Layout/LineLength] + + lint = xargs + rubocop + sh("#{find.shelljoin} | #{lint.shelljoin}") +end + +desc("Format `*.rb`") +multitask(:"format:rb") do + # while `syntax_tree` is much faster than `rubocop`, `rubocop` is the only formatter with full syntax support + find = %w[find ./lib ./test ./examples -type f -and -name *.rb -print0] + fmt = xargs + %w[rubocop --fail-level F --autocorrect --format simple --] + sh("#{find.shelljoin} | #{fmt.shelljoin}") +end -Minitest::TestTask.create do |t| - t.libs = %w[.] - t.test_globs = ENV.fetch("TEST", "test/**/*_test.rb") +desc("Format `*.rbi`") +multitask(:"format:rbi") do + find = %w[find ./rbi -type f -and -name *.rbi -print0] + fmt = xargs + %w[stree write --] + sh(ruby_opt, "#{find.shelljoin} | #{fmt.shelljoin}") end -RuboCop::RakeTask.new(:rubocop) do |t| - t.options = %w[--fail-level E --autocorrect] - if ENV.key?("CI") - t.options += %w[--format github] +desc("Format `*.rbs`") +multitask(:"format:rbs") do + find = %w[find ./sig -type f -name *.rbs -print0] + inplace = /darwin|bsd/ =~ RUBY_PLATFORM ? ["-i", ""] : %w[-i] + uuid = SecureRandom.uuid + + # `syntax_tree` has trouble with `rbs`'s class & module aliases + + sed_bin = /darwin/ =~ RUBY_PLATFORM ? "/usr/bin/sed" : "sed" + sed = xargs + [sed_bin, "-E", *inplace, "-e"] + # annotate unprocessable aliases with a unique comment + pre = sed + ["s/(class|module) ([^ ]+) = (.+$)/# \\1 #{uuid}\\n\\2: \\3/", "--"] + fmt = xargs + %w[stree write --plugin=rbs --] + # remove the unique comment and unprocessable aliases to type aliases + subst = <<~SED + s/# (class|module) #{uuid}/\\1/ + t l1 + b + + : l1 + N + s/\\n *([^:]+): (.+)$/ \\1 = \\2/ + SED + # for each line: + # 1. try transform the unique comment into `class | module`, if successful, branch to label `l1`. + # 2. at label `l1`, join previously annotated line with `class | module` information. + pst = sed + [subst, "--"] + + success = false + + # transform class aliases to type aliases, which syntax tree has no trouble with + sh("#{find.shelljoin} | #{pre.shelljoin}") + # run syntax tree to format `*.rbs` files + sh(ruby_opt, "#{find.shelljoin} | #{fmt.shelljoin}") do + success = _1 end + # transform type aliases back to class aliases + sh("#{find.shelljoin} | #{pst.shelljoin}") + + # always run post-processing to remove comment marker + fail unless success end -RuboCop::RakeTask.new(:format) do |t| - t.options = %w[--fail-level F --autocorrect --format offenses] +desc("Format everything") +multitask(format: [:"format:rb", :"format:rbi", :"format:rbs"]) + +desc("Typecheck `*.rbs`") +multitask(:"typecheck:steep") do + sh(*%w[steep check]) end -task(:build) do - sh(*%w[gem build -- prelude.gemspec]) +directory(examples) + +desc("Typecheck `*.rbi`") +multitask("typecheck:sorbet": examples) do + sh(*%w[srb typecheck --dir], examples) +end + +directory(tapioca) do + sh(*%w[tapioca init]) +end + +desc("Typecheck everything") +multitask(typecheck: [:"typecheck:steep", :"typecheck:sorbet"]) + +desc("Lint and typecheck") +multitask(lint: [:"lint:rubocop", :typecheck]) + +desc("Build yard docs") +multitask(:"build:docs") do + sh(*%w[yard]) +end + +desc("Build ruby gem") +multitask(:"build:gem") do + # optimizing for grepping through the gem bundle: many tools honour `.ignore` files, including VSCode + # + # both `rbi` and `sig` directories are navigable by their respective tool chains and therefore can be ignored by tools such as `rg` + Pathname(ignore_file).write(<<~GLOB) + rbi/* + sig/* + GLOB + + sh(*%w[gem build -- prelude_sdk.gemspec]) + rm_rf(ignore_file) end -task(release: [:build]) do - sh(*%w[gem push], *FileList["prelude-*.gem"]) +desc("Release ruby gem") +multitask(release: [:"build:gem"]) do + sh(*%w[gem push], *FileList["*.gem"]) end diff --git a/SECURITY.md b/SECURITY.md index b80688e9..910ce27b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,9 +2,9 @@ ## Reporting Security Issues -This SDK is generated by [Stainless Software Inc](http://stainlessapi.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. +This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. -To report a security issue, please contact the Stainless team at security@stainlessapi.com. +To report a security issue, please contact the Stainless team at security@stainless.com. ## Responsible Disclosure @@ -16,11 +16,11 @@ before making any information public. ## Reporting Non-SDK Related Security Issues If you encounter security issues that are not directly related to SDKs but pertain to the services -or products provided by Prelude please follow the respective company's security reporting guidelines. +or products provided by Prelude, please follow the respective company's security reporting guidelines. ### Prelude Terms and Policies -Please contact hello@prelude.so for any questions or concerns regarding security of our services. +Please contact hello@prelude.so for any questions or concerns regarding the security of our services. --- diff --git a/Steepfile b/Steepfile new file mode 100644 index 00000000..528b48c3 --- /dev/null +++ b/Steepfile @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require "yaml" + +target(:lib) do + configure_code_diagnostics(Steep::Diagnostic::Ruby.strict) + + signature("sig") + + YAML.safe_load_file("./manifest.yaml", symbolize_names: true) => {dependencies:} + # currently these libraries lack the `*.rbs` annotations required by `steep` + stdlibs = dependencies - %w[English etc net/http rbconfig set stringio] + + stdlibs.each { library(_1) } +end diff --git a/bin/check-release-environment b/bin/check-release-environment index 7036147b..c05436e8 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -3,7 +3,7 @@ errors=() if [ -z "${GEM_HOST_API_KEY}" ]; then - errors+=("The PRELUDE_GEM_HOST_API_KEY secret has not been set. Please set it in either this repository's secrets or your organization secrets") + errors+=("The GEM_HOST_API_KEY secret has not been set. Please set it in either this repository's secrets or your organization secrets") fi lenErrors=${#errors[@]} diff --git a/examples/.keep b/examples/.keep new file mode 100644 index 00000000..d8c73e93 --- /dev/null +++ b/examples/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store example files demonstrating usage of this SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/lib/prelude.rb b/lib/prelude.rb deleted file mode 100644 index dce37b1c..00000000 --- a/lib/prelude.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -# Standard libraries. -require "cgi" -require "date" -require "json" -require "net/http" -require "securerandom" -require "time" -require "uri" - -# Gems. -require "connection_pool" - -# Package files. -require_relative "prelude/base_client" -require_relative "prelude/base_model" -require_relative "prelude/request_options" -require_relative "prelude/pooled_net_requester" -require_relative "prelude/util" -require_relative "prelude/version" -require_relative "prelude/models/transactional_send_response" -require_relative "prelude/models/verification_create_response" -require_relative "prelude/models/verification_check_response" -require_relative "prelude/models/watch_feed_back_response" -require_relative "prelude/models/watch_predict_response" -require_relative "prelude/resources/transactional" -require_relative "prelude/resources/verification" -require_relative "prelude/resources/watch" -require_relative "prelude/client" diff --git a/lib/prelude/base_client.rb b/lib/prelude/base_client.rb deleted file mode 100644 index 9ee87574..00000000 --- a/lib/prelude/base_client.rb +++ /dev/null @@ -1,516 +0,0 @@ -# frozen_string_literal: true - -module Prelude - # @!visibility private - class BaseClient - MAX_REDIRECTS = 20 # from whatwg fetch spec - - # @!attribute requester - # @return [Prelude::PooledNetRequester] - attr_accessor :requester - - # @param base_url [String] - # @param timeout [Float] - # @param max_retries [Integer] - # @param initial_retry_delay [Float] - # @param max_retry_delay [Float] - # @param headers [Hash{String => String}] - # @param idempotency_header [String, nil] - def initialize( - base_url:, - timeout: 0.0, - max_retries: 0, - initial_retry_delay: 0, - max_retry_delay: 0, - headers: {}, - idempotency_header: nil - ) - self.requester = Prelude::PooledNetRequester.new - base_url_parsed = URI.parse(base_url) - @headers = Prelude::Util.normalized_headers( - { - "X-Stainless-Lang" => "ruby", - "X-Stainless-Package-Version" => Prelude::VERSION, - "X-Stainless-Runtime" => RUBY_ENGINE, - "X-Stainless-Runtime-Version" => RUBY_ENGINE_VERSION, - "Accept" => "application/json" - }, - headers - ) - @host = base_url_parsed.host - @scheme = base_url_parsed.scheme - @port = base_url_parsed.port - @base_path = Prelude::Util.normalize_path(base_url_parsed.path) - @idempotency_header = idempotency_header&.to_s&.downcase - @max_retries = max_retries - @timeout = timeout - @initial_retry_delay = initial_retry_delay - @max_retry_delay = max_retry_delay - end - - # @return [Hash{String => String}] - def auth_headers - {} - end - - # @return [String] - def generate_idempotency_key - "stainless-ruby-retry-#{SecureRandom.uuid}" - end - - # @param req [Hash{Symbol => Object}] - # @option req [Hash{Symbol => Object}, Array, Object, nil] :body - # - # @raise [ArgumentError] - private def validate_request!(req) - case (body = req[:body]) - in Hash - body.each_key do |k| - unless k.is_a?(Symbol) - raise ArgumentError, "Request body keys must be Symbols, got #{k.inspect}" - end - end - else - # Body can be at least a Hash or Array, just check for Hash shape for now. - end - end - - # @param req [Hash{Symbol => Object}] - # @option req [String] :url - # @option req [String] :host - # @option req [String] :scheme - # @option req [String] :path - # @option req [String] :port - # @option req [Hash{String => Array}] :query - # @option req [Hash{String => Array}] :extra_query - # - # @return [Hash{Symbol => Object}] - def resolve_uri_elements(req) - from_args = - if (url = req[:url]) - Prelude::Util.parse_uri(url) - else - path = Prelude::Util.normalize_path("/#{@base_path}/#{req.fetch(:path)}") - req.slice(:scheme, :host, :port, :query).merge(path: path) - end - - query = Prelude::Util.deep_merge( - from_args[:query] || {}, - req[:extra_query] || {}, - concat: true - ) - { - host: @host, - scheme: @scheme, - port: @port, - **from_args, - query: query - } - end - - # @param req [Hash{Symbol => Object}] - # @param opts [Prelude::RequestOptions, Hash{Symbol => Object}] - # - # @return [Hash{Symbol => Object}] - private def build_request(req, opts) - options = Prelude::Util.deep_merge(req, opts) - method = options.fetch(:method) - body, extra_body = options.values_at(:body, :extra_body) - - headers = Prelude::Util.normalized_headers( - @headers, - auth_headers, - *options.values_at(:headers, :extra_headers) - ) - if @idempotency_header && - !headers.key?(@idempotency_header) && - ![:get, :head, :options].include?(method) - headers[@idempotency_header] = options.fetch(:idempotency_key) { generate_idempotency_key } - end - - unless headers.key?("x-stainless-retry-count") - headers["x-stainless-retry-count"] = "0" - end - headers.reject! { |_, v| v.nil? || v == "" } - - if [:get, :head, :options].include?(method) - body = nil - elsif extra_body - body = Prelude::Util.deep_merge(body, extra_body) - end - - body = - case headers["content-type"] - in "application/json" - JSON.dump(body) - else - body - end - - url_elements = resolve_uri_elements(options) - {method: method, headers: headers, body: body, **url_elements} - end - - # @param response [Net::HTTPResponse] - # - # @raise [JSON::ParserError] - # @return [Object] - private def parse_body(response) - case response.content_type - in "application/json" - JSON.parse(response.body, symbolize_names: true) - else - # TODO: parsing other response types - response.body - end - end - - # @param message [String] - # @param body [Object] - # @param response [Net::HTTPResponse] - private def make_status_error(message:, body:, response:) - raise NotImplementedError - end - - # @param response [Net::HTTPResponse] - private def make_status_error_from_response(response) - err_body = - begin - parse_body(response) - rescue JSON::ParserError - response - end - - # We include the body in the error message as well as returning it - # since logging error messages is a common and quick way to assess what's - # wrong with a response. - message = "Error code: #{response.code}; Response: #{response.body}" - make_status_error(message: message, body: err_body, response: response) - end - - # @param response [Net::HTTPResponse] - # - # @return [Boolean] - private def should_retry?(response) - case response["x-should-retry"] - in "true" - true - in "false" - false - else - case response.code.to_i - in 408 | 409 | 429 | (500..) - # retry on: - # 408: timeouts - # 409: locks - # 429: rate limits - # 500+: unknown errors - true - else - false - end - end - end - - # @param response [Net::HTTPResponse] - # @param retry_count [Integer] - # - # @return [Float] - private def retry_delay(response, retry_count:) - # Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it. - span = Float(response["retry-after-ms"], exception: false)&.then { |v| v / 1000 } - return span if span - - retry_header = response["retry-after"] - return span if (span = Float(retry_header, exception: false)) - - # TODO(ruby) - this should be removed when we support middlewares - now = - if response["x-stainless-mock-sleep-base"] - Time.httpdate(response["x-stainless-mock-sleep-base"]) - else - Time.now - end - - span = - if retry_header - Prelude::Util.suppress(ArgumentError) do - Time.httpdate(retry_header) - now - end - end - return span if span - - scale = retry_count**2 - jitter = 1 - (0.25 * rand) - (@initial_retry_delay * scale * jitter).clamp(0, @max_retry_delay) - end - - # @param request [Hash{Symbol => Object}] - # @option options [Symbol] :method - # @option options [Hash{String => String}] :headers - # @option options [String, nil] :body - # - # @param status [Integer] - # @param location_header [URI::Generic] - # - # @raise [Prelude::HTTP::Error] - # @return [Hash{Symbol => Object}] - private def follow_redirect(request, status:, location_header:) - uri = Prelude::Util.unparse_uri(request) - location = - Prelude::Util.suppress(ArgumentError) do - URI.join(uri, location_header) - end - - # TODO(ruby): these should be response errors - unless location - message = "server responded with status #{status} but no valid location header" - raise HTTP::APIConnectionError.new(message: message, request: request) - end - - request = {**request, **resolve_uri_elements(url: location)} - - case [uri.scheme, location.scheme] - in ["https", "http"] - message = "tried to redirect to a insecure URL" - raise HTTP::APIConnectionError.new(message: message, request: request) - else - nil - end - - # from whatwg fetch spec - case [status, (method = request.fetch(:method))] - in [301 | 302, :post] | [303, _] - drop = %w[content-encoding content-language content-location content-type content-length] - request = { - **request, - method: method == :head ? :head : :get, - headers: request.fetch(:headers).except(*drop), - body: nil - } - else - end - - # from undici - if Prelude::Util.uri_origin(uri) != Prelude::Util.uri_origin(location) - drop = %w[authorization cookie proxy-authorization host] - request = {**request, headers: request.fetch(:headers).except(*drop)} - end - - request - end - - # @param request [Hash{Symbol => Object}] - # @option options [Symbol] :method - # @option options [Hash{String => String}] :headers - # @option options [String, nil] :body - # - # @param max_retries [Integer] - # @param timeout [Float] - # @param redirect_count [Integer] - # @param retry_count [Integer] - # @param send_retry_header [Boolean] - # - # @raise [Prelude::HTTP::Error] - # @return [Net::HTTPResponse] - private def send_request( - request, - max_retries:, - timeout:, - redirect_count:, - retry_count:, - send_retry_header: - ) - if send_retry_header - request.fetch(:headers)["x-stainless-retry-count"] = retry_count.to_s - end - - begin - response = @requester.execute(request, timeout: timeout) - status = response.code.to_i - rescue Timeout::Error, Net::HTTPBadResponse => e - status = e - end - - case status - in ..299 - response - in 300..399 - if redirect_count >= MAX_REDIRECTS - message = "failed to complete the request within #{MAX_REDIRECTS} redirects" - raise HTTP::APIConnectionError.new(message: message, request: request) - end - - request = follow_redirect(request, status: status, location_header: response["location"]) - send_request( - request, - max_retries: max_retries, - timeout: timeout, - redirect_count: redirect_count + 1, - retry_count: retry_count, - send_retry_header: send_retry_header - ) - in 400.. | Timeout::Error | Net::HTTPBadResponse - if response && !should_retry?(response) - raise make_status_error_from_response(response) - end - - if retry_count >= max_retries - message = "failed to complete the request within #{max_retries} retries" - case status - in Timeout::Error - raise HTTP::APITimeoutError.new(message: message, request: request) - else - raise HTTP::InternalServerError.new(message: message, response: response, body: response.body) - end - end - - delay = retry_delay(response, retry_count: retry_count) - if response&.key?("x-stainless-mock-sleep") - request.fetch(:headers)["x-stainless-mock-slept"] = delay - else - sleep(delay) - end - - send_request( - request, - max_retries: max_retries, - timeout: timeout, - redirect_count: redirect_count, - retry_count: retry_count + 1, - send_retry_header: send_retry_header - ) - end - end - - # @param req [Hash{Symbol => Object}] - # @param opts [Prelude::RequestOptions, Hash{Symbol => Object}] - # - # @return [Object] - private def parse_response(req, opts, response) - parsed = parse_body(response) - raw_data = Prelude::Util.dig(parsed, req[:unwrap]) - - page, model = req.values_at(:page, :model) - case [page, model] - in [Class, _] - page.new(client: self, model: model, req: req, opts: opts, response: response, raw_data: raw_data) - in [nil, _] unless model.nil? - Prelude::Converter.convert(model, raw_data) - in [nil, nil] - raw_data - end - end - - # Execute the request specified by req + opts. This is the method that all - # resource methods call into. - # Params req & opts are kept separate up until this point so that we can - # validate opts as it was given to us by the user. - # @param req [Hash{Symbol => Object}] - # @param opts [Prelude::RequestOptions, Hash{Symbol => Object}] - # - # @raise [Prelude::HTTP::Error] - # @return [Object] - def request(req, opts) - Prelude::RequestOptions.validate!(opts) - validate_request!(req) - request = build_request(req, opts) - - # Don't send the current retry count in the headers if the caller modified the header defaults. - send_retry_header = request.fetch(:headers)["x-stainless-retry-count"] == "0" - response = send_request( - request, - max_retries: opts.fetch(:max_retries, @max_retries), - timeout: opts.fetch(:timeout, @timeout), - redirect_count: 0, - retry_count: 0, - send_retry_header: send_retry_header - ) - parse_response(req, opts, response) - end - - # @return [String] - def inspect - base_url = Prelude::Util.unparse_uri(scheme: @scheme, host: @host, port: @port, path: @base_path) - "#<#{self.class.name}:0x#{object_id.to_s(16)} base_url=#{base_url} max_retries=#{@max_retries} timeout=#{@timeout}>" - end - end - - class Error < StandardError - end - - module HTTP - class Error < Prelude::Error - end - - class ResponseError < Error - # @!attribute [r] response - # @return [Net::HTTPResponse] - attr_reader :response - - # @!attribute [r] body - # @return [Object] - attr_reader :body - - # @!attribute [r] code - # @return [Integer] - attr_reader :code - - # @param message [String] - # @param response [Net::HTTPResponse] - # @param body [Object] - def initialize(message:, response:, body:) - super(message) - @response = response - @body = body - @code = response.code.to_i - end - end - - class RequestError < Error - # @!attribute [r] request - # @return [Hash{Symbol => Object}] - attr_reader :request - - # @param message [String] - # @param request [Hash{Symbol => Object}] - def initialize(message:, request:) - super(message) - @request = request - end - end - - class BadRequestError < ResponseError - end - - class AuthenticationError < ResponseError - end - - class PermissionDeniedError < ResponseError - end - - class NotFoundError < ResponseError - end - - class ConflictError < ResponseError - end - - class UnprocessableEntityError < ResponseError - end - - class RateLimitError < ResponseError - end - - class InternalServerError < ResponseError - end - - class APIStatusError < ResponseError - end - - class APIConnectionError < RequestError - end - - class APITimeoutError < RequestError - end - end -end diff --git a/lib/prelude/base_model.rb b/lib/prelude/base_model.rb deleted file mode 100644 index 0638e850..00000000 --- a/lib/prelude/base_model.rb +++ /dev/null @@ -1,262 +0,0 @@ -# frozen_string_literal: true - -module Prelude - # @!visibility private - module Converter - # Based on `value`, returns a value that conforms to `type`, to the extent possible: - # - If the given `value` conforms to `type` already, the given `value`. - # - If it's possible and safe to convert the given `value` to `type`, such a converted value. - # - Otherwise, the given `value` unaltered. - # - # @param type [Class, Prelude::Converter] - # @param value [Object] - # - # @raise [StandardError] - # @return [Object] - def self.convert(type, value) - # If `type.is_a?(Converter)`, `type` is an instance of a class that mixes - # in `Converter`, indicating that the type should define `#convert` on this - # instance. This is used for Enums and ArrayOfs, which are parameterized. - # If `type.include?(Converter)`, `type` is a class that mixes in `Converter` - # which we use to signal that the class should define `.convert`. This is - # used where the class itself fully specifies the type, like model classes. - # We don't monkey-patch Ruby-native types, so those need to be handled - # directly. - if type.is_a?(Converter) || type.include?(Converter) - type.convert(value) - elsif type <= NilClass - nil - elsif type <= Date - Date.parse(value) - elsif type <= Time - Time.parse(value) - elsif type <= Float - value.is_a?(Numeric) ? value.to_f : value - elsif [Object, Hash, Integer, String].any? { |cls| type <= cls } - value - else - raise StandardError, "Unexpected type #{type}" - end - end - end - - # When we don't know what to expect for the value. - # @!visibility private - class Unknown - include Prelude::Converter - - # @param value [Object] - # - # @return [Object] - def self.convert(value) - value - end - end - - # Ruby has no Boolean class; this is something for models to refer to. - # @!visibility private - class BooleanModel - include Prelude::Converter - - # @param value [Boolean, Object] - # - # @return [Boolean, Object] - def self.convert(value) - value - end - end - - # A value from among a specified list of options. OpenAPI enum values map to - # Ruby values in the SDK as follows: - # boolean => true|false - # integer => Integer - # float => Float - # string => Symbol - # We can therefore convert string values to Symbols, but can't convert other - # values safely. - # @!visibility private - class Enum - include Prelude::Converter - - # @param value [Symbol, String, Object] - # - # @return [Symbol, Object] - def self.convert(value) - case value - in String - value.to_sym - else - value - end - end - - # @return [Array] All of the valid Symbol values for this enum. - def self.values - @values ||= constants.map { |c| const_get(c) } - end - end - - # Array of items of a given type. - # @!visibility private - class ArrayOf - include Prelude::Converter - - # @param items_type_info [Proc, Object, nil] - # @param enum [Proc, nil] - def initialize(items_type_info = nil, enum: nil) - @items_type_fn = enum || (items_type_info.is_a?(Proc) ? items_type_info : -> { items_type_info }) - end - - # @param value [Enumerable, Object] - # - # @return [Array] - def convert(value) - items_type = @items_type_fn.call - case value - in Enumerable - value.map { |item| Converter.convert(items_type, item) }.to_a - else - value - end - end - end - - class BaseModel - include Prelude::Converter - - # @!visibility private - # - # Assumes superclass fields are totally defined before fields are accessed / defined on subclasses. - # - # @return [Hash{Symbol => Hash{Symbol => Object}}] - def self.fields - @fields ||= (superclass == BaseModel ? {} : superclass.fields.dup) - end - - # @!visibility private - # - # @param name_sym [Symbol] - # @param api_name [Symbol, nil] - # @param type_info [Proc, Object] - # @param mode [Symbol] - # - # @return [void] - private_class_method def self.add_field(name_sym, api_name:, type_info:, mode:) - type_fn = type_info.is_a?(Proc) ? type_info : -> { type_info } - key = api_name || name_sym - fields[name_sym] = {type_fn: type_fn, mode: mode, key: key} - - define_method("#{name_sym}=") { |val| @data[key] = val } - - define_method(name_sym) do - field_type = type_fn.call - Prelude::Converter.convert(field_type, @data[key]) - rescue StandardError - name = self.class.name.split("::").last - raise Prelude::ConversionError, - "Failed to parse #{name}.#{name_sym} as #{field_type.inspect}. " \ - "To get the unparsed API response, use #{name}[:#{key}]." - end - end - - # @!visibility private - # - # NB `required` is just a signal to the reader. We don't do runtime validation anyway. - private_class_method def self.required(name_sym, type_info = nil, mode = :rw, api_name: nil, enum: nil) - add_field(name_sym, api_name: api_name, type_info: enum || type_info, mode: mode) - end - - # @!visibility private - # - # NB `optional` is just a signal to the reader. We don't do runtime validation anyway. - private_class_method def self.optional(name_sym, type_info = nil, mode = :rw, api_name: nil, enum: nil) - add_field(name_sym, api_name: api_name, type_info: enum || type_info, mode: mode) - end - - # @!visibility private - # - # @param data [Hash{Symbol => Object}] - # @return [BaseModel] - def self.convert(data) - new(data) - end - - # Create a new instance of a model. - # @param data [Hash{Symbol => Object}] Raw data to initialize the model with. - def initialize(data = {}) - unless data.respond_to?(:to_h) - raise ArgumentError, - "Expected a Hash, got #{data.inspect}" - end - - @data = {} - data.to_h.each do |field_name, value| - next if value.nil? - name = field_name.to_sym - next if self.class.fields.dig(name, :mode) == :w - - @data[name] = value - end - end - - # Returns a Hash of the data underlying this object. - # Keys are Symbols and values are the raw values from the response. - # The return value indicates which values were ever set on the object - - # i.e. there will be a key in this hash if they ever were, even if the - # set value was nil. - # This method is not recursive. - # The returned value is shared by the object, so it should not be mutated. - # - # @return [Hash{Symbol => Object}] Data for this object. - def to_h - @data - end - - alias_method :to_hash, :to_h - - # Returns the raw value associated with the given key, if found. Otherwise, nil is returned. - # It is valid to lookup keys that are not in the API spec, for example to access - # undocumented features. - # This method does not parse response data into higher-level types. - # Lookup by anything other than a Symbol is an ArgumentError. - # - # @param key [Symbol] Key to look up by. - # - # @return [Object, nil] The raw value at the given key. - def [](key) - unless key.instance_of?(Symbol) - raise ArgumentError, "Expected symbol key for lookup, got #{key.inspect}" - end - @data[key] - end - - # @param keys [Array, nil] - # - # @return [Hash{Symbol => Object}] - def deconstruct_keys(keys) - (keys || self.class.fields.keys).filter_map do |k| - unless self.class.fields.key?(k) - next - end - - [k, method(k).call] - end - .to_h - end - - # @return [String] - def inspect - "#<#{self.class.name}:0x#{object_id.to_s(16)} #{deconstruct_keys(nil).map do |k, v| - "#{k}=#{v.inspect}" - end.join(' ')}>" - end - - # @return [String] - def to_s - @data.to_s - end - end - - class ConversionError < Error - end -end diff --git a/lib/prelude/client.rb b/lib/prelude/client.rb deleted file mode 100644 index 3eb48450..00000000 --- a/lib/prelude/client.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -module Prelude - class Client < Prelude::BaseClient - # Default max number of retries to attempt after a failed retryable request. - DEFAULT_MAX_RETRIES = 2 - - # Default per-request timeout. - DEFAULT_TIMEOUT_IN_SECONDS = 60 - - # Default initial retry delay in seconds. - # Overall delay is calculated using exponential backoff + jitter. - DEFAULT_INITIAL_RETRY_DELAY = 0.5 - - # Default max retry delay in seconds. - DEFAULT_MAX_RETRY_DELAY = 8.0 - - # Client option - # @return [String] - attr_reader :api_token - - # @return [Prelude::Resources::Transactional] - attr_reader :transactional - - # @return [Prelude::Resources::Verification] - attr_reader :verification - - # @return [Prelude::Resources::Watch] - attr_reader :watch - - # @!visibility private - def auth_headers - {"Authorization" => "Bearer #{@api_token}"} - end - - # Creates and returns a new client for interacting with the API. - # - # @param base_url [String, nil] Override the default base URL for the API, e.g., `"https://api.example.com/v2/"` - # @param api_token [String, nil] Bearer token for authorizing API requests. Defaults to `ENV["API_TOKEN"]` - # @param max_retries [Integer] Max number of retries to attempt after a failed retryable request. - def initialize( - base_url: nil, - api_token: ENV["API_TOKEN"], - max_retries: DEFAULT_MAX_RETRIES, - timeout: DEFAULT_TIMEOUT_IN_SECONDS, - initial_retry_delay: DEFAULT_INITIAL_RETRY_DELAY, - max_retry_delay: DEFAULT_MAX_RETRY_DELAY - ) - base_url ||= "https://api.prelude.dev" - - if api_token.nil? - raise ArgumentError, "api_token is required" - end - - @api_token = api_token.to_s - - super( - base_url: base_url, - timeout: timeout, - max_retries: max_retries, - initial_retry_delay: initial_retry_delay, - max_retry_delay: max_retry_delay - ) - - @transactional = Prelude::Resources::Transactional.new(client: self) - @verification = Prelude::Resources::Verification.new(client: self) - @watch = Prelude::Resources::Watch.new(client: self) - end - - # @!visibility private - private def make_status_error(message:, body:, response:) - case response.code.to_i - in 400 - Prelude::HTTP::BadRequestError.new(message: message, response: response, body: body) - in 401 - Prelude::HTTP::AuthenticationError.new(message: message, response: response, body: body) - in 403 - Prelude::HTTP::PermissionDeniedError.new(message: message, response: response, body: body) - in 404 - Prelude::HTTP::NotFoundError.new(message: message, response: response, body: body) - in 409 - Prelude::HTTP::ConflictError.new(message: message, response: response, body: body) - in 422 - Prelude::HTTP::UnprocessableEntityError.new(message: message, response: response, body: body) - in 429 - Prelude::HTTP::RateLimitError.new(message: message, response: response, body: body) - in 500..599 - Prelude::HTTP::InternalServerError.new(message: message, response: response, body: body) - else - Prelude::HTTP::APIStatusError.new(message: message, response: response, body: body) - end - end - end -end diff --git a/lib/prelude/models/transactional_send_response.rb b/lib/prelude/models/transactional_send_response.rb deleted file mode 100644 index f310e5d5..00000000 --- a/lib/prelude/models/transactional_send_response.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -module Prelude - module Models - class TransactionalSendResponse < Prelude::BaseModel - # @!attribute [rw] id - # The message identifier. - # @return [String] - required :id, String - - # @!attribute [rw] created_at - # The message creation date. - # @return [Time] - required :created_at, Time - - # @!attribute [rw] expires_at - # The message expiration date. - # @return [Time] - required :expires_at, Time - - # @!attribute [rw] template_id - # The template identifier. - # @return [String] - required :template_id, String - - # @!attribute [rw] to - # The recipient's phone number. - # @return [String] - required :to, String - - # @!attribute [rw] variables - # The variables to be replaced in the template. - # @return [Hash] - required :variables, Hash - - # @!attribute [rw] callback_url - # The callback URL. - # @return [String] - optional :callback_url, String - - # @!attribute [rw] correlation_id - # A unique, user-defined identifier that will be included in webhook events. - # @return [String] - optional :correlation_id, String - - # @!attribute [rw] from - # The Sender ID. - # @return [String] - optional :from, String - - # @!parse - # # Create a new instance of TransactionalSendResponse from a Hash of raw data. - # # - # # @param data [Hash{Symbol => Object}] . - # # @option data [String] :id The message identifier. - # # @option data [String] :created_at The message creation date. - # # @option data [String] :expires_at The message expiration date. - # # @option data [String] :template_id The template identifier. - # # @option data [String] :to The recipient's phone number. - # # @option data [Hash] :variables The variables to be replaced in the template. - # # @option data [String, nil] :callback_url The callback URL. - # # @option data [String, nil] :correlation_id A unique, user-defined identifier that will be included in webhook events. - # # @option data [String, nil] :from The Sender ID. - # def initialize(data = {}) = super - end - end -end diff --git a/lib/prelude/models/verification_check_response.rb b/lib/prelude/models/verification_check_response.rb deleted file mode 100644 index e8befe42..00000000 --- a/lib/prelude/models/verification_check_response.rb +++ /dev/null @@ -1,56 +0,0 @@ -# frozen_string_literal: true - -module Prelude - module Models - class VerificationCheckResponse < Prelude::BaseModel - # @!attribute [rw] id - # The verification identifier. - # @return [String] - optional :id, String - - # @!attribute [rw] metadata - # The metadata for this verification. - # @return [Prelude::Models::VerificationCheckResponse::Metadata] - optional :metadata, -> { Prelude::Models::VerificationCheckResponse::Metadata } - - # @!attribute [rw] request_id - # @return [String] - optional :request_id, String - - # @!attribute [rw] status - # The status of the check. - # @return [Symbol, Prelude::Models::VerificationCheckResponse::Status] - optional :status, enum: -> { Prelude::Models::VerificationCheckResponse::Status } - - class Metadata < Prelude::BaseModel - # @!attribute [rw] correlation_id - # @return [String] - optional :correlation_id, String - - # @!parse - # # Create a new instance of Metadata from a Hash of raw data. - # # - # # @param data [Hash{Symbol => Object}] . - # # @option data [String, nil] :correlation_id - # def initialize(data = {}) = super - end - - # The status of the check. - class Status < Prelude::Enum - SUCCESS = :success - FAILURE = :failure - EXPIRED = :expired - end - - # @!parse - # # Create a new instance of VerificationCheckResponse from a Hash of raw data. - # # - # # @param data [Hash{Symbol => Object}] . - # # @option data [String, nil] :id The verification identifier. - # # @option data [Object, nil] :metadata The metadata for this verification. - # # @option data [String, nil] :request_id - # # @option data [String, nil] :status The status of the check. - # def initialize(data = {}) = super - end - end -end diff --git a/lib/prelude/models/verification_create_response.rb b/lib/prelude/models/verification_create_response.rb deleted file mode 100644 index 5b8022c0..00000000 --- a/lib/prelude/models/verification_create_response.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -module Prelude - module Models - class VerificationCreateResponse < Prelude::BaseModel - # @!attribute [rw] id - # The verification identifier. - # @return [String] - optional :id, String - - # @!attribute [rw] metadata - # The metadata for this verification. - # @return [Prelude::Models::VerificationCreateResponse::Metadata] - optional :metadata, -> { Prelude::Models::VerificationCreateResponse::Metadata } - - # @!attribute [rw] method_ - # The method used for verifying this phone number. - # @return [Symbol, Prelude::Models::VerificationCreateResponse::Method] - optional :method_, api_name: :method, enum: -> { Prelude::Models::VerificationCreateResponse::Method } - - # @!attribute [rw] request_id - # @return [String] - optional :request_id, String - - # @!attribute [rw] status - # The status of the verification. - # @return [Symbol, Prelude::Models::VerificationCreateResponse::Status] - optional :status, enum: -> { Prelude::Models::VerificationCreateResponse::Status } - - class Metadata < Prelude::BaseModel - # @!attribute [rw] correlation_id - # @return [String] - optional :correlation_id, String - - # @!parse - # # Create a new instance of Metadata from a Hash of raw data. - # # - # # @param data [Hash{Symbol => Object}] . - # # @option data [String, nil] :correlation_id - # def initialize(data = {}) = super - end - - # The method used for verifying this phone number. - class Method < Prelude::Enum - MESSAGE = :message - end - - # The status of the verification. - class Status < Prelude::Enum - SUCCESS = :success - RETRY = :retry - BLOCKED = :blocked - end - - # @!parse - # # Create a new instance of VerificationCreateResponse from a Hash of raw data. - # # - # # @param data [Hash{Symbol => Object}] . - # # @option data [String, nil] :id The verification identifier. - # # @option data [Object, nil] :metadata The metadata for this verification. - # # @option data [String, nil] :method The method used for verifying this phone number. - # # @option data [String, nil] :request_id - # # @option data [String, nil] :status The status of the verification. - # def initialize(data = {}) = super - end - end -end diff --git a/lib/prelude/models/watch_feed_back_response.rb b/lib/prelude/models/watch_feed_back_response.rb deleted file mode 100644 index 6a424ade..00000000 --- a/lib/prelude/models/watch_feed_back_response.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -module Prelude - module Models - class WatchFeedBackResponse < Prelude::BaseModel - # @!attribute [rw] id - # A unique identifier for your feedback request. - # @return [String] - optional :id, String - - # @!parse - # # Create a new instance of WatchFeedBackResponse from a Hash of raw data. - # # - # # @param data [Hash{Symbol => Object}] . - # # @option data [String, nil] :id A unique identifier for your feedback request. - # def initialize(data = {}) = super - end - end -end diff --git a/lib/prelude/models/watch_predict_response.rb b/lib/prelude/models/watch_predict_response.rb deleted file mode 100644 index 8b66a284..00000000 --- a/lib/prelude/models/watch_predict_response.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -module Prelude - module Models - class WatchPredictResponse < Prelude::BaseModel - # @!attribute [rw] id - # A unique identifier for your prediction request. - # @return [String] - optional :id, String - - # @!attribute [rw] prediction - # A label indicating the trustworthiness of the phone number. - # @return [Symbol, Prelude::Models::WatchPredictResponse::Prediction] - optional :prediction, enum: -> { Prelude::Models::WatchPredictResponse::Prediction } - - # @!attribute [rw] reasoning - # @return [Prelude::Models::WatchPredictResponse::Reasoning] - optional :reasoning, -> { Prelude::Models::WatchPredictResponse::Reasoning } - - # A label indicating the trustworthiness of the phone number. - class Prediction < Prelude::Enum - ALLOW = :allow - BLOCK = :block - end - - class Reasoning < Prelude::BaseModel - # @!attribute [rw] cause - # A label explaining why the phone number was classified as not trustworthy - # @return [Symbol, Prelude::Models::WatchPredictResponse::Reasoning::Cause] - optional :cause, enum: -> { Prelude::Models::WatchPredictResponse::Reasoning::Cause } - - # @!attribute [rw] score - # Indicates the risk of the phone number being genuine or involved in fraudulent patterns. The higher the riskier. - # @return [Float] - optional :score, Float - - # A label explaining why the phone number was classified as not trustworthy - class Cause < Prelude::Enum - NONE = :none - SMART_ANTIFRAUD = :smart_antifraud - REPEAT_NUMBER = :repeat_number - INVALID_LINE = :invalid_line - end - - # @!parse - # # Create a new instance of Reasoning from a Hash of raw data. - # # - # # @param data [Hash{Symbol => Object}] . - # # @option data [String, nil] :cause A label explaining why the phone number was classified as not trustworthy - # # @option data [Float, nil] :score Indicates the risk of the phone number being genuine or involved in fraudulent - # # patterns. The higher the riskier. - # def initialize(data = {}) = super - end - - # @!parse - # # Create a new instance of WatchPredictResponse from a Hash of raw data. - # # - # # @param data [Hash{Symbol => Object}] . - # # @option data [String, nil] :id A unique identifier for your prediction request. - # # @option data [String, nil] :prediction A label indicating the trustworthiness of the phone number. - # # @option data [Object, nil] :reasoning - # def initialize(data = {}) = super - end - end -end diff --git a/lib/prelude/pooled_net_requester.rb b/lib/prelude/pooled_net_requester.rb deleted file mode 100644 index 815c3180..00000000 --- a/lib/prelude/pooled_net_requester.rb +++ /dev/null @@ -1,81 +0,0 @@ -# frozen_string_literal: true - -module Prelude - # @!visibility private - class PooledNetRequester - def initialize - @mutex = Mutex.new - @pools = {} - end - - # @param req [Hash{Symbol => Object}] - # @param timeout [Float] - # - # @return [ConnectionPool] - private def get_pool(req, timeout:) - scheme, hostname = req.fetch_values(:scheme, :host) - scheme = scheme.to_sym - port = req.fetch(:port) do - case scheme - in :http - Net::HTTP.http_default_port - else - Net::HTTP.https_default_port - end - end - - @mutex.synchronize do - @pools[hostname] ||= ConnectionPool.new do - conn = Net::HTTP.new(hostname, port) - conn.use_ssl = scheme == :https - conn.max_retries = 0 - conn.open_timeout = timeout - conn.start - conn - end - @pools[hostname] - end - end - - # @param req [Hash{Symbol => Object}] - # @param timeout [Float] - # - # @return [Net::HTTPResponse] - def execute(req, timeout:) - method, headers, body = req.fetch_values(:method, :headers, :body) - content_type = headers["content-type"] - - get_pool(req, timeout: timeout).with do |conn| - uri = Prelude::Util.unparse_uri(req, absolute: false) - - request = Net::HTTPGenericRequest.new( - method.to_s.upcase, - !body.nil?, - method != :head, - uri.to_s - ) - - case [content_type, body] - in ["multipart/form-data", Hash] - form_data = - body.filter_map do |k, v| - next if v.nil? - [k.to_s, v].flatten - end - request.set_form(form_data, content_type) - headers = headers.merge("content-type" => nil) - else - request.body = body - end - - headers.each do |k, v| - request[k] = v - end - - conn.read_timeout = timeout - conn.write_timeout = timeout - conn.request(request) - end - end - end -end diff --git a/lib/prelude/request_options.rb b/lib/prelude/request_options.rb deleted file mode 100644 index 4abf17e9..00000000 --- a/lib/prelude/request_options.rb +++ /dev/null @@ -1,124 +0,0 @@ -# frozen_string_literal: true - -module Prelude - # Specify HTTP behaviour to use for a specific request. These options supplement or override those - # provided at the client level. - # - # When making a request, you can pass an actual {RequestOptions} instance, or simply pass a Hash - # with symbol keys matching the attributes on this class. - class RequestOptions - # @!visibility private - # - # @return [Array] - private_class_method def self.options - @options ||= [] - end - - # @!visibility private - # - # @param name [Symbol] - private_class_method def self.option(name) - define_method("#{name}=") { |val| @_values[name] = val } - define_method(name) { @_values[name] } - options << name - end - - # @!visibility private - # - # @param opts [Prelude::RequestOptions, Hash{Symbol => Object}] - # - # @raise [ArgumentError] - def self.validate!(opts) - case opts - in Prelude::RequestOptions | Hash - opts.to_h.each_key do |k| - unless options.include?(k) - raise ArgumentError, "Request `opts` keys must be one of #{options}, got #{k.inspect}" - end - end - else - raise ArgumentError, "Request `opts` must be a Hash or RequestOptions, got #{opts.inspect}" - end - end - - # Returns a new instance of RequestOptions. - # - # @param values [Hash{Symbol => Object}] initial option values to set on the instance. - # @option values [String] :idempotency_key - # @option values [Hash{Symbol => String}] :extra_headers - # @option values [Hash{Symbol => Array}] :extra_query - # @option values [Hash{Symbol => Object}] :extra_body - # @option values [Integer] :max_retries - # @option values [Integer] :timeout - def initialize(values = {}) - @_values = values - end - - # @!attribute idempotency_key - # Idempotency key to send with request and all associated retries. Will only be sent for write - # requests. - # @return [String] - option :idempotency_key - - # @!attribute extra_headers - # Extra headers to send with the request. These are `.merged`’d into any `extra_headers` given at the - # client level. - # @return [Hash{String => String}] - option :extra_headers - - # @!attribute extra_query - # Extra query params to send with the request. These are `.merge`’d into any `query` given at - # the client level. - # @return [Hash{Symbol => Array}] - option :extra_query - - # @!attribute extra_body - # Extra data to send with the request. These are deep merged into any data generated as part - # of the normal request. - # @return [Hash{Symbol => Object}] - option :extra_body - - # @!attribute max_retries - # Maximum number of retries to attempt after a failed initial request. - # @return [Integer] - option :max_retries - - # @!attribute timeout - # Request timeout in seconds. - # @return [Integer] - option :timeout - - # Lookup an option previously set on this instance. - # - # @return [Object] - def [](key) - @_values[key] - end - - # Return a Hash containing the options set on this instance. - # - # @return [Hash{Symbol => Object}] - def to_h - @_values - end - - alias_method :to_hash, :to_h - - # @return [String] - def inspect - "#<#{self.class}:0x#{object_id.to_s(16)} #{@_values.inspect}>" - end - - # @return [String] - def to_s - @_values.to_s - end - - # @param keys [Array, nil] - # - # @return [Hash{Symbol => Object}] - def deconstruct_keys(keys) - @_values.deconstruct_keys(keys) - end - end -end diff --git a/lib/prelude/resources/transactional.rb b/lib/prelude/resources/transactional.rb deleted file mode 100644 index ab6493d8..00000000 --- a/lib/prelude/resources/transactional.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -module Prelude - module Resources - class Transactional - # @param client [Prelude::Client] - def initialize(client:) - @client = client - end - - # Send a transactional message to your user. - # - # @param params [Hash{Symbol => Object}] Attributes to send in this request. - # @option params [String] :template_id The template identifier. - # @option params [String] :to The recipient's phone number. - # @option params [String, nil] :callback_url The callback URL. - # @option params [String, nil] :correlation_id A unique, user-defined identifier that will be included in webhook events. - # @option params [String, nil] :expires_at The message expiration date. - # @option params [String, nil] :from The Sender ID. - # @option params [Hash, nil] :variables The variables to be replaced in the template. - # - # @param opts [Hash{Symbol => Object}, Prelude::RequestOptions] Options to specify HTTP behaviour for this request. - # - # @return [Prelude::Models::TransactionalSendResponse] - def send(params = {}, opts = {}) - req = { - method: :post, - path: "/v2/transactional", - body: params, - headers: {"Content-Type" => "application/json"}, - model: Prelude::Models::TransactionalSendResponse - } - @client.request(req, opts) - end - end - end -end diff --git a/lib/prelude/resources/verification.rb b/lib/prelude/resources/verification.rb deleted file mode 100644 index eaa5401f..00000000 --- a/lib/prelude/resources/verification.rb +++ /dev/null @@ -1,57 +0,0 @@ -# frozen_string_literal: true - -module Prelude - module Resources - class Verification - # @param client [Prelude::Client] - def initialize(client:) - @client = client - end - - # Create a new verification for a specific phone number. If another non-expired - # verification exists (the request is performed within the verification window), - # this endpoint will perform a retry instead. - # - # @param params [Hash{Symbol => Object}] Attributes to send in this request. - # @option params [Target] :target The target. Currently this can only be an E.164 formatted phone number. - # @option params [Metadata, nil] :metadata The metadata for this verification. This object will be returned with every - # response or webhook sent that refers to this verification. - # @option params [Options, nil] :options Verification options - # @option params [Signals, nil] :signals The signals used for anti-fraud. - # - # @param opts [Hash{Symbol => Object}, Prelude::RequestOptions] Options to specify HTTP behaviour for this request. - # - # @return [Prelude::Models::VerificationCreateResponse] - def create(params = {}, opts = {}) - req = { - method: :post, - path: "/v2/verification", - body: params, - headers: {"Content-Type" => "application/json"}, - model: Prelude::Models::VerificationCreateResponse - } - @client.request(req, opts) - end - - # Check the validity of a verification code. - # - # @param params [Hash{Symbol => Object}] Attributes to send in this request. - # @option params [String] :code The OTP code to validate. - # @option params [Target] :target The target. Currently this can only be an E.164 formatted phone number. - # - # @param opts [Hash{Symbol => Object}, Prelude::RequestOptions] Options to specify HTTP behaviour for this request. - # - # @return [Prelude::Models::VerificationCheckResponse] - def check(params = {}, opts = {}) - req = { - method: :post, - path: "/v2/verification/check", - body: params, - headers: {"Content-Type" => "application/json"}, - model: Prelude::Models::VerificationCheckResponse - } - @client.request(req, opts) - end - end - end -end diff --git a/lib/prelude/resources/watch.rb b/lib/prelude/resources/watch.rb deleted file mode 100644 index 28350135..00000000 --- a/lib/prelude/resources/watch.rb +++ /dev/null @@ -1,57 +0,0 @@ -# frozen_string_literal: true - -module Prelude - module Resources - class Watch - # @param client [Prelude::Client] - def initialize(client:) - @client = client - end - - # Once the user with a trustworthy phone number demonstrates authentic behavior, - # call this endpoint to report their authenticity to our systems. - # - # @param params [Hash{Symbol => Object}] Attributes to send in this request. - # @option params [Feedback] :feedback You should send a feedback event back to Watch API when your user demonstrates - # authentic behavior. - # @option params [Target] :target The target. Currently this can only be an E.164 formatted phone number. - # - # @param opts [Hash{Symbol => Object}, Prelude::RequestOptions] Options to specify HTTP behaviour for this request. - # - # @return [Prelude::Models::WatchFeedBackResponse] - def feed_back(params = {}, opts = {}) - req = { - method: :post, - path: "/v2/watch/feedback", - body: params, - headers: {"Content-Type" => "application/json"}, - model: Prelude::Models::WatchFeedBackResponse - } - @client.request(req, opts) - end - - # Identify trustworthy phone numbers to mitigate fake traffic or traffic involved - # in fraud and international revenue share fraud (IRSF) patterns. This endpoint - # must be implemented in conjunction with the `watch/feedback` endpoint. - # - # @param params [Hash{Symbol => Object}] Attributes to send in this request. - # @option params [Target] :target The target. Currently this can only be an E.164 formatted phone number. - # @option params [Signals, nil] :signals It is highly recommended that you provide the signals to increase prediction - # performance. - # - # @param opts [Hash{Symbol => Object}, Prelude::RequestOptions] Options to specify HTTP behaviour for this request. - # - # @return [Prelude::Models::WatchPredictResponse] - def predict(params = {}, opts = {}) - req = { - method: :post, - path: "/v2/watch/predict", - body: params, - headers: {"Content-Type" => "application/json"}, - model: Prelude::Models::WatchPredictResponse - } - @client.request(req, opts) - end - end - end -end diff --git a/lib/prelude/util.rb b/lib/prelude/util.rb deleted file mode 100644 index 613592cd..00000000 --- a/lib/prelude/util.rb +++ /dev/null @@ -1,201 +0,0 @@ -# frozen_string_literal: true - -module Prelude - # @!visibility private - class Util - # Use this to indicate that a value should be explicitly removed from a data structure - # when using `Prelude::Util.deep_merge`. - # E.g. merging `{a: 1}` and `{a: OMIT}` should produce `{}`, where merging `{a: 1}` and - # `{}` would produce `{a: 1}`. - OMIT = Object.new.freeze - - # Recursively merge one hash with another. - # If the values at a given key are not both hashes, just take the new value. - # @param left [Hash, Array, Symbol, String, Integer, Float, nil, Object] - # @param right [Hash, Array, Symbol, String, Integer, Float, nil, Object] - # @param concat [true, false] whether to merge sequences by concatenation - # - # @return [Object] - def self.deep_merge(left, right, concat: false) - right_cleaned = - case right - in Hash - right.reject { |_, value| value == OMIT } - else - right - end - - case [left, right_cleaned, concat] - in [Hash, Hash, _] - left - .reject { |key, _| right[key] == OMIT } - .merge(right_cleaned) do |_, old_val, new_val| - deep_merge(old_val, new_val, concat: concat) - end - in [Array, Array, true] - left.concat(right_cleaned) - else - right_cleaned - end - end - - # @param exceptions [Array] - # @param blk [Proc] - # - # @return [Object, nil] - def self.suppress(*exceptions, &blk) - blk.call - rescue *exceptions - nil - end - - # @param data [Hash, Array, Object] - # @param pick [Symbol, Integer, Array, nil] - # - # @return [Object, nil] - def self.dig(data, pick) - case [data, pick] - in [_, nil] - data - in [Hash, Symbol] | [Array, Integer] - data[pick] - in [Hash | Array, Array] - data.dig(*pick) - end - end - - # @param input [String, Numeric, Boolean, nil] - # - # @return [Integer, String, nil] - def self.coerce_integer(input) - case input - in true - 1 - in false - 0 - else - Integer(input, exception: false) || input - end - end - - # @param input [String, Numeric, Boolean, nil] - # - # @return [Float, String, nil] - def self.coerce_float(input) - case input - in true - 1.0 - in false - 0.0 - else - Float(input, exception: false) || input - end - end - - # @param input [String, Numeric, Boolean, nil] - # - # @return [Boolean, String, Numeric, nil] - def self.coerce_boolean(input) - case input.is_a?(String) ? input.downcase : input - in Numeric - !input.zero? - in "true" - true - in "false" - false - else - input - end - end - - # @param input [String, Numeric, Boolean, nil] - # - # @raise [ArgumentError] - # @return [Boolean, nil] - def self.coerce_boolean!(input) - case (coerced = coerce_boolean(input)) - in true | false | nil - coerced - else - raise ArgumentError, "Unable to coerce #{input.inspect} into boolean value" - end - end - - # @param url [URI::Generic, String] - - # - # @return [Hash{Symbol => Object}] - def self.parse_uri(url) - uri = - case url - in URI::Generic - url - in String - URI.parse(url) - end - { - scheme: uri.scheme, - host: uri.host, - port: uri.port, - path: uri.path, - query: CGI.parse(uri.query || "") - } - end - - # @param parsed [Hash{Symbol => String}] - - # @option parsed [String] :scheme - # @option parsed [String] :host - # @option parsed [Integer] :port - # @option parsed [String] :path - # @option parsed [Hash{String => Array}] :query - # - # @param absolute [Boolean] - # - # @return [URI::Generic] - def self.unparse_uri(parsed, absolute: true) - scheme, host, port = parsed.fetch_values(:scheme, :host, :port) - path, query = parsed.fetch_values(:path, :query) - uri = String.new - - if absolute - uri << "#{scheme}://#{host}" - case [scheme, port] - in [_, nil] | ["http", 80] | ["https", 443] - nil - else - uri << ":#{port}" - end - end - - qs = query.length.positive? ? "?#{URI.encode_www_form(query)}" : "" - uri << "#{path}#{qs}" - URI.parse(uri) - end - - # @param uri [URI::Generic] - # - # @return [String] - def self.uri_origin(uri) - if uri.respond_to?(:origin) - uri.origin - else - "#{uri.scheme}://#{uri.host}#{uri.port == uri.default_port ? '' : ":#{uri.port}"}" - end - end - - # @param path [String] - # - # @return [String] - def self.normalize_path(path) - path.gsub(%r{/+}, "/") - end - - # @param headers [Array String, Integer, nil}>] - # - # @return [Hash{String => String, nil}] - def self.normalized_headers(*headers) - {}.merge(*headers.compact).to_h do |key, val| - [key.downcase, val&.to_s&.strip] - end - end - end -end diff --git a/lib/prelude/version.rb b/lib/prelude/version.rb deleted file mode 100644 index 81bcdba8..00000000 --- a/lib/prelude/version.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -module Prelude - VERSION = "0.1.0-alpha.1" -end diff --git a/lib/prelude_sdk.rb b/lib/prelude_sdk.rb new file mode 100644 index 00000000..d75731c7 --- /dev/null +++ b/lib/prelude_sdk.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +# Standard libraries. +# rubocop:disable Lint/RedundantRequireStatement +require "English" +require "cgi" +require "date" +require "erb" +require "etc" +require "json" +require "net/http" +require "pathname" +require "rbconfig" +require "securerandom" +require "set" +require "stringio" +require "time" +require "uri" +# rubocop:enable Lint/RedundantRequireStatement + +# We already ship the preferred sorbet manifests in the package itself. +# `tapioca` currently does not offer us a way to opt out of unnecessary compilation. +if Object.const_defined?(:Tapioca) && + caller.chain([$PROGRAM_NAME]).chain(ARGV).any?(/tapioca/) && + ARGV.none?(/dsl/) + return +end + +# Gems. +require "connection_pool" + +# Package files. +require_relative "prelude_sdk/version" +require_relative "prelude_sdk/internal/util" +require_relative "prelude_sdk/internal/type/converter" +require_relative "prelude_sdk/internal/type/unknown" +require_relative "prelude_sdk/internal/type/boolean" +require_relative "prelude_sdk/internal/type/file_input" +require_relative "prelude_sdk/internal/type/enum" +require_relative "prelude_sdk/internal/type/union" +require_relative "prelude_sdk/internal/type/array_of" +require_relative "prelude_sdk/internal/type/hash_of" +require_relative "prelude_sdk/internal/type/base_model" +require_relative "prelude_sdk/internal/type/base_page" +require_relative "prelude_sdk/internal/type/request_parameters" +require_relative "prelude_sdk/internal" +require_relative "prelude_sdk/request_options" +require_relative "prelude_sdk/file_part" +require_relative "prelude_sdk/errors" +require_relative "prelude_sdk/internal/transport/base_client" +require_relative "prelude_sdk/internal/transport/pooled_net_requester" +require_relative "prelude_sdk/client" +require_relative "prelude_sdk/models/lookup_lookup_params" +require_relative "prelude_sdk/models/lookup_lookup_response" +require_relative "prelude_sdk/models/transactional_send_params" +require_relative "prelude_sdk/models/transactional_send_response" +require_relative "prelude_sdk/models/verification_check_params" +require_relative "prelude_sdk/models/verification_check_response" +require_relative "prelude_sdk/models/verification_create_params" +require_relative "prelude_sdk/models/verification_create_response" +require_relative "prelude_sdk/models/watch_predict_params" +require_relative "prelude_sdk/models/watch_predict_response" +require_relative "prelude_sdk/models/watch_send_events_params" +require_relative "prelude_sdk/models/watch_send_events_response" +require_relative "prelude_sdk/models/watch_send_feedbacks_params" +require_relative "prelude_sdk/models/watch_send_feedbacks_response" +require_relative "prelude_sdk/models" +require_relative "prelude_sdk/resources/lookup" +require_relative "prelude_sdk/resources/transactional" +require_relative "prelude_sdk/resources/verification" +require_relative "prelude_sdk/resources/watch" diff --git a/lib/prelude_sdk/client.rb b/lib/prelude_sdk/client.rb new file mode 100644 index 00000000..d476593f --- /dev/null +++ b/lib/prelude_sdk/client.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module PreludeSDK + class Client < PreludeSDK::Internal::Transport::BaseClient + # Default max number of retries to attempt after a failed retryable request. + DEFAULT_MAX_RETRIES = 2 + + # Default per-request timeout. + DEFAULT_TIMEOUT_IN_SECONDS = 60.0 + + # Default initial retry delay in seconds. + # Overall delay is calculated using exponential backoff + jitter. + DEFAULT_INITIAL_RETRY_DELAY = 0.5 + + # Default max retry delay in seconds. + DEFAULT_MAX_RETRY_DELAY = 8.0 + + # Bearer token for authorizing API requests. + # @return [String] + attr_reader :api_token + + # @return [PreludeSDK::Resources::Lookup] + attr_reader :lookup + + # @return [PreludeSDK::Resources::Transactional] + attr_reader :transactional + + # @return [PreludeSDK::Resources::Verification] + attr_reader :verification + + # @return [PreludeSDK::Resources::Watch] + attr_reader :watch + + # @api private + # + # @return [Hash{String=>String}] + private def auth_headers + return {} if @api_token.nil? + + {"authorization" => "Bearer #{@api_token}"} + end + + # Creates and returns a new client for interacting with the API. + # + # @param api_token [String, nil] Bearer token for authorizing API requests. Defaults to `ENV["API_TOKEN"]` + # + # @param base_url [String, nil] Override the default base URL for the API, e.g., + # `"https://api.example.com/v2/"`. Defaults to `ENV["PRELUDE_BASE_URL"]` + # + # @param max_retries [Integer] Max number of retries to attempt after a failed retryable request. + # + # @param timeout [Float] + # + # @param initial_retry_delay [Float] + # + # @param max_retry_delay [Float] + def initialize( + api_token: ENV["API_TOKEN"], + base_url: ENV["PRELUDE_BASE_URL"], + max_retries: self.class::DEFAULT_MAX_RETRIES, + timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS, + initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY, + max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY + ) + base_url ||= "https://api.prelude.dev" + + if api_token.nil? + raise ArgumentError.new("api_token is required, and can be set via environ: \"API_TOKEN\"") + end + + @api_token = api_token.to_s + + super( + base_url: base_url, + timeout: timeout, + max_retries: max_retries, + initial_retry_delay: initial_retry_delay, + max_retry_delay: max_retry_delay + ) + + @lookup = PreludeSDK::Resources::Lookup.new(client: self) + @transactional = PreludeSDK::Resources::Transactional.new(client: self) + @verification = PreludeSDK::Resources::Verification.new(client: self) + @watch = PreludeSDK::Resources::Watch.new(client: self) + end + end +end diff --git a/lib/prelude_sdk/errors.rb b/lib/prelude_sdk/errors.rb new file mode 100644 index 00000000..3e691645 --- /dev/null +++ b/lib/prelude_sdk/errors.rb @@ -0,0 +1,214 @@ +# frozen_string_literal: true + +module PreludeSDK + module Errors + class Error < StandardError + # @!attribute cause + # + # @return [StandardError, nil] + end + + class ConversionError < PreludeSDK::Errors::Error + # @return [StandardError, nil] + def cause = @cause.nil? ? super : @cause + + # @api private + # + # @param on [Class] + # @param method [Symbol] + # @param target [Object] + # @param value [Object] + # @param cause [StandardError, nil] + def initialize(on:, method:, target:, value:, cause: nil) + cls = on.name.split("::").last + + message = [ + "Failed to parse #{cls}.#{method} from #{value.class} to #{target.inspect}.", + "To get the unparsed API response, use #{cls}[#{method.inspect}].", + cause && "Cause: #{cause.message}" + ].filter(&:itself).join(" ") + + @cause = cause + super(message) + end + end + + class APIError < PreludeSDK::Errors::Error + # @return [URI::Generic] + attr_accessor :url + + # @return [Integer, nil] + attr_accessor :status + + # @return [Object, nil] + attr_accessor :body + + # @api private + # + # @param url [URI::Generic] + # @param status [Integer, nil] + # @param body [Object, nil] + # @param request [nil] + # @param response [nil] + # @param message [String, nil] + def initialize(url:, status: nil, body: nil, request: nil, response: nil, message: nil) + @url = url + @status = status + @body = body + @request = request + @response = response + super(message) + end + end + + class APIConnectionError < PreludeSDK::Errors::APIError + # @!attribute status + # + # @return [nil] + + # @!attribute body + # + # @return [nil] + + # @api private + # + # @param url [URI::Generic] + # @param status [nil] + # @param body [nil] + # @param request [nil] + # @param response [nil] + # @param message [String, nil] + def initialize( + url:, + status: nil, + body: nil, + request: nil, + response: nil, + message: "Connection error." + ) + super + end + end + + class APITimeoutError < PreludeSDK::Errors::APIConnectionError + # @api private + # + # @param url [URI::Generic] + # @param status [nil] + # @param body [nil] + # @param request [nil] + # @param response [nil] + # @param message [String, nil] + def initialize( + url:, + status: nil, + body: nil, + request: nil, + response: nil, + message: "Request timed out." + ) + super + end + end + + class APIStatusError < PreludeSDK::Errors::APIError + # @api private + # + # @param url [URI::Generic] + # @param status [Integer] + # @param body [Object, nil] + # @param request [nil] + # @param response [nil] + # @param message [String, nil] + # + # @return [self] + def self.for(url:, status:, body:, request:, response:, message: nil) + kwargs = { + url: url, + status: status, + body: body, + request: request, + response: response, + message: message + } + + case status + in 400 + PreludeSDK::Errors::BadRequestError.new(**kwargs) + in 401 + PreludeSDK::Errors::AuthenticationError.new(**kwargs) + in 403 + PreludeSDK::Errors::PermissionDeniedError.new(**kwargs) + in 404 + PreludeSDK::Errors::NotFoundError.new(**kwargs) + in 409 + PreludeSDK::Errors::ConflictError.new(**kwargs) + in 422 + PreludeSDK::Errors::UnprocessableEntityError.new(**kwargs) + in 429 + PreludeSDK::Errors::RateLimitError.new(**kwargs) + in (500..) + PreludeSDK::Errors::InternalServerError.new(**kwargs) + else + PreludeSDK::Errors::APIStatusError.new(**kwargs) + end + end + + # @!parse + # # @return [Integer] + # attr_accessor :status + + # @api private + # + # @param url [URI::Generic] + # @param status [Integer] + # @param body [Object, nil] + # @param request [nil] + # @param response [nil] + # @param message [String, nil] + def initialize(url:, status:, body:, request:, response:, message: nil) + message ||= {url: url.to_s, status: status, body: body} + super( + url: url, + status: status, + body: body, + request: request, + response: response, + message: message&.to_s + ) + end + end + + class BadRequestError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 400 + end + + class AuthenticationError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 401 + end + + class PermissionDeniedError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 403 + end + + class NotFoundError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 404 + end + + class ConflictError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 409 + end + + class UnprocessableEntityError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 422 + end + + class RateLimitError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 429 + end + + class InternalServerError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = (500..) + end + end +end diff --git a/lib/prelude_sdk/file_part.rb b/lib/prelude_sdk/file_part.rb new file mode 100644 index 00000000..08f98519 --- /dev/null +++ b/lib/prelude_sdk/file_part.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module PreludeSDK + class FilePart + # @return [Pathname, StringIO, IO, String] + attr_reader :content + + # @return [String, nil] + attr_reader :content_type + + # @return [String, nil] + attr_reader :filename + + # @api private + # + # @return [String] + private def read + case content + in Pathname + content.read(binmode: true) + in StringIO + content.string + in IO + content.read + in String + content + end + end + + # @param a [Object] + # + # @return [String] + def to_json(*a) = read.to_json(*a) + + # @param a [Object] + # + # @return [String] + def to_yaml(*a) = read.to_yaml(*a) + + # @param content [Pathname, StringIO, IO, String] + # @param filename [String, nil] + # @param content_type [String, nil] + def initialize(content, filename: nil, content_type: nil) + @content = content + @filename = + case content + in Pathname + filename.nil? ? content.basename.to_path : ::File.basename(filename) + else + filename.nil? ? nil : ::File.basename(filename) + end + @content_type = content_type + end + end +end diff --git a/lib/prelude_sdk/internal.rb b/lib/prelude_sdk/internal.rb new file mode 100644 index 00000000..e8a1be9e --- /dev/null +++ b/lib/prelude_sdk/internal.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + OMIT = + Object.new.tap do + _1.define_singleton_method(:inspect) { "#<#{PreludeSDK::Internal}::OMIT>" } + end + .freeze + + define_sorbet_constant!(:AnyHash) do + T.type_alias { T::Hash[Symbol, T.anything] } + end + define_sorbet_constant!(:FileInput) do + T.type_alias { T.any(Pathname, StringIO, IO, String, PreludeSDK::FilePart) } + end + end +end diff --git a/lib/prelude_sdk/internal/transport/base_client.rb b/lib/prelude_sdk/internal/transport/base_client.rb new file mode 100644 index 00000000..07e7c179 --- /dev/null +++ b/lib/prelude_sdk/internal/transport/base_client.rb @@ -0,0 +1,555 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Transport + # @api private + # + # @abstract + class BaseClient + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # from whatwg fetch spec + MAX_REDIRECTS = 20 + + # rubocop:disable Style/MutableConstant + PLATFORM_HEADERS = + { + "x-stainless-arch" => PreludeSDK::Internal::Util.arch, + "x-stainless-lang" => "ruby", + "x-stainless-os" => PreludeSDK::Internal::Util.os, + "x-stainless-package-version" => PreludeSDK::VERSION, + "x-stainless-runtime" => ::RUBY_ENGINE, + "x-stainless-runtime-version" => ::RUBY_ENGINE_VERSION + } + # rubocop:enable Style/MutableConstant + + class << self + # @api private + # + # @param req [Hash{Symbol=>Object}] + # + # @raise [ArgumentError] + def validate!(req) + keys = [:method, :path, :query, :headers, :body, :unwrap, :page, :stream, :model, :options] + case req + in Hash + req.each_key do |k| + unless keys.include?(k) + raise ArgumentError.new("Request `req` keys must be one of #{keys}, got #{k.inspect}") + end + end + else + raise ArgumentError.new("Request `req` must be a Hash or RequestOptions, got #{req.inspect}") + end + end + + # @api private + # + # @param status [Integer] + # @param headers [Hash{String=>String}, Net::HTTPHeader] + # + # @return [Boolean] + def should_retry?(status, headers:) + coerced = PreludeSDK::Internal::Util.coerce_boolean(headers["x-should-retry"]) + case [coerced, status] + in [true | false, _] + coerced + in [_, 408 | 409 | 429 | (500..)] + # retry on: + # 408: timeouts + # 409: locks + # 429: rate limits + # 500+: unknown errors + true + else + false + end + end + + # @api private + # + # @param request [Hash{Symbol=>Object}] . + # + # @option request [Symbol] :method + # + # @option request [URI::Generic] :url + # + # @option request [Hash{String=>String}] :headers + # + # @option request [Object] :body + # + # @option request [Integer] :max_retries + # + # @option request [Float] :timeout + # + # @param status [Integer] + # + # @param response_headers [Hash{String=>String}, Net::HTTPHeader] + # + # @return [Hash{Symbol=>Object}] + def follow_redirect(request, status:, response_headers:) + method, url, headers = request.fetch_values(:method, :url, :headers) + location = + Kernel.then do + URI.join(url, response_headers["location"]) + rescue ArgumentError + message = "Server responded with status #{status} but no valid location header." + raise PreludeSDK::Errors::APIConnectionError.new( + url: url, + response: response_headers, + message: message + ) + end + + request = {**request, url: location} + + case [url.scheme, location.scheme] + in ["https", "http"] + message = "Tried to redirect to a insecure URL" + raise PreludeSDK::Errors::APIConnectionError.new( + url: url, + response: response_headers, + message: message + ) + else + nil + end + + # from whatwg fetch spec + case [status, method] + in [301 | 302, :post] | [303, _] + drop = %w[content-encoding content-language content-length content-location content-type] + request = { + **request, + method: method == :head ? :head : :get, + headers: headers.except(*drop), + body: nil + } + else + end + + # from undici + if PreludeSDK::Internal::Util.uri_origin(url) != PreludeSDK::Internal::Util.uri_origin(location) + drop = %w[authorization cookie host proxy-authorization] + request = {**request, headers: request.fetch(:headers).except(*drop)} + end + + request + end + + # @api private + # + # @param status [Integer, PreludeSDK::Errors::APIConnectionError] + # @param stream [Enumerable, nil] + def reap_connection!(status, stream:) + case status + in (..199) | (300..499) + stream&.each { next } + in PreludeSDK::Errors::APIConnectionError | (500..) + PreludeSDK::Internal::Util.close_fused!(stream) + else + end + end + end + + # @return [URI::Generic] + attr_reader :base_url + + # @return [Float] + attr_reader :timeout + + # @return [Integer] + attr_reader :max_retries + + # @return [Float] + attr_reader :initial_retry_delay + + # @return [Float] + attr_reader :max_retry_delay + + # @return [Hash{String=>String}] + attr_reader :headers + + # @return [String, nil] + attr_reader :idempotency_header + + # @api private + # @return [PreludeSDK::Internal::Transport::PooledNetRequester] + attr_reader :requester + + # @api private + # + # @param base_url [String] + # @param timeout [Float] + # @param max_retries [Integer] + # @param initial_retry_delay [Float] + # @param max_retry_delay [Float] + # @param headers [Hash{String=>String, Integer, Array, nil}] + # @param idempotency_header [String, nil] + def initialize( + base_url:, + timeout: 0.0, + max_retries: 0, + initial_retry_delay: 0.0, + max_retry_delay: 0.0, + headers: {}, + idempotency_header: nil + ) + @requester = PreludeSDK::Internal::Transport::PooledNetRequester.new + @headers = PreludeSDK::Internal::Util.normalized_headers( + self.class::PLATFORM_HEADERS, + { + "accept" => "application/json", + "content-type" => "application/json" + }, + headers + ) + @base_url_components = PreludeSDK::Internal::Util.parse_uri(base_url) + @base_url = PreludeSDK::Internal::Util.unparse_uri(@base_url_components) + @idempotency_header = idempotency_header&.to_s&.downcase + @timeout = timeout + @max_retries = max_retries + @initial_retry_delay = initial_retry_delay + @max_retry_delay = max_retry_delay + end + + # @api private + # + # @return [Hash{String=>String}] + private def auth_headers = {} + + # @api private + # + # @return [String] + private def generate_idempotency_key = "stainless-ruby-retry-#{SecureRandom.uuid}" + + # @api private + # + # @param req [Hash{Symbol=>Object}] . + # + # @option req [Symbol] :method + # + # @option req [String, Array] :path + # + # @option req [Hash{String=>Array, String, nil}, nil] :query + # + # @option req [Hash{String=>String, Integer, Array, nil}, nil] :headers + # + # @option req [Object, nil] :body + # + # @option req [Symbol, Integer, Array, Proc, nil] :unwrap + # + # @option req [Class, nil] :page + # + # @option req [Class, nil] :stream + # + # @option req [PreludeSDK::Internal::Type::Converter, Class, nil] :model + # + # @param opts [Hash{Symbol=>Object}] . + # + # @option opts [String, nil] :idempotency_key + # + # @option opts [Hash{String=>Array, String, nil}, nil] :extra_query + # + # @option opts [Hash{String=>String, nil}, nil] :extra_headers + # + # @option opts [Object, nil] :extra_body + # + # @option opts [Integer, nil] :max_retries + # + # @option opts [Float, nil] :timeout + # + # @return [Hash{Symbol=>Object}] + private def build_request(req, opts) + method, uninterpolated_path = req.fetch_values(:method, :path) + + path = PreludeSDK::Internal::Util.interpolate_path(uninterpolated_path) + + query = PreludeSDK::Internal::Util.deep_merge(req[:query].to_h, opts[:extra_query].to_h) + + headers = PreludeSDK::Internal::Util.normalized_headers( + @headers, + auth_headers, + req[:headers].to_h, + opts[:extra_headers].to_h + ) + + if @idempotency_header && + !headers.key?(@idempotency_header) && + (!Net::HTTP::IDEMPOTENT_METHODS_.include?(method.to_s.upcase) || opts.key?(:idempotency_key)) + headers[@idempotency_header] = opts.fetch(:idempotency_key) { generate_idempotency_key } + end + + unless headers.key?("x-stainless-retry-count") + headers["x-stainless-retry-count"] = "0" + end + + timeout = opts.fetch(:timeout, @timeout).to_f.clamp(0..) + unless headers.key?("x-stainless-timeout") || timeout.zero? + headers["x-stainless-timeout"] = timeout.to_s + end + + headers.reject! { |_, v| v.to_s.empty? } + + body = + case method + in :get | :head | :options | :trace + nil + else + PreludeSDK::Internal::Util.deep_merge(*[req[:body], opts[:extra_body]].compact) + end + + url = PreludeSDK::Internal::Util.join_parsed_uri( + @base_url_components, + {**req, path: path, query: query} + ) + headers, encoded = PreludeSDK::Internal::Util.encode_content(headers, body) + { + method: method, + url: url, + headers: headers, + body: encoded, + max_retries: opts.fetch(:max_retries, @max_retries), + timeout: timeout + } + end + + # @api private + # + # @param headers [Hash{String=>String}] + # @param retry_count [Integer] + # + # @return [Float] + private def retry_delay(headers, retry_count:) + # Non-standard extension + span = Float(headers["retry-after-ms"], exception: false)&.then { _1 / 1000 } + return span if span + + retry_header = headers["retry-after"] + return span if (span = Float(retry_header, exception: false)) + + span = retry_header&.then do + Time.httpdate(_1) - Time.now + rescue ArgumentError + nil + end + return span if span + + scale = retry_count**2 + jitter = 1 - (0.25 * rand) + (@initial_retry_delay * scale * jitter).clamp(0, @max_retry_delay) + end + + # @api private + # + # @param request [Hash{Symbol=>Object}] . + # + # @option request [Symbol] :method + # + # @option request [URI::Generic] :url + # + # @option request [Hash{String=>String}] :headers + # + # @option request [Object] :body + # + # @option request [Integer] :max_retries + # + # @option request [Float] :timeout + # + # @param redirect_count [Integer] + # + # @param retry_count [Integer] + # + # @param send_retry_header [Boolean] + # + # @raise [PreludeSDK::Errors::APIError] + # @return [Array(Integer, Net::HTTPResponse, Enumerable)] + private def send_request(request, redirect_count:, retry_count:, send_retry_header:) + url, headers, max_retries, timeout = request.fetch_values(:url, :headers, :max_retries, :timeout) + input = {**request.except(:timeout), deadline: PreludeSDK::Internal::Util.monotonic_secs + timeout} + + if send_retry_header + headers["x-stainless-retry-count"] = retry_count.to_s + end + + begin + status, response, stream = @requester.execute(input) + rescue PreludeSDK::Errors::APIConnectionError => e + status = e + end + + case status + in ..299 + [status, response, stream] + in 300..399 if redirect_count >= self.class::MAX_REDIRECTS + self.class.reap_connection!(status, stream: stream) + + message = "Failed to complete the request within #{self.class::MAX_REDIRECTS} redirects." + raise PreludeSDK::Errors::APIConnectionError.new(url: url, response: response, message: message) + in 300..399 + self.class.reap_connection!(status, stream: stream) + + request = self.class.follow_redirect(request, status: status, response_headers: response) + send_request( + request, + redirect_count: redirect_count + 1, + retry_count: retry_count, + send_retry_header: send_retry_header + ) + in PreludeSDK::Errors::APIConnectionError if retry_count >= max_retries + raise status + in (400..) if retry_count >= max_retries || !self.class.should_retry?(status, headers: response) + decoded = Kernel.then do + PreludeSDK::Internal::Util.decode_content(response, stream: stream, suppress_error: true) + ensure + self.class.reap_connection!(status, stream: stream) + end + + raise PreludeSDK::Errors::APIStatusError.for( + url: url, + status: status, + body: decoded, + request: nil, + response: response + ) + in (400..) | PreludeSDK::Errors::APIConnectionError + self.class.reap_connection!(status, stream: stream) + + delay = retry_delay(response || {}, retry_count: retry_count) + sleep(delay) + + send_request( + request, + redirect_count: redirect_count, + retry_count: retry_count + 1, + send_retry_header: send_retry_header + ) + end + end + + # Execute the request specified by `req`. This is the method that all resource + # methods call into. + # + # @overload request(method, path, query: {}, headers: {}, body: nil, unwrap: nil, page: nil, stream: nil, model: PreludeSDK::Internal::Type::Unknown, options: {}) + # + # @param method [Symbol] + # + # @param path [String, Array] + # + # @param query [Hash{String=>Array, String, nil}, nil] + # + # @param headers [Hash{String=>String, Integer, Array, nil}, nil] + # + # @param body [Object, nil] + # + # @param unwrap [Symbol, Integer, Array, Proc, nil] + # + # @param page [Class, nil] + # + # @param stream [Class, nil] + # + # @param model [PreludeSDK::Internal::Type::Converter, Class, nil] + # + # @param options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}, nil] . + # + # @option options [String, nil] :idempotency_key + # + # @option options [Hash{String=>Array, String, nil}, nil] :extra_query + # + # @option options [Hash{String=>String, nil}, nil] :extra_headers + # + # @option options [Object, nil] :extra_body + # + # @option options [Integer, nil] :max_retries + # + # @option options [Float, nil] :timeout + # + # @raise [PreludeSDK::Errors::APIError] + # @return [Object] + def request(req) + self.class.validate!(req) + model = req.fetch(:model) { PreludeSDK::Internal::Type::Unknown } + opts = req[:options].to_h + PreludeSDK::RequestOptions.validate!(opts) + request = build_request(req.except(:options), opts) + url = request.fetch(:url) + + # Don't send the current retry count in the headers if the caller modified the header defaults. + send_retry_header = request.fetch(:headers)["x-stainless-retry-count"] == "0" + status, response, stream = send_request( + request, + redirect_count: 0, + retry_count: 0, + send_retry_header: send_retry_header + ) + + decoded = PreludeSDK::Internal::Util.decode_content(response, stream: stream) + case req + in {stream: Class => st} + st.new(model: model, url: url, status: status, response: response, stream: decoded) + in {page: Class => page} + page.new(client: self, req: req, headers: response, page_data: decoded) + else + unwrapped = PreludeSDK::Internal::Util.dig(decoded, req[:unwrap]) + PreludeSDK::Internal::Type::Converter.coerce(model, unwrapped) + end + end + + # @api private + # + # @return [String] + def inspect + # rubocop:disable Layout/LineLength + "#<#{self.class.name}:0x#{object_id.to_s(16)} base_url=#{@base_url} max_retries=#{@max_retries} timeout=#{@timeout}>" + # rubocop:enable Layout/LineLength + end + + define_sorbet_constant!(:RequestComponents) do + T.type_alias do + { + method: Symbol, + path: T.any(String, T::Array[String]), + query: T.nilable(T::Hash[String, T.nilable(T.any(T::Array[String], String))]), + headers: T.nilable( + T::Hash[String, + T.nilable( + T.any( + String, + Integer, + T::Array[T.nilable(T.any(String, Integer))] + ) + )] + ), + body: T.nilable(T.anything), + unwrap: T.nilable( + T.any( + Symbol, + Integer, + T::Array[T.any(Symbol, Integer)], + T.proc.params(arg0: T.anything).returns(T.anything) + ) + ), + page: T.nilable(T::Class[PreludeSDK::Internal::Type::BasePage[PreludeSDK::Internal::Type::BaseModel]]), + stream: T.nilable(T::Class[T.anything]), + model: T.nilable(PreludeSDK::Internal::Type::Converter::Input), + options: T.nilable(PreludeSDK::RequestOptions::OrHash) + } + end + end + define_sorbet_constant!(:RequestInput) do + T.type_alias do + { + method: Symbol, + url: URI::Generic, + headers: T::Hash[String, String], + body: T.anything, + max_retries: Integer, + timeout: Float + } + end + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/transport/pooled_net_requester.rb b/lib/prelude_sdk/internal/transport/pooled_net_requester.rb new file mode 100644 index 00000000..9e96ae81 --- /dev/null +++ b/lib/prelude_sdk/internal/transport/pooled_net_requester.rb @@ -0,0 +1,209 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Transport + # @api private + class PooledNetRequester + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # from the golang stdlib + # https://github.com/golang/go/blob/c8eced8580028328fde7c03cbfcb720ce15b2358/src/net/http/transport.go#L49 + KEEP_ALIVE_TIMEOUT = 30 + + DEFAULT_MAX_CONNECTIONS = [Etc.nprocessors, 99].max + + class << self + # @api private + # + # @param url [URI::Generic] + # + # @return [Net::HTTP] + def connect(url) + port = + case [url.port, url.scheme] + in [Integer, _] + url.port + in [nil, "http" | "ws"] + Net::HTTP.http_default_port + in [nil, "https" | "wss"] + Net::HTTP.https_default_port + end + + Net::HTTP.new(url.host, port).tap do + _1.use_ssl = %w[https wss].include?(url.scheme) + _1.max_retries = 0 + end + end + + # @api private + # + # @param conn [Net::HTTP] + # @param deadline [Float] + def calibrate_socket_timeout(conn, deadline) + timeout = deadline - PreludeSDK::Internal::Util.monotonic_secs + conn.open_timeout = conn.read_timeout = conn.write_timeout = conn.continue_timeout = timeout + end + + # @api private + # + # @param request [Hash{Symbol=>Object}] . + # + # @option request [Symbol] :method + # + # @option request [URI::Generic] :url + # + # @option request [Hash{String=>String}] :headers + # + # @param blk [Proc] + # + # @yieldparam [String] + # @return [Array(Net::HTTPGenericRequest, Proc)] + def build_request(request, &blk) + method, url, headers, body = request.fetch_values(:method, :url, :headers, :body) + req = Net::HTTPGenericRequest.new( + method.to_s.upcase, + !body.nil?, + method != :head, + URI(url.to_s) # ensure we construct a URI class of the right scheme + ) + + headers.each { req[_1] = _2 } + + case body + in nil + nil + in String + req["content-length"] ||= body.bytesize.to_s unless req["transfer-encoding"] + req.body_stream = PreludeSDK::Internal::Util::ReadIOAdapter.new(body, &blk) + in StringIO + req["content-length"] ||= body.size.to_s unless req["transfer-encoding"] + req.body_stream = PreludeSDK::Internal::Util::ReadIOAdapter.new(body, &blk) + in Pathname | IO | Enumerator + req["transfer-encoding"] ||= "chunked" unless req["content-length"] + req.body_stream = PreludeSDK::Internal::Util::ReadIOAdapter.new(body, &blk) + end + + [req, req.body_stream&.method(:close)] + end + end + + # @api private + # + # @param url [URI::Generic] + # @param deadline [Float] + # @param blk [Proc] + # + # @raise [Timeout::Error] + # @yieldparam [Net::HTTP] + private def with_pool(url, deadline:, &blk) + origin = PreludeSDK::Internal::Util.uri_origin(url) + timeout = deadline - PreludeSDK::Internal::Util.monotonic_secs + pool = + @mutex.synchronize do + @pools[origin] ||= ConnectionPool.new(size: @size) do + self.class.connect(url) + end + end + + pool.with(timeout: timeout, &blk) + end + + # @api private + # + # @param request [Hash{Symbol=>Object}] . + # + # @option request [Symbol] :method + # + # @option request [URI::Generic] :url + # + # @option request [Hash{String=>String}] :headers + # + # @option request [Object] :body + # + # @option request [Float] :deadline + # + # @return [Array(Integer, Net::HTTPResponse, Enumerable)] + def execute(request) + url, deadline = request.fetch_values(:url, :deadline) + + req = nil + eof = false + finished = false + closing = nil + + # rubocop:disable Metrics/BlockLength + enum = Enumerator.new do |y| + with_pool(url, deadline: deadline) do |conn| + next if finished + + req, closing = self.class.build_request(request) do + self.class.calibrate_socket_timeout(conn, deadline) + end + + self.class.calibrate_socket_timeout(conn, deadline) + unless conn.started? + conn.keep_alive_timeout = self.class::KEEP_ALIVE_TIMEOUT + conn.start + end + + self.class.calibrate_socket_timeout(conn, deadline) + conn.request(req) do |rsp| + y << [conn, req, rsp] + break if finished + + rsp.read_body do |bytes| + y << bytes.force_encoding(Encoding::BINARY) + break if finished + + self.class.calibrate_socket_timeout(conn, deadline) + end + eof = true + end + end + rescue Timeout::Error + raise PreludeSDK::Errors::APITimeoutError.new(url: url, request: req) + rescue StandardError + raise PreludeSDK::Errors::APIConnectionError.new(url: url, request: req) + end + # rubocop:enable Metrics/BlockLength + + conn, _, response = enum.next + body = PreludeSDK::Internal::Util.fused_enum(enum, external: true) do + finished = true + tap do + enum.next + rescue StopIteration + nil + end + ensure + conn.finish if !eof && conn&.started? + closing&.call + end + [Integer(response.code), response, body] + end + + # @api private + # + # @param size [Integer] + def initialize(size: self.class::DEFAULT_MAX_CONNECTIONS) + @mutex = Mutex.new + @size = size + @pools = {} + end + + define_sorbet_constant!(:Request) do + T.type_alias do + { + method: Symbol, + url: URI::Generic, + headers: T::Hash[String, String], + body: T.anything, + deadline: Float + } + end + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/array_of.rb b/lib/prelude_sdk/internal/type/array_of.rb new file mode 100644 index 00000000..5326b75a --- /dev/null +++ b/lib/prelude_sdk/internal/type/array_of.rb @@ -0,0 +1,167 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + # + # @abstract + # + # @generic Elem + # + # Array of items of a given type. + class ArrayOf + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + private_class_method :new + + # @overload [](type_info, spec = {}) + # + # @param type_info [Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] + # + # @param spec [Hash{Symbol=>Object}] . + # + # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const + # + # @option spec [Proc] :enum + # + # @option spec [Proc] :union + # + # @option spec [Boolean] :"nil?" + # + # @return [self] + def self.[](...) = new(...) + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ===(other) = other.is_a?(Array) && other.all?(item_type) + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ==(other) + # rubocop:disable Layout/LineLength + other.is_a?(PreludeSDK::Internal::Type::ArrayOf) && other.nilable? == nilable? && other.item_type == item_type + # rubocop:enable Layout/LineLength + end + + # @api public + # + # @return [Integer] + def hash = [self.class, item_type].hash + + # @api private + # + # @param value [Array, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [Array, Object] + def coerce(value, state:) + exactness = state.fetch(:exactness) + + unless value.is_a?(Array) + exactness[:no] += 1 + state[:error] = TypeError.new("#{value.class} can't be coerced into #{Array}") + return value + end + + target = item_type + exactness[:yes] += 1 + value + .map do |item| + case [nilable?, item] + in [true, nil] + exactness[:yes] += 1 + nil + else + PreludeSDK::Internal::Type::Converter.coerce(target, item, state: state) + end + end + end + + # @api private + # + # @param value [Array, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Array, Object] + def dump(value, state:) + target = item_type + if value.is_a?(Array) + value.map do + PreludeSDK::Internal::Type::Converter.dump(target, _1, state: state) + end + else + super + end + end + + # @api private + # + # @return [Object] + def to_sorbet_type + T::Array[PreludeSDK::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(item_type)] + end + + # @api private + # + # @return [generic] + protected def item_type = @item_type_fn.call + + # @api private + # + # @return [Boolean] + protected def nilable? = @nilable + + # @api private + # + # @param type_info [Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] + # + # @param spec [Hash{Symbol=>Object}] . + # + # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const + # + # @option spec [Proc] :enum + # + # @option spec [Proc] :union + # + # @option spec [Boolean] :"nil?" + def initialize(type_info, spec = {}) + @item_type_fn = PreludeSDK::Internal::Type::Converter.type_info(type_info || spec) + @nilable = spec.fetch(:nil?, false) + end + + # @api private + # + # @param depth [Integer] + # + # @return [String] + def inspect(depth: 0) + items = PreludeSDK::Internal::Type::Converter.inspect(item_type, depth: depth.succ) + + "#{self.class}[#{[items, nilable? ? 'nil' : nil].compact.join(' | ')}]" + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/base_model.rb b/lib/prelude_sdk/internal/type/base_model.rb new file mode 100644 index 00000000..3f71a629 --- /dev/null +++ b/lib/prelude_sdk/internal/type/base_model.rb @@ -0,0 +1,536 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @abstract + class BaseModel + extend PreludeSDK::Internal::Type::Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + class << self + # @api private + # + # Assumes superclass fields are totally defined before fields are accessed / + # defined on subclasses. + # + # @param child [Class] + def inherited(child) + super + child.known_fields.replace(known_fields.dup) + end + + # @api private + # + # @return [Hash{Symbol=>Hash{Symbol=>Object}}] + def known_fields = @known_fields ||= {} + + # @api private + # + # @return [Hash{Symbol=>Hash{Symbol=>Object}}] + def fields + known_fields.transform_values do |field| + {**field.except(:type_fn), type: field.fetch(:type_fn).call} + end + end + + # @api private + # + # @param name_sym [Symbol] + # + # @param required [Boolean] + # + # @param type_info [Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] + # + # @param spec [Hash{Symbol=>Object}] . + # + # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const + # + # @option spec [Proc] :enum + # + # @option spec [Proc] :union + # + # @option spec [Boolean] :"nil?" + private def add_field(name_sym, required:, type_info:, spec:) + type_fn, info = + case type_info + in Proc | PreludeSDK::Internal::Type::Converter | Class + [PreludeSDK::Internal::Type::Converter.type_info({**spec, union: type_info}), spec] + in Hash + [PreludeSDK::Internal::Type::Converter.type_info(type_info), type_info] + end + + setter = :"#{name_sym}=" + api_name = info.fetch(:api_name, name_sym) + nilable = info.fetch(:nil?, false) + const = if required && !nilable + info.fetch( + :const, + PreludeSDK::Internal::OMIT + ) + else + PreludeSDK::Internal::OMIT + end + + [name_sym, setter].each { undef_method(_1) } if known_fields.key?(name_sym) + + known_fields[name_sym] = + { + mode: @mode, + api_name: api_name, + required: required, + nilable: nilable, + const: const, + type_fn: type_fn + } + + define_method(setter) do |value| + target = type_fn.call + state = PreludeSDK::Internal::Type::Converter.new_coerce_state(translate_names: false) + coerced = PreludeSDK::Internal::Type::Converter.coerce(target, value, state: state) + status = @coerced.store(name_sym, state.fetch(:error) || true) + stored = + case [target, status] + in [PreludeSDK::Internal::Type::Converter | Symbol, true] + coerced + else + value + end + @data.store(name_sym, stored) + end + + # rubocop:disable Style/CaseEquality + # rubocop:disable Metrics/BlockLength + define_method(name_sym) do + target = type_fn.call + + case @coerced[name_sym] + in true | false if PreludeSDK::Internal::Type::Converter === target + @data.fetch(name_sym) + in ::StandardError => e + raise PreludeSDK::Errors::ConversionError.new( + on: self.class, + method: __method__, + target: target, + value: @data.fetch(name_sym), + cause: e + ) + else + Kernel.then do + value = @data.fetch(name_sym) { const == PreludeSDK::Internal::OMIT ? nil : const } + state = PreludeSDK::Internal::Type::Converter.new_coerce_state(translate_names: false) + if (nilable || !required) && value.nil? + nil + else + PreludeSDK::Internal::Type::Converter.coerce( + target, value, state: state + ) + end + rescue StandardError => e + raise PreludeSDK::Errors::ConversionError.new( + on: self.class, + method: __method__, + target: target, + value: value, + cause: e + ) + end + end + end + # rubocop:enable Metrics/BlockLength + # rubocop:enable Style/CaseEquality + end + + # @api private + # + # @param name_sym [Symbol] + # + # @param type_info [Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] + # + # @param spec [Hash{Symbol=>Object}] . + # + # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const + # + # @option spec [Proc] :enum + # + # @option spec [Proc] :union + # + # @option spec [Boolean] :"nil?" + def required(name_sym, type_info, spec = {}) + add_field(name_sym, required: true, type_info: type_info, spec: spec) + end + + # @api private + # + # @param name_sym [Symbol] + # + # @param type_info [Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] + # + # @param spec [Hash{Symbol=>Object}] . + # + # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const + # + # @option spec [Proc] :enum + # + # @option spec [Proc] :union + # + # @option spec [Boolean] :"nil?" + def optional(name_sym, type_info, spec = {}) + add_field(name_sym, required: false, type_info: type_info, spec: spec) + end + + # @api private + # + # `request_only` attributes not excluded from `.#coerce` when receiving responses + # even if well behaved servers should not send them + # + # @param blk [Proc] + private def request_only(&blk) + @mode = :dump + blk.call + ensure + @mode = nil + end + + # @api private + # + # `response_only` attributes are omitted from `.#dump` when making requests + # + # @param blk [Proc] + private def response_only(&blk) + @mode = :coerce + blk.call + ensure + @mode = nil + end + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ==(other) + other.is_a?(Class) && other <= PreludeSDK::Internal::Type::BaseModel && other.fields == fields + end + + # @api public + # + # @return [Integer] + def hash = fields.hash + end + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ==(other) = self.class == other.class && @data == other.to_h + + # @api public + # + # @return [Integer] + def hash = [self.class, @data].hash + + class << self + # @api private + # + # @param value [PreludeSDK::Internal::Type::BaseModel, Hash{Object=>Object}, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [self, Object] + def coerce(value, state:) + exactness = state.fetch(:exactness) + + if value.is_a?(self) + exactness[:yes] += 1 + return value + end + + unless (val = PreludeSDK::Internal::Util.coerce_hash(value)).is_a?(Hash) + exactness[:no] += 1 + state[:error] = TypeError.new("#{value.class} can't be coerced into #{Hash}") + return value + end + exactness[:yes] += 1 + + keys = val.keys.to_set + instance = new + data = instance.to_h + status = instance.instance_variable_get(:@coerced) + + # rubocop:disable Metrics/BlockLength + fields.each do |name, field| + mode, required, target = field.fetch_values(:mode, :required, :type) + api_name, nilable, const = field.fetch_values(:api_name, :nilable, :const) + src_name = state.fetch(:translate_names) ? api_name : name + + unless val.key?(src_name) + if required && mode != :dump && const == PreludeSDK::Internal::OMIT + exactness[nilable ? :maybe : :no] += 1 + else + exactness[:yes] += 1 + end + next + end + + item = val.fetch(src_name) + keys.delete(src_name) + + state[:error] = nil + converted = + if item.nil? && (nilable || !required) + exactness[nilable ? :yes : :maybe] += 1 + nil + else + coerced = PreludeSDK::Internal::Type::Converter.coerce(target, item, state: state) + case target + in PreludeSDK::Internal::Type::Converter | Symbol + coerced + else + item + end + end + + status.store(name, state.fetch(:error) || true) + data.store(name, converted) + end + # rubocop:enable Metrics/BlockLength + + keys.each { data.store(_1, val.fetch(_1)) } + instance + end + + # @api private + # + # @param value [self, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Hash{Object=>Object}, Object] + def dump(value, state:) + unless (coerced = PreludeSDK::Internal::Util.coerce_hash(value)).is_a?(Hash) + return super + end + + acc = {} + + coerced.each do |key, val| + name = key.is_a?(String) ? key.to_sym : key + case (field = known_fields[name]) + in nil + acc.store(name, super(val, state: state)) + else + api_name, mode, type_fn = field.fetch_values(:api_name, :mode, :type_fn) + case mode + in :coerce + next + else + target = type_fn.call + acc.store(api_name, PreludeSDK::Internal::Type::Converter.dump(target, val, state: state)) + end + end + end + + known_fields.each_value do |field| + api_name, mode, const = field.fetch_values(:api_name, :mode, :const) + next if mode == :coerce || acc.key?(api_name) || const == PreludeSDK::Internal::OMIT + acc.store(api_name, const) + end + + acc + end + + # @api private + # + # @return [Object] + def to_sorbet_type + self + end + end + + class << self + # @api private + # + # @param model [PreludeSDK::Internal::Type::BaseModel] + # @param convert [Boolean] + # + # @return [Hash{Symbol=>Object}] + def recursively_to_h(model, convert:) + rec = ->(x) do + case x + in PreludeSDK::Internal::Type::BaseModel + if convert + fields = x.class.known_fields + x.to_h.to_h do |key, val| + [key, rec.call(fields.key?(key) ? x.public_send(key) : val)] + rescue PreludeSDK::Errors::ConversionError + [key, rec.call(val)] + end + else + rec.call(x.to_h) + end + in Hash + x.transform_values(&rec) + in Array + x.map(&rec) + else + x + end + end + rec.call(model) + end + end + + # @api public + # + # Returns the raw value associated with the given key, if found. Otherwise, nil is + # returned. + # + # It is valid to lookup keys that are not in the API spec, for example to access + # undocumented features. This method does not parse response data into + # higher-level types. Lookup by anything other than a Symbol is an ArgumentError. + # + # @param key [Symbol] + # + # @return [Object, nil] + def [](key) + unless key.instance_of?(Symbol) + raise ArgumentError.new("Expected symbol key for lookup, got #{key.inspect}") + end + + @data[key] + end + + # @api public + # + # Returns a Hash of the data underlying this object. O(1) + # + # Keys are Symbols and values are the raw values from the response. The return + # value indicates which values were ever set on the object. i.e. there will be a + # key in this hash if they ever were, even if the set value was nil. + # + # This method is not recursive. The returned value is shared by the object, so it + # should not be mutated. + # + # @return [Hash{Symbol=>Object}] + def to_h = @data + + alias_method :to_hash, :to_h + + # @api public + # + # In addition to the behaviour of `#to_h`, this method will recursively call + # `#to_h` on nested models. + # + # @return [Hash{Symbol=>Object}] + def deep_to_h = self.class.recursively_to_h(@data, convert: false) + + # @param keys [Array, nil] + # + # @return [Hash{Symbol=>Object}] + # + # @example + # # `lookup_lookup_response` is a `PreludeSDK::Models::LookupLookupResponse` + # lookup_lookup_response => { + # caller_name: caller_name, + # country_code: country_code, + # flags: flags + # } + def deconstruct_keys(keys) + (keys || self.class.known_fields.keys) + .filter_map do |k| + unless self.class.known_fields.key?(k) + next + end + + [k, public_send(k)] + end + .to_h + end + + # @api public + # + # @param a [Object] + # + # @return [String] + def to_json(*a) = PreludeSDK::Internal::Type::Converter.dump(self.class, self).to_json(*a) + + # @api public + # + # @param a [Object] + # + # @return [String] + def to_yaml(*a) = PreludeSDK::Internal::Type::Converter.dump(self.class, self).to_yaml(*a) + + # Create a new instance of a model. + # + # @param data [Hash{Symbol=>Object}, self] + def initialize(data = {}) + @data = {} + @coerced = {} + PreludeSDK::Internal::Util.coerce_hash!(data).each do + if self.class.known_fields.key?(_1) + public_send(:"#{_1}=", _2) + else + @data.store(_1, _2) + @coerced.store(_1, false) + end + end + end + + class << self + # @api private + # + # @param depth [Integer] + # + # @return [String] + def inspect(depth: 0) + return super() if depth.positive? + + depth = depth.succ + deferred = fields.transform_values do |field| + type, required, nilable = field.fetch_values(:type, :required, :nilable) + inspected = [ + PreludeSDK::Internal::Type::Converter.inspect(type, depth: depth), + !required || nilable ? "nil" : nil + ].compact.join(" | ") + -> { inspected }.tap { _1.define_singleton_method(:inspect) { call } } + end + + "#{name}[#{deferred.inspect}]" + end + end + + # @api public + # + # @return [String] + def to_s = deep_to_h.to_s + + # @api private + # + # @return [String] + def inspect + converted = self.class.recursively_to_h(self, convert: true) + "#<#{self.class}:0x#{object_id.to_s(16)} #{converted}>" + end + + define_sorbet_constant!(:KnownField) do + T.type_alias { {mode: T.nilable(Symbol), required: T::Boolean, nilable: T::Boolean} } + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/base_page.rb b/lib/prelude_sdk/internal/type/base_page.rb new file mode 100644 index 00000000..0f8af4f7 --- /dev/null +++ b/lib/prelude_sdk/internal/type/base_page.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + # + # @generic Elem + # + # This module provides a base implementation for paginated responses in the SDK. + module BasePage + # rubocop:disable Lint/UnusedMethodArgument + + # @api public + # + # @return [Boolean] + def next_page? = (raise NotImplementedError) + + # @api public + # + # @raise [PreludeSDK::Errors::APIError] + # @return [self] + def next_page = (raise NotImplementedError) + + # @api public + # + # @param blk [Proc] + # + # @yieldparam [generic] + # @return [void] + def auto_paging_each(&blk) = (raise NotImplementedError) + + # @return [Enumerable>] + def to_enum = super(:auto_paging_each) + + alias_method :enum_for, :to_enum + + # @api private + # + # @param client [PreludeSDK::Internal::Transport::BaseClient] + # @param req [Hash{Symbol=>Object}] + # @param headers [Hash{String=>String}, Net::HTTPHeader] + # @param page_data [Object] + def initialize(client:, req:, headers:, page_data:) + @client = client + @req = req + @model = req.fetch(:model) + super() + end + + # rubocop:enable Lint/UnusedMethodArgument + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/boolean.rb b/lib/prelude_sdk/internal/type/boolean.rb new file mode 100644 index 00000000..1d4865a4 --- /dev/null +++ b/lib/prelude_sdk/internal/type/boolean.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + # + # @abstract + # + # Ruby has no Boolean class; this is something for models to refer to. + class Boolean + extend PreludeSDK::Internal::Type::Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + private_class_method :new + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def self.===(other) = other == true || other == false + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def self.==(other) = other.is_a?(Class) && other <= PreludeSDK::Internal::Type::Boolean + + class << self + # @api private + # + # Coerce value to Boolean if possible, otherwise return the original value. + # + # @param value [Boolean, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [Boolean, Object] + def coerce(value, state:) + state.fetch(:exactness)[value == true || value == false ? :yes : :no] += 1 + value + end + + # @!method dump(value, state:) + # @api private + # + # @param value [Boolean, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Boolean, Object] + + # @api private + # + # @return [Object] + def to_sorbet_type + T::Boolean + end + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/converter.rb b/lib/prelude_sdk/internal/type/converter.rb new file mode 100644 index 00000000..06edbaab --- /dev/null +++ b/lib/prelude_sdk/internal/type/converter.rb @@ -0,0 +1,300 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + module Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # rubocop:disable Lint/UnusedMethodArgument + + # @api private + # + # @param value [Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [Object] + def coerce(value, state:) = (raise NotImplementedError) + + # @api private + # + # @param value [Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Object] + def dump(value, state:) + case value + in Array + value.map { PreludeSDK::Internal::Type::Unknown.dump(_1, state: state) } + in Hash + value.transform_values { PreludeSDK::Internal::Type::Unknown.dump(_1, state: state) } + in PreludeSDK::Internal::Type::BaseModel + value.class.dump(value, state: state) + in StringIO + value.string + in Pathname | IO + state[:can_retry] = false if value.is_a?(IO) + PreludeSDK::FilePart.new(value) + in PreludeSDK::FilePart + state[:can_retry] = false if value.content.is_a?(IO) + value + else + value + end + end + + # @api private + # + # @param depth [Integer] + # + # @return [String] + def inspect(depth: 0) + super() + end + + # rubocop:enable Lint/UnusedMethodArgument + + class << self + # @api private + # + # @param spec [Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] . + # + # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const + # + # @option spec [Proc] :enum + # + # @option spec [Proc] :union + # + # @option spec [Boolean] :"nil?" + # + # @return [Proc] + def type_info(spec) + case spec + in Proc + spec + in Hash + type_info(spec.slice(:const, :enum, :union).first&.last) + in true | false + -> { PreludeSDK::Internal::Type::Boolean } + in PreludeSDK::Internal::Type::Converter | Class | Symbol + -> { spec } + in NilClass | Integer | Float + -> { spec.class } + end + end + + # @api private + # + # @param translate_names [Boolean] + # + # @return [Hash{Symbol=>Object}] + def new_coerce_state(translate_names: true) + { + translate_names: translate_names, + strictness: true, + exactness: {yes: 0, no: 0, maybe: 0}, + error: nil, + branched: 0 + } + end + + # @api private + # + # Based on `target`, transform `value` into `target`, to the extent possible: + # + # 1. if the given `value` conforms to `target` already, return the given `value` + # 2. if it's possible and safe to convert the given `value` to `target`, then the + # converted value + # 3. otherwise, the given `value` unaltered + # + # The coercion process is subject to improvement between minor release versions. + # See https://docs.pydantic.dev/latest/concepts/unions/#smart-mode + # + # @param target [PreludeSDK::Internal::Type::Converter, Class] + # + # @param value [Object] + # + # @param state [Hash{Symbol=>Object}] The `strictness` is one of `true`, `false`. This informs the coercion strategy + # when we have to decide between multiple possible conversion targets: + # + # - `true`: the conversion must be exact, with minimum coercion. + # - `false`: the conversion can be approximate, with some coercion. + # + # The `exactness` is `Hash` with keys being one of `yes`, `no`, or `maybe`. For + # any given conversion attempt, the exactness will be updated based on how closely + # the value recursively matches the target type: + # + # - `yes`: the value can be converted to the target type with minimum coercion. + # - `maybe`: the value can be converted to the target type with some reasonable + # coercion. + # - `no`: the value cannot be converted to the target type. + # + # See implementation below for more details. + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [Object] + def coerce(target, value, state: PreludeSDK::Internal::Type::Converter.new_coerce_state) + # rubocop:disable Metrics/BlockNesting + exactness = state.fetch(:exactness) + + case target + in PreludeSDK::Internal::Type::Converter + return target.coerce(value, state: state) + in Class + if value.is_a?(target) + exactness[:yes] += 1 + return value + end + + case target + in -> { _1 <= NilClass } + exactness[value.nil? ? :yes : :maybe] += 1 + return nil + in -> { _1 <= Integer } + case value + in Integer + exactness[:yes] += 1 + return value + else + Kernel.then do + return Integer(value).tap { exactness[:maybe] += 1 } + rescue ArgumentError, TypeError => e + state[:error] = e + end + end + in -> { _1 <= Float } + if value.is_a?(Numeric) + exactness[:yes] += 1 + return Float(value) + else + Kernel.then do + return Float(value).tap { exactness[:maybe] += 1 } + rescue ArgumentError, TypeError => e + state[:error] = e + end + end + in -> { _1 <= String } + case value + in String | Symbol | Numeric + exactness[value.is_a?(Numeric) ? :maybe : :yes] += 1 + return value.to_s + in StringIO + exactness[:yes] += 1 + return value.string + else + state[:error] = TypeError.new("#{value.class} can't be coerced into #{String}") + end + in -> { _1 <= Date || _1 <= Time } + Kernel.then do + return target.parse(value).tap { exactness[:yes] += 1 } + rescue ArgumentError, TypeError => e + state[:error] = e + end + in -> { _1 <= StringIO } if value.is_a?(String) + exactness[:yes] += 1 + return StringIO.new(value.b) + else + end + in Symbol + case value + in Symbol | String + if value.to_sym == target + exactness[:yes] += 1 + return target + else + exactness[:maybe] += 1 + return value + end + else + message = "cannot convert non-matching #{value.class} into #{target.inspect}" + state[:error] = ArgumentError.new(message) + end + else + end + + exactness[:no] += 1 + value + # rubocop:enable Metrics/BlockNesting + end + + # @api private + # + # @param target [PreludeSDK::Internal::Type::Converter, Class] + # + # @param value [Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Object] + def dump(target, value, state: {can_retry: true}) + case target + in PreludeSDK::Internal::Type::Converter + target.dump(value, state: state) + else + PreludeSDK::Internal::Type::Unknown.dump(value, state: state) + end + end + + # @api private + # + # @param target [Object] + # @param depth [Integer] + # + # @return [String] + def inspect(target, depth:) + case target + in PreludeSDK::Internal::Type::Converter + target.inspect(depth: depth.succ) + else + target.inspect + end + end + end + + define_sorbet_constant!(:Input) do + T.type_alias { T.any(PreludeSDK::Internal::Type::Converter, T::Class[T.anything]) } + end + define_sorbet_constant!(:CoerceState) do + T.type_alias do + { + translate_names: T::Boolean, + strictness: T::Boolean, + exactness: {yes: Integer, no: Integer, maybe: Integer}, + error: T::Class[StandardError], + branched: Integer + } + end + end + define_sorbet_constant!(:DumpState) do + T.type_alias { {can_retry: T::Boolean} } + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/enum.rb b/lib/prelude_sdk/internal/type/enum.rb new file mode 100644 index 00000000..0d7b50e9 --- /dev/null +++ b/lib/prelude_sdk/internal/type/enum.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + # + # A value from among a specified list of options. OpenAPI enum values map to Ruby + # values in the SDK as follows: + # + # 1. boolean => true | false + # 2. integer => Integer + # 3. float => Float + # 4. string => Symbol + # + # We can therefore convert string values to Symbols, but can't convert other + # values safely. + module Enum + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # All of the valid Symbol values for this enum. + # + # @return [Array] + def values = constants.map { const_get(_1) } + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ===(other) = values.include?(other) + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ==(other) + # rubocop:disable Style/CaseEquality + PreludeSDK::Internal::Type::Enum === other && other.values.to_set == values.to_set + # rubocop:enable Style/CaseEquality + end + + # @api public + # + # @return [Integer] + def hash = values.to_set.hash + + # @api private + # + # Unlike with primitives, `Enum` additionally validates that the value is a member + # of the enum. + # + # @param value [String, Symbol, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [Symbol, Object] + def coerce(value, state:) + exactness = state.fetch(:exactness) + val = value.is_a?(String) ? value.to_sym : value + + if values.include?(val) + exactness[:yes] += 1 + val + elsif values.first&.class == val.class + exactness[:maybe] += 1 + value + else + exactness[:no] += 1 + state[:error] = TypeError.new("#{value.class} can't be coerced into #{self}") + value + end + end + + # @!method dump(value, state:) + # @api private + # + # @param value [Symbol, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Symbol, Object] + + # @api private + # + # @return [Object] + def to_sorbet_type + types = values.map { PreludeSDK::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(_1) }.uniq + case types + in [] + T.noreturn + in [type] + type + else + T.any(*types) + end + end + + # @api private + # + # @param depth [Integer] + # + # @return [String] + def inspect(depth: 0) + if depth.positive? + return is_a?(Module) ? super() : self.class.name + end + + members = values.map { PreludeSDK::Internal::Type::Converter.inspect(_1, depth: depth.succ) } + prefix = is_a?(Module) ? name : self.class.name + + "#{prefix}[#{members.join(' | ')}]" + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/file_input.rb b/lib/prelude_sdk/internal/type/file_input.rb new file mode 100644 index 00000000..3ca60682 --- /dev/null +++ b/lib/prelude_sdk/internal/type/file_input.rb @@ -0,0 +1,108 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + # + # @abstract + # + # Either `Pathname` or `StringIO`, or `IO`, or + # `PreludeSDK::Internal::Type::FileInput`. + # + # Note: when `IO` is used, all retries are disabled, since many IO` streams are + # not rewindable. + class FileInput + extend PreludeSDK::Internal::Type::Converter + + private_class_method :new + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def self.===(other) + case other + in Pathname | StringIO | IO | String | PreludeSDK::FilePart + true + else + false + end + end + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def self.==(other) = other.is_a?(Class) && other <= PreludeSDK::Internal::Type::FileInput + + class << self + # @api private + # + # @param value [StringIO, String, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [StringIO, Object] + def coerce(value, state:) + exactness = state.fetch(:exactness) + case value + in String + exactness[:yes] += 1 + StringIO.new(value) + in StringIO + exactness[:yes] += 1 + value + else + state[:error] = TypeError.new("#{value.class} can't be coerced into #{StringIO}") + exactness[:no] += 1 + value + end + end + + # @api private + # + # @param value [Pathname, StringIO, IO, String, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Pathname, StringIO, IO, String, Object] + def dump(value, state:) + # rubocop:disable Lint/DuplicateBranch + case value + in IO + state[:can_retry] = false + in PreludeSDK::FilePart if value.content.is_a?(IO) + state[:can_retry] = false + else + end + # rubocop:enable Lint/DuplicateBranch + + value + end + + # @api private + # + # @return [Object] + def to_sorbet_type + T.any(Pathname, StringIO, IO, String, PreludeSDK::FilePart) + end + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/hash_of.rb b/lib/prelude_sdk/internal/type/hash_of.rb new file mode 100644 index 00000000..5e56a52a --- /dev/null +++ b/lib/prelude_sdk/internal/type/hash_of.rb @@ -0,0 +1,187 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + # + # @abstract + # + # @generic Elem + # + # Hash of items of a given type. + class HashOf + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + private_class_method :new + + # @overload [](type_info, spec = {}) + # + # @param type_info [Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] + # + # @param spec [Hash{Symbol=>Object}] . + # + # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const + # + # @option spec [Proc] :enum + # + # @option spec [Proc] :union + # + # @option spec [Boolean] :"nil?" + # + # @return [self] + def self.[](...) = new(...) + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ===(other) + type = item_type + case other + in Hash + other.all? do |key, val| + case [key, val] + in [Symbol | String, ^type] + true + else + false + end + end + else + false + end + end + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ==(other) + # rubocop:disable Layout/LineLength + other.is_a?(PreludeSDK::Internal::Type::HashOf) && other.nilable? == nilable? && other.item_type == item_type + # rubocop:enable Layout/LineLength + end + + # @api public + # + # @return [Integer] + def hash = [self.class, item_type].hash + + # @api private + # + # @param value [Hash{Object=>Object}, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [Hash{Symbol=>Object}, Object] + def coerce(value, state:) + exactness = state.fetch(:exactness) + + unless value.is_a?(Hash) + exactness[:no] += 1 + state[:error] = TypeError.new("#{value.class} can't be coerced into #{Hash}") + return value + end + + target = item_type + exactness[:yes] += 1 + value + .to_h do |key, val| + k = key.is_a?(String) ? key.to_sym : key + v = + case [nilable?, val] + in [true, nil] + exactness[:yes] += 1 + nil + else + PreludeSDK::Internal::Type::Converter.coerce(target, val, state: state) + end + + exactness[:no] += 1 unless k.is_a?(Symbol) + [k, v] + end + end + + # @api private + # + # @param value [Hash{Object=>Object}, Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Hash{Symbol=>Object}, Object] + def dump(value, state:) + target = item_type + if value.is_a?(Hash) + value.transform_values do + PreludeSDK::Internal::Type::Converter.dump(target, _1, state: state) + end + else + super + end + end + + # @api private + # + # @return [Object] + def to_sorbet_type + T::Hash[PreludeSDK::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(item_type)] + end + + # @api private + # + # @return [generic] + protected def item_type = @item_type_fn.call + + # @api private + # + # @return [Boolean] + protected def nilable? = @nilable + + # @api private + # + # @param type_info [Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] + # + # @param spec [Hash{Symbol=>Object}] . + # + # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const + # + # @option spec [Proc] :enum + # + # @option spec [Proc] :union + # + # @option spec [Boolean] :"nil?" + def initialize(type_info, spec = {}) + @item_type_fn = PreludeSDK::Internal::Type::Converter.type_info(type_info || spec) + @nilable = spec.fetch(:nil?, false) + end + + # @api private + # + # @param depth [Integer] + # + # @return [String] + def inspect(depth: 0) + items = PreludeSDK::Internal::Type::Converter.inspect(item_type, depth: depth.succ) + + "#{self.class}[#{[items, nilable? ? 'nil' : nil].compact.join(' | ')}]" + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/request_parameters.rb b/lib/prelude_sdk/internal/type/request_parameters.rb new file mode 100644 index 00000000..357d063c --- /dev/null +++ b/lib/prelude_sdk/internal/type/request_parameters.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + module RequestParameters + # @!attribute request_options + # Options to specify HTTP behaviour for this request. + # + # @return [PreludeSDK::RequestOptions, Hash{Symbol=>Object}] + + # @param mod [Module] + def self.included(mod) + raise ArgumentError.new(mod) unless mod <= PreludeSDK::Internal::Type::BaseModel + + mod.optional(:request_options, PreludeSDK::RequestOptions) + end + + # @api private + module Converter + # @api private + # + # @param params [Object] + # + # @return [Array(Object, Hash{Symbol=>Object})] + def dump_request(params) + state = {can_retry: true} + case (dumped = dump(params, state: state)) + in Hash + options = PreludeSDK::Internal::Util.coerce_hash!(dumped[:request_options]).to_h + request_options = state.fetch(:can_retry) ? options : {**options, max_retries: 0} + [dumped.except(:request_options), request_options] + else + [dumped, nil] + end + end + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/union.rb b/lib/prelude_sdk/internal/type/union.rb new file mode 100644 index 00000000..df734361 --- /dev/null +++ b/lib/prelude_sdk/internal/type/union.rb @@ -0,0 +1,235 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + module Union + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # @api private + # + # All of the specified variant info for this union. + # + # @return [Array] + private def known_variants = (@known_variants ||= []) + + # @api private + # + # @return [Array] + protected def derefed_variants + known_variants.map { |key, variant_fn| [key, variant_fn.call] } + end + + # All of the specified variants for this union. + # + # @return [Array] + def variants = derefed_variants.map(&:last) + + # @api private + # + # @param property [Symbol] + private def discriminator(property) + case property + in Symbol + @discriminator = property + end + end + + # @api private + # + # @param key [Symbol, Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] + # + # @param spec [Hash{Symbol=>Object}, Proc, PreludeSDK::Internal::Type::Converter, Class] . + # + # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const + # + # @option spec [Proc] :enum + # + # @option spec [Proc] :union + # + # @option spec [Boolean] :"nil?" + private def variant(key, spec = nil) + variant_info = + case key + in Symbol + [key, PreludeSDK::Internal::Type::Converter.type_info(spec)] + in Proc | PreludeSDK::Internal::Type::Converter | Class | Hash + [nil, PreludeSDK::Internal::Type::Converter.type_info(key)] + end + + known_variants << variant_info + end + + # @api private + # + # @param value [Object] + # + # @return [PreludeSDK::Internal::Type::Converter, Class, nil] + private def resolve_variant(value) + case [@discriminator, value] + in [_, PreludeSDK::Internal::Type::BaseModel] + value.class + in [Symbol, Hash] + key = value.fetch(@discriminator) do + value.fetch(@discriminator.to_s, PreludeSDK::Internal::OMIT) + end + + return nil if key == PreludeSDK::Internal::OMIT + + key = key.to_sym if key.is_a?(String) + known_variants.find { |k,| k == key }&.last&.call + else + nil + end + end + + # rubocop:disable Style/HashEachMethods + # rubocop:disable Style/CaseEquality + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ===(other) + known_variants.any? do |_, variant_fn| + variant_fn.call === other + end + end + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def ==(other) + PreludeSDK::Internal::Type::Union === other && other.derefed_variants == derefed_variants + end + + # @api public + # + # @return [Integer] + def hash = variants.hash + + # @api private + # + # Tries to efficiently coerce the given value to one of the known variants. + # + # If the value cannot match any of the known variants, the coercion is considered + # non-viable and returns the original value. + # + # @param value [Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [Object] + def coerce(value, state:) + if (target = resolve_variant(value)) + return PreludeSDK::Internal::Type::Converter.coerce(target, value, state: state) + end + + strictness = state.fetch(:strictness) + exactness = state.fetch(:exactness) + + alternatives = [] + known_variants.each do |_, variant_fn| + target = variant_fn.call + exact = state[:exactness] = {yes: 0, no: 0, maybe: 0} + state[:branched] += 1 + + coerced = PreludeSDK::Internal::Type::Converter.coerce(target, value, state: state) + yes, no, maybe = exact.values + if (no + maybe).zero? || (!strictness && yes.positive?) + exact.each { exactness[_1] += _2 } + state[:exactness] = exactness + return coerced + elsif maybe.positive? + alternatives << [[-yes, -maybe, no], exact, coerced] + end + end + + case alternatives.sort_by!(&:first) + in [] + exactness[:no] += 1 + state[:error] = ArgumentError.new("no matching variant for #{value.inspect}") + value + in [[_, exact, coerced], *] + exact.each { exactness[_1] += _2 } + coerced + end + .tap { state[:exactness] = exactness } + ensure + state[:strictness] = strictness + end + + # @api private + # + # @param value [Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Object] + def dump(value, state:) + if (target = resolve_variant(value)) + return PreludeSDK::Internal::Type::Converter.dump(target, value, state: state) + end + + known_variants.each do + target = _2.call + return PreludeSDK::Internal::Type::Converter.dump(target, value, state: state) if target === value + end + + super + end + + # @api private + # + # @return [Object] + def to_sorbet_type + types = variants.map { PreludeSDK::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(_1) }.uniq + case types + in [] + T.noreturn + in [type] + type + else + T.any(*types) + end + end + + # rubocop:enable Style/CaseEquality + # rubocop:enable Style/HashEachMethods + + # @api private + # + # @param depth [Integer] + # + # @return [String] + def inspect(depth: 0) + if depth.positive? + return is_a?(Module) ? super() : self.class.name + end + + members = variants.map { PreludeSDK::Internal::Type::Converter.inspect(_1, depth: depth.succ) } + prefix = is_a?(Module) ? name : self.class.name + + "#{prefix}[#{members.join(' | ')}]" + end + end + end + end +end diff --git a/lib/prelude_sdk/internal/type/unknown.rb b/lib/prelude_sdk/internal/type/unknown.rb new file mode 100644 index 00000000..9b499125 --- /dev/null +++ b/lib/prelude_sdk/internal/type/unknown.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + module Type + # @api private + # + # @abstract + # + # When we don't know what to expect for the value. + class Unknown + extend PreludeSDK::Internal::Type::Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # rubocop:disable Lint/UnusedMethodArgument + + private_class_method :new + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def self.===(other) = true + + # @api public + # + # @param other [Object] + # + # @return [Boolean] + def self.==(other) = other.is_a?(Class) && other <= PreludeSDK::Internal::Type::Unknown + + class << self + # @api private + # + # No coercion needed for Unknown type. + # + # @param value [Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :translate_names + # + # @option state [Boolean] :strictness + # + # @option state [Hash{Symbol=>Object}] :exactness + # + # @option state [Class] :error + # + # @option state [Integer] :branched + # + # @return [Object] + def coerce(value, state:) + state.fetch(:exactness)[:yes] += 1 + value + end + + # @!method dump(value, state:) + # @api private + # + # @param value [Object] + # + # @param state [Hash{Symbol=>Object}] . + # + # @option state [Boolean] :can_retry + # + # @return [Object] + + # @api private + # + # @return [Object] + def to_sorbet_type + T.anything + end + end + + # rubocop:enable Lint/UnusedMethodArgument + end + end + end +end diff --git a/lib/prelude_sdk/internal/util.rb b/lib/prelude_sdk/internal/util.rb new file mode 100644 index 00000000..4b94baf2 --- /dev/null +++ b/lib/prelude_sdk/internal/util.rb @@ -0,0 +1,914 @@ +# frozen_string_literal: true + +module PreludeSDK + module Internal + # @api private + module Util + # @api private + # + # @return [Float] + def self.monotonic_secs = Process.clock_gettime(Process::CLOCK_MONOTONIC) + + # @api private + # + # @param ns [Module, Class] + # + # @return [Enumerable] + def self.walk_namespaces(ns) + ns.constants(false).lazy.flat_map do + case (c = ns.const_get(_1, false)) + in Module | Class + walk_namespaces(c) + else + [] + end + end + .chain([ns]) + end + + class << self + # @api private + # + # @return [String] + def arch + case (arch = RbConfig::CONFIG["arch"])&.downcase + in nil + "unknown" + in /aarch64|arm64/ + "arm64" + in /x86_64/ + "x64" + in /arm/ + "arm" + else + "other:#{arch}" + end + end + + # @api private + # + # @return [String] + def os + case (host = RbConfig::CONFIG["host_os"])&.downcase + in nil + "Unknown" + in /linux/ + "Linux" + in /darwin/ + "MacOS" + in /freebsd/ + "FreeBSD" + in /openbsd/ + "OpenBSD" + in /mswin|mingw|cygwin|ucrt/ + "Windows" + else + "Other:#{host}" + end + end + end + + class << self + # @api private + # + # @param input [Object] + # + # @return [Boolean] + def primitive?(input) + case input + in true | false | Numeric | Symbol | String + true + else + false + end + end + + # @api private + # + # @param input [String, Boolean] + # + # @return [Boolean, Object] + def coerce_boolean(input) + case input.is_a?(String) ? input.downcase : input + in "true" + true + in "false" + false + else + input + end + end + + # @api private + # + # @param input [String, Boolean] + # + # @raise [ArgumentError] + # @return [Boolean, nil] + def coerce_boolean!(input) + case coerce_boolean(input) + in true | false | nil => coerced + coerced + else + raise ArgumentError.new("Unable to coerce #{input.inspect} into boolean value") + end + end + + # @api private + # + # @param input [String, Integer] + # + # @return [Integer, Object] + def coerce_integer(input) + Integer(input, exception: false) || input + end + + # @api private + # + # @param input [String, Integer, Float] + # + # @return [Float, Object] + def coerce_float(input) + Float(input, exception: false) || input + end + + # @api private + # + # @param input [Object] + # + # @return [Hash{Object=>Object}, Object] + def coerce_hash(input) + case input + in NilClass | Array | Set | Enumerator | StringIO | IO + input + else + input.respond_to?(:to_h) ? input.to_h : input + end + end + + # @api private + # + # @param input [Object] + # + # @raise [ArgumentError] + # @return [Hash{Object=>Object}, nil] + def coerce_hash!(input) + case coerce_hash(input) + in Hash | nil => coerced + coerced + else + message = "Expected a #{Hash} or #{PreludeSDK::Internal::Type::BaseModel}, got #{data.inspect}" + raise ArgumentError.new(message) + end + end + end + + class << self + # @api private + # + # @param lhs [Object] + # @param rhs [Object] + # @param concat [Boolean] + # + # @return [Object] + private def deep_merge_lr(lhs, rhs, concat: false) + case [lhs, rhs, concat] + in [Hash, Hash, _] + lhs.merge(rhs) { deep_merge_lr(_2, _3, concat: concat) } + in [Array, Array, true] + lhs.concat(rhs) + else + rhs + end + end + + # @api private + # + # Recursively merge one hash with another. If the values at a given key are not + # both hashes, just take the new value. + # + # @param values [Array] + # + # @param sentinel [Object, nil] the value to return if no values are provided. + # + # @param concat [Boolean] whether to merge sequences by concatenation. + # + # @return [Object] + def deep_merge(*values, sentinel: nil, concat: false) + case values + in [value, *values] + values.reduce(value) do |acc, val| + deep_merge_lr(acc, val, concat: concat) + end + else + sentinel + end + end + + # @api private + # + # @param data [Hash{Symbol=>Object}, Array, Object] + # @param pick [Symbol, Integer, Array, Proc, nil] + # @param blk [Proc, nil] + # + # @return [Object, nil] + def dig(data, pick, &blk) + case [data, pick] + in [_, nil] + data + in [Hash, Symbol] | [Array, Integer] + data.fetch(pick) { blk&.call } + in [Hash | Array, Array] + pick.reduce(data) do |acc, key| + case acc + in Hash if acc.key?(key) + acc.fetch(key) + in Array if key.is_a?(Integer) && key < acc.length + acc[key] + else + return blk&.call + end + end + in [_, Proc] + pick.call(data) + else + blk&.call + end + end + end + + class << self + # @api private + # + # @param uri [URI::Generic] + # + # @return [String] + def uri_origin(uri) + "#{uri.scheme}://#{uri.host}#{uri.port == uri.default_port ? '' : ":#{uri.port}"}" + end + + # @api private + # + # @param path [String, Array] + # + # @return [String] + def interpolate_path(path) + case path + in String + path + in [] + "" + in [String => p, *interpolations] + encoded = interpolations.map { ERB::Util.url_encode(_1) } + format(p, *encoded) + end + end + end + + class << self + # @api private + # + # @param query [String, nil] + # + # @return [Hash{String=>Array}] + def decode_query(query) + CGI.parse(query.to_s) + end + + # @api private + # + # @param query [Hash{String=>Array, String, nil}, nil] + # + # @return [String, nil] + def encode_query(query) + query.to_h.empty? ? nil : URI.encode_www_form(query) + end + end + + class << self + # @api private + # + # @param url [URI::Generic, String] + # + # @return [Hash{Symbol=>String, Integer, nil}] + def parse_uri(url) + parsed = URI::Generic.component.zip(URI.split(url)).to_h + {**parsed, query: decode_query(parsed.fetch(:query))} + end + + # @api private + # + # @param parsed [Hash{Symbol=>String, Integer, nil}] . + # + # @option parsed [String, nil] :scheme + # + # @option parsed [String, nil] :host + # + # @option parsed [Integer, nil] :port + # + # @option parsed [String, nil] :path + # + # @option parsed [Hash{String=>Array}] :query + # + # @return [URI::Generic] + def unparse_uri(parsed) + URI::Generic.build(**parsed, query: encode_query(parsed.fetch(:query))) + end + + # @api private + # + # @param lhs [Hash{Symbol=>String, Integer, nil}] . + # + # @option lhs [String, nil] :scheme + # + # @option lhs [String, nil] :host + # + # @option lhs [Integer, nil] :port + # + # @option lhs [String, nil] :path + # + # @option lhs [Hash{String=>Array}] :query + # + # @param rhs [Hash{Symbol=>String, Integer, nil}] . + # + # @option rhs [String, nil] :scheme + # + # @option rhs [String, nil] :host + # + # @option rhs [Integer, nil] :port + # + # @option rhs [String, nil] :path + # + # @option rhs [Hash{String=>Array}] :query + # + # @return [URI::Generic] + def join_parsed_uri(lhs, rhs) + base_path, base_query = lhs.fetch_values(:path, :query) + slashed = base_path.end_with?("/") ? base_path : "#{base_path}/" + + parsed_path, parsed_query = parse_uri(rhs.fetch(:path)).fetch_values(:path, :query) + override = URI::Generic.build(**rhs.slice(:scheme, :host, :port), path: parsed_path) + + joined = URI.join(URI::Generic.build(lhs.except(:path, :query)), slashed, override) + query = deep_merge( + joined.path == base_path ? base_query : {}, + parsed_query, + rhs[:query].to_h, + concat: true + ) + + joined.query = encode_query(query) + joined + end + end + + class << self + # @api private + # + # @param headers [Hash{String=>String, Integer, Array, nil}] + # + # @return [Hash{String=>String}] + def normalized_headers(*headers) + {}.merge(*headers.compact).to_h do |key, val| + value = + case val + in Array + val.filter_map { _1&.to_s&.strip }.join(", ") + else + val&.to_s&.strip + end + [key.downcase, value] + end + end + end + + # @api private + # + # An adapter that satisfies the IO interface required by `::IO.copy_stream` + class ReadIOAdapter + # @api private + # + # @return [Boolean, nil] + def close? = @closing + + # @api private + def close + case @stream + in Enumerator + PreludeSDK::Internal::Util.close_fused!(@stream) + in IO if close? + @stream.close + else + end + end + + # @api private + # + # @param max_len [Integer, nil] + # + # @return [String] + private def read_enum(max_len) + case max_len + in nil + @stream.to_a.join + in Integer + @buf << @stream.next while @buf.length < max_len + @buf.slice!(..max_len) + end + rescue StopIteration + @stream = nil + @buf.slice!(0..) + end + + # @api private + # + # @param max_len [Integer, nil] + # @param out_string [String, nil] + # + # @return [String, nil] + def read(max_len = nil, out_string = nil) + case @stream + in nil + nil + in IO | StringIO + @stream.read(max_len, out_string) + in Enumerator + read = read_enum(max_len) + case out_string + in String + out_string.replace(read) + in nil + read + end + end + .tap(&@blk) + end + + # @api private + # + # @param src [String, Pathname, StringIO, Enumerable] + # @param blk [Proc] + # + # @yieldparam [String] + def initialize(src, &blk) + @stream = + case src + in String + StringIO.new(src) + in Pathname + @closing = true + src.open(binmode: true) + else + src + end + @buf = String.new + @blk = blk + end + end + + class << self + # @param blk [Proc] + # + # @yieldparam [Enumerator::Yielder] + # @return [Enumerable] + def writable_enum(&blk) + Enumerator.new do |y| + buf = String.new + y.define_singleton_method(:write) do + self << buf.replace(_1) + buf.bytesize + end + + blk.call(y) + end + end + end + + # @type [Regexp] + JSON_CONTENT = %r{^application/(?:vnd(?:\.[^.]+)*\+)?json(?!l)} + # @type [Regexp] + JSONL_CONTENT = %r{^application/(:?x-(?:n|l)djson)|(:?(?:x-)?jsonl)} + + class << self + # @api private + # + # @param y [Enumerator::Yielder] + # @param val [Object] + # @param closing [Array] + # @param content_type [String, nil] + private def write_multipart_content(y, val:, closing:, content_type: nil) + content_line = "Content-Type: %s\r\n\r\n" + + case val + in PreludeSDK::FilePart + return write_multipart_content( + y, + val: val.content, + closing: closing, + content_type: val.content_type + ) + in Pathname + y << format(content_line, content_type || "application/octet-stream") + io = val.open(binmode: true) + closing << io.method(:close) + IO.copy_stream(io, y) + in IO + y << format(content_line, content_type || "application/octet-stream") + IO.copy_stream(val, y) + in StringIO + y << format(content_line, content_type || "application/octet-stream") + y << val.string + in -> { primitive?(_1) } + y << format(content_line, content_type || "text/plain") + y << val.to_s + else + y << format(content_line, content_type || "application/json") + y << JSON.generate(val) + end + y << "\r\n" + end + + # @api private + # + # @param y [Enumerator::Yielder] + # @param boundary [String] + # @param key [Symbol, String] + # @param val [Object] + # @param closing [Array] + private def write_multipart_chunk(y, boundary:, key:, val:, closing:) + y << "--#{boundary}\r\n" + y << "Content-Disposition: form-data" + + unless key.nil? + name = ERB::Util.url_encode(key.to_s) + y << "; name=\"#{name}\"" + end + + case val + in PreludeSDK::FilePart unless val.filename.nil? + filename = ERB::Util.url_encode(val.filename) + y << "; filename=\"#{filename}\"" + in Pathname | IO + filename = ERB::Util.url_encode(::File.basename(val.to_path)) + y << "; filename=\"#{filename}\"" + else + end + y << "\r\n" + + write_multipart_content(y, val: val, closing: closing) + end + + # @api private + # + # https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#special-considerations-for-multipart-content + # + # @param body [Object] + # + # @return [Array(String, Enumerable)] + private def encode_multipart_streaming(body) + boundary = SecureRandom.urlsafe_base64(60) + + closing = [] + strio = writable_enum do |y| + case body + in Hash + body.each do |key, val| + case val + in Array if val.all? { primitive?(_1) } + val.each do |v| + write_multipart_chunk(y, boundary: boundary, key: key, val: v, closing: closing) + end + else + write_multipart_chunk(y, boundary: boundary, key: key, val: val, closing: closing) + end + end + else + write_multipart_chunk(y, boundary: boundary, key: nil, val: body, closing: closing) + end + y << "--#{boundary}--\r\n" + end + + fused_io = fused_enum(strio) { closing.each(&:call) } + [boundary, fused_io] + end + + # @api private + # + # @param headers [Hash{String=>String}] + # @param body [Object] + # + # @return [Object] + def encode_content(headers, body) + # rubocop:disable Style/CaseEquality + # rubocop:disable Layout/LineLength + content_type = headers["content-type"] + case [content_type, body] + in [PreludeSDK::Internal::Util::JSON_CONTENT, Hash | Array | -> { primitive?(_1) }] + [headers, JSON.generate(body)] + in [PreludeSDK::Internal::Util::JSONL_CONTENT, Enumerable] unless PreludeSDK::Internal::Type::FileInput === body + [headers, body.lazy.map { JSON.generate(_1) }] + in [%r{^multipart/form-data}, Hash | PreludeSDK::Internal::Type::FileInput] + boundary, strio = encode_multipart_streaming(body) + headers = {**headers, "content-type" => "#{content_type}; boundary=#{boundary}"} + [headers, strio] + in [_, Symbol | Numeric] + [headers, body.to_s] + in [_, StringIO] + [headers, body.string] + in [_, PreludeSDK::FilePart] + [headers, body.content] + else + [headers, body] + end + # rubocop:enable Layout/LineLength + # rubocop:enable Style/CaseEquality + end + + # @api private + # + # https://www.iana.org/assignments/character-sets/character-sets.xhtml + # + # @param content_type [String] + # @param text [String] + def force_charset!(content_type, text:) + charset = /charset=([^;\s]+)/.match(content_type)&.captures&.first + + return unless charset + + begin + encoding = Encoding.find(charset) + text.force_encoding(encoding) + rescue ArgumentError + nil + end + end + + # @api private + # + # Assumes each chunk in stream has `Encoding::BINARY`. + # + # @param headers [Hash{String=>String}, Net::HTTPHeader] + # @param stream [Enumerable] + # @param suppress_error [Boolean] + # + # @raise [JSON::ParserError] + # @return [Object] + def decode_content(headers, stream:, suppress_error: false) + case (content_type = headers["content-type"]) + in PreludeSDK::Internal::Util::JSON_CONTENT + json = stream.to_a.join + begin + JSON.parse(json, symbolize_names: true) + rescue JSON::ParserError => e + raise e unless suppress_error + json + end + in PreludeSDK::Internal::Util::JSONL_CONTENT + lines = decode_lines(stream) + chain_fused(lines) do |y| + lines.each { y << JSON.parse(_1, symbolize_names: true) } + end + in %r{^text/event-stream} + lines = decode_lines(stream) + decode_sse(lines) + else + text = stream.to_a.join + force_charset!(content_type, text: text) + StringIO.new(text) + end + end + end + + class << self + # @api private + # + # https://doc.rust-lang.org/std/iter/trait.FusedIterator.html + # + # @param enum [Enumerable] + # @param external [Boolean] + # @param close [Proc] + # + # @return [Enumerable] + def fused_enum(enum, external: false, &close) + fused = false + iter = Enumerator.new do |y| + next if fused + + fused = true + if external + loop { y << enum.next } + else + enum.each(&y) + end + ensure + close&.call + close = nil + end + + iter.define_singleton_method(:rewind) do + fused = true + self + end + iter + end + + # @api private + # + # @param enum [Enumerable, nil] + def close_fused!(enum) + return unless enum.is_a?(Enumerator) + + # rubocop:disable Lint/UnreachableLoop + enum.rewind.each { break } + # rubocop:enable Lint/UnreachableLoop + end + + # @api private + # + # @param enum [Enumerable, nil] + # @param blk [Proc] + # + # @yieldparam [Enumerator::Yielder] + # @return [Enumerable] + def chain_fused(enum, &blk) + iter = Enumerator.new { blk.call(_1) } + fused_enum(iter) { close_fused!(enum) } + end + end + + class << self + # @api private + # + # Assumes Strings have been forced into having `Encoding::BINARY`. + # + # This decoder is responsible for reassembling lines split across multiple + # fragments. + # + # @param enum [Enumerable] + # + # @return [Enumerable] + def decode_lines(enum) + re = /(\r\n|\r|\n)/ + buffer = String.new + cr_seen = nil + + chain_fused(enum) do |y| + enum.each do |row| + offset = buffer.bytesize + buffer << row + while (match = re.match(buffer, cr_seen&.to_i || offset)) + case [match.captures.first, cr_seen] + in ["\r", nil] + cr_seen = match.end(1) + next + in ["\r" | "\r\n", Integer] + y << buffer.slice!(..(cr_seen.pred)) + else + y << buffer.slice!(..(match.end(1).pred)) + end + offset = 0 + cr_seen = nil + end + end + + y << buffer.slice!(..(cr_seen.pred)) unless cr_seen.nil? + y << buffer unless buffer.empty? + end + end + + # @api private + # + # https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream + # + # Assumes that `lines` has been decoded with `#decode_lines`. + # + # @param lines [Enumerable] + # + # @return [EnumerableObject}>] + def decode_sse(lines) + # rubocop:disable Metrics/BlockLength + chain_fused(lines) do |y| + blank = {event: nil, data: nil, id: nil, retry: nil} + current = {} + + lines.each do |line| + case line.sub(/\R$/, "") + in "" + next if current.empty? + y << {**blank, **current} + current = {} + in /^:/ + next + in /^([^:]+):\s?(.*)$/ + field, value = Regexp.last_match.captures + case field + in "event" + current.merge!(event: value) + in "data" + (current[:data] ||= String.new) << (value << "\n") + in "id" unless value.include?("\0") + current.merge!(id: value) + in "retry" if /^\d+$/ =~ value + current.merge!(retry: Integer(value)) + else + end + else + end + end + # rubocop:enable Metrics/BlockLength + + y << {**blank, **current} unless current.empty? + end + end + end + + # @api private + module SorbetRuntimeSupport + class MissingSorbetRuntimeError < ::RuntimeError + end + + # @api private + # + # @return [Hash{Symbol=>Object}] + private def sorbet_runtime_constants = @sorbet_runtime_constants ||= {} + + # @api private + # + # @param name [Symbol] + def const_missing(name) + super unless sorbet_runtime_constants.key?(name) + + unless Object.const_defined?(:T) + message = "Trying to access a Sorbet constant #{name.inspect} without `sorbet-runtime`." + raise MissingSorbetRuntimeError.new(message) + end + + sorbet_runtime_constants.fetch(name).call + end + + # @api private + # + # @param name [Symbol] + # + # @return [Boolean] + def sorbet_constant_defined?(name) = sorbet_runtime_constants.key?(name) + + # @api private + # + # @param name [Symbol] + # @param blk [Proc] + def define_sorbet_constant!(name, &blk) = sorbet_runtime_constants.store(name, blk) + + # @api private + # + # @return [Object] + def to_sorbet_type = raise NotImplementedError + + class << self + # @api private + # + # @param type [PreludeSDK::Internal::Util::SorbetRuntimeSupport, Object] + # + # @return [Object] + def to_sorbet_type(type) + case type + in PreludeSDK::Internal::Util::SorbetRuntimeSupport + type.to_sorbet_type + in Class | Module + type + in true | false + T::Boolean + else + type.class + end + end + end + end + + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + define_sorbet_constant!(:ParsedUri) do + T.type_alias do + { + scheme: T.nilable(String), + host: T.nilable(String), + port: T.nilable(Integer), + path: T.nilable(String), + query: T::Hash[String, T::Array[String]] + } + end + end + + define_sorbet_constant!(:ServerSentEvent) do + T.type_alias do + { + event: T.nilable(String), + data: T.nilable(String), + id: T.nilable(String), + retry: T.nilable(Integer) + } + end + end + end + end +end diff --git a/lib/prelude_sdk/models.rb b/lib/prelude_sdk/models.rb new file mode 100644 index 00000000..a0c9e2c7 --- /dev/null +++ b/lib/prelude_sdk/models.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module PreludeSDK + [PreludeSDK::Internal::Type::BaseModel, *PreludeSDK::Internal::Type::BaseModel.subclasses].each do |cls| + cls.define_sorbet_constant!(:OrHash) { T.type_alias { T.any(cls, PreludeSDK::Internal::AnyHash) } } + end + + PreludeSDK::Internal::Util.walk_namespaces(PreludeSDK::Models).each do |mod| + case mod + in PreludeSDK::Internal::Type::Enum | PreludeSDK::Internal::Type::Union + mod.constants.each do |name| + case mod.const_get(name) + in true | false + mod.define_sorbet_constant!(:TaggedBoolean) { T.type_alias { T::Boolean } } + mod.define_sorbet_constant!(:OrBoolean) { T.type_alias { T::Boolean } } + in Integer + mod.define_sorbet_constant!(:TaggedInteger) { T.type_alias { Integer } } + mod.define_sorbet_constant!(:OrInteger) { T.type_alias { Integer } } + in Float + mod.define_sorbet_constant!(:TaggedFloat) { T.type_alias { Float } } + mod.define_sorbet_constant!(:OrFloat) { T.type_alias { Float } } + in Symbol + mod.define_sorbet_constant!(:TaggedSymbol) { T.type_alias { Symbol } } + mod.define_sorbet_constant!(:OrSymbol) { T.type_alias { T.any(Symbol, String) } } + else + end + end + else + end + end + + PreludeSDK::Internal::Util.walk_namespaces(PreludeSDK::Models) + .lazy + .grep(PreludeSDK::Internal::Type::Union) + .each do |mod| + const = :Variants + next if mod.sorbet_constant_defined?(const) + + mod.define_sorbet_constant!(const) { T.type_alias { mod.to_sorbet_type } } + end + + LookupLookupParams = PreludeSDK::Models::LookupLookupParams + + TransactionalSendParams = PreludeSDK::Models::TransactionalSendParams + + VerificationCheckParams = PreludeSDK::Models::VerificationCheckParams + + VerificationCreateParams = PreludeSDK::Models::VerificationCreateParams + + WatchPredictParams = PreludeSDK::Models::WatchPredictParams + + WatchSendEventsParams = PreludeSDK::Models::WatchSendEventsParams + + WatchSendFeedbacksParams = PreludeSDK::Models::WatchSendFeedbacksParams +end diff --git a/lib/prelude_sdk/models/lookup_lookup_params.rb b/lib/prelude_sdk/models/lookup_lookup_params.rb new file mode 100644 index 00000000..5c450976 --- /dev/null +++ b/lib/prelude_sdk/models/lookup_lookup_params.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Lookup#lookup + class LookupLookupParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + # @!attribute type + # Optional features. Possible values are: + # + # - `cnam` - Retrieve CNAM (Caller ID Name) along with other information. Contact + # us if you need to use this functionality. + # + # @return [Array, nil] + optional :type, -> { PreludeSDK::Internal::Type::ArrayOf[enum: PreludeSDK::LookupLookupParams::Type] } + + # @!method initialize(type: nil, request_options: {}) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::LookupLookupParams} for more details. + # + # @param type [Array] Optional features. Possible values are: + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}] + + module Type + extend PreludeSDK::Internal::Type::Enum + + CNAM = :cnam + + # @!method self.values + # @return [Array] + end + end + end +end diff --git a/lib/prelude_sdk/models/lookup_lookup_response.rb b/lib/prelude_sdk/models/lookup_lookup_response.rb new file mode 100644 index 00000000..6c13f0ea --- /dev/null +++ b/lib/prelude_sdk/models/lookup_lookup_response.rb @@ -0,0 +1,236 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Lookup#lookup + class LookupLookupResponse < PreludeSDK::Internal::Type::BaseModel + # @!attribute caller_name + # The CNAM (Caller ID Name) associated with the phone number. Contact us if you + # need to use this functionality. Once enabled, put `cnam` option to `type` query + # parameter. + # + # @return [String, nil] + optional :caller_name, String + + # @!attribute country_code + # The country code of the phone number. + # + # @return [String, nil] + optional :country_code, String + + # @!attribute flags + # A list of flags associated with the phone number. + # + # - `ported` - Indicates the phone number has been transferred from one carrier to + # another. + # - `temporary` - Indicates the phone number is likely a temporary or virtual + # number, often used for verification services or burner phones. + # + # @return [Array, nil] + optional :flags, + -> { PreludeSDK::Internal::Type::ArrayOf[enum: PreludeSDK::Models::LookupLookupResponse::Flag] } + + # @!attribute line_type + # The type of phone line. + # + # - `calling_cards` - Numbers that are associated with providers of pre-paid + # domestic and international calling cards. + # - `fixed_line` - Landline phone numbers. + # - `isp` - Numbers reserved for Internet Service Providers. + # - `local_rate` - Numbers that can be assigned non-geographically. + # - `mobile` - Mobile phone numbers. + # - `other` - Other types of services. + # - `pager` - Number ranges specifically allocated to paging devices. + # - `payphone` - Allocated numbers for payphone kiosks in some countries. + # - `premium_rate` - Landline numbers where the calling party pays more than + # standard. + # - `satellite` - Satellite phone numbers. + # - `service` - Automated applications. + # - `shared_cost` - Specific landline ranges where the cost of making the call is + # shared between the calling and called party. + # - `short_codes_commercial` - Short codes are memorable, easy-to-use numbers, + # like the UK's NHS 111, often sold to businesses. Not available in all + # countries. + # - `toll_free` - Number where the called party pays for the cost of the call not + # the calling party. + # - `universal_access` - Number ranges reserved for Universal Access initiatives. + # - `unknown` - Unknown phone number type. + # - `vpn` - Numbers are used exclusively within a private telecommunications + # network, connecting the operator's terminals internally and not accessible via + # the public telephone network. + # - `voice_mail` - A specific category of Interactive Voice Response (IVR) + # services. + # - `voip` - Specific ranges for providers of VoIP services to allow incoming + # calls from the regular telephony network. + # + # @return [Symbol, PreludeSDK::Models::LookupLookupResponse::LineType, nil] + optional :line_type, enum: -> { PreludeSDK::Models::LookupLookupResponse::LineType } + + # @!attribute network_info + # The current carrier information. + # + # @return [PreludeSDK::Models::LookupLookupResponse::NetworkInfo, nil] + optional :network_info, -> { PreludeSDK::Models::LookupLookupResponse::NetworkInfo } + + # @!attribute original_network_info + # The original carrier information. + # + # @return [PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo, nil] + optional :original_network_info, -> { PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo } + + # @!attribute phone_number + # The phone number. + # + # @return [String, nil] + optional :phone_number, String + + # @!method initialize(caller_name: nil, country_code: nil, flags: nil, line_type: nil, network_info: nil, original_network_info: nil, phone_number: nil) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::LookupLookupResponse} for more details. + # + # @param caller_name [String] The CNAM (Caller ID Name) associated with the phone number. Contact us if you ne + # + # @param country_code [String] The country code of the phone number. + # + # @param flags [Array] A list of flags associated with the phone number. + # + # @param line_type [Symbol, PreludeSDK::Models::LookupLookupResponse::LineType] The type of phone line. + # + # @param network_info [PreludeSDK::Models::LookupLookupResponse::NetworkInfo] The current carrier information. + # + # @param original_network_info [PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo] The original carrier information. + # + # @param phone_number [String] The phone number. + + module Flag + extend PreludeSDK::Internal::Type::Enum + + PORTED = :ported + TEMPORARY = :temporary + + # @!method self.values + # @return [Array] + end + + # The type of phone line. + # + # - `calling_cards` - Numbers that are associated with providers of pre-paid + # domestic and international calling cards. + # - `fixed_line` - Landline phone numbers. + # - `isp` - Numbers reserved for Internet Service Providers. + # - `local_rate` - Numbers that can be assigned non-geographically. + # - `mobile` - Mobile phone numbers. + # - `other` - Other types of services. + # - `pager` - Number ranges specifically allocated to paging devices. + # - `payphone` - Allocated numbers for payphone kiosks in some countries. + # - `premium_rate` - Landline numbers where the calling party pays more than + # standard. + # - `satellite` - Satellite phone numbers. + # - `service` - Automated applications. + # - `shared_cost` - Specific landline ranges where the cost of making the call is + # shared between the calling and called party. + # - `short_codes_commercial` - Short codes are memorable, easy-to-use numbers, + # like the UK's NHS 111, often sold to businesses. Not available in all + # countries. + # - `toll_free` - Number where the called party pays for the cost of the call not + # the calling party. + # - `universal_access` - Number ranges reserved for Universal Access initiatives. + # - `unknown` - Unknown phone number type. + # - `vpn` - Numbers are used exclusively within a private telecommunications + # network, connecting the operator's terminals internally and not accessible via + # the public telephone network. + # - `voice_mail` - A specific category of Interactive Voice Response (IVR) + # services. + # - `voip` - Specific ranges for providers of VoIP services to allow incoming + # calls from the regular telephony network. + # + # @see PreludeSDK::Models::LookupLookupResponse#line_type + module LineType + extend PreludeSDK::Internal::Type::Enum + + CALLING_CARDS = :calling_cards + FIXED_LINE = :fixed_line + ISP = :isp + LOCAL_RATE = :local_rate + MOBILE = :mobile + OTHER = :other + PAGER = :pager + PAYPHONE = :payphone + PREMIUM_RATE = :premium_rate + SATELLITE = :satellite + SERVICE = :service + SHARED_COST = :shared_cost + SHORT_CODES_COMMERCIAL = :short_codes_commercial + TOLL_FREE = :toll_free + UNIVERSAL_ACCESS = :universal_access + UNKNOWN = :unknown + VPN = :vpn + VOICE_MAIL = :voice_mail + VOIP = :voip + + # @!method self.values + # @return [Array] + end + + # @see PreludeSDK::Models::LookupLookupResponse#network_info + class NetworkInfo < PreludeSDK::Internal::Type::BaseModel + # @!attribute carrier_name + # The name of the carrier. + # + # @return [String, nil] + optional :carrier_name, String + + # @!attribute mcc + # Mobile Country Code. + # + # @return [String, nil] + optional :mcc, String + + # @!attribute mnc + # Mobile Network Code. + # + # @return [String, nil] + optional :mnc, String + + # @!method initialize(carrier_name: nil, mcc: nil, mnc: nil) + # The current carrier information. + # + # @param carrier_name [String] The name of the carrier. + # + # @param mcc [String] Mobile Country Code. + # + # @param mnc [String] Mobile Network Code. + end + + # @see PreludeSDK::Models::LookupLookupResponse#original_network_info + class OriginalNetworkInfo < PreludeSDK::Internal::Type::BaseModel + # @!attribute carrier_name + # The name of the original carrier. + # + # @return [String, nil] + optional :carrier_name, String + + # @!attribute mcc + # Mobile Country Code. + # + # @return [String, nil] + optional :mcc, String + + # @!attribute mnc + # Mobile Network Code. + # + # @return [String, nil] + optional :mnc, String + + # @!method initialize(carrier_name: nil, mcc: nil, mnc: nil) + # The original carrier information. + # + # @param carrier_name [String] The name of the original carrier. + # + # @param mcc [String] Mobile Country Code. + # + # @param mnc [String] Mobile Network Code. + end + end + end +end diff --git a/lib/prelude_sdk/models/transactional_send_params.rb b/lib/prelude_sdk/models/transactional_send_params.rb new file mode 100644 index 00000000..c0c4d6f8 --- /dev/null +++ b/lib/prelude_sdk/models/transactional_send_params.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Transactional#send_ + class TransactionalSendParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + # @!attribute template_id + # The template identifier. + # + # @return [String] + required :template_id, String + + # @!attribute to + # The recipient's phone number. + # + # @return [String] + required :to, String + + # @!attribute callback_url + # The callback URL. + # + # @return [String, nil] + optional :callback_url, String + + # @!attribute correlation_id + # A unique, user-defined identifier that will be included in webhook events. + # + # @return [String, nil] + optional :correlation_id, String + + # @!attribute expires_at + # The message expiration date. + # + # @return [String, nil] + optional :expires_at, String + + # @!attribute from + # The Sender ID. + # + # @return [String, nil] + optional :from, String + + # @!attribute locale + # A BCP-47 formatted locale string with the language the text message will be sent + # to. If there's no locale set, the language will be determined by the country + # code of the phone number. If the language specified doesn't exist, the default + # set on the template will be used. + # + # @return [String, nil] + optional :locale, String + + # @!attribute variables + # The variables to be replaced in the template. + # + # @return [Hash{Symbol=>String}, nil] + optional :variables, PreludeSDK::Internal::Type::HashOf[String] + + # @!method initialize(template_id:, to:, callback_url: nil, correlation_id: nil, expires_at: nil, from: nil, locale: nil, variables: nil, request_options: {}) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::TransactionalSendParams} for more details. + # + # @param template_id [String] The template identifier. + # + # @param to [String] The recipient's phone number. + # + # @param callback_url [String] The callback URL. + # + # @param correlation_id [String] A unique, user-defined identifier that will be included in webhook events. + # + # @param expires_at [String] The message expiration date. + # + # @param from [String] The Sender ID. + # + # @param locale [String] A BCP-47 formatted locale string with the language the text message will be sent + # + # @param variables [Hash{Symbol=>String}] The variables to be replaced in the template. + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}] + end + end +end diff --git a/lib/prelude_sdk/models/transactional_send_response.rb b/lib/prelude_sdk/models/transactional_send_response.rb new file mode 100644 index 00000000..c5fa3343 --- /dev/null +++ b/lib/prelude_sdk/models/transactional_send_response.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Transactional#send_ + class TransactionalSendResponse < PreludeSDK::Internal::Type::BaseModel + # @!attribute id + # The message identifier. + # + # @return [String] + required :id, String + + # @!attribute created_at + # The message creation date. + # + # @return [Time] + required :created_at, Time + + # @!attribute expires_at + # The message expiration date. + # + # @return [Time] + required :expires_at, Time + + # @!attribute template_id + # The template identifier. + # + # @return [String] + required :template_id, String + + # @!attribute to + # The recipient's phone number. + # + # @return [String] + required :to, String + + # @!attribute variables + # The variables to be replaced in the template. + # + # @return [Hash{Symbol=>String}] + required :variables, PreludeSDK::Internal::Type::HashOf[String] + + # @!attribute callback_url + # The callback URL. + # + # @return [String, nil] + optional :callback_url, String + + # @!attribute correlation_id + # A unique, user-defined identifier that will be included in webhook events. + # + # @return [String, nil] + optional :correlation_id, String + + # @!attribute from + # The Sender ID. + # + # @return [String, nil] + optional :from, String + + # @!method initialize(id:, created_at:, expires_at:, template_id:, to:, variables:, callback_url: nil, correlation_id: nil, from: nil) + # @param id [String] The message identifier. + # + # @param created_at [Time] The message creation date. + # + # @param expires_at [Time] The message expiration date. + # + # @param template_id [String] The template identifier. + # + # @param to [String] The recipient's phone number. + # + # @param variables [Hash{Symbol=>String}] The variables to be replaced in the template. + # + # @param callback_url [String] The callback URL. + # + # @param correlation_id [String] A unique, user-defined identifier that will be included in webhook events. + # + # @param from [String] The Sender ID. + end + end +end diff --git a/lib/prelude_sdk/models/verification_check_params.rb b/lib/prelude_sdk/models/verification_check_params.rb new file mode 100644 index 00000000..9143064a --- /dev/null +++ b/lib/prelude_sdk/models/verification_check_params.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Verification#check + class VerificationCheckParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + # @!attribute code + # The OTP code to validate. + # + # @return [String] + required :code, String + + # @!attribute target + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + # + # @return [PreludeSDK::Models::VerificationCheckParams::Target] + required :target, -> { PreludeSDK::VerificationCheckParams::Target } + + # @!method initialize(code:, target:, request_options: {}) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::VerificationCheckParams} for more details. + # + # @param code [String] The OTP code to validate. + # + # @param target [PreludeSDK::Models::VerificationCheckParams::Target] The verification target. Either a phone number or an email address. To use the e + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}] + + class Target < PreludeSDK::Internal::Type::BaseModel + # @!attribute type + # The type of the target. Either "phone_number" or "email_address". + # + # @return [Symbol, PreludeSDK::Models::VerificationCheckParams::Target::Type] + required :type, enum: -> { PreludeSDK::VerificationCheckParams::Target::Type } + + # @!attribute value + # An E.164 formatted phone number or an email address. + # + # @return [String] + required :value, String + + # @!method initialize(type:, value:) + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + # + # @param type [Symbol, PreludeSDK::Models::VerificationCheckParams::Target::Type] The type of the target. Either "phone_number" or "email_address". + # + # @param value [String] An E.164 formatted phone number or an email address. + + # The type of the target. Either "phone_number" or "email_address". + # + # @see PreludeSDK::Models::VerificationCheckParams::Target#type + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER = :phone_number + EMAIL_ADDRESS = :email_address + + # @!method self.values + # @return [Array] + end + end + end + end +end diff --git a/lib/prelude_sdk/models/verification_check_response.rb b/lib/prelude_sdk/models/verification_check_response.rb new file mode 100644 index 00000000..1b9ed869 --- /dev/null +++ b/lib/prelude_sdk/models/verification_check_response.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Verification#check + class VerificationCheckResponse < PreludeSDK::Internal::Type::BaseModel + # @!attribute status + # The status of the check. + # + # @return [Symbol, PreludeSDK::Models::VerificationCheckResponse::Status] + required :status, enum: -> { PreludeSDK::Models::VerificationCheckResponse::Status } + + # @!attribute id + # The verification identifier. + # + # @return [String, nil] + optional :id, String + + # @!attribute metadata + # The metadata for this verification. + # + # @return [PreludeSDK::Models::VerificationCheckResponse::Metadata, nil] + optional :metadata, -> { PreludeSDK::Models::VerificationCheckResponse::Metadata } + + # @!attribute request_id + # + # @return [String, nil] + optional :request_id, String + + # @!method initialize(status:, id: nil, metadata: nil, request_id: nil) + # @param status [Symbol, PreludeSDK::Models::VerificationCheckResponse::Status] The status of the check. + # + # @param id [String] The verification identifier. + # + # @param metadata [PreludeSDK::Models::VerificationCheckResponse::Metadata] The metadata for this verification. + # + # @param request_id [String] + + # The status of the check. + # + # @see PreludeSDK::Models::VerificationCheckResponse#status + module Status + extend PreludeSDK::Internal::Type::Enum + + SUCCESS = :success + FAILURE = :failure + EXPIRED_OR_NOT_FOUND = :expired_or_not_found + + # @!method self.values + # @return [Array] + end + + # @see PreludeSDK::Models::VerificationCheckResponse#metadata + class Metadata < PreludeSDK::Internal::Type::BaseModel + # @!attribute correlation_id + # + # @return [String, nil] + optional :correlation_id, String + + # @!method initialize(correlation_id: nil) + # The metadata for this verification. + # + # @param correlation_id [String] + end + end + end +end diff --git a/lib/prelude_sdk/models/verification_create_params.rb b/lib/prelude_sdk/models/verification_create_params.rb new file mode 100644 index 00000000..ca0f7f29 --- /dev/null +++ b/lib/prelude_sdk/models/verification_create_params.rb @@ -0,0 +1,388 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Verification#create + class VerificationCreateParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + # @!attribute target + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + # + # @return [PreludeSDK::Models::VerificationCreateParams::Target] + required :target, -> { PreludeSDK::VerificationCreateParams::Target } + + # @!attribute dispatch_id + # The identifier of the dispatch that came from the front-end SDK. + # + # @return [String, nil] + optional :dispatch_id, String + + # @!attribute metadata + # The metadata for this verification. This object will be returned with every + # response or webhook sent that refers to this verification. + # + # @return [PreludeSDK::Models::VerificationCreateParams::Metadata, nil] + optional :metadata, -> { PreludeSDK::VerificationCreateParams::Metadata } + + # @!attribute options + # Verification options + # + # @return [PreludeSDK::Models::VerificationCreateParams::Options, nil] + optional :options, -> { PreludeSDK::VerificationCreateParams::Options } + + # @!attribute signals + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + # + # @return [PreludeSDK::Models::VerificationCreateParams::Signals, nil] + optional :signals, -> { PreludeSDK::VerificationCreateParams::Signals } + + # @!method initialize(target:, dispatch_id: nil, metadata: nil, options: nil, signals: nil, request_options: {}) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::VerificationCreateParams} for more details. + # + # @param target [PreludeSDK::Models::VerificationCreateParams::Target] The verification target. Either a phone number or an email address. To use the e + # + # @param dispatch_id [String] The identifier of the dispatch that came from the front-end SDK. + # + # @param metadata [PreludeSDK::Models::VerificationCreateParams::Metadata] The metadata for this verification. This object will be returned with every resp + # + # @param options [PreludeSDK::Models::VerificationCreateParams::Options] Verification options + # + # @param signals [PreludeSDK::Models::VerificationCreateParams::Signals] The signals used for anti-fraud. For more details, refer to [Signals](/verify/v2 + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}] + + class Target < PreludeSDK::Internal::Type::BaseModel + # @!attribute type + # The type of the target. Either "phone_number" or "email_address". + # + # @return [Symbol, PreludeSDK::Models::VerificationCreateParams::Target::Type] + required :type, enum: -> { PreludeSDK::VerificationCreateParams::Target::Type } + + # @!attribute value + # An E.164 formatted phone number or an email address. + # + # @return [String] + required :value, String + + # @!method initialize(type:, value:) + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + # + # @param type [Symbol, PreludeSDK::Models::VerificationCreateParams::Target::Type] The type of the target. Either "phone_number" or "email_address". + # + # @param value [String] An E.164 formatted phone number or an email address. + + # The type of the target. Either "phone_number" or "email_address". + # + # @see PreludeSDK::Models::VerificationCreateParams::Target#type + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER = :phone_number + EMAIL_ADDRESS = :email_address + + # @!method self.values + # @return [Array] + end + end + + class Metadata < PreludeSDK::Internal::Type::BaseModel + # @!attribute correlation_id + # A user-defined identifier to correlate this verification with. + # + # @return [String, nil] + optional :correlation_id, String + + # @!method initialize(correlation_id: nil) + # The metadata for this verification. This object will be returned with every + # response or webhook sent that refers to this verification. + # + # @param correlation_id [String] A user-defined identifier to correlate this verification with. + end + + class Options < PreludeSDK::Internal::Type::BaseModel + # @!attribute app_realm + # This allows you to automatically retrieve and fill the OTP code on mobile apps. + # Currently only Android devices are supported. + # + # @return [PreludeSDK::Models::VerificationCreateParams::Options::AppRealm, nil] + optional :app_realm, -> { PreludeSDK::VerificationCreateParams::Options::AppRealm } + + # @!attribute callback_url + # The URL where webhooks will be sent when verification events occur, including + # verification creation, attempt creation, and delivery status changes. For more + # details, refer to [Webhook](/verify/v2/documentation/webhook). + # + # @return [String, nil] + optional :callback_url, String + + # @!attribute code_size + # The size of the code generated. It should be between 4 and 8. Defaults to the + # code size specified from the Dashboard. + # + # @return [Integer, nil] + optional :code_size, Integer + + # @!attribute custom_code + # The custom code to use for OTP verification. To use the custom code feature, + # contact us to enable it for your account. For more details, refer to + # [Custom Code](/verify/v2/documentation/custom-codes). + # + # @return [String, nil] + optional :custom_code, String + + # @!attribute locale + # A BCP-47 formatted locale string with the language the text message will be sent + # to. If there's no locale set, the language will be determined by the country + # code of the phone number. If the language specified doesn't exist, it defaults + # to US English. + # + # @return [String, nil] + optional :locale, String + + # @!attribute method_ + # The method used for verifying this phone number. The 'voice' option provides an + # accessible alternative for visually impaired users by delivering the + # verification code through a phone call rather than a text message. It also + # allows verification of landline numbers that cannot receive SMS messages. + # + # @return [Symbol, PreludeSDK::Models::VerificationCreateParams::Options::Method, nil] + optional :method_, + enum: -> { + PreludeSDK::VerificationCreateParams::Options::Method + }, + api_name: :method + + # @!attribute preferred_channel + # The preferred channel to be used in priority for verification. + # + # @return [Symbol, PreludeSDK::Models::VerificationCreateParams::Options::PreferredChannel, nil] + optional :preferred_channel, + enum: -> { + PreludeSDK::VerificationCreateParams::Options::PreferredChannel + } + + # @!attribute sender_id + # The Sender ID to use for this message. The Sender ID needs to be enabled by + # Prelude. + # + # @return [String, nil] + optional :sender_id, String + + # @!attribute template_id + # The identifier of a verification template. It applies use case-specific + # settings, such as the message content or certain verification parameters. + # + # @return [String, nil] + optional :template_id, String + + # @!attribute variables + # The variables to be replaced in the template. + # + # @return [Hash{Symbol=>String}, nil] + optional :variables, PreludeSDK::Internal::Type::HashOf[String] + + # @!method initialize(app_realm: nil, callback_url: nil, code_size: nil, custom_code: nil, locale: nil, method_: nil, preferred_channel: nil, sender_id: nil, template_id: nil, variables: nil) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::VerificationCreateParams::Options} for more details. + # + # Verification options + # + # @param app_realm [PreludeSDK::Models::VerificationCreateParams::Options::AppRealm] This allows you to automatically retrieve and fill the OTP code on mobile apps. + # + # @param callback_url [String] The URL where webhooks will be sent when verification events occur, including ve + # + # @param code_size [Integer] The size of the code generated. It should be between 4 and 8. Defaults to the co + # + # @param custom_code [String] The custom code to use for OTP verification. To use the custom code feature, con + # + # @param locale [String] A BCP-47 formatted locale string with the language the text message will be sent + # + # @param method_ [Symbol, PreludeSDK::Models::VerificationCreateParams::Options::Method] The method used for verifying this phone number. The 'voice' option provides an + # + # @param preferred_channel [Symbol, PreludeSDK::Models::VerificationCreateParams::Options::PreferredChannel] The preferred channel to be used in priority for verification. + # + # @param sender_id [String] The Sender ID to use for this message. The Sender ID needs to be enabled by Prel + # + # @param template_id [String] The identifier of a verification template. It applies use case-specific settings + # + # @param variables [Hash{Symbol=>String}] The variables to be replaced in the template. + + # @see PreludeSDK::Models::VerificationCreateParams::Options#app_realm + class AppRealm < PreludeSDK::Internal::Type::BaseModel + # @!attribute platform + # The platform the SMS will be sent to. We are currently only supporting + # "android". + # + # @return [Symbol, PreludeSDK::Models::VerificationCreateParams::Options::AppRealm::Platform] + required :platform, enum: -> { PreludeSDK::VerificationCreateParams::Options::AppRealm::Platform } + + # @!attribute value + # The Android SMS Retriever API hash code that identifies your app. + # + # @return [String] + required :value, String + + # @!method initialize(platform:, value:) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::VerificationCreateParams::Options::AppRealm} for more + # details. + # + # This allows you to automatically retrieve and fill the OTP code on mobile apps. + # Currently only Android devices are supported. + # + # @param platform [Symbol, PreludeSDK::Models::VerificationCreateParams::Options::AppRealm::Platform] The platform the SMS will be sent to. We are currently only supporting "android" + # + # @param value [String] The Android SMS Retriever API hash code that identifies your app. + + # The platform the SMS will be sent to. We are currently only supporting + # "android". + # + # @see PreludeSDK::Models::VerificationCreateParams::Options::AppRealm#platform + module Platform + extend PreludeSDK::Internal::Type::Enum + + ANDROID = :android + + # @!method self.values + # @return [Array] + end + end + + # The method used for verifying this phone number. The 'voice' option provides an + # accessible alternative for visually impaired users by delivering the + # verification code through a phone call rather than a text message. It also + # allows verification of landline numbers that cannot receive SMS messages. + # + # @see PreludeSDK::Models::VerificationCreateParams::Options#method_ + module Method + extend PreludeSDK::Internal::Type::Enum + + AUTO = :auto + VOICE = :voice + + # @!method self.values + # @return [Array] + end + + # The preferred channel to be used in priority for verification. + # + # @see PreludeSDK::Models::VerificationCreateParams::Options#preferred_channel + module PreferredChannel + extend PreludeSDK::Internal::Type::Enum + + SMS = :sms + RCS = :rcs + WHATSAPP = :whatsapp + VIBER = :viber + ZALO = :zalo + TELEGRAM = :telegram + SILENT = :silent + VOICE = :voice + + # @!method self.values + # @return [Array] + end + end + + class Signals < PreludeSDK::Internal::Type::BaseModel + # @!attribute app_version + # The version of your application. + # + # @return [String, nil] + optional :app_version, String + + # @!attribute device_id + # The unique identifier for the user's device. For Android, this corresponds to + # the `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + # + # @return [String, nil] + optional :device_id, String + + # @!attribute device_model + # The model of the user's device. + # + # @return [String, nil] + optional :device_model, String + + # @!attribute device_platform + # The type of the user's device. + # + # @return [Symbol, PreludeSDK::Models::VerificationCreateParams::Signals::DevicePlatform, nil] + optional :device_platform, enum: -> { PreludeSDK::VerificationCreateParams::Signals::DevicePlatform } + + # @!attribute ip + # The IP address of the user's device. + # + # @return [String, nil] + optional :ip, String + + # @!attribute is_trusted_user + # This signal should provide a higher level of trust, indicating that the user is + # genuine. Contact us to discuss your use case. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + # + # @return [Boolean, nil] + optional :is_trusted_user, PreludeSDK::Internal::Type::Boolean + + # @!attribute os_version + # The version of the user's device operating system. + # + # @return [String, nil] + optional :os_version, String + + # @!attribute user_agent + # The user agent of the user's device. If the individual fields (os_version, + # device_platform, device_model) are provided, we will prioritize those values + # instead of parsing them from the user agent string. + # + # @return [String, nil] + optional :user_agent, String + + # @!method initialize(app_version: nil, device_id: nil, device_model: nil, device_platform: nil, ip: nil, is_trusted_user: nil, os_version: nil, user_agent: nil) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::VerificationCreateParams::Signals} for more details. + # + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + # + # @param app_version [String] The version of your application. + # + # @param device_id [String] The unique identifier for the user's device. For Android, this corresponds to th + # + # @param device_model [String] The model of the user's device. + # + # @param device_platform [Symbol, PreludeSDK::Models::VerificationCreateParams::Signals::DevicePlatform] The type of the user's device. + # + # @param ip [String] The IP address of the user's device. + # + # @param is_trusted_user [Boolean] This signal should provide a higher level of trust, indicating that the user is + # + # @param os_version [String] The version of the user's device operating system. + # + # @param user_agent [String] The user agent of the user's device. If the individual fields (os_version, devic + + # The type of the user's device. + # + # @see PreludeSDK::Models::VerificationCreateParams::Signals#device_platform + module DevicePlatform + extend PreludeSDK::Internal::Type::Enum + + ANDROID = :android + IOS = :ios + IPADOS = :ipados + TVOS = :tvos + WEB = :web + + # @!method self.values + # @return [Array] + end + end + end + end +end diff --git a/lib/prelude_sdk/models/verification_create_response.rb b/lib/prelude_sdk/models/verification_create_response.rb new file mode 100644 index 00000000..df405655 --- /dev/null +++ b/lib/prelude_sdk/models/verification_create_response.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Verification#create + class VerificationCreateResponse < PreludeSDK::Internal::Type::BaseModel + # @!attribute id + # The verification identifier. + # + # @return [String] + required :id, String + + # @!attribute method_ + # The method used for verifying this phone number. + # + # @return [Symbol, PreludeSDK::Models::VerificationCreateResponse::Method] + required :method_, enum: -> { PreludeSDK::Models::VerificationCreateResponse::Method }, api_name: :method + + # @!attribute status + # The status of the verification. + # + # @return [Symbol, PreludeSDK::Models::VerificationCreateResponse::Status] + required :status, enum: -> { PreludeSDK::Models::VerificationCreateResponse::Status } + + # @!attribute channels + # The ordered sequence of channels to be used for verification + # + # @return [Array, nil] + optional :channels, PreludeSDK::Internal::Type::ArrayOf[String] + + # @!attribute metadata + # The metadata for this verification. + # + # @return [PreludeSDK::Models::VerificationCreateResponse::Metadata, nil] + optional :metadata, -> { PreludeSDK::Models::VerificationCreateResponse::Metadata } + + # @!attribute reason + # The reason why the verification was blocked. Only present when status is + # "blocked". + # + # @return [Symbol, PreludeSDK::Models::VerificationCreateResponse::Reason, nil] + optional :reason, enum: -> { PreludeSDK::Models::VerificationCreateResponse::Reason } + + # @!attribute request_id + # + # @return [String, nil] + optional :request_id, String + + # @!attribute silent + # The silent verification specific properties. + # + # @return [PreludeSDK::Models::VerificationCreateResponse::Silent, nil] + optional :silent, -> { PreludeSDK::Models::VerificationCreateResponse::Silent } + + # @!method initialize(id:, method_:, status:, channels: nil, metadata: nil, reason: nil, request_id: nil, silent: nil) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::VerificationCreateResponse} for more details. + # + # @param id [String] The verification identifier. + # + # @param method_ [Symbol, PreludeSDK::Models::VerificationCreateResponse::Method] The method used for verifying this phone number. + # + # @param status [Symbol, PreludeSDK::Models::VerificationCreateResponse::Status] The status of the verification. + # + # @param channels [Array] The ordered sequence of channels to be used for verification + # + # @param metadata [PreludeSDK::Models::VerificationCreateResponse::Metadata] The metadata for this verification. + # + # @param reason [Symbol, PreludeSDK::Models::VerificationCreateResponse::Reason] The reason why the verification was blocked. Only present when status is "blocke + # + # @param request_id [String] + # + # @param silent [PreludeSDK::Models::VerificationCreateResponse::Silent] The silent verification specific properties. + + # The method used for verifying this phone number. + # + # @see PreludeSDK::Models::VerificationCreateResponse#method_ + module Method + extend PreludeSDK::Internal::Type::Enum + + MESSAGE = :message + SILENT = :silent + VOICE = :voice + + # @!method self.values + # @return [Array] + end + + # The status of the verification. + # + # @see PreludeSDK::Models::VerificationCreateResponse#status + module Status + extend PreludeSDK::Internal::Type::Enum + + SUCCESS = :success + RETRY = :retry + BLOCKED = :blocked + + # @!method self.values + # @return [Array] + end + + # @see PreludeSDK::Models::VerificationCreateResponse#metadata + class Metadata < PreludeSDK::Internal::Type::BaseModel + # @!attribute correlation_id + # + # @return [String, nil] + optional :correlation_id, String + + # @!method initialize(correlation_id: nil) + # The metadata for this verification. + # + # @param correlation_id [String] + end + + # The reason why the verification was blocked. Only present when status is + # "blocked". + # + # @see PreludeSDK::Models::VerificationCreateResponse#reason + module Reason + extend PreludeSDK::Internal::Type::Enum + + SUSPICIOUS = :suspicious + REPEATED_ATTEMPTS = :repeated_attempts + INVALID_PHONE_LINE = :invalid_phone_line + INVALID_PHONE_NUMBER = :invalid_phone_number + IN_BLOCK_LIST = :in_block_list + + # @!method self.values + # @return [Array] + end + + # @see PreludeSDK::Models::VerificationCreateResponse#silent + class Silent < PreludeSDK::Internal::Type::BaseModel + # @!attribute request_url + # The URL to start the silent verification towards. + # + # @return [String] + required :request_url, String + + # @!method initialize(request_url:) + # The silent verification specific properties. + # + # @param request_url [String] The URL to start the silent verification towards. + end + end + end +end diff --git a/lib/prelude_sdk/models/watch_predict_params.rb b/lib/prelude_sdk/models/watch_predict_params.rb new file mode 100644 index 00000000..57422484 --- /dev/null +++ b/lib/prelude_sdk/models/watch_predict_params.rb @@ -0,0 +1,191 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Watch#predict + class WatchPredictParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + # @!attribute target + # The prediction target. Only supports phone numbers for now. + # + # @return [PreludeSDK::Models::WatchPredictParams::Target] + required :target, -> { PreludeSDK::WatchPredictParams::Target } + + # @!attribute dispatch_id + # The identifier of the dispatch that came from the front-end SDK. + # + # @return [String, nil] + optional :dispatch_id, String + + # @!attribute metadata + # The metadata for this prediction. + # + # @return [PreludeSDK::Models::WatchPredictParams::Metadata, nil] + optional :metadata, -> { PreludeSDK::WatchPredictParams::Metadata } + + # @!attribute signals + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + # + # @return [PreludeSDK::Models::WatchPredictParams::Signals, nil] + optional :signals, -> { PreludeSDK::WatchPredictParams::Signals } + + # @!method initialize(target:, dispatch_id: nil, metadata: nil, signals: nil, request_options: {}) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::WatchPredictParams} for more details. + # + # @param target [PreludeSDK::Models::WatchPredictParams::Target] The prediction target. Only supports phone numbers for now. + # + # @param dispatch_id [String] The identifier of the dispatch that came from the front-end SDK. + # + # @param metadata [PreludeSDK::Models::WatchPredictParams::Metadata] The metadata for this prediction. + # + # @param signals [PreludeSDK::Models::WatchPredictParams::Signals] The signals used for anti-fraud. For more details, refer to [Signals](/verify/v2 + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}] + + class Target < PreludeSDK::Internal::Type::BaseModel + # @!attribute type + # The type of the target. Either "phone_number" or "email_address". + # + # @return [Symbol, PreludeSDK::Models::WatchPredictParams::Target::Type] + required :type, enum: -> { PreludeSDK::WatchPredictParams::Target::Type } + + # @!attribute value + # An E.164 formatted phone number or an email address. + # + # @return [String] + required :value, String + + # @!method initialize(type:, value:) + # The prediction target. Only supports phone numbers for now. + # + # @param type [Symbol, PreludeSDK::Models::WatchPredictParams::Target::Type] The type of the target. Either "phone_number" or "email_address". + # + # @param value [String] An E.164 formatted phone number or an email address. + + # The type of the target. Either "phone_number" or "email_address". + # + # @see PreludeSDK::Models::WatchPredictParams::Target#type + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER = :phone_number + EMAIL_ADDRESS = :email_address + + # @!method self.values + # @return [Array] + end + end + + class Metadata < PreludeSDK::Internal::Type::BaseModel + # @!attribute correlation_id + # A user-defined identifier to correlate this prediction with. + # + # @return [String, nil] + optional :correlation_id, String + + # @!method initialize(correlation_id: nil) + # The metadata for this prediction. + # + # @param correlation_id [String] A user-defined identifier to correlate this prediction with. + end + + class Signals < PreludeSDK::Internal::Type::BaseModel + # @!attribute app_version + # The version of your application. + # + # @return [String, nil] + optional :app_version, String + + # @!attribute device_id + # The unique identifier for the user's device. For Android, this corresponds to + # the `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + # + # @return [String, nil] + optional :device_id, String + + # @!attribute device_model + # The model of the user's device. + # + # @return [String, nil] + optional :device_model, String + + # @!attribute device_platform + # The type of the user's device. + # + # @return [Symbol, PreludeSDK::Models::WatchPredictParams::Signals::DevicePlatform, nil] + optional :device_platform, enum: -> { PreludeSDK::WatchPredictParams::Signals::DevicePlatform } + + # @!attribute ip + # The IP address of the user's device. + # + # @return [String, nil] + optional :ip, String + + # @!attribute is_trusted_user + # This signal should provide a higher level of trust, indicating that the user is + # genuine. Contact us to discuss your use case. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + # + # @return [Boolean, nil] + optional :is_trusted_user, PreludeSDK::Internal::Type::Boolean + + # @!attribute os_version + # The version of the user's device operating system. + # + # @return [String, nil] + optional :os_version, String + + # @!attribute user_agent + # The user agent of the user's device. If the individual fields (os_version, + # device_platform, device_model) are provided, we will prioritize those values + # instead of parsing them from the user agent string. + # + # @return [String, nil] + optional :user_agent, String + + # @!method initialize(app_version: nil, device_id: nil, device_model: nil, device_platform: nil, ip: nil, is_trusted_user: nil, os_version: nil, user_agent: nil) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::WatchPredictParams::Signals} for more details. + # + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + # + # @param app_version [String] The version of your application. + # + # @param device_id [String] The unique identifier for the user's device. For Android, this corresponds to th + # + # @param device_model [String] The model of the user's device. + # + # @param device_platform [Symbol, PreludeSDK::Models::WatchPredictParams::Signals::DevicePlatform] The type of the user's device. + # + # @param ip [String] The IP address of the user's device. + # + # @param is_trusted_user [Boolean] This signal should provide a higher level of trust, indicating that the user is + # + # @param os_version [String] The version of the user's device operating system. + # + # @param user_agent [String] The user agent of the user's device. If the individual fields (os_version, devic + + # The type of the user's device. + # + # @see PreludeSDK::Models::WatchPredictParams::Signals#device_platform + module DevicePlatform + extend PreludeSDK::Internal::Type::Enum + + ANDROID = :android + IOS = :ios + IPADOS = :ipados + TVOS = :tvos + WEB = :web + + # @!method self.values + # @return [Array] + end + end + end + end +end diff --git a/lib/prelude_sdk/models/watch_predict_response.rb b/lib/prelude_sdk/models/watch_predict_response.rb new file mode 100644 index 00000000..a0e16f3c --- /dev/null +++ b/lib/prelude_sdk/models/watch_predict_response.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Watch#predict + class WatchPredictResponse < PreludeSDK::Internal::Type::BaseModel + # @!attribute id + # The prediction identifier. + # + # @return [String] + required :id, String + + # @!attribute prediction + # The prediction outcome. + # + # @return [Symbol, PreludeSDK::Models::WatchPredictResponse::Prediction] + required :prediction, enum: -> { PreludeSDK::Models::WatchPredictResponse::Prediction } + + # @!attribute request_id + # A string that identifies this specific request. Report it back to us to help us + # diagnose your issues. + # + # @return [String] + required :request_id, String + + # @!method initialize(id:, prediction:, request_id:) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::WatchPredictResponse} for more details. + # + # @param id [String] The prediction identifier. + # + # @param prediction [Symbol, PreludeSDK::Models::WatchPredictResponse::Prediction] The prediction outcome. + # + # @param request_id [String] A string that identifies this specific request. Report it back to us to help us + + # The prediction outcome. + # + # @see PreludeSDK::Models::WatchPredictResponse#prediction + module Prediction + extend PreludeSDK::Internal::Type::Enum + + LEGITIMATE = :legitimate + SUSPICIOUS = :suspicious + + # @!method self.values + # @return [Array] + end + end + end +end diff --git a/lib/prelude_sdk/models/watch_send_events_params.rb b/lib/prelude_sdk/models/watch_send_events_params.rb new file mode 100644 index 00000000..0a6464da --- /dev/null +++ b/lib/prelude_sdk/models/watch_send_events_params.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Watch#send_events + class WatchSendEventsParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + # @!attribute events + # A list of events to dispatch. + # + # @return [Array] + required :events, -> { PreludeSDK::Internal::Type::ArrayOf[PreludeSDK::WatchSendEventsParams::Event] } + + # @!method initialize(events:, request_options: {}) + # @param events [Array] A list of events to dispatch. + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}] + + class Event < PreludeSDK::Internal::Type::BaseModel + # @!attribute confidence + # A confidence level you want to assign to the event. + # + # @return [Symbol, PreludeSDK::Models::WatchSendEventsParams::Event::Confidence] + required :confidence, enum: -> { PreludeSDK::WatchSendEventsParams::Event::Confidence } + + # @!attribute label + # A label to describe what the event refers to. + # + # @return [String] + required :label, String + + # @!attribute target + # The event target. Only supports phone numbers for now. + # + # @return [PreludeSDK::Models::WatchSendEventsParams::Event::Target] + required :target, -> { PreludeSDK::WatchSendEventsParams::Event::Target } + + # @!method initialize(confidence:, label:, target:) + # @param confidence [Symbol, PreludeSDK::Models::WatchSendEventsParams::Event::Confidence] A confidence level you want to assign to the event. + # + # @param label [String] A label to describe what the event refers to. + # + # @param target [PreludeSDK::Models::WatchSendEventsParams::Event::Target] The event target. Only supports phone numbers for now. + + # A confidence level you want to assign to the event. + # + # @see PreludeSDK::Models::WatchSendEventsParams::Event#confidence + module Confidence + extend PreludeSDK::Internal::Type::Enum + + MAXIMUM = :maximum + HIGH = :high + NEUTRAL = :neutral + LOW = :low + MINIMUM = :minimum + + # @!method self.values + # @return [Array] + end + + # @see PreludeSDK::Models::WatchSendEventsParams::Event#target + class Target < PreludeSDK::Internal::Type::BaseModel + # @!attribute type + # The type of the target. Either "phone_number" or "email_address". + # + # @return [Symbol, PreludeSDK::Models::WatchSendEventsParams::Event::Target::Type] + required :type, enum: -> { PreludeSDK::WatchSendEventsParams::Event::Target::Type } + + # @!attribute value + # An E.164 formatted phone number or an email address. + # + # @return [String] + required :value, String + + # @!method initialize(type:, value:) + # The event target. Only supports phone numbers for now. + # + # @param type [Symbol, PreludeSDK::Models::WatchSendEventsParams::Event::Target::Type] The type of the target. Either "phone_number" or "email_address". + # + # @param value [String] An E.164 formatted phone number or an email address. + + # The type of the target. Either "phone_number" or "email_address". + # + # @see PreludeSDK::Models::WatchSendEventsParams::Event::Target#type + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER = :phone_number + EMAIL_ADDRESS = :email_address + + # @!method self.values + # @return [Array] + end + end + end + end + end +end diff --git a/lib/prelude_sdk/models/watch_send_events_response.rb b/lib/prelude_sdk/models/watch_send_events_response.rb new file mode 100644 index 00000000..a9495a2c --- /dev/null +++ b/lib/prelude_sdk/models/watch_send_events_response.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Watch#send_events + class WatchSendEventsResponse < PreludeSDK::Internal::Type::BaseModel + # @!attribute request_id + # A string that identifies this specific request. Report it back to us to help us + # diagnose your issues. + # + # @return [String] + required :request_id, String + + # @!attribute status + # The status of the events dispatch. + # + # @return [Symbol, PreludeSDK::Models::WatchSendEventsResponse::Status] + required :status, enum: -> { PreludeSDK::Models::WatchSendEventsResponse::Status } + + # @!method initialize(request_id:, status:) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::WatchSendEventsResponse} for more details. + # + # @param request_id [String] A string that identifies this specific request. Report it back to us to help us + # + # @param status [Symbol, PreludeSDK::Models::WatchSendEventsResponse::Status] The status of the events dispatch. + + # The status of the events dispatch. + # + # @see PreludeSDK::Models::WatchSendEventsResponse#status + module Status + extend PreludeSDK::Internal::Type::Enum + + SUCCESS = :success + + # @!method self.values + # @return [Array] + end + end + end +end diff --git a/lib/prelude_sdk/models/watch_send_feedbacks_params.rb b/lib/prelude_sdk/models/watch_send_feedbacks_params.rb new file mode 100644 index 00000000..afa975f4 --- /dev/null +++ b/lib/prelude_sdk/models/watch_send_feedbacks_params.rb @@ -0,0 +1,229 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Watch#send_feedbacks + class WatchSendFeedbacksParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + # @!attribute feedbacks + # A list of feedbacks to send. + # + # @return [Array] + required :feedbacks, + -> { PreludeSDK::Internal::Type::ArrayOf[PreludeSDK::WatchSendFeedbacksParams::Feedback] } + + # @!method initialize(feedbacks:, request_options: {}) + # @param feedbacks [Array] A list of feedbacks to send. + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}] + + class Feedback < PreludeSDK::Internal::Type::BaseModel + # @!attribute target + # The feedback target. Only supports phone numbers for now. + # + # @return [PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target] + required :target, -> { PreludeSDK::WatchSendFeedbacksParams::Feedback::Target } + + # @!attribute type + # The type of feedback. + # + # @return [Symbol, PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Type] + required :type, enum: -> { PreludeSDK::WatchSendFeedbacksParams::Feedback::Type } + + # @!attribute dispatch_id + # The identifier of the dispatch that came from the front-end SDK. + # + # @return [String, nil] + optional :dispatch_id, String + + # @!attribute metadata + # The metadata for this feedback. + # + # @return [PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Metadata, nil] + optional :metadata, -> { PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata } + + # @!attribute signals + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + # + # @return [PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals, nil] + optional :signals, -> { PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals } + + # @!method initialize(target:, type:, dispatch_id: nil, metadata: nil, signals: nil) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::WatchSendFeedbacksParams::Feedback} for more details. + # + # @param target [PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target] The feedback target. Only supports phone numbers for now. + # + # @param type [Symbol, PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Type] The type of feedback. + # + # @param dispatch_id [String] The identifier of the dispatch that came from the front-end SDK. + # + # @param metadata [PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Metadata] The metadata for this feedback. + # + # @param signals [PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals] The signals used for anti-fraud. For more details, refer to [Signals](/verify/v2 + + # @see PreludeSDK::Models::WatchSendFeedbacksParams::Feedback#target + class Target < PreludeSDK::Internal::Type::BaseModel + # @!attribute type + # The type of the target. Either "phone_number" or "email_address". + # + # @return [Symbol, PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target::Type] + required :type, enum: -> { PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::Type } + + # @!attribute value + # An E.164 formatted phone number or an email address. + # + # @return [String] + required :value, String + + # @!method initialize(type:, value:) + # The feedback target. Only supports phone numbers for now. + # + # @param type [Symbol, PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target::Type] The type of the target. Either "phone_number" or "email_address". + # + # @param value [String] An E.164 formatted phone number or an email address. + + # The type of the target. Either "phone_number" or "email_address". + # + # @see PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target#type + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER = :phone_number + EMAIL_ADDRESS = :email_address + + # @!method self.values + # @return [Array] + end + end + + # The type of feedback. + # + # @see PreludeSDK::Models::WatchSendFeedbacksParams::Feedback#type + module Type + extend PreludeSDK::Internal::Type::Enum + + VERIFICATION_STARTED = :"verification.started" + VERIFICATION_COMPLETED = :"verification.completed" + + # @!method self.values + # @return [Array] + end + + # @see PreludeSDK::Models::WatchSendFeedbacksParams::Feedback#metadata + class Metadata < PreludeSDK::Internal::Type::BaseModel + # @!attribute correlation_id + # A user-defined identifier to correlate this feedback with. + # + # @return [String, nil] + optional :correlation_id, String + + # @!method initialize(correlation_id: nil) + # The metadata for this feedback. + # + # @param correlation_id [String] A user-defined identifier to correlate this feedback with. + end + + # @see PreludeSDK::Models::WatchSendFeedbacksParams::Feedback#signals + class Signals < PreludeSDK::Internal::Type::BaseModel + # @!attribute app_version + # The version of your application. + # + # @return [String, nil] + optional :app_version, String + + # @!attribute device_id + # The unique identifier for the user's device. For Android, this corresponds to + # the `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + # + # @return [String, nil] + optional :device_id, String + + # @!attribute device_model + # The model of the user's device. + # + # @return [String, nil] + optional :device_model, String + + # @!attribute device_platform + # The type of the user's device. + # + # @return [Symbol, PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform, nil] + optional :device_platform, + enum: -> { PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform } + + # @!attribute ip + # The IP address of the user's device. + # + # @return [String, nil] + optional :ip, String + + # @!attribute is_trusted_user + # This signal should provide a higher level of trust, indicating that the user is + # genuine. Contact us to discuss your use case. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + # + # @return [Boolean, nil] + optional :is_trusted_user, PreludeSDK::Internal::Type::Boolean + + # @!attribute os_version + # The version of the user's device operating system. + # + # @return [String, nil] + optional :os_version, String + + # @!attribute user_agent + # The user agent of the user's device. If the individual fields (os_version, + # device_platform, device_model) are provided, we will prioritize those values + # instead of parsing them from the user agent string. + # + # @return [String, nil] + optional :user_agent, String + + # @!method initialize(app_version: nil, device_id: nil, device_model: nil, device_platform: nil, ip: nil, is_trusted_user: nil, os_version: nil, user_agent: nil) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals} for more + # details. + # + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + # + # @param app_version [String] The version of your application. + # + # @param device_id [String] The unique identifier for the user's device. For Android, this corresponds to th + # + # @param device_model [String] The model of the user's device. + # + # @param device_platform [Symbol, PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform] The type of the user's device. + # + # @param ip [String] The IP address of the user's device. + # + # @param is_trusted_user [Boolean] This signal should provide a higher level of trust, indicating that the user is + # + # @param os_version [String] The version of the user's device operating system. + # + # @param user_agent [String] The user agent of the user's device. If the individual fields (os_version, devic + + # The type of the user's device. + # + # @see PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals#device_platform + module DevicePlatform + extend PreludeSDK::Internal::Type::Enum + + ANDROID = :android + IOS = :ios + IPADOS = :ipados + TVOS = :tvos + WEB = :web + + # @!method self.values + # @return [Array] + end + end + end + end + end +end diff --git a/lib/prelude_sdk/models/watch_send_feedbacks_response.rb b/lib/prelude_sdk/models/watch_send_feedbacks_response.rb new file mode 100644 index 00000000..1374e706 --- /dev/null +++ b/lib/prelude_sdk/models/watch_send_feedbacks_response.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module PreludeSDK + module Models + # @see PreludeSDK::Resources::Watch#send_feedbacks + class WatchSendFeedbacksResponse < PreludeSDK::Internal::Type::BaseModel + # @!attribute request_id + # A string that identifies this specific request. Report it back to us to help us + # diagnose your issues. + # + # @return [String] + required :request_id, String + + # @!attribute status + # The status of the feedbacks sending. + # + # @return [Symbol, PreludeSDK::Models::WatchSendFeedbacksResponse::Status] + required :status, enum: -> { PreludeSDK::Models::WatchSendFeedbacksResponse::Status } + + # @!method initialize(request_id:, status:) + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::WatchSendFeedbacksResponse} for more details. + # + # @param request_id [String] A string that identifies this specific request. Report it back to us to help us + # + # @param status [Symbol, PreludeSDK::Models::WatchSendFeedbacksResponse::Status] The status of the feedbacks sending. + + # The status of the feedbacks sending. + # + # @see PreludeSDK::Models::WatchSendFeedbacksResponse#status + module Status + extend PreludeSDK::Internal::Type::Enum + + SUCCESS = :success + + # @!method self.values + # @return [Array] + end + end + end +end diff --git a/lib/prelude_sdk/request_options.rb b/lib/prelude_sdk/request_options.rb new file mode 100644 index 00000000..7d0bda9a --- /dev/null +++ b/lib/prelude_sdk/request_options.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module PreludeSDK + # Specify HTTP behaviour to use for a specific request. These options supplement + # or override those provided at the client level. + # + # When making a request, you can pass an actual {RequestOptions} instance, or + # simply pass a Hash with symbol keys matching the attributes on this class. + class RequestOptions < PreludeSDK::Internal::Type::BaseModel + # @api private + # + # @param opts [PreludeSDK::RequestOptions, Hash{Symbol=>Object}] + # + # @raise [ArgumentError] + def self.validate!(opts) + case opts + in PreludeSDK::RequestOptions | Hash + opts.to_h.each_key do |k| + unless fields.include?(k) + raise ArgumentError.new("Request `opts` keys must be one of #{fields.keys}, got #{k.inspect}") + end + end + else + raise ArgumentError.new("Request `opts` must be a Hash or RequestOptions, got #{opts.inspect}") + end + end + + # @!attribute idempotency_key + # Idempotency key to send with request and all associated retries. Will only be + # sent for write requests. + # + # @return [String, nil] + optional :idempotency_key, String + + # @!attribute extra_query + # Extra query params to send with the request. These are `.merge`’d into any + # `query` given at the client level. + # + # @return [Hash{String=>Array, String, nil}, nil] + optional :extra_query, PreludeSDK::Internal::Type::HashOf[PreludeSDK::Internal::Type::ArrayOf[String]] + + # @!attribute extra_headers + # Extra headers to send with the request. These are `.merged`’d into any + # `extra_headers` given at the client level. + # + # @return [Hash{String=>String, nil}, nil] + optional :extra_headers, PreludeSDK::Internal::Type::HashOf[String, nil?: true] + + # @!attribute extra_body + # Extra data to send with the request. These are deep merged into any data + # generated as part of the normal request. + # + # @return [Object, nil] + optional :extra_body, PreludeSDK::Internal::Type::HashOf[PreludeSDK::Internal::Type::Unknown] + + # @!attribute max_retries + # Maximum number of retries to attempt after a failed initial request. + # + # @return [Integer, nil] + optional :max_retries, Integer + + # @!attribute timeout + # Request timeout in seconds. + # + # @return [Float, nil] + optional :timeout, Float + + # @!method initialize(values = {}) + # Returns a new instance of RequestOptions. + # + # @param values [Hash{Symbol=>Object}] + + define_sorbet_constant!(:OrHash) do + T.type_alias { T.any(PreludeSDK::RequestOptions, PreludeSDK::Internal::AnyHash) } + end + end +end diff --git a/lib/prelude_sdk/resources/lookup.rb b/lib/prelude_sdk/resources/lookup.rb new file mode 100644 index 00000000..ea5b3566 --- /dev/null +++ b/lib/prelude_sdk/resources/lookup.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module PreludeSDK + module Resources + class Lookup + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::LookupLookupParams} for more details. + # + # Retrieve detailed information about a phone number including carrier data, line + # type, and portability status. + # + # @overload lookup(phone_number, type: nil, request_options: {}) + # + # @param phone_number [String] An E.164 formatted phone number to look up. + # + # @param type [Array] Optional features. Possible values are: + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}, nil] + # + # @return [PreludeSDK::Models::LookupLookupResponse] + # + # @see PreludeSDK::Models::LookupLookupParams + def lookup(phone_number, params = {}) + parsed, options = PreludeSDK::LookupLookupParams.dump_request(params) + @client.request( + method: :get, + path: ["v2/lookup/%1$s", phone_number], + query: parsed, + model: PreludeSDK::Models::LookupLookupResponse, + options: options + ) + end + + # @api private + # + # @param client [PreludeSDK::Client] + def initialize(client:) + @client = client + end + end + end +end diff --git a/lib/prelude_sdk/resources/transactional.rb b/lib/prelude_sdk/resources/transactional.rb new file mode 100644 index 00000000..65ba63cc --- /dev/null +++ b/lib/prelude_sdk/resources/transactional.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module PreludeSDK + module Resources + class Transactional + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::TransactionalSendParams} for more details. + # + # Send a transactional message to your user. + # + # @overload send_(template_id:, to:, callback_url: nil, correlation_id: nil, expires_at: nil, from: nil, locale: nil, variables: nil, request_options: {}) + # + # @param template_id [String] The template identifier. + # + # @param to [String] The recipient's phone number. + # + # @param callback_url [String] The callback URL. + # + # @param correlation_id [String] A unique, user-defined identifier that will be included in webhook events. + # + # @param expires_at [String] The message expiration date. + # + # @param from [String] The Sender ID. + # + # @param locale [String] A BCP-47 formatted locale string with the language the text message will be sent + # + # @param variables [Hash{Symbol=>String}] The variables to be replaced in the template. + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}, nil] + # + # @return [PreludeSDK::Models::TransactionalSendResponse] + # + # @see PreludeSDK::Models::TransactionalSendParams + def send_(params) + parsed, options = PreludeSDK::TransactionalSendParams.dump_request(params) + @client.request( + method: :post, + path: "v2/transactional", + body: parsed, + model: PreludeSDK::Models::TransactionalSendResponse, + options: options + ) + end + + # @api private + # + # @param client [PreludeSDK::Client] + def initialize(client:) + @client = client + end + end + end +end diff --git a/lib/prelude_sdk/resources/verification.rb b/lib/prelude_sdk/resources/verification.rb new file mode 100644 index 00000000..721dee9c --- /dev/null +++ b/lib/prelude_sdk/resources/verification.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +module PreludeSDK + module Resources + class Verification + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::VerificationCreateParams} for more details. + # + # Create a new verification for a specific phone number. If another non-expired + # verification exists (the request is performed within the verification window), + # this endpoint will perform a retry instead. + # + # @overload create(target:, dispatch_id: nil, metadata: nil, options: nil, signals: nil, request_options: {}) + # + # @param target [PreludeSDK::Models::VerificationCreateParams::Target] The verification target. Either a phone number or an email address. To use the e + # + # @param dispatch_id [String] The identifier of the dispatch that came from the front-end SDK. + # + # @param metadata [PreludeSDK::Models::VerificationCreateParams::Metadata] The metadata for this verification. This object will be returned with every resp + # + # @param options [PreludeSDK::Models::VerificationCreateParams::Options] Verification options + # + # @param signals [PreludeSDK::Models::VerificationCreateParams::Signals] The signals used for anti-fraud. For more details, refer to [Signals](/verify/v2 + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}, nil] + # + # @return [PreludeSDK::Models::VerificationCreateResponse] + # + # @see PreludeSDK::Models::VerificationCreateParams + def create(params) + parsed, options = PreludeSDK::VerificationCreateParams.dump_request(params) + @client.request( + method: :post, + path: "v2/verification", + body: parsed, + model: PreludeSDK::Models::VerificationCreateResponse, + options: options + ) + end + + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::VerificationCheckParams} for more details. + # + # Check the validity of a verification code. + # + # @overload check(code:, target:, request_options: {}) + # + # @param code [String] The OTP code to validate. + # + # @param target [PreludeSDK::Models::VerificationCheckParams::Target] The verification target. Either a phone number or an email address. To use the e + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}, nil] + # + # @return [PreludeSDK::Models::VerificationCheckResponse] + # + # @see PreludeSDK::Models::VerificationCheckParams + def check(params) + parsed, options = PreludeSDK::VerificationCheckParams.dump_request(params) + @client.request( + method: :post, + path: "v2/verification/check", + body: parsed, + model: PreludeSDK::Models::VerificationCheckResponse, + options: options + ) + end + + # @api private + # + # @param client [PreludeSDK::Client] + def initialize(client:) + @client = client + end + end + end +end diff --git a/lib/prelude_sdk/resources/watch.rb b/lib/prelude_sdk/resources/watch.rb new file mode 100644 index 00000000..ed071fdc --- /dev/null +++ b/lib/prelude_sdk/resources/watch.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +module PreludeSDK + module Resources + class Watch + # Some parameter documentations has been truncated, see + # {PreludeSDK::Models::WatchPredictParams} for more details. + # + # Predict the outcome of a verification based on Prelude’s anti-fraud system. + # + # @overload predict(target:, dispatch_id: nil, metadata: nil, signals: nil, request_options: {}) + # + # @param target [PreludeSDK::Models::WatchPredictParams::Target] The prediction target. Only supports phone numbers for now. + # + # @param dispatch_id [String] The identifier of the dispatch that came from the front-end SDK. + # + # @param metadata [PreludeSDK::Models::WatchPredictParams::Metadata] The metadata for this prediction. + # + # @param signals [PreludeSDK::Models::WatchPredictParams::Signals] The signals used for anti-fraud. For more details, refer to [Signals](/verify/v2 + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}, nil] + # + # @return [PreludeSDK::Models::WatchPredictResponse] + # + # @see PreludeSDK::Models::WatchPredictParams + def predict(params) + parsed, options = PreludeSDK::WatchPredictParams.dump_request(params) + @client.request( + method: :post, + path: "v2/watch/predict", + body: parsed, + model: PreludeSDK::Models::WatchPredictResponse, + options: options + ) + end + + # Send real-time event data from end-user interactions within your application. + # Events will be analyzed for proactive fraud prevention and risk scoring. + # + # @overload send_events(events:, request_options: {}) + # + # @param events [Array] A list of events to dispatch. + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}, nil] + # + # @return [PreludeSDK::Models::WatchSendEventsResponse] + # + # @see PreludeSDK::Models::WatchSendEventsParams + def send_events(params) + parsed, options = PreludeSDK::WatchSendEventsParams.dump_request(params) + @client.request( + method: :post, + path: "v2/watch/event", + body: parsed, + model: PreludeSDK::Models::WatchSendEventsResponse, + options: options + ) + end + + # Send feedback regarding your end-users verification funnel. Events will be + # analyzed for proactive fraud prevention and risk scoring. + # + # @overload send_feedbacks(feedbacks:, request_options: {}) + # + # @param feedbacks [Array] A list of feedbacks to send. + # + # @param request_options [PreludeSDK::RequestOptions, Hash{Symbol=>Object}, nil] + # + # @return [PreludeSDK::Models::WatchSendFeedbacksResponse] + # + # @see PreludeSDK::Models::WatchSendFeedbacksParams + def send_feedbacks(params) + parsed, options = PreludeSDK::WatchSendFeedbacksParams.dump_request(params) + @client.request( + method: :post, + path: "v2/watch/feedback", + body: parsed, + model: PreludeSDK::Models::WatchSendFeedbacksResponse, + options: options + ) + end + + # @api private + # + # @param client [PreludeSDK::Client] + def initialize(client:) + @client = client + end + end + end +end diff --git a/lib/prelude_sdk/version.rb b/lib/prelude_sdk/version.rb new file mode 100644 index 00000000..679f6fd4 --- /dev/null +++ b/lib/prelude_sdk/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module PreludeSDK + VERSION = "0.1.0.pre.alpha.2" +end diff --git a/manifest.yaml b/manifest.yaml new file mode 100644 index 00000000..556686f5 --- /dev/null +++ b/manifest.yaml @@ -0,0 +1,15 @@ +dependencies: + - English + - cgi + - date + - erb + - etc + - json + - net/http + - pathname + - rbconfig + - securerandom + - set + - stringio + - time + - uri diff --git a/prelude.gemspec b/prelude.gemspec deleted file mode 100644 index 6a34c990..00000000 --- a/prelude.gemspec +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require_relative "lib/prelude/version" - -Gem::Specification.new do |s| - s.name = "prelude" - s.version = Prelude::VERSION - s.summary = "Ruby library to access the Prelude API" - s.authors = ["Prelude"] - s.email = "hello@prelude.so" - s.files = Dir["lib/**/*.rb"] - s.extra_rdoc_files = ["README.md"] - s.required_ruby_version = ">= 3.0.0" - s.add_dependency "connection_pool" - s.homepage = "https://rubydoc.info/github/prelude-so/ruby-sdk" - s.metadata["homepage_uri"] = s.homepage - s.metadata["source_code_uri"] = "https://github.com/prelude-so/ruby-sdk" - s.metadata["rubygems_mfa_required"] = "true" -end diff --git a/prelude_sdk.gemspec b/prelude_sdk.gemspec new file mode 100644 index 00000000..f8bdce2a --- /dev/null +++ b/prelude_sdk.gemspec @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require_relative "lib/prelude_sdk/version" + +Gem::Specification.new do |s| + s.name = "prelude-sdk" + s.version = PreludeSDK::VERSION + s.summary = "Ruby library to access the Prelude API" + s.authors = ["Prelude"] + s.email = "hello@prelude.so" + s.homepage = "https://gemdocs.org/gems/prelude-sdk" + s.metadata["homepage_uri"] = s.homepage + s.metadata["source_code_uri"] = "https://github.com/prelude-so/ruby-sdk" + s.metadata["rubygems_mfa_required"] = false.to_s + s.required_ruby_version = ">= 3.2.0" + + s.files = Dir[ + "lib/**/*.rb", + "rbi/**/*.rbi", + "sig/**/*.rbs", + "manifest.yaml", + "SECURITY.md", + "CHANGELOG.md", + ".ignore" + ] + s.extra_rdoc_files = ["README.md"] + s.add_dependency "connection_pool" +end diff --git a/rbi/prelude_sdk/client.rbi b/rbi/prelude_sdk/client.rbi new file mode 100644 index 00000000..3993294f --- /dev/null +++ b/rbi/prelude_sdk/client.rbi @@ -0,0 +1,59 @@ +# typed: strong + +module PreludeSDK + class Client < PreludeSDK::Internal::Transport::BaseClient + DEFAULT_MAX_RETRIES = 2 + + DEFAULT_TIMEOUT_IN_SECONDS = T.let(60.0, Float) + + DEFAULT_INITIAL_RETRY_DELAY = T.let(0.5, Float) + + DEFAULT_MAX_RETRY_DELAY = T.let(8.0, Float) + + # Bearer token for authorizing API requests. + sig { returns(String) } + attr_reader :api_token + + sig { returns(PreludeSDK::Resources::Lookup) } + attr_reader :lookup + + sig { returns(PreludeSDK::Resources::Transactional) } + attr_reader :transactional + + sig { returns(PreludeSDK::Resources::Verification) } + attr_reader :verification + + sig { returns(PreludeSDK::Resources::Watch) } + attr_reader :watch + + # @api private + sig { override.returns(T::Hash[String, String]) } + private def auth_headers + end + + # Creates and returns a new client for interacting with the API. + sig do + params( + api_token: T.nilable(String), + base_url: T.nilable(String), + max_retries: Integer, + timeout: Float, + initial_retry_delay: Float, + max_retry_delay: Float + ).returns(T.attached_class) + end + def self.new( + # Bearer token for authorizing API requests. Defaults to `ENV["API_TOKEN"]` + api_token: ENV["API_TOKEN"], + # Override the default base URL for the API, e.g., + # `"https://api.example.com/v2/"`. Defaults to `ENV["PRELUDE_BASE_URL"]` + base_url: ENV["PRELUDE_BASE_URL"], + # Max number of retries to attempt after a failed retryable request. + max_retries: PreludeSDK::Client::DEFAULT_MAX_RETRIES, + timeout: PreludeSDK::Client::DEFAULT_TIMEOUT_IN_SECONDS, + initial_retry_delay: PreludeSDK::Client::DEFAULT_INITIAL_RETRY_DELAY, + max_retry_delay: PreludeSDK::Client::DEFAULT_MAX_RETRY_DELAY + ) + end + end +end diff --git a/rbi/prelude_sdk/errors.rbi b/rbi/prelude_sdk/errors.rbi new file mode 100644 index 00000000..9700ed96 --- /dev/null +++ b/rbi/prelude_sdk/errors.rbi @@ -0,0 +1,178 @@ +# typed: strong + +module PreludeSDK + module Errors + class Error < StandardError + sig { returns(T.nilable(StandardError)) } + attr_accessor :cause + end + + class ConversionError < PreludeSDK::Errors::Error + sig { returns(T.nilable(StandardError)) } + def cause + end + + # @api private + sig do + params( + on: T::Class[StandardError], + method: Symbol, + target: T.anything, + value: T.anything, + cause: T.nilable(StandardError) + ).returns(T.attached_class) + end + def self.new(on:, method:, target:, value:, cause: nil) + end + end + + class APIError < PreludeSDK::Errors::Error + sig { returns(URI::Generic) } + attr_accessor :url + + sig { returns(T.nilable(Integer)) } + attr_accessor :status + + sig { returns(T.nilable(T.anything)) } + attr_accessor :body + + # @api private + sig do + params( + url: URI::Generic, + status: T.nilable(Integer), + body: T.nilable(Object), + request: NilClass, + response: NilClass, + message: T.nilable(String) + ).returns(T.attached_class) + end + def self.new( + url:, + status: nil, + body: nil, + request: nil, + response: nil, + message: nil + ) + end + end + + class APIConnectionError < PreludeSDK::Errors::APIError + sig { void } + attr_accessor :status + + sig { void } + attr_accessor :body + + # @api private + sig do + params( + url: URI::Generic, + status: NilClass, + body: NilClass, + request: NilClass, + response: NilClass, + message: T.nilable(String) + ).returns(T.attached_class) + end + def self.new( + url:, + status: nil, + body: nil, + request: nil, + response: nil, + message: "Connection error." + ) + end + end + + class APITimeoutError < PreludeSDK::Errors::APIConnectionError + # @api private + sig do + params( + url: URI::Generic, + status: NilClass, + body: NilClass, + request: NilClass, + response: NilClass, + message: T.nilable(String) + ).returns(T.attached_class) + end + def self.new( + url:, + status: nil, + body: nil, + request: nil, + response: nil, + message: "Request timed out." + ) + end + end + + class APIStatusError < PreludeSDK::Errors::APIError + # @api private + sig do + params( + url: URI::Generic, + status: Integer, + body: T.nilable(Object), + request: NilClass, + response: NilClass, + message: T.nilable(String) + ).returns(T.attached_class) + end + def self.for(url:, status:, body:, request:, response:, message: nil) + end + + sig { returns(Integer) } + attr_accessor :status + + # @api private + sig do + params( + url: URI::Generic, + status: Integer, + body: T.nilable(Object), + request: NilClass, + response: NilClass, + message: T.nilable(String) + ).returns(T.attached_class) + end + def self.new(url:, status:, body:, request:, response:, message: nil) + end + end + + class BadRequestError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 400 + end + + class AuthenticationError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 401 + end + + class PermissionDeniedError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 403 + end + + class NotFoundError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 404 + end + + class ConflictError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 409 + end + + class UnprocessableEntityError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 422 + end + + class RateLimitError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = 429 + end + + class InternalServerError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS = T.let((500..), T::Range[Integer]) + end + end +end diff --git a/rbi/prelude_sdk/file_part.rbi b/rbi/prelude_sdk/file_part.rbi new file mode 100644 index 00000000..5e975788 --- /dev/null +++ b/rbi/prelude_sdk/file_part.rbi @@ -0,0 +1,37 @@ +# typed: strong + +module PreludeSDK + class FilePart + sig { returns(T.any(Pathname, StringIO, IO, String)) } + attr_reader :content + + sig { returns(T.nilable(String)) } + attr_reader :content_type + + sig { returns(T.nilable(String)) } + attr_reader :filename + + # @api private + sig { returns(String) } + private def read + end + + sig { params(a: T.anything).returns(String) } + def to_json(*a) + end + + sig { params(a: T.anything).returns(String) } + def to_yaml(*a) + end + + sig do + params( + content: T.any(Pathname, StringIO, IO, String), + filename: T.nilable(String), + content_type: T.nilable(String) + ).returns(T.attached_class) + end + def self.new(content, filename: nil, content_type: nil) + end + end +end diff --git a/rbi/prelude_sdk/internal.rbi b/rbi/prelude_sdk/internal.rbi new file mode 100644 index 00000000..899e480f --- /dev/null +++ b/rbi/prelude_sdk/internal.rbi @@ -0,0 +1,18 @@ +# typed: strong + +module PreludeSDK + module Internal + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # Due to the current WIP status of Shapes support in Sorbet, types referencing + # this alias might be refined in the future. + AnyHash = T.type_alias { T::Hash[Symbol, T.anything] } + + FileInput = + T.type_alias do + T.any(Pathname, StringIO, IO, String, PreludeSDK::FilePart) + end + + OMIT = T.let(Object.new.freeze, T.anything) + end +end diff --git a/rbi/prelude_sdk/internal/transport/base_client.rbi b/rbi/prelude_sdk/internal/transport/base_client.rbi new file mode 100644 index 00000000..c0e5935a --- /dev/null +++ b/rbi/prelude_sdk/internal/transport/base_client.rbi @@ -0,0 +1,296 @@ +# typed: strong + +module PreludeSDK + module Internal + module Transport + # @api private + class BaseClient + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + abstract! + + RequestComponents = + T.type_alias do + { + method: Symbol, + path: T.any(String, T::Array[String]), + query: + T.nilable( + T::Hash[String, T.nilable(T.any(T::Array[String], String))] + ), + headers: + T.nilable( + T::Hash[ + String, + T.nilable( + T.any( + String, + Integer, + T::Array[T.nilable(T.any(String, Integer))] + ) + ) + ] + ), + body: T.nilable(T.anything), + unwrap: + T.nilable( + T.any( + Symbol, + Integer, + T::Array[T.any(Symbol, Integer)], + T.proc.params(arg0: T.anything).returns(T.anything) + ) + ), + page: + T.nilable( + T::Class[ + PreludeSDK::Internal::Type::BasePage[ + PreludeSDK::Internal::Type::BaseModel + ] + ] + ), + stream: T.nilable(T::Class[T.anything]), + model: T.nilable(PreludeSDK::Internal::Type::Converter::Input), + options: T.nilable(PreludeSDK::RequestOptions::OrHash) + } + end + + RequestInput = + T.type_alias do + { + method: Symbol, + url: URI::Generic, + headers: T::Hash[String, String], + body: T.anything, + max_retries: Integer, + timeout: Float + } + end + + # from whatwg fetch spec + MAX_REDIRECTS = 20 + + PLATFORM_HEADERS = T::Hash[String, String] + + class << self + # @api private + sig do + params( + req: + PreludeSDK::Internal::Transport::BaseClient::RequestComponents + ).void + end + def validate!(req) + end + + # @api private + sig do + params( + status: Integer, + headers: T.any(T::Hash[String, String], Net::HTTPHeader) + ).returns(T::Boolean) + end + def should_retry?(status, headers:) + end + + # @api private + sig do + params( + request: + PreludeSDK::Internal::Transport::BaseClient::RequestInput, + status: Integer, + response_headers: T.any(T::Hash[String, String], Net::HTTPHeader) + ).returns(PreludeSDK::Internal::Transport::BaseClient::RequestInput) + end + def follow_redirect(request, status:, response_headers:) + end + + # @api private + sig do + params( + status: T.any(Integer, PreludeSDK::Errors::APIConnectionError), + stream: T.nilable(T::Enumerable[String]) + ).void + end + def reap_connection!(status, stream:) + end + end + + sig { returns(URI::Generic) } + attr_reader :base_url + + sig { returns(Float) } + attr_reader :timeout + + sig { returns(Integer) } + attr_reader :max_retries + + sig { returns(Float) } + attr_reader :initial_retry_delay + + sig { returns(Float) } + attr_reader :max_retry_delay + + sig { returns(T::Hash[String, String]) } + attr_reader :headers + + sig { returns(T.nilable(String)) } + attr_reader :idempotency_header + + # @api private + sig { returns(PreludeSDK::Internal::Transport::PooledNetRequester) } + attr_reader :requester + + # @api private + sig do + params( + base_url: String, + timeout: Float, + max_retries: Integer, + initial_retry_delay: Float, + max_retry_delay: Float, + headers: + T::Hash[ + String, + T.nilable( + T.any( + String, + Integer, + T::Array[T.nilable(T.any(String, Integer))] + ) + ) + ], + idempotency_header: T.nilable(String) + ).returns(T.attached_class) + end + def self.new( + base_url:, + timeout: 0.0, + max_retries: 0, + initial_retry_delay: 0.0, + max_retry_delay: 0.0, + headers: {}, + idempotency_header: nil + ) + end + + # @api private + sig { overridable.returns(T::Hash[String, String]) } + private def auth_headers + end + + # @api private + sig { returns(String) } + private def generate_idempotency_key + end + + # @api private + sig do + overridable + .params( + req: + PreludeSDK::Internal::Transport::BaseClient::RequestComponents, + opts: PreludeSDK::Internal::AnyHash + ) + .returns(PreludeSDK::Internal::Transport::BaseClient::RequestInput) + end + private def build_request(req, opts) + end + + # @api private + sig do + params( + headers: T::Hash[String, String], + retry_count: Integer + ).returns(Float) + end + private def retry_delay(headers, retry_count:) + end + + # @api private + sig do + params( + request: PreludeSDK::Internal::Transport::BaseClient::RequestInput, + redirect_count: Integer, + retry_count: Integer, + send_retry_header: T::Boolean + ).returns([Integer, Net::HTTPResponse, T::Enumerable[String]]) + end + private def send_request( + request, + redirect_count:, + retry_count:, + send_retry_header: + ) + end + + # Execute the request specified by `req`. This is the method that all resource + # methods call into. + # + # @overload request(method, path, query: {}, headers: {}, body: nil, unwrap: nil, page: nil, stream: nil, model: PreludeSDK::Internal::Type::Unknown, options: {}) + sig do + params( + method: Symbol, + path: T.any(String, T::Array[String]), + query: + T.nilable( + T::Hash[String, T.nilable(T.any(T::Array[String], String))] + ), + headers: + T.nilable( + T::Hash[ + String, + T.nilable( + T.any( + String, + Integer, + T::Array[T.nilable(T.any(String, Integer))] + ) + ) + ] + ), + body: T.nilable(T.anything), + unwrap: + T.nilable( + T.any( + Symbol, + Integer, + T::Array[T.any(Symbol, Integer)], + T.proc.params(arg0: T.anything).returns(T.anything) + ) + ), + page: + T.nilable( + T::Class[ + PreludeSDK::Internal::Type::BasePage[ + PreludeSDK::Internal::Type::BaseModel + ] + ] + ), + stream: T.nilable(T::Class[T.anything]), + model: T.nilable(PreludeSDK::Internal::Type::Converter::Input), + options: T.nilable(PreludeSDK::RequestOptions::OrHash) + ).returns(T.anything) + end + def request( + method, + path, + query: {}, + headers: {}, + body: nil, + unwrap: nil, + page: nil, + stream: nil, + model: PreludeSDK::Internal::Type::Unknown, + options: {} + ) + end + + # @api private + sig { returns(String) } + def inspect + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/transport/pooled_net_requester.rbi b/rbi/prelude_sdk/internal/transport/pooled_net_requester.rbi new file mode 100644 index 00000000..6b158634 --- /dev/null +++ b/rbi/prelude_sdk/internal/transport/pooled_net_requester.rbi @@ -0,0 +1,80 @@ +# typed: strong + +module PreludeSDK + module Internal + module Transport + # @api private + class PooledNetRequester + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + Request = + T.type_alias do + { + method: Symbol, + url: URI::Generic, + headers: T::Hash[String, String], + body: T.anything, + deadline: Float + } + end + + # from the golang stdlib + # https://github.com/golang/go/blob/c8eced8580028328fde7c03cbfcb720ce15b2358/src/net/http/transport.go#L49 + KEEP_ALIVE_TIMEOUT = 30 + + DEFAULT_MAX_CONNECTIONS = T.let(T.unsafe(nil), Integer) + + class << self + # @api private + sig { params(url: URI::Generic).returns(Net::HTTP) } + def connect(url) + end + + # @api private + sig { params(conn: Net::HTTP, deadline: Float).void } + def calibrate_socket_timeout(conn, deadline) + end + + # @api private + sig do + params( + request: + PreludeSDK::Internal::Transport::PooledNetRequester::Request, + blk: T.proc.params(arg0: String).void + ).returns([Net::HTTPGenericRequest, T.proc.void]) + end + def build_request(request, &blk) + end + end + + # @api private + sig do + params( + url: URI::Generic, + deadline: Float, + blk: T.proc.params(arg0: Net::HTTP).void + ).void + end + private def with_pool(url, deadline:, &blk) + end + + # @api private + sig do + params( + request: + PreludeSDK::Internal::Transport::PooledNetRequester::Request + ).returns([Integer, Net::HTTPResponse, T::Enumerable[String]]) + end + def execute(request) + end + + # @api private + sig { params(size: Integer).returns(T.attached_class) } + def self.new( + size: PreludeSDK::Internal::Transport::PooledNetRequester::DEFAULT_MAX_CONNECTIONS + ) + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/array_of.rbi b/rbi/prelude_sdk/internal/type/array_of.rbi new file mode 100644 index 00000000..109ea642 --- /dev/null +++ b/rbi/prelude_sdk/internal/type/array_of.rbi @@ -0,0 +1,104 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + # + # Array of items of a given type. + class ArrayOf + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + abstract! + + Elem = type_member(:out) + + sig do + params( + type_info: + T.any( + PreludeSDK::Internal::AnyHash, + T.proc.returns(PreludeSDK::Internal::Type::Converter::Input), + PreludeSDK::Internal::Type::Converter::Input + ), + spec: PreludeSDK::Internal::AnyHash + ).returns(T.attached_class) + end + def self.[](type_info, spec = {}) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ===(other) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ==(other) + end + + sig { returns(Integer) } + def hash + end + + # @api private + sig do + override + .params( + value: T.any(T::Array[T.anything], T.anything), + state: PreludeSDK::Internal::Type::Converter::CoerceState + ) + .returns(T.any(T::Array[T.anything], T.anything)) + end + def coerce(value, state:) + end + + # @api private + sig do + override + .params( + value: T.any(T::Array[T.anything], T.anything), + state: PreludeSDK::Internal::Type::Converter::DumpState + ) + .returns(T.any(T::Array[T.anything], T.anything)) + end + def dump(value, state:) + end + + # @api private + sig { returns(T.anything) } + def to_sorbet_type + end + + # @api private + sig { returns(Elem) } + protected def item_type + end + + # @api private + sig { returns(T::Boolean) } + protected def nilable? + end + + # @api private + sig do + params( + type_info: + T.any( + PreludeSDK::Internal::AnyHash, + T.proc.returns(PreludeSDK::Internal::Type::Converter::Input), + PreludeSDK::Internal::Type::Converter::Input + ), + spec: PreludeSDK::Internal::AnyHash + ).void + end + def initialize(type_info, spec = {}) + end + + # @api private + sig { params(depth: Integer).returns(String) } + def inspect(depth: 0) + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/base_model.rbi b/rbi/prelude_sdk/internal/type/base_model.rbi new file mode 100644 index 00000000..b5313aec --- /dev/null +++ b/rbi/prelude_sdk/internal/type/base_model.rbi @@ -0,0 +1,304 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + class BaseModel + extend PreludeSDK::Internal::Type::Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + abstract! + + KnownField = + T.type_alias do + { + mode: T.nilable(Symbol), + required: T::Boolean, + nilable: T::Boolean + } + end + + OrHash = + T.type_alias do + T.any( + PreludeSDK::Internal::Type::BaseModel, + PreludeSDK::Internal::AnyHash + ) + end + + class << self + # @api private + # + # Assumes superclass fields are totally defined before fields are accessed / + # defined on subclasses. + sig { params(child: T.self_type).void } + def inherited(child) + end + + # @api private + sig do + returns( + T::Hash[ + Symbol, + T.all( + PreludeSDK::Internal::Type::BaseModel::KnownField, + { + type_fn: + T.proc.returns( + PreludeSDK::Internal::Type::Converter::Input + ) + } + ) + ] + ) + end + def known_fields + end + + # @api private + sig do + returns( + T::Hash[ + Symbol, + T.all( + PreludeSDK::Internal::Type::BaseModel::KnownField, + { type: PreludeSDK::Internal::Type::Converter::Input } + ) + ] + ) + end + def fields + end + + # @api private + sig do + params( + name_sym: Symbol, + required: T::Boolean, + type_info: + T.any( + { + const: + T.nilable( + T.any(NilClass, T::Boolean, Integer, Float, Symbol) + ), + enum: + T.nilable( + T.proc.returns( + PreludeSDK::Internal::Type::Converter::Input + ) + ), + union: + T.nilable( + T.proc.returns( + PreludeSDK::Internal::Type::Converter::Input + ) + ), + api_name: Symbol, + nil?: T::Boolean + }, + T.proc.returns(PreludeSDK::Internal::Type::Converter::Input), + PreludeSDK::Internal::Type::Converter::Input + ), + spec: PreludeSDK::Internal::AnyHash + ).void + end + private def add_field(name_sym, required:, type_info:, spec:) + end + + # @api private + sig do + params( + name_sym: Symbol, + type_info: + T.any( + PreludeSDK::Internal::AnyHash, + T.proc.returns(PreludeSDK::Internal::Type::Converter::Input), + PreludeSDK::Internal::Type::Converter::Input + ), + spec: PreludeSDK::Internal::AnyHash + ).void + end + def required(name_sym, type_info, spec = {}) + end + + # @api private + sig do + params( + name_sym: Symbol, + type_info: + T.any( + PreludeSDK::Internal::AnyHash, + T.proc.returns(PreludeSDK::Internal::Type::Converter::Input), + PreludeSDK::Internal::Type::Converter::Input + ), + spec: PreludeSDK::Internal::AnyHash + ).void + end + def optional(name_sym, type_info, spec = {}) + end + + # @api private + # + # `request_only` attributes not excluded from `.#coerce` when receiving responses + # even if well behaved servers should not send them + sig { params(blk: T.proc.void).void } + private def request_only(&blk) + end + + # @api private + # + # `response_only` attributes are omitted from `.#dump` when making requests + sig { params(blk: T.proc.void).void } + private def response_only(&blk) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ==(other) + end + + sig { returns(Integer) } + def hash + end + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ==(other) + end + + sig { returns(Integer) } + def hash + end + + class << self + # @api private + sig do + override + .params( + value: + T.any( + PreludeSDK::Internal::Type::BaseModel, + T::Hash[T.anything, T.anything], + T.anything + ), + state: PreludeSDK::Internal::Type::Converter::CoerceState + ) + .returns(T.any(T.attached_class, T.anything)) + end + def coerce(value, state:) + end + + # @api private + sig do + override + .params( + value: T.any(T.attached_class, T.anything), + state: PreludeSDK::Internal::Type::Converter::DumpState + ) + .returns(T.any(T::Hash[T.anything, T.anything], T.anything)) + end + def dump(value, state:) + end + + # @api private + sig { returns(T.anything) } + def to_sorbet_type + end + end + + class << self + # @api private + sig do + params( + model: PreludeSDK::Internal::Type::BaseModel, + convert: T::Boolean + ).returns(PreludeSDK::Internal::AnyHash) + end + def recursively_to_h(model, convert:) + end + end + + # Returns the raw value associated with the given key, if found. Otherwise, nil is + # returned. + # + # It is valid to lookup keys that are not in the API spec, for example to access + # undocumented features. This method does not parse response data into + # higher-level types. Lookup by anything other than a Symbol is an ArgumentError. + sig { params(key: Symbol).returns(T.nilable(T.anything)) } + def [](key) + end + + # Returns a Hash of the data underlying this object. O(1) + # + # Keys are Symbols and values are the raw values from the response. The return + # value indicates which values were ever set on the object. i.e. there will be a + # key in this hash if they ever were, even if the set value was nil. + # + # This method is not recursive. The returned value is shared by the object, so it + # should not be mutated. + sig { overridable.returns(PreludeSDK::Internal::AnyHash) } + def to_h + end + + # Returns a Hash of the data underlying this object. O(1) + # + # Keys are Symbols and values are the raw values from the response. The return + # value indicates which values were ever set on the object. i.e. there will be a + # key in this hash if they ever were, even if the set value was nil. + # + # This method is not recursive. The returned value is shared by the object, so it + # should not be mutated. + sig { overridable.returns(PreludeSDK::Internal::AnyHash) } + def to_hash + end + + # In addition to the behaviour of `#to_h`, this method will recursively call + # `#to_h` on nested models. + sig { overridable.returns(PreludeSDK::Internal::AnyHash) } + def deep_to_h + end + + sig do + params(keys: T.nilable(T::Array[Symbol])).returns( + PreludeSDK::Internal::AnyHash + ) + end + def deconstruct_keys(keys) + end + + sig { params(a: T.anything).returns(String) } + def to_json(*a) + end + + sig { params(a: T.anything).returns(String) } + def to_yaml(*a) + end + + # Create a new instance of a model. + sig do + params(data: T.any(T::Hash[Symbol, T.anything], T.self_type)).returns( + T.attached_class + ) + end + def self.new(data = {}) + end + + class << self + # @api private + sig { params(depth: Integer).returns(String) } + def inspect(depth: 0) + end + end + + sig { returns(String) } + def to_s + end + + # @api private + sig { returns(String) } + def inspect + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/base_page.rbi b/rbi/prelude_sdk/internal/type/base_page.rbi new file mode 100644 index 00000000..c037af7b --- /dev/null +++ b/rbi/prelude_sdk/internal/type/base_page.rbi @@ -0,0 +1,42 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + # + # This module provides a base implementation for paginated responses in the SDK. + module BasePage + Elem = type_member(:out) + + sig { overridable.returns(T::Boolean) } + def next_page? + end + + sig { overridable.returns(T.self_type) } + def next_page + end + + sig { overridable.params(blk: T.proc.params(arg0: Elem).void).void } + def auto_paging_each(&blk) + end + + sig { returns(T::Enumerable[Elem]) } + def to_enum + end + + # @api private + sig do + params( + client: PreludeSDK::Internal::Transport::BaseClient, + req: PreludeSDK::Internal::Transport::BaseClient::RequestComponents, + headers: T.any(T::Hash[String, String], Net::HTTPHeader), + page_data: T.anything + ).void + end + def initialize(client:, req:, headers:, page_data:) + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/boolean.rbi b/rbi/prelude_sdk/internal/type/boolean.rbi new file mode 100644 index 00000000..38b19095 --- /dev/null +++ b/rbi/prelude_sdk/internal/type/boolean.rbi @@ -0,0 +1,58 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + # + # Ruby has no Boolean class; this is something for models to refer to. + class Boolean + extend PreludeSDK::Internal::Type::Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + abstract! + + sig { params(other: T.anything).returns(T::Boolean) } + def self.===(other) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def self.==(other) + end + + class << self + # @api private + # + # Coerce value to Boolean if possible, otherwise return the original value. + sig do + override + .params( + value: T.any(T::Boolean, T.anything), + state: PreludeSDK::Internal::Type::Converter::CoerceState + ) + .returns(T.any(T::Boolean, T.anything)) + end + def coerce(value, state:) + end + + # @api private + sig do + override + .params( + value: T.any(T::Boolean, T.anything), + state: PreludeSDK::Internal::Type::Converter::DumpState + ) + .returns(T.any(T::Boolean, T.anything)) + end + def dump(value, state:) + end + + # @api private + sig { returns(T.anything) } + def to_sorbet_type + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/converter.rbi b/rbi/prelude_sdk/internal/type/converter.rbi new file mode 100644 index 00000000..d2c3a0b7 --- /dev/null +++ b/rbi/prelude_sdk/internal/type/converter.rbi @@ -0,0 +1,162 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + module Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + Input = + T.type_alias do + T.any(PreludeSDK::Internal::Type::Converter, T::Class[T.anything]) + end + + CoerceState = + T.type_alias do + { + translate_names: T::Boolean, + strictness: T::Boolean, + exactness: { + yes: Integer, + no: Integer, + maybe: Integer + }, + error: T::Class[StandardError], + branched: Integer + } + end + + DumpState = T.type_alias { { can_retry: T::Boolean } } + + # @api private + sig do + overridable + .params( + value: T.anything, + state: PreludeSDK::Internal::Type::Converter::CoerceState + ) + .returns(T.anything) + end + def coerce(value, state:) + end + + # @api private + sig do + overridable + .params( + value: T.anything, + state: PreludeSDK::Internal::Type::Converter::DumpState + ) + .returns(T.anything) + end + def dump(value, state:) + end + + # @api private + sig { params(depth: Integer).returns(String) } + def inspect(depth: 0) + end + + class << self + # @api private + sig do + params( + spec: + T.any( + { + const: + T.nilable( + T.any(NilClass, T::Boolean, Integer, Float, Symbol) + ), + enum: + T.nilable( + T.proc.returns( + PreludeSDK::Internal::Type::Converter::Input + ) + ), + union: + T.nilable( + T.proc.returns( + PreludeSDK::Internal::Type::Converter::Input + ) + ) + }, + T.proc.returns(PreludeSDK::Internal::Type::Converter::Input), + PreludeSDK::Internal::Type::Converter::Input + ) + ).returns(T.proc.returns(T.anything)) + end + def self.type_info(spec) + end + + # @api private + sig do + params(translate_names: T::Boolean).returns( + PreludeSDK::Internal::Type::Converter::CoerceState + ) + end + def self.new_coerce_state(translate_names: true) + end + + # @api private + # + # Based on `target`, transform `value` into `target`, to the extent possible: + # + # 1. if the given `value` conforms to `target` already, return the given `value` + # 2. if it's possible and safe to convert the given `value` to `target`, then the + # converted value + # 3. otherwise, the given `value` unaltered + # + # The coercion process is subject to improvement between minor release versions. + # See https://docs.pydantic.dev/latest/concepts/unions/#smart-mode + sig do + params( + target: PreludeSDK::Internal::Type::Converter::Input, + value: T.anything, + state: PreludeSDK::Internal::Type::Converter::CoerceState + ).returns(T.anything) + end + def self.coerce( + target, + value, + # The `strictness` is one of `true`, `false`. This informs the coercion strategy + # when we have to decide between multiple possible conversion targets: + # + # - `true`: the conversion must be exact, with minimum coercion. + # - `false`: the conversion can be approximate, with some coercion. + # + # The `exactness` is `Hash` with keys being one of `yes`, `no`, or `maybe`. For + # any given conversion attempt, the exactness will be updated based on how closely + # the value recursively matches the target type: + # + # - `yes`: the value can be converted to the target type with minimum coercion. + # - `maybe`: the value can be converted to the target type with some reasonable + # coercion. + # - `no`: the value cannot be converted to the target type. + # + # See implementation below for more details. + state: PreludeSDK::Internal::Type::Converter.new_coerce_state + ) + end + + # @api private + sig do + params( + target: PreludeSDK::Internal::Type::Converter::Input, + value: T.anything, + state: PreludeSDK::Internal::Type::Converter::DumpState + ).returns(T.anything) + end + def self.dump(target, value, state: { can_retry: true }) + end + + # @api private + sig { params(target: T.anything, depth: Integer).returns(String) } + def self.inspect(target, depth:) + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/enum.rbi b/rbi/prelude_sdk/internal/type/enum.rbi new file mode 100644 index 00000000..14fd5221 --- /dev/null +++ b/rbi/prelude_sdk/internal/type/enum.rbi @@ -0,0 +1,82 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + # + # A value from among a specified list of options. OpenAPI enum values map to Ruby + # values in the SDK as follows: + # + # 1. boolean => true | false + # 2. integer => Integer + # 3. float => Float + # 4. string => Symbol + # + # We can therefore convert string values to Symbols, but can't convert other + # values safely. + module Enum + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # All of the valid Symbol values for this enum. + sig do + overridable.returns( + T::Array[T.any(NilClass, T::Boolean, Integer, Float, Symbol)] + ) + end + def values + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ===(other) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ==(other) + end + + sig { returns(Integer) } + def hash + end + + # @api private + # + # Unlike with primitives, `Enum` additionally validates that the value is a member + # of the enum. + sig do + override + .params( + value: T.any(String, Symbol, T.anything), + state: PreludeSDK::Internal::Type::Converter::CoerceState + ) + .returns(T.any(Symbol, T.anything)) + end + def coerce(value, state:) + end + + # @api private + sig do + override + .params( + value: T.any(Symbol, T.anything), + state: PreludeSDK::Internal::Type::Converter::DumpState + ) + .returns(T.any(Symbol, T.anything)) + end + def dump(value, state:) + end + + # @api private + sig { returns(T.anything) } + def to_sorbet_type + end + + # @api private + sig { params(depth: Integer).returns(String) } + def inspect(depth: 0) + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/file_input.rbi b/rbi/prelude_sdk/internal/type/file_input.rbi new file mode 100644 index 00000000..a0eb5213 --- /dev/null +++ b/rbi/prelude_sdk/internal/type/file_input.rbi @@ -0,0 +1,59 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + # + # Either `Pathname` or `StringIO`, or `IO`, or + # `PreludeSDK::Internal::Type::FileInput`. + # + # Note: when `IO` is used, all retries are disabled, since many IO` streams are + # not rewindable. + class FileInput + extend PreludeSDK::Internal::Type::Converter + + abstract! + + sig { params(other: T.anything).returns(T::Boolean) } + def self.===(other) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def self.==(other) + end + + class << self + # @api private + sig do + override + .params( + value: T.any(StringIO, String, T.anything), + state: PreludeSDK::Internal::Type::Converter::CoerceState + ) + .returns(T.any(StringIO, T.anything)) + end + def coerce(value, state:) + end + + # @api private + sig do + override + .params( + value: T.any(Pathname, StringIO, IO, String, T.anything), + state: PreludeSDK::Internal::Type::Converter::DumpState + ) + .returns(T.any(Pathname, StringIO, IO, String, T.anything)) + end + def dump(value, state:) + end + + # @api private + sig { returns(T.anything) } + def to_sorbet_type + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/hash_of.rbi b/rbi/prelude_sdk/internal/type/hash_of.rbi new file mode 100644 index 00000000..08d0536c --- /dev/null +++ b/rbi/prelude_sdk/internal/type/hash_of.rbi @@ -0,0 +1,104 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + # + # Hash of items of a given type. + class HashOf + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + abstract! + + Elem = type_member(:out) + + sig do + params( + type_info: + T.any( + PreludeSDK::Internal::AnyHash, + T.proc.returns(PreludeSDK::Internal::Type::Converter::Input), + PreludeSDK::Internal::Type::Converter::Input + ), + spec: PreludeSDK::Internal::AnyHash + ).returns(T.attached_class) + end + def self.[](type_info, spec = {}) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ===(other) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ==(other) + end + + sig { returns(Integer) } + def hash + end + + # @api private + sig do + override + .params( + value: T.any(T::Hash[T.anything, T.anything], T.anything), + state: PreludeSDK::Internal::Type::Converter::CoerceState + ) + .returns(T.any(PreludeSDK::Internal::AnyHash, T.anything)) + end + def coerce(value, state:) + end + + # @api private + sig do + override + .params( + value: T.any(T::Hash[T.anything, T.anything], T.anything), + state: PreludeSDK::Internal::Type::Converter::DumpState + ) + .returns(T.any(PreludeSDK::Internal::AnyHash, T.anything)) + end + def dump(value, state:) + end + + # @api private + sig { returns(T.anything) } + def to_sorbet_type + end + + # @api private + sig { returns(Elem) } + protected def item_type + end + + # @api private + sig { returns(T::Boolean) } + protected def nilable? + end + + # @api private + sig do + params( + type_info: + T.any( + PreludeSDK::Internal::AnyHash, + T.proc.returns(PreludeSDK::Internal::Type::Converter::Input), + PreludeSDK::Internal::Type::Converter::Input + ), + spec: PreludeSDK::Internal::AnyHash + ).void + end + def initialize(type_info, spec = {}) + end + + # @api private + sig { params(depth: Integer).returns(String) } + def inspect(depth: 0) + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/request_parameters.rbi b/rbi/prelude_sdk/internal/type/request_parameters.rbi new file mode 100644 index 00000000..4af4fac9 --- /dev/null +++ b/rbi/prelude_sdk/internal/type/request_parameters.rbi @@ -0,0 +1,29 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + module RequestParameters + # Options to specify HTTP behaviour for this request. + sig { returns(PreludeSDK::RequestOptions) } + attr_reader :request_options + + sig { params(request_options: PreludeSDK::RequestOptions::OrHash).void } + attr_writer :request_options + + # @api private + module Converter + # @api private + sig do + params(params: T.anything).returns( + [T.anything, PreludeSDK::Internal::AnyHash] + ) + end + def dump_request(params) + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/union.rbi b/rbi/prelude_sdk/internal/type/union.rbi new file mode 100644 index 00000000..54aec9e9 --- /dev/null +++ b/rbi/prelude_sdk/internal/type/union.rbi @@ -0,0 +1,121 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + module Union + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # @api private + # + # All of the specified variant info for this union. + sig do + returns( + T::Array[ + [ + T.nilable(Symbol), + T.proc.returns(PreludeSDK::Internal::Type::Converter::Input) + ] + ] + ) + end + private def known_variants + end + + # @api private + sig { returns(T::Array[[T.nilable(Symbol), T.anything]]) } + protected def derefed_variants + end + + # All of the specified variants for this union. + sig { overridable.returns(T::Array[T.anything]) } + def variants + end + + # @api private + sig { params(property: Symbol).void } + private def discriminator(property) + end + + # @api private + sig do + params( + key: + T.any( + Symbol, + PreludeSDK::Internal::AnyHash, + T.proc.returns(T.anything), + T.anything + ), + spec: + T.any( + PreludeSDK::Internal::AnyHash, + T.proc.returns(T.anything), + T.anything + ) + ).void + end + private def variant(key, spec = nil) + end + + # @api private + sig { params(value: T.anything).returns(T.nilable(T.anything)) } + private def resolve_variant(value) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ===(other) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def ==(other) + end + + sig { returns(Integer) } + def hash + end + + # @api private + # + # Tries to efficiently coerce the given value to one of the known variants. + # + # If the value cannot match any of the known variants, the coercion is considered + # non-viable and returns the original value. + sig do + override + .params( + value: T.anything, + state: PreludeSDK::Internal::Type::Converter::CoerceState + ) + .returns(T.anything) + end + def coerce(value, state:) + end + + # @api private + sig do + override + .params( + value: T.anything, + state: PreludeSDK::Internal::Type::Converter::DumpState + ) + .returns(T.anything) + end + def dump(value, state:) + end + + # @api private + sig { returns(T.anything) } + def to_sorbet_type + end + + # @api private + sig { params(depth: Integer).returns(String) } + def inspect(depth: 0) + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/type/unknown.rbi b/rbi/prelude_sdk/internal/type/unknown.rbi new file mode 100644 index 00000000..72147b4e --- /dev/null +++ b/rbi/prelude_sdk/internal/type/unknown.rbi @@ -0,0 +1,58 @@ +# typed: strong + +module PreludeSDK + module Internal + module Type + # @api private + # + # When we don't know what to expect for the value. + class Unknown + extend PreludeSDK::Internal::Type::Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + abstract! + + sig { params(other: T.anything).returns(T::Boolean) } + def self.===(other) + end + + sig { params(other: T.anything).returns(T::Boolean) } + def self.==(other) + end + + class << self + # @api private + # + # No coercion needed for Unknown type. + sig do + override + .params( + value: T.anything, + state: PreludeSDK::Internal::Type::Converter::CoerceState + ) + .returns(T.anything) + end + def coerce(value, state:) + end + + # @api private + sig do + override + .params( + value: T.anything, + state: PreludeSDK::Internal::Type::Converter::DumpState + ) + .returns(T.anything) + end + def dump(value, state:) + end + + # @api private + sig { returns(T.anything) } + def to_sorbet_type + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/internal/util.rbi b/rbi/prelude_sdk/internal/util.rbi new file mode 100644 index 00000000..7f7c325a --- /dev/null +++ b/rbi/prelude_sdk/internal/util.rbi @@ -0,0 +1,487 @@ +# typed: strong + +module PreludeSDK + module Internal + # @api private + module Util + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + # @api private + sig { returns(Float) } + def self.monotonic_secs + end + + # @api private + sig do + params(ns: T.any(Module, T::Class[T.anything])).returns( + T::Enumerable[T.any(Module, T::Class[T.anything])] + ) + end + def self.walk_namespaces(ns) + end + + class << self + # @api private + sig { returns(String) } + def arch + end + + # @api private + sig { returns(String) } + def os + end + end + + class << self + # @api private + sig { params(input: T.anything).returns(T::Boolean) } + def primitive?(input) + end + + # @api private + sig do + params(input: T.any(String, T::Boolean)).returns( + T.any(T::Boolean, T.anything) + ) + end + def coerce_boolean(input) + end + + # @api private + sig do + params(input: T.any(String, T::Boolean)).returns( + T.nilable(T::Boolean) + ) + end + def coerce_boolean!(input) + end + + # @api private + sig do + params(input: T.any(String, Integer)).returns( + T.any(Integer, T.anything) + ) + end + def coerce_integer(input) + end + + # @api private + sig do + params(input: T.any(String, Integer, Float)).returns( + T.any(Float, T.anything) + ) + end + def coerce_float(input) + end + + # @api private + sig do + params(input: T.anything).returns( + T.any(T::Hash[T.anything, T.anything], T.anything) + ) + end + def coerce_hash(input) + end + + # @api private + sig do + params(input: T.anything).returns( + T.nilable(T::Hash[T.anything, T.anything]) + ) + end + def coerce_hash!(input) + end + end + + class << self + # @api private + sig do + params(lhs: T.anything, rhs: T.anything, concat: T::Boolean).returns( + T.anything + ) + end + private def deep_merge_lr(lhs, rhs, concat: false) + end + + # @api private + # + # Recursively merge one hash with another. If the values at a given key are not + # both hashes, just take the new value. + sig do + params( + values: T::Array[T.anything], + sentinel: T.nilable(T.anything), + concat: T::Boolean + ).returns(T.anything) + end + def deep_merge( + *values, + # the value to return if no values are provided. + sentinel: nil, + # whether to merge sequences by concatenation. + concat: false + ) + end + + # @api private + sig do + params( + data: + T.any( + PreludeSDK::Internal::AnyHash, + T::Array[T.anything], + T.anything + ), + pick: + T.nilable( + T.any( + Symbol, + Integer, + T::Array[T.any(Symbol, Integer)], + T.proc.params(arg0: T.anything).returns(T.anything) + ) + ), + blk: T.nilable(T.proc.returns(T.anything)) + ).returns(T.nilable(T.anything)) + end + def dig(data, pick, &blk) + end + end + + class << self + # @api private + sig { params(uri: URI::Generic).returns(String) } + def uri_origin(uri) + end + + # @api private + sig { params(path: T.any(String, T::Array[String])).returns(String) } + def interpolate_path(path) + end + end + + class << self + # @api private + sig do + params(query: T.nilable(String)).returns( + T::Hash[String, T::Array[String]] + ) + end + def decode_query(query) + end + + # @api private + sig do + params( + query: + T.nilable( + T::Hash[String, T.nilable(T.any(T::Array[String], String))] + ) + ).returns(T.nilable(String)) + end + def encode_query(query) + end + end + + ParsedUri = + T.type_alias do + { + scheme: T.nilable(String), + host: T.nilable(String), + port: T.nilable(Integer), + path: T.nilable(String), + query: T::Hash[String, T::Array[String]] + } + end + + class << self + # @api private + sig do + params(url: T.any(URI::Generic, String)).returns( + PreludeSDK::Internal::Util::ParsedUri + ) + end + def parse_uri(url) + end + + # @api private + sig do + params(parsed: PreludeSDK::Internal::Util::ParsedUri).returns( + URI::Generic + ) + end + def unparse_uri(parsed) + end + + # @api private + sig do + params( + lhs: PreludeSDK::Internal::Util::ParsedUri, + rhs: PreludeSDK::Internal::Util::ParsedUri + ).returns(URI::Generic) + end + def join_parsed_uri(lhs, rhs) + end + end + + class << self + # @api private + sig do + params( + headers: + T::Hash[ + String, + T.nilable( + T.any( + String, + Integer, + T::Array[T.nilable(T.any(String, Integer))] + ) + ) + ] + ).returns(T::Hash[String, String]) + end + def normalized_headers(*headers) + end + end + + # @api private + # + # An adapter that satisfies the IO interface required by `::IO.copy_stream` + class ReadIOAdapter + # @api private + sig { returns(T.nilable(T::Boolean)) } + def close? + end + + # @api private + sig { void } + def close + end + + # @api private + sig { params(max_len: T.nilable(Integer)).returns(String) } + private def read_enum(max_len) + end + + # @api private + sig do + params( + max_len: T.nilable(Integer), + out_string: T.nilable(String) + ).returns(T.nilable(String)) + end + def read(max_len = nil, out_string = nil) + end + + # @api private + sig do + params( + src: T.any(String, Pathname, StringIO, T::Enumerable[String]), + blk: T.proc.params(arg0: String).void + ).returns(T.attached_class) + end + def self.new(src, &blk) + end + end + + class << self + sig do + params(blk: T.proc.params(y: Enumerator::Yielder).void).returns( + T::Enumerable[String] + ) + end + def writable_enum(&blk) + end + end + + JSON_CONTENT = + T.let(%r{^application/(?:vnd(?:\.[^.]+)*\+)?json(?!l)}, Regexp) + JSONL_CONTENT = + T.let(%r{^application/(:?x-(?:n|l)djson)|(:?(?:x-)?jsonl)}, Regexp) + + class << self + # @api private + sig do + params( + y: Enumerator::Yielder, + val: T.anything, + closing: T::Array[T.proc.void], + content_type: T.nilable(String) + ).void + end + private def write_multipart_content( + y, + val:, + closing:, + content_type: nil + ) + end + + # @api private + sig do + params( + y: Enumerator::Yielder, + boundary: String, + key: T.any(Symbol, String), + val: T.anything, + closing: T::Array[T.proc.void] + ).void + end + private def write_multipart_chunk(y, boundary:, key:, val:, closing:) + end + + # @api private + # + # https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#special-considerations-for-multipart-content + sig do + params(body: T.anything).returns([String, T::Enumerable[String]]) + end + private def encode_multipart_streaming(body) + end + + # @api private + sig do + params(headers: T::Hash[String, String], body: T.anything).returns( + T.anything + ) + end + def encode_content(headers, body) + end + + # @api private + # + # https://www.iana.org/assignments/character-sets/character-sets.xhtml + sig { params(content_type: String, text: String).void } + def force_charset!(content_type, text:) + end + + # @api private + # + # Assumes each chunk in stream has `Encoding::BINARY`. + sig do + params( + headers: T.any(T::Hash[String, String], Net::HTTPHeader), + stream: T::Enumerable[String], + suppress_error: T::Boolean + ).returns(T.anything) + end + def decode_content(headers, stream:, suppress_error: false) + end + end + + class << self + # @api private + # + # https://doc.rust-lang.org/std/iter/trait.FusedIterator.html + sig do + params( + enum: T::Enumerable[T.anything], + external: T::Boolean, + close: T.proc.void + ).returns(T::Enumerable[T.anything]) + end + def fused_enum(enum, external: false, &close) + end + + # @api private + sig { params(enum: T.nilable(T::Enumerable[T.anything])).void } + def close_fused!(enum) + end + + # @api private + sig do + params( + enum: T.nilable(T::Enumerable[T.anything]), + blk: T.proc.params(arg0: Enumerator::Yielder).void + ).returns(T::Enumerable[T.anything]) + end + def chain_fused(enum, &blk) + end + end + + ServerSentEvent = + T.type_alias do + { + event: T.nilable(String), + data: T.nilable(String), + id: T.nilable(String), + retry: T.nilable(Integer) + } + end + + class << self + # @api private + # + # Assumes Strings have been forced into having `Encoding::BINARY`. + # + # This decoder is responsible for reassembling lines split across multiple + # fragments. + sig do + params(enum: T::Enumerable[String]).returns(T::Enumerable[String]) + end + def decode_lines(enum) + end + + # @api private + # + # https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream + # + # Assumes that `lines` has been decoded with `#decode_lines`. + sig do + params(lines: T::Enumerable[String]).returns( + T::Enumerable[PreludeSDK::Internal::Util::ServerSentEvent] + ) + end + def decode_sse(lines) + end + end + + # @api private + module SorbetRuntimeSupport + class MissingSorbetRuntimeError < ::RuntimeError + end + + # @api private + sig { returns(T::Hash[Symbol, T.anything]) } + private def sorbet_runtime_constants + end + + # @api private + sig { params(name: Symbol).void } + def const_missing(name) + end + + # @api private + sig { params(name: Symbol).returns(T::Boolean) } + def sorbet_constant_defined?(name) + end + + # @api private + sig { params(name: Symbol, blk: T.proc.returns(T.anything)).void } + def define_sorbet_constant!(name, &blk) + end + + # @api private + sig { returns(T.anything) } + def to_sorbet_type + end + + class << self + # @api private + sig do + params( + type: + T.any( + PreludeSDK::Internal::Util::SorbetRuntimeSupport, + T.anything + ) + ).returns(T.anything) + end + def to_sorbet_type(type) + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/models.rbi b/rbi/prelude_sdk/models.rbi new file mode 100644 index 00000000..1d98e71d --- /dev/null +++ b/rbi/prelude_sdk/models.rbi @@ -0,0 +1,17 @@ +# typed: strong + +module PreludeSDK + LookupLookupParams = PreludeSDK::Models::LookupLookupParams + + TransactionalSendParams = PreludeSDK::Models::TransactionalSendParams + + VerificationCheckParams = PreludeSDK::Models::VerificationCheckParams + + VerificationCreateParams = PreludeSDK::Models::VerificationCreateParams + + WatchPredictParams = PreludeSDK::Models::WatchPredictParams + + WatchSendEventsParams = PreludeSDK::Models::WatchSendEventsParams + + WatchSendFeedbacksParams = PreludeSDK::Models::WatchSendFeedbacksParams +end diff --git a/rbi/prelude_sdk/models/lookup_lookup_params.rbi b/rbi/prelude_sdk/models/lookup_lookup_params.rbi new file mode 100644 index 00000000..ad434902 --- /dev/null +++ b/rbi/prelude_sdk/models/lookup_lookup_params.rbi @@ -0,0 +1,78 @@ +# typed: strong + +module PreludeSDK + module Models + class LookupLookupParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + OrHash = + T.type_alias do + T.any(PreludeSDK::LookupLookupParams, PreludeSDK::Internal::AnyHash) + end + + # Optional features. Possible values are: + # + # - `cnam` - Retrieve CNAM (Caller ID Name) along with other information. Contact + # us if you need to use this functionality. + sig do + returns( + T.nilable(T::Array[PreludeSDK::LookupLookupParams::Type::OrSymbol]) + ) + end + attr_reader :type + + sig do + params( + type: T::Array[PreludeSDK::LookupLookupParams::Type::OrSymbol] + ).void + end + attr_writer :type + + sig do + params( + type: T::Array[PreludeSDK::LookupLookupParams::Type::OrSymbol], + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(T.attached_class) + end + def self.new( + # Optional features. Possible values are: + # + # - `cnam` - Retrieve CNAM (Caller ID Name) along with other information. Contact + # us if you need to use this functionality. + type: nil, + request_options: {} + ) + end + + sig do + override.returns( + { + type: T::Array[PreludeSDK::LookupLookupParams::Type::OrSymbol], + request_options: PreludeSDK::RequestOptions + } + ) + end + def to_hash + end + + module Type + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias { T.all(Symbol, PreludeSDK::LookupLookupParams::Type) } + OrSymbol = T.type_alias { T.any(Symbol, String) } + + CNAM = T.let(:cnam, PreludeSDK::LookupLookupParams::Type::TaggedSymbol) + + sig do + override.returns( + T::Array[PreludeSDK::LookupLookupParams::Type::TaggedSymbol] + ) + end + def self.values + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/lookup_lookup_response.rbi b/rbi/prelude_sdk/models/lookup_lookup_response.rbi new file mode 100644 index 00000000..d000c56c --- /dev/null +++ b/rbi/prelude_sdk/models/lookup_lookup_response.rbi @@ -0,0 +1,520 @@ +# typed: strong + +module PreludeSDK + module Models + class LookupLookupResponse < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::LookupLookupResponse, + PreludeSDK::Internal::AnyHash + ) + end + + # The CNAM (Caller ID Name) associated with the phone number. Contact us if you + # need to use this functionality. Once enabled, put `cnam` option to `type` query + # parameter. + sig { returns(T.nilable(String)) } + attr_reader :caller_name + + sig { params(caller_name: String).void } + attr_writer :caller_name + + # The country code of the phone number. + sig { returns(T.nilable(String)) } + attr_reader :country_code + + sig { params(country_code: String).void } + attr_writer :country_code + + # A list of flags associated with the phone number. + # + # - `ported` - Indicates the phone number has been transferred from one carrier to + # another. + # - `temporary` - Indicates the phone number is likely a temporary or virtual + # number, often used for verification services or burner phones. + sig do + returns( + T.nilable( + T::Array[ + PreludeSDK::Models::LookupLookupResponse::Flag::TaggedSymbol + ] + ) + ) + end + attr_reader :flags + + sig do + params( + flags: + T::Array[PreludeSDK::Models::LookupLookupResponse::Flag::OrSymbol] + ).void + end + attr_writer :flags + + # The type of phone line. + # + # - `calling_cards` - Numbers that are associated with providers of pre-paid + # domestic and international calling cards. + # - `fixed_line` - Landline phone numbers. + # - `isp` - Numbers reserved for Internet Service Providers. + # - `local_rate` - Numbers that can be assigned non-geographically. + # - `mobile` - Mobile phone numbers. + # - `other` - Other types of services. + # - `pager` - Number ranges specifically allocated to paging devices. + # - `payphone` - Allocated numbers for payphone kiosks in some countries. + # - `premium_rate` - Landline numbers where the calling party pays more than + # standard. + # - `satellite` - Satellite phone numbers. + # - `service` - Automated applications. + # - `shared_cost` - Specific landline ranges where the cost of making the call is + # shared between the calling and called party. + # - `short_codes_commercial` - Short codes are memorable, easy-to-use numbers, + # like the UK's NHS 111, often sold to businesses. Not available in all + # countries. + # - `toll_free` - Number where the called party pays for the cost of the call not + # the calling party. + # - `universal_access` - Number ranges reserved for Universal Access initiatives. + # - `unknown` - Unknown phone number type. + # - `vpn` - Numbers are used exclusively within a private telecommunications + # network, connecting the operator's terminals internally and not accessible via + # the public telephone network. + # - `voice_mail` - A specific category of Interactive Voice Response (IVR) + # services. + # - `voip` - Specific ranges for providers of VoIP services to allow incoming + # calls from the regular telephony network. + sig do + returns( + T.nilable( + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + ) + end + attr_reader :line_type + + sig do + params( + line_type: + PreludeSDK::Models::LookupLookupResponse::LineType::OrSymbol + ).void + end + attr_writer :line_type + + # The current carrier information. + sig do + returns( + T.nilable(PreludeSDK::Models::LookupLookupResponse::NetworkInfo) + ) + end + attr_reader :network_info + + sig do + params( + network_info: + PreludeSDK::Models::LookupLookupResponse::NetworkInfo::OrHash + ).void + end + attr_writer :network_info + + # The original carrier information. + sig do + returns( + T.nilable( + PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo + ) + ) + end + attr_reader :original_network_info + + sig do + params( + original_network_info: + PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo::OrHash + ).void + end + attr_writer :original_network_info + + # The phone number. + sig { returns(T.nilable(String)) } + attr_reader :phone_number + + sig { params(phone_number: String).void } + attr_writer :phone_number + + sig do + params( + caller_name: String, + country_code: String, + flags: + T::Array[PreludeSDK::Models::LookupLookupResponse::Flag::OrSymbol], + line_type: + PreludeSDK::Models::LookupLookupResponse::LineType::OrSymbol, + network_info: + PreludeSDK::Models::LookupLookupResponse::NetworkInfo::OrHash, + original_network_info: + PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo::OrHash, + phone_number: String + ).returns(T.attached_class) + end + def self.new( + # The CNAM (Caller ID Name) associated with the phone number. Contact us if you + # need to use this functionality. Once enabled, put `cnam` option to `type` query + # parameter. + caller_name: nil, + # The country code of the phone number. + country_code: nil, + # A list of flags associated with the phone number. + # + # - `ported` - Indicates the phone number has been transferred from one carrier to + # another. + # - `temporary` - Indicates the phone number is likely a temporary or virtual + # number, often used for verification services or burner phones. + flags: nil, + # The type of phone line. + # + # - `calling_cards` - Numbers that are associated with providers of pre-paid + # domestic and international calling cards. + # - `fixed_line` - Landline phone numbers. + # - `isp` - Numbers reserved for Internet Service Providers. + # - `local_rate` - Numbers that can be assigned non-geographically. + # - `mobile` - Mobile phone numbers. + # - `other` - Other types of services. + # - `pager` - Number ranges specifically allocated to paging devices. + # - `payphone` - Allocated numbers for payphone kiosks in some countries. + # - `premium_rate` - Landline numbers where the calling party pays more than + # standard. + # - `satellite` - Satellite phone numbers. + # - `service` - Automated applications. + # - `shared_cost` - Specific landline ranges where the cost of making the call is + # shared between the calling and called party. + # - `short_codes_commercial` - Short codes are memorable, easy-to-use numbers, + # like the UK's NHS 111, often sold to businesses. Not available in all + # countries. + # - `toll_free` - Number where the called party pays for the cost of the call not + # the calling party. + # - `universal_access` - Number ranges reserved for Universal Access initiatives. + # - `unknown` - Unknown phone number type. + # - `vpn` - Numbers are used exclusively within a private telecommunications + # network, connecting the operator's terminals internally and not accessible via + # the public telephone network. + # - `voice_mail` - A specific category of Interactive Voice Response (IVR) + # services. + # - `voip` - Specific ranges for providers of VoIP services to allow incoming + # calls from the regular telephony network. + line_type: nil, + # The current carrier information. + network_info: nil, + # The original carrier information. + original_network_info: nil, + # The phone number. + phone_number: nil + ) + end + + sig do + override.returns( + { + caller_name: String, + country_code: String, + flags: + T::Array[ + PreludeSDK::Models::LookupLookupResponse::Flag::TaggedSymbol + ], + line_type: + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol, + network_info: PreludeSDK::Models::LookupLookupResponse::NetworkInfo, + original_network_info: + PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo, + phone_number: String + } + ) + end + def to_hash + end + + module Flag + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, PreludeSDK::Models::LookupLookupResponse::Flag) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + PORTED = + T.let( + :ported, + PreludeSDK::Models::LookupLookupResponse::Flag::TaggedSymbol + ) + TEMPORARY = + T.let( + :temporary, + PreludeSDK::Models::LookupLookupResponse::Flag::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::Models::LookupLookupResponse::Flag::TaggedSymbol + ] + ) + end + def self.values + end + end + + # The type of phone line. + # + # - `calling_cards` - Numbers that are associated with providers of pre-paid + # domestic and international calling cards. + # - `fixed_line` - Landline phone numbers. + # - `isp` - Numbers reserved for Internet Service Providers. + # - `local_rate` - Numbers that can be assigned non-geographically. + # - `mobile` - Mobile phone numbers. + # - `other` - Other types of services. + # - `pager` - Number ranges specifically allocated to paging devices. + # - `payphone` - Allocated numbers for payphone kiosks in some countries. + # - `premium_rate` - Landline numbers where the calling party pays more than + # standard. + # - `satellite` - Satellite phone numbers. + # - `service` - Automated applications. + # - `shared_cost` - Specific landline ranges where the cost of making the call is + # shared between the calling and called party. + # - `short_codes_commercial` - Short codes are memorable, easy-to-use numbers, + # like the UK's NHS 111, often sold to businesses. Not available in all + # countries. + # - `toll_free` - Number where the called party pays for the cost of the call not + # the calling party. + # - `universal_access` - Number ranges reserved for Universal Access initiatives. + # - `unknown` - Unknown phone number type. + # - `vpn` - Numbers are used exclusively within a private telecommunications + # network, connecting the operator's terminals internally and not accessible via + # the public telephone network. + # - `voice_mail` - A specific category of Interactive Voice Response (IVR) + # services. + # - `voip` - Specific ranges for providers of VoIP services to allow incoming + # calls from the regular telephony network. + module LineType + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, PreludeSDK::Models::LookupLookupResponse::LineType) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + CALLING_CARDS = + T.let( + :calling_cards, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + FIXED_LINE = + T.let( + :fixed_line, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + ISP = + T.let( + :isp, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + LOCAL_RATE = + T.let( + :local_rate, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + MOBILE = + T.let( + :mobile, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + OTHER = + T.let( + :other, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + PAGER = + T.let( + :pager, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + PAYPHONE = + T.let( + :payphone, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + PREMIUM_RATE = + T.let( + :premium_rate, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + SATELLITE = + T.let( + :satellite, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + SERVICE = + T.let( + :service, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + SHARED_COST = + T.let( + :shared_cost, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + SHORT_CODES_COMMERCIAL = + T.let( + :short_codes_commercial, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + TOLL_FREE = + T.let( + :toll_free, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + UNIVERSAL_ACCESS = + T.let( + :universal_access, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + UNKNOWN = + T.let( + :unknown, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + VPN = + T.let( + :vpn, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + VOICE_MAIL = + T.let( + :voice_mail, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + VOIP = + T.let( + :voip, + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::Models::LookupLookupResponse::LineType::TaggedSymbol + ] + ) + end + def self.values + end + end + + class NetworkInfo < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::LookupLookupResponse::NetworkInfo, + PreludeSDK::Internal::AnyHash + ) + end + + # The name of the carrier. + sig { returns(T.nilable(String)) } + attr_reader :carrier_name + + sig { params(carrier_name: String).void } + attr_writer :carrier_name + + # Mobile Country Code. + sig { returns(T.nilable(String)) } + attr_reader :mcc + + sig { params(mcc: String).void } + attr_writer :mcc + + # Mobile Network Code. + sig { returns(T.nilable(String)) } + attr_reader :mnc + + sig { params(mnc: String).void } + attr_writer :mnc + + # The current carrier information. + sig do + params(carrier_name: String, mcc: String, mnc: String).returns( + T.attached_class + ) + end + def self.new( + # The name of the carrier. + carrier_name: nil, + # Mobile Country Code. + mcc: nil, + # Mobile Network Code. + mnc: nil + ) + end + + sig do + override.returns({ carrier_name: String, mcc: String, mnc: String }) + end + def to_hash + end + end + + class OriginalNetworkInfo < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo, + PreludeSDK::Internal::AnyHash + ) + end + + # The name of the original carrier. + sig { returns(T.nilable(String)) } + attr_reader :carrier_name + + sig { params(carrier_name: String).void } + attr_writer :carrier_name + + # Mobile Country Code. + sig { returns(T.nilable(String)) } + attr_reader :mcc + + sig { params(mcc: String).void } + attr_writer :mcc + + # Mobile Network Code. + sig { returns(T.nilable(String)) } + attr_reader :mnc + + sig { params(mnc: String).void } + attr_writer :mnc + + # The original carrier information. + sig do + params(carrier_name: String, mcc: String, mnc: String).returns( + T.attached_class + ) + end + def self.new( + # The name of the original carrier. + carrier_name: nil, + # Mobile Country Code. + mcc: nil, + # Mobile Network Code. + mnc: nil + ) + end + + sig do + override.returns({ carrier_name: String, mcc: String, mnc: String }) + end + def to_hash + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/transactional_send_params.rbi b/rbi/prelude_sdk/models/transactional_send_params.rbi new file mode 100644 index 00000000..b565a35e --- /dev/null +++ b/rbi/prelude_sdk/models/transactional_send_params.rbi @@ -0,0 +1,126 @@ +# typed: strong + +module PreludeSDK + module Models + class TransactionalSendParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + OrHash = + T.type_alias do + T.any( + PreludeSDK::TransactionalSendParams, + PreludeSDK::Internal::AnyHash + ) + end + + # The template identifier. + sig { returns(String) } + attr_accessor :template_id + + # The recipient's phone number. + sig { returns(String) } + attr_accessor :to + + # The callback URL. + sig { returns(T.nilable(String)) } + attr_reader :callback_url + + sig { params(callback_url: String).void } + attr_writer :callback_url + + # A unique, user-defined identifier that will be included in webhook events. + sig { returns(T.nilable(String)) } + attr_reader :correlation_id + + sig { params(correlation_id: String).void } + attr_writer :correlation_id + + # The message expiration date. + sig { returns(T.nilable(String)) } + attr_reader :expires_at + + sig { params(expires_at: String).void } + attr_writer :expires_at + + # The Sender ID. + sig { returns(T.nilable(String)) } + attr_reader :from + + sig { params(from: String).void } + attr_writer :from + + # A BCP-47 formatted locale string with the language the text message will be sent + # to. If there's no locale set, the language will be determined by the country + # code of the phone number. If the language specified doesn't exist, the default + # set on the template will be used. + sig { returns(T.nilable(String)) } + attr_reader :locale + + sig { params(locale: String).void } + attr_writer :locale + + # The variables to be replaced in the template. + sig { returns(T.nilable(T::Hash[Symbol, String])) } + attr_reader :variables + + sig { params(variables: T::Hash[Symbol, String]).void } + attr_writer :variables + + sig do + params( + template_id: String, + to: String, + callback_url: String, + correlation_id: String, + expires_at: String, + from: String, + locale: String, + variables: T::Hash[Symbol, String], + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(T.attached_class) + end + def self.new( + # The template identifier. + template_id:, + # The recipient's phone number. + to:, + # The callback URL. + callback_url: nil, + # A unique, user-defined identifier that will be included in webhook events. + correlation_id: nil, + # The message expiration date. + expires_at: nil, + # The Sender ID. + from: nil, + # A BCP-47 formatted locale string with the language the text message will be sent + # to. If there's no locale set, the language will be determined by the country + # code of the phone number. If the language specified doesn't exist, the default + # set on the template will be used. + locale: nil, + # The variables to be replaced in the template. + variables: nil, + request_options: {} + ) + end + + sig do + override.returns( + { + template_id: String, + to: String, + callback_url: String, + correlation_id: String, + expires_at: String, + from: String, + locale: String, + variables: T::Hash[Symbol, String], + request_options: PreludeSDK::RequestOptions + } + ) + end + def to_hash + end + end + end +end diff --git a/rbi/prelude_sdk/models/transactional_send_response.rbi b/rbi/prelude_sdk/models/transactional_send_response.rbi new file mode 100644 index 00000000..f76223b8 --- /dev/null +++ b/rbi/prelude_sdk/models/transactional_send_response.rbi @@ -0,0 +1,113 @@ +# typed: strong + +module PreludeSDK + module Models + class TransactionalSendResponse < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::TransactionalSendResponse, + PreludeSDK::Internal::AnyHash + ) + end + + # The message identifier. + sig { returns(String) } + attr_accessor :id + + # The message creation date. + sig { returns(Time) } + attr_accessor :created_at + + # The message expiration date. + sig { returns(Time) } + attr_accessor :expires_at + + # The template identifier. + sig { returns(String) } + attr_accessor :template_id + + # The recipient's phone number. + sig { returns(String) } + attr_accessor :to + + # The variables to be replaced in the template. + sig { returns(T::Hash[Symbol, String]) } + attr_accessor :variables + + # The callback URL. + sig { returns(T.nilable(String)) } + attr_reader :callback_url + + sig { params(callback_url: String).void } + attr_writer :callback_url + + # A unique, user-defined identifier that will be included in webhook events. + sig { returns(T.nilable(String)) } + attr_reader :correlation_id + + sig { params(correlation_id: String).void } + attr_writer :correlation_id + + # The Sender ID. + sig { returns(T.nilable(String)) } + attr_reader :from + + sig { params(from: String).void } + attr_writer :from + + sig do + params( + id: String, + created_at: Time, + expires_at: Time, + template_id: String, + to: String, + variables: T::Hash[Symbol, String], + callback_url: String, + correlation_id: String, + from: String + ).returns(T.attached_class) + end + def self.new( + # The message identifier. + id:, + # The message creation date. + created_at:, + # The message expiration date. + expires_at:, + # The template identifier. + template_id:, + # The recipient's phone number. + to:, + # The variables to be replaced in the template. + variables:, + # The callback URL. + callback_url: nil, + # A unique, user-defined identifier that will be included in webhook events. + correlation_id: nil, + # The Sender ID. + from: nil + ) + end + + sig do + override.returns( + { + id: String, + created_at: Time, + expires_at: Time, + template_id: String, + to: String, + variables: T::Hash[Symbol, String], + callback_url: String, + correlation_id: String, + from: String + } + ) + end + def to_hash + end + end + end +end diff --git a/rbi/prelude_sdk/models/verification_check_params.rbi b/rbi/prelude_sdk/models/verification_check_params.rbi new file mode 100644 index 00000000..7819ff03 --- /dev/null +++ b/rbi/prelude_sdk/models/verification_check_params.rbi @@ -0,0 +1,140 @@ +# typed: strong + +module PreludeSDK + module Models + class VerificationCheckParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + OrHash = + T.type_alias do + T.any( + PreludeSDK::VerificationCheckParams, + PreludeSDK::Internal::AnyHash + ) + end + + # The OTP code to validate. + sig { returns(String) } + attr_accessor :code + + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + sig { returns(PreludeSDK::VerificationCheckParams::Target) } + attr_reader :target + + sig do + params(target: PreludeSDK::VerificationCheckParams::Target::OrHash).void + end + attr_writer :target + + sig do + params( + code: String, + target: PreludeSDK::VerificationCheckParams::Target::OrHash, + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(T.attached_class) + end + def self.new( + # The OTP code to validate. + code:, + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + target:, + request_options: {} + ) + end + + sig do + override.returns( + { + code: String, + target: PreludeSDK::VerificationCheckParams::Target, + request_options: PreludeSDK::RequestOptions + } + ) + end + def to_hash + end + + class Target < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::VerificationCheckParams::Target, + PreludeSDK::Internal::AnyHash + ) + end + + # The type of the target. Either "phone_number" or "email_address". + sig do + returns(PreludeSDK::VerificationCheckParams::Target::Type::OrSymbol) + end + attr_accessor :type + + # An E.164 formatted phone number or an email address. + sig { returns(String) } + attr_accessor :value + + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + sig do + params( + type: PreludeSDK::VerificationCheckParams::Target::Type::OrSymbol, + value: String + ).returns(T.attached_class) + end + def self.new( + # The type of the target. Either "phone_number" or "email_address". + type:, + # An E.164 formatted phone number or an email address. + value: + ) + end + + sig do + override.returns( + { + type: PreludeSDK::VerificationCheckParams::Target::Type::OrSymbol, + value: String + } + ) + end + def to_hash + end + + # The type of the target. Either "phone_number" or "email_address". + module Type + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, PreludeSDK::VerificationCheckParams::Target::Type) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + PHONE_NUMBER = + T.let( + :phone_number, + PreludeSDK::VerificationCheckParams::Target::Type::TaggedSymbol + ) + EMAIL_ADDRESS = + T.let( + :email_address, + PreludeSDK::VerificationCheckParams::Target::Type::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::VerificationCheckParams::Target::Type::TaggedSymbol + ] + ) + end + def self.values + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/verification_check_response.rbi b/rbi/prelude_sdk/models/verification_check_response.rbi new file mode 100644 index 00000000..a9b67156 --- /dev/null +++ b/rbi/prelude_sdk/models/verification_check_response.rbi @@ -0,0 +1,149 @@ +# typed: strong + +module PreludeSDK + module Models + class VerificationCheckResponse < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::VerificationCheckResponse, + PreludeSDK::Internal::AnyHash + ) + end + + # The status of the check. + sig do + returns( + PreludeSDK::Models::VerificationCheckResponse::Status::TaggedSymbol + ) + end + attr_accessor :status + + # The verification identifier. + sig { returns(T.nilable(String)) } + attr_reader :id + + sig { params(id: String).void } + attr_writer :id + + # The metadata for this verification. + sig do + returns( + T.nilable(PreludeSDK::Models::VerificationCheckResponse::Metadata) + ) + end + attr_reader :metadata + + sig do + params( + metadata: + PreludeSDK::Models::VerificationCheckResponse::Metadata::OrHash + ).void + end + attr_writer :metadata + + sig { returns(T.nilable(String)) } + attr_reader :request_id + + sig { params(request_id: String).void } + attr_writer :request_id + + sig do + params( + status: + PreludeSDK::Models::VerificationCheckResponse::Status::OrSymbol, + id: String, + metadata: + PreludeSDK::Models::VerificationCheckResponse::Metadata::OrHash, + request_id: String + ).returns(T.attached_class) + end + def self.new( + # The status of the check. + status:, + # The verification identifier. + id: nil, + # The metadata for this verification. + metadata: nil, + request_id: nil + ) + end + + sig do + override.returns( + { + status: + PreludeSDK::Models::VerificationCheckResponse::Status::TaggedSymbol, + id: String, + metadata: PreludeSDK::Models::VerificationCheckResponse::Metadata, + request_id: String + } + ) + end + def to_hash + end + + # The status of the check. + module Status + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, PreludeSDK::Models::VerificationCheckResponse::Status) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + SUCCESS = + T.let( + :success, + PreludeSDK::Models::VerificationCheckResponse::Status::TaggedSymbol + ) + FAILURE = + T.let( + :failure, + PreludeSDK::Models::VerificationCheckResponse::Status::TaggedSymbol + ) + EXPIRED_OR_NOT_FOUND = + T.let( + :expired_or_not_found, + PreludeSDK::Models::VerificationCheckResponse::Status::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::Models::VerificationCheckResponse::Status::TaggedSymbol + ] + ) + end + def self.values + end + end + + class Metadata < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::VerificationCheckResponse::Metadata, + PreludeSDK::Internal::AnyHash + ) + end + + sig { returns(T.nilable(String)) } + attr_reader :correlation_id + + sig { params(correlation_id: String).void } + attr_writer :correlation_id + + # The metadata for this verification. + sig { params(correlation_id: String).returns(T.attached_class) } + def self.new(correlation_id: nil) + end + + sig { override.returns({ correlation_id: String }) } + def to_hash + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/verification_create_params.rbi b/rbi/prelude_sdk/models/verification_create_params.rbi new file mode 100644 index 00000000..48087edc --- /dev/null +++ b/rbi/prelude_sdk/models/verification_create_params.rbi @@ -0,0 +1,805 @@ +# typed: strong + +module PreludeSDK + module Models + class VerificationCreateParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + OrHash = + T.type_alias do + T.any( + PreludeSDK::VerificationCreateParams, + PreludeSDK::Internal::AnyHash + ) + end + + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + sig { returns(PreludeSDK::VerificationCreateParams::Target) } + attr_reader :target + + sig do + params( + target: PreludeSDK::VerificationCreateParams::Target::OrHash + ).void + end + attr_writer :target + + # The identifier of the dispatch that came from the front-end SDK. + sig { returns(T.nilable(String)) } + attr_reader :dispatch_id + + sig { params(dispatch_id: String).void } + attr_writer :dispatch_id + + # The metadata for this verification. This object will be returned with every + # response or webhook sent that refers to this verification. + sig { returns(T.nilable(PreludeSDK::VerificationCreateParams::Metadata)) } + attr_reader :metadata + + sig do + params( + metadata: PreludeSDK::VerificationCreateParams::Metadata::OrHash + ).void + end + attr_writer :metadata + + # Verification options + sig { returns(T.nilable(PreludeSDK::VerificationCreateParams::Options)) } + attr_reader :options + + sig do + params( + options: PreludeSDK::VerificationCreateParams::Options::OrHash + ).void + end + attr_writer :options + + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + sig { returns(T.nilable(PreludeSDK::VerificationCreateParams::Signals)) } + attr_reader :signals + + sig do + params( + signals: PreludeSDK::VerificationCreateParams::Signals::OrHash + ).void + end + attr_writer :signals + + sig do + params( + target: PreludeSDK::VerificationCreateParams::Target::OrHash, + dispatch_id: String, + metadata: PreludeSDK::VerificationCreateParams::Metadata::OrHash, + options: PreludeSDK::VerificationCreateParams::Options::OrHash, + signals: PreludeSDK::VerificationCreateParams::Signals::OrHash, + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(T.attached_class) + end + def self.new( + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + target:, + # The identifier of the dispatch that came from the front-end SDK. + dispatch_id: nil, + # The metadata for this verification. This object will be returned with every + # response or webhook sent that refers to this verification. + metadata: nil, + # Verification options + options: nil, + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + signals: nil, + request_options: {} + ) + end + + sig do + override.returns( + { + target: PreludeSDK::VerificationCreateParams::Target, + dispatch_id: String, + metadata: PreludeSDK::VerificationCreateParams::Metadata, + options: PreludeSDK::VerificationCreateParams::Options, + signals: PreludeSDK::VerificationCreateParams::Signals, + request_options: PreludeSDK::RequestOptions + } + ) + end + def to_hash + end + + class Target < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::VerificationCreateParams::Target, + PreludeSDK::Internal::AnyHash + ) + end + + # The type of the target. Either "phone_number" or "email_address". + sig do + returns(PreludeSDK::VerificationCreateParams::Target::Type::OrSymbol) + end + attr_accessor :type + + # An E.164 formatted phone number or an email address. + sig { returns(String) } + attr_accessor :value + + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + sig do + params( + type: PreludeSDK::VerificationCreateParams::Target::Type::OrSymbol, + value: String + ).returns(T.attached_class) + end + def self.new( + # The type of the target. Either "phone_number" or "email_address". + type:, + # An E.164 formatted phone number or an email address. + value: + ) + end + + sig do + override.returns( + { + type: + PreludeSDK::VerificationCreateParams::Target::Type::OrSymbol, + value: String + } + ) + end + def to_hash + end + + # The type of the target. Either "phone_number" or "email_address". + module Type + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, PreludeSDK::VerificationCreateParams::Target::Type) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + PHONE_NUMBER = + T.let( + :phone_number, + PreludeSDK::VerificationCreateParams::Target::Type::TaggedSymbol + ) + EMAIL_ADDRESS = + T.let( + :email_address, + PreludeSDK::VerificationCreateParams::Target::Type::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::VerificationCreateParams::Target::Type::TaggedSymbol + ] + ) + end + def self.values + end + end + end + + class Metadata < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::VerificationCreateParams::Metadata, + PreludeSDK::Internal::AnyHash + ) + end + + # A user-defined identifier to correlate this verification with. + sig { returns(T.nilable(String)) } + attr_reader :correlation_id + + sig { params(correlation_id: String).void } + attr_writer :correlation_id + + # The metadata for this verification. This object will be returned with every + # response or webhook sent that refers to this verification. + sig { params(correlation_id: String).returns(T.attached_class) } + def self.new( + # A user-defined identifier to correlate this verification with. + correlation_id: nil + ) + end + + sig { override.returns({ correlation_id: String }) } + def to_hash + end + end + + class Options < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::VerificationCreateParams::Options, + PreludeSDK::Internal::AnyHash + ) + end + + # This allows you to automatically retrieve and fill the OTP code on mobile apps. + # Currently only Android devices are supported. + sig do + returns( + T.nilable(PreludeSDK::VerificationCreateParams::Options::AppRealm) + ) + end + attr_reader :app_realm + + sig do + params( + app_realm: + PreludeSDK::VerificationCreateParams::Options::AppRealm::OrHash + ).void + end + attr_writer :app_realm + + # The URL where webhooks will be sent when verification events occur, including + # verification creation, attempt creation, and delivery status changes. For more + # details, refer to [Webhook](/verify/v2/documentation/webhook). + sig { returns(T.nilable(String)) } + attr_reader :callback_url + + sig { params(callback_url: String).void } + attr_writer :callback_url + + # The size of the code generated. It should be between 4 and 8. Defaults to the + # code size specified from the Dashboard. + sig { returns(T.nilable(Integer)) } + attr_reader :code_size + + sig { params(code_size: Integer).void } + attr_writer :code_size + + # The custom code to use for OTP verification. To use the custom code feature, + # contact us to enable it for your account. For more details, refer to + # [Custom Code](/verify/v2/documentation/custom-codes). + sig { returns(T.nilable(String)) } + attr_reader :custom_code + + sig { params(custom_code: String).void } + attr_writer :custom_code + + # A BCP-47 formatted locale string with the language the text message will be sent + # to. If there's no locale set, the language will be determined by the country + # code of the phone number. If the language specified doesn't exist, it defaults + # to US English. + sig { returns(T.nilable(String)) } + attr_reader :locale + + sig { params(locale: String).void } + attr_writer :locale + + # The method used for verifying this phone number. The 'voice' option provides an + # accessible alternative for visually impaired users by delivering the + # verification code through a phone call rather than a text message. It also + # allows verification of landline numbers that cannot receive SMS messages. + sig do + returns( + T.nilable( + PreludeSDK::VerificationCreateParams::Options::Method::OrSymbol + ) + ) + end + attr_reader :method_ + + sig do + params( + method_: + PreludeSDK::VerificationCreateParams::Options::Method::OrSymbol + ).void + end + attr_writer :method_ + + # The preferred channel to be used in priority for verification. + sig do + returns( + T.nilable( + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::OrSymbol + ) + ) + end + attr_reader :preferred_channel + + sig do + params( + preferred_channel: + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::OrSymbol + ).void + end + attr_writer :preferred_channel + + # The Sender ID to use for this message. The Sender ID needs to be enabled by + # Prelude. + sig { returns(T.nilable(String)) } + attr_reader :sender_id + + sig { params(sender_id: String).void } + attr_writer :sender_id + + # The identifier of a verification template. It applies use case-specific + # settings, such as the message content or certain verification parameters. + sig { returns(T.nilable(String)) } + attr_reader :template_id + + sig { params(template_id: String).void } + attr_writer :template_id + + # The variables to be replaced in the template. + sig { returns(T.nilable(T::Hash[Symbol, String])) } + attr_reader :variables + + sig { params(variables: T::Hash[Symbol, String]).void } + attr_writer :variables + + # Verification options + sig do + params( + app_realm: + PreludeSDK::VerificationCreateParams::Options::AppRealm::OrHash, + callback_url: String, + code_size: Integer, + custom_code: String, + locale: String, + method_: + PreludeSDK::VerificationCreateParams::Options::Method::OrSymbol, + preferred_channel: + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::OrSymbol, + sender_id: String, + template_id: String, + variables: T::Hash[Symbol, String] + ).returns(T.attached_class) + end + def self.new( + # This allows you to automatically retrieve and fill the OTP code on mobile apps. + # Currently only Android devices are supported. + app_realm: nil, + # The URL where webhooks will be sent when verification events occur, including + # verification creation, attempt creation, and delivery status changes. For more + # details, refer to [Webhook](/verify/v2/documentation/webhook). + callback_url: nil, + # The size of the code generated. It should be between 4 and 8. Defaults to the + # code size specified from the Dashboard. + code_size: nil, + # The custom code to use for OTP verification. To use the custom code feature, + # contact us to enable it for your account. For more details, refer to + # [Custom Code](/verify/v2/documentation/custom-codes). + custom_code: nil, + # A BCP-47 formatted locale string with the language the text message will be sent + # to. If there's no locale set, the language will be determined by the country + # code of the phone number. If the language specified doesn't exist, it defaults + # to US English. + locale: nil, + # The method used for verifying this phone number. The 'voice' option provides an + # accessible alternative for visually impaired users by delivering the + # verification code through a phone call rather than a text message. It also + # allows verification of landline numbers that cannot receive SMS messages. + method_: nil, + # The preferred channel to be used in priority for verification. + preferred_channel: nil, + # The Sender ID to use for this message. The Sender ID needs to be enabled by + # Prelude. + sender_id: nil, + # The identifier of a verification template. It applies use case-specific + # settings, such as the message content or certain verification parameters. + template_id: nil, + # The variables to be replaced in the template. + variables: nil + ) + end + + sig do + override.returns( + { + app_realm: + PreludeSDK::VerificationCreateParams::Options::AppRealm, + callback_url: String, + code_size: Integer, + custom_code: String, + locale: String, + method_: + PreludeSDK::VerificationCreateParams::Options::Method::OrSymbol, + preferred_channel: + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::OrSymbol, + sender_id: String, + template_id: String, + variables: T::Hash[Symbol, String] + } + ) + end + def to_hash + end + + class AppRealm < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::VerificationCreateParams::Options::AppRealm, + PreludeSDK::Internal::AnyHash + ) + end + + # The platform the SMS will be sent to. We are currently only supporting + # "android". + sig do + returns( + PreludeSDK::VerificationCreateParams::Options::AppRealm::Platform::OrSymbol + ) + end + attr_accessor :platform + + # The Android SMS Retriever API hash code that identifies your app. + sig { returns(String) } + attr_accessor :value + + # This allows you to automatically retrieve and fill the OTP code on mobile apps. + # Currently only Android devices are supported. + sig do + params( + platform: + PreludeSDK::VerificationCreateParams::Options::AppRealm::Platform::OrSymbol, + value: String + ).returns(T.attached_class) + end + def self.new( + # The platform the SMS will be sent to. We are currently only supporting + # "android". + platform:, + # The Android SMS Retriever API hash code that identifies your app. + value: + ) + end + + sig do + override.returns( + { + platform: + PreludeSDK::VerificationCreateParams::Options::AppRealm::Platform::OrSymbol, + value: String + } + ) + end + def to_hash + end + + # The platform the SMS will be sent to. We are currently only supporting + # "android". + module Platform + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::VerificationCreateParams::Options::AppRealm::Platform + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + ANDROID = + T.let( + :android, + PreludeSDK::VerificationCreateParams::Options::AppRealm::Platform::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::VerificationCreateParams::Options::AppRealm::Platform::TaggedSymbol + ] + ) + end + def self.values + end + end + end + + # The method used for verifying this phone number. The 'voice' option provides an + # accessible alternative for visually impaired users by delivering the + # verification code through a phone call rather than a text message. It also + # allows verification of landline numbers that cannot receive SMS messages. + module Method + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::VerificationCreateParams::Options::Method + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + AUTO = + T.let( + :auto, + PreludeSDK::VerificationCreateParams::Options::Method::TaggedSymbol + ) + VOICE = + T.let( + :voice, + PreludeSDK::VerificationCreateParams::Options::Method::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::VerificationCreateParams::Options::Method::TaggedSymbol + ] + ) + end + def self.values + end + end + + # The preferred channel to be used in priority for verification. + module PreferredChannel + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::VerificationCreateParams::Options::PreferredChannel + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + SMS = + T.let( + :sms, + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::TaggedSymbol + ) + RCS = + T.let( + :rcs, + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::TaggedSymbol + ) + WHATSAPP = + T.let( + :whatsapp, + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::TaggedSymbol + ) + VIBER = + T.let( + :viber, + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::TaggedSymbol + ) + ZALO = + T.let( + :zalo, + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::TaggedSymbol + ) + TELEGRAM = + T.let( + :telegram, + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::TaggedSymbol + ) + SILENT = + T.let( + :silent, + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::TaggedSymbol + ) + VOICE = + T.let( + :voice, + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::VerificationCreateParams::Options::PreferredChannel::TaggedSymbol + ] + ) + end + def self.values + end + end + end + + class Signals < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::VerificationCreateParams::Signals, + PreludeSDK::Internal::AnyHash + ) + end + + # The version of your application. + sig { returns(T.nilable(String)) } + attr_reader :app_version + + sig { params(app_version: String).void } + attr_writer :app_version + + # The unique identifier for the user's device. For Android, this corresponds to + # the `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + sig { returns(T.nilable(String)) } + attr_reader :device_id + + sig { params(device_id: String).void } + attr_writer :device_id + + # The model of the user's device. + sig { returns(T.nilable(String)) } + attr_reader :device_model + + sig { params(device_model: String).void } + attr_writer :device_model + + # The type of the user's device. + sig do + returns( + T.nilable( + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::OrSymbol + ) + ) + end + attr_reader :device_platform + + sig do + params( + device_platform: + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::OrSymbol + ).void + end + attr_writer :device_platform + + # The IP address of the user's device. + sig { returns(T.nilable(String)) } + attr_reader :ip + + sig { params(ip: String).void } + attr_writer :ip + + # This signal should provide a higher level of trust, indicating that the user is + # genuine. Contact us to discuss your use case. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + sig { returns(T.nilable(T::Boolean)) } + attr_reader :is_trusted_user + + sig { params(is_trusted_user: T::Boolean).void } + attr_writer :is_trusted_user + + # The version of the user's device operating system. + sig { returns(T.nilable(String)) } + attr_reader :os_version + + sig { params(os_version: String).void } + attr_writer :os_version + + # The user agent of the user's device. If the individual fields (os_version, + # device_platform, device_model) are provided, we will prioritize those values + # instead of parsing them from the user agent string. + sig { returns(T.nilable(String)) } + attr_reader :user_agent + + sig { params(user_agent: String).void } + attr_writer :user_agent + + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + sig do + params( + app_version: String, + device_id: String, + device_model: String, + device_platform: + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::OrSymbol, + ip: String, + is_trusted_user: T::Boolean, + os_version: String, + user_agent: String + ).returns(T.attached_class) + end + def self.new( + # The version of your application. + app_version: nil, + # The unique identifier for the user's device. For Android, this corresponds to + # the `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + device_id: nil, + # The model of the user's device. + device_model: nil, + # The type of the user's device. + device_platform: nil, + # The IP address of the user's device. + ip: nil, + # This signal should provide a higher level of trust, indicating that the user is + # genuine. Contact us to discuss your use case. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + is_trusted_user: nil, + # The version of the user's device operating system. + os_version: nil, + # The user agent of the user's device. If the individual fields (os_version, + # device_platform, device_model) are provided, we will prioritize those values + # instead of parsing them from the user agent string. + user_agent: nil + ) + end + + sig do + override.returns( + { + app_version: String, + device_id: String, + device_model: String, + device_platform: + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::OrSymbol, + ip: String, + is_trusted_user: T::Boolean, + os_version: String, + user_agent: String + } + ) + end + def to_hash + end + + # The type of the user's device. + module DevicePlatform + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + ANDROID = + T.let( + :android, + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::TaggedSymbol + ) + IOS = + T.let( + :ios, + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::TaggedSymbol + ) + IPADOS = + T.let( + :ipados, + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::TaggedSymbol + ) + TVOS = + T.let( + :tvos, + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::TaggedSymbol + ) + WEB = + T.let( + :web, + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::VerificationCreateParams::Signals::DevicePlatform::TaggedSymbol + ] + ) + end + def self.values + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/verification_create_response.rbi b/rbi/prelude_sdk/models/verification_create_response.rbi new file mode 100644 index 00000000..891328f1 --- /dev/null +++ b/rbi/prelude_sdk/models/verification_create_response.rbi @@ -0,0 +1,336 @@ +# typed: strong + +module PreludeSDK + module Models + class VerificationCreateResponse < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::VerificationCreateResponse, + PreludeSDK::Internal::AnyHash + ) + end + + # The verification identifier. + sig { returns(String) } + attr_accessor :id + + # The method used for verifying this phone number. + sig do + returns( + PreludeSDK::Models::VerificationCreateResponse::Method::TaggedSymbol + ) + end + attr_accessor :method_ + + # The status of the verification. + sig do + returns( + PreludeSDK::Models::VerificationCreateResponse::Status::TaggedSymbol + ) + end + attr_accessor :status + + # The ordered sequence of channels to be used for verification + sig { returns(T.nilable(T::Array[String])) } + attr_reader :channels + + sig { params(channels: T::Array[String]).void } + attr_writer :channels + + # The metadata for this verification. + sig do + returns( + T.nilable(PreludeSDK::Models::VerificationCreateResponse::Metadata) + ) + end + attr_reader :metadata + + sig do + params( + metadata: + PreludeSDK::Models::VerificationCreateResponse::Metadata::OrHash + ).void + end + attr_writer :metadata + + # The reason why the verification was blocked. Only present when status is + # "blocked". + sig do + returns( + T.nilable( + PreludeSDK::Models::VerificationCreateResponse::Reason::TaggedSymbol + ) + ) + end + attr_reader :reason + + sig do + params( + reason: + PreludeSDK::Models::VerificationCreateResponse::Reason::OrSymbol + ).void + end + attr_writer :reason + + sig { returns(T.nilable(String)) } + attr_reader :request_id + + sig { params(request_id: String).void } + attr_writer :request_id + + # The silent verification specific properties. + sig do + returns( + T.nilable(PreludeSDK::Models::VerificationCreateResponse::Silent) + ) + end + attr_reader :silent + + sig do + params( + silent: PreludeSDK::Models::VerificationCreateResponse::Silent::OrHash + ).void + end + attr_writer :silent + + sig do + params( + id: String, + method_: + PreludeSDK::Models::VerificationCreateResponse::Method::OrSymbol, + status: + PreludeSDK::Models::VerificationCreateResponse::Status::OrSymbol, + channels: T::Array[String], + metadata: + PreludeSDK::Models::VerificationCreateResponse::Metadata::OrHash, + reason: + PreludeSDK::Models::VerificationCreateResponse::Reason::OrSymbol, + request_id: String, + silent: PreludeSDK::Models::VerificationCreateResponse::Silent::OrHash + ).returns(T.attached_class) + end + def self.new( + # The verification identifier. + id:, + # The method used for verifying this phone number. + method_:, + # The status of the verification. + status:, + # The ordered sequence of channels to be used for verification + channels: nil, + # The metadata for this verification. + metadata: nil, + # The reason why the verification was blocked. Only present when status is + # "blocked". + reason: nil, + request_id: nil, + # The silent verification specific properties. + silent: nil + ) + end + + sig do + override.returns( + { + id: String, + method_: + PreludeSDK::Models::VerificationCreateResponse::Method::TaggedSymbol, + status: + PreludeSDK::Models::VerificationCreateResponse::Status::TaggedSymbol, + channels: T::Array[String], + metadata: PreludeSDK::Models::VerificationCreateResponse::Metadata, + reason: + PreludeSDK::Models::VerificationCreateResponse::Reason::TaggedSymbol, + request_id: String, + silent: PreludeSDK::Models::VerificationCreateResponse::Silent + } + ) + end + def to_hash + end + + # The method used for verifying this phone number. + module Method + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::Models::VerificationCreateResponse::Method + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + MESSAGE = + T.let( + :message, + PreludeSDK::Models::VerificationCreateResponse::Method::TaggedSymbol + ) + SILENT = + T.let( + :silent, + PreludeSDK::Models::VerificationCreateResponse::Method::TaggedSymbol + ) + VOICE = + T.let( + :voice, + PreludeSDK::Models::VerificationCreateResponse::Method::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::Models::VerificationCreateResponse::Method::TaggedSymbol + ] + ) + end + def self.values + end + end + + # The status of the verification. + module Status + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::Models::VerificationCreateResponse::Status + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + SUCCESS = + T.let( + :success, + PreludeSDK::Models::VerificationCreateResponse::Status::TaggedSymbol + ) + RETRY = + T.let( + :retry, + PreludeSDK::Models::VerificationCreateResponse::Status::TaggedSymbol + ) + BLOCKED = + T.let( + :blocked, + PreludeSDK::Models::VerificationCreateResponse::Status::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::Models::VerificationCreateResponse::Status::TaggedSymbol + ] + ) + end + def self.values + end + end + + class Metadata < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::VerificationCreateResponse::Metadata, + PreludeSDK::Internal::AnyHash + ) + end + + sig { returns(T.nilable(String)) } + attr_reader :correlation_id + + sig { params(correlation_id: String).void } + attr_writer :correlation_id + + # The metadata for this verification. + sig { params(correlation_id: String).returns(T.attached_class) } + def self.new(correlation_id: nil) + end + + sig { override.returns({ correlation_id: String }) } + def to_hash + end + end + + # The reason why the verification was blocked. Only present when status is + # "blocked". + module Reason + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::Models::VerificationCreateResponse::Reason + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + SUSPICIOUS = + T.let( + :suspicious, + PreludeSDK::Models::VerificationCreateResponse::Reason::TaggedSymbol + ) + REPEATED_ATTEMPTS = + T.let( + :repeated_attempts, + PreludeSDK::Models::VerificationCreateResponse::Reason::TaggedSymbol + ) + INVALID_PHONE_LINE = + T.let( + :invalid_phone_line, + PreludeSDK::Models::VerificationCreateResponse::Reason::TaggedSymbol + ) + INVALID_PHONE_NUMBER = + T.let( + :invalid_phone_number, + PreludeSDK::Models::VerificationCreateResponse::Reason::TaggedSymbol + ) + IN_BLOCK_LIST = + T.let( + :in_block_list, + PreludeSDK::Models::VerificationCreateResponse::Reason::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::Models::VerificationCreateResponse::Reason::TaggedSymbol + ] + ) + end + def self.values + end + end + + class Silent < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::VerificationCreateResponse::Silent, + PreludeSDK::Internal::AnyHash + ) + end + + # The URL to start the silent verification towards. + sig { returns(String) } + attr_accessor :request_url + + # The silent verification specific properties. + sig { params(request_url: String).returns(T.attached_class) } + def self.new( + # The URL to start the silent verification towards. + request_url: + ) + end + + sig { override.returns({ request_url: String }) } + def to_hash + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/watch_predict_params.rbi b/rbi/prelude_sdk/models/watch_predict_params.rbi new file mode 100644 index 00000000..1124519c --- /dev/null +++ b/rbi/prelude_sdk/models/watch_predict_params.rbi @@ -0,0 +1,382 @@ +# typed: strong + +module PreludeSDK + module Models + class WatchPredictParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + OrHash = + T.type_alias do + T.any(PreludeSDK::WatchPredictParams, PreludeSDK::Internal::AnyHash) + end + + # The prediction target. Only supports phone numbers for now. + sig { returns(PreludeSDK::WatchPredictParams::Target) } + attr_reader :target + + sig do + params(target: PreludeSDK::WatchPredictParams::Target::OrHash).void + end + attr_writer :target + + # The identifier of the dispatch that came from the front-end SDK. + sig { returns(T.nilable(String)) } + attr_reader :dispatch_id + + sig { params(dispatch_id: String).void } + attr_writer :dispatch_id + + # The metadata for this prediction. + sig { returns(T.nilable(PreludeSDK::WatchPredictParams::Metadata)) } + attr_reader :metadata + + sig do + params(metadata: PreludeSDK::WatchPredictParams::Metadata::OrHash).void + end + attr_writer :metadata + + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + sig { returns(T.nilable(PreludeSDK::WatchPredictParams::Signals)) } + attr_reader :signals + + sig do + params(signals: PreludeSDK::WatchPredictParams::Signals::OrHash).void + end + attr_writer :signals + + sig do + params( + target: PreludeSDK::WatchPredictParams::Target::OrHash, + dispatch_id: String, + metadata: PreludeSDK::WatchPredictParams::Metadata::OrHash, + signals: PreludeSDK::WatchPredictParams::Signals::OrHash, + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(T.attached_class) + end + def self.new( + # The prediction target. Only supports phone numbers for now. + target:, + # The identifier of the dispatch that came from the front-end SDK. + dispatch_id: nil, + # The metadata for this prediction. + metadata: nil, + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + signals: nil, + request_options: {} + ) + end + + sig do + override.returns( + { + target: PreludeSDK::WatchPredictParams::Target, + dispatch_id: String, + metadata: PreludeSDK::WatchPredictParams::Metadata, + signals: PreludeSDK::WatchPredictParams::Signals, + request_options: PreludeSDK::RequestOptions + } + ) + end + def to_hash + end + + class Target < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchPredictParams::Target, + PreludeSDK::Internal::AnyHash + ) + end + + # The type of the target. Either "phone_number" or "email_address". + sig { returns(PreludeSDK::WatchPredictParams::Target::Type::OrSymbol) } + attr_accessor :type + + # An E.164 formatted phone number or an email address. + sig { returns(String) } + attr_accessor :value + + # The prediction target. Only supports phone numbers for now. + sig do + params( + type: PreludeSDK::WatchPredictParams::Target::Type::OrSymbol, + value: String + ).returns(T.attached_class) + end + def self.new( + # The type of the target. Either "phone_number" or "email_address". + type:, + # An E.164 formatted phone number or an email address. + value: + ) + end + + sig do + override.returns( + { + type: PreludeSDK::WatchPredictParams::Target::Type::OrSymbol, + value: String + } + ) + end + def to_hash + end + + # The type of the target. Either "phone_number" or "email_address". + module Type + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, PreludeSDK::WatchPredictParams::Target::Type) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + PHONE_NUMBER = + T.let( + :phone_number, + PreludeSDK::WatchPredictParams::Target::Type::TaggedSymbol + ) + EMAIL_ADDRESS = + T.let( + :email_address, + PreludeSDK::WatchPredictParams::Target::Type::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::WatchPredictParams::Target::Type::TaggedSymbol + ] + ) + end + def self.values + end + end + end + + class Metadata < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchPredictParams::Metadata, + PreludeSDK::Internal::AnyHash + ) + end + + # A user-defined identifier to correlate this prediction with. + sig { returns(T.nilable(String)) } + attr_reader :correlation_id + + sig { params(correlation_id: String).void } + attr_writer :correlation_id + + # The metadata for this prediction. + sig { params(correlation_id: String).returns(T.attached_class) } + def self.new( + # A user-defined identifier to correlate this prediction with. + correlation_id: nil + ) + end + + sig { override.returns({ correlation_id: String }) } + def to_hash + end + end + + class Signals < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchPredictParams::Signals, + PreludeSDK::Internal::AnyHash + ) + end + + # The version of your application. + sig { returns(T.nilable(String)) } + attr_reader :app_version + + sig { params(app_version: String).void } + attr_writer :app_version + + # The unique identifier for the user's device. For Android, this corresponds to + # the `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + sig { returns(T.nilable(String)) } + attr_reader :device_id + + sig { params(device_id: String).void } + attr_writer :device_id + + # The model of the user's device. + sig { returns(T.nilable(String)) } + attr_reader :device_model + + sig { params(device_model: String).void } + attr_writer :device_model + + # The type of the user's device. + sig do + returns( + T.nilable( + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::OrSymbol + ) + ) + end + attr_reader :device_platform + + sig do + params( + device_platform: + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::OrSymbol + ).void + end + attr_writer :device_platform + + # The IP address of the user's device. + sig { returns(T.nilable(String)) } + attr_reader :ip + + sig { params(ip: String).void } + attr_writer :ip + + # This signal should provide a higher level of trust, indicating that the user is + # genuine. Contact us to discuss your use case. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + sig { returns(T.nilable(T::Boolean)) } + attr_reader :is_trusted_user + + sig { params(is_trusted_user: T::Boolean).void } + attr_writer :is_trusted_user + + # The version of the user's device operating system. + sig { returns(T.nilable(String)) } + attr_reader :os_version + + sig { params(os_version: String).void } + attr_writer :os_version + + # The user agent of the user's device. If the individual fields (os_version, + # device_platform, device_model) are provided, we will prioritize those values + # instead of parsing them from the user agent string. + sig { returns(T.nilable(String)) } + attr_reader :user_agent + + sig { params(user_agent: String).void } + attr_writer :user_agent + + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + sig do + params( + app_version: String, + device_id: String, + device_model: String, + device_platform: + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::OrSymbol, + ip: String, + is_trusted_user: T::Boolean, + os_version: String, + user_agent: String + ).returns(T.attached_class) + end + def self.new( + # The version of your application. + app_version: nil, + # The unique identifier for the user's device. For Android, this corresponds to + # the `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + device_id: nil, + # The model of the user's device. + device_model: nil, + # The type of the user's device. + device_platform: nil, + # The IP address of the user's device. + ip: nil, + # This signal should provide a higher level of trust, indicating that the user is + # genuine. Contact us to discuss your use case. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + is_trusted_user: nil, + # The version of the user's device operating system. + os_version: nil, + # The user agent of the user's device. If the individual fields (os_version, + # device_platform, device_model) are provided, we will prioritize those values + # instead of parsing them from the user agent string. + user_agent: nil + ) + end + + sig do + override.returns( + { + app_version: String, + device_id: String, + device_model: String, + device_platform: + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::OrSymbol, + ip: String, + is_trusted_user: T::Boolean, + os_version: String, + user_agent: String + } + ) + end + def to_hash + end + + # The type of the user's device. + module DevicePlatform + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::WatchPredictParams::Signals::DevicePlatform + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + ANDROID = + T.let( + :android, + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::TaggedSymbol + ) + IOS = + T.let( + :ios, + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::TaggedSymbol + ) + IPADOS = + T.let( + :ipados, + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::TaggedSymbol + ) + TVOS = + T.let( + :tvos, + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::TaggedSymbol + ) + WEB = + T.let( + :web, + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::WatchPredictParams::Signals::DevicePlatform::TaggedSymbol + ] + ) + end + def self.values + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/watch_predict_response.rbi b/rbi/prelude_sdk/models/watch_predict_response.rbi new file mode 100644 index 00000000..0b943e5c --- /dev/null +++ b/rbi/prelude_sdk/models/watch_predict_response.rbi @@ -0,0 +1,96 @@ +# typed: strong + +module PreludeSDK + module Models + class WatchPredictResponse < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::WatchPredictResponse, + PreludeSDK::Internal::AnyHash + ) + end + + # The prediction identifier. + sig { returns(String) } + attr_accessor :id + + # The prediction outcome. + sig do + returns( + PreludeSDK::Models::WatchPredictResponse::Prediction::TaggedSymbol + ) + end + attr_accessor :prediction + + # A string that identifies this specific request. Report it back to us to help us + # diagnose your issues. + sig { returns(String) } + attr_accessor :request_id + + sig do + params( + id: String, + prediction: + PreludeSDK::Models::WatchPredictResponse::Prediction::OrSymbol, + request_id: String + ).returns(T.attached_class) + end + def self.new( + # The prediction identifier. + id:, + # The prediction outcome. + prediction:, + # A string that identifies this specific request. Report it back to us to help us + # diagnose your issues. + request_id: + ) + end + + sig do + override.returns( + { + id: String, + prediction: + PreludeSDK::Models::WatchPredictResponse::Prediction::TaggedSymbol, + request_id: String + } + ) + end + def to_hash + end + + # The prediction outcome. + module Prediction + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, PreludeSDK::Models::WatchPredictResponse::Prediction) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + LEGITIMATE = + T.let( + :legitimate, + PreludeSDK::Models::WatchPredictResponse::Prediction::TaggedSymbol + ) + SUSPICIOUS = + T.let( + :suspicious, + PreludeSDK::Models::WatchPredictResponse::Prediction::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::Models::WatchPredictResponse::Prediction::TaggedSymbol + ] + ) + end + def self.values + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/watch_send_events_params.rbi b/rbi/prelude_sdk/models/watch_send_events_params.rbi new file mode 100644 index 00000000..203e2c89 --- /dev/null +++ b/rbi/prelude_sdk/models/watch_send_events_params.rbi @@ -0,0 +1,245 @@ +# typed: strong + +module PreludeSDK + module Models + class WatchSendEventsParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchSendEventsParams, + PreludeSDK::Internal::AnyHash + ) + end + + # A list of events to dispatch. + sig { returns(T::Array[PreludeSDK::WatchSendEventsParams::Event]) } + attr_accessor :events + + sig do + params( + events: T::Array[PreludeSDK::WatchSendEventsParams::Event::OrHash], + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(T.attached_class) + end + def self.new( + # A list of events to dispatch. + events:, + request_options: {} + ) + end + + sig do + override.returns( + { + events: T::Array[PreludeSDK::WatchSendEventsParams::Event], + request_options: PreludeSDK::RequestOptions + } + ) + end + def to_hash + end + + class Event < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchSendEventsParams::Event, + PreludeSDK::Internal::AnyHash + ) + end + + # A confidence level you want to assign to the event. + sig do + returns( + PreludeSDK::WatchSendEventsParams::Event::Confidence::OrSymbol + ) + end + attr_accessor :confidence + + # A label to describe what the event refers to. + sig { returns(String) } + attr_accessor :label + + # The event target. Only supports phone numbers for now. + sig { returns(PreludeSDK::WatchSendEventsParams::Event::Target) } + attr_reader :target + + sig do + params( + target: PreludeSDK::WatchSendEventsParams::Event::Target::OrHash + ).void + end + attr_writer :target + + sig do + params( + confidence: + PreludeSDK::WatchSendEventsParams::Event::Confidence::OrSymbol, + label: String, + target: PreludeSDK::WatchSendEventsParams::Event::Target::OrHash + ).returns(T.attached_class) + end + def self.new( + # A confidence level you want to assign to the event. + confidence:, + # A label to describe what the event refers to. + label:, + # The event target. Only supports phone numbers for now. + target: + ) + end + + sig do + override.returns( + { + confidence: + PreludeSDK::WatchSendEventsParams::Event::Confidence::OrSymbol, + label: String, + target: PreludeSDK::WatchSendEventsParams::Event::Target + } + ) + end + def to_hash + end + + # A confidence level you want to assign to the event. + module Confidence + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::WatchSendEventsParams::Event::Confidence + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + MAXIMUM = + T.let( + :maximum, + PreludeSDK::WatchSendEventsParams::Event::Confidence::TaggedSymbol + ) + HIGH = + T.let( + :high, + PreludeSDK::WatchSendEventsParams::Event::Confidence::TaggedSymbol + ) + NEUTRAL = + T.let( + :neutral, + PreludeSDK::WatchSendEventsParams::Event::Confidence::TaggedSymbol + ) + LOW = + T.let( + :low, + PreludeSDK::WatchSendEventsParams::Event::Confidence::TaggedSymbol + ) + MINIMUM = + T.let( + :minimum, + PreludeSDK::WatchSendEventsParams::Event::Confidence::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::WatchSendEventsParams::Event::Confidence::TaggedSymbol + ] + ) + end + def self.values + end + end + + class Target < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchSendEventsParams::Event::Target, + PreludeSDK::Internal::AnyHash + ) + end + + # The type of the target. Either "phone_number" or "email_address". + sig do + returns( + PreludeSDK::WatchSendEventsParams::Event::Target::Type::OrSymbol + ) + end + attr_accessor :type + + # An E.164 formatted phone number or an email address. + sig { returns(String) } + attr_accessor :value + + # The event target. Only supports phone numbers for now. + sig do + params( + type: + PreludeSDK::WatchSendEventsParams::Event::Target::Type::OrSymbol, + value: String + ).returns(T.attached_class) + end + def self.new( + # The type of the target. Either "phone_number" or "email_address". + type:, + # An E.164 formatted phone number or an email address. + value: + ) + end + + sig do + override.returns( + { + type: + PreludeSDK::WatchSendEventsParams::Event::Target::Type::OrSymbol, + value: String + } + ) + end + def to_hash + end + + # The type of the target. Either "phone_number" or "email_address". + module Type + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::WatchSendEventsParams::Event::Target::Type + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + PHONE_NUMBER = + T.let( + :phone_number, + PreludeSDK::WatchSendEventsParams::Event::Target::Type::TaggedSymbol + ) + EMAIL_ADDRESS = + T.let( + :email_address, + PreludeSDK::WatchSendEventsParams::Event::Target::Type::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::WatchSendEventsParams::Event::Target::Type::TaggedSymbol + ] + ) + end + def self.values + end + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/watch_send_events_response.rbi b/rbi/prelude_sdk/models/watch_send_events_response.rbi new file mode 100644 index 00000000..f2836804 --- /dev/null +++ b/rbi/prelude_sdk/models/watch_send_events_response.rbi @@ -0,0 +1,82 @@ +# typed: strong + +module PreludeSDK + module Models + class WatchSendEventsResponse < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::WatchSendEventsResponse, + PreludeSDK::Internal::AnyHash + ) + end + + # A string that identifies this specific request. Report it back to us to help us + # diagnose your issues. + sig { returns(String) } + attr_accessor :request_id + + # The status of the events dispatch. + sig do + returns( + PreludeSDK::Models::WatchSendEventsResponse::Status::TaggedSymbol + ) + end + attr_accessor :status + + sig do + params( + request_id: String, + status: PreludeSDK::Models::WatchSendEventsResponse::Status::OrSymbol + ).returns(T.attached_class) + end + def self.new( + # A string that identifies this specific request. Report it back to us to help us + # diagnose your issues. + request_id:, + # The status of the events dispatch. + status: + ) + end + + sig do + override.returns( + { + request_id: String, + status: + PreludeSDK::Models::WatchSendEventsResponse::Status::TaggedSymbol + } + ) + end + def to_hash + end + + # The status of the events dispatch. + module Status + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, PreludeSDK::Models::WatchSendEventsResponse::Status) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + SUCCESS = + T.let( + :success, + PreludeSDK::Models::WatchSendEventsResponse::Status::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::Models::WatchSendEventsResponse::Status::TaggedSymbol + ] + ) + end + def self.values + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/watch_send_feedbacks_params.rbi b/rbi/prelude_sdk/models/watch_send_feedbacks_params.rbi new file mode 100644 index 00000000..94ced708 --- /dev/null +++ b/rbi/prelude_sdk/models/watch_send_feedbacks_params.rbi @@ -0,0 +1,500 @@ +# typed: strong + +module PreludeSDK + module Models + class WatchSendFeedbacksParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchSendFeedbacksParams, + PreludeSDK::Internal::AnyHash + ) + end + + # A list of feedbacks to send. + sig { returns(T::Array[PreludeSDK::WatchSendFeedbacksParams::Feedback]) } + attr_accessor :feedbacks + + sig do + params( + feedbacks: + T::Array[PreludeSDK::WatchSendFeedbacksParams::Feedback::OrHash], + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(T.attached_class) + end + def self.new( + # A list of feedbacks to send. + feedbacks:, + request_options: {} + ) + end + + sig do + override.returns( + { + feedbacks: T::Array[PreludeSDK::WatchSendFeedbacksParams::Feedback], + request_options: PreludeSDK::RequestOptions + } + ) + end + def to_hash + end + + class Feedback < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchSendFeedbacksParams::Feedback, + PreludeSDK::Internal::AnyHash + ) + end + + # The feedback target. Only supports phone numbers for now. + sig { returns(PreludeSDK::WatchSendFeedbacksParams::Feedback::Target) } + attr_reader :target + + sig do + params( + target: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::OrHash + ).void + end + attr_writer :target + + # The type of feedback. + sig do + returns( + PreludeSDK::WatchSendFeedbacksParams::Feedback::Type::OrSymbol + ) + end + attr_accessor :type + + # The identifier of the dispatch that came from the front-end SDK. + sig { returns(T.nilable(String)) } + attr_reader :dispatch_id + + sig { params(dispatch_id: String).void } + attr_writer :dispatch_id + + # The metadata for this feedback. + sig do + returns( + T.nilable(PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata) + ) + end + attr_reader :metadata + + sig do + params( + metadata: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata::OrHash + ).void + end + attr_writer :metadata + + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + sig do + returns( + T.nilable(PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals) + ) + end + attr_reader :signals + + sig do + params( + signals: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::OrHash + ).void + end + attr_writer :signals + + sig do + params( + target: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::OrHash, + type: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Type::OrSymbol, + dispatch_id: String, + metadata: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata::OrHash, + signals: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::OrHash + ).returns(T.attached_class) + end + def self.new( + # The feedback target. Only supports phone numbers for now. + target:, + # The type of feedback. + type:, + # The identifier of the dispatch that came from the front-end SDK. + dispatch_id: nil, + # The metadata for this feedback. + metadata: nil, + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + signals: nil + ) + end + + sig do + override.returns( + { + target: PreludeSDK::WatchSendFeedbacksParams::Feedback::Target, + type: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Type::OrSymbol, + dispatch_id: String, + metadata: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata, + signals: PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals + } + ) + end + def to_hash + end + + class Target < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target, + PreludeSDK::Internal::AnyHash + ) + end + + # The type of the target. Either "phone_number" or "email_address". + sig do + returns( + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::Type::OrSymbol + ) + end + attr_accessor :type + + # An E.164 formatted phone number or an email address. + sig { returns(String) } + attr_accessor :value + + # The feedback target. Only supports phone numbers for now. + sig do + params( + type: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::Type::OrSymbol, + value: String + ).returns(T.attached_class) + end + def self.new( + # The type of the target. Either "phone_number" or "email_address". + type:, + # An E.164 formatted phone number or an email address. + value: + ) + end + + sig do + override.returns( + { + type: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::Type::OrSymbol, + value: String + } + ) + end + def to_hash + end + + # The type of the target. Either "phone_number" or "email_address". + module Type + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::Type + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + PHONE_NUMBER = + T.let( + :phone_number, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::Type::TaggedSymbol + ) + EMAIL_ADDRESS = + T.let( + :email_address, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::Type::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::WatchSendFeedbacksParams::Feedback::Target::Type::TaggedSymbol + ] + ) + end + def self.values + end + end + end + + # The type of feedback. + module Type + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Type + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + VERIFICATION_STARTED = + T.let( + :"verification.started", + PreludeSDK::WatchSendFeedbacksParams::Feedback::Type::TaggedSymbol + ) + VERIFICATION_COMPLETED = + T.let( + :"verification.completed", + PreludeSDK::WatchSendFeedbacksParams::Feedback::Type::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::WatchSendFeedbacksParams::Feedback::Type::TaggedSymbol + ] + ) + end + def self.values + end + end + + class Metadata < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata, + PreludeSDK::Internal::AnyHash + ) + end + + # A user-defined identifier to correlate this feedback with. + sig { returns(T.nilable(String)) } + attr_reader :correlation_id + + sig { params(correlation_id: String).void } + attr_writer :correlation_id + + # The metadata for this feedback. + sig { params(correlation_id: String).returns(T.attached_class) } + def self.new( + # A user-defined identifier to correlate this feedback with. + correlation_id: nil + ) + end + + sig { override.returns({ correlation_id: String }) } + def to_hash + end + end + + class Signals < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals, + PreludeSDK::Internal::AnyHash + ) + end + + # The version of your application. + sig { returns(T.nilable(String)) } + attr_reader :app_version + + sig { params(app_version: String).void } + attr_writer :app_version + + # The unique identifier for the user's device. For Android, this corresponds to + # the `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + sig { returns(T.nilable(String)) } + attr_reader :device_id + + sig { params(device_id: String).void } + attr_writer :device_id + + # The model of the user's device. + sig { returns(T.nilable(String)) } + attr_reader :device_model + + sig { params(device_model: String).void } + attr_writer :device_model + + # The type of the user's device. + sig do + returns( + T.nilable( + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::OrSymbol + ) + ) + end + attr_reader :device_platform + + sig do + params( + device_platform: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::OrSymbol + ).void + end + attr_writer :device_platform + + # The IP address of the user's device. + sig { returns(T.nilable(String)) } + attr_reader :ip + + sig { params(ip: String).void } + attr_writer :ip + + # This signal should provide a higher level of trust, indicating that the user is + # genuine. Contact us to discuss your use case. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + sig { returns(T.nilable(T::Boolean)) } + attr_reader :is_trusted_user + + sig { params(is_trusted_user: T::Boolean).void } + attr_writer :is_trusted_user + + # The version of the user's device operating system. + sig { returns(T.nilable(String)) } + attr_reader :os_version + + sig { params(os_version: String).void } + attr_writer :os_version + + # The user agent of the user's device. If the individual fields (os_version, + # device_platform, device_model) are provided, we will prioritize those values + # instead of parsing them from the user agent string. + sig { returns(T.nilable(String)) } + attr_reader :user_agent + + sig { params(user_agent: String).void } + attr_writer :user_agent + + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + sig do + params( + app_version: String, + device_id: String, + device_model: String, + device_platform: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::OrSymbol, + ip: String, + is_trusted_user: T::Boolean, + os_version: String, + user_agent: String + ).returns(T.attached_class) + end + def self.new( + # The version of your application. + app_version: nil, + # The unique identifier for the user's device. For Android, this corresponds to + # the `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + device_id: nil, + # The model of the user's device. + device_model: nil, + # The type of the user's device. + device_platform: nil, + # The IP address of the user's device. + ip: nil, + # This signal should provide a higher level of trust, indicating that the user is + # genuine. Contact us to discuss your use case. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + is_trusted_user: nil, + # The version of the user's device operating system. + os_version: nil, + # The user agent of the user's device. If the individual fields (os_version, + # device_platform, device_model) are provided, we will prioritize those values + # instead of parsing them from the user agent string. + user_agent: nil + ) + end + + sig do + override.returns( + { + app_version: String, + device_id: String, + device_model: String, + device_platform: + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::OrSymbol, + ip: String, + is_trusted_user: T::Boolean, + os_version: String, + user_agent: String + } + ) + end + def to_hash + end + + # The type of the user's device. + module DevicePlatform + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + ANDROID = + T.let( + :android, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::TaggedSymbol + ) + IOS = + T.let( + :ios, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::TaggedSymbol + ) + IPADOS = + T.let( + :ipados, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::TaggedSymbol + ) + TVOS = + T.let( + :tvos, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::TaggedSymbol + ) + WEB = + T.let( + :web, + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals::DevicePlatform::TaggedSymbol + ] + ) + end + def self.values + end + end + end + end + end + end +end diff --git a/rbi/prelude_sdk/models/watch_send_feedbacks_response.rbi b/rbi/prelude_sdk/models/watch_send_feedbacks_response.rbi new file mode 100644 index 00000000..3be9f0b8 --- /dev/null +++ b/rbi/prelude_sdk/models/watch_send_feedbacks_response.rbi @@ -0,0 +1,86 @@ +# typed: strong + +module PreludeSDK + module Models + class WatchSendFeedbacksResponse < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + PreludeSDK::Models::WatchSendFeedbacksResponse, + PreludeSDK::Internal::AnyHash + ) + end + + # A string that identifies this specific request. Report it back to us to help us + # diagnose your issues. + sig { returns(String) } + attr_accessor :request_id + + # The status of the feedbacks sending. + sig do + returns( + PreludeSDK::Models::WatchSendFeedbacksResponse::Status::TaggedSymbol + ) + end + attr_accessor :status + + sig do + params( + request_id: String, + status: + PreludeSDK::Models::WatchSendFeedbacksResponse::Status::OrSymbol + ).returns(T.attached_class) + end + def self.new( + # A string that identifies this specific request. Report it back to us to help us + # diagnose your issues. + request_id:, + # The status of the feedbacks sending. + status: + ) + end + + sig do + override.returns( + { + request_id: String, + status: + PreludeSDK::Models::WatchSendFeedbacksResponse::Status::TaggedSymbol + } + ) + end + def to_hash + end + + # The status of the feedbacks sending. + module Status + extend PreludeSDK::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + PreludeSDK::Models::WatchSendFeedbacksResponse::Status + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + SUCCESS = + T.let( + :success, + PreludeSDK::Models::WatchSendFeedbacksResponse::Status::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + PreludeSDK::Models::WatchSendFeedbacksResponse::Status::TaggedSymbol + ] + ) + end + def self.values + end + end + end + end +end diff --git a/rbi/prelude_sdk/request_options.rbi b/rbi/prelude_sdk/request_options.rbi new file mode 100644 index 00000000..97fe00d5 --- /dev/null +++ b/rbi/prelude_sdk/request_options.rbi @@ -0,0 +1,59 @@ +# typed: strong + +module PreludeSDK + # Specify HTTP behaviour to use for a specific request. These options supplement + # or override those provided at the client level. + # + # When making a request, you can pass an actual {RequestOptions} instance, or + # simply pass a Hash with symbol keys matching the attributes on this class. + class RequestOptions < PreludeSDK::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any(PreludeSDK::RequestOptions, PreludeSDK::Internal::AnyHash) + end + + # @api private + sig { params(opts: PreludeSDK::RequestOptions::OrHash).void } + def self.validate!(opts) + end + + # Idempotency key to send with request and all associated retries. Will only be + # sent for write requests. + sig { returns(T.nilable(String)) } + attr_accessor :idempotency_key + + # Extra query params to send with the request. These are `.merge`’d into any + # `query` given at the client level. + sig do + returns( + T.nilable(T::Hash[String, T.nilable(T.any(T::Array[String], String))]) + ) + end + attr_accessor :extra_query + + # Extra headers to send with the request. These are `.merged`’d into any + # `extra_headers` given at the client level. + sig { returns(T.nilable(T::Hash[String, T.nilable(String)])) } + attr_accessor :extra_headers + + # Extra data to send with the request. These are deep merged into any data + # generated as part of the normal request. + sig { returns(T.nilable(T.anything)) } + attr_accessor :extra_body + + # Maximum number of retries to attempt after a failed initial request. + sig { returns(T.nilable(Integer)) } + attr_accessor :max_retries + + # Request timeout in seconds. + sig { returns(T.nilable(Float)) } + attr_accessor :timeout + + # Returns a new instance of RequestOptions. + sig do + params(values: PreludeSDK::Internal::AnyHash).returns(T.attached_class) + end + def self.new(values = {}) + end + end +end diff --git a/rbi/prelude_sdk/resources/lookup.rbi b/rbi/prelude_sdk/resources/lookup.rbi new file mode 100644 index 00000000..05342a88 --- /dev/null +++ b/rbi/prelude_sdk/resources/lookup.rbi @@ -0,0 +1,33 @@ +# typed: strong + +module PreludeSDK + module Resources + class Lookup + # Retrieve detailed information about a phone number including carrier data, line + # type, and portability status. + sig do + params( + phone_number: String, + type: T::Array[PreludeSDK::LookupLookupParams::Type::OrSymbol], + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(PreludeSDK::Models::LookupLookupResponse) + end + def lookup( + # An E.164 formatted phone number to look up. + phone_number, + # Optional features. Possible values are: + # + # - `cnam` - Retrieve CNAM (Caller ID Name) along with other information. Contact + # us if you need to use this functionality. + type: nil, + request_options: {} + ) + end + + # @api private + sig { params(client: PreludeSDK::Client).returns(T.attached_class) } + def self.new(client:) + end + end + end +end diff --git a/rbi/prelude_sdk/resources/transactional.rbi b/rbi/prelude_sdk/resources/transactional.rbi new file mode 100644 index 00000000..846c420e --- /dev/null +++ b/rbi/prelude_sdk/resources/transactional.rbi @@ -0,0 +1,50 @@ +# typed: strong + +module PreludeSDK + module Resources + class Transactional + # Send a transactional message to your user. + sig do + params( + template_id: String, + to: String, + callback_url: String, + correlation_id: String, + expires_at: String, + from: String, + locale: String, + variables: T::Hash[Symbol, String], + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(PreludeSDK::Models::TransactionalSendResponse) + end + def send_( + # The template identifier. + template_id:, + # The recipient's phone number. + to:, + # The callback URL. + callback_url: nil, + # A unique, user-defined identifier that will be included in webhook events. + correlation_id: nil, + # The message expiration date. + expires_at: nil, + # The Sender ID. + from: nil, + # A BCP-47 formatted locale string with the language the text message will be sent + # to. If there's no locale set, the language will be determined by the country + # code of the phone number. If the language specified doesn't exist, the default + # set on the template will be used. + locale: nil, + # The variables to be replaced in the template. + variables: nil, + request_options: {} + ) + end + + # @api private + sig { params(client: PreludeSDK::Client).returns(T.attached_class) } + def self.new(client:) + end + end + end +end diff --git a/rbi/prelude_sdk/resources/verification.rbi b/rbi/prelude_sdk/resources/verification.rbi new file mode 100644 index 00000000..dad3119d --- /dev/null +++ b/rbi/prelude_sdk/resources/verification.rbi @@ -0,0 +1,61 @@ +# typed: strong + +module PreludeSDK + module Resources + class Verification + # Create a new verification for a specific phone number. If another non-expired + # verification exists (the request is performed within the verification window), + # this endpoint will perform a retry instead. + sig do + params( + target: PreludeSDK::VerificationCreateParams::Target::OrHash, + dispatch_id: String, + metadata: PreludeSDK::VerificationCreateParams::Metadata::OrHash, + options: PreludeSDK::VerificationCreateParams::Options::OrHash, + signals: PreludeSDK::VerificationCreateParams::Signals::OrHash, + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(PreludeSDK::Models::VerificationCreateResponse) + end + def create( + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + target:, + # The identifier of the dispatch that came from the front-end SDK. + dispatch_id: nil, + # The metadata for this verification. This object will be returned with every + # response or webhook sent that refers to this verification. + metadata: nil, + # Verification options + options: nil, + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + signals: nil, + request_options: {} + ) + end + + # Check the validity of a verification code. + sig do + params( + code: String, + target: PreludeSDK::VerificationCheckParams::Target::OrHash, + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(PreludeSDK::Models::VerificationCheckResponse) + end + def check( + # The OTP code to validate. + code:, + # The verification target. Either a phone number or an email address. To use the + # email verification feature contact us to discuss your use case. + target:, + request_options: {} + ) + end + + # @api private + sig { params(client: PreludeSDK::Client).returns(T.attached_class) } + def self.new(client:) + end + end + end +end diff --git a/rbi/prelude_sdk/resources/watch.rbi b/rbi/prelude_sdk/resources/watch.rbi new file mode 100644 index 00000000..0009a999 --- /dev/null +++ b/rbi/prelude_sdk/resources/watch.rbi @@ -0,0 +1,67 @@ +# typed: strong + +module PreludeSDK + module Resources + class Watch + # Predict the outcome of a verification based on Prelude’s anti-fraud system. + sig do + params( + target: PreludeSDK::WatchPredictParams::Target::OrHash, + dispatch_id: String, + metadata: PreludeSDK::WatchPredictParams::Metadata::OrHash, + signals: PreludeSDK::WatchPredictParams::Signals::OrHash, + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(PreludeSDK::Models::WatchPredictResponse) + end + def predict( + # The prediction target. Only supports phone numbers for now. + target:, + # The identifier of the dispatch that came from the front-end SDK. + dispatch_id: nil, + # The metadata for this prediction. + metadata: nil, + # The signals used for anti-fraud. For more details, refer to + # [Signals](/verify/v2/documentation/prevent-fraud#signals). + signals: nil, + request_options: {} + ) + end + + # Send real-time event data from end-user interactions within your application. + # Events will be analyzed for proactive fraud prevention and risk scoring. + sig do + params( + events: T::Array[PreludeSDK::WatchSendEventsParams::Event::OrHash], + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(PreludeSDK::Models::WatchSendEventsResponse) + end + def send_events( + # A list of events to dispatch. + events:, + request_options: {} + ) + end + + # Send feedback regarding your end-users verification funnel. Events will be + # analyzed for proactive fraud prevention and risk scoring. + sig do + params( + feedbacks: + T::Array[PreludeSDK::WatchSendFeedbacksParams::Feedback::OrHash], + request_options: PreludeSDK::RequestOptions::OrHash + ).returns(PreludeSDK::Models::WatchSendFeedbacksResponse) + end + def send_feedbacks( + # A list of feedbacks to send. + feedbacks:, + request_options: {} + ) + end + + # @api private + sig { params(client: PreludeSDK::Client).returns(T.attached_class) } + def self.new(client:) + end + end + end +end diff --git a/rbi/prelude_sdk/version.rbi b/rbi/prelude_sdk/version.rbi new file mode 100644 index 00000000..e8fcee2b --- /dev/null +++ b/rbi/prelude_sdk/version.rbi @@ -0,0 +1,5 @@ +# typed: strong + +module PreludeSDK + VERSION = T.let(T.unsafe(nil), String) +end diff --git a/release-please-config.json b/release-please-config.json index 8ee84fda..509ed0a2 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -60,5 +60,11 @@ } ], "release-type": "ruby", - "version-file": "lib/prelude/version.rb" + "version-file": "lib/prelude_sdk/version.rb", + "extra-files": [ + { + "type": "ruby-readme", + "path": "README.md" + } + ] } \ No newline at end of file diff --git a/scripts/bootstrap b/scripts/bootstrap index 0b65ccb0..cc31aa85 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -2,9 +2,9 @@ set -e -cd "$(dirname "$0")/.." +cd -- "$(dirname -- "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then brew bundle check >/dev/null 2>&1 || { echo "==> Installing Homebrew dependencies…" brew bundle @@ -13,4 +13,4 @@ fi echo "==> Installing Ruby dependencies…" -bundle install +exec -- bundle install "$@" diff --git a/scripts/format b/scripts/format index 0113828e..177d1e63 100755 --- a/scripts/format +++ b/scripts/format @@ -2,7 +2,8 @@ set -e -cd "$(dirname "$0")/.." +cd -- "$(dirname -- "$0")/.." echo "==> Running formatters" -bundle exec rake format + +exec -- bundle exec rake format "$@" diff --git a/scripts/lint b/scripts/lint index 469c0c5f..08b0dbeb 100755 --- a/scripts/lint +++ b/scripts/lint @@ -2,6 +2,8 @@ set -e -cd "$(dirname "$0")/.." +cd -- "$(dirname -- "$0")/.." -# bundle exec srb tc +echo "==> Running linters" + +exec -- bundle exec rake lint "$@" diff --git a/scripts/test b/scripts/test index 2e1fe093..8e5d35cd 100755 --- a/scripts/test +++ b/scripts/test @@ -2,7 +2,7 @@ set -e -cd "$(dirname "$0")/.." +cd -- "$(dirname -- "$0")/.." RED='\033[0;31m' GREEN='\033[0;32m' diff --git a/sig/prelude_sdk/client.rbs b/sig/prelude_sdk/client.rbs new file mode 100644 index 00000000..baf79a2f --- /dev/null +++ b/sig/prelude_sdk/client.rbs @@ -0,0 +1,32 @@ +module PreludeSDK + class Client < PreludeSDK::Internal::Transport::BaseClient + DEFAULT_MAX_RETRIES: 2 + + DEFAULT_TIMEOUT_IN_SECONDS: Float + + DEFAULT_INITIAL_RETRY_DELAY: Float + + DEFAULT_MAX_RETRY_DELAY: Float + + attr_reader api_token: String + + attr_reader lookup: PreludeSDK::Resources::Lookup + + attr_reader transactional: PreludeSDK::Resources::Transactional + + attr_reader verification: PreludeSDK::Resources::Verification + + attr_reader watch: PreludeSDK::Resources::Watch + + private def auth_headers: -> ::Hash[String, String] + + def initialize: ( + ?api_token: String?, + ?base_url: String?, + ?max_retries: Integer, + ?timeout: Float, + ?initial_retry_delay: Float, + ?max_retry_delay: Float + ) -> void + end +end diff --git a/sig/prelude_sdk/errors.rbs b/sig/prelude_sdk/errors.rbs new file mode 100644 index 00000000..99936945 --- /dev/null +++ b/sig/prelude_sdk/errors.rbs @@ -0,0 +1,110 @@ +module PreludeSDK + module Errors + class Error < StandardError + attr_accessor cause: StandardError? + end + + class ConversionError < PreludeSDK::Errors::Error + def cause: -> StandardError? + + def initialize: ( + on: Class, + method: Symbol, + target: top, + value: top, + ?cause: StandardError? + ) -> void + end + + class APIError < PreludeSDK::Errors::Error + attr_accessor url: URI::Generic + + attr_accessor status: Integer? + + attr_accessor body: top? + + def initialize: ( + url: URI::Generic, + ?status: Integer?, + ?body: Object?, + ?request: nil, + ?response: nil, + ?message: String? + ) -> void + end + + class APIConnectionError < PreludeSDK::Errors::APIError + def initialize: ( + url: URI::Generic, + ?status: nil, + ?body: nil, + ?request: nil, + ?response: nil, + ?message: String? + ) -> void + end + + class APITimeoutError < PreludeSDK::Errors::APIConnectionError + def initialize: ( + url: URI::Generic, + ?status: nil, + ?body: nil, + ?request: nil, + ?response: nil, + ?message: String? + ) -> void + end + + class APIStatusError < PreludeSDK::Errors::APIError + def self.for: ( + url: URI::Generic, + status: Integer, + body: Object?, + request: nil, + response: nil, + ?message: String? + ) -> instance + + def initialize: ( + url: URI::Generic, + status: Integer, + body: Object?, + request: nil, + response: nil, + ?message: String? + ) -> void + end + + class BadRequestError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS: 400 + end + + class AuthenticationError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS: 401 + end + + class PermissionDeniedError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS: 403 + end + + class NotFoundError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS: 404 + end + + class ConflictError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS: 409 + end + + class UnprocessableEntityError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS: 422 + end + + class RateLimitError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS: 429 + end + + class InternalServerError < PreludeSDK::Errors::APIStatusError + HTTP_STATUS: Range[Integer] + end + end +end diff --git a/sig/prelude_sdk/file_part.rbs b/sig/prelude_sdk/file_part.rbs new file mode 100644 index 00000000..9044004f --- /dev/null +++ b/sig/prelude_sdk/file_part.rbs @@ -0,0 +1,21 @@ +module PreludeSDK + class FilePart + attr_reader content: Pathname | StringIO | IO | String + + attr_reader content_type: String? + + attr_reader filename: String? + + private def read: -> String + + def to_json: (*top a) -> String + + def to_yaml: (*top a) -> String + + def initialize: ( + Pathname | StringIO | IO | String content, + ?filename: String?, + ?content_type: String? + ) -> void + end +end diff --git a/sig/prelude_sdk/internal.rbs b/sig/prelude_sdk/internal.rbs new file mode 100644 index 00000000..f4656591 --- /dev/null +++ b/sig/prelude_sdk/internal.rbs @@ -0,0 +1,9 @@ +module PreludeSDK + module Internal + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + type file_input = Pathname | StringIO | IO | String | PreludeSDK::FilePart + + OMIT: Object + end +end diff --git a/sig/prelude_sdk/internal/transport/base_client.rbs b/sig/prelude_sdk/internal/transport/base_client.rbs new file mode 100644 index 00000000..9eccc638 --- /dev/null +++ b/sig/prelude_sdk/internal/transport/base_client.rbs @@ -0,0 +1,131 @@ +module PreludeSDK + module Internal + module Transport + class BaseClient + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + type request_components = + { + method: Symbol, + path: String | ::Array[String], + query: ::Hash[String, (::Array[String] | String)?]?, + headers: ::Hash[String, (String + | Integer + | ::Array[(String | Integer)?])?]?, + body: top?, + unwrap: (Symbol + | Integer + | ::Array[(Symbol | Integer)] + | (^(top arg0) -> top))?, + page: Class?, + stream: Class?, + model: PreludeSDK::Internal::Type::Converter::input?, + options: PreludeSDK::request_opts? + } + type request_input = + { + method: Symbol, + url: URI::Generic, + headers: ::Hash[String, String], + body: top, + max_retries: Integer, + timeout: Float + } + + MAX_REDIRECTS: 20 + + PLATFORM_HEADERS: ::Hash[String, String] + + def self.validate!: ( + PreludeSDK::Internal::Transport::BaseClient::request_components req + ) -> void + + def self.should_retry?: ( + Integer status, + headers: ::Hash[String, String] + ) -> bool + + def self.follow_redirect: ( + PreludeSDK::Internal::Transport::BaseClient::request_input request, + status: Integer, + response_headers: ::Hash[String, String] + ) -> PreludeSDK::Internal::Transport::BaseClient::request_input + + def self.reap_connection!: ( + Integer | PreludeSDK::Errors::APIConnectionError status, + stream: Enumerable[String]? + ) -> void + + attr_reader base_url: URI::Generic + + attr_reader timeout: Float + + attr_reader max_retries: Integer + + attr_reader initial_retry_delay: Float + + attr_reader max_retry_delay: Float + + attr_reader headers: ::Hash[String, String] + + attr_reader idempotency_header: String? + + # @api private + attr_reader requester: PreludeSDK::Internal::Transport::PooledNetRequester + + def initialize: ( + base_url: String, + ?timeout: Float, + ?max_retries: Integer, + ?initial_retry_delay: Float, + ?max_retry_delay: Float, + ?headers: ::Hash[String, (String + | Integer + | ::Array[(String | Integer)?])?], + ?idempotency_header: String? + ) -> void + + private def auth_headers: -> ::Hash[String, String] + + private def generate_idempotency_key: -> String + + private def build_request: ( + PreludeSDK::Internal::Transport::BaseClient::request_components req, + PreludeSDK::request_options opts + ) -> PreludeSDK::Internal::Transport::BaseClient::request_input + + private def retry_delay: ( + ::Hash[String, String] headers, + retry_count: Integer + ) -> Float + + private def send_request: ( + PreludeSDK::Internal::Transport::BaseClient::request_input request, + redirect_count: Integer, + retry_count: Integer, + send_retry_header: bool + ) -> [Integer, top, Enumerable[String]] + + def request: ( + Symbol method, + String | ::Array[String] path, + ?query: ::Hash[String, (::Array[String] | String)?]?, + ?headers: ::Hash[String, (String + | Integer + | ::Array[(String | Integer)?])?]?, + ?body: top?, + ?unwrap: (Symbol + | Integer + | ::Array[(Symbol | Integer)] + | (^(top arg0) -> top))?, + ?page: Class?, + ?stream: Class?, + ?model: PreludeSDK::Internal::Type::Converter::input?, + ?options: PreludeSDK::request_opts? + ) -> top + + def inspect: -> String + end + end + end +end diff --git a/sig/prelude_sdk/internal/transport/pooled_net_requester.rbs b/sig/prelude_sdk/internal/transport/pooled_net_requester.rbs new file mode 100644 index 00000000..ce2d6c33 --- /dev/null +++ b/sig/prelude_sdk/internal/transport/pooled_net_requester.rbs @@ -0,0 +1,45 @@ +module PreludeSDK + module Internal + module Transport + class PooledNetRequester + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + type request = + { + method: Symbol, + url: URI::Generic, + headers: ::Hash[String, String], + body: top, + deadline: Float + } + + KEEP_ALIVE_TIMEOUT: 30 + + DEFAULT_MAX_CONNECTIONS: Integer + + def self.connect: (URI::Generic url) -> top + + def self.calibrate_socket_timeout: (top conn, Float deadline) -> void + + def self.build_request: ( + PreludeSDK::Internal::Transport::PooledNetRequester::request request + ) { + (String arg0) -> void + } -> [top, (^-> void)] + + private def with_pool: ( + URI::Generic url, + deadline: Float + ) { + (top arg0) -> void + } -> void + + def execute: ( + PreludeSDK::Internal::Transport::PooledNetRequester::request request + ) -> [Integer, top, Enumerable[String]] + + def initialize: (?size: Integer) -> void + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/array_of.rbs b/sig/prelude_sdk/internal/type/array_of.rbs new file mode 100644 index 00000000..c7eb3b23 --- /dev/null +++ b/sig/prelude_sdk/internal/type/array_of.rbs @@ -0,0 +1,48 @@ +module PreludeSDK + module Internal + module Type + class ArrayOf[Elem] + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + def self.[]: ( + ::Hash[Symbol, top] + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input type_info, + ?::Hash[Symbol, top] spec + ) -> instance + + def ===: (top other) -> bool + + def ==: (top other) -> bool + + def hash: -> Integer + + def coerce: ( + ::Array[top] | top value, + state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> (::Array[top] | top) + + def dump: ( + ::Array[top] | top value, + state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> (::Array[top] | top) + + def to_sorbet_type: -> top + + def item_type: -> Elem + + def nilable?: -> bool + + def initialize: ( + ::Hash[Symbol, top] + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input type_info, + ?::Hash[Symbol, top] spec + ) -> void + + def inspect: (?depth: Integer) -> String + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/base_model.rbs b/sig/prelude_sdk/internal/type/base_model.rbs new file mode 100644 index 00000000..6f5777ad --- /dev/null +++ b/sig/prelude_sdk/internal/type/base_model.rbs @@ -0,0 +1,102 @@ +module PreludeSDK + module Internal + module Type + class BaseModel + extend PreludeSDK::Internal::Type::Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + type known_field = + { mode: (:coerce | :dump)?, required: bool, nilable: bool } + + def self.inherited: (self child) -> void + + def self.known_fields: -> ::Hash[Symbol, (PreludeSDK::Internal::Type::BaseModel::known_field + & { type_fn: (^-> PreludeSDK::Internal::Type::Converter::input) })] + + def self.fields: -> ::Hash[Symbol, (PreludeSDK::Internal::Type::BaseModel::known_field + & { type: PreludeSDK::Internal::Type::Converter::input })] + + private def self.add_field: ( + Symbol name_sym, + required: bool, + type_info: { + const: (nil | bool | Integer | Float | Symbol)?, + enum: ^-> PreludeSDK::Internal::Type::Converter::input?, + union: ^-> PreludeSDK::Internal::Type::Converter::input?, + api_name: Symbol + } + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input, + spec: ::Hash[Symbol, top] + ) -> void + + def self.required: ( + Symbol name_sym, + ::Hash[Symbol, top] + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input type_info, + ?::Hash[Symbol, top] spec + ) -> void + + def self.optional: ( + Symbol name_sym, + ::Hash[Symbol, top] + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input type_info, + ?::Hash[Symbol, top] spec + ) -> void + + private def self.request_only: { -> void } -> void + + private def self.response_only: { -> void } -> void + + def self.==: (top other) -> bool + + def self.hash: -> Integer + + def ==: (top other) -> bool + + def hash: -> Integer + + def self.coerce: ( + PreludeSDK::Internal::Type::BaseModel | ::Hash[top, top] | top value, + state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> (instance | top) + + def self.dump: ( + instance | top value, + state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> (::Hash[top, top] | top) + + def self.to_sorbet_type: -> top + + def self.recursively_to_h: ( + PreludeSDK::Internal::Type::BaseModel model, + convert: bool + ) -> ::Hash[Symbol, top] + + def []: (Symbol key) -> top? + + def to_h: -> ::Hash[Symbol, top] + + alias to_hash to_h + + def deep_to_h: -> ::Hash[Symbol, top] + + def deconstruct_keys: (::Array[Symbol]? keys) -> ::Hash[Symbol, top] + + def to_json: (*top a) -> String + + def to_yaml: (*top a) -> String + + def initialize: (?::Hash[Symbol, top] | instance data) -> void + + def self.inspect: (?depth: Integer) -> String + + def to_s: -> String + + def inspect: -> String + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/base_page.rbs b/sig/prelude_sdk/internal/type/base_page.rbs new file mode 100644 index 00000000..b6762df9 --- /dev/null +++ b/sig/prelude_sdk/internal/type/base_page.rbs @@ -0,0 +1,24 @@ +module PreludeSDK + module Internal + module Type + module BasePage[Elem] + def next_page?: -> bool + + def next_page: -> instance + + def auto_paging_each: { (Elem arg0) -> void } -> void + + def to_enum: -> Enumerable[Elem] + + alias enum_for to_enum + + def initialize: ( + client: PreludeSDK::Internal::Transport::BaseClient, + req: PreludeSDK::Internal::Transport::BaseClient::request_components, + headers: ::Hash[String, String], + page_data: top + ) -> void + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/boolean.rbs b/sig/prelude_sdk/internal/type/boolean.rbs new file mode 100644 index 00000000..3e03677b --- /dev/null +++ b/sig/prelude_sdk/internal/type/boolean.rbs @@ -0,0 +1,26 @@ +module PreludeSDK + module Internal + module Type + class Boolean + extend PreludeSDK::Internal::Type::Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + def self.===: (top other) -> bool + + def self.==: (top other) -> bool + + def self.coerce: ( + bool | top value, + state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> (bool | top) + + def self.dump: ( + bool | top value, + state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> (bool | top) + + def self.to_sorbet_type: -> top + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/converter.rbs b/sig/prelude_sdk/internal/type/converter.rbs new file mode 100644 index 00000000..d40b4195 --- /dev/null +++ b/sig/prelude_sdk/internal/type/converter.rbs @@ -0,0 +1,62 @@ +module PreludeSDK + module Internal + module Type + module Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + type input = PreludeSDK::Internal::Type::Converter | Class + + type coerce_state = + { + translate_names: bool, + strictness: bool, + exactness: { yes: Integer, no: Integer, maybe: Integer }, + error: Class, + branched: Integer + } + + type dump_state = { can_retry: bool } + + def coerce: ( + top value, + state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> top + + def dump: ( + top value, + state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> top + + def inspect: (?depth: Integer) -> String + + def self.type_info: ( + { + const: (nil | bool | Integer | Float | Symbol)?, + enum: ^-> PreludeSDK::Internal::Type::Converter::input?, + union: ^-> PreludeSDK::Internal::Type::Converter::input? + } + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input spec + ) -> (^-> top) + + def self.new_coerce_state: ( + ?translate_names: bool + ) -> PreludeSDK::Internal::Type::Converter::coerce_state + + def self.coerce: ( + PreludeSDK::Internal::Type::Converter::input target, + top value, + ?state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> top + + def self.dump: ( + PreludeSDK::Internal::Type::Converter::input target, + top value, + ?state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> top + + def self.inspect: (top target, depth: Integer) -> String + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/enum.rbs b/sig/prelude_sdk/internal/type/enum.rbs new file mode 100644 index 00000000..3944ee72 --- /dev/null +++ b/sig/prelude_sdk/internal/type/enum.rbs @@ -0,0 +1,32 @@ +module PreludeSDK + module Internal + module Type + module Enum + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + def self.values: -> ::Array[(nil | bool | Integer | Float | Symbol)] + + def ===: (top other) -> bool + + def ==: (top other) -> bool + + def hash: -> Integer + + def coerce: ( + String | Symbol | top value, + state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> (Symbol | top) + + def dump: ( + Symbol | top value, + state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> (Symbol | top) + + def to_sorbet_type: -> top + + def inspect: (?depth: Integer) -> String + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/file_input.rbs b/sig/prelude_sdk/internal/type/file_input.rbs new file mode 100644 index 00000000..9462ab34 --- /dev/null +++ b/sig/prelude_sdk/internal/type/file_input.rbs @@ -0,0 +1,25 @@ +module PreludeSDK + module Internal + module Type + class FileInput + extend PreludeSDK::Internal::Type::Converter + + def self.===: (top other) -> bool + + def self.==: (top other) -> bool + + def self.coerce: ( + StringIO | String | top value, + state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> (StringIO | top) + + def self.dump: ( + Pathname | StringIO | IO | String | top value, + state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> (Pathname | StringIO | IO | String | top) + + def self.to_sorbet_type: -> top + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/hash_of.rbs b/sig/prelude_sdk/internal/type/hash_of.rbs new file mode 100644 index 00000000..202e6691 --- /dev/null +++ b/sig/prelude_sdk/internal/type/hash_of.rbs @@ -0,0 +1,48 @@ +module PreludeSDK + module Internal + module Type + class HashOf[Elem] + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + def self.[]: ( + ::Hash[Symbol, top] + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input type_info, + ?::Hash[Symbol, top] spec + ) -> instance + + def ===: (top other) -> bool + + def ==: (top other) -> bool + + def hash: -> Integer + + def coerce: ( + ::Hash[top, top] | top value, + state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> (::Hash[Symbol, top] | top) + + def dump: ( + ::Hash[top, top] | top value, + state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> (::Hash[Symbol, top] | top) + + def to_sorbet_type: -> top + + def item_type: -> Elem + + def nilable?: -> bool + + def initialize: ( + ::Hash[Symbol, top] + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input type_info, + ?::Hash[Symbol, top] spec + ) -> void + + def inspect: (?depth: Integer) -> String + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/request_parameters.rbs b/sig/prelude_sdk/internal/type/request_parameters.rbs new file mode 100644 index 00000000..5ab34b44 --- /dev/null +++ b/sig/prelude_sdk/internal/type/request_parameters.rbs @@ -0,0 +1,19 @@ +module PreludeSDK + module Internal + module Type + type request_parameters = { request_options: PreludeSDK::request_opts } + + module RequestParameters + attr_reader request_options: PreludeSDK::request_opts + + def request_options=: ( + PreludeSDK::request_opts + ) -> PreludeSDK::request_opts + + module Converter + def dump_request: (top params) -> [top, ::Hash[Symbol, top]] + end + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/union.rbs b/sig/prelude_sdk/internal/type/union.rbs new file mode 100644 index 00000000..6d12da17 --- /dev/null +++ b/sig/prelude_sdk/internal/type/union.rbs @@ -0,0 +1,52 @@ +module PreludeSDK + module Internal + module Type + module Union + include PreludeSDK::Internal::Type::Converter + include PreludeSDK::Internal::Util::SorbetRuntimeSupport + + private def self.known_variants: -> ::Array[[Symbol?, (^-> PreludeSDK::Internal::Type::Converter::input)]] + + def self.derefed_variants: -> ::Array[[Symbol?, top]] + + def self.variants: -> ::Array[top] + + private def self.discriminator: (Symbol property) -> void + + private def self.variant: ( + Symbol + | ::Hash[Symbol, top] + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input key, + ?::Hash[Symbol, top] + | ^-> PreludeSDK::Internal::Type::Converter::input + | PreludeSDK::Internal::Type::Converter::input spec + ) -> void + + private def self.resolve_variant: ( + top value + ) -> PreludeSDK::Internal::Type::Converter::input? + + def ===: (top other) -> bool + + def ==: (top other) -> bool + + def hash: -> Integer + + def coerce: ( + top value, + state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> top + + def dump: ( + top value, + state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> top + + def to_sorbet_type: -> top + + def inspect: (?depth: Integer) -> String + end + end + end +end diff --git a/sig/prelude_sdk/internal/type/unknown.rbs b/sig/prelude_sdk/internal/type/unknown.rbs new file mode 100644 index 00000000..804b80c0 --- /dev/null +++ b/sig/prelude_sdk/internal/type/unknown.rbs @@ -0,0 +1,26 @@ +module PreludeSDK + module Internal + module Type + class Unknown + extend PreludeSDK::Internal::Type::Converter + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + def self.===: (top other) -> bool + + def self.==: (top other) -> bool + + def self.coerce: ( + top value, + state: PreludeSDK::Internal::Type::Converter::coerce_state + ) -> top + + def self.dump: ( + top value, + state: PreludeSDK::Internal::Type::Converter::dump_state + ) -> top + + def self.to_sorbet_type: -> top + end + end + end +end diff --git a/sig/prelude_sdk/internal/util.rbs b/sig/prelude_sdk/internal/util.rbs new file mode 100644 index 00000000..3aa12477 --- /dev/null +++ b/sig/prelude_sdk/internal/util.rbs @@ -0,0 +1,185 @@ +module PreludeSDK + module Internal + module Util + extend PreludeSDK::Internal::Util::SorbetRuntimeSupport + + def self?.monotonic_secs: -> Float + + def self?.walk_namespaces: ( + Module | Class ns + ) -> Enumerable[(Module | Class)] + + def self?.arch: -> String + + def self?.os: -> String + + def self?.primitive?: (top input) -> bool + + def self?.coerce_boolean: (String | bool input) -> (bool | top) + + def self?.coerce_boolean!: (String | bool input) -> bool? + + def self?.coerce_integer: (String | Integer input) -> (Integer | top) + + def self?.coerce_float: (String | Integer | Float input) -> (Float | top) + + def self?.coerce_hash: (top input) -> (::Hash[top, top] | top) + + def self?.coerce_hash!: (top input) -> ::Hash[top, top]? + + def self?.deep_merge_lr: (top lhs, top rhs, ?concat: bool) -> top + + def self?.deep_merge: ( + *::Array[top] values, + ?sentinel: top?, + ?concat: bool + ) -> top + + def self?.dig: ( + ::Hash[Symbol, top] | ::Array[top] | top data, + (Symbol + | Integer + | ::Array[(Symbol | Integer)] + | (^(top arg0) -> top))? pick + ) { + -> top? + } -> top? + + def self?.uri_origin: (URI::Generic uri) -> String + + def self?.interpolate_path: (String | ::Array[String] path) -> String + + def self?.decode_query: (String? query) -> ::Hash[String, ::Array[String]] + + def self?.encode_query: ( + ::Hash[String, (::Array[String] | String)?]? query + ) -> String? + + type parsed_uri = + { + scheme: String?, + host: String?, + port: Integer?, + path: String?, + query: ::Hash[String, ::Array[String]] + } + + def self?.parse_uri: ( + URI::Generic | String url + ) -> PreludeSDK::Internal::Util::parsed_uri + + def self?.unparse_uri: ( + PreludeSDK::Internal::Util::parsed_uri parsed + ) -> URI::Generic + + def self?.join_parsed_uri: ( + PreludeSDK::Internal::Util::parsed_uri lhs, + PreludeSDK::Internal::Util::parsed_uri rhs + ) -> URI::Generic + + def self?.normalized_headers: ( + *::Hash[String, (String + | Integer + | ::Array[(String | Integer)?])?] headers + ) -> ::Hash[String, String] + + class ReadIOAdapter + def close?: -> bool? + + def close: -> void + + private def read_enum: (Integer? max_len) -> String + + def read: (?Integer? max_len, ?String? out_string) -> String? + + def initialize: ( + String | Pathname | StringIO | Enumerable[String] src + ) { + (String arg0) -> void + } -> void + end + + def self?.writable_enum: { + (Enumerator::Yielder y) -> void + } -> Enumerable[String] + + JSON_CONTENT: Regexp + JSONL_CONTENT: Regexp + + def self?.write_multipart_content: ( + Enumerator::Yielder y, + val: top, + closing: ::Array[^-> void], + ?content_type: String? + ) -> void + + def self?.write_multipart_chunk: ( + Enumerator::Yielder y, + boundary: String, + key: Symbol | String, + val: top, + closing: ::Array[^-> void] + ) -> void + + def self?.encode_multipart_streaming: ( + top body + ) -> [String, Enumerable[String]] + + def self?.encode_content: ( + ::Hash[String, String] headers, + top body + ) -> top + + def self?.force_charset!: (String content_type, text: String) -> void + + def self?.decode_content: ( + ::Hash[String, String] headers, + stream: Enumerable[String], + ?suppress_error: bool + ) -> top + + def self?.fused_enum: ( + Enumerable[top] enum, + ?external: bool + ) { + -> void + } -> Enumerable[top] + + def self?.close_fused!: (Enumerable[top]? enum) -> void + + def self?.chain_fused: ( + Enumerable[top]? enum + ) { + (Enumerator::Yielder arg0) -> void + } -> Enumerable[top] + + type server_sent_event = + { event: String?, data: String?, id: String?, retry: Integer? } + + def self?.decode_lines: (Enumerable[String] enum) -> Enumerable[String] + + def self?.decode_sse: ( + Enumerable[String] lines + ) -> Enumerable[PreludeSDK::Internal::Util::server_sent_event] + + module SorbetRuntimeSupport + class MissingSorbetRuntimeError < ::RuntimeError + end + + private def sorbet_runtime_constants: -> ::Hash[Symbol, top] + + def const_missing: (Symbol name) -> void + + def sorbet_constant_defined?: (Symbol name) -> bool + + def define_sorbet_constant!: (Symbol name) { -> top } -> void + + def to_sorbet_type: -> top + + def self.to_sorbet_type: ( + PreludeSDK::Internal::Util::SorbetRuntimeSupport | top `type` + ) -> top + end + end + end +end diff --git a/sig/prelude_sdk/models.rbs b/sig/prelude_sdk/models.rbs new file mode 100644 index 00000000..4ae49a44 --- /dev/null +++ b/sig/prelude_sdk/models.rbs @@ -0,0 +1,15 @@ +module PreludeSDK + class LookupLookupParams = PreludeSDK::Models::LookupLookupParams + + class TransactionalSendParams = PreludeSDK::Models::TransactionalSendParams + + class VerificationCheckParams = PreludeSDK::Models::VerificationCheckParams + + class VerificationCreateParams = PreludeSDK::Models::VerificationCreateParams + + class WatchPredictParams = PreludeSDK::Models::WatchPredictParams + + class WatchSendEventsParams = PreludeSDK::Models::WatchSendEventsParams + + class WatchSendFeedbacksParams = PreludeSDK::Models::WatchSendFeedbacksParams +end diff --git a/sig/prelude_sdk/models/lookup_lookup_params.rbs b/sig/prelude_sdk/models/lookup_lookup_params.rbs new file mode 100644 index 00000000..bfddfba8 --- /dev/null +++ b/sig/prelude_sdk/models/lookup_lookup_params.rbs @@ -0,0 +1,38 @@ +module PreludeSDK + module Models + type lookup_lookup_params = + { type: ::Array[PreludeSDK::Models::LookupLookupParams::type_] } + & PreludeSDK::Internal::Type::request_parameters + + class LookupLookupParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + attr_reader type: ::Array[PreludeSDK::Models::LookupLookupParams::type_]? + + def type=: ( + ::Array[PreludeSDK::Models::LookupLookupParams::type_] + ) -> ::Array[PreludeSDK::Models::LookupLookupParams::type_] + + def initialize: ( + ?type: ::Array[PreludeSDK::Models::LookupLookupParams::type_], + ?request_options: PreludeSDK::request_opts + ) -> void + + def to_hash: -> { + type: ::Array[PreludeSDK::Models::LookupLookupParams::type_], + request_options: PreludeSDK::RequestOptions + } + + type type_ = :cnam + + module Type + extend PreludeSDK::Internal::Type::Enum + + CNAM: :cnam + + def self?.values: -> ::Array[PreludeSDK::Models::LookupLookupParams::type_] + end + end + end +end diff --git a/sig/prelude_sdk/models/lookup_lookup_response.rbs b/sig/prelude_sdk/models/lookup_lookup_response.rbs new file mode 100644 index 00000000..c80b0bb8 --- /dev/null +++ b/sig/prelude_sdk/models/lookup_lookup_response.rbs @@ -0,0 +1,179 @@ +module PreludeSDK + module Models + type lookup_lookup_response = + { + caller_name: String, + country_code: String, + flags: ::Array[PreludeSDK::Models::LookupLookupResponse::flag], + line_type: PreludeSDK::Models::LookupLookupResponse::line_type, + network_info: PreludeSDK::Models::LookupLookupResponse::NetworkInfo, + original_network_info: PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo, + phone_number: String + } + + class LookupLookupResponse < PreludeSDK::Internal::Type::BaseModel + attr_reader caller_name: String? + + def caller_name=: (String) -> String + + attr_reader country_code: String? + + def country_code=: (String) -> String + + attr_reader flags: ::Array[PreludeSDK::Models::LookupLookupResponse::flag]? + + def flags=: ( + ::Array[PreludeSDK::Models::LookupLookupResponse::flag] + ) -> ::Array[PreludeSDK::Models::LookupLookupResponse::flag] + + attr_reader line_type: PreludeSDK::Models::LookupLookupResponse::line_type? + + def line_type=: ( + PreludeSDK::Models::LookupLookupResponse::line_type + ) -> PreludeSDK::Models::LookupLookupResponse::line_type + + attr_reader network_info: PreludeSDK::Models::LookupLookupResponse::NetworkInfo? + + def network_info=: ( + PreludeSDK::Models::LookupLookupResponse::NetworkInfo + ) -> PreludeSDK::Models::LookupLookupResponse::NetworkInfo + + attr_reader original_network_info: PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo? + + def original_network_info=: ( + PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo + ) -> PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo + + attr_reader phone_number: String? + + def phone_number=: (String) -> String + + def initialize: ( + ?caller_name: String, + ?country_code: String, + ?flags: ::Array[PreludeSDK::Models::LookupLookupResponse::flag], + ?line_type: PreludeSDK::Models::LookupLookupResponse::line_type, + ?network_info: PreludeSDK::Models::LookupLookupResponse::NetworkInfo, + ?original_network_info: PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo, + ?phone_number: String + ) -> void + + def to_hash: -> { + caller_name: String, + country_code: String, + flags: ::Array[PreludeSDK::Models::LookupLookupResponse::flag], + line_type: PreludeSDK::Models::LookupLookupResponse::line_type, + network_info: PreludeSDK::Models::LookupLookupResponse::NetworkInfo, + original_network_info: PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo, + phone_number: String + } + + type flag = :ported | :temporary + + module Flag + extend PreludeSDK::Internal::Type::Enum + + PORTED: :ported + TEMPORARY: :temporary + + def self?.values: -> ::Array[PreludeSDK::Models::LookupLookupResponse::flag] + end + + type line_type = + :calling_cards + | :fixed_line + | :isp + | :local_rate + | :mobile + | :other + | :pager + | :payphone + | :premium_rate + | :satellite + | :service + | :shared_cost + | :short_codes_commercial + | :toll_free + | :universal_access + | :unknown + | :vpn + | :voice_mail + | :voip + + module LineType + extend PreludeSDK::Internal::Type::Enum + + CALLING_CARDS: :calling_cards + FIXED_LINE: :fixed_line + ISP: :isp + LOCAL_RATE: :local_rate + MOBILE: :mobile + OTHER: :other + PAGER: :pager + PAYPHONE: :payphone + PREMIUM_RATE: :premium_rate + SATELLITE: :satellite + SERVICE: :service + SHARED_COST: :shared_cost + SHORT_CODES_COMMERCIAL: :short_codes_commercial + TOLL_FREE: :toll_free + UNIVERSAL_ACCESS: :universal_access + UNKNOWN: :unknown + VPN: :vpn + VOICE_MAIL: :voice_mail + VOIP: :voip + + def self?.values: -> ::Array[PreludeSDK::Models::LookupLookupResponse::line_type] + end + + type network_info = { carrier_name: String, mcc: String, mnc: String } + + class NetworkInfo < PreludeSDK::Internal::Type::BaseModel + attr_reader carrier_name: String? + + def carrier_name=: (String) -> String + + attr_reader mcc: String? + + def mcc=: (String) -> String + + attr_reader mnc: String? + + def mnc=: (String) -> String + + def initialize: ( + ?carrier_name: String, + ?mcc: String, + ?mnc: String + ) -> void + + def to_hash: -> { carrier_name: String, mcc: String, mnc: String } + end + + type original_network_info = + { carrier_name: String, mcc: String, mnc: String } + + class OriginalNetworkInfo < PreludeSDK::Internal::Type::BaseModel + attr_reader carrier_name: String? + + def carrier_name=: (String) -> String + + attr_reader mcc: String? + + def mcc=: (String) -> String + + attr_reader mnc: String? + + def mnc=: (String) -> String + + def initialize: ( + ?carrier_name: String, + ?mcc: String, + ?mnc: String + ) -> void + + def to_hash: -> { carrier_name: String, mcc: String, mnc: String } + end + end + end +end diff --git a/sig/prelude_sdk/models/transactional_send_params.rbs b/sig/prelude_sdk/models/transactional_send_params.rbs new file mode 100644 index 00000000..348f1b67 --- /dev/null +++ b/sig/prelude_sdk/models/transactional_send_params.rbs @@ -0,0 +1,73 @@ +module PreludeSDK + module Models + type transactional_send_params = + { + template_id: String, + to: String, + callback_url: String, + correlation_id: String, + expires_at: String, + from: String, + locale: String, + variables: ::Hash[Symbol, String] + } + & PreludeSDK::Internal::Type::request_parameters + + class TransactionalSendParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + attr_accessor template_id: String + + attr_accessor to: String + + attr_reader callback_url: String? + + def callback_url=: (String) -> String + + attr_reader correlation_id: String? + + def correlation_id=: (String) -> String + + attr_reader expires_at: String? + + def expires_at=: (String) -> String + + attr_reader from: String? + + def from=: (String) -> String + + attr_reader locale: String? + + def locale=: (String) -> String + + attr_reader variables: ::Hash[Symbol, String]? + + def variables=: (::Hash[Symbol, String]) -> ::Hash[Symbol, String] + + def initialize: ( + template_id: String, + to: String, + ?callback_url: String, + ?correlation_id: String, + ?expires_at: String, + ?from: String, + ?locale: String, + ?variables: ::Hash[Symbol, String], + ?request_options: PreludeSDK::request_opts + ) -> void + + def to_hash: -> { + template_id: String, + to: String, + callback_url: String, + correlation_id: String, + expires_at: String, + from: String, + locale: String, + variables: ::Hash[Symbol, String], + request_options: PreludeSDK::RequestOptions + } + end + end +end diff --git a/sig/prelude_sdk/models/transactional_send_response.rbs b/sig/prelude_sdk/models/transactional_send_response.rbs new file mode 100644 index 00000000..79f67899 --- /dev/null +++ b/sig/prelude_sdk/models/transactional_send_response.rbs @@ -0,0 +1,66 @@ +module PreludeSDK + module Models + type transactional_send_response = + { + id: String, + created_at: Time, + expires_at: Time, + template_id: String, + to: String, + variables: ::Hash[Symbol, String], + callback_url: String, + correlation_id: String, + from: String + } + + class TransactionalSendResponse < PreludeSDK::Internal::Type::BaseModel + attr_accessor id: String + + attr_accessor created_at: Time + + attr_accessor expires_at: Time + + attr_accessor template_id: String + + attr_accessor to: String + + attr_accessor variables: ::Hash[Symbol, String] + + attr_reader callback_url: String? + + def callback_url=: (String) -> String + + attr_reader correlation_id: String? + + def correlation_id=: (String) -> String + + attr_reader from: String? + + def from=: (String) -> String + + def initialize: ( + id: String, + created_at: Time, + expires_at: Time, + template_id: String, + to: String, + variables: ::Hash[Symbol, String], + ?callback_url: String, + ?correlation_id: String, + ?from: String + ) -> void + + def to_hash: -> { + id: String, + created_at: Time, + expires_at: Time, + template_id: String, + to: String, + variables: ::Hash[Symbol, String], + callback_url: String, + correlation_id: String, + from: String + } + end + end +end diff --git a/sig/prelude_sdk/models/verification_check_params.rbs b/sig/prelude_sdk/models/verification_check_params.rbs new file mode 100644 index 00000000..b0222f11 --- /dev/null +++ b/sig/prelude_sdk/models/verification_check_params.rbs @@ -0,0 +1,61 @@ +module PreludeSDK + module Models + type verification_check_params = + { code: String, target: PreludeSDK::VerificationCheckParams::Target } + & PreludeSDK::Internal::Type::request_parameters + + class VerificationCheckParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + attr_accessor code: String + + attr_accessor target: PreludeSDK::VerificationCheckParams::Target + + def initialize: ( + code: String, + target: PreludeSDK::VerificationCheckParams::Target, + ?request_options: PreludeSDK::request_opts + ) -> void + + def to_hash: -> { + code: String, + target: PreludeSDK::VerificationCheckParams::Target, + request_options: PreludeSDK::RequestOptions + } + + type target = + { + type: PreludeSDK::Models::VerificationCheckParams::Target::type_, + value: String + } + + class Target < PreludeSDK::Internal::Type::BaseModel + attr_accessor type: PreludeSDK::Models::VerificationCheckParams::Target::type_ + + attr_accessor value: String + + def initialize: ( + type: PreludeSDK::Models::VerificationCheckParams::Target::type_, + value: String + ) -> void + + def to_hash: -> { + type: PreludeSDK::Models::VerificationCheckParams::Target::type_, + value: String + } + + type type_ = :phone_number | :email_address + + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER: :phone_number + EMAIL_ADDRESS: :email_address + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCheckParams::Target::type_] + end + end + end + end +end diff --git a/sig/prelude_sdk/models/verification_check_response.rbs b/sig/prelude_sdk/models/verification_check_response.rbs new file mode 100644 index 00000000..539f3f5d --- /dev/null +++ b/sig/prelude_sdk/models/verification_check_response.rbs @@ -0,0 +1,67 @@ +module PreludeSDK + module Models + type verification_check_response = + { + status: PreludeSDK::Models::VerificationCheckResponse::status, + id: String, + metadata: PreludeSDK::Models::VerificationCheckResponse::Metadata, + request_id: String + } + + class VerificationCheckResponse < PreludeSDK::Internal::Type::BaseModel + attr_accessor status: PreludeSDK::Models::VerificationCheckResponse::status + + attr_reader id: String? + + def id=: (String) -> String + + attr_reader metadata: PreludeSDK::Models::VerificationCheckResponse::Metadata? + + def metadata=: ( + PreludeSDK::Models::VerificationCheckResponse::Metadata + ) -> PreludeSDK::Models::VerificationCheckResponse::Metadata + + attr_reader request_id: String? + + def request_id=: (String) -> String + + def initialize: ( + status: PreludeSDK::Models::VerificationCheckResponse::status, + ?id: String, + ?metadata: PreludeSDK::Models::VerificationCheckResponse::Metadata, + ?request_id: String + ) -> void + + def to_hash: -> { + status: PreludeSDK::Models::VerificationCheckResponse::status, + id: String, + metadata: PreludeSDK::Models::VerificationCheckResponse::Metadata, + request_id: String + } + + type status = :success | :failure | :expired_or_not_found + + module Status + extend PreludeSDK::Internal::Type::Enum + + SUCCESS: :success + FAILURE: :failure + EXPIRED_OR_NOT_FOUND: :expired_or_not_found + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCheckResponse::status] + end + + type metadata = { correlation_id: String } + + class Metadata < PreludeSDK::Internal::Type::BaseModel + attr_reader correlation_id: String? + + def correlation_id=: (String) -> String + + def initialize: (?correlation_id: String) -> void + + def to_hash: -> { correlation_id: String } + end + end + end +end diff --git a/sig/prelude_sdk/models/verification_create_params.rbs b/sig/prelude_sdk/models/verification_create_params.rbs new file mode 100644 index 00000000..f00f83e2 --- /dev/null +++ b/sig/prelude_sdk/models/verification_create_params.rbs @@ -0,0 +1,345 @@ +module PreludeSDK + module Models + type verification_create_params = + { + target: PreludeSDK::VerificationCreateParams::Target, + dispatch_id: String, + metadata: PreludeSDK::VerificationCreateParams::Metadata, + options: PreludeSDK::VerificationCreateParams::Options, + signals: PreludeSDK::VerificationCreateParams::Signals + } + & PreludeSDK::Internal::Type::request_parameters + + class VerificationCreateParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + attr_accessor target: PreludeSDK::VerificationCreateParams::Target + + attr_reader dispatch_id: String? + + def dispatch_id=: (String) -> String + + attr_reader metadata: PreludeSDK::VerificationCreateParams::Metadata? + + def metadata=: ( + PreludeSDK::VerificationCreateParams::Metadata + ) -> PreludeSDK::VerificationCreateParams::Metadata + + attr_reader options: PreludeSDK::VerificationCreateParams::Options? + + def options=: ( + PreludeSDK::VerificationCreateParams::Options + ) -> PreludeSDK::VerificationCreateParams::Options + + attr_reader signals: PreludeSDK::VerificationCreateParams::Signals? + + def signals=: ( + PreludeSDK::VerificationCreateParams::Signals + ) -> PreludeSDK::VerificationCreateParams::Signals + + def initialize: ( + target: PreludeSDK::VerificationCreateParams::Target, + ?dispatch_id: String, + ?metadata: PreludeSDK::VerificationCreateParams::Metadata, + ?options: PreludeSDK::VerificationCreateParams::Options, + ?signals: PreludeSDK::VerificationCreateParams::Signals, + ?request_options: PreludeSDK::request_opts + ) -> void + + def to_hash: -> { + target: PreludeSDK::VerificationCreateParams::Target, + dispatch_id: String, + metadata: PreludeSDK::VerificationCreateParams::Metadata, + options: PreludeSDK::VerificationCreateParams::Options, + signals: PreludeSDK::VerificationCreateParams::Signals, + request_options: PreludeSDK::RequestOptions + } + + type target = + { + type: PreludeSDK::Models::VerificationCreateParams::Target::type_, + value: String + } + + class Target < PreludeSDK::Internal::Type::BaseModel + attr_accessor type: PreludeSDK::Models::VerificationCreateParams::Target::type_ + + attr_accessor value: String + + def initialize: ( + type: PreludeSDK::Models::VerificationCreateParams::Target::type_, + value: String + ) -> void + + def to_hash: -> { + type: PreludeSDK::Models::VerificationCreateParams::Target::type_, + value: String + } + + type type_ = :phone_number | :email_address + + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER: :phone_number + EMAIL_ADDRESS: :email_address + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCreateParams::Target::type_] + end + end + + type metadata = { correlation_id: String } + + class Metadata < PreludeSDK::Internal::Type::BaseModel + attr_reader correlation_id: String? + + def correlation_id=: (String) -> String + + def initialize: (?correlation_id: String) -> void + + def to_hash: -> { correlation_id: String } + end + + type options = + { + app_realm: PreludeSDK::VerificationCreateParams::Options::AppRealm, + callback_url: String, + code_size: Integer, + custom_code: String, + locale: String, + method_: PreludeSDK::Models::VerificationCreateParams::Options::method_, + preferred_channel: PreludeSDK::Models::VerificationCreateParams::Options::preferred_channel, + sender_id: String, + template_id: String, + variables: ::Hash[Symbol, String] + } + + class Options < PreludeSDK::Internal::Type::BaseModel + attr_reader app_realm: PreludeSDK::VerificationCreateParams::Options::AppRealm? + + def app_realm=: ( + PreludeSDK::VerificationCreateParams::Options::AppRealm + ) -> PreludeSDK::VerificationCreateParams::Options::AppRealm + + attr_reader callback_url: String? + + def callback_url=: (String) -> String + + attr_reader code_size: Integer? + + def code_size=: (Integer) -> Integer + + attr_reader custom_code: String? + + def custom_code=: (String) -> String + + attr_reader locale: String? + + def locale=: (String) -> String + + attr_reader method_: PreludeSDK::Models::VerificationCreateParams::Options::method_? + + def method_=: ( + PreludeSDK::Models::VerificationCreateParams::Options::method_ + ) -> PreludeSDK::Models::VerificationCreateParams::Options::method_ + + attr_reader preferred_channel: PreludeSDK::Models::VerificationCreateParams::Options::preferred_channel? + + def preferred_channel=: ( + PreludeSDK::Models::VerificationCreateParams::Options::preferred_channel + ) -> PreludeSDK::Models::VerificationCreateParams::Options::preferred_channel + + attr_reader sender_id: String? + + def sender_id=: (String) -> String + + attr_reader template_id: String? + + def template_id=: (String) -> String + + attr_reader variables: ::Hash[Symbol, String]? + + def variables=: (::Hash[Symbol, String]) -> ::Hash[Symbol, String] + + def initialize: ( + ?app_realm: PreludeSDK::VerificationCreateParams::Options::AppRealm, + ?callback_url: String, + ?code_size: Integer, + ?custom_code: String, + ?locale: String, + ?method_: PreludeSDK::Models::VerificationCreateParams::Options::method_, + ?preferred_channel: PreludeSDK::Models::VerificationCreateParams::Options::preferred_channel, + ?sender_id: String, + ?template_id: String, + ?variables: ::Hash[Symbol, String] + ) -> void + + def to_hash: -> { + app_realm: PreludeSDK::VerificationCreateParams::Options::AppRealm, + callback_url: String, + code_size: Integer, + custom_code: String, + locale: String, + method_: PreludeSDK::Models::VerificationCreateParams::Options::method_, + preferred_channel: PreludeSDK::Models::VerificationCreateParams::Options::preferred_channel, + sender_id: String, + template_id: String, + variables: ::Hash[Symbol, String] + } + + type app_realm = + { + platform: PreludeSDK::Models::VerificationCreateParams::Options::AppRealm::platform, + value: String + } + + class AppRealm < PreludeSDK::Internal::Type::BaseModel + attr_accessor platform: PreludeSDK::Models::VerificationCreateParams::Options::AppRealm::platform + + attr_accessor value: String + + def initialize: ( + platform: PreludeSDK::Models::VerificationCreateParams::Options::AppRealm::platform, + value: String + ) -> void + + def to_hash: -> { + platform: PreludeSDK::Models::VerificationCreateParams::Options::AppRealm::platform, + value: String + } + + type platform = :android + + module Platform + extend PreludeSDK::Internal::Type::Enum + + ANDROID: :android + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCreateParams::Options::AppRealm::platform] + end + end + + type method_ = :auto | :voice + + module Method + extend PreludeSDK::Internal::Type::Enum + + AUTO: :auto + VOICE: :voice + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCreateParams::Options::method_] + end + + type preferred_channel = + :sms + | :rcs + | :whatsapp + | :viber + | :zalo + | :telegram + | :silent + | :voice + + module PreferredChannel + extend PreludeSDK::Internal::Type::Enum + + SMS: :sms + RCS: :rcs + WHATSAPP: :whatsapp + VIBER: :viber + ZALO: :zalo + TELEGRAM: :telegram + SILENT: :silent + VOICE: :voice + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCreateParams::Options::preferred_channel] + end + end + + type signals = + { + app_version: String, + device_id: String, + device_model: String, + device_platform: PreludeSDK::Models::VerificationCreateParams::Signals::device_platform, + ip: String, + is_trusted_user: bool, + os_version: String, + user_agent: String + } + + class Signals < PreludeSDK::Internal::Type::BaseModel + attr_reader app_version: String? + + def app_version=: (String) -> String + + attr_reader device_id: String? + + def device_id=: (String) -> String + + attr_reader device_model: String? + + def device_model=: (String) -> String + + attr_reader device_platform: PreludeSDK::Models::VerificationCreateParams::Signals::device_platform? + + def device_platform=: ( + PreludeSDK::Models::VerificationCreateParams::Signals::device_platform + ) -> PreludeSDK::Models::VerificationCreateParams::Signals::device_platform + + attr_reader ip: String? + + def ip=: (String) -> String + + attr_reader is_trusted_user: bool? + + def is_trusted_user=: (bool) -> bool + + attr_reader os_version: String? + + def os_version=: (String) -> String + + attr_reader user_agent: String? + + def user_agent=: (String) -> String + + def initialize: ( + ?app_version: String, + ?device_id: String, + ?device_model: String, + ?device_platform: PreludeSDK::Models::VerificationCreateParams::Signals::device_platform, + ?ip: String, + ?is_trusted_user: bool, + ?os_version: String, + ?user_agent: String + ) -> void + + def to_hash: -> { + app_version: String, + device_id: String, + device_model: String, + device_platform: PreludeSDK::Models::VerificationCreateParams::Signals::device_platform, + ip: String, + is_trusted_user: bool, + os_version: String, + user_agent: String + } + + type device_platform = :android | :ios | :ipados | :tvos | :web + + module DevicePlatform + extend PreludeSDK::Internal::Type::Enum + + ANDROID: :android + IOS: :ios + IPADOS: :ipados + TVOS: :tvos + WEB: :web + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCreateParams::Signals::device_platform] + end + end + end + end +end diff --git a/sig/prelude_sdk/models/verification_create_response.rbs b/sig/prelude_sdk/models/verification_create_response.rbs new file mode 100644 index 00000000..f2784195 --- /dev/null +++ b/sig/prelude_sdk/models/verification_create_response.rbs @@ -0,0 +1,136 @@ +module PreludeSDK + module Models + type verification_create_response = + { + id: String, + method_: PreludeSDK::Models::VerificationCreateResponse::method_, + status: PreludeSDK::Models::VerificationCreateResponse::status, + channels: ::Array[String], + metadata: PreludeSDK::Models::VerificationCreateResponse::Metadata, + reason: PreludeSDK::Models::VerificationCreateResponse::reason, + request_id: String, + silent: PreludeSDK::Models::VerificationCreateResponse::Silent + } + + class VerificationCreateResponse < PreludeSDK::Internal::Type::BaseModel + attr_accessor id: String + + attr_accessor method_: PreludeSDK::Models::VerificationCreateResponse::method_ + + attr_accessor status: PreludeSDK::Models::VerificationCreateResponse::status + + attr_reader channels: ::Array[String]? + + def channels=: (::Array[String]) -> ::Array[String] + + attr_reader metadata: PreludeSDK::Models::VerificationCreateResponse::Metadata? + + def metadata=: ( + PreludeSDK::Models::VerificationCreateResponse::Metadata + ) -> PreludeSDK::Models::VerificationCreateResponse::Metadata + + attr_reader reason: PreludeSDK::Models::VerificationCreateResponse::reason? + + def reason=: ( + PreludeSDK::Models::VerificationCreateResponse::reason + ) -> PreludeSDK::Models::VerificationCreateResponse::reason + + attr_reader request_id: String? + + def request_id=: (String) -> String + + attr_reader silent: PreludeSDK::Models::VerificationCreateResponse::Silent? + + def silent=: ( + PreludeSDK::Models::VerificationCreateResponse::Silent + ) -> PreludeSDK::Models::VerificationCreateResponse::Silent + + def initialize: ( + id: String, + method_: PreludeSDK::Models::VerificationCreateResponse::method_, + status: PreludeSDK::Models::VerificationCreateResponse::status, + ?channels: ::Array[String], + ?metadata: PreludeSDK::Models::VerificationCreateResponse::Metadata, + ?reason: PreludeSDK::Models::VerificationCreateResponse::reason, + ?request_id: String, + ?silent: PreludeSDK::Models::VerificationCreateResponse::Silent + ) -> void + + def to_hash: -> { + id: String, + method_: PreludeSDK::Models::VerificationCreateResponse::method_, + status: PreludeSDK::Models::VerificationCreateResponse::status, + channels: ::Array[String], + metadata: PreludeSDK::Models::VerificationCreateResponse::Metadata, + reason: PreludeSDK::Models::VerificationCreateResponse::reason, + request_id: String, + silent: PreludeSDK::Models::VerificationCreateResponse::Silent + } + + type method_ = :message | :silent | :voice + + module Method + extend PreludeSDK::Internal::Type::Enum + + MESSAGE: :message + SILENT: :silent + VOICE: :voice + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCreateResponse::method_] + end + + type status = :success | :retry | :blocked + + module Status + extend PreludeSDK::Internal::Type::Enum + + SUCCESS: :success + RETRY: :retry + BLOCKED: :blocked + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCreateResponse::status] + end + + type metadata = { correlation_id: String } + + class Metadata < PreludeSDK::Internal::Type::BaseModel + attr_reader correlation_id: String? + + def correlation_id=: (String) -> String + + def initialize: (?correlation_id: String) -> void + + def to_hash: -> { correlation_id: String } + end + + type reason = + :suspicious + | :repeated_attempts + | :invalid_phone_line + | :invalid_phone_number + | :in_block_list + + module Reason + extend PreludeSDK::Internal::Type::Enum + + SUSPICIOUS: :suspicious + REPEATED_ATTEMPTS: :repeated_attempts + INVALID_PHONE_LINE: :invalid_phone_line + INVALID_PHONE_NUMBER: :invalid_phone_number + IN_BLOCK_LIST: :in_block_list + + def self?.values: -> ::Array[PreludeSDK::Models::VerificationCreateResponse::reason] + end + + type silent = { request_url: String } + + class Silent < PreludeSDK::Internal::Type::BaseModel + attr_accessor request_url: String + + def initialize: (request_url: String) -> void + + def to_hash: -> { request_url: String } + end + end + end +end diff --git a/sig/prelude_sdk/models/watch_predict_params.rbs b/sig/prelude_sdk/models/watch_predict_params.rbs new file mode 100644 index 00000000..b9bd63aa --- /dev/null +++ b/sig/prelude_sdk/models/watch_predict_params.rbs @@ -0,0 +1,180 @@ +module PreludeSDK + module Models + type watch_predict_params = + { + target: PreludeSDK::WatchPredictParams::Target, + dispatch_id: String, + metadata: PreludeSDK::WatchPredictParams::Metadata, + signals: PreludeSDK::WatchPredictParams::Signals + } + & PreludeSDK::Internal::Type::request_parameters + + class WatchPredictParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + attr_accessor target: PreludeSDK::WatchPredictParams::Target + + attr_reader dispatch_id: String? + + def dispatch_id=: (String) -> String + + attr_reader metadata: PreludeSDK::WatchPredictParams::Metadata? + + def metadata=: ( + PreludeSDK::WatchPredictParams::Metadata + ) -> PreludeSDK::WatchPredictParams::Metadata + + attr_reader signals: PreludeSDK::WatchPredictParams::Signals? + + def signals=: ( + PreludeSDK::WatchPredictParams::Signals + ) -> PreludeSDK::WatchPredictParams::Signals + + def initialize: ( + target: PreludeSDK::WatchPredictParams::Target, + ?dispatch_id: String, + ?metadata: PreludeSDK::WatchPredictParams::Metadata, + ?signals: PreludeSDK::WatchPredictParams::Signals, + ?request_options: PreludeSDK::request_opts + ) -> void + + def to_hash: -> { + target: PreludeSDK::WatchPredictParams::Target, + dispatch_id: String, + metadata: PreludeSDK::WatchPredictParams::Metadata, + signals: PreludeSDK::WatchPredictParams::Signals, + request_options: PreludeSDK::RequestOptions + } + + type target = + { + type: PreludeSDK::Models::WatchPredictParams::Target::type_, + value: String + } + + class Target < PreludeSDK::Internal::Type::BaseModel + attr_accessor type: PreludeSDK::Models::WatchPredictParams::Target::type_ + + attr_accessor value: String + + def initialize: ( + type: PreludeSDK::Models::WatchPredictParams::Target::type_, + value: String + ) -> void + + def to_hash: -> { + type: PreludeSDK::Models::WatchPredictParams::Target::type_, + value: String + } + + type type_ = :phone_number | :email_address + + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER: :phone_number + EMAIL_ADDRESS: :email_address + + def self?.values: -> ::Array[PreludeSDK::Models::WatchPredictParams::Target::type_] + end + end + + type metadata = { correlation_id: String } + + class Metadata < PreludeSDK::Internal::Type::BaseModel + attr_reader correlation_id: String? + + def correlation_id=: (String) -> String + + def initialize: (?correlation_id: String) -> void + + def to_hash: -> { correlation_id: String } + end + + type signals = + { + app_version: String, + device_id: String, + device_model: String, + device_platform: PreludeSDK::Models::WatchPredictParams::Signals::device_platform, + ip: String, + is_trusted_user: bool, + os_version: String, + user_agent: String + } + + class Signals < PreludeSDK::Internal::Type::BaseModel + attr_reader app_version: String? + + def app_version=: (String) -> String + + attr_reader device_id: String? + + def device_id=: (String) -> String + + attr_reader device_model: String? + + def device_model=: (String) -> String + + attr_reader device_platform: PreludeSDK::Models::WatchPredictParams::Signals::device_platform? + + def device_platform=: ( + PreludeSDK::Models::WatchPredictParams::Signals::device_platform + ) -> PreludeSDK::Models::WatchPredictParams::Signals::device_platform + + attr_reader ip: String? + + def ip=: (String) -> String + + attr_reader is_trusted_user: bool? + + def is_trusted_user=: (bool) -> bool + + attr_reader os_version: String? + + def os_version=: (String) -> String + + attr_reader user_agent: String? + + def user_agent=: (String) -> String + + def initialize: ( + ?app_version: String, + ?device_id: String, + ?device_model: String, + ?device_platform: PreludeSDK::Models::WatchPredictParams::Signals::device_platform, + ?ip: String, + ?is_trusted_user: bool, + ?os_version: String, + ?user_agent: String + ) -> void + + def to_hash: -> { + app_version: String, + device_id: String, + device_model: String, + device_platform: PreludeSDK::Models::WatchPredictParams::Signals::device_platform, + ip: String, + is_trusted_user: bool, + os_version: String, + user_agent: String + } + + type device_platform = :android | :ios | :ipados | :tvos | :web + + module DevicePlatform + extend PreludeSDK::Internal::Type::Enum + + ANDROID: :android + IOS: :ios + IPADOS: :ipados + TVOS: :tvos + WEB: :web + + def self?.values: -> ::Array[PreludeSDK::Models::WatchPredictParams::Signals::device_platform] + end + end + end + end +end diff --git a/sig/prelude_sdk/models/watch_predict_response.rbs b/sig/prelude_sdk/models/watch_predict_response.rbs new file mode 100644 index 00000000..d9c46afc --- /dev/null +++ b/sig/prelude_sdk/models/watch_predict_response.rbs @@ -0,0 +1,41 @@ +module PreludeSDK + module Models + type watch_predict_response = + { + id: String, + prediction: PreludeSDK::Models::WatchPredictResponse::prediction, + request_id: String + } + + class WatchPredictResponse < PreludeSDK::Internal::Type::BaseModel + attr_accessor id: String + + attr_accessor prediction: PreludeSDK::Models::WatchPredictResponse::prediction + + attr_accessor request_id: String + + def initialize: ( + id: String, + prediction: PreludeSDK::Models::WatchPredictResponse::prediction, + request_id: String + ) -> void + + def to_hash: -> { + id: String, + prediction: PreludeSDK::Models::WatchPredictResponse::prediction, + request_id: String + } + + type prediction = :legitimate | :suspicious + + module Prediction + extend PreludeSDK::Internal::Type::Enum + + LEGITIMATE: :legitimate + SUSPICIOUS: :suspicious + + def self?.values: -> ::Array[PreludeSDK::Models::WatchPredictResponse::prediction] + end + end + end +end diff --git a/sig/prelude_sdk/models/watch_send_events_params.rbs b/sig/prelude_sdk/models/watch_send_events_params.rbs new file mode 100644 index 00000000..2d768787 --- /dev/null +++ b/sig/prelude_sdk/models/watch_send_events_params.rbs @@ -0,0 +1,98 @@ +module PreludeSDK + module Models + type watch_send_events_params = + { events: ::Array[PreludeSDK::WatchSendEventsParams::Event] } + & PreludeSDK::Internal::Type::request_parameters + + class WatchSendEventsParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + attr_accessor events: ::Array[PreludeSDK::WatchSendEventsParams::Event] + + def initialize: ( + events: ::Array[PreludeSDK::WatchSendEventsParams::Event], + ?request_options: PreludeSDK::request_opts + ) -> void + + def to_hash: -> { + events: ::Array[PreludeSDK::WatchSendEventsParams::Event], + request_options: PreludeSDK::RequestOptions + } + + type event = + { + confidence: PreludeSDK::Models::WatchSendEventsParams::Event::confidence, + label: String, + target: PreludeSDK::WatchSendEventsParams::Event::Target + } + + class Event < PreludeSDK::Internal::Type::BaseModel + attr_accessor confidence: PreludeSDK::Models::WatchSendEventsParams::Event::confidence + + attr_accessor label: String + + attr_accessor target: PreludeSDK::WatchSendEventsParams::Event::Target + + def initialize: ( + confidence: PreludeSDK::Models::WatchSendEventsParams::Event::confidence, + label: String, + target: PreludeSDK::WatchSendEventsParams::Event::Target + ) -> void + + def to_hash: -> { + confidence: PreludeSDK::Models::WatchSendEventsParams::Event::confidence, + label: String, + target: PreludeSDK::WatchSendEventsParams::Event::Target + } + + type confidence = :maximum | :high | :neutral | :low | :minimum + + module Confidence + extend PreludeSDK::Internal::Type::Enum + + MAXIMUM: :maximum + HIGH: :high + NEUTRAL: :neutral + LOW: :low + MINIMUM: :minimum + + def self?.values: -> ::Array[PreludeSDK::Models::WatchSendEventsParams::Event::confidence] + end + + type target = + { + type: PreludeSDK::Models::WatchSendEventsParams::Event::Target::type_, + value: String + } + + class Target < PreludeSDK::Internal::Type::BaseModel + attr_accessor type: PreludeSDK::Models::WatchSendEventsParams::Event::Target::type_ + + attr_accessor value: String + + def initialize: ( + type: PreludeSDK::Models::WatchSendEventsParams::Event::Target::type_, + value: String + ) -> void + + def to_hash: -> { + type: PreludeSDK::Models::WatchSendEventsParams::Event::Target::type_, + value: String + } + + type type_ = :phone_number | :email_address + + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER: :phone_number + EMAIL_ADDRESS: :email_address + + def self?.values: -> ::Array[PreludeSDK::Models::WatchSendEventsParams::Event::Target::type_] + end + end + end + end + end +end diff --git a/sig/prelude_sdk/models/watch_send_events_response.rbs b/sig/prelude_sdk/models/watch_send_events_response.rbs new file mode 100644 index 00000000..7969a03f --- /dev/null +++ b/sig/prelude_sdk/models/watch_send_events_response.rbs @@ -0,0 +1,35 @@ +module PreludeSDK + module Models + type watch_send_events_response = + { + request_id: String, + status: PreludeSDK::Models::WatchSendEventsResponse::status + } + + class WatchSendEventsResponse < PreludeSDK::Internal::Type::BaseModel + attr_accessor request_id: String + + attr_accessor status: PreludeSDK::Models::WatchSendEventsResponse::status + + def initialize: ( + request_id: String, + status: PreludeSDK::Models::WatchSendEventsResponse::status + ) -> void + + def to_hash: -> { + request_id: String, + status: PreludeSDK::Models::WatchSendEventsResponse::status + } + + type status = :success + + module Status + extend PreludeSDK::Internal::Type::Enum + + SUCCESS: :success + + def self?.values: -> ::Array[PreludeSDK::Models::WatchSendEventsResponse::status] + end + end + end +end diff --git a/sig/prelude_sdk/models/watch_send_feedbacks_params.rbs b/sig/prelude_sdk/models/watch_send_feedbacks_params.rbs new file mode 100644 index 00000000..b2264396 --- /dev/null +++ b/sig/prelude_sdk/models/watch_send_feedbacks_params.rbs @@ -0,0 +1,211 @@ +module PreludeSDK + module Models + type watch_send_feedbacks_params = + { feedbacks: ::Array[PreludeSDK::WatchSendFeedbacksParams::Feedback] } + & PreludeSDK::Internal::Type::request_parameters + + class WatchSendFeedbacksParams < PreludeSDK::Internal::Type::BaseModel + extend PreludeSDK::Internal::Type::RequestParameters::Converter + include PreludeSDK::Internal::Type::RequestParameters + + attr_accessor feedbacks: ::Array[PreludeSDK::WatchSendFeedbacksParams::Feedback] + + def initialize: ( + feedbacks: ::Array[PreludeSDK::WatchSendFeedbacksParams::Feedback], + ?request_options: PreludeSDK::request_opts + ) -> void + + def to_hash: -> { + feedbacks: ::Array[PreludeSDK::WatchSendFeedbacksParams::Feedback], + request_options: PreludeSDK::RequestOptions + } + + type feedback = + { + target: PreludeSDK::WatchSendFeedbacksParams::Feedback::Target, + type: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::type_, + dispatch_id: String, + metadata: PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata, + signals: PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals + } + + class Feedback < PreludeSDK::Internal::Type::BaseModel + attr_accessor target: PreludeSDK::WatchSendFeedbacksParams::Feedback::Target + + attr_accessor type: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::type_ + + attr_reader dispatch_id: String? + + def dispatch_id=: (String) -> String + + attr_reader metadata: PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata? + + def metadata=: ( + PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata + ) -> PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata + + attr_reader signals: PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals? + + def signals=: ( + PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals + ) -> PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals + + def initialize: ( + target: PreludeSDK::WatchSendFeedbacksParams::Feedback::Target, + type: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::type_, + ?dispatch_id: String, + ?metadata: PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata, + ?signals: PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals + ) -> void + + def to_hash: -> { + target: PreludeSDK::WatchSendFeedbacksParams::Feedback::Target, + type: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::type_, + dispatch_id: String, + metadata: PreludeSDK::WatchSendFeedbacksParams::Feedback::Metadata, + signals: PreludeSDK::WatchSendFeedbacksParams::Feedback::Signals + } + + type target = + { + type: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target::type_, + value: String + } + + class Target < PreludeSDK::Internal::Type::BaseModel + attr_accessor type: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target::type_ + + attr_accessor value: String + + def initialize: ( + type: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target::type_, + value: String + ) -> void + + def to_hash: -> { + type: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target::type_, + value: String + } + + type type_ = :phone_number | :email_address + + module Type + extend PreludeSDK::Internal::Type::Enum + + PHONE_NUMBER: :phone_number + EMAIL_ADDRESS: :email_address + + def self?.values: -> ::Array[PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Target::type_] + end + end + + type type_ = :"verification.started" | :"verification.completed" + + module Type + extend PreludeSDK::Internal::Type::Enum + + VERIFICATION_STARTED: :"verification.started" + VERIFICATION_COMPLETED: :"verification.completed" + + def self?.values: -> ::Array[PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::type_] + end + + type metadata = { correlation_id: String } + + class Metadata < PreludeSDK::Internal::Type::BaseModel + attr_reader correlation_id: String? + + def correlation_id=: (String) -> String + + def initialize: (?correlation_id: String) -> void + + def to_hash: -> { correlation_id: String } + end + + type signals = + { + app_version: String, + device_id: String, + device_model: String, + device_platform: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals::device_platform, + ip: String, + is_trusted_user: bool, + os_version: String, + user_agent: String + } + + class Signals < PreludeSDK::Internal::Type::BaseModel + attr_reader app_version: String? + + def app_version=: (String) -> String + + attr_reader device_id: String? + + def device_id=: (String) -> String + + attr_reader device_model: String? + + def device_model=: (String) -> String + + attr_reader device_platform: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals::device_platform? + + def device_platform=: ( + PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals::device_platform + ) -> PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals::device_platform + + attr_reader ip: String? + + def ip=: (String) -> String + + attr_reader is_trusted_user: bool? + + def is_trusted_user=: (bool) -> bool + + attr_reader os_version: String? + + def os_version=: (String) -> String + + attr_reader user_agent: String? + + def user_agent=: (String) -> String + + def initialize: ( + ?app_version: String, + ?device_id: String, + ?device_model: String, + ?device_platform: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals::device_platform, + ?ip: String, + ?is_trusted_user: bool, + ?os_version: String, + ?user_agent: String + ) -> void + + def to_hash: -> { + app_version: String, + device_id: String, + device_model: String, + device_platform: PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals::device_platform, + ip: String, + is_trusted_user: bool, + os_version: String, + user_agent: String + } + + type device_platform = :android | :ios | :ipados | :tvos | :web + + module DevicePlatform + extend PreludeSDK::Internal::Type::Enum + + ANDROID: :android + IOS: :ios + IPADOS: :ipados + TVOS: :tvos + WEB: :web + + def self?.values: -> ::Array[PreludeSDK::Models::WatchSendFeedbacksParams::Feedback::Signals::device_platform] + end + end + end + end + end +end diff --git a/sig/prelude_sdk/models/watch_send_feedbacks_response.rbs b/sig/prelude_sdk/models/watch_send_feedbacks_response.rbs new file mode 100644 index 00000000..a4f7b6e1 --- /dev/null +++ b/sig/prelude_sdk/models/watch_send_feedbacks_response.rbs @@ -0,0 +1,35 @@ +module PreludeSDK + module Models + type watch_send_feedbacks_response = + { + request_id: String, + status: PreludeSDK::Models::WatchSendFeedbacksResponse::status + } + + class WatchSendFeedbacksResponse < PreludeSDK::Internal::Type::BaseModel + attr_accessor request_id: String + + attr_accessor status: PreludeSDK::Models::WatchSendFeedbacksResponse::status + + def initialize: ( + request_id: String, + status: PreludeSDK::Models::WatchSendFeedbacksResponse::status + ) -> void + + def to_hash: -> { + request_id: String, + status: PreludeSDK::Models::WatchSendFeedbacksResponse::status + } + + type status = :success + + module Status + extend PreludeSDK::Internal::Type::Enum + + SUCCESS: :success + + def self?.values: -> ::Array[PreludeSDK::Models::WatchSendFeedbacksResponse::status] + end + end + end +end diff --git a/sig/prelude_sdk/request_options.rbs b/sig/prelude_sdk/request_options.rbs new file mode 100644 index 00000000..c48f1695 --- /dev/null +++ b/sig/prelude_sdk/request_options.rbs @@ -0,0 +1,36 @@ +module PreludeSDK + type request_opts = + PreludeSDK::RequestOptions + | PreludeSDK::request_options + | ::Hash[Symbol, top] + + type request_options = + { + idempotency_key: String?, + extra_query: ::Hash[String, (::Array[String] | String)?]?, + extra_headers: ::Hash[String, String?]?, + extra_body: top?, + max_retries: Integer?, + timeout: Float? + } + + class RequestOptions < PreludeSDK::Internal::Type::BaseModel + def self.validate!: (PreludeSDK::request_opts opts) -> void + + attr_accessor idempotency_key: String? + + attr_accessor extra_query: ::Hash[String, (::Array[String] | String)?]? + + attr_accessor extra_headers: ::Hash[String, String?]? + + attr_accessor extra_body: top? + + attr_accessor max_retries: Integer? + + attr_accessor timeout: Float? + + def initialize: ( + ?PreludeSDK::request_options | ::Hash[Symbol, top] values + ) -> void + end +end diff --git a/sig/prelude_sdk/resources/lookup.rbs b/sig/prelude_sdk/resources/lookup.rbs new file mode 100644 index 00000000..2fea180a --- /dev/null +++ b/sig/prelude_sdk/resources/lookup.rbs @@ -0,0 +1,13 @@ +module PreludeSDK + module Resources + class Lookup + def lookup: ( + String phone_number, + ?type: ::Array[PreludeSDK::Models::LookupLookupParams::type_], + ?request_options: PreludeSDK::request_opts + ) -> PreludeSDK::Models::LookupLookupResponse + + def initialize: (client: PreludeSDK::Client) -> void + end + end +end diff --git a/sig/prelude_sdk/resources/transactional.rbs b/sig/prelude_sdk/resources/transactional.rbs new file mode 100644 index 00000000..7149fe7e --- /dev/null +++ b/sig/prelude_sdk/resources/transactional.rbs @@ -0,0 +1,19 @@ +module PreludeSDK + module Resources + class Transactional + def send_: ( + template_id: String, + to: String, + ?callback_url: String, + ?correlation_id: String, + ?expires_at: String, + ?from: String, + ?locale: String, + ?variables: ::Hash[Symbol, String], + ?request_options: PreludeSDK::request_opts + ) -> PreludeSDK::Models::TransactionalSendResponse + + def initialize: (client: PreludeSDK::Client) -> void + end + end +end diff --git a/sig/prelude_sdk/resources/verification.rbs b/sig/prelude_sdk/resources/verification.rbs new file mode 100644 index 00000000..2de53cbc --- /dev/null +++ b/sig/prelude_sdk/resources/verification.rbs @@ -0,0 +1,22 @@ +module PreludeSDK + module Resources + class Verification + def create: ( + target: PreludeSDK::VerificationCreateParams::Target, + ?dispatch_id: String, + ?metadata: PreludeSDK::VerificationCreateParams::Metadata, + ?options: PreludeSDK::VerificationCreateParams::Options, + ?signals: PreludeSDK::VerificationCreateParams::Signals, + ?request_options: PreludeSDK::request_opts + ) -> PreludeSDK::Models::VerificationCreateResponse + + def check: ( + code: String, + target: PreludeSDK::VerificationCheckParams::Target, + ?request_options: PreludeSDK::request_opts + ) -> PreludeSDK::Models::VerificationCheckResponse + + def initialize: (client: PreludeSDK::Client) -> void + end + end +end diff --git a/sig/prelude_sdk/resources/watch.rbs b/sig/prelude_sdk/resources/watch.rbs new file mode 100644 index 00000000..1bea527c --- /dev/null +++ b/sig/prelude_sdk/resources/watch.rbs @@ -0,0 +1,25 @@ +module PreludeSDK + module Resources + class Watch + def predict: ( + target: PreludeSDK::WatchPredictParams::Target, + ?dispatch_id: String, + ?metadata: PreludeSDK::WatchPredictParams::Metadata, + ?signals: PreludeSDK::WatchPredictParams::Signals, + ?request_options: PreludeSDK::request_opts + ) -> PreludeSDK::Models::WatchPredictResponse + + def send_events: ( + events: ::Array[PreludeSDK::WatchSendEventsParams::Event], + ?request_options: PreludeSDK::request_opts + ) -> PreludeSDK::Models::WatchSendEventsResponse + + def send_feedbacks: ( + feedbacks: ::Array[PreludeSDK::WatchSendFeedbacksParams::Feedback], + ?request_options: PreludeSDK::request_opts + ) -> PreludeSDK::Models::WatchSendFeedbacksResponse + + def initialize: (client: PreludeSDK::Client) -> void + end + end +end diff --git a/sig/prelude_sdk/version.rbs b/sig/prelude_sdk/version.rbs new file mode 100644 index 00000000..d67b2a63 --- /dev/null +++ b/sig/prelude_sdk/version.rbs @@ -0,0 +1,3 @@ +module PreludeSDK + VERSION: String +end diff --git a/sorbet/config b/sorbet/config new file mode 100644 index 00000000..6fe84ed8 --- /dev/null +++ b/sorbet/config @@ -0,0 +1,2 @@ +--dir=rbi/ +--ignore=test/ diff --git a/sorbet/rbi/.gitignore b/sorbet/rbi/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/sorbet/rbi/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/test/prelude/base_client_test.rb b/test/prelude/base_client_test.rb deleted file mode 100644 index 6af45246..00000000 --- a/test/prelude/base_client_test.rb +++ /dev/null @@ -1,64 +0,0 @@ -# frozen_string_literal: true - -require_relative "test_helper" - -class Prelude::Test::BaseClientTest < Minitest::Test - parallelize_me! - - def test_from_uri_string - assert_equal( - { - scheme: "h", - host: "a.b", - port: nil, - path: "/c", - query: {"d" => ["e"]} - }, - Prelude::BaseClient.new( - base_url: "h://nope/ignored" - ).resolve_uri_elements( - url: "h://a.b/c?d=e" - ) - ) - end - - def test_extra_query - assert_equal( - { - scheme: "h", - host: "a.b", - port: nil, - path: "/c", - query: {"d" => ["e"], "f" => ["g"]} - }, - Prelude::BaseClient.new( - base_url: "h://nope" - ).resolve_uri_elements( - host: "a.b", - scheme: "h", - path: "/c", - query: {"d" => ["e"]}, - extra_query: { - "f" => ["g"] - } - ) - ) - end - - def test_path_merged - assert_equal( - { - scheme: "h", - host: "a.b", - port: nil, - path: "/c/c2", - query: {} - }, - Prelude::BaseClient.new( - base_url: "h://a.b/c" - ).resolve_uri_elements( - path: "c2" - ) - ) - end -end diff --git a/test/prelude/client_test.rb b/test/prelude/client_test.rb deleted file mode 100644 index 63a7ef57..00000000 --- a/test/prelude/client_test.rb +++ /dev/null @@ -1,303 +0,0 @@ -# frozen_string_literal: true - -require_relative "test_helper" - -class PreludeTest < Minitest::Test - parallelize_me! - - def test_raises_on_missing_non_nullable_opts - e = assert_raises(ArgumentError) do - Prelude::Client.new - end - assert_match(/is required/, e.message) - end - - class MockResponse - # @return [Integer] - attr_accessor :code - - # @return [String] - attr_accessor :body - - # @return [String] - attr_accessor :content_type - - # @param code [Integer] - # @param data [Object] - # @param headers [Hash{String => String}] - def initialize(code, data, headers) - @headers = headers - self.code = code - self.body = JSON.generate(data) - self.content_type = "application/json" - end - - def [](header) - @headers[header] - end - - def key?(header) - @headers.key?(header) - end - end - - class MockRequester - # @return [Integer] - attr_accessor :response_code - - # @return [Object] - attr_accessor :response_data - - # @return [Hash{String => String}] - attr_accessor :response_headers - - # @return [Array Object}>] - attr_accessor :attempts - - # @param response_code [Integer] - # @param response_data [Object] - # @param response_headers [Hash{String => String}] - def initialize(response_code, response_data, response_headers) - self.response_code = response_code - self.response_data = response_data - self.response_headers = response_headers - self.attempts = [] - end - - # @param req [Hash{Symbol => Object}] - # @param timeout [Float, nil] - def execute(req, timeout:) - # Deep copy the request because it is mutated on each retry. - attempts.push(Marshal.load(Marshal.dump(req))) - MockResponse.new(response_code, response_data, response_headers) - end - end - - def test_client_default_request_default_retry_attempts - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(500, {}, {"x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create({target: {"type" => "phone_number", "value" => "+30123456789"}}) - end - assert_equal(3, requester.attempts.length) - end - - def test_client_given_request_default_retry_attempts - prelude = Prelude::Client.new( - base_url: "http://localhost:4010", - api_token: "My API Token", - max_retries: 3 - ) - requester = MockRequester.new(500, {}, {"x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create({target: {"type" => "phone_number", "value" => "+30123456789"}}) - end - assert_equal(4, requester.attempts.length) - end - - def test_client_default_request_given_retry_attempts - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(500, {}, {"x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create( - {target: {"type" => "phone_number", "value" => "+30123456789"}}, - max_retries: 3 - ) - end - assert_equal(4, requester.attempts.length) - end - - def test_client_given_request_given_retry_attempts - prelude = Prelude::Client.new( - base_url: "http://localhost:4010", - api_token: "My API Token", - max_retries: 3 - ) - requester = MockRequester.new(500, {}, {"x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create( - {target: {"type" => "phone_number", "value" => "+30123456789"}}, - max_retries: 4 - ) - end - assert_equal(5, requester.attempts.length) - end - - def test_client_retry_after_seconds - prelude = Prelude::Client.new( - base_url: "http://localhost:4010", - api_token: "My API Token", - max_retries: 1 - ) - requester = MockRequester.new(500, {}, {"retry-after" => "1.3", "x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create({target: {"type" => "phone_number", "value" => "+30123456789"}}) - end - assert_equal(2, requester.attempts.length) - assert_equal(requester.attempts.last[:headers]["x-stainless-mock-slept"], 1.3) - end - - def test_client_retry_after_date - prelude = Prelude::Client.new( - base_url: "http://localhost:4010", - api_token: "My API Token", - max_retries: 1 - ) - requester = MockRequester.new( - 500, - {}, - { - "retry-after" => (Time.now + 2).httpdate, - "x-stainless-mock-sleep" => "true", - "x-stainless-mock-sleep-base" => Time.now.httpdate - } - ) - prelude.requester = requester - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create({target: {"type" => "phone_number", "value" => "+30123456789"}}) - end - assert_equal(2, requester.attempts.length) - assert_equal(requester.attempts.last[:headers]["x-stainless-mock-slept"], 2) - end - - def test_client_retry_after_ms - prelude = Prelude::Client.new( - base_url: "http://localhost:4010", - api_token: "My API Token", - max_retries: 1 - ) - requester = MockRequester.new(500, {}, {"retry-after-ms" => "1300", "x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create({target: {"type" => "phone_number", "value" => "+30123456789"}}) - end - assert_equal(2, requester.attempts.length) - assert_equal(requester.attempts.last[:headers]["x-stainless-mock-slept"], 1.3) - end - - def test_retry_count_header - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(500, {}, {"x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create({target: {"type" => "phone_number", "value" => "+30123456789"}}) - end - - retry_count_headers = requester.attempts.map { |a| a[:headers]["x-stainless-retry-count"] } - assert_equal(%w[0 1 2], retry_count_headers) - end - - def test_omit_retry_count_header - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(500, {}, {"x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create( - {target: {"type" => "phone_number", "value" => "+30123456789"}}, - extra_headers: {"x-stainless-retry-count" => nil} - ) - end - - retry_count_headers = requester.attempts.map { |a| a[:headers]["x-stainless-retry-count"] } - assert_equal([nil, nil, nil], retry_count_headers) - end - - def test_overwrite_retry_count_header - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(500, {}, {"x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - - assert_raises(Prelude::HTTP::InternalServerError) do - prelude.verification.create( - {target: {"type" => "phone_number", "value" => "+30123456789"}}, - extra_headers: {"x-stainless-retry-count" => "42"} - ) - end - - retry_count_headers = requester.attempts.map { |a| a[:headers]["x-stainless-retry-count"] } - assert_equal(%w[42 42 42], retry_count_headers) - end - - def test_client_redirect_307 - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(307, {}, {"location" => "/redirected"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::APIConnectionError) do - prelude.verification.create( - {target: {"type" => "phone_number", "value" => "+30123456789"}}, - extra_headers: {} - ) - end - assert_equal(requester.attempts[1][:path], "/redirected") - assert_equal(requester.attempts[1][:method], requester.attempts[0][:method]) - assert_equal(requester.attempts[1][:body], requester.attempts[0][:body]) - assert_equal( - requester.attempts[1][:headers]["content-type"], - requester.attempts[0][:headers]["content-type"] - ) - end - - def test_client_redirect_303 - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(303, {}, {"location" => "/redirected"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::APIConnectionError) do - prelude.verification.create( - {target: {"type" => "phone_number", "value" => "+30123456789"}}, - extra_headers: {} - ) - end - assert_equal(requester.attempts[1][:path], "/redirected") - assert_equal(requester.attempts[1][:method], :get) - assert_nil(requester.attempts[1][:body]) - assert_nil(requester.attempts[1][:headers]["Content-Type"]) - end - - def test_client_redirect_auth_keep_same_origin - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(307, {}, {"location" => "/redirected"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::APIConnectionError) do - prelude.verification.create( - {target: {"type" => "phone_number", "value" => "+30123456789"}}, - extra_headers: {"Authorization" => "Bearer xyz"} - ) - end - assert_equal( - requester.attempts[1][:headers]["authorization"], - requester.attempts[0][:headers]["authorization"] - ) - end - - def test_client_redirect_auth_strip_cross_origin - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(307, {}, {"location" => "https://example.com/redirected"}) - prelude.requester = requester - assert_raises(Prelude::HTTP::APIConnectionError) do - prelude.verification.create( - {target: {"type" => "phone_number", "value" => "+30123456789"}}, - extra_headers: {"Authorization" => "Bearer xyz"} - ) - end - assert_nil(requester.attempts[1][:headers]["Authorization"]) - end - - def test_default_headers - prelude = Prelude::Client.new(base_url: "http://localhost:4010", api_token: "My API Token") - requester = MockRequester.new(200, {}, {"x-stainless-mock-sleep" => "true"}) - prelude.requester = requester - prelude.verification.create({target: {"type" => "phone_number", "value" => "+30123456789"}}) - headers = requester.attempts[0][:headers] - refute_empty(headers["x-stainless-lang"]) - refute_empty(headers["x-stainless-package-version"]) - refute_empty(headers["x-stainless-runtime"]) - refute_empty(headers["x-stainless-runtime-version"]) - end -end diff --git a/test/prelude/resources/transactional_test.rb b/test/prelude/resources/transactional_test.rb deleted file mode 100644 index e27ebc23..00000000 --- a/test/prelude/resources/transactional_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require_relative "../test_helper" - -class Prelude::Test::Resources::TransactionalTest < Minitest::Test - parallelize_me! - - def setup - @prelude = Prelude::Client.new( - base_url: ENV.fetch("TEST_API_BASE_URL", "http://localhost:4010"), - api_token: "My API Token" - ) - end - - def test_send_required_params - skip( - "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) - response = @prelude.transactional.send({template_id: "template_id", to: "to"}) - assert_kind_of(Prelude::Models::TransactionalSendResponse, response) - end -end diff --git a/test/prelude/resources/verification_test.rb b/test/prelude/resources/verification_test.rb deleted file mode 100644 index 37c715fd..00000000 --- a/test/prelude/resources/verification_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require_relative "../test_helper" - -class Prelude::Test::Resources::VerificationTest < Minitest::Test - parallelize_me! - - def setup - @prelude = Prelude::Client.new( - base_url: ENV.fetch("TEST_API_BASE_URL", "http://localhost:4010"), - api_token: "My API Token" - ) - end - - def test_create_required_params - response = @prelude.verification.create({target: {"type" => "phone_number", "value" => "+30123456789"}}) - assert_kind_of(Prelude::Models::VerificationCreateResponse, response) - end - - def test_check_required_params - response = @prelude.verification.check( - {code: "12345", target: {"type" => "phone_number", "value" => "+30123456789"}} - ) - assert_kind_of(Prelude::Models::VerificationCheckResponse, response) - end -end diff --git a/test/prelude/resources/watch_test.rb b/test/prelude/resources/watch_test.rb deleted file mode 100644 index 0eded262..00000000 --- a/test/prelude/resources/watch_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require_relative "../test_helper" - -class Prelude::Test::Resources::WatchTest < Minitest::Test - parallelize_me! - - def setup - @prelude = Prelude::Client.new( - base_url: ENV.fetch("TEST_API_BASE_URL", "http://localhost:4010"), - api_token: "My API Token" - ) - end - - def test_feed_back_required_params - response = @prelude.watch.feed_back( - {feedback: {"type" => "CONFIRM_TARGET"}, target: {"type" => "phone_number", "value" => "+30123456789"}} - ) - assert_kind_of(Prelude::Models::WatchFeedBackResponse, response) - end - - def test_predict_required_params - response = @prelude.watch.predict({target: {"type" => "phone_number", "value" => "+30123456789"}}) - assert_kind_of(Prelude::Models::WatchPredictResponse, response) - end -end diff --git a/test/prelude/test_helper.rb b/test/prelude/test_helper.rb deleted file mode 100644 index bfc48854..00000000 --- a/test/prelude/test_helper.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -# Requiring this file from each test file ensures we always do the following, even -# when running a single-file test: -# - Load the whole gem (as one would in production) -# - Define shared testing namespace so that we don't need to indent test files as much -# - Setting up testing dependencies - -require_relative "../../lib/prelude" -require_relative "test_namespaces" - -require "minitest" -require "stringio" diff --git a/test/prelude/util_test.rb b/test/prelude/util_test.rb deleted file mode 100644 index 560d9fdf..00000000 --- a/test/prelude/util_test.rb +++ /dev/null @@ -1,104 +0,0 @@ -# frozen_string_literal: true - -require_relative "test_helper" - -class Prelude::Test::UtilTest < Minitest::Test - def test_left_map - assert_nil(Prelude::Util.deep_merge({a: 1}, nil)) - end - - def test_right_map - assert_equal(Prelude::Util.deep_merge(nil, {a: 1}), {a: 1}) - end - - def test_disjoint_maps - assert_equal( - Prelude::Util.deep_merge({b: 2}, {a: 1}), {a: 1, b: 2} - ) - end - - def test_overlapping_maps - assert_equal( - Prelude::Util.deep_merge({b: 2, c: 3}, {a: 1, c: 4}), - {a: 1, b: 2, c: 4} - ) - end - - def test_nested - assert_equal( - Prelude::Util.deep_merge({b: {b2: 1}}, {b: {b2: 2}}), - {b: {b2: 2}} - ) - end - - def test_nested_left_map - assert_equal( - Prelude::Util.deep_merge({b: {b2: 1}}, {b: 6}), - {b: 6} - ) - end - - def test_omission - assert_equal( - {b: {b2: 1, b3: {d: 5}}}, - Prelude::Util.deep_merge( - {b: {b2: 1, b3: {c: 4, d: 5}}}, - {b: {b2: 1, b3: {c: Prelude::Util::OMIT, d: 5}}} - ) - ) - end - - def test_concat - assert_equal( - {a: {b: [1, 2, 3, 4]}}, - Prelude::Util.deep_merge( - {a: {b: [1, 2]}}, - {a: {b: [3, 4]}}, - concat: true - ) - ) - end - - def test_concat_false - assert_equal( - {a: {b: [3, 4]}}, - Prelude::Util.deep_merge( - {a: {b: [1, 2]}}, - {a: {b: [3, 4]}}, - concat: false - ) - ) - end - - def test_dig - assert_equal(1, Prelude::Util.dig(1, nil)) - assert_nil(Prelude::Util.dig({a: 1}, :b)) - assert_equal(1, Prelude::Util.dig({a: 1}, :a)) - assert_equal(1, Prelude::Util.dig({a: {b: 1}}, [:a, :b])) - assert_nil(Prelude::Util.dig([], 1)) - assert_equal(1, Prelude::Util.dig([nil, [nil, 1]], [1, 1])) - assert_equal(1, Prelude::Util.dig({a: [nil, 1]}, [:a, 1])) - - assert_raises(NoMatchingPatternError) do - Prelude::Util.dig([], 1.0) - end - assert_raises(NoMatchingPatternError) do - Prelude::Util.dig(Object, 1) - end - end - - def test_uri_parsing - %w[ - http://example.com - https://example.com/ - https://example.com:443/example?e1=e1&e2=e2&e= - ].each do |url| - uri = URI.parse(url) - parsed = Prelude::Util.parse_uri(uri) - unparsed = Prelude::Util.unparse_uri(parsed) - - assert_equal(unparsed, uri) - assert_equal(parsed, Prelude::Util.parse_uri(unparsed)) - end - end -end diff --git a/test/prelude_sdk/client_test.rb b/test/prelude_sdk/client_test.rb new file mode 100644 index 00000000..ab81c704 --- /dev/null +++ b/test/prelude_sdk/client_test.rb @@ -0,0 +1,317 @@ +# frozen_string_literal: true + +require_relative "test_helper" + +class PreludeSDKTest < Minitest::Test + extend Minitest::Serial + include WebMock::API + + def before_all + super + WebMock.enable! + end + + def setup + super + Thread.current.thread_variable_set(:mock_sleep, []) + end + + def teardown + Thread.current.thread_variable_set(:mock_sleep, nil) + WebMock.reset! + super + end + + def after_all + WebMock.disable! + super + end + + def test_raises_on_missing_non_nullable_opts + e = assert_raises(ArgumentError) do + PreludeSDK::Client.new + end + assert_match(/is required/, e.message) + end + + def test_client_default_request_default_retry_attempts + stub_request(:post, "http://localhost/v2/verification").to_return_json(status: 500, body: {}) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + assert_raises(PreludeSDK::Errors::InternalServerError) do + prelude.verification.create(target: {type: :phone_number, value: "+30123456789"}) + end + + assert_requested(:any, /./, times: 3) + end + + def test_client_given_request_default_retry_attempts + stub_request(:post, "http://localhost/v2/verification").to_return_json(status: 500, body: {}) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token", max_retries: 3) + + assert_raises(PreludeSDK::Errors::InternalServerError) do + prelude.verification.create(target: {type: :phone_number, value: "+30123456789"}) + end + + assert_requested(:any, /./, times: 4) + end + + def test_client_default_request_given_retry_attempts + stub_request(:post, "http://localhost/v2/verification").to_return_json(status: 500, body: {}) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + assert_raises(PreludeSDK::Errors::InternalServerError) do + prelude.verification.create( + target: {type: :phone_number, value: "+30123456789"}, + request_options: {max_retries: 3} + ) + end + + assert_requested(:any, /./, times: 4) + end + + def test_client_given_request_given_retry_attempts + stub_request(:post, "http://localhost/v2/verification").to_return_json(status: 500, body: {}) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token", max_retries: 3) + + assert_raises(PreludeSDK::Errors::InternalServerError) do + prelude.verification.create( + target: {type: :phone_number, value: "+30123456789"}, + request_options: {max_retries: 4} + ) + end + + assert_requested(:any, /./, times: 5) + end + + def test_client_retry_after_seconds + stub_request(:post, "http://localhost/v2/verification").to_return_json( + status: 500, + headers: {"retry-after" => "1.3"}, + body: {} + ) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token", max_retries: 1) + + assert_raises(PreludeSDK::Errors::InternalServerError) do + prelude.verification.create(target: {type: :phone_number, value: "+30123456789"}) + end + + assert_requested(:any, /./, times: 2) + assert_equal(1.3, Thread.current.thread_variable_get(:mock_sleep).last) + end + + def test_client_retry_after_date + stub_request(:post, "http://localhost/v2/verification").to_return_json( + status: 500, + headers: {"retry-after" => (Time.now + 10).httpdate}, + body: {} + ) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token", max_retries: 1) + + assert_raises(PreludeSDK::Errors::InternalServerError) do + Thread.current.thread_variable_set(:time_now, Time.now) + prelude.verification.create(target: {type: :phone_number, value: "+30123456789"}) + Thread.current.thread_variable_set(:time_now, nil) + end + + assert_requested(:any, /./, times: 2) + assert_in_delta(10, Thread.current.thread_variable_get(:mock_sleep).last, 1.0) + end + + def test_client_retry_after_ms + stub_request(:post, "http://localhost/v2/verification").to_return_json( + status: 500, + headers: {"retry-after-ms" => "1300"}, + body: {} + ) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token", max_retries: 1) + + assert_raises(PreludeSDK::Errors::InternalServerError) do + prelude.verification.create(target: {type: :phone_number, value: "+30123456789"}) + end + + assert_requested(:any, /./, times: 2) + assert_equal(1.3, Thread.current.thread_variable_get(:mock_sleep).last) + end + + def test_retry_count_header + stub_request(:post, "http://localhost/v2/verification").to_return_json(status: 500, body: {}) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + assert_raises(PreludeSDK::Errors::InternalServerError) do + prelude.verification.create(target: {type: :phone_number, value: "+30123456789"}) + end + + 3.times do + assert_requested(:any, /./, headers: {"x-stainless-retry-count" => _1}) + end + end + + def test_omit_retry_count_header + stub_request(:post, "http://localhost/v2/verification").to_return_json(status: 500, body: {}) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + assert_raises(PreludeSDK::Errors::InternalServerError) do + prelude.verification.create( + target: {type: :phone_number, value: "+30123456789"}, + request_options: {extra_headers: {"x-stainless-retry-count" => nil}} + ) + end + + assert_requested(:any, /./, times: 3) do + refute_includes(_1.headers.keys.map(&:downcase), "x-stainless-retry-count") + end + end + + def test_overwrite_retry_count_header + stub_request(:post, "http://localhost/v2/verification").to_return_json(status: 500, body: {}) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + assert_raises(PreludeSDK::Errors::InternalServerError) do + prelude.verification.create( + target: {type: :phone_number, value: "+30123456789"}, + request_options: {extra_headers: {"x-stainless-retry-count" => "42"}} + ) + end + + assert_requested(:any, /./, headers: {"x-stainless-retry-count" => "42"}, times: 3) + end + + def test_client_redirect_307 + stub_request(:post, "http://localhost/v2/verification").to_return_json( + status: 307, + headers: {"location" => "/redirected"}, + body: {} + ) + stub_request(:any, "http://localhost/redirected").to_return( + status: 307, + headers: {"location" => "/redirected"} + ) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + assert_raises(PreludeSDK::Errors::APIConnectionError) do + prelude.verification.create( + target: {type: :phone_number, value: "+30123456789"}, + request_options: {extra_headers: {}} + ) + end + + recorded, = WebMock::RequestRegistry.instance.requested_signatures.hash.first + + assert_requested(:any, "http://localhost/redirected", times: PreludeSDK::Client::MAX_REDIRECTS) do + assert_equal(recorded.method, _1.method) + assert_equal(recorded.body, _1.body) + assert_equal( + recorded.headers.transform_keys(&:downcase).fetch("content-type"), + _1.headers.transform_keys(&:downcase).fetch("content-type") + ) + end + end + + def test_client_redirect_303 + stub_request(:post, "http://localhost/v2/verification").to_return_json( + status: 303, + headers: {"location" => "/redirected"}, + body: {} + ) + stub_request(:get, "http://localhost/redirected").to_return( + status: 303, + headers: {"location" => "/redirected"} + ) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + assert_raises(PreludeSDK::Errors::APIConnectionError) do + prelude.verification.create( + target: {type: :phone_number, value: "+30123456789"}, + request_options: {extra_headers: {}} + ) + end + + assert_requested(:get, "http://localhost/redirected", times: PreludeSDK::Client::MAX_REDIRECTS) do + headers = _1.headers.keys.map(&:downcase) + refute_includes(headers, "content-type") + assert_nil(_1.body) + end + end + + def test_client_redirect_auth_keep_same_origin + stub_request(:post, "http://localhost/v2/verification").to_return_json( + status: 307, + headers: {"location" => "/redirected"}, + body: {} + ) + stub_request(:any, "http://localhost/redirected").to_return( + status: 307, + headers: {"location" => "/redirected"} + ) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + assert_raises(PreludeSDK::Errors::APIConnectionError) do + prelude.verification.create( + target: {type: :phone_number, value: "+30123456789"}, + request_options: {extra_headers: {"authorization" => "Bearer xyz"}} + ) + end + + recorded, = WebMock::RequestRegistry.instance.requested_signatures.hash.first + auth_header = recorded.headers.transform_keys(&:downcase).fetch("authorization") + + assert_equal("Bearer xyz", auth_header) + assert_requested(:any, "http://localhost/redirected", times: PreludeSDK::Client::MAX_REDIRECTS) do + auth_header = _1.headers.transform_keys(&:downcase).fetch("authorization") + assert_equal("Bearer xyz", auth_header) + end + end + + def test_client_redirect_auth_strip_cross_origin + stub_request(:post, "http://localhost/v2/verification").to_return_json( + status: 307, + headers: {"location" => "https://example.com/redirected"}, + body: {} + ) + stub_request(:any, "https://example.com/redirected").to_return( + status: 307, + headers: {"location" => "https://example.com/redirected"} + ) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + assert_raises(PreludeSDK::Errors::APIConnectionError) do + prelude.verification.create( + target: {type: :phone_number, value: "+30123456789"}, + request_options: {extra_headers: {"authorization" => "Bearer xyz"}} + ) + end + + assert_requested(:any, "https://example.com/redirected", times: PreludeSDK::Client::MAX_REDIRECTS) do + headers = _1.headers.keys.map(&:downcase) + refute_includes(headers, "authorization") + end + end + + def test_default_headers + stub_request(:post, "http://localhost/v2/verification").to_return_json(status: 200, body: {}) + + prelude = PreludeSDK::Client.new(base_url: "http://localhost", api_token: "My API Token") + + prelude.verification.create(target: {type: :phone_number, value: "+30123456789"}) + + assert_requested(:any, /./) do |req| + headers = req.headers.transform_keys(&:downcase).fetch_values("accept", "content-type") + headers.each { refute_empty(_1) } + end + end +end diff --git a/test/prelude_sdk/file_part_test.rb b/test/prelude_sdk/file_part_test.rb new file mode 100644 index 00000000..a09931dc --- /dev/null +++ b/test/prelude_sdk/file_part_test.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require_relative "test_helper" + +class PreludeSDK::Test::FilePartTest < Minitest::Test + def test_to_json + text = "gray" + filepart = PreludeSDK::FilePart.new(StringIO.new(text)) + + assert_equal(text.to_json, filepart.to_json) + assert_equal(text.to_yaml, filepart.to_yaml) + end +end diff --git a/test/prelude_sdk/internal/sorbet_runtime_support_test.rb b/test/prelude_sdk/internal/sorbet_runtime_support_test.rb new file mode 100644 index 00000000..91b25643 --- /dev/null +++ b/test/prelude_sdk/internal/sorbet_runtime_support_test.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +class PreludeSDK::Test::SorbetRuntimeSupportTest < Minitest::Test + i_suck_and_my_tests_are_order_dependent! + + module E + extend PreludeSDK::Internal::Type::Enum + + define_sorbet_constant!(:TaggedSymbol) { 1 } + end + + module U + extend PreludeSDK::Internal::Type::Union + + define_sorbet_constant!(:Variants) { 2 } + end + + class M < PreludeSDK::Internal::Type::BaseModel + define_sorbet_constant!(:OrHash) { 3 } + end + + def test_nil_aliases + err = PreludeSDK::Internal::Util::SorbetRuntimeSupport::MissingSorbetRuntimeError + + assert_raises(err) { PreludeSDK::Internal::AnyHash } + assert_raises(err) { PreludeSDK::Internal::FileInput } + assert_raises(err) { PreludeSDK::Internal::Type::Converter::Input } + assert_raises(err) { PreludeSDK::Internal::Type::Converter::CoerceState } + assert_raises(err) { PreludeSDK::Internal::Type::Converter::DumpState } + assert_raises(err) { PreludeSDK::Internal::Type::BaseModel::KnownField } + assert_raises(err) { PreludeSDK::Internal::Util::ParsedUri } + assert_raises(err) { PreludeSDK::Internal::Util::ServerSentEvent } + assert_raises(err) { PreludeSDK::Internal::Transport::BaseClient::RequestComponents } + assert_raises(err) { PreludeSDK::Internal::Transport::BaseClient::RequestInput } + assert_raises(err) { PreludeSDK::Internal::Transport::PooledNetRequester::Request } + assert_raises(err) { E::TaggedSymbol } + assert_raises(err) { U::Variants } + assert_raises(err) { M::OrHash } + end + + def test_stubbed_aliases + Kernel.instance_eval { const_set(:T, nil) } + + assert_equal(1, E::TaggedSymbol) + assert_equal(2, U::Variants) + assert_equal(3, M::OrHash) + end +end diff --git a/test/prelude_sdk/internal/type/base_model_test.rb b/test/prelude_sdk/internal/type/base_model_test.rb new file mode 100644 index 00000000..b02ab591 --- /dev/null +++ b/test/prelude_sdk/internal/type/base_model_test.rb @@ -0,0 +1,689 @@ +# frozen_string_literal: true + +require_relative "../../test_helper" + +class PreludeSDK::Test::PrimitiveModelTest < Minitest::Test + A = PreludeSDK::Internal::Type::ArrayOf[-> { Integer }] + H = PreludeSDK::Internal::Type::HashOf[-> { Integer }, nil?: true] + + module E + extend PreludeSDK::Internal::Type::Enum + end + + module U + extend PreludeSDK::Internal::Type::Union + end + + class B < PreludeSDK::Internal::Type::BaseModel + optional :a, Integer + optional :b, B + end + + def test_typing + converters = [ + PreludeSDK::Internal::Type::Unknown, + PreludeSDK::Internal::Type::Boolean, + A, + H, + E, + U, + B + ] + + converters.each do |conv| + assert_pattern do + conv => PreludeSDK::Internal::Type::Converter + end + end + end + + def test_coerce + cases = { + [PreludeSDK::Internal::Type::Unknown, :a] => [{yes: 1}, :a], + [NilClass, :a] => [{maybe: 1}, nil], + [NilClass, nil] => [{yes: 1}, nil], + [PreludeSDK::Internal::Type::Boolean, true] => [{yes: 1}, true], + [PreludeSDK::Internal::Type::Boolean, "true"] => [{no: 1}, "true"], + [Integer, 1] => [{yes: 1}, 1], + [Integer, 1.0] => [{maybe: 1}, 1], + [Integer, "1"] => [{maybe: 1}, 1], + [Integer, "one"] => [{no: 1}, "one"], + [Float, 1] => [{yes: 1}, 1.0], + [Float, "1"] => [{maybe: 1}, 1.0], + [Float, :one] => [{no: 1}, :one], + [String, :str] => [{yes: 1}, "str"], + [String, "str"] => [{yes: 1}, "str"], + [String, 1] => [{maybe: 1}, "1"], + [:a, "a"] => [{yes: 1}, :a], + [Date, "1990-09-19"] => [{yes: 1}, Date.new(1990, 9, 19)], + [Date, Date.new(1990, 9, 19)] => [{yes: 1}, Date.new(1990, 9, 19)], + [Date, "one"] => [{no: 1}, "one"], + [Time, "1990-09-19"] => [{yes: 1}, Time.new(1990, 9, 19)], + [Time, Time.new(1990, 9, 19)] => [{yes: 1}, Time.new(1990, 9, 19)], + [Time, "one"] => [{no: 1}, "one"] + } + + cases.each do |lhs, rhs| + target, input = lhs + exactness, expect = rhs + state = PreludeSDK::Internal::Type::Converter.new_coerce_state + assert_pattern do + PreludeSDK::Internal::Type::Converter.coerce(target, input, state: state) => ^expect + state.fetch(:exactness).filter { _2.nonzero? }.to_h => ^exactness + end + end + end + + def test_dump + cases = { + [PreludeSDK::Internal::Type::Unknown, B.new(a: "one", b: B.new(a: 1.0))] => {a: "one", b: {a: 1}}, + [A, B.new(a: "one", b: B.new(a: 1.0))] => {a: "one", b: {a: 1}}, + [H, B.new(a: "one", b: B.new(a: 1.0))] => {a: "one", b: {a: 1}}, + [E, B.new(a: "one", b: B.new(a: 1.0))] => {a: "one", b: {a: 1}}, + [U, B.new(a: "one", b: B.new(a: 1.0))] => {a: "one", b: {a: 1}}, + [B, B.new(a: "one", b: B.new(a: 1.0))] => {a: "one", b: {a: 1}}, + [String, B.new(a: "one", b: B.new(a: 1.0))] => {a: "one", b: {a: 1}}, + [:b, B.new(a: "one", b: B.new(a: 1.0))] => {a: "one", b: {a: 1}}, + [nil, B.new(a: "one", b: B.new(a: 1.0))] => {a: "one", b: {a: 1}}, + [PreludeSDK::Internal::Type::Boolean, true] => true, + [PreludeSDK::Internal::Type::Boolean, "true"] => "true", + [Integer, "1"] => "1", + [Float, 1] => 1, + [String, "one"] => "one", + [String, :one] => :one, + [:a, :b] => :b, + [:a, "a"] => "a", + [String, StringIO.new("one")] => "one", + [String, Pathname(__FILE__)] => PreludeSDK::FilePart + } + + cases.each do + target, input = _1 + expect = _2 + assert_pattern do + PreludeSDK::Internal::Type::Converter.dump(target, input) => ^expect + end + end + end + + def test_coerce_errors + cases = { + [Integer, "one"] => ArgumentError, + [Float, "one"] => ArgumentError, + [String, Time] => TypeError, + [Date, "one"] => ArgumentError, + [Time, "one"] => ArgumentError + } + + cases.each do |testcase, expect| + target, input = testcase + state = PreludeSDK::Internal::Type::Converter.new_coerce_state + PreludeSDK::Internal::Type::Converter.coerce(target, input, state: state) + assert_pattern do + state => {error: ^expect} + end + end + end + + def test_dump_retry + types = [ + PreludeSDK::Internal::Type::Unknown, + PreludeSDK::Internal::Type::Boolean, + A, + H, + E, + U, + B + ] + Pathname(__FILE__).open do |fd| + cases = [ + fd, + [fd], + {a: fd}, + {a: {b: fd}} + ] + types.product(cases).each do |target, input| + state = {can_retry: true} + PreludeSDK::Internal::Type::Converter.dump(target, input, state: state) + + assert_pattern do + state => {can_retry: false} + end + end + end + end +end + +class PreludeSDK::Test::EnumModelTest < Minitest::Test + class E0 + include PreludeSDK::Internal::Type::Enum + attr_reader :values + + def initialize(*values) = (@values = values) + end + + module E1 + extend PreludeSDK::Internal::Type::Enum + + TRUE = true + end + + module E2 + extend PreludeSDK::Internal::Type::Enum + + ONE = 1 + TWO = 2 + end + + module E3 + extend PreludeSDK::Internal::Type::Enum + + ONE = 1.0 + TWO = 2.0 + end + + module E4 + extend PreludeSDK::Internal::Type::Enum + + ONE = :one + TWO = :two + end + + def test_coerce + cases = { + [E0.new, "one"] => [{no: 1}, "one"], + [E0.new(:one), "one"] => [{yes: 1}, :one], + [E0.new(:two), "one"] => [{maybe: 1}, "one"], + + [E1, true] => [{yes: 1}, true], + [E1, false] => [{no: 1}, false], + [E1, :true] => [{no: 1}, :true], + + [E2, 1] => [{yes: 1}, 1], + [E2, 1.0] => [{yes: 1}, 1], + [E2, 1.2] => [{no: 1}, 1.2], + [E2, "1"] => [{no: 1}, "1"], + + [E3, 1.0] => [{yes: 1}, 1.0], + [E3, 1] => [{yes: 1}, 1.0], + [E3, "one"] => [{no: 1}, "one"], + + [E4, :one] => [{yes: 1}, :one], + [E4, "one"] => [{yes: 1}, :one], + [E4, "1"] => [{maybe: 1}, "1"], + [E4, :"1"] => [{maybe: 1}, :"1"], + [E4, 1] => [{no: 1}, 1] + } + + cases.each do |lhs, rhs| + target, input = lhs + exactness, expect = rhs + state = PreludeSDK::Internal::Type::Converter.new_coerce_state + assert_pattern do + PreludeSDK::Internal::Type::Converter.coerce(target, input, state: state) => ^expect + state.fetch(:exactness).filter { _2.nonzero? }.to_h => ^exactness + end + end + end + + def test_dump + cases = { + [E1, true] => true, + [E1, "true"] => "true", + + [E2, 1.0] => 1.0, + [E2, 3] => 3, + [E2, "1.0"] => "1.0", + + [E3, 1.0] => 1.0, + [E3, 3] => 3, + [E3, "1.0"] => "1.0", + + [E4, :one] => :one, + [E4, "one"] => "one", + [E4, "1.0"] => "1.0" + } + + cases.each do + target, input = _1 + expect = _2 + assert_pattern do + PreludeSDK::Internal::Type::Converter.dump(target, input) => ^expect + end + end + end +end + +class PreludeSDK::Test::CollectionModelTest < Minitest::Test + A1 = PreludeSDK::Internal::Type::ArrayOf[-> { Integer }] + H1 = PreludeSDK::Internal::Type::HashOf[Integer] + + A2 = PreludeSDK::Internal::Type::ArrayOf[H1] + H2 = PreludeSDK::Internal::Type::HashOf[-> { A1 }] + + A3 = PreludeSDK::Internal::Type::ArrayOf[Integer, nil?: true] + H3 = PreludeSDK::Internal::Type::HashOf[Integer, nil?: true] + + def test_coerce + cases = { + [A1, []] => [{yes: 1}, []], + [A1, {}] => [{no: 1}, {}], + [A1, [1, 2.0]] => [{yes: 2, maybe: 1}, [1, 2]], + [A1, ["1", 2.0]] => [{yes: 1, maybe: 2}, [1, 2]], + [H1, {}] => [{yes: 1}, {}], + [H1, []] => [{no: 1}, []], + [H1, {a: 1, b: 2}] => [{yes: 3}, {a: 1, b: 2}], + [H1, {"a" => 1, "b" => 2}] => [{yes: 3}, {a: 1, b: 2}], + [H1, {[] => 1}] => [{yes: 2, no: 1}, {[] => 1}], + [H1, {a: 1.5}] => [{yes: 1, maybe: 1}, {a: 1}], + + [A2, [{}, {"a" => 1}]] => [{yes: 4}, [{}, {a: 1}]], + [A2, [{"a" => "1"}]] => [{yes: 2, maybe: 1}, [{a: 1}]], + [H2, {a: [1, 2]}] => [{yes: 4}, {a: [1, 2]}], + [H2, {"a" => ["1", 2]}] => [{yes: 3, maybe: 1}, {a: [1, 2]}], + [H2, {"a" => ["one", 2]}] => [{yes: 3, no: 1}, {a: ["one", 2]}], + + [A3, [nil, 1]] => [{yes: 3}, [nil, 1]], + [A3, [nil, "1"]] => [{yes: 2, maybe: 1}, [nil, 1]], + [H3, {a: nil, b: "1"}] => [{yes: 2, maybe: 1}, {a: nil, b: 1}], + [H3, {a: nil}] => [{yes: 2}, {a: nil}] + } + + cases.each do |lhs, rhs| + target, input = lhs + exactness, expect = rhs + state = PreludeSDK::Internal::Type::Converter.new_coerce_state + assert_pattern do + PreludeSDK::Internal::Type::Converter.coerce(target, input, state: state) => ^expect + state.fetch(:exactness).filter { _2.nonzero? }.to_h => ^exactness + end + end + end +end + +class PreludeSDK::Test::BaseModelTest < Minitest::Test + class M1 < PreludeSDK::Internal::Type::BaseModel + required :a, Integer + end + + class M2 < M1 + required :a, Time + required :b, Integer, nil?: true + optional :c, String + end + + class M3 < PreludeSDK::Internal::Type::BaseModel + optional :c, const: :c + required :d, const: :d + end + + class M4 < M1 + request_only do + required :a, Integer + optional :b, String + end + + response_only do + required :c, Integer + optional :d, String + end + end + + class M5 < PreludeSDK::Internal::Type::BaseModel + request_only do + required :c, const: :c + end + + response_only do + required :d, const: :d + end + end + + class M6 < M1 + required :a, PreludeSDK::Internal::Type::ArrayOf[M6] + optional :b, M6 + end + + def test_coerce + cases = { + [M1, {}] => [{yes: 1, no: 1}, {}], + [M1, :m1] => [{no: 1}, :m1], + + [M2, {}] => [{yes: 2, no: 1, maybe: 1}, {}], + [M2, {a: "1990-09-19", b: nil}] => [{yes: 4}, {a: "1990-09-19", b: nil}], + [M2, {a: "1990-09-19", b: "1"}] => [{yes: 3, maybe: 1}, {a: "1990-09-19", b: "1"}], + [M2, {a: "1990-09-19"}] => [{yes: 3, maybe: 1}, {a: "1990-09-19"}], + [M2, {a: "1990-09-19", c: nil}] => [{yes: 2, maybe: 2}, {a: "1990-09-19", c: nil}], + + [M3, {c: "c", d: "d"}] => [{yes: 3}, {c: :c, d: :d}], + [M3, {c: "d", d: "c"}] => [{yes: 1, maybe: 2}, {c: "d", d: "c"}], + + [M4, {c: 2}] => [{yes: 5}, {c: 2}], + [M4, {a: "1", c: 2}] => [{yes: 4, maybe: 1}, {a: "1", c: 2}], + [M4, {b: nil, c: 2}] => [{yes: 4, maybe: 1}, {b: nil, c: 2}], + + [M5, {}] => [{yes: 3}, {}], + [M5, {c: "c"}] => [{yes: 3}, {c: :c}], + [M5, {d: "d"}] => [{yes: 3}, {d: :d}], + [M5, {d: nil}] => [{yes: 2, no: 1}, {d: nil}], + + [M6, {a: [{a: []}]}] => [{yes: 6}, -> { _1 in {a: [M6]} }], + [M6, {b: {a: []}}] => [{yes: 4, no: 1}, -> { _1 in {b: M6} }] + } + + cases.each do |lhs, rhs| + target, input = lhs + exactness, expect = rhs + state = PreludeSDK::Internal::Type::Converter.new_coerce_state + assert_pattern do + coerced = PreludeSDK::Internal::Type::Converter.coerce(target, input, state: state) + assert_equal(coerced, coerced) + if coerced.is_a?(PreludeSDK::Internal::Type::BaseModel) + coerced.to_h => ^expect + else + coerced => ^expect + end + state.fetch(:exactness).filter { _2.nonzero? }.to_h => ^exactness + end + end + end + + def test_dump + cases = { + [M3, M3.new] => {d: :d}, + [M3, {}] => {d: :d}, + [M3, {d: 1}] => {d: 1}, + + [M4, M4.new(a: 1, b: "b", c: 2, d: "d")] => {a: 1, b: "b"}, + [M4, {a: 1, b: "b", c: 2, d: "d"}] => {a: 1, b: "b"}, + + [M5, M5.new] => {c: :c}, + [M5, {}] => {c: :c}, + [M5, {c: 1}] => {c: 1} + } + + cases.each do + target, input = _1 + expect = _2 + assert_pattern do + PreludeSDK::Internal::Type::Converter.dump(target, input) => ^expect + end + end + end + + def test_accessors + cases = { + M2.new({a: "1990-09-19", b: "1"}) => [{a: "1990-09-19", b: "1"}, {a: Time.new(1990, 9, 19), b: 1}], + M2.new(a: "one", b: "one") => [{a: "one", b: "one"}, {a: ArgumentError, b: ArgumentError}], + M2.new(a: nil, b: 2.0) => [{a: nil, b: 2.0}, {a: TypeError}], + M2.new(a: nil, b: 2.2) => [{a: nil, b: 2.2}, {a: TypeError, b: 2}], + + M3.new => [{}, {d: :d}], + M3.new(d: 1) => [{d: 1}, {d: ArgumentError}], + + M5.new => [{}, {c: :c, d: :d}] + } + + cases.each do + target = _1 + data, attributes = _2 + + assert_pattern do + target.to_h => ^data + end + + attributes.each do |accessor, expect| + case expect + in Class if expect <= StandardError + tap do + target.public_send(accessor) + flunk + rescue PreludeSDK::Errors::ConversionError => e + assert_kind_of(expect, e.cause) + end + else + assert_pattern { target.public_send(accessor) => ^expect } + end + end + end + end + + def test_inplace_modification + m1 = M6.new(a: []) + m1.a << M6.new(a: []) + + m2 = M6.new(b: M6.new(a: [])) + m2.b.a << M6.new(a: []) + + m3 = M6.new(a: []) + m4 = M6.new(b: m3) + m3.a << M6.new(a: []) + + assert_pattern do + m1 => {a: [{a: []}]} + m2 => {b: {a: [{a: []}]}} + m4 => {b: {a: [{a: []}]}} + end + end +end + +class PreludeSDK::Test::UnionTest < Minitest::Test + class U0 + include PreludeSDK::Internal::Type::Union + + def initialize(*variants) = variants.each { variant(_1) } + end + + module U1 + extend PreludeSDK::Internal::Type::Union + variant const: :a + variant const: 2 + end + + class M1 < PreludeSDK::Internal::Type::BaseModel + required :t, const: :a, api_name: :type + optional :c, String + end + + class M2 < PreludeSDK::Internal::Type::BaseModel + required :type, const: :b + optional :c, String + end + + module U2 + extend PreludeSDK::Internal::Type::Union + discriminator :type + + variant :a, M1 + variant :b, M2 + end + + module U3 + extend PreludeSDK::Internal::Type::Union + discriminator :type + + variant :a, M1 + variant String + end + + module U4 + extend PreludeSDK::Internal::Type::Union + discriminator :type + + variant String + variant :a, M1 + end + + class M3 < PreludeSDK::Internal::Type::BaseModel + optional :recur, -> { U5 } + required :a, Integer + end + + class M4 < PreludeSDK::Internal::Type::BaseModel + optional :recur, -> { U5 } + required :a, PreludeSDK::Internal::Type::ArrayOf[-> { U5 }] + end + + class M5 < PreludeSDK::Internal::Type::BaseModel + optional :recur, -> { U5 } + required :b, PreludeSDK::Internal::Type::ArrayOf[-> { U5 }] + end + + module U5 + extend PreludeSDK::Internal::Type::Union + + variant -> { M3 } + variant -> { M4 } + end + + module U6 + extend PreludeSDK::Internal::Type::Union + + variant -> { M3 } + variant -> { M5 } + end + + def test_accessors + model = M3.new(recur: []) + tap do + model.recur + flunk + rescue PreludeSDK::Errors::ConversionError => e + assert_kind_of(ArgumentError, e.cause) + end + end + + def test_coerce + cases = { + [U0, :""] => [{no: 1}, 0, :""], + + [U0.new(Integer, Float), "one"] => [{no: 1}, 2, "one"], + [U0.new(Integer, Float), 1.0] => [{yes: 1}, 2, 1.0], + [U0.new({const: :a}), "a"] => [{yes: 1}, 1, :a], + [U0.new({const: :a}), "2"] => [{maybe: 1}, 1, "2"], + + [U1, "a"] => [{yes: 1}, 1, :a], + [U1, "2"] => [{maybe: 1}, 2, "2"], + [U1, :b] => [{maybe: 1}, 2, :b], + + [U2, {type: :a}] => [{yes: 3}, 0, {t: :a}], + [U2, {type: "b"}] => [{yes: 3}, 0, {type: :b}], + + [U3, "one"] => [{yes: 1}, 2, "one"], + [U4, "one"] => [{yes: 1}, 1, "one"], + + [U5, {a: []}] => [{yes: 3}, 2, {a: []}], + [U6, {b: []}] => [{yes: 3}, 2, {b: []}], + + [U5, {a: [{a: []}]}] => [{yes: 6}, 4, {a: [M4.new(a: [])]}], + [U5, {a: [{a: [{a: []}]}]}] => [{yes: 9}, 6, {a: [M4.new(a: [M4.new(a: [])])]}] + } + + cases.each do |lhs, rhs| + target, input = lhs + exactness, branched, expect = rhs + state = PreludeSDK::Internal::Type::Converter.new_coerce_state + assert_pattern do + coerced = PreludeSDK::Internal::Type::Converter.coerce(target, input, state: state) + assert_equal(coerced, coerced) + if coerced.is_a?(PreludeSDK::Internal::Type::BaseModel) + coerced.to_h => ^expect + else + coerced => ^expect + end + state.fetch(:exactness).filter { _2.nonzero? }.to_h => ^exactness + state => {branched: ^branched} + end + end + end +end + +class PreludeSDK::Test::BaseModelQoLTest < Minitest::Test + class E0 + include PreludeSDK::Internal::Type::Enum + attr_reader :values + + def initialize(*values) = (@values = values) + end + + module E1 + extend PreludeSDK::Internal::Type::Enum + + A = 1 + end + + module E2 + extend PreludeSDK::Internal::Type::Enum + + A = 1 + end + + module E3 + extend PreludeSDK::Internal::Type::Enum + + A = 2 + B = 3 + end + + class U0 + include PreludeSDK::Internal::Type::Union + + def initialize(*variants) = variants.each { variant(_1) } + end + + module U1 + extend PreludeSDK::Internal::Type::Union + + variant String + variant Integer + end + + module U2 + extend PreludeSDK::Internal::Type::Union + + variant String + variant Integer + end + + class M1 < PreludeSDK::Internal::Type::BaseModel + required :a, Integer + end + + class M2 < PreludeSDK::Internal::Type::BaseModel + required :a, Integer, nil?: true + end + + class M3 < M2 + required :a, Integer + end + + def test_equality + cases = { + [PreludeSDK::Internal::Type::Unknown, PreludeSDK::Internal::Type::Unknown] => true, + [PreludeSDK::Internal::Type::Boolean, PreludeSDK::Internal::Type::Boolean] => true, + [PreludeSDK::Internal::Type::Unknown, PreludeSDK::Internal::Type::Boolean] => false, + [E0.new(:a, :b), E0.new(:a, :b)] => true, + [E0.new(:a, :b), E0.new(:b, :a)] => true, + [E0.new(:a, :b), E0.new(:b, :c)] => false, + [E1, E2] => true, + [E1, E3] => false, + [U0.new(String, Integer), U0.new(String, Integer)] => true, + [U0.new(String, Integer), U0.new(Integer, String)] => false, + [U0.new(String, Float), U0.new(String, Integer)] => false, + [U1, U2] => true, + [M1, M2] => false, + [M1, M3] => true, + [M1.new(a: 1), M1.new(a: 1)] => true + } + + cases.each do + if _2 + assert_equal(*_1) + assert_equal(*_1.map(&:hash)) + else + refute_equal(*_1) + refute_equal(*_1.map(&:hash)) + end + end + end +end diff --git a/test/prelude_sdk/internal/util_test.rb b/test/prelude_sdk/internal/util_test.rb new file mode 100644 index 00000000..dc69c004 --- /dev/null +++ b/test/prelude_sdk/internal/util_test.rb @@ -0,0 +1,598 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +class PreludeSDK::Test::UtilDataHandlingTest < Minitest::Test + def test_left_map + assert_pattern do + PreludeSDK::Internal::Util.deep_merge({a: 1}, nil) => nil + end + end + + def test_right_map + assert_pattern do + PreludeSDK::Internal::Util.deep_merge(nil, {a: 1}) => {a: 1} + end + end + + def test_disjoint_maps + assert_pattern do + PreludeSDK::Internal::Util.deep_merge({b: 2}, {a: 1}) => {a: 1, b: 2} + end + end + + def test_overlapping_maps + assert_pattern do + PreludeSDK::Internal::Util.deep_merge({b: 2, c: 3}, {a: 1, c: 4}) => {a: 1, b: 2, c: 4} + end + end + + def test_nested + assert_pattern do + PreludeSDK::Internal::Util.deep_merge({b: {b2: 1}}, {b: {b2: 2}}) => {b: {b2: 2}} + end + end + + def test_nested_left_map + assert_pattern do + PreludeSDK::Internal::Util.deep_merge({b: {b2: 1}}, {b: 6}) => {b: 6} + end + end + + def test_omission + merged = PreludeSDK::Internal::Util.deep_merge( + {b: {b2: 1, b3: {c: 4, d: 5}}}, + {b: {b2: 1, b3: {c: PreludeSDK::Internal::OMIT, d: 5}}} + ) + + assert_pattern do + merged => {b: {b2: 1, b3: {d: 5}}} + end + end + + def test_concat + merged = PreludeSDK::Internal::Util.deep_merge( + {a: {b: [1, 2]}}, + {a: {b: [3, 4]}}, + concat: true + ) + + assert_pattern do + merged => {a: {b: [1, 2, 3, 4]}} + end + end + + def test_concat_false + merged = PreludeSDK::Internal::Util.deep_merge( + {a: {b: [1, 2]}}, + {a: {b: [3, 4]}}, + concat: false + ) + + assert_pattern do + merged => {a: {b: [3, 4]}} + end + end + + def test_dig + assert_pattern do + PreludeSDK::Internal::Util.dig(1, nil) => 1 + PreludeSDK::Internal::Util.dig({a: 1}, :b) => nil + PreludeSDK::Internal::Util.dig({a: 1}, :a) => 1 + PreludeSDK::Internal::Util.dig({a: {b: 1}}, [:a, :b]) => 1 + + PreludeSDK::Internal::Util.dig([], 1) => nil + PreludeSDK::Internal::Util.dig([nil, [nil, 1]], [1, 1]) => 1 + PreludeSDK::Internal::Util.dig({a: [nil, 1]}, [:a, 1]) => 1 + PreludeSDK::Internal::Util.dig([], 1.0) => nil + + PreludeSDK::Internal::Util.dig(Object, 1) => nil + PreludeSDK::Internal::Util.dig([], 1.0) { 2 } => 2 + PreludeSDK::Internal::Util.dig([], ->(_) { 2 }) => 2 + PreludeSDK::Internal::Util.dig([1], -> { _1 in [1] }) => true + end + end +end + +class PreludeSDK::Test::UtilUriHandlingTest < Minitest::Test + def test_parsing + %w[ + http://example.com + https://example.com/ + https://example.com:443/example?e1=e1&e2=e2&e= + ].each do |url| + parsed = PreludeSDK::Internal::Util.parse_uri(url) + unparsed = PreludeSDK::Internal::Util.unparse_uri(parsed).to_s + + assert_equal(url, unparsed) + assert_equal(parsed, PreludeSDK::Internal::Util.parse_uri(unparsed)) + end + end + + def test_joining + cases = [ + [ + "h://a.b/c?d=e", + "h://nope/ignored", + PreludeSDK::Internal::Util.parse_uri("h://a.b/c?d=e") + ], + [ + "h://a.b/c?d=e", + "h://nope", + { + host: "a.b", + path: "/c", + query: {"d" => ["e"]} + } + ] + ] + + cases.each do |expect, lhs, rhs| + assert_equal( + URI.parse(expect), + PreludeSDK::Internal::Util.join_parsed_uri( + PreludeSDK::Internal::Util.parse_uri(lhs), + rhs + ) + ) + end + end + + def test_joining_queries + base_url = "h://a.b/c?d=e" + cases = { + "c2" => "h://a.b/c/c2", + "/c2?f=g" => "h://a.b/c2?f=g", + "/c?f=g" => "h://a.b/c?d=e&f=g" + } + + cases.each do |path, expected| + assert_equal( + URI.parse(expected), + PreludeSDK::Internal::Util.join_parsed_uri( + PreludeSDK::Internal::Util.parse_uri(base_url), + {path: path} + ) + ) + end + end +end + +class PreludeSDK::Test::RegexMatchTest < Minitest::Test + def test_json_content + cases = { + "application/json" => true, + "application/jsonl" => false, + "application/vnd.github.v3+json" => true, + "application/vnd.api+json" => true + } + cases.each do |header, verdict| + assert_pattern do + PreludeSDK::Internal::Util::JSON_CONTENT.match?(header) => ^verdict + end + end + end + + def test_jsonl_content + cases = { + "application/x-ndjson" => true, + "application/x-ldjson" => true, + "application/jsonl" => true, + "application/x-jsonl" => true, + "application/json" => false, + "application/vnd.api+json" => false + } + cases.each do |header, verdict| + assert_pattern do + PreludeSDK::Internal::Util::JSONL_CONTENT.match?(header) => ^verdict + end + end + end +end + +class PreludeSDK::Test::UtilFormDataEncodingTest < Minitest::Test + class FakeCGI < CGI + def initialize(headers, io) + encoded = io.to_a + @ctype = headers["content-type"] + # rubocop:disable Lint/EmptyBlock + @io = PreludeSDK::Internal::Util::ReadIOAdapter.new(encoded.to_enum) {} + # rubocop:enable Lint/EmptyBlock + @c_len = encoded.join.bytesize.to_s + super() + end + + def stdinput = @io + + def env_table + { + "REQUEST_METHOD" => "POST", + "CONTENT_TYPE" => @ctype, + "CONTENT_LENGTH" => @c_len + } + end + end + + def test_file_encode + file = Pathname(__FILE__) + headers = {"content-type" => "multipart/form-data"} + cases = { + "abc" => "abc", + StringIO.new("abc") => "abc", + PreludeSDK::FilePart.new("abc") => "abc", + PreludeSDK::FilePart.new(StringIO.new("abc")) => "abc", + file => /^class PreludeSDK/, + PreludeSDK::FilePart.new(file) => /^class PreludeSDK/ + } + cases.each do |body, val| + encoded = PreludeSDK::Internal::Util.encode_content(headers, body) + cgi = FakeCGI.new(*encoded) + assert_pattern do + cgi[""].read => ^val + end + end + end + + def test_hash_encode + headers = {"content-type" => "multipart/form-data"} + cases = { + {a: 2, b: 3} => {"a" => "2", "b" => "3"}, + {a: 2, b: nil} => {"a" => "2", "b" => "null"}, + {a: 2, b: [1, 2, 3]} => {"a" => "2", "b" => "1"}, + {strio: StringIO.new("a")} => {"strio" => "a"}, + {strio: PreludeSDK::FilePart.new("a")} => {"strio" => "a"}, + {pathname: Pathname(__FILE__)} => {"pathname" => -> { _1.read in /^class PreludeSDK/ }}, + {pathname: PreludeSDK::FilePart.new(Pathname(__FILE__))} => { + "pathname" => -> { + _1.read in /^class PreludeSDK/ + } + } + } + cases.each do |body, testcase| + encoded = PreludeSDK::Internal::Util.encode_content(headers, body) + cgi = FakeCGI.new(*encoded) + testcase.each do |key, val| + assert_pattern do + cgi[key] => ^val + end + end + end + end +end + +class PreludeSDK::Test::UtilIOAdapterTest < Minitest::Test + def test_copy_read + cases = { + StringIO.new("abc") => "abc", + Enumerator.new { _1 << "abc" } => "abc" + } + cases.each do |input, expected| + io = StringIO.new + # rubocop:disable Lint/EmptyBlock + adapter = PreludeSDK::Internal::Util::ReadIOAdapter.new(input) {} + # rubocop:enable Lint/EmptyBlock + IO.copy_stream(adapter, io) + assert_equal(expected, io.string) + end + end + + def test_copy_write + cases = { + StringIO.new => "", + StringIO.new("abc") => "abc" + } + cases.each do |input, expected| + enum = PreludeSDK::Internal::Util.writable_enum do |y| + IO.copy_stream(input, y) + end + assert_equal(expected, enum.to_a.join) + end + end +end + +class PreludeSDK::Test::UtilFusedEnumTest < Minitest::Test + def test_closing + arr = [1, 2, 3] + once = 0 + fused = PreludeSDK::Internal::Util.fused_enum(arr.to_enum) do + once = once.succ + end + + enumerated_1 = fused.to_a + assert_equal(arr, enumerated_1) + assert_equal(1, once) + + enumerated_2 = fused.to_a + assert_equal([], enumerated_2) + assert_equal(1, once) + end + + def test_rewind_chain + once = 0 + fused = PreludeSDK::Internal::Util.fused_enum([1, 2, 3].to_enum) do + once = once.succ + end + .lazy + .map(&:succ) + .filter(&:odd?) + first = fused.next + + assert_equal(3, first) + assert_equal(0, once) + assert_raises(StopIteration) { fused.rewind.next } + assert_equal(1, once) + end + + def test_external_iteration + it = [1, 2, 3].to_enum + first = it.next + fused = PreludeSDK::Internal::Util.fused_enum(it, external: true) + + assert_equal(1, first) + assert_equal([2, 3], fused.to_a) + end + + def test_close_fused + once = 0 + fused = PreludeSDK::Internal::Util.fused_enum([1, 2, 3].to_enum) do + once = once.succ + end + + PreludeSDK::Internal::Util.close_fused!(fused) + + assert_equal(1, once) + assert_equal([], fused.to_a) + assert_equal(1, once) + end + + def test_closed_fused_extern_iteration + taken = 0 + enum = [1, 2, 3].to_enum.lazy.map do + taken = taken.succ + _1 + end + fused = PreludeSDK::Internal::Util.fused_enum(enum) + first = fused.next + + assert_equal(1, first) + PreludeSDK::Internal::Util.close_fused!(fused) + assert_equal(1, taken) + end + + def test_closed_fused_taken_count + taken = 0 + enum = [1, 2, 3].to_enum.lazy.map do + taken = taken.succ + _1 + end + .map(&:succ) + .filter(&:odd?) + fused = PreludeSDK::Internal::Util.fused_enum(enum) + + assert_equal(0, taken) + PreludeSDK::Internal::Util.close_fused!(fused) + assert_equal(0, taken) + end + + def test_closed_fused_extern_iter_taken_count + taken = 0 + enum = [1, 2, 3].to_enum.lazy.map do + taken = taken.succ + _1 + end + .map(&:succ) + .filter(&:itself) + first = enum.next + assert_equal(2, first) + assert_equal(1, taken) + + fused = PreludeSDK::Internal::Util.fused_enum(enum) + PreludeSDK::Internal::Util.close_fused!(fused) + assert_equal(1, taken) + end + + def test_close_fused_sse_chain + taken = 0 + enum = [1, 2, 3].to_enum.lazy.map do + taken = taken.succ + _1 + end + .map(&:succ) + .filter(&:odd?) + .map(&:to_s) + + fused_1 = PreludeSDK::Internal::Util.fused_enum(enum) + fused_2 = PreludeSDK::Internal::Util.decode_lines(fused_1) + fused_3 = PreludeSDK::Internal::Util.decode_sse(fused_2) + + assert_equal(0, taken) + PreludeSDK::Internal::Util.close_fused!(fused_3) + assert_equal(0, taken) + end +end + +class PreludeSDK::Test::UtilContentDecodingTest < Minitest::Test + def test_charset + cases = { + "application/json" => Encoding::BINARY, + "application/json; charset=utf-8" => Encoding::UTF_8, + "charset=uTf-8 application/json; " => Encoding::UTF_8, + "charset=UTF-8; application/json; " => Encoding::UTF_8, + "charset=ISO-8859-1 ;application/json; " => Encoding::ISO_8859_1, + "charset=EUC-KR ;application/json; " => Encoding::EUC_KR + } + text = String.new.force_encoding(Encoding::BINARY) + cases.each do |content_type, encoding| + PreludeSDK::Internal::Util.force_charset!(content_type, text: text) + assert_equal(encoding, text.encoding) + end + end +end + +class PreludeSDK::Test::UtilSseTest < Minitest::Test + def test_decode_lines + cases = { + %w[] => %w[], + %W[\n\n] => %W[\n \n], + %W[\n \n] => %W[\n \n], + %w[a] => %w[a], + %W[a\nb] => %W[a\n b], + %W[a\nb\n] => %W[a\n b\n], + %W[\na b\n] => %W[\n ab\n], + %W[\na b\n\n] => %W[\n ab\n \n], + %W[\na b] => %W[\n ab], + %W[\u1F62E\u200D\u1F4A8] => %W[\u1F62E\u200D\u1F4A8], + %W[\u1F62E \u200D \u1F4A8] => %W[\u1F62E\u200D\u1F4A8], + ["\xf0\x9f".b, "\xa5\xba".b] => ["\xf0\x9f\xa5\xba".b], + ["\xf0".b, "\x9f".b, "\xa5".b, "\xba".b] => ["\xf0\x9f\xa5\xba".b] + } + eols = %W[\n \r \r\n] + cases.each do |enum, expected| + eols.each do |eol| + lines = PreludeSDK::Internal::Util.decode_lines(enum.map { _1.gsub("\n", eol) }) + assert_equal(expected.map { _1.gsub("\n", eol) }, lines.to_a, "eol=#{JSON.generate(eol)}") + end + end + end + + def test_mixed_decode_lines + cases = { + %w[] => %w[], + %W[\r\r] => %W[\r \r], + %W[\r \r] => %W[\r \r], + %W[\r\r\r] => %W[\r \r \r], + %W[\r\r \r] => %W[\r \r \r], + %W[\r \n] => %W[\r\n], + %W[\r\r\n] => %W[\r \r\n], + %W[\n\r] => %W[\n \r] + } + cases.each do |enum, expected| + lines = PreludeSDK::Internal::Util.decode_lines(enum) + assert_equal(expected, lines.to_a) + end + end + + def test_decode_sse + cases = { + "empty input" => { + [] => [] + }, + "single data event" => { + [ + "data: hello world\n", + "\n" + ] => [ + {data: "hello world\n"} + ] + }, + "multiple data lines" => { + [ + "data: line 1\n", + "data: line 2\n", + "\n" + ] => [ + {data: "line 1\nline 2\n"} + ] + }, + "complete event" => { + [ + "id: 123\n", + "event: update\n", + "data: hello world\n", + "retry: 5000\n", + "\n" + ] => [ + { + event: "update", + id: "123", + data: "hello world\n", + retry: 5000 + } + ] + }, + "multiple events" => { + [ + "event: update\n", + "data: first\n", + "\n", + "event: message\n", + "data: second\n", + "\n" + ] => [ + {event: "update", data: "first\n"}, + {event: "message", data: "second\n"} + ] + }, + "comments" => { + [ + ": this is a comment\n", + "data: actual data\n", + "\n" + ] => [ + {data: "actual data\n"} + ] + }, + "invalid retry" => { + [ + "retry: not a number\n", + "data: hello\n", + "\n" + ] => [ + {data: "hello\n"} + ] + }, + "invalid id with null" => { + [ + "id: bad\0id\n", + "data: hello\n", + "\n" + ] => [ + {data: "hello\n"} + ] + }, + "leading space in value" => { + [ + "data: hello world\n", + "data: leading space\n", + "\n" + ] => [ + {data: "hello world\n leading space\n"} + ] + }, + "no final newline" => { + [ + "data: hello\n", + "id: 1" + ] => [ + {data: "hello\n", id: "1"} + ] + }, + "multiple empty lines" => { + [ + "data: first\n", + "\n", + "\n", + "data: second\n", + "\n" + ] => [ + {data: "first\n"}, + {data: "second\n"} + ] + }, + "multibyte unicode" => { + [ + "data: \u1F62E\u200D\u1F4A8\n" + ] => [ + {data: "\u1F62E\u200D\u1F4A8\n"} + ] + } + } + + cases.each do |name, test_cases| + test_cases.each do |input, expected| + actual = PreludeSDK::Internal::Util.decode_sse(input).map(&:compact) + assert_equal(expected, actual, name) + end + end + end +end diff --git a/test/prelude/test_namespaces.rb b/test/prelude_sdk/resource_namespaces.rb similarity index 82% rename from test/prelude/test_namespaces.rb rename to test/prelude_sdk/resource_namespaces.rb index 12bd3de2..2ed01f93 100644 --- a/test/prelude/test_namespaces.rb +++ b/test/prelude_sdk/resource_namespaces.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Prelude +module PreludeSDK module Test module Resources end diff --git a/test/prelude_sdk/resources/lookup_test.rb b/test/prelude_sdk/resources/lookup_test.rb new file mode 100644 index 00000000..628ab1ba --- /dev/null +++ b/test/prelude_sdk/resources/lookup_test.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +class PreludeSDK::Test::Resources::LookupTest < PreludeSDK::Test::ResourceTest + def test_lookup + response = @prelude.lookup.lookup("+12065550100") + + assert_pattern do + response => PreludeSDK::Models::LookupLookupResponse + end + + assert_pattern do + response => { + caller_name: String | nil, + country_code: String | nil, + flags: ^(PreludeSDK::Internal::Type::ArrayOf[enum: PreludeSDK::Models::LookupLookupResponse::Flag]) | nil, + line_type: PreludeSDK::Models::LookupLookupResponse::LineType | nil, + network_info: PreludeSDK::Models::LookupLookupResponse::NetworkInfo | nil, + original_network_info: PreludeSDK::Models::LookupLookupResponse::OriginalNetworkInfo | nil, + phone_number: String | nil + } + end + end +end diff --git a/test/prelude_sdk/resources/transactional_test.rb b/test/prelude_sdk/resources/transactional_test.rb new file mode 100644 index 00000000..1714b7fe --- /dev/null +++ b/test/prelude_sdk/resources/transactional_test.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +class PreludeSDK::Test::Resources::TransactionalTest < PreludeSDK::Test::ResourceTest + def test_send__required_params + skip( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + + response = + @prelude.transactional.send_(template_id: "template_01jd1xq0cffycayqtdkdbv4d61", to: "+30123456789") + + assert_pattern do + response => PreludeSDK::Models::TransactionalSendResponse + end + + assert_pattern do + response => { + id: String, + created_at: Time, + expires_at: Time, + template_id: String, + to: String, + variables: ^(PreludeSDK::Internal::Type::HashOf[String]), + callback_url: String | nil, + correlation_id: String | nil, + from: String | nil + } + end + end +end diff --git a/test/prelude_sdk/resources/verification_test.rb b/test/prelude_sdk/resources/verification_test.rb new file mode 100644 index 00000000..9cf37f73 --- /dev/null +++ b/test/prelude_sdk/resources/verification_test.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +class PreludeSDK::Test::Resources::VerificationTest < PreludeSDK::Test::ResourceTest + def test_create_required_params + skip( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + + response = @prelude.verification.create(target: {type: :phone_number, value: "+30123456789"}) + + assert_pattern do + response => PreludeSDK::Models::VerificationCreateResponse + end + + assert_pattern do + response => { + id: String, + method_: PreludeSDK::Models::VerificationCreateResponse::Method, + status: PreludeSDK::Models::VerificationCreateResponse::Status, + channels: ^(PreludeSDK::Internal::Type::ArrayOf[String]) | nil, + metadata: PreludeSDK::Models::VerificationCreateResponse::Metadata | nil, + reason: PreludeSDK::Models::VerificationCreateResponse::Reason | nil, + request_id: String | nil, + silent: PreludeSDK::Models::VerificationCreateResponse::Silent | nil + } + end + end + + def test_check_required_params + response = + @prelude.verification.check(code: "12345", target: {type: :phone_number, value: "+30123456789"}) + + assert_pattern do + response => PreludeSDK::Models::VerificationCheckResponse + end + + assert_pattern do + response => { + status: PreludeSDK::Models::VerificationCheckResponse::Status, + id: String | nil, + metadata: PreludeSDK::Models::VerificationCheckResponse::Metadata | nil, + request_id: String | nil + } + end + end +end diff --git a/test/prelude_sdk/resources/watch_test.rb b/test/prelude_sdk/resources/watch_test.rb new file mode 100644 index 00000000..5c450ddb --- /dev/null +++ b/test/prelude_sdk/resources/watch_test.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +class PreludeSDK::Test::Resources::WatchTest < PreludeSDK::Test::ResourceTest + def test_predict_required_params + response = @prelude.watch.predict(target: {type: :phone_number, value: "+30123456789"}) + + assert_pattern do + response => PreludeSDK::Models::WatchPredictResponse + end + + assert_pattern do + response => { + id: String, + prediction: PreludeSDK::Models::WatchPredictResponse::Prediction, + request_id: String + } + end + end + + def test_send_events_required_params + response = + @prelude.watch.send_events( + events: [ + { + confidence: :maximum, + label: "onboarding.start", + target: {type: :phone_number, value: "+30123456789"} + } + ] + ) + + assert_pattern do + response => PreludeSDK::Models::WatchSendEventsResponse + end + + assert_pattern do + response => { + request_id: String, + status: PreludeSDK::Models::WatchSendEventsResponse::Status + } + end + end + + def test_send_feedbacks_required_params + response = + @prelude.watch.send_feedbacks( + feedbacks: [{target: {type: :phone_number, value: "+30123456789"}, type: :"verification.started"}] + ) + + assert_pattern do + response => PreludeSDK::Models::WatchSendFeedbacksResponse + end + + assert_pattern do + response => { + request_id: String, + status: PreludeSDK::Models::WatchSendFeedbacksResponse::Status + } + end + end +end diff --git a/test/prelude_sdk/test_helper.rb b/test/prelude_sdk/test_helper.rb new file mode 100644 index 00000000..e8dea7f3 --- /dev/null +++ b/test/prelude_sdk/test_helper.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +# Requiring this file from each test file ensures we always do the following, even +# when running a single-file test: +# - Load the whole gem (as one would in production) +# - Define shared testing namespace so that we don't need to indent test files as much +# - Setting up testing dependencies + +require "digest" +require "singleton" + +require "async" +require "minitest/autorun" +require "minitest/focus" +require "minitest/hooks/test" +require "minitest/proveit" +require "minitest/rg" +require "webmock" + +require_relative "../../lib/prelude_sdk" +require_relative "resource_namespaces" + +module Kernel + alias_method :_sleep, :sleep + + def sleep(secs) + case Thread.current.thread_variable_get(:mock_sleep) + in Array => counter + counter << secs + secs + else + _sleep(secs) + end + end +end + +class Time + class << self + alias_method :_now, :now + end + + def self.now = Thread.current.thread_variable_get(:time_now) || _now +end + +class PreludeSDK::Test::SingletonClient < PreludeSDK::Client + include Singleton + + TEST_API_BASE_URL = ENV.fetch("TEST_API_BASE_URL", "http://localhost:4010") + + def initialize + super(base_url: PreludeSDK::Test::SingletonClient::TEST_API_BASE_URL, api_token: "My API Token") + end +end + +module Minitest::Serial + def test_order = :random + + def run_one_method(...) = Minitest::Runnable.run_one_method(...) +end + +class Minitest::Test + include Minitest::Hooks + + make_my_diffs_pretty! + parallelize_me! + prove_it! +end + +class PreludeSDK::Test::ResourceTest < Minitest::Test + def async? + return @async unless @async.nil? + @async = Digest::SHA256.hexdigest(self.class.name).to_i(16).odd? + end + + def before_all + super + @prelude = PreludeSDK::Test::SingletonClient.instance + end + + def around_all = async? ? Sync { super } : super + + def around = async? ? Async { super }.wait : super +end + +module WebMock + AssertionFailure.error_class = Minitest::Assertion +end