or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions.mdapplication-lifecycle.mdcli.mdconfiguration.mdevents.mdhooks.mdindex.mdrouting.md

events.mddocs/

0

# Events System

1

2

Sails.js inherits from Node.js EventEmitter and provides a comprehensive event system for managing application lifecycle, routing events, and custom functionality. The event system enables loose coupling between components and supports both built-in framework events and custom application events.

3

4

## EventEmitter Inheritance

5

6

Sails applications inherit from Node.js EventEmitter, providing full event functionality:

7

8

```javascript { .api }

9

// Sails extends EventEmitter

10

class Sails extends EventEmitter { ... }

11

12

// Event listener methods

13

sails.on(event: String, listener: Function): Sails

14

sails.once(event: String, listener: Function): Sails

15

sails.off(event: String, listener?: Function): Sails

16

sails.emit(event: String, ...args): Boolean

17

sails.removeAllListeners(event?: String): Sails

18

sails.listenerCount(event: String): Number

19

sails.listeners(event: String): Function[]

20

```

21

22

**Basic Event Usage**:

23

```javascript

24

const sails = require('sails');

25

26

// Listen for events

27

sails.on('lifted', () => {

28

console.log('Sails app is ready!');

29

});

30

31

// Listen once

32

sails.once('ready', () => {

33

console.log('App components loaded');

34

});

35

36

// Remove listener

37

const handler = () => console.log('Event fired');

38

sails.on('custom-event', handler);

39

sails.off('custom-event', handler);

40

41

// Emit custom events

42

sails.emit('user-registered', { userId: 123, email: 'user@example.com' });

43

```

44

45

## Core Lifecycle Events

46

47

### Application Lifecycle Events

48

49

```javascript { .api }

50

// Application successfully lifted

51

sails.on('lifted', callback: Function): void

52

53

// Application shutdown initiated

54

sails.on('lower', callback: Function): void

55

56

// Application components loaded (internal)

57

sails.on('ready', callback: Function): void

58

```

59

60

**Lifecycle Event Examples**:

61

```javascript

62

// Application startup complete

63

sails.on('lifted', () => {

64

console.log(`Sails app lifted on port ${sails.config.port}`);

65

console.log(`Environment: ${sails.config.environment}`);

66

67

// Start background jobs

68

startBackgroundTasks();

69

70

// Register with service discovery

71

registerWithLoadBalancer();

72

});

73

74

// Application shutdown initiated

75

sails.on('lower', () => {

76

console.log('Sails app is shutting down...');

77

78

// Cleanup background jobs

79

stopBackgroundTasks();

80

81

// Close external connections

82

closeExternalConnections();

83

});

84

85

// Internal ready state (before HTTP server starts)

86

sails.on('ready', () => {

87

console.log('App components loaded, starting HTTP server...');

88

89

// Perform pre-startup tasks

90

validateConfiguration();

91

initializeServices();

92

});

93

```

94

95

### Startup Sequence Events

96

97

The application startup follows a specific event sequence:

98

99

```javascript

100

// 1. Configuration loaded

101

sails.on('hook:userconfig:loaded', () => {

102

console.log('User configuration loaded');

103

});

104

105

// 2. Hooks initialized

106

sails.on('hook:*:loaded', (hookName) => {

107

console.log(`Hook loaded: ${hookName}`);

108

});

109

110

// 3. Components ready

111

sails.on('ready', () => {

112

console.log('All components ready');

113

});

114

115

// 4. Application lifted

116

sails.on('lifted', () => {

117

console.log('Application fully operational');

118

});

119

```

120

121

## Router Events

122

123

### Route Binding Events

124

125

```javascript { .api }

126

// Before static routes are bound

127

sails.on('router:before', callback: Function): void

128

129

// After static routes are bound

130

sails.on('router:after', callback: Function): void

131

132

// Router reset event

133

sails.on('router:reset', callback: Function): void

134

```

135

136

**Router Event Examples**:

137

