@formo/analytics 1.23.0 → 1.24.0
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.
- package/README.md +75 -2
- package/dist/cjs/src/FormoAnalytics.js +1 -1
- package/dist/cjs/src/lib/event/EventFactory.d.ts +5 -1
- package/dist/cjs/src/lib/event/EventFactory.js +61 -6
- package/dist/cjs/src/lib/event/EventManager.d.ts +3 -2
- package/dist/cjs/src/lib/event/EventManager.js +3 -2
- package/dist/cjs/src/types/base.d.ts +24 -0
- package/dist/cjs/src/version.d.ts +2 -0
- package/dist/cjs/src/version.js +7 -0
- package/dist/esm/src/FormoAnalytics.js +1 -1
- package/dist/esm/src/lib/event/EventFactory.d.ts +5 -1
- package/dist/esm/src/lib/event/EventFactory.js +61 -6
- package/dist/esm/src/lib/event/EventManager.d.ts +3 -2
- package/dist/esm/src/lib/event/EventManager.js +3 -2
- package/dist/esm/src/types/base.d.ts +24 -0
- package/dist/esm/src/version.d.ts +2 -0
- package/dist/esm/src/version.js +4 -0
- package/dist/index.umd.min.js +1 -1
- package/package.json +14 -30
- package/dist/cjs/src/lib/version.d.ts +0 -2
- package/dist/cjs/src/lib/version.js +0 -6
- package/dist/esm/src/lib/version.d.ts +0 -2
- package/dist/esm/src/lib/version.js +0 -3
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
-
The Formo Web SDK is a Javascript library that allows you to track
|
|
20
|
+
The Formo Web SDK is a Javascript library that allows you to track user event data from your website and app.
|
|
21
21
|
|
|
22
22
|
You can install Formo on:
|
|
23
23
|
- [Websites](https://docs.formo.so/install#website)
|
|
@@ -36,7 +36,80 @@ Learn how Formo handles [onchain attribution](https://docs.formo.so/data/attribu
|
|
|
36
36
|
|
|
37
37
|
Join the [Formo community Slack channel](https://formo.so/slack) for help and questions.
|
|
38
38
|
|
|
39
|
+
## Development
|
|
40
|
+
|
|
41
|
+
### Building the SDK
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pnpm install
|
|
45
|
+
pnpm build
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Running Tests
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pnpm test
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Publishing a New Release
|
|
55
|
+
|
|
56
|
+
This project uses **OIDC Trusted Publishing** for secure, automated npm releases. No manual token management required!
|
|
57
|
+
|
|
58
|
+
1. **(Optional) Preview release notes**:
|
|
59
|
+
```bash
|
|
60
|
+
pnpm preview-release
|
|
61
|
+
```
|
|
62
|
+
This shows what the release notes will look like based on commits since the last tag.
|
|
63
|
+
|
|
64
|
+
2. **Update the version** in `package.json`:
|
|
65
|
+
```bash
|
|
66
|
+
npm version patch # For bug fixes (1.24.0 → 1.24.1)
|
|
67
|
+
npm version minor # For new features (1.24.0 → 1.25.0)
|
|
68
|
+
npm version major # For breaking changes (1.24.0 → 2.0.0)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> **Note**: `npm version` automatically:
|
|
72
|
+
> - Updates `package.json` with the new version
|
|
73
|
+
> - Updates `src/version.ts` with the new version (via the `version` script)
|
|
74
|
+
> - Creates a git commit with the changes
|
|
75
|
+
> - Creates a version tag (e.g., `v1.24.1`)
|
|
76
|
+
|
|
77
|
+
3. **Push the commit and tag**:
|
|
78
|
+
```bash
|
|
79
|
+
git push --follow-tags
|
|
80
|
+
# or separately:
|
|
81
|
+
# git push && git push --tags
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
> **Important**: You must push both the commit AND the tag. Use `--follow-tags` to push both in one command.
|
|
85
|
+
|
|
86
|
+
4. **Automatic workflow execution**:
|
|
87
|
+
- GitHub Actions workflow triggers on the `v*` tag
|
|
88
|
+
- Builds and tests the package
|
|
89
|
+
- Publishes to npm using OIDC (no tokens needed!)
|
|
90
|
+
- Creates a GitHub release with:
|
|
91
|
+
- Changelog from git commits
|
|
92
|
+
- Installation instructions
|
|
93
|
+
- CDN usage examples
|
|
94
|
+
- SRI hash for secure CDN usage
|
|
95
|
+
|
|
96
|
+
#### What Gets Published
|
|
97
|
+
|
|
98
|
+
- **npm**: `@formo/analytics@<version>`
|
|
99
|
+
- **GitHub Release**: Tagged release with changelog and SRI hash
|
|
100
|
+
- **CDN**: `https://cdn.formo.so/analytics@<version>`
|
|
101
|
+
- **Provenance**: Automatically generated cryptographic attestations
|
|
102
|
+
|
|
103
|
+
#### Security Features
|
|
104
|
+
|
|
105
|
+
✅ **OIDC Trusted Publishing** - No long-lived tokens
|
|
106
|
+
✅ **Automatic Provenance** - Cryptographic proof of build authenticity
|
|
107
|
+
✅ **SRI Hash** - Subresource integrity for CDN usage
|
|
108
|
+
✅ **Secure by Default** - Short-lived, workflow-specific credentials
|
|
109
|
+
|
|
110
|
+
Learn more: [npm Trusted Publishing Documentation](https://docs.npmjs.com/trusted-publishers)
|
|
111
|
+
|
|
39
112
|
## Contributing
|
|
40
113
|
|
|
41
|
-
|
|
114
|
+
Contributions are welcome! Feel free to open fixes and feature suggestions.
|
|
42
115
|
|
|
@@ -126,7 +126,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
126
126
|
retryCount: options.retryCount,
|
|
127
127
|
maxQueueSize: options.maxQueueSize,
|
|
128
128
|
flushInterval: options.flushInterval,
|
|
129
|
-
}));
|
|
129
|
+
}), options);
|
|
130
130
|
// Check consent status on initialization
|
|
131
131
|
if (this.hasOptedOutTracking()) {
|
|
132
132
|
lib_1.logger.info("User has previously opted out of tracking");
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { Address, APIEvent, ChainID, IFormoEvent, IFormoEventContext, IFormoEventProperties, Nullable, SignatureStatus, TransactionStatus } from "../../types";
|
|
1
|
+
import { Address, APIEvent, ChainID, IFormoEvent, IFormoEventContext, IFormoEventProperties, Nullable, Options, SignatureStatus, TransactionStatus } from "../../types";
|
|
2
2
|
import { IEventFactory } from "./type";
|
|
3
3
|
declare class EventFactory implements IEventFactory {
|
|
4
|
+
private options?;
|
|
5
|
+
private compiledPathPattern?;
|
|
6
|
+
constructor(options?: Options);
|
|
4
7
|
private getTimezone;
|
|
5
8
|
private getLocation;
|
|
6
9
|
private getLanguage;
|
|
@@ -8,6 +11,7 @@ declare class EventFactory implements IEventFactory {
|
|
|
8
11
|
private extractUTMParameters;
|
|
9
12
|
private extractReferralParameter;
|
|
10
13
|
private getTrafficSources;
|
|
14
|
+
private getScreen;
|
|
11
15
|
private generateContext;
|
|
12
16
|
/**
|
|
13
17
|
* Add any missing default page properties using values from options and defaults
|
|
@@ -59,13 +59,14 @@ var validators_1 = require("../../validators");
|
|
|
59
59
|
var logger_1 = require("../logger");
|
|
60
60
|
var mergeDeepRight_1 = __importDefault(require("../ramda/mergeDeepRight"));
|
|
61
61
|
var storage_1 = require("../storage");
|
|
62
|
-
var version_1 = require("
|
|
62
|
+
var version_1 = require("../../version");
|
|
63
63
|
var constants_2 = require("./constants");
|
|
64
64
|
var utils_2 = require("./utils");
|
|
65
65
|
var browsers_1 = require("../browser/browsers");
|
|
66
66
|
var EventFactory = /** @class */ (function () {
|
|
67
|
-
function EventFactory() {
|
|
67
|
+
function EventFactory(options) {
|
|
68
68
|
var _this = this;
|
|
69
|
+
var _a;
|
|
69
70
|
this.extractUTMParameters = function (url) {
|
|
70
71
|
var result = {
|
|
71
72
|
utm_campaign: "",
|
|
@@ -87,14 +88,33 @@ var EventFactory = /** @class */ (function () {
|
|
|
87
88
|
return result;
|
|
88
89
|
};
|
|
89
90
|
this.extractReferralParameter = function (urlObj) {
|
|
90
|
-
var _a;
|
|
91
|
-
|
|
91
|
+
var _a, _b, _c;
|
|
92
|
+
// Strategy: Check query params first, then check path pattern if configured
|
|
93
|
+
// Query params logic:
|
|
94
|
+
// - If no referral config exists → use defaults
|
|
95
|
+
// - If referral config exists but queryParams is undefined → use defaults
|
|
96
|
+
// - If referral config exists with queryParams → use those
|
|
97
|
+
var defaultParams = ["ref", "referral", "refcode"];
|
|
98
|
+
var referralParams = !((_a = _this.options) === null || _a === void 0 ? void 0 : _a.referral)
|
|
99
|
+
? defaultParams // No referral config at all → use defaults
|
|
100
|
+
: ((_b = _this.options.referral.queryParams) !== null && _b !== void 0 ? _b : defaultParams); // Has config → use queryParams or defaults
|
|
101
|
+
// Check query parameters (if any configured)
|
|
92
102
|
for (var _i = 0, referralParams_1 = referralParams; _i < referralParams_1.length; _i++) {
|
|
93
103
|
var param = referralParams_1[_i];
|
|
94
|
-
var value = (
|
|
104
|
+
var value = (_c = urlObj.searchParams.get(param)) === null || _c === void 0 ? void 0 : _c.trim();
|
|
95
105
|
if (value)
|
|
96
106
|
return value;
|
|
97
107
|
}
|
|
108
|
+
// Check URL path pattern if configured
|
|
109
|
+
if (_this.compiledPathPattern) {
|
|
110
|
+
var pathname = urlObj.pathname;
|
|
111
|
+
var match = pathname.match(_this.compiledPathPattern);
|
|
112
|
+
if (match && match[1]) {
|
|
113
|
+
var referralCode = match[1].trim();
|
|
114
|
+
if (referralCode)
|
|
115
|
+
return referralCode;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
98
118
|
return "";
|
|
99
119
|
};
|
|
100
120
|
this.getTrafficSources = function (url) {
|
|
@@ -148,6 +168,16 @@ var EventFactory = /** @class */ (function () {
|
|
|
148
168
|
}
|
|
149
169
|
return pageProps;
|
|
150
170
|
};
|
|
171
|
+
this.options = options;
|
|
172
|
+
// Compile regex pattern once for better performance
|
|
173
|
+
if ((_a = options === null || options === void 0 ? void 0 : options.referral) === null || _a === void 0 ? void 0 : _a.pathPattern) {
|
|
174
|
+
try {
|
|
175
|
+
this.compiledPathPattern = new RegExp(options.referral.pathPattern);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
logger_1.logger.warn("Invalid referral path pattern: ".concat(options.referral.pathPattern, ". Error: ").concat(error));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
151
181
|
}
|
|
152
182
|
EventFactory.prototype.getTimezone = function () {
|
|
153
183
|
try {
|
|
@@ -184,6 +214,31 @@ var EventFactory = /** @class */ (function () {
|
|
|
184
214
|
EventFactory.prototype.getLibraryVersion = function () {
|
|
185
215
|
return version_1.version;
|
|
186
216
|
};
|
|
217
|
+
// Get screen dimensions and pixel density
|
|
218
|
+
// Returns safe defaults if any error occurs to ensure event creation continues
|
|
219
|
+
EventFactory.prototype.getScreen = function () {
|
|
220
|
+
var _a, _b;
|
|
221
|
+
var safeDefaults = {
|
|
222
|
+
screen_width: 0,
|
|
223
|
+
screen_height: 0,
|
|
224
|
+
screen_density: 1,
|
|
225
|
+
viewport_width: 0,
|
|
226
|
+
viewport_height: 0,
|
|
227
|
+
};
|
|
228
|
+
try {
|
|
229
|
+
return {
|
|
230
|
+
screen_width: ((_a = globalThis.screen) === null || _a === void 0 ? void 0 : _a.width) || 0,
|
|
231
|
+
screen_height: ((_b = globalThis.screen) === null || _b === void 0 ? void 0 : _b.height) || 0,
|
|
232
|
+
screen_density: globalThis.devicePixelRatio || 1,
|
|
233
|
+
viewport_width: globalThis.innerWidth || 0,
|
|
234
|
+
viewport_height: globalThis.innerHeight || 0,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
logger_1.logger.error("Error resolving screen properties:", error);
|
|
239
|
+
return safeDefaults;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
187
242
|
// Contextual fields that are automatically collected and populated by the Formo SDK
|
|
188
243
|
EventFactory.prototype.generateContext = function (context) {
|
|
189
244
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -199,7 +254,7 @@ var EventFactory = /** @class */ (function () {
|
|
|
199
254
|
timezone = this.getTimezone();
|
|
200
255
|
location = this.getLocation();
|
|
201
256
|
library_version = this.getLibraryVersion();
|
|
202
|
-
defaultContext = __assign(__assign({ user_agent: globalThis.navigator.userAgent, locale: language, timezone: timezone, location: location }, this.getTrafficSources(globalThis.location.href)), { page_path: path, page_title: document.title, page_url: globalThis.location.href, library_name: "Formo Web SDK", library_version: library_version, browser: browserName });
|
|
257
|
+
defaultContext = __assign(__assign(__assign({ user_agent: globalThis.navigator.userAgent, locale: language, timezone: timezone, location: location }, this.getTrafficSources(globalThis.location.href)), { page_path: path, page_title: document.title, page_url: globalThis.location.href, library_name: "Formo Web SDK", library_version: library_version, browser: browserName }), this.getScreen());
|
|
203
258
|
mergedContext = (0, mergeDeepRight_1.default)(defaultContext, context || {});
|
|
204
259
|
return [2 /*return*/, mergedContext];
|
|
205
260
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Address, APIEvent } from "../../types";
|
|
1
|
+
import { Address, APIEvent, Options } from "../../types";
|
|
2
2
|
import { IEventQueue } from "../queue";
|
|
3
3
|
import { IEventFactory, IEventManager } from "./type";
|
|
4
4
|
/**
|
|
@@ -10,8 +10,9 @@ declare class EventManager implements IEventManager {
|
|
|
10
10
|
/**
|
|
11
11
|
*
|
|
12
12
|
* @param eventQueue Event queue instance
|
|
13
|
+
* @param options Optional configuration (referral parsing, etc.)
|
|
13
14
|
*/
|
|
14
|
-
constructor(eventQueue: IEventQueue);
|
|
15
|
+
constructor(eventQueue: IEventQueue, options?: Options);
|
|
15
16
|
/**
|
|
16
17
|
* Consumes a new incoming event
|
|
17
18
|
* @param event Incoming event data
|
|
@@ -58,10 +58,11 @@ var EventManager = /** @class */ (function () {
|
|
|
58
58
|
/**
|
|
59
59
|
*
|
|
60
60
|
* @param eventQueue Event queue instance
|
|
61
|
+
* @param options Optional configuration (referral parsing, etc.)
|
|
61
62
|
*/
|
|
62
|
-
function EventManager(eventQueue) {
|
|
63
|
+
function EventManager(eventQueue, options) {
|
|
63
64
|
this.eventQueue = eventQueue;
|
|
64
|
-
this.eventFactory = new EventFactory_1.EventFactory();
|
|
65
|
+
this.eventFactory = new EventFactory_1.EventFactory(options);
|
|
65
66
|
}
|
|
66
67
|
/**
|
|
67
68
|
* Consumes a new incoming event
|
|
@@ -94,6 +94,24 @@ export interface AutocaptureOptions {
|
|
|
94
94
|
*/
|
|
95
95
|
chain?: boolean;
|
|
96
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Configuration options for referral parameter parsing
|
|
99
|
+
*/
|
|
100
|
+
export interface ReferralOptions {
|
|
101
|
+
/**
|
|
102
|
+
* Custom query parameter names to check for referral codes
|
|
103
|
+
* @default ["ref", "referral", "refcode"]
|
|
104
|
+
* @example ["via", "referrer", "source"] - will check ?via=CODE, ?referrer=CODE, ?source=CODE
|
|
105
|
+
*/
|
|
106
|
+
queryParams?: string[];
|
|
107
|
+
/**
|
|
108
|
+
* URL path pattern to extract referral code from
|
|
109
|
+
* Should be a regex string that matches the path segment containing the referral code
|
|
110
|
+
* The first capture group will be used as the referral code
|
|
111
|
+
* @example "/r/([^/]+)" - will extract "01K17FKB" from "https://glider.fi/r/01K17FKB"
|
|
112
|
+
*/
|
|
113
|
+
pathPattern?: string;
|
|
114
|
+
}
|
|
97
115
|
export interface Options {
|
|
98
116
|
provider?: EIP1193Provider;
|
|
99
117
|
tracking?: boolean | TrackingOptions;
|
|
@@ -122,6 +140,12 @@ export interface Options {
|
|
|
122
140
|
enabled?: boolean;
|
|
123
141
|
levels?: LogLevel[];
|
|
124
142
|
};
|
|
143
|
+
/**
|
|
144
|
+
* Configuration for referral parameter parsing from URLs
|
|
145
|
+
* Allows customizing how referral codes are detected from query parameters and URL paths
|
|
146
|
+
* @example { queryParams: ["via"], pathPattern: "/r/([^/]+)" }
|
|
147
|
+
*/
|
|
148
|
+
referral?: ReferralOptions;
|
|
125
149
|
ready?: (formo: IFormoAnalytics) => void;
|
|
126
150
|
}
|
|
127
151
|
export interface FormoAnalyticsProviderProps {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.version = void 0;
|
|
4
|
+
// This file is auto-generated by scripts/update-version.js during npm version
|
|
5
|
+
// Do not edit manually - it will be overwritten
|
|
6
|
+
exports.version = '1.24.0';
|
|
7
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -123,7 +123,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
123
123
|
retryCount: options.retryCount,
|
|
124
124
|
maxQueueSize: options.maxQueueSize,
|
|
125
125
|
flushInterval: options.flushInterval,
|
|
126
|
-
}));
|
|
126
|
+
}), options);
|
|
127
127
|
// Check consent status on initialization
|
|
128
128
|
if (this.hasOptedOutTracking()) {
|
|
129
129
|
logger.info("User has previously opted out of tracking");
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { Address, APIEvent, ChainID, IFormoEvent, IFormoEventContext, IFormoEventProperties, Nullable, SignatureStatus, TransactionStatus } from "../../types";
|
|
1
|
+
import { Address, APIEvent, ChainID, IFormoEvent, IFormoEventContext, IFormoEventProperties, Nullable, Options, SignatureStatus, TransactionStatus } from "../../types";
|
|
2
2
|
import { IEventFactory } from "./type";
|
|
3
3
|
declare class EventFactory implements IEventFactory {
|
|
4
|
+
private options?;
|
|
5
|
+
private compiledPathPattern?;
|
|
6
|
+
constructor(options?: Options);
|
|
4
7
|
private getTimezone;
|
|
5
8
|
private getLocation;
|
|
6
9
|
private getLanguage;
|
|
@@ -8,6 +11,7 @@ declare class EventFactory implements IEventFactory {
|
|
|
8
11
|
private extractUTMParameters;
|
|
9
12
|
private extractReferralParameter;
|
|
10
13
|
private getTrafficSources;
|
|
14
|
+
private getScreen;
|
|
11
15
|
private generateContext;
|
|
12
16
|
/**
|
|
13
17
|
* Add any missing default page properties using values from options and defaults
|
|
@@ -53,13 +53,14 @@ import { isUndefined } from "../../validators";
|
|
|
53
53
|
import { logger } from "../logger";
|
|
54
54
|
import mergeDeepRight from "../ramda/mergeDeepRight";
|
|
55
55
|
import { session } from "../storage";
|
|
56
|
-
import { version } from "
|
|
56
|
+
import { version } from "../../version";
|
|
57
57
|
import { CHANNEL, VERSION } from "./constants";
|
|
58
58
|
import { generateAnonymousId } from "./utils";
|
|
59
59
|
import { detectBrowser } from "../browser/browsers";
|
|
60
60
|
var EventFactory = /** @class */ (function () {
|
|
61
|
-
function EventFactory() {
|
|
61
|
+
function EventFactory(options) {
|
|
62
62
|
var _this = this;
|
|
63
|
+
var _a;
|
|
63
64
|
this.extractUTMParameters = function (url) {
|
|
64
65
|
var result = {
|
|
65
66
|
utm_campaign: "",
|
|
@@ -81,14 +82,33 @@ var EventFactory = /** @class */ (function () {
|
|
|
81
82
|
return result;
|
|
82
83
|
};
|
|
83
84
|
this.extractReferralParameter = function (urlObj) {
|
|
84
|
-
var _a;
|
|
85
|
-
|
|
85
|
+
var _a, _b, _c;
|
|
86
|
+
// Strategy: Check query params first, then check path pattern if configured
|
|
87
|
+
// Query params logic:
|
|
88
|
+
// - If no referral config exists → use defaults
|
|
89
|
+
// - If referral config exists but queryParams is undefined → use defaults
|
|
90
|
+
// - If referral config exists with queryParams → use those
|
|
91
|
+
var defaultParams = ["ref", "referral", "refcode"];
|
|
92
|
+
var referralParams = !((_a = _this.options) === null || _a === void 0 ? void 0 : _a.referral)
|
|
93
|
+
? defaultParams // No referral config at all → use defaults
|
|
94
|
+
: ((_b = _this.options.referral.queryParams) !== null && _b !== void 0 ? _b : defaultParams); // Has config → use queryParams or defaults
|
|
95
|
+
// Check query parameters (if any configured)
|
|
86
96
|
for (var _i = 0, referralParams_1 = referralParams; _i < referralParams_1.length; _i++) {
|
|
87
97
|
var param = referralParams_1[_i];
|
|
88
|
-
var value = (
|
|
98
|
+
var value = (_c = urlObj.searchParams.get(param)) === null || _c === void 0 ? void 0 : _c.trim();
|
|
89
99
|
if (value)
|
|
90
100
|
return value;
|
|
91
101
|
}
|
|
102
|
+
// Check URL path pattern if configured
|
|
103
|
+
if (_this.compiledPathPattern) {
|
|
104
|
+
var pathname = urlObj.pathname;
|
|
105
|
+
var match = pathname.match(_this.compiledPathPattern);
|
|
106
|
+
if (match && match[1]) {
|
|
107
|
+
var referralCode = match[1].trim();
|
|
108
|
+
if (referralCode)
|
|
109
|
+
return referralCode;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
92
112
|
return "";
|
|
93
113
|
};
|
|
94
114
|
this.getTrafficSources = function (url) {
|
|
@@ -142,6 +162,16 @@ var EventFactory = /** @class */ (function () {
|
|
|
142
162
|
}
|
|
143
163
|
return pageProps;
|
|
144
164
|
};
|
|
165
|
+
this.options = options;
|
|
166
|
+
// Compile regex pattern once for better performance
|
|
167
|
+
if ((_a = options === null || options === void 0 ? void 0 : options.referral) === null || _a === void 0 ? void 0 : _a.pathPattern) {
|
|
168
|
+
try {
|
|
169
|
+
this.compiledPathPattern = new RegExp(options.referral.pathPattern);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
logger.warn("Invalid referral path pattern: ".concat(options.referral.pathPattern, ". Error: ").concat(error));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
145
175
|
}
|
|
146
176
|
EventFactory.prototype.getTimezone = function () {
|
|
147
177
|
try {
|
|
@@ -178,6 +208,31 @@ var EventFactory = /** @class */ (function () {
|
|
|
178
208
|
EventFactory.prototype.getLibraryVersion = function () {
|
|
179
209
|
return version;
|
|
180
210
|
};
|
|
211
|
+
// Get screen dimensions and pixel density
|
|
212
|
+
// Returns safe defaults if any error occurs to ensure event creation continues
|
|
213
|
+
EventFactory.prototype.getScreen = function () {
|
|
214
|
+
var _a, _b;
|
|
215
|
+
var safeDefaults = {
|
|
216
|
+
screen_width: 0,
|
|
217
|
+
screen_height: 0,
|
|
218
|
+
screen_density: 1,
|
|
219
|
+
viewport_width: 0,
|
|
220
|
+
viewport_height: 0,
|
|
221
|
+
};
|
|
222
|
+
try {
|
|
223
|
+
return {
|
|
224
|
+
screen_width: ((_a = globalThis.screen) === null || _a === void 0 ? void 0 : _a.width) || 0,
|
|
225
|
+
screen_height: ((_b = globalThis.screen) === null || _b === void 0 ? void 0 : _b.height) || 0,
|
|
226
|
+
screen_density: globalThis.devicePixelRatio || 1,
|
|
227
|
+
viewport_width: globalThis.innerWidth || 0,
|
|
228
|
+
viewport_height: globalThis.innerHeight || 0,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
logger.error("Error resolving screen properties:", error);
|
|
233
|
+
return safeDefaults;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
181
236
|
// Contextual fields that are automatically collected and populated by the Formo SDK
|
|
182
237
|
EventFactory.prototype.generateContext = function (context) {
|
|
183
238
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -193,7 +248,7 @@ var EventFactory = /** @class */ (function () {
|
|
|
193
248
|
timezone = this.getTimezone();
|
|
194
249
|
location = this.getLocation();
|
|
195
250
|
library_version = this.getLibraryVersion();
|
|
196
|
-
defaultContext = __assign(__assign({ user_agent: globalThis.navigator.userAgent, locale: language, timezone: timezone, location: location }, this.getTrafficSources(globalThis.location.href)), { page_path: path, page_title: document.title, page_url: globalThis.location.href, library_name: "Formo Web SDK", library_version: library_version, browser: browserName });
|
|
251
|
+
defaultContext = __assign(__assign(__assign({ user_agent: globalThis.navigator.userAgent, locale: language, timezone: timezone, location: location }, this.getTrafficSources(globalThis.location.href)), { page_path: path, page_title: document.title, page_url: globalThis.location.href, library_name: "Formo Web SDK", library_version: library_version, browser: browserName }), this.getScreen());
|
|
197
252
|
mergedContext = mergeDeepRight(defaultContext, context || {});
|
|
198
253
|
return [2 /*return*/, mergedContext];
|
|
199
254
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Address, APIEvent } from "../../types";
|
|
1
|
+
import { Address, APIEvent, Options } from "../../types";
|
|
2
2
|
import { IEventQueue } from "../queue";
|
|
3
3
|
import { IEventFactory, IEventManager } from "./type";
|
|
4
4
|
/**
|
|
@@ -10,8 +10,9 @@ declare class EventManager implements IEventManager {
|
|
|
10
10
|
/**
|
|
11
11
|
*
|
|
12
12
|
* @param eventQueue Event queue instance
|
|
13
|
+
* @param options Optional configuration (referral parsing, etc.)
|
|
13
14
|
*/
|
|
14
|
-
constructor(eventQueue: IEventQueue);
|
|
15
|
+
constructor(eventQueue: IEventQueue, options?: Options);
|
|
15
16
|
/**
|
|
16
17
|
* Consumes a new incoming event
|
|
17
18
|
* @param event Incoming event data
|
|
@@ -55,10 +55,11 @@ var EventManager = /** @class */ (function () {
|
|
|
55
55
|
/**
|
|
56
56
|
*
|
|
57
57
|
* @param eventQueue Event queue instance
|
|
58
|
+
* @param options Optional configuration (referral parsing, etc.)
|
|
58
59
|
*/
|
|
59
|
-
function EventManager(eventQueue) {
|
|
60
|
+
function EventManager(eventQueue, options) {
|
|
60
61
|
this.eventQueue = eventQueue;
|
|
61
|
-
this.eventFactory = new EventFactory();
|
|
62
|
+
this.eventFactory = new EventFactory(options);
|
|
62
63
|
}
|
|
63
64
|
/**
|
|
64
65
|
* Consumes a new incoming event
|
|
@@ -94,6 +94,24 @@ export interface AutocaptureOptions {
|
|
|
94
94
|
*/
|
|
95
95
|
chain?: boolean;
|
|
96
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Configuration options for referral parameter parsing
|
|
99
|
+
*/
|
|
100
|
+
export interface ReferralOptions {
|
|
101
|
+
/**
|
|
102
|
+
* Custom query parameter names to check for referral codes
|
|
103
|
+
* @default ["ref", "referral", "refcode"]
|
|
104
|
+
* @example ["via", "referrer", "source"] - will check ?via=CODE, ?referrer=CODE, ?source=CODE
|
|
105
|
+
*/
|
|
106
|
+
queryParams?: string[];
|
|
107
|
+
/**
|
|
108
|
+
* URL path pattern to extract referral code from
|
|
109
|
+
* Should be a regex string that matches the path segment containing the referral code
|
|
110
|
+
* The first capture group will be used as the referral code
|
|
111
|
+
* @example "/r/([^/]+)" - will extract "01K17FKB" from "https://glider.fi/r/01K17FKB"
|
|
112
|
+
*/
|
|
113
|
+
pathPattern?: string;
|
|
114
|
+
}
|
|
97
115
|
export interface Options {
|
|
98
116
|
provider?: EIP1193Provider;
|
|
99
117
|
tracking?: boolean | TrackingOptions;
|
|
@@ -122,6 +140,12 @@ export interface Options {
|
|
|
122
140
|
enabled?: boolean;
|
|
123
141
|
levels?: LogLevel[];
|
|
124
142
|
};
|
|
143
|
+
/**
|
|
144
|
+
* Configuration for referral parameter parsing from URLs
|
|
145
|
+
* Allows customizing how referral codes are detected from query parameters and URL paths
|
|
146
|
+
* @example { queryParams: ["via"], pathPattern: "/r/([^/]+)" }
|
|
147
|
+
*/
|
|
148
|
+
referral?: ReferralOptions;
|
|
125
149
|
ready?: (formo: IFormoAnalytics) => void;
|
|
126
150
|
}
|
|
127
151
|
export interface FormoAnalyticsProviderProps {
|