blueticks 1.1.2 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -0
  3. data/lib/blueticks/client.rb +47 -5
  4. data/lib/blueticks/resources/account.rb +2 -2
  5. data/lib/blueticks/resources/audiences.rb +30 -22
  6. data/lib/blueticks/resources/boards.rb +124 -0
  7. data/lib/blueticks/resources/campaigns.rb +28 -23
  8. data/lib/blueticks/resources/chats.rb +42 -86
  9. data/lib/blueticks/resources/contacts.rb +18 -11
  10. data/lib/blueticks/resources/engines.rb +12 -19
  11. data/lib/blueticks/resources/groups.rb +69 -28
  12. data/lib/blueticks/resources/identity.rb +27 -0
  13. data/lib/blueticks/resources/latest_chats.rb +22 -0
  14. data/lib/blueticks/resources/messages.rb +127 -31
  15. data/lib/blueticks/resources/newsletters.rb +43 -0
  16. data/lib/blueticks/resources/ping.rb +6 -3
  17. data/lib/blueticks/resources/realtime.rb +19 -0
  18. data/lib/blueticks/resources/scheduled_messages.rb +81 -32
  19. data/lib/blueticks/resources/suno.rb +57 -0
  20. data/lib/blueticks/resources/utils.rb +3 -13
  21. data/lib/blueticks/resources/webhooks.rb +20 -20
  22. data/lib/blueticks/types/account.rb +2 -1
  23. data/lib/blueticks/types/audiences.rb +15 -9
  24. data/lib/blueticks/types/boards.rb +110 -0
  25. data/lib/blueticks/types/campaigns.rb +13 -12
  26. data/lib/blueticks/types/chats.rb +20 -79
  27. data/lib/blueticks/types/contacts.rb +6 -7
  28. data/lib/blueticks/types/coverage.rb +14 -0
  29. data/lib/blueticks/types/engines.rb +9 -8
  30. data/lib/blueticks/types/groups.rb +33 -6
  31. data/lib/blueticks/types/identity.rb +28 -0
  32. data/lib/blueticks/types/latest_chats.rb +32 -0
  33. data/lib/blueticks/types/messages.rb +132 -11
  34. data/lib/blueticks/types/newsletter.rb +33 -0
  35. data/lib/blueticks/types/ok_result.rb +13 -0
  36. data/lib/blueticks/types/paginated.rb +75 -0
  37. data/lib/blueticks/types/ping.rb +11 -3
  38. data/lib/blueticks/types/realtime.rb +23 -0
  39. data/lib/blueticks/types/scheduled_messages.rb +28 -14
  40. data/lib/blueticks/types/suno.rb +42 -0
  41. data/lib/blueticks/types/utils.rb +5 -12
  42. data/lib/blueticks/types/webhooks.rb +14 -11
  43. data/lib/blueticks/version.rb +1 -1
  44. data/lib/blueticks.rb +2 -2
  45. metadata +16 -1
@@ -1,52 +1,101 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../base_resource"
4
- require_relative "../types/deleted_resource"
5
4
  require_relative "../types/scheduled_messages"
6
- require_relative "../types/page"
5
+ require_relative "../types/deleted_resource"
6
+ require_relative "../types/paginated"
7
7
 
8
8
  module Blueticks
9
9
  module Resources
10
10
  class ScheduledMessagesResource < BaseResource
11
- # List scheduled messages.
11
+ # Send / schedule a message to a chat.
12
12
  #
