@vrplatform/hyperline-client 1.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.
Files changed (45) hide show
  1. package/build/main/client.d.ts +812 -0
  2. package/build/main/client.js +187 -0
  3. package/build/main/client.js.map +1 -0
  4. package/build/main/const.d.ts +26 -0
  5. package/build/main/const.js +209 -0
  6. package/build/main/const.js.map +1 -0
  7. package/build/main/hooks.d.ts +10 -0
  8. package/build/main/hooks.js +13 -0
  9. package/build/main/hooks.js.map +1 -0
  10. package/build/main/index.d.ts +4 -868
  11. package/build/main/index.js +4 -216
  12. package/build/main/index.js.map +1 -1
  13. package/build/main/tsconfig.main.tsbuildinfo +1 -1
  14. package/build/main/types.d.ts +35 -0
  15. package/build/main/types.js +2 -0
  16. package/build/main/types.js.map +1 -0
  17. package/build/main/utils.d.ts +1 -0
  18. package/build/main/utils.js +6 -0
  19. package/build/main/utils.js.map +1 -0
  20. package/build/module/client.d.ts +812 -0
  21. package/build/module/client.js +189 -0
  22. package/build/module/client.js.map +1 -0
  23. package/build/module/const.d.ts +26 -0
  24. package/build/module/const.js +209 -0
  25. package/build/module/const.js.map +1 -0
  26. package/build/module/hooks.d.ts +10 -0
  27. package/build/module/hooks.js +13 -0
  28. package/build/module/hooks.js.map +1 -0
  29. package/build/module/index.d.ts +4 -868
  30. package/build/module/index.js +4 -218
  31. package/build/module/index.js.map +1 -1
  32. package/build/module/tsconfig.esm.tsbuildinfo +1 -1
  33. package/build/module/types.d.ts +35 -0
  34. package/build/module/types.js +2 -0
  35. package/build/module/types.js.map +1 -0
  36. package/build/module/utils.d.ts +1 -0
  37. package/build/module/utils.js +6 -0
  38. package/build/module/utils.js.map +1 -0
  39. package/package.json +3 -3
  40. package/src/client.ts +362 -0
  41. package/src/const.ts +220 -0
  42. package/src/hooks.ts +24 -0
  43. package/src/index.ts +4 -443
  44. package/src/types.ts +43 -0
  45. package/src/utils.ts +5 -0
