Skip to content

Commit

Permalink
[CHECKOUT SDK][CHECKOUT WIDGETS][CM-896]feat: Load latest compatible …
Browse files Browse the repository at this point in the history
…Widgets bundle (#2217)
  • Loading branch information
jwhardwick authored Sep 25, 2024
1 parent 2d6704d commit c253fe9
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 49 deletions.
1 change: 1 addition & 0 deletions packages/checkout/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export type {
WalletFilter,
WalletInfo,
SquidConfig,
CheckoutWidgetsVersionConfig,
} from './types';

export {
Expand Down
75 changes: 46 additions & 29 deletions packages/checkout/sdk/src/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
/* eslint-disable class-methods-use-this */
import { Web3Provider } from '@ethersproject/providers';
import { ethers } from 'ethers';
import { Environment } from '@imtbl/config';
import { Passport } from '@imtbl/passport';
import { track } from '@imtbl/metrics';
import { Passport } from '@imtbl/passport';
import { ethers } from 'ethers';
import { HttpClient } from './api/http';
import { AvailabilityService, availabilityService } from './availability';
import * as balances from './balances';
import * as tokens from './tokens';
import { CheckoutConfiguration } from './config';
import * as connect from './connect';
import * as provider from './provider';
import * as wallet from './wallet';
import * as network from './network';
import * as transaction from './transaction';
import { handleProviderError } from './transaction';
import { CheckoutError, CheckoutErrorType } from './errors';
import { FiatRampService, FiatRampWidgetParams } from './fiatRamp';
import * as gasEstimatorService from './gasEstimate';
import * as network from './network';
import * as provider from './provider';
import { InjectedProvidersManager } from './provider/injectedProvidersManager';
import { createReadOnlyProviders } from './readOnlyProviders/readOnlyProvider';
import * as smartCheckout from './smartCheckout';
import * as buy from './smartCheckout/buy';
import * as cancel from './smartCheckout/cancel';
import { getItemRequirementsFromRequirements } from './smartCheckout/itemRequirements';
import * as sell from './smartCheckout/sell';
import * as smartCheckout from './smartCheckout';
import * as swap from './swap';
import * as tokens from './tokens';
import * as transaction from './transaction';
import { handleProviderError } from './transaction';
import {
AddNetworkParams,
BuyParams,
Expand All @@ -27,6 +34,7 @@ import {
CheckConnectionParams,
CheckConnectionResult,
CheckoutModuleConfiguration,
CheckoutWidgetsVersionConfig,
ConnectParams,
ConnectResult,
CreateProviderParams,
Expand Down Expand Up @@ -61,23 +69,16 @@ import {
TokenInfo,
ValidateProviderOptions,
} from './types';
import { CheckoutConfiguration } from './config';
import { createReadOnlyProviders } from './readOnlyProviders/readOnlyProvider';
import { SellParams } from './types/sell';
import { CancelParams } from './types/cancel';
import { FiatRampService, FiatRampWidgetParams } from './fiatRamp';
import { getItemRequirementsFromRequirements } from './smartCheckout/itemRequirements';
import { CheckoutError, CheckoutErrorType } from './errors';
import { AvailabilityService, availabilityService } from './availability';
import { getWidgetsEsmUrl, loadUnresolvedBundle } from './widgets/load';
import { SellParams } from './types/sell';
import { SwapParams, SwapQuoteResult, SwapResult } from './types/swap';
import { WidgetsInit } from './types/widgets';
import { HttpClient } from './api/http';
import { isMatchingAddress } from './utils/utils';
import * as wallet from './wallet';
import { WidgetConfiguration } from './widgets/definitions/configurations';
import { SemanticVersion } from './widgets/definitions/types';
import { validateAndBuildVersion } from './widgets/version';
import { InjectedProvidersManager } from './provider/injectedProvidersManager';
import { SwapParams, SwapQuoteResult, SwapResult } from './types/swap';
import { getWidgetsEsmUrl, loadUnresolvedBundle } from './widgets/load';
import { determineWidgetsVersion, validateAndBuildVersion } from './widgets/version';
import { globalPackageVersion } from './env';

const SANDBOX_CONFIGURATION = {
baseConfig: {
Expand Down Expand Up @@ -134,10 +135,27 @@ export class Checkout {
const checkout = this;

// Preload the configurations
await checkout.config.remote.getConfig();
const versionConfig = (
await checkout.config.remote.getConfig('checkoutWidgetsVersion')
) as CheckoutWidgetsVersionConfig | undefined;

// Determine the version of the widgets to load
const validatedBuildVersion = validateAndBuildVersion(init.version);
const initVersionProvided = init.version !== undefined;
const widgetsVersion = determineWidgetsVersion(
validatedBuildVersion,
initVersionProvided,
versionConfig,
);

track('checkout_sdk', 'widgets', {
sdkVersion: globalPackageVersion(),
validatedSdkVersion: validatedBuildVersion,
widgetsVersion,
});

try {
const factory = await this.loadEsModules(init.config, init.version);
const factory = await this.loadEsModules(init.config, widgetsVersion);
return factory;
} catch (err: any) {
throw new CheckoutError(
Expand All @@ -150,15 +168,14 @@ export class Checkout {

private async loadUmdBundle(
config: WidgetConfiguration,
version?: SemanticVersion,
validVersion: string,
) {
const checkout = this;

const factory = new Promise<ImmutableCheckoutWidgets.WidgetsFactory>(
(resolve, reject) => {
try {
const scriptId = 'immutable-checkout-widgets-bundle';
const validVersion = validateAndBuildVersion(version);

// Prevent the script to be loaded more than once
// by checking the presence of the script and its version.
Expand Down Expand Up @@ -225,11 +242,11 @@ export class Checkout {

private async loadEsModules(
config: WidgetConfiguration,
version?: SemanticVersion,
validVersion: string,
) {
const checkout = this;
try {
const cdnUrl = getWidgetsEsmUrl(version);
const cdnUrl = getWidgetsEsmUrl(validVersion);

// WebpackIgnore comment required to prevent webpack modifying the import statement and
// breaking the dynamic import in certain applications integrating checkout
Expand All @@ -248,7 +265,7 @@ export class Checkout {
}

// Fallback to UMD bundle if esm bundle fails to load
return await checkout.loadUmdBundle(config, version);
return await checkout.loadUmdBundle(config, validVersion);
}

/**
Expand Down
12 changes: 9 additions & 3 deletions packages/checkout/sdk/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ interface CheckoutFeatureConfiguration {
* A type representing the on-ramp configurations for the checkout SDK.
* @property {boolean} enable - To enable on-ramp feature in Checkout sdk.
*/
export interface CheckoutOnRampConfiguration extends CheckoutFeatureConfiguration {}
export interface CheckoutOnRampConfiguration extends CheckoutFeatureConfiguration { }

/**
* A type representing the swap configurations for the checkout SDK.
* @property {boolean} enable - To enable swap feature in Checkout sdk.
*/
export interface CheckoutSwapConfiguration extends CheckoutFeatureConfiguration {}
export interface CheckoutSwapConfiguration extends CheckoutFeatureConfiguration { }

/**
* A type representing the bridge configurations for the checkout SDK.
* @property {boolean} enable - To enable bridge feature in Checkout sdk.
*/
export interface CheckoutBridgeConfiguration extends CheckoutFeatureConfiguration {}
export interface CheckoutBridgeConfiguration extends CheckoutFeatureConfiguration { }

/**
* A type representing checkout SDK configurations.
Expand Down Expand Up @@ -81,6 +81,8 @@ export type RemoteConfiguration = {
telemetry?: TelemetryConfig;
/** Squid config. */
squid?: SquidConfig;
/** The checkout version info. */
checkoutWidgetsVersion: CheckoutWidgetsVersionConfig;
};

/**
Expand Down Expand Up @@ -261,3 +263,7 @@ export type GasEstimateSwapTokenConfig = {
export type ChainTokensConfig = {
[key in ChainId]?: TokenInfo[];
};

export type CheckoutWidgetsVersionConfig = {
compatibleVersionMarkers: string[];
};
10 changes: 3 additions & 7 deletions packages/checkout/sdk/src/widgets/load.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('load', () => {
const scriptId = 'immutable-checkout-widgets-bundle';

beforeEach(() => {
jest.spyOn(console, 'warn').mockImplementation(() => {});
jest.spyOn(console, 'warn').mockImplementation(() => { });
});

describe('load unresolved bundle', () => {
Expand All @@ -24,17 +24,13 @@ describe('load', () => {

describe('get widgets esm url', () => {
it('should validate the versioning', () => {
expect(getWidgetsEsmUrl()).toEqual(
expect(getWidgetsEsmUrl(SDK_VERSION)).toEqual(
`https://cdn.jsdelivr.net/npm/@imtbl/sdk@${SDK_VERSION}/dist/browser/checkout/widgets-esm.js`,
);
});

it('should change version', () => {
expect(getWidgetsEsmUrl({
major: 1,
minor: 2,
patch: 3,
})).toEqual(
expect(getWidgetsEsmUrl('1.2.3')).toEqual(
'https://cdn.jsdelivr.net/npm/@imtbl/[email protected]/dist/browser/checkout/widgets-esm.js',
);
});
Expand Down
5 changes: 1 addition & 4 deletions packages/checkout/sdk/src/widgets/load.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { useLocalBundle } from '../env';
import { SemanticVersion } from './definitions/types';
import { validateAndBuildVersion } from './version';

// Loads the checkout widgets bundle from the CDN and appends the script to the document head
export function loadUnresolvedBundle(
Expand Down Expand Up @@ -28,9 +26,8 @@ export function loadUnresolvedBundle(

// Gets the CDN url for the split checkout widgets bundle
export function getWidgetsEsmUrl(
version?: SemanticVersion,
validVersion: string,
): string {
const validVersion = validateAndBuildVersion(version);
let cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets-esm.js`;
if (useLocalBundle()) cdnUrl = `http://${window.location.host}/lib/js/index.js`;
return cdnUrl;
Expand Down
Loading

0 comments on commit c253fe9

Please sign in to comment.