@formo/analytics 1.17.0 → 1.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/.env.example +1 -0
  2. package/.github/workflows/ci.yml +50 -0
  3. package/.github/workflows/release.yml +54 -0
  4. package/.husky/post-commit +7 -0
  5. package/.husky/pre-commit +11 -0
  6. package/.releaserc.js +34 -0
  7. package/CONTRIBUTING.md +83 -0
  8. package/package.json +1 -4
  9. package/scripts/generate-sri.sh +52 -0
  10. package/src/FormoAnalytics.ts +1031 -0
  11. package/src/FormoAnalyticsProvider.tsx +84 -0
  12. package/src/constants/base.ts +6 -0
  13. package/src/constants/config.ts +660 -0
  14. package/src/constants/events.ts +21 -0
  15. package/src/constants/index.ts +3 -0
  16. package/src/global.d.ts +12 -0
  17. package/src/index.ts +3 -0
  18. package/src/lib/event/EventFactory.ts +519 -0
  19. package/src/lib/event/EventManager.ts +39 -0
  20. package/src/lib/event/constants.ts +4 -0
  21. package/src/lib/event/index.ts +3 -0
  22. package/src/lib/event/type.ts +9 -0
  23. package/src/lib/event/utils.ts +33 -0
  24. package/src/lib/fetch.ts +3 -0
  25. package/src/lib/index.ts +5 -0
  26. package/src/lib/logger/Logger.ts +115 -0
  27. package/src/lib/logger/index.ts +2 -0
  28. package/src/lib/logger/type.ts +14 -0
  29. package/src/lib/queue/EventQueue.ts +306 -0
  30. package/src/lib/queue/index.ts +2 -0
  31. package/src/lib/queue/type.ts +6 -0
  32. package/src/lib/ramda/internal/_curry1.ts +19 -0
  33. package/src/lib/ramda/internal/_curry2.ts +37 -0
  34. package/src/lib/ramda/internal/_curry3.ts +68 -0
  35. package/src/lib/ramda/internal/_has.ts +3 -0
  36. package/src/lib/ramda/internal/_isObject.ts +3 -0
  37. package/src/lib/ramda/internal/_isPlaceholder.ts +5 -0
  38. package/src/lib/ramda/mergeDeepRight.ts +13 -0
  39. package/src/lib/ramda/mergeDeepWithKey.ts +22 -0
  40. package/src/lib/ramda/mergeWithKey.ts +28 -0
  41. package/src/lib/storage/StorageManager.ts +51 -0
  42. package/src/lib/storage/built-in/blueprint.ts +17 -0
  43. package/src/lib/storage/built-in/cookie.ts +60 -0
  44. package/src/lib/storage/built-in/memory.ts +23 -0
  45. package/src/lib/storage/built-in/web.ts +57 -0
  46. package/src/lib/storage/constant.ts +2 -0
  47. package/src/lib/storage/index.ts +25 -0
  48. package/src/lib/storage/type.ts +21 -0
  49. package/src/lib/version.ts +2 -0
  50. package/src/types/base.ts +120 -0
  51. package/src/types/events.ts +126 -0
  52. package/src/types/index.ts +3 -0
  53. package/src/types/provider.ts +17 -0
  54. package/src/utils/address.ts +43 -0
  55. package/src/utils/base.ts +3 -0
  56. package/src/utils/converter.ts +44 -0
  57. package/src/utils/generate.ts +16 -0
  58. package/src/utils/index.ts +4 -0
  59. package/src/utils/timestamp.ts +9 -0
  60. package/src/validators/address.ts +69 -0
  61. package/src/validators/agent.ts +4 -0
  62. package/src/validators/checks.ts +160 -0
  63. package/src/validators/index.ts +7 -0
  64. package/src/validators/network.ts +34 -0
  65. package/src/validators/object.ts +4 -0
  66. package/src/validators/string.ts +4 -0
  67. package/src/validators/uint8array.ts +17 -0
  68. package/test/lib/events.spec.ts +12 -0
  69. package/test/utils/address.spec.ts +14 -0
  70. package/test/utils/converter.spec.ts +31 -0
  71. package/test/validators/address.spec.ts +15 -0
  72. package/tsconfig.json +28 -0
  73. package/webpack.config.ts +23 -0