```javascript

138

// Before route binding - modify routes

139

sails.on('router:before', () => {

140

console.log('Binding routes...');

141

142

// Add dynamic routes

143

sails.get('/health', (req, res) => {

144

return res.json({ status: 'ok', timestamp: Date.now() });

145

});

146

147

// Modify existing routes

148

modifyApiRoutes();

149

});

150

151

// After route binding - log route information

152

sails.on('router:after', () => {

153

console.log('Routes bound successfully');

154

155

const routes = sails.router.getSortedRouteAddresses();

156

console.log(`Total routes: ${routes.length}`);

157

158

// Log all routes in development

159

if (sails.config.environment === 'development') {

160

routes.forEach(route => console.log(` ${route}`));

161

}

162

});

163

164

// Router reset - cleanup custom routes

165

sails.on('router:reset', () => {

166

console.log('Router reset, clearing custom routes');

167

clearCustomRoutes();

168

});

169

```

170

171

### Request Handling Events

172

173

```javascript { .api }

174

// Virtual request routing

175

sails.on('router:request', (req, res): void

176

177

// Server error handling

178

sails.on('router:request:500', (req, res, err): void

179

180

// Not found handling

181

sails.on('router:request:404', (req, res): void

182

```

183

184

**Request Event Examples**:

185

```javascript

186

// Log all virtual requests

187

sails.on('router:request', (req, res) => {

188

console.log(`Virtual request: ${req.method} ${req.url}`);

189

});

190

191

// Custom 500 error handling

192

sails.on('router:request:500', (req, res, err) => {

193

console.error('Server error:', err);

194

195

// Log error details

196

console.error(`URL: ${req.url}`);

197

console.error(`Method: ${req.method}`);

198

console.error(`User: ${req.session?.userId || 'anonymous'}`);

199

200

// Send custom error response

201

if (!res.headersSent) {

202

return res.status(500).json({

203

error: 'Internal server error',

204

requestId: req.id,

205

timestamp: Date.now()

206

});

207

}

208

});

209

210

// Custom 404 handling

211

sails.on('router:request:404', (req, res) => {

212

console.log(`404 Not Found: ${req.method} ${req.url}`);

213

214

// Track 404s for analytics

215

trackNotFoundRequest(req);

216

217

// Send custom 404 response

218

if (!res.headersSent) {

219

return res.status(404).json({

220

error: 'Resource not found',

221

path: req.url,

222

suggestion: 'Check the API documentation'

223

});

224

}

225

});

226

```

227

228

## Hook Events

229

230

Hooks can define and emit custom events during their lifecycle:

231

232

### Hook Lifecycle Events

233

234

```javascript { .api }

235

// Hook-specific events

236

sails.on('hook:${hookName}:loaded', callback: Function): void

237

sails.on('hook:${hookName}:ready', callback: Function): void

238

```

239

240

**Hook Event Examples**:

241

```javascript

242

// Listen for specific hook events

243

sails.on('hook:orm:loaded', () => {

244

console.log('ORM hook loaded, models available');

245

246

// Perform database initialization

247

initializeDatabase();

248

});

249

250

sails.on('hook:sockets:loaded', () => {

251

console.log('Sockets hook loaded, WebSocket support available');

252

253

// Configure real-time features

254

setupRealtimeFeatures();

255

});

256

257

// Listen for all hook load events

258

sails.on('hook:*:loaded', (hookName) => {

259

console.log(`Hook loaded: ${hookName}`);

260

261

// Track loading progress

262

trackHookLoadingProgress(hookName);

263

});

264

```

265

266

### Custom Hook Events

267

268

Custom hooks can emit their own events:

269

270

```javascript

271

// api/hooks/my-hook/index.js

272

module.exports = function(sails) {

273

return {

274

initialize: function(cb) {

275

// Emit custom hook event

276

sails.emit('hook:my-hook:initialized', {

277

message: 'My hook is ready',

278

features: ['feature1', 'feature2']

279

});

280

281

// Set up periodic events

282

setInterval(() => {

283

sails.emit('hook:my-hook:heartbeat', { timestamp: Date.now() });

284

}, 30000);

285

286

return cb();

287

}

288

};

289

};

290

291

// Listen for custom hook events

292

sails.on('hook:my-hook:initialized', (data) => {

293

console.log('Custom hook initialized:', data.message);

294

console.log('Available features:', data.features);

295

});

296

297

sails.on('hook:my-hook:heartbeat', (data) => {

298

console.log('Hook heartbeat:', new Date(data.timestamp));

299

});

300

```

