Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6eb6756
chore(tests): bump steady to v0.20.1
stainless-app[bot] Mar 31, 2026
4206b20
chore(tests): bump steady to v0.20.2
stainless-app[bot] Mar 31, 2026
cde1131
fix: variable name typo
stainless-app[bot] Mar 31, 2026
3e2268d
fix: align path encoding with RFC 3986 section 3.3
stainless-app[bot] Mar 31, 2026
4ff46f6
codegen metadata
stainless-app[bot] Apr 1, 2026
9b272e8
feat(api): added new unset preferences methods
stainless-app[bot] Apr 2, 2026
f710ae2
feat(api): api update
stainless-app[bot] Apr 6, 2026
0715076
fix: multipart encoding for file arrays
stainless-app[bot] Apr 8, 2026
3544679
codegen metadata
stainless-app[bot] Apr 9, 2026
52fa84d
codegen metadata
stainless-app[bot] Apr 9, 2026
e75ece0
codegen metadata
stainless-app[bot] Apr 10, 2026
cf7ad98
codegen metadata
stainless-app[bot] Apr 10, 2026
5b37b24
chore(tests): bump steady to v0.22.1
stainless-app[bot] Apr 17, 2026
1e34f54
feat(KNO-12791): Add workflow recipient run APIs
stainless-app[bot] Apr 21, 2026
1023475
chore(internal): more robust bootstrap script
stainless-app[bot] Apr 22, 2026
628d4cc
feat(api): api update
stainless-app[bot] Apr 22, 2026
da22d6e
feat(api): api update
stainless-app[bot] Apr 23, 2026
74dcf58
codegen metadata
stainless-app[bot] Apr 23, 2026
bd57879
feat(api): api update
stainless-app[bot] Apr 23, 2026
ad75b97
feat: support setting headers via env
stainless-app[bot] Apr 27, 2026
99888a2
codegen metadata
stainless-app[bot] Apr 29, 2026
14c7bc7
feat(api): api update
stainless-app[bot] Apr 30, 2026
99d03c1
codegen metadata
stainless-app[bot] Apr 30, 2026
75b292f
codegen metadata
stainless-app[bot] May 6, 2026
373e78b
feat(api): api update
stainless-app[bot] May 7, 2026
8c8ac76
codegen metadata
stainless-app[bot] May 12, 2026
95ff0e3
ci: pin GitHub Actions to commit SHAs
stainless-app[bot] May 12, 2026
4e8b8cf
fix(client): elide content type header on requests without body
stainless-app[bot] May 13, 2026
98b0385
codegen metadata
stainless-app[bot] May 14, 2026
76bdadc
feat(api): api update
stainless-app[bot] May 21, 2026
2d54bf7
feat(api): api update
stainless-app[bot] May 21, 2026
27e68a8
feat(api): api update
stainless-app[bot] May 28, 2026
cf13a4e
feat(api): api update
stainless-app[bot] May 29, 2026
9db1d9a
release: 1.36.0
stainless-app[bot] May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ jobs:
github.repository == 'stainless-sdks/knock-ruby' &&
(github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
with:
bundler-cache: false
- run: |-
Expand All @@ -39,7 +39,7 @@ jobs:
github.repository == 'stainless-sdks/knock-ruby' &&
!startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
uses: actions/github-script@v8
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setOutput('github_token', await core.getIDToken());

Expand All @@ -60,9 +60,9 @@ jobs:
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
with:
bundler-cache: false
- run: |-
Expand All @@ -76,9 +76,9 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/knock-ruby' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
with:
bundler-cache: false
- run: |-
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-gem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
with:
bundler-cache: false
- run: |-
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-doctor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
if: github.repository == 'knocklabs/knock-ruby' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Check release environment
run: |
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.35.0"
".": "1.36.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 90
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-c4b73cfc78e9b583cae6abe7c1f73caf2b81d9d8c4338819707f7089443b9754.yml
openapi_spec_hash: 8ee18f8419b62f10276dff5d35ee5f27
config_hash: 32503026a45db991d0d102f25af40a77
configured_endpoints: 94
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-49a6bd373e9b091c767273d512ca517d1452c1ab954230454534cab87a9e6a1b.yml
openapi_spec_hash: 7503066f9de54d7b8dbf50543b1b7929
config_hash: 625db64572b7ee0ee1dd00546e53fc5f
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
# Changelog

## 1.36.0 (2026-05-29)

Full Changelog: [v1.35.0...v1.36.0](https://github.com/knocklabs/knock-ruby/compare/v1.35.0...v1.36.0)

### Features

* **api:** added new unset preferences methods ([9b272e8](https://github.com/knocklabs/knock-ruby/commit/9b272e8ced5eb194a57d79ba442fba9539a0c0ef))
* **api:** api update ([cf13a4e](https://github.com/knocklabs/knock-ruby/commit/cf13a4eac94e30e2bd0256af75cb9547057890aa))
* **api:** api update ([27e68a8](https://github.com/knocklabs/knock-ruby/commit/27e68a833d6045919ff9b61ee416cd65078c2aa3))
* **api:** api update ([2d54bf7](https://github.com/knocklabs/knock-ruby/commit/2d54bf7fb14986bfcbe5a4f2cc4a797e65c8e670))
* **api:** api update ([76bdadc](https://github.com/knocklabs/knock-ruby/commit/76bdadc2b8b10eecfbe70ed14a8f6c040e27374e))
* **api:** api update ([373e78b](https://github.com/knocklabs/knock-ruby/commit/373e78b7f24449c77d98c0d05c897fdeb05641aa))
* **api:** api update ([14c7bc7](https://github.com/knocklabs/knock-ruby/commit/14c7bc73e1677dc239ac48035ee0b034709750ae))
* **api:** api update ([bd57879](https://github.com/knocklabs/knock-ruby/commit/bd578791c347de8b63caf60ba6340f19ac3a6a48))
* **api:** api update ([da22d6e](https://github.com/knocklabs/knock-ruby/commit/da22d6e5573c3f093d081edcb6881ac23fcf9173))
* **api:** api update ([628d4cc](https://github.com/knocklabs/knock-ruby/commit/628d4cc040ba05590a453be6824ea9329792f394))
* **api:** api update ([f710ae2](https://github.com/knocklabs/knock-ruby/commit/f710ae264c9e1acdcf36b41b93e49cd7a8ebaf12))
* **KNO-12791:** Add workflow recipient run APIs ([1e34f54](https://github.com/knocklabs/knock-ruby/commit/1e34f54ffff850939a1effd58cb9711b442d7a93))
* support setting headers via env ([ad75b97](https://github.com/knocklabs/knock-ruby/commit/ad75b97225fd6634d7850dde00d5035e64d168a2))


### Bug Fixes

* align path encoding with RFC 3986 section 3.3 ([3e2268d](https://github.com/knocklabs/knock-ruby/commit/3e2268d3e0547fa66ad253e35c86da963cc36215))
* **client:** elide content type header on requests without body ([4e8b8cf](https://github.com/knocklabs/knock-ruby/commit/4e8b8cfd2dbdd693a880d960df5e48baa29fce2b))
* multipart encoding for file arrays ([0715076](https://github.com/knocklabs/knock-ruby/commit/0715076b3cb219501a9bedd7a449f4cedef2babb))
* variable name typo ([cde1131](https://github.com/knocklabs/knock-ruby/commit/cde113151eb2879204409723971653616876fdee))


### Chores

* **internal:** more robust bootstrap script ([1023475](https://github.com/knocklabs/knock-ruby/commit/1023475aa6b6f5c04dae72aaf7ad397aa769e033))
* **tests:** bump steady to v0.20.1 ([6eb6756](https://github.com/knocklabs/knock-ruby/commit/6eb6756ef89a7b99a3825bd5ab899bf2f0b030e2))
* **tests:** bump steady to v0.20.2 ([4206b20](https://github.com/knocklabs/knock-ruby/commit/4206b20a8cd60362598da173185bbd236e659eff))
* **tests:** bump steady to v0.22.1 ([5b37b24](https://github.com/knocklabs/knock-ruby/commit/5b37b2467d9d996161d02d5df3bbdf703f51bad7))

## 1.35.0 (2026-03-27)

Full Changelog: [v1.34.0...v1.35.0](https://github.com/knocklabs/knock-ruby/compare/v1.34.0...v1.35.0)
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GIT
PATH
remote: .
specs:
knockapi (1.35.0)
knockapi (1.36.0)
cgi
connection_pool

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application
<!-- x-release-please-start-version -->

```ruby
gem "knockapi", "~> 1.35.0"
gem "knockapi", "~> 1.36.0"
```

<!-- x-release-please-end -->
Expand Down
8 changes: 8 additions & 0 deletions lib/knockapi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
require_relative "knockapi/models/recipients/channel_data_request"
require_relative "knockapi/models/recipients/preference_set_request"
require_relative "knockapi/models/identify_user_request"
require_relative "knockapi/models/workflow_recipient_run"
require_relative "knockapi/models/activity"
require_relative "knockapi/models/audience_add_members_params"
require_relative "knockapi/models/audience_list_members_params"
Expand Down Expand Up @@ -132,6 +133,7 @@
require_relative "knockapi/models/object_set_params"
require_relative "knockapi/models/object_set_preferences_params"
require_relative "knockapi/models/object_unset_channel_data_params"
require_relative "knockapi/models/object_unset_preferences_params"
require_relative "knockapi/models/page_info"
require_relative "knockapi/models/providers/ms_team_check_auth_params"
require_relative "knockapi/models/providers/ms_team_check_auth_response"
Expand Down Expand Up @@ -214,8 +216,13 @@
require_relative "knockapi/models/user_set_channel_data_params"
require_relative "knockapi/models/user_set_preferences_params"
require_relative "knockapi/models/user_unset_channel_data_params"
require_relative "knockapi/models/user_unset_preferences_params"
require_relative "knockapi/models/user_update_params"
require_relative "knockapi/models/workflow_cancel_params"
require_relative "knockapi/models/workflow_recipient_run_detail"
require_relative "knockapi/models/workflow_recipient_run_event"
require_relative "knockapi/models/workflow_recipient_run_get_params"
require_relative "knockapi/models/workflow_recipient_run_list_params"
require_relative "knockapi/models/workflow_trigger_params"
require_relative "knockapi/models/workflow_trigger_response"
require_relative "knockapi/models"
Expand Down Expand Up @@ -245,4 +252,5 @@
require_relative "knockapi/resources/users/bulk"
require_relative "knockapi/resources/users/feeds"
require_relative "knockapi/resources/users/guides"
require_relative "knockapi/resources/workflow_recipient_runs"
require_relative "knockapi/resources/workflows"
17 changes: 17 additions & 0 deletions lib/knockapi/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ class Client < Knockapi::Internal::Transport::BaseClient
# @return [Knockapi::Resources::Workflows]
attr_reader :workflows

# A workflow run represents an individual execution of a workflow for a specific
# recipient.
# @return [Knockapi::Resources::WorkflowRecipientRuns]
attr_reader :workflow_recipient_runs

# A schedule is a per-recipient, timezone-aware configuration for when to invoke a
# workflow.
# @return [Knockapi::Resources::Schedules]
Expand Down Expand Up @@ -117,6 +122,17 @@ def initialize(
headers = {
"x-knock-branch" => (@branch = branch&.to_s)
}
custom_headers_env = ENV["KNOCK_CUSTOM_HEADERS"]
unless custom_headers_env.nil?
parsed = {}
custom_headers_env.split("\n").each do |line|
colon = line.index(":")
unless colon.nil?
parsed[line[0...colon].strip] = line[(colon + 1)..].strip
end
end
headers = parsed.merge(headers)
end

@api_key = api_key.to_s

Expand All @@ -139,6 +155,7 @@ def initialize(
@providers = Knockapi::Resources::Providers.new(client: self)
@integrations = Knockapi::Resources::Integrations.new(client: self)
@workflows = Knockapi::Resources::Workflows.new(client: self)
@workflow_recipient_runs = Knockapi::Resources::WorkflowRecipientRuns.new(client: self)
@schedules = Knockapi::Resources::Schedules.new(client: self)
@channels = Knockapi::Resources::Channels.new(client: self)
@audiences = Knockapi::Resources::Audiences.new(client: self)
Expand Down
2 changes: 2 additions & 0 deletions lib/knockapi/internal/transport/base_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ def initialize(
Knockapi::Internal::Util.deep_merge(*[req[:body], opts[:extra_body]].compact)
end

headers.delete("content-type") if body.nil?

url = Knockapi::Internal::Util.join_parsed_uri(
@base_url_components,
{**req, path: path, query: query}
Expand Down
26 changes: 21 additions & 5 deletions lib/knockapi/internal/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def coerce_hash!(input)
in Hash | nil => coerced
coerced
else
message = "Expected a #{Hash} or #{Knockapi::Internal::Type::BaseModel}, got #{data.inspect}"
message = "Expected a #{Hash} or #{Knockapi::Internal::Type::BaseModel}, got #{input.inspect}"
raise ArgumentError.new(message)
end
end
Expand Down Expand Up @@ -237,6 +237,11 @@ def dig(data, pick, &blk)
end
end

# @type [Regexp]
#
# https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3
RFC_3986_NOT_PCHARS = /[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/

class << self
# @api private
#
Expand All @@ -247,6 +252,15 @@ def uri_origin(uri)
"#{uri.scheme}://#{uri.host}#{":#{uri.port}" unless uri.port == uri.default_port}"
end

# @api private
#
# @param path [String, Integer]
#
# @return [String]
def encode_path(path)
path.to_s.gsub(Knockapi::Internal::Util::RFC_3986_NOT_PCHARS) { ERB::Util.url_encode(_1) }
end

# @api private
#
# @param path [String, Array<String>]
Expand All @@ -259,7 +273,7 @@ def interpolate_path(path)
in []
""
in [String => p, *interpolations]
encoded = interpolations.map { ERB::Util.url_encode(_1) }
encoded = interpolations.map { encode_path(_1) }
format(p, *encoded)
end
end
Expand Down Expand Up @@ -576,10 +590,10 @@ def encode_query_params(query)

case val
in Knockapi::FilePart unless val.filename.nil?
filename = ERB::Util.url_encode(val.filename)
filename = encode_path(val.filename)
y << "; filename=\"#{filename}\""
in Pathname | IO
filename = ERB::Util.url_encode(::File.basename(val.to_path))
filename = encode_path(::File.basename(val.to_path))
y << "; filename=\"#{filename}\""
else
end
Expand All @@ -596,6 +610,7 @@ def encode_query_params(query)
#
# @return [Array(String, Enumerable<String>)]
private def encode_multipart_streaming(body)
# rubocop:disable Style/CaseEquality
# RFC 1521 Section 7.2.1 says we should have 70 char maximum for boundary length
boundary = SecureRandom.urlsafe_base64(46)

Expand All @@ -605,7 +620,7 @@ def encode_query_params(query)
in Hash
body.each do |key, val|
case val
in Array if val.all? { primitive?(_1) }
in Array if val.all? { primitive?(_1) || Knockapi::Internal::Type::FileInput === _1 }
val.each do |v|
write_multipart_chunk(y, boundary: boundary, key: key, val: v, closing: closing)
end
Expand All @@ -621,6 +636,7 @@ def encode_query_params(query)

fused_io = fused_enum(strio) { closing.each(&:call) }
[boundary, fused_io]
# rubocop:enable Style/CaseEquality
end

# @api private
Expand Down
14 changes: 14 additions & 0 deletions lib/knockapi/models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ module Knockapi

ObjectUnsetChannelDataParams = Knockapi::Models::ObjectUnsetChannelDataParams

ObjectUnsetPreferencesParams = Knockapi::Models::ObjectUnsetPreferencesParams

PageInfo = Knockapi::Models::PageInfo

Providers = Knockapi::Models::Providers
Expand Down Expand Up @@ -205,9 +207,21 @@ module Knockapi

UserUnsetChannelDataParams = Knockapi::Models::UserUnsetChannelDataParams

UserUnsetPreferencesParams = Knockapi::Models::UserUnsetPreferencesParams

UserUpdateParams = Knockapi::Models::UserUpdateParams

WorkflowCancelParams = Knockapi::Models::WorkflowCancelParams

WorkflowRecipientRun = Knockapi::Models::WorkflowRecipientRun

WorkflowRecipientRunDetail = Knockapi::Models::WorkflowRecipientRunDetail

WorkflowRecipientRunEvent = Knockapi::Models::WorkflowRecipientRunEvent

WorkflowRecipientRunGetParams = Knockapi::Models::WorkflowRecipientRunGetParams

WorkflowRecipientRunListParams = Knockapi::Models::WorkflowRecipientRunListParams

WorkflowTriggerParams = Knockapi::Models::WorkflowTriggerParams
end
20 changes: 10 additions & 10 deletions lib/knockapi/models/message_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,22 @@ class MessageEvent < Knockapi::Internal::Type::BaseModel
module Type
extend Knockapi::Internal::Type::Enum

MESSAGE_READ = :"message.read"
MESSAGE_SENT = :"message.sent"
MESSAGE_SEEN = :"message.seen"
MESSAGE_ARCHIVED = :"message.archived"
MESSAGE_BOUNCED = :"message.bounced"
MESSAGE_CREATED = :"message.created"
MESSAGE_QUEUED = :"message.queued"
MESSAGE_DELIVERED = :"message.delivered"
MESSAGE_NOT_SENT = :"message.not_sent"
MESSAGE_BOUNCED = :"message.bounced"
MESSAGE_UNDELIVERED = :"message.undelivered"
MESSAGE_DELIVERY_ATTEMPTED = :"message.delivery_attempted"
MESSAGE_INTERACTED = :"message.interacted"
MESSAGE_LINK_CLICKED = :"message.link_clicked"
MESSAGE_NOT_SENT = :"message.not_sent"
MESSAGE_QUEUED = :"message.queued"
MESSAGE_READ = :"message.read"
MESSAGE_SEEN = :"message.seen"
MESSAGE_SENT = :"message.sent"
MESSAGE_INTERACTED = :"message.interacted"
MESSAGE_UNARCHIVED = :"message.unarchived"
MESSAGE_UNDELIVERED = :"message.undelivered"
MESSAGE_UNREAD = :"message.unread"
MESSAGE_UNSEEN = :"message.unseen"
MESSAGE_UNREAD = :"message.unread"
MESSAGE_CREATED = :"message.created"

# @!method self.values
# @return [Array<Symbol>]
Expand Down
Loading
Loading