@tari-project/tarijs 0.10.0 → 0.11.0

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 (71) hide show
  1. package/README.md +127 -67
  2. package/TODO.md +91 -3
  3. package/docusaurus/tari-docs/README.md +200 -17
  4. package/docusaurus/tari-docs/docs/api-reference.md +665 -0
  5. package/docusaurus/tari-docs/docs/contributing.md +619 -0
  6. package/docusaurus/tari-docs/docs/guides/getting-started-tutorial.md +965 -0
  7. package/docusaurus/tari-docs/docs/guides/production-deployment.md +977 -0
  8. package/docusaurus/tari-docs/docs/index.md +114 -11
  9. package/docusaurus/tari-docs/docs/installation.md +142 -1
  10. package/docusaurus/tari-docs/docs/signers/metamask.md +529 -0
  11. package/docusaurus/tari-docs/docs/troubleshooting.md +661 -0
  12. package/docusaurus/tari-docs/package.json +1 -1
  13. package/examples/vite-typescript-react/README.md +9 -0
  14. package/examples/vite-typescript-react/eslint.config.js +23 -0
  15. package/examples/vite-typescript-react/index.html +13 -0
  16. package/examples/vite-typescript-react/package.json +35 -0
  17. package/examples/vite-typescript-react/public/vite.svg +1 -0
  18. package/examples/vite-typescript-react/src/App.css +42 -0
  19. package/examples/vite-typescript-react/src/App.tsx +50 -0
  20. package/examples/vite-typescript-react/src/assets/react.svg +1 -0
  21. package/examples/vite-typescript-react/src/index.css +68 -0
  22. package/examples/vite-typescript-react/src/main.tsx +10 -0
  23. package/examples/vite-typescript-react/src/vite-env.d.ts +1 -0
  24. package/examples/vite-typescript-react/tsconfig.app.json +27 -0
  25. package/examples/vite-typescript-react/tsconfig.json +7 -0
  26. package/examples/vite-typescript-react/tsconfig.node.json +25 -0
  27. package/examples/vite-typescript-react/vite.config.ts +7 -0
  28. package/package.json +2 -2
  29. package/packages/builders/package.json +2 -2
  30. package/packages/builders/src/transaction/TransactionBuilder.ts +4 -12
  31. package/packages/indexer_provider/package.json +2 -2
  32. package/packages/indexer_provider/src/provider.ts +5 -5
  33. package/packages/indexer_provider/tsconfig.json +4 -2
  34. package/packages/metamask_signer/package.json +2 -2
  35. package/packages/metamask_signer/src/index.ts +2 -14
  36. package/packages/{tari_permissions → permissions}/package.json +2 -2
  37. package/packages/{tari_permissions → permissions}/src/helpers.ts +1 -1
  38. package/packages/permissions/src/index.ts +2 -0
  39. package/packages/{tari_permissions/src/tari_permissions.ts → permissions/src/permissions.ts} +56 -6
  40. package/packages/react-mui-connect-button/moon.yml +71 -0
  41. package/packages/react-mui-connect-button/package.json +40 -0
  42. package/packages/react-mui-connect-button/src/Logos.tsx +60 -0
  43. package/packages/react-mui-connect-button/src/TariConnectButton.tsx +51 -0
  44. package/packages/react-mui-connect-button/src/TariWalletSelectionDialog.tsx +116 -0
  45. package/packages/react-mui-connect-button/src/content/tari-logo-white.svg +18 -0
  46. package/packages/react-mui-connect-button/src/content/tari-logo.svg +18 -0
  47. package/packages/react-mui-connect-button/src/content/walletconnect-logo.svg +13 -0
  48. package/packages/react-mui-connect-button/src/defaultPermissions.ts +0 -0
  49. package/packages/react-mui-connect-button/src/index.ts +24 -0
  50. package/packages/react-mui-connect-button/tsconfig.json +31 -0
  51. package/packages/tari_provider/package.json +2 -2
  52. package/packages/tari_signer/package.json +2 -2
  53. package/packages/tari_universe/package.json +2 -2
  54. package/packages/tari_universe/tsconfig.json +4 -2
  55. package/packages/tarijs/package.json +2 -2
  56. package/packages/tarijs/tsconfig.json +4 -2
  57. package/packages/tarijs_types/package.json +2 -2
  58. package/packages/wallet_daemon/package.json +2 -2
  59. package/packages/wallet_daemon/src/provider.ts +9 -12
  60. package/packages/wallet_daemon/src/signer.ts +11 -6
  61. package/packages/wallet_daemon/tsconfig.json +1 -1
  62. package/packages/walletconnect/package.json +3 -2
  63. package/packages/walletconnect/src/index.ts +52 -26
  64. package/packages/walletconnect/tsconfig.json +3 -0
  65. package/pnpm-workspace.yaml +15 -7
  66. package/scripts/check_versions.sh +4 -0
  67. package/scripts/clean_everything.sh +38 -0
  68. package/tsconfig.json +6 -0
  69. package/packages/tari_permissions/src/index.ts +0 -2
  70. /package/packages/{tari_permissions → permissions}/moon.yml +0 -0
  71. /package/packages/{tari_permissions → permissions}/tsconfig.json +0 -0
