or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

amount-utilities.mdcontainer-di.mddata-utilities.mderror-handling.mdindex.mdserver-utilities.mdutility-functions.md

server-utilities.mddocs/

0

# Server Utilities

1

2

Server lifecycle management utilities including graceful shutdown patterns, configuration file loading, version detection, and Node.js module utilities.

3

4

## Capabilities

5

6

### Graceful Server Shutdown

7

8

Enhanced HTTP server with graceful shutdown capabilities that properly handles existing connections during server termination.

9

10

```typescript { .api }

11

import { Server } from "http";

12

13

/**

14

* Abstract class providing graceful shutdown functionality for HTTP servers

15

*/

16

abstract class GracefulShutdownServer {

17

/** Indicates if the server is currently shutting down */

18

public isShuttingDown: boolean;

19

20

/** Abstract method that must be implemented by concrete classes */

21

public abstract shutdown(timeout?: number): Promise<void>;

22

23

/**

24

* Creates a graceful shutdown server from an existing HTTP server

25

* @param originalServer - The HTTP server to enhance

26

* @param waitingResponseTime - Time to wait between connection checks (default: 200ms)

27

* @returns Enhanced server with graceful shutdown capabilities

28

*/

29

public static create<T extends Server>(

30

originalServer: T,

31

waitingResponseTime?: number

32

): T & GracefulShutdownServer;

33

}

34

```

35

36

**Usage Examples:**

37

38

```typescript

39

import { GracefulShutdownServer } from "medusa-core-utils";

40

import { createServer } from "http";

41

import express from "express";

42

43

// Create Express app and HTTP server

44

const app = express();

45

const httpServer = createServer(app);

46

47

// Enhance server with graceful shutdown

48

const server = GracefulShutdownServer.create(httpServer);

49

50

// Start server

51

server.listen(3000, () => {

52

console.log("Server running on port 3000");

53

});

54

55

// Handle shutdown signals

56

const gracefulShutdown = async (signal: string) => {

57

console.log(`Received ${signal}. Starting graceful shutdown...`);

58

59

try {

60

// Stop accepting new connections and wait for existing ones to finish

61

await server.shutdown(30000); // 30 second timeout

62

console.log("Server shut down gracefully");

63

process.exit(0);

64

} catch (error) {

65

console.error("Error during shutdown:", error);

66

process.exit(1);

67

}

68

};

69

70

// Register signal handlers

71

process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));

72

process.on("SIGINT", () => gracefulShutdown("SIGINT"));

73

74

// Check shutdown status

75

app.get("/health", (req, res) => {

76

if (server.isShuttingDown) {

77

res.status(503).json({ status: "shutting down" });

78

} else {

79

res.json({ status: "healthy" });

80

}

81

});

82

83

// With custom waiting time for faster shutdown cycles

84

const fastShutdownServer = GracefulShutdownServer.create(httpServer, 50);

85

```

86

87

### Configuration File Loading

88

89

Dynamic configuration file loading with error handling and support for various module formats.

90

91

```typescript { .api }

92

/**

93

* Attempts to resolve and load a configuration file from a directory

94

* @param rootDir - The directory to search for the config file

95

* @param configName - The name of the config file (without extension)

96

* @returns Object containing the loaded config, file path, and any errors

97

*/

98

function getConfigFile<TConfig = unknown>(

99

rootDir: string,

100

configName: string

101

): {

102

configModule: TConfig;

103

configFilePath: string;

104

error: any

105

};

106

```

107

108

**Usage Examples:**

109

110

```typescript

111

import { getConfigFile } from "medusa-core-utils";

112

import path from "path";

113

114

// Load application configuration

115

const { configModule, configFilePath, error } = getConfigFile(

116

process.cwd(),

117

"medusa-config"

118

);

119

120

if (error) {

121

console.log("No config file found, using defaults");

122

// Handle missing config gracefully

123

} else {

124

console.log(`Loaded config from: ${configFilePath}`);

125

console.log("Config:", configModule);

126

}

127

128

// Type-safe configuration loading

129

interface AppConfig {

130

database: {

131

host: string;

132

port: number;

133

};

134

redis: {

135

url: string;

136

};

137

server: {

138

port: number;

139

};

140

}

141

142

function loadAppConfig(): AppConfig {

143

const { configModule, error } = getConfigFile<AppConfig>(

144

process.cwd(),

145

"app-config"

146

);

147

148

if (error || !configModule) {

149

// Return default configuration

150

return {

151

database: {

152

host: "localhost",

153

port: 5432

154

},

155

redis: {

156

url: "redis://localhost:6379"

157

},

158

server: {

159

port: 3000

160

}

161

};

162

}

163

164

return configModule;

165

}

166

167

// Multi-environment config loading

168

function loadEnvironmentConfig(env: string = "development") {

169

const configName = `config.${env}`;

170

const { configModule, error } = getConfigFile(

171

path.join(process.cwd(), "config"),

172

configName

173

);

174

175

if (error) {

176

console.warn(`Failed to load ${configName}, falling back to default config`);

177

return getConfigFile(process.cwd(), "config").configModule;

178

}

179

180

return configModule;

181

}

182

183

// Plugin configuration loading

184

function loadPluginConfigs(pluginDir: string): Record<string, any> {

185

const fs = require("fs");

186

const plugins = {};

187

188

try {

189

const files = fs.readdirSync(pluginDir);

190

191

for (const file of files) {

192

if (file.endsWith("-config.js")) {

193

const pluginName = file.replace("-config.js", "");

194

const { configModule, error } = getConfigFile(pluginDir, file.replace(".js", ""));

195

196

if (!error && configModule) {

197

plugins[pluginName] = configModule;

198

}

199

}

200

}

201

} catch (error) {

202

console.warn("Failed to load plugin configs:", error.message);

203

}

204

205

return plugins;

206

}

207

```

