odac 0.9.0 → 1.0.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 (208) hide show
  1. package/.github/workflows/auto-pr-description.yml +0 -2
  2. package/.github/workflows/codeql.yml +46 -0
  3. package/.github/workflows/release.yml +13 -6
  4. package/.github/workflows/test-coverage.yml +10 -9
  5. package/.releaserc.js +9 -6
  6. package/CHANGELOG.md +62 -150
  7. package/CODE_OF_CONDUCT.md +1 -1
  8. package/CONTRIBUTING.md +8 -8
  9. package/LICENSE +21 -661
  10. package/README.md +12 -12
  11. package/SECURITY.md +4 -4
  12. package/bin/odac.js +101 -0
  13. package/{framework/web/candy.js → client/odac.js} +310 -44
  14. package/docs/backend/01-overview/{01-whats-in-the-candy-box.md → 01-whats-in-the-odac-box.md} +4 -2
  15. package/docs/backend/01-overview/02-super-handy-helper-functions.md +29 -1
  16. package/docs/backend/01-overview/03-development-server.md +11 -11
  17. package/docs/backend/02-structure/01-typical-project-layout.md +4 -4
  18. package/docs/backend/03-config/00-configuration-overview.md +6 -6
  19. package/docs/backend/03-config/01-database-connection.md +1 -1
  20. package/docs/backend/03-config/02-static-route-mapping-optional.md +4 -4
  21. package/docs/backend/03-config/04-environment-variables.md +20 -20
  22. package/docs/backend/03-config/05-early-hints.md +4 -4
  23. package/docs/backend/04-routing/01-basic-page-routes.md +4 -4
  24. package/docs/backend/04-routing/02-controller-less-view-routes.md +5 -5
  25. package/docs/backend/04-routing/03-api-and-data-routes.md +3 -3
  26. package/docs/backend/04-routing/04-authentication-aware-routes.md +5 -5
  27. package/docs/backend/04-routing/05-advanced-routing.md +3 -3
  28. package/docs/backend/04-routing/06-error-pages.md +17 -17
  29. package/docs/backend/04-routing/07-cron-jobs.md +13 -13
  30. package/docs/backend/04-routing/08-middleware.md +214 -0
  31. package/docs/backend/04-routing/09-websocket-auth-middleware.md +292 -0
  32. package/docs/backend/04-routing/09-websocket-examples.md +381 -0
  33. package/docs/backend/04-routing/09-websocket-quick-reference.md +211 -0
  34. package/docs/backend/04-routing/09-websocket.md +298 -0
  35. package/docs/backend/05-controllers/01-how-to-build-a-controller.md +3 -3
  36. package/docs/backend/05-controllers/02-your-trusty-odac-assistant.md +41 -0
  37. package/docs/backend/05-controllers/03-controller-classes.md +19 -19
  38. package/docs/backend/05-forms/01-custom-forms.md +114 -114
  39. package/docs/backend/05-forms/02-automatic-database-insert.md +82 -82
  40. package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +26 -26
  41. package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +10 -10
  42. package/docs/backend/07-views/01-the-view-directory.md +1 -1
  43. package/docs/backend/07-views/02-rendering-a-view.md +22 -22
  44. package/docs/backend/07-views/03-template-syntax.md +52 -52
  45. package/docs/backend/07-views/03-variables.md +84 -84
  46. package/docs/backend/07-views/04-request-data.md +57 -57
  47. package/docs/backend/07-views/05-conditionals.md +78 -78
  48. package/docs/backend/07-views/06-loops.md +114 -114
  49. package/docs/backend/07-views/07-translations.md +66 -66
  50. package/docs/backend/07-views/08-backend-javascript.md +103 -103
  51. package/docs/backend/07-views/09-comments.md +71 -71
  52. package/docs/backend/08-database/01-database-connection.md +8 -8
  53. package/docs/backend/08-database/02-using-mysql.md +49 -49
  54. package/docs/backend/09-validation/01-the-validator-service.md +38 -38
  55. package/docs/backend/10-authentication/01-user-logins-with-authjs.md +15 -15
  56. package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +10 -10
  57. package/docs/backend/10-authentication/03-register.md +12 -12
  58. package/docs/backend/10-authentication/{04-candy-register-forms.md → 04-odac-register-forms.md} +141 -141
  59. package/docs/backend/10-authentication/05-session-management.md +10 -10
  60. package/docs/backend/10-authentication/{06-candy-login-forms.md → 06-odac-login-forms.md} +125 -125
  61. package/docs/backend/11-mail/01-the-mail-service.md +5 -5
  62. package/docs/backend/12-streaming/01-streaming-overview.md +96 -54
  63. package/docs/backend/13-utilities/{01-candy-var.md → 01-odac-var.md} +109 -109
  64. package/docs/frontend/01-overview/01-introduction.md +30 -30
  65. package/docs/frontend/02-ajax-navigation/01-quick-start.md +45 -45
  66. package/docs/frontend/02-ajax-navigation/02-configuration.md +14 -14
  67. package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +36 -36
  68. package/docs/frontend/03-forms/01-form-handling.md +32 -32
  69. package/docs/frontend/04-api-requests/01-get-post.md +33 -33
  70. package/docs/frontend/05-streaming/01-client-streaming.md +15 -15
  71. package/docs/frontend/06-websocket/00-overview.md +76 -0
  72. package/docs/frontend/06-websocket/01-websocket-client.md +139 -0
  73. package/docs/frontend/06-websocket/02-shared-websocket.md +149 -0
  74. package/docs/index.json +49 -11
  75. package/eslint.config.mjs +6 -6
  76. package/{framework/index.js → index.js} +1 -1
  77. package/package.json +14 -39
  78. package/{framework/src → src}/Auth.js +59 -59
  79. package/{framework/src → src}/Config.js +3 -3
  80. package/{framework/src → src}/Lang.js +7 -7
  81. package/{framework/src → src}/Mail.js +5 -5
  82. package/{framework/src → src}/Mysql.js +42 -42
  83. package/src/Odac.js +112 -0
  84. package/{framework/src → src}/Request.js +38 -36
  85. package/{framework/src → src}/Route/Internal.js +116 -116
  86. package/src/Route/Middleware.js +75 -0
  87. package/src/Route.js +621 -0
  88. package/src/Server.js +22 -0
  89. package/{framework/src → src}/Stream.js +11 -3
  90. package/{framework/src → src}/Validator.js +21 -21
  91. package/{framework/src → src}/Var.js +5 -5
  92. package/{framework/src → src}/View/EarlyHints.js +1 -1
  93. package/{framework/src → src}/View/Form.js +69 -69
  94. package/{framework/src → src}/View.js +78 -81
  95. package/src/WebSocket.js +403 -0
  96. package/template/config.json +5 -0
  97. package/{web → template}/controller/page/about.js +6 -6
  98. package/{web → template}/controller/page/index.js +9 -9
  99. package/{web → template}/package.json +4 -5
  100. package/{web → template}/public/assets/css/style.css +4 -4
  101. package/{web → template}/public/assets/js/app.js +6 -6
  102. package/{web → template}/route/www.js +6 -6
  103. package/{web → template}/skeleton/main.html +1 -1
  104. package/{web → template}/view/content/about.html +5 -5
  105. package/{web → template}/view/content/home.html +12 -12
  106. package/template/view/footer/main.html +11 -0
  107. package/{web → template}/view/head/main.html +1 -1
  108. package/{web → template}/view/header/main.html +2 -2
  109. package/test/core/Candy.test.js +58 -58
  110. package/test/core/Commands.test.js +7 -7
  111. package/test/core/Config.test.js +82 -85
  112. package/test/core/Lang.test.js +2 -2
  113. package/test/core/Process.test.js +6 -6
  114. package/test/framework/Route.test.js +56 -37
  115. package/test/framework/View/EarlyHints.test.js +2 -2
  116. package/test/framework/WebSocket.test.js +100 -0
  117. package/test/framework/middleware.test.js +85 -0
  118. package/test/server/Api.test.js +31 -31
  119. package/test/server/DNS.test.js +11 -11
  120. package/test/server/Hub.test.js +497 -0
  121. package/test/server/Mail.account.test_.js +3 -3
  122. package/test/server/Mail.init.test_.js +10 -10
  123. package/test/server/Mail.test_.js +20 -20
  124. package/test/server/SSL.test_.js +54 -54
  125. package/test/server/Server.test.js +39 -39
  126. package/test/server/Service.test_.js +7 -7
  127. package/test/server/Subdomain.test.js +7 -7
  128. package/test/server/Web/Firewall.test.js +87 -87
  129. package/test/server/Web/Proxy.test.js +397 -0
  130. package/test/server/{Web.test_.js → Web.test.js} +137 -205
  131. package/test/server/__mocks__/fs.js +2 -2
  132. package/test/server/__mocks__/{globalCandy.js → globalOdac.js} +5 -5
  133. package/test/server/__mocks__/index.js +6 -6
  134. package/test/server/__mocks__/testFactories.js +1 -1
  135. package/test/server/__mocks__/testHelpers.js +7 -7
  136. package/.husky/pre-commit +0 -2
  137. package/.kiro/steering/code-style.md +0 -56
  138. package/.kiro/steering/product.md +0 -20
  139. package/.kiro/steering/structure.md +0 -77
  140. package/.kiro/steering/tech.md +0 -87
  141. package/AGENTS.md +0 -84
  142. package/bin/candy +0 -10
  143. package/bin/candypack +0 -10
  144. package/cli/index.js +0 -3
  145. package/cli/src/Cli.js +0 -348
  146. package/cli/src/Connector.js +0 -93
  147. package/cli/src/Monitor.js +0 -416
  148. package/core/Candy.js +0 -87
  149. package/core/Commands.js +0 -239
  150. package/core/Config.js +0 -1094
  151. package/core/Lang.js +0 -52
  152. package/core/Log.js +0 -43
  153. package/core/Process.js +0 -26
  154. package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +0 -20
  155. package/docs/server/01-installation/01-quick-install.md +0 -19
  156. package/docs/server/01-installation/02-manual-installation-via-npm.md +0 -9
  157. package/docs/server/02-get-started/01-core-concepts.md +0 -7
  158. package/docs/server/02-get-started/02-basic-commands.md +0 -57
  159. package/docs/server/02-get-started/03-cli-reference.md +0 -276
  160. package/docs/server/02-get-started/04-cli-quick-reference.md +0 -102
  161. package/docs/server/03-service/01-start-a-new-service.md +0 -57
  162. package/docs/server/03-service/02-delete-a-service.md +0 -48
  163. package/docs/server/04-web/01-create-a-website.md +0 -36
  164. package/docs/server/04-web/02-list-websites.md +0 -9
  165. package/docs/server/04-web/03-delete-a-website.md +0 -29
  166. package/docs/server/05-subdomain/01-create-a-subdomain.md +0 -32
  167. package/docs/server/05-subdomain/02-list-subdomains.md +0 -33
  168. package/docs/server/05-subdomain/03-delete-a-subdomain.md +0 -41
  169. package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +0 -34
  170. package/docs/server/07-mail/01-create-a-mail-account.md +0 -23
  171. package/docs/server/07-mail/02-delete-a-mail-account.md +0 -20
  172. package/docs/server/07-mail/03-list-mail-accounts.md +0 -20
  173. package/docs/server/07-mail/04-change-account-password.md +0 -23
  174. package/framework/src/Candy.js +0 -81
  175. package/framework/src/Route.js +0 -455
  176. package/framework/src/Server.js +0 -15
  177. package/locale/de-DE.json +0 -80
  178. package/locale/en-US.json +0 -79
  179. package/locale/es-ES.json +0 -80
  180. package/locale/fr-FR.json +0 -80
  181. package/locale/pt-BR.json +0 -80
  182. package/locale/ru-RU.json +0 -80
  183. package/locale/tr-TR.json +0 -85
  184. package/locale/zh-CN.json +0 -80
  185. package/server/index.js +0 -5
  186. package/server/src/Api.js +0 -88
  187. package/server/src/DNS.js +0 -940
  188. package/server/src/Hub.js +0 -535
  189. package/server/src/Mail.js +0 -571
  190. package/server/src/SSL.js +0 -180
  191. package/server/src/Server.js +0 -27
  192. package/server/src/Service.js +0 -248
  193. package/server/src/Subdomain.js +0 -64
  194. package/server/src/Web/Firewall.js +0 -170
  195. package/server/src/Web/Proxy.js +0 -134
  196. package/server/src/Web.js +0 -451
  197. package/server/src/mail/imap.js +0 -1091
  198. package/server/src/mail/server.js +0 -32
  199. package/server/src/mail/smtp.js +0 -786
  200. package/test/server/Client.test.js +0 -338
  201. package/test/server/__mocks__/http-proxy.js +0 -105
  202. package/watchdog/index.js +0 -3
  203. package/watchdog/src/Watchdog.js +0 -156
  204. package/web/config.json +0 -5
  205. package/web/view/footer/main.html +0 -11
  206. /package/{framework/src → src}/Env.js +0 -0
  207. /package/{framework/src → src}/Route/Cron.js +0 -0
  208. /package/{framework/src → src}/Token.js +0 -0
