@entitlehub/sdk 0.3.0 → 0.3.1
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/CHANGELOG.md +16 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +1 -1
- package/package.json +11 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@entitlehub/sdk`. Adheres to [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## 0.3.1 (2026-09-20)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `isReceiptRevoked(err)`: was this purchase report refused because the receipt has been refunded?
|
|
9
|
+
Reporting a refunded receipt answers `409 receipt_revoked`: no grant is written, and the
|
|
10
|
+
entitlement it had granted is revoked server-side. Shipped as a function because the obvious
|
|
11
|
+
guess, `err.status === 409`, is wrong: the catalog endpoints answer 409 for their own conflicts
|
|
12
|
+
(`product_exists`, `entitlement_in_use`, …).
|
|
13
|
+
|
|
14
|
+
### Notes
|
|
15
|
+
- If you are on **0.2.0 or earlier**, `err.body` and `err.apiCode` do not exist, so a check written
|
|
16
|
+
against them silently never matches. Upgrade to 0.3.0+ before relying on either.
|
|
17
|
+
- `err.code` remains the SDK-level category (`config` | `auth` | `http` | `network` | `no_fetch`).
|
|
18
|
+
The API's own code is `err.apiCode`, and has been since 0.3.0. Branch on `apiCode`, or just call
|
|
19
|
+
`isReceiptRevoked`.
|
|
20
|
+
|
|
5
21
|
## 0.3.0 (2026-09-19)
|
|
6
22
|
|
|
7
23
|
### Added
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var I=Object.defineProperty;var
|
|
1
|
+
"use strict";var I=Object.defineProperty;var H=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var D=(r,t)=>{for(var e in t)I(r,e,{get:t[e],enumerable:!0})},q=(r,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of U(t))!A.call(r,s)&&s!==e&&I(r,s,{get:()=>t[s],enumerable:!(n=H(t,s))||n.enumerable});return r};var N=r=>q(I({},"__esModule",{value:!0}),r);var L={};D(L,{CustomerInfo:()=>c,EntitleHub:()=>y,EntitleHubError:()=>a,EntitleHubServer:()=>b,EntitlementsApi:()=>l,OfferingsApi:()=>m,ProductsApi:()=>g,isReceiptRevoked:()=>x});module.exports=N(L);var c=class{constructor(t){this.appUserId=t.app_user_id,this.entitlements=t.active_entitlements??[];let e={};for(let n of this.entitlements)e[n.entitlement]=n;this.active=e}isActive(t){return!!this.active[t]}get activeEntitlementIds(){return Object.keys(this.active)}expirationDate(t){let e=this.active[t];if(e)return e.expires_at?new Date(e.expires_at):null}};var S="0.3.0";var a=class extends Error{constructor(t,e,n="error",s){super(t),this.name="EntitleHubError",this.status=e,this.code=n,this.body=s,this.apiCode=typeof s?.code=="string"?s.code:void 0}};function x(r){if(!r||typeof r!="object")return!1;let t=r;return t.apiCode==="receipt_revoked"||t.body?.code==="receipt_revoked"}var K=r=>new Promise(t=>setTimeout(t,r));async function i(r,t,e,n){let s=r.fetchImpl??globalThis.fetch;if(!s)throw new a("No fetch implementation available. On Node <18, pass fetchImpl.",0,"no_fetch");let C=`${r.baseUrl.replace(/\/$/,"")}${e}`,E=t==="GET"?r.retries??2:0,_;for(let f=0;f<=E;f++){let w=new AbortController,T=r.timeoutMs?setTimeout(()=>w.abort(),r.timeoutMs):void 0;try{let u=await s(C,{method:t,headers:{Authorization:`Bearer ${r.apiKey}`,"X-EntitleHub-Client":r.client??`${"js"}/${S}`,...n?{"Content-Type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:w.signal}),v=await u.text(),h=v?j(v):{};if(!u.ok){let O=`HTTP ${u.status}`,P=h&&typeof h=="object"?h:void 0;throw P&&"error"in P&&(O=String(P.error)),new a(O,u.status,u.status===401||u.status===403?"auth":"http",P)}return h}catch(u){if(_=u,u instanceof a)throw u;f<E&&await K(250*(f+1))}finally{T&&clearTimeout(T)}}throw new a(`Network request failed: ${String(_?.message??_)}`,0,"network")}function j(r){try{return JSON.parse(r)}catch{return{}}}var y=class{constructor(t){this.listeners=new Set;if(!t.apiKey)throw new a("apiKey is required.",0,"config");if(!t.appUserId)throw new a("appUserId is required.",0,"config");if(t.apiKey.startsWith("sk_"))throw new a("Never use a secret (sk_) key in the client SDK. Use your publishable (pk_) key.",0,"config");this.appUserId=t.appUserId,this.cacheTtlMs=t.cacheTtlMs??5*6e4,this.http={baseUrl:t.baseUrl??"https://entitlehub.com/v1",apiKey:t.apiKey,fetchImpl:t.fetchImpl,timeoutMs:15e3,client:t.client}}get currentAppUserId(){return this.appUserId}async logIn(t){return this.appUserId=t,this.cached=void 0,this.getCustomerInfo({fetchPolicy:"network-only"})}logOut(){this.cached=void 0}async getCustomerInfo(t={}){if((t.fetchPolicy??"cache-first")==="cache-first"&&this.cached&&Date.now()-this.cached.at<this.cacheTtlMs)return this.cached.info;let n=await i(this.http,"GET",`/subscribers/${encodeURIComponent(this.appUserId)}`),s=new c(n);this.cached={info:s,at:Date.now()};for(let C of this.listeners)try{C(s)}catch{}return s}async isEntitled(t){return(await this.getCustomerInfo()).isActive(t)}async checkEntitlement(t,e={}){return i(this.http,"POST","/check",{app_user_id:this.appUserId,entitlement:t,sandbox:!!e.sandbox})}async getOfferings(){return i(this.http,"GET","/offerings")}async reportPurchase(t){let e=await i(this.http,"POST",`/subscribers/${encodeURIComponent(this.appUserId)}/purchases`,{store:t.store??"",store_product_id:t.storeProductId??"",is_sandbox:!!t.isSandbox,purchase_token:t.purchaseToken??"",is_subscription:!!t.isSubscription,signed_transaction:t.signedTransaction??"",stripe_subscription_id:t.stripeSubscriptionId??""}),n=new c(e);this.cached={info:n,at:Date.now()};for(let s of this.listeners)try{s(n)}catch{}return n}addCustomerInfoUpdateListener(t){return this.listeners.add(t),()=>this.listeners.delete(t)}};var o=encodeURIComponent;function p(r){return typeof r=="string"?r:"id"in r?{id:r.id}:{store:r.store,store_product_id:r.storeProductId}}function d(r){return typeof r=="string"?{seg:o(r),qs:""}:"id"in r?{seg:o(r.id),qs:""}:{seg:o(r.storeProductId),qs:`?store=${o(r.store)}`}}var k=r=>r?.includeArchived?"include_archived=true":"";async function $(r,t){try{return await r()}catch(e){if(e instanceof a&&e.apiCode===t&&e.body?.existing)return e.body.existing;throw e}}var l=class{constructor(t){this.http=t}async list(t){let e=k(t);return(await i(this.http,"GET",`/entitlements${e?`?${e}`:""}`)).entitlements}get(t){return i(this.http,"GET",`/entitlements/${o(t)}`)}create(t){return i(this.http,"POST","/entitlements",{key:t.key,name:t.name,description:t.description,products:t.products?.map(p)})}ensure(t){return $(()=>this.create(t),"entitlement_exists")}update(t,e){return i(this.http,"PATCH",`/entitlements/${o(t)}`,{name:e.name,description:e.description,products:e.products?.map(p)})}delete(t){return i(this.http,"DELETE",`/entitlements/${o(t)}`)}async products(t,e){let n=k(e);return(await i(this.http,"GET",`/entitlements/${o(t)}/products${n?`?${n}`:""}`)).products}attachProducts(t,e){return i(this.http,"POST",`/entitlements/${o(t)}/attach_products`,{products:e.map(p)})}detachProducts(t,e){return i(this.http,"POST",`/entitlements/${o(t)}/detach_products`,{products:e.map(p)})}archive(t){return i(this.http,"POST",`/entitlements/${o(t)}/archive`)}unarchive(t){return i(this.http,"POST",`/entitlements/${o(t)}/unarchive`)}},g=class{constructor(t){this.http=t}async list(t){let e=new URLSearchParams;t?.store&&e.set("store",t.store),t?.entitlement&&e.set("entitlement",t.entitlement),t?.includeArchived&&e.set("include_archived","true");let n=e.toString();return(await i(this.http,"GET",`/products${n?`?${n}`:""}`)).products}get(t){let{seg:e,qs:n}=d(t);return i(this.http,"GET",`/products/${e}${n}`)}create(t){return i(this.http,"POST","/products",{store:t.store,store_product_id:t.storeProductId,type:t.type,duration:t.duration,display_name:t.displayName,price_micros:t.priceMicros,currency:t.currency,entitlements:t.entitlements})}ensure(t){return $(()=>this.create(t),"product_exists")}update(t,e){let{seg:n,qs:s}=d(t);return i(this.http,"PATCH",`/products/${n}${s}`,{display_name:e.displayName,price_micros:e.priceMicros,currency:e.currency,entitlements:e.entitlements})}delete(t){let{seg:e,qs:n}=d(t);return i(this.http,"DELETE",`/products/${e}${n}`)}attachEntitlements(t,e){let{seg:n,qs:s}=d(t);return i(this.http,"POST",`/products/${n}/attach_entitlements${s}`,{entitlements:e})}detachEntitlements(t,e){let{seg:n,qs:s}=d(t);return i(this.http,"POST",`/products/${n}/detach_entitlements${s}`,{entitlements:e})}archive(t){let{seg:e,qs:n}=d(t);return i(this.http,"POST",`/products/${e}/archive${n}`)}unarchive(t){let{seg:e,qs:n}=d(t);return i(this.http,"POST",`/products/${e}/unarchive${n}`)}},m=class{constructor(t){this.http=t}async list(t){let e=k(t);return(await i(this.http,"GET",`/offerings/all${e?`?${e}`:""}`)).offerings}get(t){return i(this.http,"GET",`/offerings/${o(t)}`)}create(t){return i(this.http,"POST","/offerings",{identifier:t.identifier,display_name:t.displayName,is_current:t.isCurrent,metadata:t.metadata,packages:t.packages?.map(R)})}update(t,e){return i(this.http,"PATCH",`/offerings/${o(t)}`,{display_name:e.displayName,is_current:e.isCurrent,metadata:e.metadata})}delete(t){return i(this.http,"DELETE",`/offerings/${o(t)}`)}archive(t){return i(this.http,"POST",`/offerings/${o(t)}/archive`)}unarchive(t){return i(this.http,"POST",`/offerings/${o(t)}/unarchive`)}async packages(t){return(await i(this.http,"GET",`/offerings/${o(t)}/packages`)).packages}addPackage(t,e){return i(this.http,"POST",`/offerings/${o(t)}/packages`,R(e))}updatePackage(t,e,n){return i(this.http,"PATCH",`/offerings/${o(t)}/packages/${o(e)}`,{display_name:n.displayName,position:n.position,product:n.product===void 0?void 0:p(n.product)})}deletePackage(t,e){return i(this.http,"DELETE",`/offerings/${o(t)}/packages/${o(e)}`)}};function R(r){return{identifier:r.identifier,product:p(r.product),position:r.position,display_name:r.displayName}}var b=class{constructor(t){if(!t.apiKey)throw new a("apiKey is required.",0,"config");if(!t.apiKey.startsWith("sk_"))throw new a("EntitleHubServer needs a secret (sk_) key. For client reads, use the EntitleHub class with a pk_ key.",0,"config");this.http={baseUrl:t.baseUrl??"https://entitlehub.com/v1",apiKey:t.apiKey,fetchImpl:t.fetchImpl,timeoutMs:15e3},this.entitlements=new l(this.http),this.products=new g(this.http),this.offerings=new m(this.http)}async reportPurchase(t,e){let n=await i(this.http,"POST",`/subscribers/${encodeURIComponent(t)}/purchases`,{store:e.store,store_product_id:e.storeProductId,is_sandbox:!!e.isSandbox,transaction_id:e.transactionId??"",purchase_token:e.purchaseToken??"",is_subscription:!!e.isSubscription,signed_transaction:e.signedTransaction??"",stripe_subscription_id:e.stripeSubscriptionId??""});return new c(n)}async grantEntitlement(t,e,n={}){let s=await i(this.http,"POST",`/subscribers/${encodeURIComponent(t)}/grant`,{entitlement:e,duration_days:n.durationDays??0,is_sandbox:!!n.isSandbox});return new c(s)}async getCustomerInfo(t){let e=await i(this.http,"GET",`/subscribers/${encodeURIComponent(t)}`);return new c(e)}async check(t,e,n={}){return i(this.http,"POST","/check",{app_user_id:t,entitlement:e,sandbox:!!n.sandbox})}};0&&(module.exports={CustomerInfo,EntitleHub,EntitleHubError,EntitleHubServer,EntitlementsApi,OfferingsApi,ProductsApi,isReceiptRevoked});
|
package/dist/index.d.cts
CHANGED
|
@@ -187,6 +187,21 @@ declare class EntitleHubError extends Error {
|
|
|
187
187
|
readonly body?: Record<string, unknown>;
|
|
188
188
|
constructor(message: string, status: number, code?: string, body?: Record<string, unknown>);
|
|
189
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Was this purchase report refused because the receipt has been REFUNDED?
|
|
192
|
+
*
|
|
193
|
+
* Reporting a refunded receipt answers 409 `receipt_revoked`: no grant is written, and EntitleHub
|
|
194
|
+
* revokes the entitlement it had granted. Apple stamps revocationDate permanently and StoreKit
|
|
195
|
+
* keeps handing the transaction back, so this is the signal that a purchase went away because the
|
|
196
|
+
* money was returned, rather than for some unexplained reason.
|
|
197
|
+
*
|
|
198
|
+
* Shipped as a function so nobody has to write the check themselves: reaching for `status === 409`
|
|
199
|
+
* is the obvious guess and the wrong one, because the catalog endpoints answer 409 for their own
|
|
200
|
+
* conflicts (`product_exists`, `entitlement_in_use`, …). Matching on the API code is exact.
|
|
201
|
+
*
|
|
202
|
+
* Duck-typed rather than `instanceof`, so it still works when the error crosses a bundle boundary.
|
|
203
|
+
*/
|
|
204
|
+
declare function isReceiptRevoked(err: unknown): boolean;
|
|
190
205
|
interface HttpOptions {
|
|
191
206
|
baseUrl: string;
|
|
192
207
|
apiKey: string;
|
|
@@ -438,7 +453,7 @@ declare class EntitleHubServer {
|
|
|
438
453
|
*
|
|
439
454
|
* Three modes (pick one):
|
|
440
455
|
* • Google (validated): { store:"play", storeProductId, purchaseToken, isSubscription }
|
|
441
|
-
* • Apple (validated): { signedTransaction }
|
|
456
|
+
* • Apple (validated): { signedTransaction } - store/product are read from the JWS
|
|
442
457
|
* • Stripe (validated): { stripeSubscriptionId }, validated via your Stripe secret key
|
|
443
458
|
* • Trusted server-report: { store, storeProductId }, no store validation; only when you've
|
|
444
459
|
* already validated the receipt elsewhere.
|
|
@@ -457,4 +472,4 @@ declare class EntitleHubServer {
|
|
|
457
472
|
}): Promise<CheckResult>;
|
|
458
473
|
}
|
|
459
474
|
|
|
460
|
-
export { type ActiveEntitlement, type CatalogEntitlement, type CatalogOffering, type CatalogPackage, type CatalogProduct, type CheckResult, type CreateEntitlementInput, type CreateProductInput, CustomerInfo, type CustomerInfoListener, type CustomerInfoResponse, type Deleted, type Duration, EntitleHub, EntitleHubError, type EntitleHubOptions, EntitleHubServer, type EntitleHubServerOptions, type EntitlementStatus, EntitlementsApi, type FetchPolicy, type ListedOffering, type OfferingEntitlement, type OfferingProduct, type Offerings, OfferingsApi, type PackageInput, type ProductRef, type ProductType, ProductsApi, type PurchaseInput, type Store };
|
|
475
|
+
export { type ActiveEntitlement, type CatalogEntitlement, type CatalogOffering, type CatalogPackage, type CatalogProduct, type CheckResult, type CreateEntitlementInput, type CreateProductInput, CustomerInfo, type CustomerInfoListener, type CustomerInfoResponse, type Deleted, type Duration, EntitleHub, EntitleHubError, type EntitleHubOptions, EntitleHubServer, type EntitleHubServerOptions, type EntitlementStatus, EntitlementsApi, type FetchPolicy, type ListedOffering, type OfferingEntitlement, type OfferingProduct, type Offerings, OfferingsApi, type PackageInput, type ProductRef, type ProductType, ProductsApi, type PurchaseInput, type Store, isReceiptRevoked };
|
package/dist/index.d.ts
CHANGED
|
@@ -187,6 +187,21 @@ declare class EntitleHubError extends Error {
|
|
|
187
187
|
readonly body?: Record<string, unknown>;
|
|
188
188
|
constructor(message: string, status: number, code?: string, body?: Record<string, unknown>);
|
|
189
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Was this purchase report refused because the receipt has been REFUNDED?
|
|
192
|
+
*
|
|
193
|
+
* Reporting a refunded receipt answers 409 `receipt_revoked`: no grant is written, and EntitleHub
|
|
194
|
+
* revokes the entitlement it had granted. Apple stamps revocationDate permanently and StoreKit
|
|
195
|
+
* keeps handing the transaction back, so this is the signal that a purchase went away because the
|
|
196
|
+
* money was returned, rather than for some unexplained reason.
|
|
197
|
+
*
|
|
198
|
+
* Shipped as a function so nobody has to write the check themselves: reaching for `status === 409`
|
|
199
|
+
* is the obvious guess and the wrong one, because the catalog endpoints answer 409 for their own
|
|
200
|
+
* conflicts (`product_exists`, `entitlement_in_use`, …). Matching on the API code is exact.
|
|
201
|
+
*
|
|
202
|
+
* Duck-typed rather than `instanceof`, so it still works when the error crosses a bundle boundary.
|
|
203
|
+
*/
|
|
204
|
+
declare function isReceiptRevoked(err: unknown): boolean;
|
|
190
205
|
interface HttpOptions {
|
|
191
206
|
baseUrl: string;
|
|
192
207
|
apiKey: string;
|
|
@@ -438,7 +453,7 @@ declare class EntitleHubServer {
|
|
|
438
453
|
*
|
|
439
454
|
* Three modes (pick one):
|
|
440
455
|
* • Google (validated): { store:"play", storeProductId, purchaseToken, isSubscription }
|
|
441
|
-
* • Apple (validated): { signedTransaction }
|
|
456
|
+
* • Apple (validated): { signedTransaction } - store/product are read from the JWS
|
|
442
457
|
* • Stripe (validated): { stripeSubscriptionId }, validated via your Stripe secret key
|
|
443
458
|
* • Trusted server-report: { store, storeProductId }, no store validation; only when you've
|
|
444
459
|
* already validated the receipt elsewhere.
|
|
@@ -457,4 +472,4 @@ declare class EntitleHubServer {
|
|
|
457
472
|
}): Promise<CheckResult>;
|
|
458
473
|
}
|
|
459
474
|
|
|
460
|
-
export { type ActiveEntitlement, type CatalogEntitlement, type CatalogOffering, type CatalogPackage, type CatalogProduct, type CheckResult, type CreateEntitlementInput, type CreateProductInput, CustomerInfo, type CustomerInfoListener, type CustomerInfoResponse, type Deleted, type Duration, EntitleHub, EntitleHubError, type EntitleHubOptions, EntitleHubServer, type EntitleHubServerOptions, type EntitlementStatus, EntitlementsApi, type FetchPolicy, type ListedOffering, type OfferingEntitlement, type OfferingProduct, type Offerings, OfferingsApi, type PackageInput, type ProductRef, type ProductType, ProductsApi, type PurchaseInput, type Store };
|
|
475
|
+
export { type ActiveEntitlement, type CatalogEntitlement, type CatalogOffering, type CatalogPackage, type CatalogProduct, type CheckResult, type CreateEntitlementInput, type CreateProductInput, CustomerInfo, type CustomerInfoListener, type CustomerInfoResponse, type Deleted, type Duration, EntitleHub, EntitleHubError, type EntitleHubOptions, EntitleHubServer, type EntitleHubServerOptions, type EntitlementStatus, EntitlementsApi, type FetchPolicy, type ListedOffering, type OfferingEntitlement, type OfferingProduct, type Offerings, OfferingsApi, type PackageInput, type ProductRef, type ProductType, ProductsApi, type PurchaseInput, type Store, isReceiptRevoked };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var u=class{constructor(t){this.appUserId=t.app_user_id,this.entitlements=t.active_entitlements??[];let e={};for(let r of this.entitlements)e[r.entitlement]=r;this.active=e}isActive(t){return!!this.active[t]}get activeEntitlementIds(){return Object.keys(this.active)}expirationDate(t){let e=this.active[t];if(e)return e.expires_at?new Date(e.expires_at):null}};var
|
|
1
|
+
var u=class{constructor(t){this.appUserId=t.app_user_id,this.entitlements=t.active_entitlements??[];let e={};for(let r of this.entitlements)e[r.entitlement]=r;this.active=e}isActive(t){return!!this.active[t]}get activeEntitlementIds(){return Object.keys(this.active)}expirationDate(t){let e=this.active[t];if(e)return e.expires_at?new Date(e.expires_at):null}};var O="0.3.0";var a=class extends Error{constructor(t,e,r="error",o){super(t),this.name="EntitleHubError",this.status=e,this.code=r,this.body=o,this.apiCode=typeof o?.code=="string"?o.code:void 0}};function $(n){if(!n||typeof n!="object")return!1;let t=n;return t.apiCode==="receipt_revoked"||t.body?.code==="receipt_revoked"}var H=n=>new Promise(t=>setTimeout(t,n));async function i(n,t,e,r){let o=n.fetchImpl??globalThis.fetch;if(!o)throw new a("No fetch implementation available. On Node <18, pass fetchImpl.",0,"no_fetch");let y=`${n.baseUrl.replace(/\/$/,"")}${e}`,k=t==="GET"?n.retries??2:0,b;for(let f=0;f<=k;f++){let E=new AbortController,w=n.timeoutMs?setTimeout(()=>E.abort(),n.timeoutMs):void 0;try{let c=await o(y,{method:t,headers:{Authorization:`Bearer ${n.apiKey}`,"X-EntitleHub-Client":n.client??`${"js"}/${O}`,...r?{"Content-Type":"application/json"}:{}},body:r?JSON.stringify(r):void 0,signal:E.signal}),T=await c.text(),h=T?U(T):{};if(!c.ok){let v=`HTTP ${c.status}`,P=h&&typeof h=="object"?h:void 0;throw P&&"error"in P&&(v=String(P.error)),new a(v,c.status,c.status===401||c.status===403?"auth":"http",P)}return h}catch(c){if(b=c,c instanceof a)throw c;f<k&&await H(250*(f+1))}finally{w&&clearTimeout(w)}}throw new a(`Network request failed: ${String(b?.message??b)}`,0,"network")}function U(n){try{return JSON.parse(n)}catch{return{}}}var C=class{constructor(t){this.listeners=new Set;if(!t.apiKey)throw new a("apiKey is required.",0,"config");if(!t.appUserId)throw new a("appUserId is required.",0,"config");if(t.apiKey.startsWith("sk_"))throw new a("Never use a secret (sk_) key in the client SDK. Use your publishable (pk_) key.",0,"config");this.appUserId=t.appUserId,this.cacheTtlMs=t.cacheTtlMs??5*6e4,this.http={baseUrl:t.baseUrl??"https://entitlehub.com/v1",apiKey:t.apiKey,fetchImpl:t.fetchImpl,timeoutMs:15e3,client:t.client}}get currentAppUserId(){return this.appUserId}async logIn(t){return this.appUserId=t,this.cached=void 0,this.getCustomerInfo({fetchPolicy:"network-only"})}logOut(){this.cached=void 0}async getCustomerInfo(t={}){if((t.fetchPolicy??"cache-first")==="cache-first"&&this.cached&&Date.now()-this.cached.at<this.cacheTtlMs)return this.cached.info;let r=await i(this.http,"GET",`/subscribers/${encodeURIComponent(this.appUserId)}`),o=new u(r);this.cached={info:o,at:Date.now()};for(let y of this.listeners)try{y(o)}catch{}return o}async isEntitled(t){return(await this.getCustomerInfo()).isActive(t)}async checkEntitlement(t,e={}){return i(this.http,"POST","/check",{app_user_id:this.appUserId,entitlement:t,sandbox:!!e.sandbox})}async getOfferings(){return i(this.http,"GET","/offerings")}async reportPurchase(t){let e=await i(this.http,"POST",`/subscribers/${encodeURIComponent(this.appUserId)}/purchases`,{store:t.store??"",store_product_id:t.storeProductId??"",is_sandbox:!!t.isSandbox,purchase_token:t.purchaseToken??"",is_subscription:!!t.isSubscription,signed_transaction:t.signedTransaction??"",stripe_subscription_id:t.stripeSubscriptionId??""}),r=new u(e);this.cached={info:r,at:Date.now()};for(let o of this.listeners)try{o(r)}catch{}return r}addCustomerInfoUpdateListener(t){return this.listeners.add(t),()=>this.listeners.delete(t)}};var s=encodeURIComponent;function p(n){return typeof n=="string"?n:"id"in n?{id:n.id}:{store:n.store,store_product_id:n.storeProductId}}function d(n){return typeof n=="string"?{seg:s(n),qs:""}:"id"in n?{seg:s(n.id),qs:""}:{seg:s(n.storeProductId),qs:`?store=${s(n.store)}`}}var _=n=>n?.includeArchived?"include_archived=true":"";async function x(n,t){try{return await n()}catch(e){if(e instanceof a&&e.apiCode===t&&e.body?.existing)return e.body.existing;throw e}}var l=class{constructor(t){this.http=t}async list(t){let e=_(t);return(await i(this.http,"GET",`/entitlements${e?`?${e}`:""}`)).entitlements}get(t){return i(this.http,"GET",`/entitlements/${s(t)}`)}create(t){return i(this.http,"POST","/entitlements",{key:t.key,name:t.name,description:t.description,products:t.products?.map(p)})}ensure(t){return x(()=>this.create(t),"entitlement_exists")}update(t,e){return i(this.http,"PATCH",`/entitlements/${s(t)}`,{name:e.name,description:e.description,products:e.products?.map(p)})}delete(t){return i(this.http,"DELETE",`/entitlements/${s(t)}`)}async products(t,e){let r=_(e);return(await i(this.http,"GET",`/entitlements/${s(t)}/products${r?`?${r}`:""}`)).products}attachProducts(t,e){return i(this.http,"POST",`/entitlements/${s(t)}/attach_products`,{products:e.map(p)})}detachProducts(t,e){return i(this.http,"POST",`/entitlements/${s(t)}/detach_products`,{products:e.map(p)})}archive(t){return i(this.http,"POST",`/entitlements/${s(t)}/archive`)}unarchive(t){return i(this.http,"POST",`/entitlements/${s(t)}/unarchive`)}},g=class{constructor(t){this.http=t}async list(t){let e=new URLSearchParams;t?.store&&e.set("store",t.store),t?.entitlement&&e.set("entitlement",t.entitlement),t?.includeArchived&&e.set("include_archived","true");let r=e.toString();return(await i(this.http,"GET",`/products${r?`?${r}`:""}`)).products}get(t){let{seg:e,qs:r}=d(t);return i(this.http,"GET",`/products/${e}${r}`)}create(t){return i(this.http,"POST","/products",{store:t.store,store_product_id:t.storeProductId,type:t.type,duration:t.duration,display_name:t.displayName,price_micros:t.priceMicros,currency:t.currency,entitlements:t.entitlements})}ensure(t){return x(()=>this.create(t),"product_exists")}update(t,e){let{seg:r,qs:o}=d(t);return i(this.http,"PATCH",`/products/${r}${o}`,{display_name:e.displayName,price_micros:e.priceMicros,currency:e.currency,entitlements:e.entitlements})}delete(t){let{seg:e,qs:r}=d(t);return i(this.http,"DELETE",`/products/${e}${r}`)}attachEntitlements(t,e){let{seg:r,qs:o}=d(t);return i(this.http,"POST",`/products/${r}/attach_entitlements${o}`,{entitlements:e})}detachEntitlements(t,e){let{seg:r,qs:o}=d(t);return i(this.http,"POST",`/products/${r}/detach_entitlements${o}`,{entitlements:e})}archive(t){let{seg:e,qs:r}=d(t);return i(this.http,"POST",`/products/${e}/archive${r}`)}unarchive(t){let{seg:e,qs:r}=d(t);return i(this.http,"POST",`/products/${e}/unarchive${r}`)}},m=class{constructor(t){this.http=t}async list(t){let e=_(t);return(await i(this.http,"GET",`/offerings/all${e?`?${e}`:""}`)).offerings}get(t){return i(this.http,"GET",`/offerings/${s(t)}`)}create(t){return i(this.http,"POST","/offerings",{identifier:t.identifier,display_name:t.displayName,is_current:t.isCurrent,metadata:t.metadata,packages:t.packages?.map(S)})}update(t,e){return i(this.http,"PATCH",`/offerings/${s(t)}`,{display_name:e.displayName,is_current:e.isCurrent,metadata:e.metadata})}delete(t){return i(this.http,"DELETE",`/offerings/${s(t)}`)}archive(t){return i(this.http,"POST",`/offerings/${s(t)}/archive`)}unarchive(t){return i(this.http,"POST",`/offerings/${s(t)}/unarchive`)}async packages(t){return(await i(this.http,"GET",`/offerings/${s(t)}/packages`)).packages}addPackage(t,e){return i(this.http,"POST",`/offerings/${s(t)}/packages`,S(e))}updatePackage(t,e,r){return i(this.http,"PATCH",`/offerings/${s(t)}/packages/${s(e)}`,{display_name:r.displayName,position:r.position,product:r.product===void 0?void 0:p(r.product)})}deletePackage(t,e){return i(this.http,"DELETE",`/offerings/${s(t)}/packages/${s(e)}`)}};function S(n){return{identifier:n.identifier,product:p(n.product),position:n.position,display_name:n.displayName}}var I=class{constructor(t){if(!t.apiKey)throw new a("apiKey is required.",0,"config");if(!t.apiKey.startsWith("sk_"))throw new a("EntitleHubServer needs a secret (sk_) key. For client reads, use the EntitleHub class with a pk_ key.",0,"config");this.http={baseUrl:t.baseUrl??"https://entitlehub.com/v1",apiKey:t.apiKey,fetchImpl:t.fetchImpl,timeoutMs:15e3},this.entitlements=new l(this.http),this.products=new g(this.http),this.offerings=new m(this.http)}async reportPurchase(t,e){let r=await i(this.http,"POST",`/subscribers/${encodeURIComponent(t)}/purchases`,{store:e.store,store_product_id:e.storeProductId,is_sandbox:!!e.isSandbox,transaction_id:e.transactionId??"",purchase_token:e.purchaseToken??"",is_subscription:!!e.isSubscription,signed_transaction:e.signedTransaction??"",stripe_subscription_id:e.stripeSubscriptionId??""});return new u(r)}async grantEntitlement(t,e,r={}){let o=await i(this.http,"POST",`/subscribers/${encodeURIComponent(t)}/grant`,{entitlement:e,duration_days:r.durationDays??0,is_sandbox:!!r.isSandbox});return new u(o)}async getCustomerInfo(t){let e=await i(this.http,"GET",`/subscribers/${encodeURIComponent(t)}`);return new u(e)}async check(t,e,r={}){return i(this.http,"POST","/check",{app_user_id:t,entitlement:e,sandbox:!!r.sandbox})}};export{u as CustomerInfo,C as EntitleHub,a as EntitleHubError,I as EntitleHubServer,l as EntitlementsApi,m as OfferingsApi,g as ProductsApi,$ as isReceiptRevoked};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entitlehub/sdk",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "EntitleHub SDK: one entitlement API across App Store, Google Play, Stripe, and web. Works in browsers, React Native, Expo, and Node.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"entitlehub",
|
|
@@ -12,10 +12,17 @@
|
|
|
12
12
|
"stripe"
|
|
13
13
|
],
|
|
14
14
|
"homepage": "https://entitlehub.com",
|
|
15
|
-
"repository": {
|
|
16
|
-
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/DanCue44/entitlehub-sdk.git"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/DanCue44/entitlehub-sdk/issues"
|
|
21
|
+
},
|
|
17
22
|
"license": "MIT",
|
|
18
|
-
"publishConfig": {
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
19
26
|
"type": "module",
|
|
20
27
|
"main": "./dist/index.cjs",
|
|
21
28
|
"module": "./dist/index.js",
|