Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Index.res
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
%%raw("import './index.css'")

Sentry.initiateSentry(~dsn=GlobalVars.sentryDSN)
ServiceWorkerHelpers.registerSW()->ignore

let app = switch ReactDOM.querySelector("#app") {
| Some(container) =>
Expand Down
274 changes: 207 additions & 67 deletions src/Utilities/LoggerUtils.res
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,51 @@ let toSnakeCaseWithSeparator = (str, separator) => {
)
}

let logFileToObj = (logFile: HyperLoggerTypes.logFile) => {
let getStringFromBool = val => val ? "true" : "false"
[
("timestamp", logFile.timestamp->JSON.Encode.string),
(
"log_type",
switch logFile.logType {
| DEBUG => "DEBUG"
| INFO => "INFO"
| ERROR => "ERROR"
| WARNING => "WARNING"
| SILENT => "SILENT"
}->JSON.Encode.string,
),
("component", "WEB"->JSON.Encode.string),
(
"category",
switch logFile.category {
| API => "API"
| USER_ERROR => "USER_ERROR"
| USER_EVENT => "USER_EVENT"
| MERCHANT_EVENT => "MERCHANT_EVENT"
}->JSON.Encode.string,
),
("source", logFile.source->convertToScreamingSnakeCase->JSON.Encode.string),
("version", logFile.version->JSON.Encode.string),
("value", logFile.value->JSON.Encode.string),
// ("internal_metadata", logFile.internalMetadata->JSON.Encode.string),
("session_id", logFile.sessionId->JSON.Encode.string),
("merchant_id", logFile.merchantId->JSON.Encode.string),
("payment_id", logFile.paymentId->JSON.Encode.string),
("app_id", logFile.appId->JSON.Encode.string),
("platform", logFile.platform->convertToScreamingSnakeCase->JSON.Encode.string),
("user_agent", logFile.userAgent->JSON.Encode.string),
("event_name", logFile.eventName->eventNameToStrMapper->JSON.Encode.string),
("browser_name", logFile.browserName->convertToScreamingSnakeCase->JSON.Encode.string),
("browser_version", logFile.browserVersion->JSON.Encode.string),
("latency", logFile.latency->JSON.Encode.string),
("first_event", logFile.firstEvent->getStringFromBool->JSON.Encode.string),
("payment_method", logFile.paymentMethod->convertToScreamingSnakeCase->JSON.Encode.string),
]
->Dict.fromArray
->JSON.Encode.object
}