package/src/index.ts CHANGED
@@ -1,443 +1,4 @@
1
- import { day } from '@finalytic/utils';
2
- import type { TrackingEvent } from '@vrplatform/log';
3
- import type { components, operations, paths } from './_types.generated';
4
-
5
- export type HyperlineEntities = components['schemas'];
6
- export type HyperlineEndpoints = paths;
7
-
8
- export const webhooks = {
9
- 'payment_method.created': 'hyperline_payment_method_created',
10
- 'payment_method.errored': 'hyperline_payment_method_errored',
11
- 'payment_method.deleted': 'hyperline_payment_method_deleted',
12
- 'subscription.activated': 'hyperline_subscription_status_changed',
13
- 'subscription.reactivated': 'hyperline_subscription_status_changed',
14
- 'subscription.cancelled': 'hyperline_subscription_status_changed',
15
- 'subscription.cancellation_scheduled':
16
- 'hyperline_subscription_cancellation_scheduled',
17
- // 'subscription.created': 'hyperline_subscription_created',
18
- 'subscription.errored': 'hyperline_subscription_status_changed',
19
- 'subscription.paused': 'hyperline_subscription_status_changed',
20
- 'subscription.voided': 'hyperline_subscription_status_changed',
21
- // 'subscription.charged': 'hyperline_subscription_charged',
22
- 'customer.created': 'hyperline_customer_created',
23
- 'customer.updated': 'hyperline_customer_updated',
24
- } satisfies Record<string, TrackingEvent>;
25
-
26
- export type HyperlineWebhook = keyof typeof webhooks;
27
- export type HyperlineEvent<T extends HyperlineWebhook> = (typeof webhooks)[T];
28
- export type HyperlinePayload<T extends HyperlineWebhook> = {
29
- event_type: T;
30
- data: Record<string, any>;
31
- };
32
-
33
- export type BillableEvent = {
34
- record: {
35
- id: '202408_cus_w_Q7M9bXcHMKB6';
36
- amount: 26;
37
- };
38
- timestamp: '2024-08-07T07:35:20.307Z';
39
- event_type: 'api_call';
40
- customer_id: 'cus_w_Q7M9bXcHMKB6';
41
- };
42
- export type BillableEvents = {
43
- events_created: BillableEvent[];
44
- };
45
- export type CreateBillableEvent = {
46
- customer_id: string;
47
- event_type: 'api_call';
48
- timestamp: string;
49
- record: {
50
- id?: string;
51
- durationInMs?: number;
52
- isVerified?: true;
53
- amount?: number;
54
- amountGl?: number;
55
- amountNonGl?: number;
56
- };
57
- };
58
-
59
- type Logger = { error(message?: any, ...optionalParams: any[]): void };
60
-
61
- function arrayBufferToBase64(arrayBuffer: ArrayBuffer) {
62
- const uint8Array = new Uint8Array(arrayBuffer);
63
- const binaryString = String.fromCharCode.apply(null, uint8Array as any);
64
- return btoa(binaryString);
65
- }
66
-
67
- export class HyperlineAPI {
68
- constructor(token: string, logger: Logger = console) {
69
- this.headers = {
70
- 'Content-Type': 'application/json',
71
- Authorization: `Bearer ${token}`,
72
- };
73
- this.logger = logger;
74
- }
75
-
76
- private headers: Record<string, string>;
77
-
78
- private logger: Logger;
79
-
80
- private async fetchBasic<T>(
81
- path: string,
82
- options?: RequestInit,
83
- data?: Record<string, any>
84
- ): Promise<T | null> {
85
- if (data) options = { body: JSON.stringify(data), ...(options || {}) };
86
-
87
- const sandbox = this.headers.Authorization.includes('test')
88
- ? 'sandbox.'
89
- : '';
90
-
91
- const result = await fetch(`https://${sandbox}${path}`, {
92
- method: 'GET',
93
- ...options,
94
- headers: { ...this.headers, ...options?.headers },
95
- });
96
-
97
- const content: any = await result.json();
98
- if (!result || !result?.ok) {
99
- const status = result?.status;
100
- const statusText = result?.statusText;
101
-
102
- if (status === 429) {
103
- // get difference between rate limit reset and now
104
- const rateLimitReset = day(result?.headers.get('x-ratelimit-reset'));
105
- const diff = rateLimitReset.diff(day(), 'milliseconds');
106
-
107
- // wait until rate limit resets
108
- await new Promise((resolve) => setTimeout(resolve, diff));
109
-
110
- return await this.fetchBasic<T>(path, options, data);
111
- } else if (status === 404) {
112
- return null;
113
- } else
114
- throw new Error(
115
- `Hyperline Error ${status} (${statusText}) in ${path} for ${options?.method || 'GET'}: ${content.message}`
116
- );
117
- } else if (result.headers.get('content-type')?.includes('application/pdf'))
118
- return arrayBufferToBase64(await result.arrayBuffer()) as T;
119
-
120
- return content as T;
121
- }
122
-
123
- private async fetch<T>(
124
- path: string,
125
- options?: RequestInit,
126
- data?: Record<string, any>
127
- ): Promise<T | null> {
128
- return await this.fetchBasic(`api.hyperline.co${path}`, options, data);
129
- }
130
-
131
- private async fetchIngest<T>(
132
- path: string,
133
- options?: RequestInit,
134
- data?: Record<string, any>
135
- ): Promise<T | null> {
136
- return await this.fetchBasic(`ingest.hyperline.co${path}`, options, data);
137
- }
138
-
139
- // CUSTOMER
140
-
141
- async getCustomer(id?: string) {
142
- if (!id) {
143
- this.logger.error('Missing customer ID', { id });
144
- throw new Error('Missing customer ID');
145
- }
146
-
147
- return await this.fetch<
148
- paths['/v1/customers/{id}']['get']['responses'][200]['content']['application/json']
149
- >(`/v1/customers/${id}`);
150
- }
151
-
152
- async getCustomers(skip = 0, take = 100) {
153
- return await this.fetch<
154
- paths['/v1/customers']['get']['responses'][200]['content']['application/json']
155
- >(`/v1/customers?take=${take}&skip=${skip}`);
156
- }
157
-
158
- async getAllCustomers(
159
- items: paths['/v1/customers']['get']['responses'][200]['content']['application/json']['data'] = []
160
- ): Promise<
161
- paths['/v1/customers']['get']['responses'][200]['content']['application/json']['data']
162
- > {
163
- const { data } = (await this.getCustomers(items.length)) || { data: [] };
164
-
165
- return data.length
166
- ? this.getAllCustomers([...items, ...data])
167
- : [...items, ...data];
168
- }
169
-
170
- async createCustomer(
171
- data: NonNullable<
172
- paths['/v1/customers']['post']['requestBody']
173
- >['content']['application/json']
174
- ) {
175
- return await this.fetch<
176
- paths['/v1/customers']['post']['responses'][201]['content']['application/json']
177
- >(
178
- '/v1/customers',
179
- { method: 'POST' },
180
- { currency: 'USD', timezone: 'Etc/UTC', ...data }
181
- );
182
- }
183
-
184
- async updateCustomer(
185
- id: string,
186
- data: NonNullable<
187
- paths['/v1/customers/{id}']['put']['requestBody']
188
- >['content']['application/json']
189
- ) {
190
- if (!id) {
191
- this.logger.error('Missing customer ID', { id });
192
- throw new Error('Missing customer ID');
193
- }
194
-
195
- return await this.fetch<
196
- paths['/v1/customers/{id}']['put']['responses'][200]['content']['application/json']
197
- >(`/v1/customers/${id}`, { method: 'PUT' }, data);
198
- }
199
-
200
- async deleteCustomer(id: string) {
201
- return await this.fetch<
202
- paths['/v1/customers/{id}']['delete']['responses'][204]['content']
203
- >(`/v1/customers/${id}`, {
204
- method: 'DELETE',
205
- });
206
- }
207
-
208
- async archiveCustomer(id: string) {
209
- return await this.fetch<
210
- paths['/v1/customers/{id}/archive']['put']['responses'][200]['content']['application/json']
211
- >(`/v1/customers/${id}/archive`, {
212
- method: 'PUT',
213
- });
214
- }
215
-
216
- async unarchiveCustomer(id: string) {
217
- if (!id) {
218
- this.logger.error('Missing customer ID', { id });
219
- throw new Error('Missing customer ID');
220
- }
221
-
222
- return await this.fetch<
223
- paths['/v1/customers/{id}/unarchive']['put']['responses'][200]['content']['application/json']
224
- >(`/v1/customers/${id}/unarchive`, { method: 'PUT' });
225
- }
226
-
227
- async getCustomerPortal(id: string) {
228
- return await this.fetch<
229
- paths['/v1/customers/{id}/portal']['get']['responses'][200]['content']['application/json']
230
- >(`/v1/customers/${id}/portal`);
231
- }
232
-
233
- // SUBSCRIPTION
234
-
235
- async getSubscription(id: string) {
236
- if (!id) {
237
- this.logger.error('Missing subscription ID', { id });
238
- throw new Error('Missing subscription ID');
239
- }
240
-
241
- return await this.fetch<
242
- paths['/v2/subscriptions/{id}']['get']['responses'][200]['content']['application/json']
243
- >(`/v2/subscriptions/${id}?include_live_billing=true`);
244
- }
245
-
246
- async getSubscriptions(
247
- skip = 0,
248
- take = 100,
249
- query: operations['getSubscriptions']['parameters']['query'] = {
250
- status: 'all',
251
- }
252
- ) {
253
- return await this.fetch<
254
- paths['/v2/subscriptions']['get']['responses'][200]['content']['application/json']
255
- >(
256
- `/v2/subscriptions?take=${take}&skip=${skip}${Object.entries(query)
257
- .filter(([_, value]) => value !== undefined)
258
- .map(([key, value]) => `&${key}=${value}`)
259
- .join('')}`
260
- );
261
- }
262
-
263
- async getAllSubscriptions(
264
- items: paths['/v2/subscriptions']['get']['responses'][200]['content']['application/json']['data'] = [],
265
- query: operations['getSubscriptions']['parameters']['query'] = {}
266
- ): Promise<
267
- paths['/v2/subscriptions']['get']['responses'][200]['content']['application/json']['data']
268
- > {
269
- const { data } = (await this.getSubscriptions(
270
- items.length,
271
- 100,
272
- query
273
- )) || { data: [] };
274
-
275
- return data.length
276
- ? this.getAllSubscriptions([...items, ...data], query)
277
- : [...items, ...data];
278
- }
279
-
280
- async createSubscription(
281
- data: NonNullable<
282
- paths['/v2/subscriptions']['post']['requestBody']
283
- >['content']['application/json']
284
- ) {
285
- return await this.fetch<
286
- paths['/v2/subscriptions']['post']['responses'][201]['content']['application/json']
287
- >('/v2/subscriptions', { method: 'POST' }, data);
288
- }
289
-
290
- async updateSubscription(
291
- id: string,
292
- data: NonNullable<
293
- paths['/v1/subscriptions/{id}/update']['post']['requestBody']
294
- >['content']['application/json']
295
- ) {
296
- return await this.fetch<
297
- paths['/v1/subscriptions/{id}/update']['post']['responses'][201]['content']['application/json']
298
- >(`/v1/subscriptions/${id}/update`, { method: 'POST' }, data);
299
- }
300
-
301
- async cancelSubscription(
302
- id: string,
303
- data: NonNullable<
304
- paths['/v1/subscriptions/{id}/cancel']['post']['requestBody']
305
- >['content']['application/json']
306
- ) {
307
- return await this.fetch<
308
- paths['/v1/subscriptions/{id}/cancel']['post']['responses'][200]['content']['application/json']
309
- >(
310
- `/v1/subscriptions/${id}/cancel`,
311
- {
312
- method: 'POST',
313
- },
314
- data
315
- );
316
- }
317
-
318
- async reinstateSubscription(id: string) {
319
- return await this.fetch<
320
- paths['/v1/subscriptions/{id}/reinstate']['post']['responses'][200]['content']['application/json']
321
- >(`/v1/subscriptions/${id}/reinstate`, {
322
- method: 'POST',
323
- });
324
- }
325
-
326
- // PLAN
327
-
328
- async getPlan(id: string) {
329
- if (!id) {
330
- this.logger.error('Missing plan ID', { id });
331
- throw new Error('Missing plan ID');
332
- }
333
-
334
- return await this.fetch<
335
- paths['/v1/plans/{id}']['get']['responses'][200]['content']['application/json']
336
- >(`/v1/plans/${id}`);
337
- }
338
-
339
- async getPlans(skip = 0, take = 100) {
340
- return await this.fetch<
341
- paths['/v1/plans']['get']['responses'][200]['content']['application/json']
342
- >(`/v1/plans?take=${take}&skip=${skip}`);
343
- }
344
-
345
- // INVOICE
346
-
347
- async getInvoice(id: string) {
348
- if (!id) {
349
- this.logger.error('Missing invoice ID', { id });
350
- throw new Error('Missing invoice ID');
351
- }
352
-
353
- return await this.fetch<
354
- paths['/v1/invoices/{id}']['get']['responses'][200]['content']['application/json']
355
- >(`/v1/invoices/${id}`);
356
- }
357
-
358
- async getInvoices(
359
- skip = 0,
360
- take = 100,
361
- query: operations['getInvoices']['parameters']['query'] = { status: 'all' }
362
- ) {
363
- return await this.fetch<
364
- paths['/v1/invoices']['get']['responses'][200]['content']['application/json']
365
- >(
366
- `/v1/invoices?take=${take}&skip=${skip}&${Object.entries(query)
367
- .filter(([_, value]) => value !== undefined)
368
- .map(([key, value]) => `&${key}=${value}`)
369
- .join('')}`
370
- );
371
- }
372
-
373
- async getInvoicesByCustomerId(id: string) {
374
- return await this.fetch<
375
- paths['/v1/invoices']['get']['responses'][200]['content']['application/json']
376
- >(`/v1/invoices?customerId__equals=${id}`);
377
- }
378
-
379
- async getInvoiceDownload(id: string) {
380
- return await this.fetch<string>(
381
- // TODO: fix if type != unknown paths['/v1/invoices/{id}/download']['get']['responses'][200]['content']['application/pdf']
382
- `/v1/invoices/${id}/download`,
383
- {
384
- headers: { 'Content-type': 'application/pdf' },
385
- }
386
- );
387
- }
388
-
389
- async getAllInvoices(
390
- items: paths['/v1/invoices']['get']['responses'][200]['content']['application/json']['data'] = []
391
- ): Promise<
392
- paths['/v1/invoices']['get']['responses'][200]['content']['application/json']['data']
393
- > {
394
- const { data } = (await this.getInvoices(items.length)) || { data: [] };
395
-
396
- return data.length
397
- ? this.getAllInvoices([...items, ...data])
398
- : [...items, ...data];
399
- }
400
-
401
- // OTHERS
402
-
403
- async createBillableEvent(data: CreateBillableEvent[]) {
404
- if (!data.length) return { events_created: [] };
405
-
406
- return await this.fetchIngest<BillableEvents>(
407
- '/v1/events/batch',
408
- { method: 'POST' },
409
- data
410
- );
411
- }
412
-
413
- async getComponentToken(data: {
414
- customer_id: string;
415
- }) {
416
- return await this.fetch<
417
- paths['/v1/integrations/components/token']['post']['responses'][201]['content']['application/json']
418
- >('/v1/integrations/components/token', { method: 'POST' }, data);
419
- }
420
- }
421
-
422
- export function useHyperline(
423
- env: {
424
- PRODUCTION_HYPERLINE_API_KEY: string;
425
- DEV_HYPERLINE_API_KEY: string;
426
- },
427
- environment: 'production' | 'development',
428
- logger: Logger
429
- ) {
430
- const isProduction = environment === 'production';
431
-
432
- const token = isProduction
433
- ? env.PRODUCTION_HYPERLINE_API_KEY
434
- : env.DEV_HYPERLINE_API_KEY;
435
-
436
- const hyperline = useHyperlineByToken(token, logger);
437
-
438
- return { hyperline, token, isProduction };
439
- }
440
-
441
- export function useHyperlineByToken(token: string, logger: Logger = console) {
442
- return new HyperlineAPI(token, logger);
443
- }
1
+ export * from './const';
2
+ export * from './types';
3
+ export * from './client';
4
+ export * from './hooks';
package/src/types.ts ADDED
@@ -0,0 +1,43 @@
1
+ import type { components, paths } from './_types.generated';
2
+ import { WEBHOOKS } from './const';
3
+
4
+ export type HyperlineEntities = components['schemas'];
5
+
6
+ export type HyperlineEndpoints = paths;
7
+
8
+ export type HyperlineWebhook = keyof typeof WEBHOOKS;
9
+
10
+ export type HyperlineEvent<T extends HyperlineWebhook> = (typeof WEBHOOKS)[T];
11
+
12
+ export type HyperlinePayload<T extends HyperlineWebhook> = {
13
+ event_type: T;
14
+ data: Record<string, any>;
15
+ };
16
+
17
+ export type BillableEvent = {
18
+ record: {
19
+ id: '202408_cus_w_Q7M9bXcHMKB6';
20
+ amount: 26;
21
+ };
22
+ timestamp: '2024-08-07T07:35:20.307Z';
23
+ event_type: 'api_call';
24
+ customer_id: 'cus_w_Q7M9bXcHMKB6';
25
+ };
26
+
27
+ export type BillableEvents = {
28
+ events_created: BillableEvent[];
29
+ };
30
+
31
+ export type CreateBillableEvent = {
32
+ customer_id: string;
33
+ event_type: 'api_call';
34
+ timestamp: string;
35
+ record: {
36
+ id?: string;
37
+ durationInMs?: number;
38
+ isVerified?: true;
39
+ amount?: number;
40
+ amountGl?: number;
41
+ amountNonGl?: number;
42
+ };
43
+ };
package/src/utils.ts ADDED
@@ -0,0 +1,5 @@
1
+ export function arrayBufferToBase64(arrayBuffer: ArrayBuffer) {
2
+ const uint8Array = new Uint8Array(arrayBuffer);
3
+ const binaryString = String.fromCharCode.apply(null, uint8Array as any);
4
+ return btoa(binaryString);
5
+ }