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.
- package/.github/workflows/auto-pr-description.yml +0 -2
- package/.github/workflows/codeql.yml +46 -0
- package/.github/workflows/release.yml +13 -6
- package/.github/workflows/test-coverage.yml +10 -9
- package/.releaserc.js +9 -6
- package/CHANGELOG.md +62 -150
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTING.md +8 -8
- package/LICENSE +21 -661
- package/README.md +12 -12
- package/SECURITY.md +4 -4
- package/bin/odac.js +101 -0
- package/{framework/web/candy.js → client/odac.js} +310 -44
- package/docs/backend/01-overview/{01-whats-in-the-candy-box.md → 01-whats-in-the-odac-box.md} +4 -2
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +29 -1
- package/docs/backend/01-overview/03-development-server.md +11 -11
- package/docs/backend/02-structure/01-typical-project-layout.md +4 -4
- package/docs/backend/03-config/00-configuration-overview.md +6 -6
- package/docs/backend/03-config/01-database-connection.md +1 -1
- package/docs/backend/03-config/02-static-route-mapping-optional.md +4 -4
- package/docs/backend/03-config/04-environment-variables.md +20 -20
- package/docs/backend/03-config/05-early-hints.md +4 -4
- package/docs/backend/04-routing/01-basic-page-routes.md +4 -4
- package/docs/backend/04-routing/02-controller-less-view-routes.md +5 -5
- package/docs/backend/04-routing/03-api-and-data-routes.md +3 -3
- package/docs/backend/04-routing/04-authentication-aware-routes.md +5 -5
- package/docs/backend/04-routing/05-advanced-routing.md +3 -3
- package/docs/backend/04-routing/06-error-pages.md +17 -17
- package/docs/backend/04-routing/07-cron-jobs.md +13 -13
- package/docs/backend/04-routing/08-middleware.md +214 -0
- package/docs/backend/04-routing/09-websocket-auth-middleware.md +292 -0
- package/docs/backend/04-routing/09-websocket-examples.md +381 -0
- package/docs/backend/04-routing/09-websocket-quick-reference.md +211 -0
- package/docs/backend/04-routing/09-websocket.md +298 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +3 -3
- package/docs/backend/05-controllers/02-your-trusty-odac-assistant.md +41 -0
- package/docs/backend/05-controllers/03-controller-classes.md +19 -19
- package/docs/backend/05-forms/01-custom-forms.md +114 -114
- package/docs/backend/05-forms/02-automatic-database-insert.md +82 -82
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +26 -26
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +10 -10
- package/docs/backend/07-views/01-the-view-directory.md +1 -1
- package/docs/backend/07-views/02-rendering-a-view.md +22 -22
- package/docs/backend/07-views/03-template-syntax.md +52 -52
- package/docs/backend/07-views/03-variables.md +84 -84
- package/docs/backend/07-views/04-request-data.md +57 -57
- package/docs/backend/07-views/05-conditionals.md +78 -78
- package/docs/backend/07-views/06-loops.md +114 -114
- package/docs/backend/07-views/07-translations.md +66 -66
- package/docs/backend/07-views/08-backend-javascript.md +103 -103
- package/docs/backend/07-views/09-comments.md +71 -71
- package/docs/backend/08-database/01-database-connection.md +8 -8
- package/docs/backend/08-database/02-using-mysql.md +49 -49
- package/docs/backend/09-validation/01-the-validator-service.md +38 -38
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +15 -15
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +10 -10
- package/docs/backend/10-authentication/03-register.md +12 -12
- package/docs/backend/10-authentication/{04-candy-register-forms.md → 04-odac-register-forms.md} +141 -141
- package/docs/backend/10-authentication/05-session-management.md +10 -10
- package/docs/backend/10-authentication/{06-candy-login-forms.md → 06-odac-login-forms.md} +125 -125
- package/docs/backend/11-mail/01-the-mail-service.md +5 -5
- package/docs/backend/12-streaming/01-streaming-overview.md +96 -54
- package/docs/backend/13-utilities/{01-candy-var.md → 01-odac-var.md} +109 -109
- package/docs/frontend/01-overview/01-introduction.md +30 -30
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +45 -45
- package/docs/frontend/02-ajax-navigation/02-configuration.md +14 -14
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +36 -36
- package/docs/frontend/03-forms/01-form-handling.md +32 -32
- package/docs/frontend/04-api-requests/01-get-post.md +33 -33
- package/docs/frontend/05-streaming/01-client-streaming.md +15 -15
- package/docs/frontend/06-websocket/00-overview.md +76 -0
- package/docs/frontend/06-websocket/01-websocket-client.md +139 -0
- package/docs/frontend/06-websocket/02-shared-websocket.md +149 -0
- package/docs/index.json +49 -11
- package/eslint.config.mjs +6 -6
- package/{framework/index.js → index.js} +1 -1
- package/package.json +14 -39
- package/{framework/src → src}/Auth.js +59 -59
- package/{framework/src → src}/Config.js +3 -3
- package/{framework/src → src}/Lang.js +7 -7
- package/{framework/src → src}/Mail.js +5 -5
- package/{framework/src → src}/Mysql.js +42 -42
- package/src/Odac.js +112 -0
- package/{framework/src → src}/Request.js +38 -36
- package/{framework/src → src}/Route/Internal.js +116 -116
- package/src/Route/Middleware.js +75 -0
- package/src/Route.js +621 -0
- package/src/Server.js +22 -0
- package/{framework/src → src}/Stream.js +11 -3
- package/{framework/src → src}/Validator.js +21 -21
- package/{framework/src → src}/Var.js +5 -5
- package/{framework/src → src}/View/EarlyHints.js +1 -1
- package/{framework/src → src}/View/Form.js +69 -69
- package/{framework/src → src}/View.js +78 -81
- package/src/WebSocket.js +403 -0
- package/template/config.json +5 -0
- package/{web → template}/controller/page/about.js +6 -6
- package/{web → template}/controller/page/index.js +9 -9
- package/{web → template}/package.json +4 -5
- package/{web → template}/public/assets/css/style.css +4 -4
- package/{web → template}/public/assets/js/app.js +6 -6
- package/{web → template}/route/www.js +6 -6
- package/{web → template}/skeleton/main.html +1 -1
- package/{web → template}/view/content/about.html +5 -5
- package/{web → template}/view/content/home.html +12 -12
- package/template/view/footer/main.html +11 -0
- package/{web → template}/view/head/main.html +1 -1
- package/{web → template}/view/header/main.html +2 -2
- package/test/core/Candy.test.js +58 -58
- package/test/core/Commands.test.js +7 -7
- package/test/core/Config.test.js +82 -85
- package/test/core/Lang.test.js +2 -2
- package/test/core/Process.test.js +6 -6
- package/test/framework/Route.test.js +56 -37
- package/test/framework/View/EarlyHints.test.js +2 -2
- package/test/framework/WebSocket.test.js +100 -0
- package/test/framework/middleware.test.js +85 -0
- package/test/server/Api.test.js +31 -31
- package/test/server/DNS.test.js +11 -11
- package/test/server/Hub.test.js +497 -0
- package/test/server/Mail.account.test_.js +3 -3
- package/test/server/Mail.init.test_.js +10 -10
- package/test/server/Mail.test_.js +20 -20
- package/test/server/SSL.test_.js +54 -54
- package/test/server/Server.test.js +39 -39
- package/test/server/Service.test_.js +7 -7
- package/test/server/Subdomain.test.js +7 -7
- package/test/server/Web/Firewall.test.js +87 -87
- package/test/server/Web/Proxy.test.js +397 -0
- package/test/server/{Web.test_.js → Web.test.js} +137 -205
- package/test/server/__mocks__/fs.js +2 -2
- package/test/server/__mocks__/{globalCandy.js → globalOdac.js} +5 -5
- package/test/server/__mocks__/index.js +6 -6
- package/test/server/__mocks__/testFactories.js +1 -1
- package/test/server/__mocks__/testHelpers.js +7 -7
- package/.husky/pre-commit +0 -2
- package/.kiro/steering/code-style.md +0 -56
- package/.kiro/steering/product.md +0 -20
- package/.kiro/steering/structure.md +0 -77
- package/.kiro/steering/tech.md +0 -87
- package/AGENTS.md +0 -84
- package/bin/candy +0 -10
- package/bin/candypack +0 -10
- package/cli/index.js +0 -3
- package/cli/src/Cli.js +0 -348
- package/cli/src/Connector.js +0 -93
- package/cli/src/Monitor.js +0 -416
- package/core/Candy.js +0 -87
- package/core/Commands.js +0 -239
- package/core/Config.js +0 -1094
- package/core/Lang.js +0 -52
- package/core/Log.js +0 -43
- package/core/Process.js +0 -26
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +0 -20
- package/docs/server/01-installation/01-quick-install.md +0 -19
- package/docs/server/01-installation/02-manual-installation-via-npm.md +0 -9
- package/docs/server/02-get-started/01-core-concepts.md +0 -7
- package/docs/server/02-get-started/02-basic-commands.md +0 -57
- package/docs/server/02-get-started/03-cli-reference.md +0 -276
- package/docs/server/02-get-started/04-cli-quick-reference.md +0 -102
- package/docs/server/03-service/01-start-a-new-service.md +0 -57
- package/docs/server/03-service/02-delete-a-service.md +0 -48
- package/docs/server/04-web/01-create-a-website.md +0 -36
- package/docs/server/04-web/02-list-websites.md +0 -9
- package/docs/server/04-web/03-delete-a-website.md +0 -29
- package/docs/server/05-subdomain/01-create-a-subdomain.md +0 -32
- package/docs/server/05-subdomain/02-list-subdomains.md +0 -33
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +0 -41
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +0 -34
- package/docs/server/07-mail/01-create-a-mail-account.md +0 -23
- package/docs/server/07-mail/02-delete-a-mail-account.md +0 -20
- package/docs/server/07-mail/03-list-mail-accounts.md +0 -20
- package/docs/server/07-mail/04-change-account-password.md +0 -23
- package/framework/src/Candy.js +0 -81
- package/framework/src/Route.js +0 -455
- package/framework/src/Server.js +0 -15
- package/locale/de-DE.json +0 -80
- package/locale/en-US.json +0 -79
- package/locale/es-ES.json +0 -80
- package/locale/fr-FR.json +0 -80
- package/locale/pt-BR.json +0 -80
- package/locale/ru-RU.json +0 -80
- package/locale/tr-TR.json +0 -85
- package/locale/zh-CN.json +0 -80
- package/server/index.js +0 -5
- package/server/src/Api.js +0 -88
- package/server/src/DNS.js +0 -940
- package/server/src/Hub.js +0 -535
- package/server/src/Mail.js +0 -571
- package/server/src/SSL.js +0 -180
- package/server/src/Server.js +0 -27
- package/server/src/Service.js +0 -248
- package/server/src/Subdomain.js +0 -64
- package/server/src/Web/Firewall.js +0 -170
- package/server/src/Web/Proxy.js +0 -134
- package/server/src/Web.js +0 -451
- package/server/src/mail/imap.js +0 -1091
- package/server/src/mail/server.js +0 -32
- package/server/src/mail/smtp.js +0 -786
- package/test/server/Client.test.js +0 -338
- package/test/server/__mocks__/http-proxy.js +0 -105
- package/watchdog/index.js +0 -3
- package/watchdog/src/Watchdog.js +0 -156
- package/web/config.json +0 -5
- package/web/view/footer/main.html +0 -11
- /package/{framework/src → src}/Env.js +0 -0
- /package/{framework/src → src}/Route/Cron.js +0 -0
- /package/{framework/src → src}/Token.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Streaming API
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Odac provides a unified streaming API that automatically handles Server-Sent Events (SSE), with future support for WebSocket and HTTP/3.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
@@ -8,8 +8,8 @@ CandyPack provides a unified streaming API that automatically handles Server-Sen
|
|
|
8
8
|
|
|
9
9
|
```javascript
|
|
10
10
|
// route/www.js
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
Odac.Route.get('/hello', async (Odac) => {
|
|
12
|
+
Odac.stream('Hello World')
|
|
13
13
|
})
|
|
14
14
|
```
|
|
15
15
|
|
|
@@ -17,11 +17,11 @@ Candy.Route.get('/hello', async (Candy) => {
|
|
|
17
17
|
|
|
18
18
|
```javascript
|
|
19
19
|
// route/www.js
|
|
20
|
-
|
|
20
|
+
Odac.Route.get('/hello', 'hello')
|
|
21
21
|
|
|
22
22
|
// controller/hello/get/index.js
|
|
23
|
-
module.exports = async (
|
|
24
|
-
|
|
23
|
+
module.exports = async (Odac) => {
|
|
24
|
+
Odac.stream('Hello World')
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
27
|
|
|
@@ -29,34 +29,37 @@ module.exports = async (Candy) => {
|
|
|
29
29
|
|
|
30
30
|
```javascript
|
|
31
31
|
// controller/get/index.js
|
|
32
|
-
module.exports = async (
|
|
33
|
-
|
|
32
|
+
module.exports = async (Odac) => {
|
|
33
|
+
Odac.stream({ message: 'Hello', time: Date.now() })
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
## Multiple Messages
|
|
38
38
|
|
|
39
|
-
### Callback Pattern
|
|
39
|
+
### Callback Pattern with Auto-Cleanup
|
|
40
40
|
|
|
41
41
|
```javascript
|
|
42
42
|
// controller/get/index.js
|
|
43
|
-
module.exports = async (
|
|
44
|
-
|
|
43
|
+
module.exports = async (Odac) => {
|
|
44
|
+
Odac.stream((send) => {
|
|
45
45
|
send({ type: 'connected' })
|
|
46
46
|
|
|
47
|
-
setInterval
|
|
47
|
+
// Use Odac.setInterval for automatic cleanup
|
|
48
|
+
Odac.setInterval(() => {
|
|
48
49
|
send({ time: Date.now() })
|
|
49
50
|
}, 1000)
|
|
50
51
|
})
|
|
51
52
|
}
|
|
52
53
|
```
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
**Important:** Always use `Odac.setInterval()` and `Odac.setTimeout()` instead of global functions. They are automatically cleaned up when the connection closes.
|
|
56
|
+
|
|
57
|
+
### Manual Cleanup (Alternative)
|
|
55
58
|
|
|
56
59
|
```javascript
|
|
57
60
|
// controller/get/index.js
|
|
58
|
-
module.exports = async (
|
|
59
|
-
|
|
61
|
+
module.exports = async (Odac) => {
|
|
62
|
+
Odac.stream((send, close) => {
|
|
60
63
|
send({ type: 'connected' })
|
|
61
64
|
|
|
62
65
|
const interval = setInterval(() => {
|
|
@@ -77,8 +80,8 @@ module.exports = async (Candy) => {
|
|
|
77
80
|
|
|
78
81
|
```javascript
|
|
79
82
|
// controller/get/index.js
|
|
80
|
-
module.exports = async (
|
|
81
|
-
|
|
83
|
+
module.exports = async (Odac) => {
|
|
84
|
+
Odac.stream([1, 2, 3, 4, 5])
|
|
82
85
|
}
|
|
83
86
|
```
|
|
84
87
|
|
|
@@ -86,9 +89,9 @@ module.exports = async (Candy) => {
|
|
|
86
89
|
|
|
87
90
|
```javascript
|
|
88
91
|
// controller/users/get/index.js
|
|
89
|
-
module.exports = async (
|
|
90
|
-
|
|
91
|
-
const users = await
|
|
92
|
+
module.exports = async (Odac) => {
|
|
93
|
+
Odac.stream(async function* () {
|
|
94
|
+
const users = await Odac.Mysql.table('users').get()
|
|
92
95
|
|
|
93
96
|
for (const user of users) {
|
|
94
97
|
yield user
|
|
@@ -101,8 +104,8 @@ module.exports = async (Candy) => {
|
|
|
101
104
|
|
|
102
105
|
```javascript
|
|
103
106
|
// controller/app/get/index.js
|
|
104
|
-
module.exports = async (
|
|
105
|
-
|
|
107
|
+
module.exports = async (Odac) => {
|
|
108
|
+
Odac.stream(
|
|
106
109
|
fetch('https://api.example.com/data')
|
|
107
110
|
.then(r => r.json())
|
|
108
111
|
)
|
|
@@ -113,9 +116,9 @@ module.exports = async (Candy) => {
|
|
|
113
116
|
|
|
114
117
|
```javascript
|
|
115
118
|
// controller/file/get/index.js
|
|
116
|
-
module.exports = async (
|
|
119
|
+
module.exports = async (Odac) => {
|
|
117
120
|
const fs = require('fs')
|
|
118
|
-
|
|
121
|
+
Odac.stream(fs.createReadStream('large-file.txt'))
|
|
119
122
|
}
|
|
120
123
|
```
|
|
121
124
|
|
|
@@ -125,27 +128,26 @@ module.exports = async (Candy) => {
|
|
|
125
128
|
|
|
126
129
|
```javascript
|
|
127
130
|
// controller/monitor/get/index.js
|
|
128
|
-
module.exports = async (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
stream.on('close', () => {
|
|
138
|
-
clearInterval(interval)
|
|
131
|
+
module.exports = async (Odac) => {
|
|
132
|
+
return Odac.stream((send) => {
|
|
133
|
+
send({ type: 'connected' })
|
|
134
|
+
|
|
135
|
+
// Use Odac.setInterval for automatic cleanup
|
|
136
|
+
Odac.setInterval(() => {
|
|
137
|
+
send({ time: Date.now() })
|
|
138
|
+
}, 1000)
|
|
139
139
|
})
|
|
140
140
|
}
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
+
**Note:** When using `Odac.setInterval()` or `Odac.setTimeout()`, cleanup is automatic. No need for manual `clearInterval()` or `clearTimeout()`.
|
|
144
|
+
|
|
143
145
|
### Error Handling
|
|
144
146
|
|
|
145
147
|
```javascript
|
|
146
148
|
// controller/data/get/fetch.js
|
|
147
|
-
module.exports = async (
|
|
148
|
-
const stream =
|
|
149
|
+
module.exports = async (Odac) => {
|
|
150
|
+
const stream = Odac.stream()
|
|
149
151
|
|
|
150
152
|
try {
|
|
151
153
|
const data = await fetchData()
|
|
@@ -162,11 +164,11 @@ module.exports = async (Candy) => {
|
|
|
162
164
|
|
|
163
165
|
```javascript
|
|
164
166
|
// route/www.js
|
|
165
|
-
|
|
167
|
+
Odac.Route.get('/logs', 'logs')
|
|
166
168
|
|
|
167
169
|
// controller/logs/get/index.js
|
|
168
|
-
module.exports = async (
|
|
169
|
-
|
|
170
|
+
module.exports = async (Odac) => {
|
|
171
|
+
return Odac.stream(async function* () {
|
|
170
172
|
const logStream = await getDeploymentLogs()
|
|
171
173
|
|
|
172
174
|
for await (const log of logStream) {
|
|
@@ -183,16 +185,16 @@ module.exports = async (Candy) => {
|
|
|
183
185
|
|
|
184
186
|
```javascript
|
|
185
187
|
// route/www.js
|
|
186
|
-
|
|
188
|
+
Odac.Route.get('/posts', 'posts')
|
|
187
189
|
|
|
188
190
|
// controller/posts/get/index.js
|
|
189
|
-
module.exports = async (
|
|
190
|
-
|
|
191
|
+
module.exports = async (Odac) => {
|
|
192
|
+
return Odac.stream(async function* () {
|
|
191
193
|
let page = 1
|
|
192
194
|
let hasMore = true
|
|
193
195
|
|
|
194
196
|
while (hasMore) {
|
|
195
|
-
const posts = await
|
|
197
|
+
const posts = await Odac.Mysql.table('posts')
|
|
196
198
|
.limit(10)
|
|
197
199
|
.offset((page - 1) * 10)
|
|
198
200
|
.get()
|
|
@@ -261,7 +263,7 @@ function Dashboard() {
|
|
|
261
263
|
|
|
262
264
|
## Protocol
|
|
263
265
|
|
|
264
|
-
|
|
266
|
+
Odac uses **Server-Sent Events (SSE)** for streaming:
|
|
265
267
|
- ✅ One-way communication (server → client)
|
|
266
268
|
- ✅ Automatic reconnection
|
|
267
269
|
- ✅ Works over HTTP/2
|
|
@@ -275,26 +277,66 @@ CandyPack uses **Server-Sent Events (SSE)** for streaming:
|
|
|
275
277
|
- **Reconnection:** Automatic (browser handles)
|
|
276
278
|
- **Compression:** Supported via HTTP/2
|
|
277
279
|
|
|
280
|
+
## Memory Management
|
|
281
|
+
|
|
282
|
+
Odac automatically manages timers and intervals in streaming contexts:
|
|
283
|
+
|
|
284
|
+
```javascript
|
|
285
|
+
module.exports = async (Odac) => {
|
|
286
|
+
return Odac.stream((send) => {
|
|
287
|
+
// ✅ Automatically cleaned up when connection closes
|
|
288
|
+
Odac.setInterval(() => {
|
|
289
|
+
send({ time: Date.now() })
|
|
290
|
+
}, 1000)
|
|
291
|
+
|
|
292
|
+
Odac.setTimeout(() => {
|
|
293
|
+
send({ type: 'delayed' })
|
|
294
|
+
}, 5000)
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Why this matters:**
|
|
300
|
+
- Prevents memory leaks
|
|
301
|
+
- No orphaned intervals after disconnect
|
|
302
|
+
- Automatic cleanup on connection close
|
|
303
|
+
|
|
304
|
+
**Manual cleanup (if needed):**
|
|
305
|
+
```javascript
|
|
306
|
+
const intervalId = Odac.setInterval(() => { ... }, 1000)
|
|
307
|
+
Odac.clearInterval(intervalId)
|
|
308
|
+
|
|
309
|
+
const timeoutId = Odac.setTimeout(() => { ... }, 5000)
|
|
310
|
+
Odac.clearTimeout(timeoutId)
|
|
311
|
+
```
|
|
312
|
+
|
|
278
313
|
## Best Practices
|
|
279
314
|
|
|
280
|
-
1. **
|
|
281
|
-
2. **
|
|
282
|
-
3. **
|
|
283
|
-
4. **
|
|
315
|
+
1. **Use Odac timers:** Always use `Odac.setInterval()` and `Odac.setTimeout()` instead of global functions
|
|
316
|
+
2. **Return the stream:** Always `return Odac.stream(...)` from your controller
|
|
317
|
+
3. **Throttle messages:** Don't send too frequently (use intervals)
|
|
318
|
+
4. **Handle errors:** Use try-catch for async operations
|
|
284
319
|
5. **Test reconnection:** Ensure your app handles connection drops
|
|
285
320
|
|
|
286
321
|
## Troubleshooting
|
|
287
322
|
|
|
288
323
|
**Connection drops immediately:**
|
|
289
|
-
- Check if you're calling `
|
|
324
|
+
- Check if you're calling `Odac.return()` or `res.end()`
|
|
290
325
|
- Don't use both streaming and regular responses
|
|
326
|
+
- Make sure to `return Odac.stream(...)`
|
|
291
327
|
|
|
292
328
|
**Messages not received:**
|
|
293
329
|
- Verify JSON format
|
|
294
330
|
- Check browser console for errors
|
|
295
331
|
- Ensure CORS headers if cross-origin
|
|
296
332
|
|
|
297
|
-
**High memory usage:**
|
|
298
|
-
-
|
|
299
|
-
-
|
|
300
|
-
-
|
|
333
|
+
**High memory usage / Memory leaks:**
|
|
334
|
+
- Use `Odac.setInterval()` instead of global `setInterval()`
|
|
335
|
+
- Use `Odac.setTimeout()` instead of global `setTimeout()`
|
|
336
|
+
- Avoid creating intervals outside the stream callback
|
|
337
|
+
- Check for other resource leaks (database connections, file handles)
|
|
338
|
+
|
|
339
|
+
**Intervals keep running after disconnect:**
|
|
340
|
+
- Replace `setInterval()` with `Odac.setInterval()`
|
|
341
|
+
- Replace `setTimeout()` with `Odac.setTimeout()`
|
|
342
|
+
- These are automatically cleaned up when the connection closes
|