@hanzo/commerce 7.6.1 → 7.6.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.
Files changed (258) hide show
  1. package/LICENSE.md +21 -0
  2. package/client.ts +120 -4
  3. package/dist/billing.d.ts +2 -0
  4. package/dist/billing.js +3 -0
  5. package/dist/billing.js.map +1 -0
  6. package/dist/client.d.ts +464 -0
  7. package/dist/client.js +424 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/components/Icons.d.ts +18 -0
  10. package/dist/components/Icons.js +19 -0
  11. package/dist/components/Icons.js.map +1 -0
  12. package/dist/components/add-to-cart-widget.d.ts +11 -0
  13. package/dist/components/add-to-cart-widget.js +85 -0
  14. package/dist/components/add-to-cart-widget.js.map +1 -0
  15. package/dist/components/buy/buy-card.d.ts +30 -0
  16. package/dist/components/buy/buy-card.js +109 -0
  17. package/dist/components/buy/buy-card.js.map +1 -0
  18. package/dist/components/buy/carousel-buy-card.d.ts +12 -0
  19. package/dist/components/buy/carousel-buy-card.js +94 -0
  20. package/dist/components/buy/carousel-buy-card.js.map +1 -0
  21. package/dist/components/buy/multi-family/all-variants-carousel.d.ts +4 -0
  22. package/dist/components/buy/multi-family/all-variants-carousel.js +115 -0
  23. package/dist/components/buy/multi-family/all-variants-carousel.js.map +1 -0
  24. package/dist/components/buy/multi-family/family-carousel/index.d.ts +4 -0
  25. package/dist/components/buy/multi-family/family-carousel/index.js +27 -0
  26. package/dist/components/buy/multi-family/family-carousel/index.js.map +1 -0
  27. package/dist/components/buy/multi-family/family-carousel/slide.d.ts +11 -0
  28. package/dist/components/buy/multi-family/family-carousel/slide.js +35 -0
  29. package/dist/components/buy/multi-family/family-carousel/slide.js.map +1 -0
  30. package/dist/components/buy/multi-family/family-carousel/state.d.ts +20 -0
  31. package/dist/components/buy/multi-family/family-carousel/state.js +59 -0
  32. package/dist/components/buy/multi-family/family-carousel/state.js.map +1 -0
  33. package/dist/components/buy/multi-family/index.d.ts +2 -0
  34. package/dist/components/buy/multi-family/index.js +3 -0
  35. package/dist/components/buy/multi-family/index.js.map +1 -0
  36. package/dist/components/buy/single-family-selector.d.ts +15 -0
  37. package/dist/components/buy/single-family-selector.js +28 -0
  38. package/dist/components/buy/single-family-selector.js.map +1 -0
  39. package/dist/components/buy/title-and-byline.d.ts +8 -0
  40. package/dist/components/buy/title-and-byline.js +7 -0
  41. package/dist/components/buy/title-and-byline.js.map +1 -0
  42. package/dist/components/cart/cart-panel/cart-line-item.d.ts +11 -0
  43. package/dist/components/cart/cart-panel/cart-line-item.js +25 -0
  44. package/dist/components/cart/cart-panel/cart-line-item.js.map +1 -0
  45. package/dist/components/cart/cart-panel/index.d.ts +19 -0
  46. package/dist/components/cart/cart-panel/index.js +65 -0
  47. package/dist/components/cart/cart-panel/index.js.map +1 -0
  48. package/dist/components/cart/cart-panel/promo-code.d.ts +4 -0
  49. package/dist/components/cart/cart-panel/promo-code.js +62 -0
  50. package/dist/components/cart/cart-panel/promo-code.js.map +1 -0
  51. package/dist/components/cart/cart-panel/total-area.d.ts +7 -0
  52. package/dist/components/cart/cart-panel/total-area.js +14 -0
  53. package/dist/components/cart/cart-panel/total-area.js.map +1 -0
  54. package/dist/components/checkout/payment-step-form/card-icon-row.d.ts +2 -0
  55. package/dist/components/checkout/payment-step-form/card-icon-row.js +14 -0
  56. package/dist/components/checkout/payment-step-form/card-icon-row.js.map +1 -0
  57. package/dist/components/checkout/payment-step-form/card-icons/amex.d.ts +4 -0
  58. package/dist/components/checkout/payment-step-form/card-icons/amex.js +6 -0
  59. package/dist/components/checkout/payment-step-form/card-icons/amex.js.map +1 -0
  60. package/dist/components/checkout/payment-step-form/card-icons/diners-club.d.ts +4 -0
  61. package/dist/components/checkout/payment-step-form/card-icons/diners-club.js +6 -0
  62. package/dist/components/checkout/payment-step-form/card-icons/diners-club.js.map +1 -0
  63. package/dist/components/checkout/payment-step-form/card-icons/discover.d.ts +4 -0
  64. package/dist/components/checkout/payment-step-form/card-icons/discover.js +6 -0
  65. package/dist/components/checkout/payment-step-form/card-icons/discover.js.map +1 -0
  66. package/dist/components/checkout/payment-step-form/card-icons/jcb.d.ts +4 -0
  67. package/dist/components/checkout/payment-step-form/card-icons/jcb.js +6 -0
  68. package/dist/components/checkout/payment-step-form/card-icons/jcb.js.map +1 -0
  69. package/dist/components/checkout/payment-step-form/card-icons/mastercard.d.ts +4 -0
  70. package/dist/components/checkout/payment-step-form/card-icons/mastercard.js +6 -0
  71. package/dist/components/checkout/payment-step-form/card-icons/mastercard.js.map +1 -0
  72. package/dist/components/checkout/payment-step-form/card-icons/visa.d.ts +4 -0
  73. package/dist/components/checkout/payment-step-form/card-icons/visa.js +6 -0
  74. package/dist/components/checkout/payment-step-form/card-icons/visa.js.map +1 -0
  75. package/dist/components/checkout/payment-step-form/cc-button.d.ts +3 -0
  76. package/dist/components/checkout/payment-step-form/cc-button.js +6 -0
  77. package/dist/components/checkout/payment-step-form/cc-button.js.map +1 -0
  78. package/dist/components/checkout/payment-step-form/contact-form.d.ts +5 -0
  79. package/dist/components/checkout/payment-step-form/contact-form.js +6 -0
  80. package/dist/components/checkout/payment-step-form/contact-form.js.map +1 -0
  81. package/dist/components/checkout/payment-step-form/crypto-icons/btc.d.ts +4 -0
  82. package/dist/components/checkout/payment-step-form/crypto-icons/btc.js +6 -0
  83. package/dist/components/checkout/payment-step-form/crypto-icons/btc.js.map +1 -0
  84. package/dist/components/checkout/payment-step-form/crypto-icons/eth.d.ts +4 -0
  85. package/dist/components/checkout/payment-step-form/crypto-icons/eth.js +6 -0
  86. package/dist/components/checkout/payment-step-form/crypto-icons/eth.js.map +1 -0
  87. package/dist/components/checkout/payment-step-form/crypto-icons/usdt.d.ts +4 -0
  88. package/dist/components/checkout/payment-step-form/crypto-icons/usdt.js +6 -0
  89. package/dist/components/checkout/payment-step-form/crypto-icons/usdt.js.map +1 -0
  90. package/dist/components/checkout/payment-step-form/index.d.ts +4 -0
  91. package/dist/components/checkout/payment-step-form/index.js +66 -0
  92. package/dist/components/checkout/payment-step-form/index.js.map +1 -0
  93. package/dist/components/checkout/payment-step-form/methods/bank-transfer.d.ts +4 -0
  94. package/dist/components/checkout/payment-step-form/methods/bank-transfer.js +24 -0
  95. package/dist/components/checkout/payment-step-form/methods/bank-transfer.js.map +1 -0
  96. package/dist/components/checkout/payment-step-form/methods/card.d.ts +4 -0
  97. package/dist/components/checkout/payment-step-form/methods/card.js +160 -0
  98. package/dist/components/checkout/payment-step-form/methods/card.js.map +1 -0
  99. package/dist/components/checkout/payment-step-form/methods/crypto.d.ts +9 -0
  100. package/dist/components/checkout/payment-step-form/methods/crypto.js +137 -0
  101. package/dist/components/checkout/payment-step-form/methods/crypto.js.map +1 -0
  102. package/dist/components/checkout/payment-step-form/methods/index.d.ts +6 -0
  103. package/dist/components/checkout/payment-step-form/methods/index.js +21 -0
  104. package/dist/components/checkout/payment-step-form/methods/index.js.map +1 -0
  105. package/dist/components/checkout/shipping-step-form.d.ts +3 -0
  106. package/dist/components/checkout/shipping-step-form.js +53 -0
  107. package/dist/components/checkout/shipping-step-form.js.map +1 -0
  108. package/dist/components/index.d.ts +8 -0
  109. package/dist/components/index.js +9 -0
  110. package/dist/components/index.js.map +1 -0
  111. package/dist/components/item/product-card.d.ts +7 -0
  112. package/dist/components/item/product-card.js +9 -0
  113. package/dist/components/item/product-card.js.map +1 -0
  114. package/dist/components/item-selector/button.d.ts +4 -0
  115. package/dist/components/item-selector/button.js +47 -0
  116. package/dist/components/item-selector/button.js.map +1 -0
  117. package/dist/components/item-selector/carousel/index.d.ts +12 -0
  118. package/dist/components/item-selector/carousel/index.js +74 -0
  119. package/dist/components/item-selector/carousel/index.js.map +1 -0
  120. package/dist/components/item-selector/carousel/slider.d.ts +8 -0
  121. package/dist/components/item-selector/carousel/slider.js +12 -0
  122. package/dist/components/item-selector/carousel/slider.js.map +1 -0
  123. package/dist/components/item-selector/index.d.ts +2 -0
  124. package/dist/components/item-selector/index.js +3 -0
  125. package/dist/components/item-selector/index.js.map +1 -0
  126. package/dist/components/item-selector/quantity-indicator.d.ts +9 -0
  127. package/dist/components/item-selector/quantity-indicator.js +16 -0
  128. package/dist/components/item-selector/quantity-indicator.js.map +1 -0
  129. package/dist/components/node-tabs/index.d.ts +14 -0
  130. package/dist/components/node-tabs/index.js +42 -0
  131. package/dist/components/node-tabs/index.js.map +1 -0
  132. package/dist/components/node-tabs/node-image.d.ts +6 -0
  133. package/dist/components/node-tabs/node-image.js +13 -0
  134. package/dist/components/node-tabs/node-image.js.map +1 -0
  135. package/dist/index.d.ts +9 -0
  136. package/dist/index.js +9 -0
  137. package/dist/index.js.map +1 -0
  138. package/dist/metering.d.ts +162 -0
  139. package/dist/metering.js +204 -0
  140. package/dist/metering.js.map +1 -0
  141. package/dist/metering.test.d.ts +13 -0
  142. package/dist/metering.test.js +181 -0
  143. package/dist/metering.test.js.map +1 -0
  144. package/dist/service/context.d.ts +8 -0
  145. package/dist/service/context.js +19 -0
  146. package/dist/service/context.js.map +1 -0
  147. package/dist/service/debug.d.ts +10 -0
  148. package/dist/service/debug.js +30 -0
  149. package/dist/service/debug.js.map +1 -0
  150. package/dist/service/impls/standalone/actual-line-item.d.ts +40 -0
  151. package/dist/service/impls/standalone/actual-line-item.js +84 -0
  152. package/dist/service/impls/standalone/actual-line-item.js.map +1 -0
  153. package/dist/service/impls/standalone/get-instance.d.ts +2 -0
  154. package/dist/service/impls/standalone/get-instance.js +39 -0
  155. package/dist/service/impls/standalone/get-instance.js.map +1 -0
  156. package/dist/service/impls/standalone/index.d.ts +67 -0
  157. package/dist/service/impls/standalone/index.js +416 -0
  158. package/dist/service/impls/standalone/index.js.map +1 -0
  159. package/dist/service/impls/standalone/order/firebase.d.ts +6 -0
  160. package/dist/service/impls/standalone/order/firebase.js +6 -0
  161. package/dist/service/impls/standalone/order/firebase.js.map +1 -0
  162. package/dist/service/impls/standalone/order/index.d.ts +30 -0
  163. package/dist/service/impls/standalone/order/index.js +21 -0
  164. package/dist/service/impls/standalone/order/index.js.map +1 -0
  165. package/dist/service/impls/standalone/persistence.d.ts +4 -0
  166. package/dist/service/impls/standalone/persistence.js +22 -0
  167. package/dist/service/impls/standalone/persistence.js.map +1 -0
  168. package/dist/service/path-utils.d.ts +7 -0
  169. package/dist/service/path-utils.js +16 -0
  170. package/dist/service/path-utils.js.map +1 -0
  171. package/dist/service/sep.d.ts +6 -0
  172. package/dist/service/sep.js +6 -0
  173. package/dist/service/sep.js.map +1 -0
  174. package/dist/types/category-node.d.ts +36 -0
  175. package/dist/types/category-node.js +2 -0
  176. package/dist/types/category-node.js.map +1 -0
  177. package/dist/types/checkout.d.ts +33 -0
  178. package/dist/types/checkout.js +2 -0
  179. package/dist/types/checkout.js.map +1 -0
  180. package/dist/types/commerce-config.d.ts +11 -0
  181. package/dist/types/commerce-config.js +2 -0
  182. package/dist/types/commerce-config.js.map +1 -0
  183. package/dist/types/commerce-service.d.ts +109 -0
  184. package/dist/types/commerce-service.js +2 -0
  185. package/dist/types/commerce-service.js.map +1 -0
  186. package/dist/types/family.d.ts +16 -0
  187. package/dist/types/family.js +2 -0
  188. package/dist/types/family.js.map +1 -0
  189. package/dist/types/index.d.ts +13 -0
  190. package/dist/types/index.js +8 -0
  191. package/dist/types/index.js.map +1 -0
  192. package/dist/types/item-selector.d.ts +72 -0
  193. package/dist/types/item-selector.js +2 -0
  194. package/dist/types/item-selector.js.map +1 -0
  195. package/dist/types/line-item.d.ts +14 -0
  196. package/dist/types/line-item.js +2 -0
  197. package/dist/types/line-item.js.map +1 -0
  198. package/dist/types/multi-family-selector-props.d.ts +16 -0
  199. package/dist/types/multi-family-selector-props.js +2 -0
  200. package/dist/types/multi-family-selector-props.js.map +1 -0
  201. package/dist/types/product.d.ts +15 -0
  202. package/dist/types/product.js +2 -0
  203. package/dist/types/product.js.map +1 -0
  204. package/dist/types/promo.d.ts +7 -0
  205. package/dist/types/promo.js +2 -0
  206. package/dist/types/promo.js.map +1 -0
  207. package/dist/types/selection-ui-specifier.d.ts +40 -0
  208. package/dist/types/selection-ui-specifier.js +2 -0
  209. package/dist/types/selection-ui-specifier.js.map +1 -0
  210. package/dist/types/string-mutator.d.ts +9 -0
  211. package/dist/types/string-mutator.js +2 -0
  212. package/dist/types/string-mutator.js.map +1 -0
  213. package/dist/types/token-separators.d.ts +6 -0
  214. package/dist/types/token-separators.js +2 -0
  215. package/dist/types/token-separators.js.map +1 -0
  216. package/dist/util/analytics.d.ts +9 -0
  217. package/dist/util/analytics.js +10 -0
  218. package/dist/util/analytics.js.map +1 -0
  219. package/dist/util/countries.d.ts +7 -0
  220. package/dist/util/countries.js +197 -0
  221. package/dist/util/countries.js.map +1 -0
  222. package/dist/util/error.d.ts +1 -0
  223. package/dist/util/error.js +22 -0
  224. package/dist/util/error.js.map +1 -0
  225. package/dist/util/index.d.ts +15 -0
  226. package/dist/util/index.js +54 -0
  227. package/dist/util/index.js.map +1 -0
  228. package/dist/util/item-selector-options-accessor.d.ts +3 -0
  229. package/dist/util/item-selector-options-accessor.js +27 -0
  230. package/dist/util/item-selector-options-accessor.js.map +1 -0
  231. package/dist/util/line-item-ref.d.ts +8 -0
  232. package/dist/util/line-item-ref.js +15 -0
  233. package/dist/util/line-item-ref.js.map +1 -0
  234. package/dist/util/multi-family-selector-options-accessor.d.ts +3 -0
  235. package/dist/util/multi-family-selector-options-accessor.js +11 -0
  236. package/dist/util/multi-family-selector-options-accessor.js.map +1 -0
  237. package/dist/util/obs-string-mutator.d.ts +8 -0
  238. package/dist/util/obs-string-mutator.js +15 -0
  239. package/dist/util/obs-string-mutator.js.map +1 -0
  240. package/dist/util/product-media-accessor.d.ts +29 -0
  241. package/dist/util/product-media-accessor.js +22 -0
  242. package/dist/util/product-media-accessor.js.map +1 -0
  243. package/dist/util/promo-codes.d.ts +3 -0
  244. package/dist/util/promo-codes.js +100 -0
  245. package/dist/util/promo-codes.js.map +1 -0
  246. package/dist/util/selection-ui-specifiers.d.ts +3 -0
  247. package/dist/util/selection-ui-specifiers.js +24 -0
  248. package/dist/util/selection-ui-specifiers.js.map +1 -0
  249. package/dist/util/square-payment.d.ts +7 -0
  250. package/dist/util/square-payment.js +37 -0
  251. package/dist/util/square-payment.js.map +1 -0
  252. package/dist/util/use-sync-sku-param-w-current-item.d.ts +2 -0
  253. package/dist/util/use-sync-sku-param-w-current-item.js +61 -0
  254. package/dist/util/use-sync-sku-param-w-current-item.js.map +1 -0
  255. package/index.ts +18 -1
  256. package/metering.test.ts +199 -0
  257. package/metering.ts +289 -0
  258. package/package.json +18 -16
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 hanzo
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/client.ts CHANGED
@@ -67,6 +67,29 @@ export type Balance = {
67
67
  available: number
68
68
  }