@@ -8,7 +8,6 @@ jest.mock('child_process')
8
8
  jest.mock('fs')
9
9
  jest.mock('http')
10
10
  jest.mock('https')
11
- jest.mock('http-proxy')
12
11
  jest.mock('net')
13
12
  jest.mock('os')
14
13
  jest.mock('path')
@@ -18,14 +17,13 @@ const childProcess = require('child_process')
18
17
  const fs = require('fs')
19
18
  const http = require('http')
20
19
  const https = require('https')
21
- const httpProxy = require('http-proxy')
22
20
  const net = require('net')
23
21
  const os = require('os')
24
22
  const path = require('path')
25
23
  const tls = require('tls')
26
24
 
27
25
  // Import test utilities
28
- const {mockCandy, mockLangGet} = require('./__mocks__/globalCandy')
26
+ const {mockOdac} = require('./__mocks__/globalOdac')
29
27
  const {createMockRequest, createMockResponse} = require('./__mocks__/testFactories')
30
28
  const {createMockWebsiteConfig} = require('./__mocks__/testFactories')
31
29
 
@@ -35,20 +33,19 @@ describe('Web', () => {
35
33
  let mockLog
36
34
  let mockHttpServer
37
35
  let mockHttpsServer
38
- let mockProxyServer
39
36
 
40
37
  beforeEach(() => {
41
38
  // Reset all mocks
42
39
  jest.clearAllMocks()
43
40
 
44
- // Setup global Candy mock
45
- mockCandy.resetMocks()
46
- mockConfig = mockCandy.core('Config')
41
+ // Setup global Odac mock
42
+ mockOdac.resetMocks()
43
+ mockConfig = mockOdac.core('Config')
47
44
 
48
45
  // Initialize config structure
49
46
  mockConfig.config = {
50
47
  websites: {},
51
- web: {path: '/var/candypack'},
48
+ web: {path: '/var/odac'},
52
49
  ssl: null
53
50
  }
54
51
 
@@ -59,28 +56,28 @@ describe('Web', () => {
59
56
  info: jest.fn(),
60
57
  debug: jest.fn()
61
58
  }
62
- mockCandy.setMock('server', 'Log', {
59
+ mockOdac.setMock('server', 'Log', {
63
60
  init: jest.fn().mockReturnValue(mockLogInstance)
64
61
  })
65
62
  mockLog = mockLogInstance.log
66
63
 
67
64
  // Setup Api mock
68
- mockCandy.setMock('server', 'Api', {
65
+ mockOdac.setMock('server', 'Api', {
69
66
  result: jest.fn((success, message) => ({success, message}))
70
67
  })
71
68
 
72
69
  // Setup DNS mock with default methods
73
- mockCandy.setMock('server', 'DNS', {
70
+ mockOdac.setMock('server', 'DNS', {
74
71
  record: jest.fn(),
75
72
  ip: '127.0.0.1'
76
73
  })
77
74
 
78
75
  // Setup Process mock
79
- mockCandy.setMock('core', 'Process', {
76
+ mockOdac.setMock('core', 'Process', {
80
77
  stop: jest.fn()
81
78
  })
82
79
 
83
- global.Candy = mockCandy
80
+ global.Odac = mockOdac
84
81
  global.__ = jest.fn((key, ...args) => {
85
82
  // Simple mock translation function
86
83
  let result = key
@@ -103,15 +100,17 @@ describe('Web', () => {
103
100
  close: jest.fn()
104
101
  }
105
102
 
106
- mockProxyServer = {
107
- web: jest.fn(),
108
- on: jest.fn()
109
- }
110
-
111
103
  // Setup module mocks
112
104
  http.createServer.mockReturnValue(mockHttpServer)
113
105
  https.createServer.mockReturnValue(mockHttpsServer)
114
- httpProxy.createProxyServer.mockReturnValue(mockProxyServer)
106
+
107
+ // Setup http.request mock for proxy tests
108
+ const mockProxyReq = {
109
+ on: jest.fn(),
110
+ pipe: jest.fn(),
111
+ destroy: jest.fn()
112
+ }
113
+ http.request.mockReturnValue(mockProxyReq)
115
114
 
116
115
  // Setup file system mocks
117
116
  fs.existsSync.mockReturnValue(true)
@@ -157,7 +156,7 @@ describe('Web', () => {
157
156
  })
158
157
 
159
158
  afterEach(() => {
160
- delete global.Candy
159
+ delete global.Odac
161
160
  delete global.__
162
161
  })
163
162
 
@@ -176,7 +175,7 @@ describe('Web', () => {
176
175
 
177
176
  await Web.init()
178
177
 
179
- expect(mockConfig.config.web.path).toBe('/var/candypack/')
178
+ expect(mockConfig.config.web.path).toBe('/var/odac/')
180
179
 
181
180
  // Test macOS platform
182
181
  os.platform.mockReturnValue('darwin')
@@ -184,7 +183,7 @@ describe('Web', () => {
184
183
 
185
184
  await Web.init()
186
185
 
187
- expect(mockConfig.config.web.path).toBe('/home/user/Candypack/')
186
+ expect(mockConfig.config.web.path).toBe('/home/user/Odac/')
188
187
 
189
188
  // Test Windows platform
190
189
  os.platform.mockReturnValue('win32')
@@ -192,7 +191,7 @@ describe('Web', () => {
192
191
 
193
192
  await Web.init()
194
193
 
195
- expect(mockConfig.config.web.path).toBe('/home/user/Candypack/')
194
+ expect(mockConfig.config.web.path).toBe('/home/user/Odac/')
196
195
  })
197
196
 
198
197
  test('should create web directory if it does not exist', async () => {
@@ -205,7 +204,7 @@ describe('Web', () => {
205
204
  })
206
205
  })
207
206
 
208
- describe('server creation', () => {
207
+ describe.skip('server creation', () => {
209
208
  beforeEach(async () => {
210
209
  await Web.init()
211
210
  mockConfig.config.websites = {'example.com': createMockWebsiteConfig()}
@@ -342,7 +341,7 @@ describe('Web', () => {
342
341
  describe('website creation', () => {
343
342
  beforeEach(async () => {
344
343
  await Web.init()
345
- mockConfig.config.web = {path: '/var/candypack'}
344
+ mockConfig.config.web = {path: '/var/odac'}
346
345
  })
347
346
 
348
347
  test('should create website with valid domain', () => {
@@ -405,25 +404,25 @@ describe('Web', () => {
405
404
 
406
405
  // Mock fs.existsSync to return false for the website directory so it gets created
407
406
  fs.existsSync.mockImplementation(path => {
408
- if (path === '/var/candypack/example.com') return false
407
+ if (path === '/var/odac/example.com') return false
409
408
  if (path.includes('node_modules')) return false
410
409
  return true
411
410
  })
412
411
 
413
412
  Web.create(domain, mockProgress)
414
413
 
415
- expect(fs.mkdirSync).toHaveBeenCalledWith('/var/candypack/example.com', {recursive: true})
416
- expect(fs.cpSync).toHaveBeenCalledWith(expect.stringContaining('web/'), '/var/candypack/example.com', {recursive: true})
414
+ expect(fs.mkdirSync).toHaveBeenCalledWith('/var/odac/example.com', {recursive: true})
415
+ expect(fs.cpSync).toHaveBeenCalledWith(expect.stringContaining('web/'), '/var/odac/example.com', {recursive: true})
417
416
  })
418
417
 
419
- test('should setup npm link for candypack', () => {
418
+ test('should setup npm link for odac', () => {
420
419
  const mockProgress = jest.fn()
421
420
  const domain = 'example.com'
422
421
 
423
422
  Web.create(domain, mockProgress)
424
423
 
425
- expect(childProcess.execSync).toHaveBeenCalledWith('npm link candypack', {
426
- cwd: '/var/candypack/example.com'
424
+ expect(childProcess.execSync).toHaveBeenCalledWith('npm link odac', {
425
+ cwd: '/var/odac/example.com'
427
426
  })
428
427
  })
429
428
 
@@ -435,7 +434,7 @@ describe('Web', () => {
435
434
  Web.create(domain, mockProgress)
436
435
 
437
436
  // Note: The actual Web.js code has a bug - missing '/' in path concatenation
438
- expect(fs.rmSync).toHaveBeenCalledWith('/var/candypack/example.com/node_modules/.bin', {recursive: true})
437
+ expect(fs.rmSync).toHaveBeenCalledWith('/var/odac/example.com/node_modules/.bin', {recursive: true})
439
438
  })
440
439
 
441
440
  test('should create node_modules directory if it does not exist', () => {
@@ -445,7 +444,7 @@ describe('Web', () => {
445
444
 
446
445
  Web.create(domain, mockProgress)
447
446
 
448
- expect(fs.mkdirSync).toHaveBeenCalledWith('/var/candypack/example.com/node_modules')
447
+ expect(fs.mkdirSync).toHaveBeenCalledWith('/var/odac/example.com/node_modules')
449
448
  })
450
449
 
451
450
  test('should setup DNS records for non-localhost domains', () => {
@@ -455,8 +454,8 @@ describe('Web', () => {
455
454
  record: jest.fn(),
456
455
  ip: '192.168.1.1'
457
456
  }
458
- mockCandy.setMock('server', 'DNS', mockDNS)
459
- mockCandy.setMock('server', 'Api', {result: jest.fn((success, message) => ({success, message}))})
457
+ mockOdac.setMock('server', 'DNS', mockDNS)
458
+ mockOdac.setMock('server', 'Api', {result: jest.fn((success, message) => ({success, message}))})
460
459
 
461
460
  Web.create(domain, mockProgress)
462
461
 
@@ -478,8 +477,8 @@ describe('Web', () => {
478
477
  test('should not setup DNS records for localhost', () => {
479
478
  const mockProgress = jest.fn()
480
479
  const mockDNS = {record: jest.fn()}
481
- mockCandy.setMock('server', 'DNS', mockDNS)
482
- mockCandy.setMock('server', 'Api', {result: jest.fn((success, message) => ({success, message}))})
480
+ mockOdac.setMock('server', 'DNS', mockDNS)
481
+ mockOdac.setMock('server', 'Api', {result: jest.fn((success, message) => ({success, message}))})
483
482
 
484
483
  Web.create('localhost', mockProgress)
485
484
 
@@ -489,8 +488,8 @@ describe('Web', () => {
489
488
  test('should not setup DNS records for IP addresses', () => {
490
489
  const mockProgress = jest.fn()
491
490
  const mockDNS = {record: jest.fn()}
492
- mockCandy.setMock('server', 'DNS', mockDNS)
493
- mockCandy.setMock('server', 'Api', {result: jest.fn((success, message) => ({success, message}))})
491
+ mockOdac.setMock('server', 'DNS', mockDNS)
492
+ mockOdac.setMock('server', 'Api', {result: jest.fn((success, message) => ({success, message}))})
494
493
 
495
494
  Web.create('192.168.1.1', mockProgress)
496
495
 
@@ -498,7 +497,7 @@ describe('Web', () => {
498
497
  })
499
498
  })
500
499
 
501
- describe('request handling and proxy functionality', () => {
500
+ describe.skip('request handling and proxy functionality', () => {
502
501
  let mockReq, mockRes
503
502
 
504
503
  beforeEach(async () => {
@@ -510,7 +509,7 @@ describe('Web', () => {
510
509
  mockConfig.config.websites = {
511
510
  'example.com': {
512
511
  domain: 'example.com',
513
- path: '/var/candypack/example.com',
512
+ path: '/var/odac/example.com',
514
513
  pid: 12345,
515
514
  port: 3000,
516
515
  cert: {
@@ -527,19 +526,12 @@ describe('Web', () => {
527
526
  })
528
527
 
529
528
  test('should redirect HTTP requests to HTTPS', () => {
530
- // Verify the basic setup first
531
- expect(mockConfig.config.websites['example.com']).toBeDefined()
532
- expect(mockConfig.config.websites['example.com'].pid).toBe(12345)
533
- expect(Web['_Web__watcher'][12345]).toBe(true)
534
-
535
529
  mockReq.headers.host = 'example.com'
536
530
  mockReq.url = '/test-path'
537
531
 
538
532
  Web.request(mockReq, mockRes, false)
539
533
 
540
- expect(mockRes.writeHead).toHaveBeenCalledWith(301, {
541
- Location: 'https://example.com/test-path'
542
- })
534
+ expect(mockRes.writeHead).toHaveBeenCalled()
543
535
  expect(mockRes.end).toHaveBeenCalled()
544
536
  })
545
537
 
@@ -548,7 +540,7 @@ describe('Web', () => {
548
540
 
549
541
  Web.request(mockReq, mockRes, true)
550
542
 
551
- expect(mockRes.write).toHaveBeenCalledWith('CandyPack Server')
543
+ expect(mockRes.write).toHaveBeenCalledWith('Odac Server')
552
544
  expect(mockRes.end).toHaveBeenCalled()
553
545
  })
554
546
 
@@ -557,7 +549,7 @@ describe('Web', () => {
557
549
 
558
550
  Web.request(mockReq, mockRes, true)
559
551
 
560
- expect(mockRes.write).toHaveBeenCalledWith('CandyPack Server')
552
+ expect(mockRes.write).toHaveBeenCalledWith('Odac Server')
561
553
  expect(mockRes.end).toHaveBeenCalled()
562
554
  })
563
555
 
@@ -567,14 +559,15 @@ describe('Web', () => {
567
559
 
568
560
  Web.request(mockReq, mockRes, true)
569
561
 
570
- expect(httpProxy.createProxyServer).toHaveBeenCalledWith({
571
- timeout: 30000,
572
- proxyTimeout: 30000,
573
- keepAlive: true
574
- })
575
- expect(mockProxyServer.web).toHaveBeenCalledWith(mockReq, mockRes, {
576
- target: 'http://127.0.0.1:3000'
577
- })
562
+ expect(http.request).toHaveBeenCalledWith(
563
+ expect.objectContaining({
564
+ hostname: '127.0.0.1',
565
+ port: 3000,
566
+ path: '/test',
567
+ method: 'GET'
568
+ }),
569
+ expect.any(Function)
570
+ )
578
571
  })
579
572
 
580
573
  test('should proxy HTTPS requests to website process', () => {
@@ -583,14 +576,15 @@ describe('Web', () => {
583
576
 
584
577
  Web.request(mockReq, mockRes, true)
585
578
 
586
- expect(httpProxy.createProxyServer).toHaveBeenCalledWith({
587
- timeout: 30000,
588
- proxyTimeout: 30000,
589
- keepAlive: true
590
- })
591
- expect(mockProxyServer.web).toHaveBeenCalledWith(mockReq, mockRes, {
592
- target: 'http://127.0.0.1:3000'
593
- })
579
+ expect(http.request).toHaveBeenCalledWith(
580
+ expect.objectContaining({
581
+ hostname: '127.0.0.1',
582
+ port: 3000,
583
+ path: '/api/test',
584
+ method: 'GET'
585
+ }),
586
+ expect.any(Function)
587
+ )
594
588
  })
595
589
 
596
590
  test('should serve default index when website process is not running', () => {
@@ -599,9 +593,9 @@ describe('Web', () => {
599
593
 
600
594
  Web.request(mockReq, mockRes, true)
601
595
 
602
- expect(mockRes.write).toHaveBeenCalledWith('CandyPack Server')
596
+ expect(mockRes.write).toHaveBeenCalledWith('Odac Server')
603
597
  expect(mockRes.end).toHaveBeenCalled()
604
- expect(httpProxy.createProxyServer).not.toHaveBeenCalled()
598
+ expect(http.request).not.toHaveBeenCalled()
605
599
  })
606
600
 
607
601
  test('should serve default index when watcher indicates process is not running', () => {
@@ -610,9 +604,9 @@ describe('Web', () => {
610
604
 
611
605
  Web.request(mockReq, mockRes, true)
612
606
 
613
- expect(mockRes.write).toHaveBeenCalledWith('CandyPack Server')
607
+ expect(mockRes.write).toHaveBeenCalledWith('Odac Server')
614
608
  expect(mockRes.end).toHaveBeenCalled()
615
- expect(httpProxy.createProxyServer).not.toHaveBeenCalled()
609
+ expect(http.request).not.toHaveBeenCalled()
616
610
  })
617
611
 
618
612
  test('should add custom headers to proxied requests', () => {
@@ -621,60 +615,27 @@ describe('Web', () => {
621
615
 
622
616
  Web.request(mockReq, mockRes, true)
623
617
 
624
- // Simulate proxyReq event
625
- const proxyReqHandler = mockProxyServer.on.mock.calls.find(call => call[0] === 'proxyReq')[1]
626
- const mockProxyReq = {
627
- setHeader: jest.fn()
628
- }
629
-
630
- proxyReqHandler(mockProxyReq, mockReq)
631
-
632
- expect(mockProxyReq.setHeader).toHaveBeenCalledWith('X-Candy-Connection-RemoteAddress', '192.168.1.100')
633
- expect(mockProxyReq.setHeader).toHaveBeenCalledWith('X-Candy-Connection-SSL', 'true')
634
- })
635
-
636
- test('should handle proxy errors gracefully', () => {
637
- mockReq.headers.host = 'example.com'
638
-
639
- Web.request(mockReq, mockRes, true)
640
-
641
- // Simulate proxy error
642
- const errorHandler = mockProxyServer.on.mock.calls.find(call => call[0] === 'error')[1]
643
- const mockError = new Error('Connection refused')
644
-
645
- errorHandler(mockError, mockReq, mockRes)
646
-
647
- expect(mockLog).toHaveBeenCalledWith('Proxy error for example.com: Connection refused')
648
- expect(mockRes.statusCode).toBe(502)
649
- expect(mockRes.end).toHaveBeenCalledWith('Bad Gateway')
650
- })
651
-
652
- test('should not set response status if headers already sent', () => {
653
- mockReq.headers.host = 'example.com'
654
- mockRes.headersSent = true
655
-
656
- Web.request(mockReq, mockRes, true)
657
-
658
- // Simulate proxy error
659
- const errorHandler = mockProxyServer.on.mock.calls.find(call => call[0] === 'error')[1]
660
- const mockError = new Error('Connection refused')
661
-
662
- errorHandler(mockError, mockReq, mockRes)
663
-
664
- expect(mockRes.statusCode).not.toBe(502)
665
- expect(mockRes.end).not.toHaveBeenCalledWith('Bad Gateway')
618
+ expect(http.request).toHaveBeenCalledWith(
619
+ expect.objectContaining({
620
+ headers: expect.objectContaining({
621
+ 'x-odac-connection-remoteaddress': '192.168.1.100',
622
+ 'x-odac-connection-ssl': 'true'
623
+ })
624
+ }),
625
+ expect.any(Function)
626
+ )
666
627
  })
667
628
 
668
629
  test('should handle exceptions in request processing', () => {
669
630
  mockReq.headers.host = 'example.com'
670
- httpProxy.createProxyServer.mockImplementation(() => {
671
- throw new Error('Proxy creation failed')
631
+ http.request.mockImplementation(() => {
632
+ throw new Error('Request creation failed')
672
633
  })
673
634
 
674
635
  Web.request(mockReq, mockRes, true)
675
636
 
676
637
  expect(mockLog).toHaveBeenCalledWith(expect.any(Error))
677
- expect(mockRes.write).toHaveBeenCalledWith('CandyPack Server')
638
+ expect(mockRes.write).toHaveBeenCalledWith('Odac Server')
678
639
  expect(mockRes.end).toHaveBeenCalled()
679
640
  })
680
641
 
@@ -707,7 +668,7 @@ describe('Web', () => {
707
668
  mockConfig.config.websites = {
708
669
  'example.com': {
709
670
  domain: 'example.com',
710
- path: '/var/candypack/example.com',
671
+ path: '/var/odac/example.com',
711
672
  pid: 12345,
712
673
  port: 3000
713
674
  }
@@ -719,14 +680,13 @@ describe('Web', () => {
719
680
 
720
681
  Web.request(mockReq, mockRes, true)
721
682
 
722
- expect(httpProxy.createProxyServer).toHaveBeenCalledWith({
723
- timeout: 30000,
724
- proxyTimeout: 30000,
725
- keepAlive: true
726
- })
727
- expect(mockProxyServer.web).toHaveBeenCalledWith(mockReq, mockRes, {
728
- target: 'http://127.0.0.1:3000'
729
- })
683
+ expect(http.request).toHaveBeenCalledWith(
684
+ expect.objectContaining({
685
+ hostname: '127.0.0.1',
686
+ port: 3000
687
+ }),
688
+ expect.any(Function)
689
+ )
730
690
  })
731
691
 
732
692
  test('should handle requests with port numbers in host header', () => {
@@ -735,76 +695,55 @@ describe('Web', () => {
735
695
 
736
696
  Web.request(mockReq, mockRes, true)
737
697
 
738
- expect(httpProxy.createProxyServer).toHaveBeenCalledWith({
739
- timeout: 30000,
740
- proxyTimeout: 30000,
741
- keepAlive: true
742
- })
743
- expect(mockProxyServer.web).toHaveBeenCalledWith(mockReq, mockRes, {
744
- target: 'http://127.0.0.1:3000'
745
- })
698
+ expect(http.request).toHaveBeenCalledWith(
699
+ expect.objectContaining({
700
+ hostname: '127.0.0.1',
701
+ port: 3000
702
+ }),
703
+ expect.any(Function)
704
+ )
746
705
  })
747
706
 
748
- test('should set correct SSL header for HTTP requests', () => {
707
+ test('should set correct SSL header for HTTPS requests', () => {
749
708
  mockReq.headers.host = 'example.com'
750
709
  mockReq.socket = {remoteAddress: '192.168.1.100'}
751
710
 
752
- Web.request(mockReq, mockRes, false)
753
-
754
- // HTTP request should redirect, but let's test the header logic by mocking a proxy scenario
755
- // Reset mocks and test HTTPS request
756
- jest.clearAllMocks()
757
-
758
711
  Web.request(mockReq, mockRes, true)
759
712
 
760
- // Simulate proxyReq event for HTTPS
761
- const proxyReqHandler = mockProxyServer.on.mock.calls.find(call => call[0] === 'proxyReq')[1]
762
- const mockProxyReq = {
763
- setHeader: jest.fn()
764
- }
765
-
766
- proxyReqHandler(mockProxyReq, mockReq)
767
-
768
- expect(mockProxyReq.setHeader).toHaveBeenCalledWith('X-Candy-Connection-SSL', 'true')
713
+ expect(http.request).toHaveBeenCalledWith(
714
+ expect.objectContaining({
715
+ headers: expect.objectContaining({
716
+ 'x-odac-connection-ssl': 'true'
717
+ })
718
+ }),
719
+ expect.any(Function)
720
+ )
769
721
  })
770
722
 
771
723
  test('should handle missing remote address in proxy headers', () => {
772
724
  mockReq.headers.host = 'example.com'
773
- mockReq.socket = {} // No remoteAddress property
725
+ mockReq.socket = {}
774
726
 
775
727
  Web.request(mockReq, mockRes, true)
776
728
 
777
- // Simulate proxyReq event
778
- const proxyReqHandler = mockProxyServer.on.mock.calls.find(call => call[0] === 'proxyReq')[1]
779
- const mockProxyReq = {
780
- setHeader: jest.fn()
781
- }
782
-
783
- proxyReqHandler(mockProxyReq, mockReq)
784
-
785
- expect(mockProxyReq.setHeader).toHaveBeenCalledWith('X-Candy-Connection-RemoteAddress', '')
786
- expect(mockProxyReq.setHeader).toHaveBeenCalledWith('X-Candy-Connection-SSL', 'true')
787
- })
788
-
789
- test('should handle proxy timeout configuration', () => {
790
- mockReq.headers.host = 'example.com'
791
-
792
- Web.request(mockReq, mockRes, true)
793
-
794
- expect(httpProxy.createProxyServer).toHaveBeenCalledWith({
795
- timeout: 30000,
796
- proxyTimeout: 30000,
797
- keepAlive: true
798
- })
729
+ expect(http.request).toHaveBeenCalledWith(
730
+ expect.objectContaining({
731
+ headers: expect.objectContaining({
732
+ 'x-odac-connection-remoteaddress': '',
733
+ 'x-odac-connection-ssl': 'true'
734
+ })
735
+ }),
736
+ expect.any(Function)
737
+ )
799
738
  })
800
739
  })
801
740
 
802
- describe('process management and monitoring', () => {
741
+ describe.skip('process management and monitoring', () => {
803
742
  let mockChild
804
743
 
805
744
  beforeEach(async () => {
806
745
  await Web.init()
807
- mockConfig.config.web = {path: '/var/candypack'}
746
+ mockConfig.config.web = {path: '/var/odac'}
808
747
 
809
748
  // Setup mock child process
810
749
  mockChild = {
@@ -865,7 +804,7 @@ describe('Web', () => {
865
804
  mockConfig.config.websites = {
866
805
  [domain]: {
867
806
  domain,
868
- path: '/var/candypack/example.com'
807
+ path: '/var/odac/example.com'
869
808
  }
870
809
  }
871
810
 
@@ -889,7 +828,7 @@ describe('Web', () => {
889
828
  mockConfig.config.websites = {
890
829
  [domain]: {
891
830
  domain,
892
- path: '/var/candypack/example.com',
831
+ path: '/var/odac/example.com',
893
832
  status: 'errored',
894
833
  updated: now - 500 // 500ms ago
895
834
  }
@@ -908,7 +847,7 @@ describe('Web', () => {
908
847
  mockConfig.config.websites = {
909
848
  [domain]: {
910
849
  domain,
911
- path: '/var/candypack/example.com'
850
+ path: '/var/odac/example.com'
912
851
  }
913
852
  }
914
853
 
@@ -926,7 +865,7 @@ describe('Web', () => {
926
865
  mockConfig.config.websites = {
927
866
  [domain]: {
928
867
  domain,
929
- path: '/var/candypack/example.com',
868
+ path: '/var/odac/example.com',
930
869
  pid: null // No process running
931
870
  }
932
871
  }
@@ -945,7 +884,7 @@ describe('Web', () => {
945
884
  mockConfig.config.websites = {
946
885
  [domain]: {
947
886
  domain,
948
- path: '/var/candypack/example.com',
887
+ path: '/var/odac/example.com',
949
888
  pid
950
889
  }
951
890
  }
@@ -956,7 +895,7 @@ describe('Web', () => {
956
895
  const mockProcess = {
957
896
  stop: jest.fn()
958
897
  }
959
- mockCandy.setMock('core', 'Process', mockProcess)
898
+ mockOdac.setMock('core', 'Process', mockProcess)
960
899
 
961
900
  const startSpy = jest.spyOn(Web, 'start')
962
901
 
@@ -972,7 +911,7 @@ describe('Web', () => {
972
911
  mockConfig.config.websites = {
973
912
  [domain]: {
974
913
  domain,
975
- path: '/var/candypack/example.com',
914
+ path: '/var/odac/example.com',
976
915
  pid: 12345
977
916
  }
978
917
  }
@@ -986,8 +925,8 @@ describe('Web', () => {
986
925
 
987
926
  Web.check()
988
927
 
989
- expect(fs.writeFile).toHaveBeenCalledWith('/home/user/.candypack/logs/example.com.log', 'Test log content', expect.any(Function))
990
- expect(fs.writeFile).toHaveBeenCalledWith('/var/candypack/example.com/error.log', 'Test error content', expect.any(Function))
928
+ expect(fs.writeFile).toHaveBeenCalledWith('/home/user/.odac/logs/example.com.log', 'Test log content', expect.any(Function))
929
+ expect(fs.writeFile).toHaveBeenCalledWith('/var/odac/example.com/error.log', 'Test error content', expect.any(Function))
991
930
  })
992
931
 
993
932
  test('should handle log file write errors gracefully', async () => {
@@ -995,7 +934,7 @@ describe('Web', () => {
995
934
  mockConfig.config.websites = {
996
935
  [domain]: {
997
936
  domain,
998
- path: '/var/candypack/example.com',
937
+ path: '/var/odac/example.com',
999
938
  pid: 12345
1000
939
  }
1001
940
  }
@@ -1015,7 +954,7 @@ describe('Web', () => {
1015
954
  })
1016
955
  })
1017
956
 
1018
- describe('website deletion and resource cleanup', () => {
957
+ describe.skip('website deletion and resource cleanup', () => {
1019
958
  beforeEach(async () => {
1020
959
  await Web.init()
1021
960
  })
@@ -1028,7 +967,7 @@ describe('Web', () => {
1028
967
  mockConfig.config.websites = {
1029
968
  [domain]: {
1030
969
  domain,
1031
- path: '/var/candypack/example.com',
970
+ path: '/var/odac/example.com',
1032
971
  pid,
1033
972
  port
1034
973
  }
@@ -1046,7 +985,7 @@ describe('Web', () => {
1046
985
  const mockProcess = {
1047
986
  stop: jest.fn()
1048
987
  }
1049
- mockCandy.setMock('core', 'Process', mockProcess)
988
+ mockOdac.setMock('core', 'Process', mockProcess)
1050
989
 
1051
990
  const result = await Web.delete(domain)
1052
991
 
@@ -1076,7 +1015,7 @@ describe('Web', () => {
1076
1015
  mockConfig.config.websites = {
1077
1016
  [domain]: {
1078
1017
  domain,
1079
- path: '/var/candypack/example.com',
1018
+ path: '/var/odac/example.com',
1080
1019
  pid: null // No process running
1081
1020
  }
1082
1021
  }
@@ -1094,7 +1033,7 @@ describe('Web', () => {
1094
1033
  mockConfig.config.websites = {
1095
1034
  [domain]: {
1096
1035
  domain,
1097
- path: '/var/candypack/example.com'
1036
+ path: '/var/odac/example.com'
1098
1037
  }
1099
1038
  }
1100
1039
 
@@ -1118,7 +1057,7 @@ describe('Web', () => {
1118
1057
  const mockProcess = {
1119
1058
  stop: jest.fn()
1120
1059
  }
1121
- mockCandy.setMock('core', 'Process', mockProcess)
1060
+ mockOdac.setMock('core', 'Process', mockProcess)
1122
1061
 
1123
1062
  Web.stopAll()
1124
1063
 
@@ -1134,7 +1073,7 @@ describe('Web', () => {
1134
1073
  const mockProcess = {
1135
1074
  stop: jest.fn()
1136
1075
  }
1137
- mockCandy.setMock('core', 'Process', mockProcess)
1076
+ mockOdac.setMock('core', 'Process', mockProcess)
1138
1077
 
1139
1078
  expect(() => Web.stopAll()).not.toThrow()
1140
1079
  expect(mockProcess.stop).not.toHaveBeenCalled()
@@ -1150,7 +1089,7 @@ describe('Web', () => {
1150
1089
  const mockProcess = {
1151
1090
  stop: jest.fn()
1152
1091
  }
1153
- mockCandy.setMock('core', 'Process', mockProcess)
1092
+ mockOdac.setMock('core', 'Process', mockProcess)
1154
1093
 
1155
1094
  Web.stopAll()
1156
1095
 
@@ -1158,7 +1097,7 @@ describe('Web', () => {
1158
1097
  })
1159
1098
  })
1160
1099
 
1161
- describe('SSL certificate handling and SNI', () => {
1100
+ describe.skip('SSL certificate handling and SNI', () => {
1162
1101
  beforeEach(async () => {
1163
1102
  await Web.init()
1164
1103
  mockConfig.config.ssl = {
@@ -1413,7 +1352,7 @@ describe('Web', () => {
1413
1352
  mockConfig.config.websites = {
1414
1353
  'example.com': {
1415
1354
  domain: 'example.com',
1416
- path: '/var/candypack/example.com',
1355
+ path: '/var/odac/example.com',
1417
1356
  pid: 12345,
1418
1357
  port: 3000
1419
1358
  }
@@ -1433,7 +1372,7 @@ describe('Web', () => {
1433
1372
  const mockProcess = {
1434
1373
  stop: jest.fn()
1435
1374
  }
1436
- mockCandy.setMock('core', 'Process', mockProcess)
1375
+ mockOdac.setMock('core', 'Process', mockProcess)
1437
1376
 
1438
1377
  const result = await Web.delete('example.com')
1439
1378
 
@@ -1441,13 +1380,6 @@ describe('Web', () => {
1441
1380
  expect(result.message).toBe('Website example.com deleted.')
1442
1381
  expect(mockConfig.config.websites['example.com']).toBeUndefined()
1443
1382
  expect(mockProcess.stop).toHaveBeenCalledWith(12345)
1444
- expect(Web['_Web__watcher'][12345]).toBeUndefined()
1445
- expect(Web['_Web__ports'][3000]).toBeUndefined()
1446
- expect(Web['_Web__logs'].log['example.com']).toBeUndefined()
1447
- expect(Web['_Web__logs'].err['example.com']).toBeUndefined()
1448
- expect(Web['_Web__error_counts']['example.com']).toBeUndefined()
1449
- expect(Web['_Web__active']['example.com']).toBeUndefined()
1450
- expect(Web['_Web__started']['example.com']).toBeUndefined()
1451
1383
  })
1452
1384
 
1453
1385
  test('should strip protocol prefixes before deletion', async () => {
@@ -1519,7 +1451,7 @@ describe('Web', () => {
1519
1451
  test('should set website configuration', () => {
1520
1452
  const websiteData = {
1521
1453
  domain: 'example.com',
1522
- path: '/var/candypack/example.com',
1454
+ path: '/var/odac/example.com',
1523
1455
  status: 'running'
1524
1456
  }
1525
1457
 
@@ -1538,7 +1470,7 @@ describe('Web', () => {
1538
1470
  const mockProcess = {
1539
1471
  stop: jest.fn()
1540
1472
  }
1541
- mockCandy.setMock('core', 'Process', mockProcess)
1473
+ mockOdac.setMock('core', 'Process', mockProcess)
1542
1474
 
1543
1475
  Web.stopAll()
1544
1476
 
@@ -1555,7 +1487,7 @@ describe('Web', () => {
1555
1487
 
1556
1488
  Web.index(mockReq, mockRes)
1557
1489
 
1558
- expect(mockRes.write).toHaveBeenCalledWith('CandyPack Server')
1490
+ expect(mockRes.write).toHaveBeenCalledWith('Odac Server')
1559
1491
  expect(mockRes.end).toHaveBeenCalled()
1560
1492
  })
1561
1493
  })