@yaebal/test 0.0.1 → 0.2.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.
Files changed (107) hide show
  1. package/README.md +400 -15
  2. package/lib/api.d.ts +83 -0
  3. package/lib/api.d.ts.map +1 -0
  4. package/lib/api.js +186 -0
  5. package/lib/api.js.map +1 -0
  6. package/lib/api.test.d.ts +2 -0
  7. package/lib/api.test.d.ts.map +1 -0
  8. package/lib/api.test.js +131 -0
  9. package/lib/api.test.js.map +1 -0
  10. package/lib/bot-messages.d.ts +42 -0
  11. package/lib/bot-messages.d.ts.map +1 -0
  12. package/lib/bot-messages.js +72 -0
  13. package/lib/bot-messages.js.map +1 -0
  14. package/lib/chat-actor.d.ts +45 -0
  15. package/lib/chat-actor.d.ts.map +1 -0
  16. package/lib/chat-actor.js +72 -0
  17. package/lib/chat-actor.js.map +1 -0
  18. package/lib/clock.d.ts +22 -0
  19. package/lib/clock.d.ts.map +1 -0
  20. package/lib/clock.js +72 -0
  21. package/lib/clock.js.map +1 -0
  22. package/lib/clock.test.d.ts +2 -0
  23. package/lib/clock.test.d.ts.map +1 -0
  24. package/lib/clock.test.js +69 -0
  25. package/lib/clock.test.js.map +1 -0
  26. package/lib/env.d.ts +100 -0
  27. package/lib/env.d.ts.map +1 -0
  28. package/lib/env.js +164 -0
  29. package/lib/env.js.map +1 -0
  30. package/lib/env.test.d.ts +2 -0
  31. package/lib/env.test.d.ts.map +1 -0
  32. package/lib/env.test.js +302 -0
  33. package/lib/env.test.js.map +1 -0
  34. package/lib/fetch.d.ts +3 -0
  35. package/lib/fetch.d.ts.map +1 -0
  36. package/lib/fetch.js +12 -0
  37. package/lib/fetch.js.map +1 -0
  38. package/lib/index.d.ts +19 -52
  39. package/lib/index.d.ts.map +1 -1
  40. package/lib/index.js +19 -115
  41. package/lib/index.js.map +1 -1
  42. package/lib/internal.d.ts +25 -0
  43. package/lib/internal.d.ts.map +1 -0
  44. package/lib/internal.js +19 -0
  45. package/lib/internal.js.map +1 -0
  46. package/lib/keyboard.d.ts +15 -0
  47. package/lib/keyboard.d.ts.map +1 -0
  48. package/lib/keyboard.js +25 -0
  49. package/lib/keyboard.js.map +1 -0
  50. package/lib/keyboard.test.d.ts +2 -0
  51. package/lib/keyboard.test.d.ts.map +1 -0
  52. package/lib/keyboard.test.js +31 -0
  53. package/lib/keyboard.test.js.map +1 -0
  54. package/lib/normalize.d.ts +10 -0
  55. package/lib/normalize.d.ts.map +1 -0
  56. package/lib/normalize.js +27 -0
  57. package/lib/normalize.js.map +1 -0
  58. package/lib/reactions.d.ts +3 -0
  59. package/lib/reactions.d.ts.map +1 -0
  60. package/lib/reactions.js +17 -0
  61. package/lib/reactions.js.map +1 -0
  62. package/lib/updates.d.ts +126 -0
  63. package/lib/updates.d.ts.map +1 -0
  64. package/lib/updates.js +200 -0
  65. package/lib/updates.js.map +1 -0
  66. package/lib/updates.test.d.ts +2 -0
  67. package/lib/updates.test.d.ts.map +1 -0
  68. package/lib/updates.test.js +72 -0
  69. package/lib/updates.test.js.map +1 -0
  70. package/lib/user-actor.d.ts +188 -0
  71. package/lib/user-actor.d.ts.map +1 -0
  72. package/lib/user-actor.js +465 -0
  73. package/lib/user-actor.js.map +1 -0
  74. package/lib/webhook.d.ts +18 -0
  75. package/lib/webhook.d.ts.map +1 -0
  76. package/lib/webhook.js +25 -0
  77. package/lib/webhook.js.map +1 -0
  78. package/lib/webhook.test.d.ts +2 -0
  79. package/lib/webhook.test.d.ts.map +1 -0
  80. package/lib/webhook.test.js +36 -0
  81. package/lib/webhook.test.js.map +1 -0
  82. package/package.json +7 -5
  83. package/src/api.test.ts +180 -0
  84. package/src/api.ts +289 -0
  85. package/src/bot-messages.ts +117 -0
  86. package/src/chat-actor.ts +101 -0
  87. package/src/clock.test.ts +80 -0
  88. package/src/clock.ts +118 -0
  89. package/src/env.test.ts +370 -0
  90. package/src/env.ts +235 -0
  91. package/src/fetch.ts +11 -0
  92. package/src/index.ts +79 -169
  93. package/src/internal.ts +43 -0
  94. package/src/keyboard.test.ts +35 -0
  95. package/src/keyboard.ts +38 -0
  96. package/src/normalize.ts +34 -0
  97. package/src/reactions.ts +18 -0
  98. package/src/updates.test.ts +107 -0
  99. package/src/updates.ts +354 -0
  100. package/src/user-actor.ts +702 -0
  101. package/src/webhook.test.ts +54 -0
  102. package/src/webhook.ts +48 -0
  103. package/lib/index.test.d.ts +0 -2
  104. package/lib/index.test.d.ts.map +0 -1
  105. package/lib/index.test.js +0 -66
  106. package/lib/index.test.js.map +0 -1
  107. package/src/index.test.ts +0 -101
