@genvoris/node 1.0.0 → 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/LICENSE +21 -21
- package/README.md +184 -132
- package/dist/index.d.mts +98 -1
- package/dist/index.d.ts +98 -1
- package/dist/index.js +96 -13
- package/dist/index.mjs +96 -13
- package/package.json +55 -52
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Genvoris
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Genvoris
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,132 +1,184 @@
|
|
|
1
|
-
# @genvoris/node
|
|
2
|
-
|
|
3
|
-
Official Node.js SDK for the [Genvoris Virtual Try-On API](https://docs.genvoris.org).
|
|
4
|
-
|
|
5
|
-
## Requirements
|
|
6
|
-
|
|
7
|
-
Node.js **18** or higher (uses native `fetch`).
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm install @genvoris/node
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Quick start
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
import Genvoris from '@genvoris/node';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
await gv.customers.
|
|
41
|
-
await gv.customers.
|
|
42
|
-
await gv.customers.
|
|
43
|
-
await gv.customers.
|
|
44
|
-
await gv.customers.
|
|
45
|
-
await gv.customers.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
await gv.plans.
|
|
53
|
-
await gv.plans.
|
|
54
|
-
await gv.plans.
|
|
55
|
-
await gv.plans.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
await gv.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
1
|
+
# @genvoris/node
|
|
2
|
+
|
|
3
|
+
Official Node.js SDK for the [Genvoris Virtual Try-On API](https://docs.genvoris.org).
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
Node.js **18** or higher (uses native `fetch`).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @genvoris/node
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import Genvoris from '@genvoris/node';
|
|
19
|
+
|
|
20
|
+
// Server-side only. Never expose GENVORIS_API_KEY in browser code.
|
|
21
|
+
const gv = new Genvoris({ apiKey: process.env.GENVORIS_API_KEY! });
|
|
22
|
+
|
|
23
|
+
// Create a customer
|
|
24
|
+
const customer = await gv.customers.create({
|
|
25
|
+
externalId: 'user_42',
|
|
26
|
+
email: 'shopper@example.com',
|
|
27
|
+
planId: 'pln_xxxxxxxx',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Mint a session token for the widget
|
|
31
|
+
const session = await gv.sessions.mint({ customerId: customer.id });
|
|
32
|
+
// → pass session.token to your frontend
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Resources
|
|
36
|
+
|
|
37
|
+
### Customers
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
await gv.customers.create({ externalId, email?, planId?, metadata? })
|
|
41
|
+
await gv.customers.retrieve(id)
|
|
42
|
+
await gv.customers.update(id, { email?, planId?, status?, resetPeriod? })
|
|
43
|
+
await gv.customers.list({ status?, limit?, cursor? })
|
|
44
|
+
await gv.customers.cancel(id)
|
|
45
|
+
await gv.customers.usage(id)
|
|
46
|
+
await gv.customers.sessions(id)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Plans
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
await gv.plans.list({ include_inactive? })
|
|
53
|
+
await gv.plans.create({ name, monthlyTryOns, externalPriceId?, active? })
|
|
54
|
+
await gv.plans.retrieve(id)
|
|
55
|
+
await gv.plans.update(id, { name?, monthlyTryOns?, active? })
|
|
56
|
+
await gv.plans.archive(id)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Sessions
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
await gv.sessions.mint({ customerId, ttlSeconds? })
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Events
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
await gv.events.track({
|
|
69
|
+
sessionId: 'session_12345678',
|
|
70
|
+
eventType: 'WIDGET_OPENED',
|
|
71
|
+
productId: 'sku_123',
|
|
72
|
+
productTitle: 'Linen Shirt',
|
|
73
|
+
pageUrl: 'https://store.example/products/linen-shirt',
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
await gv.events.trackBatch([
|
|
77
|
+
{ sessionId, eventType: 'PHOTO_UPLOADED' },
|
|
78
|
+
{ sessionId, eventType: 'TRYON_GENERATED', productId },
|
|
79
|
+
])
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Conversions and returns
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
await gv.conversions.create({
|
|
86
|
+
orderId: 'order_1001',
|
|
87
|
+
platform: 'custom',
|
|
88
|
+
amountCents: 12900,
|
|
89
|
+
currency: 'USD',
|
|
90
|
+
quantity: 1,
|
|
91
|
+
productId: 'sku_123',
|
|
92
|
+
productTitle: 'Linen Shirt',
|
|
93
|
+
sessionId: 'session_12345678',
|
|
94
|
+
customerEmail: 'shopper@example.com',
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
await gv.returns.create({
|
|
98
|
+
orderId: 'order_1001',
|
|
99
|
+
platform: 'custom',
|
|
100
|
+
refundedAmountCents: 12900,
|
|
101
|
+
currency: 'USD',
|
|
102
|
+
reason: 'size_exchange',
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Webhooks
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
await gv.webhooks.list()
|
|
110
|
+
await gv.webhooks.create({ url, secret, events })
|
|
111
|
+
await gv.webhooks.test(id)
|
|
112
|
+
await gv.webhooks.delete(id)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Hosted widget integration
|
|
116
|
+
|
|
117
|
+
Use this SDK from your backend to mint short-lived customer session tokens, record conversions/returns, and verify webhooks. For browser-hosted widgets, route try-on and analytics calls through your own same-origin endpoint or another approved public-widget flow; do not place `gvk_live_...` keys in HTML or client JavaScript.
|
|
118
|
+
|
|
119
|
+
A typical flow is:
|
|
120
|
+
|
|
121
|
+
1. Backend uses `gv.customers.create(...)` and `gv.sessions.mint(...)`.
|
|
122
|
+
2. Frontend loads `https://api.genvoris.org/widget.js?no_fab=1` with a same-origin `data-api-url`/`data-events-url` and the minted customer token.
|
|
123
|
+
3. Backend records orders with `gv.conversions.create(...)` and refunds with `gv.returns.create(...)`.
|
|
124
|
+
|
|
125
|
+
## Webhook verification
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { WebhooksResource } from '@genvoris/node';
|
|
129
|
+
|
|
130
|
+
// In your Express / Next.js handler — pass the raw body, not parsed JSON
|
|
131
|
+
const event = WebhooksResource.verify({
|
|
132
|
+
payload: req.body,
|
|
133
|
+
header: req.header('x-genvoris-signature') ?? '',
|
|
134
|
+
secret: process.env.GENVORIS_WEBHOOK_SECRET!,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
console.log(event.type, event.data);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The signature format is `t=<unix>,v1=<hex>`. The signed string is `${timestamp}.${rawBody}` using HMAC-SHA256. Verification uses `crypto.timingSafeEqual`.
|
|
141
|
+
|
|
142
|
+
## Error handling
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import {
|
|
146
|
+
GenvorisAPIError,
|
|
147
|
+
GenvorisAuthError,
|
|
148
|
+
GenvorisRateLimitError,
|
|
149
|
+
GenvorisValidationError,
|
|
150
|
+
} from '@genvoris/node';
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
await gv.customers.retrieve('cus_missing');
|
|
154
|
+
} catch (err) {
|
|
155
|
+
if (err instanceof GenvorisAuthError) {
|
|
156
|
+
// 401 / 403 — bad or revoked key
|
|
157
|
+
} else if (err instanceof GenvorisRateLimitError) {
|
|
158
|
+
console.log(`retry after ${err.retryAfterSeconds}s`);
|
|
159
|
+
} else if (err instanceof GenvorisValidationError) {
|
|
160
|
+
console.error(err.fieldErrors);
|
|
161
|
+
} else if (err instanceof GenvorisAPIError) {
|
|
162
|
+
console.error(err.status, err.code, err.requestId);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The client automatically retries `429`, `502`, `503`, and `504` responses using exponential backoff with jitter (`min(2^n × 250 ms, 8 000 ms)`), up to `maxRetries` (default: 3).
|
|
168
|
+
|
|
169
|
+
## Configuration
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const gv = new Genvoris({
|
|
173
|
+
apiKey: process.env.GENVORIS_API_KEY!,
|
|
174
|
+
baseUrl: 'https://genvoris.org/api/v1', // default
|
|
175
|
+
timeoutMs: 30_000, // default 30 s
|
|
176
|
+
maxRetries: 3, // default 3
|
|
177
|
+
defaultHeaders: { 'X-My-Header': 'val' },
|
|
178
|
+
fetch: customFetch, // bring-your-own fetch
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/index.d.mts
CHANGED
|
@@ -161,6 +161,12 @@ interface SessionMintParams {
|
|
|
161
161
|
/** JWT lifetime in seconds. Default: 900 (15 min). */
|
|
162
162
|
ttlSeconds?: number;
|
|
163
163
|
}
|
|
164
|
+
interface SessionRevokeParams {
|
|
165
|
+
/** Genvoris customer ID or your `externalId`. */
|
|
166
|
+
customerId: string;
|
|
167
|
+
/** The `jti` claim of the session token to revoke. */
|
|
168
|
+
jti: string;
|
|
169
|
+
}
|
|
164
170
|
interface MintedSession {
|
|
165
171
|
token: string;
|
|
166
172
|
token_type: 'Bearer';
|
|
@@ -176,6 +182,10 @@ interface MintedSession {
|
|
|
176
182
|
period_end: string | null;
|
|
177
183
|
};
|
|
178
184
|
}
|
|
185
|
+
interface RevokedSession {
|
|
186
|
+
jti: string;
|
|
187
|
+
revoked: true;
|
|
188
|
+
}
|
|
179
189
|
declare class SessionsResource {
|
|
180
190
|
private readonly config;
|
|
181
191
|
constructor(config: GenvorisConfig);
|
|
@@ -186,6 +196,14 @@ declare class SessionsResource {
|
|
|
186
196
|
* Genvoris widget — never exposed in client-side code directly.
|
|
187
197
|
*/
|
|
188
198
|
mint({ customerId, ttlSeconds }: SessionMintParams): Promise<MintedSession>;
|
|
199
|
+
/**
|
|
200
|
+
* Revoke a previously minted session token by its `jti` claim.
|
|
201
|
+
*
|
|
202
|
+
* Use this on end-customer logout or when a token is suspected
|
|
203
|
+
* compromised. The token is rejected immediately even though its
|
|
204
|
+
* signature and expiry are otherwise still valid. Idempotent.
|
|
205
|
+
*/
|
|
206
|
+
revoke({ customerId, jti }: SessionRevokeParams): Promise<RevokedSession>;
|
|
189
207
|
}
|
|
190
208
|
|
|
191
209
|
interface WebhookCreateParams {
|
|
@@ -265,6 +283,82 @@ declare class WebhooksResource {
|
|
|
265
283
|
static verify<T extends Record<string, unknown> = Record<string, unknown>>({ payload, header, secret, toleranceSeconds, }: WebhookVerifyOptions): GenvorisEvent<T>;
|
|
266
284
|
}
|
|
267
285
|
|
|
286
|
+
type WidgetEventType = 'WIDGET_OPENED' | 'PHOTO_UPLOADED' | 'TRYON_GENERATED' | 'TRYON_VIEWED' | 'RESULT_SHARED' | 'ADDED_TO_CART' | 'CHECKOUT_STARTED' | 'CLOSED';
|
|
287
|
+
interface WidgetEventInput {
|
|
288
|
+
sessionId: string;
|
|
289
|
+
eventType: WidgetEventType;
|
|
290
|
+
productId?: string;
|
|
291
|
+
productTitle?: string;
|
|
292
|
+
pageUrl?: string;
|
|
293
|
+
metadata?: Record<string, unknown>;
|
|
294
|
+
}
|
|
295
|
+
interface EventBatchInput {
|
|
296
|
+
events: WidgetEventInput[];
|
|
297
|
+
}
|
|
298
|
+
interface EventsAccepted {
|
|
299
|
+
accepted: number;
|
|
300
|
+
}
|
|
301
|
+
declare class EventsResource {
|
|
302
|
+
private readonly config;
|
|
303
|
+
constructor(config: GenvorisConfig);
|
|
304
|
+
/** Track one hosted-widget funnel event. */
|
|
305
|
+
track(event: WidgetEventInput): Promise<EventsAccepted>;
|
|
306
|
+
/** Track a batch of 1–50 hosted-widget funnel events. */
|
|
307
|
+
trackBatch(events: WidgetEventInput[]): Promise<EventsAccepted>;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
type ConversionPlatform = 'shopify' | 'woocommerce' | 'custom';
|
|
311
|
+
interface ConversionCreateParams {
|
|
312
|
+
/** Platform order ID. Duplicate order IDs are idempotently deduped per merchant/platform. */
|
|
313
|
+
orderId: string;
|
|
314
|
+
platform: ConversionPlatform;
|
|
315
|
+
/** Order value in integer cents. */
|
|
316
|
+
amountCents: number;
|
|
317
|
+
/** ISO 4217 currency code. Defaults to USD server-side. */
|
|
318
|
+
currency?: string;
|
|
319
|
+
quantity?: number;
|
|
320
|
+
productId?: string;
|
|
321
|
+
productTitle?: string;
|
|
322
|
+
/** Widget session ID for hard attribution. */
|
|
323
|
+
sessionId?: string;
|
|
324
|
+
/** Hashed by the portal before storage. */
|
|
325
|
+
customerEmail?: string;
|
|
326
|
+
/** Soft-attribution lookback window. Default: 1440 minutes. */
|
|
327
|
+
attributionWindowMinutes?: number;
|
|
328
|
+
}
|
|
329
|
+
interface ConversionEvent {
|
|
330
|
+
id: string;
|
|
331
|
+
attributedFromTryOn: boolean;
|
|
332
|
+
deduped?: boolean;
|
|
333
|
+
}
|
|
334
|
+
declare class ConversionsResource {
|
|
335
|
+
private readonly config;
|
|
336
|
+
constructor(config: GenvorisConfig);
|
|
337
|
+
/** Store an order conversion for attribution/lift analytics. */
|
|
338
|
+
create(params: ConversionCreateParams): Promise<ConversionEvent>;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
interface ReturnCreateParams {
|
|
342
|
+
/** Platform order ID matching a conversion when possible. */
|
|
343
|
+
orderId: string;
|
|
344
|
+
platform: ConversionPlatform;
|
|
345
|
+
/** Refunded amount in integer cents. */
|
|
346
|
+
refundedAmountCents: number;
|
|
347
|
+
/** ISO 4217 currency code. Defaults to USD server-side. */
|
|
348
|
+
currency?: string;
|
|
349
|
+
reason?: string;
|
|
350
|
+
}
|
|
351
|
+
interface ReturnEvent {
|
|
352
|
+
id: string;
|
|
353
|
+
conversionEventId: string | null;
|
|
354
|
+
}
|
|
355
|
+
declare class ReturnsResource {
|
|
356
|
+
private readonly config;
|
|
357
|
+
constructor(config: GenvorisConfig);
|
|
358
|
+
/** Store a return/refund event for conversion and returns-saved analytics. */
|
|
359
|
+
create(params: ReturnCreateParams): Promise<ReturnEvent>;
|
|
360
|
+
}
|
|
361
|
+
|
|
268
362
|
declare class GenvorisAPIError extends Error {
|
|
269
363
|
readonly status: number;
|
|
270
364
|
readonly code: string;
|
|
@@ -322,7 +416,10 @@ declare class Genvoris {
|
|
|
322
416
|
readonly plans: PlansResource;
|
|
323
417
|
readonly sessions: SessionsResource;
|
|
324
418
|
readonly webhooks: WebhooksResource;
|
|
419
|
+
readonly events: EventsResource;
|
|
420
|
+
readonly conversions: ConversionsResource;
|
|
421
|
+
readonly returns: ReturnsResource;
|
|
325
422
|
constructor(config: GenvorisConfig);
|
|
326
423
|
}
|
|
327
424
|
|
|
328
|
-
export { type Customer, type CustomerCreateParams, type CustomerList, type CustomerListParams, type CustomerSession, type CustomerSessionList, type CustomerUpdateParams, type CustomerUsage, GenvorisAPIError, GenvorisAuthError, type GenvorisConfig, type GenvorisEvent, GenvorisRateLimitError, GenvorisValidationError, type MintedSession, type Plan, type PlanCreateParams, type PlanList, type PlanListParams, type PlanUpdateParams, type SessionMintParams, type WebhookCreateParams, type WebhookEndpoint, type WebhookEndpointList, type WebhookVerifyOptions, WebhooksResource, Genvoris as default };
|
|
425
|
+
export { type ConversionCreateParams, type ConversionEvent, type ConversionPlatform, type Customer, type CustomerCreateParams, type CustomerList, type CustomerListParams, type CustomerSession, type CustomerSessionList, type CustomerUpdateParams, type CustomerUsage, type EventBatchInput, type EventsAccepted, GenvorisAPIError, GenvorisAuthError, type GenvorisConfig, type GenvorisEvent, GenvorisRateLimitError, GenvorisValidationError, type MintedSession, type Plan, type PlanCreateParams, type PlanList, type PlanListParams, type PlanUpdateParams, type ReturnCreateParams, type ReturnEvent, type SessionMintParams, type WebhookCreateParams, type WebhookEndpoint, type WebhookEndpointList, type WebhookVerifyOptions, WebhooksResource, type WidgetEventInput, type WidgetEventType, Genvoris as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -161,6 +161,12 @@ interface SessionMintParams {
|
|
|
161
161
|
/** JWT lifetime in seconds. Default: 900 (15 min). */
|
|
162
162
|
ttlSeconds?: number;
|
|
163
163
|
}
|
|
164
|
+
interface SessionRevokeParams {
|
|
165
|
+
/** Genvoris customer ID or your `externalId`. */
|
|
166
|
+
customerId: string;
|
|
167
|
+
/** The `jti` claim of the session token to revoke. */
|
|
168
|
+
jti: string;
|
|
169
|
+
}
|
|
164
170
|
interface MintedSession {
|
|
165
171
|
token: string;
|
|
166
172
|
token_type: 'Bearer';
|
|
@@ -176,6 +182,10 @@ interface MintedSession {
|
|
|
176
182
|
period_end: string | null;
|
|
177
183
|
};
|
|
178
184
|
}
|
|
185
|
+
interface RevokedSession {
|
|
186
|
+
jti: string;
|
|
187
|
+
revoked: true;
|
|
188
|
+
}
|
|
179
189
|
declare class SessionsResource {
|
|
180
190
|
private readonly config;
|
|
181
191
|
constructor(config: GenvorisConfig);
|
|
@@ -186,6 +196,14 @@ declare class SessionsResource {
|
|
|
186
196
|
* Genvoris widget — never exposed in client-side code directly.
|
|
187
197
|
*/
|
|
188
198
|
mint({ customerId, ttlSeconds }: SessionMintParams): Promise<MintedSession>;
|
|
199
|
+
/**
|
|
200
|
+
* Revoke a previously minted session token by its `jti` claim.
|
|
201
|
+
*
|
|
202
|
+
* Use this on end-customer logout or when a token is suspected
|
|
203
|
+
* compromised. The token is rejected immediately even though its
|
|
204
|
+
* signature and expiry are otherwise still valid. Idempotent.
|
|
205
|
+
*/
|
|
206
|
+
revoke({ customerId, jti }: SessionRevokeParams): Promise<RevokedSession>;
|
|
189
207
|
}
|
|
190
208
|
|
|
191
209
|
interface WebhookCreateParams {
|
|
@@ -265,6 +283,82 @@ declare class WebhooksResource {
|
|
|
265
283
|
static verify<T extends Record<string, unknown> = Record<string, unknown>>({ payload, header, secret, toleranceSeconds, }: WebhookVerifyOptions): GenvorisEvent<T>;
|
|
266
284
|
}
|
|
267
285
|
|
|
286
|
+
type WidgetEventType = 'WIDGET_OPENED' | 'PHOTO_UPLOADED' | 'TRYON_GENERATED' | 'TRYON_VIEWED' | 'RESULT_SHARED' | 'ADDED_TO_CART' | 'CHECKOUT_STARTED' | 'CLOSED';
|
|
287
|
+
interface WidgetEventInput {
|
|
288
|
+
sessionId: string;
|
|
289
|
+
eventType: WidgetEventType;
|
|
290
|
+
productId?: string;
|
|
291
|
+
productTitle?: string;
|
|
292
|
+
pageUrl?: string;
|
|
293
|
+
metadata?: Record<string, unknown>;
|
|
294
|
+
}
|
|
295
|
+
interface EventBatchInput {
|
|
296
|
+
events: WidgetEventInput[];
|
|
297
|
+
}
|
|
298
|
+
interface EventsAccepted {
|
|
299
|
+
accepted: number;
|
|
300
|
+
}
|
|
301
|
+
declare class EventsResource {
|
|
302
|
+
private readonly config;
|
|
303
|
+
constructor(config: GenvorisConfig);
|
|
304
|
+
/** Track one hosted-widget funnel event. */
|
|
305
|
+
track(event: WidgetEventInput): Promise<EventsAccepted>;
|
|
306
|
+
/** Track a batch of 1–50 hosted-widget funnel events. */
|
|
307
|
+
trackBatch(events: WidgetEventInput[]): Promise<EventsAccepted>;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
type ConversionPlatform = 'shopify' | 'woocommerce' | 'custom';
|
|
311
|
+
interface ConversionCreateParams {
|
|
312
|
+
/** Platform order ID. Duplicate order IDs are idempotently deduped per merchant/platform. */
|
|
313
|
+
orderId: string;
|
|
314
|
+
platform: ConversionPlatform;
|
|
315
|
+
/** Order value in integer cents. */
|
|
316
|
+
amountCents: number;
|
|
317
|
+
/** ISO 4217 currency code. Defaults to USD server-side. */
|
|
318
|
+
currency?: string;
|
|
319
|
+
quantity?: number;
|
|
320
|
+
productId?: string;
|
|
321
|
+
productTitle?: string;
|
|
322
|
+
/** Widget session ID for hard attribution. */
|
|
323
|
+
sessionId?: string;
|
|
324
|
+
/** Hashed by the portal before storage. */
|
|
325
|
+
customerEmail?: string;
|
|
326
|
+
/** Soft-attribution lookback window. Default: 1440 minutes. */
|
|
327
|
+
attributionWindowMinutes?: number;
|
|
328
|
+
}
|
|
329
|
+
interface ConversionEvent {
|
|
330
|
+
id: string;
|
|
331
|
+
attributedFromTryOn: boolean;
|
|
332
|
+
deduped?: boolean;
|
|
333
|
+
}
|
|
334
|
+
declare class ConversionsResource {
|
|
335
|
+
private readonly config;
|
|
336
|
+
constructor(config: GenvorisConfig);
|
|
337
|
+
/** Store an order conversion for attribution/lift analytics. */
|
|
338
|
+
create(params: ConversionCreateParams): Promise<ConversionEvent>;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
interface ReturnCreateParams {
|
|
342
|
+
/** Platform order ID matching a conversion when possible. */
|
|
343
|
+
orderId: string;
|
|
344
|
+
platform: ConversionPlatform;
|
|
345
|
+
/** Refunded amount in integer cents. */
|
|
346
|
+
refundedAmountCents: number;
|
|
347
|
+
/** ISO 4217 currency code. Defaults to USD server-side. */
|
|
348
|
+
currency?: string;
|
|
349
|
+
reason?: string;
|
|
350
|
+
}
|
|
351
|
+
interface ReturnEvent {
|
|
352
|
+
id: string;
|
|
353
|
+
conversionEventId: string | null;
|
|
354
|
+
}
|
|
355
|
+
declare class ReturnsResource {
|
|
356
|
+
private readonly config;
|
|
357
|
+
constructor(config: GenvorisConfig);
|
|
358
|
+
/** Store a return/refund event for conversion and returns-saved analytics. */
|
|
359
|
+
create(params: ReturnCreateParams): Promise<ReturnEvent>;
|
|
360
|
+
}
|
|
361
|
+
|
|
268
362
|
declare class GenvorisAPIError extends Error {
|
|
269
363
|
readonly status: number;
|
|
270
364
|
readonly code: string;
|
|
@@ -322,7 +416,10 @@ declare class Genvoris {
|
|
|
322
416
|
readonly plans: PlansResource;
|
|
323
417
|
readonly sessions: SessionsResource;
|
|
324
418
|
readonly webhooks: WebhooksResource;
|
|
419
|
+
readonly events: EventsResource;
|
|
420
|
+
readonly conversions: ConversionsResource;
|
|
421
|
+
readonly returns: ReturnsResource;
|
|
325
422
|
constructor(config: GenvorisConfig);
|
|
326
423
|
}
|
|
327
424
|
|
|
328
|
-
export { type Customer, type CustomerCreateParams, type CustomerList, type CustomerListParams, type CustomerSession, type CustomerSessionList, type CustomerUpdateParams, type CustomerUsage, GenvorisAPIError, GenvorisAuthError, type GenvorisConfig, type GenvorisEvent, GenvorisRateLimitError, GenvorisValidationError, type MintedSession, type Plan, type PlanCreateParams, type PlanList, type PlanListParams, type PlanUpdateParams, type SessionMintParams, type WebhookCreateParams, type WebhookEndpoint, type WebhookEndpointList, type WebhookVerifyOptions, WebhooksResource, Genvoris as default };
|
|
425
|
+
export { type ConversionCreateParams, type ConversionEvent, type ConversionPlatform, type Customer, type CustomerCreateParams, type CustomerList, type CustomerListParams, type CustomerSession, type CustomerSessionList, type CustomerUpdateParams, type CustomerUsage, type EventBatchInput, type EventsAccepted, GenvorisAPIError, GenvorisAuthError, type GenvorisConfig, type GenvorisEvent, GenvorisRateLimitError, GenvorisValidationError, type MintedSession, type Plan, type PlanCreateParams, type PlanList, type PlanListParams, type PlanUpdateParams, type ReturnCreateParams, type ReturnEvent, type SessionMintParams, type WebhookCreateParams, type WebhookEndpoint, type WebhookEndpointList, type WebhookVerifyOptions, WebhooksResource, type WidgetEventInput, type WidgetEventType, Genvoris as default };
|
package/dist/index.js
CHANGED
|
@@ -64,12 +64,12 @@ var GenvorisValidationError = class extends GenvorisAPIError {
|
|
|
64
64
|
var RETRY_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
65
65
|
var MAX_DELAY_MS = 8e3;
|
|
66
66
|
var DEFAULT_BASE_URL = "https://genvoris.org/api/v1";
|
|
67
|
-
var SDK_VERSION = "1.
|
|
67
|
+
var SDK_VERSION = "1.1.0";
|
|
68
68
|
function sleep(ms) {
|
|
69
69
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
70
70
|
}
|
|
71
71
|
async function request(config, path, opts = {}, attempt = 0) {
|
|
72
|
-
const { method = "GET", body, query } = opts;
|
|
72
|
+
const { method = "GET", body, query, contentType } = opts;
|
|
73
73
|
const fetchFn = config.fetch ?? globalThis.fetch;
|
|
74
74
|
const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
75
75
|
let url = `${baseUrl}${path}`;
|
|
@@ -88,20 +88,33 @@ async function request(config, path, opts = {}, attempt = 0) {
|
|
|
88
88
|
);
|
|
89
89
|
let res;
|
|
90
90
|
try {
|
|
91
|
+
const headers = {
|
|
92
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
93
|
+
"User-Agent": `genvoris-node/${SDK_VERSION}`,
|
|
94
|
+
Accept: "application/json",
|
|
95
|
+
...config.defaultHeaders
|
|
96
|
+
};
|
|
97
|
+
if (body !== void 0 || contentType) {
|
|
98
|
+
headers["Content-Type"] = contentType ?? "application/json";
|
|
99
|
+
}
|
|
91
100
|
res = await fetchFn(url, {
|
|
92
101
|
method,
|
|
93
|
-
headers
|
|
94
|
-
Authorization: `Bearer ${config.apiKey}`,
|
|
95
|
-
"Content-Type": "application/json",
|
|
96
|
-
"User-Agent": `genvoris-node/${SDK_VERSION}`,
|
|
97
|
-
...config.defaultHeaders
|
|
98
|
-
},
|
|
102
|
+
headers,
|
|
99
103
|
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
100
104
|
signal: controller.signal
|
|
101
105
|
});
|
|
102
|
-
}
|
|
106
|
+
} catch (err) {
|
|
103
107
|
clearTimeout(timerId);
|
|
108
|
+
if (attempt < (config.maxRetries ?? 3)) {
|
|
109
|
+
const target = Math.pow(2, attempt) * 250;
|
|
110
|
+
const jittered = target * (0.7 + Math.random() * 0.6);
|
|
111
|
+
const delay = Math.min(jittered, MAX_DELAY_MS);
|
|
112
|
+
await sleep(delay);
|
|
113
|
+
return request(config, path, opts, attempt + 1);
|
|
114
|
+
}
|
|
115
|
+
throw err;
|
|
104
116
|
}
|
|
117
|
+
clearTimeout(timerId);
|
|
105
118
|
if (res.ok) {
|
|
106
119
|
if (res.status === 204) return void 0;
|
|
107
120
|
return res.json();
|
|
@@ -112,13 +125,14 @@ async function request(config, path, opts = {}, attempt = 0) {
|
|
|
112
125
|
errBody = await res.json();
|
|
113
126
|
} catch {
|
|
114
127
|
}
|
|
115
|
-
const code = errBody.error
|
|
116
|
-
const message = errBody.message
|
|
128
|
+
const code = errBody.error || "unknown_error";
|
|
129
|
+
const message = errBody.message || code;
|
|
117
130
|
if (RETRY_STATUSES.has(res.status)) {
|
|
118
131
|
const maxRetries = config.maxRetries ?? 3;
|
|
119
132
|
if (attempt < maxRetries) {
|
|
120
|
-
const
|
|
121
|
-
const
|
|
133
|
+
const target = Math.pow(2, attempt) * 250;
|
|
134
|
+
const jittered = target * (0.7 + Math.random() * 0.6);
|
|
135
|
+
const delay = Math.min(jittered, MAX_DELAY_MS);
|
|
122
136
|
await sleep(delay);
|
|
123
137
|
return request(config, path, opts, attempt + 1);
|
|
124
138
|
}
|
|
@@ -262,12 +276,29 @@ var SessionsResource = class {
|
|
|
262
276
|
}
|
|
263
277
|
);
|
|
264
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Revoke a previously minted session token by its `jti` claim.
|
|
281
|
+
*
|
|
282
|
+
* Use this on end-customer logout or when a token is suspected
|
|
283
|
+
* compromised. The token is rejected immediately even though its
|
|
284
|
+
* signature and expiry are otherwise still valid. Idempotent.
|
|
285
|
+
*/
|
|
286
|
+
revoke({ customerId, jti }) {
|
|
287
|
+
return request(
|
|
288
|
+
this.config,
|
|
289
|
+
`/customers/${encodeURIComponent(customerId)}/sessions/${encodeURIComponent(jti)}`,
|
|
290
|
+
{ method: "DELETE" }
|
|
291
|
+
);
|
|
292
|
+
}
|
|
265
293
|
};
|
|
266
294
|
|
|
267
295
|
// src/resources/webhooks.ts
|
|
268
296
|
var import_node_crypto = require("crypto");
|
|
269
297
|
function hexToBytes(hex) {
|
|
270
298
|
if (hex.length % 2 !== 0) throw new Error("genvoris: invalid hex string");
|
|
299
|
+
if (!/^[a-f0-9]+$/i.test(hex)) {
|
|
300
|
+
throw new Error("genvoris: invalid hex string \u2014 non-hex characters");
|
|
301
|
+
}
|
|
271
302
|
const bytes = new Uint8Array(hex.length / 2);
|
|
272
303
|
for (let i = 0; i < bytes.length; i++) {
|
|
273
304
|
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
@@ -362,6 +393,55 @@ var WebhooksResource = class {
|
|
|
362
393
|
}
|
|
363
394
|
};
|
|
364
395
|
|
|
396
|
+
// src/resources/events.ts
|
|
397
|
+
var EventsResource = class {
|
|
398
|
+
constructor(config) {
|
|
399
|
+
this.config = config;
|
|
400
|
+
}
|
|
401
|
+
/** Track one hosted-widget funnel event. */
|
|
402
|
+
track(event) {
|
|
403
|
+
return request(this.config, "/events", {
|
|
404
|
+
method: "POST",
|
|
405
|
+
body: event
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
/** Track a batch of 1–50 hosted-widget funnel events. */
|
|
409
|
+
trackBatch(events) {
|
|
410
|
+
return request(this.config, "/events", {
|
|
411
|
+
method: "POST",
|
|
412
|
+
body: { events }
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// src/resources/conversions.ts
|
|
418
|
+
var ConversionsResource = class {
|
|
419
|
+
constructor(config) {
|
|
420
|
+
this.config = config;
|
|
421
|
+
}
|
|
422
|
+
/** Store an order conversion for attribution/lift analytics. */
|
|
423
|
+
create(params) {
|
|
424
|
+
return request(this.config, "/conversions", {
|
|
425
|
+
method: "POST",
|
|
426
|
+
body: params
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
// src/resources/returns.ts
|
|
432
|
+
var ReturnsResource = class {
|
|
433
|
+
constructor(config) {
|
|
434
|
+
this.config = config;
|
|
435
|
+
}
|
|
436
|
+
/** Store a return/refund event for conversion and returns-saved analytics. */
|
|
437
|
+
create(params) {
|
|
438
|
+
return request(this.config, "/returns", {
|
|
439
|
+
method: "POST",
|
|
440
|
+
body: params
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
365
445
|
// src/index.ts
|
|
366
446
|
var Genvoris = class {
|
|
367
447
|
constructor(config) {
|
|
@@ -372,6 +452,9 @@ var Genvoris = class {
|
|
|
372
452
|
this.plans = new PlansResource(config);
|
|
373
453
|
this.sessions = new SessionsResource(config);
|
|
374
454
|
this.webhooks = new WebhooksResource(config);
|
|
455
|
+
this.events = new EventsResource(config);
|
|
456
|
+
this.conversions = new ConversionsResource(config);
|
|
457
|
+
this.returns = new ReturnsResource(config);
|
|
375
458
|
}
|
|
376
459
|
};
|
|
377
460
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.mjs
CHANGED
|
@@ -33,12 +33,12 @@ var GenvorisValidationError = class extends GenvorisAPIError {
|
|
|
33
33
|
var RETRY_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
34
34
|
var MAX_DELAY_MS = 8e3;
|
|
35
35
|
var DEFAULT_BASE_URL = "https://genvoris.org/api/v1";
|
|
36
|
-
var SDK_VERSION = "1.
|
|
36
|
+
var SDK_VERSION = "1.1.0";
|
|
37
37
|
function sleep(ms) {
|
|
38
38
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
39
39
|
}
|
|
40
40
|
async function request(config, path, opts = {}, attempt = 0) {
|
|
41
|
-
const { method = "GET", body, query } = opts;
|
|
41
|
+
const { method = "GET", body, query, contentType } = opts;
|
|
42
42
|
const fetchFn = config.fetch ?? globalThis.fetch;
|
|
43
43
|
const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
44
44
|
let url = `${baseUrl}${path}`;
|
|
@@ -57,20 +57,33 @@ async function request(config, path, opts = {}, attempt = 0) {
|
|
|
57
57
|
);
|
|
58
58
|
let res;
|
|
59
59
|
try {
|
|
60
|
+
const headers = {
|
|
61
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
62
|
+
"User-Agent": `genvoris-node/${SDK_VERSION}`,
|
|
63
|
+
Accept: "application/json",
|
|
64
|
+
...config.defaultHeaders
|
|
65
|
+
};
|
|
66
|
+
if (body !== void 0 || contentType) {
|
|
67
|
+
headers["Content-Type"] = contentType ?? "application/json";
|
|
68
|
+
}
|
|
60
69
|
res = await fetchFn(url, {
|
|
61
70
|
method,
|
|
62
|
-
headers
|
|
63
|
-
Authorization: `Bearer ${config.apiKey}`,
|
|
64
|
-
"Content-Type": "application/json",
|
|
65
|
-
"User-Agent": `genvoris-node/${SDK_VERSION}`,
|
|
66
|
-
...config.defaultHeaders
|
|
67
|
-
},
|
|
71
|
+
headers,
|
|
68
72
|
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
69
73
|
signal: controller.signal
|
|
70
74
|
});
|
|
71
|
-
}
|
|
75
|
+
} catch (err) {
|
|
72
76
|
clearTimeout(timerId);
|
|
77
|
+
if (attempt < (config.maxRetries ?? 3)) {
|
|
78
|
+
const target = Math.pow(2, attempt) * 250;
|
|
79
|
+
const jittered = target * (0.7 + Math.random() * 0.6);
|
|
80
|
+
const delay = Math.min(jittered, MAX_DELAY_MS);
|
|
81
|
+
await sleep(delay);
|
|
82
|
+
return request(config, path, opts, attempt + 1);
|
|
83
|
+
}
|
|
84
|
+
throw err;
|
|
73
85
|
}
|
|
86
|
+
clearTimeout(timerId);
|
|
74
87
|
if (res.ok) {
|
|
75
88
|
if (res.status === 204) return void 0;
|
|
76
89
|
return res.json();
|
|
@@ -81,13 +94,14 @@ async function request(config, path, opts = {}, attempt = 0) {
|
|
|
81
94
|
errBody = await res.json();
|
|
82
95
|
} catch {
|
|
83
96
|
}
|
|
84
|
-
const code = errBody.error
|
|
85
|
-
const message = errBody.message
|
|
97
|
+
const code = errBody.error || "unknown_error";
|
|
98
|
+
const message = errBody.message || code;
|
|
86
99
|
if (RETRY_STATUSES.has(res.status)) {
|
|
87
100
|
const maxRetries = config.maxRetries ?? 3;
|
|
88
101
|
if (attempt < maxRetries) {
|
|
89
|
-
const
|
|
90
|
-
const
|
|
102
|
+
const target = Math.pow(2, attempt) * 250;
|
|
103
|
+
const jittered = target * (0.7 + Math.random() * 0.6);
|
|
104
|
+
const delay = Math.min(jittered, MAX_DELAY_MS);
|
|
91
105
|
await sleep(delay);
|
|
92
106
|
return request(config, path, opts, attempt + 1);
|
|
93
107
|
}
|
|
@@ -231,12 +245,29 @@ var SessionsResource = class {
|
|
|
231
245
|
}
|
|
232
246
|
);
|
|
233
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Revoke a previously minted session token by its `jti` claim.
|
|
250
|
+
*
|
|
251
|
+
* Use this on end-customer logout or when a token is suspected
|
|
252
|
+
* compromised. The token is rejected immediately even though its
|
|
253
|
+
* signature and expiry are otherwise still valid. Idempotent.
|
|
254
|
+
*/
|
|
255
|
+
revoke({ customerId, jti }) {
|
|
256
|
+
return request(
|
|
257
|
+
this.config,
|
|
258
|
+
`/customers/${encodeURIComponent(customerId)}/sessions/${encodeURIComponent(jti)}`,
|
|
259
|
+
{ method: "DELETE" }
|
|
260
|
+
);
|
|
261
|
+
}
|
|
234
262
|
};
|
|
235
263
|
|
|
236
264
|
// src/resources/webhooks.ts
|
|
237
265
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
238
266
|
function hexToBytes(hex) {
|
|
239
267
|
if (hex.length % 2 !== 0) throw new Error("genvoris: invalid hex string");
|
|
268
|
+
if (!/^[a-f0-9]+$/i.test(hex)) {
|
|
269
|
+
throw new Error("genvoris: invalid hex string \u2014 non-hex characters");
|
|
270
|
+
}
|
|
240
271
|
const bytes = new Uint8Array(hex.length / 2);
|
|
241
272
|
for (let i = 0; i < bytes.length; i++) {
|
|
242
273
|
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
@@ -331,6 +362,55 @@ var WebhooksResource = class {
|
|
|
331
362
|
}
|
|
332
363
|
};
|
|
333
364
|
|
|
365
|
+
// src/resources/events.ts
|
|
366
|
+
var EventsResource = class {
|
|
367
|
+
constructor(config) {
|
|
368
|
+
this.config = config;
|
|
369
|
+
}
|
|
370
|
+
/** Track one hosted-widget funnel event. */
|
|
371
|
+
track(event) {
|
|
372
|
+
return request(this.config, "/events", {
|
|
373
|
+
method: "POST",
|
|
374
|
+
body: event
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
/** Track a batch of 1–50 hosted-widget funnel events. */
|
|
378
|
+
trackBatch(events) {
|
|
379
|
+
return request(this.config, "/events", {
|
|
380
|
+
method: "POST",
|
|
381
|
+
body: { events }
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
// src/resources/conversions.ts
|
|
387
|
+
var ConversionsResource = class {
|
|
388
|
+
constructor(config) {
|
|
389
|
+
this.config = config;
|
|
390
|
+
}
|
|
391
|
+
/** Store an order conversion for attribution/lift analytics. */
|
|
392
|
+
create(params) {
|
|
393
|
+
return request(this.config, "/conversions", {
|
|
394
|
+
method: "POST",
|
|
395
|
+
body: params
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
// src/resources/returns.ts
|
|
401
|
+
var ReturnsResource = class {
|
|
402
|
+
constructor(config) {
|
|
403
|
+
this.config = config;
|
|
404
|
+
}
|
|
405
|
+
/** Store a return/refund event for conversion and returns-saved analytics. */
|
|
406
|
+
create(params) {
|
|
407
|
+
return request(this.config, "/returns", {
|
|
408
|
+
method: "POST",
|
|
409
|
+
body: params
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
334
414
|
// src/index.ts
|
|
335
415
|
var Genvoris = class {
|
|
336
416
|
constructor(config) {
|
|
@@ -341,6 +421,9 @@ var Genvoris = class {
|
|
|
341
421
|
this.plans = new PlansResource(config);
|
|
342
422
|
this.sessions = new SessionsResource(config);
|
|
343
423
|
this.webhooks = new WebhooksResource(config);
|
|
424
|
+
this.events = new EventsResource(config);
|
|
425
|
+
this.conversions = new ConversionsResource(config);
|
|
426
|
+
this.returns = new ReturnsResource(config);
|
|
344
427
|
}
|
|
345
428
|
};
|
|
346
429
|
export {
|
package/package.json
CHANGED
|
@@ -1,52 +1,55 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@genvoris/node",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Official Node.js SDK for the Genvoris Virtual Try-On API",
|
|
5
|
-
"main": "./dist/index.js",
|
|
6
|
-
"module": "./dist/index.mjs",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"import": "./dist/index.mjs",
|
|
12
|
-
"require": "./dist/index.js"
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"scripts": {
|
|
16
|
-
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@genvoris/node",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Official Node.js SDK for the Genvoris Virtual Try-On API",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
17
|
+
"pretest": "npm run build",
|
|
18
|
+
"test": "node --test",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"genvoris",
|
|
35
|
+
"virtual-try-on",
|
|
36
|
+
"vton",
|
|
37
|
+
"ecommerce",
|
|
38
|
+
"fashion",
|
|
39
|
+
"ai"
|
|
40
|
+
],
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/DevSajjadAli/genvoris-node"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://docs.genvoris.org",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/DevSajjadAli/genvoris-node/issues",
|
|
48
|
+
"email": "support@genvoris.org"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": ">=18",
|
|
52
|
+
"typescript": "^5.4.5",
|
|
53
|
+
"tsup": "^8.0.2"
|
|
54
|
+
}
|
|
55
|
+
}
|