13
- # Retrieves a list of all resources from the service. Cursor-paginated.
14
- def list(limit: nil, cursor: nil)
15
- params = {}
16
- params["limit"] = limit unless limit.nil?
17
- params["cursor"] = cursor unless cursor.nil?
18
- data = client.request("GET", "/v1/scheduled-messages", params: params.empty? ? nil : params)
19
- Types::Page.from_hash(data, item_type: Types::ScheduledMessage)
13
+ # Queue a message for delivery to `chat_id` (a WhatsApp JID or phone). The
14
+ # body is a discriminated union keyed on `type` (`text`, `media`, `poll`).
15
+ # Omit `send_at` to dispatch as soon as possible, or pass an ISO-8601
16
+ # timestamp to schedule it.
17
+ #
18
+ # `mentions` is an Array of participant JIDs to @mention in a group;
19
+ # `recipient_name` is an optional display name for the scheduled-message list.
20
+ #
21
+ # - `type: "text"` — requires `text`.
22
+ # - `type: "media"` — requires `media_url` or `media_base64`; optional
23
+ # `media_kind`, `media_filename`.
24
+ # - `type: "poll"` — requires `poll_question` and `poll_options`; optional
25
+ # `poll_allow_multiple`.
26
+ def create(chat_id, type:, text: nil, media_url: nil, media_base64: nil,
27
+ media_kind: nil, media_filename: nil, poll_question: nil,
28
+ poll_options: nil, poll_allow_multiple: nil, reply_to: nil,
29
+ secret: nil, send_at: nil, idempotency_key: nil,
30
+ mentions: nil, recipient_name: nil)
31
+ body = { "type" => type }
32
+ body["text"] = text unless text.nil?
33
+ body["mediaUrl"] = media_url unless media_url.nil?
34
+ body["mediaBase64"] = media_base64 unless media_base64.nil?
35
+ body["mediaKind"] = media_kind unless media_kind.nil?
36
+ body["mediaFilename"] = media_filename unless media_filename.nil?
37
+ body["pollQuestion"] = poll_question unless poll_question.nil?
38
+ body["pollOptions"] = poll_options unless poll_options.nil?
39
+ body["pollAllowMultiple"] = poll_allow_multiple unless poll_allow_multiple.nil?
40
+ body["replyTo"] = reply_to unless reply_to.nil?
41
+ body["secret"] = secret unless secret.nil?
42
+ body["sendAt"] = send_at unless send_at.nil?
43
+ body["mentions"] = mentions unless mentions.nil?
44
+ body["recipientName"] = recipient_name unless recipient_name.nil?
45
+ env = client.request("POST", "/v1/scheduled-messages/#{chat_id}", body: body,
46
+ idempotency_key: idempotency_key)
47
+ Types::ScheduledMessage.from_hash(env && env["data"])
20
48
  end
21
49
 
22
- # Get scheduled message.
23
- #
24
- # Retrieves a single resource with the given id from the service.
25
- def retrieve(id)
26
- data = client.request("GET", "/v1/scheduled-messages/#{id}")
27
- Types::ScheduledMessage.from_hash(data)
50
+ # Get the current status of a queued/scheduled message by id.
51
+ def retrieve(message_id)
52
+ env = client.request("GET", "/v1/scheduled-messages/#{message_id}")
53
+ Types::ScheduledMessage.from_hash(env && env["data"])
28
54
  end
29
55
 
30
- # Update scheduled message.
31
- #
32
- # Updates the resource identified by id using data.
33
- def update(id, text: nil, media_url: nil, media_caption: nil, send_at: nil)
56
+ # List messages in the user-messages queue (all sources), newest first.
57
+ # Offset-paginated. Optionally filter by `chat_id` and/or lifecycle
58
+ # `status`.
59
+ def list(chat_id: nil, search_token: nil, status: nil, order: nil, skip: nil, limit: nil)
60
+ params = {}
61
+ params["chatId"] = chat_id unless chat_id.nil?
62
+ params["searchToken"] = search_token unless search_token.nil?
63
+ params["status"] = status unless status.nil?
64
+ params["order"] = order unless order.nil?
65
+ params["skip"] = skip unless skip.nil?
66
+ params["limit"] = limit unless limit.nil?
67
+ env = client.request("GET", "/v1/scheduled-messages", params: params.empty? ? nil : params)
68
+ Types::PaginatedPage.from_hash(env, item_type: Types::ScheduledMessage)
69
+ end
70
+
71
+ # Edit a previously-queued message that has not dispatched yet. Pass any
72
+ # subset of the editable fields.
73
+ def update(message_id, type: nil, text: nil, media_url: nil, media_base64: nil,
74
+ media_kind: nil, media_filename: nil, poll_question: nil,
75
+ poll_options: nil, poll_allow_multiple: nil, reply_to: nil,
76
+ secret: nil, send_at: nil, mentions: nil)
34
77
  body = {}
