or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdport-configuration.mdport-finding.mdsocket-finding.md

socket-finding.mddocs/

0

# Socket Finding

1

2

Unix socket path discovery for finding available socket file paths with configurable directory and permission settings.

3

4

## Capabilities

5

6

### Get Socket Function

7

8

Finds and returns an unbound Unix socket path. Creates necessary directories if they don't exist.

9

10

```javascript { .api }

11

/**

12

* Responds with a unbound socket using the specified directory and base name on the current machine

13

* @param {SocketFinderOptions} [options] - Socket search options

14

* @param {function} [callback] - Callback function (err, socketPath) => void

15

* @returns {Promise<string>} Promise resolving to available socket path (when no callback provided)

16

*/

17

function getSocket(options?: SocketFinderOptions): Promise<string>;

18

function getSocket(callback: (err: Error, socket: string) => void): void;

19

function getSocket(options: SocketFinderOptions, callback: (err: Error, socket: string) => void): void;

20

```

21

22

**Usage Examples:**

23

24

```javascript

25

const portfinder = require('portfinder');

26

27

// Basic usage with callback - uses default path

28

portfinder.getSocket(function (err, socketPath) {

29

if (err) throw err;

30

console.log('Available socket:', socketPath); // e.g., '/tmp/portfinder.sock'

31

});

32

33

// Promise-based usage

34

portfinder.getSocketPromise()

35

.then((socketPath) => {

36

console.log('Available socket:', socketPath);

37

})

38

.catch((err) => {

39

console.error('Error finding socket:', err);

40

});

41

42

// With custom path - callback style

43

portfinder.getSocket({

44

path: '/var/run/myapp.sock'

45

}, function(err, socketPath) {

46

if (err) throw err;

47

console.log('Socket path:', socketPath); // '/var/run/myapp.sock' or '/var/run/myapp1.sock'

48

});

49

50

// With custom directory permissions - Promise style

51

portfinder.getSocket({

52

path: '/tmp/sockets/app.sock',

53

mod: parseInt('755', 8) // Directory permissions in octal

54

})

55

.then(socketPath => {

56

console.log('Socket with custom permissions:', socketPath);

57

});

58

```

59

60

### Get Socket Promise Function

61

62

Promise-based version of getSocket (alias for getSocket without callback).

63

64

```javascript { .api }

65

/**

66

* Responds a promise that resolves to an unbound socket path

67

* @param {SocketFinderOptions} [options] - Socket search options

68

* @returns {Promise<string>} Promise resolving to available socket path

69

*/

70

function getSocketPromise(options?: SocketFinderOptions): Promise<string>;

71

```

72

73

**Usage Example:**

74

75

```javascript

76

const portfinder = require('portfinder');

77

78

// Equivalent to getSocket without callback

79

const socketPath = await portfinder.getSocketPromise({

80

path: '/run/user/1000/app.sock'

81

});

82

console.log('Found socket path:', socketPath);

83

```

84

85

### Next Socket Function

86

87

Gets the next socket path in sequence by incrementing numeric suffix.

88

89

```javascript { .api }

90

/**

91

* Gets the next socket path in sequence from the specified socketPath

92

* @param {string} socketPath - Path to increment from

93

* @returns {string} Next socket path with incremented numeric suffix

94

*/

95

function nextSocket(socketPath: string): string;

96

```

97

98

**Usage Examples:**

99

100

```javascript

101

const portfinder = require('portfinder');

102

103

// Basic increment

104

const currentSocket = '/tmp/app.sock';

105

const nextSocket = portfinder.nextSocket(currentSocket);

106

console.log('Next socket:', nextSocket); // '/tmp/app1.sock'

107

108

// With existing number

109

const numbered = '/tmp/server5.sock';

110

const incremented = portfinder.nextSocket(numbered);

111

console.log('Incremented socket:', incremented); // '/tmp/server6.sock'

112

113

// Manual socket iteration

114

let testSocket = '/var/run/worker.sock';

115

for (let i = 0; i < 5; i++) {

116

console.log('Testing socket:', testSocket);

117

testSocket = portfinder.nextSocket(testSocket);

118

}

119

// Outputs: worker.sock, worker1.sock, worker2.sock, worker3.sock, worker4.sock

120

```

121

122

## Options Interface

123

124

```javascript { .api }

125

/**

126

* Options for socket finding operations

127

*/

128

interface SocketFinderOptions {

129

/**

130

* Path to the socket file to create

131

* Defaults to ${basePath}.sock (e.g., '/tmp/portfinder.sock')

132

*/

133

path?: string;

134

135

/**

136

* Mode to use when creating folder for socket if it doesn't exist

137

* Should be specified in octal format (e.g., parseInt('755', 8))

138

* Defaults to 755 (rwxr-xr-x)

139

*/

140

mod?: number;

141

}

142

```

143

144

## Socket Path Resolution

145

146

### Default Behavior

147

148

