@bundleup/sdk 0.0.18 â 0.2.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/LICENSE +21 -0
- package/README.md +898 -148
- package/dist/index.d.mts +221 -105
- package/dist/index.d.ts +221 -105
- package/dist/index.js +346 -238
- package/dist/index.mjs +346 -238
- package/package.json +31 -10
- package/dist/chunk-B6T6V2FR.mjs +0 -24
- package/dist/chunk-GKEHPYLJ.mjs +0 -17
- package/dist/chunk-U6VVRHFA.mjs +0 -17
- package/dist/client.d.mts +0 -8
- package/dist/client.d.ts +0 -8
- package/dist/client.js +0 -119
- package/dist/client.mjs +0 -84
- package/dist/server.d.mts +0 -21
- package/dist/server.d.ts +0 -21
- package/dist/server.js +0 -94
- package/dist/server.mjs +0 -61
- package/dist/utils.d.mts +0 -5
- package/dist/utils.d.ts +0 -5
- package/dist/utils.js +0 -50
- package/dist/utils.mjs +0 -10
package/README.md
CHANGED
|
@@ -3,21 +3,45 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@bundleup/sdk)
|
|
4
4
|
[](https://opensource.org/licenses/ISC)
|
|
5
5
|
|
|
6
|
-
Official JavaScript/TypeScript SDK for the [BundleUp](https://bundleup.io) API. Connect to 100+ integrations with a single, unified API.
|
|
6
|
+
Official JavaScript/TypeScript SDK for the [BundleUp](https://bundleup.io) API. Connect to 100+ integrations with a single, unified API. Build once, integrate everywhere.
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [Requirements](#requirements)
|
|
12
|
+
- [Features](#features)
|
|
13
|
+
- [Quick Start](#quick-start)
|
|
14
|
+
- [Authentication](#authentication)
|
|
15
|
+
- [Core Concepts](#core-concepts)
|
|
16
|
+
- [API Reference](#api-reference)
|
|
17
|
+
- [Connections](#connections)
|
|
18
|
+
- [Integrations](#integrations)
|
|
19
|
+
- [Webhooks](#webhooks)
|
|
20
|
+
- [Proxy API](#proxy-api)
|
|
21
|
+
- [Unify API](#unify-api)
|
|
22
|
+
- [Error Handling](#error-handling)
|
|
23
|
+
- [Development](#development)
|
|
24
|
+
- [Contributing](#contributing)
|
|
25
|
+
- [License](#license)
|
|
26
|
+
- [Support](#support)
|
|
7
27
|
|
|
8
28
|
## Installation
|
|
9
29
|
|
|
30
|
+
Install the SDK using your preferred package manager:
|
|
31
|
+
|
|
32
|
+
**npm:**
|
|
33
|
+
|
|
10
34
|
```bash
|
|
11
35
|
npm install @bundleup/sdk
|
|
12
36
|
```
|
|
13
37
|
|
|
14
|
-
|
|
38
|
+
**yarn:**
|
|
15
39
|
|
|
16
40
|
```bash
|
|
17
41
|
yarn add @bundleup/sdk
|
|
18
42
|
```
|
|
19
43
|
|
|
20
|
-
|
|
44
|
+
**pnpm:**
|
|
21
45
|
|
|
22
46
|
```bash
|
|
23
47
|
pnpm add @bundleup/sdk
|
|
@@ -25,34 +49,76 @@ pnpm add @bundleup/sdk
|
|
|
25
49
|
|
|
26
50
|
## Requirements
|
|
27
51
|
|
|
28
|
-
- Node.js 16 or higher
|
|
29
|
-
- TypeScript 5.0+ (for TypeScript projects)
|
|
52
|
+
- **Node.js**: 16.0.0 or higher
|
|
53
|
+
- **TypeScript**: 5.0+ (for TypeScript projects)
|
|
54
|
+
- **Fetch API**: Native fetch support (Node.js 18+) or polyfill for older versions
|
|
55
|
+
|
|
56
|
+
### Node.js Compatibility
|
|
57
|
+
|
|
58
|
+
For Node.js versions below 18, you'll need to install a fetch polyfill:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install node-fetch
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Then import it before using the SDK:
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
import fetch from 'node-fetch';
|
|
68
|
+
globalThis.fetch = fetch;
|
|
69
|
+
```
|
|
30
70
|
|
|
31
71
|
## Features
|
|
32
72
|
|
|
33
|
-
- **TypeScript First** - Built with TypeScript, includes
|
|
34
|
-
- **Modern JavaScript** - ESM and CommonJS support for maximum compatibility
|
|
35
|
-
- **Promise-based API** -
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
73
|
+
- ð **TypeScript First** - Built with TypeScript, includes comprehensive type definitions
|
|
74
|
+
- ðĶ **Modern JavaScript** - ESM and CommonJS support for maximum compatibility
|
|
75
|
+
- ⥠**Promise-based API** - Async/await support using native fetch
|
|
76
|
+
- ð **100+ Integrations** - Connect to Slack, GitHub, Jira, Linear, and many more
|
|
77
|
+
- ðŊ **Unified API** - Consistent interface across all integrations via Unify API
|
|
78
|
+
- ð **Proxy API** - Direct access to underlying integration APIs
|
|
79
|
+
- ðŠķ **Lightweight** - Zero dependencies beyond native fetch API
|
|
80
|
+
- ðĄïļ **Error Handling** - Comprehensive error messages and validation
|
|
81
|
+
- ð **Well Documented** - Extensive documentation and examples
|
|
38
82
|
|
|
39
83
|
## Quick Start
|
|
40
84
|
|
|
85
|
+
Get started with BundleUp in just a few lines of code:
|
|
86
|
+
|
|
41
87
|
```javascript
|
|
42
88
|
import { BundleUp } from '@bundleup/sdk';
|
|
43
89
|
|
|
44
|
-
// Initialize the client
|
|
90
|
+
// Initialize the client
|
|
45
91
|
const client = new BundleUp(process.env.BUNDLEUP_API_KEY);
|
|
46
92
|
|
|
47
|
-
// List all connections
|
|
93
|
+
// List all active connections
|
|
48
94
|
const connections = await client.connections.list();
|
|
49
|
-
console.log(connections);
|
|
95
|
+
console.log(`You have ${connections.length} active connections`);
|
|
96
|
+
|
|
97
|
+
// Use the Proxy API to make requests to integrated services
|
|
98
|
+
const proxy = client.proxy('conn_123');
|
|
99
|
+
const response = await proxy.get('/api/users');
|
|
100
|
+
const users = await response.json();
|
|
101
|
+
console.log('Users:', users);
|
|
102
|
+
|
|
103
|
+
// Use the Unify API for standardized data across integrations
|
|
104
|
+
const unify = client.unify('conn_456');
|
|
105
|
+
const channels = await unify.chat.channels({ limit: 10 });
|
|
106
|
+
console.log('Chat channels:', channels.data);
|
|
50
107
|
```
|
|
51
108
|
|
|
52
109
|
## Authentication
|
|
53
110
|
|
|
54
111
|
The BundleUp SDK uses API keys for authentication. You can obtain your API key from the [BundleUp Dashboard](https://app.bundleup.io).
|
|
55
112
|
|
|
113
|
+
### Getting Your API Key
|
|
114
|
+
|
|
115
|
+
1. Sign in to your [BundleUp Dashboard](https://app.bundleup.io)
|
|
116
|
+
2. Navigate to **API Keys**
|
|
117
|
+
3. Click **Create API Key**
|
|
118
|
+
4. Copy your API key and store it securely
|
|
119
|
+
|
|
120
|
+
### Initializing the SDK
|
|
121
|
+
|
|
56
122
|
```javascript
|
|
57
123
|
import { BundleUp } from '@bundleup/sdk';
|
|
58
124
|
|
|
@@ -63,273 +129,957 @@ const client = new BundleUp('your_api_key_here');
|
|
|
63
129
|
const client = new BundleUp(process.env.BUNDLEUP_API_KEY);
|
|
64
130
|
```
|
|
65
131
|
|
|
66
|
-
|
|
132
|
+
### Security Best Practices
|
|
133
|
+
|
|
134
|
+
- â
**DO** store API keys in environment variables
|
|
135
|
+
- â
**DO** use a secrets management service in production
|
|
136
|
+
- â
**DO** rotate API keys regularly
|
|
137
|
+
- â **DON'T** commit API keys to version control
|
|
138
|
+
- â **DON'T** hardcode API keys in your source code
|
|
139
|
+
- â **DON'T** share API keys in public channels
|
|
140
|
+
|
|
141
|
+
**Example `.env` file:**
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
BUNDLEUP_API_KEY=bu_live_1234567890abcdefghijklmnopqrstuvwxyz
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Loading environment variables:**
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
import 'dotenv/config'; // For Node.js projects
|
|
151
|
+
import { BundleUp } from '@bundleup/sdk';
|
|
152
|
+
|
|
153
|
+
const client = new BundleUp(process.env.BUNDLEUP_API_KEY);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Core Concepts
|
|
67
157
|
|
|
68
|
-
|
|
158
|
+
### Platform API
|
|
159
|
+
|
|
160
|
+
The **Platform API** provides access to core BundleUp features like managing connections and integrations. Use this API to list, retrieve, and delete connections, as well as discover available integrations.
|
|
161
|
+
|
|
162
|
+
### Proxy API
|
|
163
|
+
|
|
164
|
+
The **Proxy API** allows you to make direct HTTP requests to the underlying integration's API through BundleUp. This is useful when you need access to integration-specific features not covered by the Unify API.
|
|
165
|
+
|
|
166
|
+
### Unify API
|
|
167
|
+
|
|
168
|
+
The **Unify API** provides a standardized, normalized interface across different integrations. For example, you can fetch chat channels from Slack, Discord, or Microsoft Teams using the same API call.
|
|
169
|
+
|
|
170
|
+
## API Reference
|
|
69
171
|
|
|
70
172
|
### Connections
|
|
71
173
|
|
|
72
|
-
Manage your integration connections
|
|
174
|
+
Manage your integration connections.
|
|
175
|
+
|
|
176
|
+
#### List Connections
|
|
177
|
+
|
|
178
|
+
Retrieve a list of all connections in your account.
|
|
73
179
|
|
|
74
180
|
```javascript
|
|
75
|
-
// List all connections
|
|
76
181
|
const connections = await client.connections.list();
|
|
182
|
+
```
|
|
77
183
|
|
|
78
|
-
|
|
79
|
-
const connections = await client.connections.list({ status: 'active', limit: '10' });
|
|
184
|
+
**With query parameters:**
|
|
80
185
|
|
|
81
|
-
|
|
82
|
-
const
|
|
186
|
+
```javascript
|
|
187
|
+
const connections = await client.connections.list({
|
|
188
|
+
integration_id: 'int_slack',
|
|
189
|
+
limit: 50,
|
|
190
|
+
offset: 0,
|
|
191
|
+
external_id: 'user_123',
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Query Parameters:**
|
|
196
|
+
|
|
197
|
+
- `integration_id` (string): Filter by integration ID
|
|
198
|
+
- `integration_identifier` (string): Filter by integration identifier (e.g., 'slack', 'github')
|
|
199
|
+
- `external_id` (string): Filter by external user/account ID
|
|
200
|
+
- `limit` (number): Maximum number of results (default: 50, max: 100)
|
|
201
|
+
- `offset` (number): Number of results to skip for pagination
|
|
83
202
|
|
|
84
|
-
|
|
85
|
-
|
|
203
|
+
**Response:**
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
[
|
|
207
|
+
{
|
|
208
|
+
id: 'conn_123abc',
|
|
209
|
+
externalId: 'user_456',
|
|
210
|
+
integrationId: 'int_slack',
|
|
211
|
+
isValid: true,
|
|
212
|
+
createdAt: '2024-01-15T10:30:00Z',
|
|
213
|
+
updatedAt: '2024-01-20T14:22:00Z',
|
|
214
|
+
refreshedAt: '2024-01-20T14:22:00Z',
|
|
215
|
+
expiresAt: '2024-04-20T14:22:00Z',
|
|
216
|
+
},
|
|
217
|
+
// ... more connections
|
|
218
|
+
];
|
|
86
219
|
```
|
|
87
220
|
|
|
221
|
+
#### Retrieve a Connection
|
|
222
|
+
|
|
223
|
+
Get details of a specific connection by ID.
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
const connection = await client.connections.retrieve('conn_123abc');
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Response:**
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
{
|
|
233
|
+
id: 'conn_123abc',
|
|
234
|
+
externalId: 'user_456',
|
|
235
|
+
integrationId: 'int_slack',
|
|
236
|
+
isValid: true,
|
|
237
|
+
createdAt: '2024-01-15T10:30:00Z',
|
|
238
|
+
updatedAt: '2024-01-20T14:22:00Z',
|
|
239
|
+
refreshedAt: '2024-01-20T14:22:00Z',
|
|
240
|
+
expiresAt: '2024-04-20T14:22:00Z'
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Delete a Connection
|
|
245
|
+
|
|
246
|
+
Remove a connection from your account.
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
await client.connections.del('conn_123abc');
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Note:** Deleting a connection will revoke access to the integration and cannot be undone.
|
|
253
|
+
|
|
88
254
|
### Integrations
|
|
89
255
|
|
|
90
|
-
|
|
256
|
+
Discover and work with available integrations.
|
|
257
|
+
|
|
258
|
+
#### List Integrations
|
|
259
|
+
|
|
260
|
+
Get a list of all available integrations.
|
|
91
261
|
|
|
92
262
|
```javascript
|
|
93
|
-
// List all integrations
|
|
94
263
|
const integrations = await client.integrations.list();
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**With query parameters:**
|
|
267
|
+
|
|
268
|
+
```javascript
|
|
269
|
+
const integrations = await client.integrations.list({
|
|
270
|
+
status: 'active',
|
|
271
|
+
limit: 100,
|
|
272
|
+
offset: 0,
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Query Parameters:**
|
|
277
|
+
|
|
278
|
+
- `status` (string): Filter by status ('active', 'inactive', 'beta')
|
|
279
|
+
- `limit` (number): Maximum number of results
|
|
280
|
+
- `offset` (number): Number of results to skip for pagination
|
|
281
|
+
|
|
282
|
+
**Response:**
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
[
|
|
286
|
+
{
|
|
287
|
+
id: 'int_slack',
|
|
288
|
+
identifier: 'slack',
|
|
289
|
+
name: 'Slack',
|
|
290
|
+
category: 'chat',
|
|
291
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
292
|
+
updatedAt: '2024-01-15T10:00:00Z',
|
|
293
|
+
},
|
|
294
|
+
// ... more integrations
|
|
295
|
+
];
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
#### Retrieve an Integration
|
|
95
299
|
|
|
96
|
-
|
|
97
|
-
|
|
300
|
+
Get details of a specific integration.
|
|
301
|
+
|
|
302
|
+
```javascript
|
|
303
|
+
const integration = await client.integrations.retrieve('int_slack');
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Response:**
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
{
|
|
310
|
+
id: 'int_slack',
|
|
311
|
+
identifier: 'slack',
|
|
312
|
+
name: 'Slack',
|
|
313
|
+
category: 'chat',
|
|
314
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
315
|
+
updatedAt: '2024-01-15T10:00:00Z'
|
|
316
|
+
}
|
|
98
317
|
```
|
|
99
318
|
|
|
100
319
|
### Webhooks
|
|
101
320
|
|
|
102
|
-
Manage webhook subscriptions
|
|
321
|
+
Manage webhook subscriptions for real-time event notifications.
|
|
322
|
+
|
|
323
|
+
#### List Webhooks
|
|
324
|
+
|
|
325
|
+
Get all registered webhooks.
|
|
103
326
|
|
|
104
327
|
```javascript
|
|
105
|
-
// List all webhooks
|
|
106
328
|
const webhooks = await client.webhooks.list();
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**With pagination:**
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
const webhooks = await client.webhooks.list({
|
|
335
|
+
limit: 50,
|
|
336
|
+
offset: 0,
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Response:**
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
[
|
|
344
|
+
{
|
|
345
|
+
id: 'webhook_123',
|
|
346
|
+
name: 'My Webhook',
|
|
347
|
+
url: 'https://example.com/webhook',
|
|
348
|
+
events: {
|
|
349
|
+
'connection.created': true,
|
|
350
|
+
'connection.deleted': true,
|
|
351
|
+
},
|
|
352
|
+
createdAt: '2024-01-15T10:30:00Z',
|
|
353
|
+
updatedAt: '2024-01-20T14:22:00Z',
|
|
354
|
+
lastTriggeredAt: '2024-01-20T14:22:00Z',
|
|
355
|
+
},
|
|
356
|
+
];
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
#### Create a Webhook
|
|
107
360
|
|
|
108
|
-
|
|
361
|
+
Register a new webhook endpoint.
|
|
362
|
+
|
|
363
|
+
```javascript
|
|
109
364
|
const webhook = await client.webhooks.create({
|
|
365
|
+
name: 'Connection Events Webhook',
|
|
110
366
|
url: 'https://example.com/webhook',
|
|
111
367
|
events: {
|
|
112
368
|
'connection.created': true,
|
|
113
|
-
'connection.deleted': true
|
|
114
|
-
|
|
369
|
+
'connection.deleted': true,
|
|
370
|
+
'connection.updated': true,
|
|
371
|
+
},
|
|
115
372
|
});
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
**Webhook Events:**
|
|
376
|
+
|
|
377
|
+
- `connection.created` - Triggered when a new connection is established
|
|
378
|
+
- `connection.deleted` - Triggered when a connection is removed
|
|
379
|
+
- `connection.updated` - Triggered when a connection is modified
|
|
380
|
+
|
|
381
|
+
**Request Body:**
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
{
|
|
385
|
+
name: string; // Friendly name for the webhook
|
|
386
|
+
url: string; // Your webhook endpoint URL
|
|
387
|
+
events: { // Events to subscribe to
|
|
388
|
+
[eventName: string]: boolean;
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Response:**
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
{
|
|
397
|
+
id: 'webhook_123',
|
|
398
|
+
name: 'Connection Events Webhook',
|
|
399
|
+
url: 'https://example.com/webhook',
|
|
400
|
+
events: {
|
|
401
|
+
'connection.created': true,
|
|
402
|
+
'connection.deleted': true,
|
|
403
|
+
'connection.updated': true
|
|
404
|
+
},
|
|
405
|
+
createdAt: '2024-01-15T10:30:00Z',
|
|
406
|
+
updatedAt: '2024-01-15T10:30:00Z'
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
#### Retrieve a Webhook
|
|
411
|
+
|
|
412
|
+
Get details of a specific webhook.
|
|
116
413
|
|
|
117
|
-
|
|
414
|
+
```javascript
|
|
118
415
|
const webhook = await client.webhooks.retrieve('webhook_123');
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
#### Update a Webhook
|
|
119
419
|
|
|
120
|
-
|
|
420
|
+
Modify an existing webhook.
|
|
421
|
+
|
|
422
|
+
```javascript
|
|
121
423
|
const updated = await client.webhooks.update('webhook_123', {
|
|
122
|
-
|
|
424
|
+
name: 'Updated Webhook Name',
|
|
425
|
+
url: 'https://example.com/new-webhook',
|
|
426
|
+
events: {
|
|
427
|
+
'connection.created': true,
|
|
428
|
+
'connection.deleted': false,
|
|
429
|
+
},
|
|
123
430
|
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
#### Delete a Webhook
|
|
124
434
|
|
|
125
|
-
|
|
435
|
+
Remove a webhook subscription.
|
|
436
|
+
|
|
437
|
+
```javascript
|
|
126
438
|
await client.webhooks.del('webhook_123');
|
|
127
439
|
```
|
|
128
440
|
|
|
441
|
+
#### Webhook Payload Example
|
|
442
|
+
|
|
443
|
+
When an event occurs, BundleUp sends a POST request to your webhook URL with the following payload:
|
|
444
|
+
|
|
445
|
+
```json
|
|
446
|
+
{
|
|
447
|
+
"id": "evt_1234567890",
|
|
448
|
+
"type": "connection.created",
|
|
449
|
+
"created_at": "2024-01-15T10:30:00Z",
|
|
450
|
+
"data": {
|
|
451
|
+
"id": "conn_123abc",
|
|
452
|
+
"external_id": "user_456",
|
|
453
|
+
"integration_id": "int_slack",
|
|
454
|
+
"is_valid": true,
|
|
455
|
+
"created_at": "2024-01-15T10:30:00Z"
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
#### Webhook Security
|
|
461
|
+
|
|
462
|
+
To verify webhook signatures:
|
|
463
|
+
|
|
464
|
+
```javascript
|
|
465
|
+
import crypto from 'crypto';
|
|
466
|
+
|
|
467
|
+
function verifyWebhookSignature(payload, signature, secret) {
|
|
468
|
+
const hmac = crypto.createHmac('sha256', secret);
|
|
469
|
+
hmac.update(payload);
|
|
470
|
+
const digest = hmac.digest('hex');
|
|
471
|
+
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// In your webhook handler
|
|
475
|
+
app.post('/webhook', (req, res) => {
|
|
476
|
+
const signature = req.headers['x-bundleup-signature'];
|
|
477
|
+
const payload = JSON.stringify(req.body);
|
|
478
|
+
|
|
479
|
+
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
|
|
480
|
+
return res.status(401).send('Invalid signature');
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Process the webhook
|
|
484
|
+
console.log('Webhook received:', req.body);
|
|
485
|
+
res.status(200).send('OK');
|
|
486
|
+
});
|
|
487
|
+
```
|
|
488
|
+
|
|
129
489
|
### Proxy API
|
|
130
490
|
|
|
131
|
-
Make direct
|
|
491
|
+
Make direct HTTP requests to integration APIs through BundleUp.
|
|
492
|
+
|
|
493
|
+
#### Creating a Proxy Instance
|
|
132
494
|
|
|
133
495
|
```javascript
|
|
134
|
-
|
|
135
|
-
|
|
496
|
+
const proxy = client.proxy('conn_123abc');
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
#### GET Request
|
|
136
500
|
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
const data = await
|
|
501
|
+
```javascript
|
|
502
|
+
const response = await proxy.get('/api/users');
|
|
503
|
+
const data = await response.json();
|
|
504
|
+
console.log(data);
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
**With custom headers:**
|
|
508
|
+
|
|
509
|
+
```javascript
|
|
510
|
+
const response = await proxy.get('/api/users', {
|
|
511
|
+
'X-Custom-Header': 'value',
|
|
512
|
+
Accept: 'application/json',
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
#### POST Request
|
|
517
|
+
|
|
518
|
+
```javascript
|
|
519
|
+
const response = await proxy.post(
|
|
520
|
+
'/api/users',
|
|
521
|
+
JSON.stringify({
|
|
522
|
+
name: 'John Doe',
|
|
523
|
+
email: 'john@example.com',
|
|
524
|
+
role: 'developer',
|
|
525
|
+
}),
|
|
526
|
+
);
|
|
140
527
|
|
|
141
|
-
// Make POST request
|
|
142
|
-
const response = await proxy.post('/api/users', JSON.stringify({
|
|
143
|
-
name: 'John Doe',
|
|
144
|
-
email: 'john@example.com'
|
|
145
|
-
}));
|
|
146
528
|
const newUser = await response.json();
|
|
529
|
+
console.log('Created user:', newUser);
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
**With custom headers:**
|
|
147
533
|
|
|
148
|
-
|
|
149
|
-
const response = await proxy.
|
|
150
|
-
|
|
151
|
-
|
|
534
|
+
```javascript
|
|
535
|
+
const response = await proxy.post('/api/users', JSON.stringify({ name: 'John Doe' }), {
|
|
536
|
+
'Content-Type': 'application/json',
|
|
537
|
+
'X-API-Version': '2.0',
|
|
538
|
+
});
|
|
539
|
+
```
|
|
152
540
|
|
|
153
|
-
|
|
154
|
-
const response = await proxy.patch('/api/users/123', JSON.stringify({
|
|
155
|
-
email: 'jane@example.com'
|
|
156
|
-
}));
|
|
541
|
+
#### PUT Request
|
|
157
542
|
|
|
158
|
-
|
|
159
|
-
await proxy.
|
|
543
|
+
```javascript
|
|
544
|
+
const response = await proxy.put(
|
|
545
|
+
'/api/users/123',
|
|
546
|
+
JSON.stringify({
|
|
547
|
+
name: 'Jane Doe',
|
|
548
|
+
email: 'jane@example.com',
|
|
549
|
+
}),
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
const updatedUser = await response.json();
|
|
160
553
|
```
|
|
161
554
|
|
|
162
|
-
|
|
555
|
+
#### PATCH Request
|
|
163
556
|
|
|
164
|
-
|
|
557
|
+
```javascript
|
|
558
|
+
const response = await proxy.patch(
|
|
559
|
+
'/api/users/123',
|
|
560
|
+
JSON.stringify({
|
|
561
|
+
email: 'newemail@example.com',
|
|
562
|
+
}),
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
const partiallyUpdated = await response.json();
|
|
566
|
+
```
|
|
165
567
|
|
|
166
|
-
####
|
|
568
|
+
#### DELETE Request
|
|
167
569
|
|
|
168
570
|
```javascript
|
|
169
|
-
|
|
170
|
-
const unify = client.unify('conn_123');
|
|
571
|
+
const response = await proxy.delete('/api/users/123');
|
|
171
572
|
|
|
172
|
-
|
|
173
|
-
|
|
573
|
+
if (response.ok) {
|
|
574
|
+
console.log('User deleted successfully');
|
|
575
|
+
}
|
|
576
|
+
```
|
|
174
577
|
|
|
175
|
-
|
|
176
|
-
const channels = await unify.chat.channels({
|
|
177
|
-
limit: 50,
|
|
178
|
-
after: 'cursor_token'
|
|
179
|
-
});
|
|
578
|
+
#### Working with Different Content Types
|
|
180
579
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
580
|
+
**Sending form data:**
|
|
581
|
+
|
|
582
|
+
```javascript
|
|
583
|
+
const formData = new URLSearchParams();
|
|
584
|
+
formData.append('name', 'John Doe');
|
|
585
|
+
formData.append('email', 'john@example.com');
|
|
586
|
+
|
|
587
|
+
const response = await proxy.post('/api/users', formData.toString(), {
|
|
588
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
185
589
|
});
|
|
186
590
|
```
|
|
187
591
|
|
|
188
|
-
|
|
592
|
+
**Uploading files:**
|
|
189
593
|
|
|
190
594
|
```javascript
|
|
191
|
-
|
|
595
|
+
import FormData from 'form-data';
|
|
596
|
+
import fs from 'fs';
|
|
192
597
|
|
|
193
|
-
|
|
194
|
-
|
|
598
|
+
const form = new FormData();
|
|
599
|
+
form.append('file', fs.createReadStream('document.pdf'));
|
|
600
|
+
form.append('title', 'My Document');
|
|
195
601
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
602
|
+
const response = await proxy.post('/api/documents', form, form.getHeaders());
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
#### Handling Binary Data
|
|
606
|
+
|
|
607
|
+
```javascript
|
|
608
|
+
const response = await proxy.get('/api/files/download/123');
|
|
609
|
+
const buffer = await response.arrayBuffer();
|
|
610
|
+
fs.writeFileSync('downloaded-file.pdf', Buffer.from(buffer));
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### Unify API
|
|
614
|
+
|
|
615
|
+
Access unified, normalized data across different integrations with a consistent interface.
|
|
616
|
+
|
|
617
|
+
#### Creating a Unify Instance
|
|
618
|
+
|
|
619
|
+
```javascript
|
|
620
|
+
const unify = client.unify('conn_123abc');
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
#### Chat API
|
|
624
|
+
|
|
625
|
+
The Chat API provides a unified interface for chat platforms like Slack, Discord, and Microsoft Teams.
|
|
201
626
|
|
|
202
|
-
|
|
203
|
-
const tags = await unify.git.tags({ repoName: 'owner/repo' });
|
|
627
|
+
##### List Channels
|
|
204
628
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
629
|
+
Retrieve a list of channels from the connected chat platform.
|
|
630
|
+
|
|
631
|
+
```javascript
|
|
632
|
+
const result = await unify.chat.channels({
|
|
633
|
+
limit: 100,
|
|
634
|
+
after: null,
|
|
635
|
+
include_raw: false,
|
|
209
636
|
});
|
|
210
637
|
|
|
211
|
-
|
|
212
|
-
|
|
638
|
+
console.log('Channels:', result.data);
|
|
639
|
+
console.log('Next cursor:', result.metadata.next);
|
|
213
640
|
```
|
|
214
641
|
|
|
215
|
-
|
|
642
|
+
**Parameters:**
|
|
643
|
+
|
|
644
|
+
- `limit` (number, optional): Maximum number of channels to return (default: 100, max: 1000)
|
|
645
|
+
- `after` (string, optional): Pagination cursor from previous response
|
|
646
|
+
- `include_raw` (boolean, optional): Include raw API response from the integration (default: false)
|
|
647
|
+
|
|
648
|
+
**Response:**
|
|
649
|
+
|
|
650
|
+
```typescript
|
|
651
|
+
{
|
|
652
|
+
data: [
|
|
653
|
+
{
|
|
654
|
+
id: 'C1234567890',
|
|
655
|
+
name: 'general'
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
id: 'C0987654321',
|
|
659
|
+
name: 'engineering'
|
|
660
|
+
}
|
|
661
|
+
],
|
|
662
|
+
metadata: {
|
|
663
|
+
next: 'cursor_abc123' // Use this for pagination
|
|
664
|
+
},
|
|
665
|
+
_raw?: { // Only present if include_raw: true
|
|
666
|
+
// Original response from the integration API
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
**Pagination example:**
|
|
216
672
|
|
|
217
673
|
```javascript
|
|
218
|
-
|
|
219
|
-
|
|
674
|
+
let allChannels = [];
|
|
675
|
+
let cursor = null;
|
|
676
|
+
|
|
677
|
+
do {
|
|
678
|
+
const result = await unify.chat.channels({
|
|
679
|
+
limit: 100,
|
|
680
|
+
after: cursor,
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
allChannels = [...allChannels, ...result.data];
|
|
684
|
+
cursor = result.metadata.next;
|
|
685
|
+
} while (cursor);
|
|
686
|
+
|
|
687
|
+
console.log(`Fetched ${allChannels.length} total channels`);
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
#### Git API
|
|
220
691
|
|
|
221
|
-
|
|
222
|
-
|
|
692
|
+
The Git API provides a unified interface for version control platforms like GitHub, GitLab, and Bitbucket.
|
|
693
|
+
|
|
694
|
+
##### List Repositories
|
|
695
|
+
|
|
696
|
+
```javascript
|
|
697
|
+
const result = await unify.git.repos({
|
|
223
698
|
limit: 50,
|
|
224
|
-
after:
|
|
699
|
+
after: null,
|
|
700
|
+
include_raw: false,
|
|
225
701
|
});
|
|
226
702
|
|
|
227
|
-
|
|
228
|
-
const issues = await client.unify('conn_123').pm.issues({
|
|
229
|
-
includeRaw: true
|
|
230
|
-
});
|
|
703
|
+
console.log('Repositories:', result.data);
|
|
231
704
|
```
|
|
232
705
|
|
|
233
|
-
|
|
706
|
+
**Response:**
|
|
234
707
|
|
|
235
|
-
|
|
708
|
+
```typescript
|
|
709
|
+
{
|
|
710
|
+
data: [
|
|
711
|
+
{
|
|
712
|
+
id: '123456',
|
|
713
|
+
name: 'my-awesome-project',
|
|
714
|
+
full_name: 'organization/my-awesome-project',
|
|
715
|
+
description: 'An awesome project',
|
|
716
|
+
url: 'https://github.com/organization/my-awesome-project',
|
|
717
|
+
created_at: '2023-01-15T10:30:00Z',
|
|
718
|
+
updated_at: '2024-01-20T14:22:00Z',
|
|
719
|
+
pushed_at: '2024-01-20T14:22:00Z'
|
|
720
|
+
}
|
|
721
|
+
],
|
|
722
|
+
metadata: {
|
|
723
|
+
next: 'cursor_xyz789'
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
##### List Pull Requests
|
|
236
729
|
|
|
237
730
|
```javascript
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
731
|
+
const result = await unify.git.pulls('organization/repo-name', {
|
|
732
|
+
limit: 20,
|
|
733
|
+
after: null,
|
|
734
|
+
include_raw: false,
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
console.log('Pull Requests:', result.data);
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
**Parameters:**
|
|
741
|
+
|
|
742
|
+
- `repoName` (string, required): Repository name in the format 'owner/repo'
|
|
743
|
+
- `limit` (number, optional): Maximum number of PRs to return
|
|
744
|
+
- `after` (string, optional): Pagination cursor
|
|
745
|
+
- `include_raw` (boolean, optional): Include raw API response
|
|
746
|
+
|
|
747
|
+
**Response:**
|
|
748
|
+
|
|
749
|
+
```typescript
|
|
750
|
+
{
|
|
751
|
+
data: [
|
|
752
|
+
{
|
|
753
|
+
id: '12345',
|
|
754
|
+
number: 42,
|
|
755
|
+
title: 'Add new feature',
|
|
756
|
+
description: 'This PR adds an awesome new feature',
|
|
757
|
+
draft: false,
|
|
758
|
+
state: 'open',
|
|
759
|
+
url: 'https://github.com/org/repo/pull/42',
|
|
760
|
+
user: 'john-doe',
|
|
761
|
+
created_at: '2024-01-15T10:30:00Z',
|
|
762
|
+
updated_at: '2024-01-20T14:22:00Z',
|
|
763
|
+
merged_at: null
|
|
764
|
+
}
|
|
765
|
+
],
|
|
766
|
+
metadata: {
|
|
767
|
+
next: null
|
|
250
768
|
}
|
|
251
769
|
}
|
|
252
770
|
```
|
|
253
771
|
|
|
254
|
-
|
|
772
|
+
##### List Tags
|
|
773
|
+
|
|
774
|
+
```javascript
|
|
775
|
+
const result = await unify.git.tags('organization/repo-name', {
|
|
776
|
+
limit: 50,
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
console.log('Tags:', result.data);
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
**Response:**
|
|
255
783
|
|
|
256
|
-
|
|
784
|
+
```typescript
|
|
785
|
+
{
|
|
786
|
+
data: [
|
|
787
|
+
{
|
|
788
|
+
name: 'v1.0.0',
|
|
789
|
+
commit_sha: 'abc123def456'
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
name: 'v0.9.0',
|
|
793
|
+
commit_sha: 'def456ghi789'
|
|
794
|
+
}
|
|
795
|
+
],
|
|
796
|
+
metadata: {
|
|
797
|
+
next: null
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
```
|
|
257
801
|
|
|
258
|
-
|
|
802
|
+
##### List Releases
|
|
259
803
|
|
|
260
804
|
```javascript
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
status: 'active',
|
|
264
|
-
limit: '50',
|
|
265
|
-
page: '1'
|
|
805
|
+
const result = await unify.git.releases('organization/repo-name', {
|
|
806
|
+
limit: 10,
|
|
266
807
|
});
|
|
808
|
+
|
|
809
|
+
console.log('Releases:', result.data);
|
|
267
810
|
```
|
|
268
811
|
|
|
269
|
-
|
|
812
|
+
**Response:**
|
|
270
813
|
|
|
271
|
-
|
|
814
|
+
```typescript
|
|
815
|
+
{
|
|
816
|
+
data: [
|
|
817
|
+
{
|
|
818
|
+
id: '54321',
|
|
819
|
+
name: 'Version 1.0.0',
|
|
820
|
+
tag_name: 'v1.0.0',
|
|
821
|
+
description: 'Initial release with all the features',
|
|
822
|
+
prerelease: false,
|
|
823
|
+
url: 'https://github.com/org/repo/releases/tag/v1.0.0',
|
|
824
|
+
created_at: '2024-01-15T10:30:00Z',
|
|
825
|
+
released_at: '2024-01-15T10:30:00Z'
|
|
826
|
+
}
|
|
827
|
+
],
|
|
828
|
+
metadata: {
|
|
829
|
+
next: null
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
#### Project Management API
|
|
835
|
+
|
|
836
|
+
The PM API provides a unified interface for project management platforms like Jira, Linear, and Asana.
|
|
837
|
+
|
|
838
|
+
##### List Issues
|
|
272
839
|
|
|
273
840
|
```javascript
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
841
|
+
const result = await unify.pm.issues({
|
|
842
|
+
limit: 100,
|
|
843
|
+
after: null,
|
|
844
|
+
include_raw: false,
|
|
277
845
|
});
|
|
278
|
-
```
|
|
279
846
|
|
|
280
|
-
|
|
847
|
+
console.log('Issues:', result.data);
|
|
848
|
+
```
|
|
281
849
|
|
|
282
|
-
|
|
850
|
+
**Response:**
|
|
283
851
|
|
|
284
852
|
```typescript
|
|
285
|
-
|
|
853
|
+
{
|
|
854
|
+
data: [
|
|
855
|
+
{
|
|
856
|
+
id: 'PROJ-123',
|
|
857
|
+
url: 'https://jira.example.com/browse/PROJ-123',
|
|
858
|
+
title: 'Fix login bug',
|
|
859
|
+
status: 'in_progress',
|
|
860
|
+
description: 'Users are unable to log in',
|
|
861
|
+
created_at: '2024-01-15T10:30:00Z',
|
|
862
|
+
updated_at: '2024-01-20T14:22:00Z'
|
|
863
|
+
}
|
|
864
|
+
],
|
|
865
|
+
metadata: {
|
|
866
|
+
next: 'cursor_def456'
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
```
|
|
286
870
|
|
|
287
|
-
|
|
871
|
+
**Filtering and sorting:**
|
|
288
872
|
|
|
289
|
-
|
|
290
|
-
const
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
873
|
+
```javascript
|
|
874
|
+
const openIssues = result.data.filter(issue => issue.status === 'open');
|
|
875
|
+
const sortedByDate = result.data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
## Error Handling
|
|
879
|
+
|
|
880
|
+
The SDK throws standard JavaScript errors with descriptive messages. Always wrap SDK calls in try-catch blocks for proper error handling.
|
|
881
|
+
|
|
882
|
+
```javascript
|
|
883
|
+
try {
|
|
884
|
+
const connections = await client.connections.list();
|
|
885
|
+
} catch (error) {
|
|
886
|
+
console.error('Failed to fetch connections:', error.message);
|
|
887
|
+
}
|
|
297
888
|
```
|
|
298
889
|
|
|
890
|
+
### Getting Help
|
|
891
|
+
|
|
892
|
+
If you're still experiencing issues:
|
|
893
|
+
|
|
894
|
+
1. Check the [BundleUp Documentation](https://docs.bundleup.io)
|
|
895
|
+
2. Search [GitHub Issues](https://github.com/bundleup/javascript/issues)
|
|
896
|
+
3. Join our [Community Discord](https://discord.gg/bundleup)
|
|
897
|
+
4. Contact [support@bundleup.io](mailto:support@bundleup.io)
|
|
898
|
+
|
|
899
|
+
When reporting issues, please include:
|
|
900
|
+
|
|
901
|
+
- SDK version (`@bundleup/sdk` version from package.json)
|
|
902
|
+
- Node.js version (`node --version`)
|
|
903
|
+
- Minimal code to reproduce the issue
|
|
904
|
+
- Full error message and stack trace
|
|
905
|
+
|
|
299
906
|
## Development
|
|
300
907
|
|
|
301
|
-
|
|
908
|
+
### Setting Up Development Environment
|
|
302
909
|
|
|
303
910
|
```bash
|
|
911
|
+
# Clone the repository
|
|
912
|
+
git clone https://github.com/bundleup/javascript.git
|
|
913
|
+
cd javascript/packages/sdk
|
|
914
|
+
|
|
915
|
+
# Install dependencies
|
|
304
916
|
npm install
|
|
917
|
+
|
|
918
|
+
# Build the package
|
|
919
|
+
npm run build
|
|
920
|
+
|
|
921
|
+
# Run tests
|
|
922
|
+
npm test
|
|
923
|
+
|
|
924
|
+
# Watch mode for development
|
|
925
|
+
npm run dev
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
### Project Structure
|
|
929
|
+
|
|
930
|
+
```
|
|
931
|
+
src/
|
|
932
|
+
âââ index.ts # Main entry point
|
|
933
|
+
âââ proxy.ts # Proxy API implementation
|
|
934
|
+
âââ unify.ts # Unify API implementation
|
|
935
|
+
âââ utils.ts # Utility functions
|
|
936
|
+
âââ resources/
|
|
937
|
+
â âââ base.ts # Base resource class
|
|
938
|
+
â âââ connection.ts # Connections API
|
|
939
|
+
â âââ integration.ts # Integrations API
|
|
940
|
+
â âââ webhooks.ts # Webhooks API
|
|
941
|
+
âââ unify/
|
|
942
|
+
â âââ base.ts # Base Unify class
|
|
943
|
+
â âââ chat.ts # Chat Unify API
|
|
944
|
+
â âââ git.ts # Git Unify API
|
|
945
|
+
â âââ pm.ts # PM Unify API
|
|
946
|
+
âââ __tests__/ # Test files
|
|
305
947
|
```
|
|
306
948
|
|
|
307
|
-
|
|
949
|
+
### Running Tests
|
|
308
950
|
|
|
309
951
|
```bash
|
|
952
|
+
# Run all tests
|
|
953
|
+
npm test
|
|
954
|
+
|
|
955
|
+
# Run tests in watch mode
|
|
956
|
+
npm test -- --watch
|
|
957
|
+
|
|
958
|
+
# Run specific test file
|
|
959
|
+
npm test -- proxy.test.ts
|
|
960
|
+
|
|
961
|
+
# Run with coverage
|
|
962
|
+
npm test -- --coverage
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
### Building
|
|
966
|
+
|
|
967
|
+
```bash
|
|
968
|
+
# Build for production
|
|
310
969
|
npm run build
|
|
970
|
+
|
|
971
|
+
# Clean build artifacts
|
|
972
|
+
npm run clean
|
|
973
|
+
|
|
974
|
+
# Build and watch for changes
|
|
975
|
+
npm run dev
|
|
311
976
|
```
|
|
312
977
|
|
|
313
|
-
|
|
978
|
+
### Linting
|
|
314
979
|
|
|
315
980
|
```bash
|
|
316
|
-
|
|
981
|
+
# Run ESLint
|
|
982
|
+
npm run lint
|
|
983
|
+
|
|
984
|
+
# Fix linting issues
|
|
985
|
+
npm run lint -- --fix
|
|
317
986
|
```
|
|
318
987
|
|
|
319
988
|
## Contributing
|
|
320
989
|
|
|
321
|
-
|
|
990
|
+
We welcome contributions to the BundleUp JavaScript SDK! Here's how you can help:
|
|
991
|
+
|
|
992
|
+
### Reporting Bugs
|
|
993
|
+
|
|
994
|
+
1. Check if the bug has already been reported in [GitHub Issues](https://github.com/bundleup/javascript/issues)
|
|
995
|
+
2. If not, create a new issue with:
|
|
996
|
+
- Clear title and description
|
|
997
|
+
- Steps to reproduce
|
|
998
|
+
- Expected vs actual behavior
|
|
999
|
+
- SDK version and environment details
|
|
1000
|
+
|
|
1001
|
+
### Suggesting Features
|
|
1002
|
+
|
|
1003
|
+
1. Open a new issue with the "feature request" label
|
|
1004
|
+
2. Describe the feature and its use case
|
|
1005
|
+
3. Explain why this feature would be useful
|
|
1006
|
+
|
|
1007
|
+
### Pull Requests
|
|
1008
|
+
|
|
1009
|
+
1. Fork the repository
|
|
1010
|
+
2. Create a new branch: `git checkout -b feature/my-new-feature`
|
|
1011
|
+
3. Make your changes
|
|
1012
|
+
4. Write or update tests
|
|
1013
|
+
5. Ensure all tests pass: `npm test`
|
|
1014
|
+
6. Commit your changes: `git commit -am 'Add new feature'`
|
|
1015
|
+
7. Push to the branch: `git push origin feature/my-new-feature`
|
|
1016
|
+
8. Submit a pull request
|
|
1017
|
+
|
|
1018
|
+
### Development Guidelines
|
|
1019
|
+
|
|
1020
|
+
- Follow the existing code style
|
|
1021
|
+
- Add tests for new features
|
|
1022
|
+
- Update documentation for API changes
|
|
1023
|
+
- Keep commits focused and atomic
|
|
1024
|
+
- Write clear commit messages
|
|
322
1025
|
|
|
323
1026
|
## License
|
|
324
1027
|
|
|
325
1028
|
This package is available as open source under the terms of the [ISC License](https://opensource.org/licenses/ISC).
|
|
326
1029
|
|
|
1030
|
+
```
|
|
1031
|
+
Copyright (c) 2024 BundleUp
|
|
1032
|
+
|
|
1033
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
1034
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
1035
|
+
copyright notice and this permission notice appear in all copies.
|
|
1036
|
+
|
|
1037
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
1038
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
1039
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
1040
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
1041
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
1042
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
1043
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
1044
|
+
```
|
|
1045
|
+
|
|
327
1046
|
## Support
|
|
328
1047
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
1048
|
+
Need help? We're here for you!
|
|
1049
|
+
|
|
1050
|
+
### Documentation
|
|
1051
|
+
|
|
1052
|
+
- **Official Docs**: [https://docs.bundleup.io](https://docs.bundleup.io)
|
|
1053
|
+
- **API Reference**: [https://docs.bundleup.io/api](https://docs.bundleup.io/api)
|
|
1054
|
+
- **SDK Guides**: [https://docs.bundleup.io/sdk/javascript](https://docs.bundleup.io/sdk/javascript)
|
|
1055
|
+
|
|
1056
|
+
### Community
|
|
1057
|
+
|
|
1058
|
+
- **Discord**: [https://discord.gg/bundleup](https://discord.gg/bundleup)
|
|
1059
|
+
- **GitHub Discussions**: [https://github.com/bundleup/javascript/discussions](https://github.com/bundleup/javascript/discussions)
|
|
1060
|
+
- **Stack Overflow**: Tag your questions with `bundleup`
|
|
1061
|
+
|
|
1062
|
+
### Direct Support
|
|
1063
|
+
|
|
1064
|
+
- **Email**: [support@bundleup.io](mailto:support@bundleup.io)
|
|
1065
|
+
- **GitHub Issues**: [https://github.com/bundleup/javascript/issues](https://github.com/bundleup/javascript/issues)
|
|
1066
|
+
- **Twitter**: [@bundleup_io](https://twitter.com/bundleup_io)
|
|
1067
|
+
|
|
1068
|
+
### Enterprise Support
|
|
1069
|
+
|
|
1070
|
+
For enterprise customers, we offer:
|
|
1071
|
+
|
|
1072
|
+
- Priority support with SLA
|
|
1073
|
+
- Dedicated support channel
|
|
1074
|
+
- Architecture consultation
|
|
1075
|
+
- Custom integration assistance
|
|
1076
|
+
|
|
1077
|
+
Contact [enterprise@bundleup.io](mailto:enterprise@bundleup.io) for more information.
|
|
332
1078
|
|
|
333
1079
|
## Code of Conduct
|
|
334
1080
|
|
|
335
1081
|
Everyone interacting in the BundleUp project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/bundleup/javascript/blob/main/CODE_OF_CONDUCT).
|
|
1082
|
+
|
|
1083
|
+
---
|
|
1084
|
+
|
|
1085
|
+
Made with âĪïļ by the [BundleUp](https://bundleup.io) team
|