or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advertising-monetization.mdapplication-lifecycle.mdauthentication.mdcore-bridge.mddevice-features.mdgeolocation.mdindex.mdlaunch-parameters.mdmiddleware.mdpayments-commerce.mdqr-barcode-scanning.mdsocial-features.mdstorage-data.mdui-display.mduser-data.md

middleware.mddocs/

0

# Middleware System

1

2

Redux-style middleware system for intercepting and processing VK Bridge communications, enabling logging, data transformation, error handling, and custom request/response processing.

3

4

## Capabilities

5

6

### Apply Middleware

7

8

Create an enhanced VK Bridge instance with middleware applied to the send method.

9

10

```typescript { .api }

11

/**

12

* Apply middleware to VK Bridge instance

13

* Creates enhanced bridge with middleware chain applied to send method

14

* @param middlewares - Array of middleware functions to apply

15

* @returns Function that takes bridge and returns enhanced bridge

16

*/

17

function applyMiddleware(

18

...middlewares: Array<Middleware | undefined | null>

19

): (bridge: VKBridge) => VKBridge;

20

21

type Middleware<S extends VKBridgeSend = VKBridgeSend> = (

22

api: MiddlewareAPI<S>

23

) => (next: S) => S;

24

25

interface MiddlewareAPI<S extends VKBridgeSend = VKBridgeSend> {

26

/** Send function for making bridge calls within middleware */

27

send: S;

28

/** Subscribe function for event listening within middleware */

29

subscribe(listener: VKBridgeSubscribeHandler): void;

30

}

31

32

type VKBridgeSend = <K extends AnyRequestMethodName>(

33

method: K,

34

props?: RequestProps<K> & RequestIdProp

35

) => Promise<K extends AnyReceiveMethodName ? ReceiveData<K> : void>;

36

```

37

38

**Usage Examples:**

39

40

```typescript

41

import bridge, { applyMiddleware } from "@vkontakte/vk-bridge";

42

43

// Create logger middleware

44

const loggerMiddleware = ({ send, subscribe }) => (next) => async (method, props) => {

45

console.log('→', method, props);

46

const startTime = Date.now();

47

48

try {

49

const result = await next(method, props);

50

const duration = Date.now() - startTime;

51

console.log('✓', method, `${duration}ms`, result);

52

return result;

53

} catch (error) {

54

const duration = Date.now() - startTime;

55

console.error('✗', method, `${duration}ms`, error);

56

throw error;

57

}

58

};

59

60

// Apply middleware and create enhanced bridge

61

const enhancedBridge = applyMiddleware(loggerMiddleware)(bridge);

62

63

// Use enhanced bridge normally

64

await enhancedBridge.send('VKWebAppInit');

65

await enhancedBridge.send('VKWebAppGetUserInfo');

66

```

67

68

### Built-in Middleware Examples

69

70

#### Logging Middleware

71

72

```typescript { .api }

73

interface LoggerMiddleware {

74

/** Log all requests and responses with timing */

75

(api: MiddlewareAPI): (next: VKBridgeSend) => VKBridgeSend;

76

}

77

```

78

79

**Usage Examples:**

80

81

```typescript

82

// Basic logger

83

const basicLogger = ({ send, subscribe }) => (next) => async (method, props) => {

84

console.log(`Sending: ${method}`, props);

85

const result = await next(method, props);

86

console.log(`Received: ${method}`, result);

87

return result;

88

};

89

90

// Advanced logger with timing and error tracking

91

const advancedLogger = ({ send, subscribe }) => (next) => async (method, props) => {

92

const requestId = props?.request_id || Math.random().toString(36).substr(2, 9);

93

const startTime = performance.now();

94

95

console.group(`🔄 ${method} [${requestId}]`);

96

console.log('Parameters:', props);

97

98

try {

99

const result = await next(method, props);

100

const duration = performance.now() - startTime;

101

102

console.log('✅ Success:', result);

103

console.log(`⏱️ Duration: ${duration.toFixed(2)}ms`);

104

console.groupEnd();

105

106

return result;

107

} catch (error) {

108

const duration = performance.now() - startTime;

109

110

console.error('❌ Error:', error);

111

console.log(`⏱️ Duration: ${duration.toFixed(2)}ms`);

112

console.groupEnd();

113

114

throw error;

115

}

116

};

117

118

const loggedBridge = applyMiddleware(advancedLogger)(bridge);

119

```

120

121

#### Error Handling Middleware

122

123

```typescript { .api }

124

interface ErrorHandlerMiddleware {

125

/** Handle and transform errors before they reach the application */

126

(api: MiddlewareAPI): (next: VKBridgeSend) => VKBridgeSend;

127

}

128

```

129

130

**Usage Examples:**

131

132