@@ -0,0 +1,69 @@
1
+ import { isUint8Array, uint8ArrayToHexString } from "./uint8array";
2
+ import { keccak256 } from "ethereum-cryptography/keccak.js";
3
+ import { utf8ToBytes } from "ethereum-cryptography/utils.js";
4
+ import { ValidInputTypes } from "../types";
5
+ import { isHexStrict } from "./string";
6
+
7
+ export const isAddress = (value: ValidInputTypes, checkChecksum = true) => {
8
+ if (typeof value !== "string" && !isUint8Array(value)) {
9
+ return false;
10
+ }
11
+
12
+ let valueToCheck: string;
13
+
14
+ if (isUint8Array(value)) {
15
+ valueToCheck = uint8ArrayToHexString(value);
16
+ } else if (typeof value === "string" && !isHexStrict(value)) {
17
+ valueToCheck = value.toLowerCase().startsWith("0x") ? value : `0x${value}`;
18
+ } else {
19
+ valueToCheck = value;
20
+ }
21
+
22
+ // check if it has the basic requirements of an address
23
+ if (!/^(0x)?[0-9a-f]{40}$/i.test(valueToCheck)) {
24
+ return false;
25
+ }
26
+ // If it's ALL lowercase or ALL upppercase
27
+ if (
28
+ /^(0x|0X)?[0-9a-f]{40}$/.test(valueToCheck) ||
29
+ /^(0x|0X)?[0-9A-F]{40}$/.test(valueToCheck)
30
+ ) {
31
+ return true;
32
+ // Otherwise check each case
33
+ }
34
+ return checkChecksum ? checkAddressCheckSum(valueToCheck) : true;
35
+ };
36
+
37
+ export const checkAddressCheckSum = (data: string): boolean => {
38
+ if (!/^(0x)?[0-9a-f]{40}$/i.test(data)) return false;
39
+ const address = data.slice(2);
40
+ const updatedData = utf8ToBytes(address.toLowerCase());
41
+
42
+ const addressHash = uint8ArrayToHexString(
43
+ keccak256(ensureIfUint8Array(updatedData))
44
+ ).slice(2);
45
+
46
+ for (let i = 0; i < 40; i += 1) {
47
+ // the nth letter should be uppercase if the nth digit of casemap is 1
48
+ if (
49
+ (parseInt(addressHash[i], 16) > 7 &&
50
+ address[i].toUpperCase() !== address[i]) ||
51
+ (parseInt(addressHash[i], 16) <= 7 &&
52
+ address[i].toLowerCase() !== address[i])
53
+ ) {
54
+ return false;
55
+ }
56
+ }
57
+ return true;
58
+ };
59
+
60
+ export function ensureIfUint8Array<T = any>(data: T) {
61
+ if (
62
+ !(data instanceof Uint8Array) &&
63
+ (data as { constructor: { name: string } })?.constructor?.name ===
64
+ "Uint8Array"
65
+ ) {
66
+ return Uint8Array.from(data as unknown as Uint8Array);
67
+ }
68
+ return data;
69
+ }
@@ -0,0 +1,4 @@
1
+ export const isLocalhost = () =>
2
+ /^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*:)*?:?0*1$/.test(
3
+ window.location.hostname
4
+ ) || window.location.protocol === "file:";
@@ -0,0 +1,160 @@
1
+ /**
2
+ * A function to check given value is a function
3
+ * @param value input value
4
+ * @returns boolean
5
+ */
6
+ const isFunction = (value: any): value is Function =>
7
+ typeof value === "function" &&
8
+ Boolean(value.constructor && value.call && value.apply);
9
+
10
+ /**
11
+ * A function to check given value is a string
12
+ * @param value input value
13
+ * @returns boolean
14
+ */
15
+ const isString = (value: any): value is string => typeof value === "string";
16
+
17
+ /**
18
+ * A function to check given value is null or not
19
+ * @param value input value
20
+ * @returns boolean
21
+ */
22
+ const isNull = (value: any): value is null => value === null;
23
+
24
+ /**
25
+ * A function to check given value is undefined
26
+ * @param value input value
27
+ * @returns boolean
28
+ */
29
+ const isUndefined = (value: any): value is undefined =>
30
+ typeof value === "undefined";
31
+
32
+ /**
33
+ * A function to check given value is null or undefined
34
+ * @param value input value
35
+ * @returns boolean
36
+ */
37
+ const isNullOrUndefined = (value: any): boolean =>
38
+ isNull(value) || isUndefined(value);
39
+
40
+ /**
41
+ * Checks if the input is a BigInt
42
+ * @param value input value
43
+ * @returns True if the input is a BigInt
44
+ */
45
+ const isBigInt = (value: any): value is bigint => typeof value === "bigint";
46
+
47
+ /**
48
+ * A function to check given value is defined
49
+ * @param value input value
50
+ * @returns boolean
51
+ */
52
+ const isDefined = (value: any): boolean => !isUndefined(value);
53
+
54
+ /**
55
+ * A function to check given value is defined and not null
56
+ * @param value input value
57
+ * @returns boolean
58
+ */
59
+ const isDefinedAndNotNull = (value: any): boolean => !isNullOrUndefined(value);
60
+
61
+ /**
62
+ * A function to check given value is defined and not null
63
+ * @param value input value
64
+ * @returns boolean
65
+ */
66
+ const isDefinedNotNullAndNotEmptyString = (value: any): boolean =>
67
+ isDefinedAndNotNull(value) && value !== "";
68
+
69
+ /**
70
+ * Determines if the input is of type error
71
+ * @param value input value
72
+ * @returns true if the input is of type error else false
73
+ */
74
+ const isTypeOfError = (value: any): boolean => {
75
+ switch (Object.prototype.toString.call(value)) {
76
+ case "[object Error]":
77
+ case "[object Exception]":
78
+ case "[object DOMException]":
79
+ return true;
80
+ default:
81
+ return value instanceof Error;
82
+ }
83
+ };
84
+
85
+ /**
86
+ * A function to check given value is an array
87
+ * @param value input value
88
+ * @returns true if the input is of type array else false
89
+ */
90
+ const isArray = (arg: any): arg is Array<any> => {
91
+ return Array.isArray(arg);
92
+ };
93
+
94
+ const isBoolean = (arg: any): arg is boolean => {
95
+ return typeof arg === "boolean";
96
+ };
97
+
98
+ const isNumber = (arg: any): arg is number => {
99
+ return typeof arg === "number";
100
+ };
101
+
102
+ const isObject = (value: any): value is object => typeof value === "object";
103
+
104
+ const isObjectAndNotNull = (value: any): value is object =>
105
+ !isNull(value) && isObject(value) && !isArray(value);
106
+
107
+ const isRegExp = (arg: any): arg is RegExp => {
108
+ return isObject(arg) && objectToString(arg) === "[object RegExp]";
109
+ };
110
+
111
+ const isDate = (arg: any): arg is Date => {
112
+ return isObject(arg) && objectToString(arg) === "[object Date]";
113
+ };
114
+
115
+ const isError = (arg: any): arg is Error => {
116
+ return (
117
+ isObject(arg) &&
118
+ (objectToString(arg) === "[object Error]" || arg instanceof Error)
119
+ );
120
+ };
121
+
122
+ const isPrimitive = (
123
+ arg: any
124
+ ): arg is null | boolean | number | string | symbol | undefined => {
125
+ return (
126
+ arg === null ||
127
+ typeof arg === "boolean" ||
128
+ typeof arg === "number" ||
129
+ typeof arg === "string" ||
130
+ typeof arg === "symbol" || // ES6 symbol
131
+ typeof arg === "undefined"
132
+ );
133
+ };
134
+
135
+ const objectToString = (arg: any) => {
136
+ return Object.prototype.toString.call(arg);
137
+ };
138
+
139
+ export {
140
+ isFunction,
141
+ isString,
142
+ isNull,
143
+ isUndefined,
144
+ isNullOrUndefined,
145
+ isTypeOfError,
146
+ isDefined,
147
+ isDefinedAndNotNull,
148
+ isDefinedNotNullAndNotEmptyString,
149
+ isBigInt,
150
+ isArray,
151
+ isBoolean,
152
+ isNumber,
153
+ isObject,
154
+ isObjectAndNotNull,
155
+ isRegExp,
156
+ isDate,
157
+ isError,
158
+ isPrimitive,
159
+ objectToString,
160
+ };
@@ -0,0 +1,7 @@
1
+ export * from "./address";
2
+ export * from "./agent";
3
+ export * from "./checks";
4
+ export * from "./network";
5
+ export * from "./object";
6
+ export * from "./string";
7
+ export * from "./uint8array";
@@ -0,0 +1,34 @@
1
+ const objectToString = Object.prototype.toString;
2
+
3
+ const isError = (value: any) => objectToString.call(value) === "[object Error]";
4
+
5
+ const errorMessages = new Set([
6
+ "network error", // Chrome
7
+ "Failed to fetch", // Chrome
8
+ "NetworkError when attempting to fetch resource.", // Firefox
9
+ "The Internet connection appears to be offline.", // Safari 16
10
+ "Load failed", // Safari 17+
11
+ "Network request failed", // `cross-fetch`
12
+ "fetch failed", // Undici (Node.js)
13
+ "terminated", // Undici (Node.js)
14
+ ]);
15
+
16
+ export function isNetworkError(error: any) {
17
+ const isValid =
18
+ error &&
19
+ isError(error) &&
20
+ error.name === "TypeError" &&
21
+ typeof error.message === "string";
22
+
23
+ if (!isValid) {
24
+ return false;
25
+ }
26
+
27
+ // We do an extra check for Safari 17+ as it has a very generic error message.
28
+ // Network errors in Safari have no stack.
29
+ if (error.message === "Load failed") {
30
+ return error.stack === undefined;
31
+ }
32
+
33
+ return errorMessages.has(error.message);
34
+ }
@@ -0,0 +1,4 @@
1
+ export const isNullish = (item: unknown): item is undefined | null =>
2
+ // Using "null" value intentionally for validation
3
+ // eslint-disable-next-line no-null/no-null
4
+ item === undefined || item === null;
@@ -0,0 +1,4 @@
1
+ import { ValidInputTypes } from "../types";
2
+
3
+ export const isHexStrict = (hex: ValidInputTypes) =>
4
+ typeof hex === "string" && /^((-)?0x[0-9a-f]+|(0x))$/i.test(hex);
@@ -0,0 +1,17 @@
1
+ export function isUint8Array(data: unknown | Uint8Array): data is Uint8Array {
2
+ return (
3
+ data instanceof Uint8Array ||
4
+ (data as { constructor: { name: string } })?.constructor?.name ===
5
+ "Uint8Array" ||
6
+ (data as { constructor: { name: string } })?.constructor?.name === "Buffer"
7
+ );
8
+ }
9
+
10
+ export function uint8ArrayToHexString(uint8Array: Uint8Array): string {
11
+ let hexString = "0x";
12
+ for (const e of uint8Array as any) {
13
+ const hex = e.toString(16);
14
+ hexString += hex.length === 1 ? `0${hex}` : hex;
15
+ }
16
+ return hexString;
17
+ }
@@ -0,0 +1,12 @@
1
+ import { describe, it } from "mocha";
2
+ import { expect } from "chai";
3
+ import { getCookieDomain } from "../../src/lib/event/utils";
4
+
5
+ describe("getCookieDomain", () => {
6
+ it("should return the cookie domain format", () => {
7
+ expect(getCookieDomain("192.168.0.1")).to.equal("");
8
+ expect(getCookieDomain("localhost:3000")).to.equal("");
9
+ expect(getCookieDomain("example.com")).to.equal(".example.com");
10
+ expect(getCookieDomain("www.example.com")).to.equal(".example.com");
11
+ });
12
+ });
@@ -0,0 +1,14 @@
1
+ import { describe, it } from "mocha";
2
+ import { expect } from "chai";
3
+ import { toChecksumAddress } from "../../src/utils";
4
+
5
+ describe("toChecksumAddress", () => {
6
+ it("should return the checksum of the address", () => {
7
+ expect(
8
+ toChecksumAddress("0x82827Bc8342a16b681AfbA6B979E3D1aE5F28a0e")
9
+ ).to.equal("0x82827Bc8342a16b681AfbA6B979E3D1aE5F28a0e");
10
+ expect(
11
+ toChecksumAddress("0x82827bc8342a16b681afba6b979e3d1ae5f28a0e")
12
+ ).to.equal("0x82827Bc8342a16b681AfbA6B979E3D1aE5F28a0e");
13
+ });
14
+ });
@@ -0,0 +1,31 @@
1
+ import { describe, it } from "mocha";
2
+ import { expect } from "chai";
3
+ import { toSnakeCase } from "../../src/utils";
4
+
5
+ describe("toSnakeCase", () => {
6
+ it("should convert object keys to snake case", () => {
7
+ expect(
8
+ toSnakeCase({ chainId: "12345", hashMessage: "John Doe" })
9
+ ).to.deep.equal({
10
+ chain_id: "12345",
11
+ hash_message: "John Doe",
12
+ });
13
+ });
14
+
15
+ it("should convert object keys to snake case, omitting keys in the omitKeys array", () => {
16
+ expect(
17
+ toSnakeCase(
18
+ {
19
+ chainId: "12345",
20
+ hashMessage: "John Doe",
21
+ "user-agent": "Mozilla/5.0",
22
+ },
23
+ ["user-agent"]
24
+ )
25
+ ).to.deep.equal({
26
+ chain_id: "12345",
27
+ hash_message: "John Doe",
28
+ "user-agent": "Mozilla/5.0",
29
+ });
30
+ });
31
+ });
@@ -0,0 +1,15 @@
1
+ import { expect } from "chai";
2
+ import { describe, it } from "mocha";
3
+ import { isAddress } from "../../src/validators";
4
+
5
+ describe("isAddress", () => {
6
+ it("should return true if the input is a valid ethereum address", () => {
7
+ expect(isAddress("0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC")).to.equal(
8
+ true
9
+ );
10
+ });
11
+
12
+ it("should return false otherwise", () => {
13
+ expect(isAddress("o")).to.equal(false);
14
+ });
15
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "react-jsx",
4
+ "outDir": "dist/cjs",
5
+ "allowJs": false,
6
+ "esModuleInterop": true,
7
+ "resolveJsonModule": true,
8
+ "skipLibCheck": true,
9
+ "strict": true,
10
+ "module": "commonjs",
11
+ "target": "es5",
12
+ "lib": ["es2015", "dom"],
13
+ "moduleResolution": "node",
14
+ "declaration": true,
15
+ "noImplicitThis": false,
16
+ "noImplicitAny": true,
17
+ "noUnusedParameters": true,
18
+ "declarationMap": true,
19
+ "composite": true,
20
+ "incremental": true,
21
+ "sourceMap": true,
22
+ "isolatedModules": true
23
+ },
24
+ "ts-node": {
25
+ "files": true
26
+ },
27
+ "include": ["src", "test"]
28
+ }
@@ -0,0 +1,23 @@
1
+ import path from "path";
2
+
3
+ module.exports = {
4
+ entry: {
5
+ bundle: "./src/index.ts",
6
+ "bundle.min": "./src/index.ts",
7
+ },
8
+ output: {
9
+ path: path.resolve(__dirname, "dist"),
10
+ filename: "index.umd.min.js",
11
+ libraryTarget: "umd",
12
+ library: "FormoAnalytics",
13
+ libraryExport: "FormoAnalytics",
14
+ umdNamedDefine: true,
15
+ },
16
+ resolve: {
17
+ extensions: [".ts", ".tsx", ".js"],
18
+ },
19
+ devtool: "source-map",
20
+ module: {
21
+ rules: [{ test: /\.tsx?$/, loader: "ts-loader" }],
22
+ },
23
+ };