@balancy/utils 1.0.34
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.
- package/README.md +283 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +3212 -0
- package/dist/index.umd.js +3230 -0
- package/dist/indexeddb/IndexedDBFileHelper.d.ts +107 -0
- package/dist/indexeddb/IndexedDBFileHelper.d.ts.map +1 -0
- package/dist/indexeddb/IndexedDBFileHelperAdapter.d.ts +56 -0
- package/dist/indexeddb/IndexedDBFileHelperAdapter.d.ts.map +1 -0
- package/dist/indexeddb/index.d.ts +4 -0
- package/dist/indexeddb/index.d.ts.map +1 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# @balancy/utils
|
|
2
|
+
|
|
3
|
+
Набор утилитарных функций и хелперов для экосистемы Balancy.
|
|
4
|
+
|
|
5
|
+
## ⭐ Основные возможности
|
|
6
|
+
|
|
7
|
+
- **IndexedDB FileHelper** - Полнофункциональная система работы с файлами через IndexedDB
|
|
8
|
+
- **Утилитарные функции** - Набор полезных хелперов для разработки
|
|
9
|
+
|
|
10
|
+
## Установка
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @balancy/utils
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 🚀 Быстрый старт с IndexedDB FileHelper
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { IndexedDBFileHelperAdapter } from '@balancy/utils';
|
|
20
|
+
import { Balancy, DataObjectsManager } from '@balancy/core'; // Импорт из приложения
|
|
21
|
+
|
|
22
|
+
// Создание и инициализация файлового помощника
|
|
23
|
+
const fileHelperAdapter = await IndexedDBFileHelperAdapter.create({
|
|
24
|
+
cachePath: '.balancy',
|
|
25
|
+
preloadStrategy: 'full' // полная предзагрузка для максимальной производительности
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// ❗ ВАЖНО: Настройка интеграции с DataObjectsManager (решает проблему дублирования)
|
|
29
|
+
fileHelperAdapter.setSpriteLoader((id, callback) => {
|
|
30
|
+
DataObjectsManager.loadSprite(id, callback);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Получение статистики
|
|
34
|
+
const stats = fileHelperAdapter.getCacheStats();
|
|
35
|
+
console.log(`📁 Files: ${stats.fileCount}, 💾 Memory: ${stats.memoryUsage}`);
|
|
36
|
+
|
|
37
|
+
// Инициализация Balancy
|
|
38
|
+
await Balancy.Main.initializeFileHelper(fileHelperAdapter);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 🛠️ Использование утилитарных функций
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { isEmpty, deepClone, formatNumber, generateId, delay, retry } from '@balancy/utils';
|
|
45
|
+
|
|
46
|
+
// Проверка на пустое значение
|
|
47
|
+
console.log(isEmpty('')); // true
|
|
48
|
+
console.log(isEmpty([])); // true
|
|
49
|
+
console.log(isEmpty({})); // true
|
|
50
|
+
|
|
51
|
+
// Глубокое клонирование
|
|
52
|
+
const original = { a: 1, b: { c: 2 } };
|
|
53
|
+
const cloned = deepClone(original);
|
|
54
|
+
|
|
55
|
+
// Форматирование чисел
|
|
56
|
+
console.log(formatNumber(1234567)); // "1,234,567"
|
|
57
|
+
|
|
58
|
+
// Генерация ID
|
|
59
|
+
console.log(generateId()); // "AbC12xyz"
|
|
60
|
+
console.log(generateId(12)); // "AbC12xyzDeFg"
|
|
61
|
+
|
|
62
|
+
// Задержка
|
|
63
|
+
await delay(1000); // ждет 1 секунду
|
|
64
|
+
|
|
65
|
+
// Retry с экспоненциальной задержкой
|
|
66
|
+
const result = await retry(async () => {
|
|
67
|
+
// некая асинхронная операция
|
|
68
|
+
return await fetchData();
|
|
69
|
+
}, 3, 1000); // 3 попытки, начальная задержка 1с
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 📁 IndexedDB FileHelper API
|
|
73
|
+
|
|
74
|
+
### `IndexedDBFileHelperAdapter.create(config)`
|
|
75
|
+
Основной способ создания адаптера файловой системы.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
interface IndexedDBFileHelperConfig {
|
|
79
|
+
cachePath: string; // Путь к кэшу (обязательно)
|
|
80
|
+
codePath?: string; // Путь к генерируемому коду
|
|
81
|
+
resourcesPath?: string; // Путь к ресурсам
|
|
82
|
+
preloadStrategy?: 'none' | 'partial' | 'full'; // Стратегия предзагрузки
|
|
83
|
+
enableLogging?: boolean; // Включить логирование
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Альтернативные методы создания:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// Быстрое создание без предзагрузки
|
|
91
|
+
const fastAdapter = await IndexedDBFileHelperAdapter.createFast({
|
|
92
|
+
cachePath: '.balancy'
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Создание с частичной предзагрузкой
|
|
96
|
+
const partialAdapter = await IndexedDBFileHelperAdapter.createWithPartialPreload({
|
|
97
|
+
cachePath: '.balancy'
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Основные методы:
|
|
102
|
+
|
|
103
|
+
#### `getBinaryFile(key: string): Promise<Uint8Array | null>`
|
|
104
|
+
Загружает бинарный файл по ключу.
|
|
105
|
+
|
|
106
|
+
#### `saveBinaryFile(key: string, data: Uint8Array): Promise<boolean>`
|
|
107
|
+
Сохраняет бинарные данные.
|
|
108
|
+
|
|
109
|
+
#### `hasFile(key: string): Promise<boolean>`
|
|
110
|
+
Проверяет существование файла.
|
|
111
|
+
|
|
112
|
+
#### `deleteFile(key: string): Promise<boolean>`
|
|
113
|
+
Удаляет файл из кэша.
|
|
114
|
+
|
|
115
|
+
#### `getCacheStats(): CacheStats`
|
|
116
|
+
Возвращает статистику использования кэша.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
interface CacheStats {
|
|
120
|
+
fileCount: number; // Количество файлов в кэше
|
|
121
|
+
memoryUsage: string; // Использование памяти (в читаемом формате)
|
|
122
|
+
hitRate?: number; // Процент попаданий в кэш
|
|
123
|
+
totalRequests?: number; // Общее количество запросов
|
|
124
|
+
cacheHits?: number; // Количество попаданий в кэш
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## 🔧 Утилитарные функции
|
|
129
|
+
|
|
130
|
+
### `isEmpty(value: any): boolean`
|
|
131
|
+
Проверяет, является ли значение пустым (null, undefined, пустая строка, пустой массив, пустой объект).
|
|
132
|
+
|
|
133
|
+
### `deepClone<T>(obj: T): T`
|
|
134
|
+
Выполняет глубокое клонирование объекта.
|
|
135
|
+
|
|
136
|
+
### `formatNumber(num: number, locale?: string): string`
|
|
137
|
+
Форматирует число с разделителями тысяч. По умолчанию использует локаль 'en-US'.
|
|
138
|
+
|
|
139
|
+
### `generateId(length?: number): string`
|
|
140
|
+
Генерирует случайный ID указанной длины (по умолчанию 8 символов).
|
|
141
|
+
|
|
142
|
+
### `delay(ms: number): Promise<void>`
|
|
143
|
+
Создает задержку на указанное количество миллисекунд.
|
|
144
|
+
|
|
145
|
+
### `retry<T>(fn: () => Promise<T>, maxAttempts?: number, baseDelay?: number): Promise<T>`
|
|
146
|
+
Выполняет функцию с повторными попытками при ошибках. Использует экспоненциальную задержку между попытками.
|
|
147
|
+
|
|
148
|
+
## 📖 Примеры использования
|
|
149
|
+
|
|
150
|
+
### Интеграция с игровой логикой
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Сохранение игровых данных
|
|
154
|
+
const gameData = {
|
|
155
|
+
playerLevel: 42,
|
|
156
|
+
coins: 1500,
|
|
157
|
+
achievements: ['first_win', 'level_10']
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const jsonData = JSON.stringify(gameData);
|
|
161
|
+
await adapter.saveBinaryFile('player_data.json', new TextEncoder().encode(jsonData));
|
|
162
|
+
|
|
163
|
+
// Загрузка игровых данных
|
|
164
|
+
const savedData = await adapter.getBinaryFile('player_data.json');
|
|
165
|
+
if (savedData) {
|
|
166
|
+
const parsedData = JSON.parse(new TextDecoder().decode(savedData));
|
|
167
|
+
console.log('Игровые данные:', parsedData);
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Мониторинг производительности
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const stats = adapter.getCacheStats();
|
|
175
|
+
console.log(`Cache hit rate: ${stats.hitRate}%`);
|
|
176
|
+
console.log(`Memory usage: ${stats.memoryUsage}`);
|
|
177
|
+
console.log(`Total files: ${stats.fileCount}`);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## 🏗️ Стратегии предзагрузки
|
|
181
|
+
|
|
182
|
+
- **`'full'`** - Загружает ВСЕ файлы в память при инициализации. Максимальная производительность, больше памяти.
|
|
183
|
+
- **`'partial'`** - Загружает только файлы из основного кэша. Компромисс между скоростью и памятью.
|
|
184
|
+
- **`'none'`** - Не предзагружает файлы. Минимальное использование памяти, файлы загружаются по требованию.
|
|
185
|
+
|
|
186
|
+
## 📋 TypeScript интерфейсы
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// Основные интерфейсы для FileHelper
|
|
190
|
+
interface FileHelperPaths {
|
|
191
|
+
cachePath: string;
|
|
192
|
+
codePath?: string;
|
|
193
|
+
resourcesPath?: string;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
interface ICachedFileHelper {
|
|
197
|
+
getBinaryFile(key: string): Promise<Uint8Array | null>;
|
|
198
|
+
saveBinaryFile(key: string, data: Uint8Array): Promise<boolean>;
|
|
199
|
+
hasFile(key: string): Promise<boolean>;
|
|
200
|
+
deleteFile(key: string): Promise<boolean>;
|
|
201
|
+
clearCache(): Promise<boolean>;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Утилитарные интерфейсы
|
|
205
|
+
interface RetryOptions {
|
|
206
|
+
maxAttempts?: number;
|
|
207
|
+
baseDelay?: number;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
interface UtilsConfig {
|
|
211
|
+
defaultLocale?: string;
|
|
212
|
+
defaultIdLength?: number;
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## 🚨 Важные замечания
|
|
217
|
+
|
|
218
|
+
### Интеграция с Balancy Core
|
|
219
|
+
|
|
220
|
+
Пакет `@balancy/utils` создан как **опциональная зависимость** от `@balancy/core`. Это означает:
|
|
221
|
+
|
|
222
|
+
✅ **Можно использовать** IndexedDB функциональность независимо от Balancy Core
|
|
223
|
+
✅ **Можно интегрировать** с Balancy Core для полной функциональности
|
|
224
|
+
✅ **TypeScript поддержка** полностью работает в обоих случаях
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
// Независимое использование
|
|
228
|
+
import { IndexedDBFileHelperAdapter } from '@balancy/utils';
|
|
229
|
+
const adapter = await IndexedDBFileHelperAdapter.create({ cachePath: '.balancy' });
|
|
230
|
+
|
|
231
|
+
// Интеграция с Balancy (требует @balancy/core)
|
|
232
|
+
import { Balancy } from '@balancy/core';
|
|
233
|
+
import { IndexedDBFileHelperAdapter } from '@balancy/utils';
|
|
234
|
+
|
|
235
|
+
const adapter = await IndexedDBFileHelperAdapter.create({ cachePath: '.balancy' });
|
|
236
|
+
await Balancy.Main.initializeFileHelper(adapter);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Производительность
|
|
240
|
+
|
|
241
|
+
- **Стратегия `'full'`** рекомендуется для продакшн приложений
|
|
242
|
+
- **Стратегия `'partial'`** подходит для разработки
|
|
243
|
+
- **Стратегия `'none'`** для ограниченных ресурсов
|
|
244
|
+
|
|
245
|
+
### Совместимость
|
|
246
|
+
|
|
247
|
+
- ✅ Современные браузеры с поддержкой IndexedDB
|
|
248
|
+
- ✅ Web Workers (с ограничениями)
|
|
249
|
+
- ❌ Node.js (IndexedDB недоступен)
|
|
250
|
+
- ❌ React Native (требуется полифилл)
|
|
251
|
+
|
|
252
|
+
## 🔧 Решение проблем
|
|
253
|
+
|
|
254
|
+
### Проблема дублирования DataObjectsManager
|
|
255
|
+
|
|
256
|
+
Если вы видите ошибку `Cannot read properties of undefined (reading 'loadSpritePrivate')`, это означает дублирование модулей.
|
|
257
|
+
|
|
258
|
+
**Симптомы:**
|
|
259
|
+
```javascript
|
|
260
|
+
console.log(DataObjectsManager.instance); // то undefined, то объект
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Решение:**
|
|
264
|
+
```typescript
|
|
265
|
+
// ❌ НЕПРАВИЛЬНО: Прямой импорт в utils может привести к дублированию
|
|
266
|
+
// import { DataObjectsManager } from '@balancy/core'; // в utils пакете
|
|
267
|
+
|
|
268
|
+
// ✅ ПРАВИЛЬНО: Передача через setSpriteLoader
|
|
269
|
+
import { DataObjectsManager } from '@balancy/core'; // в вашем приложении
|
|
270
|
+
|
|
271
|
+
const adapter = await IndexedDBFileHelperAdapter.create({cachePath: '.balancy'});
|
|
272
|
+
adapter.setSpriteLoader((id, callback) => {
|
|
273
|
+
DataObjectsManager.loadSprite(id, callback); // Использует правильный экземпляр
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Лицензия
|
|
278
|
+
|
|
279
|
+
MIT
|
|
280
|
+
|
|
281
|
+
## Поддержка
|
|
282
|
+
|
|
283
|
+
Для вопросов и поддержки обращайтесь к команде Balancy.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export * from './indexeddb';
|
|
2
|
+
/**
|
|
3
|
+
* Проверяет, является ли значение пустым (null, undefined, пустая строка, пустой массив, пустой объект)
|
|
4
|
+
*/
|
|
5
|
+
export declare function isEmpty(value: any): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Глубокое клонирование объекта
|
|
8
|
+
*/
|
|
9
|
+
export declare function deepClone<T>(obj: T): T;
|
|
10
|
+
/**
|
|
11
|
+
* Форматирование чисел с разделителями тысяч
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatNumber(num: number, locale?: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Генерация случайного ID
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateId(length?: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* Задержка выполнения (Promise-based sleep)
|
|
20
|
+
*/
|
|
21
|
+
export declare function delay(ms: number): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Retry функция с экспоненциальной задержкой
|
|
24
|
+
*/
|
|
25
|
+
export declare function retry<T>(fn: () => Promise<T>, maxAttempts?: number, baseDelay?: number): Promise<T>;
|
|
26
|
+
export interface RetryOptions {
|
|
27
|
+
maxAttempts?: number;
|
|
28
|
+
baseDelay?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface UtilsConfig {
|
|
31
|
+
defaultLocale?: string;
|
|
32
|
+
defaultIdLength?: number;
|
|
33
|
+
}
|
|
34
|
+
export declare const VERSION = "1.0.0-rc.24";
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,aAAa,CAAC;AAM5B;;GAEG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAM3C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CActC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAgB,GAAG,MAAM,CAE1E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,GAAE,MAAU,GAAG,MAAM,CAOrD;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,CAAC,EAC3B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,WAAW,GAAE,MAAU,EACvB,SAAS,GAAE,MAAa,GACvB,OAAO,CAAC,CAAC,CAAC,CAeZ;AAGD,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAGD,eAAO,MAAM,OAAO,gBAAgB,CAAC"}
|