78
+ body["type"] = type unless type.nil?
35
79
  body["text"] = text unless text.nil?
36
- body["media_url"] = media_url unless media_url.nil?
37
- body["media_caption"] = media_caption unless media_caption.nil?
38
- body["send_at"] = send_at unless send_at.nil?
39
- data = client.request("PATCH", "/v1/scheduled-messages/#{id}", body: body)
40
- Types::ScheduledMessage.from_hash(data)
80
+ body["mediaUrl"] = media_url unless media_url.nil?
81
+ body["mediaBase64"] = media_base64 unless media_base64.nil?
82
+ body["mediaKind"] = media_kind unless media_kind.nil?
83
+ body["mediaFilename"] = media_filename unless media_filename.nil?
84
+ body["pollQuestion"] = poll_question unless poll_question.nil?
85
+ body["pollOptions"] = poll_options unless poll_options.nil?
86
+ body["pollAllowMultiple"] = poll_allow_multiple unless poll_allow_multiple.nil?
87
+ body["replyTo"] = reply_to unless reply_to.nil?
88
+ body["secret"] = secret unless secret.nil?
89
+ body["sendAt"] = send_at unless send_at.nil?
90
+ body["mentions"] = mentions unless mentions.nil?
91
+ env = client.request("PATCH", "/v1/scheduled-messages/#{message_id}", body: body)
92
+ Types::ScheduledMessage.from_hash(env && env["data"])
41
93
  end
42
94
 
43
- # Cancel scheduled message.
44
- #
45
- # Cancel a queued scheduled message before it fires. Soft-deletes the row
46
- # (still queryable in audit logs). Returns the deleted ref.
47
- def delete(id)
48
- data = client.request("DELETE", "/v1/scheduled-messages/#{id}")
49
- Types::DeletedResource.from_hash(data)
95
+ # Delete (cancel) a queued/scheduled message by id.
96
+ def delete(message_id)
97
+ env = client.request("DELETE", "/v1/scheduled-messages/#{message_id}")
98
+ Types::DeletedResource.from_hash(env && env["data"])
50
99
  end
51
100
  end
