@kelviq/js-sdk 2.0.0-beta → 2.0.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/dist/index.d.ts +1 -1
- package/dist/kelviq-js-sdk.iife.js +1 -1
- package/dist/kelviq-js-sdk.js +67 -63
- package/dist/kelviq-js-sdk.umd.js +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var kelviqSDK=function(){"use strict";var
|
|
1
|
+
var kelviqSDK=function(){"use strict";var U=Object.defineProperty;var _=(y,p,q)=>p in y?U(y,p,{enumerable:!0,configurable:!0,writable:!0,value:q}):y[p]=q;var E=(y,p,q)=>_(y,typeof p!="symbol"?p+"":p,q);function y(a){const e={};if(!a||!Array.isArray(a.entitlements))return console.warn("[Kelviq SDK] transformApiEntitlements: Invalid or empty entitlements array in API response.",a),e;const s={};a.entitlements.forEach(t=>{if(!t||typeof t.featureId!="string"||typeof t.featureType!="string"){console.warn("[Kelviq SDK] transformApiEntitlements: Skipping invalid raw entitlement object:",t);return}s[t.featureId]||(s[t.featureId]=[]),s[t.featureId].push(t)});for(const t of Object.keys(s)){const c=s[t],u=c[0].featureType;let A=0,r=null,f=null,l=!1,h=!1;if(u==="METER"){let n=!0;for(const i of c)A+=typeof i.currentUsage=="number"?i.currentUsage:0,typeof i.usageLimit=="number"&&(r=(r??0)+i.usageLimit,n=!1);n&&(r=null),f=r!==null?r-A:null,l=c.some(i=>i.hardLimit===!0),h=f===null||f>0}else if(u==="CUSTOMIZABLE"){const n=c[0];r=typeof n.usageLimit=="number"?n.usageLimit:null,A=typeof n.currentUsage=="number"?n.currentUsage:0,f=typeof n.remaining=="number"?n.remaining:null,l=n.hardLimit===!0,h=c.some(i=>i.hasAccess)}else if(u==="BOOLEAN")h=c.some(n=>n.hasAccess);else{console.warn(`[Kelviq SDK] transformApiEntitlements: Encountered unknown featureType: '${u}' for feature '${t}'. This entitlement will be ignored.`);continue}const R={featureId:t,featureType:u,hasAccess:h,hardLimit:l,currentUsage:A,usageLimit:r,remaining:f,items:c};e[t]=R}return e}const p="GET",q=5e3,K=3,P=1e3;function C(a){const{method:e=p,headers:s={},body:t,timeout:c=q,maxRetries:u=K,backoffBaseDelay:A=P,queryParams:r,accessToken:f}=a;let l=a.url,h=0;return new Promise((R,n)=>{if(r){const m=new URLSearchParams;for(const g in r)r[g]!==void 0&&m.append(g,String(r[g]));m.toString()&&(l=l+(l.includes("?")?"&":"?")+m.toString())}function i(){const m=new XMLHttpRequest;m.open(e,l,!0),m.timeout=c;const g={Accept:"application/json","X-Requested-With":"XMLHttpRequest",...s};e!=="GET"&&t&&typeof t=="object"&&!(t instanceof FormData)&&(g["Content-Type"]||(g["Content-Type"]="application/json")),f&&(g.Authorization=`Bearer ${f}`);for(const[o,d]of Object.entries(g))m.setRequestHeader(o,d);m.onload=function(){const{status:o,statusText:d,responseText:F}=m;if(o>=200&&o<300)try{const v=F?JSON.parse(F):{};R({status:o,statusText:d,data:v})}catch(v){const w=v instanceof Error?v:new Error(String(v));console.error(`Kelviq SDK (apiRequest): Invalid JSON response for URL ${l}. Error: ${w.message}. Response: ${F}`),n(new Error(`Invalid JSON response: ${w.message}`))}else S(`Request to ${l} failed with status ${o} ${d}. Response: ${F}`)},m.onerror=()=>S(`Network error for URL ${l}. The request could not be completed.`),m.ontimeout=()=>S(`Request to ${l} timed out.`);function S(o){if(h<u){h++;const d=Math.min(A*Math.pow(2,h-1),3e4);console.warn(`Kelviq SDK (apiRequest): Retrying request to ${l}. Attempt ${h}/${u}. Error: ${o}. Retrying in ${d}ms.`),setTimeout(i,d)}else n(new Error(`${o} (Max retries ${u} reached)`))}try{let o=t;t&&typeof t=="object"&&!(t instanceof FormData)&&g["Content-Type"]==="application/json"&&(o=JSON.stringify(t)),m.send(o)}catch(o){const d=o instanceof Error?o:new Error(String(o));console.error(`Kelviq SDK (apiRequest): Error sending request to ${l}.`,d),n(new Error(`Failed to send request: ${d.message}`))}}i()})}const L="https://edge.api.kelviq.com/api/v1/",D="https://edge.sandboxapi.kelviq.com/api/v1/",T="entitlements/";class ${constructor(e,s){E(this,"options");E(this,"entitlementsCache",null);E(this,"rawApiResponse",null);E(this,"isFetching",!1);E(this,"inFlightPromise",null);E(this,"readyPromise",null);E(this,"lastFetchError",null);E(this,"apiRequestService");if(!e||!e.customerId)throw new Error("[Kelviq SDK] KelviqClient: CustomerId is required in options.");this.options={...e,apiConfig:e.apiConfig||{},entitlementsPath:e.entitlementsPath||T},this.apiRequestService=s||C}async fetchAllEntitlements(e=!1){if(this.inFlightPromise&&!e)return this.inFlightPromise;if(this.entitlementsCache&&!e)return Promise.resolve(this.entitlementsCache);this.isFetching=!0,this.lastFetchError=null;const{apiUrl:s=this.options.environment==="sandbox"?D:L,entitlementsPath:t,customerId:c,accessToken:u,apiConfig:A,onError:r}=this.options,f=s.replace(/\/$/,""),l=t.replace(/^\//,""),h=`${f}/${l}`,R={customer_id:c};return this.inFlightPromise=this.apiRequestService({url:h,method:"GET",queryParams:R,accessToken:u,...A||{}}).then(n=>{if(n&&n.data&&Array.isArray(n.data.entitlements)){const i=n.data;return this.rawApiResponse={customerId:i.customer_id??i.customerId,entitlements:i.entitlements},this.entitlementsCache=y(n.data),this.isFetching=!1,this.inFlightPromise=null,this.entitlementsCache}else{const i=new Error("[Kelviq SDK] Received empty, malformed, or invalid data structure from entitlements API.");throw this.lastFetchError=i,this.isFetching=!1,this.inFlightPromise=null,this.entitlementsCache=null,this.rawApiResponse=null,r&&r(i),i}}).catch(n=>{const i=n instanceof Error?n:new Error(String(n));throw this.lastFetchError=i,this.isFetching=!1,this.inFlightPromise=null,this.entitlementsCache=null,this.rawApiResponse=null,r&&r(i),i}),this.inFlightPromise}getEntitlement(e){return this.entitlementsCache?this.entitlementsCache[e]??null:(console.warn(`[Kelviq SDK] getEntitlement: Entitlements not fetched or cache is empty for featureId '${e}'. Call fetchAllEntitlements() first.`),null)}getEntitlements(){return this.entitlementsCache}getRawEntitlement(e){return this.rawApiResponse?this.rawApiResponse.entitlements.filter(s=>s.featureId===e):(console.warn(`[Kelviq SDK] getRawEntitlement: Entitlements not fetched for featureId '${e}'. Call fetchAllEntitlements() first.`),null)}getRawEntitlements(){return this.rawApiResponse}hasAccess(e){if(!this.entitlementsCache)return console.warn(`[Kelviq SDK] hasAccess: Entitlements not fetched yet for featureId '${e}'. Call fetchAllEntitlements() first. Returning false.`),!1;const s=this.entitlementsCache[e];return s?s.hasAccess:!1}isLoading(){return this.isFetching}getLastError(){return this.lastFetchError}ready(){return this.readyPromise??Promise.resolve()}_setReadyPromise(e){this.readyPromise=e}clearCache(){this.entitlementsCache=null,this.rawApiResponse=null,this.isFetching=!1,this.lastFetchError=null,console.log("[Kelviq SDK] Entitlement cache cleared.")}}function I(a,e){const s={...a,initializeAndFetch:a.initializeAndFetch??!0,apiConfig:a.apiConfig||{},environment:a.environment||"production",entitlementsPath:a.entitlementsPath||T},t=new $(s,e);if(s.initializeAndFetch===!0){const c=t.fetchAllEntitlements().catch(u=>{console.error("[Kelviq SDK] Initial fetch on client creation failed:",u.message)});t._setReadyPromise(c.then(()=>{}))}return t}return I}();
|
package/dist/kelviq-js-sdk.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
var S = Object.defineProperty;
|
|
2
|
-
var T = (
|
|
3
|
-
var g = (
|
|
4
|
-
function w(
|
|
2
|
+
var T = (r, e, i) => e in r ? S(r, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : r[e] = i;
|
|
3
|
+
var g = (r, e, i) => T(r, typeof e != "symbol" ? e + "" : e, i);
|
|
4
|
+
function w(r) {
|
|
5
5
|
const e = {};
|
|
6
|
-
if (!
|
|
6
|
+
if (!r || !Array.isArray(r.entitlements))
|
|
7
7
|
return console.warn(
|
|
8
8
|
"[Kelviq SDK] transformApiEntitlements: Invalid or empty entitlements array in API response.",
|
|
9
|
-
|
|
9
|
+
r
|
|
10
10
|
), e;
|
|
11
11
|
const i = {};
|
|
12
|
-
|
|
12
|
+
r.entitlements.forEach((t) => {
|
|
13
13
|
if (!t || typeof t.featureId != "string" || typeof t.featureType != "string") {
|
|
14
14
|
console.warn(
|
|
15
15
|
"[Kelviq SDK] transformApiEntitlements: Skipping invalid raw entitlement object:",
|
|
@@ -21,17 +21,17 @@ function w(s) {
|
|
|
21
21
|
});
|
|
22
22
|
for (const t of Object.keys(i)) {
|
|
23
23
|
const c = i[t], u = c[0].featureType;
|
|
24
|
-
let E = 0, l = null, f = null, o = !1,
|
|
24
|
+
let E = 0, l = null, f = null, o = !1, h = !1;
|
|
25
25
|
if (u === "METER") {
|
|
26
26
|
let n = !0;
|
|
27
|
-
for (const
|
|
28
|
-
E += typeof
|
|
29
|
-
n && (l = null), f = l !== null ? l - E : null, o = c.some((
|
|
27
|
+
for (const s of c)
|
|
28
|
+
E += typeof s.currentUsage == "number" ? s.currentUsage : 0, typeof s.usageLimit == "number" && (l = (l ?? 0) + s.usageLimit, n = !1);
|
|
29
|
+
n && (l = null), f = l !== null ? l - E : null, o = c.some((s) => s.hardLimit === !0), h = f === null || f > 0;
|
|
30
30
|
} else if (u === "CUSTOMIZABLE") {
|
|
31
31
|
const n = c[0];
|
|
32
|
-
l = typeof n.usageLimit == "number" ? n.usageLimit : null, E = typeof n.currentUsage == "number" ? n.currentUsage : 0, f = typeof n.remaining == "number" ? n.remaining : null, o = n.hardLimit === !0,
|
|
32
|
+
l = typeof n.usageLimit == "number" ? n.usageLimit : null, E = typeof n.currentUsage == "number" ? n.currentUsage : 0, f = typeof n.remaining == "number" ? n.remaining : null, o = n.hardLimit === !0, h = c.some((s) => s.hasAccess);
|
|
33
33
|
} else if (u === "BOOLEAN")
|
|
34
|
-
|
|
34
|
+
h = c.some((n) => n.hasAccess);
|
|
35
35
|
else {
|
|
36
36
|
console.warn(
|
|
37
37
|
`[Kelviq SDK] transformApiEntitlements: Encountered unknown featureType: '${u}' for feature '${t}'. This entitlement will be ignored.`
|
|
@@ -41,7 +41,7 @@ function w(s) {
|
|
|
41
41
|
const A = {
|
|
42
42
|
featureId: t,
|
|
43
43
|
featureType: u,
|
|
44
|
-
hasAccess:
|
|
44
|
+
hasAccess: h,
|
|
45
45
|
hardLimit: o,
|
|
46
46
|
currentUsage: E,
|
|
47
47
|
usageLimit: l,
|
|
@@ -53,7 +53,7 @@ function w(s) {
|
|
|
53
53
|
return e;
|
|
54
54
|
}
|
|
55
55
|
const P = "GET", C = 5e3, K = 3, L = 1e3;
|
|
56
|
-
function $(
|
|
56
|
+
function $(r) {
|
|
57
57
|
const {
|
|
58
58
|
method: e = P,
|
|
59
59
|
headers: i = {},
|
|
@@ -65,33 +65,33 @@ function $(s) {
|
|
|
65
65
|
queryParams: l,
|
|
66
66
|
accessToken: f
|
|
67
67
|
// Use the direct accessToken
|
|
68
|
-
} =
|
|
69
|
-
let o =
|
|
68
|
+
} = r;
|
|
69
|
+
let o = r.url, h = 0;
|
|
70
70
|
return new Promise((A, n) => {
|
|
71
71
|
if (l) {
|
|
72
|
-
const
|
|
73
|
-
for (const
|
|
74
|
-
l[
|
|
75
|
-
|
|
72
|
+
const m = new URLSearchParams();
|
|
73
|
+
for (const p in l)
|
|
74
|
+
l[p] !== void 0 && m.append(p, String(l[p]));
|
|
75
|
+
m.toString() && (o = o + (o.includes("?") ? "&" : "?") + m.toString());
|
|
76
76
|
}
|
|
77
|
-
function
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
const
|
|
77
|
+
function s() {
|
|
78
|
+
const m = new XMLHttpRequest();
|
|
79
|
+
m.open(e, o, !0), m.timeout = c;
|
|
80
|
+
const p = {
|
|
81
81
|
Accept: "application/json",
|
|
82
82
|
"X-Requested-With": "XMLHttpRequest",
|
|
83
83
|
...i
|
|
84
84
|
// Apply custom headers, allowing them to override defaults
|
|
85
85
|
};
|
|
86
|
-
e !== "GET" && t && typeof t == "object" && !(t instanceof FormData) && (
|
|
87
|
-
for (const [a,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const { status: a, statusText:
|
|
86
|
+
e !== "GET" && t && typeof t == "object" && !(t instanceof FormData) && (p["Content-Type"] || (p["Content-Type"] = "application/json")), f && (p.Authorization = `Bearer ${f}`);
|
|
87
|
+
for (const [a, d] of Object.entries(p))
|
|
88
|
+
m.setRequestHeader(a, d);
|
|
89
|
+
m.onload = function() {
|
|
90
|
+
const { status: a, statusText: d, responseText: R } = m;
|
|
91
91
|
if (a >= 200 && a < 300)
|
|
92
92
|
try {
|
|
93
93
|
const y = R ? JSON.parse(R) : {};
|
|
94
|
-
A({ status: a, statusText:
|
|
94
|
+
A({ status: a, statusText: d, data: y });
|
|
95
95
|
} catch (y) {
|
|
96
96
|
const v = y instanceof Error ? y : new Error(String(y));
|
|
97
97
|
console.error(
|
|
@@ -100,22 +100,22 @@ function $(s) {
|
|
|
100
100
|
}
|
|
101
101
|
else
|
|
102
102
|
q(
|
|
103
|
-
`Request to ${o} failed with status ${a} ${
|
|
103
|
+
`Request to ${o} failed with status ${a} ${d}. Response: ${R}`
|
|
104
104
|
);
|
|
105
|
-
},
|
|
105
|
+
}, m.onerror = () => q(
|
|
106
106
|
`Network error for URL ${o}. The request could not be completed.`
|
|
107
|
-
),
|
|
107
|
+
), m.ontimeout = () => q(`Request to ${o} timed out.`);
|
|
108
108
|
function q(a) {
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
E * Math.pow(2,
|
|
109
|
+
if (h < u) {
|
|
110
|
+
h++;
|
|
111
|
+
const d = Math.min(
|
|
112
|
+
E * Math.pow(2, h - 1),
|
|
113
113
|
3e4
|
|
114
114
|
// Cap retry delay at 30 seconds
|
|
115
115
|
);
|
|
116
116
|
console.warn(
|
|
117
|
-
`Kelviq SDK (apiRequest): Retrying request to ${o}. Attempt ${
|
|
118
|
-
), setTimeout(
|
|
117
|
+
`Kelviq SDK (apiRequest): Retrying request to ${o}. Attempt ${h}/${u}. Error: ${a}. Retrying in ${d}ms.`
|
|
118
|
+
), setTimeout(s, d);
|
|
119
119
|
} else
|
|
120
120
|
n(
|
|
121
121
|
new Error(`${a} (Max retries ${u} reached)`)
|
|
@@ -123,20 +123,20 @@ function $(s) {
|
|
|
123
123
|
}
|
|
124
124
|
try {
|
|
125
125
|
let a = t;
|
|
126
|
-
t && typeof t == "object" && !(t instanceof FormData) &&
|
|
126
|
+
t && typeof t == "object" && !(t instanceof FormData) && p["Content-Type"] === "application/json" && (a = JSON.stringify(t)), m.send(a);
|
|
127
127
|
} catch (a) {
|
|
128
|
-
const
|
|
128
|
+
const d = a instanceof Error ? a : new Error(String(a));
|
|
129
129
|
console.error(
|
|
130
130
|
`Kelviq SDK (apiRequest): Error sending request to ${o}.`,
|
|
131
|
-
|
|
132
|
-
), n(new Error(`Failed to send request: ${
|
|
131
|
+
d
|
|
132
|
+
), n(new Error(`Failed to send request: ${d.message}`));
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
-
|
|
135
|
+
s();
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
|
-
const D = "https://edge.api.kelviq.com/api/v1/",
|
|
139
|
-
class
|
|
138
|
+
const D = "https://edge.api.kelviq.com/api/v1/", I = "https://edge.sandboxapi.kelviq.com/api/v1/", F = "entitlements/";
|
|
139
|
+
class U {
|
|
140
140
|
/**
|
|
141
141
|
* Creates an instance of KelviqClient.
|
|
142
142
|
* Prefer using the `kelviqSDK` factory function for instantiation.
|
|
@@ -179,33 +179,37 @@ class I {
|
|
|
179
179
|
return Promise.resolve(this.entitlementsCache);
|
|
180
180
|
this.isFetching = !0, this.lastFetchError = null;
|
|
181
181
|
const {
|
|
182
|
-
apiUrl: i = this.options.environment === "sandbox" ?
|
|
182
|
+
apiUrl: i = this.options.environment === "sandbox" ? I : D,
|
|
183
183
|
entitlementsPath: t,
|
|
184
184
|
customerId: c,
|
|
185
185
|
accessToken: u,
|
|
186
186
|
apiConfig: E,
|
|
187
187
|
onError: l
|
|
188
|
-
} = this.options, f = i.replace(/\/$/, ""), o = t.replace(/^\//, ""),
|
|
188
|
+
} = this.options, f = i.replace(/\/$/, ""), o = t.replace(/^\//, ""), h = `${f}/${o}`, A = {
|
|
189
189
|
customer_id: c
|
|
190
190
|
};
|
|
191
191
|
return this.inFlightPromise = this.apiRequestService({
|
|
192
|
-
url:
|
|
192
|
+
url: h,
|
|
193
193
|
method: "GET",
|
|
194
194
|
queryParams: A,
|
|
195
195
|
accessToken: u,
|
|
196
196
|
...E || {}
|
|
197
197
|
}).then((n) => {
|
|
198
|
-
if (n && n.data && Array.isArray(n.data.entitlements))
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
198
|
+
if (n && n.data && Array.isArray(n.data.entitlements)) {
|
|
199
|
+
const s = n.data;
|
|
200
|
+
return this.rawApiResponse = {
|
|
201
|
+
customerId: s.customer_id ?? s.customerId,
|
|
202
|
+
entitlements: s.entitlements
|
|
203
|
+
}, this.entitlementsCache = w(n.data), this.isFetching = !1, this.inFlightPromise = null, this.entitlementsCache;
|
|
204
|
+
} else {
|
|
205
|
+
const s = new Error(
|
|
202
206
|
"[Kelviq SDK] Received empty, malformed, or invalid data structure from entitlements API."
|
|
203
207
|
);
|
|
204
|
-
throw this.lastFetchError =
|
|
208
|
+
throw this.lastFetchError = s, this.isFetching = !1, this.inFlightPromise = null, this.entitlementsCache = null, this.rawApiResponse = null, l && l(s), s;
|
|
205
209
|
}
|
|
206
210
|
}).catch((n) => {
|
|
207
|
-
const
|
|
208
|
-
throw this.lastFetchError =
|
|
211
|
+
const s = n instanceof Error ? n : new Error(String(n));
|
|
212
|
+
throw this.lastFetchError = s, this.isFetching = !1, this.inFlightPromise = null, this.entitlementsCache = null, this.rawApiResponse = null, l && l(s), s;
|
|
209
213
|
}), this.inFlightPromise;
|
|
210
214
|
}
|
|
211
215
|
/**
|
|
@@ -296,14 +300,14 @@ class I {
|
|
|
296
300
|
this.entitlementsCache = null, this.rawApiResponse = null, this.isFetching = !1, this.lastFetchError = null, console.log("[Kelviq SDK] Entitlement cache cleared.");
|
|
297
301
|
}
|
|
298
302
|
}
|
|
299
|
-
function b(
|
|
303
|
+
function b(r, e) {
|
|
300
304
|
const i = {
|
|
301
|
-
...
|
|
302
|
-
initializeAndFetch:
|
|
303
|
-
apiConfig:
|
|
304
|
-
environment:
|
|
305
|
-
entitlementsPath:
|
|
306
|
-
}, t = new
|
|
305
|
+
...r,
|
|
306
|
+
initializeAndFetch: r.initializeAndFetch ?? !0,
|
|
307
|
+
apiConfig: r.apiConfig || {},
|
|
308
|
+
environment: r.environment || "production",
|
|
309
|
+
entitlementsPath: r.entitlementsPath || F
|
|
310
|
+
}, t = new U(i, e);
|
|
307
311
|
if (i.initializeAndFetch === !0) {
|
|
308
312
|
const c = t.fetchAllEntitlements().catch((u) => {
|
|
309
313
|
console.error(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(f,c){typeof exports=="object"&&typeof module<"u"?module.exports=c():typeof define=="function"&&define.amd?define(c):(f=typeof globalThis<"u"?globalThis:f||self,f.kelviqSDK=c())})(this,function(){"use strict";var
|
|
1
|
+
(function(f,c){typeof exports=="object"&&typeof module<"u"?module.exports=c():typeof define=="function"&&define.amd?define(c):(f=typeof globalThis<"u"?globalThis:f||self,f.kelviqSDK=c())})(this,function(){"use strict";var U=Object.defineProperty;var _=(f,c,q)=>c in f?U(f,c,{enumerable:!0,configurable:!0,writable:!0,value:q}):f[c]=q;var A=(f,c,q)=>_(f,typeof c!="symbol"?c+"":c,q);function f(a){const e={};if(!a||!Array.isArray(a.entitlements))return console.warn("[Kelviq SDK] transformApiEntitlements: Invalid or empty entitlements array in API response.",a),e;const s={};a.entitlements.forEach(t=>{if(!t||typeof t.featureId!="string"||typeof t.featureType!="string"){console.warn("[Kelviq SDK] transformApiEntitlements: Skipping invalid raw entitlement object:",t);return}s[t.featureId]||(s[t.featureId]=[]),s[t.featureId].push(t)});for(const t of Object.keys(s)){const u=s[t],m=u[0].featureType;let y=0,r=null,p=null,o=!1,d=!1;if(m==="METER"){let n=!0;for(const i of u)y+=typeof i.currentUsage=="number"?i.currentUsage:0,typeof i.usageLimit=="number"&&(r=(r??0)+i.usageLimit,n=!1);n&&(r=null),p=r!==null?r-y:null,o=u.some(i=>i.hardLimit===!0),d=p===null||p>0}else if(m==="CUSTOMIZABLE"){const n=u[0];r=typeof n.usageLimit=="number"?n.usageLimit:null,y=typeof n.currentUsage=="number"?n.currentUsage:0,p=typeof n.remaining=="number"?n.remaining:null,o=n.hardLimit===!0,d=u.some(i=>i.hasAccess)}else if(m==="BOOLEAN")d=u.some(n=>n.hasAccess);else{console.warn(`[Kelviq SDK] transformApiEntitlements: Encountered unknown featureType: '${m}' for feature '${t}'. This entitlement will be ignored.`);continue}const R={featureId:t,featureType:m,hasAccess:d,hardLimit:o,currentUsage:y,usageLimit:r,remaining:p,items:u};e[t]=R}return e}const c="GET",q=5e3,K=3,P=1e3;function C(a){const{method:e=c,headers:s={},body:t,timeout:u=q,maxRetries:m=K,backoffBaseDelay:y=P,queryParams:r,accessToken:p}=a;let o=a.url,d=0;return new Promise((R,n)=>{if(r){const h=new URLSearchParams;for(const E in r)r[E]!==void 0&&h.append(E,String(r[E]));h.toString()&&(o=o+(o.includes("?")?"&":"?")+h.toString())}function i(){const h=new XMLHttpRequest;h.open(e,o,!0),h.timeout=u;const E={Accept:"application/json","X-Requested-With":"XMLHttpRequest",...s};e!=="GET"&&t&&typeof t=="object"&&!(t instanceof FormData)&&(E["Content-Type"]||(E["Content-Type"]="application/json")),p&&(E.Authorization=`Bearer ${p}`);for(const[l,g]of Object.entries(E))h.setRequestHeader(l,g);h.onload=function(){const{status:l,statusText:g,responseText:T}=h;if(l>=200&&l<300)try{const v=T?JSON.parse(T):{};R({status:l,statusText:g,data:v})}catch(v){const w=v instanceof Error?v:new Error(String(v));console.error(`Kelviq SDK (apiRequest): Invalid JSON response for URL ${o}. Error: ${w.message}. Response: ${T}`),n(new Error(`Invalid JSON response: ${w.message}`))}else F(`Request to ${o} failed with status ${l} ${g}. Response: ${T}`)},h.onerror=()=>F(`Network error for URL ${o}. The request could not be completed.`),h.ontimeout=()=>F(`Request to ${o} timed out.`);function F(l){if(d<m){d++;const g=Math.min(y*Math.pow(2,d-1),3e4);console.warn(`Kelviq SDK (apiRequest): Retrying request to ${o}. Attempt ${d}/${m}. Error: ${l}. Retrying in ${g}ms.`),setTimeout(i,g)}else n(new Error(`${l} (Max retries ${m} reached)`))}try{let l=t;t&&typeof t=="object"&&!(t instanceof FormData)&&E["Content-Type"]==="application/json"&&(l=JSON.stringify(t)),h.send(l)}catch(l){const g=l instanceof Error?l:new Error(String(l));console.error(`Kelviq SDK (apiRequest): Error sending request to ${o}.`,g),n(new Error(`Failed to send request: ${g.message}`))}}i()})}const L="https://edge.api.kelviq.com/api/v1/",D="https://edge.sandboxapi.kelviq.com/api/v1/",S="entitlements/";class ${constructor(e,s){A(this,"options");A(this,"entitlementsCache",null);A(this,"rawApiResponse",null);A(this,"isFetching",!1);A(this,"inFlightPromise",null);A(this,"readyPromise",null);A(this,"lastFetchError",null);A(this,"apiRequestService");if(!e||!e.customerId)throw new Error("[Kelviq SDK] KelviqClient: CustomerId is required in options.");this.options={...e,apiConfig:e.apiConfig||{},entitlementsPath:e.entitlementsPath||S},this.apiRequestService=s||C}async fetchAllEntitlements(e=!1){if(this.inFlightPromise&&!e)return this.inFlightPromise;if(this.entitlementsCache&&!e)return Promise.resolve(this.entitlementsCache);this.isFetching=!0,this.lastFetchError=null;const{apiUrl:s=this.options.environment==="sandbox"?D:L,entitlementsPath:t,customerId:u,accessToken:m,apiConfig:y,onError:r}=this.options,p=s.replace(/\/$/,""),o=t.replace(/^\//,""),d=`${p}/${o}`,R={customer_id:u};return this.inFlightPromise=this.apiRequestService({url:d,method:"GET",queryParams:R,accessToken:m,...y||{}}).then(n=>{if(n&&n.data&&Array.isArray(n.data.entitlements)){const i=n.data;return this.rawApiResponse={customerId:i.customer_id??i.customerId,entitlements:i.entitlements},this.entitlementsCache=f(n.data),this.isFetching=!1,this.inFlightPromise=null,this.entitlementsCache}else{const i=new Error("[Kelviq SDK] Received empty, malformed, or invalid data structure from entitlements API.");throw this.lastFetchError=i,this.isFetching=!1,this.inFlightPromise=null,this.entitlementsCache=null,this.rawApiResponse=null,r&&r(i),i}}).catch(n=>{const i=n instanceof Error?n:new Error(String(n));throw this.lastFetchError=i,this.isFetching=!1,this.inFlightPromise=null,this.entitlementsCache=null,this.rawApiResponse=null,r&&r(i),i}),this.inFlightPromise}getEntitlement(e){return this.entitlementsCache?this.entitlementsCache[e]??null:(console.warn(`[Kelviq SDK] getEntitlement: Entitlements not fetched or cache is empty for featureId '${e}'. Call fetchAllEntitlements() first.`),null)}getEntitlements(){return this.entitlementsCache}getRawEntitlement(e){return this.rawApiResponse?this.rawApiResponse.entitlements.filter(s=>s.featureId===e):(console.warn(`[Kelviq SDK] getRawEntitlement: Entitlements not fetched for featureId '${e}'. Call fetchAllEntitlements() first.`),null)}getRawEntitlements(){return this.rawApiResponse}hasAccess(e){if(!this.entitlementsCache)return console.warn(`[Kelviq SDK] hasAccess: Entitlements not fetched yet for featureId '${e}'. Call fetchAllEntitlements() first. Returning false.`),!1;const s=this.entitlementsCache[e];return s?s.hasAccess:!1}isLoading(){return this.isFetching}getLastError(){return this.lastFetchError}ready(){return this.readyPromise??Promise.resolve()}_setReadyPromise(e){this.readyPromise=e}clearCache(){this.entitlementsCache=null,this.rawApiResponse=null,this.isFetching=!1,this.lastFetchError=null,console.log("[Kelviq SDK] Entitlement cache cleared.")}}function I(a,e){const s={...a,initializeAndFetch:a.initializeAndFetch??!0,apiConfig:a.apiConfig||{},environment:a.environment||"production",entitlementsPath:a.entitlementsPath||S},t=new $(s,e);if(s.initializeAndFetch===!0){const u=t.fetchAllEntitlements().catch(m=>{console.error("[Kelviq SDK] Initial fetch on client creation failed:",m.message)});t._setReadyPromise(u.then(()=>{}))}return t}return I});
|