api-ape 0.0.0 → 1.0.2
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 +458 -0
- package/client/README.md +69 -0
- package/client/browser.js +17 -0
- package/client/connectSocket.js +260 -0
- package/dist/ape.js +454 -0
- package/example/ExpressJs/README.md +97 -0
- package/example/ExpressJs/api/message.js +11 -0
- package/example/ExpressJs/backend.js +37 -0
- package/example/ExpressJs/index.html +88 -0
- package/example/ExpressJs/package-lock.json +834 -0
- package/example/ExpressJs/package.json +10 -0
- package/example/ExpressJs/styles.css +128 -0
- package/example/NextJs/.dockerignore +29 -0
- package/example/NextJs/Dockerfile +52 -0
- package/example/NextJs/Dockerfile.dev +27 -0
- package/example/NextJs/README.md +113 -0
- package/example/NextJs/ape/client.js +66 -0
- package/example/NextJs/ape/embed.js +12 -0
- package/example/NextJs/ape/index.js +23 -0
- package/example/NextJs/ape/logic/chat.js +62 -0
- package/example/NextJs/ape/onConnect.js +69 -0
- package/example/NextJs/ape/onDisconnect.js +13 -0
- package/example/NextJs/ape/onError.js +9 -0
- package/example/NextJs/ape/onReceive.js +15 -0
- package/example/NextJs/ape/onSend.js +15 -0
- package/example/NextJs/api/message.js +44 -0
- package/example/NextJs/docker-compose.yml +22 -0
- package/example/NextJs/next-env.d.ts +5 -0
- package/example/NextJs/next.config.js +8 -0
- package/example/NextJs/package-lock.json +5107 -0
- package/example/NextJs/package.json +25 -0
- package/example/NextJs/pages/Info.tsx +153 -0
- package/example/NextJs/pages/_app.tsx +6 -0
- package/example/NextJs/pages/index.tsx +264 -0
- package/example/NextJs/public/favicon.ico +0 -0
- package/example/NextJs/public/vercel.svg +4 -0
- package/example/NextJs/server.js +40 -0
- package/example/NextJs/styles/Chat.module.css +448 -0
- package/example/NextJs/styles/Home.module.css +129 -0
- package/example/NextJs/styles/globals.css +26 -0
- package/example/NextJs/tsconfig.json +20 -0
- package/example/README.md +66 -0
- package/index.d.ts +179 -0
- package/index.js +11 -0
- package/package.json +11 -4
- package/server/README.md +93 -0
- package/server/index.js +6 -0
- package/server/lib/broadcast.js +63 -0
- package/server/lib/loader.js +10 -0
- package/server/lib/main.js +23 -0
- package/server/lib/wiring.js +94 -0
- package/server/security/extractRootDomain.js +21 -0
- package/server/security/origin.js +13 -0
- package/server/security/reply.js +21 -0
- package/server/socket/open.js +10 -0
- package/server/socket/receive.js +66 -0
- package/server/socket/send.js +55 -0
- package/server/utils/deepRequire.js +45 -0
- package/server/utils/genId.js +24 -0
- package/todo.md +85 -0
- package/utils/jss.js +273 -0
- package/utils/jss.test.js +261 -0
- package/utils/messageHash.js +43 -0
- package/utils/messageHash.test.js +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
# 🦍 api-ape
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/api-ape)
|
|
4
|
+
[](https://github.com/codemeasandwich/api-ape/blob/main/LICENSE)
|
|
5
|
+
[](https://github.com/codemeasandwich/api-ape/issues)
|
|
6
|
+
|
|
7
|
+
**Remote Procedure Events (RPE)** — A lightweight WebSocket framework for building real-time APIs. Call server functions from the browser like local methods. Get real-time broadcasts with zero setup.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install api-ape
|
|
15
|
+
# or
|
|
16
|
+
pnpm add api-ape
|
|
17
|
+
# or
|
|
18
|
+
yarn add api-ape
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Requirements:** Node.js 14+ (for server), modern browsers (for client)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### Server (Express.js)
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
const express = require('express')
|
|
31
|
+
const ape = require('api-ape')
|
|
32
|
+
|
|
33
|
+
const app = express()
|
|
34
|
+
|
|
35
|
+
// Wire up api-ape - loads controllers from ./api folder
|
|
36
|
+
ape(app, { where: 'api' })
|
|
37
|
+
|
|
38
|
+
app.listen(3000)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Create a Controller
|
|
42
|
+
|
|
43
|
+
Drop a file in your `api/` folder — it automatically becomes an endpoint:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
// api/hello.js
|
|
47
|
+
module.exports = function(name) {
|
|
48
|
+
return `Hello, ${name}!`
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Client (Browser)
|
|
53
|
+
|
|
54
|
+
Include the bundled client and start calling:
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<script src="/api/ape.js"></script>
|
|
58
|
+
<script>
|
|
59
|
+
// Call server functions like local methods
|
|
60
|
+
const result = await ape.hello('World')
|
|
61
|
+
console.log(result) // "Hello, World!"
|
|
62
|
+
|
|
63
|
+
// Listen for broadcasts
|
|
64
|
+
ape.on('message', ({ data }) => {
|
|
65
|
+
console.log('New message:', data)
|
|
66
|
+
})
|
|
67
|
+
</script>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**That's it!** Your server function is now callable from the browser.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Key Concepts
|
|
75
|
+
|
|
76
|
+
* **Auto-wiring** — Drop JS files in a folder, they become API endpoints automatically
|
|
77
|
+
* **Real-time broadcasts** — Built-in `broadcast()` and `broadcastOthers()` methods for pushing to clients
|
|
78
|
+
* **Promise-based calls** — Chainable paths like `ape.users.list()` map to `api/users/list.js`
|
|
79
|
+
* **Automatic reconnection** — Client auto-reconnects on disconnect with exponential backoff
|
|
80
|
+
* **JJS Encoding** — Extended JSON supporting Date, RegExp, Error, Set, Map, undefined, and circular refs
|
|
81
|
+
* **Connection lifecycle hooks** — Customize behavior on connect, receive, send, error, and disconnect
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## API Reference
|
|
86
|
+
|
|
87
|
+
### Server
|
|
88
|
+
|
|
89
|
+
#### `ape(app, options)`
|
|
90
|
+
|
|
91
|
+
Initialize api-ape on an Express app.
|
|
92
|
+
|
|
93
|
+
| Option | Type | Description |
|
|
94
|
+
|--------|------|-------------|
|
|
95
|
+
| `where` | `string` | Directory containing controller files (default: `'api'`) |
|
|
96
|
+
| `onConnent` | `function` | Connection lifecycle hook (see [Connection Lifecycle](#connection-lifecycle)) |
|
|
97
|
+
|
|
98
|
+
#### Controller Context (`this`)
|
|
99
|
+
|
|
100
|
+
Inside controller functions, `this` provides:
|
|
101
|
+
|
|
102
|
+
| Property | Description |
|
|
103
|
+
|----------|-------------|
|
|
104
|
+
| `this.broadcast(type, data)` | Send to **ALL** connected clients |
|
|
105
|
+
| `this.broadcastOthers(type, data)` | Send to all **EXCEPT** the caller |
|
|
106
|
+
| `this.online()` | Get count of connected clients |
|
|
107
|
+
| `this.getClients()` | Get array of connected hostIds |
|
|
108
|
+
| `this.hostId` | Unique ID of the calling client |
|
|
109
|
+
| `this.req` | Original HTTP request |
|
|
110
|
+
| `this.socket` | WebSocket instance |
|
|
111
|
+
| `this.agent` | Parsed user-agent (browser, OS, device) |
|
|
112
|
+
|
|
113
|
+
### Client
|
|
114
|
+
|
|
115
|
+
#### `ape.<path>.<method>(...args)`
|
|
116
|
+
|
|
117
|
+
Call a server function. Returns a Promise.
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
// Calls api/users/list.js
|
|
121
|
+
const users = await ape.users.list()
|
|
122
|
+
|
|
123
|
+
// Calls api/users/create.js with data
|
|
124
|
+
const user = await ape.users.create({ name: 'Alice' })
|
|
125
|
+
|
|
126
|
+
// Nested paths work too
|
|
127
|
+
// ape.admin.users -> api/admin/users.js
|
|
128
|
+
// ape.admin.users.delete -> api/admin/users/delete.js
|
|
129
|
+
await ape.admin.users.delete(userId)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### `ape.on(type, handler)`
|
|
133
|
+
|
|
134
|
+
Listen for server broadcasts.
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
ape.on('notification', ({ data, err, type }) => {
|
|
138
|
+
console.log('Received:', data)
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Configuration
|
|
145
|
+
|
|
146
|
+
### Default Options
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
ape(app, {
|
|
150
|
+
where: 'api', // Controller directory
|
|
151
|
+
onConnent: undefined // Lifecycle hook (optional)
|
|
152
|
+
})
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Connection Lifecycle Hook
|
|
156
|
+
|
|
157
|
+
Customize behavior per connection:
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
ape(app, {
|
|
161
|
+
where: 'api',
|
|
162
|
+
onConnent(socket, req, hostId) {
|
|
163
|
+
return {
|
|
164
|
+
// Embed values into `this` for all controllers
|
|
165
|
+
embed: {
|
|
166
|
+
userId: req.session?.userId,
|
|
167
|
+
clientId: String(hostId)
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
// Before/after hooks
|
|
171
|
+
onReceive: (queryId, data, type) => {
|
|
172
|
+
console.log(`→ ${type}`)
|
|
173
|
+
return (err, result) => console.log(`← ${type}`, err || result)
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
onSend: (data, type) => {
|
|
177
|
+
console.log(`⇐ ${type}`)
|
|
178
|
+
return (err, result) => console.log(`Sent: ${type}`)
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
onError: (errStr) => console.error(errStr),
|
|
182
|
+
onDisconnent: () => console.log('Client left')
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Common Recipes
|
|
191
|
+
|
|
192
|
+
### Broadcast to Other Clients
|
|
193
|
+
|
|
194
|
+
```js
|
|
195
|
+
// api/message.js
|
|
196
|
+
module.exports = function(data) {
|
|
197
|
+
// Broadcast to all OTHER connected clients (not the sender)
|
|
198
|
+
this.broadcastOthers('message', data)
|
|
199
|
+
return { success: true }
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Broadcast to All Clients
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
// api/announcement.js
|
|
207
|
+
module.exports = function(announcement) {
|
|
208
|
+
// Broadcast to ALL connected clients including sender
|
|
209
|
+
this.broadcast('announcement', announcement)
|
|
210
|
+
return { sent: true }
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Get Online Count
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
// api/stats.js
|
|
218
|
+
module.exports = function() {
|
|
219
|
+
return {
|
|
220
|
+
online: this.online(),
|
|
221
|
+
clients: this.getClients()
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Access Request Data
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
// api/profile.js
|
|
230
|
+
module.exports = function() {
|
|
231
|
+
// Access original HTTP request
|
|
232
|
+
const userId = this.req.session?.userId
|
|
233
|
+
const userAgent = this.agent.browser.name
|
|
234
|
+
|
|
235
|
+
return { userId, userAgent }
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Error Handling
|
|
240
|
+
|
|
241
|
+
```js
|
|
242
|
+
// api/data.js
|
|
243
|
+
module.exports = async function(id) {
|
|
244
|
+
try {
|
|
245
|
+
const data = await fetchData(id)
|
|
246
|
+
return data
|
|
247
|
+
} catch (err) {
|
|
248
|
+
// Errors are automatically sent to client
|
|
249
|
+
throw new Error(`Failed to fetch: ${err.message}`)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Client-Side Error Handling
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
try {
|
|
258
|
+
const result = await ape.data.get(id)
|
|
259
|
+
console.log(result)
|
|
260
|
+
} catch (err) {
|
|
261
|
+
console.error('Server error:', err)
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## JJS Encoding
|
|
268
|
+
|
|
269
|
+
api-ape uses **JJS (JSON SuperSet)** encoding, which extends JSON to support:
|
|
270
|
+
|
|
271
|
+
| Type | Supported |
|
|
272
|
+
|------|-----------|
|
|
273
|
+
| `Date` | ✅ Preserved as Date objects |
|
|
274
|
+
| `RegExp` | ✅ Preserved as RegExp |
|
|
275
|
+
| `Error` | ✅ Preserved with name, message, stack |
|
|
276
|
+
| `undefined` | ✅ Preserved (not converted to null) |
|
|
277
|
+
| `Set` | ✅ Preserved as Set |
|
|
278
|
+
| `Map` | ✅ Preserved as Map |
|
|
279
|
+
| Circular refs | ✅ Handled via pointers |
|
|
280
|
+
|
|
281
|
+
This is automatic — send a Date, receive a Date. No configuration needed.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Examples & Demos
|
|
286
|
+
|
|
287
|
+
The repository contains working examples:
|
|
288
|
+
|
|
289
|
+
* **`example/ExpressJs/`** — Simple real-time chat app
|
|
290
|
+
- Minimal setup with Express.js
|
|
291
|
+
- Broadcast messages to other clients
|
|
292
|
+
- Message history
|
|
293
|
+
|
|
294
|
+
* **`example/NextJs/`** — Production-ready chat application
|
|
295
|
+
- Custom Next.js server integration
|
|
296
|
+
- React hooks integration
|
|
297
|
+
- User presence tracking
|
|
298
|
+
- Docker support
|
|
299
|
+
- Connection lifecycle hooks
|
|
300
|
+
|
|
301
|
+
### Run an Example
|
|
302
|
+
|
|
303
|
+
**ExpressJs:**
|
|
304
|
+
```bash
|
|
305
|
+
cd example/ExpressJs
|
|
306
|
+
npm install
|
|
307
|
+
npm start
|
|
308
|
+
# Open http://localhost:3000
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**NextJs:**
|
|
312
|
+
```bash
|
|
313
|
+
cd example/NextJs
|
|
314
|
+
npm install
|
|
315
|
+
npm run dev
|
|
316
|
+
# Open http://localhost:3000
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Or with Docker:
|
|
320
|
+
```bash
|
|
321
|
+
cd example/NextJs
|
|
322
|
+
docker-compose up --build
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Troubleshooting & FAQ
|
|
328
|
+
|
|
329
|
+
### CORS Errors in Browser
|
|
330
|
+
|
|
331
|
+
Ensure your Express server allows WebSocket connections from your origin. api-ape uses `express-ws` which handles CORS automatically, but verify your Express CORS middleware allows WebSocket upgrade requests.
|
|
332
|
+
|
|
333
|
+
### Controller Not Found
|
|
334
|
+
|
|
335
|
+
* Check that your controller file is in the `where` directory (default: `api/`)
|
|
336
|
+
* Ensure the file exports a function: `module.exports = function(...) { ... }`
|
|
337
|
+
* File paths map directly: `api/users/list.js` → `ape.users.list()`
|
|
338
|
+
|
|
339
|
+
### Connection Drops Frequently
|
|
340
|
+
|
|
341
|
+
The client automatically reconnects with exponential backoff. If connections drop often:
|
|
342
|
+
* Check server WebSocket timeout settings
|
|
343
|
+
* Verify network stability
|
|
344
|
+
* Check server logs for errors
|
|
345
|
+
|
|
346
|
+
### Binary Data / File Uploads
|
|
347
|
+
|
|
348
|
+
JJS encoding supports complex types, but for large binary data, consider:
|
|
349
|
+
* Sending file URLs instead of raw data
|
|
350
|
+
* Using a separate file upload endpoint
|
|
351
|
+
* Chunking large payloads
|
|
352
|
+
|
|
353
|
+
### TypeScript Support
|
|
354
|
+
|
|
355
|
+
Type definitions are included (`index.d.ts`). For full type safety, you may need to:
|
|
356
|
+
* Define interfaces for your controller parameters and return types
|
|
357
|
+
* Use type assertions when calling `ape.<path>.<method>()`
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Tests & CI
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
npm test # Run test suite
|
|
365
|
+
npm run test:watch # Watch mode
|
|
366
|
+
npm run test:cover # Coverage report
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Test Commands:**
|
|
370
|
+
- `npm test` — Run all tests
|
|
371
|
+
- `npm run test:watch` — Watch mode for development
|
|
372
|
+
- `npm run test:cover` — Generate coverage report
|
|
373
|
+
- `npm run test:update` — Update snapshots
|
|
374
|
+
|
|
375
|
+
**Supported:** Node.js 14+, modern browsers (Chrome, Firefox, Safari, Edge)
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Contributing
|
|
380
|
+
|
|
381
|
+
Contributions welcome! Here's how to help:
|
|
382
|
+
|
|
383
|
+
1. **Fork the repository**
|
|
384
|
+
2. **Create a branch:** `git checkout -b feature/your-feature-name`
|
|
385
|
+
3. **Make your changes** and add tests
|
|
386
|
+
4. **Run tests:** `npm test`
|
|
387
|
+
5. **Commit:** Follow conventional commit messages
|
|
388
|
+
6. **Push and open a PR** with a clear description
|
|
389
|
+
|
|
390
|
+
**Guidelines:**
|
|
391
|
+
* Add tests for new features
|
|
392
|
+
* Keep code style consistent
|
|
393
|
+
* Update documentation if needed
|
|
394
|
+
* Ensure all tests pass
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Releases / Changelog
|
|
399
|
+
|
|
400
|
+
Versioning follows [Semantic Versioning](https://semver.org/).
|
|
401
|
+
|
|
402
|
+
**Current version:** See `package.json` or npm registry
|
|
403
|
+
|
|
404
|
+
**Release notes:** Check [GitHub releases](https://github.com/codemeasandwich/api-ape/releases) for detailed changelog.
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Security
|
|
409
|
+
|
|
410
|
+
**Reporting vulnerabilities:** Please report security issues via [GitHub Security Advisories](https://github.com/codemeasandwich/api-ape/security/advisories) or email the maintainer.
|
|
411
|
+
|
|
412
|
+
**Security considerations:**
|
|
413
|
+
* Validate all input in controllers
|
|
414
|
+
* Use authentication/authorization in `onConnent` hooks
|
|
415
|
+
* Sanitize data before broadcasting
|
|
416
|
+
* Keep dependencies up to date
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Project Structure
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
api-ape/
|
|
424
|
+
├── client/
|
|
425
|
+
│ ├── browser.js # Browser entry point (window.ape)
|
|
426
|
+
│ └── connectSocket.js # WebSocket client with auto-reconnect
|
|
427
|
+
├── server/
|
|
428
|
+
│ ├── lib/
|
|
429
|
+
│ │ ├── main.js # Express integration
|
|
430
|
+
│ │ ├── loader.js # Auto-loads controller files
|
|
431
|
+
│ │ ├── broadcast.js # Client tracking & broadcast
|
|
432
|
+
│ │ └── wiring.js # WebSocket handler setup
|
|
433
|
+
│ ├── socket/
|
|
434
|
+
│ │ ├── receive.js # Incoming message handler
|
|
435
|
+
│ │ └── send.js # Outgoing message handler
|
|
436
|
+
│ └── security/
|
|
437
|
+
│ └── reply.js # Duplicate request protection
|
|
438
|
+
├── utils/
|
|
439
|
+
│ ├── jss.js # JSON SuperSet encoder/decoder
|
|
440
|
+
│ └── messageHash.js # Request deduplication
|
|
441
|
+
└── example/
|
|
442
|
+
├── ExpressJs/ # Chat app example
|
|
443
|
+
└── NextJs/ # Next.js integration
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## License & Authors
|
|
449
|
+
|
|
450
|
+
**License:** MIT
|
|
451
|
+
|
|
452
|
+
**Author:** [Brian Shannon](https://github.com/codemeasandwich)
|
|
453
|
+
|
|
454
|
+
**Repository:** [github.com/codemeasandwich/api-ape](https://github.com/codemeasandwich/api-ape)
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
**Made with 🦍 by the api-ape community**
|
package/client/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# 🦍 api-ape Client
|
|
2
|
+
|
|
3
|
+
WebSocket client library with auto-reconnection and proxy-based API calls.
|
|
4
|
+
|
|
5
|
+
## Files
|
|
6
|
+
|
|
7
|
+
| File | Description |
|
|
8
|
+
|------|-------------|
|
|
9
|
+
| `browser.js` | Browser entry point - exposes `window.ape` |
|
|
10
|
+
| `connectSocket.js` | WebSocket client with auto-reconnect, queuing, and JJS encoding |
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### Browser (via script tag)
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<script src="/api/ape.js"></script>
|
|
18
|
+
<script>
|
|
19
|
+
// Call server functions
|
|
20
|
+
ape.hello('World').then(result => console.log(result))
|
|
21
|
+
|
|
22
|
+
// Listen for broadcasts
|
|
23
|
+
ape.on('message', ({ data }) => console.log(data))
|
|
24
|
+
</script>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### ES Module Import
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm i api-ape
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import ape from 'api-ape'
|
|
35
|
+
|
|
36
|
+
// Configure
|
|
37
|
+
ape.configure({ port: 3000 })
|
|
38
|
+
|
|
39
|
+
// Connect and enable auto-reconnect
|
|
40
|
+
const { sender, setOnReciver } = ape()
|
|
41
|
+
ape.autoReconnect()
|
|
42
|
+
|
|
43
|
+
// Use sender as API
|
|
44
|
+
sender.users.list().then(users => ...)
|
|
45
|
+
|
|
46
|
+
// Listen for broadcasts
|
|
47
|
+
setOnReciver('newUser', ({ data }) => ...)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- **Proxy-based API** — `ape.path.method(data)` converts to WebSocket calls
|
|
53
|
+
- **Auto-reconnect** — Reconnects on disconnect with queued messages
|
|
54
|
+
- **Promise-based** — All calls return promises with matched responses via queryId
|
|
55
|
+
- **JJS encoding** — Supports Date, RegExp, Error, Set, Map, undefined over the wire
|
|
56
|
+
- **Request timeout** — Configurable timeout (default: 10s)
|
|
57
|
+
|
|
58
|
+
## Configuration
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
ape.configure({
|
|
62
|
+
port: 3000, // WebSocket port
|
|
63
|
+
host: 'api.example.com' // WebSocket host
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Default port detection:
|
|
68
|
+
- Local (`localhost`, `127.0.0.1`): `9010`
|
|
69
|
+
- Remote: Uses current page port or `443`/`80`
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import connectSocket from './connectSocket.js'
|
|
2
|
+
|
|
3
|
+
// Auto-configure for current page
|
|
4
|
+
const port = window.location.port || (window.location.protocol === 'https:' ? 443 : 80)
|
|
5
|
+
connectSocket.configure({ port: parseInt(port, 10) })
|
|
6
|
+
|
|
7
|
+
const { sender, setOnReciver } = connectSocket()
|
|
8
|
+
connectSocket.autoReconnect()
|
|
9
|
+
|
|
10
|
+
// Global API - use defineProperty to bypass Proxy interception
|
|
11
|
+
window.ape = sender
|
|
12
|
+
Object.defineProperty(window.ape, 'on', {
|
|
13
|
+
value: setOnReciver,
|
|
14
|
+
writable: false,
|
|
15
|
+
enumerable: false,
|
|
16
|
+
configurable: false
|
|
17
|
+
})
|