@objectiv/queue-local-storage
Advanced tools
Comparing version 0.0.7 to 0.0.8
@@ -1,258 +0,4 @@ | ||
/* | ||
* Copyright 2021-2022 Objectiv B.V. | ||
*/ | ||
import { AbstractGlobalContext, AbstractLocationContext, Contexts, AbstractEvent } from "@objectiv/schema"; | ||
import { TrackerQueueStoreInterface, TrackerConsole, TrackerQueueStoreConfig, TrackerEvent, NonEmptyArray } from '@objectiv/tracker-core'; | ||
/** | ||
* An array of Location Contexts | ||
*/ | ||
type LocationStack = AbstractLocationContext[]; | ||
/** | ||
* An array of Global Contexts | ||
*/ | ||
type GlobalContexts = AbstractGlobalContext[]; | ||
/** | ||
* The configuration of the Contexts interface | ||
*/ | ||
type ContextsConfig = { | ||
location_stack?: LocationStack; | ||
global_contexts?: GlobalContexts; | ||
}; | ||
/** | ||
* TrackerConsole is a simplified implementation of Console. | ||
*/ | ||
type TrackerConsole = Pick<Console, "debug" | "error" | "group" | "groupCollapsed" | "groupEnd" | "info" | "log" | "warn">; | ||
/** | ||
* TrackerEvents are simply a combination of an `event` name and their Contexts. | ||
* Contexts are entirely optional, although Collectors will mostly likely enforce minimal requirements around them. | ||
* Eg. An interactive TrackerEvent without a Location Stack is probably not descriptive enough to be acceptable. | ||
*/ | ||
type TrackerEventConfig = Pick<AbstractEvent, "_type"> & ContextsConfig & { | ||
// Unless the Event config has been preconfigured with an id the TrackerEvent will generate one for us | ||
id?: string; | ||
}; | ||
/** | ||
* An Event before it has been handed over to the Tracker. | ||
* Properties that will be set by the Tracker or Transport are omitted: `id`, `time` | ||
*/ | ||
type UntrackedEvent = Omit<AbstractEvent, "id" | "time">; | ||
/** | ||
* Our main TrackerEvent interface and basic implementation | ||
*/ | ||
declare class TrackerEvent implements UntrackedEvent, Contexts { | ||
// Event interface | ||
readonly _type: string; | ||
id: string; | ||
time?: number; | ||
// Contexts interface | ||
readonly location_stack: AbstractLocationContext[]; | ||
readonly global_contexts: AbstractGlobalContext[]; | ||
/** | ||
* Configures the TrackerEvent instance via a TrackerEventConfig and optionally one or more ContextConfig. | ||
* | ||
* TrackerEventConfig is used mainly to configure the `event` property, although it can also carry Contexts. | ||
* | ||
* ContextConfigs are used to configure location_stack and global_contexts. If multiple configurations have been | ||
* provided they will be merged onto each other to produce a single location_stack and global_contexts. | ||
*/ | ||
constructor({ _type, id, ...otherEventProps }: TrackerEventConfig, ...contextConfigs: ContextsConfig[]); | ||
/** | ||
* Tracking time setter. | ||
* Defaults to Date.now() if not timestampMs is provided. | ||
*/ | ||
setTime(timestampMs?: number): void; | ||
/** | ||
* Custom JSON serializer that cleans up the internally properties we use internally to differentiate between | ||
* Contexts and Event types and for validation. This ensures the Event we send to Collectors has only OSF properties. | ||
*/ | ||
toJSON(): this & { | ||
location_stack: ({} & AbstractLocationContext)[]; | ||
global_contexts: ({} & AbstractGlobalContext)[]; | ||
}; | ||
} | ||
/** | ||
* A TypeScript generic describing an array with at least one item of the given Type | ||
*/ | ||
type NonEmptyArray<T> = [ | ||
T, | ||
...T[] | ||
]; | ||
/** | ||
* The TrackerQueueStoreConfig object. | ||
*/ | ||
type TrackerQueueStoreConfig = { | ||
/** | ||
* Optional. A TrackerConsole instance for logging. | ||
*/ | ||
console?: TrackerConsole; | ||
}; | ||
/** | ||
* Our Tracker Queue Store generic interface. | ||
*/ | ||
interface TrackerQueueStoreInterface { | ||
/** | ||
* Optional. A TrackerConsole instance for logging. | ||
*/ | ||
readonly console?: TrackerConsole; | ||
/** | ||
* A name describing the Queue Store implementation for debugging purposes | ||
*/ | ||
readonly queueStoreName: string; | ||
/** | ||
* How many TrackerEvents are in the store | ||
*/ | ||
length: number; | ||
/** | ||
* Read Events from the store, if `size` is omitted all TrackerEvents will be returned | ||
*/ | ||
read(size?: number, filterPredicate?: (event: TrackerEvent) => boolean): Promise<TrackerEvent[]>; | ||
/** | ||
* Write Events to the store | ||
*/ | ||
write(...args: NonEmptyArray<TrackerEvent>): Promise<any>; | ||
/** | ||
* Delete TrackerEvents from the store by id | ||
*/ | ||
delete(TrackerEventIds: string[]): Promise<any>; | ||
/** | ||
* Delete all TrackerEvents from the store | ||
*/ | ||
clear(): Promise<any>; | ||
} | ||
/** | ||
* TrackerTransports can receive either Events ready to be processed or Event Promises. | ||
*/ | ||
type TransportableEvent = TrackerEvent | Promise<TrackerEvent>; | ||
/** | ||
* The configuration of TrackerTransportTransportSwitch | ||
*/ | ||
type TrackerTransportConfig = { | ||
/** | ||
* Optional. A TrackerConsole instance for logging. | ||
*/ | ||
console?: TrackerConsole; | ||
}; | ||
/** | ||
* The TrackerTransport interface provides a single function to handle one or more TrackerEvents. | ||
* | ||
* TrackerTransport implementations may vary depending on platform. Eg: web: fetch, node: https module, etc | ||
* | ||
* Also, simpler implementations can synchronously send TrackerEvents right away to the Collector while more complex | ||
* ones may leverage Queues, Workers and Storage for asynchronous sending, or batching. | ||
*/ | ||
interface TrackerTransportInterface { | ||
/** | ||
* Optional. A TrackerConsole instance for logging. | ||
*/ | ||
readonly console?: TrackerConsole; | ||
/** | ||
* A name describing the Transport implementation for debugging purposes | ||
*/ | ||
readonly transportName: string; | ||
/** | ||
* Should return if the TrackerTransport can be used. Most useful in combination with TransportSwitch. | ||
*/ | ||
isUsable(): boolean; | ||
/** | ||
* Process one or more TransportableEvent. Eg. Send, queue, store, etc | ||
*/ | ||
handle(...args: NonEmptyArray<TransportableEvent>): Promise<any>; | ||
} | ||
/** | ||
* The Interface of RetryTransportAttempts | ||
*/ | ||
type TrackerTransportRetryAttemptInterface = TrackerTransportConfig & Required<TrackerTransportRetryConfig>; | ||
/** | ||
* A RetryTransportAttempt is a TransportRetry worker. | ||
* TransportRetry creates a RetryTransportAttempt instance whenever its `handle` method is invoked. | ||
*/ | ||
declare class TrackerTransportRetryAttempt implements TrackerTransportRetryAttemptInterface { | ||
readonly console?: TrackerConsole; | ||
// RetryTransport State | ||
readonly transport: TrackerTransportInterface; | ||
readonly maxAttempts: number; | ||
readonly maxRetryMs: number; | ||
readonly minTimeoutMs: number; | ||
readonly maxTimeoutMs: number; | ||
readonly retryFactor: number; | ||
/** | ||
* The list of Events to handle. | ||
*/ | ||
events: NonEmptyArray<TransportableEvent>; | ||
/** | ||
* A list of errors in reverse order. Eg: element 0 is the last error occurred. N-1 is the first. | ||
*/ | ||
errors: Error[]; | ||
/** | ||
* How many times we have tried so far. Used in the calculation of the exponential backoff. | ||
*/ | ||
attemptCount: number; | ||
/** | ||
* Start time is persisted before each attempt and checked before retrying to verify if we exceeded maxRetryMs. | ||
*/ | ||
startTime: number; | ||
constructor(retryTransportInstance: TrackerTransportRetry, events: NonEmptyArray<TransportableEvent>); | ||
/** | ||
* Determines how much time we have to wait based on the number of attempts and the configuration variables | ||
*/ | ||
calculateNextTimeoutMs(attemptCount: number): number; | ||
/** | ||
* Verifies if we exceeded maxAttempts or maxRetryMs before attempting to call the given Transport's `handle` method. | ||
* If promise rejections occur it invokes the `retry` method. | ||
*/ | ||
run(): Promise<any>; | ||
/** | ||
* Handles the given error, waits for the appropriate time and `attempt`s again | ||
*/ | ||
retry(error: Error): Promise<any>; | ||
} | ||
/** | ||
* The configuration object of a RetryTransport. Requires a TrackerTransport instance. | ||
*/ | ||
type TrackerTransportRetryConfig = { | ||
/** | ||
* The TrackerTransport instance to wrap around. Retry Transport will invoke the wrapped TrackerTransport `handle`. | ||
*/ | ||
transport: TrackerTransportInterface; | ||
/** | ||
* Optional. How many times we will retry before giving up. Defaults to 10; | ||
*/ | ||
maxAttempts?: number; | ||
/** | ||
* Optional. How much time we will keep retrying before giving up. Defaults to Infinity; | ||
*/ | ||
maxRetryMs?: number; | ||
/** | ||
* Optional. The following properties are used to calculate the exponential timeouts between attempts. | ||
* | ||
* Given an `attemptCount`, representing how many times we retried so far, this is the formula: | ||
* min( round( minTimeoutMs * pow(retryFactor, attemptCount) ), maxTimeoutMs) | ||
*/ | ||
minTimeoutMs?: number; // defaults to 1000 | ||
maxTimeoutMs?: number; // defaults to Infinity | ||
retryFactor?: number; // defaults to 2 | ||
}; | ||
/** | ||
* A TrackerTransport implementing exponential backoff retries around a TrackerTransport handle method. | ||
* It allows to also specify maximum retry time and number of attempts. | ||
*/ | ||
declare class TrackerTransportRetry implements TrackerTransportInterface { | ||
readonly console?: TrackerConsole; | ||
readonly transportName = "TrackerTransportRetry"; | ||
// RetryTransportConfig | ||
readonly transport: TrackerTransportInterface; | ||
readonly maxAttempts: number; | ||
readonly maxRetryMs: number; | ||
readonly minTimeoutMs: number; | ||
readonly maxTimeoutMs: number; | ||
readonly retryFactor: number; | ||
// A list of attempts that are currently running | ||
attempts: TrackerTransportRetryAttempt[]; | ||
constructor(config: TrackerTransportConfig & TrackerTransportRetryConfig); | ||
/** | ||
* Creates a RetryTransportAttempt for the given Events and runs it. | ||
*/ | ||
handle(...args: NonEmptyArray<TransportableEvent>): Promise<any>; | ||
isUsable(): boolean; | ||
} | ||
/** | ||
* A Local Storage implementation of a TrackerQueueStore. | ||
@@ -278,2 +24,3 @@ */ | ||
} | ||
export { LocalStorageQueueStore }; |
@@ -1,16 +0,2 @@ | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. | ||
Permission to use, copy, modify, and/or distribute this software for any | ||
purpose with or without fee is hereby granted. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */ | ||
function t(t,e,o,n){return new(o||(o=Promise))((function(r,i){function a(t){try{l(n.next(t))}catch(t){i(t)}}function c(t){try{l(n.throw(t))}catch(t){i(t)}}function l(t){var e;t.done?r(t.value):(e=t.value,e instanceof o?e:new o((function(t){t(e)}))).then(a,c)}l((n=n.apply(t,e||[])).next())}))}function e(t,e){var o,n,r,i,a={label:0,sent:function(){if(1&r[0])throw r[1];return r[1]},trys:[],ops:[]};return i={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function c(i){return function(c){return function(i){if(o)throw new TypeError("Generator is already executing.");for(;a;)try{if(o=1,n&&(r=2&i[0]?n.return:i[0]?n.throw||((r=n.return)&&r.call(n),0):n.next)&&!(r=r.call(n,i[1])).done)return r;switch(n=0,r&&(i=[2&i[0],r.value]),i[0]){case 0:case 1:r=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,n=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(r=a.trys,(r=r.length>0&&r[r.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!r||i[1]>r[0]&&i[1]<r[3])){a.label=i[1];break}if(6===i[0]&&a.label<r[1]){a.label=r[1],r=i;break}if(r&&a.label<r[2]){a.label=r[2],a.ops.push(i);break}r[2]&&a.ops.pop(),a.trys.pop();continue}i=e.call(t,a)}catch(t){i=[6,t],n=0}finally{o=r=0}if(5&i[0])throw i[1];return{value:i[0]?i[1]:void 0,done:!0}}([i,c])}}}var o=function(){function o(t){if(this.queueStoreName="LocalStorageQueueStore",this.console=t.console,"undefined"==typeof localStorage)throw new Error("".concat(this.queueStoreName,": failed to initialize: window.localStorage is not available."));this.localStorageKey="objectiv-events-queue-".concat(t.trackerId),this.console&&this.console.log("%c「objectiv:".concat(this.queueStoreName,"」 Initialized"),"font-weight: bold")}return o.prototype.getEventsFromLocalStorage=function(){var t;try{return JSON.parse(null!==(t=localStorage.getItem(this.localStorageKey))&&void 0!==t?t:"[]")}catch(t){this.console&&this.console.error("%c「objectiv:".concat(this.queueStoreName,"」 Failed to parse Events from localStorage: ").concat(t),"font-weight: bold")}return[]},o.prototype.writeEventsToLocalStorage=function(t){try{localStorage.setItem(this.localStorageKey,JSON.stringify(t))}catch(t){this.console&&this.console.error("%c「objectiv:".concat(this.queueStoreName,"」 Failed to write Events to localStorage: ").concat(t),"font-weight: bold")}},Object.defineProperty(o.prototype,"length",{get:function(){return this.getEventsFromLocalStorage().length},enumerable:!1,configurable:!0}),o.prototype.read=function(o,n){return t(this,void 0,void 0,(function(){var t;return e(this,(function(e){return t=this.getEventsFromLocalStorage(),n&&(t=t.filter(n)),[2,t.slice(0,o)]}))}))},o.prototype.write=function(){for(var o=[],n=0;n<arguments.length;n++)o[n]=arguments[n];return t(this,void 0,void 0,(function(){var t;return e(this,(function(e){return(t=this.getEventsFromLocalStorage()).push.apply(t,o),this.writeEventsToLocalStorage(t),[2]}))}))},o.prototype.delete=function(o){return t(this,void 0,void 0,(function(){var t;return e(this,(function(e){return t=(t=this.getEventsFromLocalStorage()).filter((function(t){return!o.includes(t.id)})),this.writeEventsToLocalStorage(t),[2]}))}))},o.prototype.clear=function(){return t(this,void 0,void 0,(function(){return e(this,(function(t){return this.writeEventsToLocalStorage([]),[2]}))}))},o}();export{o as LocalStorageQueueStore}; | ||
//# sourceMappingURL=index.js.map | ||
var n=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var g=o=>n(o,"__esModule",{value:!0});var S=(o,e)=>{for(var t in e)n(o,t,{get:e[t],enumerable:!0})},u=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of c(e))!l.call(o,a)&&(t||a!=="default")&&n(o,a,{get:()=>e[a],enumerable:!(r=i(e,a))||r.enumerable});return o};var h=(o=>(e,t)=>o&&o.get(e)||(t=u(g({}),e,1),o&&o.set(e,t),t))(typeof WeakMap!="undefined"?new WeakMap:0);var m={};S(m,{LocalStorageQueueStore:()=>s});var s=class{constructor(e){this.queueStoreName="LocalStorageQueueStore";if(this.console=e.console,typeof localStorage>"u")throw new Error(`${this.queueStoreName}: failed to initialize: window.localStorage is not available.`);this.localStorageKey=`objectiv-events-queue-${e.trackerId}`,this.console&&this.console.log(`%c\uFF62objectiv:${this.queueStoreName}\uFF63 Initialized`,"font-weight: bold")}getEventsFromLocalStorage(){var e;try{return JSON.parse((e=localStorage.getItem(this.localStorageKey))!=null?e:"[]")}catch(t){this.console&&this.console.error(`%c\uFF62objectiv:${this.queueStoreName}\uFF63 Failed to parse Events from localStorage: ${t}`,"font-weight: bold")}return[]}writeEventsToLocalStorage(e){try{localStorage.setItem(this.localStorageKey,JSON.stringify(e))}catch(t){this.console&&this.console.error(`%c\uFF62objectiv:${this.queueStoreName}\uFF63 Failed to write Events to localStorage: ${t}`,"font-weight: bold")}}get length(){return this.getEventsFromLocalStorage().length}async read(e,t){let r=this.getEventsFromLocalStorage();return t&&(r=r.filter(t)),r.slice(0,e)}async write(...e){let t=this.getEventsFromLocalStorage();t.push(...e),this.writeEventsToLocalStorage(t)}async delete(e){let t=this.getEventsFromLocalStorage();t=t.filter(r=>!e.includes(r.id)),this.writeEventsToLocalStorage(t)}async clear(){this.writeEventsToLocalStorage([])}};module.exports=h(m);0&&(module.exports={LocalStorageQueueStore}); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@objectiv/queue-local-storage", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"description": "A TrackerQueueStore based on localStorage API", | ||
@@ -29,10 +29,17 @@ "license": "Apache-2.0", | ||
], | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"module": "dist/index.js", | ||
"main": "./dist/index.js", | ||
"module": "./dist/index.mjs", | ||
"types": "./dist/index.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"exports": { | ||
".": { | ||
"require": "./dist/index.js", | ||
"import": "./dist/index.mjs", | ||
"types": "./dist/index.d.ts" | ||
} | ||
}, | ||
"scripts": { | ||
"build": "rollup -c --silent --failAfterWarnings", | ||
"build": "tsup src/index.ts --format cjs,esm --minify --dts --sourcemap --clean", | ||
"prettify": "prettier --write .", | ||
@@ -48,5 +55,3 @@ "tsc": "tsc --noEmit", | ||
"devDependencies": { | ||
"@objectiv/testing-tools": "^0.0.7", | ||
"@rollup/plugin-commonjs": "^21.0.1", | ||
"@rollup/plugin-node-resolve": "^13.1.1", | ||
"@objectiv/testing-tools": "^0.0.8", | ||
"@types/jest": "^27.0.3", | ||
@@ -56,14 +61,10 @@ "jest": "^27.4.5", | ||
"prettier": "^2.5.1", | ||
"rollup": "^2.61.1", | ||
"rollup-plugin-filesize": "^9.1.1", | ||
"rollup-plugin-sizes": "^1.0.4", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"rollup-plugin-ts": "^2.0.4", | ||
"shx": "^0.3.3", | ||
"ts-jest": "^27.1.2", | ||
"typescript": "^4.5.4" | ||
"tsup": "^5.11.13", | ||
"typescript": "^4.5.5" | ||
}, | ||
"dependencies": { | ||
"@objectiv/tracker-core": "~0.0.7" | ||
"@objectiv/tracker-core": "~0.0.8" | ||
} | ||
} |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
9
7
14575
37
1