52
101
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../base_resource"
4
+ require_relative "../types/suno"
5
+
6
+ module Blueticks
7
+ module Resources
8
+ class SunoResource < BaseResource
9
+ # Get the Suno credit / plan usage for the workspace.
10
+ def account
11
+ env = client.request("GET", "/v1/suno/account")
12
+ Types::SunoAccount.from_hash(env && env["data"])
13
+ end
14
+
15
+ # Submit a song generation job. Requires `style`; `lyrics` is required unless `instrumental` is true. The many
16
+ # optional knobs mirror the Suno request (vocal_gender, weirdness,
17
+ # style_influence, audio_influence, instrumental, model, title, upload_id,
18
+ # captcha_token, negative_style).
19
+ def create_song(style:, lyrics: nil, negative_style: nil, vocal_gender: nil,
20
+ weirdness: nil, style_influence: nil, audio_influence: nil,
21
+ instrumental: nil, model: nil, title: nil, upload_id: nil,
22
+ captcha_token: nil)
23
+ body = { "style" => style }
24
+ body["lyrics"] = lyrics unless lyrics.nil?
25
+ body["negativeStyle"] = negative_style unless negative_style.nil?
26
+ body["vocalGender"] = vocal_gender unless vocal_gender.nil?
27
+ body["weirdness"] = weirdness unless weirdness.nil?
28
+ body["styleInfluence"] = style_influence unless style_influence.nil?
29
+ body["audioInfluence"] = audio_influence unless audio_influence.nil?
30
+ body["instrumental"] = instrumental unless instrumental.nil?
31
+ body["model"] = model unless model.nil?
32
+ body["title"] = title unless title.nil?
33
+ body["uploadId"] = upload_id unless upload_id.nil?
34
+ body["captchaToken"] = captcha_token unless captcha_token.nil?
35
+ env = client.request("POST", "/v1/suno/songs", body: body)
36
+ Types::GenerateSongResult.from_hash(env && env["data"])
37
+ end
38
+
39
+ # Get a generated song (clip) by id.
40
+ def get_song(song_id)
41
+ env = client.request("GET", "/v1/suno/songs/#{song_id}")
42
+ Types::SongClip.from_hash(env && env["data"])
43
+ end
44
+
45
+ # Register a reference-audio upload (by URL or base64) for use as an
46
+ # influence on a subsequent song generation.
47
+ def create_upload(audio_url: nil, audio_base64: nil, file_name: nil)
48
+ body = {}
49
+ body["audioUrl"] = audio_url unless audio_url.nil?
50
+ body["audioBase64"] = audio_base64 unless audio_base64.nil?
51
+ body["fileName"] = file_name unless file_name.nil?
52
+ env = client.request("POST", "/v1/suno/uploads", body: body)
53
+ Types::CreateUploadResult.from_hash(env && env["data"])
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,23 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../base_resource"
4
- require_relative "../types/utils"
5
4
 
6
5
  module Blueticks
7
6
  module Resources
7
+ # UtilsResource had methods for /v1/utils/* which are not in the current spec.
8
+ # The accessor is kept for backward compatibility with test_client.rb.
9
+ # No public methods are exposed.
8
10
  class UtilsResource < BaseResource
9
- # Validate a phone number or chat-id; returns the engine's canonical form.
10
- def validate_phone(phone_or_chat_id:)
11
- data = client.request("POST", "/v1/utils/validate_phone",
12
- body: { "phone_or_chat_id" => phone_or_chat_id })
13
- Types::PhoneValidation.from_hash(data)
14
- end
15
-
16
- # Fetch OpenGraph-style metadata for a URL (uses the engine's renderer).
17
- def link_preview(url:)
18
- data = client.request("GET", "/v1/utils/link_preview", params: { "url" => url })
19
- Types::LinkPreview.from_hash(data)
20
- end
21
11
  end
22
12
  end
23
13
  end
@@ -3,50 +3,50 @@
3
3
  require_relative "../base_resource"
4
4
  require_relative "../types/deleted_resource"
5
5
  require_relative "../types/webhooks"
6
- require_relative "../types/page"
6
+ require_relative "../types/paginated"
7
7
 
8
8
  module Blueticks
9
9
  module Resources
10
10
  class WebhooksResource < BaseResource
11
+ # Create a webhook subscription.
11
12
  def create(url:, events:, description: nil)
12
13
  body = { "url" => url, "events" => events }
13
14
  body["description"] = description unless description.nil?
14
- data = client.request("POST", "/v1/webhooks", body: body)
15
- Types::WebhookCreateResult.from_hash(data)
15
+ env = client.request("POST", "/v1/webhooks", body: body)
16
+ Types::Webhook.from_hash(env && env["data"])
16
17
  end
17
18
 
18
- # List webhooks, newest first. Cursor-paginated.
19
- def list(limit: nil, cursor: nil)
19
+ # List webhooks, newest first. Offset-paginated.
20
+ def list(order: nil, skip: nil, limit: nil)
20
21
  params = {}
22
+ params["order"] = order unless order.nil?
23
+ params["skip"] = skip unless skip.nil?
21
24
  params["limit"] = limit unless limit.nil?