208

209

### Version Detection

210

211

Utility to detect the installed version of the Medusa framework.

212

213

```typescript { .api }

214

/**

215

* Gets the version of the installed @medusajs/medusa package

216

* @returns Version string or empty string if not found

217

*/

218

function getMedusaVersion(): string;

219

```

220

221

**Usage Examples:**

222

223

```typescript

224

import { getMedusaVersion } from "medusa-core-utils";

225

226

// Get current Medusa version

227

const version = getMedusaVersion();

228

229

if (version) {

230

console.log(`Medusa version: ${version}`);

231

} else {

232

console.log("Medusa package not found");

233

}

234

235

// Version compatibility checking

236

function checkCompatibility() {

237

const currentVersion = getMedusaVersion();

238

239

if (!currentVersion) {

240

throw new Error("Medusa package not installed");

241

}

242

243

const [major, minor] = currentVersion.split('.').map(Number);

244

245

if (major < 1 || (major === 1 && minor < 2)) {

246

throw new Error(`Unsupported Medusa version: ${currentVersion}. Minimum required: 1.2.0`);

247

}

248

249

return currentVersion;

250

}

251

252

// System information gathering

253

function getSystemInfo() {

254

return {

255

nodeVersion: process.version,

256

medusaVersion: getMedusaVersion(),

257

platform: process.platform,

258

arch: process.arch,

259

environment: process.env.NODE_ENV || "development"

260

};

261

}

262

263

// Health check endpoint

264

app.get("/health", (req, res) => {

265

const medusaVersion = getMedusaVersion();

266

267

res.json({

268

status: "healthy",

269

timestamp: new Date().toISOString(),

270

versions: {

271

node: process.version,

272

medusa: medusaVersion || "not-installed"

273

}

274

});

275

});

276

```

277

278

### Module Require Utilities

279

280

Cross-platform utility for creating require functions from specific file paths.

281

282

```typescript { .api }

283

/**

284

* Creates a require function from a specific file path

285

* Polyfill for Node's Module.createRequire (added in Node v10.12.0)

286

* @param filename - The file path to create require function for

287

* @returns require function scoped to the given path

288

*/

289

function createRequireFromPath(filename: string): NodeRequire;

290

```

291

292

**Usage Examples:**

293

294

```typescript

295

import { createRequireFromPath } from "medusa-core-utils";

296

import path from "path";

297

298

// Create require function for a specific directory

299

const pluginDir = path.join(process.cwd(), "plugins", "my-plugin");

300

const pluginRequire = createRequireFromPath(path.join(pluginDir, "index.js"));

301

302

// Use the scoped require to load modules relative to plugin directory

303

try {

304

const pluginConfig = pluginRequire("./config.json");

305

const pluginHelpers = pluginRequire("./helpers");

306

307

console.log("Plugin loaded successfully");

308

} catch (error) {

309

console.error("Failed to load plugin:", error);

310

}

311

312

// Dynamic module loading from different contexts

313

function loadModuleFromPath(modulePath: string, fromDirectory: string) {

314

const requireFromPath = createRequireFromPath(

315

path.join(fromDirectory, "package.json")

316

);

317

318

try {

319

return requireFromPath(modulePath);

320

} catch (error) {

321

throw new Error(`Failed to load module ${modulePath} from ${fromDirectory}: ${error.message}`);

322

}

323

}

324

325

// Plugin system implementation

326

class PluginLoader {

327

private pluginDir: string;

328

private pluginRequire: NodeRequire;

329

330

constructor(pluginDirectory: string) {

331

this.pluginDir = pluginDirectory;

332

this.pluginRequire = createRequireFromPath(

333

path.join(pluginDirectory, "index.js")

334

);

335

}

336

337

loadPlugin(pluginName: string) {

338

try {

339

const pluginMain = this.pluginRequire(`./${pluginName}`);

340

const pluginPackage = this.pluginRequire(`./${pluginName}/package.json`);

341

342

return {

343

name: pluginName,

344

version: pluginPackage.version,

345

main: pluginMain,

346

path: path.join(this.pluginDir, pluginName)

347

};

348

} catch (error) {

349

throw new Error(`Failed to load plugin ${pluginName}: ${error.message}`);

350

}

351

}

352

}

353

354

// Cross-Node.js version compatibility

355

function createRequire(filename: string) {

356

// Use native createRequire if available (Node.js 12+)

357

if (require.createRequire) {

358

return require.createRequire(filename);

359

}

360

361

// Fallback to custom implementation for older Node.js

362

return createRequireFromPath(filename);

363

}