codehooks-js 1.3.16 → 1.3.18
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 +84 -52
- package/package.json +1 -1
- package/types/index.d.ts +9 -0
package/README.md
CHANGED
|
@@ -1,98 +1,130 @@
|
|
|
1
1
|
# codehooks-js
|
|
2
2
|
|
|
3
|
-
The official JavaScript/TypeScript library for [Codehooks.io](https://codehooks.io) -
|
|
3
|
+
The official JavaScript/TypeScript library for [Codehooks.io](https://codehooks.io) - the platform for webhooks, automations, and integrations.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Why Codehooks?
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Deploy production-ready webhook endpoints in under a minute. No need to assemble API Gateway, Lambda, DynamoDB, and SQS yourself.
|
|
8
8
|
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **File Storage** - Static file serving and blob storage
|
|
14
|
-
- **Workflows** - Step-based application logic
|
|
15
|
-
|
|
16
|
-
All in one platform with zero infrastructure management.
|
|
9
|
+
- **Webhook-First Design** - Built-in `rawBody` access for HMAC signature verification
|
|
10
|
+
- **Reliable Processing** - Automatic retries via queues and workers
|
|
11
|
+
- **All-in-One Infrastructure** - Database, key-value store, queues, and workers included
|
|
12
|
+
- **Flat-Rate Pricing** - Unlimited compute, no surprise bills from webhook volume
|
|
17
13
|
|
|
18
14
|
## Quick Start
|
|
19
15
|
|
|
20
16
|
Install the [Codehooks CLI](https://codehooks.io/docs/cli):
|
|
21
17
|
|
|
22
18
|
```shell
|
|
23
|
-
|
|
19
|
+
npm install -g codehooks
|
|
24
20
|
```
|
|
25
21
|
|
|
26
|
-
|
|
22
|
+
Create a new project and install the library:
|
|
27
23
|
|
|
28
24
|
```shell
|
|
25
|
+
codehooks create myproject
|
|
26
|
+
cd myproject
|
|
29
27
|
npm install codehooks-js
|
|
30
28
|
```
|
|
31
29
|
|
|
32
|
-
##
|
|
30
|
+
## Webhook Handler Example
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
Handle incoming webhooks with signature verification and reliable background processing:
|
|
35
33
|
|
|
36
34
|
```javascript
|
|
37
|
-
/*
|
|
38
|
-
* REST API with NoSQL database storage.
|
|
39
|
-
* Codehooks (c) example code.
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
35
|
import { app, datastore } from 'codehooks-js';
|
|
36
|
+
import crypto from 'crypto';
|
|
37
|
+
|
|
38
|
+
// Webhook endpoint with HMAC signature verification
|
|
39
|
+
app.post('/webhooks/incoming', async (req, res) => {
|
|
40
|
+
const signature = req.headers['x-webhook-signature'];
|
|
41
|
+
const secret = process.env.WEBHOOK_SECRET;
|
|
42
|
+
|
|
43
|
+
// Use rawBody for signature verification (preserves exact bytes)
|
|
44
|
+
const expectedSig = crypto
|
|
45
|
+
.createHmac('sha256', secret)
|
|
46
|
+
.update(req.rawBody)
|
|
47
|
+
.digest('hex');
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
if (signature !== expectedSig) {
|
|
50
|
+
return res.status(401).json({ error: 'Invalid signature' });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Store the webhook event
|
|
47
54
|
const conn = await datastore.open();
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
const event = await conn.insertOne('webhook_events', {
|
|
56
|
+
payload: req.body,
|
|
57
|
+
received: new Date()
|
|
51
58
|
});
|
|
52
|
-
|
|
59
|
+
|
|
60
|
+
// Queue for reliable background processing
|
|
61
|
+
await conn.enqueue('processWebhook', { eventId: event._id });
|
|
62
|
+
|
|
63
|
+
res.json({ received: true });
|
|
53
64
|
});
|
|
54
65
|
|
|
55
|
-
//
|
|
56
|
-
app.
|
|
66
|
+
// Background worker with automatic retries
|
|
67
|
+
app.worker('processWebhook', async (req, res) => {
|
|
68
|
+
const { eventId } = req.body.payload;
|
|
69
|
+
const conn = await datastore.open();
|
|
70
|
+
|
|
71
|
+
const event = await conn.getOne('webhook_events', eventId);
|
|
72
|
+
console.log('Processing webhook:', event.payload);
|
|
57
73
|
|
|
58
|
-
//
|
|
59
|
-
|
|
74
|
+
// Your processing logic here
|
|
75
|
+
|
|
76
|
+
res.end();
|
|
77
|
+
});
|
|
60
78
|
|
|
61
|
-
// return app to serverless runtime engine
|
|
62
79
|
export default app.init();
|
|
63
80
|
```
|
|
64
81
|
|
|
65
|
-
## TypeScript
|
|
82
|
+
## TypeScript Support
|
|
66
83
|
|
|
67
|
-
|
|
68
|
-
Start developing using TypeScript and strong types shown in the example code below.
|
|
84
|
+
Full TypeScript support with strong types:
|
|
69
85
|
|
|
70
86
|
```typescript
|
|
71
|
-
|
|
72
|
-
* REST API with NoSQL database storage.
|
|
73
|
-
* Codehooks (c) example code in TypeScript.
|
|
74
|
-
*/
|
|
87
|
+
import { app, datastore, httpRequest, httpResponse } from 'codehooks-js';
|
|
75
88
|
|
|
76
|
-
|
|
89
|
+
app.post('/webhooks/github', async (req: httpRequest, res: httpResponse) => {
|
|
90
|
+
const event = req.headers['x-github-event'];
|
|
91
|
+
const payload = req.body;
|
|
77
92
|
|
|
78
|
-
// Example GET route and a NoSQL database insert operation
|
|
79
|
-
app.get('/myroute', async (req: httpRequest, res: httpResponse) => {
|
|
80
|
-
console.log('GET');
|
|
81
93
|
const conn = await datastore.open();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
94
|
+
await conn.insertOne('github_events', {
|
|
95
|
+
event,
|
|
96
|
+
payload,
|
|
97
|
+
timestamp: new Date()
|
|
85
98
|
});
|
|
86
|
-
|
|
99
|
+
|
|
100
|
+
res.json({ status: 'ok' });
|
|
87
101
|
});
|
|
88
102
|
|
|
89
|
-
|
|
90
|
-
|
|
103
|
+
export default app.init();
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## REST API Example
|
|
107
|
+
|
|
108
|
+
Build traditional REST APIs with the same simplicity:
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
import { app, datastore } from 'codehooks-js';
|
|
112
|
+
|
|
113
|
+
app.get('/api/users/:id', async (req, res) => {
|
|
114
|
+
const conn = await datastore.open();
|
|
115
|
+
const user = await conn.getOne('users', req.params.id);
|
|
116
|
+
res.json(user);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
app.post('/api/users', async (req, res) => {
|
|
120
|
+
const conn = await datastore.open();
|
|
121
|
+
const user = await conn.insertOne('users', req.body);
|
|
122
|
+
res.status(201).json(user);
|
|
123
|
+
});
|
|
91
124
|
|
|
92
|
-
// CRUD
|
|
93
|
-
app.crudlify(
|
|
125
|
+
// Auto-generate CRUD endpoints for any collection
|
|
126
|
+
app.crudlify();
|
|
94
127
|
|
|
95
|
-
// return app to serverless runtime engine
|
|
96
128
|
export default app.init();
|
|
97
129
|
```
|
|
98
130
|
|
package/package.json
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -513,6 +513,10 @@ export type httpRequest = {
|
|
|
513
513
|
* - JSON payload
|
|
514
514
|
*/
|
|
515
515
|
body: any;
|
|
516
|
+
/**
|
|
517
|
+
* - Get the raw unparsed request body as a string
|
|
518
|
+
*/
|
|
519
|
+
rawBody: string;
|
|
516
520
|
/**
|
|
517
521
|
* - Get the URL full path, e.g. /dev/myroute
|
|
518
522
|
*/
|
|
@@ -622,6 +626,11 @@ export type httpResponse = {
|
|
|
622
626
|
|
|
623
627
|
export type nextFunction = (error?: string) => void;
|
|
624
628
|
|
|
629
|
+
// Aliases for developers familiar with Express.js conventions
|
|
630
|
+
export type Request = httpRequest;
|
|
631
|
+
export type Response = httpResponse;
|
|
632
|
+
export type NextFunction = nextFunction;
|
|
633
|
+
|
|
625
634
|
export type Filesystem = {
|
|
626
635
|
/**
|
|
627
636
|
* - Get binary file input stream. Takes a path (string) to file (e.g. /static/logo.png) and an options object (Object) for future use. Returns a Promise resolving to a binary data stream emitter.
|