301

302

## Custom Application Events

303

304

Applications can define and emit custom events for business logic:

305

306

### User Events

307

308

```javascript

309

// User registration event

310

sails.on('user:registered', (userData) => {

311

console.log('New user registered:', userData.email);

312

313

// Send welcome email

314

EmailService.sendWelcomeEmail(userData.email, userData.name);

315

316

// Create user profile

317

UserProfileService.createProfile(userData.id);

318

319

// Track registration

320

AnalyticsService.track('user_registered', {

321

userId: userData.id,

322

source: userData.registrationSource

323

});

324

});

325

326

// User login event

327

sails.on('user:login', (loginData) => {

328

console.log('User logged in:', loginData.userId);

329

330

// Update last login timestamp

331

User.updateOne(loginData.userId).set({ lastLoginAt: Date.now() });

332

333

// Log security events

334

SecurityService.logLogin(loginData);

335

});

336

337

// Emit user events

338

const newUser = await User.create({

339

email: 'user@example.com',

340

name: 'John Doe'

341

}).fetch();

342

343

sails.emit('user:registered', {

344

id: newUser.id,

345

email: newUser.email,

346

name: newUser.name,

347

registrationSource: 'web'

348

});

349

```

350

351

### Business Logic Events

352

353

```javascript

354

// Order events

355

sails.on('order:created', async (orderData) => {

356

console.log('New order created:', orderData.id);

357

358

// Send confirmation email

359

await EmailService.sendOrderConfirmation(orderData);

360

361

// Update inventory

362

await InventoryService.reserveItems(orderData.items);

363

364

// Process payment

365

await PaymentService.processPayment(orderData.paymentInfo);

366

});

367

368

sails.on('order:shipped', (orderData) => {

369

console.log('Order shipped:', orderData.id);

370

371

// Send shipping notification

372

NotificationService.sendShippingNotification(orderData);

373

374

// Update tracking

375

TrackingService.createTrackingRecord(orderData);

376

});

377

378

// Payment events

379

sails.on('payment:successful', (paymentData) => {

380

console.log('Payment successful:', paymentData.transactionId);

381

382

// Fulfill order

383

OrderService.fulfillOrder(paymentData.orderId);

384

385

// Send receipt

386

EmailService.sendReceipt(paymentData);

387

});

388

389

sails.on('payment:failed', (paymentData) => {

390

console.error('Payment failed:', paymentData.error);

391

392

// Cancel order

393

OrderService.cancelOrder(paymentData.orderId);

394

395

// Notify customer

396

NotificationService.sendPaymentFailureNotification(paymentData);

397

});

398

```

399

400

## Event-Driven Architecture Patterns

401

402

### Event Aggregation

403

404

```javascript

405

// Collect multiple related events

406

const EventAggregator = {

407

events: [],

408

409

collect(eventName, eventData) {

410

this.events.push({ name: eventName, data: eventData, timestamp: Date.now() });

411

},

412

413

flush() {

414

const events = this.events.slice();

415

this.events = [];

416

return events;

417

}

418

};

419

420

// Listen to multiple events

421

['user:registered', 'user:login', 'user:logout'].forEach(eventName => {

422

sails.on(eventName, (data) => {

423

EventAggregator.collect(eventName, data);

424

});

425

});

426

427

// Periodic processing

428

setInterval(() => {

429

const events = EventAggregator.flush();

430

if (events.length > 0) {

431

AnalyticsService.batchProcess(events);

432

}

433

}, 60000); // Every minute

434

```

435

436

### Event Middleware

437

438

