@vybit/oauth2-sdk 1.0.1 → 1.0.3
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
CHANGED
|
@@ -6,6 +6,12 @@ OAuth 2.0 authentication SDK for Vybit.
|
|
|
6
6
|
|
|
7
7
|
Complete OAuth2 implementation for Vybit authentication, including authorization URL generation, token exchange, and authenticated API calls.
|
|
8
8
|
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
1. Create a [Vybit developer account](https://developer.vybit.net)
|
|
12
|
+
2. Navigate to OAUTH CONFIGURATION and specify a service name
|
|
13
|
+
3. Store your VYBIT_CLIENT_ID and VYBIT_CLIENT_SECRET (use environment variables)
|
|
14
|
+
|
|
9
15
|
## Installation
|
|
10
16
|
|
|
11
17
|
```bash
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vybit/oauth2-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "OAuth 2.0 SDK for Vybit authentication and authorization",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"build": "tsc",
|
|
9
|
-
"clean": "rm -rf dist",
|
|
8
|
+
"build": "tsc -b",
|
|
9
|
+
"clean": "rm -rf dist *.tsbuildinfo",
|
|
10
10
|
"dev": "tsc --watch",
|
|
11
|
-
"test": "jest --config ../../jest.config.js --rootDir ../.."
|
|
11
|
+
"test": "jest --config ../../jest.config.js --rootDir ../..",
|
|
12
|
+
"lint": "echo 'Run lint from root: npm run lint'"
|
|
12
13
|
},
|
|
13
14
|
"keywords": [
|
|
14
15
|
"vybit",
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
"authentication",
|
|
17
18
|
"sdk"
|
|
18
19
|
],
|
|
19
|
-
"author": "
|
|
20
|
+
"author": "Flatirontek LLC",
|
|
20
21
|
"license": "MIT",
|
|
21
22
|
"repository": {
|
|
22
23
|
"type": "git",
|
|
@@ -38,7 +39,7 @@
|
|
|
38
39
|
"node": ">=16.0.0"
|
|
39
40
|
},
|
|
40
41
|
"dependencies": {
|
|
41
|
-
"@vybit/core": "^1.0
|
|
42
|
+
"@vybit/core": "^1.1.0"
|
|
42
43
|
},
|
|
43
44
|
"peerDependencies": {
|
|
44
45
|
"node-fetch": "^3.0.0"
|
|
@@ -48,4 +49,4 @@
|
|
|
48
49
|
"optional": true
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
|
-
}
|
|
52
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"oauth2-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/oauth2-client.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* OAuth2 Client Tests
|
|
4
|
-
*
|
|
5
|
-
* These tests mirror the exact functionality tested in the developer portal,
|
|
6
|
-
* covering all 6 steps of the OAuth flow.
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
const oauth2_client_1 = require("../oauth2-client");
|
|
10
|
-
const core_1 = require("@vybit/core");
|
|
11
|
-
// Mock fetch globally
|
|
12
|
-
const mockFetch = jest.fn();
|
|
13
|
-
global.fetch = mockFetch;
|
|
14
|
-
describe('VybitOAuth2Client', () => {
|
|
15
|
-
let client;
|
|
16
|
-
const validConfig = {
|
|
17
|
-
clientId: 'test-client-id',
|
|
18
|
-
clientSecret: 'test-client-secret',
|
|
19
|
-
redirectUri: 'https://example.com/callback'
|
|
20
|
-
};
|
|
21
|
-
beforeEach(() => {
|
|
22
|
-
client = new oauth2_client_1.VybitOAuth2Client(validConfig);
|
|
23
|
-
mockFetch.mockClear();
|
|
24
|
-
});
|
|
25
|
-
describe('Configuration Validation', () => {
|
|
26
|
-
it('should validate required configuration', () => {
|
|
27
|
-
expect(() => new oauth2_client_1.VybitOAuth2Client({
|
|
28
|
-
...validConfig,
|
|
29
|
-
clientId: ''
|
|
30
|
-
})).toThrow(core_1.VybitValidationError);
|
|
31
|
-
expect(() => new oauth2_client_1.VybitOAuth2Client({
|
|
32
|
-
...validConfig,
|
|
33
|
-
clientSecret: ''
|
|
34
|
-
})).toThrow(core_1.VybitValidationError);
|
|
35
|
-
expect(() => new oauth2_client_1.VybitOAuth2Client({
|
|
36
|
-
...validConfig,
|
|
37
|
-
redirectUri: ''
|
|
38
|
-
})).toThrow(core_1.VybitValidationError);
|
|
39
|
-
});
|
|
40
|
-
it('should validate redirect URI format', () => {
|
|
41
|
-
expect(() => new oauth2_client_1.VybitOAuth2Client({
|
|
42
|
-
...validConfig,
|
|
43
|
-
redirectUri: 'invalid-url'
|
|
44
|
-
})).toThrow(core_1.VybitValidationError);
|
|
45
|
-
});
|
|
46
|
-
it('should accept valid configuration', () => {
|
|
47
|
-
expect(() => new oauth2_client_1.VybitOAuth2Client(validConfig)).not.toThrow();
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
describe('Step 1: Authorization URL Generation', () => {
|
|
51
|
-
it('should generate correct authorization URL', () => {
|
|
52
|
-
const authUrl = client.getAuthorizationUrl();
|
|
53
|
-
expect(authUrl).toContain('https://app.vybit.net');
|
|
54
|
-
expect(authUrl).toContain('client_id=test-client-id');
|
|
55
|
-
expect(authUrl).toContain('redirect_uri=https%3A%2F%2Fexample.com%2Fcallback');
|
|
56
|
-
expect(authUrl).toContain('response_type=code');
|
|
57
|
-
expect(authUrl).toContain('state=');
|
|
58
|
-
});
|
|
59
|
-
it('should use custom state when provided', () => {
|
|
60
|
-
const customState = 'custom-state-123';
|
|
61
|
-
const authUrl = client.getAuthorizationUrl({ state: customState });
|
|
62
|
-
expect(authUrl).toContain(`state=${customState}`);
|
|
63
|
-
});
|
|
64
|
-
it('should include scope when provided', () => {
|
|
65
|
-
const authUrl = client.getAuthorizationUrl({ scope: 'read' });
|
|
66
|
-
expect(authUrl).toContain('scope=read');
|
|
67
|
-
});
|
|
68
|
-
it('should always use production domain', () => {
|
|
69
|
-
const authUrl = client.getAuthorizationUrl();
|
|
70
|
-
expect(authUrl).toContain('https://app.vybit.net');
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
describe('Step 3: Token Exchange', () => {
|
|
74
|
-
it('should successfully exchange code for token', async () => {
|
|
75
|
-
const mockTokenResponse = {
|
|
76
|
-
access_token: 'test-access-token',
|
|
77
|
-
token_type: 'Bearer'
|
|
78
|
-
};
|
|
79
|
-
mockFetch.mockResolvedValueOnce({
|
|
80
|
-
ok: true,
|
|
81
|
-
json: () => Promise.resolve(mockTokenResponse)
|
|
82
|
-
});
|
|
83
|
-
const result = await client.exchangeCodeForToken('test-auth-code');
|
|
84
|
-
expect(result).toEqual(mockTokenResponse);
|
|
85
|
-
expect(client.getAccessToken()).toBe('test-access-token');
|
|
86
|
-
// Verify correct API call
|
|
87
|
-
expect(mockFetch).toHaveBeenCalledWith('https://app.vybit.net/service/token', expect.objectContaining({
|
|
88
|
-
method: 'POST',
|
|
89
|
-
headers: {
|
|
90
|
-
'Content-Type': 'application/x-www-form-urlencoded'
|
|
91
|
-
},
|
|
92
|
-
body: expect.any(URLSearchParams)
|
|
93
|
-
}));
|
|
94
|
-
});
|
|
95
|
-
it('should handle token exchange errors', async () => {
|
|
96
|
-
mockFetch.mockResolvedValueOnce({
|
|
97
|
-
ok: false,
|
|
98
|
-
status: 400,
|
|
99
|
-
statusText: 'Bad Request'
|
|
100
|
-
});
|
|
101
|
-
await expect(client.exchangeCodeForToken('invalid-code')).rejects.toThrow(core_1.VybitAPIError);
|
|
102
|
-
});
|
|
103
|
-
it('should handle auth errors in response', async () => {
|
|
104
|
-
mockFetch.mockResolvedValueOnce({
|
|
105
|
-
ok: true,
|
|
106
|
-
json: () => Promise.resolve({ error: 'invalid_client' })
|
|
107
|
-
});
|
|
108
|
-
await expect(client.exchangeCodeForToken('test-code')).rejects.toThrow(core_1.VybitAuthError);
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
describe('Step 4: Token Verification', () => {
|
|
112
|
-
beforeEach(() => {
|
|
113
|
-
client.setAccessToken('test-token');
|
|
114
|
-
});
|
|
115
|
-
it('should verify valid token', async () => {
|
|
116
|
-
mockFetch.mockResolvedValueOnce({
|
|
117
|
-
ok: true,
|
|
118
|
-
json: () => Promise.resolve({ status: 'ok' })
|
|
119
|
-
});
|
|
120
|
-
const isValid = await client.verifyToken();
|
|
121
|
-
expect(isValid).toBe(true);
|
|
122
|
-
expect(mockFetch).toHaveBeenCalledWith('https://vybit.net/service/test', {
|
|
123
|
-
headers: {
|
|
124
|
-
Authorization: 'Bearer test-token'
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
it('should handle invalid token', async () => {
|
|
129
|
-
mockFetch.mockResolvedValueOnce({
|
|
130
|
-
ok: false,
|
|
131
|
-
status: 401
|
|
132
|
-
});
|
|
133
|
-
const isValid = await client.verifyToken();
|
|
134
|
-
expect(isValid).toBe(false);
|
|
135
|
-
});
|
|
136
|
-
it('should handle network errors gracefully', async () => {
|
|
137
|
-
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
138
|
-
const isValid = await client.verifyToken();
|
|
139
|
-
expect(isValid).toBe(false);
|
|
140
|
-
});
|
|
141
|
-
it('should require access token', async () => {
|
|
142
|
-
const clientWithoutToken = new oauth2_client_1.VybitOAuth2Client(validConfig);
|
|
143
|
-
await expect(clientWithoutToken.verifyToken()).rejects.toThrow(core_1.VybitAuthError);
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
describe('Step 5: Get Vybit List', () => {
|
|
147
|
-
beforeEach(() => {
|
|
148
|
-
client.setAccessToken('test-token');
|
|
149
|
-
});
|
|
150
|
-
it('should fetch vybit list successfully', async () => {
|
|
151
|
-
const mockVybitResponse = {
|
|
152
|
-
'0': { name: 'My Alert', triggerKey: 'abc123def456' },
|
|
153
|
-
'1': { name: 'Notification Sound', triggerKey: 'def456ghi789' },
|
|
154
|
-
'2': { name: 'Status Update', triggerKey: 'ghi789jkl012' }
|
|
155
|
-
};
|
|
156
|
-
mockFetch.mockResolvedValueOnce({
|
|
157
|
-
ok: true,
|
|
158
|
-
json: () => Promise.resolve(mockVybitResponse)
|
|
159
|
-
});
|
|
160
|
-
const vybits = await client.getVybitList();
|
|
161
|
-
expect(vybits).toHaveLength(3);
|
|
162
|
-
expect(vybits[0]).toEqual({ name: 'My Alert', triggerKey: 'abc123def456' });
|
|
163
|
-
expect(vybits[1]).toEqual({ name: 'Notification Sound', triggerKey: 'def456ghi789' });
|
|
164
|
-
expect(vybits[2]).toEqual({ name: 'Status Update', triggerKey: 'ghi789jkl012' });
|
|
165
|
-
expect(mockFetch).toHaveBeenCalledWith('https://vybit.net/rest/vybit_list', {
|
|
166
|
-
headers: {
|
|
167
|
-
Authorization: 'Bearer test-token'
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
it('should handle API errors', async () => {
|
|
172
|
-
mockFetch.mockResolvedValueOnce({
|
|
173
|
-
ok: false,
|
|
174
|
-
status: 403,
|
|
175
|
-
statusText: 'Forbidden'
|
|
176
|
-
});
|
|
177
|
-
await expect(client.getVybitList()).rejects.toThrow(core_1.VybitAPIError);
|
|
178
|
-
});
|
|
179
|
-
it('should require access token', async () => {
|
|
180
|
-
const clientWithoutToken = new oauth2_client_1.VybitOAuth2Client(validConfig);
|
|
181
|
-
await expect(clientWithoutToken.getVybitList()).rejects.toThrow(core_1.VybitAuthError);
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
describe('Step 6: Send Vybit Notification', () => {
|
|
185
|
-
beforeEach(() => {
|
|
186
|
-
client.setAccessToken('test-token');
|
|
187
|
-
});
|
|
188
|
-
it('should send notification with all optional parameters', async () => {
|
|
189
|
-
const mockResponse = {
|
|
190
|
-
result: 1,
|
|
191
|
-
plk: 'bbxope6xhryminef'
|
|
192
|
-
};
|
|
193
|
-
mockFetch.mockResolvedValueOnce({
|
|
194
|
-
ok: true,
|
|
195
|
-
json: () => Promise.resolve(mockResponse)
|
|
196
|
-
});
|
|
197
|
-
const triggerOptions = {
|
|
198
|
-
message: 'Test notification',
|
|
199
|
-
imageUrl: 'https://example.com/image.jpg',
|
|
200
|
-
linkUrl: 'https://example.com/redirect',
|
|
201
|
-
log: 'Test log entry <a href="https://example.com">link</a>'
|
|
202
|
-
};
|
|
203
|
-
const result = await client.sendVybitNotification('test-trigger-key', triggerOptions);
|
|
204
|
-
expect(result).toEqual(mockResponse);
|
|
205
|
-
// Verify the API call
|
|
206
|
-
const [url, options] = mockFetch.mock.calls[0];
|
|
207
|
-
expect(url).toBe('https://vybit.net/fire/test-trigger-key');
|
|
208
|
-
expect(options.method).toBe('POST');
|
|
209
|
-
expect(options.headers['Authorization']).toBe('Bearer test-token');
|
|
210
|
-
expect(options.headers['Content-Type']).toBe('application/json');
|
|
211
|
-
const body = JSON.parse(options.body);
|
|
212
|
-
expect(body).toEqual(triggerOptions);
|
|
213
|
-
});
|
|
214
|
-
it('should send notification with minimal parameters', async () => {
|
|
215
|
-
const mockResponse = { result: 1, plk: 'test-plk' };
|
|
216
|
-
mockFetch.mockResolvedValueOnce({
|
|
217
|
-
ok: true,
|
|
218
|
-
json: () => Promise.resolve(mockResponse)
|
|
219
|
-
});
|
|
220
|
-
const result = await client.sendVybitNotification('test-trigger-key');
|
|
221
|
-
expect(result).toEqual(mockResponse);
|
|
222
|
-
const body = JSON.parse(mockFetch.mock.calls[0][1].body);
|
|
223
|
-
expect(body).toEqual({});
|
|
224
|
-
});
|
|
225
|
-
it('should validate URL parameters', async () => {
|
|
226
|
-
await expect(client.sendVybitNotification('test-key', {
|
|
227
|
-
imageUrl: 'invalid-url'
|
|
228
|
-
})).rejects.toThrow(core_1.VybitValidationError);
|
|
229
|
-
await expect(client.sendVybitNotification('test-key', {
|
|
230
|
-
linkUrl: 'also-invalid'
|
|
231
|
-
})).rejects.toThrow(core_1.VybitValidationError);
|
|
232
|
-
});
|
|
233
|
-
it('should handle API errors', async () => {
|
|
234
|
-
mockFetch.mockResolvedValueOnce({
|
|
235
|
-
ok: false,
|
|
236
|
-
status: 404,
|
|
237
|
-
statusText: 'Not Found'
|
|
238
|
-
});
|
|
239
|
-
await expect(client.sendVybitNotification('invalid-key')).rejects.toThrow(core_1.VybitAPIError);
|
|
240
|
-
});
|
|
241
|
-
it('should require access token', async () => {
|
|
242
|
-
const clientWithoutToken = new oauth2_client_1.VybitOAuth2Client(validConfig);
|
|
243
|
-
await expect(clientWithoutToken.sendVybitNotification('test-key')).rejects.toThrow(core_1.VybitAuthError);
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
describe('Token Management', () => {
|
|
247
|
-
it('should set and get access token', () => {
|
|
248
|
-
expect(client.getAccessToken()).toBeUndefined();
|
|
249
|
-
client.setAccessToken('new-token');
|
|
250
|
-
expect(client.getAccessToken()).toBe('new-token');
|
|
251
|
-
});
|
|
252
|
-
it('should allow overriding token in API calls', async () => {
|
|
253
|
-
client.setAccessToken('default-token');
|
|
254
|
-
mockFetch.mockResolvedValueOnce({
|
|
255
|
-
ok: true,
|
|
256
|
-
json: () => Promise.resolve({ status: 'ok' })
|
|
257
|
-
});
|
|
258
|
-
await client.verifyToken('override-token');
|
|
259
|
-
expect(mockFetch).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
|
|
260
|
-
headers: expect.objectContaining({
|
|
261
|
-
Authorization: 'Bearer override-token'
|
|
262
|
-
})
|
|
263
|
-
}));
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
//# sourceMappingURL=oauth2-client.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"oauth2-client.test.js","sourceRoot":"","sources":["../../src/__tests__/oauth2-client.test.ts"],"names":[],"mappings":"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"}
|