@formo/analytics 1.27.0 → 1.28.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/dist/cjs/src/FormoAnalytics.d.ts +69 -12
- package/dist/cjs/src/FormoAnalytics.js +273 -147
- package/dist/cjs/src/event/EventFactory.d.ts +10 -2
- package/dist/cjs/src/event/EventFactory.js +32 -21
- package/dist/cjs/src/index.d.ts +4 -0
- package/dist/cjs/src/index.js +6 -0
- package/dist/cjs/src/privy/index.d.ts +9 -0
- package/dist/cjs/src/privy/index.js +12 -0
- package/dist/cjs/src/privy/types.d.ts +175 -0
- package/dist/cjs/src/privy/types.js +12 -0
- package/dist/cjs/src/privy/utils.d.ts +32 -0
- package/dist/cjs/src/privy/utils.js +188 -0
- package/dist/cjs/src/session/index.js +2 -1
- package/dist/cjs/src/solana/SolanaAdapter.d.ts +211 -0
- package/dist/cjs/src/solana/SolanaAdapter.js +975 -0
- package/dist/cjs/src/solana/SolanaManager.d.ts +24 -0
- package/dist/cjs/src/solana/SolanaManager.js +80 -0
- package/dist/cjs/src/solana/address.d.ts +72 -0
- package/dist/cjs/src/solana/address.js +176 -0
- package/dist/cjs/src/solana/index.d.ts +13 -0
- package/dist/cjs/src/solana/index.js +32 -0
- package/dist/cjs/src/solana/types.d.ts +206 -0
- package/dist/cjs/src/solana/types.js +80 -0
- package/dist/cjs/src/types/base.d.ts +17 -0
- package/dist/cjs/src/types/events.d.ts +4 -3
- package/dist/cjs/src/utils/address.d.ts +21 -0
- package/dist/cjs/src/utils/address.js +48 -1
- package/dist/cjs/src/utils/builderCode.d.ts +30 -0
- package/dist/cjs/src/utils/builderCode.js +143 -0
- package/dist/cjs/src/utils/index.d.ts +1 -0
- package/dist/cjs/src/utils/index.js +1 -0
- package/dist/cjs/src/version.d.ts +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/cjs/src/wagmi/WagmiEventHandler.js +13 -15
- package/dist/cjs/src/wagmi/utils.d.ts +5 -0
- package/dist/cjs/src/wagmi/utils.js +20 -0
- package/dist/esm/src/FormoAnalytics.d.ts +69 -12
- package/dist/esm/src/FormoAnalytics.js +274 -148
- package/dist/esm/src/event/EventFactory.d.ts +10 -2
- package/dist/esm/src/event/EventFactory.js +34 -23
- package/dist/esm/src/index.d.ts +4 -0
- package/dist/esm/src/index.js +3 -0
- package/dist/esm/src/privy/index.d.ts +9 -0
- package/dist/esm/src/privy/index.js +8 -0
- package/dist/esm/src/privy/types.d.ts +175 -0
- package/dist/esm/src/privy/types.js +11 -0
- package/dist/esm/src/privy/utils.d.ts +32 -0
- package/dist/esm/src/privy/utils.js +185 -0
- package/dist/esm/src/session/index.js +2 -1
- package/dist/esm/src/solana/SolanaAdapter.d.ts +211 -0
- package/dist/esm/src/solana/SolanaAdapter.js +972 -0
- package/dist/esm/src/solana/SolanaManager.d.ts +24 -0
- package/dist/esm/src/solana/SolanaManager.js +77 -0
- package/dist/esm/src/solana/address.d.ts +72 -0
- package/dist/esm/src/solana/address.js +167 -0
- package/dist/esm/src/solana/index.d.ts +13 -0
- package/dist/esm/src/solana/index.js +13 -0
- package/dist/esm/src/solana/types.d.ts +206 -0
- package/dist/esm/src/solana/types.js +74 -0
- package/dist/esm/src/types/base.d.ts +17 -0
- package/dist/esm/src/types/events.d.ts +4 -3
- package/dist/esm/src/utils/address.d.ts +21 -0
- package/dist/esm/src/utils/address.js +45 -0
- package/dist/esm/src/utils/builderCode.d.ts +30 -0
- package/dist/esm/src/utils/builderCode.js +140 -0
- package/dist/esm/src/utils/index.d.ts +1 -0
- package/dist/esm/src/utils/index.js +1 -0
- package/dist/esm/src/version.d.ts +1 -1
- package/dist/esm/src/version.js +1 -1
- package/dist/esm/src/wagmi/WagmiEventHandler.js +14 -16
- package/dist/esm/src/wagmi/utils.d.ts +5 -0
- package/dist/esm/src/wagmi/utils.js +19 -0
- package/dist/index.umd.min.js +1 -1
- package/package.json +15 -3
|
@@ -4,6 +4,14 @@ declare class EventFactory implements IEventFactory {
|
|
|
4
4
|
private options?;
|
|
5
5
|
private compiledPathPattern?;
|
|
6
6
|
constructor(options?: Options);
|
|
7
|
+
/**
|
|
8
|
+
* Validate an address for both EVM and Solana chains.
|
|
9
|
+
* Uses chainId for strict validation when available.
|
|
10
|
+
* @param address The address to validate
|
|
11
|
+
* @param chainId Optional chain ID for strict chain-specific validation
|
|
12
|
+
* @returns The validated address or null if invalid
|
|
13
|
+
*/
|
|
14
|
+
private validateEventAddress;
|
|
7
15
|
private getTimezone;
|
|
8
16
|
private getLocation;
|
|
9
17
|
private getLanguage;
|
|
@@ -22,12 +30,12 @@ declare class EventFactory implements IEventFactory {
|
|
|
22
30
|
private getEnrichedEvent;
|
|
23
31
|
generatePageEvent(category?: string, name?: string, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
24
32
|
generateDetectWalletEvent(providerName: string, rdns: string, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
25
|
-
generateIdentifyEvent(providerName
|
|
33
|
+
generateIdentifyEvent(providerName?: string, rdns?: string, address?: Nullable<Address>, userId?: Nullable<string>, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
26
34
|
generateConnectEvent(chainId: ChainID, address: Address, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
27
35
|
generateDisconnectEvent(chainId?: ChainID, address?: Address, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
28
36
|
generateChainChangedEvent(chainId: ChainID, address: Address, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
29
37
|
generateSignatureEvent(status: SignatureStatus, chainId: ChainID, address: Address, message: string, signatureHash?: string, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
30
|
-
generateTransactionEvent(status: TransactionStatus, chainId: ChainID, address: Address, data?: string, to?: string, value?: string, transactionHash?: string, function_name?: string, function_args?: Record<string, unknown>, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
38
|
+
generateTransactionEvent(status: TransactionStatus, chainId: ChainID, address: Address, data?: string, to?: string, value?: string, transactionHash?: string, function_name?: string, function_args?: Record<string, unknown>, builder_codes?: string, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
31
39
|
generateTrackEvent(event: string, properties?: IFormoEventProperties, context?: IFormoEventContext): Promise<IFormoEvent>;
|
|
32
40
|
create(event: APIEvent, address?: Address, userId?: string): Promise<IFormoEvent>;
|
|
33
41
|
}
|
|
@@ -46,8 +46,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
48
|
import { COUNTRY_LIST, LOCAL_ANONYMOUS_ID_KEY, SESSION_TRAFFIC_SOURCE_KEY, } from "../constants";
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
49
|
+
import { toSnakeCase } from "../utils";
|
|
50
|
+
import { validateAddress } from "../utils/address";
|
|
51
51
|
import { getCurrentTimeFormatted } from "../utils/timestamp";
|
|
52
52
|
import { isUndefined } from "../validators";
|
|
53
53
|
import { logger } from "../logger";
|
|
@@ -192,6 +192,19 @@ var EventFactory = /** @class */ (function () {
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Validate an address for both EVM and Solana chains.
|
|
197
|
+
* Uses chainId for strict validation when available.
|
|
198
|
+
* @param address The address to validate
|
|
199
|
+
* @param chainId Optional chain ID for strict chain-specific validation
|
|
200
|
+
* @returns The validated address or null if invalid
|
|
201
|
+
*/
|
|
202
|
+
EventFactory.prototype.validateEventAddress = function (address, chainId) {
|
|
203
|
+
if (!address) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
return validateAddress(address, chainId) || null;
|
|
207
|
+
};
|
|
195
208
|
EventFactory.prototype.getTimezone = function () {
|
|
196
209
|
try {
|
|
197
210
|
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
@@ -274,15 +287,16 @@ var EventFactory = /** @class */ (function () {
|
|
|
274
287
|
};
|
|
275
288
|
EventFactory.prototype.getEnrichedEvent = function (formoEvent, context) {
|
|
276
289
|
return __awaiter(this, void 0, void 0, function () {
|
|
277
|
-
var commonEventData, validAddress, processedEvent;
|
|
290
|
+
var commonEventData, eventChainId, validAddress, processedEvent;
|
|
278
291
|
var _a;
|
|
279
|
-
|
|
280
|
-
|
|
292
|
+
var _b;
|
|
293
|
+
return __generator(this, function (_c) {
|
|
294
|
+
switch (_c.label) {
|
|
281
295
|
case 0:
|
|
282
296
|
_a = {};
|
|
283
297
|
return [4 /*yield*/, this.generateContext(context)];
|
|
284
298
|
case 1:
|
|
285
|
-
commonEventData = (_a.context =
|
|
299
|
+
commonEventData = (_a.context = _c.sent(),
|
|
286
300
|
_a.original_timestamp = getCurrentTimeFormatted(),
|
|
287
301
|
_a.user_id = formoEvent.user_id,
|
|
288
302
|
_a.type = formoEvent.type,
|
|
@@ -290,13 +304,9 @@ var EventFactory = /** @class */ (function () {
|
|
|
290
304
|
_a.version = VERSION,
|
|
291
305
|
_a);
|
|
292
306
|
commonEventData.anonymous_id = generateAnonymousId(LOCAL_ANONYMOUS_ID_KEY);
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
commonEventData.address = null;
|
|
299
|
-
}
|
|
307
|
+
eventChainId = (_b = formoEvent.properties) === null || _b === void 0 ? void 0 : _b.chainId;
|
|
308
|
+
validAddress = this.validateEventAddress(formoEvent.address, eventChainId);
|
|
309
|
+
commonEventData.address = validAddress;
|
|
300
310
|
processedEvent = mergeDeepRight(formoEvent, commonEventData);
|
|
301
311
|
if (processedEvent.event === undefined) {
|
|
302
312
|
processedEvent.event = null;
|
|
@@ -342,7 +352,7 @@ var EventFactory = /** @class */ (function () {
|
|
|
342
352
|
var identifyEvent;
|
|
343
353
|
return __generator(this, function (_a) {
|
|
344
354
|
identifyEvent = {
|
|
345
|
-
properties: __assign({ providerName: providerName, rdns: rdns }, properties),
|
|
355
|
+
properties: __assign(__assign(__assign({}, (providerName !== undefined && { providerName: providerName })), (rdns !== undefined && { rdns: rdns })), properties),
|
|
346
356
|
user_id: userId,
|
|
347
357
|
address: address,
|
|
348
358
|
type: "identify",
|
|
@@ -403,12 +413,12 @@ var EventFactory = /** @class */ (function () {
|
|
|
403
413
|
});
|
|
404
414
|
});
|
|
405
415
|
};
|
|
406
|
-
EventFactory.prototype.generateTransactionEvent = function (status, chainId, address, data, to, value, transactionHash, function_name, function_args, properties, context) {
|
|
416
|
+
EventFactory.prototype.generateTransactionEvent = function (status, chainId, address, data, to, value, transactionHash, function_name, function_args, builder_codes, properties, context) {
|
|
407
417
|
return __awaiter(this, void 0, void 0, function () {
|
|
408
418
|
var transactionEvent;
|
|
409
419
|
return __generator(this, function (_a) {
|
|
410
420
|
transactionEvent = {
|
|
411
|
-
properties: __assign(__assign(__assign(__assign(__assign(__assign(__assign({ status: status, chainId: chainId }, (data && { data: data })), (to && { to: to })), (value && { value: value })), (transactionHash && { transactionHash: transactionHash })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })), properties),
|
|
421
|
+
properties: __assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign({ status: status, chainId: chainId }, (data && { data: data })), (to && { to: to })), (value && { value: value })), (transactionHash && { transactionHash: transactionHash })), (function_name && { function_name: function_name })), (function_args && { function_args: function_args })), (builder_codes && { builder_codes: builder_codes })), properties),
|
|
412
422
|
address: address,
|
|
413
423
|
type: "transaction",
|
|
414
424
|
};
|
|
@@ -441,7 +451,7 @@ var EventFactory = /** @class */ (function () {
|
|
|
441
451
|
// Returns an event with type, context, properties, and common properties
|
|
442
452
|
EventFactory.prototype.create = function (event, address, userId) {
|
|
443
453
|
return __awaiter(this, void 0, void 0, function () {
|
|
444
|
-
var formoEvent, _a,
|
|
454
|
+
var formoEvent, _a, chainId;
|
|
445
455
|
return __generator(this, function (_b) {
|
|
446
456
|
switch (_b.label) {
|
|
447
457
|
case 0:
|
|
@@ -487,7 +497,7 @@ var EventFactory = /** @class */ (function () {
|
|
|
487
497
|
case 14:
|
|
488
498
|
formoEvent = _b.sent();
|
|
489
499
|
return [3 /*break*/, 19];
|
|
490
|
-
case 15: return [4 /*yield*/, this.generateTransactionEvent(event.status, event.chainId, event.address, event.data, event.to, event.value, event.transactionHash, event.function_name, event.function_args, event.properties, event.context)];
|
|
500
|
+
case 15: return [4 /*yield*/, this.generateTransactionEvent(event.status, event.chainId, event.address, event.data, event.to, event.value, event.transactionHash, event.function_name, event.function_args, event.builder_codes, event.properties, event.context)];
|
|
491
501
|
case 16:
|
|
492
502
|
formoEvent = _b.sent();
|
|
493
503
|
return [3 /*break*/, 19];
|
|
@@ -497,11 +507,12 @@ var EventFactory = /** @class */ (function () {
|
|
|
497
507
|
return [3 /*break*/, 19];
|
|
498
508
|
case 19:
|
|
499
509
|
// Set address if not already set by the specific event generator
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
510
|
+
// Uses chainId for strict chain-specific validation
|
|
511
|
+
// Skip backfill for identify events to prevent stale address being used
|
|
512
|
+
if ((formoEvent.address === undefined || formoEvent.address === null) &&
|
|
513
|
+
event.type !== "identify") {
|
|
514
|
+
chainId = 'chainId' in event ? event.chainId : undefined;
|
|
515
|
+
formoEvent.address = this.validateEventAddress(address, chainId);
|
|
505
516
|
}
|
|
506
517
|
formoEvent.user_id = userId || null;
|
|
507
518
|
return [2 /*return*/, formoEvent];
|
package/dist/esm/src/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export * from "./FormoAnalyticsProvider";
|
|
2
2
|
export * from "./FormoAnalytics";
|
|
3
3
|
export * from "./types";
|
|
4
|
+
export { parsePrivyProperties } from "./privy";
|
|
5
|
+
export type { PrivyUser, PrivyLinkedAccount, PrivyAccountType, PrivyProfileProperties, PrivyWalletInfo } from "./privy";
|
|
6
|
+
export { SolanaManager } from "./solana";
|
|
7
|
+
export type { SolanaOptions, SolanaCluster, ISolanaAdapter, SolanaWalletContext, SolanaPublicKey, SolanaConnection, } from "./solana";
|
|
4
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/src/index.js
CHANGED
|
@@ -2,6 +2,9 @@ import { formofy } from "./initialization";
|
|
|
2
2
|
export * from "./FormoAnalyticsProvider";
|
|
3
3
|
export * from "./FormoAnalytics";
|
|
4
4
|
export * from "./types";
|
|
5
|
+
export { parsePrivyProperties } from "./privy";
|
|
6
|
+
// Solana integration exports
|
|
7
|
+
export { SolanaManager } from "./solana";
|
|
5
8
|
if (typeof window !== "undefined")
|
|
6
9
|
window.formofy = formofy;
|
|
7
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privy integration module
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for enriching wallet profiles with Privy user data.
|
|
5
|
+
* This module exports the property extraction utility and related types.
|
|
6
|
+
*/
|
|
7
|
+
export { parsePrivyProperties } from "./utils";
|
|
8
|
+
export type { PrivyUser, PrivyLinkedAccount, PrivyAccountType, PrivyProfileProperties, PrivyWalletInfo, } from "./types";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privy integration module
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for enriching wallet profiles with Privy user data.
|
|
5
|
+
* This module exports the property extraction utility and related types.
|
|
6
|
+
*/
|
|
7
|
+
export { parsePrivyProperties } from "./utils";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privy-specific type definitions for user profile enrichment
|
|
3
|
+
*
|
|
4
|
+
* These types provide TypeScript interfaces for Privy user objects
|
|
5
|
+
* from the Privy React SDK (`usePrivy()` hook).
|
|
6
|
+
*
|
|
7
|
+
* Based on the Privy user object structure:
|
|
8
|
+
* https://docs.privy.io/user-management/users/the-user-object
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Valid Privy linked account type strings.
|
|
12
|
+
*/
|
|
13
|
+
export type PrivyAccountType = "email" | "phone" | "wallet" | "farcaster" | "telegram" | "apple_oauth" | "discord_oauth" | "github_oauth" | "google_oauth" | "instagram_oauth" | "linkedin_oauth" | "spotify_oauth" | "tiktok_oauth" | "twitter_oauth" | "line" | "custom_auth" | "passkey" | "cross_app" | string;
|
|
14
|
+
/**
|
|
15
|
+
* A linked account entry from the Privy user object.
|
|
16
|
+
* Each linked account has a `type` discriminator and type-specific fields.
|
|
17
|
+
*/
|
|
18
|
+
export interface PrivyLinkedAccount {
|
|
19
|
+
type: PrivyAccountType;
|
|
20
|
+
address?: string;
|
|
21
|
+
number?: string;
|
|
22
|
+
username?: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
displayName?: string;
|
|
25
|
+
subject?: string;
|
|
26
|
+
email?: string;
|
|
27
|
+
chainType?: string;
|
|
28
|
+
walletClient?: string;
|
|
29
|
+
walletClientType?: string;
|
|
30
|
+
connectorType?: string;
|
|
31
|
+
delegated?: boolean;
|
|
32
|
+
fid?: number;
|
|
33
|
+
ownerAddress?: string;
|
|
34
|
+
bio?: string;
|
|
35
|
+
pfp?: string;
|
|
36
|
+
url?: string;
|
|
37
|
+
signerPublicKey?: string;
|
|
38
|
+
telegramUserId?: string;
|
|
39
|
+
firstName?: string;
|
|
40
|
+
lastName?: string;
|
|
41
|
+
firstVerifiedAt?: number | null;
|
|
42
|
+
latestVerifiedAt?: number | null;
|
|
43
|
+
verifiedAt?: number | null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Privy user object as returned by the Privy React SDK.
|
|
47
|
+
*
|
|
48
|
+
* Convenience accessors: user.email, user.phone, user.wallet, user.discord,
|
|
49
|
+
* user.twitter, user.farcaster, user.github, user.google, user.linkedin,
|
|
50
|
+
* user.apple, user.instagram, user.spotify, user.tiktok, user.telegram, user.line
|
|
51
|
+
*/
|
|
52
|
+
export interface PrivyUser {
|
|
53
|
+
/** Privy user ID in DID format (e.g., "did:privy:cm3np...") */
|
|
54
|
+
id: string;
|
|
55
|
+
/** Account creation timestamp */
|
|
56
|
+
createdAt?: number;
|
|
57
|
+
/** All linked accounts */
|
|
58
|
+
linkedAccounts?: PrivyLinkedAccount[];
|
|
59
|
+
/** Optional custom metadata */
|
|
60
|
+
customMetadata?: Record<string, unknown>;
|
|
61
|
+
email?: {
|
|
62
|
+
address: string;
|
|
63
|
+
};
|
|
64
|
+
phone?: {
|
|
65
|
+
number: string;
|
|
66
|
+
};
|
|
67
|
+
wallet?: {
|
|
68
|
+
address: string;
|
|
69
|
+
chainType?: string;
|
|
70
|
+
walletClient?: string;
|
|
71
|
+
walletClientType?: string;
|
|
72
|
+
connectorType?: string;
|
|
73
|
+
};
|
|
74
|
+
google?: {
|
|
75
|
+
email?: string;
|
|
76
|
+
name?: string;
|
|
77
|
+
subject?: string;
|
|
78
|
+
};
|
|
79
|
+
discord?: {
|
|
80
|
+
username?: string;
|
|
81
|
+
subject?: string;
|
|
82
|
+
email?: string;
|
|
83
|
+
};
|
|
84
|
+
twitter?: {
|
|
85
|
+
username?: string;
|
|
86
|
+
name?: string;
|
|
87
|
+
subject?: string;
|
|
88
|
+
profilePictureUrl?: string;
|
|
89
|
+
};
|
|
90
|
+
farcaster?: {
|
|
91
|
+
fid?: number;
|
|
92
|
+
username?: string;
|
|
93
|
+
displayName?: string;
|
|
94
|
+
ownerAddress?: string;
|
|
95
|
+
bio?: string;
|
|
96
|
+
pfp?: string;
|
|
97
|
+
};
|
|
98
|
+
github?: {
|
|
99
|
+
username?: string;
|
|
100
|
+
name?: string;
|
|
101
|
+
subject?: string;
|
|
102
|
+
};
|
|
103
|
+
linkedin?: {
|
|
104
|
+
email?: string;
|
|
105
|
+
name?: string;
|
|
106
|
+
subject?: string;
|
|
107
|
+
};
|
|
108
|
+
apple?: {
|
|
109
|
+
email?: string;
|
|
110
|
+
subject?: string;
|
|
111
|
+
};
|
|
112
|
+
instagram?: {
|
|
113
|
+
username?: string;
|
|
114
|
+
subject?: string;
|
|
115
|
+
};
|
|
116
|
+
spotify?: {
|
|
117
|
+
email?: string;
|
|
118
|
+
name?: string;
|
|
119
|
+
subject?: string;
|
|
120
|
+
};
|
|
121
|
+
tiktok?: {
|
|
122
|
+
username?: string;
|
|
123
|
+
name?: string;
|
|
124
|
+
subject?: string;
|
|
125
|
+
};
|
|
126
|
+
line?: {
|
|
127
|
+
email?: string;
|
|
128
|
+
name?: string;
|
|
129
|
+
subject?: string;
|
|
130
|
+
};
|
|
131
|
+
telegram?: {
|
|
132
|
+
telegramUserId?: string;
|
|
133
|
+
username?: string;
|
|
134
|
+
firstName?: string;
|
|
135
|
+
lastName?: string;
|
|
136
|
+
};
|
|
137
|
+
/** MFA methods */
|
|
138
|
+
mfaMethods?: Array<string>;
|
|
139
|
+
/** Whether the user has accepted terms */
|
|
140
|
+
hasAcceptedTerms?: boolean;
|
|
141
|
+
/** Whether this is a guest user */
|
|
142
|
+
isGuest?: boolean;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Extracted profile properties from a Privy user.
|
|
146
|
+
* These are the properties that get sent as event properties via `identify()`.
|
|
147
|
+
*/
|
|
148
|
+
export interface PrivyProfileProperties {
|
|
149
|
+
privyDid: string;
|
|
150
|
+
privyCreatedAt?: number;
|
|
151
|
+
email?: string;
|
|
152
|
+
apple?: string;
|
|
153
|
+
discord?: string;
|
|
154
|
+
twitter?: string;
|
|
155
|
+
farcaster?: string;
|
|
156
|
+
github?: string;
|
|
157
|
+
google?: string;
|
|
158
|
+
linkedin?: string;
|
|
159
|
+
line?: string;
|
|
160
|
+
spotify?: string;
|
|
161
|
+
telegram?: string;
|
|
162
|
+
tiktok?: string;
|
|
163
|
+
instagram?: string;
|
|
164
|
+
[key: string]: unknown;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Wallet info extracted from Privy linked accounts.
|
|
168
|
+
*/
|
|
169
|
+
export interface PrivyWalletInfo {
|
|
170
|
+
address: string;
|
|
171
|
+
walletClient?: string;
|
|
172
|
+
chainType?: string;
|
|
173
|
+
isEmbedded: boolean;
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privy-specific type definitions for user profile enrichment
|
|
3
|
+
*
|
|
4
|
+
* These types provide TypeScript interfaces for Privy user objects
|
|
5
|
+
* from the Privy React SDK (`usePrivy()` hook).
|
|
6
|
+
*
|
|
7
|
+
* Based on the Privy user object structure:
|
|
8
|
+
* https://docs.privy.io/user-management/users/the-user-object
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for extracting profile properties from Privy user objects.
|
|
3
|
+
*/
|
|
4
|
+
import { PrivyProfileProperties, PrivyUser, PrivyWalletInfo } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Extract profile properties and wallet addresses from a Privy user object.
|
|
7
|
+
*
|
|
8
|
+
* Parses the Privy user's linked accounts into a flat properties object
|
|
9
|
+
* (email, social accounts, etc.) and extracts all linked wallet addresses.
|
|
10
|
+
*
|
|
11
|
+
* @param user - The Privy user object from `usePrivy()`
|
|
12
|
+
* @returns An object with `properties` and `wallets`
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { parsePrivyProperties } from '@formo/analytics';
|
|
17
|
+
*
|
|
18
|
+
* const { user } = usePrivy();
|
|
19
|
+
* if (user) {
|
|
20
|
+
* const { properties, wallets } = parsePrivyProperties(user);
|
|
21
|
+
*
|
|
22
|
+
* for (const wallet of wallets) {
|
|
23
|
+
* formo.identify({ address: wallet.address, userId: user.id }, properties);
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function parsePrivyProperties(user: PrivyUser): {
|
|
29
|
+
properties: PrivyProfileProperties;
|
|
30
|
+
wallets: PrivyWalletInfo[];
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for extracting profile properties from Privy user objects.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Extract profile properties and wallet addresses from a Privy user object.
|
|
6
|
+
*
|
|
7
|
+
* Parses the Privy user's linked accounts into a flat properties object
|
|
8
|
+
* (email, social accounts, etc.) and extracts all linked wallet addresses.
|
|
9
|
+
*
|
|
10
|
+
* @param user - The Privy user object from `usePrivy()`
|
|
11
|
+
* @returns An object with `properties` and `wallets`
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { parsePrivyProperties } from '@formo/analytics';
|
|
16
|
+
*
|
|
17
|
+
* const { user } = usePrivy();
|
|
18
|
+
* if (user) {
|
|
19
|
+
* const { properties, wallets } = parsePrivyProperties(user);
|
|
20
|
+
*
|
|
21
|
+
* for (const wallet of wallets) {
|
|
22
|
+
* formo.identify({ address: wallet.address, userId: user.id }, properties);
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function parsePrivyProperties(user) {
|
|
28
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
29
|
+
var accounts = user.linkedAccounts || [];
|
|
30
|
+
// Extract profile properties
|
|
31
|
+
var properties = {
|
|
32
|
+
privyDid: user.id,
|
|
33
|
+
privyCreatedAt: user.createdAt,
|
|
34
|
+
};
|
|
35
|
+
// Email
|
|
36
|
+
if ((_a = user.email) === null || _a === void 0 ? void 0 : _a.address) {
|
|
37
|
+
properties.email = user.email.address;
|
|
38
|
+
}
|
|
39
|
+
// Social accounts - extract usernames/identifiers
|
|
40
|
+
if ((_b = user.apple) === null || _b === void 0 ? void 0 : _b.email) {
|
|
41
|
+
properties.apple = user.apple.email;
|
|
42
|
+
}
|
|
43
|
+
if ((_c = user.discord) === null || _c === void 0 ? void 0 : _c.username) {
|
|
44
|
+
properties.discord = user.discord.username;
|
|
45
|
+
}
|
|
46
|
+
if ((_d = user.farcaster) === null || _d === void 0 ? void 0 : _d.username) {
|
|
47
|
+
properties.farcaster = user.farcaster.username;
|
|
48
|
+
}
|
|
49
|
+
if ((_e = user.github) === null || _e === void 0 ? void 0 : _e.username) {
|
|
50
|
+
properties.github = user.github.username;
|
|
51
|
+
}
|
|
52
|
+
if ((_f = user.google) === null || _f === void 0 ? void 0 : _f.email) {
|
|
53
|
+
properties.google = user.google.email;
|
|
54
|
+
}
|
|
55
|
+
if ((_g = user.instagram) === null || _g === void 0 ? void 0 : _g.username) {
|
|
56
|
+
properties.instagram = user.instagram.username;
|
|
57
|
+
}
|
|
58
|
+
if ((_h = user.line) === null || _h === void 0 ? void 0 : _h.email) {
|
|
59
|
+
properties.line = user.line.email;
|
|
60
|
+
}
|
|
61
|
+
if ((_j = user.linkedin) === null || _j === void 0 ? void 0 : _j.email) {
|
|
62
|
+
properties.linkedin = user.linkedin.email;
|
|
63
|
+
}
|
|
64
|
+
if ((_k = user.spotify) === null || _k === void 0 ? void 0 : _k.email) {
|
|
65
|
+
properties.spotify = user.spotify.email;
|
|
66
|
+
}
|
|
67
|
+
if ((_l = user.telegram) === null || _l === void 0 ? void 0 : _l.username) {
|
|
68
|
+
properties.telegram = user.telegram.username;
|
|
69
|
+
}
|
|
70
|
+
if ((_m = user.tiktok) === null || _m === void 0 ? void 0 : _m.username) {
|
|
71
|
+
properties.tiktok = user.tiktok.username;
|
|
72
|
+
}
|
|
73
|
+
if ((_o = user.twitter) === null || _o === void 0 ? void 0 : _o.username) {
|
|
74
|
+
properties.twitter = user.twitter.username;
|
|
75
|
+
}
|
|
76
|
+
// Fallback to linkedAccounts if convenience accessors are not populated
|
|
77
|
+
if (!properties.email) {
|
|
78
|
+
var emailAccount = accounts.find(function (account) { return account.type === "email"; });
|
|
79
|
+
if (emailAccount === null || emailAccount === void 0 ? void 0 : emailAccount.address) {
|
|
80
|
+
properties.email = emailAccount.address;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (!properties.apple) {
|
|
84
|
+
var appleAccount = accounts.find(function (a) { return a.type === "apple_oauth"; });
|
|
85
|
+
if (appleAccount === null || appleAccount === void 0 ? void 0 : appleAccount.email) {
|
|
86
|
+
properties.apple = appleAccount.email;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (!properties.discord) {
|
|
90
|
+
var discordAccount = accounts.find(function (a) { return a.type === "discord_oauth"; });
|
|
91
|
+
if (discordAccount === null || discordAccount === void 0 ? void 0 : discordAccount.username) {
|
|
92
|
+
properties.discord = discordAccount.username;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!properties.farcaster) {
|
|
96
|
+
var farcasterAccount = accounts.find(function (a) { return a.type === "farcaster"; });
|
|
97
|
+
if (farcasterAccount === null || farcasterAccount === void 0 ? void 0 : farcasterAccount.username) {
|
|
98
|
+
properties.farcaster = farcasterAccount.username;
|
|
99
|
+
}
|
|
100
|
+
else if (farcasterAccount === null || farcasterAccount === void 0 ? void 0 : farcasterAccount.displayName) {
|
|
101
|
+
properties.farcaster = farcasterAccount.displayName;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (!properties.github) {
|
|
105
|
+
var githubAccount = accounts.find(function (a) { return a.type === "github_oauth"; });
|
|
106
|
+
if (githubAccount === null || githubAccount === void 0 ? void 0 : githubAccount.username) {
|
|
107
|
+
properties.github = githubAccount.username;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!properties.google) {
|
|
111
|
+
var googleAccount = accounts.find(function (a) { return a.type === "google_oauth"; });
|
|
112
|
+
if (googleAccount === null || googleAccount === void 0 ? void 0 : googleAccount.email) {
|
|
113
|
+
properties.google = googleAccount.email;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!properties.instagram) {
|
|
117
|
+
var instagramAccount = accounts.find(function (a) { return a.type === "instagram_oauth"; });
|
|
118
|
+
if (instagramAccount === null || instagramAccount === void 0 ? void 0 : instagramAccount.username) {
|
|
119
|
+
properties.instagram = instagramAccount.username;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (!properties.line) {
|
|
123
|
+
var lineAccount = accounts.find(function (a) { return a.type === "line"; });
|
|
124
|
+
if (lineAccount === null || lineAccount === void 0 ? void 0 : lineAccount.email) {
|
|
125
|
+
properties.line = lineAccount.email;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!properties.linkedin) {
|
|
129
|
+
var linkedinAccount = accounts.find(function (a) { return a.type === "linkedin_oauth"; });
|
|
130
|
+
if (linkedinAccount === null || linkedinAccount === void 0 ? void 0 : linkedinAccount.email) {
|
|
131
|
+
properties.linkedin = linkedinAccount.email;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (!properties.spotify) {
|
|
135
|
+
var spotifyAccount = accounts.find(function (a) { return a.type === "spotify_oauth"; });
|
|
136
|
+
if (spotifyAccount === null || spotifyAccount === void 0 ? void 0 : spotifyAccount.email) {
|
|
137
|
+
properties.spotify = spotifyAccount.email;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (!properties.telegram) {
|
|
141
|
+
var telegramAccount = accounts.find(function (a) { return a.type === "telegram"; });
|
|
142
|
+
if (telegramAccount === null || telegramAccount === void 0 ? void 0 : telegramAccount.username) {
|
|
143
|
+
properties.telegram = telegramAccount.username;
|
|
144
|
+
}
|
|
145
|
+
else if (telegramAccount === null || telegramAccount === void 0 ? void 0 : telegramAccount.telegramUserId) {
|
|
146
|
+
properties.telegram = telegramAccount.telegramUserId;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!properties.tiktok) {
|
|
150
|
+
var tiktokAccount = accounts.find(function (a) { return a.type === "tiktok_oauth"; });
|
|
151
|
+
if (tiktokAccount === null || tiktokAccount === void 0 ? void 0 : tiktokAccount.username) {
|
|
152
|
+
properties.tiktok = tiktokAccount.username;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (!properties.twitter) {
|
|
156
|
+
var twitterAccount = accounts.find(function (a) { return a.type === "twitter_oauth"; });
|
|
157
|
+
if (twitterAccount === null || twitterAccount === void 0 ? void 0 : twitterAccount.username) {
|
|
158
|
+
properties.twitter = twitterAccount.username;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Use OAuth emails as fallback for email if still blank
|
|
162
|
+
// Priority: email -> google -> apple -> linkedin
|
|
163
|
+
if (!properties.email) {
|
|
164
|
+
if (properties.google) {
|
|
165
|
+
properties.email = properties.google;
|
|
166
|
+
}
|
|
167
|
+
else if (properties.apple) {
|
|
168
|
+
properties.email = properties.apple;
|
|
169
|
+
}
|
|
170
|
+
else if (properties.linkedin) {
|
|
171
|
+
properties.email = properties.linkedin;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Extract wallet addresses
|
|
175
|
+
var wallets = accounts
|
|
176
|
+
.filter(function (a) { return a.type === "wallet" && a.address; })
|
|
177
|
+
.map(function (a) { return ({
|
|
178
|
+
address: a.address,
|
|
179
|
+
walletClient: a.walletClientType || a.walletClient,
|
|
180
|
+
chainType: a.chainType,
|
|
181
|
+
isEmbedded: a.walletClientType === "privy" || a.walletClient === "privy",
|
|
182
|
+
}); });
|
|
183
|
+
return { properties: properties, wallets: wallets };
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -96,7 +96,8 @@ var FormoAnalyticsSession = /** @class */ (function () {
|
|
|
96
96
|
var _a;
|
|
97
97
|
var identifiedKey = this.generateIdentificationKey(address, rdns);
|
|
98
98
|
var identifiedWallets = ((_a = cookie().get(SESSION_WALLET_IDENTIFIED_KEY)) === null || _a === void 0 ? void 0 : _a.split(",")) || [];
|
|
99
|
-
|
|
99
|
+
var alreadyExists = identifiedWallets.includes(identifiedKey);
|
|
100
|
+
if (!alreadyExists) {
|
|
100
101
|
identifiedWallets.push(identifiedKey);
|
|
101
102
|
var newValue = identifiedWallets.join(",");
|
|
102
103
|
cookie().set(SESSION_WALLET_IDENTIFIED_KEY, newValue, {
|