fix(install): публичный адрес LiveKit вычисляется после TLS_ENABLED

Установщик падал на 'TLS_ENABLED: unbound variable': расчёт LIVEKIT_PUBLIC_URL
стоял выше определения TLS_ENABLED. Значение перенесено после блока TLS,
dry-run проходит.
This commit is contained in:
2026-09-20 18:13:04 +03:00
parent ecd52c11d3
commit ca34d05377
33 changed files with 2505 additions and 71 deletions
+35 -5
View File
@@ -17,12 +17,14 @@
* `__жирный__`, `*курсив*`, `_курсив_`, `***жирный курсив***`, `` `код` ``,
* ```блок кода```, `~~зачёркнутый~~`, `==выделение==`, `||спойлер||`,
* `> цитата`, ссылки `http(s)://…`, упоминания `<@id>`, ссылки на комнаты
* `<#id>` и `#канал`.
* `<#id>`, `#канал` и кастомные эмодзи сервера `<:имя:file_id>`.
*
* Незакрытые маркеры остаются обычным текстом: шаблон требует закрывающую
* пару, поэтому `==фыв` и `**фыв` рендерятся как есть.
*/
import { CUSTOM_EMOJI_TOKEN_SOURCE } from '@/lib/customEmoji';
/** Вид строчного токена. */
export type InlineKind =
| 'code'
@@ -34,6 +36,7 @@ export type InlineKind =
| 'mark'
| 'mention'
| 'channel-link'
| 'custom-emoji'
| 'link'
| 'channel';
@@ -61,9 +64,30 @@ export interface InlineToken {
* «текст со скобками». Одиночная `*` не считается маркером внутри ряда
* звёздочек (`**фыв` не превращается в курсив со «звёздочкой» в тексте), а
* `_` — внутри слова (`foo_bar_baz`).
*
* Токен кастомного эмодзи `<:имя:file_id>` (`<a:…>` — анимированный) стоит
* отдельной альтернативой: с `<@id>` и `<#id>` он не пересекается, а строгий
* формат (латиница/цифры/подчёркивания в имени, снежинка в id) оставляет
* битые токены обычным текстом.
*/
const INLINE_PATTERN =
/(`[^`\n]+`)|(\*\*\*[^*\n]+\*\*\*)|(\*\*[^*\n]+\*\*)|(__[^_\n]+__)|(~~[^~\n]+~~)|(\|\|[^|\n]+\|\|)|((?<!\*)\*(?!\*)[^*\n]+(?<!\*)\*(?!\*))|((?<![\p{L}\p{N}_])_(?!_)[^_\n]+(?<!_)_(?![\p{L}\p{N}_]))|(==[^=\n]+==)|(<@[^\s<>]+>)|(<#[^\s<>]+>)|(https?:\/\/[^\s<>()]+)|(#[\p{L}\p{N}_-]+)/gu;
const INLINE_ALTERNATIVES = [
'(`[^`\\n]+`)',
'(\\*\\*\\*[^*\\n]+\\*\\*\\*)',
'(\\*\\*[^*\\n]+\\*\\*)',
'(__[^_\\n]+__)',
'(~~[^~\\n]+~~)',
'(\\|\\|[^|\\n]+\\|\\|)',
'((?<!\\*)\\*(?!\\*)[^*\\n]+(?<!\\*)\\*(?!\\*))',
'((?<![\\p{L}\\p{N}_])_(?!_)[^_\\n]+(?<!_)_(?![\\p{L}\\p{N}_]))',
'(==[^=\\n]+==)',
'(<@[^\\s<>]+>)',
'(<#[^\\s<>]+>)',
`(${CUSTOM_EMOJI_TOKEN_SOURCE})`,
'(https?:\\/\\/[^\\s<>()]+)',
'(#[\\p{L}\\p{N}_-]+)',
];
const INLINE_PATTERN = new RegExp(INLINE_ALTERNATIVES.join('|'), 'gu');
/** Вид токена по номеру группы шаблона (порядок альтернатив выше). */
const GROUP_KINDS: readonly InlineKind[] = [
@@ -78,6 +102,7 @@ const GROUP_KINDS: readonly InlineKind[] = [
'mark',
'mention',
'channel-link',
'custom-emoji',
'link',
'channel',
];
@@ -95,6 +120,9 @@ const MARKER_LENGTH: Readonly<Record<InlineKind, number>> = {
// содержимое — весь токен.
mention: 0,
'channel-link': 0,
// Токен эмодзи `<:имя:id>` целиком считается содержимым: маркеры `<:имя:`
// и `>` рисует зеркало композера, когда каретка внутри токена.
'custom-emoji': 0,
link: 0,
channel: 0,
};
@@ -149,8 +177,10 @@ export function parseInline(text: string, offset = 0): InlineToken[] {
}
/**
* Есть ли у токена парные маркеры. У упоминаний, ссылок на комнаты, ссылок и
* каналов их нет: содержимое — весь токен, прятать нечего.
* Есть ли у токена маркеры, которые зеркало прячет вне каретки. У упоминаний,
* ссылок на комнаты, ссылок и каналов их нет: содержимое — весь токен, прятать
* нечего. У кастомного эмодзи маркеры есть (`<:имя:` и `>`), но «содержимым»
* остаётся весь токен — зеркало показывает его текстом, пока каретка внутри.
*/
export function hasMarkers(kind: InlineKind): boolean {
return kind !== 'mention' && kind !== 'channel-link' && kind !== 'link' && kind !== 'channel';