meta-sovereign 0.49.14 → 0.49.16

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 (88) hide show
  1. package/js/src/server/background-jobs.js +3 -1
  2. package/js/src/server/backup-job.js +1 -0
  3. package/js/src/server/index.js +2 -2
  4. package/js/src/server/routes-telegram-channel-manage.js +79 -0
  5. package/js/src/server/routes-telegram-contact-extras.js +102 -0
  6. package/js/src/server/routes-telegram-emoji-groups.js +20 -0
  7. package/js/src/server/routes-telegram-security-extras.js +64 -0
  8. package/js/src/server/routes-telegram-storage.js +73 -0
  9. package/js/src/server/routes-telegram-translate-chat.js +31 -0
  10. package/js/src/server/routes-telegram-yextras.js +17 -0
  11. package/js/src/server/routes-telegram.js +6 -0
  12. package/js/src/sources/secret-chat-crypto.js +275 -0
  13. package/js/src/sources/secret-chat-session.js +178 -0
  14. package/js/src/sources/secret-chat-tl.js +418 -0
  15. package/js/src/sources/telegram-actions.js +25 -3
  16. package/js/src/sources/telegram-channel-manage.js +263 -0
  17. package/js/src/sources/telegram-chat-info.js +19 -0
  18. package/js/src/sources/telegram-chat-removal.js +21 -2
  19. package/js/src/sources/telegram-contact-extras.js +290 -0
  20. package/js/src/sources/telegram-emoji-groups.js +95 -0
  21. package/js/src/sources/telegram-format.js +39 -4
  22. package/js/src/sources/telegram-notify-extras.js +144 -0
  23. package/js/src/sources/telegram-security-extras.js +208 -0
  24. package/js/src/sources/telegram-security.js +5 -0
  25. package/js/src/sources/telegram-stickers.js +6 -1
  26. package/js/src/sources/telegram-storage.js +380 -0
  27. package/js/src/sources/telegram-translate-chat.js +57 -0
  28. package/js/src/sources/telegram-translate.js +5 -5
  29. package/js/src/sources/telegram-write-outcome.js +40 -0
  30. package/js/src/storage/backup.js +17 -3
  31. package/js/src/web/app.css +220 -1
  32. package/js/src/web/app.js +5 -0
  33. package/js/src/web/auto-download.js +37 -0
  34. package/js/src/web/chat-actions.js +50 -28
  35. package/js/src/web/chat-channel-limit.js +142 -0
  36. package/js/src/web/chat-contact-extras.js +396 -0
  37. package/js/src/web/chat-contact-share.js +109 -0
  38. package/js/src/web/chat-contacts-synced.js +64 -0
  39. package/js/src/web/chat-contacts-window.js +24 -1
  40. package/js/src/web/chat-drafts-clear.js +52 -24
  41. package/js/src/web/chat-edit.js +3 -0
  42. package/js/src/web/chat-emoji-custom.js +338 -0
  43. package/js/src/web/chat-emoji-status.js +21 -9
  44. package/js/src/web/chat-emoji-tools.js +17 -1
  45. package/js/src/web/chat-emoji.js +214 -72
  46. package/js/src/web/chat-failure.js +2 -0
  47. package/js/src/web/chat-group-stickers.js +3 -10
  48. package/js/src/web/chat-invite.js +12 -1
  49. package/js/src/web/chat-manage.js +303 -0
  50. package/js/src/web/chat-message.js +19 -8
  51. package/js/src/web/chat-paid-send.js +14 -8
  52. package/js/src/web/chat-privacy.js +19 -0
  53. package/js/src/web/chat-profile-extras.js +4 -4
  54. package/js/src/web/chat-public-link.js +314 -0
  55. package/js/src/web/chat-replies-block.js +91 -0
  56. package/js/src/web/chat-security-extras.js +303 -0
  57. package/js/src/web/chat-security-forgot.js +240 -0
  58. package/js/src/web/chat-security.js +9 -0
  59. package/js/src/web/chat-selection.js +28 -8
  60. package/js/src/web/chat-sign-in-code.js +62 -0
  61. package/js/src/web/chat-similar.js +14 -1
  62. package/js/src/web/chat-translate-bar.js +293 -0
  63. package/js/src/web/chat-translate.js +93 -27
  64. package/js/src/web/chat-translation-switch.js +20 -22
  65. package/js/src/web/chat-view.js +6 -0
  66. package/js/src/web/contact-links.js +171 -0
  67. package/js/src/web/dom-telegram-calls.js +53 -0
  68. package/js/src/web/dom.js +3 -1
  69. package/js/src/web/locales/en-chat-account.js +225 -0
  70. package/js/src/web/locales/hi-chat-account.js +222 -0
  71. package/js/src/web/locales/ru-chat-account.js +222 -0
  72. package/js/src/web/locales/zh-chat-account.js +206 -0
  73. package/js/src/web/message-text.js +5 -2
  74. package/js/src/web/passkey-codec.js +100 -0
  75. package/js/src/web/person-panel.js +3 -0
  76. package/js/src/web/settings-confirm.js +62 -0
  77. package/js/src/web/settings-fields.js +47 -0
  78. package/js/src/web/settings-media.js +21 -1
  79. package/js/src/web/settings-notify-extras.js +160 -0
  80. package/js/src/web/settings-notify.js +16 -4
  81. package/js/src/web/settings-storage.js +235 -0
  82. package/js/src/web/settings-view.js +5 -1
  83. package/js/src/web/sign-in-code-guard.js +91 -0
  84. package/js/src/web/translate-detect.js +108 -0
  85. package/js/src/web/translate-store.js +140 -0
  86. package/js/src/web/tutorial-clear.js +50 -4
  87. package/js/src/web/use-redraw.js +14 -0
  88. package/package.json +14 -2