package/src/updates.ts ADDED
@@ -0,0 +1,354 @@
1
+ /**
2
+ * fixture builders — the escape hatch beneath the actor api. every actor
3
+ * method ({@link UserActor.sendMessage} & co.) is sugar over one of these;
4
+ * reach for them directly when you need an update shape the actors don't
5
+ * cover, or want full control over every field.
6
+ */
7
+ import type { Message, Update, UpdateName, User } from "@yaebal/core";
8
+
9
+ /** the payload type for a given update kind — reuses core's `Update` shape, no extra types package needed. */
10
+ type Payload<K extends UpdateName> = NonNullable<Update[K]>;
11
+
12
+ let updateIdCounter = 0;
13
+ let userIdCounter = 0;
14
+
15
+ /** build an {@link Update} from a partial, filling in a fresh `update_id`. */
16
+ export function createUpdate(partial: Partial<Update> = {}): Update {
17
+ return { update_id: ++updateIdCounter, ...partial };
18
+ }
19
+
20
+ /** options for {@link buildUser}. */
21
+ export interface BuildUserOptions {
22
+ id?: number;
23
+ firstName?: string;
24
+ lastName?: string;
25
+ username?: string;
26
+ languageCode?: string;
27
+ isBot?: boolean;
28
+ }
29
+
30
+ /** build a {@link User}, auto-allocating an id if none is given. */
31
+ export function buildUser(options: BuildUserOptions = {}): User {
32
+ const {
33
+ id = ++userIdCounter,
34
+ firstName = "u",
35
+ lastName,
36
+ username,
37
+ languageCode,
38
+ isBot = false,
39
+ } = options;
40
+
41
+ return {
42
+ id,
43
+ is_bot: isBot,
44
+ first_name: firstName,
45
+ ...(lastName !== undefined ? { last_name: lastName } : {}),
46
+ ...(username !== undefined ? { username } : {}),
47
+ ...(languageCode !== undefined ? { language_code: languageCode } : {}),
48
+ };
49
+ }
50
+
51
+ const stubUser = (id: number) => buildUser({ id });
52
+
53
+ /** options shared by the message-shaped factories (`message`, `edited_message`, `channel_post`, ...). */
54
+ export interface MessageUpdateOptions {
55
+ text?: string;
56
+ chatId?: number;
57
+ fromId?: number;
58
+ chatType?: "private" | "group" | "supergroup" | "channel";
59
+ }
60
+
61
+ function buildMessage(
62
+ options: MessageUpdateOptions,
63
+ defaultChatType: NonNullable<MessageUpdateOptions["chatType"]>,
64
+ ): Message {
65
+ const { text = "", chatId = 1, fromId = chatId, chatType = defaultChatType } = options;
66
+
67
+ return {
68
+ message_id: 1,
69
+ date: 0,
70
+ chat: { id: chatId, type: chatType },
71
+ from: stubUser(fromId),
72
+ text,
73
+ };
74
+ }
75
+
76
+ /** build a `message` {@link Update}. */
77
+ export function messageUpdate(options: MessageUpdateOptions = {}): Update {
78
+ return createUpdate({ message: buildMessage(options, "private") });
79
+ }
80
+
81
+ /** build an `edited_message` {@link Update}. */
82
+ export function editedMessageUpdate(options: MessageUpdateOptions = {}): Update {
83
+ return createUpdate({ edited_message: buildMessage(options, "private") });
84
+ }
85
+
86
+ /** build a `channel_post` {@link Update}. */
87
+ export function channelPostUpdate(options: MessageUpdateOptions = {}): Update {
88
+ return createUpdate({ channel_post: buildMessage(options, "channel") });
89
+ }
90
+
91
+ /** build an `edited_channel_post` {@link Update}. */
92
+ export function editedChannelPostUpdate(options: MessageUpdateOptions = {}): Update {
93
+ return createUpdate({ edited_channel_post: buildMessage(options, "channel") });
94
+ }
95
+
96
+ /** options for {@link callbackUpdate}. */
97
+ export interface CallbackUpdateOptions {
98
+ data?: string;
99
+ chatId?: number;
100
+ fromId?: number;
101
+ message?: Message;
102
+ }
103
+
104
+ /** build a `callback_query` {@link Update}. */
105
+ export function callbackUpdate(options: CallbackUpdateOptions = {}): Update {
106
+ const { data = "", chatId = 1, fromId = chatId, message } = options;
107
+
108
+ return createUpdate({
109
+ callback_query: {
110
+ id: "1",
111
+ chat_instance: "0",
112
+ from: stubUser(fromId),
113
+ message: message ?? {
114
+ message_id: 1,
115
+ date: 0,
116
+ chat: { id: chatId, type: "private" },
117
+ },
118
+ data,
119
+ },
120
+ });
121
+ }
122
+
123
+ /** options for {@link inlineQueryUpdate}. */
124
+ export interface InlineQueryUpdateOptions {
125
+ query?: string;
126
+ fromId?: number;
127
+ id?: string;
128
+ offset?: string;
129
+ chatType?: Payload<"inline_query">["chat_type"];
130
+ }
131
+
132
+ /** build an `inline_query` {@link Update}. */
133
+ export function inlineQueryUpdate(options: InlineQueryUpdateOptions = {}): Update {
134
+ const { query = "", fromId = 1, id = "1", offset = "", chatType } = options;
135
+
136
+ return createUpdate({
137
+ inline_query: {
138
+ id,
139
+ from: stubUser(fromId),
140
+ query,
141
+ offset,
142
+ ...(chatType ? { chat_type: chatType } : {}),
143
+ },
144
+ });
145
+ }
146
+
147
+ /** options for {@link chosenInlineResultUpdate}. */
148
+ export interface ChosenInlineResultUpdateOptions {
149
+ resultId?: string;
150
+ fromId?: number;
151
+ query?: string;
152
+ inlineMessageId?: string;
153
+ }
154
+
155
+ /** build a `chosen_inline_result` {@link Update}. */
156
+ export function chosenInlineResultUpdate(options: ChosenInlineResultUpdateOptions = {}): Update {
157
+ const { resultId = "1", fromId = 1, query = "", inlineMessageId } = options;
158
+
159
+ return createUpdate({
160
+ chosen_inline_result: {
161
+ result_id: resultId,
162
+ from: stubUser(fromId),
163
+ query,
164
+ ...(inlineMessageId ? { inline_message_id: inlineMessageId } : {}),
165
+ },
166
+ });
167
+ }
168
+
169
+ /** options for {@link shippingQueryUpdate}. */
170
+ export interface ShippingQueryUpdateOptions {
171
+ id?: string;
172
+ fromId?: number;
173
+ invoicePayload?: string;
174
+ shippingAddress?: Partial<Payload<"shipping_query">["shipping_address"]>;
175
+ }
176
+
177
+ /** build a `shipping_query` {@link Update}. */
178
+ export function shippingQueryUpdate(options: ShippingQueryUpdateOptions = {}): Update {
179
+ const { id = "1", fromId = 1, invoicePayload = "", shippingAddress = {} } = options;
180
+
181
+ return createUpdate({
182
+ shipping_query: {
183
+ id,
184
+ from: stubUser(fromId),
185
+ invoice_payload: invoicePayload,
186
+ shipping_address: {
187
+ country_code: "US",
188
+ state: "",
189
+ city: "New York",
190
+ street_line1: "",
191
+ street_line2: "",
192
+ post_code: "10001",
193
+ ...shippingAddress,
194
+ },
195
+ },
196
+ });
197
+ }
198
+
199
+ /** options for {@link preCheckoutQueryUpdate}. */
200
+ export interface PreCheckoutQueryUpdateOptions {
201
+ id?: string;
202
+ fromId?: number;
203
+ currency?: string;
204
+ totalAmount?: number;
205
+ invoicePayload?: string;
206
+ }
207
+
208
+ /** build a `pre_checkout_query` {@link Update}. */
209
+ export function preCheckoutQueryUpdate(options: PreCheckoutQueryUpdateOptions = {}): Update {
210
+ const {
211
+ id = "1",
212
+ fromId = 1,
213
+ currency = "USD",
214
+ totalAmount = 100,
215
+ invoicePayload = "",
216
+ } = options;
217
+
218
+ return createUpdate({
219
+ pre_checkout_query: {
220
+ id,
221
+ from: stubUser(fromId),
222
+ currency,
223
+ total_amount: totalAmount,
224
+ invoice_payload: invoicePayload,
225
+ },
226
+ });
227
+ }
228
+
229
+ /** options for {@link pollUpdate}. */
230
+ export interface PollUpdateOptions {
231
+ id?: string;
232
+ question?: string;
233
+ options?: string[];
234
+ isClosed?: boolean;
235
+ }
236
+
237
+ /** build a `poll` {@link Update}. */
238
+ export function pollUpdate(options: PollUpdateOptions = {}): Update {
239
+ const { id = "1", question = "", options: choices = ["yes", "no"], isClosed = false } = options;
240
+
241
+ return createUpdate({
242
+ poll: {
243
+ id,
244
+ question,
245
+ options: choices.map((text, i) => ({ persistent_id: String(i), text, voter_count: 0 })),
246
+ total_voter_count: 0,
247
+ is_closed: isClosed,
248
+ is_anonymous: true,
249
+ type: "regular",
250
+ allows_multiple_answers: false,
251
+ allows_revoting: false,
252
+ members_only: false,
253
+ },
254
+ });
255
+ }
256
+
257
+ /** options for {@link pollAnswerUpdate}. */
258
+ export interface PollAnswerUpdateOptions {
259
+ pollId?: string;
260
+ fromId?: number;
261
+ optionIds?: number[];
262
+ }
263
+
264
+ /** build a `poll_answer` {@link Update}. */
265
+ export function pollAnswerUpdate(options: PollAnswerUpdateOptions = {}): Update {
266
+ const { pollId = "1", fromId = 1, optionIds = [0] } = options;
267
+
268
+ return createUpdate({
269
+ poll_answer: {
270
+ poll_id: pollId,
271
+ user: stubUser(fromId),
272
+ option_ids: optionIds,
273
+ option_persistent_ids: optionIds.map(String),
274
+ },
275
+ });
276
+ }
277
+
278
+ /** options for {@link myChatMemberUpdate} / {@link chatMemberUpdate}. */
279
+ export interface ChatMemberUpdateOptions {
280
+ chatId?: number;
281
+ fromId?: number;
282
+ userId?: number;
283
+ oldStatus?: string;
284
+ newStatus?: string;
285
+ }
286
+
287
+ function buildChatMemberUpdate(options: ChatMemberUpdateOptions): Payload<"my_chat_member"> {
288
+ const {
289
+ chatId = 1,
290
+ fromId = chatId,
291
+ userId = fromId,
292
+ oldStatus = "member",
293
+ newStatus = "member",
294
+ } = options;
295
+ const user = stubUser(userId);
296
+
297
+ return {
298
+ chat: { id: chatId, type: "group" },
299
+ from: stubUser(fromId),
300
+ date: 0,
301
+ old_chat_member: { status: oldStatus, user },
302
+ new_chat_member: { status: newStatus, user },
303
+ };
304
+ }
305
+
306
+ /** build a `my_chat_member` {@link Update} (the bot's own membership changed). */
307
+ export function myChatMemberUpdate(options: ChatMemberUpdateOptions = {}): Update {
308
+ return createUpdate({ my_chat_member: buildChatMemberUpdate(options) });
309
+ }
310
+
311
+ /** build a `chat_member` {@link Update} (another member's membership changed). */
312
+ export function chatMemberUpdate(options: ChatMemberUpdateOptions = {}): Update {
313
+ return createUpdate({ chat_member: buildChatMemberUpdate(options) });
314
+ }
315
+
316
+ /** options for {@link chatJoinRequestUpdate}. */
317
+ export interface ChatJoinRequestUpdateOptions {
318
+ chatId?: number;
319
+ fromId?: number;
320
+ userChatId?: number;
321
+ bio?: string;
322
+ }
323
+
324
+ /** build a `chat_join_request` {@link Update}. */
325
+ export function chatJoinRequestUpdate(options: ChatJoinRequestUpdateOptions = {}): Update {
326
+ const { chatId = 1, fromId = 1, userChatId = fromId, bio } = options;
327
+
328
+ return createUpdate({
329
+ chat_join_request: {
330
+ chat: { id: chatId, type: "group" },
331
+ from: stubUser(fromId),
332
+ user_chat_id: userChatId,
333
+ date: 0,
334
+ ...(bio ? { bio } : {}),
335
+ },
336
+ });
337
+ }
338
+
339
+ /** infer which payload key an update carries; defaults to `"message"`. */
340
+ export function detectUpdateType(update: Update): UpdateName {
341
+ if (update.message) return "message";
342
+ if (update.edited_message) return "edited_message";
343
+ if (update.channel_post) return "channel_post";
344
+ if (update.callback_query) return "callback_query";
345
+
346
+ const bag = update as unknown as Record<string, unknown>;
347
+ for (const key of Object.keys(bag)) {
348
+ if (key !== "update_id" && bag[key] !== undefined) return key as UpdateName;
349
+ }
350
+
351
+ return "message";
352
+ }
353
+
354
+ export type { Message, Update, UpdateName, User };