22
- params["cursor"] = cursor unless cursor.nil?
23
- data = client.request("GET", "/v1/webhooks", params: params.empty? ? nil : params)
24
- Types::Page.from_hash(data, item_type: Types::Webhook)
25
+ env = client.request("GET", "/v1/webhooks", params: params.empty? ? nil : params)
26
+ Types::PaginatedPage.from_hash(env, item_type: Types::Webhook)
25
27
  end
26
28
 
27
- def get(webhook_id)
28
- data = client.request("GET", "/v1/webhooks/#{webhook_id}")
29
- Types::Webhook.from_hash(data)
29
+ # Retrieve a webhook by id.
30
+ def retrieve(webhook_id)
31
+ env = client.request("GET", "/v1/webhooks/#{webhook_id}")
32
+ Types::Webhook.from_hash(env && env["data"])
30
33
  end
31
34
 
35
+ # Update a webhook's url, events, description and/or status.
32
36
  def update(webhook_id, url: nil, events: nil, description: nil, status: nil)
33
37
  body = {}
34
38
  body["url"] = url unless url.nil?
35
39
  body["events"] = events unless events.nil?
36
40
  body["description"] = description unless description.nil?
37
41
  body["status"] = status unless status.nil?
38
- data = client.request("PATCH", "/v1/webhooks/#{webhook_id}", body: body)
39
- Types::Webhook.from_hash(data)
42
+ env = client.request("PATCH", "/v1/webhooks/#{webhook_id}", body: body)
43
+ Types::Webhook.from_hash(env && env["data"])
40
44
  end
41
45
 
46
+ # Delete a webhook.
42
47
  def delete(webhook_id)
43
- data = client.request("DELETE", "/v1/webhooks/#{webhook_id}")
44
- Types::DeletedResource.from_hash(data)
45
- end
46
-
47
- def rotate_secret(webhook_id)
48
- data = client.request("POST", "/v1/webhooks/#{webhook_id}/rotate-secret")
49
- Types::WebhookCreateResult.from_hash(data)
48
+ env = client.request("DELETE", "/v1/webhooks/#{webhook_id}")
49
+ Types::DeletedResource.from_hash(env && env["data"])
50
50
  end
51
51
  end
52
52
  end
@@ -8,8 +8,9 @@ module Blueticks
8
8
  class Account < Base
9
9
  field :id, :string
10
10
  field :name, :string
11
+ field :user_email, :string, nullable: true, wire_name: "userEmail"
11
12
  field :timezone, :string, nullable: true
12
- field :created_at, :string
13
+ field :created_at, :string, wire_name: "createdAt"
13
14
  end
14
15
  end
15
16
  end
@@ -4,26 +4,32 @@ require_relative "base"
4
4
 
5
5
  module Blueticks
6
6
  module Types
7
- class Contact < Base
7
+ # A contact stored inside an audience (ContactResponse). `variables` is a
8
+ # free-form hash of merge-field values.
9
+ class AudienceContact < Base
8
10
  field :id, :string
9
11
  field :to, :string
10
- field :variables, %i[hash_of string]
11
- field :added_at, :string
12
+ field :variables, :hash
13
+ field :added_at, :string, wire_name: "addedAt"
12
14
  end
13
15
 
16
+ # An audience (AudienceResponse).
14
17
  class Audience < Base
15
18
  field :id, :string
16
19
  field :name, :string
17
- field :contact_count, :integer
18
- field :created_at, :string
19
- field :contacts, [:array, Contact], optional: true
20
- field :page, :integer, optional: true
21
- field :has_more, :boolean, optional: true
20
+ field :contact_count, :integer, wire_name: "contactCount"
21
+ field :created_at, :string, wire_name: "createdAt"
22
22
  end
23
23
 
24
+ # Result of appending contacts to an audience (POST .../contacts).
24
25
  class AppendContactsResult < Base
25
26
  field :added, :integer
26
- field :contact_count, :integer
27
+ field :contact_count, :integer, wire_name: "contactCount"
28
+ end
29
+
30
+ # Result of removing a contact from an audience (DELETE .../contacts/{id}).
31
+ class ContactRemoval < Base
32
+ field :id, :string
27
33
  end
