odac 1.1.0 → 1.2.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.
- package/.agent/rules/coding.md +27 -0
- package/.agent/rules/memory.md +33 -0
- package/.agent/rules/project.md +30 -0
- package/.agent/rules/workflow.md +16 -0
- package/.github/workflows/release.yml +42 -1
- package/.github/workflows/test-coverage.yml +6 -5
- package/.github/workflows/test-publish.yml +36 -0
- package/.husky/pre-commit +10 -0
- package/.husky/pre-push +13 -0
- package/.releaserc.js +3 -3
- package/CHANGELOG.md +67 -0
- package/README.md +16 -0
- package/bin/odac.js +182 -40
- package/client/odac.js +10 -4
- package/docs/backend/01-overview/03-development-server.md +38 -45
- package/docs/backend/02-structure/01-typical-project-layout.md +59 -26
- package/docs/backend/03-config/00-configuration-overview.md +6 -6
- package/docs/backend/03-config/01-database-connection.md +2 -2
- package/docs/backend/03-config/02-static-route-mapping-optional.md +1 -1
- package/docs/backend/03-config/03-request-timeout.md +1 -1
- package/docs/backend/03-config/04-environment-variables.md +4 -4
- package/docs/backend/03-config/05-early-hints.md +2 -2
- package/docs/backend/04-routing/03-api-and-data-routes.md +18 -0
- package/docs/backend/04-routing/07-cron-jobs.md +17 -1
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +48 -3
- package/docs/backend/05-controllers/03-controller-classes.md +40 -20
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +17 -0
- package/docs/backend/07-views/10-styling-and-tailwind.md +93 -0
- package/docs/backend/08-database/01-getting-started.md +2 -2
- package/docs/backend/10-authentication/03-register.md +1 -1
- package/docs/backend/10-authentication/04-odac-register-forms.md +2 -2
- package/docs/backend/10-authentication/05-session-management.md +15 -1
- package/docs/backend/10-authentication/06-odac-login-forms.md +2 -2
- package/docs/backend/10-authentication/07-magic-links.md +1 -1
- package/docs/index.json +5 -1
- package/jest.config.js +1 -1
- package/package.json +9 -5
- package/src/Auth.js +58 -23
- package/src/Config.js +7 -7
- package/src/Env.js +3 -1
- package/src/Ipc.js +7 -0
- package/src/Lang.js +9 -2
- package/src/Odac.js +44 -35
- package/src/Request.js +1 -1
- package/src/Route/Cron.js +58 -17
- package/src/Route/Internal.js +1 -1
- package/src/Route.js +282 -99
- package/src/Server.js +40 -3
- package/src/Storage.js +4 -0
- package/src/Token.js +6 -4
- package/src/Validator.js +1 -1
- package/src/Var.js +22 -6
- package/src/View/EarlyHints.js +43 -33
- package/src/View/Form.js +17 -11
- package/src/View.js +62 -6
- package/template/package.json +3 -1
- package/template/view/content/home.html +3 -3
- package/template/view/head/main.html +2 -2
- package/test/Client.test.js +168 -0
- package/test/Config.test.js +112 -0
- package/test/Lang.test.js +92 -0
- package/test/Odac.test.js +86 -0
- package/test/{framework/middleware.test.js → Route/Middleware.test.js} +2 -2
- package/test/{framework/Route.test.js → Route.test.js} +1 -1
- package/test/{framework/View → View}/EarlyHints.test.js +1 -1
- package/test/{framework/WebSocket.test.js → WebSocket.test.js} +2 -2
- package/test/scripts/check-coverage.js +4 -4
- package/test/cli/Cli.test.js +0 -36
- package/test/core/Commands.test.js +0 -538
- package/test/core/Config.test.js +0 -1432
- package/test/core/Lang.test.js +0 -250
- package/test/core/Odac.test.js +0 -234
- package/test/core/Process.test.js +0 -156
- package/test/server/Api.test.js +0 -647
- package/test/server/DNS.test.js +0 -2050
- package/test/server/DNS.test.js.bak +0 -2084
- package/test/server/Hub.test.js +0 -497
- package/test/server/Log.test.js +0 -73
- package/test/server/Mail.account.test_.js +0 -460
- package/test/server/Mail.init.test_.js +0 -411
- package/test/server/Mail.test_.js +0 -1340
- package/test/server/SSL.test_.js +0 -1491
- package/test/server/Server.test.js +0 -765
- package/test/server/Service.test_.js +0 -1127
- package/test/server/Subdomain.test.js +0 -440
- package/test/server/Web/Firewall.test.js +0 -175
- package/test/server/Web/Proxy.test.js +0 -397
- package/test/server/Web.test.js +0 -1494
- package/test/server/__mocks__/acme-client.js +0 -17
- package/test/server/__mocks__/bcrypt.js +0 -50
- package/test/server/__mocks__/child_process.js +0 -389
- package/test/server/__mocks__/crypto.js +0 -432
- package/test/server/__mocks__/fs.js +0 -450
- package/test/server/__mocks__/globalOdac.js +0 -227
- package/test/server/__mocks__/http.js +0 -575
- package/test/server/__mocks__/https.js +0 -272
- package/test/server/__mocks__/index.js +0 -249
- package/test/server/__mocks__/mail/server.js +0 -100
- package/test/server/__mocks__/mail/smtp.js +0 -31
- package/test/server/__mocks__/mailparser.js +0 -81
- package/test/server/__mocks__/net.js +0 -369
- package/test/server/__mocks__/node-forge.js +0 -328
- package/test/server/__mocks__/os.js +0 -320
- package/test/server/__mocks__/path.js +0 -291
- package/test/server/__mocks__/selfsigned.js +0 -8
- package/test/server/__mocks__/server/src/mail/server.js +0 -100
- package/test/server/__mocks__/server/src/mail/smtp.js +0 -31
- package/test/server/__mocks__/smtp-server.js +0 -106
- package/test/server/__mocks__/sqlite3.js +0 -394
- package/test/server/__mocks__/testFactories.js +0 -299
- package/test/server/__mocks__/testHelpers.js +0 -363
- package/test/server/__mocks__/tls.js +0 -229
- /package/template/{config.json → odac.json} +0 -0
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock implementation of mailparser for server tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const {createMockEmailMessage} = require('./testFactories')
|
|
6
|
-
|
|
7
|
-
const simpleParser = jest.fn((source, options, callback) => {
|
|
8
|
-
if (typeof options === 'function') {
|
|
9
|
-
callback = options
|
|
10
|
-
options = {}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Create a mock parsed email
|
|
14
|
-
const mockParsedEmail = createMockEmailMessage()
|
|
15
|
-
|
|
16
|
-
// Allow customization through options
|
|
17
|
-
if (options.from) mockParsedEmail.from.value[0].address = options.from
|
|
18
|
-
if (options.to) mockParsedEmail.to[0].address = options.to
|
|
19
|
-
if (options.subject) mockParsedEmail.subject = options.subject
|
|
20
|
-
if (options.text) mockParsedEmail.text = options.text
|
|
21
|
-
if (options.html) mockParsedEmail.html = options.html
|
|
22
|
-
|
|
23
|
-
// Simulate async parsing
|
|
24
|
-
setTimeout(() => {
|
|
25
|
-
if (callback) {
|
|
26
|
-
callback(null, mockParsedEmail)
|
|
27
|
-
}
|
|
28
|
-
}, 0)
|
|
29
|
-
|
|
30
|
-
// Return a promise if no callback provided
|
|
31
|
-
if (!callback) {
|
|
32
|
-
return Promise.resolve(mockParsedEmail)
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
// Mock for streaming parser
|
|
37
|
-
const parseHeaders = jest.fn((source, callback) => {
|
|
38
|
-
const mockHeaders = new Map([
|
|
39
|
-
['from', 'sender@example.com'],
|
|
40
|
-
['to', 'recipient@example.com'],
|
|
41
|
-
['subject', 'Test Email'],
|
|
42
|
-
['date', new Date().toISOString()],
|
|
43
|
-
['message-id', '<test@example.com>']
|
|
44
|
-
])
|
|
45
|
-
|
|
46
|
-
setTimeout(() => {
|
|
47
|
-
if (callback) {
|
|
48
|
-
callback(null, mockHeaders)
|
|
49
|
-
}
|
|
50
|
-
}, 0)
|
|
51
|
-
|
|
52
|
-
if (!callback) {
|
|
53
|
-
return Promise.resolve(mockHeaders)
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
// Mock for attachment parsing
|
|
58
|
-
const parseAttachment = jest.fn((attachment, callback) => {
|
|
59
|
-
const mockAttachment = {
|
|
60
|
-
filename: 'test.txt',
|
|
61
|
-
contentType: 'text/plain',
|
|
62
|
-
size: 100,
|
|
63
|
-
content: Buffer.from('test attachment content')
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
setTimeout(() => {
|
|
67
|
-
if (callback) {
|
|
68
|
-
callback(null, mockAttachment)
|
|
69
|
-
}
|
|
70
|
-
}, 0)
|
|
71
|
-
|
|
72
|
-
if (!callback) {
|
|
73
|
-
return Promise.resolve(mockAttachment)
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
module.exports = {
|
|
78
|
-
simpleParser,
|
|
79
|
-
parseHeaders,
|
|
80
|
-
parseAttachment
|
|
81
|
-
}
|
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock implementation of the net module for server tests
|
|
3
|
-
* Provides comprehensive mocking of TCP server and socket operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const {createMockEventEmitter} = require('./testHelpers')
|
|
7
|
-
|
|
8
|
-
// Track active servers and connections
|
|
9
|
-
const activeServers = new Map()
|
|
10
|
-
const activeConnections = new Map()
|
|
11
|
-
let nextConnectionId = 1
|
|
12
|
-
|
|
13
|
-
const createMockSocket = (options = {}) => {
|
|
14
|
-
const socket = createMockEventEmitter()
|
|
15
|
-
const connectionId = nextConnectionId++
|
|
16
|
-
|
|
17
|
-
Object.assign(socket, {
|
|
18
|
-
// Connection properties
|
|
19
|
-
remoteAddress: options.remoteAddress || '127.0.0.1',
|
|
20
|
-
remotePort: options.remotePort || Math.floor(Math.random() * 50000) + 10000,
|
|
21
|
-
localAddress: options.localAddress || '127.0.0.1',
|
|
22
|
-
localPort: options.localPort || 1453,
|
|
23
|
-
remoteFamily: options.remoteFamily || 'IPv4',
|
|
24
|
-
localFamily: options.localFamily || 'IPv4',
|
|
25
|
-
|
|
26
|
-
// State properties
|
|
27
|
-
readable: true,
|
|
28
|
-
writable: true,
|
|
29
|
-
destroyed: false,
|
|
30
|
-
connecting: false,
|
|
31
|
-
readyState: 'open',
|
|
32
|
-
|
|
33
|
-
// Buffer properties
|
|
34
|
-
bytesRead: 0,
|
|
35
|
-
bytesWritten: 0,
|
|
36
|
-
|
|
37
|
-
// Methods
|
|
38
|
-
write: jest.fn((data, encoding, callback) => {
|
|
39
|
-
if (socket.destroyed || !socket.writable) {
|
|
40
|
-
const error = new Error('Cannot write to destroyed socket')
|
|
41
|
-
if (callback) callback(error)
|
|
42
|
-
return false
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
socket.bytesWritten += Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data, encoding)
|
|
46
|
-
|
|
47
|
-
if (callback) {
|
|
48
|
-
setTimeout(callback, 0)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return true
|
|
52
|
-
}),
|
|
53
|
-
|
|
54
|
-
end: jest.fn((data, encoding, callback) => {
|
|
55
|
-
if (data) {
|
|
56
|
-
socket.write(data, encoding)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (typeof encoding === 'function') {
|
|
60
|
-
callback = encoding
|
|
61
|
-
}
|
|
62
|
-
if (typeof data === 'function') {
|
|
63
|
-
callback = data
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
socket.writable = false
|
|
67
|
-
|
|
68
|
-
setTimeout(() => {
|
|
69
|
-
socket.emit('end')
|
|
70
|
-
if (callback) callback()
|
|
71
|
-
}, 0)
|
|
72
|
-
|
|
73
|
-
return socket
|
|
74
|
-
}),
|
|
75
|
-
|
|
76
|
-
destroy: jest.fn(error => {
|
|
77
|
-
if (socket.destroyed) return socket
|
|
78
|
-
|
|
79
|
-
socket.destroyed = true
|
|
80
|
-
socket.readable = false
|
|
81
|
-
socket.writable = false
|
|
82
|
-
socket.readyState = 'closed'
|
|
83
|
-
|
|
84
|
-
activeConnections.delete(connectionId)
|
|
85
|
-
|
|
86
|
-
setTimeout(() => {
|
|
87
|
-
if (error) {
|
|
88
|
-
socket.emit('error', error)
|
|
89
|
-
}
|
|
90
|
-
socket.emit('close', !!error)
|
|
91
|
-
}, 0)
|
|
92
|
-
|
|
93
|
-
return socket
|
|
94
|
-
}),
|
|
95
|
-
|
|
96
|
-
pause: jest.fn(() => {
|
|
97
|
-
socket.readable = false
|
|
98
|
-
return socket
|
|
99
|
-
}),
|
|
100
|
-
|
|
101
|
-
resume: jest.fn(() => {
|
|
102
|
-
socket.readable = true
|
|
103
|
-
return socket
|
|
104
|
-
}),
|
|
105
|
-
|
|
106
|
-
setTimeout: jest.fn((timeout, callback) => {
|
|
107
|
-
if (callback) {
|
|
108
|
-
socket.once('timeout', callback)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const timeoutId = setTimeout(() => {
|
|
112
|
-
socket.emit('timeout')
|
|
113
|
-
}, timeout)
|
|
114
|
-
|
|
115
|
-
socket._timeout = timeoutId
|
|
116
|
-
return socket
|
|
117
|
-
}),
|
|
118
|
-
|
|
119
|
-
setNoDelay: jest.fn((noDelay = true) => {
|
|
120
|
-
socket._noDelay = noDelay
|
|
121
|
-
return socket
|
|
122
|
-
}),
|
|
123
|
-
|
|
124
|
-
setKeepAlive: jest.fn((enable = false, initialDelay = 0) => {
|
|
125
|
-
socket._keepAlive = enable
|
|
126
|
-
socket._keepAliveInitialDelay = initialDelay
|
|
127
|
-
return socket
|
|
128
|
-
}),
|
|
129
|
-
|
|
130
|
-
address: jest.fn(() => ({
|
|
131
|
-
address: socket.localAddress,
|
|
132
|
-
family: socket.localFamily,
|
|
133
|
-
port: socket.localPort
|
|
134
|
-
})),
|
|
135
|
-
|
|
136
|
-
// Test helpers
|
|
137
|
-
__simulateData: data => {
|
|
138
|
-
if (!socket.destroyed && socket.readable) {
|
|
139
|
-
socket.bytesRead += Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data)
|
|
140
|
-
socket.emit('data', Buffer.isBuffer(data) ? data : Buffer.from(data))
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
|
|
144
|
-
__simulateError: error => {
|
|
145
|
-
socket.emit('error', error)
|
|
146
|
-
},
|
|
147
|
-
|
|
148
|
-
__simulateClose: (hadError = false) => {
|
|
149
|
-
socket.destroy()
|
|
150
|
-
}
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
activeConnections.set(connectionId, socket)
|
|
154
|
-
return socket
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const createMockServer = (options = {}) => {
|
|
158
|
-
const server = createMockEventEmitter()
|
|
159
|
-
const serverId = Math.floor(Math.random() * 1000)
|
|
160
|
-
|
|
161
|
-
Object.assign(server, {
|
|
162
|
-
// State properties
|
|
163
|
-
listening: false,
|
|
164
|
-
maxConnections: options.maxConnections || 0,
|
|
165
|
-
connections: 0,
|
|
166
|
-
|
|
167
|
-
// Server address info
|
|
168
|
-
address: jest.fn(() => {
|
|
169
|
-
if (!server.listening) return null
|
|
170
|
-
return {
|
|
171
|
-
address: server._address || '127.0.0.1',
|
|
172
|
-
family: server._family || 'IPv4',
|
|
173
|
-
port: server._port || 1453
|
|
174
|
-
}
|
|
175
|
-
}),
|
|
176
|
-
|
|
177
|
-
// Methods
|
|
178
|
-
listen: jest.fn((port, hostname, backlog, callback) => {
|
|
179
|
-
// Handle different argument patterns
|
|
180
|
-
if (typeof port === 'function') {
|
|
181
|
-
callback = port
|
|
182
|
-
port = 0
|
|
183
|
-
} else if (typeof hostname === 'function') {
|
|
184
|
-
callback = hostname
|
|
185
|
-
hostname = undefined
|
|
186
|
-
} else if (typeof backlog === 'function') {
|
|
187
|
-
callback = backlog
|
|
188
|
-
backlog = undefined
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
server._port = port || Math.floor(Math.random() * 50000) + 10000
|
|
192
|
-
server._address = hostname || '127.0.0.1'
|
|
193
|
-
server._family = 'IPv4'
|
|
194
|
-
server.listening = true
|
|
195
|
-
|
|
196
|
-
if (callback) {
|
|
197
|
-
server.once('listening', callback)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
setTimeout(() => {
|
|
201
|
-
server.emit('listening')
|
|
202
|
-
}, 0)
|
|
203
|
-
|
|
204
|
-
return server
|
|
205
|
-
}),
|
|
206
|
-
|
|
207
|
-
close: jest.fn(callback => {
|
|
208
|
-
if (!server.listening) {
|
|
209
|
-
const error = new Error('Server is not running')
|
|
210
|
-
if (callback) {
|
|
211
|
-
setTimeout(() => callback(error), 0)
|
|
212
|
-
}
|
|
213
|
-
return server
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
server.listening = false
|
|
217
|
-
|
|
218
|
-
// Close all connections
|
|
219
|
-
activeConnections.forEach(socket => {
|
|
220
|
-
if (socket.localPort === server._port) {
|
|
221
|
-
socket.destroy()
|
|
222
|
-
}
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
if (callback) {
|
|
226
|
-
server.once('close', callback)
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
setTimeout(() => {
|
|
230
|
-
server.emit('close')
|
|
231
|
-
}, 0)
|
|
232
|
-
|
|
233
|
-
activeServers.delete(serverId)
|
|
234
|
-
return server
|
|
235
|
-
}),
|
|
236
|
-
|
|
237
|
-
getConnections: jest.fn(callback => {
|
|
238
|
-
const count = Array.from(activeConnections.values()).filter(socket => socket.localPort === server._port && !socket.destroyed).length
|
|
239
|
-
|
|
240
|
-
if (callback) {
|
|
241
|
-
setTimeout(() => callback(null, count), 0)
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return count
|
|
245
|
-
}),
|
|
246
|
-
|
|
247
|
-
ref: jest.fn(() => server),
|
|
248
|
-
unref: jest.fn(() => server),
|
|
249
|
-
|
|
250
|
-
// Test helpers
|
|
251
|
-
__simulateConnection: (socketOptions = {}) => {
|
|
252
|
-
if (!server.listening) {
|
|
253
|
-
throw new Error('Server is not listening')
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const socket = createMockSocket({
|
|
257
|
-
localPort: server._port,
|
|
258
|
-
localAddress: server._address,
|
|
259
|
-
...socketOptions
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
server.connections++
|
|
263
|
-
|
|
264
|
-
setTimeout(() => {
|
|
265
|
-
server.emit('connection', socket)
|
|
266
|
-
}, 0)
|
|
267
|
-
|
|
268
|
-
return socket
|
|
269
|
-
},
|
|
270
|
-
|
|
271
|
-
__simulateError: error => {
|
|
272
|
-
server.emit('error', error)
|
|
273
|
-
}
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
activeServers.set(serverId, server)
|
|
277
|
-
return server
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const net = {
|
|
281
|
-
// Server creation
|
|
282
|
-
createServer: jest.fn((options, connectionListener) => {
|
|
283
|
-
if (typeof options === 'function') {
|
|
284
|
-
connectionListener = options
|
|
285
|
-
options = {}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const server = createMockServer(options)
|
|
289
|
-
|
|
290
|
-
if (connectionListener) {
|
|
291
|
-
server.on('connection', connectionListener)
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return server
|
|
295
|
-
}),
|
|
296
|
-
|
|
297
|
-
// Socket creation
|
|
298
|
-
createConnection: jest.fn((options, connectListener) => {
|
|
299
|
-
const socket = createMockSocket()
|
|
300
|
-
|
|
301
|
-
if (typeof options === 'number') {
|
|
302
|
-
options = {port: options}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
socket.connecting = true
|
|
306
|
-
socket.readyState = 'opening'
|
|
307
|
-
|
|
308
|
-
if (connectListener) {
|
|
309
|
-
socket.once('connect', connectListener)
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Simulate connection
|
|
313
|
-
setTimeout(() => {
|
|
314
|
-
socket.connecting = false
|
|
315
|
-
socket.readyState = 'open'
|
|
316
|
-
socket.emit('connect')
|
|
317
|
-
}, 0)
|
|
318
|
-
|
|
319
|
-
return socket
|
|
320
|
-
}),
|
|
321
|
-
|
|
322
|
-
connect: jest.fn((...args) => net.createConnection(...args)),
|
|
323
|
-
|
|
324
|
-
// Utility functions
|
|
325
|
-
isIP: jest.fn(input => {
|
|
326
|
-
if (typeof input !== 'string') return 0
|
|
327
|
-
|
|
328
|
-
// Simple IPv4 check
|
|
329
|
-
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/
|
|
330
|
-
if (ipv4Regex.test(input)) {
|
|
331
|
-
const parts = input.split('.')
|
|
332
|
-
if (parts.every(part => parseInt(part) >= 0 && parseInt(part) <= 255)) {
|
|
333
|
-
return 4
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Simple IPv6 check
|
|
338
|
-
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/
|
|
339
|
-
if (ipv6Regex.test(input)) {
|
|
340
|
-
return 6
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return 0
|
|
344
|
-
}),
|
|
345
|
-
|
|
346
|
-
isIPv4: jest.fn(input => net.isIP(input) === 4),
|
|
347
|
-
isIPv6: jest.fn(input => net.isIP(input) === 6),
|
|
348
|
-
|
|
349
|
-
// Socket class
|
|
350
|
-
Socket: jest.fn(function (options = {}) {
|
|
351
|
-
return createMockSocket(options)
|
|
352
|
-
}),
|
|
353
|
-
|
|
354
|
-
// Server class
|
|
355
|
-
Server: jest.fn(function (options = {}, connectionListener) {
|
|
356
|
-
return createMockServer(options, connectionListener)
|
|
357
|
-
}),
|
|
358
|
-
|
|
359
|
-
// Test helpers
|
|
360
|
-
__getActiveServers: () => new Map(activeServers),
|
|
361
|
-
__getActiveConnections: () => new Map(activeConnections),
|
|
362
|
-
__clearAll: () => {
|
|
363
|
-
activeServers.clear()
|
|
364
|
-
activeConnections.clear()
|
|
365
|
-
nextConnectionId = 1
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
module.exports = net
|