@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 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`
@@ -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: string;
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: string;
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>;
@@ -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
- assertConfigValue('apiUrl', config.apiUrl);
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(config.apiUrl);
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hiclimba/client",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Node SDK for Toasty product backends and customer-scoped API access.",
5
5
  "license": "MIT",
6
6
  "private": false,