Закомитил промежуточную почти работающую версию ...

This commit is contained in:
AidarKC
2026-04-07 13:57:09 +03:00
parent 4deaedf79f
commit 3016d25f73
43 changed files with 271 additions and 143 deletions
+66 -36
View File
@@ -1,7 +1,7 @@
import { navigate, getRoute, PRE_AUTH_PAGES } from './router.js?v=20260405171816';
import { renderToolbar } from './components/toolbar.js?v=20260405171816';
import { captureClientError, setClientErrorTransport } from './services/client-error-reporter.js?v=20260405171816';
import { initPwaPush } from './services/pwa-push-service.js?v=20260405171816';
import { navigate, getRoute, PRE_AUTH_PAGES } from './router.js?v=20260407105357';
import { renderToolbar } from './components/toolbar.js?v=20260407105357';
import { captureClientError, setClientErrorTransport } from './services/client-error-reporter.js?v=20260407105357';
import { initPwaPush } from './services/pwa-push-service.js?v=20260407105357';
import {
authService,
authorizeSession,
@@ -12,38 +12,38 @@ import {
terminateCurrentSession,
addIncomingMessage,
setContacts,
} from './state.js?v=20260405171816';
} from './state.js?v=20260407105357';
import * as startView from './pages/start-view.js?v=20260405171816';
import * as entrySettingsView from './pages/entry-settings-view.js?v=20260405171816';
import * as registerView from './pages/register-view.js?v=20260405171816';
import * as registrationPaymentView from './pages/registration-payment-view.js?v=20260405171816';
import * as registrationKeysView from './pages/registration-keys-view.js?v=20260405171816';
import * as topupView from './pages/topup-view.js?v=20260405171816';
import * as loginView from './pages/login-view.js?v=20260405171816';
import * as loginCameraView from './pages/login-camera-view.js?v=20260405171816';
import * as loginPasswordView from './pages/login-password-view.js?v=20260405171816';
import * as keyStorageView from './pages/key-storage-view.js?v=20260405171816';
import * as startView from './pages/start-view.js?v=20260407105357';
import * as entrySettingsView from './pages/entry-settings-view.js?v=20260407105357';
import * as registerView from './pages/register-view.js?v=20260407105357';
import * as registrationPaymentView from './pages/registration-payment-view.js?v=20260407105357';
import * as registrationKeysView from './pages/registration-keys-view.js?v=20260407105357';
import * as topupView from './pages/topup-view.js?v=20260407105357';
import * as loginView from './pages/login-view.js?v=20260407105357';
import * as loginCameraView from './pages/login-camera-view.js?v=20260407105357';
import * as loginPasswordView from './pages/login-password-view.js?v=20260407105357';
import * as keyStorageView from './pages/key-storage-view.js?v=20260407105357';
import * as profileView from './pages/profile-view.js?v=20260405171816';
import * as walletView from './pages/wallet-view.js?v=20260405171816';
import * as settingsView from './pages/settings-view.js?v=20260405171816';
import * as serverSettingsView from './pages/server-settings-view.js?v=20260405171816';
import * as deviceView from './pages/device-view.js?v=20260405171816';
import * as connectDeviceView from './pages/connect-device-view.js?v=20260405171816';
import * as deviceQrView from './pages/device-qr-view.js?v=20260405171816';
import * as deviceCameraView from './pages/device-camera-view.js?v=20260405171816';
import * as showKeysView from './pages/show-keys-view.js?v=20260405171816';
import * as deviceSessionView from './pages/device-session-view.js?v=20260405171816';
import * as languageView from './pages/language-view.js?v=20260405171816';
import * as messagesList from './pages/messages-list.js?v=20260405171816';
import * as contactSearchView from './pages/contact-search-view.js?v=20260405171816';
import * as chatView from './pages/chat-view.js?v=20260405171816';
import * as channelsList from './pages/channels-list.js?v=20260405171816';
import * as channelView from './pages/channel-view.js?v=20260405171816';
import * as addChannelView from './pages/add-channel-view.js?v=20260405171816';
import * as networkView from './pages/network-view.js?v=20260405171816';
import * as notificationsView from './pages/notifications-view.js?v=20260405171816';
import * as profileView from './pages/profile-view.js?v=20260407105357';
import * as walletView from './pages/wallet-view.js?v=20260407105357';
import * as settingsView from './pages/settings-view.js?v=20260407105357';
import * as serverSettingsView from './pages/server-settings-view.js?v=20260407105357';
import * as deviceView from './pages/device-view.js?v=20260407105357';
import * as connectDeviceView from './pages/connect-device-view.js?v=20260407105357';
import * as deviceQrView from './pages/device-qr-view.js?v=20260407105357';
import * as deviceCameraView from './pages/device-camera-view.js?v=20260407105357';
import * as showKeysView from './pages/show-keys-view.js?v=20260407105357';
import * as deviceSessionView from './pages/device-session-view.js?v=20260407105357';
import * as languageView from './pages/language-view.js?v=20260407105357';
import * as messagesList from './pages/messages-list.js?v=20260407105357';
import * as contactSearchView from './pages/contact-search-view.js?v=20260407105357';
import * as chatView from './pages/chat-view.js?v=20260407105357';
import * as channelsList from './pages/channels-list.js?v=20260407105357';
import * as channelView from './pages/channel-view.js?v=20260407105357';
import * as addChannelView from './pages/add-channel-view.js?v=20260407105357';
import * as networkView from './pages/network-view.js?v=20260407105357';
import * as notificationsView from './pages/notifications-view.js?v=20260407105357';
const routes = {
'start-view': startView,
@@ -84,7 +84,20 @@ let currentCleanup = null;
setClientErrorTransport((payload) => authService.reportClientError(payload));
function showGlobalErrorAlert(title, details = {}) {
const lines = [title];
if (details.message) lines.push(`Сообщение: ${details.message}`);
if (details.pageId) lines.push(`Экран: ${details.pageId}`);
if (details.sourceUrl) lines.push(`Источник: ${details.sourceUrl}`);
if (Number.isFinite(details.lineNumber)) lines.push(`Строка: ${details.lineNumber}`);
if (Number.isFinite(details.columnNumber)) lines.push(`Колонка: ${details.columnNumber}`);
if (details.reasonType) lines.push(`Тип: ${details.reasonType}`);
if (details.stack) lines.push(`Stack:\n${details.stack}`);
window.alert(lines.join('\n'));
}
window.addEventListener('error', (event) => {
const pageId = getRoute().pageId || '';
captureClientError({
kind: 'global_error',
message: event.message || 'Global JS error',
@@ -93,22 +106,39 @@ window.addEventListener('error', (event) => {
lineNumber: event.lineno,
columnNumber: event.colno,
context: {
pageId: getRoute().pageId || '',
pageId,
},
});
showGlobalErrorAlert('Поймана глобальная ошибка UI', {
message: event.message || 'Global JS error',
stack: event.error?.stack || '',
sourceUrl: event.filename || '',
lineNumber: event.lineno,
columnNumber: event.colno,
pageId,
});
});
window.addEventListener('unhandledrejection', (event) => {
const reason = event.reason;
const pageId = getRoute().pageId || '';
captureClientError({
kind: 'unhandled_rejection',
message: reason?.message || String(reason || 'Unhandled promise rejection'),
stack: reason?.stack || '',
context: {
pageId: getRoute().pageId || '',
pageId,
reasonType: reason?.constructor?.name || typeof reason,
},
});
showGlobalErrorAlert('Пойман необработанный Promise reject', {
message: reason?.message || String(reason || 'Unhandled promise rejection'),
stack: reason?.stack || '',
pageId,
reasonType: reason?.constructor?.name || typeof reason,
});
});
function renderApp() {
+1 -1
View File
@@ -1,4 +1,4 @@
import { resolveToolbarActive } from '../router.js?v=20260405171816';
import { resolveToolbarActive } from '../router.js?v=20260407105357';
const ITEMS = [
{ pageId: 'messages-list', label: 'Личные сообщения', icon: '💬' },
+1 -1
View File
@@ -1,6 +1,6 @@
export const profile = {
login: '@shine.alex',
name: 'Алексей сияющий',
name: '',
avatarInitials: 'АС',
phone: '+7 (916) 221-45-88',
address: 'Москва, Пресненская наб., 12',
+1 -1
View File
@@ -1,4 +1,4 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
export const pageMeta = { id: 'add-channel-view', title: 'Добавить канал' };
+3 -3
View File
@@ -1,6 +1,6 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { channelPosts, channels } from '../mock-data.js?v=20260405171816';
import { addLocalChannelPost, authService, getLocalChannelPosts, state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { channelPosts, channels } from '../mock-data.js?v=20260407105357';
import { addLocalChannelPost, authService, getLocalChannelPosts, state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'channel-view', title: 'Канал' };
+3 -3
View File
@@ -1,6 +1,6 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { directMessages } from '../mock-data.js?v=20260405171816';
import { addChatMessage, getChatMessages, authService, state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { directMessages } from '../mock-data.js?v=20260407105357';
import { addChatMessage, getChatMessages, authService, state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'chat-view', title: 'Чат' };
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'connect-device-view', title: 'Подключить устройство' };
+3 -3
View File
@@ -1,6 +1,6 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { directMessages } from '../mock-data.js?v=20260405171816';
import { authService, ensureChat, setContacts, state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { directMessages } from '../mock-data.js?v=20260407105357';
import { authService, ensureChat, setContacts, state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'contact-search-view', title: 'Поиск контактов' };
+1 -1
View File
@@ -1,4 +1,4 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
export const pageMeta = { id: 'device-camera-view', title: 'Подключить через камеру' };
+3 -3
View File
@@ -1,6 +1,6 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { profile } from '../mock-data.js?v=20260405171816';
import { state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { profile } from '../mock-data.js?v=20260407105357';
import { state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'device-qr-view', title: 'Показать QR-код' };
+2 -2
View File
@@ -1,4 +1,4 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import {
authService,
isSessionInvalidError,
@@ -6,7 +6,7 @@ import {
setAuthError,
state,
terminateCurrentSession,
} from '../state.js?v=20260405171816';
} from '../state.js?v=20260407105357';
export const pageMeta = { id: 'device-session-view', title: 'Сеанс устройства' };
+2 -2
View File
@@ -1,4 +1,4 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import {
authService,
isSessionInvalidError,
@@ -7,7 +7,7 @@ import {
setAuthInfo,
state,
terminateCurrentSession,
} from '../state.js?v=20260405171816';
} from '../state.js?v=20260407105357';
export const pageMeta = { id: 'device-view', title: 'Устройства' };
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { checkServerAvailability, saveEntrySettings, state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { checkServerAvailability, saveEntrySettings, state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'entry-settings-view', title: 'Настройки входа', showAppChrome: false };
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { authorizeSession, state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { authorizeSession, state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'key-storage-view', title: 'Какие ключи сохранить', showAppChrome: false };
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'language-view', title: 'Язык' };
+1 -1
View File
@@ -1,4 +1,4 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
export const pageMeta = { id: 'login-camera-view', title: 'Войти по камере', showAppChrome: false };
+2 -2
View File
@@ -1,11 +1,11 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import {
authService,
clearAuthMessages,
setAuthBusy,
setAuthError,
state,
} from '../state.js?v=20260405171816';
} from '../state.js?v=20260407105357';
export const pageMeta = { id: 'login-password-view', title: 'Войти по логину', showAppChrome: false };
+1 -1
View File
@@ -1,4 +1,4 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
export const pageMeta = { id: 'login-view', title: 'Войти', showAppChrome: false };
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { directMessages } from '../mock-data.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { directMessages } from '../mock-data.js?v=20260407105357';
export const pageMeta = { id: 'messages-list', title: 'Личные сообщения' };
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { authService, state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { authService, state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'network-view', title: 'Связи' };
+3 -3
View File
@@ -1,6 +1,6 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { notifications } from '../mock-data.js?v=20260405171816';
import { state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { notifications } from '../mock-data.js?v=20260407105357';
import { state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'notifications-view', title: 'Уведомления' };
+19 -25
View File
@@ -1,27 +1,27 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { profile } from '../mock-data.js?v=20260405171816';
import { state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { profile } from '../mock-data.js?v=20260407105357';
import { state } from '../state.js?v=20260407105357';
import {
loadProfileSnapshot,
saveProfileParamBlock,
saveProfileToggle,
} from '../services/user-profile-params.js?v=20260405171816';
} from '../services/user-profile-params.js?v=20260407105357';
export const pageMeta = { id: 'profile-view', title: 'Профиль' };
function getDisplayName(fields) {
const firstName = fields.find((field) => field.key === 'first_name')?.value?.trim() || '';
const lastName = fields.find((field) => field.key === 'last_name')?.value?.trim() || '';
const fullName = `${firstName} ${lastName}`.trim();
return fullName || profile.name;
}
function toggleText(enabled) {
return enabled ? 'Yes' : 'No';
}
function showLocalErrorAlert(prefix, error) {
const message = error?.message || 'Неизвестная ошибка';
const stack = error?.stack ? `\n\nStack:\n${error.stack}` : '';
window.alert(`${prefix}: ${message}${stack}`);
}
export function render({ navigate }) {
const login = state.session.login || profile.login;
const displayLogin = String(login || '').toUpperCase();
const screen = document.createElement('section');
screen.className = 'stack';
@@ -45,8 +45,7 @@ export function render({ navigate }) {
<div class="row" style="gap:12px; align-items:center;">
<div class="avatar large">${profile.avatarInitials}</div>
<div>
<h2 style="font-size:22px; margin-bottom:2px;" data-profile-name="true">${profile.name}</h2>
<p class="meta-muted">${login}</p>
<h2 style="font-size:22px; margin-bottom:2px;" data-profile-login="true">${displayLogin}</h2>
</div>
</div>
<button class="primary-btn" type="button" data-reload="true">Обновить</button>
@@ -59,13 +58,6 @@ export function render({ navigate }) {
<button class="badge profile-toggle-btn is-no" type="button" data-toggle="shine">Сияющий: No</button>
`;
const hint = document.createElement('div');
hint.className = 'card profile-data-help';
hint.innerHTML = `
<div class="meta-muted">Личные данные пользователя</div>
<p>Параметры читаются через API GetUserParam. Изменения записываются в блокчейн и после этого список сразу обновляется.</p>
`;
const status = document.createElement('div');
status.className = 'status-line';
status.textContent = 'Загрузка параметров...';
@@ -73,7 +65,6 @@ export function render({ navigate }) {
const listWrap = document.createElement('div');
listWrap.className = 'stack profile-param-list';
const profileNameEl = topRow.querySelector('[data-profile-name="true"]');
const reloadBtn = topRow.querySelector('[data-reload="true"]');
const officialBtn = badgesRow.querySelector('[data-toggle="official"]');
const shineBtn = badgesRow.querySelector('[data-toggle="shine"]');
@@ -105,15 +96,15 @@ export function render({ navigate }) {
}
function renderFields(fields) {
profileNameEl.textContent = getDisplayName(fields);
listWrap.innerHTML = '';
fields.forEach((field) => {
const row = document.createElement('div');
row.className = 'card profile-param-item row';
const value = String(field.value || '').trim() || 'не заполнено';
const isNameField = field.key === 'first_name' || field.key === 'last_name';
const valueClass = isNameField ? 'profile-param-value profile-param-value-small' : 'profile-param-value';
row.innerHTML = `
<div class="profile-param-value"><b>${field.label}</b>: ${value}</div>
<div class="${valueClass}"><b>${field.label}</b>: ${value}</div>
<button class="ghost-btn" type="button" data-edit-field="${field.key}">Изменить</button>
`;
listWrap.append(row);
@@ -140,6 +131,7 @@ export function render({ navigate }) {
} catch (error) {
status.className = 'status-line is-unavailable';
status.textContent = `Не удалось загрузить параметры: ${error.message || 'ошибка сети'}`;
showLocalErrorAlert('Ошибка загрузки параметров профиля', error);
} finally {
reloadBtn.disabled = false;
officialBtn.disabled = false;
@@ -167,6 +159,7 @@ export function render({ navigate }) {
} catch (error) {
status.className = 'status-line is-unavailable';
status.textContent = `Не удалось изменить ${toggleKey}: ${error.message || 'ошибка сети'}`;
showLocalErrorAlert(`Ошибка изменения ${toggleKey}`, error);
}
}
@@ -191,6 +184,7 @@ export function render({ navigate }) {
} catch (error) {
status.className = 'status-line is-unavailable';
status.textContent = `Не удалось изменить ${field.key}: ${error.message || 'ошибка сети'}`;
showLocalErrorAlert(`Ошибка изменения ${field.key}`, error);
}
}
@@ -206,7 +200,7 @@ export function render({ navigate }) {
officialBtn.addEventListener('click', () => onToggleClick('official'));
shineBtn.addEventListener('click', () => onToggleClick('shine'));
card.append(topRow, badgesRow, hint, status, listWrap);
card.append(topRow, badgesRow, status, listWrap);
screen.append(card);
refreshProfileSnapshot();
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { authService, clearAuthMessages, state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { authService, clearAuthMessages, state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'register-view', title: 'Зарегистрироваться', showAppChrome: false };
+2 -2
View File
@@ -1,4 +1,4 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import {
authService,
authorizeSession,
@@ -6,7 +6,7 @@ import {
setAuthError,
setAuthInfo,
state,
} from '../state.js?v=20260405171816';
} from '../state.js?v=20260407105357';
export const pageMeta = { id: 'registration-keys-view', title: 'Сохранение ключей', showAppChrome: false };
@@ -1,11 +1,11 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import {
authService,
refreshRegistrationBalance,
setAuthError,
setAuthInfo,
state,
} from '../state.js?v=20260405171816';
} from '../state.js?v=20260407105357';
export const pageMeta = { id: 'registration-payment-view', title: 'Оплата регистрации', showAppChrome: false };
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { checkServerAvailability, saveEntrySettings, state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { checkServerAvailability, saveEntrySettings, state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'server-settings-view', title: 'Настройки серверов' };
+1 -1
View File
@@ -1,4 +1,4 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
export const pageMeta = { id: 'settings-view', title: 'Настройки' };
+3 -3
View File
@@ -1,6 +1,6 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { state } from '../state.js?v=20260405171816';
import { loadEncryptedUserSecrets } from '../services/key-vault.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { state } from '../state.js?v=20260407105357';
import { loadEncryptedUserSecrets } from '../services/key-vault.js?v=20260407105357';
export const pageMeta = { id: 'show-keys-view', title: 'Показать ключи' };
+1 -1
View File
@@ -1,4 +1,4 @@
import { clearStartHint, state } from '../state.js?v=20260405171816';
import { clearStartHint, state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'start-view', title: 'Старт', showAppChrome: false };
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { state } from '../state.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { state } from '../state.js?v=20260407105357';
export const pageMeta = { id: 'topup-view', title: 'Пополнение счета', showAppChrome: false };
+2 -2
View File
@@ -1,5 +1,5 @@
import { renderHeader } from '../components/header.js?v=20260405171816';
import { wallet } from '../mock-data.js?v=20260405171816';
import { renderHeader } from '../components/header.js?v=20260407105357';
import { wallet } from '../mock-data.js?v=20260407105357';
export const pageMeta = { id: 'wallet-view', title: 'Кошелёк' };
+17 -8
View File
@@ -1,4 +1,4 @@
import { WsJsonClient } from './ws-client.js?v=20260405171816';
import { WsJsonClient } from './ws-client.js?v=20260407105357';
import {
bytesToBase64,
deriveEd25519FromPassword,
@@ -11,13 +11,13 @@ import {
signBytes,
signBase64,
utf8Bytes,
} from './crypto-utils.js?v=20260405171816';
} from './crypto-utils.js?v=20260407105357';
import {
loadEncryptedUserSecrets,
loadSessionMaterial,
saveEncryptedUserSecrets,
saveSessionMaterial,
} from './key-vault.js?v=20260405171816';
} from './key-vault.js?v=20260407105357';
const BCH_SUFFIX = '001';
@@ -378,6 +378,12 @@ export class AuthService {
const user = await this.getUser(cleanLogin);
const blockchainName = String(user?.blockchainName || `${cleanLogin}-${BCH_SUFFIX}`).trim();
const freshNum = Number(user?.serverLastGlobalNumber);
const freshHash = String(user?.serverLastGlobalHash || '').trim().toLowerCase();
const freshCursor = {
serverLastGlobalNumber: Number.isFinite(freshNum) ? freshNum : -1,
serverLastGlobalHash: freshHash.length === 64 ? freshHash : '0'.repeat(64),
};
const savedKeys = await loadEncryptedUserSecrets(cleanLogin, storagePwd);
const blockchainPrivatePkcs8 = savedKeys?.blockchainKey;
@@ -391,11 +397,14 @@ export class AuthService {
const blockNumber = Number(cursor?.serverLastGlobalNumber ?? -1) + 1;
const prevBlockHash = String(cursor?.serverLastGlobalHash || '0'.repeat(64));
// Для USER_PARAM отправляем старт новой line-цепочки:
// prevLineNumber=-1, prevLineHash=0x00..00, thisLineNumber=-1.
// Этот формат соответствует BodyHasLine правилам на сервере.
const bodyBytes = makeUserParamBodyBytes({
lineCode: Number(cursor?.serverLastGlobalNumber ?? 0),
prevLineNumber: Number(cursor?.serverLastGlobalNumber ?? 0),
prevLineHashHex: prevBlockHash,
thisLineNumber: 1,
lineCode: 0,
prevLineNumber: -1,
prevLineHashHex: '0'.repeat(64),
thisLineNumber: -1,
key: cleanParam,
value: cleanValue,
});
@@ -426,7 +435,7 @@ export class AuthService {
return response;
};
let cursor = { serverLastGlobalNumber: -1, serverLastGlobalHash: '0'.repeat(64) };
let cursor = freshCursor;
let response = await tryAdd(cursor);
if (response.status !== 200) {
const knownNum = Number(response?.payload?.serverLastGlobalNumber);
+1 -1
View File
@@ -1,7 +1,7 @@
import {
decryptJsonWithStoragePwd,
encryptJsonWithStoragePwd,
} from './crypto-utils.js?v=20260405171816';
} from './crypto-utils.js?v=20260407105357';
const DB_NAME = 'shine-ui-auth';
const DB_VERSION = 1;
+1 -1
View File
@@ -1,4 +1,4 @@
import { authService, state } from '../state.js?v=20260403081123';
import { authService, state } from '../state.js?v=20260407105357';
export const profileFieldDefs = [
{ key: 'first_name', readKeys: ['first_name'], label: 'Имя', placeholder: 'Введите имя' },
+1 -1
View File
@@ -1,4 +1,4 @@
import { captureClientError } from './client-error-reporter.js?v=20260405171816';
import { captureClientError } from './client-error-reporter.js?v=20260407105357';
const DEFAULT_TIMEOUT_MS = 12000;
+3 -3
View File
@@ -1,6 +1,6 @@
import { chatMessages, wallet } from './mock-data.js?v=20260405171816';
import { AuthService } from './services/auth-service.js?v=20260405171816';
import { clearClientAuthData } from './services/key-vault.js?v=20260405171816';
import { chatMessages, wallet } from './mock-data.js?v=20260407105357';
import { AuthService } from './services/auth-service.js?v=20260407105357';
import { clearClientAuthData } from './services/key-vault.js?v=20260407105357';
const clone = (value) => JSON.parse(JSON.stringify(value));
const SESSION_STORAGE_KEY = 'shine-ui-current-session-v1';