@@ -78,14 +78,16 @@ export const backgroundJobs = ({ ctx, store, log, later, backups }) => {
78
78
  });
79
79
  const purge = cachePurgeFor({ store, log, later });
80
80
  return {
81
+ // Returns a promise settled once a backup in flight has finished.
81
82
  stopJobs: () => {
82
- backup.stopBackups();
83
+ const backupDone = backup.stopBackups();
83
84
  audience.stopAudienceSync();
84
85
  purge.stopCachePurge();
85
86
  // The other timers and pollers the server started with the port.
86
87
  ctx.autoImport?.close();
87
88
  ctx.whatsappSignIn?.stop().catch(() => {});
88
89
  ctx.stopPulls?.();
90
+ return backupDone;
89
91
  },
90
92
  };
91
93
  };
@@ -87,5 +87,6 @@ export const backupJobFor = ({ ctx, store, log, later, backups }) => {
87
87
  });
88
88
  });
89
89
  }
90
+ // Resolves once a backup in flight has finished (and pruned).
90
91
  return { stopBackups: () => scheduler?.stop() };
91
92
  };
@@ -916,13 +916,13 @@ export const startServer = async ({
916
916
  bus?.close();
917
917
  ctx.replies.close().catch(() => {});
918
918
  ctx.closeAutomations().catch(() => {});
919
- ctx.stopJobs();
919
+ const jobsDone = ctx.stopJobs();
920
920
  ctx.chatIndex.close();
921
921
  stopAll(telegramAccount, ctx.telegramAccounts, ctx.telegramExtras);
922
922
  wsHandle?.close();
923
923
  signaling?.close();
924
924
  closeFront();
925
- server.close(() => resolve());
925
+ server.close(() => Promise.resolve(jobsDone).then(resolve, resolve));
926
926
  for (const socket of sockets) {
927
927
  socket.destroy();
928
928
  }
@@ -0,0 +1,79 @@
1
+ // Managing a channel or group (R-Y216): the routes of the POSTS table in
2
+ // routes-telegram.js, each validated strictly before the account is asked.
3
+ // The source validates again; this keeps junk off the account. Deleting a
4
+ // chat for everyone is `remove-chat` with the action `destroy`.
5
+ //
6
+ // Its routes:
7
+ // POST /api/telegram/channel-username-check {chat, username} -> { ok,
8
+ // status } whether the public link is free, or a
9
+ // code: invalid, taken, too-many-public (R-Y216)
10
+ // POST /api/telegram/channel-username-save {chat, username} -> { ok } the
11
+ // public link set; '' makes the chat private
12
+ // POST /api/telegram/public-channels {} -> { ok, channels } the user's
13
+ // public channels, for "Revoke link"
14
+ // POST /api/telegram/public-link-revoke {chat} -> { ok } one of them
15
+ // made private
16
+ // POST /api/telegram/usernames-deactivate {chat} -> { ok } every
17
+ // collectible username of the chat deactivated
18
+ // POST /api/telegram/channel-color-save {chat, forProfile, color?, emoji?}
19
+ // -> { ok } the name or profile colour (boosts needed)
20
+ // POST /api/telegram/channel-emoji-status {chat, documentId, until?} ->
21
+ // { ok } the channel's emoji status (null removes it)
22
+ // POST /api/telegram/inactive-channels {} -> { ok, channels } channels the
23
+ // user could leave when there are too many
24
+ // POST /api/telegram/leave-channels {chats} -> { ok, left } the chosen
25
+ // inactive channels left
26
+
27
+ import { route } from './routes-telegram-admin-extras.js';
28
+
29
+ const CHANNEL = /^-100\d{1,20}$/;
30
+ const NAME = /^[A-Za-z][A-Za-z0-9_]{3,30}[A-Za-z0-9]$/;
31
+ const DIGITS = /^\d{1,20}$/;
32
+ const MAX_LEAVE = 100;
33
+
34
+ const channelOf = (b) => CHANNEL.test(String(b.chat ?? ''));
35
+ const nameOf = (b) => typeof b.username === 'string' && NAME.test(b.username);
36
+ const WHAT = 'chat required';
37
+
38
+ export const CHANNEL_MANAGE_POSTS = {
39
+ 'channel-username-check': route(
40
+ 'channelUsernameCheck',
41
+ 'chat and username required',
42
+ (b) => channelOf(b) && nameOf(b)
43
+ ),
44
+ 'channel-username-save': route(
45
+ 'channelUsernameSave',
46
+ 'chat and username required',
47
+ (b) => channelOf(b) && (b.username === '' || nameOf(b))
48
+ ),
49
+ 'public-channels': route('publicChannels', WHAT, () => true),
50
+ 'public-link-revoke': route('publicLinkRevoke', WHAT, channelOf),
51
+ 'usernames-deactivate': route('usernamesDeactivate', WHAT, channelOf),
52
+ 'channel-color-save': route(
53
+ 'channelColorSave',
54
+ 'chat and colour required',
55
+ (b) =>
56
+ channelOf(b) &&
57
+ typeof b.forProfile === 'boolean' &&
58
+ (b.color === undefined || Number.isInteger(b.color)) &&
59
+ (b.emoji === undefined || DIGITS.test(String(b.emoji)))
60
+ ),
61
+ 'channel-emoji-status': route(
62
+ 'channelEmojiStatusSet',
63
+ 'chat and status required',
64
+ (b) =>
65
+ channelOf(b) &&
66
+ (b.documentId === null || DIGITS.test(String(b.documentId))) &&
67
+ (b.until === undefined || Number.isInteger(b.until))
68
+ ),
69
+ 'inactive-channels': route('inactiveChannels', WHAT, () => true),
70
+ 'leave-channels': route(
71
+ 'leaveChannels',
72
+ 'chats required',
73
+ (b) =>
74
+ Array.isArray(b.chats) &&
75
+ b.chats.length > 0 &&
76
+ b.chats.length <= MAX_LEAVE &&
77
+ b.chats.every((x) => CHANNEL.test(String(x)))
78
+ ),
79
+ };
@@ -0,0 +1,102 @@
1
+ // Contact notes, share-my-contact links, phone links, photos for contacts,
2
+ // suggested birthdays, synced contacts and blocking from Replies (R-Y217):
3
+ // the routes of the POSTS table in routes-telegram.js, each validated
4
+ // strictly before the account is asked.
5
+ //
6
+ // Its routes:
7
+ // POST /api/telegram/contact-note {chat, note} -> { ok, note } the private
8
+ // note on a contact (at most 128 characters, "" clears)
9
+ // POST /api/telegram/contact-token {} -> { ok, url, expires } the link
10
+ // t.me/contact/<token> to share the user's contact
11
+ // POST /api/telegram/contact-token-open {token} -> { ok, chat, name } the
12
+ // person that link names
13
+ // POST /api/telegram/phone-resolve {phone} -> { ok, found, chat?, name? }
14
+ // the person with that number (t.me/+<digits>)
15
+ // POST /api/telegram/contact-photo {chat, mode, token?} -> { ok, mode }
16
+ // mode save (only the user sees it), suggest, or reset
17
+ // (the personal photo removed; no token)
18
+ // POST /api/telegram/birthday-suggest {chat, day, month, year?} -> { ok }
19
+ // POST /api/telegram/saved-contacts {} -> { ok, count } the imported
20
+ // contacts Telegram keeps
21
+ // POST /api/telegram/saved-contacts-reset {} -> { ok } those deleted
22
+ // POST /api/telegram/block-from-replies {msgId, deleteMessage?,
23
+ // deleteHistory?, reportSpam?} -> { ok } the sender
24
+ // of a message of the Replies chat blocked
25
+
26
+ import { route } from './routes-telegram-admin-extras.js';
27
+ import {
28
+ MODES,
29
+ NOTE_MAX,
30
+ PHONE_DIGITS,
31
+ TOKEN,
32
+ USER,
33
+ validMsgId,
34
+ } from '../sources/telegram-contact-extras.js';
35
+
36
+ const UPLOAD = /^[a-f0-9]{32}$/;
37
+ const user = (b) => USER.test(String(b.chat ?? ''));
38
+ const flag = (v) => v === undefined || typeof v === 'boolean';
39
+ const always = () => true;
40
+
41
+ export const CONTACT_EXTRAS_POSTS = {
42
+ 'contact-note': route(
43
+ 'contactNote',
44
+ 'chat and note required',
45
+ (b) => user(b) && typeof b.note === 'string' && b.note.length <= NOTE_MAX,
46
+ (b) => ({ chat: String(b.chat), note: b.note })
47
+ ),
48
+ 'contact-token': route('contactToken', 'unsupported', always, () => ({})),
49
+ 'contact-token-open': route(
50
+ 'contactTokenOpen',
51
+ 'token required',
52
+ (b) => typeof b.token === 'string' && TOKEN.test(b.token),
53
+ (b) => ({ token: b.token })
54
+ ),
55
+ 'phone-resolve': route(
56
+ 'phoneResolve',
57
+ 'phone required',
58
+ (b) =>
59
+ typeof b.phone === 'string' &&
60
+ PHONE_DIGITS.test(b.phone.replace(/^\+/, '')),
61
+ (b) => ({ phone: b.phone })
62
+ ),
63
+ 'contact-photo': route(
64
+ 'contactPhoto',
65
+ 'chat, mode and token required',
66
+ (b) =>
67
+ user(b) &&
68
+ MODES.includes(b.mode) &&
69
+ (b.mode === 'reset'
70
+ ? b.token === undefined
71
+ : typeof b.token === 'string' && UPLOAD.test(b.token)),
72
+ (b) => ({ chat: String(b.chat), mode: b.mode, token: b.token })
73
+ ),
74
+ 'birthday-suggest': route(
75
+ 'birthdaySuggest',
76
+ 'chat, day and month required',
77
+ (b) => user(b) && Number.isInteger(b.day) && Number.isInteger(b.month),
78
+ ({ chat, day, month, year }) => ({ chat: String(chat), day, month, year })
79
+ ),
80
+ 'saved-contacts': route('savedContacts', 'unsupported', always, () => ({})),
81
+ 'saved-contacts-reset': route(
82
+ 'savedContactsReset',
83
+ 'unsupported',
84
+ always,
85
+ () => ({})
86
+ ),
87
+ 'block-from-replies': route(
88
+ 'blockFromReplies',
89
+ 'msgId required',
90
+ (b) =>
91
+ validMsgId(b.msgId) &&
92
+ flag(b.deleteMessage) &&
93
+ flag(b.deleteHistory) &&
94
+ flag(b.reportSpam),
95
+ ({ msgId, deleteMessage, deleteHistory, reportSpam }) => ({
96
+ msgId,
97
+ deleteMessage,
98
+ deleteHistory,
99
+ reportSpam,
100
+ })
101
+ ),
102
+ };
@@ -0,0 +1,20 @@
1
+ // The emoji panel's Premium flag and category groups (R-Y214): the route
2
+ // of the POSTS table in routes-telegram.js, validated before the account
3
+ // is asked.
4
+ //
5
+ // Its routes:
6
+ // POST /api/telegram/emoji-panel-info {status?} -> { ok, premium, groups:
7
+ // [{ title, iconEmojiId, emoticons }] } whether the
8
+ // account has Premium and Telegram's emoji groups
9
+ // (status: true, the emoji status picker's)
10
+
11
+ import { route } from './routes-telegram-admin-extras.js';
12
+
13
+ export const EMOJI_GROUPS_POSTS = {
14
+ 'emoji-panel-info': route(
15
+ 'emojiPanelInfo',
16
+ 'status must be true or false',
17
+ (b) => b.status === undefined || typeof b.status === 'boolean',
18
+ (b) => ({ status: b.status === true })
19
+ ),
20
+ };
@@ -0,0 +1,64 @@
1
+ // More of Privacy and Security (R-Y218): the routes of the POSTS table in
2
+ // routes-telegram.js, each validated strictly before the account is asked.
3
+ // A code in a body is passed on and never kept.
4
+ //
5
+ // Its routes:
6
+ // POST /api/telegram/login-email-send {email} -> { ok, pattern, length }
7
+ // POST /api/telegram/login-email-verify {code} -> { ok, email }
8
+ // POST /api/telegram/recovery-request -> { ok, pattern } a code mailed to
9
+ // the recovery email
10
+ // POST /api/telegram/recovery-confirm {code} -> { ok } the password gone
11
+ // POST /api/telegram/password-reset -> { ok, result: 'ok' | 'wait' |
12
+ // 'failed-wait', until }
13
+ // POST /api/telegram/password-reset-cancel -> { ok }
14
+ // POST /api/telegram/passkeys -> { ok, passkeys: [{ id, name, created,
15
+ // lastUsed }] }
16
+ // POST /api/telegram/passkey-options -> { ok, options } WebAuthn JSON
17
+ // POST /api/telegram/passkey-register {id, rawId, clientData,
18
+ // attestation} -> { ok, passkey } (base64url strings)
19
+ // POST /api/telegram/passkey-delete {id} -> { ok }
20
+ // POST /api/telegram/sign-in-codes -> { ok, codes } fresh codes from 777000
21
+ // POST /api/telegram/invalidate-codes {codes: ['12345']} -> { ok }
22
+
23
+ import { route } from './routes-telegram-admin-extras.js';
24
+
25
+ const EMAIL = /^[^\s@]{1,64}@[^\s@]{1,255}$/;
26
+ const CODE = /^[0-9A-Za-z]{1,16}$/;
27
+ const str = (v, max) =>
28
+ typeof v === 'string' && v.length > 0 && v.length <= max;
29
+ const nothing = () => true;
30
+ const code = (b) => CODE.test(String(b.code ?? ''));
31
+
32
+ export const SECURITY_EXTRAS_POSTS = {
33
+ 'login-email-send': route('loginEmailSend', 'a valid email required', (b) =>
34
+ EMAIL.test(String(b.email ?? ''))
35
+ ),
36
+ 'login-email-verify': route('loginEmailVerify', 'the code required', code),
37
+ 'recovery-request': route('recoveryRequest', 'no body', nothing),
38
+ 'recovery-confirm': route('recoveryConfirm', 'the code required', code),
39
+ 'password-reset': route('passwordReset', 'no body', nothing),
40
+ 'password-reset-cancel': route('passwordResetCancel', 'no body', nothing),
41
+ passkeys: route('passkeys', 'no body', nothing),
42
+ 'passkey-options': route('passkeyOptions', 'no body', nothing),
43
+ 'passkey-register': route(
44
+ 'passkeyRegister',
45
+ 'id, rawId, clientData and attestation required',
46
+ (b) =>
47
+ ['id', 'rawId', 'clientData', 'attestation'].every((k) =>
48
+ str(b[k], 100_000)
49
+ )
50
+ ),
51
+ 'passkey-delete': route('passkeyDelete', 'the passkey id required', (b) =>
52
+ str(b.id, 1024)
53
+ ),
54
+ 'sign-in-codes': route('signInCodes', 'no body', nothing),
55
+ 'invalidate-codes': route(
56
+ 'invalidateCodes',
57
+ 'one to ten codes required',
58
+ (b) =>
59
+ Array.isArray(b.codes) &&
60
+ b.codes.length > 0 &&
61
+ b.codes.length <= 10 &&
62
+ b.codes.every((v) => /^\d{5,6}$/.test(String(v)))
63
+ ),
64
+ };
@@ -0,0 +1,73 @@
1
+ // Local storage management, reaction notifications, resetting the
2
+ // notification settings and Telegram's automatic-download preset (R-Y215):
3
+ // the routes of the POSTS table in routes-telegram.js, each validated
4
+ // strictly before the account is asked.
5
+ //
6
+ // Its routes:
7
+ // POST /api/telegram/storage-usage {} -> { ok, total, kinds, chats,
8
+ // limits } the media cache by kind (photos, videos,
9
+ // voice, files, stickers, other) and by chat
10
+ // POST /api/telegram/storage-clear {kind} | {all: true} -> { ok,
11
+ // removed: { bytes, files } } only files inside the
12
+ // media cache are removed
13
+ // POST /api/telegram/storage-limits {} -> { ok, maxGb, olderDays }
14
+ // POST /api/telegram/storage-limits-set {maxGb, olderDays} -> { ok, ...,
15
+ // removed } maxGb 0, 1, 5 or 20; olderDays 0, 7, 30
16
+ // or 365 (0 is none); applied at once
17
+ // POST /api/telegram/reaction-notify {} -> { ok, messages, stories,
18
+ // previews, sound } who is told of reactions
19
+ // ('nobody', 'contacts', 'all')
20
+ // POST /api/telegram/reaction-notify-set {messages?, stories?, previews?,
21
+ // sound?} -> the same row
22
+ // POST /api/telegram/notify-reset {} -> { ok } every notification
23
+ // setting back to Telegram's default
24
+ // POST /api/telegram/auto-download-preset {} -> { ok, medium: {
25
+ // disabled, photoMax, videoMax, fileMax } } bytes
26
+
27
+ import { validClear, validLimits } from '../sources/telegram-storage.js';
28
+ import { validReactionChange } from '../sources/telegram-notify-extras.js';
29
+ import { route } from './routes-telegram-admin-extras.js';
30
+
31
+ const anyone = () => true;
32
+ const nothing = () => ({});
33
+
34
+ export const STORAGE_POSTS = {
35
+ 'storage-usage': route('storageUsage', 'not supported', anyone, nothing),
36
+ 'storage-clear': route(
37
+ 'storageClear',
38
+ 'a kind or all required',
39
+ validClear,
40
+ (b) => (b.all === true ? { all: true } : { kind: b.kind })
41
+ ),
42
+ 'storage-limits': route('storageLimits', 'not supported', anyone, nothing),
43
+ 'storage-limits-set': route(
44
+ 'storageLimitsSet',
45
+ 'maxGb and olderDays required',
46
+ validLimits,
47
+ (b) => ({ maxGb: b.maxGb, olderDays: b.olderDays })
48
+ ),
49
+ 'reaction-notify': route(
50
+ 'reactionNotifyGet',
51
+ 'not supported',
52
+ anyone,
53
+ nothing
54
+ ),
55
+ 'reaction-notify-set': route(
56
+ 'reactionNotifySet',
57
+ 'a change required',
58
+ validReactionChange,
59
+ (b) => ({
60
+ messages: b.messages,
61
+ stories: b.stories,
62
+ previews: b.previews,
63
+ sound: b.sound,
64
+ })
65
+ ),
66
+ 'notify-reset': route('notifyResetAll', 'not supported', anyone, nothing),
67
+ 'auto-download-preset': route(
68
+ 'autoDownloadPreset',
69
+ 'not supported',
70
+ anyone,
71
+ nothing
72
+ ),
73
+ };
@@ -0,0 +1,31 @@
1
+ // The translate bar and the summary (R-Y213): routes of the POSTS table in
2
+ // routes-telegram.js, validated strictly before the account is asked.
3
+ //
4
+ // Its routes:
5
+ // POST /api/telegram/translate-account {} -> { ok, premium } whether the
6
+ // account has Premium (the bar is offered only then)
7
+ // POST /api/telegram/summarize {chat, id, to?} -> { ok, text, entities }
8
+ // a long message summarized (messages.summarizeText);
9
+ // refusals come as { ok: false, code }
10
+
11
+ import { route } from './routes-telegram-admin-extras.js';
12
+
13
+ const LANG = /^[a-z]{2,3}(-[A-Za-z]{2,4})?$/;
14
+
15
+ export const TRANSLATE_CHAT_POSTS = {
16
+ 'translate-account': route(
17
+ 'translateAccount',
18
+ 'nothing required',
19
+ () => true,
20
+ () => ({})
21
+ ),
22
+ summarize: route(
23
+ 'summarizeMessage',
24
+ 'chat and id required',
25
+ (b) =>
26
+ /^-?\d{1,20}$/.test(String(b.chat ?? '')) &&
27
+ Number.isInteger(b.id) &&
28
+ b.id > 0 &&
29
+ (b.to === undefined || (typeof b.to === 'string' && LANG.test(b.to)))
30
+ ),
31
+ };
@@ -0,0 +1,17 @@
1
+ // The route tables of the R-Y213..R-Y216 features in one spread, so that
2
+ // routes-telegram.js stays under its line limit. Each table documents its
3
+ // own routes in its file's header:
4
+ // routes-telegram-translate-chat.js (R-Y213), -emoji-groups.js (R-Y214),
5
+ // -storage.js (R-Y215), -channel-manage.js (R-Y216).
6
+
7
+ import { TRANSLATE_CHAT_POSTS } from './routes-telegram-translate-chat.js';
8
+ import { EMOJI_GROUPS_POSTS } from './routes-telegram-emoji-groups.js';
9
+ import { STORAGE_POSTS } from './routes-telegram-storage.js';
10
+ import { CHANNEL_MANAGE_POSTS } from './routes-telegram-channel-manage.js';
11
+
12
+ export const YEXTRAS_POSTS = {
13
+ ...TRANSLATE_CHAT_POSTS,
14
+ ...EMOJI_GROUPS_POSTS,
15
+ ...STORAGE_POSTS,
16
+ ...CHANNEL_MANAGE_POSTS,
17
+ };
@@ -206,6 +206,7 @@ import { WEB_APPS_POSTS } from './routes-telegram-web-apps.js';
206
206
  import { BOT_LOGIN_POSTS } from './routes-telegram-bot-login.js';
207
207
  import { ADMIN_POSTS } from './routes-telegram-admin.js';
208
208
  import { GROUP_EXTRAS_POSTS } from './routes-telegram-group-extras.js';
209
+ import { YEXTRAS_POSTS } from './routes-telegram-yextras.js';
209
210
  import {
210
211
  INSTANT_VIEW_GETS,
211
212
  INSTANT_VIEW_POSTS,
@@ -242,6 +243,7 @@ import { FOLDER_EDIT_POSTS } from './routes-telegram-folder-edit.js';
242
243
  import { CHATLIST_POSTS } from './routes-telegram-chatlists.js';
243
244
  import { STICKER_SETTINGS_POSTS } from './routes-telegram-sticker-settings.js';
244
245
  import { CHAT_THEME_POSTS } from './routes-telegram-chat-themes.js';
246
+ import { CONTACT_EXTRAS_POSTS } from './routes-telegram-contact-extras.js';
245
247
  import { CLOUD_THEME_POSTS } from './routes-telegram-cloud-themes.js';
246
248
  import { COMMON_CHATS_POSTS } from './routes-telegram-common-chats.js';
247
249
  import { STATS_POSTS } from './routes-telegram-stats.js';
@@ -266,6 +268,7 @@ import { EMOJI_STATUS_POSTS } from './routes-telegram-emoji-status.js';
266
268
  import { ROUND_POSTS } from './routes-telegram-round.js';
267
269
  import { PRIVACY_POSTS } from './routes-telegram-privacy.js';
268
270
  import { SECURITY_POSTS } from './routes-telegram-security.js';
271
+ import { SECURITY_EXTRAS_POSTS } from './routes-telegram-security-extras.js';
269
272
  import { SHARE_POSTS } from './routes-telegram-share.js';
270
273
  import { INLINE_POSTS } from './routes-telegram-inline.js';
271
274
  import { MESSAGE_LINK_POSTS } from './routes-telegram-message-links.js';
@@ -1020,6 +1023,8 @@ const POSTS = {
1020
1023
  : [400, { error: 'chat and a change required', code: 'bad-request' }],
1021
1024
  ...ADMIN_POSTS,
1022
1025
  ...EPHEMERAL_POSTS,
1026
+ ...YEXTRAS_POSTS,
1027
+ ...CONTACT_EXTRAS_POSTS,
1023
1028
  ...GROUP_EXTRAS_POSTS,
1024
1029
  ...INSTANT_VIEW_POSTS,
1025
1030
  ...STICKER_EXTRAS_POSTS,
@@ -1069,6 +1074,7 @@ const POSTS = {
1069
1074
  ...ROUND_POSTS,
1070
1075
  ...PRIVACY_POSTS,
1071
1076
  ...SECURITY_POSTS,
1077
+ ...SECURITY_EXTRAS_POSTS,
1072
1078
  ...SHARE_POSTS,
1073
1079
  ...INLINE_POSTS,
1074
1080
  ...TTL_POSTS,