```javascript

439

// Event middleware pattern

440

const EventMiddleware = {

441

use(eventName, middleware) {

442

const originalEmit = sails.emit;

443

444

sails.emit = function(event, ...args) {

445

if (event === eventName) {

446

// Run middleware before emitting

447

middleware(event, args, () => {

448

originalEmit.call(this, event, ...args);

449

});

450

} else {

451

originalEmit.call(this, event, ...args);

452

}

453

};

454

}

455

};

456

457

// Use middleware

458

EventMiddleware.use('user:registered', (event, args, next) => {

459

console.log('Middleware: Processing user registration');

460

461

// Validate event data

462

if (!args[0].email) {

463

console.error('Invalid user registration data');

464

return; // Don't proceed

465

}

466

467

// Add metadata

468

args[0].processedAt = Date.now();

469

470

next();

471

});

472

```

473

474

### Event Sourcing Pattern

475

476

```javascript

477

// Simple event sourcing implementation

478

const EventStore = {

479

events: [],

480

481

append(event) {

482

this.events.push({

483

...event,

484

id: require('uuid').v4(),

485

timestamp: Date.now()

486

});

487

},

488

489

getEvents(aggregateId) {

490

return this.events.filter(e => e.aggregateId === aggregateId);

491

},

492

493

replay(aggregateId) {

494

const events = this.getEvents(aggregateId);

495

return events.reduce((state, event) => {

496

return applyEvent(state, event);

497

}, {});

498

}

499

};

500

501

// Store all user events

502

sails.on('user:*', (eventData) => {

503

EventStore.append({

504

type: 'user_event',

505

aggregateId: eventData.userId,

506

data: eventData

507

});

508

});

509

```

510

511

## Error Handling with Events

512

513

### Event Error Handling

514

515

```javascript

516

// Handle event errors

517

sails.on('error', (err) => {

518

console.error('Unhandled event error:', err);

519

520

// Log to external service

521

ErrorReportingService.reportError(err);

522

});

523

524

// Safe event emission

525

function safeEmit(eventName, eventData) {

526

try {

527

sails.emit(eventName, eventData);

528

} catch (err) {

529

console.error(`Error emitting event ${eventName}:`, err);

530

sails.emit('event:error', { eventName, eventData, error: err });

531

}

532

}

533

534

// Error recovery

535

sails.on('event:error', ({ eventName, eventData, error }) => {

536

console.log(`Attempting to recover from event error: ${eventName}`);

537

538

// Retry logic

539

setTimeout(() => {

540

safeEmit(eventName, eventData);

541

}, 5000);

542

});

543

```

544

545

## Event Performance and Monitoring

546

547

### Event Metrics

548

549

```javascript

550

// Event performance monitoring

551

const EventMetrics = {

552

counts: new Map(),

553

timings: new Map(),

554

555

track(eventName) {

556

this.counts.set(eventName, (this.counts.get(eventName) || 0) + 1);

557

},

558

559

time(eventName, duration) {

560

if (!this.timings.has(eventName)) {

561

this.timings.set(eventName, []);

562

}

563

this.timings.get(eventName).push(duration);

564

},

565

566

getStats() {

567

const stats = {};

568

569

for (const [event, count] of this.counts) {

570

stats[event] = { count };

571

572

if (this.timings.has(event)) {

573

const times = this.timings.get(event);

574

stats[event].avgTime = times.reduce((a, b) => a + b, 0) / times.length;

575

}

576

}

577

578

return stats;

579

}

580

};

581

582

// Monitor all events

583

const originalEmit = sails.emit;

584

sails.emit = function(event, ...args) {

585

const start = Date.now();

586

EventMetrics.track(event);

587

588

const result = originalEmit.call(this, event, ...args);

589

590

EventMetrics.time(event, Date.now() - start);

591

return result;

592

};

593

594

// Log metrics periodically

595

setInterval(() => {

596

console.log('Event Statistics:', EventMetrics.getStats());

597

}, 300000); // Every 5 minutes

598

```

599

600

The Sails.js event system provides a robust foundation for building event-driven applications with comprehensive lifecycle management, routing events, and custom business logic events, supporting modern architectural patterns and real-time functionality.