```typescript

133

// Retry middleware for network errors

134

const retryMiddleware = ({ send, subscribe }) => (next) => async (method, props) => {

135

const maxRetries = 3;

136

let lastError;

137

138

for (let attempt = 1; attempt <= maxRetries; attempt++) {

139

try {

140

return await next(method, props);

141

} catch (error) {

142

lastError = error;

143

144

// Only retry on network/client errors

145

if (error.error_type === 'client_error' && attempt < maxRetries) {

146

console.warn(`Retry ${attempt}/${maxRetries} for ${method}`);

147

await new Promise(resolve => setTimeout(resolve, 1000 * attempt));

148

continue;

149

}

150

151

throw error;

152

}

153

}

154

155

throw lastError;

156

};

157

158

// Global error handler

159

const errorHandlerMiddleware = ({ send, subscribe }) => (next) => async (method, props) => {

160

try {

161

return await next(method, props);

162

} catch (error) {

163

// Log error for analytics

164

console.error('Bridge error:', { method, props, error });

165

166

// Transform specific errors

167

if (error.error_type === 'auth_error' && error.error_data.error_code === 4) {

168

throw new Error('User cancelled authorization');

169

}

170

171

if (error.error_type === 'client_error' && error.error_data.error_code === 1) {

172

throw new Error('Method not supported on this platform');

173

}

174

175

// Re-throw original error

176

throw error;

177

}

178

};

179

180

const robustBridge = applyMiddleware(retryMiddleware, errorHandlerMiddleware)(bridge);

181

```

182

183

#### Data Transformation Middleware

184

185

```typescript { .api }

186

interface DataTransformMiddleware {

187

/** Transform request/response data */

188

(api: MiddlewareAPI): (next: VKBridgeSend) => VKBridgeSend;

189

}

190

```

191

192

**Usage Examples:**

193

194

```typescript

195

// Request/response transformer

196

const transformerMiddleware = ({ send, subscribe }) => (next) => async (method, props) => {

197

// Transform outgoing requests

198

let transformedProps = props;

199

200

if (method === 'VKWebAppGetAuthToken' && props) {

201

// Ensure scope is always a string

202

transformedProps = {

203

...props,

204

scope: Array.isArray(props.scope) ? props.scope.join(',') : props.scope

205

};

206

}

207

208

const result = await next(method, transformedProps);

209

210

// Transform incoming responses

211

if (method === 'VKWebAppGetUserInfo' && result) {

212

return {

213

...result,

214

full_name: `${result.first_name} ${result.last_name}`,

215

avatar: result.photo_200 || result.photo_100

216

};

217

}

218

219

return result;

220

};

221

222

// Data normalization middleware

223

const normalizerMiddleware = ({ send, subscribe }) => (next) => async (method, props) => {

224

const result = await next(method, props);

225

226

// Normalize timestamps to Date objects

227

if (result && typeof result === 'object') {

228

const normalizedResult = { ...result };

229

230

// Convert known timestamp fields

231

const timestampFields = ['vk_ts', 'timestamp', 'date', 'created', 'updated'];

232

timestampFields.forEach(field => {

233

if (field in normalizedResult && typeof normalizedResult[field] === 'number') {

234

normalizedResult[`${field}_date`] = new Date(normalizedResult[field] * 1000);

235

}

236

});

237

238

return normalizedResult;

239

}

240

241

return result;

242

};

243

244

const transformedBridge = applyMiddleware(transformerMiddleware, normalizerMiddleware)(bridge);

245

```

246

247

#### Analytics Middleware

248

249

```typescript { .api }

250

interface AnalyticsMiddleware {

251

/** Track bridge usage for analytics */

252

(api: MiddlewareAPI): (next: VKBridgeSend) => VKBridgeSend;

253

}

254

```

255

256

**Usage Examples:**

257

258

```typescript

259

// Usage tracking middleware

260

const analyticsMiddleware = ({ send, subscribe }) => (next) => async (method, props) => {

261

const startTime = Date.now();

262

263

try {

264

const result = await next(method, props);

265

const duration = Date.now() - startTime;

266

267

// Track successful usage

268

trackEvent('bridge_method_success', {

269

method,

270

duration,

271

platform: bridge.isWebView() ? 'webview' : 'web',

272

timestamp: Date.now()

273

});

274

275

return result;

276

} catch (error) {

277

const duration = Date.now() - startTime;

278

279

// Track errors

280

trackEvent('bridge_method_error', {

281

method,

282

duration,

283

error_type: error.error_type,

284

error_code: error.error_data?.error_code,

285

platform: bridge.isWebView() ? 'webview' : 'web',

286

timestamp: Date.now()

287

});

288

289

throw error;

290

}

291

};

292

293

// Performance monitoring

294

const performanceMiddleware = ({ send, subscribe }) => (next) => async (method, props) => {

295

const startTime = performance.now();

296

297

try {

298

const result = await next(method, props);

299

const duration = performance.now() - startTime;

300

301

// Log slow operations

302

if (duration > 1000) {

303

console.warn(`Slow bridge operation: ${method} took ${duration.toFixed(2)}ms`);

304

}

305

306

// Send to monitoring service

307

if (window.performance && window.performance.mark) {

308

window.performance.mark(`bridge-${method}-start`);

309

window.performance.mark(`bridge-${method}-end`);

310

window.performance.measure(`bridge-${method}`, `bridge-${method}-start`, `bridge-${method}-end`);

311

}

312

313

return result;

314

} catch (error) {

315

const duration = performance.now() - startTime;

316

console.error(`Bridge error in ${method} after ${duration.toFixed(2)}ms:`, error);

317

throw error;

318

}

319

};

320

321

const monitoredBridge = applyMiddleware(analyticsMiddleware, performanceMiddleware)(bridge);

322

```

