@formo/analytics 1.38.2 → 1.40.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 +4 -1
- package/dist/cjs/src/FormoAnalytics.js +56 -36
- package/dist/cjs/src/FormoAnalyticsProvider.js +20 -0
- package/dist/cjs/src/event/EventFactory.d.ts +9 -1
- package/dist/cjs/src/event/EventFactory.js +31 -16
- package/dist/cjs/src/event/EventManager.d.ts +3 -1
- package/dist/cjs/src/event/EventManager.js +33 -4
- package/dist/cjs/src/event/cancellation.d.ts +4 -0
- package/dist/cjs/src/event/cancellation.js +7 -0
- package/dist/cjs/src/event/type.d.ts +1 -0
- package/dist/cjs/src/event/utils.d.ts +5 -1
- package/dist/cjs/src/event/utils.js +57 -2
- package/dist/cjs/src/evm/EvmEventTracker.d.ts +7 -0
- package/dist/cjs/src/evm/EvmEventTracker.js +31 -5
- package/dist/cjs/src/queue/EventQueue.d.ts +1 -0
- package/dist/cjs/src/queue/EventQueue.js +11 -6
- package/dist/cjs/src/solana/SolanaManager.d.ts +37 -9
- package/dist/cjs/src/solana/SolanaManager.js +135 -20
- package/dist/cjs/src/solana/SolanaStoreHandler.d.ts +6 -0
- package/dist/cjs/src/solana/SolanaStoreHandler.js +17 -8
- package/dist/cjs/src/solana/SolanaWalletStandardRegistry.d.ts +163 -0
- package/dist/cjs/src/solana/SolanaWalletStandardRegistry.js +447 -0
- package/dist/cjs/src/solana/index.d.ts +10 -5
- package/dist/cjs/src/solana/index.js +12 -6
- package/dist/cjs/src/solana/storeTypes.d.ts +20 -1
- package/dist/cjs/src/solana/types.d.ts +32 -9
- package/dist/cjs/src/solana/types.js +15 -0
- package/dist/cjs/src/solana/walletStandardTypes.d.ts +54 -0
- package/dist/cjs/src/solana/walletStandardTypes.js +21 -0
- package/dist/cjs/src/storage/StorageManager.d.ts +2 -0
- package/dist/cjs/src/storage/StorageManager.js +6 -0
- package/dist/cjs/src/storage/index.d.ts +1 -0
- package/dist/cjs/src/storage/index.js +7 -1
- package/dist/cjs/src/types/base.d.ts +15 -5
- package/dist/cjs/src/version.d.ts +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/esm/src/FormoAnalytics.d.ts +4 -1
- package/dist/esm/src/FormoAnalytics.js +54 -34
- package/dist/esm/src/FormoAnalyticsProvider.js +20 -0
- package/dist/esm/src/event/EventFactory.d.ts +9 -1
- package/dist/esm/src/event/EventFactory.js +31 -16
- package/dist/esm/src/event/EventManager.d.ts +3 -1
- package/dist/esm/src/event/EventManager.js +33 -4
- package/dist/esm/src/event/cancellation.d.ts +4 -0
- package/dist/esm/src/event/cancellation.js +4 -0
- package/dist/esm/src/event/type.d.ts +1 -0
- package/dist/esm/src/event/utils.d.ts +5 -1
- package/dist/esm/src/event/utils.js +56 -3
- package/dist/esm/src/evm/EvmEventTracker.d.ts +7 -0
- package/dist/esm/src/evm/EvmEventTracker.js +31 -5
- package/dist/esm/src/queue/EventQueue.d.ts +1 -0
- package/dist/esm/src/queue/EventQueue.js +11 -6
- package/dist/esm/src/solana/SolanaManager.d.ts +37 -9
- package/dist/esm/src/solana/SolanaManager.js +135 -20
- package/dist/esm/src/solana/SolanaStoreHandler.d.ts +6 -0
- package/dist/esm/src/solana/SolanaStoreHandler.js +18 -9
- package/dist/esm/src/solana/SolanaWalletStandardRegistry.d.ts +163 -0
- package/dist/esm/src/solana/SolanaWalletStandardRegistry.js +444 -0
- package/dist/esm/src/solana/index.d.ts +10 -5
- package/dist/esm/src/solana/index.js +10 -5
- package/dist/esm/src/solana/storeTypes.d.ts +20 -1
- package/dist/esm/src/solana/types.d.ts +32 -9
- package/dist/esm/src/solana/types.js +14 -0
- package/dist/esm/src/solana/walletStandardTypes.d.ts +54 -0
- package/dist/esm/src/solana/walletStandardTypes.js +18 -0
- package/dist/esm/src/storage/StorageManager.d.ts +2 -0
- package/dist/esm/src/storage/StorageManager.js +6 -0
- package/dist/esm/src/storage/index.d.ts +1 -0
- package/dist/esm/src/storage/index.js +5 -0
- package/dist/esm/src/types/base.d.ts +15 -5
- package/dist/esm/src/version.d.ts +1 -1
- package/dist/esm/src/version.js +1 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +2 -2
|
@@ -67,11 +67,18 @@ import { CHANNEL, CLICK_ID_PARAMS, DEFAULT_EXCLUDED_QUERY_PARAMS, DEFAULT_REFERR
|
|
|
67
67
|
import { sanitizeTrafficSources } from "./sanitize";
|
|
68
68
|
import { generateAnonymousId } from "./utils";
|
|
69
69
|
import { detectBrowser } from "../browser/browsers";
|
|
70
|
+
import { EVENT_CREATION_CANCELLED } from "./cancellation";
|
|
70
71
|
var ISO_3166_ALPHA_2_REGEX = /^[A-Z]{2}$/;
|
|
71
72
|
var EventFactory = /** @class */ (function () {
|
|
72
|
-
function EventFactory(options
|
|
73
|
+
function EventFactory(options,
|
|
74
|
+
/** Consulted once per event, after the only await in creation. */
|
|
75
|
+
canCreate) {
|
|
76
|
+
if (canCreate === void 0) { canCreate = function () { return true; }; }
|
|
73
77
|
var _this = this;
|
|
74
78
|
var _a, _b;
|
|
79
|
+
this.canCreate = canCreate;
|
|
80
|
+
/** Bumped by invalidate(); an event created across a bump is dropped. */
|
|
81
|
+
this.generation = 0;
|
|
75
82
|
this.extractUTMParameters = function (url) {
|
|
76
83
|
var result = {
|
|
77
84
|
utm_campaign: "",
|
|
@@ -404,6 +411,10 @@ var EventFactory = /** @class */ (function () {
|
|
|
404
411
|
return safeDefaults;
|
|
405
412
|
}
|
|
406
413
|
};
|
|
414
|
+
/** Drop every event still being created. Called on clear() and close(). */
|
|
415
|
+
EventFactory.prototype.invalidate = function () {
|
|
416
|
+
this.generation++;
|
|
417
|
+
};
|
|
407
418
|
// Contextual fields that are automatically collected and populated by the Formo SDK
|
|
408
419
|
EventFactory.prototype.generateContext = function (context) {
|
|
409
420
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -427,24 +438,28 @@ var EventFactory = /** @class */ (function () {
|
|
|
427
438
|
};
|
|
428
439
|
EventFactory.prototype.getEnrichedEvent = function (formoEvent, context) {
|
|
429
440
|
return __awaiter(this, void 0, void 0, function () {
|
|
430
|
-
var commonEventData, eventChainId, validAddress, processedEvent;
|
|
431
|
-
var _a;
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
switch (_d.label) {
|
|
441
|
+
var generation, enrichedContext, commonEventData, eventChainId, validAddress, processedEvent;
|
|
442
|
+
var _a, _b;
|
|
443
|
+
return __generator(this, function (_c) {
|
|
444
|
+
switch (_c.label) {
|
|
435
445
|
case 0:
|
|
436
|
-
|
|
446
|
+
generation = this.generation;
|
|
437
447
|
return [4 /*yield*/, this.generateContext(context)];
|
|
438
448
|
case 1:
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
449
|
+
enrichedContext = _c.sent();
|
|
450
|
+
if (generation !== this.generation || !this.canCreate()) {
|
|
451
|
+
throw EVENT_CREATION_CANCELLED;
|
|
452
|
+
}
|
|
453
|
+
commonEventData = {
|
|
454
|
+
context: enrichedContext,
|
|
455
|
+
original_timestamp: getCurrentTimeFormatted(),
|
|
456
|
+
user_id: formoEvent.user_id,
|
|
457
|
+
type: formoEvent.type,
|
|
458
|
+
channel: CHANNEL,
|
|
459
|
+
version: VERSION,
|
|
460
|
+
};
|
|
461
|
+
commonEventData.anonymous_id = generateAnonymousId(LOCAL_ANONYMOUS_ID_KEY, (_a = this.options) === null || _a === void 0 ? void 0 : _a.crossSubdomainCookies);
|
|
462
|
+
eventChainId = (_b = formoEvent.properties) === null || _b === void 0 ? void 0 : _b.chainId;
|
|
448
463
|
validAddress = this.validateEventAddress(formoEvent.address, eventChainId);
|
|
449
464
|
commonEventData.address = validAddress;
|
|
450
465
|
processedEvent = mergeDeepRight(formoEvent, commonEventData);
|
|
@@ -5,14 +5,16 @@ import { IEventFactory, IEventManager } from "./type";
|
|
|
5
5
|
* A service to generate valid event payloads and queue them for processing
|
|
6
6
|
*/
|
|
7
7
|
declare class EventManager implements IEventManager {
|
|
8
|
+
private readonly canAcceptEvent;
|
|
8
9
|
eventQueue: IEventQueue;
|
|
9
10
|
eventFactory: IEventFactory;
|
|
11
|
+
private generation;
|
|
10
12
|
/**
|
|
11
13
|
*
|
|
12
14
|
* @param eventQueue Event queue instance
|
|
13
15
|
* @param options Optional configuration (referral parsing, etc.)
|
|
14
16
|
*/
|
|
15
|
-
constructor(eventQueue: IEventQueue, options?: Options);
|
|
17
|
+
constructor(eventQueue: IEventQueue, options?: Options, canAcceptEvent?: () => boolean);
|
|
16
18
|
/**
|
|
17
19
|
* Consumes a new incoming event
|
|
18
20
|
* @param event Incoming event data
|
|
@@ -47,6 +47,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
47
47
|
};
|
|
48
48
|
import { logger } from "../logger";
|
|
49
49
|
import { EventFactory } from "./EventFactory";
|
|
50
|
+
import { EVENT_CREATION_CANCELLED } from "./cancellation";
|
|
50
51
|
import { isBlockedAddress } from "../utils/address";
|
|
51
52
|
/**
|
|
52
53
|
* A service to generate valid event payloads and queue them for processing
|
|
@@ -57,9 +58,13 @@ var EventManager = /** @class */ (function () {
|
|
|
57
58
|
* @param eventQueue Event queue instance
|
|
58
59
|
* @param options Optional configuration (referral parsing, etc.)
|
|
59
60
|
*/
|
|
60
|
-
function EventManager(eventQueue, options) {
|
|
61
|
+
function EventManager(eventQueue, options, canAcceptEvent) {
|
|
62
|
+
if (canAcceptEvent === void 0) { canAcceptEvent = function () { return true; }; }
|
|
63
|
+
var _this = this;
|
|
64
|
+
this.canAcceptEvent = canAcceptEvent;
|
|
65
|
+
this.generation = 0;
|
|
61
66
|
this.eventQueue = eventQueue;
|
|
62
|
-
this.eventFactory = new EventFactory(options);
|
|
67
|
+
this.eventFactory = new EventFactory(options, function () { return _this.canAcceptEvent(); });
|
|
63
68
|
}
|
|
64
69
|
/**
|
|
65
70
|
* Consumes a new incoming event
|
|
@@ -67,14 +72,34 @@ var EventManager = /** @class */ (function () {
|
|
|
67
72
|
*/
|
|
68
73
|
EventManager.prototype.addEvent = function (event, address, userId) {
|
|
69
74
|
return __awaiter(this, void 0, void 0, function () {
|
|
70
|
-
var callback, _event, formoEvent;
|
|
75
|
+
var callback, _event, generation, shouldContinue, formoEvent, error_1;
|
|
76
|
+
var _this = this;
|
|
71
77
|
return __generator(this, function (_a) {
|
|
72
78
|
switch (_a.label) {
|
|
73
79
|
case 0:
|
|
74
80
|
callback = event.callback, _event = __rest(event, ["callback"]);
|
|
75
|
-
|
|
81
|
+
generation = this.generation;
|
|
82
|
+
shouldContinue = function () {
|
|
83
|
+
return generation === _this.generation && _this.canAcceptEvent();
|
|
84
|
+
};
|
|
85
|
+
if (!shouldContinue())
|
|
86
|
+
return [2 /*return*/];
|
|
87
|
+
_a.label = 1;
|
|
76
88
|
case 1:
|
|
89
|
+
_a.trys.push([1, 3, , 4]);
|
|
90
|
+
return [4 /*yield*/, this.eventFactory.create(_event, address, userId)];
|
|
91
|
+
case 2:
|
|
77
92
|
formoEvent = _a.sent();
|
|
93
|
+
return [3 /*break*/, 4];
|
|
94
|
+
case 3:
|
|
95
|
+
error_1 = _a.sent();
|
|
96
|
+
if (error_1 === EVENT_CREATION_CANCELLED)
|
|
97
|
+
return [2 /*return*/];
|
|
98
|
+
throw error_1;
|
|
99
|
+
case 4:
|
|
100
|
+
// Reject work invalidated while enrichment was pending.
|
|
101
|
+
if (!shouldContinue())
|
|
102
|
+
return [2 /*return*/];
|
|
78
103
|
// Check if the final event has a blocked address - don't queue it
|
|
79
104
|
if (formoEvent.address && isBlockedAddress(formoEvent.address)) {
|
|
80
105
|
logger.warn("Event blocked: Address ".concat(formoEvent.address, " is in the blocked list and cannot emit events"));
|
|
@@ -95,10 +120,14 @@ var EventManager = /** @class */ (function () {
|
|
|
95
120
|
};
|
|
96
121
|
/** Drop any buffered events (consent withdrawal). Recoverable. */
|
|
97
122
|
EventManager.prototype.clear = function () {
|
|
123
|
+
this.generation++;
|
|
124
|
+
this.eventFactory.invalidate();
|
|
98
125
|
this.eventQueue.clear();
|
|
99
126
|
};
|
|
100
127
|
/** Terminal shutdown on teardown: nothing can be sent after this. */
|
|
101
128
|
EventManager.prototype.close = function () {
|
|
129
|
+
this.generation++;
|
|
130
|
+
this.eventFactory.invalidate();
|
|
102
131
|
this.eventQueue.close();
|
|
103
132
|
};
|
|
104
133
|
return EventManager;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { AnonymousID } from "../types";
|
|
2
2
|
declare const generateAnonymousId: (key: string, crossSubdomainCookies?: boolean) => AnonymousID;
|
|
3
|
-
|
|
3
|
+
/** Clear the anonymous id from every storage layer. */
|
|
4
|
+
declare const clearAnonymousId: (key: string) => void;
|
|
5
|
+
/** Test hook: forget the page-lifetime memory, as a new page load would. */
|
|
6
|
+
declare const __resetAnonymousIdMemory: () => void;
|
|
7
|
+
export { generateAnonymousId, clearAnonymousId, __resetAnonymousIdMemory };
|
|
4
8
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -10,13 +10,26 @@ var __assign = (this && this.__assign) || function () {
|
|
|
10
10
|
return __assign.apply(this, arguments);
|
|
11
11
|
};
|
|
12
12
|
import { generateNativeUUID } from "../utils";
|
|
13
|
-
import { cookie } from "../storage";
|
|
13
|
+
import { cookie, local, usesCookieStorage } from "../storage";
|
|
14
14
|
import { getIdentityCookieDomain, getIdentityCookieSecurity, } from "../storage/cookiePolicy";
|
|
15
|
+
/** Page-lifetime fallback when persistent storage is unavailable. */
|
|
16
|
+
var volatileAnonymousId;
|
|
17
|
+
/** Persistent fallback when cookies are unavailable. */
|
|
18
|
+
var readLocal = function (key) {
|
|
19
|
+
try {
|
|
20
|
+
var value = local().get(key);
|
|
21
|
+
return typeof value === "string" && value ? value : undefined;
|
|
22
|
+
}
|
|
23
|
+
catch (_a) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
15
27
|
var generateAnonymousId = function (key, crossSubdomainCookies) {
|
|
28
|
+
var _a, _b;
|
|
16
29
|
var storedAnonymousId = cookie().get(key);
|
|
17
30
|
var anonymousId = (storedAnonymousId && typeof storedAnonymousId === "string"
|
|
18
31
|
? storedAnonymousId
|
|
19
|
-
: generateNativeUUID());
|
|
32
|
+
: (_b = (_a = readLocal(key)) !== null && _a !== void 0 ? _a : volatileAnonymousId) !== null && _b !== void 0 ? _b : generateNativeUUID());
|
|
20
33
|
var domain = getIdentityCookieDomain(crossSubdomainCookies);
|
|
21
34
|
// Re-set the cookie with the configured scope. When crossSubdomainCookies
|
|
22
35
|
// is true, this migrates legacy host-only cookies on the current host to the apex
|
|
@@ -24,7 +37,47 @@ var generateAnonymousId = function (key, crossSubdomainCookies) {
|
|
|
24
37
|
// example.com is not visible from app.example.com) cannot be migrated
|
|
25
38
|
// until the user revisits that host.
|
|
26
39
|
cookie().set(key, anonymousId, __assign(__assign({ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365).toUTCString(), path: "/" }, getIdentityCookieSecurity()), (domain ? { domain: domain } : {})));
|
|
40
|
+
// Retry host-only when a domain-scoped write is rejected.
|
|
41
|
+
if (domain && cookie().get(key) !== anonymousId) {
|
|
42
|
+
cookie().set(key, anonymousId, __assign({ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365).toUTCString(), path: "/" }, getIdentityCookieSecurity()));
|
|
43
|
+
}
|
|
44
|
+
if (cookie().get(key) === anonymousId) {
|
|
45
|
+
// Prefer the cookie and discard the fallback copy.
|
|
46
|
+
volatileAnonymousId = undefined;
|
|
47
|
+
if (usesCookieStorage() && readLocal(key)) {
|
|
48
|
+
try {
|
|
49
|
+
local().remove(key);
|
|
50
|
+
}
|
|
51
|
+
catch (_c) {
|
|
52
|
+
// Storage is unavailable.
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return anonymousId;
|
|
56
|
+
}
|
|
57
|
+
// Persist across embedded page loads when cookies are blocked.
|
|
58
|
+
try {
|
|
59
|
+
local().set(key, anonymousId);
|
|
60
|
+
}
|
|
61
|
+
catch (_d) {
|
|
62
|
+
// Memory remains the last fallback.
|
|
63
|
+
}
|
|
64
|
+
volatileAnonymousId = anonymousId;
|
|
27
65
|
return anonymousId;
|
|
28
66
|
};
|
|
29
|
-
|
|
67
|
+
/** Clear the anonymous id from every storage layer. */
|
|
68
|
+
var clearAnonymousId = function (key) {
|
|
69
|
+
cookie().remove(key);
|
|
70
|
+
try {
|
|
71
|
+
local().remove(key);
|
|
72
|
+
}
|
|
73
|
+
catch (_a) {
|
|
74
|
+
// Storage is unavailable.
|
|
75
|
+
}
|
|
76
|
+
volatileAnonymousId = undefined;
|
|
77
|
+
};
|
|
78
|
+
/** Test hook: forget the page-lifetime memory, as a new page load would. */
|
|
79
|
+
var __resetAnonymousIdMemory = function () {
|
|
80
|
+
volatileAnonymousId = undefined;
|
|
81
|
+
};
|
|
82
|
+
export { generateAnonymousId, clearAnonymousId, __resetAnonymousIdMemory };
|
|
30
83
|
//# sourceMappingURL=utils.js.map
|
|
@@ -11,6 +11,8 @@ export interface EvmEventTrackerDeps {
|
|
|
11
11
|
isTrackingSuppressed(): boolean;
|
|
12
12
|
/** Whether an event on this chain would actually be sent. */
|
|
13
13
|
willTrackEvent(chainId?: ChainID): boolean;
|
|
14
|
+
/** Retry detect events after the active chain changes. */
|
|
15
|
+
retryDetection(): void;
|
|
14
16
|
/** In wagmi mode the SDK does not wrap providers itself. */
|
|
15
17
|
isWagmiMode(): boolean;
|
|
16
18
|
/** Emission. The tracker decides WHEN; the SDK owns the event API. */
|
|
@@ -152,6 +154,8 @@ export declare class EvmEventTracker {
|
|
|
152
154
|
* had already replaced.
|
|
153
155
|
*/
|
|
154
156
|
private unsubscribeDiscovery?;
|
|
157
|
+
/** Discovery store retained for complete listener cleanup. */
|
|
158
|
+
private discoveryStore?;
|
|
155
159
|
constructor(wallet: WalletStateStore, registry: EvmProviderRegistry, deps: EvmEventTrackerDeps);
|
|
156
160
|
/** Stop listening for wallet announcements. Called from SDK teardown. */
|
|
157
161
|
cleanup(): void;
|
|
@@ -259,8 +263,11 @@ export declare class EvmEventTracker {
|
|
|
259
263
|
private registerConnectListener;
|
|
260
264
|
private registerDisconnectListener;
|
|
261
265
|
private onConnected;
|
|
266
|
+
/** Whether Formo owns provider lifecycle tracking. */
|
|
267
|
+
private tracksDiscovered;
|
|
262
268
|
getProviders(): Promise<readonly EIP6963ProviderDetail[]>;
|
|
263
269
|
detectWallets(providers: readonly EIP6963ProviderDetail[]): Promise<void>;
|
|
270
|
+
detectableProviders(): readonly EIP6963ProviderDetail[];
|
|
264
271
|
/**
|
|
265
272
|
* Seed a provider's chain from whatever it already exposes synchronously.
|
|
266
273
|
*
|
|
@@ -267,7 +267,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
267
267
|
};
|
|
268
268
|
/** Stop listening for wallet announcements. Called from SDK teardown. */
|
|
269
269
|
EvmEventTracker.prototype.cleanup = function () {
|
|
270
|
-
var _a;
|
|
270
|
+
var _a, _b;
|
|
271
271
|
// A replay in flight (awaiting the active wallet's accounts) must not
|
|
272
272
|
// resume into a torn-down instance and commit a session there.
|
|
273
273
|
this.disposed = true;
|
|
@@ -277,11 +277,13 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
277
277
|
this.retryRequested = false;
|
|
278
278
|
try {
|
|
279
279
|
(_a = this.unsubscribeDiscovery) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
280
|
+
(_b = this.discoveryStore) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
280
281
|
}
|
|
281
282
|
catch (e) {
|
|
282
283
|
logger.warn("Failed to unsubscribe from provider discovery", e);
|
|
283
284
|
}
|
|
284
285
|
this.unsubscribeDiscovery = undefined;
|
|
286
|
+
this.discoveryStore = undefined;
|
|
285
287
|
};
|
|
286
288
|
EvmEventTracker.prototype.sessionGeneration = function (provider) {
|
|
287
289
|
var _a;
|
|
@@ -1015,6 +1017,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1015
1017
|
this.wallet.provider = provider;
|
|
1016
1018
|
}
|
|
1017
1019
|
this.wallet.set('evm', { chainId: nextChainId });
|
|
1020
|
+
this.deps.retryDetection();
|
|
1018
1021
|
_a.label = 1;
|
|
1019
1022
|
case 1:
|
|
1020
1023
|
_a.trys.push([1, 5, , 6]);
|
|
@@ -1332,12 +1335,17 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1332
1335
|
});
|
|
1333
1336
|
});
|
|
1334
1337
|
};
|
|
1338
|
+
/** Whether Formo owns provider lifecycle tracking. */
|
|
1339
|
+
EvmEventTracker.prototype.tracksDiscovered = function () {
|
|
1340
|
+
return !this.deps.isWagmiMode();
|
|
1341
|
+
};
|
|
1335
1342
|
EvmEventTracker.prototype.getProviders = function () {
|
|
1336
1343
|
return __awaiter(this, void 0, void 0, function () {
|
|
1337
1344
|
var store, providers, injected, injectedProviderInfo, injectedDetail, uniqueProviders, _i, uniqueProviders_1, detail;
|
|
1338
1345
|
var _this = this;
|
|
1339
1346
|
return __generator(this, function (_a) {
|
|
1340
1347
|
store = createStore();
|
|
1348
|
+
this.discoveryStore = store;
|
|
1341
1349
|
providers = store.getProviders();
|
|
1342
1350
|
this.unsubscribeDiscovery = store.subscribe(function (providerDetails) {
|
|
1343
1351
|
providers = providerDetails;
|
|
@@ -1356,8 +1364,12 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1356
1364
|
var p = detail === null || detail === void 0 ? void 0 : detail.provider;
|
|
1357
1365
|
return !!p && !_this.registry.isTracked(p);
|
|
1358
1366
|
});
|
|
1359
|
-
|
|
1367
|
+
// Wagmi detects only providers added by this announcement.
|
|
1368
|
+
var toDetect = _this.tracksDiscovered() ? newDetails : newlyAddedDetails;
|
|
1369
|
+
if (_this.tracksDiscovered() && newDetails.length > 0) {
|
|
1360
1370
|
_this.trackProviders(newDetails);
|
|
1371
|
+
}
|
|
1372
|
+
if (toDetect.length > 0) {
|
|
1361
1373
|
// Detect newly discovered wallets (session de-dupes) with error handling
|
|
1362
1374
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1363
1375
|
var e_3;
|
|
@@ -1365,7 +1377,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1365
1377
|
switch (_a.label) {
|
|
1366
1378
|
case 0:
|
|
1367
1379
|
_a.trys.push([0, 2, , 3]);
|
|
1368
|
-
return [4 /*yield*/, this.detectWallets(
|
|
1380
|
+
return [4 /*yield*/, this.detectWallets(toDetect)];
|
|
1369
1381
|
case 1:
|
|
1370
1382
|
_a.sent();
|
|
1371
1383
|
return [3 /*break*/, 3];
|
|
@@ -1391,7 +1403,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1391
1403
|
if (this.registry.injected &&
|
|
1392
1404
|
this.registry.injected.provider === injected) {
|
|
1393
1405
|
// Ensure it's tracked
|
|
1394
|
-
if (!this.registry.isTracked(injected)) {
|
|
1406
|
+
if (this.tracksDiscovered() && !this.registry.isTracked(injected)) {
|
|
1395
1407
|
this.trackEIP1193Provider(injected);
|
|
1396
1408
|
}
|
|
1397
1409
|
// Merge with existing providers instead of overwriting
|
|
@@ -1399,7 +1411,7 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1399
1411
|
return [2 /*return*/, this.registry.all];
|
|
1400
1412
|
}
|
|
1401
1413
|
// Re-check if the injected provider is already tracked just before tracking
|
|
1402
|
-
if (!this.registry.isTracked(injected)) {
|
|
1414
|
+
if (this.tracksDiscovered() && !this.registry.isTracked(injected)) {
|
|
1403
1415
|
this.trackEIP1193Provider(injected);
|
|
1404
1416
|
}
|
|
1405
1417
|
injectedProviderInfo = detectInjectedProviderInfo(injected);
|
|
@@ -1459,6 +1471,20 @@ var EvmEventTracker = /** @class */ (function () {
|
|
|
1459
1471
|
});
|
|
1460
1472
|
});
|
|
1461
1473
|
};
|
|
1474
|
+
EvmEventTracker.prototype.detectableProviders = function () {
|
|
1475
|
+
var _a;
|
|
1476
|
+
var available = new Set();
|
|
1477
|
+
(_a = this.discoveryStore) === null || _a === void 0 ? void 0 : _a.getProviders().forEach(function (detail) {
|
|
1478
|
+
return available.add(detail.provider);
|
|
1479
|
+
});
|
|
1480
|
+
var injected = typeof window !== "undefined" ? window.ethereum : undefined;
|
|
1481
|
+
if (injected)
|
|
1482
|
+
available.add(injected);
|
|
1483
|
+
this.externallyRegistered.forEach(function (provider) { return available.add(provider); });
|
|
1484
|
+
return this.registry.all.filter(function (detail) {
|
|
1485
|
+
return available.has(detail.provider);
|
|
1486
|
+
});
|
|
1487
|
+
};
|
|
1462
1488
|
/**
|
|
1463
1489
|
* Seed a provider's chain from whatever it already exposes synchronously.
|
|
1464
1490
|
*
|
|
@@ -83,6 +83,7 @@ var EventQueue = /** @class */ (function () {
|
|
|
83
83
|
this.queue = [];
|
|
84
84
|
this.queueByteSize = 0; // running total of queued items' byteSize
|
|
85
85
|
this.payloadHashes = new Set();
|
|
86
|
+
this.generation = 0;
|
|
86
87
|
// Terminal shutdown flag. Once set, enqueue() and flush() are no-ops for
|
|
87
88
|
// the rest of this instance's life. See close().
|
|
88
89
|
this.closed = false;
|
|
@@ -216,6 +217,7 @@ var EventQueue = /** @class */ (function () {
|
|
|
216
217
|
* withdrawal / SDK teardown so nothing buffered can be sent later.
|
|
217
218
|
*/
|
|
218
219
|
EventQueue.prototype.clear = function () {
|
|
220
|
+
this.generation++;
|
|
219
221
|
if (this.timer) {
|
|
220
222
|
clearTimeout(this.timer);
|
|
221
223
|
this.timer = null;
|
|
@@ -223,6 +225,8 @@ var EventQueue = /** @class */ (function () {
|
|
|
223
225
|
this.queue = [];
|
|
224
226
|
this.queueByteSize = 0;
|
|
225
227
|
this.payloadHashes.clear();
|
|
228
|
+
this.flushed = false;
|
|
229
|
+
this.pendingFlush = null;
|
|
226
230
|
};
|
|
227
231
|
/**
|
|
228
232
|
* Terminal shutdown. Unlike clear(), which only empties the buffer and can
|
|
@@ -259,11 +263,12 @@ var EventQueue = /** @class */ (function () {
|
|
|
259
263
|
});
|
|
260
264
|
EventQueue.prototype.enqueue = function (event, callback) {
|
|
261
265
|
return __awaiter(this, void 0, void 0, function () {
|
|
262
|
-
var message_id, queueItem, hasReachedFlushAt, hasReachedQueueSize;
|
|
266
|
+
var generation, message_id, queueItem, hasReachedFlushAt, hasReachedQueueSize;
|
|
263
267
|
return __generator(this, function (_a) {
|
|
264
268
|
switch (_a.label) {
|
|
265
269
|
case 0:
|
|
266
270
|
callback = callback || noop;
|
|
271
|
+
generation = this.generation;
|
|
267
272
|
// A torn-down instance must never buffer, however late the caller
|
|
268
273
|
// arrives. See close().
|
|
269
274
|
if (this.closed)
|
|
@@ -276,12 +281,12 @@ var EventQueue = /** @class */ (function () {
|
|
|
276
281
|
return [4 /*yield*/, this.generateMessageId(event)];
|
|
277
282
|
case 1:
|
|
278
283
|
message_id = _a.sent();
|
|
279
|
-
|
|
280
|
-
// suspended here, and on a queue that has not flushed yet its event
|
|
281
|
-
// would push and flush immediately - the exact shape of the bug close()
|
|
282
|
-
// exists to stop.
|
|
283
|
-
if (this.closed)
|
|
284
|
+
if (this.closed || generation !== this.generation)
|
|
284
285
|
return [2 /*return*/];
|
|
286
|
+
if (this.canSend && !this.canSend()) {
|
|
287
|
+
this.clear();
|
|
288
|
+
return [2 /*return*/];
|
|
289
|
+
}
|
|
285
290
|
// check if the message already exists
|
|
286
291
|
if (this.isDuplicate(message_id)) {
|
|
287
292
|
logger.warn("Event already enqueued, try again after ".concat(millisecondsToSecond(this.flushIntervalMs), " seconds."));
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SolanaManager
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Subscribes to framework-kit's zustand store for automatic event capture
|
|
6
|
-
* of wallet connect/disconnect and transaction lifecycle events.
|
|
4
|
+
* Owns the two ways the SDK learns about Solana wallets:
|
|
7
5
|
*
|
|
8
|
-
*
|
|
6
|
+
* 1. `SolanaWalletStandardRegistry`: discovers wallets through the Wallet
|
|
7
|
+
* Standard and reports detect / connect / disconnect. On by default, so
|
|
8
|
+
* compatible wallets registered by Solana Kit, wallet-adapter,
|
|
9
|
+
* framework-kit, or another host are covered with no configuration,
|
|
10
|
+
* exactly like EVM wallets through EIP-6963. `solana: false` turns it off.
|
|
11
|
+
* 2. `SolanaStoreHandler`: subscribes to framework-kit's zustand store for
|
|
12
|
+
* connect / disconnect / cluster changes AND the transaction lifecycle.
|
|
13
|
+
* Opt-in through `solana: { store }` or `formo.solana.setStore()`.
|
|
14
|
+
*
|
|
15
|
+
* Both observe the same Wallet Standard connection when a framework-kit app
|
|
16
|
+
* connects. A store supplied at initialization owns wallet events; a store
|
|
17
|
+
* attached later takes ownership when it observes its first connection and
|
|
18
|
+
* adopts any connect the registry already reported. One connect per
|
|
19
|
+
* connection, whichever path an app is on.
|
|
20
|
+
*
|
|
21
|
+
* For signMessage/signTransaction tracking (not captured by either path),
|
|
9
22
|
* use formo.signature() directly with the address and chainId.
|
|
10
23
|
*
|
|
11
|
-
* For manual event tracking
|
|
24
|
+
* For manual event tracking, use the core API directly:
|
|
12
25
|
* formo.transaction(), formo.signature(), formo.connect(), formo.disconnect().
|
|
13
26
|
*/
|
|
14
27
|
import { FormoAnalytics } from "../FormoAnalytics";
|
|
@@ -16,9 +29,19 @@ import { SolanaCluster, SolanaOptions } from "./types";
|
|
|
16
29
|
import { SolanaClientStore } from "./storeTypes";
|
|
17
30
|
export declare class SolanaManager {
|
|
18
31
|
private formo;
|
|
32
|
+
private readonly enabled;
|
|
19
33
|
private storeHandler?;
|
|
34
|
+
private registry?;
|
|
20
35
|
private pendingCluster?;
|
|
21
|
-
|
|
36
|
+
private storeOwnsWalletEvents;
|
|
37
|
+
/**
|
|
38
|
+
* @param formo - The SDK instance events are reported to.
|
|
39
|
+
* @param options - `options.solana` as passed to the SDK, if an object.
|
|
40
|
+
* @param enabled - Whether Solana tracking is enabled. False only when the
|
|
41
|
+
* host app passed `solana: false`; both discovery and stores then stay off.
|
|
42
|
+
*/
|
|
43
|
+
constructor(formo: FormoAnalytics, options?: SolanaOptions, enabled?: boolean);
|
|
44
|
+
private attachStore;
|
|
22
45
|
/**
|
|
23
46
|
* Set the framework-kit zustand store for automatic event tracking.
|
|
24
47
|
* This enables autocapture mode — connect/disconnect and transaction events
|
|
@@ -39,11 +62,16 @@ export declare class SolanaManager {
|
|
|
39
62
|
cluster?: SolanaCluster;
|
|
40
63
|
}): void;
|
|
41
64
|
/**
|
|
42
|
-
* Update the cluster/network.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
65
|
+
* Update the cluster/network.
|
|
66
|
+
*
|
|
67
|
+
* With a framework-kit store, only needed if the store endpoint doesn't
|
|
68
|
+
* contain a recognizable cluster name (e.g. custom RPC URLs). Without one,
|
|
69
|
+
* this is how a non-mainnet app tells the SDK which cluster its Wallet
|
|
70
|
+
* Standard connections are on, since the standard itself cannot say.
|
|
45
71
|
*/
|
|
46
72
|
setCluster(cluster: SolanaCluster): void;
|
|
73
|
+
/** Names of the Wallet Standard wallets discovered so far. */
|
|
74
|
+
get discoveredWallets(): string[];
|
|
47
75
|
cleanup(): void;
|
|
48
76
|
}
|
|
49
77
|
//# sourceMappingURL=SolanaManager.d.ts.map
|