28
34
  end
29
35
  end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Blueticks
6
+ module Types
7
+ # A status/priority label with its colour (OptionRef).
8
+ class BoardOption < Base
9
+ field :label, :string
10
+ field :bgcolor, :string
11
+ end
12
+
13
+ # A board column definition (BoardColumn). `type` is the column kind
14
+ # (e.g. "status", "text"); `options` lists the selectable labels.
15
+ class BoardColumn < Base
16
+ field :column_id, :string
17
+ field :title, :string
18
+ field :type, :string
19
+ field :options, [:array, BoardOption]
20
+ end
21
+
22
+ # A board summary (BoardRow) as returned by boards.list.
23
+ class Board < Base
24
+ field :board_id, :string
25
+ field :name, :string
26
+ field :description, :string, optional: true
27
+ field :domain, :string, optional: true
28
+ field :agent_managed, :boolean
29
+ field :memory_retention_days, :integer, optional: true
30
+ field :item_count, :integer, optional: true
31
+ field :web_url, :string
32
+ field :created_at, :string
33
+ field :updated_at, :string
34
+ end
35
+
36
+ # A board with its columns (BoardDetail) as returned by boards.create and
37
+ # boards.retrieve.
38
+ class BoardDetail < Base
39
+ field :board_id, :string
40
+ field :name, :string
41
+ field :description, :string, optional: true
42
+ field :domain, :string, optional: true
43
+ field :agent_managed, :boolean
44
+ field :memory_retention_days, :integer, optional: true
45
+ field :item_count, :integer, optional: true
46
+ field :web_url, :string
47
+ field :created_at, :string
48
+ field :updated_at, :string
49
+ field :columns, [:array, BoardColumn]
50
+ end
51
+
52
+ # Short board reference (BoardRef) embedded in a bulk-upsert result.
53
+ class BoardRef < Base
54
+ field :board_id, :string
55
+ field :name, :string
56
+ field :description, :string, optional: true
57
+ field :domain, :string, optional: true
58
+ field :web_url, :string
59
+ end
60
+
61
+ # The chat message an item was extracted from (ItemSource).
62
+ class ItemSource < Base
63
+ field :chat_id, :string, optional: true
64
+ field :chat_name, :string, optional: true
65
+ field :message_key, :string, optional: true
66
+ field :excerpt, :string, optional: true
67
+ field :extracted_at, :integer, optional: true
68
+ end
69
+
70
+ # A board item / task (BoardItem). `cells` holds custom column values keyed
71
+ # by column title (string or number).
72
+ class BoardItem < Base
73
+ field :item_id, :string
74
+ field :text, :string
75
+ field :status, BoardOption, optional: true
76
+ field :priority, BoardOption, optional: true
77
+ field :due_date, :string, optional: true
78
+ field :cells, :hash, optional: true
79
+ field :source, ItemSource, optional: true
80
+ field :confidence, :number, optional: true
81
+ field :last_seen_at, :integer, optional: true
82
+ field :web_url, :string
83
+ field :created_at, :string
84
+ field :updated_at, :string
85
+ end
86
+
87
+ # Result of a bulk upsert (BulkItemsResponse).
88
+ class BulkItemsResult < Base
89
+ field :created, [:array, BoardItem]
90
+ field :updated, [:array, BoardItem]
91
+ field :unchanged, :integer
92
+ field :board, BoardRef
93
+ end
94
+
95
+ # One candidate-to-existing-item match (FindSimilarResponse.matches[]).
96
+ class SimilarMatch < Base
97
+ field :candidate_index, :integer
98
+ field :item_id, :string
99
+ field :text, :string
100
+ field :score, :number
101
+ end
102
+
103
+ # Result of boards.find_similar_items (FindSimilarResponse). `misses` holds
104
+ # the indexes of candidates with no match.
105
+ class FindSimilarResult < Base
106
+ field :matches, [:array, SimilarMatch]
107
+ field :misses, %i[array integer]
108
+ end
109
+ end
110
+ end
@@ -8,21 +8,22 @@ module Blueticks
8
8
  pending running paused complete_sent complete_delivered aborted