323

324

### Multiple Middleware Composition

325

326

```typescript { .api }

327

/**

328

* Compose multiple middleware functions

329

* Middleware is applied in order: first middleware wraps the second, etc.

330

*/

331

function composeMiddleware(...middlewares: Middleware[]): (bridge: VKBridge) => VKBridge;

332

```

333

334

**Usage Examples:**

335

336

```typescript

337

// Create comprehensive middleware stack

338

const middlewareStack = [

339

// First: Log all requests (outermost)

340

loggerMiddleware,

341

342

// Second: Handle authentication errors

343

authErrorHandlerMiddleware,

344

345

// Third: Retry failed requests

346

retryMiddleware,

347

348

// Fourth: Transform data

349

transformerMiddleware,

350

351

// Fifth: Track analytics (innermost)

352

analyticsMiddleware

353

];

354

355

// Apply all middleware

356

const fullBridge = applyMiddleware(...middlewareStack)(bridge);

357

358

// Alternative: Step by step application

359

const step1 = applyMiddleware(loggerMiddleware)(bridge);

360

const step2 = applyMiddleware(authErrorHandlerMiddleware)(step1);

361

const step3 = applyMiddleware(retryMiddleware)(step2);

362

const fullBridge2 = applyMiddleware(transformerMiddleware, analyticsMiddleware)(step3);

363

364

// Use the enhanced bridge

365

await fullBridge.send('VKWebAppInit');

366

await fullBridge.send('VKWebAppGetUserInfo');

367

```

368

369

### Conditional Middleware

370

371

```typescript

372

// Development vs production middleware

373

const createBridge = (isDevelopment: boolean) => {

374

const middlewares = [];

375

376

if (isDevelopment) {

377

middlewares.push(advancedLogger);

378

middlewares.push(performanceMiddleware);

379

} else {

380

middlewares.push(basicLogger);

381

middlewares.push(analyticsMiddleware);

382

}

383

384

// Always apply error handling

385

middlewares.push(errorHandlerMiddleware);

386

387

return applyMiddleware(...middlewares)(bridge);

388

};

389

390

const developmentBridge = createBridge(true);

391

const productionBridge = createBridge(false);

392

393

// Feature-based middleware

394

const createFeatureBridge = (features: { analytics?: boolean; retry?: boolean; logging?: boolean }) => {

395

const middlewares = [];

396

397

if (features.logging) {

398

middlewares.push(loggerMiddleware);

399

}

400

401

if (features.retry) {

402

middlewares.push(retryMiddleware);

403

}

404

405

if (features.analytics) {

406

middlewares.push(analyticsMiddleware);

407

}

408

409

return middlewares.length > 0 ? applyMiddleware(...middlewares)(bridge) : bridge;

410

};

411

```

412

413

## Advanced Middleware Patterns

414

415

### Middleware with State

416

417

```typescript

418

// Middleware with internal state

419

const createCacheMiddleware = (ttl: number = 60000) => {

420

const cache = new Map();

421

422

return ({ send, subscribe }) => (next) => async (method, props) => {

423

// Only cache certain methods

424

const cacheableMethods = ['VKWebAppGetUserInfo', 'VKWebAppGetConfig'];

425

426

if (!cacheableMethods.includes(method)) {

427

return next(method, props);

428

}

429

430

const cacheKey = `${method}:${JSON.stringify(props)}`;

431

const cached = cache.get(cacheKey);

432

433

if (cached && Date.now() - cached.timestamp < ttl) {

434

console.log('Cache hit:', method);

435

return cached.data;

436

}

437

438

const result = await next(method, props);

439

cache.set(cacheKey, { data: result, timestamp: Date.now() });

440

441

return result;

442

};

443

};

444

445

const cachedBridge = applyMiddleware(createCacheMiddleware(30000))(bridge);

446

```

447

448

### Async Middleware

449

450

```typescript

451

// Middleware with async initialization

452

const createAuthMiddleware = async (authConfig) => {

453

const authToken = await getStoredAuthToken();

454

455

return ({ send, subscribe }) => (next) => async (method, props) => {

456

// Auto-inject auth token for API calls

457

if (method === 'VKWebAppCallAPIMethod' && authToken) {

458

const enhancedProps = {

459

...props,

460

params: {

461

...props.params,

462

access_token: authToken

463

}

464

};

465

return next(method, enhancedProps);

466

}

467

468

return next(method, props);

469

};

470

};

471

472

// Async bridge creation

473

async function createAuthenticatedBridge() {

474

const authMiddleware = await createAuthMiddleware(authConfig);

475

return applyMiddleware(authMiddleware)(bridge);

476

}

477

478

const authenticatedBridge = await createAuthenticatedBridge();

479

```