let defaultLoggerConfig: HyperLoggerTypes.loggerMake = {
sendLogs: () => (),
setClientSecret: _x => (),
Expand Down Expand Up @@ -131,106 +176,201 @@ let defaultLoggerConfig: HyperLoggerTypes.loggerMake = {

let saveLogsToIndexedDB = (logs: array<HyperLoggerTypes.logFile>) => {
Promise.make((resolve, reject) => {
let request = openDBAndGetRequest(~dbName="HyperLogger", ~objectStoreName="logs")
switch openDBAndGetRequest(~dbName="HyperLogger", ~objectStoreName="logs") {
| Some(request) =>
request->OpenDBRequest.onsuccess(_ => {
let db = OpenDBRequest.result(request)

if logs->Array.length > 0 {
let transaction = db->DB.transaction(["logs"], "readwrite")
let store = transaction->Transaction.objectStore("logs")

transaction->Transaction.oncomplete(
_ => {
db->DB.close
resolve()
},
)

transaction->Transaction.onerror(
_ => {
db->DB.close
reject()
},
)

logs->Array.forEach(
log => {
let _ = store->ObjectStore.put(log)
},
)
} else {
db->DB.close
reject()
}
})

request->OpenDBRequest.onsuccess(_ => {
let db = OpenDBRequest.result(request)
request->OpenDBRequest.onerror(_ => {
reject()
})
| None => reject()
}
})
}

let retrieveLogsFromIndexedDB = () => {
Promise.make((resolve, reject) => {
switch openDBAndGetRequest(~dbName="HyperLogger", ~objectStoreName="logs") {
| Some(request) =>
request->OpenDBRequest.onsuccess(_ => {
let db = OpenDBRequest.result(request)
let transaction = db->DB.transaction(["logs"], "readonly")
let store = transaction->Transaction.objectStore("logs")
let getAllRequest = store->ObjectStore.getAll

getAllRequest->Request.onsuccess(
_ => {
let result = Request.result(getAllRequest)
db->DB.close
resolve(result)
},
)

getAllRequest->Request.onerror(
_ => {
db->DB.close
reject([])
},
)
})

request->OpenDBRequest.onerror(_ => {
reject([])
})
| None => reject([])
}
})
}

if logs->Array.length > 0 {
let clearLogsFromIndexedDB = () => {
Promise.make((resolve, reject) => {
switch openDBAndGetRequest(~dbName="HyperLogger", ~objectStoreName="logs") {
| Some(request) =>
request->OpenDBRequest.onsuccess(_ => {
let db = OpenDBRequest.result(request)
let transaction = db->DB.transaction(["logs"], "readwrite")
let store = transaction->Transaction.objectStore("logs")
let clearRequest = store->ObjectStore.clear

transaction->Transaction.oncomplete(
clearRequest->Request.onsuccess(
_ => {
db->DB.close
resolve()
},
)

transaction->Transaction.onerror(
clearRequest->Request.onerror(
_ => {
db->DB.close
reject()
},
)
})

logs->Array.forEach(
log => {
let _ = store->ObjectStore.put(log)
},
)
} else {
db->DB.close
request->OpenDBRequest.onerror(_ => {
reject()
}
})

request->OpenDBRequest.onerror(_ => {
reject()
})
})
| None => reject()
}
})
}

let retrieveLogsFromIndexedDB = () => {
let retrieveAndClearLogsFromIndexedDB = () => {
Promise.make((resolve, reject) => {
let request = openDBAndGetRequest(~dbName="HyperLogger", ~objectStoreName="logs")
switch openDBAndGetRequest(~dbName="HyperLogger", ~objectStoreName="logs") {
| Some(request) =>
request->OpenDBRequest.onsuccess(_ => {
let db = OpenDBRequest.result(request)
let transaction = db->DB.transaction(["logs"], "readwrite")
let store = transaction->Transaction.objectStore("logs")
let getAllRequest = store->ObjectStore.getAll

request->OpenDBRequest.onsuccess(_ => {
let db = OpenDBRequest.result(request)
let transaction = db->DB.transaction(["logs"], "readonly")
let store = transaction->Transaction.objectStore("logs")
let getAllRequest = store->ObjectStore.getAll
getAllRequest->Request.onsuccess(
_ => {
let result = Request.result(getAllRequest)
let _ = store->ObjectStore.clear

getAllRequest->Request.onsuccess(
_ => {
let result = Request.result(getAllRequest)
db->DB.close
resolve(result)
},
)
transaction->Transaction.oncomplete(
_ => {
db->DB.close
resolve(result)
},
)

getAllRequest->Request.onerror(
_ => {
db->DB.close
reject([])
},
)
})

request->OpenDBRequest.onerror(_ => {
reject([])
})
transaction->Transaction.onerror(
_ => {
db->DB.close
reject([])
},
)
},
)

getAllRequest->Request.onerror(
_ => {
db->DB.close
reject([])
},
)
})

request->OpenDBRequest.onerror(_ => {
reject([])
})
| None => reject([])
}
})
}

let clearLogsFromIndexedDB = () => {
let saveRawLogsToIndexedDB = (logs: array<JSON.t>) => {
Promise.make((resolve, reject) => {
let request = openDBAndGetRequest(~dbName="HyperLogger", ~objectStoreName="logs")
if logs->Array.length === 0 {
resolve()
} else {
switch openDBAndGetRequest(~dbName="HyperLogger", ~objectStoreName="logs") {
| Some(request) =>
request->OpenDBRequest.onsuccess(_ => {
let db = OpenDBRequest.result(request)
let transaction = db->DB.transaction(["logs"], "readwrite")
let store = transaction->Transaction.objectStore("logs")

request->OpenDBRequest.onsuccess(_ => {
let db = OpenDBRequest.result(request)
let transaction = db->DB.transaction(["logs"], "readwrite")
let store = transaction->Transaction.objectStore("logs")
let clearRequest = store->ObjectStore.clear
transaction->Transaction.oncomplete(
_ => {
db->DB.close
resolve()
},
)

clearRequest->Request.onsuccess(
_ => {
db->DB.close
resolve()
},
)
transaction->Transaction.onerror(
_ => {
db->DB.close
reject()
},
)

clearRequest->Request.onerror(
_ => {
db->DB.close
reject()
},
)
})
logs->Array.forEach(
log => {
let _ = store->ObjectStore.put(log)
},
)
})

request->OpenDBRequest.onerror(_ => {
reject()
})
request->OpenDBRequest.onerror(_ => {
reject()
})
| None => reject()
}
}
})
}

Expand Down
23 changes: 23 additions & 0 deletions src/Window.res
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,26 @@ external removeEventListener: (string, 'ev => unit) => unit = "removeEventListen
@val external windowOpen: (string, string, string) => Nullable.t<window> = "open"
@val external isSecureContext: bool = "isSecureContext"

type serviceWorkerRegistration

module ServiceWorker = {
type t
@send
external postMessage: (t, {..}) => unit = "postMessage"
@get
external scriptURL: t => string = "scriptURL"
}

module ServiceWorkerContainer = {
type t

@get
external controller: t => Nullable.t<ServiceWorker.t> = "controller"

@send
external register: (t, string) => promise<serviceWorkerRegistration> = "register"
}

/* Module Definitions */
module Navigator = {
@val @scope("navigator")
Expand All @@ -118,6 +138,9 @@ module Navigator = {

@val @scope("navigator")
external sendBeacon: (string, string) => unit = "sendBeacon"

@val @scope(("window", "navigator"))
external serviceWorker: option<ServiceWorkerContainer.t> = "serviceWorker"
}

module Location = {
Expand Down
2 changes: 1 addition & 1 deletion src/hyper-log-catcher/ErrorBoundary.res
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ module ErrorCard = {
) => {
let beaconApiCall = data => {
if data->Array.length > 0 {
let logData = data->Array.map(HyperLogger.logFileToObj)->JSON.Encode.array->JSON.stringify
let logData = data->Array.map(LoggerUtils.logFileToObj)->JSON.Encode.array->JSON.stringify
Window.Navigator.sendBeacon(GlobalVars.logEndpoint, logData)
}
}
Expand Down
Loading
Loading