Skip to content

Commit 41295ea

Browse files
committed
WIP - Simplified storage
1 parent 4267f07 commit 41295ea

26 files changed

+332
-612
lines changed

packages/browser/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,17 @@
3636
"scripts": {
3737
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --minify --sourcemap --target=es2020 --format=esm --outfile=dist/index.min.js",
3838
"watch": "tsc -p tsconfig.json -w --preserveWatchOutput",
39-
"test": ""
39+
"test": "jest"
4040
},
4141
"sideEffects": [
4242
"dist/index.js"
4343
],
4444
"devDependencies": {
45-
"esbuild": "0.8.49"
45+
"@jest/globals": "26.6.2",
46+
"esbuild": "0.8.49",
47+
"jest": "26.6.3",
48+
"jest-ts-webcompat-resolver": "1.0.0",
49+
"ts-jest": "26.5.1"
4650
},
4751
"dependencies": {
4852
"@exceptionless/core": "2.0.0-pre",

packages/browser/src/BrowserExceptionlessClient.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
import { ExceptionlessClient } from "@exceptionless/core";
1+
import {
2+
Configuration,
3+
ExceptionlessClient
4+
} from "@exceptionless/core";
25

3-
import { BrowserConfiguration } from "./configuration/BrowserConfiguration.js";
46
import { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js";
57
import { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js";
68
import { BrowserWrapFunctions } from "./plugins/BrowserWrapFunctions.js";
79
import { BrowserErrorParser } from "./services/BrowserErrorParser.js";
810
import { BrowserModuleCollector } from "./services/BrowserModuleCollector.js";
911
import { BrowserRequestInfoCollector } from "./services/BrowserRequestInfoCollector.js";
12+
import { BrowserLocalStorage } from "./storage/BrowserLocalStorage.js";
1013
import { BrowserFetchSubmissionClient } from "./submission/BrowserFetchSubmissionClient.js";
1114

1215
export class BrowserExceptionlessClient extends ExceptionlessClient {
13-
constructor() {
14-
super(new BrowserConfiguration());
15-
}
16-
17-
public async startup(configurationOrApiKey?: (config: BrowserConfiguration) => void | string): Promise<void> {
16+
public async startup(configurationOrApiKey?: (config: Configuration) => void | string): Promise<void> {
1817
const config = this.config;
1918
if (configurationOrApiKey) {
20-
config.addPlugin(new BrowserGlobalHandlerPlugin());
21-
config.addPlugin(new BrowserLifeCyclePlugin());
22-
config.addPlugin(new BrowserWrapFunctions());
23-
19+
config.services.storage = new BrowserLocalStorage();
2420
config.services.errorParser = new BrowserErrorParser();
2521
config.services.moduleCollector = new BrowserModuleCollector();
2622
config.services.requestInfoCollector = new BrowserRequestInfoCollector();
2723
config.services.submissionClient = new BrowserFetchSubmissionClient(config);
24+
25+
config.addPlugin(new BrowserGlobalHandlerPlugin());
26+
config.addPlugin(new BrowserLifeCyclePlugin());
27+
config.addPlugin(new BrowserWrapFunctions());
2828
}
2929

3030
await super.startup(configurationOrApiKey);

packages/browser/src/configuration/BrowserConfiguration.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

packages/browser/src/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
export { BrowserConfiguration } from "./configuration/BrowserConfiguration.js";
21
export { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js";
32
export { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js";
43
export { BrowserWrapFunctions } from "./plugins/BrowserWrapFunctions.js";
54
export { BrowserErrorParser } from "./services/BrowserErrorParser.js";
65
export { BrowserModuleCollector } from "./services/BrowserModuleCollector.js";
76
export { BrowserRequestInfoCollector } from "./services/BrowserRequestInfoCollector.js";
87
export { BrowserLocalStorage } from "./storage/BrowserLocalStorage.js";
9-
export { BrowserLocalStorageProvider as BrowserStorageProvider } from "./storage/BrowserLocalStorageProvider.js";
108
export { BrowserFetchSubmissionClient } from "./submission/BrowserFetchSubmissionClient.js";
119
export { BrowserExceptionlessClient } from "./BrowserExceptionlessClient.js";
1210

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,50 @@
1-
import { KeyValueStorageBase } from "@exceptionless/core";
2-
3-
export class BrowserLocalStorage extends KeyValueStorageBase {
4-
private prefix: string;
5-
6-
public static isAvailable(): boolean {
7-
try {
8-
const storage = window.localStorage;
9-
const x = "__storage_test__";
10-
storage.setItem(x, x);
11-
storage.removeItem(x);
12-
return true;
13-
} catch (e) {
14-
return false;
15-
}
1+
import { IStorage } from "@exceptionless/core";
2+
3+
export class BrowserLocalStorage implements IStorage {
4+
constructor(private prefix: string = "exceptionless:") { }
5+
6+
public length(): Promise<number> {
7+
return Promise.resolve(this.getKeys().length);
168
}
179

18-
constructor(namespace: string, prefix: string = "com.exceptionless.", maxItems: number = 20) {
19-
super(maxItems);
10+
public clear(): Promise<void> {
11+
for (const key of this.getKeys()) {
12+
window.localStorage.removeItem(key);
13+
}
14+
15+
return Promise.resolve();
16+
}
2017

21-
this.prefix = prefix + namespace + "-";
18+
public getItem(key: string): Promise<string> {
19+
return Promise.resolve(window.localStorage.getItem(this.getKey(key)));
2220
}
2321

24-
public writeValue(key: string, value: string): void {
25-
window.localStorage.setItem(key, value);
22+
public key(index: number): Promise<string> {
23+
const keys = this.getKeys();
24+
return Promise.resolve(keys[index]);
2625
}
2726

28-
public readValue(key: string): string {
29-
return window.localStorage.getItem(key);
27+
public keys(): Promise<string[]> {
28+
return Promise.resolve(this.getKeys());
3029
}
3130

32-
public removeValue(key: string): void {
33-
window.localStorage.removeItem(key);
31+
public removeItem(key: string): Promise<void> {
32+
window.localStorage.removeItem(this.getKey(key));
33+
return Promise.resolve();
3434
}
3535

36-
public getAllKeys(): string[] {
37-
return Object.keys(window.localStorage)
38-
.filter((key) => key.indexOf(this.prefix) === 0);
36+
public setItem(key: string, value: string): Promise<void> {
37+
window.localStorage.setItem(this.getKey(key), value);
38+
return Promise.resolve();
3939
}
4040

41-
public getKey(timestamp: number): string {
42-
return this.prefix + timestamp;
41+
private getKeys(): string[] {
42+
return Object.keys(window.localStorage)
43+
.filter(key => key.startsWith(this.prefix))
44+
.map(key => key?.substr(this.prefix.length));
4345
}
4446

45-
public getTimestamp(key: string): number {
46-
return parseInt(key.substr(this.prefix.length), 10);
47+
private getKey(key: string): string {
48+
return this.prefix + key;
4749
}
4850
}

packages/browser/src/storage/BrowserLocalStorageProvider.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { describeStorage } from "@exceptionless/core/test/storage/InMemoryStorage.test";
2+
import { IStorage } from "@exceptionless/core/src/storage/IStorage";
3+
import { BrowserLocalStorage } from "../../src/storage/BrowserLocalStorage.js";
4+
5+
function resetLocalStorage() {
6+
localStorage.clear();
7+
}
8+
9+
describeStorage(
10+
"BrowserLocalStorage",
11+
(): IStorage => new BrowserLocalStorage(),
12+
resetLocalStorage,
13+
resetLocalStorage
14+
);

packages/core/src/ExceptionlessClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class ExceptionlessClient {
2525
configurationOrApiKey(this.config);
2626
}
2727

28-
this.config.services.queue.onEventsPosted(() => this.updateSettingsTimer());
28+
this.config.services.queue.onEventsPosted(() => Promise.resolve(this.updateSettingsTimer()));
2929
}
3030

3131
this.updateSettingsTimer(configurationOrApiKey ? 5000 : 0);
@@ -208,7 +208,7 @@ export class ExceptionlessClient {
208208
ev.date = new Date();
209209
}
210210

211-
config.services.queue.enqueue(ev);
211+
await config.services.queue.enqueue(ev);
212212

213213
if (ev.reference_id && ev.reference_id.length > 0) {
214214
context.log.info(`Setting last reference id "${ev.reference_id}"`);

packages/core/src/configuration/Configuration.ts

Lines changed: 14 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -85,30 +85,26 @@ export class Configuration {
8585
/**
8686
* The API key that will be used when sending events to the server.
8787
* @type {string}
88-
* @private
8988
*/
90-
private _apiKey: string;
89+
public apiKey: string;
9190

9291
/**
9392
* The server url that all events will be sent to.
9493
* @type {string}
95-
* @private
9694
*/
9795
private _serverUrl: string = "https://collector.exceptionless.io";
9896

9997
/**
10098
* The config server url that all configuration will be retrieved from.
10199
* @type {string}
102-
* @private
103100
*/
104-
private _configServerUrl: string = "https://config.exceptionless.io";
101+
public configServerUrl: string = "https://config.exceptionless.io";
105102

106103
/**
107104
* The heartbeat server url that all heartbeats will be sent to.
108105
* @type {string}
109-
* @private
110106
*/
111-
private _heartbeatServerUrl: string = "https://heartbeat.exceptionless.io";
107+
public heartbeatServerUrl: string = "https://heartbeat.exceptionless.io";
112108

113109
/**
114110
* How often the client should check for updated server settings when idle. The default is every 2 minutes.
@@ -153,22 +149,6 @@ export class Configuration {
153149
*/
154150
private _subscribers: Array<(config: Configuration) => void> = [];
155151

156-
/**
157-
* The API key that will be used when sending events to the server.
158-
* @returns {string}
159-
*/
160-
public get apiKey(): string {
161-
return this._apiKey;
162-
}
163-
164-
/**
165-
* The API key that will be used when sending events to the server.
166-
* @param value
167-
*/
168-
public set apiKey(value: string) {
169-
this._apiKey = value || null;
170-
}
171-
172152
/**
173153
* Returns true if the apiKey is valid.
174154
* @returns {boolean}
@@ -192,44 +172,8 @@ export class Configuration {
192172
public set serverUrl(value: string) {
193173
if (value) {
194174
this._serverUrl = value;
195-
this._configServerUrl = value;
196-
this._heartbeatServerUrl = value;
197-
}
198-
}
199-
200-
/**
201-
* The config server url that all configuration will be retrieved from.
202-
* @returns {string}
203-
*/
204-
public get configServerUrl(): string {
205-
return this._configServerUrl;
206-
}
207-
208-
/**
209-
* The config server url that all configuration will be retrieved from.
210-
* @param value
211-
*/
212-
public set configServerUrl(value: string) {
213-
if (value) {
214-
this._configServerUrl = value;
215-
}
216-
}
217-
218-
/**
219-
* The heartbeat server url that all heartbeats will be sent to.
220-
* @returns {string}
221-
*/
222-
public get heartbeatServerUrl(): string {
223-
return this._heartbeatServerUrl;
224-
}
225-
226-
/**
227-
* The heartbeat server url that all heartbeats will be sent to.
228-
* @param value
229-
*/
230-
public set heartbeatServerUrl(value: string) {
231-
if (value) {
232-
this._heartbeatServerUrl = value;
175+
this.configServerUrl = value;
176+
this.heartbeatServerUrl = value;
233177
}
234178
}
235179

@@ -546,10 +490,7 @@ export class Configuration {
546490
public setUserIdentity(userInfo: UserInfo): void;
547491
public setUserIdentity(identity: string): void;
548492
public setUserIdentity(identity: string, name: string): void;
549-
public setUserIdentity(
550-
userInfoOrIdentity: UserInfo | string,
551-
name?: string,
552-
): void {
493+
public setUserIdentity(userInfoOrIdentity: UserInfo | string, name?: string): void {
553494
const userInfo: UserInfo = typeof userInfoOrIdentity !== "string"
554495
? userInfoOrIdentity
555496
: { identity: userInfoOrIdentity, name };
@@ -589,6 +530,14 @@ export class Configuration {
589530
this.addPlugin(new ReferenceIdPlugin());
590531
}
591532

533+
534+
/**
535+
* Writes events to storage on enqueue and removes them when submitted. (Defaults to false)
536+
* This setting only works in environments that supports persisted storage.
537+
* There is also a performance penalty of extra IO/serialization.
538+
*/
539+
public usePersistedQueueStorage: boolean = false;
540+
592541
// TODO: Support a min log level.
593542
public useDebugLogger(): void {
594543
this.services.log = new ConsoleLog();

0 commit comments

Comments
 (0)