Skip to content

Commit

Permalink
feat(sdk): enhanced event tracking and version management
Browse files Browse the repository at this point in the history
  • Loading branch information
thekiba committed May 27, 2024
1 parent b41996e commit cfc013d
Show file tree
Hide file tree
Showing 11 changed files with 472 additions and 121 deletions.
1 change: 1 addition & 0 deletions packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"webpack-cli": "^5.0.0",
"rollup": "^3.18.0",
"@rollup/plugin-typescript": "^11.0.0",
"@rollup/plugin-replace": "5.0.5",
"vite": "^4.2.1",
"vite-tsconfig-paths": "^4.0.5",
"vitest": "^0.29.2",
Expand Down
54 changes: 34 additions & 20 deletions packages/sdk/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
import typescript from '@rollup/plugin-typescript';
import typescript from "@rollup/plugin-typescript";
import packageJson from "./package.json" with { type: "json" };
import replace from "@rollup/plugin-replace";

const version = packageJson.version;

export default [
{
input: 'src/index.ts',
output: {
format: 'esm',
file: './lib/esm/index.mjs',
sourcemap: true
},
plugins: [typescript()],
external: ['@tonconnect/protocol', '@tonconnect/isomorphic-fetch', '@tonconnect/isomorphic-eventsource']
{
input: "src/index.ts",
output: {
format: "esm",
file: "./lib/esm/index.mjs",
sourcemap: true
},
plugins: [
replace({
TON_CONNECT_SDK_VERSION: JSON.stringify(version)
}),
typescript()
],
external: ["@tonconnect/protocol", "@tonconnect/isomorphic-fetch", "@tonconnect/isomorphic-eventsource"]
},
{
input: "src/index.ts",
output: {
format: "cjs",
file: "./lib/cjs/index.cjs",
sourcemap: true
},
{
input: 'src/index.ts',
output: {
format: 'cjs',
file: './lib/cjs/index.cjs',
sourcemap: true
},
plugins: [typescript()],
external: ['@tonconnect/protocol', '@tonconnect/isomorphic-fetch', '@tonconnect/isomorphic-eventsource']
}
plugins: [
replace({
TON_CONNECT_SDK_VERSION: JSON.stringify(version)
}),
typescript()
],
external: ["@tonconnect/protocol", "@tonconnect/isomorphic-fetch", "@tonconnect/isomorphic-eventsource"]
}
];
3 changes: 3 additions & 0 deletions packages/sdk/src/constants/version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare const TON_CONNECT_SDK_VERSION: string;

export const tonConnectSdkVersion = TON_CONNECT_SDK_VERSION;
18 changes: 15 additions & 3 deletions packages/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ export { IStorage } from './storage/models/storage.interface';
export { TonConnect as default } from './ton-connect';
export { WalletsListManager } from './wallets-list-manager';
export { ITonConnect } from './ton-connect.interface';
export type { EventDispatcher } from './tracker/event-dispatcher';
export type {
EventDispatcher,
RemoveTonConnectPrefix,
AddTonConnectPrefix
} from './tracker/event-dispatcher';
export {
createConnectionStartedEvent,
createConnectionErrorEvent,
Expand All @@ -16,7 +20,10 @@ export {
createDisconnectionEvent,
createTransactionSentForSignatureEvent,
createTransactionSigningFailedEvent,
createTransactionSignedEvent
createTransactionSignedEvent,
createRequestVersionEvent,
createResponseVersionEvent,
createVersionInfo
} from './tracker/types';
export type {
AuthType,
Expand All @@ -36,7 +43,12 @@ export type {
TransactionSignedEvent,
TransactionSentForSignatureEvent,
TransactionSigningFailedEvent,
SdkActionEvent
SdkActionEvent,
RequestVersionEvent,
ResponseVersionEvent,
VersionEvent,
Version,
WithoutVersion
} from './tracker/types';
export { BrowserEventDispatcher } from './tracker/browser-event-dispatcher';
export type { TonAddressItem, TonProofItem, ConnectItem } from '@tonconnect/protocol';
Expand Down
27 changes: 18 additions & 9 deletions packages/sdk/src/ton-connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ import { WalletsListManager } from 'src/wallets-list-manager';
import { WithoutIdDistributive } from 'src/utils/types';
import { checkSendTransactionSupport } from 'src/utils/feature-support';
import { callForSuccess } from 'src/utils/call-for-success';
import { logError } from 'src/utils/log';
import { logDebug, logError } from 'src/utils/log';
import { createAbortController } from 'src/utils/create-abort-controller';
import { TonConnectTracker } from 'src/tracker/ton-connect-tracker';
import { tonConnectSdkVersion } from 'src/constants/version';

export class TonConnect implements ITonConnect {
private static readonly walletsList = new WalletsListManager();
Expand Down Expand Up @@ -128,7 +129,10 @@ export class TonConnect implements ITonConnect {
cacheTTLMs: options?.walletsListCacheTTLMs
});

this.tracker = new TonConnectTracker(options?.eventDispatcher);
this.tracker = new TonConnectTracker({
eventDispatcher: options?.eventDispatcher,
tonConnectSdkVersion: tonConnectSdkVersion
});

if (!this.dappSettings.manifestUrl) {
throw new DappMetadataError(
Expand Down Expand Up @@ -333,7 +337,7 @@ export class TonConnect implements ITonConnect {
this.provider = provider;
provider.listen(this.walletEventsListener.bind(this));

const onAbortRestore = () => {
const onAbortRestore = (): void => {
this.tracker.trackConnectionRestoringError('Connection restoring was aborted');
provider?.closeConnection();
provider = null;
Expand All @@ -345,7 +349,7 @@ export class TonConnect implements ITonConnect {
await provider?.restoreConnection({
openingDeadlineMS: options?.openingDeadlineMS,
signal: _options.signal
})
});

abortController.signal.removeEventListener('abort', onAbortRestore);
if (this.connected) {
Expand Down Expand Up @@ -429,7 +433,12 @@ export class TonConnect implements ITonConnect {
);

if (sendTransactionParser.isError(response)) {
this.tracker.trackTransactionSigningFailed(this.wallet, transaction, response.error.message, response.error.code);
this.tracker.trackTransactionSigningFailed(
this.wallet,
transaction,
response.error.message,
response.error.code
);
return sendTransactionParser.parseAndThrowError(response);
}

Expand Down Expand Up @@ -496,7 +505,7 @@ export class TonConnect implements ITonConnect {
if (document.hidden) {
this.pauseConnection();
} else {
this.unPauseConnection().catch(e => logError('Cannot unpause connection', e));
this.unPauseConnection().catch();
}
});
} catch (e) {
Expand Down Expand Up @@ -571,11 +580,11 @@ export class TonConnect implements ITonConnect {
const error = connectErrorsParser.parseError(connectEventError);
this.statusChangeErrorSubscriptions.forEach(errorsHandler => errorsHandler(error));

console.debug(error);
this.tracker.trackConnectionError(connectEventError.message, connectEventError.code)
logDebug(error);
this.tracker.trackConnectionError(connectEventError.message, connectEventError.code);

if (error instanceof ManifestNotFoundError || error instanceof ManifestContentErrorError) {
console.error(error);
logError(error);
throw error;
}
}
Expand Down
33 changes: 30 additions & 3 deletions packages/sdk/src/tracker/browser-event-dispatcher.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { getWindow } from 'src/utils/web-api';
import { EventDispatcher } from 'src/tracker/event-dispatcher';
import { AddTonConnectPrefix, EventDispatcher, RemoveTonConnectPrefix } from './event-dispatcher';

/**
* A concrete implementation of EventDispatcher that dispatches events to the browser window.
*/
export class BrowserEventDispatcher<T> implements EventDispatcher<T> {
export class BrowserEventDispatcher<T extends { type: string }> implements EventDispatcher<T> {
/**
* The window object, possibly undefined in a server environment.
* @private
Expand All @@ -17,8 +17,35 @@ export class BrowserEventDispatcher<T> implements EventDispatcher<T> {
* @param eventDetails - The details of the event to dispatch.
* @returns A promise that resolves when the event has been dispatched.
*/
public async dispatchEvent(eventName: string, eventDetails: T): Promise<void> {
public async dispatchEvent<P extends AddTonConnectPrefix<T['type']>>(
eventName: P,
eventDetails: T & { type: RemoveTonConnectPrefix<P> }
): Promise<void> {
const event = new CustomEvent<T>(eventName, { detail: eventDetails });
this.window?.dispatchEvent(event);
}

/**
* Adds an event listener to the browser window.
* @param eventName - The name of the event to listen for.
* @param listener - The listener to add.
* @param options - The options for the listener.
* @returns A function that removes the listener.
*/
public async addEventListener<P extends AddTonConnectPrefix<T['type']>>(
eventName: P,
listener: (event: CustomEvent<T & { type: RemoveTonConnectPrefix<P> }>) => void,
options?: AddEventListenerOptions
): Promise<() => void> {
this.window?.addEventListener(
eventName,
listener as EventListener | EventListenerObject,
options
);
return () =>
this.window?.removeEventListener(
eventName,
listener as EventListener | EventListenerObject
);
}
}
31 changes: 29 additions & 2 deletions packages/sdk/src/tracker/event-dispatcher.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
/**
* Removes the `ton-connect-` and `ton-connect-ui-` prefixes from the given string.
*/
export type RemoveTonConnectPrefix<T> = T extends `ton-connect-ui-${infer Rest}`
? Rest
: T extends `ton-connect-${infer Rest}`
? Rest
: T;

export type AddTonConnectPrefix<T extends string> = `ton-connect-${T}` | `ton-connect-ui-${T}`;

/**
* Interface for an event dispatcher that sends events.
*/
export interface EventDispatcher<T> {
export interface EventDispatcher<T extends { type: string }> {
/**
* Dispatches an event with the given name and details.
* @param eventName - The name of the event to dispatch.
* @param eventDetails - The details of the event to dispatch.
*/
dispatchEvent(eventName: string, eventDetails: T): Promise<void>;
dispatchEvent<P extends AddTonConnectPrefix<T['type']>>(
eventName: P,
eventDetails: T & { type: RemoveTonConnectPrefix<P> }
): Promise<void>;

/**
* Adds an event listener.
* @param eventName - The name of the event to listen for.
* @param listener - The listener to add.
* @param options - The options for the listener.
* @returns A function that removes the listener.
*/
addEventListener<P extends AddTonConnectPrefix<T['type']>>(
eventName: P,
listener: (event: CustomEvent<T & { type: RemoveTonConnectPrefix<P> }>) => void,
options?: AddEventListenerOptions
): Promise<() => void>;
}
Loading

0 comments on commit cfc013d

Please sign in to comment.