api-ape 1.0.1 → 1.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 +314 -83
- package/client/README.md +32 -0
- package/client/connectSocket.js +288 -5
- package/dist/ape.js +289 -44
- package/example/NextJs/pages/Info.tsx +153 -0
- package/example/NextJs/pages/index.tsx +121 -39
- package/example/NextJs/styles/Chat.module.css +255 -1
- package/package.json +2 -2
- package/server/README.md +44 -0
- package/server/lib/fileTransfer.js +247 -0
- package/server/lib/main.js +70 -2
- package/server/lib/wiring.js +4 -2
- package/server/socket/receive.js +118 -3
- package/server/socket/send.js +97 -2
package/README.md
CHANGED
|
@@ -1,53 +1,25 @@
|
|
|
1
1
|
# 🦍 api-ape
|
|
2
2
|
|
|
3
|
-
|
|
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)
|
|
4
6
|
|
|
5
|
-
Call server functions from the browser like local methods. Get real-time broadcasts with zero setup.
|
|
6
|
-
|
|
7
|
-
```js
|
|
8
|
-
// Client: call server function, get result
|
|
9
|
-
const pets = await ape.pets.list()
|
|
10
|
-
|
|
11
|
-
// Client: listen for broadcasts
|
|
12
|
-
ape.on('newPet', ({ data }) => console.log('New pet:', data))
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
file: api/pets/list.js
|
|
16
|
-
```js
|
|
17
|
-
// Server: define function, broadcast to others
|
|
18
|
-
module.exports = function list() {
|
|
19
|
-
return getPetList()
|
|
20
|
-
}
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
file: api/pets/newPet.js
|
|
24
|
-
```js
|
|
25
|
-
// Server: define function, broadcast to others
|
|
26
|
-
module.exports = function newPet(data) {
|
|
27
|
-
// broadcast to all other clients
|
|
28
|
-
this.broadcastOthers('newPet', data)
|
|
29
|
-
return savePet(data)
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## Features
|
|
36
|
-
|
|
37
|
-
- **🔌 Auto-wiring** — Drop JS files in a folder, they become API endpoints
|
|
38
|
-
- **📡 Real-time** — Built-in broadcast to all or other clients
|
|
39
|
-
- **🔄 Reconnection** — Client auto-reconnects on disconnect
|
|
40
|
-
- **📦 JJS Encoding** — Supports Date, RegExp, Error, Set, Map, undefined over the wire
|
|
41
|
-
- **🎯 Simple API** — Promise-based calls with chainable paths
|
|
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.
|
|
42
8
|
|
|
43
9
|
---
|
|
44
10
|
|
|
45
|
-
##
|
|
11
|
+
## Install
|
|
46
12
|
|
|
47
13
|
```bash
|
|
48
14
|
npm install api-ape
|
|
15
|
+
# or
|
|
16
|
+
pnpm add api-ape
|
|
17
|
+
# or
|
|
18
|
+
yarn add api-ape
|
|
49
19
|
```
|
|
50
20
|
|
|
21
|
+
**Requirements:** Node.js 14+ (for server), modern browsers (for client)
|
|
22
|
+
|
|
51
23
|
---
|
|
52
24
|
|
|
53
25
|
## Quick Start
|
|
@@ -66,9 +38,9 @@ ape(app, { where: 'api' })
|
|
|
66
38
|
app.listen(3000)
|
|
67
39
|
```
|
|
68
40
|
|
|
69
|
-
###
|
|
41
|
+
### Create a Controller
|
|
70
42
|
|
|
71
|
-
|
|
43
|
+
Drop a file in your `api/` folder — it automatically becomes an endpoint:
|
|
72
44
|
|
|
73
45
|
```js
|
|
74
46
|
// api/hello.js
|
|
@@ -77,24 +49,16 @@ module.exports = function(name) {
|
|
|
77
49
|
}
|
|
78
50
|
```
|
|
79
51
|
|
|
80
|
-
```js
|
|
81
|
-
// api/message.js
|
|
82
|
-
module.exports = function(data) {
|
|
83
|
-
// Broadcast to all OTHER connected clients
|
|
84
|
-
this.broadcastOthers('message', data)
|
|
85
|
-
return data
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
52
|
### Client (Browser)
|
|
90
53
|
|
|
91
|
-
Include the bundled client:
|
|
54
|
+
Include the bundled client and start calling:
|
|
92
55
|
|
|
93
56
|
```html
|
|
94
57
|
<script src="/api/ape.js"></script>
|
|
95
58
|
<script>
|
|
96
|
-
// Call server functions
|
|
97
|
-
ape.hello('World')
|
|
59
|
+
// Call server functions like local methods
|
|
60
|
+
const result = await ape.hello('World')
|
|
61
|
+
console.log(result) // "Hello, World!"
|
|
98
62
|
|
|
99
63
|
// Listen for broadcasts
|
|
100
64
|
ape.on('message', ({ data }) => {
|
|
@@ -103,6 +67,19 @@ Include the bundled client:
|
|
|
103
67
|
</script>
|
|
104
68
|
```
|
|
105
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
|
+
|
|
106
83
|
---
|
|
107
84
|
|
|
108
85
|
## API Reference
|
|
@@ -115,8 +92,8 @@ Initialize api-ape on an Express app.
|
|
|
115
92
|
|
|
116
93
|
| Option | Type | Description |
|
|
117
94
|
|--------|------|-------------|
|
|
118
|
-
| `where` | `string` | Directory containing controller files |
|
|
119
|
-
| `onConnent` | `function` | Connection lifecycle hook (see
|
|
95
|
+
| `where` | `string` | Directory containing controller files (default: `'api'`) |
|
|
96
|
+
| `onConnent` | `function` | Connection lifecycle hook (see [Connection Lifecycle](#connection-lifecycle)) |
|
|
120
97
|
|
|
121
98
|
#### Controller Context (`this`)
|
|
122
99
|
|
|
@@ -124,8 +101,8 @@ Inside controller functions, `this` provides:
|
|
|
124
101
|
|
|
125
102
|
| Property | Description |
|
|
126
103
|
|----------|-------------|
|
|
127
|
-
| `this.broadcast(type, data)` | Send to ALL connected clients |
|
|
128
|
-
| `this.broadcastOthers(type, data)` | Send to all EXCEPT the caller |
|
|
104
|
+
| `this.broadcast(type, data)` | Send to **ALL** connected clients |
|
|
105
|
+
| `this.broadcastOthers(type, data)` | Send to all **EXCEPT** the caller |
|
|
129
106
|
| `this.online()` | Get count of connected clients |
|
|
130
107
|
| `this.getClients()` | Get array of connected hostIds |
|
|
131
108
|
| `this.hostId` | Unique ID of the calling client |
|
|
@@ -133,17 +110,61 @@ Inside controller functions, `this` provides:
|
|
|
133
110
|
| `this.socket` | WebSocket instance |
|
|
134
111
|
| `this.agent` | Parsed user-agent (browser, OS, device) |
|
|
135
112
|
|
|
136
|
-
|
|
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:
|
|
137
158
|
|
|
138
159
|
```js
|
|
139
160
|
ape(app, {
|
|
140
161
|
where: 'api',
|
|
141
|
-
onConnent(socket, req,
|
|
162
|
+
onConnent(socket, req, hostId) {
|
|
142
163
|
return {
|
|
143
164
|
// Embed values into `this` for all controllers
|
|
144
165
|
embed: {
|
|
145
166
|
userId: req.session?.userId,
|
|
146
|
-
clientId:
|
|
167
|
+
clientId: String(hostId)
|
|
147
168
|
},
|
|
148
169
|
|
|
149
170
|
// Before/after hooks
|
|
@@ -164,31 +185,81 @@ ape(app, {
|
|
|
164
185
|
})
|
|
165
186
|
```
|
|
166
187
|
|
|
167
|
-
|
|
188
|
+
---
|
|
168
189
|
|
|
169
|
-
|
|
190
|
+
## Common Recipes
|
|
170
191
|
|
|
171
|
-
|
|
192
|
+
### Broadcast to Other Clients
|
|
172
193
|
|
|
173
194
|
```js
|
|
174
|
-
//
|
|
175
|
-
|
|
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
|
+
```
|
|
176
202
|
|
|
177
|
-
|
|
178
|
-
ape.users.create({ name: 'Alice' }).then(user => ...)
|
|
203
|
+
### Broadcast to All Clients
|
|
179
204
|
|
|
180
|
-
|
|
181
|
-
|
|
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
|
+
}
|
|
182
212
|
```
|
|
183
213
|
|
|
184
|
-
|
|
214
|
+
### Get Online Count
|
|
185
215
|
|
|
186
|
-
|
|
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
|
|
187
227
|
|
|
188
228
|
```js
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
+
}
|
|
192
263
|
```
|
|
193
264
|
|
|
194
265
|
---
|
|
@@ -207,25 +278,177 @@ api-ape uses **JJS (JSON SuperSet)** encoding, which extends JSON to support:
|
|
|
207
278
|
| `Map` | ✅ Preserved as Map |
|
|
208
279
|
| Circular refs | ✅ Handled via pointers |
|
|
209
280
|
|
|
210
|
-
This is automatic — send a Date, receive a Date.
|
|
281
|
+
This is automatic — send a Date, receive a Date. No configuration needed.
|
|
211
282
|
|
|
212
283
|
---
|
|
213
284
|
|
|
214
|
-
## Examples
|
|
285
|
+
## Examples & Demos
|
|
286
|
+
|
|
287
|
+
The repository contains working examples:
|
|
215
288
|
|
|
216
|
-
|
|
289
|
+
* **`example/ExpressJs/`** — Simple real-time chat app
|
|
290
|
+
- Minimal setup with Express.js
|
|
291
|
+
- Broadcast messages to other clients
|
|
292
|
+
- Message history
|
|
217
293
|
|
|
218
|
-
|
|
219
|
-
-
|
|
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
|
|
220
300
|
|
|
221
|
-
Run
|
|
301
|
+
### Run an Example
|
|
222
302
|
|
|
303
|
+
**ExpressJs:**
|
|
223
304
|
```bash
|
|
224
305
|
cd example/ExpressJs
|
|
225
306
|
npm install
|
|
226
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 Transfers
|
|
347
|
+
|
|
348
|
+
api-ape supports transparent binary file transfers. Simply return `Buffer` data from controllers:
|
|
349
|
+
|
|
350
|
+
```js
|
|
351
|
+
// api/files/download.js
|
|
352
|
+
module.exports = function(filename) {
|
|
353
|
+
return {
|
|
354
|
+
name: filename,
|
|
355
|
+
data: fs.readFileSync(`./uploads/${filename}`) // Buffer
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
The client receives `ArrayBuffer` automatically:
|
|
361
|
+
|
|
362
|
+
```js
|
|
363
|
+
const result = await ape.files.download('image.png')
|
|
364
|
+
console.log(result.data) // ArrayBuffer
|
|
365
|
+
|
|
366
|
+
// Display as image
|
|
367
|
+
const blob = new Blob([result.data])
|
|
368
|
+
img.src = URL.createObjectURL(blob)
|
|
227
369
|
```
|
|
228
370
|
|
|
371
|
+
**Uploads work the same way:**
|
|
372
|
+
|
|
373
|
+
```js
|
|
374
|
+
// Client
|
|
375
|
+
const arrayBuffer = await file.arrayBuffer()
|
|
376
|
+
await ape.files.upload({ name: file.name, data: arrayBuffer })
|
|
377
|
+
|
|
378
|
+
// Server (api/files/upload.js)
|
|
379
|
+
module.exports = function({ name, data }) {
|
|
380
|
+
fs.writeFileSync(`./uploads/${name}`, data) // data is Buffer
|
|
381
|
+
return { success: true }
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Binary data is transferred via temporary HTTP endpoints (`/api/ape/data/:hash`) with session verification and auto-cleanup.
|
|
386
|
+
|
|
387
|
+
### TypeScript Support
|
|
388
|
+
|
|
389
|
+
Type definitions are included (`index.d.ts`). For full type safety, you may need to:
|
|
390
|
+
* Define interfaces for your controller parameters and return types
|
|
391
|
+
* Use type assertions when calling `ape.<path>.<method>()`
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Tests & CI
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
npm test # Run test suite
|
|
399
|
+
npm run test:watch # Watch mode
|
|
400
|
+
npm run test:cover # Coverage report
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Test Commands:**
|
|
404
|
+
- `npm test` — Run all tests
|
|
405
|
+
- `npm run test:watch` — Watch mode for development
|
|
406
|
+
- `npm run test:cover` — Generate coverage report
|
|
407
|
+
- `npm run test:update` — Update snapshots
|
|
408
|
+
|
|
409
|
+
**Supported:** Node.js 14+, modern browsers (Chrome, Firefox, Safari, Edge)
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Contributing
|
|
414
|
+
|
|
415
|
+
Contributions welcome! Here's how to help:
|
|
416
|
+
|
|
417
|
+
1. **Fork the repository**
|
|
418
|
+
2. **Create a branch:** `git checkout -b feature/your-feature-name`
|
|
419
|
+
3. **Make your changes** and add tests
|
|
420
|
+
4. **Run tests:** `npm test`
|
|
421
|
+
5. **Commit:** Follow conventional commit messages
|
|
422
|
+
6. **Push and open a PR** with a clear description
|
|
423
|
+
|
|
424
|
+
**Guidelines:**
|
|
425
|
+
* Add tests for new features
|
|
426
|
+
* Keep code style consistent
|
|
427
|
+
* Update documentation if needed
|
|
428
|
+
* Ensure all tests pass
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Releases / Changelog
|
|
433
|
+
|
|
434
|
+
Versioning follows [Semantic Versioning](https://semver.org/).
|
|
435
|
+
|
|
436
|
+
**Current version:** See `package.json` or npm registry
|
|
437
|
+
|
|
438
|
+
**Release notes:** Check [GitHub releases](https://github.com/codemeasandwich/api-ape/releases) for detailed changelog.
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Security
|
|
443
|
+
|
|
444
|
+
**Reporting vulnerabilities:** Please report security issues via [GitHub Security Advisories](https://github.com/codemeasandwich/api-ape/security/advisories) or email the maintainer.
|
|
445
|
+
|
|
446
|
+
**Security considerations:**
|
|
447
|
+
* Validate all input in controllers
|
|
448
|
+
* Use authentication/authorization in `onConnent` hooks
|
|
449
|
+
* Sanitize data before broadcasting
|
|
450
|
+
* Keep dependencies up to date
|
|
451
|
+
|
|
229
452
|
---
|
|
230
453
|
|
|
231
454
|
## Project Structure
|
|
@@ -245,7 +468,7 @@ api-ape/
|
|
|
245
468
|
│ │ ├── receive.js # Incoming message handler
|
|
246
469
|
│ │ └── send.js # Outgoing message handler
|
|
247
470
|
│ └── security/
|
|
248
|
-
│ └── reply.js
|
|
471
|
+
│ └── reply.js # Duplicate request protection
|
|
249
472
|
├── utils/
|
|
250
473
|
│ ├── jss.js # JSON SuperSet encoder/decoder
|
|
251
474
|
│ └── messageHash.js # Request deduplication
|
|
@@ -256,6 +479,14 @@ api-ape/
|
|
|
256
479
|
|
|
257
480
|
---
|
|
258
481
|
|
|
259
|
-
## License
|
|
482
|
+
## License & Authors
|
|
483
|
+
|
|
484
|
+
**License:** MIT
|
|
485
|
+
|
|
486
|
+
**Author:** [Brian Shannon](https://github.com/codemeasandwich)
|
|
487
|
+
|
|
488
|
+
**Repository:** [github.com/codemeasandwich/api-ape](https://github.com/codemeasandwich/api-ape)
|
|
489
|
+
|
|
490
|
+
---
|
|
260
491
|
|
|
261
|
-
|
|
492
|
+
**Made with 🦍 by the api-ape community**
|
package/client/README.md
CHANGED
|
@@ -67,3 +67,35 @@ ape.configure({
|
|
|
67
67
|
Default port detection:
|
|
68
68
|
- Local (`localhost`, `127.0.0.1`): `9010`
|
|
69
69
|
- Remote: Uses current page port or `443`/`80`
|
|
70
|
+
|
|
71
|
+
## File Transfers
|
|
72
|
+
|
|
73
|
+
Binary data is automatically handled. The client fetches binary resources and uploads binary data transparently.
|
|
74
|
+
|
|
75
|
+
### Receiving Binary Data
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
// Server returns Buffer, client receives ArrayBuffer
|
|
79
|
+
const result = await ape.files.download('image.png')
|
|
80
|
+
console.log(result.data) // ArrayBuffer
|
|
81
|
+
|
|
82
|
+
// Display as image
|
|
83
|
+
const blob = new Blob([result.data])
|
|
84
|
+
img.src = URL.createObjectURL(blob)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Uploading Binary Data
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
const file = input.files[0]
|
|
91
|
+
const arrayBuffer = await file.arrayBuffer()
|
|
92
|
+
|
|
93
|
+
// Binary data is uploaded automatically
|
|
94
|
+
await ape.files.upload({
|
|
95
|
+
name: file.name,
|
|
96
|
+
data: arrayBuffer // Sent via HTTP PUT
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Binary transfers use `/api/ape/data/:hash` endpoints with session verification.
|
|
101
|
+
|