blueticks 1.1.2 → 2.0.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -0
- data/lib/blueticks/client.rb +27 -5
- data/lib/blueticks/resources/account.rb +2 -2
- data/lib/blueticks/resources/audiences.rb +30 -22
- data/lib/blueticks/resources/campaigns.rb +28 -23
- data/lib/blueticks/resources/chats.rb +37 -86
- data/lib/blueticks/resources/contacts.rb +18 -11
- data/lib/blueticks/resources/engines.rb +12 -19
- data/lib/blueticks/resources/groups.rb +54 -28
- data/lib/blueticks/resources/messages.rb +110 -31
- data/lib/blueticks/resources/newsletters.rb +43 -0
- data/lib/blueticks/resources/ping.rb +6 -3
- data/lib/blueticks/resources/scheduled_messages.rb +74 -32
- data/lib/blueticks/resources/suno.rb +56 -0
- data/lib/blueticks/resources/utils.rb +3 -13
- data/lib/blueticks/resources/webhooks.rb +20 -20
- data/lib/blueticks/types/account.rb +2 -1
- data/lib/blueticks/types/audiences.rb +15 -9
- data/lib/blueticks/types/campaigns.rb +13 -12
- data/lib/blueticks/types/chats.rb +19 -78
- data/lib/blueticks/types/contacts.rb +6 -7
- data/lib/blueticks/types/engines.rb +9 -8
- data/lib/blueticks/types/groups.rb +22 -6
- data/lib/blueticks/types/messages.rb +124 -11
- data/lib/blueticks/types/newsletter.rb +33 -0
- data/lib/blueticks/types/ok_result.rb +13 -0
- data/lib/blueticks/types/paginated.rb +70 -0
- data/lib/blueticks/types/ping.rb +11 -3
- data/lib/blueticks/types/scheduled_messages.rb +28 -14
- data/lib/blueticks/types/suno.rb +42 -0
- data/lib/blueticks/types/utils.rb +5 -12
- data/lib/blueticks/types/webhooks.rb +13 -11
- data/lib/blueticks/version.rb +1 -1
- data/lib/blueticks.rb +2 -2
- metadata +7 -1
|
@@ -4,26 +4,32 @@ require_relative "base"
|
|
|
4
4
|
|
|
5
5
|
module Blueticks
|
|
6
6
|
module Types
|
|
7
|
-
|
|
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,
|
|
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
|
|
@@ -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 :
|
|
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 :
|
|
22
|
-
field :
|
|
23
|
-
field :
|
|
24
|
-
field :
|
|
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
|
-
|
|
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 :
|
|
11
|
+
field :chat_id, :string, wire_name: "chatId"
|
|
16
12
|
field :name, :string, nullable: true
|
|
17
|
-
field :
|
|
18
|
-
field :
|
|
19
|
-
field :
|
|
20
|
-
|
|
21
|
-
|
|
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, wire_name: "lastMessageAt"
|
|
17
|
+
field :unread_count, :integer, nullable: 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 :
|
|
25
|
-
field :
|
|
26
|
-
|
|
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
|
|
@@ -4,17 +4,18 @@ require_relative "base"
|
|
|
4
4
|
|
|
5
5
|
module Blueticks
|
|
6
6
|
module Types
|
|
7
|
-
|
|
7
|
+
ENGINE_TYPES = %w[gateway regular].freeze
|
|
8
|
+
|
|
9
|
+
# A single engine session connected to the workspace (engines.list item).
|
|
10
|
+
# `type` is "gateway" (a remote server-side engine / Blueticks 24/7 gateway
|
|
11
|
+
# or baileys pod) or "regular" (the user's own WhatsApp Web extension).
|
|
12
|
+
class Engine < Base
|
|
13
|
+
field :id, :string
|
|
14
|
+
field :type, [:enum, ENGINE_TYPES]
|
|
8
15
|
field :connected, :boolean
|
|
9
16
|
field :state, :string, nullable: true
|
|
10
17
|
field :stream, :string, nullable: true
|
|
11
|
-
field :has_synced, :boolean, nullable: true
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
class WhatsAppMe < Base
|
|
15
|
-
field :phone, :string, nullable: true
|
|
16
|
-
field :name, :string, nullable: true
|
|
17
|
-
field :platform, :string, nullable: true
|
|
18
|
+
field :has_synced, :boolean, nullable: true, wire_name: "hasSynced"
|
|
18
19
|
end
|
|
19
20
|
end
|
|
20
21
|
end
|
|
@@ -4,24 +4,40 @@ require_relative "base"
|
|
|
4
4
|
|
|
5
5
|
module Blueticks
|
|
6
6
|
module Types
|
|
7
|
+
# A member of a group (GroupParticipant).
|
|
7
8
|
class GroupParticipant < Base
|
|
8
|
-
field :chat_id, :string
|
|
9
|
-
field :is_admin, :boolean
|
|
10
|
-
field :is_super_admin, :boolean
|
|
9
|
+
field :chat_id, :string, wire_name: "chatId"
|
|
10
|
+
field :is_admin, :boolean, wire_name: "isAdmin"
|
|
11
|
+
field :is_super_admin, :boolean, wire_name: "isSuperAdmin"
|
|
11
12
|
field :name, :string, nullable: true
|
|
12
13
|
end
|
|
13
14
|
|
|
15
|
+
# Full group metadata (Group) returned by group create/get/update and the
|
|
16
|
+
# membership-mutating endpoints.
|
|
14
17
|
class Group < Base
|
|
15
18
|
field :id, :string
|
|
16
19
|
field :name, :string, nullable: true
|
|
17
20
|
field :description, :string, nullable: true
|
|
18
21
|
field :owner, :string, nullable: true
|
|
19
|
-
field :created_at, :string, nullable: true
|
|
20
|
-
field :last_message_at, :string, nullable: true
|
|
21
|
-
field :participant_count, :integer, nullable: true
|
|
22
|
+
field :created_at, :string, nullable: true, wire_name: "createdAt"
|
|
23
|
+
field :last_message_at, :string, nullable: true, wire_name: "lastMessageAt"
|
|
24
|
+
field :participant_count, :integer, nullable: true, wire_name: "participantCount"
|
|
22
25
|
field :announce, :boolean, nullable: true
|
|
23
26
|
field :restrict, :boolean, nullable: true
|
|
24
27
|
field :participants, [:array, GroupParticipant], nullable: true
|
|
25
28
|
end
|
|
29
|
+
|
|
30
|
+
# A group row in the groups.list / contacts.common_groups page
|
|
31
|
+
# (GroupListItem) — a slimmer projection without announce/participants.
|
|
32
|
+
class GroupListItem < Base
|
|
33
|
+
field :id, :string
|
|
34
|
+
field :name, :string, nullable: true
|
|
35
|
+
field :description, :string, nullable: true
|
|
36
|
+
field :owner, :string, nullable: true
|
|
37
|
+
field :created_at, :string, nullable: true, wire_name: "createdAt"
|
|
38
|
+
field :last_message_at, :string, nullable: true, wire_name: "lastMessageAt"
|
|
39
|
+
field :participant_count, :integer, nullable: true, wire_name: "participantCount"
|
|
40
|
+
field :restrict, :boolean, nullable: true
|
|
41
|
+
end
|
|
26
42
|
end
|
|
27
43
|
end
|
|
@@ -4,22 +4,135 @@ require_relative "base"
|
|
|
4
4
|
|
|
5
5
|
module Blueticks
|
|
6
6
|
module Types
|
|
7
|
-
|
|
7
|
+
MESSAGE_KINDS = %w[text media poll].freeze
|
|
8
|
+
MESSAGE_MEDIA_KINDS = %w[image video audio document sticker voice gif].freeze
|
|
9
|
+
MEDIA_UNAVAILABLE_REASONS = %w[expired fetching awaiting_sender error no_media].freeze
|
|
10
|
+
MESSAGE_STATUSES = %w[
|
|
11
|
+
pending before-wa-send bt-sent sending sent sent_pending_ack confirmed
|
|
12
|
+
delivered received read played cancelled error failed expired
|
|
13
|
+
].freeze
|
|
8
14
|
|
|
15
|
+
# WhatsApp wire message key (PublicWaMessageKey). `serialized` maps the
|
|
16
|
+
# wire's `_serialized` compact form.
|
|
17
|
+
class WaMessageKey < Base
|
|
18
|
+
field :from_me, :boolean, wire_name: "fromMe"
|
|
19
|
+
field :remote, :string, optional: true
|
|
20
|
+
field :id, :string, optional: true
|
|
21
|
+
field :serialized, :string, optional: true, wire_name: "_serialized"
|
|
22
|
+
field :participant, :string, optional: true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Link preview attached to a queued/scheduled message (MessageResponse).
|
|
26
|
+
# Fields are always present but may be null.
|
|
27
|
+
class LinkPreview < Base
|
|
28
|
+
field :title, :string, nullable: true
|
|
29
|
+
field :description, :string, nullable: true
|
|
30
|
+
field :canonical_url, :string, nullable: true, wire_name: "canonicalUrl"
|
|
31
|
+
field :thumbnail, :string, nullable: true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Link preview attached to a store message (PublicMessage). Fields are all
|
|
35
|
+
# optional here.
|
|
36
|
+
class PublicLinkPreview < Base
|
|
37
|
+
field :title, :string, optional: true
|
|
38
|
+
field :description, :string, optional: true
|
|
39
|
+
field :canonical_url, :string, optional: true, wire_name: "canonicalUrl"
|
|
40
|
+
field :thumbnail, :string, optional: true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The message a store message replies to (PublicQuotedMessage).
|
|
44
|
+
class QuotedMessage < Base
|
|
45
|
+
field :wa_message_key, WaMessageKey, wire_name: "waMessageKey"
|
|
46
|
+
field :text, :string, optional: true
|
|
47
|
+
field :type, :string, optional: true
|
|
48
|
+
field :author, :string, optional: true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# A message read from the WhatsApp store (PublicMessage) — the shape
|
|
52
|
+
# returned by messages.list and messages.retrieve.
|
|
53
|
+
class PublicMessage < Base
|
|
54
|
+
field :wa_message_key, WaMessageKey, wire_name: "waMessageKey"
|
|
55
|
+
field :chat_id, :string, wire_name: "chatId"
|
|
56
|
+
field :from, :string
|
|
57
|
+
field :author, :string, optional: true
|
|
58
|
+
field :sender_name, :string, optional: true, wire_name: "senderName"
|
|
59
|
+
field :timestamp, :string, optional: true
|
|
60
|
+
field :text, :string, optional: true
|
|
61
|
+
field :type, :string
|
|
62
|
+
field :from_me, :boolean, wire_name: "fromMe"
|
|
63
|
+
field :ack, :integer, optional: true
|
|
64
|
+
field :media_url, :string, optional: true, wire_name: "mediaUrl"
|
|
65
|
+
field :filename, :string, optional: true
|
|
66
|
+
field :link_preview, PublicLinkPreview, optional: true, wire_name: "linkPreview"
|
|
67
|
+
field :quoted_message, QuotedMessage, optional: true, wire_name: "quotedMessage"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Media payload for a message (Media) returned by messages.get_media.
|
|
71
|
+
class Media < Base
|
|
72
|
+
field :url, :string, optional: true
|
|
73
|
+
field :mimetype, :string, optional: true
|
|
74
|
+
field :filename, :string, optional: true
|
|
75
|
+
field :data_base64, :string, optional: true, wire_name: "dataBase64"
|
|
76
|
+
field :original_quality, :boolean, optional: true, wire_name: "originalQuality"
|
|
77
|
+
field :media_unavailable, [:enum, MEDIA_UNAVAILABLE_REASONS], optional: true, wire_name: "mediaUnavailable"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Delivery acknowledgement (MessageAck). ack: -1=error, 0=pending,
|
|
81
|
+
# 1=server, 2=device, 3=read, 4=played.
|
|
82
|
+
class MessageAck < Base
|
|
83
|
+
field :ack, :integer, nullable: true
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# A single entry in the messages.batch_acks page (BatchMessageAckEntry).
|
|
87
|
+
class BatchAckEntry < Base
|
|
88
|
+
field :key, :string
|
|
89
|
+
field :ack, :integer, nullable: true
|
|
90
|
+
field :found, :boolean
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# A pinned message summary (PinnedMessage) in the messages.pinned page.
|
|
94
|
+
class PinnedMessage < Base
|
|
95
|
+
field :key, :string
|
|
96
|
+
field :chat_id, :string, wire_name: "chatId"
|
|
97
|
+
field :text, :string, nullable: true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Result of a load-older request (LoadOlderResult).
|
|
101
|
+
class LoadOlderResult < Base
|
|
102
|
+
field :total_messages, :integer, nullable: true, wire_name: "totalMessages"
|
|
103
|
+
field :added, :integer, nullable: true
|
|
104
|
+
field :can_load_more, :boolean, wire_name: "canLoadMore"
|
|
105
|
+
field :history_unavailable, :boolean, wire_name: "historyUnavailable"
|
|
106
|
+
field :error, :string, nullable: true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# A sent/queued outbound message record — the shape returned by
|
|
110
|
+
# messages.create (direct send). The spec's send response marks only
|
|
111
|
+
# `to`, `type`, `status`, `createdAt` required; `waMessageKey` is optional
|
|
112
|
+
# (absent until the message has a wire key). The scheduled/queued variant is
|
|
113
|
+
# modelled separately by Types::ScheduledMessage.
|
|
9
114
|
class Message < Base
|
|
10
|
-
field :id, :string
|
|
115
|
+
field :id, :string, optional: true
|
|
116
|
+
field :wa_message_key, WaMessageKey, optional: true, nullable: true, wire_name: "waMessageKey"
|
|
11
117
|
field :to, :string
|
|
12
|
-
field :
|
|
118
|
+
field :type, [:enum, MESSAGE_KINDS]
|
|
13
119
|
field :text, :string, nullable: true
|
|
14
|
-
field :media_url, :string, nullable: true
|
|
120
|
+
field :media_url, :string, nullable: true, wire_name: "mediaUrl"
|
|
121
|
+
field :media_kind, [:enum, MESSAGE_MEDIA_KINDS], nullable: true, wire_name: "mediaKind"
|
|
122
|
+
field :poll_question, :string, nullable: true, wire_name: "pollQuestion"
|
|
123
|
+
field :poll_options, %i[array string], nullable: true, wire_name: "pollOptions"
|
|
124
|
+
field :poll_allow_multiple, :boolean, nullable: true, wire_name: "pollAllowMultiple"
|
|
15
125
|
field :status, [:enum, MESSAGE_STATUSES]
|
|
16
|
-
field :send_at, :string, nullable: true
|
|
17
|
-
field :created_at, :string
|
|
18
|
-
field :
|
|
19
|
-
field :
|
|
20
|
-
field :read_at, :string, nullable: true
|
|
21
|
-
field :
|
|
22
|
-
field :
|
|
126
|
+
field :send_at, :string, nullable: true, wire_name: "sendAt"
|
|
127
|
+
field :created_at, :string, wire_name: "createdAt"
|
|
128
|
+
field :confirmed_at, :string, nullable: true, wire_name: "confirmedAt"
|
|
129
|
+
field :received_at, :string, nullable: true, wire_name: "receivedAt"
|
|
130
|
+
field :read_at, :string, nullable: true, wire_name: "readAt"
|
|
131
|
+
field :played_at, :string, nullable: true, wire_name: "playedAt"
|
|
132
|
+
field :failed_at, :string, nullable: true, wire_name: "failedAt"
|
|
133
|
+
field :failure_reason, :string, nullable: true, wire_name: "failureReason"
|
|
134
|
+
field :secret, :string, nullable: true
|
|
135
|
+
field :link_preview, LinkPreview, optional: true, wire_name: "linkPreview"
|
|
23
136
|
end
|
|
24
137
|
end
|
|
25
138
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Blueticks
|
|
6
|
+
module Types
|
|
7
|
+
NEWSLETTER_VERIFICATIONS = %w[VERIFIED UNVERIFIED].freeze
|
|
8
|
+
|
|
9
|
+
# A WhatsApp newsletter (channel) as returned by create/get
|
|
10
|
+
# (NewsletterResponse). The JID is carried on `newsletter_id`.
|
|
11
|
+
class Newsletter < Base
|
|
12
|
+
field :newsletter_id, :string, wire_name: "newsletterId"
|
|
13
|
+
field :name, :string
|
|
14
|
+
field :description, :string, nullable: true
|
|
15
|
+
field :created_at, :string, nullable: true, wire_name: "createdAt"
|
|
16
|
+
field :subscribers, :integer, nullable: true
|
|
17
|
+
field :invite, :string, nullable: true
|
|
18
|
+
field :verification, [:enum, NEWSLETTER_VERIFICATIONS], nullable: true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# A newsletter row in the newsletters.list page (NewsletterListItem). Here
|
|
22
|
+
# the JID is carried on `chat_id`.
|
|
23
|
+
class NewsletterListItem < Base
|
|
24
|
+
field :chat_id, :string, wire_name: "chatId"
|
|
25
|
+
field :name, :string
|
|
26
|
+
field :description, :string, nullable: true
|
|
27
|
+
field :created_at, :string, nullable: true, wire_name: "createdAt"
|
|
28
|
+
field :subscribers, :integer, nullable: true
|
|
29
|
+
field :invite, :string, nullable: true
|
|
30
|
+
field :verification, [:enum, NEWSLETTER_VERIFICATIONS], nullable: true
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Blueticks
|
|
6
|
+
module Types
|
|
7
|
+
# Generic `{ "ok": true }` acknowledgement returned by side-effecting
|
|
8
|
+
# endpoints (chat archive/mark-read, message pin/unpin/react).
|
|
9
|
+
class OkResult < Base
|
|
10
|
+
field :ok, [:enum, [true]]
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "../errors"
|
|
5
|
+
|
|
6
|
+
module Blueticks
|
|
7
|
+
module Types
|
|
8
|
+
# Offset-paginated list envelope. Every v1 list endpoint returns this shape
|
|
9
|
+
# inside the success/data wrapper: `{ data: [...], limit, skip, total }`.
|
|
10
|
+
#
|
|
11
|
+
# Iterate `data` for the current page; advance by passing `skip: skip + limit`
|
|
12
|
+
# (or any offset) back on the next list call. `total` is the full match count
|
|
13
|
+
# across all pages. `has_more` is populated only by endpoints that echo a
|
|
14
|
+
# `hasMore` flag (e.g. messages.list); nil elsewhere.
|
|
15
|
+
class PaginatedPage
|
|
16
|
+
attr_reader :data, :limit, :skip, :total, :has_more
|
|
17
|
+
|
|
18
|
+
def initialize(data:, limit:, skip:, total:, has_more: nil)
|
|
19
|
+
@data = data
|
|
20
|
+
@limit = limit
|
|
21
|
+
@skip = skip
|
|
22
|
+
@total = total
|
|
23
|
+
@has_more = has_more
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Build a PaginatedPage from a raw list envelope, decoding each item via
|
|
27
|
+
# item_type.from_hash. Reads `data`/`limit`/`skip`/`total` (and optional
|
|
28
|
+
# `hasMore`) off the envelope; ignores the `success` flag.
|
|
29
|
+
def self.from_hash(raw, item_type:)
|
|
30
|
+
unless raw.is_a?(Hash)
|
|
31
|
+
raise Errors::ValidationError.new(message: "Expected Hash for PaginatedPage, got #{raw.class}")
|
|
32
|
+
end
|
|
33
|
+
unless raw["data"].is_a?(Array)
|
|
34
|
+
raise Errors::ValidationError.new(message: "Field 'data' must be array in PaginatedPage")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
limit = require_integer(raw, "limit")
|
|
38
|
+
skip = require_integer(raw, "skip")
|
|
39
|
+
total = require_integer(raw, "total")
|
|
40
|
+
|
|
41
|
+
has_more = raw["hasMore"]
|
|
42
|
+
unless has_more.nil? || [true, false].include?(has_more)
|
|
43
|
+
raise Errors::ValidationError.new(message: "Field 'hasMore' must be boolean or absent in PaginatedPage")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
decoded = raw["data"].each_with_index.map do |item, i|
|
|
47
|
+
item_type.from_hash(item, context: "PaginatedPage.data[#{i}]")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
new(data: decoded, limit: limit, skip: skip, total: total, has_more: has_more)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.require_integer(raw, key)
|
|
54
|
+
value = raw[key]
|
|
55
|
+
unless value.is_a?(Integer) && !value.is_a?(TrueClass) && !value.is_a?(FalseClass)
|
|
56
|
+
raise Errors::ValidationError.new(message: "Field '#{key}' must be integer in PaginatedPage")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
value
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def to_h
|
|
63
|
+
{
|
|
64
|
+
data: data.map { |d| d.respond_to?(:to_h) ? d.to_h : d },
|
|
65
|
+
limit: limit, skip: skip, total: total, has_more: has_more
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
data/lib/blueticks/types/ping.rb
CHANGED
|
@@ -4,11 +4,19 @@ require_relative "base"
|
|
|
4
4
|
|
|
5
5
|
module Blueticks
|
|
6
6
|
module Types
|
|
7
|
+
# A connected WhatsApp engine as summarized on the ping response.
|
|
8
|
+
class PingConnection < Base
|
|
9
|
+
field :id, :string
|
|
10
|
+
field :type, [:enum, %w[gateway regular]]
|
|
11
|
+
field :connected, [:enum, [true]]
|
|
12
|
+
end
|
|
13
|
+
|
|
7
14
|
# Response from GET /v1/ping.
|
|
8
15
|
class Ping < Base
|
|
9
|
-
field :
|
|
10
|
-
field :
|
|
11
|
-
field :
|
|
16
|
+
field :api, [:enum, %w[ok]]
|
|
17
|
+
field :account_id, :string, wire_name: "accountId"
|
|
18
|
+
field :whatsapp_connections, [:array, PingConnection], wire_name: "whatsappConnections"
|
|
19
|
+
field :message, :string, optional: true
|
|
12
20
|
end
|
|
13
21
|
end
|
|
14
22
|
end
|
|
@@ -1,23 +1,37 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "
|
|
3
|
+
require_relative "messages"
|
|
4
4
|
|
|
5
5
|
module Blueticks
|
|
6
6
|
module Types
|
|
7
|
+
# A queued / scheduled outbound message record — the shape returned by
|
|
8
|
+
# every scheduled_messages.* endpoint. This is a DISTINCT inline schema in
|
|
9
|
+
# the spec (not MessageResponse): only `to`, `type`, `status`, `createdAt`
|
|
10
|
+
# are required. In particular `waMessageKey` is optional and ABSENT on a
|
|
11
|
+
# record that has not dispatched yet, so it must never be decoded through a
|
|
12
|
+
# type that requires it (see Types::Message, used only by messages.create).
|
|
7
13
|
class ScheduledMessage < Base
|
|
8
|
-
field :id, :string
|
|
9
|
-
field :
|
|
10
|
-
field :
|
|
11
|
-
field :
|
|
12
|
-
field :
|
|
13
|
-
field :
|
|
14
|
-
field :
|
|
15
|
-
field :
|
|
16
|
-
field :
|
|
17
|
-
field :
|
|
18
|
-
field :
|
|
19
|
-
field :
|
|
20
|
-
field :
|
|
14
|
+
field :id, :string, optional: true
|
|
15
|
+
field :wa_message_key, WaMessageKey, optional: true, nullable: true, wire_name: "waMessageKey"
|
|
16
|
+
field :to, :string
|
|
17
|
+
field :type, [:enum, MESSAGE_KINDS]
|
|
18
|
+
field :text, :string, optional: true, nullable: true
|
|
19
|
+
field :media_url, :string, optional: true, nullable: true, wire_name: "mediaUrl"
|
|
20
|
+
field :media_kind, [:enum, MESSAGE_MEDIA_KINDS], optional: true, nullable: true, wire_name: "mediaKind"
|
|
21
|
+
field :poll_question, :string, optional: true, nullable: true, wire_name: "pollQuestion"
|
|
22
|
+
field :poll_options, %i[array string], optional: true, nullable: true, wire_name: "pollOptions"
|
|
23
|
+
field :poll_allow_multiple, :boolean, optional: true, nullable: true, wire_name: "pollAllowMultiple"
|
|
24
|
+
field :status, [:enum, MESSAGE_STATUSES]
|
|
25
|
+
field :send_at, :string, optional: true, nullable: true, wire_name: "sendAt"
|
|
26
|
+
field :created_at, :string, wire_name: "createdAt"
|
|
27
|
+
field :confirmed_at, :string, optional: true, nullable: true, wire_name: "confirmedAt"
|
|
28
|
+
field :received_at, :string, optional: true, nullable: true, wire_name: "receivedAt"
|
|
29
|
+
field :read_at, :string, optional: true, nullable: true, wire_name: "readAt"
|
|
30
|
+
field :played_at, :string, optional: true, nullable: true, wire_name: "playedAt"
|
|
31
|
+
field :failed_at, :string, optional: true, nullable: true, wire_name: "failedAt"
|
|
32
|
+
field :failure_reason, :string, optional: true, nullable: true, wire_name: "failureReason"
|
|
33
|
+
field :secret, :string, optional: true, nullable: true
|
|
34
|
+
field :link_preview, LinkPreview, optional: true, wire_name: "linkPreview"
|
|
21
35
|
end
|
|
22
36
|
end
|
|
23
37
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Blueticks
|
|
6
|
+
module Types
|
|
7
|
+
SONG_CLIP_STATUSES = %w[submitted queued running streaming complete error].freeze
|
|
8
|
+
|
|
9
|
+
# Suno credit / plan usage (AccountUsageResponse) from GET /v1/suno/account.
|
|
10
|
+
class SunoAccount < Base
|
|
11
|
+
field :credits_left, :number, wire_name: "creditsLeft"
|
|
12
|
+
field :monthly_limit, :number, nullable: true, wire_name: "monthlyLimit"
|
|
13
|
+
field :monthly_usage, :number, nullable: true, wire_name: "monthlyUsage"
|
|
14
|
+
field :plan, :string, nullable: true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# A generated song clip (SongClip / GetSongResponse).
|
|
18
|
+
class SongClip < Base
|
|
19
|
+
field :id, :string
|
|
20
|
+
field :status, [:enum, SONG_CLIP_STATUSES]
|
|
21
|
+
field :audio_url, :string, nullable: true, wire_name: "audioUrl"
|
|
22
|
+
field :image_url, :string, nullable: true, wire_name: "imageUrl"
|
|
23
|
+
field :title, :string, nullable: true
|
|
24
|
+
field :duration_sec, :number, nullable: true, wire_name: "durationSec"
|
|
25
|
+
field :model, :string, nullable: true
|
|
26
|
+
field :error_type, :string, nullable: true, optional: true, wire_name: "errorType"
|
|
27
|
+
field :error_message, :string, nullable: true, optional: true, wire_name: "errorMessage"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Result of submitting a song generation job (GenerateSongResponse).
|
|
31
|
+
class GenerateSongResult < Base
|
|
32
|
+
field :job_id, :string, wire_name: "jobId"
|
|
33
|
+
field :clips, [:array, SongClip]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Result of registering a reference-audio upload (CreateUploadResponse).
|
|
37
|
+
class CreateUploadResult < Base
|
|
38
|
+
field :upload_id, :string, wire_name: "uploadId"
|
|
39
|
+
field :status, :string
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|