This is an automated email from the ASF dual-hosted git repository. jky pushed a commit to branch mv3-migrate in repository https://gitbox.apache.org/repos/asf/flagon.git
commit c09677d25e184bf3baf388c8f1e9fb71a24b27c2 Author: Jason Young <jk...@pm.me> AuthorDate: Tue Jun 24 15:47:25 2025 -0700 Move from husky to pre-commit --- .husky/pre-commit | 83 -------- .pre-commit-config.yaml | 30 +++ eslint.config.js | 34 --- products/userale/eslint.config.js | 50 +++++ products/userale/package.json | 11 +- .../flagon-userale-ext/src/background/index.ts | 66 +++--- .../src/background/messages/config_change.ts | 22 +- .../flagon-userale-ext/src/background/ports/log.ts | 34 +-- .../packages/flagon-userale-ext/src/content.ts | 40 ++-- .../flagon-userale-ext/src/options/logging.tsx | 2 +- .../packages/flagon-userale-ext/src/popup.tsx | 14 +- .../flagon-userale-ext/src/utils/messaging.ts | 16 +- .../flagon-userale-ext/src/utils/storage.ts | 6 +- .../packages/flagon-userale-ext/tsconfig.json | 26 +-- .../userale/packages/flagon-userale/.eslintrc.json | 30 --- .../packages/flagon-userale/.husky/pre-commit | 80 -------- .../flagon-userale/build/attachHandlers.d.ts | 81 ++++++++ .../packages/flagon-userale/build/configure.d.ts | 46 +++++ .../flagon-userale/build/getInitialSettings.d.ts | 21 ++ .../packages/flagon-userale/build/main.d.ts | 228 ++------------------- .../packages/flagon-userale/build/main.global.js | 208 ++++--------------- .../flagon-userale/build/main.global.js.map | 2 +- .../userale/packages/flagon-userale/build/main.mjs | 227 ++++---------------- .../packages/flagon-userale/build/main.mjs.map | 2 +- .../packages/flagon-userale/build/packageLogs.d.ts | 106 ++++++++++ .../packages/flagon-userale/build/sendLogs.d.ts | 26 +++ .../flagon-userale/build/utils/auth/index.d.ts | 31 +++ .../flagon-userale/build/utils/headers/index.d.ts | 31 +++ .../packages/flagon-userale/build/utils/index.d.ts | 3 + .../packages/flagon-userale/eslint.config.ts | 29 --- .../example/react-app-example/src/App.js | 43 ++-- .../example/react-app-example/src/index.js | 12 +- .../example/react-app-example/src/setupTests.js | 2 +- .../packages/flagon-userale/example/test-client.js | 32 +++ .../userale/packages/flagon-userale/package.json | 18 +- .../flagon-userale/src/getInitialSettings.ts | 76 +++---- .../userale/packages/flagon-userale/src/main.ts | 35 ++-- .../packages/flagon-userale/src/sendLogs.ts | 4 +- .../packages/flagon-userale/test/globals.d.ts | 2 + .../test/{jest.config.js => jest.config.ts} | 8 + .../test/spec/attachHandlers.spec.ts | 4 +- .../flagon-userale/test/spec/sendLogs.spec.ts | 22 +- .../userale/packages/flagon-userale/tsconfig.json | 67 ++---- .../packages/flagon-userale/tsconfig.test.json | 9 + .../userale/packages/flagon-userale/tsup.config.js | 2 +- .../test/spec/fixtures/extension.fixture.ts | 2 +- products/userale/tsconfig.base.json | 18 ++ products/userale/tsconfig.json | 30 +-- 48 files changed, 858 insertions(+), 1113 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index a06fc79..0000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -npm run lint -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# http://www.apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -sound() { -echo '\a' -} - -echo "Running pre-commit hooks..." - -# Check Prettier standards -npm run format || -( - sound - echo "❌ Prettier Check Failed. Run npm run format, add changes and try commit again."; - exit 1; -) - -# Check ESLint Standards -npm run lint || -( - sound - echo "❌ ESLint Check Failed. Make the required changes listed above, add changes and try to commit again." - exit 1; -) - -# # Check types -# npm run check-types || -# ( -# sound -# echo "❌ Typescript Check Failed. Make the required changes listed above, add changes and try to commit again." -# exit 1; -# ) - -# # If everything passes... Now we can commit -# echo "✅ Checks passed, trying to build..." - -# "npm" run build || -# ( -# sound -# echo "❌ Build failed, check errors." -# exit 1; -# ) - -# echo "✅ Successful build, running tests..." -# # After build, run unit tests -# # Right now, runs all tests. Later scope to just unit tets, we can add e2e/integration as github actions on merge -# npm run test || -# ( -# sound -# echo "❌ Tests failed: View the logs to see what broke and fix it before re-committing." -# exit 1; -# ) - -# # After build, check license headers -# # These should be fixed in the postbuild step, but if a new filetype -# # emerges, this should catch it. -# npm run license:check || -# ( -# sound -# echo "❌ License check failed: View the logs to see what broke and fix it before re-committing." -# exit 1; -# ) - -# If everything passes... Now we can commit -echo '✅ All tests passed' \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..1b87166 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,30 @@ +repos: + - repo: local + hooks: + - id: userale-format + name: Prettier Format Check (userale) + entry: bash -c 'cd products/userale && pnpm run format' + language: system + pass_filenames: false + files: ^products/userale/ + + - id: userale-lint + name: ESLint Check (userale) + entry: bash -c 'cd products/userale && pnpm run lint' + language: system + pass_filenames: false + files: ^products/userale/ + + - id: userale-build + name: Build Check (userale) + entry: bash -c 'cd products/userale && pnpm run build' + language: system + pass_filenames: false + files: ^products/userale/ + + - id: userale-test + name: Tests (userale) + entry: bash -c 'cd products/userale && pnpm run test' + language: system + pass_filenames: false + files: ^products/userale/ diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index cd685ff..0000000 --- a/eslint.config.js +++ /dev/null @@ -1,34 +0,0 @@ -// eslint.config.js -import js from '@eslint/js' -import ts from '@typescript-eslint/eslint-plugin' -import parser from '@typescript-eslint/parser' - -export default [ - js.configs.recommended, - { - files: ['**/*.ts'], - languageOptions: { - parser, - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - // project: './tsconfig.json', - }, - }, - plugins: { - '@typescript-eslint': ts, - }, - rules: { - 'no-unused-vars': 'off', - - '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], - 'no-undef': 'off', - }, - }, - { - files: ['**/*.js'], - rules: { - 'no-unused-vars': 'warn', - }, - }, -] diff --git a/products/userale/eslint.config.js b/products/userale/eslint.config.js new file mode 100644 index 0000000..c9ae0c6 --- /dev/null +++ b/products/userale/eslint.config.js @@ -0,0 +1,50 @@ +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import pluginJest from 'eslint-plugin-jest'; + +export default [ + js.configs.recommended, + ...tseslint.configs.recommended, + { + files: ['**/*.{ts,tsx,js,jsx}'], + languageOptions: { + parser: tseslint.parser, + sourceType: 'module', + globals: { + window: 'readonly', + document: 'readonly', + navigator: 'readonly', + console: 'readonly', + }, + }, + plugins: { + '@typescript-eslint': tseslint.plugin, + }, + rules: { + 'no-cond-assign': 'warn', + 'no-constant-condition': 'warn', + 'no-unused-vars': 'warn', + '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-explicit-any': 'warn', + }, + }, + { + files: ['test/**/*.{ts,tsx,js,jsx}'], + plugins: { + jest: pluginJest, + }, + languageOptions: { + globals: { + describe: 'readonly', + test: 'readonly', + expect: 'readonly', + beforeEach: 'readonly', + afterEach: 'readonly', + jest: 'readonly', + }, + }, + rules: { + // Optional Jest-specific rules + }, + }, +]; diff --git a/products/userale/package.json b/products/userale/package.json index f3b5674..016a4df 100644 --- a/products/userale/package.json +++ b/products/userale/package.json @@ -3,6 +3,8 @@ "private": true, "version": "1.0.0", "scripts": { + "format": "prettier --ignore-path .gitignore --write 'packages/**/{src,test}/**/*.{ts,js,tsx,jsx}'", + "lint": "eslint 'packages/**/src/**/*.{ts,js,tsx,jsx}' --fix", "build": "pnpm -r run build", "test": "playwright test -c ./test/playwright.config.ts && pnpm -r test", "pretest": "npx playwright install", @@ -10,14 +12,21 @@ "example:watch": "nodemon -w ./example/server example/server/server.js" }, "devDependencies": { + "@eslint/js": "^9.29.0", + "@ianvs/prettier-plugin-sort-imports": "4.1.1", "@playwright/test": "^1.52.0", "@types/node": "^22.15.30", "body-parser": "^1.20.2", + "eslint": "9.29.0", + "eslint-plugin-jest": "^29.0.1", "express": "^4.18.2", "flagon-userale": "workspace:flagon-userale", "jsonschema": "^1.4.1", - "pnpm": "^10.0.0", "nodemon": "^3.0.2", + "pnpm": "^10.0.0", + "prettier": "3.6.0", + "typescript": "^5.8.3", + "typescript-eslint": "^7.8.0", "ws": "^8.18.0" } } \ No newline at end of file diff --git a/products/userale/packages/flagon-userale-ext/src/background/index.ts b/products/userale/packages/flagon-userale-ext/src/background/index.ts index 6e8df51..d3f1b35 100644 --- a/products/userale/packages/flagon-userale-ext/src/background/index.ts +++ b/products/userale/packages/flagon-userale-ext/src/background/index.ts @@ -1,35 +1,41 @@ -import { getStoredOptions } from "~/utils/storage"; -import { setOptions } from "./messages/config_change"; -import { sendToContent } from "~utils/messaging"; +import { getStoredOptions } from "~/utils/storage" +import { sendToContent } from "~utils/messaging" + +import { setOptions } from "./messages/config_change" // Top level await is not supported so immediately execute this async function to set options from storage -(async () => { - const options = await getStoredOptions(); - setOptions(options); -})(); + +;(async () => { + const options = await getStoredOptions() + setOptions(options) +})() // Takes a tabId and event data, gets the tab, and sends it function sendTabEvent(tabId: number, data: Record<string, any>, type: string) { chrome.tabs.get(tabId, (tab) => { if (!tab) return sendTabEventFromTab(tab, data, type) - }); + }) } // Sends an event directly from a tab object -function sendTabEventFromTab(tab: chrome.tabs.Tab, data: Record<string, any>, type: string) { +function sendTabEventFromTab( + tab: chrome.tabs.Tab, + data: Record<string, any>, + type: string +) { const payload = { type, tab, data - }; + } sendToContent(tab.id!, { type: "tab-event", payload }).catch((err) => console.warn(`Failed to send ${type} to tab ${tab.id}:`, err.message) - ); + ) } -// Tab event handlers +// Tab event handlers // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs // TODO handle events that are sent when the tab isn't active. @@ -39,46 +45,46 @@ function sendTabEventFromTab(tab: chrome.tabs.Tab, data: Record<string, any>, ty chrome.tabs.onActivated.addListener((activeInfo) => sendTabEvent(activeInfo.tabId, activeInfo, "tabs.onActivated") -); +) chrome.tabs.onAttached.addListener((tabId, attachInfo) => sendTabEvent(tabId, attachInfo, "tabs.onAttached") -); +) chrome.tabs.onCreated.addListener((tab) => sendTabEventFromTab(tab, {}, "tabs.onCreated") -); +) chrome.tabs.onDetached.addListener((tabId, detachInfo) => sendTabEvent(tabId, detachInfo, "tabs.onDetached") -); +) chrome.tabs.onMoved.addListener((tabId, moveInfo) => sendTabEvent(tabId, moveInfo, "tabs.onMoved") -); +) chrome.tabs.onRemoved.addListener((tabId, removeInfo) => sendTabEvent(tabId, removeInfo, "tabs.onRemoved") -); +) chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => sendTabEventFromTab(tab, changeInfo, "tabs.onUpdated") -); +) chrome.tabs.onZoomChange.addListener((zoomChangeInfo) => sendTabEvent(zoomChangeInfo.tabId, zoomChangeInfo, "tabs.onZoomChange") -); +) chrome.tabs.onHighlighted.addListener((highlightInfo) => { - // Note: No tabId is available, so send with windowId and tabIds - const data = { ...highlightInfo } - // Loop over highlightInfo.tabIds and call sendTabEvent on each - for (const tabId of highlightInfo.tabIds) { - sendTabEvent(tabId, data, "tabs.onHighlighted") - } -}); + // Note: No tabId is available, so send with windowId and tabIds + const data = { ...highlightInfo } + // Loop over highlightInfo.tabIds and call sendTabEvent on each + for (const tabId of highlightInfo.tabIds) { + sendTabEvent(tabId, data, "tabs.onHighlighted") + } +}) chrome.tabs.onReplaced.addListener((addedTabId, removedTabId) => { - const data = { addedTabId, removedTabId } - sendTabEvent(addedTabId, data, "tabs.onReplaced") -}); \ No newline at end of file + const data = { addedTabId, removedTabId } + sendTabEvent(addedTabId, data, "tabs.onReplaced") +}) diff --git a/products/userale/packages/flagon-userale-ext/src/background/messages/config_change.ts b/products/userale/packages/flagon-userale-ext/src/background/messages/config_change.ts index f895ab4..3dec31b 100644 --- a/products/userale/packages/flagon-userale-ext/src/background/messages/config_change.ts +++ b/products/userale/packages/flagon-userale-ext/src/background/messages/config_change.ts @@ -1,20 +1,22 @@ -import type { PlasmoMessaging } from "@plasmohq/messaging"; -import * as userale from "flagon-userale"; -import type { StoredOptions } from "~utils/storage"; - -let allowListRegExp: RegExp; +import * as userale from "flagon-userale" + +import type { PlasmoMessaging } from "@plasmohq/messaging" + +import type { StoredOptions } from "~utils/storage" + +let allowListRegExp: RegExp const handler: PlasmoMessaging.MessageHandler = async (req, res) => { - setOptions(req.body); + setOptions(req.body) } export function setOptions(options: StoredOptions) { - userale.options({url: options.loggingUrl}); - allowListRegExp = new RegExp(options.allowList); + userale.options({ url: options.loggingUrl }) + allowListRegExp = new RegExp(options.allowList) } export function getAllowListRegExp() { - return allowListRegExp; + return allowListRegExp } -export default handler \ No newline at end of file +export default handler diff --git a/products/userale/packages/flagon-userale-ext/src/background/ports/log.ts b/products/userale/packages/flagon-userale-ext/src/background/ports/log.ts index 445e34e..eaade7f 100644 --- a/products/userale/packages/flagon-userale-ext/src/background/ports/log.ts +++ b/products/userale/packages/flagon-userale-ext/src/background/ports/log.ts @@ -1,28 +1,30 @@ -import type { PlasmoMessaging } from "@plasmohq/messaging"; -import * as userale from "flagon-userale"; -import { getAllowListRegExp } from "~/background/messages/config_change"; +import * as userale from "flagon-userale" + +import type { PlasmoMessaging } from "@plasmohq/messaging" + +import { getAllowListRegExp } from "~/background/messages/config_change" const handler: PlasmoMessaging.PortHandler = async (req, res) => { - let log = req.body - log.browserSessionId = browserSessionId; - let allowListRegExp = getAllowListRegExp(); + const log = req.body + log.browserSessionId = browserSessionId + const allowListRegExp = getAllowListRegExp() if (allowListRegExp.test(log.pageUrl)) { - console.log(log); - userale.log(log); + console.log(log) + userale.log(log) } } -let browserSessionId = generateSessionId(); +const browserSessionId = generateSessionId() // TODO move this to a shared utils workspace (this is from packages/flagon-userale/src/, but shouldn't be publicly exported) function generateSessionId(): string { - // 32 digit hex -> 128 bits of info -> 2^64 ~= 10^19 sessions needed for 50% chance of collison - const len = 32; - const arr = new Uint8Array(len / 2); - self.crypto.getRandomValues(arr); - return Array.from(arr, (dec) => { - return dec.toString(16).padStart(2, "0"); - }).join(""); + // 32 digit hex -> 128 bits of info -> 2^64 ~= 10^19 sessions needed for 50% chance of collison + const len = 32 + const arr = new Uint8Array(len / 2) + self.crypto.getRandomValues(arr) + return Array.from(arr, (dec) => { + return dec.toString(16).padStart(2, "0") + }).join("") } export default handler diff --git a/products/userale/packages/flagon-userale-ext/src/content.ts b/products/userale/packages/flagon-userale-ext/src/content.ts index e31c14d..46e67b0 100644 --- a/products/userale/packages/flagon-userale-ext/src/content.ts +++ b/products/userale/packages/flagon-userale-ext/src/content.ts @@ -12,29 +12,33 @@ const logPort = getPort("log") userale.addCallbacks({ rerouteLog(log) { - console.log(log); - logPort.postMessage({body: log}); - return false; + console.log(log) + logPort.postMessage({ body: log }) + return false } }) chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { - if( message.type == "tab-event") { - const { type, tab, data } = message.payload; + if (message.type == "tab-event") { + const { type, tab, data } = message.payload userale.packageCustomLog( - {type}, - () => { return data; }, - true, - ); - sendResponse({ status: "received" }); + { type }, + () => { + return data + }, + true + ) + sendResponse({ status: "received" }) } else if (message.type === "issue-report") { userale.packageCustomLog( - {type: message.type}, - () => { return message.payload; }, - true, - ); - sendResponse({ status: "received" }); - } + { type: message.type }, + () => { + return message.payload + }, + true + ) + sendResponse({ status: "received" }) + } - return true -}) \ No newline at end of file + return true +}) diff --git a/products/userale/packages/flagon-userale-ext/src/options/logging.tsx b/products/userale/packages/flagon-userale-ext/src/options/logging.tsx index 6fd221e..1e55f52 100644 --- a/products/userale/packages/flagon-userale-ext/src/options/logging.tsx +++ b/products/userale/packages/flagon-userale-ext/src/options/logging.tsx @@ -23,7 +23,7 @@ function Logging() { <div> <h2>Logging Options</h2> <form onSubmit={handleSubmit}> - <label htmlFor="logging-url">Logging Endpoint URL:</label> + <label htmlFor="logging-url">Logging Endpoint URL:</label> <input id="logging-url" value={loggingUrl} diff --git a/products/userale/packages/flagon-userale-ext/src/popup.tsx b/products/userale/packages/flagon-userale-ext/src/popup.tsx index 42216a6..15a858d 100644 --- a/products/userale/packages/flagon-userale-ext/src/popup.tsx +++ b/products/userale/packages/flagon-userale-ext/src/popup.tsx @@ -1,5 +1,6 @@ -import { useState } from "react"; -import Options from "~/options"; +import { useState } from "react" + +import Options from "~/options" import { sendToContent } from "~utils/messaging" function IndexPopup() { @@ -10,15 +11,18 @@ function IndexPopup() { e.preventDefault() try { - const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); - if (!tab?.id) throw new Error("No active tab found"); + const [tab] = await chrome.tabs.query({ + active: true, + currentWindow: true + }) + if (!tab?.id) throw new Error("No active tab found") const response = await sendToContent(tab.id, { type: "issue-report", payload: { issueType, issueDescription } - }); + }) console.log("Content script response:", response) alert("Issue report sent!") setIssueDescription("") // clear after send diff --git a/products/userale/packages/flagon-userale-ext/src/utils/messaging.ts b/products/userale/packages/flagon-userale-ext/src/utils/messaging.ts index b53f411..18b3a8e 100644 --- a/products/userale/packages/flagon-userale-ext/src/utils/messaging.ts +++ b/products/userale/packages/flagon-userale-ext/src/utils/messaging.ts @@ -1,12 +1,12 @@ /** * Sends a message to the content script from the popup, options, or background page */ -export async function sendToContent (tabId: number, message: any): Promise<any> { - return new Promise((resolve, reject) => { - chrome.tabs.sendMessage(tabId, message, (response) => { - const err = chrome.runtime.lastError - if (err) reject(err) - else resolve(response) - }) +export async function sendToContent(tabId: number, message: any): Promise<any> { + return new Promise((resolve, reject) => { + chrome.tabs.sendMessage(tabId, message, (response) => { + const err = chrome.runtime.lastError + if (err) reject(err) + else resolve(response) }) -} \ No newline at end of file + }) +} diff --git a/products/userale/packages/flagon-userale-ext/src/utils/storage.ts b/products/userale/packages/flagon-userale-ext/src/utils/storage.ts index 034fc10..bc064d2 100644 --- a/products/userale/packages/flagon-userale-ext/src/utils/storage.ts +++ b/products/userale/packages/flagon-userale-ext/src/utils/storage.ts @@ -43,13 +43,13 @@ export async function setStoredOptions(values: Partial<StoredOptions>) { } catch (error) { return error } - + // Store the options for after the browser is closed - await browser.storage.local.set(values); + await browser.storage.local.set(values) // Notify the background script of the change return await sendToBackground({ name: "config_change", body: values }) -} \ No newline at end of file +} diff --git a/products/userale/packages/flagon-userale-ext/tsconfig.json b/products/userale/packages/flagon-userale-ext/tsconfig.json index 8af9f45..b25f425 100644 --- a/products/userale/packages/flagon-userale-ext/tsconfig.json +++ b/products/userale/packages/flagon-userale-ext/tsconfig.json @@ -1,20 +1,12 @@ { - "extends": "plasmo/templates/tsconfig.base", - "exclude": [ - "node_modules" - ], - "include": [ - ".plasmo/index.d.ts", - "./**/*.ts", - "./**/*.tsx" - ], + "extends": "../../tsconfig.base.json", "compilerOptions": { - "moduleResolution": "bundler", - "paths": { - "~*": [ - "./src/*" - ] - }, - "baseUrl": "." - } + "composite": true, + "declaration": true, + "module": "ESNext", + "moduleResolution": "node", + "noEmit": false + }, + "include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.tsx"], + "exclude": ["node_modules"] } diff --git a/products/userale/packages/flagon-userale/.eslintrc.json b/products/userale/packages/flagon-userale/.eslintrc.json deleted file mode 100644 index b076f65..0000000 --- a/products/userale/packages/flagon-userale/.eslintrc.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "parserOptions" : { - "sourceType" : "module", - "ecmaFeatures" : { - "modules" : true - } - }, - "plugins": ["@typescript-eslint"], - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - "env" : { - "browser" : true, - "es6" : true - }, - "rules" : { - "no-cond-assign" : "warn", - "no-constant-condition" : "warn", - "no-unused-vars" : "warn", - "@typescript-eslint/no-unused-vars": "warn", - "@typescript-eslint/no-explicit-any": "warn" - }, - "overrides": [ - { - "files": ["test/**/*"], - "plugins": ["jest"], - "env": { - "jest": true - } - } - ] -} diff --git a/products/userale/packages/flagon-userale/.husky/pre-commit b/products/userale/packages/flagon-userale/.husky/pre-commit deleted file mode 100644 index 2a8d238..0000000 --- a/products/userale/packages/flagon-userale/.husky/pre-commit +++ /dev/null @@ -1,80 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# http://www.apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -sound() { -echo '\a' -} - -echo "Running pre-commit hooks..." - -# Check Prettier standards -npm run format || -( - sound - echo "❌ Prettier Check Failed. Run npm run format, add changes and try commit again."; - exit 1; -) - -# Check ESLint Standards -npm run lint || -( - sound - echo "❌ ESLint Check Failed. Make the required changes listed above, add changes and try to commit again." - exit 1; -) - -# Check types -npm run check-types || -( - sound - echo "❌ Typescript Check Failed. Make the required changes listed above, add changes and try to commit again." - exit 1; -) - -# If everything passes... Now we can commit -echo "✅ Checks passed, trying to build..." - -"npm" run build || -( - sound - echo "❌ Build failed, check errors." - exit 1; -) - -echo "✅ Successful build, running tests..." -# After build, run unit tests -# Right now, runs all tests. Later scope to just unit tets, we can add e2e/integration as github actions on merge -npm run test || -( - sound - echo "❌ Tests failed: View the logs to see what broke and fix it before re-committing." - exit 1; -) - -# After build, check license headers -# These should be fixed in the postbuild step, but if a new filetype -# emerges, this should catch it. -npm run license:check || -( - sound - echo "❌ License check failed: View the logs to see what broke and fix it before re-committing." - exit 1; -) - -# If everything passes... Now we can commit -echo '✅ All tests passed' - diff --git a/products/userale/packages/flagon-userale/build/attachHandlers.d.ts b/products/userale/packages/flagon-userale/build/attachHandlers.d.ts new file mode 100644 index 0000000..2ae8cc5 --- /dev/null +++ b/products/userale/packages/flagon-userale/build/attachHandlers.d.ts @@ -0,0 +1,81 @@ +import { Events, Logging, Settings } from "@/types"; +import { Configuration } from "@/configure"; +/** + * Maps a MouseEvent to an object containing useful information. + * @param {MouseEvent} e Event to extract data from + */ +export declare function extractMouseDetails(e: MouseEvent): { + clicks: number; + ctrl: boolean; + alt: boolean; + shift: boolean; + meta: boolean; +}; +/** Maps a KeyboardEvent to an object containing useful infromation + * @param {KeyboardEvent} e Event to extract data from + */ +export declare function extractKeyboardDetails(e: KeyboardEvent): { + key: string; + code: string; + ctrl: boolean; + alt: boolean; + shift: boolean; + meta: boolean; +}; +/** + * Maps an InputEvent to an object containing useful information. + * @param {InputEvent} e Event to extract data from + */ +export declare function extractInputDetails(e: InputEvent): { + value: string; +}; +/** + * Maps a ChangeEvent to an object containing useful information. + * @param {Events.ChangeEvent} e Event to extract data from + */ +export declare function extractChangeDetails(e: Events.ChangeEvent): { + value: any; +}; +/** + * Maps a WheelEvent to an object containing useful information. + * @param {WheelEvent} e Event to extract data from + */ +export declare function extractWheelDetails(e: WheelEvent): { + x: number; + y: number; + z: number; +}; +/** + * Maps a ScrollEvent to an object containing useful information. + */ +export declare function extractScrollDetails(): { + x: number; + y: number; +}; +/** + * Maps a ResizeEvent to an object containing useful information. + */ +export declare function extractResizeDetails(): { + width: number; + height: number; +}; +/** + * Defines the way information is extracted from various events. + * Also defines which events we will listen to. + * @param {Settings.Config} config Configuration object to read from. + */ +export declare function defineDetails(config: Settings.DefaultConfig): void; +/** + * Defines the way information is extracted from various events. + * Also defines which events we will listen to. + * @param {Settings.Config} options UserALE Configuration object to read from. + * @param {Events.AllowedEvents} type of html event (e.g., 'click', 'mouseover', etc.), such as passed to addEventListener methods. + */ +export declare function defineCustomDetails(options: Settings.DefaultConfig, type: Events.AllowedEvents): Logging.DynamicDetailFunction | null | undefined; +/** + * Hooks the event handlers for each event type of interest. + * @param {Configuration} config Configuration singleton to use. + * @return {boolean} Whether the operation succeeded + */ +export declare function attachHandlers(config: Configuration): boolean; +//# sourceMappingURL=attachHandlers.d.ts.map \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/configure.d.ts b/products/userale/packages/flagon-userale/build/configure.d.ts new file mode 100644 index 0000000..e2ca829 --- /dev/null +++ b/products/userale/packages/flagon-userale/build/configure.d.ts @@ -0,0 +1,46 @@ +import type { Settings } from "@/types"; +export declare class Configuration { + [key: string]: Settings.ConfigValueTypes; + private static instance; + autostart: boolean; + authHeader: Settings.AuthHeader; + browserSessionId: Settings.SessionId; + custIndex: Settings.CustomIndex; + headers: Settings.Headers; + httpSessionId: Settings.SessionId; + logCountThreshold: number; + logDetails: boolean; + on: boolean; + resolution: number; + sessionId: Settings.SessionId; + time: Settings.TimeFunction; + toolName: Settings.ToolName; + toolVersion: Settings.Version; + transmitInterval: number; + url: string; + userFromParams: Settings.UserFromParams; + useraleVersion: Settings.Version; + userId: Settings.UserId; + version: Settings.Version; + websocketsEnabled: boolean; + private constructor(); + static getInstance(): Configuration; + private initialize; + /** + * Resets the configuration to its initial state. + */ + reset(): void; + /** + * Shallow merges a newConfig with the configuration class, updating it. + * Retrieves/updates the userid if userFromParams is provided. + * @param {Partial<Settings.Config>} newConfig Configuration object to merge into the current config. + */ + update(newConfig: Partial<Settings.Config>): void; + /** + * Attempts to extract the userid from the query parameters of the URL. + * @param {string} param The name of the query parameter containing the userid. + * @return {string | null} The extracted/decoded userid, or null if none is found. + */ + static getUserIdFromParams(param: string): string | null; +} +//# sourceMappingURL=configure.d.ts.map \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/getInitialSettings.d.ts b/products/userale/packages/flagon-userale/build/getInitialSettings.d.ts new file mode 100644 index 0000000..3dd3167 --- /dev/null +++ b/products/userale/packages/flagon-userale/build/getInitialSettings.d.ts @@ -0,0 +1,21 @@ +import type { Settings } from "./types"; +/** + * Extracts the initial configuration settings from the + * currently executing script tag. + * @return {Object} The extracted configuration object + */ +export declare function getInitialSettings(): Settings.Config; +/** + * defines sessionId, stores it in sessionStorage, checks to see if there is a sessionId in + * storage when script is started. This prevents events like 'submit', which refresh page data + * from refreshing the current user session + * + */ +export declare function getsessionId(sessionKey: string, value: any): any; +/** + * Creates a function to normalize the timestamp of the provided event. + * @param {Event} e An event containing a timeStamp property. + * @return {typeof timeStampScale~tsScaler} The timestamp normalizing function. + */ +export declare function timeStampScale(e: Event): Settings.TimeFunction; +//# sourceMappingURL=getInitialSettings.d.ts.map \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/main.d.ts b/products/userale/packages/flagon-userale/build/main.d.ts index a3cc624..f6df136 100644 --- a/products/userale/packages/flagon-userale/build/main.d.ts +++ b/products/userale/packages/flagon-userale/build/main.d.ts @@ -1,234 +1,30 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -declare namespace Settings { - type Version = string | null; - type UserId = string | null; - type SessionId = string | null; - type UserFromParams = string | null; - type ToolName = string | null; - type AuthHeader = CallableFunction | string | null; - type CustomIndex = string | null; - type HeaderObject = { [key: string]: string }; - type Headers = HeaderObject | null; - type ConfigValueTypes = - | string - | number - | boolean - | null - | Version - | UserId - | SessionId - | UserFromParams - | ToolName - | AuthHeader - | CustomIndex - | Headers; - - type TimeFunction = (() => number) | ((ts: number) => number); - - export interface DefaultConfig { - [key: string]: ConfigValueTypes; - } - - export interface Config extends DefaultConfig { - autostart: boolean; - authHeader: AuthHeader; - browserSessionId: SessionId; - custIndex: CustomIndex; - headers: Headers; - httpSessionId: SessionId; - logCountThreshold: number; - logDetails: boolean; - on?: boolean; - resolution: number; - sessionId: SessionId; - time: TimeFunction; - toolName: ToolName; - toolVersion?: Version; - transmitInterval: number; - url: string; - userFromParams: UserFromParams; - useraleVersion: Version; - userId: UserId; - version?: Version; - websocketsEnabled?: boolean; - } - - export interface IConfiguration extends Config { - getInstance(): Configuration; - configure(newConfig: Config): void; - } -} - -// TODO: Switch to protobuf for managing log types -declare namespace Logging { - type JSONObject = { - [key: string]: - | string - | number - | boolean - | null - | undefined - | JSONObject - | Array<string | number | boolean | null | JSONObject>; - }; - export type Log = JSONObject; // TODO: Intersect this with the default log objects (raw & interval) - export type CustomLog = JSONObject; - - export type DynamicDetailFunction<E extends Event = Event> = ( - e: E, - ) => JSONObject; - export type StaticDetailFunction = () => JSONObject; -} - -declare namespace Events { - type FormElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; - type ChangeEvent = Event<FormElement>; - export type RawEvents = - | "dblclick" - | "mouseup" - | "mousedown" - | "dragstart" - | "dragend" - | "drag" - | "drop" - | "keydown"; - export type IntervalEvents = - | "click" - | "focus" - | "blur" - | "input" - | "change" - | "mouseover" - | "submit"; - export type WindowEvents = "load" | "blur" | "focus"; - export type BufferedEvents = "wheel" | "scroll" | "resize"; - export type RefreshEvents = "submit"; - export type AllowedEvents = - | RawEvents - | IntervalEvents - | WindowEvents - | BufferedEvents - | RefreshEvents; - - export type EventDetailsMap<T extends string> = Partial<{ - [key in T]: - | Logging.DynamicDetailFunction< - | MouseEvent - | KeyboardEvent - | InputEvent - | Events.ChangeEvent - | WheelEvent - > - | Logging.StaticDetailFunction - | null; - }>; - - export type EventBoolMap<T extends string> = Partial<{ - [key in T]: boolean; - }>; -} - -declare namespace Callbacks { - export type AuthCallback = () => string; - export type HeadersCallback = () => Settings.HeaderObject; - - export type CallbackMap = { - [key in string]: CallableFunction; - }; -} - -/** - * Defines the way information is extracted from various events. - * Also defines which events we will listen to. - * @param {Settings.Config} options UserALE Configuration object to read from. - * @param {Events.AllowedEvents} type of html event (e.g., 'click', 'mouseover', etc.), such as passed to addEventListener methods. - */ -declare function defineCustomDetails(options: Settings.DefaultConfig, type: Events.AllowedEvents): Logging.DynamicDetailFunction | null | undefined; - -/** - * Registers the provided callback to be used when updating the auth header. - * @param {Callbacks.AuthCallback} callback Callback used to fetch the newest header. Should return a string. - * @returns {boolean} Whether the operation succeeded. - */ -declare function registerAuthCallback(callback: Callbacks.AuthCallback): boolean; - -/** - * Adds named callbacks to be executed when logging. - * @param {Object } newCallbacks An object containing named callback functions. - */ -declare function addCallbacks(...newCallbacks: Record<symbol | string, CallableFunction>[]): Callbacks.CallbackMap; -/** - * Removes callbacks by name. - * @param {String[]} targetKeys A list of names of functions to remove. - */ -declare function removeCallbacks(targetKeys: string[]): void; -/** - * Transforms the provided HTML event into a log and appends it to the log queue. - * @param {Event} e The event to be logged. - * @param {Function} detailFcn The function to extract additional log parameters from the event. - * @return {boolean} Whether the event was logged. - */ -declare function packageLog(e: Event, detailFcn?: Logging.DynamicDetailFunction | null): boolean; -/** - * Packages the provided customLog to include standard meta data and appends it to the log queue. - * @param {Logging.CustomLog} customLog The behavior to be logged. - * @param {Logging.DynamicDetailFunction} detailFcn The function to extract additional log parameters from the event. - * @param {boolean} userAction Indicates user behavior (true) or system behavior (false) - * @return {boolean} Whether the event was logged. - */ -declare function packageCustomLog(customLog: Logging.CustomLog, detailFcn: Logging.DynamicDetailFunction | Logging.StaticDetailFunction, userAction: boolean): boolean; -/** - * Builds a string CSS selector from the provided element - * @param {EventTarget} ele The element from which the selector is built. - * @return {string} The CSS selector for the element, or Unknown if it can't be determined. - */ -declare function getSelector(ele: EventTarget): string; -/** - * Builds an array of elements from the provided event target, to the root element. - * @param {Event} e Event from which the path should be built. - * @return {HTMLElement[]} Array of elements, starting at the event target, ending at the root element. - */ -declare function buildPath(e: Event): string[]; - -declare let started: boolean; - -declare const version: string; +import type { Settings, Logging } from "@/types"; +export declare let started: boolean; +export { defineCustomDetails as details } from "@/attachHandlers"; +export { registerAuthCallback as registerAuthCallback } from "@/utils"; +export { addCallbacks as addCallbacks, removeCallbacks as removeCallbacks, packageLog as packageLog, packageCustomLog as packageCustomLog, getSelector as getSelector, buildPath as buildPath, } from "@/packageLogs"; +export type { Logging } from "@/types"; +export declare const version: string; /** * Used to start the logging process if the * autostart configuration option is set to false. */ -declare function start(): void; +export declare function start(): void; /** * Halts the logging process. Logs will no longer be sent. */ -declare function stop(): void; +export declare function stop(): void; /** * Updates the current configuration * object with the provided values. * @param {Partial<Settings.Config>} newConfig The configuration options to use. * @return {Settings.Config} Returns the updated configuration. */ -declare function options(newConfig: Partial<Settings.Config> | undefined): Settings.Config; +export declare function options(newConfig: Partial<Settings.Config> | undefined): Settings.Config; /** * Appends a log to the log queue. * @param {Logging.CustomLog} customLog The log to append. * @return {boolean} Whether the operation succeeded. */ -declare function log(customLog: Logging.CustomLog | undefined): boolean; - -export { Logging, addCallbacks, buildPath, defineCustomDetails as details, getSelector, log, options, packageCustomLog, packageLog, registerAuthCallback, removeCallbacks, start, started, stop, version }; +export declare function log(customLog: Logging.CustomLog | undefined): boolean; +//# sourceMappingURL=main.d.ts.map \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/main.global.js b/products/userale/packages/flagon-userale/build/main.global.js index 490b8d0..2a715da 100644 --- a/products/userale/packages/flagon-userale/build/main.global.js +++ b/products/userale/packages/flagon-userale/build/main.global.js @@ -14,49 +14,18 @@ See the License for the specific language governing permissions and limitations under the License.*/ (() => { - var __defProp = Object.defineProperty; - var __getOwnPropDesc = Object.getOwnPropertyDescriptor; - var __getOwnPropNames = Object.getOwnPropertyNames; - var __hasOwnProp = Object.prototype.hasOwnProperty; - var __esm = (fn, res) => function __init() { - return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; - }; - var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); - }; - var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; - }; - var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - // src/packageLogs.ts - var packageLogs_exports = {}; - __export(packageLogs_exports, { - addCallbacks: () => addCallbacks, - buildAttrs: () => buildAttrs, - buildCSS: () => buildCSS, - buildPath: () => buildPath, - cbHandlers: () => cbHandlers, - extractTimeFields: () => extractTimeFields, - filterHandler: () => filterHandler, - getLocation: () => getLocation, - getScreenRes: () => getScreenRes, - getSelector: () => getSelector, - initPackager: () => initPackager, - logs: () => logs, - mapHandler: () => mapHandler, - packageCustomLog: () => packageCustomLog, - packageIntervalLog: () => packageIntervalLog, - packageLog: () => packageLog, - removeCallbacks: () => removeCallbacks, - selectorizePath: () => selectorizePath - }); + var logs; + var config; + var intervalId; + var intervalType; + var intervalPath; + var intervalTimer; + var intervalCounter; + var intervalLog; + var filterHandler = null; + var mapHandler = null; + var cbHandlers = {}; function addCallbacks(...newCallbacks) { newCallbacks.forEach((source) => { let descriptors = {}; @@ -322,7 +291,7 @@ let val = attr.value; try { val = JSON.parse(val); - } catch (error) { + } catch { } attributes[attr.name] = val; } @@ -340,30 +309,22 @@ } return properties; } - var logs, config, intervalId, intervalType, intervalPath, intervalTimer, intervalCounter, intervalLog, filterHandler, mapHandler, cbHandlers; - var init_packageLogs = __esm({ - "src/packageLogs.ts"() { - "use strict"; - filterHandler = null; - mapHandler = null; - cbHandlers = {}; - } - }); // src/attachHandlers.ts - var attachHandlers_exports = {}; - __export(attachHandlers_exports, { - attachHandlers: () => attachHandlers, - defineCustomDetails: () => defineCustomDetails, - defineDetails: () => defineDetails, - extractChangeDetails: () => extractChangeDetails, - extractInputDetails: () => extractInputDetails, - extractKeyboardDetails: () => extractKeyboardDetails, - extractMouseDetails: () => extractMouseDetails, - extractResizeDetails: () => extractResizeDetails, - extractScrollDetails: () => extractScrollDetails, - extractWheelDetails: () => extractWheelDetails - }); + var events; + var bufferBools; + var bufferedEvents; + var refreshEvents; + var intervalEvents = [ + "click", + "focus", + "blur", + "input", + "change", + "mouseover", + "submit" + ]; + var windowEvents = ["load", "blur", "focus"]; function extractMouseDetails(e) { return { clicks: e.detail, @@ -383,11 +344,6 @@ meta: e.metaKey }; } - function extractInputDetails(e) { - return { - value: e.target.value - }; - } function extractChangeDetails(e) { return { value: e.target.value @@ -529,25 +485,9 @@ return false; } } - var events, bufferBools, bufferedEvents, refreshEvents, intervalEvents, windowEvents; - var init_attachHandlers = __esm({ - "src/attachHandlers.ts"() { - "use strict"; - init_packageLogs(); - intervalEvents = [ - "click", - "focus", - "blur", - "input", - "change", - "mouseover", - "submit" - ]; - windowEvents = ["load", "blur", "focus"]; - } - }); // src/utils/auth/index.ts + var authCallback = null; function updateAuthHeader(config3) { if (authCallback) { try { @@ -562,7 +502,7 @@ verifyCallback(callback); authCallback = callback; return true; - } catch (e) { + } catch { return false; } } @@ -575,18 +515,9 @@ throw new Error("Userale auth callback must return a string"); } } - function resetAuthCallback() { - authCallback = null; - } - var authCallback; - var init_auth = __esm({ - "src/utils/auth/index.ts"() { - "use strict"; - authCallback = null; - } - }); // src/utils/headers/index.ts + var headersCallback = null; function updateCustomHeaders(config3) { if (headersCallback) { try { @@ -596,63 +527,6 @@ } } } - function registerHeadersCallback(callback) { - try { - verifyCallback2(callback); - headersCallback = callback; - return true; - } catch (e) { - return false; - } - } - function verifyCallback2(callback) { - if (typeof callback !== "function") { - throw new Error("Userale headers callback must be a function"); - } - const result = callback(); - if (typeof result !== "object") { - throw new Error("Userale headers callback must return an object"); - } - for (const [key, value] of Object.entries(result)) { - if (typeof key !== "string" || typeof value !== "string") { - throw new Error( - "Userale header callback must return an object with string keys and values" - ); - } - } - } - function resetHeadersCallback() { - headersCallback = null; - } - var headersCallback; - var init_headers = __esm({ - "src/utils/headers/index.ts"() { - "use strict"; - headersCallback = null; - } - }); - - // src/utils/index.ts - var utils_exports = {}; - __export(utils_exports, { - authCallback: () => authCallback, - headersCallback: () => headersCallback, - registerAuthCallback: () => registerAuthCallback, - registerHeadersCallback: () => registerHeadersCallback, - resetAuthCallback: () => resetAuthCallback, - resetHeadersCallback: () => resetHeadersCallback, - updateAuthHeader: () => updateAuthHeader, - updateCustomHeaders: () => updateCustomHeaders, - verifyAuthCallback: () => verifyCallback, - verifyHeadersCallback: () => verifyCallback2 - }); - var init_utils = __esm({ - "src/utils/index.ts"() { - "use strict"; - init_auth(); - init_headers(); - } - }); // package.json var version = "2.4.0"; @@ -841,12 +715,7 @@ var Configuration = _Configuration; Configuration.instance = null; - // src/main.ts - init_attachHandlers(); - init_packageLogs(); - // src/sendLogs.ts - init_utils(); var sendIntervalId; var wsock; function initSender(logs3, config3) { @@ -946,9 +815,6 @@ } // src/main.ts - init_attachHandlers(); - init_utils(); - init_packageLogs(); var config2 = Configuration.getInstance(); var logs2 = []; var startLoadTimestamp = Date.now(); @@ -1025,14 +891,14 @@ options, log, version, - details: (init_attachHandlers(), __toCommonJS(attachHandlers_exports)).defineCustomDetails, - registerAuthCallback: (init_utils(), __toCommonJS(utils_exports)).registerAuthCallback, - addCallbacks: (init_packageLogs(), __toCommonJS(packageLogs_exports)).addCallbacks, - removeCallbacks: (init_packageLogs(), __toCommonJS(packageLogs_exports)).removeCallbacks, - packageLog: (init_packageLogs(), __toCommonJS(packageLogs_exports)).packageLog, - packageCustomLog: (init_packageLogs(), __toCommonJS(packageLogs_exports)).packageCustomLog, - getSelector: (init_packageLogs(), __toCommonJS(packageLogs_exports)).getSelector, - buildPath: (init_packageLogs(), __toCommonJS(packageLogs_exports)).buildPath + details: defineCustomDetails, + registerAuthCallback, + addCallbacks, + removeCallbacks, + packageLog, + packageCustomLog, + getSelector, + buildPath }; } })(); diff --git a/products/userale/packages/flagon-userale/build/main.global.js.map b/products/userale/packages/flagon-userale/build/main.global.js.map index a0eea58..53a70f8 100644 --- a/products/userale/packages/flagon-userale/build/main.global.js.map +++ b/products/userale/packages/flagon-userale/build/main.global.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/packageLogs.ts","../src/attachHandlers.ts","../src/utils/auth/index.ts","../src/utils/headers/index.ts","../src/utils/index.ts","../src/getInitialSettings.ts","../src/configure.ts","../src/main.ts","../src/sendLogs.ts"],"sourcesContent":["/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements. See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n [...] \ No newline at end of file +{"version":3,"sources":["../src/packageLogs.ts","../src/attachHandlers.ts","../src/utils/auth/index.ts","../src/utils/headers/index.ts","../src/getInitialSettings.ts","../src/configure.ts","../src/sendLogs.ts","../src/main.ts"],"sourcesContent":["/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements. See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this [...] \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/main.mjs b/products/userale/packages/flagon-userale/build/main.mjs index a9318e2..c61e588 100644 --- a/products/userale/packages/flagon-userale/build/main.mjs +++ b/products/userale/packages/flagon-userale/build/main.mjs @@ -12,55 +12,18 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*/ -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __esm = (fn, res) => function __init() { - return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; -}; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// ../../node_modules/.pnpm/tsup@5.12.9_@swc+core@1.11.22_@swc+helpers@0.5.17__postcss@8.5.3_ts-node@10.9.2_@swc+co_7dfb40117802bc289cccbf76535c67e5/node_modules/tsup/assets/esm_shims.js -var init_esm_shims = __esm({ - "../../node_modules/.pnpm/tsup@5.12.9_@swc+core@1.11.22_@swc+helpers@0.5.17__postcss@8.5.3_ts-node@10.9.2_@swc+co_7dfb40117802bc289cccbf76535c67e5/node_modules/tsup/assets/esm_shims.js"() { - } -}); - // src/packageLogs.ts -var packageLogs_exports = {}; -__export(packageLogs_exports, { - addCallbacks: () => addCallbacks, - buildAttrs: () => buildAttrs, - buildCSS: () => buildCSS, - buildPath: () => buildPath, - cbHandlers: () => cbHandlers, - extractTimeFields: () => extractTimeFields, - filterHandler: () => filterHandler, - getLocation: () => getLocation, - getScreenRes: () => getScreenRes, - getSelector: () => getSelector, - initPackager: () => initPackager, - logs: () => logs, - mapHandler: () => mapHandler, - packageCustomLog: () => packageCustomLog, - packageIntervalLog: () => packageIntervalLog, - packageLog: () => packageLog, - removeCallbacks: () => removeCallbacks, - selectorizePath: () => selectorizePath -}); +var logs; +var config; +var intervalId; +var intervalType; +var intervalPath; +var intervalTimer; +var intervalCounter; +var intervalLog; +var filterHandler = null; +var mapHandler = null; +var cbHandlers = {}; function addCallbacks(...newCallbacks) { newCallbacks.forEach((source) => { let descriptors = {}; @@ -326,7 +289,7 @@ function buildAttrs(e) { let val = attr.value; try { val = JSON.parse(val); - } catch (error) { + } catch { } attributes[attr.name] = val; } @@ -344,31 +307,22 @@ function buildCSS(e) { } return properties; } -var logs, config, intervalId, intervalType, intervalPath, intervalTimer, intervalCounter, intervalLog, filterHandler, mapHandler, cbHandlers; -var init_packageLogs = __esm({ - "src/packageLogs.ts"() { - "use strict"; - init_esm_shims(); - filterHandler = null; - mapHandler = null; - cbHandlers = {}; - } -}); // src/attachHandlers.ts -var attachHandlers_exports = {}; -__export(attachHandlers_exports, { - attachHandlers: () => attachHandlers, - defineCustomDetails: () => defineCustomDetails, - defineDetails: () => defineDetails, - extractChangeDetails: () => extractChangeDetails, - extractInputDetails: () => extractInputDetails, - extractKeyboardDetails: () => extractKeyboardDetails, - extractMouseDetails: () => extractMouseDetails, - extractResizeDetails: () => extractResizeDetails, - extractScrollDetails: () => extractScrollDetails, - extractWheelDetails: () => extractWheelDetails -}); +var events; +var bufferBools; +var bufferedEvents; +var refreshEvents; +var intervalEvents = [ + "click", + "focus", + "blur", + "input", + "change", + "mouseover", + "submit" +]; +var windowEvents = ["load", "blur", "focus"]; function extractMouseDetails(e) { return { clicks: e.detail, @@ -388,11 +342,6 @@ function extractKeyboardDetails(e) { meta: e.metaKey }; } -function extractInputDetails(e) { - return { - value: e.target.value - }; -} function extractChangeDetails(e) { return { value: e.target.value @@ -534,26 +483,9 @@ function attachHandlers(config3) { return false; } } -var events, bufferBools, bufferedEvents, refreshEvents, intervalEvents, windowEvents; -var init_attachHandlers = __esm({ - "src/attachHandlers.ts"() { - "use strict"; - init_esm_shims(); - init_packageLogs(); - intervalEvents = [ - "click", - "focus", - "blur", - "input", - "change", - "mouseover", - "submit" - ]; - windowEvents = ["load", "blur", "focus"]; - } -}); // src/utils/auth/index.ts +var authCallback = null; function updateAuthHeader(config3) { if (authCallback) { try { @@ -568,7 +500,7 @@ function registerAuthCallback(callback) { verifyCallback(callback); authCallback = callback; return true; - } catch (e) { + } catch { return false; } } @@ -581,19 +513,9 @@ function verifyCallback(callback) { throw new Error("Userale auth callback must return a string"); } } -function resetAuthCallback() { - authCallback = null; -} -var authCallback; -var init_auth = __esm({ - "src/utils/auth/index.ts"() { - "use strict"; - init_esm_shims(); - authCallback = null; - } -}); // src/utils/headers/index.ts +var headersCallback = null; function updateCustomHeaders(config3) { if (headersCallback) { try { @@ -603,77 +525,11 @@ function updateCustomHeaders(config3) { } } } -function registerHeadersCallback(callback) { - try { - verifyCallback2(callback); - headersCallback = callback; - return true; - } catch (e) { - return false; - } -} -function verifyCallback2(callback) { - if (typeof callback !== "function") { - throw new Error("Userale headers callback must be a function"); - } - const result = callback(); - if (typeof result !== "object") { - throw new Error("Userale headers callback must return an object"); - } - for (const [key, value] of Object.entries(result)) { - if (typeof key !== "string" || typeof value !== "string") { - throw new Error( - "Userale header callback must return an object with string keys and values" - ); - } - } -} -function resetHeadersCallback() { - headersCallback = null; -} -var headersCallback; -var init_headers = __esm({ - "src/utils/headers/index.ts"() { - "use strict"; - init_esm_shims(); - headersCallback = null; - } -}); - -// src/utils/index.ts -var utils_exports = {}; -__export(utils_exports, { - authCallback: () => authCallback, - headersCallback: () => headersCallback, - registerAuthCallback: () => registerAuthCallback, - registerHeadersCallback: () => registerHeadersCallback, - resetAuthCallback: () => resetAuthCallback, - resetHeadersCallback: () => resetHeadersCallback, - updateAuthHeader: () => updateAuthHeader, - updateCustomHeaders: () => updateCustomHeaders, - verifyAuthCallback: () => verifyCallback, - verifyHeadersCallback: () => verifyCallback2 -}); -var init_utils = __esm({ - "src/utils/index.ts"() { - "use strict"; - init_esm_shims(); - init_auth(); - init_headers(); - } -}); - -// src/main.ts -init_esm_shims(); // package.json var version = "2.4.0"; -// src/configure.ts -init_esm_shims(); - // src/getInitialSettings.ts -init_esm_shims(); var sessionId = null; var httpSessionId = null; function getInitialSettings() { @@ -857,13 +713,7 @@ var _Configuration = class { var Configuration = _Configuration; Configuration.instance = null; -// src/main.ts -init_attachHandlers(); -init_packageLogs(); - // src/sendLogs.ts -init_esm_shims(); -init_utils(); var sendIntervalId; var wsock; function initSender(logs3, config3) { @@ -963,9 +813,6 @@ async function sendLogs(logs3, config3, retries) { } // src/main.ts -init_attachHandlers(); -init_utils(); -init_packageLogs(); var config2 = Configuration.getInstance(); var logs2 = []; var startLoadTimestamp = Date.now(); @@ -1042,14 +889,14 @@ if (typeof window !== "undefined") { options, log, version, - details: (init_attachHandlers(), __toCommonJS(attachHandlers_exports)).defineCustomDetails, - registerAuthCallback: (init_utils(), __toCommonJS(utils_exports)).registerAuthCallback, - addCallbacks: (init_packageLogs(), __toCommonJS(packageLogs_exports)).addCallbacks, - removeCallbacks: (init_packageLogs(), __toCommonJS(packageLogs_exports)).removeCallbacks, - packageLog: (init_packageLogs(), __toCommonJS(packageLogs_exports)).packageLog, - packageCustomLog: (init_packageLogs(), __toCommonJS(packageLogs_exports)).packageCustomLog, - getSelector: (init_packageLogs(), __toCommonJS(packageLogs_exports)).getSelector, - buildPath: (init_packageLogs(), __toCommonJS(packageLogs_exports)).buildPath + details: defineCustomDetails, + registerAuthCallback, + addCallbacks, + removeCallbacks, + packageLog, + packageCustomLog, + getSelector, + buildPath }; } export { diff --git a/products/userale/packages/flagon-userale/build/main.mjs.map b/products/userale/packages/flagon-userale/build/main.mjs.map index 969d89b..2c72769 100644 --- a/products/userale/packages/flagon-userale/build/main.mjs.map +++ b/products/userale/packages/flagon-userale/build/main.mjs.map @@ -1 +1 @@ -{"version":3,"sources":["../../../node_modules/.pnpm/tsup@5.12.9_@swc+core@1.11.22_@swc+helpers@0.5.17__postcss@8.5.3_ts-node@10.9.2_@swc+co_7dfb40117802bc289cccbf76535c67e5/node_modules/tsup/assets/esm_shims.js","../src/packageLogs.ts","../src/attachHandlers.ts","../src/utils/auth/index.ts","../src/utils/headers/index.ts","../src/utils/index.ts","../src/main.ts","../src/configure.ts","../src/getInitialSettings.ts","../src/sendLogs.ts"],"sourcesContent":["// Shim globals in esm bundle\ni [...] \ No newline at end of file +{"version":3,"sources":["../src/packageLogs.ts","../src/attachHandlers.ts","../src/utils/auth/index.ts","../src/utils/headers/index.ts","../src/getInitialSettings.ts","../src/configure.ts","../src/sendLogs.ts","../src/main.ts"],"sourcesContent":["/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements. See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this [...] \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/packageLogs.d.ts b/products/userale/packages/flagon-userale/build/packageLogs.d.ts new file mode 100644 index 0000000..fc4dff2 --- /dev/null +++ b/products/userale/packages/flagon-userale/build/packageLogs.d.ts @@ -0,0 +1,106 @@ +import { Callbacks, Logging } from "@/types"; +import { Configuration } from "@/configure"; +export declare let logs: Array<Logging.Log>; +export declare const filterHandler: CallableFunction | null; +export declare const mapHandler: CallableFunction | null; +export declare let cbHandlers: Callbacks.CallbackMap; +/** + * Adds named callbacks to be executed when logging. + * @param {Object } newCallbacks An object containing named callback functions. + */ +export declare function addCallbacks(...newCallbacks: Record<symbol | string, CallableFunction>[]): Callbacks.CallbackMap; +/** + * Removes callbacks by name. + * @param {String[]} targetKeys A list of names of functions to remove. + */ +export declare function removeCallbacks(targetKeys: string[]): void; +/** + * Assigns the config and log container to be used by the logging functions. + * @param {Array<Logging.Log>} newLogs Log container. + * @param {Object} newConfig Configuration to use while logging. + */ +export declare function initPackager(newLogs: Array<Logging.Log>, newConfig: Configuration): void; +/** + * Transforms the provided HTML event into a log and appends it to the log queue. + * @param {Event} e The event to be logged. + * @param {Function} detailFcn The function to extract additional log parameters from the event. + * @return {boolean} Whether the event was logged. + */ +export declare function packageLog(e: Event, detailFcn?: Logging.DynamicDetailFunction | null): boolean; +/** + * Packages the provided customLog to include standard meta data and appends it to the log queue. + * @param {Logging.CustomLog} customLog The behavior to be logged. + * @param {Logging.DynamicDetailFunction} detailFcn The function to extract additional log parameters from the event. + * @param {boolean} userAction Indicates user behavior (true) or system behavior (false) + * @return {boolean} Whether the event was logged. + */ +export declare function packageCustomLog(customLog: Logging.CustomLog, detailFcn: Logging.DynamicDetailFunction | Logging.StaticDetailFunction, userAction: boolean): boolean; +/** + * Extract the millisecond and microsecond portions of a timestamp. + * @param {Number} timeStamp The timestamp to split into millisecond and microsecond fields. + * @return {Object} An object containing the millisecond + * and microsecond portions of the timestamp. + */ +export declare function extractTimeFields(timeStamp: number): { + milli: number; + micro: number; +}; +/** + * Track intervals and gather details about it. + * @param {Object} e + * @return boolean + */ +export declare function packageIntervalLog(e: Event): boolean; +/** + * Extracts coordinate information from the event + * depending on a few browser quirks. + * @param {Event} e The event to extract coordinate information from. + * @return {Object} An object containing nullable x and y coordinates for the event. + */ +export declare function getLocation(e: Event): { + x: number; + y: number; +} | { + x: null; + y: null; +} | undefined; +/** + * Extracts innerWidth and innerHeight to provide estimates of screen resolution + * @return {Object} An object containing the innerWidth and InnerHeight + */ +export declare function getScreenRes(): { + width: number; + height: number; +}; +/** + * Builds a string CSS selector from the provided element + * @param {EventTarget} ele The element from which the selector is built. + * @return {string} The CSS selector for the element, or Unknown if it can't be determined. + */ +export declare function getSelector(ele: EventTarget): string; +/** + * Builds an array of elements from the provided event target, to the root element. + * @param {Event} e Event from which the path should be built. + * @return {HTMLElement[]} Array of elements, starting at the event target, ending at the root element. + */ +export declare function buildPath(e: Event): string[]; +/** + * Builds a CSS selector path from the provided list of elements. + * @param {EventTarget[]} path Array of HTML Elements from which the path should be built. + * @return {string[]} Array of string CSS selectors. + */ +export declare function selectorizePath(path: EventTarget[]): string[]; +/** + * Builds an object containing attributes of an element. + * Attempts to parse all attribute values as JSON text. + * @param {Event} e Event from which the target element's attributes should be extracted. + * @return {Record<string, any>} Object with element attributes as key-value pairs. + */ +export declare function buildAttrs(e: Event): Record<string, any>; +/** + * Builds an object containing all CSS properties of an element. + * @param {Event} e Event from which the target element's properties should be extracted. + * @return {Record<string, string>} Object with all CSS properties as key-value pairs. + */ +export declare function buildCSS(e: Event): Record<string, string>; +//# sourceMappingURL=packageLogs.d.ts.map \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/sendLogs.d.ts b/products/userale/packages/flagon-userale/build/sendLogs.d.ts new file mode 100644 index 0000000..7aef366 --- /dev/null +++ b/products/userale/packages/flagon-userale/build/sendLogs.d.ts @@ -0,0 +1,26 @@ +import { Configuration } from "@/configure"; +import { Logging } from "@/types"; +/** + * Initializes the log queue processors. + * @param {Array<Logging.Log>} logs Array of logs to append to. + * @param {Configuration} config Configuration object to use when logging. + */ +export declare function initSender(logs: Array<Logging.Log>, config: Configuration): void; +/** + * Checks the provided log array on an interval, flushing the logs + * if the queue has reached the threshold specified by the provided config. + * @param {Array<Logging.Log>} logs Array of logs to read from. + * @param {Configuration} config Configuration singleton to be read from. + * @return {Number} The newly created interval id. + */ +export declare function sendOnInterval(logs: Array<Logging.Log>, config: Configuration): NodeJS.Timeout; +export declare function sendOnClose(logs: Array<Logging.Log>, config: Configuration): void; +/** + * Sends the provided array of logs to the specified url, + * retrying the request up to the specified number of retries. + * @param {Array<Logging.Log>} logs Array of logs to send. + * @param {Configuration} config configuration singleton. + * @param {Number} retries Maximum number of attempts to send the logs. + */ +export declare function sendLogs(logs: Array<Logging.Log>, config: Configuration, retries: number): Promise<void>; +//# sourceMappingURL=sendLogs.d.ts.map \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/utils/auth/index.d.ts b/products/userale/packages/flagon-userale/build/utils/auth/index.d.ts new file mode 100644 index 0000000..fee0184 --- /dev/null +++ b/products/userale/packages/flagon-userale/build/utils/auth/index.d.ts @@ -0,0 +1,31 @@ +import { Configuration } from "@/configure"; +import { Callbacks } from "@/types"; +export declare let authCallback: Callbacks.AuthCallback | null; +/** + * Fetches the most up-to-date auth header string from the auth callback + * and updates the config object with the new value. + * @param {Configuration} config Configuration object to be updated. + * @param {Function} authCallback Callback used to fetch the newest header. + * @returns {void} + */ +export declare function updateAuthHeader(config: Configuration): void; +/** + * Registers the provided callback to be used when updating the auth header. + * @param {Callbacks.AuthCallback} callback Callback used to fetch the newest header. Should return a string. + * @returns {boolean} Whether the operation succeeded. + */ +export declare function registerAuthCallback(callback: Callbacks.AuthCallback): boolean; +/** + * Verify that the provided callback is a function which returns a string + * @param {Function} callback Callback used to fetch the newest header. Should return a string. + * @throws {Error} If the callback is not a function or does not return a string. + * @returns {void} + */ +export declare function verifyCallback(callback: Callbacks.AuthCallback): void; +/** + * Resets the authCallback to null. Used for primarily for testing, but could be used + * to remove the callback in production. + * @returns {void} + */ +export declare function resetAuthCallback(): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/utils/headers/index.d.ts b/products/userale/packages/flagon-userale/build/utils/headers/index.d.ts new file mode 100644 index 0000000..a8c3190 --- /dev/null +++ b/products/userale/packages/flagon-userale/build/utils/headers/index.d.ts @@ -0,0 +1,31 @@ +import { Configuration } from "@/configure"; +import { Callbacks } from "@/types"; +export declare let headersCallback: Callbacks.HeadersCallback | null; +/** + * Fetches the most up-to-date custom headers object from the headers callback + * and updates the config object with the new value. + * @param {Configuration} config Configuration object to be updated. + * @param {Callbacks.HeadersCallback} headersCallback Callback used to fetch the newest headers. + * @returns {void} + */ +export declare function updateCustomHeaders(config: Configuration): void; +/** + * Registers the provided callback to be used when updating the auth header. + * @param {Callbacks.HeadersCallback} callback Callback used to fetch the newest headers. Should return an object. + * @returns {boolean} Whether the operation succeeded. + */ +export declare function registerHeadersCallback(callback: Callbacks.HeadersCallback): boolean; +/** + * Verify that the provided callback is a function which returns a string + * @param {Callbacks.HeadersCallback} callback Callback used to fetch the newest header. Should return an object. + * @throws {Error} If the callback is not a function or does not return a string. + * @returns {void} + */ +export declare function verifyCallback(callback: Callbacks.HeadersCallback): void; +/** + * Resets the authCallback to null. Used for primarily for testing, but could be used + * to remove the callback in production. + * @returns {void} + */ +export declare function resetHeadersCallback(): void; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/build/utils/index.d.ts b/products/userale/packages/flagon-userale/build/utils/index.d.ts new file mode 100644 index 0000000..99a4b5a --- /dev/null +++ b/products/userale/packages/flagon-userale/build/utils/index.d.ts @@ -0,0 +1,3 @@ +export { authCallback, updateAuthHeader, registerAuthCallback, resetAuthCallback, verifyCallback as verifyAuthCallback, } from "./auth"; +export { headersCallback, updateCustomHeaders, registerHeadersCallback, resetHeadersCallback, verifyCallback as verifyHeadersCallback, } from "./headers"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/eslint.config.ts b/products/userale/packages/flagon-userale/eslint.config.ts deleted file mode 100644 index 859a5ec..0000000 --- a/products/userale/packages/flagon-userale/eslint.config.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import globals from "globals"; -import pluginJs from "@eslint/js"; -import tseslint from "typescript-eslint"; - - -export default [ - {languageOptions: { globals: globals.browser }}, - pluginJs.configs.recommended, - ...tseslint.configs.recommended, -]; diff --git a/products/userale/packages/flagon-userale/example/react-app-example/src/App.js b/products/userale/packages/flagon-userale/example/react-app-example/src/App.js index fb8ef69..f5979e6 100644 --- a/products/userale/packages/flagon-userale/example/react-app-example/src/App.js +++ b/products/userale/packages/flagon-userale/example/react-app-example/src/App.js @@ -15,35 +15,46 @@ * limitations under the License. */ -import logo from './logo.svg'; -import './App.css'; -import * as userale from 'flagon-userale' +import logo from "./logo.svg"; +import "./App.css"; +import * as userale from "flagon-userale"; function App() { const handleOnClick = () => { - userale.start() - } + userale.start(); + }; userale.options({ autostart: false, - logCountThreshold: '1', - transmitInterval: '1000', - toolName: "Apache UserALE React Example" - }) + logCountThreshold: "1", + transmitInterval: "1000", + toolName: "Apache UserALE React Example", + }); userale.filter(function (log) { - var type_array = ['mouseup', 'mouseover', 'mousedown', 'keydown', 'dblclick', 'blur', 'focus', 'input', 'wheel', 'scroll']; - var logType_array = ['interval']; - return !type_array.includes(log.type) && !logType_array.includes(log.logType); - }) + var type_array = [ + "mouseup", + "mouseover", + "mousedown", + "keydown", + "dblclick", + "blur", + "focus", + "input", + "wheel", + "scroll", + ]; + var logType_array = ["interval"]; + return ( + !type_array.includes(log.type) && !logType_array.includes(log.logType) + ); + }); return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> - <p onClick={handleOnClick}> - Click this text to start userale. - </p> + <p onClick={handleOnClick}>Click this text to start userale.</p> <a className="App-link" href="https://reactjs.org" diff --git a/products/userale/packages/flagon-userale/example/react-app-example/src/index.js b/products/userale/packages/flagon-userale/example/react-app-example/src/index.js index 1485810..4b7e251 100644 --- a/products/userale/packages/flagon-userale/example/react-app-example/src/index.js +++ b/products/userale/packages/flagon-userale/example/react-app-example/src/index.js @@ -15,14 +15,14 @@ * limitations under the License. */ -import React from 'react'; -import ReactDOM from 'react-dom'; -import './index.css'; -import App from './App'; +import React from "react"; +import ReactDOM from "react-dom"; +import "./index.css"; +import App from "./App"; ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, - document.getElementById('root') -); \ No newline at end of file + document.getElementById("root"), +); diff --git a/products/userale/packages/flagon-userale/example/react-app-example/src/setupTests.js b/products/userale/packages/flagon-userale/example/react-app-example/src/setupTests.js index ff2e7b5..08020be 100644 --- a/products/userale/packages/flagon-userale/example/react-app-example/src/setupTests.js +++ b/products/userale/packages/flagon-userale/example/react-app-example/src/setupTests.js @@ -19,4 +19,4 @@ // allows you to do things like: // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom'; +import "@testing-library/jest-dom"; diff --git a/products/userale/packages/flagon-userale/example/test-client.js b/products/userale/packages/flagon-userale/example/test-client.js new file mode 100644 index 0000000..a807a79 --- /dev/null +++ b/products/userale/packages/flagon-userale/example/test-client.js @@ -0,0 +1,32 @@ +"use strict"; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +const ws = new WebSocket("ws://localhost:8000"); +const encoder = new TextEncoder(); +ws.onopen = (event) => { + let logs = new Array(); + logs.push('{"target": "#document","path": [ "Window" ], "pageUrl": "https://github.com/apache/flagon/tree/master/docker", "pageTitle": "flagon/docker at master · apache/flagon · GitHub", "pageReferrer": "https://gov.teams.microsoft.us/", "browser": { "browser": "chrome", "version": "116.0.0" }, "clientTime": 1719530111079, "microTime": 0,"location": { "x": null, "y": null }, "scrnRes": { "width": 1349, "height":954 }, "type": "load", "logType": "raw", "userAction": true, "details": { [...] + logs.push('{"target": "#document","path": [ "Window" ], "pageUrl": "https://github.com/apache/flagon/tree/master/docker", "pageTitle": "flagon/docker at master · apache/flagon · GitHub", "pageReferrer": "https://gov.teams.microsoft.us/", "browser": { "browser": "chrome", "version": "116.0.0" }, "clientTime": 1719530111079, "microTime": 0,"location": { "x": null, "y": null }, "scrnRes": { "width": 1349, "height":954 }, "type": "load", "logType": "raw", "userAction": true, "details": { [...] + let data = JSON.stringify(logs); + //let arr = encoder.encode(message); + ws.send(data); +}; +ws.onmessage = (event) => { + console.log(event.data); +}; diff --git a/products/userale/packages/flagon-userale/package.json b/products/userale/packages/flagon-userale/package.json index 6d1fde2..edf1b8d 100644 --- a/products/userale/packages/flagon-userale/package.json +++ b/products/userale/packages/flagon-userale/package.json @@ -12,13 +12,9 @@ } }, "scripts": { - "format": "prettier --ignore-path .gitignore --write src/ test/", - "lint": "eslint ./src --fix --ext ts --ext js", - "check-types": "tsc --pretty --noEmit", - "build": "tsc && tsup", + "build": "tsup --onSuccess 'tsc --emitDeclarationOnly --declaration'", "clean": "rm -rf ./build", - "test": "jest -c ./test/jest.config.js", - "prepare": "husky", + "test": "jest -c ./test/jest.config.ts", "commit": "cz" }, "repository": { @@ -57,37 +53,29 @@ "npm": ">= 9.x" }, "devDependencies": { - "@eslint/js": "^9.2.0", + "@babel/preset-typescript": "^7.27.1", "@jest/globals": "^29.7.0", - "@playwright/test": "^1.52.0", "@types/jest": "^29.5.14", "@types/jsdom": "^21.1.6", "@types/node": "^20.14.2", "@types/ws": "^8.5.12", - "@typescript-eslint/eslint-plugin": "^7.8.0", - "@typescript-eslint/parser": "^7.8.0", "@typescript/lib-dom": "npm:@types/web@^0.0.144", "body-parser": "^1.20.2", "commander": "^12.1.0", "cypress": "^13.6.0", "cz-conventional-changelog": "^3.3.0", "dom-storage": "^2.1.0", - "esbuild": "^0.21.2", - "eslint": "^8.57.0", "express": "^4.18.2", "global-jsdom": "^24.0.0", "globals": "^15.2.0", - "husky": "^9.0.11", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "jsdom": "^24.0.0", "jsonschema": "^1.4.1", - "prettier": "^3.2.5", "ts-jest": "^29.4.0", "ts-node": "^10.9.2", "tsup": "^5.10.0", "typescript": "^5.8.3", - "typescript-eslint": "^7.8.0", "whatwg-fetch": "^3.6.20", "ws": "^8.18.0" }, diff --git a/products/userale/packages/flagon-userale/src/getInitialSettings.ts b/products/userale/packages/flagon-userale/src/getInitialSettings.ts index ed8b758..34fe95e 100644 --- a/products/userale/packages/flagon-userale/src/getInitialSettings.ts +++ b/products/userale/packages/flagon-userale/src/getInitialSettings.ts @@ -26,46 +26,46 @@ let httpSessionId: string | null = null; * @return {Object} The extracted configuration object */ export function getInitialSettings(): Settings.Config { + if ( + typeof WorkerGlobalScope !== "undefined" && + self instanceof WorkerGlobalScope + ) { + const settings: Settings.Config = { + authHeader: null, + autostart: true, + browserSessionId: null, + custIndex: null, + headers: null, + httpSessionId: null, + logCountThreshold: +5, + logDetails: false, + resolution: +500, + sessionId: sessionId, + time: (ts?: number) => (ts !== undefined ? ts : Date.now()), + toolName: null, + toolVersion: null, + transmitInterval: +5000, + url: "http://localhost:8000", + useraleVersion: null, + userFromParams: null, + userId: null, + }; + return settings; + } - if (typeof WorkerGlobalScope !== "undefined" && - self instanceof WorkerGlobalScope) { - const settings: Settings.Config = { - authHeader: null, - autostart: true, - browserSessionId: null, - custIndex: null, - headers: null, - httpSessionId: null, - logCountThreshold: +(5), - logDetails: false, - resolution: +(500), - sessionId: sessionId, - time: (ts?: number) => (ts !== undefined ? ts : Date.now()), - toolName: null, - toolVersion: null, - transmitInterval: +(5000), - url: "http://localhost:8000", - useraleVersion: null, - userFromParams: null, - userId: null, - }; - return settings; - } - - if (sessionId === null) { - sessionId = getsessionId( - "userAlesessionId", - "session_" + String(Date.now()), - ); - } + if (sessionId === null) { + sessionId = getsessionId( + "userAlesessionId", + "session_" + String(Date.now()), + ); + } - if (httpSessionId === null) { - httpSessionId = getsessionId( - "userAleHttpSessionId", - generatehttpSessionId(), - ); - } - + if (httpSessionId === null) { + httpSessionId = getsessionId( + "userAleHttpSessionId", + generatehttpSessionId(), + ); + } const script = document.currentScript || diff --git a/products/userale/packages/flagon-userale/src/main.ts b/products/userale/packages/flagon-userale/src/main.ts index ab6c6bf..3a209e2 100644 --- a/products/userale/packages/flagon-userale/src/main.ts +++ b/products/userale/packages/flagon-userale/src/main.ts @@ -15,10 +15,20 @@ * limitations under the License. */ +import { defineCustomDetails } from "@/attachHandlers"; +import { registerAuthCallback } from "@/utils"; +import { + addCallbacks, + removeCallbacks, + packageLog, + packageCustomLog, + getSelector, + buildPath, + initPackager, +} from "@/packageLogs"; import { version as userAleVersion } from "../package.json"; import { Configuration } from "@/configure"; import { attachHandlers } from "@/attachHandlers"; -import { initPackager, packageCustomLog } from "@/packageLogs"; import { initSender } from "@/sendLogs"; import type { Settings, Logging } from "@/types"; @@ -28,7 +38,7 @@ const logs: Array<Logging.Log> = []; const startLoadTimestamp = Date.now(); let endLoadTimestamp: number; -self.onload = function() { +self.onload = function () { endLoadTimestamp = Date.now(); }; @@ -76,7 +86,7 @@ function setup(config: Configuration) { attachHandlers(config); initSender(logs, config); started = config.on = true; - if(typeof window !== "undefined" && typeof document !== "undefined") { + if (typeof window !== "undefined" && typeof document !== "undefined") { packageCustomLog( { type: "load", @@ -145,7 +155,6 @@ export function log(customLog: Logging.CustomLog | undefined) { } } - // Only attach to window in IIFE builds if (typeof window !== "undefined") { (window as any).userale = { @@ -154,13 +163,13 @@ if (typeof window !== "undefined") { options, log, version: userAleVersion, - details: require("@/attachHandlers").defineCustomDetails, - registerAuthCallback: require("@/utils").registerAuthCallback, - addCallbacks: require("@/packageLogs").addCallbacks, - removeCallbacks: require("@/packageLogs").removeCallbacks, - packageLog: require("@/packageLogs").packageLog, - packageCustomLog: require("@/packageLogs").packageCustomLog, - getSelector: require("@/packageLogs").getSelector, - buildPath: require("@/packageLogs").buildPath, + details: defineCustomDetails, + registerAuthCallback, + addCallbacks, + removeCallbacks, + packageLog, + packageCustomLog, + getSelector, + buildPath, }; -} \ No newline at end of file +} diff --git a/products/userale/packages/flagon-userale/src/sendLogs.ts b/products/userale/packages/flagon-userale/src/sendLogs.ts index 715f460..c4bc647 100644 --- a/products/userale/packages/flagon-userale/src/sendLogs.ts +++ b/products/userale/packages/flagon-userale/src/sendLogs.ts @@ -73,14 +73,14 @@ export function sendOnClose( logs: Array<Logging.Log>, config: Configuration, ): void { - self.addEventListener("pagehide", function() { + self.addEventListener("pagehide", function () { if (!config.on) { return; } if (logs.length > 0) { const url = new URL(config.url); - + if (url.protocol === "ws:" || url.protocol === "wss:") { const data = JSON.stringify(logs); wsock.send(data); diff --git a/products/userale/packages/flagon-userale/test/globals.d.ts b/products/userale/packages/flagon-userale/test/globals.d.ts new file mode 100644 index 0000000..9debc78 --- /dev/null +++ b/products/userale/packages/flagon-userale/test/globals.d.ts @@ -0,0 +1,2 @@ +// Ensures jest globals are recognized in test files +import "@types/jest"; diff --git a/products/userale/packages/flagon-userale/test/jest.config.js b/products/userale/packages/flagon-userale/test/jest.config.ts similarity index 91% rename from products/userale/packages/flagon-userale/test/jest.config.js rename to products/userale/packages/flagon-userale/test/jest.config.ts index e38b6cb..6202fc3 100644 --- a/products/userale/packages/flagon-userale/test/jest.config.js +++ b/products/userale/packages/flagon-userale/test/jest.config.ts @@ -31,6 +31,14 @@ const config = { }, setupFiles: ["<rootDir>/test/jest.setup.js"], testMatch: ["<rootDir>/test/spec/(*.)+(spec|test).[tj]s?(x)"], + transform: { + "^.+\\.tsx?$": [ + "ts-jest", + { + tsconfig: "./tsconfig.test.json", + }, + ], + }, // Optionally specify this if you want default jsdom behavior: // testEnvironment: "jsdom", }; diff --git a/products/userale/packages/flagon-userale/test/spec/attachHandlers.spec.ts b/products/userale/packages/flagon-userale/test/spec/attachHandlers.spec.ts index 8c0b0ec..3a6a6f7 100644 --- a/products/userale/packages/flagon-userale/test/spec/attachHandlers.spec.ts +++ b/products/userale/packages/flagon-userale/test/spec/attachHandlers.spec.ts @@ -106,7 +106,7 @@ describe("attachHandlers", () => { const rate = 500; jest .spyOn(global.document, "addEventListener") - .mockImplementation(() => { }); + .mockImplementation(() => {}); // Tries to call an event 3 times. Twice in quick succession, then once after the set delay. // Number of actual calls to packageLog are recorded in callCount. Should amount to exactly 2 calls. const listenerHook = (ev: string, fn: CallableFunction) => { @@ -135,6 +135,6 @@ describe("attachHandlers", () => { describe("defineDetails", () => { // TODO: clarify what constitutes "high detail events" and what is "correct" - it.skip("configures high detail events correctly", () => { }); + it.skip("configures high detail events correctly", () => {}); }); }); diff --git a/products/userale/packages/flagon-userale/test/spec/sendLogs.spec.ts b/products/userale/packages/flagon-userale/test/spec/sendLogs.spec.ts index a2c944f..f7fc602 100644 --- a/products/userale/packages/flagon-userale/test/spec/sendLogs.spec.ts +++ b/products/userale/packages/flagon-userale/test/spec/sendLogs.spec.ts @@ -106,7 +106,7 @@ describe("sendLogs", () => { it("sends logs on page exit with fetch", () => { const fetchSpy = jest.spyOn(global, "fetch"); - + config.update({ on: true, url: "http://test.com" }); sendOnClose([], config); config.update({ on: true, url: "http://test.com" }); @@ -118,10 +118,9 @@ describe("sendLogs", () => { fetchSpy.mockRestore(); }); - it("does not send logs on page exit when config is off", () => { const fetchSpy = jest.spyOn(global, "fetch"); - + config.update({ on: false, url: "test" }); sendOnClose([{ foo: "bar" }], config); global.window.dispatchEvent(new window.CustomEvent("pagehide")); @@ -140,30 +139,29 @@ describe("sendLogs", () => { logCountThreshold: 1, }); jest.useFakeTimers(); - + const authCallback = jest.fn().mockReturnValue("fakeAuthToken"); registerAuthCallback(authCallback); - + initSender(logs, config); logs.push({ foo: "bar" }); - + jest.advanceTimersByTime(config.transmitInterval); - + expect(xhrMock.send).toHaveBeenCalledTimes(1); - + // Filter only calls to setRequestHeader with 'Authorization' const calls = (xhrMock.setRequestHeader as jest.Mock).mock.calls; const authHeaderCall = calls.find( - ([header]) => header.toLowerCase() === "authorization" + ([header]) => header.toLowerCase() === "authorization", ); - + expect(authHeaderCall?.[0].toLowerCase()).toBe("authorization"); expect(authHeaderCall?.[1]).toBe("fakeAuthToken"); - + jest.useRealTimers(); done(); }); - it("sends logs with proper custom headers when using registerHeadersCallback", (done) => { const logs: Array<Logging.Log> = []; diff --git a/products/userale/packages/flagon-userale/tsconfig.json b/products/userale/packages/flagon-userale/tsconfig.json index 12d6a32..e60896e 100644 --- a/products/userale/packages/flagon-userale/tsconfig.json +++ b/products/userale/packages/flagon-userale/tsconfig.json @@ -1,54 +1,23 @@ { + "extends": "../../tsconfig.base.json", "compilerOptions": { - "allowJs": false, - "allowSyntheticDefaultImports": true, - "allowUnreachableCode": false, - "allowUnusedLabels": false, - "baseUrl": ".", - "checkJs": false, - "declaration": true, - "declarationDir": "./build", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": false, - "isolatedModules": true, - "jsx": "preserve", - "lib": [ - "ES2021", - "WebWorker", - "dom", - "dom.iterable", - "esnext" - ], - "module": "esnext", - "moduleResolution": "bundler", - "noEmit": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": false, - "noUnusedLocals": true, - "noUnusedParameters": false, - "paths": { - "@/*": [ - "./src/*" - ] - }, - "pretty": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "target": "ES2021", - "typeRoots": [ - "node_modules/@types/" - ], + "composite": true, + "declaration": true, + "declarationMap": true, + "declarationDir": "./build", + "module": "ESNext", + "moduleResolution": "node", + "noEmit": true, + "rootDir": "./src", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } }, "include": [ - "src", - "test", - "src/types.d.ts" + "src/**/*.ts", + "src/types.d.ts" ], - "exclude": [ - "node_modules", - "build", - "logs" - ], -} + "exclude": ["node_modules", "build"] + } + \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/tsconfig.test.json b/products/userale/packages/flagon-userale/tsconfig.test.json new file mode 100644 index 0000000..90efa52 --- /dev/null +++ b/products/userale/packages/flagon-userale/tsconfig.test.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "types": ["jest"], + "allowJs": true + }, + "include": ["src", "test", "**/*.test.ts", "**/*.spec.ts", "**/__tests__/**/*.ts"] +} \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/tsup.config.js b/products/userale/packages/flagon-userale/tsup.config.js index a198654..7989b3b 100644 --- a/products/userale/packages/flagon-userale/tsup.config.js +++ b/products/userale/packages/flagon-userale/tsup.config.js @@ -8,7 +8,7 @@ export default defineConfig([ format: ['esm', 'iife'], name: 'userale', target: 'es2021', - dts: true, + dts: false, sourcemap: true, clean: true, minify: false, diff --git a/products/userale/test/spec/fixtures/extension.fixture.ts b/products/userale/test/spec/fixtures/extension.fixture.ts index 97030b9..e18d2ad 100644 --- a/products/userale/test/spec/fixtures/extension.fixture.ts +++ b/products/userale/test/spec/fixtures/extension.fixture.ts @@ -16,6 +16,7 @@ export const test = base.extend<{ ); const context = await chromium.launchPersistentContext(os.tmpdir(), { channel: 'chromium', + headless: false, args: [ `--disable-extensions-except=${pathToExtension}`, `--load-extension=${pathToExtension}`, @@ -40,7 +41,6 @@ export const test = base.extend<{ const listener = async (req: Request) => { const url = req.url(); const method = req.method(); - // console.log(req); if (!url.startsWith('http://localhost:8000') || method !== 'POST') return; diff --git a/products/userale/tsconfig.base.json b/products/userale/tsconfig.base.json new file mode 100644 index 0000000..851d2f9 --- /dev/null +++ b/products/userale/tsconfig.base.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2021", + "module": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"], + "strict": true, + "esModuleInterop": true, + "moduleResolution": "node", + "skipLibCheck": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "sourceMap": true, + "pretty": true, + "typeRoots": ["node_modules/@types"] + } + } + \ No newline at end of file diff --git a/products/userale/tsconfig.json b/products/userale/tsconfig.json index 71bad78..94dcdcc 100644 --- a/products/userale/tsconfig.json +++ b/products/userale/tsconfig.json @@ -1,14 +1,18 @@ { - "compilerOptions": { - "target": "ESNext", - "module": "CommonJS", - "lib": ["DOM", "ESNext"], - "strict": true, - "esModuleInterop": true, - "moduleResolution": "Node", - "types": ["node", "playwright"], - "skipLibCheck": true - }, - "include": ["**/*.ts", "packages/flagon-userale/test/jest.config.js"] - } - \ No newline at end of file + "references": [ + { "path": "packages/flagon-userale" }, + { "path": "packages/flagon-userale-ext" } + ], + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "lib": ["DOM", "ESNext"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "types": ["node"], + "composite": false + }, + "exclude": ["node_modules"] +}