api-ape 1.1.0 → 2.1.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/README.md +114 -11
- package/client/browser.js +19 -1
- package/client/connectSocket.js +556 -368
- package/client/transports/streaming.js +253 -0
- package/dist/ape.js +651 -301
- package/example/Bun/README.md +74 -0
- package/example/Bun/api/message.ts +11 -0
- package/example/Bun/index.html +76 -0
- package/example/Bun/package.json +9 -0
- package/example/Bun/server.ts +59 -0
- package/example/Bun/styles.css +128 -0
- package/example/ExpressJs/README.md +5 -7
- package/example/ExpressJs/backend.js +23 -21
- package/example/NextJs/ape/client.js +3 -3
- package/example/NextJs/ape/onConnect.js +5 -5
- package/example/NextJs/package-lock.json +1353 -60
- package/example/NextJs/package.json +0 -1
- package/example/NextJs/pages/index.tsx +21 -10
- package/example/NextJs/server.js +7 -11
- package/example/README.md +51 -0
- package/example/Vite/README.md +68 -0
- package/example/Vite/ape/client.ts +66 -0
- package/example/Vite/ape/onConnect.ts +52 -0
- package/example/Vite/api/message.ts +57 -0
- package/example/Vite/index.html +16 -0
- package/example/Vite/package.json +19 -0
- package/example/Vite/server.ts +62 -0
- package/example/Vite/src/App.vue +170 -0
- package/example/Vite/src/components/Info.vue +352 -0
- package/example/Vite/src/main.ts +5 -0
- package/example/Vite/src/style.css +200 -0
- package/example/Vite/src/vite-env.d.ts +7 -0
- package/example/Vite/vite.config.ts +20 -0
- package/index.d.ts +40 -3
- package/package.json +26 -11
- package/server/README.md +54 -9
- package/server/index.js +10 -2
- package/server/lib/longPolling.js +221 -0
- package/server/lib/main.js +172 -60
- package/server/security/origin.js +16 -4
- package/server/utils/deepRequire.js +25 -10
package/README.md
CHANGED
|
@@ -24,18 +24,30 @@ yarn add api-ape
|
|
|
24
24
|
|
|
25
25
|
## Quick Start
|
|
26
26
|
|
|
27
|
-
### Server (
|
|
27
|
+
### Server (Node.js)
|
|
28
28
|
|
|
29
29
|
```js
|
|
30
|
-
const
|
|
30
|
+
const { createServer } = require('http')
|
|
31
31
|
const ape = require('api-ape')
|
|
32
32
|
|
|
33
|
-
const
|
|
33
|
+
const server = createServer()
|
|
34
34
|
|
|
35
35
|
// Wire up api-ape - loads controllers from ./api folder
|
|
36
|
-
ape(
|
|
36
|
+
ape(server, { where: 'api' })
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
server.listen(3000)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**With Express:**
|
|
42
|
+
```js
|
|
43
|
+
const express = require('express')
|
|
44
|
+
const ape = require('api-ape')
|
|
45
|
+
|
|
46
|
+
const app = express()
|
|
47
|
+
const server = app.listen(3000) // Get the HTTP server
|
|
48
|
+
|
|
49
|
+
// Pass the HTTP server (not the Express app)
|
|
50
|
+
ape(server, { where: 'api' })
|
|
39
51
|
```
|
|
40
52
|
|
|
41
53
|
### Create a Controller
|
|
@@ -77,6 +89,7 @@ Include the bundled client and start calling:
|
|
|
77
89
|
* **Real-time broadcasts** — Built-in `broadcast()` and `broadcastOthers()` methods for pushing to clients
|
|
78
90
|
* **Promise-based calls** — Chainable paths like `ape.users.list()` map to `api/users/list.js`
|
|
79
91
|
* **Automatic reconnection** — Client auto-reconnects on disconnect with exponential backoff
|
|
92
|
+
* **HTTP streaming fallback** — Automatically falls back to long polling when WebSockets are blocked
|
|
80
93
|
* **JJS Encoding** — Extended JSON supporting Date, RegExp, Error, Set, Map, undefined, and circular refs
|
|
81
94
|
* **Connection lifecycle hooks** — Customize behavior on connect, receive, send, error, and disconnect
|
|
82
95
|
|
|
@@ -86,12 +99,13 @@ Include the bundled client and start calling:
|
|
|
86
99
|
|
|
87
100
|
### Server
|
|
88
101
|
|
|
89
|
-
#### `ape(
|
|
102
|
+
#### `ape(server, options)`
|
|
90
103
|
|
|
91
|
-
Initialize api-ape on
|
|
104
|
+
Initialize api-ape on a Node.js HTTP/HTTPS server.
|
|
92
105
|
|
|
93
106
|
| Option | Type | Description |
|
|
94
107
|
|--------|------|-------------|
|
|
108
|
+
| `server` | `http.Server` | Node.js HTTP or HTTPS server instance |
|
|
95
109
|
| `where` | `string` | Directory containing controller files (default: `'api'`) |
|
|
96
110
|
| `onConnent` | `function` | Connection lifecycle hook (see [Connection Lifecycle](#connection-lifecycle)) |
|
|
97
111
|
|
|
@@ -139,6 +153,53 @@ ape.on('notification', ({ data, err, type }) => {
|
|
|
139
153
|
})
|
|
140
154
|
```
|
|
141
155
|
|
|
156
|
+
#### `ape.configure(options)`
|
|
157
|
+
|
|
158
|
+
Configure client connection options.
|
|
159
|
+
|
|
160
|
+
```js
|
|
161
|
+
// Configure transport mode
|
|
162
|
+
ape.configure({ transport: 'auto' }) // Auto-detect (default)
|
|
163
|
+
ape.configure({ transport: 'websocket' }) // Force WebSocket only
|
|
164
|
+
ape.configure({ transport: 'polling' }) // Force HTTP streaming
|
|
165
|
+
|
|
166
|
+
// Configure connection details
|
|
167
|
+
ape.configure({
|
|
168
|
+
port: 9010,
|
|
169
|
+
host: 'example.com',
|
|
170
|
+
transport: 'auto'
|
|
171
|
+
})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
| Option | Type | Description |
|
|
175
|
+
|--------|------|-------------|
|
|
176
|
+
| `port` | `number` | Server port (default: auto-detect) |
|
|
177
|
+
| `host` | `string` | Server hostname (default: auto-detect) |
|
|
178
|
+
| `transport` | `string` | Transport mode: `'auto'`, `'websocket'`, or `'polling'` |
|
|
179
|
+
|
|
180
|
+
#### `ape.getTransport()`
|
|
181
|
+
|
|
182
|
+
Get the currently active transport type.
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
const transport = ape.getTransport()
|
|
186
|
+
console.log(transport) // 'websocket' | 'polling' | null
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### `ape.onConnectionChange(handler)`
|
|
190
|
+
|
|
191
|
+
Listen for connection state changes.
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
const unsubscribe = ape.onConnectionChange((state) => {
|
|
195
|
+
console.log('Connection state:', state)
|
|
196
|
+
// 'disconnected' | 'connecting' | 'connected'
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
// Later: stop listening
|
|
200
|
+
unsubscribe()
|
|
201
|
+
```
|
|
202
|
+
|
|
142
203
|
---
|
|
143
204
|
|
|
144
205
|
## Configuration
|
|
@@ -146,7 +207,7 @@ ape.on('notification', ({ data, err, type }) => {
|
|
|
146
207
|
### Default Options
|
|
147
208
|
|
|
148
209
|
```js
|
|
149
|
-
ape(
|
|
210
|
+
ape(server, {
|
|
150
211
|
where: 'api', // Controller directory
|
|
151
212
|
onConnent: undefined // Lifecycle hook (optional)
|
|
152
213
|
})
|
|
@@ -157,7 +218,7 @@ ape(app, {
|
|
|
157
218
|
Customize behavior per connection:
|
|
158
219
|
|
|
159
220
|
```js
|
|
160
|
-
ape(
|
|
221
|
+
ape(server, {
|
|
161
222
|
where: 'api',
|
|
162
223
|
onConnent(socket, req, hostId) {
|
|
163
224
|
return {
|
|
@@ -282,6 +343,48 @@ This is automatic — send a Date, receive a Date. No configuration needed.
|
|
|
282
343
|
|
|
283
344
|
---
|
|
284
345
|
|
|
346
|
+
## HTTP Streaming Fallback
|
|
347
|
+
|
|
348
|
+
api-ape automatically falls back to HTTP streaming when WebSockets are unavailable or blocked by firewalls/proxies.
|
|
349
|
+
|
|
350
|
+
### How It Works
|
|
351
|
+
|
|
352
|
+
1. **WebSocket First**: Client attempts WebSocket connection (4 second timeout)
|
|
353
|
+
2. **Auto-Fallback**: On failure, switches to HTTP streaming transport
|
|
354
|
+
3. **Background Retry**: Keeps attempting WebSocket reconnection every 30 seconds
|
|
355
|
+
4. **Auto-Upgrade**: Switches back to WebSocket when available
|
|
356
|
+
|
|
357
|
+
### Streaming Transport
|
|
358
|
+
|
|
359
|
+
When in polling mode:
|
|
360
|
+
- **GET `/api/ape/poll`**: Long-lived connection, server streams JSON messages
|
|
361
|
+
- **POST `/api/ape/poll`**: Client sends messages
|
|
362
|
+
- Cookie-based session (`apeHostId`) for authentication
|
|
363
|
+
- Heartbeat every 20 seconds to prevent proxy timeout
|
|
364
|
+
|
|
365
|
+
### Force Transport Mode
|
|
366
|
+
|
|
367
|
+
```js
|
|
368
|
+
// Force HTTP streaming (useful for testing)
|
|
369
|
+
ape.configure({ transport: 'polling' })
|
|
370
|
+
|
|
371
|
+
// Force WebSocket only (fail if unavailable)
|
|
372
|
+
ape.configure({ transport: 'websocket' })
|
|
373
|
+
|
|
374
|
+
// Auto-detect (default)
|
|
375
|
+
ape.configure({ transport: 'auto' })
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Check Active Transport
|
|
379
|
+
|
|
380
|
+
```js
|
|
381
|
+
if (ape.getTransport() === 'polling') {
|
|
382
|
+
console.log('Using HTTP streaming fallback')
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
285
388
|
## Examples & Demos
|
|
286
389
|
|
|
287
390
|
The repository contains working examples:
|
|
@@ -328,7 +431,7 @@ docker-compose up --build
|
|
|
328
431
|
|
|
329
432
|
### CORS Errors in Browser
|
|
330
433
|
|
|
331
|
-
Ensure your
|
|
434
|
+
Ensure your server allows WebSocket connections from your origin. api-ape uses the `ws` library which handles WebSocket upgrades on the HTTP server level.
|
|
332
435
|
|
|
333
436
|
### Controller Not Found
|
|
334
437
|
|
|
@@ -460,7 +563,7 @@ api-ape/
|
|
|
460
563
|
│ └── connectSocket.js # WebSocket client with auto-reconnect
|
|
461
564
|
├── server/
|
|
462
565
|
│ ├── lib/
|
|
463
|
-
│ │ ├── main.js #
|
|
566
|
+
│ │ ├── main.js # HTTP server integration
|
|
464
567
|
│ │ ├── loader.js # Auto-loads controller files
|
|
465
568
|
│ │ ├── broadcast.js # Client tracking & broadcast
|
|
466
569
|
│ │ └── wiring.js # WebSocket handler setup
|
package/client/browser.js
CHANGED
|
@@ -4,7 +4,7 @@ import connectSocket from './connectSocket.js'
|
|
|
4
4
|
const port = window.location.port || (window.location.protocol === 'https:' ? 443 : 80)
|
|
5
5
|
connectSocket.configure({ port: parseInt(port, 10) })
|
|
6
6
|
|
|
7
|
-
const { sender, setOnReciver } = connectSocket()
|
|
7
|
+
const { sender, setOnReciver, onConnectionChange, getTransport } = connectSocket()
|
|
8
8
|
connectSocket.autoReconnect()
|
|
9
9
|
|
|
10
10
|
// Global API - use defineProperty to bypass Proxy interception
|
|
@@ -15,3 +15,21 @@ Object.defineProperty(window.ape, 'on', {
|
|
|
15
15
|
enumerable: false,
|
|
16
16
|
configurable: false
|
|
17
17
|
})
|
|
18
|
+
Object.defineProperty(window.ape, 'onConnectionChange', {
|
|
19
|
+
value: onConnectionChange,
|
|
20
|
+
writable: false,
|
|
21
|
+
enumerable: false,
|
|
22
|
+
configurable: false
|
|
23
|
+
})
|
|
24
|
+
Object.defineProperty(window.ape, 'configure', {
|
|
25
|
+
value: connectSocket.configure,
|
|
26
|
+
writable: false,
|
|
27
|
+
enumerable: false,
|
|
28
|
+
configurable: false
|
|
29
|
+
})
|
|
30
|
+
Object.defineProperty(window.ape, 'getTransport', {
|
|
31
|
+
value: getTransport,
|
|
32
|
+
writable: false,
|
|
33
|
+
enumerable: false,
|
|
34
|
+
configurable: false
|
|
35
|
+
})
|