@getjoystick/joystick-js
Advanced tools
Comparing version 0.0.1-alpha.4 to 0.0.1-alpha.6
@@ -1,8 +0,8 @@ | ||
type ContentOptions = { | ||
interface ContentOptions { | ||
refresh?: boolean; | ||
serialized?: boolean; | ||
fullResponse?: boolean; | ||
}; | ||
} | ||
type Meta = { | ||
interface Meta { | ||
uid: number; | ||
@@ -12,13 +12,10 @@ mod: number; | ||
seg: object[]; | ||
}; | ||
type ApiResponse = { | ||
/** | ||
* Data as string, if serialized is true, or a JSON structure otherwise | ||
*/ | ||
data: string | Record<string, unknown>; | ||
} | ||
interface ApiResponse<TData = any> { | ||
data: TData; | ||
hash: string; | ||
meta: Meta; | ||
}; | ||
} | ||
type Properties = { | ||
interface Properties { | ||
userId?: string; | ||
@@ -32,3 +29,3 @@ apiKey: string; | ||
}; | ||
}; | ||
} | ||
@@ -48,31 +45,25 @@ interface SdkCache { | ||
type PublishContentUpdatePayload = { | ||
/** | ||
* Description | ||
*/ | ||
interface PublishContentUpdatePayload { | ||
description: string; | ||
/** | ||
* Content: can be a object, an array, a string, a boolean, or a number | ||
*/ | ||
content: Record<string, unknown> | unknown[] | string | boolean | number; | ||
/** | ||
* dynamicContentMap: an array of objects | ||
*/ | ||
dynamicContentMap?: Record<string, unknown>[]; | ||
}; | ||
} | ||
type GetDynamicContentPayload = { | ||
interface GetDynamicContentPayload { | ||
userId?: string; | ||
semVer?: string; | ||
params?: Record<string, unknown>; | ||
}; | ||
} | ||
interface ApiClient { | ||
/** | ||
* The getDynamicContent function is used to fetch dynamic content from the Joystick API. | ||
* Fetch dynamic content from the Joystick API. | ||
* | ||
* | ||
* @param contentIds: string[] Pass in an array of content ids | ||
* @param payload: GetDynamicContentPayload Pass in the userid, semver and params | ||
* @param responseType?: "serialized" Specify the type of response you want to receive | ||
* @param {string[]} contentIds Array of content ids to get | ||
* @param {GetDynamicContentPayload} payload Request's payload | ||
* @param {string} [payload.userId] UserId | ||
* @param {string} [payload.semVer] Version of the content to get | ||
* @param {Record<string, unknown>} [payload.params] Dynamic params | ||
* @param {"serialized"} [responseType] Specify the type of response you want to receive | ||
* | ||
@@ -82,9 +73,9 @@ * @return A promise that resolves to an object with a key for each content id | ||
*/ | ||
getDynamicContent(contentIds: string[], payload: GetDynamicContentPayload, responseType?: "serialized"): Promise<Record<string, ApiResponse>>; | ||
getDynamicContent(contentIds: readonly string[], payload: GetDynamicContentPayload, responseType?: "serialized"): Promise<Record<string, ApiResponse>>; | ||
/** | ||
* The publishContentUpdate function is used to update the content of a given configuration. | ||
* Updates the content of a given configuration. | ||
* | ||
* | ||
* @param contentId: string Identify the content that is being updated | ||
* @param payload: PublishContentUpdatePayload | ||
* @param {string} contentId Identify the content that is being updated | ||
* @param {PublishContentUpdatePayload} payload | ||
* description: string The description of the content being updated | ||
@@ -120,9 +111,17 @@ * content: Pass in the new content, description and dynamiccontentmap | ||
/** | ||
* The constructor function for the JoystickSdk class. | ||
* Initializes the Joystick SDK with default values. | ||
* | ||
* | ||
* @param properties {Properties} | ||
* @param properties.apiKey {string} | ||
* @param properties.userId {string} | ||
* @param services: Services Allow passing custom implementation for the services | ||
* @param {Object} properties Default values for the SDK | ||
* @param {string} properties.apiKey API Key provided by the Joystick platform | ||
* @param {string} [properties.userId] UserId value for API request payload u field | ||
* @param {string} [properties.semVer] Version of the content to return | ||
* @param {string} [properties.params] Params object to send with the requests | ||
* @param {object} [properties.options] Options | ||
* @param {number} [properties.options.cacheExpirationSeconds] Number of seconds while the cache is valid | ||
* @param {boolean} [properties.options.serialized] The returned data should come in string format (true) | ||
* @param {object} [services] Provides custom implementations for services | ||
* @param {ApiClient} [services.apiClient] Custom implementation for the API client | ||
* @param {Logger} [services.logger] Custom implementation for logging | ||
* @param {SdkCache} [services.cache] Custom implementation for caching | ||
* | ||
@@ -134,23 +133,3 @@ * @return An instance of the class | ||
getCache(): SdkCache; | ||
/** | ||
* The getParamValue function is used to retrieve the value of a parameter | ||
* from the properties object. If no such parameter exists, it returns undefined. | ||
* | ||
* | ||
* @param key: string Specify the key of the parameter that you want to get | ||
* | ||
* @return Undefined if the key does not exist | ||
* | ||
*/ | ||
getParamValue(key: string): unknown; | ||
/** | ||
* The setParamValue function sets the value of a parameter in the properties.params object | ||
* | ||
* | ||
* @param key: string Set the key of the parameter that is being passed in | ||
* @param value: unknown Set the value of a parameter | ||
* | ||
* @return this, allowing fluent setters | ||
* | ||
*/ | ||
setParamValue(key: string, value: unknown): Joystick; | ||
@@ -171,3 +150,3 @@ getApiKey(): string; | ||
/** | ||
* The getParams function returns the params property of the properties object. | ||
* Returns the params property of the properties object. | ||
* | ||
@@ -188,7 +167,10 @@ * | ||
/** | ||
* The publishContentUpdate function is used to publish a content update to Joystick. | ||
* Publish a content update to Joystick. | ||
* | ||
* | ||
* @param contentId: string Identify the content that is being published | ||
* @param payload: PublishContentUpdatePayload Pass the data to be published | ||
* @param {string} contentId Identify the content that is being published | ||
* @param {PublishContentUpdatePayload} payload Pass the data to be published | ||
* @param {string} payload.description Description of the new content | ||
* @param {Record<string, unknown> | unknown[] | string | boolean | number} payload.content Content object, or an array, or a string, a boolean, or a number | ||
* @param {Record<string, unknown>[]} [payload.dynamicContentMap] Array of objects to use as dynamic content | ||
* | ||
@@ -206,41 +188,72 @@ */ | ||
/** | ||
* The getContent function returns the content of a single file. | ||
* Returns the content of a single content ID from Joystick API. | ||
* | ||
* | ||
* @param contentId: string Identify the content that is being requested | ||
* @param options: ContentOptions Pass in an optional contentoptions object | ||
* @param {string} contentId Identify the content that is being requested | ||
* @param {ContentOptions} [options] Pass in an optional contentoptions object | ||
* @param {boolean} [options.refresh] The cache should be avoided, and the data must be requested from the API | ||
* @param {boolean} [options.serialized] Should return string representation of the data, rather than JSON one | ||
* @param {boolean} [options.fullResponse] Should include all the metadata in the response | ||
* | ||
* @return TResult, a generic type. Defaults to ApiResponse if not provided. | ||
* @return {TResult}, a generic type. Defaults to ApiResponse if not provided. | ||
* | ||
*/ | ||
getContent<TResult = ApiResponse>(contentId: string, options?: ContentOptions): Promise<TResult>; | ||
getContent<TResult extends string = string>(contentId: string, options?: ContentOptions & { | ||
fullResponse?: false; | ||
serialized: true; | ||
}): Promise<TResult>; | ||
getContent<TResult extends string = string>(contentId: string, options?: ContentOptions & { | ||
fullResponse: true; | ||
serialized: true; | ||
}): Promise<ApiResponse<TResult>>; | ||
getContent<TResult = any>(contentId: string, options?: ContentOptions & { | ||
fullResponse: true; | ||
serialized?: false; | ||
}): Promise<ApiResponse<TResult>>; | ||
getContent<TResult = any>(contentId: string, options?: ContentOptions & { | ||
serialized?: false; | ||
fullResponse?: false; | ||
}): Promise<TResult>; | ||
/** | ||
* The getContents function is used to retrieve content from the Joystick API. | ||
* It takes an array of content IDs and returns a promise that resolves with an object containing the requested contents. | ||
* The function will first check if there is any cached data for this request, and if so it will return that instead of making a new request to the API. | ||
* If no cached data exists, or if refresh: true was passed in as part of options, then it will make a new request to the API using Axios (a popular HTTP client). | ||
* Returns the contents from Joystick API DynamicContent. | ||
* | ||
* @param contentIds: string[] Pass in an array of content ids | ||
* @param options: ContentOptions Pass in the options object | ||
* | ||
* @return A promise that resolves to a record of content ids and their corresponding apiresponse | ||
* @param {string[]} contentIds Pass in an array of content ids | ||
* @param {ContentOptions} [options] Pass in an optional contentoptions object | ||
* @param {boolean} [options.refresh] The cache should be avoided, and the data must be requested from the API | ||
* @param {boolean} [options.serialized] Should return string representation of the data, rather than JSON one | ||
* @param {boolean} [options.fullResponse] Should include all the metadata in the response | ||
* | ||
*/ | ||
getContents<TResult = ApiResponse>(contentIds: string[], options?: ContentOptions): Promise<Record<string, TResult>>; | ||
/** | ||
* The setUserId function sets the userId property of the properties object. | ||
* @return {Record<string,TResult>} TResult, a generic type. Defaults to ApiResponse if not provided. | ||
* | ||
* | ||
* @param userId: string | undefined Set the userId property | ||
* | ||
* @return this, allowing fluent setters | ||
* | ||
*/ | ||
getContents<TResult extends { | ||
[K in TContentIds[number]]: string; | ||
}, TContentIds extends readonly string[]>(contentIds: TContentIds, options?: ContentOptions & { | ||
fullResponse?: false; | ||
serialized: true; | ||
}): Promise<{ | ||
[K in TContentIds[number]]: TResult[K]; | ||
}>; | ||
getContents<TResult extends { | ||
[K in TContentIds[number]]: string; | ||
}, TContentIds extends readonly string[]>(contentIds: TContentIds, options?: ContentOptions & { | ||
fullResponse: true; | ||
serialized: true; | ||
}): Promise<{ | ||
[K in TContentIds[number]]: ApiResponse<TResult[K]>; | ||
}>; | ||
getContents<TResult extends Record<string, any>>(contentIds: Array<keyof TResult>, options?: ContentOptions & { | ||
fullResponse: true; | ||
}): Promise<{ | ||
[K in keyof TResult]: ApiResponse<TResult[K]>; | ||
}>; | ||
getContents<TResult extends Record<string, any>>(contentIds: Array<keyof TResult>, options?: ContentOptions): Promise<TResult>; | ||
setUserId(userId: string | undefined): Joystick; | ||
setSerialized(serialized: boolean): Joystick; | ||
/** | ||
* The setSerialized function sets the serialized property of the options object to a boolean value. | ||
* Sets the cache expiration time in seconds locally and updates the cache implementation. | ||
* | ||
* | ||
* @param serialized: boolean Set the serialized property of the options object | ||
* @param {number} cacheExpirationSeconds Expects a value>=0, indicating the number of seconds the cache remains active | ||
* | ||
@@ -250,30 +263,9 @@ * @return this, allowing fluent setters | ||
*/ | ||
setSerialized(serialized: boolean): Joystick; | ||
/** | ||
* The setCacheExpirationSeconds function sets the cache expiration time in seconds. | ||
* | ||
* | ||
* @param cacheExpirationSeconds: number Set the cache expiration time | ||
* | ||
* @return A promise that resolves to void | ||
* | ||
* @docauthor Trelent | ||
*/ | ||
setCacheExpirationSeconds(cacheExpirationSeconds: number): Joystick; | ||
/** | ||
* The setParams function is used to set the params property of the class. | ||
* | ||
* | ||
* @param params: Record<string Define the type of the parameter being passed in | ||
* | ||
* @return this, allowing fluent setters | ||
* | ||
*/ | ||
setParams(params: Record<string, unknown>): Joystick; | ||
/** | ||
* The getSerialized function returns the serialized property of the options object. | ||
* If no value is passed in, it will return the default value of false. | ||
* Returns the serialized property value. | ||
* | ||
* | ||
* @param serialized?: boolean Set the value of this | ||
* @param {boolean} [serialized] If provided, it will be used. If not, the global serialized will be returned. | ||
* | ||
@@ -280,0 +272,0 @@ * @return A boolean or undefined |
'use strict'; | ||
var J = require('axios'); | ||
var U = require('axios'); | ||
var webcrypto = require('@peculiar/webcrypto'); | ||
@@ -8,10 +8,10 @@ | ||
var J__default = /*#__PURE__*/_interopDefault(J); | ||
var U__default = /*#__PURE__*/_interopDefault(U); | ||
var T=Object.defineProperty,M=Object.defineProperties;var L=Object.getOwnPropertyDescriptors;var S=Object.getOwnPropertySymbols;var U=Object.prototype.hasOwnProperty,F=Object.prototype.propertyIsEnumerable;var E=(n,e,t)=>e in n?T(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,l=(n,e)=>{for(var t in e||(e={}))U.call(e,t)&&E(n,t,e[t]);if(S)for(var t of S(e))F.call(e,t)&&E(n,t,e[t]);return n},d=(n,e)=>M(n,L(e));var o=(n,e,t)=>new Promise((r,i)=>{var a=c=>{try{p(t.next(c));}catch(h){i(h);}},u=c=>{try{p(t.throw(c));}catch(h){i(h);}},p=c=>c.done?r(c.value):Promise.resolve(c.value).then(a,u);p((t=t.apply(n,e)).next());});var m=class extends Error{};var g=class extends m{};var f=class extends g{};var w=class extends g{};var y=class extends g{};var s=class extends m{};var C=class{constructor(e,t){this.validateApiKey(e),this.logger=t,this.client=J__default.default.create({headers:{Accept:"application/json","Content-Type":"application/json","x-api-key":e},responseEncoding:"UTF-8",responseType:"json",validateStatus:r=>r===200});}validateApiKey(e){if(!e||!e.trim())throw new s(`Invalid apiKey: <${e}>`)}put(e,t,r){return o(this,null,function*(){this.logger.debug("Sending put request",{url:e,payload:t,params:r});try{yield this.client.put(e,t,{params:r});}catch(i){throw this.checkForErrors(i),i}})}post(e,t,r){return o(this,null,function*(){this.logger.debug("Sending post request",{url:e,payload:t,params:r});try{let{data:i}=yield this.client.post(e,t,{params:r});return i}catch(i){throw this.checkForErrors(i),i}})}checkForErrors(e){var t;if(e instanceof J.AxiosError&&((t=e.response)!=null&&t.status)){let{status:r}=e.response;if(r>=400&&r<500)throw new y(e.message);if(r>=500)throw new w(e.message);if(r!=200)throw new f(e.message)}}};var b=class{constructor(e,t,r=1e3,i=Date.now){this.validateCacheExpirationSeconds(e),this.validateMaxItemsInCache(r),this.cacheExpirationMs=e*1e3,this.logger=t,this.maxItemsInCache=r,this.nowFn=i,this.cache=new Map;}setCacheExpirationSeconds(e){this.validateCacheExpirationSeconds(e),this.cacheExpirationMs=e*1e3;}getCacheSize(){return this.cache.size}set(e,t){return this.cache.set(e,{value:t,cachedAtTimestampMs:this.nowFn(),lastAccessedAtTimestampMs:this.nowFn()}),this.checkLruMaxSize(),Promise.resolve()}get(e){let t=this.cache.get(e);return !t||this.isExpired(t)?Promise.resolve(void 0):(t.lastAccessedAtTimestampMs=this.nowFn(),Promise.resolve(t.value))}isExpired({cachedAtTimestampMs:e}){return e+this.cacheExpirationMs<this.nowFn()}clear(){return o(this,null,function*(){yield this.cache.clear();})}checkLruMaxSize(){if(this.cache.size<=this.maxItemsInCache)return;let e=[...this.cache.entries()].sort(([,t],[,r])=>r.lastAccessedAtTimestampMs-t.lastAccessedAtTimestampMs).slice(this.maxItemsInCache).map(([t])=>t);this.logger.debug({keysToDelete:e},"checkLruMaxSize"),e.forEach(t=>this.cache.delete(t));}validateCacheExpirationSeconds(e){if(e<0)throw new s(`Invalid cacheExpirationSeconds: <${e}>. It should be equal or greater than 0`)}validateMaxItemsInCache(e){if(e<1)throw new s(`Invalid maxItemsInCache: <${e}>. It should be greater than 0`)}};var A=class{debug(...e){this.shouldLog("debug")&&console.debug(...e);}error(...e){this.shouldLog("error")&&console.error(...e);}info(...e){this.shouldLog("info")&&console.info(...e);}warn(...e){this.shouldLog("warn")&&console.warn(...e);}shouldLog(e){switch(e){case"info":case"error":case"warn":return !0;case"debug":return process.env.NODE_ENV==="development"}}};var D=new webcrypto.Crypto,$=n=>Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,"0")).join("");function I(n){return o(this,null,function*(){let e=typeof n=="string"?n:JSON.stringify(n),t=yield D.subtle.digest("SHA-256",new TextEncoder().encode(e));return $(t)})}var x=class extends m{};var v=class extends x{};var k=class{constructor(e,t){this.client=e,this.logger=t;}getDynamicContent(e,t,r){return o(this,null,function*(){let{params:i,semVer:a,userId:u=""}=t,p=yield this.client.post("https://api.getjoystick.com/api/v1/combine/",{u,v:a,p:i},{c:JSON.stringify(e),dynamic:"true",responseType:r});return this.checkForErrors(p),Object.entries(p).reduce((c,[h,R])=>d(l({},c),{[h]:R}),{})})}publishContentUpdate(e,t){return o(this,null,function*(){let{description:r,content:i,dynamicContentMap:a=[]}=t;this.validateDescription(r),this.validateContent(i),this.validateDynamicContentMap(a),yield this.client.put(`https://capi.getjoystick.com/api/v1/config/${e}`,{d:r,c:i,m:a});})}validateDescription(e){if(!e||e.length<1||e.length>50)throw new s(`Invalid description: ${e}. It should be between 1 and 50 characters long`)}validateContent(e){try{JSON.stringify(e);}catch(t){throw new s("Invalid content. It should be JSON encodable")}}validateDynamicContentMap(e){if(e)try{JSON.stringify(e);}catch(t){throw new s("Invalid dynamicContentMap. It should be JSON encodable")}}checkForErrors(e){let t=Object.values(e).filter(r=>typeof r=="string").map(r=>`- ${r}`);if(t.length>0)throw new v(t.join(` | ||
`))}};var H=300,j=/^\d+.\d+.\d+$/,P=class{constructor(e,t){var p,c,h;let{semVer:r,userId:i,apiKey:a,options:u}=e;this.validateApiKey(a),this.validateUserId(i),this.validateSemVer(r),this.validateCacheExpirationSeconds(u==null?void 0:u.cacheExpirationSeconds),this.properties=e,this.logger=(p=t==null?void 0:t.logger)!=null?p:new A,this.apiClient=(c=t==null?void 0:t.apiClient)!=null?c:new k(new C(this.getApiKey(),this.logger),this.logger),this.cache=(h=t==null?void 0:t.cache)!=null?h:new b(this.getCacheExpirationSeconds(),this.logger);}getCache(){return this.cache}getParamValue(e){var t;return (t=this.properties.params)==null?void 0:t[e]}setParamValue(e,t){return this.properties.params=d(l({},this.properties.params),{[e]:t}),this}getApiKey(){return this.properties.apiKey}getUserId(){return this.properties.userId}getSemVer(){return this.properties.semVer}setSemVer(e){return this.validateSemVer(e),this.properties.semVer=e,this}getParams(){var e;return (e=this.properties.params)!=null?e:{}}getCacheExpirationSeconds(){var e,t;return (t=(e=this.properties.options)==null?void 0:e.cacheExpirationSeconds)!=null?t:H}publishContentUpdate(e,t){return o(this,null,function*(){this.validateContentId(e);try{return yield this.apiClient.publishContentUpdate(e,t)}catch(r){throw r instanceof f?this.logger.error("Found an unknown error when publishing content update to Joystick"):r instanceof w?this.logger.error("Found a server error when publishing content update to Joystick"):r instanceof y&&this.logger.error("Found a client error when publishing content update to Joystick"),r}})}clearCache(){return o(this,null,function*(){yield this.cache.clear();})}getContent(e,t){return o(this,null,function*(){return (yield this.getContents([e],t))[e]})}getContents(e,t){return o(this,null,function*(){this.validateContentIds(e);let r=yield this.buildCacheKey(e,t),i=t!=null&&t.refresh?void 0:yield this.cache.get(r);if(!i)try{i=yield this.apiClient.getDynamicContent(e,{params:this.getParams(),semVer:this.getSemVer(),userId:this.getUserId()},this.getSerialized(t==null?void 0:t.serialized)?"serialized":void 0),yield this.cache.set(r,i);}catch(a){throw a instanceof f?this.logger.error("Found an unknown error when getting content from Joystick"):a instanceof v?this.logger.error(`The following errors found when calling Multiple Content API: | ||
${a.message}`):a instanceof w?this.logger.error("Found a server error when getting content from Joystick"):a instanceof y&&this.logger.error("Found a client error when getting content from Joystick"),a}return t!=null&&t.fullResponse?i:this.simplifyResponse(i)})}setUserId(e){return this.validateUserId(e),this.properties.userId=e,this}setSerialized(e){return this.properties.options=d(l({},this.properties.options),{serialized:e}),this}setCacheExpirationSeconds(e){return this.validateCacheExpirationSeconds(e),this.properties.options=d(l({},this.properties.options),{cacheExpirationSeconds:e}),this.cache.setCacheExpirationSeconds(e),this}setParams(e){return this.properties.params=e,this}getSerialized(e){var t;return e!=null?e:(t=this.properties.options)==null?void 0:t.serialized}simplifyResponse(e){return Object.entries(e).reduce((t,[r,i])=>d(l({},t),{[r]:i.data}),{})}buildCacheKey(e,t){return o(this,null,function*(){var i;let r=[this.getApiKey(),this.getParamsSortedByKeyAsc(this.getParams()),this.getSemVer(),this.getUserId(),[...e].sort(),this.getSerialized(t==null?void 0:t.serialized),(i=t==null?void 0:t.fullResponse)!=null?i:!1];return yield I(r)})}getParamsSortedByKeyAsc(e={}){return Object.entries(e).sort(([t],[r])=>t.localeCompare(r)).reduce((t,[r,i])=>d(l({},t),{[r]:i}),{})}validateContentIds(e){if(!e||e.length==0||e.some(t=>!t.trim()))throw new s("The contentIds parameter must be a non-empty array of strings")}validateApiKey(e){if(!e||!e.trim())throw new s(`Invalid apiKey: <${e}>`)}validateCacheExpirationSeconds(e){if(e!=null&&e<0)throw new s(`Invalid cacheExpirationSeconds: <${e}>`)}validateSemVer(e){if(e&&!j.test(e))throw new s(`Invalid semVer: <${e}>`)}validateUserId(e){if(e&&!e.trim())throw new s(`Invalid userId: <${e}>`)}validateContentId(e){if(!e||!e.trim())throw new s(`Invalid contentId: <${e}>`)}}; | ||
var S=Object.defineProperty,E=Object.defineProperties;var M=Object.getOwnPropertyDescriptors;var A=Object.getOwnPropertySymbols;var O=Object.prototype.hasOwnProperty,L=Object.prototype.propertyIsEnumerable;var I=(s,e,t)=>e in s?S(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t,a=(s,e)=>{for(var t in e||(e={}))O.call(e,t)&&I(s,t,e[t]);if(A)for(var t of A(e))L.call(e,t)&&I(s,t,e[t]);return s},p=(s,e)=>E(s,M(e));var c=class extends Error{constructor(e){super(e);}};var l=class extends c{constructor(e){super(e);}};var d=class extends l{constructor(e){super(e);}};var h=class extends l{constructor(e){super(e);}};var g=class extends l{constructor(e){super(e);}};var i=class extends c{constructor(e){super(e);}};var w=class{constructor(e,t){this.validateApiKey(e),this.logger=t,this.client=U__default.default.create({headers:{Accept:"application/json","Content-Type":"application/json","x-api-key":e},responseEncoding:"UTF-8",responseType:"json",validateStatus:r=>r===200});}validateApiKey(e){if(!e||!e.trim())throw new i(`Invalid apiKey: <${e}>`)}async put(e,t,r){this.logger.debug("Sending put request",{url:e,payload:t,params:r});try{await this.client.put(e,t,{params:r});}catch(n){throw this.checkForErrors(n),n}}async post(e,t,r){this.logger.debug("Sending post request",{url:e,payload:t,params:r});try{let{data:n}=await this.client.post(e,t,{params:r});return n}catch(n){throw this.checkForErrors(n),n}}checkForErrors(e){var t;if(e instanceof U.AxiosError&&((t=e.response)!=null&&t.status)){let{status:r}=e.response;if(r>=400&&r<500)throw new g(e.message);if(r>=500)throw new h(e.message);if(r!=200)throw new d(e.message)}}};var v=class{constructor(e,t,r=1e3,n=Date.now){this.validateCacheExpirationSeconds(e),this.validateMaxItemsInCache(r),this.cacheExpirationMs=e*1e3,this.logger=t,this.maxItemsInCache=r,this.nowFn=n,this.cache=new Map;}setCacheExpirationSeconds(e){this.validateCacheExpirationSeconds(e),this.cacheExpirationMs=e*1e3;}getCacheSize(){return this.cache.size}set(e,t){return this.cache.set(e,{value:t,cachedAtTimestampMs:this.nowFn(),lastAccessedAtTimestampMs:this.nowFn()}),this.checkLruMaxSize(),Promise.resolve()}get(e){let t=this.cache.get(e);return !t||this.isExpired(t)?Promise.resolve(void 0):(t.lastAccessedAtTimestampMs=this.nowFn(),Promise.resolve(t.value))}isExpired({cachedAtTimestampMs:e}){return e+this.cacheExpirationMs<this.nowFn()}async clear(){await this.cache.clear();}checkLruMaxSize(){if(this.cache.size<=this.maxItemsInCache)return;let e=[...this.cache.entries()].sort(([,t],[,r])=>r.lastAccessedAtTimestampMs-t.lastAccessedAtTimestampMs).slice(this.maxItemsInCache).map(([t])=>t);this.logger.debug({keysToDelete:e},"checkLruMaxSize"),e.forEach(t=>this.cache.delete(t));}validateCacheExpirationSeconds(e){if(e<0)throw new i(`Invalid cacheExpirationSeconds: <${e}>. It should be equal or greater than 0`)}validateMaxItemsInCache(e){if(e<1)throw new i(`Invalid maxItemsInCache: <${e}>. It should be greater than 0`)}};var R=class{debug(...e){this.shouldLog("debug")&&console.debug(...e);}error(...e){this.shouldLog("error")&&console.error(...e);}info(...e){this.shouldLog("info")&&console.info(...e);}warn(...e){this.shouldLog("warn")&&console.warn(...e);}shouldLog(e){switch(e){case"info":case"error":case"warn":return !0;case"debug":return process.env.NODE_ENV==="development"}}};var K=new webcrypto.Crypto,V=s=>Array.from(new Uint8Array(s)).map(e=>e.toString(16).padStart(2,"0")).join("");async function k(s){let e=typeof s=="string"?s:JSON.stringify(s),t=await K.subtle.digest("SHA-256",new TextEncoder().encode(e));return V(t)}var x=class extends c{constructor(e){super(e);}};var m=class extends x{constructor(e){super(e);}};var b=class{constructor(e,t){this.client=e,this.logger=t;}async getDynamicContent(e,t,r){let{params:n,semVer:o,userId:u=""}=t,f=await this.client.post("https://api.getjoystick.com/api/v1/combine/",{u,v:o,p:n},{c:JSON.stringify(e),dynamic:"true",responseType:r});return this.checkForErrors(f),Object.entries(f).reduce((y,[C,P])=>p(a({},y),{[C]:P}),{})}async publishContentUpdate(e,t){let{description:r,content:n,dynamicContentMap:o=[]}=t;this.validateDescription(r),this.validateContent(n),this.validateDynamicContentMap(o),await this.client.put(`https://capi.getjoystick.com/api/v1/config/${e}`,{d:r,c:n,m:o});}validateDescription(e){if(!e||e.length<1||e.length>50)throw new i(`Invalid description: ${e}. It should be between 1 and 50 characters long`)}validateContent(e){try{JSON.stringify(e);}catch(t){throw new i("Invalid content. It should be JSON encodable")}}validateDynamicContentMap(e){if(e)try{JSON.stringify(e);}catch(t){throw new i("Invalid dynamicContentMap. It should be JSON encodable")}}checkForErrors(e){let t=Object.values(e).filter(r=>typeof r=="string").map(r=>`- ${r}`);if(t.length>0)throw new m(t.join(` | ||
`))}};var z=300,D=/^\d+.\d+.\d+$/,T=class{constructor(e,t){var f,y,C;let{semVer:r,userId:n,apiKey:o,options:u}=e;this.validateApiKey(o),this.validateUserId(n),this.validateSemVer(r),this.validateCacheExpirationSeconds(u==null?void 0:u.cacheExpirationSeconds),this.properties=e,this.logger=(f=t==null?void 0:t.logger)!=null?f:new R,this.apiClient=(y=t==null?void 0:t.apiClient)!=null?y:new b(new w(this.getApiKey(),this.logger),this.logger),this.cache=(C=t==null?void 0:t.cache)!=null?C:new v(this.getCacheExpirationSeconds(),this.logger);}getCache(){return this.cache}getParamValue(e){var t;return (t=this.properties.params)==null?void 0:t[e]}setParamValue(e,t){return this.properties.params=p(a({},this.properties.params),{[e]:t}),this}getApiKey(){return this.properties.apiKey}getUserId(){return this.properties.userId}getSemVer(){return this.properties.semVer}setSemVer(e){return this.validateSemVer(e),this.properties.semVer=e,this}getParams(){var e;return (e=this.properties.params)!=null?e:{}}getCacheExpirationSeconds(){var e,t;return (t=(e=this.properties.options)==null?void 0:e.cacheExpirationSeconds)!=null?t:z}async publishContentUpdate(e,t){this.validateContentId(e);try{return await this.apiClient.publishContentUpdate(e,t)}catch(r){throw r instanceof d?this.logger.error("Found an unknown error when publishing content update to Joystick"):r instanceof h?this.logger.error("Found a server error when publishing content update to Joystick"):r instanceof g&&this.logger.error("Found a client error when publishing content update to Joystick"),r}}async clearCache(){await this.cache.clear();}async getContent(e,t){return (await this.getContents([e],t))[e]}async getContents(e,t){this.validateContentIds(e);let r=await this.buildCacheKey(e,t),n=t!=null&&t.refresh?void 0:await this.cache.get(r);if(!n)try{n=await this.apiClient.getDynamicContent(e,{params:this.getParams(),semVer:this.getSemVer(),userId:this.getUserId()},this.getSerialized(t==null?void 0:t.serialized)?"serialized":void 0),await this.cache.set(r,n);}catch(o){throw o instanceof d?this.logger.error("Found an unknown error when getting content from Joystick"):o instanceof m?this.logger.error(`The following errors found when calling Multiple Content API: | ||
${o.message}`):o instanceof h?this.logger.error("Found a server error when getting content from Joystick"):o instanceof g&&this.logger.error("Found a client error when getting content from Joystick"),o}return t!=null&&t.fullResponse?n:this.simplifyResponse(n)}setUserId(e){return this.validateUserId(e),this.properties.userId=e,this}setSerialized(e){return this.properties.options=p(a({},this.properties.options),{serialized:e}),this}setCacheExpirationSeconds(e){return this.validateCacheExpirationSeconds(e),this.properties.options=p(a({},this.properties.options),{cacheExpirationSeconds:e}),this.cache.setCacheExpirationSeconds(e),this}setParams(e){return this.properties.params=e,this}getSerialized(e){var t;return e!=null?e:(t=this.properties.options)==null?void 0:t.serialized}simplifyResponse(e){return Object.entries(e).reduce((t,[r,n])=>p(a({},t),{[r]:n.data}),{})}async buildCacheKey(e,t){var n;let r=[this.getApiKey(),this.getParamsSortedByKeyAsc(this.getParams()),this.getSemVer(),this.getUserId(),[...e].sort(),this.getSerialized(t==null?void 0:t.serialized),(n=t==null?void 0:t.fullResponse)!=null?n:!1];return await k(r)}getParamsSortedByKeyAsc(e={}){return Object.entries(e).sort(([t],[r])=>t.localeCompare(r)).reduce((t,[r,n])=>p(a({},t),{[r]:n}),{})}validateContentIds(e){if(!e||e.length==0||e.some(t=>!t.trim()))throw new i("The contentIds parameter must be a non-empty array of strings")}validateApiKey(e){if(!e||!e.trim())throw new i(`Invalid apiKey: <${e}>`)}validateCacheExpirationSeconds(e){if(e!=null&&e<0)throw new i(`Invalid cacheExpirationSeconds: <${e}>`)}validateSemVer(e){if(e&&!D.test(e))throw new i(`Invalid semVer: <${e}>`)}validateUserId(e){if(e&&!e.trim())throw new i(`Invalid userId: <${e}>`)}validateContentId(e){if(!e||!e.trim())throw new i(`Invalid contentId: <${e}>`)}}; | ||
exports.Joystick = P; | ||
exports.Joystick = T; | ||
//# sourceMappingURL=out.js.map | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@getjoystick/joystick-js", | ||
"version": "0.0.1-alpha.4", | ||
"version": "0.0.1-alpha.6", | ||
"description": "JS SDK for Joystick", | ||
@@ -14,2 +14,4 @@ "main": "./dist/index.js", | ||
"pretest": "npm run build", | ||
"lint": "eslint --ext .ts src tests examples && prettier --check", | ||
"lint-fix": "eslint --fix --ext .ts src tests examples && prettier --write .", | ||
"test": "jest" | ||
@@ -21,9 +23,12 @@ }, | ||
"@types/jest": "^29.4.0", | ||
"@typescript-eslint/eslint-plugin": "^5.58.0", | ||
"@typescript-eslint/parser": "^5.58.0", | ||
"axios-mock-adapter": "^1.21.2", | ||
"dotenv": "^16.0.3", | ||
"eslint": "^8.38.0", | ||
"jest": "^29.4.3", | ||
"prettier": "^2.8.4", | ||
"prettier": "^2.8.7", | ||
"strong-mock": "^8.0.1", | ||
"ts-jest": "^29.0.5", | ||
"tsup": "^6.6.3", | ||
"tsup": "^6.7.0", | ||
"typedoc": "^0.24.1", | ||
@@ -30,0 +35,0 @@ "typescript": "^4.9.5" |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Unpublished package
Supply chain riskPackage version was not found on the registry. It may exist on a different registry and need to be configured to pull from that registry.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Unpopular package
QualityThis package is not very popular.
Found 1 instance in 1 package
111270
0
0
13
348
1