9
9
  ].freeze
10
10
 
11
+ # A campaign (CampaignResponse). Note the id is carried on `cmp_id`
12
+ # (wire `cmpId`), matching the backend document shape.
11
13
  class Campaign < Base
12
- field :id, :string
14
+ field :cmp_id, :string, wire_name: "cmpId"
13
15
  field :name, :string
14
- field :audience_id, :string
16
+ field :audience_id, :string, wire_name: "audienceId"
15
17
  field :status, [:enum, CAMPAIGN_STATUSES]
16
- field :total_count, :integer
17
- field :sent_count, :integer
18
- field :delivered_count, :integer
19
- field :read_count, :integer
20
- field :failed_count, :integer
21
- field :from, :string, nullable: true
22
- field :created_at, :string
23
- field :started_at, :string, nullable: true
24
- field :completed_at, :string, nullable: true
25
- field :aborted_at, :string, nullable: true
18
+ field :total_count, :integer, wire_name: "totalCount"
19
+ field :sent_count, :integer, wire_name: "sentCount"
20
+ field :delivered_count, :integer, wire_name: "deliveredCount"
21
+ field :read_count, :integer, wire_name: "readCount"
22
+ field :failed_count, :integer, wire_name: "failedCount"
23
+ field :created_at, :string, wire_name: "createdAt"
24
+ field :started_at, :string, nullable: true, wire_name: "startedAt"
25
+ field :completed_at, :string, nullable: true, wire_name: "completedAt"
26
+ field :aborted_at, :string, nullable: true, wire_name: "abortedAt"
26
27
  end
27
28
  end
28
29
  end
@@ -4,88 +4,29 @@ require_relative "base"
4
4
 
5
5
  module Blueticks
6
6
  module Types
7
- MESSAGE_TYPES = %w[
8
- chat image video document audio ptt sticker gif ptv
9
- poll_creation location vcard revoked
10
- ].freeze
11
-
12
- MEDIA_UNAVAILABLE_REASONS = %w[expired fetching awaiting_sender error no_media].freeze
7
+ CHAT_TYPES = %w[contact group newsletter].freeze
13
8
 
9
+ # A chat row (Chat) returned by chats.list / chats.retrieve.
14
10
  class Chat < Base
15
- field :id, :string
16
- field :name, :string, nullable: true
17
- field :is_group, :boolean
18
- field :last_message_at, :string, nullable: true
19
- field :unread_count, :integer, nullable: true
20
- end
21
-
11
+ field :chat_id, :string, wire_name: "chatId"
12
+ field :name, :string, nullable: true, optional: true
13
+ field :chat_type, [:enum, CHAT_TYPES], wire_name: "chatType"
14
+ field :pinned, :boolean, optional: true
15
+ field :archived, :boolean, optional: true
16
+ field :last_message_at, :string, nullable: true, optional: true, wire_name: "lastMessageAt"
17
+ field :unread_count, :integer, nullable: true, optional: true, wire_name: "unreadCount"
18
+ field :marked_unread, :boolean, wire_name: "markedUnread"
19
+ field :last_message_text, :string, nullable: true, optional: true, wire_name: "lastMessageText"
20
+ field :last_message_from_me, :boolean, nullable: true, optional: true, wire_name: "lastMessageFromMe"
21
+ end
22
+
23
+ # A participant of a group/community chat (Participant) as returned by
24
+ # chats.list_participants.
22
25
  class Participant < Base