@@ -0,0 +1,977 @@
1
+ ---
2
+ sidebar_position: 3
3
+ title: Production Deployment
4
+ description: Deploy tari.js applications to production with confidence - security, performance, and monitoring best practices
5
+ ---
6
+
7
+ # Production Deployment Guide 🚀
8
+
9
+ > **Ship with confidence** — Comprehensive guide to deploying tari.js applications in production environments with enterprise-grade security, performance, and reliability.
10
+
11
+ This guide covers everything you need to deploy tari.js applications safely and efficiently in production, from security hardening to performance optimization and monitoring.
12
+
13
+ ## 🎯 **Pre-Deployment Checklist**
14
+
15
+ ### **Security Audit**
16
+ - [ ] **No hardcoded secrets** — All sensitive data in environment variables
17
+ - [ ] **HTTPS enforced** — SSL/TLS certificates properly configured
18
+ - [ ] **Input validation** — All user inputs properly sanitized
19
+ - [ ] **Error handling** — No sensitive information in error messages
20
+ - [ ] **Dependency audit** — All packages scanned for vulnerabilities
21
+ - [ ] **Wallet permissions** — Minimal required permissions only
22
+
23
+ ### **Performance Optimization**
24
+ - [ ] **Bundle analysis** — Bundle size optimized and analyzed
25
+ - [ ] **Code splitting** — Dynamic imports for wallet modules
26
+ - [ ] **Asset optimization** — Images and assets compressed
27
+ - [ ] **Caching strategy** — Proper cache headers configured
28
+ - [ ] **CDN setup** — Static assets served via CDN
29
+ - [ ] **Connection pooling** — Efficient wallet connection management
30
+
31
+ ### **Testing & Quality**
32
+ - [ ] **Test coverage >90%** — Comprehensive test suite
33
+ - [ ] **E2E tests passing** — End-to-end user workflows tested
34
+ - [ ] **Load testing** — Performance under expected traffic
35
+ - [ ] **Security testing** — Penetration testing completed
36
+ - [ ] **Cross-browser testing** — Compatibility verified
37
+ - [ ] **Mobile testing** — Responsive design validated
38
+
39
+ ## 🔒 **Security Best Practices**
40
+
41
+ ### **Environment Configuration**
42
+
43
+ ```bash
44
+ # Production environment variables
45
+ NODE_ENV=production
46
+ TARI_NETWORK=mainnet
47
+ TARI_INDEXER_URL=https://your-secure-indexer.example.com
48
+ TARI_WALLET_DAEMON_URL=wss://your-secure-daemon.example.com
49
+
50
+ # Security headers
51
+ FORCE_HTTPS=true
52
+ HSTS_MAX_AGE=31536000
53
+ CSP_ENABLED=true
54
+ CORS_ORIGIN=https://yourdomain.com
55
+ ```
56
+
57
+ ### **Content Security Policy (CSP)**
58
+
59
+ ```html
60
+ <!-- Strict CSP for production -->
61
+ <meta http-equiv="Content-Security-Policy"
62
+ content="
63
+ default-src 'self';
64
+ script-src 'self' 'unsafe-eval' https://cdnjs.cloudflare.com;
65
+ style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
66
+ font-src 'self' https://fonts.gstatic.com;
67
+ connect-src 'self' wss: https: ws:;
68
+ img-src 'self' data: https:;
69
+ frame-src 'none';
70
+ object-src 'none';
71
+ base-uri 'self';
72
+ form-action 'self';
73
+ ">
74
+ ```
75
+
76
+ ### **Secure Wallet Configuration**
77
+
78
+ ```typescript
79
+ // Production wallet configuration
80
+ const secureWalletConfig = {
81
+ // Network configuration
82
+ network: 'mainnet',
83
+
84
+ // Connection security
85
+ enforceHttps: true,
86
+ validateCertificates: true,
87
+ connectionTimeout: 30000,
88
+
89
+ // Authentication
90
+ requirePermissions: true,
91
+ permissionWhitelist: [
92
+ 'accounts:read',
93
+ 'transactions:submit',
94
+ 'substates:read'
95
+ ],
96
+
97
+ // Error handling
98
+ sanitizeErrors: true,
99
+ hideStackTraces: true,
100
+
101
+ // Rate limiting
102
+ maxRequestsPerMinute: 60,
103
+ burstLimit: 10,
104
+
105
+ // Monitoring
106
+ enableAuditLog: true,
107
+ logLevel: 'info'
108
+ };
109
+ ```
110
+
111
+ ### **API Security**
112
+
113
+ ```typescript
114
+ // Secure API wrapper with rate limiting
115
+ export class SecureWalletAPI {
116
+ private rateLimiter: RateLimiter;
117
+ private auditLogger: AuditLogger;
118
+
119
+ constructor(config: SecureWalletConfig) {
120
+ this.rateLimiter = new RateLimiter({
121
+ max: config.maxRequestsPerMinute,
122
+ windowMs: 60000
123
+ });
124
+
125
+ this.auditLogger = new AuditLogger({
126
+ level: config.logLevel,
127
+ destination: config.auditLogPath
128
+ });
129
+ }
130
+
131
+ async submitTransaction(transaction: Transaction): Promise<TransactionResult> {
132
+ // Rate limiting
133
+ await this.rateLimiter.check();
134
+
135
+ // Input validation
136
+ this.validateTransaction(transaction);
137
+
138
+ // Audit logging
139
+ this.auditLogger.log('transaction_submit', {
140
+ transactionId: transaction.id,
141
+ userId: this.getCurrentUserId(),
142
+ timestamp: new Date().toISOString()
143
+ });
144
+
145
+ try {
146
+ return await this.signer.submitTransaction({ transaction });
147
+ } catch (error) {
148
+ // Sanitize error for client
149
+ throw this.sanitizeError(error);
150
+ }
151
+ }
152
+
153
+ private validateTransaction(transaction: Transaction): void {
154
+ if (!transaction || !transaction.instructions) {
155
+ throw new ValidationError('Invalid transaction structure');
156
+ }
157
+
158
+ // Additional validation logic
159
+ }
160
+
161
+ private sanitizeError(error: Error): Error {
162
+ // Remove sensitive information from error messages
163
+ return new Error('Transaction failed. Please try again.');
164
+ }
165
+ }
166
+ ```
167
+
168
+ ## ⚡ **Performance Optimization**
169
+
170
+ ### **Bundle Optimization**
171
+
172
+ ```typescript
173
+ // webpack.config.js for production
174
+ const path = require('path');
175
+ const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
176
+
177
+ module.exports = {
178
+ mode: 'production',
179
+
180
+ optimization: {
181
+ splitChunks: {
182
+ chunks: 'all',
183
+ cacheGroups: {
184
+ // Separate tari.js chunks for better caching
185
+ tari: {
186
+ test: /[\\/]node_modules[\\/]@tari-project[\\/]/,
187
+ name: 'tari',
188
+ chunks: 'all',
189
+ priority: 10
190
+ },
191
+
192
+ // Wallet-specific chunks
193
+ wallets: {
194
+ test: /[\\/]node_modules[\\/]@tari-project[\\/](wallet-daemon|metamask-signer|tari-universe)[\\/]/,
195
+ name: 'wallets',
196
+ chunks: 'async',
197
+ priority: 20
198
+ }
199
+ }
200
+ },
201
+
202
+ // Tree shaking
203
+ usedExports: true,
204
+ sideEffects: false
205
+ },
206
+
207
+ plugins: [
208
+ // Analyze bundle size
209
+ new BundleAnalyzerPlugin({
210
+ analyzerMode: 'static',
211
+ generateStatsFile: true
212
+ })
213
+ ]
214
+ };
215
+ ```
216
+
217
+ ### **Dynamic Wallet Loading**
218
+
219
+ ```typescript
220
+ // Lazy load wallet modules for better performance
221
+ export class WalletManager {
222
+ private walletCache = new Map<string, any>();
223
+
224
+ async loadWallet(type: WalletType): Promise<TariSigner> {
225
+ if (this.walletCache.has(type)) {
226
+ return this.walletCache.get(type);
227
+ }
228
+
229
+ let WalletClass;
230
+
231
+ switch (type) {
232
+ case 'metamask':
233
+ const { MetaMaskSigner } = await import('@tari-project/metamask-signer');
234
+ WalletClass = MetaMaskSigner;
235
+ break;
236
+
237
+ case 'wallet-daemon':
238
+ const { WalletDaemonSigner } = await import('@tari-project/wallet-daemon');
239
+ WalletClass = WalletDaemonSigner;
240
+ break;
241
+
242
+ case 'tari-universe':
243
+ const { TariUniverseSigner } = await import('@tari-project/tari-universe');
244
+ WalletClass = TariUniverseSigner;
245
+ break;
246
+
247
+ default:
248
+ throw new Error(`Unsupported wallet type: ${type}`);
249
+ }
250
+
251
+ const wallet = new WalletClass(this.getWalletConfig(type));
252
+ this.walletCache.set(type, wallet);
253
+
254
+ return wallet;
255
+ }
256
+ }
257
+ ```
258
+
259
+ ### **Connection Pooling**
260
+
261
+ ```typescript
262
+ // Efficient connection management
263
+ export class ConnectionPool {
264
+ private connections = new Map<string, Connection>();
265
+ private maxConnections = 10;
266
+ private connectionTimeout = 30000;
267
+
268
+ async getConnection(endpoint: string): Promise<Connection> {
269
+ const existing = this.connections.get(endpoint);
270
+
271
+ if (existing && existing.isHealthy()) {
272
+ return existing;
273
+ }
274
+
275
+ if (this.connections.size >= this.maxConnections) {
276
+ await this.cleanupStaleConnections();
277
+ }
278
+
279
+ const connection = await this.createConnection(endpoint);
280
+ this.connections.set(endpoint, connection);
281
+
282
+ return connection;
283
+ }
284
+
285
+ private async cleanupStaleConnections(): Promise<void> {
286
+ for (const [endpoint, connection] of this.connections) {
287
+ if (!connection.isHealthy()) {
288
+ await connection.close();
289
+ this.connections.delete(endpoint);
290
+ }
291
+ }
292
+ }
293
+ }
294
+ ```
295
+
296
+ ## 🏗️ **Infrastructure Setup**
297
+
298
+ ### **Docker Production Build**
299
+
300
+ ```dockerfile
301
+ # Multi-stage production build
302
+ FROM node:18-alpine AS builder
303
+
304
+ WORKDIR /app
305
+
306
+ # Copy package files
307
+ COPY package*.json ./
308
+ COPY pnpm-lock.yaml ./
309
+
310
+ # Install dependencies
311
+ RUN npm install -g pnpm
312
+ RUN pnpm install --frozen-lockfile
313
+
314
+ # Copy source
315
+ COPY . .
316
+
317
+ # Build application
318
+ RUN pnpm run build
319
+
320
+ # Production stage
321
+ FROM nginx:alpine AS production
322
+
323
+ # Copy built assets
324
+ COPY --from=builder /app/dist /usr/share/nginx/html
325
+
326
+ # Copy nginx configuration
327
+ COPY nginx.conf /etc/nginx/conf.d/default.conf
328
+
329
+ # Security headers
330
+ RUN echo 'add_header X-Frame-Options "SAMEORIGIN" always;' >> /etc/nginx/conf.d/security.conf
331
+ RUN echo 'add_header X-Content-Type-Options "nosniff" always;' >> /etc/nginx/conf.d/security.conf
332
+ RUN echo 'add_header Referrer-Policy "strict-origin-when-cross-origin" always;' >> /etc/nginx/conf.d/security.conf
333
+
334
+ EXPOSE 80
335
+
336
+ CMD ["nginx", "-g", "daemon off;"]
337
+ ```
338
+
339
+ ### **Nginx Configuration**
340
+
341
+ ```nginx
342
+ # nginx.conf for production
343
+ server {
344
+ listen 80;
345
+ listen [::]:80;
346
+ server_name yourdomain.com;
347
+
348
+ # Redirect HTTP to HTTPS
349
+ return 301 https://$server_name$request_uri;
350
+ }
351
+
352
+ server {
353
+ listen 443 ssl http2;
354
+ listen [::]:443 ssl http2;
355
+ server_name yourdomain.com;
356
+
357
+ # SSL configuration
358
+ ssl_certificate /path/to/certificate.crt;
359
+ ssl_certificate_key /path/to/private.key;
360
+ ssl_protocols TLSv1.2 TLSv1.3;
361
+ ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
362
+ ssl_prefer_server_ciphers off;
363
+
364
+ # Security headers
365
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
366
+ add_header X-Frame-Options "SAMEORIGIN" always;
367
+ add_header X-Content-Type-Options "nosniff" always;
368
+ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
369
+
370
+ # Serve static files
371
+ root /usr/share/nginx/html;
372
+ index index.html;
373
+
374
+ # Gzip compression
375
+ gzip on;
376
+ gzip_vary on;
377
+ gzip_min_length 1024;
378
+ gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
379
+
380
+ # Cache static assets
381
+ location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
382
+ expires 1y;
383
+ add_header Cache-Control "public, immutable";
384
+ }
385
+
386
+ # API proxy (if needed)
387
+ location /api/ {
388
+ proxy_pass https://your-backend-api.com;
389
+ proxy_set_header Host $host;
390
+ proxy_set_header X-Real-IP $remote_addr;
391
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
392
+ proxy_set_header X-Forwarded-Proto $scheme;
393
+ }
394
+
395
+ # WebSocket proxy for wallet daemon
396
+ location /ws/ {
397
+ proxy_pass wss://your-wallet-daemon.com;
398
+ proxy_http_version 1.1;
399
+ proxy_set_header Upgrade $http_upgrade;
400
+ proxy_set_header Connection "upgrade";
401
+ proxy_set_header Host $host;
402
+ }
403
+
404
+ # SPA fallback
405
+ try_files $uri $uri/ /index.html;
406
+ }
407
+ ```
408
+
409
+ ### **Kubernetes Deployment**
410
+
411
+ ```yaml
412
+ # kubernetes-deployment.yaml
413
+ apiVersion: apps/v1
414
+ kind: Deployment
415
+ metadata:
416
+ name: tari-js-app
417
+ labels:
418
+ app: tari-js-app
419
+ spec:
420
+ replicas: 3
421
+ selector:
422
+ matchLabels:
423
+ app: tari-js-app
424
+ template:
425
+ metadata:
426
+ labels:
427
+ app: tari-js-app
428
+ spec:
429
+ containers:
430
+ - name: tari-js-app
431
+ image: your-registry/tari-js-app:latest
432
+ ports:
433
+ - containerPort: 80
434
+ env:
435
+ - name: NODE_ENV
436
+ value: "production"
437
+ - name: TARI_NETWORK
438
+ value: "mainnet"
439
+ resources:
440
+ requests:
441
+ memory: "256Mi"
442
+ cpu: "250m"
443
+ limits:
444
+ memory: "512Mi"
445
+ cpu: "500m"
446
+ livenessProbe:
447
+ httpGet:
448
+ path: /health
449
+ port: 80
450
+ initialDelaySeconds: 30
451
+ periodSeconds: 10
452
+ readinessProbe:
453
+ httpGet:
454
+ path: /ready
455
+ port: 80
456
+ initialDelaySeconds: 5
457
+ periodSeconds: 5
458
+
459
+ ---
460
+ apiVersion: v1
461
+ kind: Service
462
+ metadata:
463
+ name: tari-js-service
464
+ spec:
465
+ selector:
466
+ app: tari-js-app
467
+ ports:
468
+ - protocol: TCP
469
+ port: 80
470
+ targetPort: 80
471
+ type: LoadBalancer
472
+
473
+ ---
474
+ apiVersion: networking.k8s.io/v1
475
+ kind: Ingress
476
+ metadata:
477
+ name: tari-js-ingress
478
+ annotations:
479
+ kubernetes.io/ingress.class: nginx
480
+ cert-manager.io/cluster-issuer: letsencrypt-prod
481
+ nginx.ingress.kubernetes.io/ssl-redirect: "true"
482
+ spec:
483
+ tls:
484
+ - hosts:
485
+ - yourdomain.com
486
+ secretName: tari-js-tls
487
+ rules:
488
+ - host: yourdomain.com
489
+ http:
490
+ paths:
491
+ - path: /
492
+ pathType: Prefix
493
+ backend:
494
+ service:
495
+ name: tari-js-service
496
+ port:
497
+ number: 80
498
+ ```
499
+
500
+ ## 📊 **Monitoring & Observability**
501
+
502
+ ### **Health Checks**
503
+
504
+ ```typescript
505
+ // Comprehensive health check system
506
+ export class HealthChecker {
507
+ async checkHealth(): Promise<HealthStatus> {
508
+ const checks = await Promise.allSettled([
509
+ this.checkWalletConnectivity(),
510
+ this.checkIndexerConnectivity(),
511
+ this.checkDatabaseHealth(),
512
+ this.checkMemoryUsage(),
513
+ this.checkDiskSpace()
514
+ ]);
515
+
516
+ return {
517
+ status: checks.every(c => c.status === 'fulfilled') ? 'healthy' : 'unhealthy',
518
+ timestamp: new Date().toISOString(),
519
+ checks: {
520
+ wallet: checks[0].status === 'fulfilled',
521
+ indexer: checks[1].status === 'fulfilled',
522
+ database: checks[2].status === 'fulfilled',
523
+ memory: checks[3].status === 'fulfilled',
524
+ disk: checks[4].status === 'fulfilled'
525
+ }
526
+ };
527
+ }
528
+
529
+ private async checkWalletConnectivity(): Promise<boolean> {
530
+ try {
531
+ const signer = new WalletDaemonSigner(this.config.wallet);
532
+ return signer.isConnected();
533
+ } catch {
534
+ return false;
535
+ }
536
+ }
537
+
538
+ private async checkIndexerConnectivity(): Promise<boolean> {
539
+ try {
540
+ const provider = new IndexerProvider(this.config.indexer);
541
+ await provider.getNetworkInfo();
542
+ return true;
543
+ } catch {
544
+ return false;
545
+ }
546
+ }
547
+ }
548
+ ```
549
+
550
+ ### **Metrics Collection**
551
+
552
+ ```typescript
553
+ // Prometheus metrics
554
+ import { register, Counter, Histogram, Gauge } from 'prom-client';
555
+
556
+ export class MetricsCollector {
557
+ private transactionCounter = new Counter({
558
+ name: 'tari_transactions_total',
559
+ help: 'Total number of transactions processed',
560
+ labelNames: ['wallet_type', 'status']
561
+ });
562
+
563
+ private transactionDuration = new Histogram({
564
+ name: 'tari_transaction_duration_seconds',
565
+ help: 'Transaction processing duration',
566
+ buckets: [0.1, 0.5, 1, 2, 5, 10]
567
+ });
568
+
569
+ private walletConnections = new Gauge({
570
+ name: 'tari_wallet_connections_active',
571
+ help: 'Number of active wallet connections'
572
+ });
573
+
574
+ recordTransaction(walletType: string, status: string, duration: number): void {
575
+ this.transactionCounter.inc({ wallet_type: walletType, status });
576
+ this.transactionDuration.observe(duration);
577
+ }
578
+
579
+ updateConnectionCount(count: number): void {
580
+ this.walletConnections.set(count);
581
+ }
582
+
583
+ getMetrics(): string {
584
+ return register.metrics();
585
+ }
586
+ }
587
+ ```
588
+
589
+ ### **Error Tracking**
590
+
591
+ ```typescript
592
+ // Sentry error tracking
593
+ import * as Sentry from '@sentry/node';
594
+
595
+ export class ErrorTracker {
596
+ constructor() {
597
+ Sentry.init({
598
+ dsn: process.env.SENTRY_DSN,
599
+ environment: process.env.NODE_ENV,
600
+ beforeSend: this.sanitizeErrorData
601
+ });
602
+ }
603
+
604
+ captureException(error: Error, context?: any): void {
605
+ Sentry.withScope(scope => {
606
+ if (context) {
607
+ scope.setContext('additional', context);
608
+ }
609
+ scope.setTag('component', 'tari-wallet');
610
+ Sentry.captureException(error);
611
+ });
612
+ }
613
+
614
+ private sanitizeErrorData(event: Sentry.Event): Sentry.Event {
615
+ // Remove sensitive information from error reports
616
+ if (event.exception?.values) {
617
+ event.exception.values.forEach(exception => {
618
+ if (exception.stacktrace?.frames) {
619
+ exception.stacktrace.frames.forEach(frame => {
620
+ // Remove local file paths
621
+ if (frame.filename?.includes('/home/')) {
622
+ frame.filename = frame.filename.replace(/\/home\/[^\/]+/, '/home/user');
623
+ }
624
+ });
625
+ }
626
+ });
627
+ }
628
+
629
+ return event;
630
+ }
631
+ }
632
+ ```
633
+
634
+ ## 🔍 **Logging Strategy**
635
+
636
+ ### **Structured Logging**
637
+
638
+ ```typescript
639
+ // Winston structured logging
640
+ import winston from 'winston';
641
+
642
+ export class Logger {
643
+ private logger: winston.Logger;
644
+
645
+ constructor() {
646
+ this.logger = winston.createLogger({
647
+ level: process.env.LOG_LEVEL || 'info',
648
+ format: winston.format.combine(
649
+ winston.format.timestamp(),
650
+ winston.format.errors({ stack: true }),
651
+ winston.format.json()
652
+ ),
653
+ defaultMeta: {
654
+ service: 'tari-wallet-app',
655
+ version: process.env.APP_VERSION
656
+ },
657
+ transports: [
658
+ new winston.transports.File({
659
+ filename: 'logs/error.log',
660
+ level: 'error'
661
+ }),
662
+ new winston.transports.File({
663
+ filename: 'logs/combined.log'
664
+ })
665
+ ]
666
+ });
667
+
668
+ if (process.env.NODE_ENV !== 'production') {
669
+ this.logger.add(new winston.transports.Console({
670
+ format: winston.format.simple()
671
+ }));
672
+ }
673
+ }
674
+
675
+ logTransaction(transactionId: string, walletType: string, userId?: string): void {
676
+ this.logger.info('Transaction processed', {
677
+ transactionId,
678
+ walletType,
679
+ userId: userId ? this.hashUserId(userId) : 'anonymous',
680
+ timestamp: new Date().toISOString()
681
+ });
682
+ }
683
+
684
+ logError(error: Error, context?: any): void {
685
+ this.logger.error('Application error', {
686
+ error: error.message,
687
+ stack: error.stack,
688
+ context: this.sanitizeContext(context)
689
+ });
690
+ }
691
+
692
+ private hashUserId(userId: string): string {
693
+ // Hash user ID for privacy
694
+ return require('crypto').createHash('sha256').update(userId).digest('hex').slice(0, 8);
695
+ }
696
+
697
+ private sanitizeContext(context: any): any {
698
+ // Remove sensitive fields from log context
699
+ if (!context) return context;
700
+
701
+ const sanitized = { ...context };
702
+ delete sanitized.privateKey;
703
+ delete sanitized.password;
704
+ delete sanitized.token;
705
+
706
+ return sanitized;
707
+ }
708
+ }
709
+ ```
710
+
711
+ ## 🚨 **Incident Response**
712
+
713
+ ### **Alerting Configuration**
714
+
715
+ ```yaml
716
+ # Prometheus alerting rules
717
+ groups:
718
+ - name: tari-wallet-alerts
719
+ rules:
720
+ - alert: HighErrorRate
721
+ expr: rate(tari_transactions_total{status="error"}[5m]) > 0.1
722
+ for: 2m
723
+ labels:
724
+ severity: warning
725
+ annotations:
726
+ summary: "High transaction error rate detected"
727
+ description: "Error rate is {{ $value }} per second"
728
+
729
+ - alert: WalletConnectionDown
730
+ expr: tari_wallet_connections_active == 0
731
+ for: 1m
732
+ labels:
733
+ severity: critical
734
+ annotations:
735
+ summary: "No active wallet connections"
736
+ description: "All wallet connections are down"
737
+
738
+ - alert: HighMemoryUsage
739
+ expr: process_resident_memory_bytes > 500000000
740
+ for: 5m
741
+ labels:
742
+ severity: warning
743
+ annotations:
744
+ summary: "High memory usage detected"
745
+ description: "Memory usage is {{ $value | humanize }}B"
746
+ ```
747
+
748
+ ### **Automated Recovery**
749
+
750
+ ```typescript
751
+ // Circuit breaker for wallet connections
752
+ export class CircuitBreaker {
753
+ private failures = 0;
754
+ private lastFailTime = 0;
755
+ private state: 'closed' | 'open' | 'half-open' = 'closed';
756
+
757
+ constructor(
758
+ private threshold = 5,
759
+ private timeout = 60000 // 1 minute
760
+ ) {}
761
+
762
+ async execute<T>(operation: () => Promise<T>): Promise<T> {
763
+ if (this.state === 'open') {
764
+ if (Date.now() - this.lastFailTime > this.timeout) {
765
+ this.state = 'half-open';
766
+ } else {
767
+ throw new Error('Circuit breaker is open');
768
+ }
769
+ }
770
+
771
+ try {
772
+ const result = await operation();
773
+ this.onSuccess();
774
+ return result;
775
+ } catch (error) {
776
+ this.onFailure();
777
+ throw error;
778
+ }
779
+ }
780
+
781
+ private onSuccess(): void {
782
+ this.failures = 0;
783
+ this.state = 'closed';
784
+ }
785
+
786
+ private onFailure(): void {
787
+ this.failures++;
788
+ this.lastFailTime = Date.now();
789
+
790
+ if (this.failures >= this.threshold) {
791
+ this.state = 'open';
792
+ }
793
+ }
794
+ }
795
+ ```
796
+
797
+ ## 📈 **Performance Monitoring**
798
+
799
+ ### **Real User Monitoring (RUM)**
800
+
801
+ ```typescript
802
+ // Performance tracking
803
+ export class PerformanceMonitor {
804
+ trackWalletConnection(walletType: string): void {
805
+ const startTime = performance.now();
806
+
807
+ return {
808
+ complete: () => {
809
+ const duration = performance.now() - startTime;
810
+ this.sendMetric('wallet_connection_time', duration, {
811
+ wallet_type: walletType
812
+ });
813
+ }
814
+ };
815
+ }
816
+
817
+ trackTransactionSubmission(transactionSize: number): void {
818
+ const startTime = performance.now();
819
+
820
+ return {
821
+ complete: (success: boolean) => {
822
+ const duration = performance.now() - startTime;
823
+ this.sendMetric('transaction_submission_time', duration, {
824
+ transaction_size: transactionSize.toString(),
825
+ success: success.toString()
826
+ });
827
+ }
828
+ };
829
+ }
830
+
831
+ private sendMetric(name: string, value: number, tags: Record<string, string>): void {
832
+ // Send to your analytics service
833
+ if (typeof gtag !== 'undefined') {
834
+ gtag('event', name, {
835
+ custom_parameter: value,
836
+ ...tags
837
+ });
838
+ }
839
+ }
840
+ }
841
+ ```
842
+
843
+ ## 🔄 **Continuous Deployment**
844
+
845
+ ### **GitHub Actions Workflow**
846
+
847
+ ```yaml
848
+ # .github/workflows/deploy-production.yml
849
+ name: Deploy to Production
850
+
851
+ on:
852
+ push:
853
+ branches: [main]
854
+ workflow_dispatch:
855
+
856
+ jobs:
857
+ test:
858
+ runs-on: ubuntu-latest
859
+ steps:
860
+ - uses: actions/checkout@v4
861
+
862
+ - name: Setup Node.js
863
+ uses: actions/setup-node@v4
864
+ with:
865
+ node-version: '18'
866
+ cache: 'pnpm'
867
+
868
+ - name: Install dependencies
869
+ run: pnpm install --frozen-lockfile
870
+
871
+ - name: Run tests
872
+ run: pnpm test
873
+
874
+ - name: Run security audit
875
+ run: pnpm audit
876
+
877
+ - name: Build application
878
+ run: pnpm build
879
+
880
+ - name: Run E2E tests
881
+ run: pnpm test:e2e
882
+
883
+ security-scan:
884
+ runs-on: ubuntu-latest
885
+ steps:
886
+ - uses: actions/checkout@v4
887
+
888
+ - name: Run Snyk security scan
889
+ uses: snyk/actions/node@master
890
+ env:
891
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
892
+
893
+ deploy:
894
+ needs: [test, security-scan]
895
+ runs-on: ubuntu-latest
896
+ environment: production
897
+
898
+ steps:
899
+ - uses: actions/checkout@v4
900
+
901
+ - name: Setup Node.js
902
+ uses: actions/setup-node@v4
903
+ with:
904
+ node-version: '18'
905
+ cache: 'pnpm'
906
+
907
+ - name: Install dependencies
908
+ run: pnpm install --frozen-lockfile
909
+
910
+ - name: Build for production
911
+ run: pnpm build
912
+ env:
913
+ NODE_ENV: production
914
+ TARI_NETWORK: mainnet
915
+
916
+ - name: Build Docker image
917
+ run: |
918
+ docker build -t ${{ secrets.DOCKER_REGISTRY }}/tari-js-app:${{ github.sha }} .
919
+ docker tag ${{ secrets.DOCKER_REGISTRY }}/tari-js-app:${{ github.sha }} ${{ secrets.DOCKER_REGISTRY }}/tari-js-app:latest
920
+
921
+ - name: Push to registry
922
+ run: |
923
+ echo ${{ secrets.DOCKER_PASSWORD }} | docker login ${{ secrets.DOCKER_REGISTRY }} -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
924
+ docker push ${{ secrets.DOCKER_REGISTRY }}/tari-js-app:${{ github.sha }}
925
+ docker push ${{ secrets.DOCKER_REGISTRY }}/tari-js-app:latest
926
+
927
+ - name: Deploy to Kubernetes
928
+ run: |
929
+ kubectl set image deployment/tari-js-app tari-js-app=${{ secrets.DOCKER_REGISTRY }}/tari-js-app:${{ github.sha }}
930
+ kubectl rollout status deployment/tari-js-app
931
+
932
+ - name: Verify deployment
933
+ run: |
934
+ kubectl get pods -l app=tari-js-app
935
+ curl -f https://yourdomain.com/health
936
+ ```
937
+
938
+ ## 🎯 **Production Checklist**
939
+
940
+ ### **Final Pre-Launch Verification**
941
+
942
+ - [ ] **Load testing completed** — Application handles expected traffic
943
+ - [ ] **Security scan passed** — No critical vulnerabilities
944
+ - [ ] **Monitoring configured** — Alerts and dashboards ready
945
+ - [ ] **Backup strategy** — Data backup and recovery procedures
946
+ - [ ] **Rollback plan** — Procedures for quick rollback if needed
947
+ - [ ] **Documentation updated** — Runbooks and operational guides
948
+ - [ ] **Team training** — Operations team familiar with deployment
949
+ - [ ] **Compliance check** — Legal and regulatory requirements met
950
+
951
+ ### **Go-Live Protocol**
952
+
953
+ 1. **Deploy during low-traffic period**
954
+ 2. **Monitor metrics closely for first 24 hours**
955
+ 3. **Verify all critical user journeys**
956
+ 4. **Check error rates and performance**
957
+ 5. **Confirm monitoring and alerting**
958
+ 6. **Document any issues and resolutions**
959
+
960
+ ## 🔗 **Related Resources**
961
+
962
+ - **[Installation Guide](../installation)** — Development environment setup
963
+ - **[Security Best Practices](https://github.com/tari-project/tari.js/blob/main/SECURITY.md)** — Comprehensive security checklist
964
+ - **[Performance Optimization](../troubleshooting#performance-issues)** — Advanced optimization techniques
965
+ - **[Monitoring Guide](../troubleshooting)** — Complete observability setup
966
+ - **[Troubleshooting](../troubleshooting)** — Common production issues
967
+
968
+ ## 💬 **Support**
969
+
970
+ - **🚨 [Emergency Support](mailto:emergency@tari.com)** — Critical production issues
971
+ - **💬 [Discord](https://discord.gg/tari)** — Community support and discussion
972
+ - **📋 [Issue Tracker](https://github.com/tari-project/tari.js/issues)** — Bug reports and feature requests
973
+ - **📚 [Documentation](https://tari-project.github.io/tari.js/)** — Complete guides and references
974
+
975
+ ---
976
+
977
+ **Ready for production?** Follow this guide step-by-step to deploy your tari.js application with enterprise-grade reliability and security! 🚀