@hiclimba/client 0.0.2 → 0.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 +20 -2
- package/lib/toasty-client.d.ts +5 -3
- package/lib/toasty-client.js +8 -2
- package/lib/toasty-client.types.d.ts +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,6 @@ const toasty = new ToastyClient({
|
|
|
17
17
|
appId: process.env.TOASTY_APP_ID!,
|
|
18
18
|
keyId: process.env.TOASTY_KEY_ID!,
|
|
19
19
|
secret: process.env.TOASTY_SECRET!,
|
|
20
|
-
apiUrl: process.env.TOASTY_API_URL!,
|
|
21
20
|
});
|
|
22
21
|
|
|
23
22
|
const identified = await toasty.identify({
|
|
@@ -26,10 +25,29 @@ const identified = await toasty.identify({
|
|
|
26
25
|
});
|
|
27
26
|
```
|
|
28
27
|
|
|
28
|
+
The default API URL is `https://api.hiclimba.com`. Pass `apiUrl` only when you
|
|
29
|
+
need to target a local, staging, or private API deployment.
|
|
30
|
+
|
|
29
31
|
`identify()` returns `customerApiToken`. It is a random Toasty app-installation
|
|
30
32
|
lookup token. It is not signed, encrypted, expiring, rotatable, privileged app
|
|
31
33
|
auth, or any kind of Shopify token.
|
|
32
34
|
|
|
35
|
+
If your backend already has a Shopify Admin delegate token for a known
|
|
36
|
+
installation, server mode can push it to Toasty:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
await toasty.pushShopifyAdminDelegateToken({
|
|
40
|
+
shop: 'merchant.myshopify.com',
|
|
41
|
+
delegateToken: '<shopify-admin-delegate-token>',
|
|
42
|
+
expiresAt: '2026-07-02T12:00:00.000Z',
|
|
43
|
+
accessScopes: ['read_products']
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Toasty validates the token against Shopify with a minimal Admin GraphQL request
|
|
48
|
+
before storing it encrypted on the existing installation. The pushed token is
|
|
49
|
+
server-side only and must never be sent from browser code.
|
|
50
|
+
|
|
33
51
|
## Customer Mode
|
|
34
52
|
|
|
35
53
|
Customer mode uses the Toasty app ID plus the `customerApiToken` returned by
|
|
@@ -39,7 +57,6 @@ Customer mode uses the Toasty app ID plus the `customerApiToken` returned by
|
|
|
39
57
|
const toasty = new ToastyClient({
|
|
40
58
|
appId: '<toasty-app-id>',
|
|
41
59
|
customerApiToken: '<customer-api-token>',
|
|
42
|
-
apiUrl: 'https://api.toasty.dev',
|
|
43
60
|
});
|
|
44
61
|
|
|
45
62
|
const customer = await toasty.getCustomer();
|
|
@@ -60,6 +77,7 @@ Authorization: Bearer custok_...
|
|
|
60
77
|
## Top-Level Methods
|
|
61
78
|
|
|
62
79
|
- `identify`
|
|
80
|
+
- `pushShopifyAdminDelegateToken`
|
|
63
81
|
- `getCustomer`
|
|
64
82
|
- `evaluateFeature`
|
|
65
83
|
- `isFeatureEnabled`
|
package/lib/toasty-client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ICancelSubscriptionInput, ICancelSubscriptionResponse, ICreateOneTimeChargeInput, ICreateOneTimeChargeResponse, ICreateSubscriptionInput, ICreateSubscriptionResponse, IGetCustomerResponse, IGetUsageMetricReportInput, IGetUsageMetricReportResponse, IIdentifyInput, IIdentifyResponse, IPublicCustomerDto, IPublicCustomerFeatureDto, IPublicCustomerPlanDto, IPublicCustomerSubscriptionDto, IPublicCustomerUsageMetricDto, ITrackUsageEventBatchInput, ITrackUsageEventBatchResponse, ITrackUsageEventInput, ITrackUsageEventResponse, IUpdateSubscriptionInput, IUpdateSubscriptionResponse, IPlanDiscount } from './toasty-client.types.js';
|
|
1
|
+
import type { ICancelSubscriptionInput, ICancelSubscriptionResponse, ICreateOneTimeChargeInput, ICreateOneTimeChargeResponse, ICreateSubscriptionInput, ICreateSubscriptionResponse, IGetCustomerResponse, IGetUsageMetricReportInput, IGetUsageMetricReportResponse, IIdentifyInput, IIdentifyResponse, IPublicCustomerDto, IPublicCustomerFeatureDto, IPublicCustomerPlanDto, IPublicCustomerSubscriptionDto, IPublicCustomerUsageMetricDto, ITrackUsageEventBatchInput, ITrackUsageEventBatchResponse, ITrackUsageEventInput, ITrackUsageEventResponse, IUpdateSubscriptionInput, IUpdateSubscriptionResponse, IPushShopifyAdminDelegateTokenInput, IPushShopifyAdminDelegateTokenResponse, IPlanDiscount } from './toasty-client.types.js';
|
|
2
|
+
export declare const DEFAULT_API_URL = "https://api.hiclimba.com";
|
|
2
3
|
export type Customer = IPublicCustomerDto;
|
|
3
4
|
export type Plan = IPublicCustomerPlanDto;
|
|
4
5
|
export type Subscription = IPublicCustomerSubscriptionDto;
|
|
@@ -13,14 +14,14 @@ export interface IToastyServerClientConfig {
|
|
|
13
14
|
appId: string;
|
|
14
15
|
keyId: string;
|
|
15
16
|
secret: string;
|
|
16
|
-
apiUrl
|
|
17
|
+
apiUrl?: string;
|
|
17
18
|
fetch?: typeof fetch;
|
|
18
19
|
allowBrowserServerCredentials?: boolean;
|
|
19
20
|
}
|
|
20
21
|
export interface IToastyCustomerClientConfig {
|
|
21
22
|
appId: string;
|
|
22
23
|
customerApiToken: string;
|
|
23
|
-
apiUrl
|
|
24
|
+
apiUrl?: string;
|
|
24
25
|
fetch?: typeof fetch;
|
|
25
26
|
}
|
|
26
27
|
export type IToastyClientConfig = IToastyServerClientConfig | IToastyCustomerClientConfig;
|
|
@@ -68,6 +69,7 @@ export declare class ToastyClient {
|
|
|
68
69
|
private readonly fetchImpl;
|
|
69
70
|
constructor(config: IToastyClientConfig);
|
|
70
71
|
identify(input: IIdentifyInput): ToastyResult<IIdentifyResponse>;
|
|
72
|
+
pushShopifyAdminDelegateToken(input: IPushShopifyAdminDelegateTokenInput): ToastyResult<IPushShopifyAdminDelegateTokenResponse>;
|
|
71
73
|
getCustomer(input?: {
|
|
72
74
|
customerId?: string;
|
|
73
75
|
}): ToastyResult<IGetCustomerResponse>;
|
package/lib/toasty-client.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash, createHmac, hkdfSync } from 'node:crypto';
|
|
2
|
+
export const DEFAULT_API_URL = 'https://api.hiclimba.com';
|
|
2
3
|
const HMAC_SIGNATURE_PREFIX = 'v1=';
|
|
3
4
|
const SIGNING_KEY_INFO = 'toasty-hmac-signing-key-v1';
|
|
4
5
|
export function sha256HexRawBody(rawBody) {
|
|
@@ -60,7 +61,8 @@ export class ToastyClient {
|
|
|
60
61
|
fetchImpl;
|
|
61
62
|
constructor(config) {
|
|
62
63
|
assertConfigValue('appId', config.appId);
|
|
63
|
-
|
|
64
|
+
const apiUrl = config.apiUrl ?? DEFAULT_API_URL;
|
|
65
|
+
assertConfigValue('apiUrl', apiUrl);
|
|
64
66
|
if (isServerConfig(config)) {
|
|
65
67
|
assertConfigValue('keyId', config.keyId);
|
|
66
68
|
assertConfigValue('secret', config.secret);
|
|
@@ -72,7 +74,7 @@ export class ToastyClient {
|
|
|
72
74
|
assertConfigValue('customerApiToken', config.customerApiToken);
|
|
73
75
|
}
|
|
74
76
|
this.config = config;
|
|
75
|
-
this.apiUrl = normalizeApiUrl(
|
|
77
|
+
this.apiUrl = normalizeApiUrl(apiUrl);
|
|
76
78
|
this.fetchImpl = config.fetch ?? fetch;
|
|
77
79
|
}
|
|
78
80
|
identify(input) {
|
|
@@ -80,6 +82,10 @@ export class ToastyClient {
|
|
|
80
82
|
assertNoShopifyTokenFields(input);
|
|
81
83
|
return this.post('/v1/identify', input);
|
|
82
84
|
}
|
|
85
|
+
pushShopifyAdminDelegateToken(input) {
|
|
86
|
+
this.assertServerMode('pushShopifyAdminDelegateToken');
|
|
87
|
+
return this.post('/v1/shopify-admin/delegate-token', input);
|
|
88
|
+
}
|
|
83
89
|
getCustomer(input = {}) {
|
|
84
90
|
if (isServerConfig(this.config)) {
|
|
85
91
|
if (!input.customerId) {
|
|
@@ -183,6 +183,20 @@ export interface IIdentifyResponse {
|
|
|
183
183
|
customerApiToken: string;
|
|
184
184
|
customer: IPublicCustomerDto;
|
|
185
185
|
}
|
|
186
|
+
export interface IPushShopifyAdminDelegateTokenInput {
|
|
187
|
+
shop: string;
|
|
188
|
+
delegateToken: string;
|
|
189
|
+
expiresAt?: string;
|
|
190
|
+
expiresInSeconds?: number;
|
|
191
|
+
accessScopes?: string[];
|
|
192
|
+
}
|
|
193
|
+
export interface IPushShopifyAdminDelegateTokenResponse {
|
|
194
|
+
ok: true;
|
|
195
|
+
installationId: string;
|
|
196
|
+
myshopifyDomain: string;
|
|
197
|
+
shopifyShopId?: string;
|
|
198
|
+
expiresAt?: string;
|
|
199
|
+
}
|
|
186
200
|
export interface ICreateSubscriptionInput {
|
|
187
201
|
shop?: string;
|
|
188
202
|
returnUrl: string;
|