23
- field :chat_id, :string
24
- field :is_admin, :boolean
25
- field :is_super_admin, :boolean, nullable: true
26
- end
27
-
28
- class ChatMessage < Base
29
- field :key, :string
30
- field :chat_id, :string
31
- field :from, :string
32
- field :timestamp, :string, nullable: true
33
- field :text, :string, nullable: true
34
- field :type, :string
35
- field :from_me, :boolean
36
- field :ack, :integer, nullable: true
37
- field :media_url, :string, nullable: true
38
- field :caption, :string, nullable: true
39
- field :filename, :string, nullable: true
40
- end
41
-
42
- class ChatMedia < Base
43
- field :url, :string, nullable: true
44
- field :mimetype, :string, nullable: true
45
- field :filename, :string, nullable: true
46
- field :data_base64, :string, nullable: true
47
- field :original_quality, :boolean, nullable: true
48
- field :media_unavailable, [:enum, MEDIA_UNAVAILABLE_REASONS], nullable: true
49
- end
50
-
51
- # Generic `{ "ok": true }` response envelope returned by acknowledged side-effects.
52
- class OkResponse < Base
53
- field :ok, :boolean
54
- end
55
-
56
- # `{ "chat_id": "..." }` envelope returned by /v1/chats/{chat_id}/open.
57
- class ChatRef < Base
58
- field :chat_id, :string
59
- end
60
-
61
- # `{ "ack": int|null }` envelope returned by .../messages/{key}/ack.
62
- class MessageAck < Base
63
- field :ack, :integer, nullable: true
64
- end
65
-
66
- # Response from POST /v1/chats/{chat_id}/messages/load_older.
67
- class LoadOlderMessagesResponse < Base
68
- field :total_messages, :integer, nullable: true
69
- field :added, :integer, nullable: true
70
- field :can_load_more, :boolean
71
- end
72
-
73
- # Response from GET /v1/chats/{chat_id}/messages/{key}/media_url.
74
- class MediaUrlResponse < Base
75
- field :url, :string, nullable: true
76
- end
77
-
78
- # Single entry in the BatchMessageAcksResponse `data` array.
79
- # `{ "key": "<message key>", "ack": <int|null> }`.
80
- class BatchMessageAckEntry < Base
81
- field :key, :string
82
- field :ack, :integer, nullable: true
83
- end
84
-
85
- # Response from POST /v1/chats/message_acks.
86
- # `{ "data": [BatchMessageAckEntry, ...] }`.
87
- class BatchMessageAcksResponse < Base
88
- field :data, [:array, BatchMessageAckEntry]
26
+ field :chat_id, :string, wire_name: "chatId"
27
+ field :name, :string, nullable: true, optional: true
28
+ field :is_admin, :boolean, wire_name: "isAdmin"
29
+ field :is_super_admin, :boolean, optional: true, wire_name: "isSuperAdmin"
89
30
  end
90
31
  end
91
32
  end
@@ -4,14 +4,13 @@ require_relative "base"
4
4
 
5
5
  module Blueticks
6
6
  module Types
7
+ # A WhatsApp contact known to the connected engine (contacts.list item).
8
+ # Per the spec, only `chatId` is required; `name` and `isBusiness` are
9
+ # optional and absent from real engine responses.
7
10
  class WhatsAppContact < Base
8
- field :chat_id, :string
9
- field :name, :string, nullable: true
10
- field :is_business, :boolean
11
- end
12
-
13
- class ProfilePicture < Base
14
- field :url, :string, nullable: true
11
+ field :chat_id, :string, wire_name: "chatId"
12
+ field :name, :string, optional: true, nullable: true
13
+ field :is_business, :boolean, optional: true, nullable: true, wire_name: "isBusiness"
15
14
  end
16
15
  end
17
16
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Blueticks
6
+ module Types
7
+ # How far back a chat is loaded (LoadCoverage). `oldest_loaded_iso` is the
8
+ # deterministic answer to "have I reached far enough back?".
9
+ class Coverage < Base
10
+ field :oldest_loaded_timestamp, :number, optional: true, wire_name: "oldestLoadedTimestamp"
11
+ field :oldest_loaded_iso, :string, optional: true, wire_name: "oldestLoadedIso"
12
+ end
13
+ end
14
+ end