@entitlehub/sdk 0.1.2 → 0.2.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/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.2.0 — 2026-07-18
6
+
7
+ ### Added
8
+ - Client `EntitleHub.reportPurchase(...)` — report a **validated** purchase (Apple JWS / Google
9
+ token / Stripe subscription) directly from the app with your publishable key; updates the cache
10
+ and notifies listeners. Validation makes a forged receipt impossible, so no secret key is needed
11
+ on the client. (The trusted server-report mode still requires a secret key.)
12
+ - Powers the new [`@entitlehub/react-native`](https://www.npmjs.com/package/@entitlehub/react-native)
13
+ purchase SDK.
14
+
15
+ ## 0.1.3 — 2026-07-18
16
+
17
+ ### Added
18
+ - `reportPurchase` accepts `stripeSubscriptionId` — EntitleHub validates the subscription against
19
+ your Stripe secret key (active/trialing → granted, current period end as the expiry).
20
+
5
21
  ## 0.1.2 — 2026-07-18
6
22
 
7
23
  ### Changed
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var d=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var E=Object.prototype.hasOwnProperty;var x=(n,e)=>{for(var t in e)d(n,t,{get:e[t],enumerable:!0})},v=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of k(e))!E.call(n,i)&&i!==t&&d(n,i,{get:()=>e[i],enumerable:!(r=C(e,i))||r.enumerable});return n};var O=n=>v(d({},"__esModule",{value:!0}),n);var T={};x(T,{CustomerInfo:()=>a,EntitleHub:()=>l,EntitleHubError:()=>s,EntitleHubServer:()=>f});module.exports=O(T);var a=class{constructor(e){this.appUserId=e.app_user_id,this.entitlements=e.active_entitlements??[];let t={};for(let r of this.entitlements)t[r.entitlement]=r;this.active=t}isActive(e){return!!this.active[e]}get activeEntitlementIds(){return Object.keys(this.active)}expirationDate(e){let t=this.active[e];if(t)return t.expires_at?new Date(t.expires_at):null}};var s=class extends Error{constructor(e,t,r="error"){super(e),this.name="EntitleHubError",this.status=t,this.code=r}},P=n=>new Promise(e=>setTimeout(e,n));async function c(n,e,t,r){let i=n.fetchImpl??globalThis.fetch;if(!i)throw new s("No fetch implementation available. On Node <18, pass fetchImpl.",0,"no_fetch");let h=`${n.baseUrl.replace(/\/$/,"")}${t}`,y=e==="GET"?n.retries??2:0,m;for(let u=0;u<=y;u++){let b=new AbortController,g=n.timeoutMs?setTimeout(()=>b.abort(),n.timeoutMs):void 0;try{let o=await i(h,{method:e,headers:{Authorization:`Bearer ${n.apiKey}`,...r?{"Content-Type":"application/json"}:{}},body:r?JSON.stringify(r):void 0,signal:b.signal}),I=await o.text(),p=I?_(I):{};if(!o.ok){let w=`HTTP ${o.status}`;throw p&&typeof p=="object"&&"error"in p&&(w=String(p.error)),new s(w,o.status,o.status===401||o.status===403?"auth":"http")}return p}catch(o){if(m=o,o instanceof s)throw o;u<y&&await P(250*(u+1))}finally{g&&clearTimeout(g)}}throw new s(`Network request failed: ${String(m?.message??m)}`,0,"network")}function _(n){try{return JSON.parse(n)}catch{return{}}}var l=class{constructor(e){this.listeners=new Set;if(!e.apiKey)throw new s("apiKey is required.",0,"config");if(!e.appUserId)throw new s("appUserId is required.",0,"config");if(e.apiKey.startsWith("sk_"))throw new s("Never use a secret (sk_) key in the client SDK \u2014 use your publishable (pk_) key.",0,"config");this.appUserId=e.appUserId,this.cacheTtlMs=e.cacheTtlMs??5*6e4,this.http={baseUrl:e.baseUrl??"https://entitlehub.com/v1",apiKey:e.apiKey,fetchImpl:e.fetchImpl,timeoutMs:15e3}}get currentAppUserId(){return this.appUserId}async logIn(e){return this.appUserId=e,this.cached=void 0,this.getCustomerInfo({fetchPolicy:"network-only"})}logOut(){this.cached=void 0}async getCustomerInfo(e={}){if((e.fetchPolicy??"cache-first")==="cache-first"&&this.cached&&Date.now()-this.cached.at<this.cacheTtlMs)return this.cached.info;let r=await c(this.http,"GET",`/subscribers/${encodeURIComponent(this.appUserId)}`),i=new a(r);this.cached={info:i,at:Date.now()};for(let h of this.listeners)try{h(i)}catch{}return i}async isEntitled(e){return(await this.getCustomerInfo()).isActive(e)}async checkEntitlement(e,t={}){return c(this.http,"POST","/check",{app_user_id:this.appUserId,entitlement:e,sandbox:!!t.sandbox})}async getOfferings(){return c(this.http,"GET","/offerings")}addCustomerInfoUpdateListener(e){return this.listeners.add(e),()=>this.listeners.delete(e)}};var f=class{constructor(e){if(!e.apiKey)throw new s("apiKey is required.",0,"config");if(!e.apiKey.startsWith("sk_"))throw new s("EntitleHubServer needs a secret (sk_) key. For client reads, use the EntitleHub class with a pk_ key.",0,"config");this.http={baseUrl:e.baseUrl??"https://entitlehub.com/v1",apiKey:e.apiKey,fetchImpl:e.fetchImpl,timeoutMs:15e3}}async reportPurchase(e,t){let r=await c(this.http,"POST",`/subscribers/${encodeURIComponent(e)}/purchases`,{store:t.store,store_product_id:t.storeProductId,is_sandbox:!!t.isSandbox,transaction_id:t.transactionId??"",purchase_token:t.purchaseToken??"",is_subscription:!!t.isSubscription,signed_transaction:t.signedTransaction??""});return new a(r)}async grantEntitlement(e,t,r={}){let i=await c(this.http,"POST",`/subscribers/${encodeURIComponent(e)}/grant`,{entitlement:t,duration_days:r.durationDays??0,is_sandbox:!!r.isSandbox});return new a(i)}async getCustomerInfo(e){let t=await c(this.http,"GET",`/subscribers/${encodeURIComponent(e)}`);return new a(t)}async check(e,t,r={}){return c(this.http,"POST","/check",{app_user_id:e,entitlement:t,sandbox:!!r.sandbox})}};0&&(module.exports={CustomerInfo,EntitleHub,EntitleHubError,EntitleHubServer});
1
+ "use strict";var d=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var x=(n,t)=>{for(var e in t)d(n,e,{get:t[e],enumerable:!0})},P=(n,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of _(t))!k.call(n,r)&&r!==e&&d(n,r,{get:()=>t[r],enumerable:!(s=C(t,r))||s.enumerable});return n};var E=n=>P(d({},"__esModule",{value:!0}),n);var S={};x(S,{CustomerInfo:()=>o,EntitleHub:()=>l,EntitleHubError:()=>i,EntitleHubServer:()=>f});module.exports=E(S);var o=class{constructor(t){this.appUserId=t.app_user_id,this.entitlements=t.active_entitlements??[];let e={};for(let s of this.entitlements)e[s.entitlement]=s;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 i=class extends Error{constructor(t,e,s="error"){super(t),this.name="EntitleHubError",this.status=e,this.code=s}},T=n=>new Promise(t=>setTimeout(t,n));async function c(n,t,e,s){let r=n.fetchImpl??globalThis.fetch;if(!r)throw new i("No fetch implementation available. On Node <18, pass fetchImpl.",0,"no_fetch");let h=`${n.baseUrl.replace(/\/$/,"")}${e}`,b=t==="GET"?n.retries??2:0,m;for(let u=0;u<=b;u++){let y=new AbortController,g=n.timeoutMs?setTimeout(()=>y.abort(),n.timeoutMs):void 0;try{let a=await r(h,{method:t,headers:{Authorization:`Bearer ${n.apiKey}`,...s?{"Content-Type":"application/json"}:{}},body:s?JSON.stringify(s):void 0,signal:y.signal}),I=await a.text(),p=I?v(I):{};if(!a.ok){let w=`HTTP ${a.status}`;throw p&&typeof p=="object"&&"error"in p&&(w=String(p.error)),new i(w,a.status,a.status===401||a.status===403?"auth":"http")}return p}catch(a){if(m=a,a instanceof i)throw a;u<b&&await T(250*(u+1))}finally{g&&clearTimeout(g)}}throw new i(`Network request failed: ${String(m?.message??m)}`,0,"network")}function v(n){try{return JSON.parse(n)}catch{return{}}}var l=class{constructor(t){this.listeners=new Set;if(!t.apiKey)throw new i("apiKey is required.",0,"config");if(!t.appUserId)throw new i("appUserId is required.",0,"config");if(t.apiKey.startsWith("sk_"))throw new i("Never use a secret (sk_) key in the client SDK \u2014 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}}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 s=await c(this.http,"GET",`/subscribers/${encodeURIComponent(this.appUserId)}`),r=new o(s);this.cached={info:r,at:Date.now()};for(let h of this.listeners)try{h(r)}catch{}return r}async isEntitled(t){return(await this.getCustomerInfo()).isActive(t)}async checkEntitlement(t,e={}){return c(this.http,"POST","/check",{app_user_id:this.appUserId,entitlement:t,sandbox:!!e.sandbox})}async getOfferings(){return c(this.http,"GET","/offerings")}async reportPurchase(t){let e=await c(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??""}),s=new o(e);this.cached={info:s,at:Date.now()};for(let r of this.listeners)try{r(s)}catch{}return s}addCustomerInfoUpdateListener(t){return this.listeners.add(t),()=>this.listeners.delete(t)}};var f=class{constructor(t){if(!t.apiKey)throw new i("apiKey is required.",0,"config");if(!t.apiKey.startsWith("sk_"))throw new i("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}}async reportPurchase(t,e){let s=await c(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 o(s)}async grantEntitlement(t,e,s={}){let r=await c(this.http,"POST",`/subscribers/${encodeURIComponent(t)}/grant`,{entitlement:e,duration_days:s.durationDays??0,is_sandbox:!!s.isSandbox});return new o(r)}async getCustomerInfo(t){let e=await c(this.http,"GET",`/subscribers/${encodeURIComponent(t)}`);return new o(e)}async check(t,e,s={}){return c(this.http,"POST","/check",{app_user_id:t,entitlement:e,sandbox:!!s.sandbox})}};0&&(module.exports={CustomerInfo,EntitleHub,EntitleHubError,EntitleHubServer});
package/dist/index.d.cts CHANGED
@@ -72,6 +72,11 @@ interface PurchaseInput {
72
72
  * `storeProductId`, so a client can't forge a purchase.
73
73
  */
74
74
  signedTransaction?: string;
75
+ /**
76
+ * Stripe subscription id. When set, EntitleHub validates it against the project's Stripe
77
+ * secret key (active/trialing → granted, with the current period end as the expiry).
78
+ */
79
+ stripeSubscriptionId?: string;
75
80
  }
76
81
 
77
82
  /**
@@ -143,6 +148,23 @@ declare class EntitleHub {
143
148
  }): Promise<CheckResult>;
144
149
  /** The project's entitlements + products — for building a paywall. */
145
150
  getOfferings(): Promise<Offerings>;
151
+ /**
152
+ * Report a VALIDATED store purchase for the current user and return the updated entitlements.
153
+ * A publishable key can only do validated reports (a forged receipt fails validation):
154
+ * • Google: { store: "play", storeProductId, purchaseToken, isSubscription: true }
155
+ * • Apple: { signedTransaction }
156
+ * • Stripe: { stripeSubscriptionId }
157
+ * Updates the cache and notifies listeners.
158
+ */
159
+ reportPurchase(purchase: {
160
+ store?: Store;
161
+ storeProductId?: string;
162
+ purchaseToken?: string;
163
+ isSubscription?: boolean;
164
+ signedTransaction?: string;
165
+ stripeSubscriptionId?: string;
166
+ isSandbox?: boolean;
167
+ }): Promise<CustomerInfo>;
146
168
  /** Subscribe to CustomerInfo refreshes. Returns an unsubscribe function. */
147
169
  addCustomerInfoUpdateListener(listener: CustomerInfoListener): () => void;
148
170
  }
@@ -169,6 +191,7 @@ declare class EntitleHubServer {
169
191
  * Three modes (pick one):
170
192
  * • Google (validated): { store:"play", storeProductId, purchaseToken, isSubscription }
171
193
  * • Apple (validated): { signedTransaction } — store/product are read from the JWS
194
+ * • Stripe (validated): { stripeSubscriptionId } — validated via your Stripe secret key
172
195
  * • Trusted server-report: { store, storeProductId } — no store validation; only when you've
173
196
  * already validated the receipt elsewhere.
174
197
  */
package/dist/index.d.ts CHANGED
@@ -72,6 +72,11 @@ interface PurchaseInput {
72
72
  * `storeProductId`, so a client can't forge a purchase.
73
73
  */
74
74
  signedTransaction?: string;
75
+ /**
76
+ * Stripe subscription id. When set, EntitleHub validates it against the project's Stripe
77
+ * secret key (active/trialing → granted, with the current period end as the expiry).
78
+ */
79
+ stripeSubscriptionId?: string;
75
80
  }
76
81
 
77
82
  /**
@@ -143,6 +148,23 @@ declare class EntitleHub {
143
148
  }): Promise<CheckResult>;
144
149
  /** The project's entitlements + products — for building a paywall. */
145
150
  getOfferings(): Promise<Offerings>;
151
+ /**
152
+ * Report a VALIDATED store purchase for the current user and return the updated entitlements.
153
+ * A publishable key can only do validated reports (a forged receipt fails validation):
154
+ * • Google: { store: "play", storeProductId, purchaseToken, isSubscription: true }
155
+ * • Apple: { signedTransaction }
156
+ * • Stripe: { stripeSubscriptionId }
157
+ * Updates the cache and notifies listeners.
158
+ */
159
+ reportPurchase(purchase: {
160
+ store?: Store;
161
+ storeProductId?: string;
162
+ purchaseToken?: string;
163
+ isSubscription?: boolean;
164
+ signedTransaction?: string;
165
+ stripeSubscriptionId?: string;
166
+ isSandbox?: boolean;
167
+ }): Promise<CustomerInfo>;
146
168
  /** Subscribe to CustomerInfo refreshes. Returns an unsubscribe function. */
147
169
  addCustomerInfoUpdateListener(listener: CustomerInfoListener): () => void;
148
170
  }
@@ -169,6 +191,7 @@ declare class EntitleHubServer {
169
191
  * Three modes (pick one):
170
192
  * • Google (validated): { store:"play", storeProductId, purchaseToken, isSubscription }
171
193
  * • Apple (validated): { signedTransaction } — store/product are read from the JWS
194
+ * • Stripe (validated): { stripeSubscriptionId } — validated via your Stripe secret key
172
195
  * • Trusted server-report: { store, storeProductId } — no store validation; only when you've
173
196
  * already validated the receipt elsewhere.
174
197
  */
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var o=class{constructor(e){this.appUserId=e.app_user_id,this.entitlements=e.active_entitlements??[];let t={};for(let n of this.entitlements)t[n.entitlement]=n;this.active=t}isActive(e){return!!this.active[e]}get activeEntitlementIds(){return Object.keys(this.active)}expirationDate(e){let t=this.active[e];if(t)return t.expires_at?new Date(t.expires_at):null}};var s=class extends Error{constructor(e,t,n="error"){super(e),this.name="EntitleHubError",this.status=t,this.code=n}},w=r=>new Promise(e=>setTimeout(e,r));async function a(r,e,t,n){let c=r.fetchImpl??globalThis.fetch;if(!c)throw new s("No fetch implementation available. On Node <18, pass fetchImpl.",0,"no_fetch");let l=`${r.baseUrl.replace(/\/$/,"")}${t}`,d=e==="GET"?r.retries??2:0,f;for(let u=0;u<=d;u++){let y=new AbortController,b=r.timeoutMs?setTimeout(()=>y.abort(),r.timeoutMs):void 0;try{let i=await c(l,{method:e,headers:{Authorization:`Bearer ${r.apiKey}`,...n?{"Content-Type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:y.signal}),g=await i.text(),p=g?C(g):{};if(!i.ok){let I=`HTTP ${i.status}`;throw p&&typeof p=="object"&&"error"in p&&(I=String(p.error)),new s(I,i.status,i.status===401||i.status===403?"auth":"http")}return p}catch(i){if(f=i,i instanceof s)throw i;u<d&&await w(250*(u+1))}finally{b&&clearTimeout(b)}}throw new s(`Network request failed: ${String(f?.message??f)}`,0,"network")}function C(r){try{return JSON.parse(r)}catch{return{}}}var h=class{constructor(e){this.listeners=new Set;if(!e.apiKey)throw new s("apiKey is required.",0,"config");if(!e.appUserId)throw new s("appUserId is required.",0,"config");if(e.apiKey.startsWith("sk_"))throw new s("Never use a secret (sk_) key in the client SDK \u2014 use your publishable (pk_) key.",0,"config");this.appUserId=e.appUserId,this.cacheTtlMs=e.cacheTtlMs??5*6e4,this.http={baseUrl:e.baseUrl??"https://entitlehub.com/v1",apiKey:e.apiKey,fetchImpl:e.fetchImpl,timeoutMs:15e3}}get currentAppUserId(){return this.appUserId}async logIn(e){return this.appUserId=e,this.cached=void 0,this.getCustomerInfo({fetchPolicy:"network-only"})}logOut(){this.cached=void 0}async getCustomerInfo(e={}){if((e.fetchPolicy??"cache-first")==="cache-first"&&this.cached&&Date.now()-this.cached.at<this.cacheTtlMs)return this.cached.info;let n=await a(this.http,"GET",`/subscribers/${encodeURIComponent(this.appUserId)}`),c=new o(n);this.cached={info:c,at:Date.now()};for(let l of this.listeners)try{l(c)}catch{}return c}async isEntitled(e){return(await this.getCustomerInfo()).isActive(e)}async checkEntitlement(e,t={}){return a(this.http,"POST","/check",{app_user_id:this.appUserId,entitlement:e,sandbox:!!t.sandbox})}async getOfferings(){return a(this.http,"GET","/offerings")}addCustomerInfoUpdateListener(e){return this.listeners.add(e),()=>this.listeners.delete(e)}};var m=class{constructor(e){if(!e.apiKey)throw new s("apiKey is required.",0,"config");if(!e.apiKey.startsWith("sk_"))throw new s("EntitleHubServer needs a secret (sk_) key. For client reads, use the EntitleHub class with a pk_ key.",0,"config");this.http={baseUrl:e.baseUrl??"https://entitlehub.com/v1",apiKey:e.apiKey,fetchImpl:e.fetchImpl,timeoutMs:15e3}}async reportPurchase(e,t){let n=await a(this.http,"POST",`/subscribers/${encodeURIComponent(e)}/purchases`,{store:t.store,store_product_id:t.storeProductId,is_sandbox:!!t.isSandbox,transaction_id:t.transactionId??"",purchase_token:t.purchaseToken??"",is_subscription:!!t.isSubscription,signed_transaction:t.signedTransaction??""});return new o(n)}async grantEntitlement(e,t,n={}){let c=await a(this.http,"POST",`/subscribers/${encodeURIComponent(e)}/grant`,{entitlement:t,duration_days:n.durationDays??0,is_sandbox:!!n.isSandbox});return new o(c)}async getCustomerInfo(e){let t=await a(this.http,"GET",`/subscribers/${encodeURIComponent(e)}`);return new o(t)}async check(e,t,n={}){return a(this.http,"POST","/check",{app_user_id:e,entitlement:t,sandbox:!!n.sandbox})}};export{o as CustomerInfo,h as EntitleHub,s as EntitleHubError,m as EntitleHubServer};
1
+ var a=class{constructor(t){this.appUserId=t.app_user_id,this.entitlements=t.active_entitlements??[];let e={};for(let s of this.entitlements)e[s.entitlement]=s;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 r=class extends Error{constructor(t,e,s="error"){super(t),this.name="EntitleHubError",this.status=e,this.code=s}},w=n=>new Promise(t=>setTimeout(t,n));async function c(n,t,e,s){let i=n.fetchImpl??globalThis.fetch;if(!i)throw new r("No fetch implementation available. On Node <18, pass fetchImpl.",0,"no_fetch");let l=`${n.baseUrl.replace(/\/$/,"")}${e}`,d=t==="GET"?n.retries??2:0,f;for(let u=0;u<=d;u++){let b=new AbortController,y=n.timeoutMs?setTimeout(()=>b.abort(),n.timeoutMs):void 0;try{let o=await i(l,{method:t,headers:{Authorization:`Bearer ${n.apiKey}`,...s?{"Content-Type":"application/json"}:{}},body:s?JSON.stringify(s):void 0,signal:b.signal}),g=await o.text(),p=g?C(g):{};if(!o.ok){let I=`HTTP ${o.status}`;throw p&&typeof p=="object"&&"error"in p&&(I=String(p.error)),new r(I,o.status,o.status===401||o.status===403?"auth":"http")}return p}catch(o){if(f=o,o instanceof r)throw o;u<d&&await w(250*(u+1))}finally{y&&clearTimeout(y)}}throw new r(`Network request failed: ${String(f?.message??f)}`,0,"network")}function C(n){try{return JSON.parse(n)}catch{return{}}}var h=class{constructor(t){this.listeners=new Set;if(!t.apiKey)throw new r("apiKey is required.",0,"config");if(!t.appUserId)throw new r("appUserId is required.",0,"config");if(t.apiKey.startsWith("sk_"))throw new r("Never use a secret (sk_) key in the client SDK \u2014 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}}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 s=await c(this.http,"GET",`/subscribers/${encodeURIComponent(this.appUserId)}`),i=new a(s);this.cached={info:i,at:Date.now()};for(let l of this.listeners)try{l(i)}catch{}return i}async isEntitled(t){return(await this.getCustomerInfo()).isActive(t)}async checkEntitlement(t,e={}){return c(this.http,"POST","/check",{app_user_id:this.appUserId,entitlement:t,sandbox:!!e.sandbox})}async getOfferings(){return c(this.http,"GET","/offerings")}async reportPurchase(t){let e=await c(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??""}),s=new a(e);this.cached={info:s,at:Date.now()};for(let i of this.listeners)try{i(s)}catch{}return s}addCustomerInfoUpdateListener(t){return this.listeners.add(t),()=>this.listeners.delete(t)}};var m=class{constructor(t){if(!t.apiKey)throw new r("apiKey is required.",0,"config");if(!t.apiKey.startsWith("sk_"))throw new r("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}}async reportPurchase(t,e){let s=await c(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 a(s)}async grantEntitlement(t,e,s={}){let i=await c(this.http,"POST",`/subscribers/${encodeURIComponent(t)}/grant`,{entitlement:e,duration_days:s.durationDays??0,is_sandbox:!!s.isSandbox});return new a(i)}async getCustomerInfo(t){let e=await c(this.http,"GET",`/subscribers/${encodeURIComponent(t)}`);return new a(e)}async check(t,e,s={}){return c(this.http,"POST","/check",{app_user_id:t,entitlement:e,sandbox:!!s.sandbox})}};export{a as CustomerInfo,h as EntitleHub,r as EntitleHubError,m as EntitleHubServer};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@entitlehub/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
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",