```javascript

149

const portfinder = require('portfinder');

150

151

// Uses global basePath setting

152

console.log('Base path:', portfinder.basePath); // '/tmp/portfinder'

153

154

portfinder.getSocketPromise().then(socketPath => {

155

console.log('Default socket:', socketPath); // '/tmp/portfinder.sock'

156

});

157

```

158

159

### Path Conflicts and Resolution

160

161

```javascript

162

const portfinder = require('portfinder');

163

const fs = require('fs');

164

165

// Create a conflicting socket file

166

fs.writeFileSync('/tmp/test.sock', '');

167

168

portfinder.getSocket({ path: '/tmp/test.sock' }, (err, socketPath) => {

169

console.log('Resolved path:', socketPath); // '/tmp/test1.sock'

170

});

171

```

172

173

## Advanced Usage Patterns

174

175

### Application-Specific Sockets

176

177

```javascript

178

const portfinder = require('portfinder');

179

const path = require('path');

180

const os = require('os');

181

182

async function createAppSocket(appName, userId) {

183

const userRunDir = `/run/user/${userId}`;

184

const socketPath = path.join(userRunDir, `${appName}.sock`);

185

186

try {

187

const finalPath = await portfinder.getSocketPromise({

188

path: socketPath,

189

mod: parseInt('700', 8) // Only user can access

190

});

191

192

return finalPath;

193

} catch (err) {

194

// Fallback to temp directory

195

const tempPath = path.join(os.tmpdir(), `${appName}-${userId}.sock`);

196

return await portfinder.getSocketPromise({ path: tempPath });

197

}

198

}

199

200

createAppSocket('myapp', 1000).then(socketPath => {

201

console.log('App socket path:', socketPath);

202

});

203

```

204

205

### Multiple Service Sockets

206

207

```javascript

208

const portfinder = require('portfinder');

209

210

async function allocateServiceSockets() {

211

const services = ['api', 'worker', 'scheduler', 'monitor'];

212

const baseDir = '/var/run/myapp';

213

214

const allocations = await Promise.all(

215

services.map(async (service) => {

216

const socketPath = await portfinder.getSocketPromise({

217

path: `${baseDir}/${service}.sock`,

218

mod: parseInt('755', 8)

219

});

220

return { service, socketPath };

221

})

222

);

223

224

return allocations;

225

}

226

227

allocateServiceSockets().then(allocations => {

228

console.log('Service socket allocations:', allocations);

229

// e.g., [

230

// { service: 'api', socketPath: '/var/run/myapp/api.sock' },

231

// { service: 'worker', socketPath: '/var/run/myapp/worker.sock' },

232

// { service: 'scheduler', socketPath: '/var/run/myapp/scheduler1.sock' }, // if scheduler.sock exists

233

// { service: 'monitor', socketPath: '/var/run/myapp/monitor.sock' }

234

// ]

235

});

236

```

237

238

### Socket Cleanup and Management

239

240

```javascript

241

const portfinder = require('portfinder');

242

const fs = require('fs').promises;

243

244

class SocketManager {

245

constructor() {

246

this.activeSockets = new Set();

247

}

248

249

async createSocket(options) {

250

const socketPath = await portfinder.getSocketPromise(options);

251

this.activeSockets.add(socketPath);

252

return socketPath;

253

}

254

255

async cleanup() {

256

const cleanupPromises = Array.from(this.activeSockets).map(async (socketPath) => {

257

try {

258

await fs.unlink(socketPath);

259

console.log('Cleaned up socket:', socketPath);

260

} catch (err) {

261

if (err.code !== 'ENOENT') {

262

console.error('Failed to cleanup socket:', socketPath, err);

263

}

264

}

265

});

266

267

await Promise.all(cleanupPromises);

268

this.activeSockets.clear();

269

}

270

}

271

272

// Usage

273

const manager = new SocketManager();

274

275

async function example() {

276

const socket1 = await manager.createSocket({ path: '/tmp/service1.sock' });

277

const socket2 = await manager.createSocket({ path: '/tmp/service2.sock' });

278

279

console.log('Created sockets:', socket1, socket2);

280

281

// Cleanup on process exit

282

process.on('exit', () => manager.cleanup());

283

}

284

```

285

286

## Directory Creation Behavior

287

288

When a socket path is requested, portfinder automatically handles directory creation:

289

290

1. **Existing Directory**: If the parent directory exists, uses it directly

291

2. **Missing Directory**: Creates the directory with specified permissions (`mod` option)

292

3. **Recursive Creation**: Creates parent directories as needed using `fs.mkdir` with `recursive: true`

293

4. **Permission Inheritance**: Uses the `mod` option for all created directories in the path

294

295

```javascript

296

const portfinder = require('portfinder');

297

298

// This will create /deep/nested/path/ if it doesn't exist

299

portfinder.getSocket({

300

path: '/deep/nested/path/app.sock',

301

mod: parseInt('755', 8)

302

}).then(socketPath => {

303

console.log('Socket created with full path:', socketPath);

304

});

305

```