69
69
 
70
+ /**
71
+ * Tier-aware balance from GET /v1/billing/tier. effectiveAvailable folds the
72
+ * tenant's included plan allotment (e.g. the free-tier daily credit) into the
73
+ * prepaid available balance — gate on this to honor included usage first.
74
+ */
75
+ export type TierResponse = {
76
+ user: string
77
+ tier: {
78
+ name: string
79
+ displayName?: string
80
+ maxAgents?: number
81
+ unlimitedAgents?: boolean
82
+ dailyCreditsCents?: number
83
+ allowedModels?: string[]
84
+ }
85
+ balance: {
86
+ currency: string
87
+ prepaidAvailable: number
88
+ dailyRemaining: number
89
+ effectiveAvailable: number
90
+ }
91
+ }
92
+
70
93
  export type Transaction = {
71
94
  id?: string
72
95
  owner?: string
@@ -270,6 +293,17 @@ export type PaymentMethod = {
270
293
  expMonth: number
271
294
  expYear: number
272
295
  }
296
+ bank_account?: {
297
+ bankName?: string
298
+ last4?: string
299
+ accountType?: 'checking' | 'savings'
300
+ routingNumber?: string
301
+ }
302
+ crypto?: {
303
+ chain: string
304
+ address: string
305
+ label?: string
306
+ }
273
307
  providerRef?: string
274
308
  providerType?: string
275
309
  createdAt?: string
@@ -349,6 +383,8 @@ export class Commerce {
349
383
  body?: unknown
350
384
  token?: string
351
385
  params?: Record<string, string>
386
+ /** Extra request headers, e.g. X-IAM-Org-Id for S2S calls. */
387
+ headers?: Record<string, string>
352
388
  },
353
389
  ): Promise<T> {
354
390
  const url = new URL(path, this.baseUrl)
@@ -365,6 +401,7 @@ export class Commerce {
365
401
  const authToken = opts?.token ?? this.token
366
402
  if (authToken) headers['Authorization'] = `Bearer ${authToken}`
367
403
  if (opts?.body) headers['Content-Type'] = 'application/json'
404
+ if (opts?.headers) Object.assign(headers, opts.headers)
368
405
 
369
406
  try {
370
407
  const res = await fetch(url.toString(), {
@@ -389,9 +426,9 @@ export class Commerce {
389
426
  // Balance
390
427
  // -----------------------------------------------------------------------
391
428
 
392
- async getBalance(user: string, currency = 'usd', token?: string): Promise<Balance> {
429
+ async getBalance(user: string, currency = 'usd', token?: string, headers?: Record<string, string>): Promise<Balance> {
393
430
  return this.request<Balance>('/v1/billing/balance', {
394
- params: { user, currency }, token,
431
+ params: { user, currency }, token, headers,
395
432
  })
396
433
  }
397
434
 
@@ -401,13 +438,25 @@ export class Commerce {
401
438
  })
402
439
  }
403
440
 
441
+ /**
442
+ * Tier-aware balance: prepaid available plus the tenant's included plan
443
+ * allotment (effectiveAvailable). Use this for the metering gate when you
444
+ * want included usage (e.g. free-tier daily credit) honored before prepaid
445
+ * funds are drawn down.
446
+ */
447
+ async getTier(user: string, opts?: { token?: string; headers?: Record<string, string> }): Promise<TierResponse> {
448
+ return this.request<TierResponse>('/v1/billing/tier', {
449
+ params: { user }, token: opts?.token, headers: opts?.headers,
450
+ })
451
+ }
452
+
404
453
  // -----------------------------------------------------------------------
405
454
  // Usage
406
455
  // -----------------------------------------------------------------------
407
456
 
408
- async addUsageRecord(record: UsageRecord, token?: string): Promise<Transaction> {
457
+ async addUsageRecord(record: UsageRecord, token?: string, headers?: Record<string, string>): Promise<Transaction> {
409
458
  return this.request<Transaction>('/v1/billing/usage', {
410
- method: 'POST', body: record, token,
459
+ method: 'POST', body: record, token, headers,
411
460
  })
412
461
  }
413
462
 
@@ -687,6 +736,73 @@ export class Commerce {
687
736
  method: 'POST', body: params, token,
688
737
  })
689
738
  }
739
+
740
+ // -----------------------------------------------------------------------
741
+ // Crypto wallet deposit address
742
+ // -----------------------------------------------------------------------
743
+
744
+ /**
745
+ * Get or create a deposit address for a given chain.
746
+ * Used for crypto top-up — user sends funds to this address.
747
+ */
748
+ async getWalletAddress(params: { chain: string; userId: string }, token?: string): Promise<{ address: string; chain: string; qrCode?: string }> {
749
+ return this.request<{ address: string; chain: string; qrCode?: string }>('/api/wallet/account', {
750
+ method: 'POST',
751
+ body: { name: `${params.userId}-${params.chain}`, blockchainType: params.chain },
752
+ token,
753
+ })
754
+ }
755
+
756
+ // -----------------------------------------------------------------------
757
+ // Bank account (ACH) and crypto payment methods
758
+ // -----------------------------------------------------------------------
759
+
760
+ /**
761
+ * Add a bank account payment method (ACH).
762
+ * plaidToken from Plaid Link or Square bank OAuth.
763
+ */
764
+ async addBankAccount(
765
+ params: {
766
+ customerId: string
767
+ plaidToken?: string // Plaid public token
768
+ bankName?: string
769
+ accountType?: 'checking' | 'savings'
770
+ },
771
+ token?: string,
772
+ ): Promise<PaymentMethod> {
773
+ return this.request<PaymentMethod>('/v1/billing/payment-methods', {
774
+ method: 'POST',
775
+ body: { customerId: params.customerId, type: 'bank_account', plaidToken: params.plaidToken, bankName: params.bankName, accountType: params.accountType },
776
+ token,
777
+ })
778
+ }
779
+
780
+ async addCryptoWallet(
781
+ params: { customerId: string; chain: string; address: string; label?: string },
782
+ token?: string,
783
+ ): Promise<PaymentMethod> {
784
+ return this.request<PaymentMethod>('/v1/billing/payment-methods', {
785
+ method: 'POST',
786
+ body: { customerId: params.customerId, type: 'crypto', chain: params.chain, address: params.address, label: params.label },
787
+ token,
788
+ })
789
+ }
790
+
791
+ // -----------------------------------------------------------------------
792
+ // Top-up
793
+ // -----------------------------------------------------------------------
794
+
795
+ /**
796
+ * Convenience: charge a saved payment method and deposit credits.
797
+ * amount is in cents.
798
+ */
799
+ async topup(params: { userId: string; paymentMethodId: string; amountCents: number; currency?: string }, token?: string): Promise<Transaction> {
800
+ return this.request<Transaction>('/v1/billing/topup', {
801
+ method: 'POST',
802
+ body: params,
803
+ token,
804
+ })
805
+ }
690
806
  }
691
807
 
692
808
  // ---------------------------------------------------------------------------
@@ -0,0 +1,2 @@
1
+ /** @hanzo/commerce/billing — re-exports from @hanzo/commerce/client */
2
+ export * from './client';
@@ -0,0 +1,3 @@
1
+ /** @hanzo/commerce/billing — re-exports from @hanzo/commerce/client */
2
+ export * from './client';
3
+ //# sourceMappingURL=billing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing.js","sourceRoot":"","sources":["../billing.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,cAAc,UAAU,CAAA"}
@@ -0,0 +1,464 @@
1
+ /**
2
+ * @hanzo/commerce/client
3
+ *
4
+ * Universal TypeScript client for the Hanzo Commerce API.
5
+ * Works in browser, Node.js, and edge runtimes — no backend required.
6
+ * Covers billing, subscriptions, payments, checkout, coupons,
7
+ * referrals, affiliates, usage, and plans.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { Commerce } from '@hanzo/commerce/client'
12
+ *
13
+ * const commerce = new Commerce({ baseUrl: 'https://api.hanzo.ai', token: iamToken })
14
+ *
15
+ * // Validate a coupon before checkout
16
+ * const coupon = await commerce.validateCoupon('LAUNCH50')
17
+ *
18
+ * // Create a checkout session
19
+ * const session = await commerce.createCheckoutSession({
20
+ * items: [{ id: 'plan_pro', quantity: 1 }],
21
+ * couponCode: 'LAUNCH50',
22
+ * referrerId: 'ref_abc123',
23
+ * successUrl: 'https://app.example.com/success',
24
+ * cancelUrl: 'https://app.example.com/cancel',
25
+ * })
26
+ * window.location.href = session.checkoutUrl
27
+ *
28
+ * // Tokenize a card (S2S — no external SDK required)
29
+ * const token = await commerce.tokenizeCard({
30
+ * number: '4242424242424242',
31
+ * expiryMonth: '12',
32
+ * expiryYear: '2027',
33
+ * cvc: '123',
34
+ * name: 'Jane Smith',
35
+ * })
36
+ *
37
+ * // Subscribe
38
+ * const sub = await commerce.subscribe({ planId: 'pro', userId: 'user_xyz' })
39
+ * ```
40
+ */
41
+ export type CommerceClientConfig = {
42
+ /**
43
+ * Commerce API base URL.
44
+ * Defaults to https://api.hanzo.ai
45
+ */
46
+ baseUrl?: string;
47
+ /** @deprecated use baseUrl */
48
+ commerceUrl?: string;
49
+ /** IAM access token for authenticated requests. */
50
+ token?: string;
51
+ /** Request timeout in milliseconds. Default 15 000. */
52
+ timeoutMs?: number;
53
+ };
54
+ export type Balance = {
55
+ balance: number;
56
+ holds: number;
57
+ available: number;
58
+ };
59
+ /**
60
+ * Tier-aware balance from GET /v1/billing/tier. effectiveAvailable folds the
61
+ * tenant's included plan allotment (e.g. the free-tier daily credit) into the
62
+ * prepaid available balance — gate on this to honor included usage first.
63
+ */
64
+ export type TierResponse = {
65
+ user: string;
66
+ tier: {
67
+ name: string;
68
+ displayName?: string;
69
+ maxAgents?: number;
70
+ unlimitedAgents?: boolean;
71
+ dailyCreditsCents?: number;
72
+ allowedModels?: string[];
73
+ };
74
+ balance: {
75
+ currency: string;
76
+ prepaidAvailable: number;
77
+ dailyRemaining: number;
78
+ effectiveAvailable: number;
79
+ };
80
+ };
81
+ export type Transaction = {
82
+ id?: string;
83
+ owner?: string;
84
+ type: 'hold' | 'hold-removed' | 'transfer' | 'deposit' | 'withdraw';
85
+ destinationId?: string;
86
+ destinationKind?: string;
87
+ sourceId?: string;
88
+ sourceKind?: string;
89
+ currency: string;
90
+ amount: number;
91
+ tags?: string[];
92
+ expiresAt?: string;
93
+ metadata?: Record<string, unknown>;
94
+ createdAt?: string;
95
+ };
96
+ export type Subscription = {
97
+ id?: string;
98
+ planId?: string;
99
+ userId?: string;
100
+ customerId?: string;
101
+ status?: 'trialing' | 'active' | 'past_due' | 'canceled' | 'unpaid' | string;
102
+ billingType?: 'charge_automatically' | 'send_invoice';
103
+ periodStart?: string;
104
+ periodEnd?: string;
105
+ trialStart?: string;
106
+ trialEnd?: string;
107
+ quantity?: number;
108
+ createdAt?: string;
109
+ cancelAtPeriodEnd?: boolean;
110
+ currentPeriodEnd?: string;
111
+ };
112
+ export type Plan = {
113
+ id?: string;
114
+ slug?: string;
115
+ name?: string;
116
+ description?: string;
117
+ price?: number;
118
+ priceMonthly?: number;
119
+ priceAnnual?: number;
120
+ currency?: string;
121
+ interval?: 'monthly' | 'yearly' | string;
122
+ intervalCount?: number;
123
+ trialPeriodDays?: number;
124
+ features?: string[];
125
+ popular?: boolean;
126
+ contactSales?: boolean;
127
+ metadata?: Record<string, unknown>;
128
+ };
129
+ export type Payment = {
130
+ id?: string;
131
+ orderId?: string;
132
+ userId?: string;
133
+ amount?: number;
134
+ amountRefunded?: number;
135
+ fee?: number;
136
+ currency?: string;
137
+ status?: 'cancelled' | 'credit' | 'disputed' | 'failed' | 'fraudulent' | 'paid' | 'refunded' | 'unpaid' | string;
138
+ captured?: boolean;
139
+ live?: boolean;
140
+ createdAt?: string;
141
+ };
142
+ export type UsageRecord = {
143
+ user: string;
144
+ currency?: string;
145
+ amount: number;
146
+ model?: string;
147
+ provider?: string;
148
+ tokens?: number;
149
+ promptTokens?: number;
150
+ completionTokens?: number;
151
+ };
152
+ export type CouponType = 'Percent' | 'Flat' | 'FreeShipping' | 'FreeItem';
153
+ export type Coupon = {
154
+ id?: string;
155
+ code: string;
156
+ type: CouponType;
157
+ /** Amount: percentage (0-100) for Percent, cents for Flat */
158
+ amount: number;
159
+ description?: string;
160
+ limit?: number;
161
+ used?: number;
162
+ startDate?: string;
163
+ endDate?: string;
164
+ enabled?: boolean;
165
+ /** Calculated discount in cents (returned by validateCoupon) */
166
+ discountCents?: number;
167
+ };
168
+ export type CouponValidateResult = {
169
+ valid: boolean;
170
+ coupon?: Coupon;
171
+ error?: string;
172
+ /** Discount in cents for a given subtotal */
173
+ discountCents?: number;
174
+ };
175
+ export type Discount = {
176
+ id?: string;
177
+ type: 'Percent' | 'Flat' | 'FreeShipping' | 'FreeItem' | 'Bulk';
178
+ amount: number;
179
+ scope?: 'Product' | 'Variant' | 'Collection' | 'Store';
180
+ enabled?: boolean;
181
+ startDate?: string;
182
+ endDate?: string;
183
+ };
184
+ export type CheckoutItem = {
185
+ id: string;
186
+ quantity?: number;
187
+ /** Price override in cents */
188
+ price?: number;
189
+ name?: string;
190
+ description?: string;
191
+ imageUrl?: string;
192
+ metadata?: Record<string, unknown>;
193
+ };
194
+ export type CheckoutSessionRequest = {
195
+ items: CheckoutItem[];
196
+ successUrl: string;
197
+ cancelUrl: string;
198
+ couponCode?: string;
199
+ referrerId?: string;
200
+ affiliateId?: string;
201
+ currency?: string;
202
+ customer?: {
203
+ email?: string;
204
+ name?: string;
205
+ address?: string;
206
+ city?: string;
207
+ zip?: string;
208
+ };
209
+ metadata?: Record<string, unknown>;
210
+ };
211
+ export type CheckoutSessionResponse = {
212
+ checkoutUrl: string;
213
+ sessionId: string;
214
+ /** Original total in cents before discount */
215
+ originalTotal?: number;
216
+ /** Final total in cents after discount */
217
+ finalTotal?: number;
218
+ discount?: {
219
+ code: string;
220
+ type: CouponType;
221
+ amount: number;
222
+ discountCents: number;
223
+ };
224
+ };
225
+ export type CardTokenizeRequest = {
226
+ number: string;
227
+ expiryMonth: string;
228
+ expiryYear: string;
229
+ cvc: string;
230
+ name?: string;
231
+ zip?: string;
232
+ };
233
+ export type CardTokenizeResult = {
234
+ token: string;
235
+ brand: string;
236
+ last4: string;
237
+ expiryMonth: string;
238
+ expiryYear: string;
239
+ provider: string;
240
+ };
241
+ export type PaymentMethodType = 'card' | 'bank_account' | 'balance' | 'crypto' | 'wire';
242
+ export type PaymentMethod = {
243
+ id: string;
244
+ type: PaymentMethodType;
245
+ isDefault?: boolean;
246
+ customerId?: string;
247
+ card?: {
248
+ brand: string;
249
+ last4: string;
250
+ expMonth: number;
251
+ expYear: number;
252
+ };
253
+ bank_account?: {
254
+ bankName?: string;
255
+ last4?: string;
256
+ accountType?: 'checking' | 'savings';
257
+ routingNumber?: string;
258
+ };
259
+ crypto?: {
260
+ chain: string;
261
+ address: string;
262
+ label?: string;
263
+ };
264
+ providerRef?: string;
265
+ providerType?: string;
266
+ createdAt?: string;
267
+ };
268
+ export type Referral = {
269
+ id?: string;
270
+ userId?: string;
271
+ referrerId?: string;
272
+ affiliateId?: string;
273
+ orderId?: string;
274
+ fee?: number;
275
+ createdAt?: string;
276
+ };
277
+ export type Referrer = {
278
+ id?: string;
279
+ userId?: string;
280
+ enabled?: boolean;
281
+ code?: string;
282
+ referrals?: Referral[];
283
+ };
284
+ export type Affiliate = {
285
+ id?: string;
286
+ userId?: string;
287
+ enabled?: boolean;
288
+ commission?: number;
289
+ couponId?: string;
290
+ connectUrl?: string;
291
+ };
292
+ export type CreditGrant = {
293
+ id?: string;
294
+ userId?: string;
295
+ amount: number;
296
+ currency: string;
297
+ expiresAt?: string;
298
+ tags?: string[];
299
+ };
300
+ export declare class Commerce {
301
+ private readonly baseUrl;
302
+ private token;
303
+ private readonly timeoutMs;
304
+ constructor(config?: CommerceClientConfig);
305
+ /** Update the auth token (e.g. after IAM token refresh). */
306
+ setToken(token: string): void;
307
+ private request;
308
+ getBalance(user: string, currency?: string, token?: string, headers?: Record<string, string>): Promise<Balance>;
309
+ getAllBalances(user: string, token?: string): Promise<Record<string, Balance>>;
310
+ /**
311
+ * Tier-aware balance: prepaid available plus the tenant's included plan
312
+ * allotment (effectiveAvailable). Use this for the metering gate when you
313
+ * want included usage (e.g. free-tier daily credit) honored before prepaid
314
+ * funds are drawn down.
315
+ */
316
+ getTier(user: string, opts?: {
317
+ token?: string;
318
+ headers?: Record<string, string>;
319
+ }): Promise<TierResponse>;
320
+ addUsageRecord(record: UsageRecord, token?: string, headers?: Record<string, string>): Promise<Transaction>;
321
+ getUsageRecords(user: string, currency?: string, token?: string): Promise<Transaction[]>;
322
+ addDeposit(params: {
323
+ user: string;
324
+ currency?: string;
325
+ amount: number;
326
+ notes?: string;
327
+ tags?: string[];
328
+ expiresIn?: string;
329
+ }, token?: string): Promise<Transaction>;
330
+ grantStarterCredit(user: string, token?: string): Promise<Transaction>;
331
+ getPlans(token?: string): Promise<Plan[]>;
332
+ getPlan(planId: string, token?: string): Promise<Plan | null>;
333
+ subscribe(params: {
334
+ planId: string;
335
+ userId?: string;
336
+ customerId?: string;
337
+ paymentMethodId?: string;
338
+ couponCode?: string;
339
+ trialDays?: number;
340
+ }, token?: string): Promise<Subscription>;
341
+ getSubscription(subscriptionId: string, token?: string): Promise<Subscription | null>;
342
+ listSubscriptions(params?: {
343
+ customerId?: string;
344
+ }, token?: string): Promise<Subscription[]>;
345
+ updateSubscription(subscriptionId: string, update: Partial<Subscription>, token?: string): Promise<Subscription>;
346
+ cancelSubscription(subscriptionId: string, immediately?: boolean, token?: string): Promise<Subscription>;
347
+ reactivateSubscription(subscriptionId: string, token?: string): Promise<Subscription>;
348
+ /**
349
+ * Create a hosted checkout session.
350
+ * Returns a URL to redirect the customer to for payment.
351
+ * Supports coupons, referral tracking, and multiple currencies.
352
+ */
353
+ createCheckoutSession(params: CheckoutSessionRequest, token?: string): Promise<CheckoutSessionResponse>;
354
+ /**
355
+ * Tokenize a payment card server-side.
356
+ * No external SDK (Square.js, Stripe.js, etc.) is needed on the frontend.
357
+ * The card data is sent to the Hanzo Commerce API over HTTPS, which
358
+ * tokenizes via the configured payment provider (Stripe).
359
+ */
360
+ tokenizeCard(card: CardTokenizeRequest, token?: string): Promise<CardTokenizeResult>;
361
+ addPaymentMethod(params: {
362
+ customerId: string;
363
+ type: PaymentMethodType;
364
+ token?: string;
365
+ providerRef?: string;
366
+ providerType?: string;
367
+ }, token?: string): Promise<PaymentMethod>;
368
+ listPaymentMethods(customerId: string, token?: string): Promise<PaymentMethod[]>;
369
+ removePaymentMethod(paymentMethodId: string, token?: string): Promise<void>;
370
+ setDefaultPaymentMethod(customerId: string, paymentMethodId: string, token?: string): Promise<PaymentMethod>;
371
+ /**
372
+ * Validate a coupon code.
373
+ * Optionally pass a subtotalCents to get the calculated discount amount.
374
+ */
375
+ validateCoupon(code: string, subtotalCents?: number, token?: string): Promise<CouponValidateResult>;
376
+ /**
377
+ * Redeem a coupon for a user. Creates credit grant records.
378
+ */
379
+ redeemCoupon(code: string, userId: string, token?: string): Promise<CreditGrant[]>;
380
+ /**
381
+ * Get or create a referrer record for a user.
382
+ * Returns the referral code/link the user can share.
383
+ */
384
+ getOrCreateReferrer(userId: string, token?: string): Promise<Referrer>;
385
+ getReferrals(userId: string, token?: string): Promise<Referral[]>;
386
+ getReferrers(userId: string, token?: string): Promise<Referrer[]>;
387
+ /**
388
+ * Get affiliate details for a user.
389
+ */
390
+ getAffiliate(userId: string, token?: string): Promise<Affiliate | null>;
391
+ /**
392
+ * Create an affiliate account for a user.
393
+ * After creation, user can connect their bank via the returnedconnectUrl.
394
+ */
395
+ createAffiliate(userId: string, token?: string): Promise<Affiliate>;
396
+ getAffiliateReferrals(affiliateId: string, token?: string): Promise<Referral[]>;
397
+ getAffiliateOrders(affiliateId: string, token?: string): Promise<unknown[]>;
398
+ getAffiliateTransactions(affiliateId: string, token?: string): Promise<Transaction[]>;
399
+ authorize(orderId: string, token?: string): Promise<Payment>;
400
+ capture(orderId: string, token?: string): Promise<Payment>;
401
+ charge(orderId: string, token?: string): Promise<Payment>;
402
+ refund(paymentId: string, token?: string): Promise<Payment>;
403
+ billingRefund(params: {
404
+ user: string;
405
+ amount: number;
406
+ originalTransactionId: string;
407
+ currency?: string;
408
+ notes?: string;
409
+ }, token?: string): Promise<Transaction>;
410
+ /**
411
+ * Get or create a deposit address for a given chain.
412
+ * Used for crypto top-up — user sends funds to this address.
413
+ */
414
+ getWalletAddress(params: {
415
+ chain: string;
416
+ userId: string;
417
+ }, token?: string): Promise<{
418
+ address: string;
419
+ chain: string;
420
+ qrCode?: string;
421
+ }>;
422
+ /**
423
+ * Add a bank account payment method (ACH).
424
+ * plaidToken from Plaid Link or Square bank OAuth.
425
+ */
426
+ addBankAccount(params: {
427
+ customerId: string;
428
+ plaidToken?: string;
429
+ bankName?: string;
430
+ accountType?: 'checking' | 'savings';
431
+ }, token?: string): Promise<PaymentMethod>;
432
+ addCryptoWallet(params: {
433
+ customerId: string;
434
+ chain: string;
435
+ address: string;
436
+ label?: string;
437
+ }, token?: string): Promise<PaymentMethod>;
438
+ /**
439
+ * Convenience: charge a saved payment method and deposit credits.
440
+ * amount is in cents.
441
+ */
442
+ topup(params: {
443
+ userId: string;
444
+ paymentMethodId: string;
445
+ amountCents: number;
446
+ currency?: string;
447
+ }, token?: string): Promise<Transaction>;
448
+ }
449
+ /**
450
+ * Create a commerce client pre-configured for api.hanzo.ai.
451
+ * Pass your IAM access token (read from localStorage or cookie).
452
+ *
453
+ * @example
454
+ * ```ts
455
+ * import { hanzoCommerce } from '@hanzo/commerce/client'
456
+ * const commerce = hanzoCommerce(localStorage.getItem('hanzo-auth-token') ?? undefined)
457
+ * const plans = await commerce.getPlans()
458
+ * ```
459
+ */
460
+ export declare function hanzoCommerce(token?: string): Commerce;
461
+ export declare class CommerceApiError extends Error {
462
+ readonly status: number;
463
+ constructor(status: number, message: string);
464
+ }