npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

smartshopping-sdk

v0.7.0

Published

Coupon autoapply SDK

Downloads

268

Readme

SmartShopping SDK

Installation

npm i smartshopping-sdk yarn add smartshopping-sdk

Integration

"storage", "tabs" and "alarms" permissions required

To use the checkAdblockAndCookie function in Manifest V3 need add "scripting" permission and host_permissions in manifest:

"host_permissions": [
  "*://*/*"
],

For Manifest V2 add "management" and "<all_urls>" permissions

Background script

Background script of extension using SmartShopping SDK might look like this:

import { bootstrap } from 'smartshopping-sdk';
import { requirePromocodes } from '../utils';

(async () => {
  const { install, startEngine, setCodes, checkAdblockAndCookie } = bootstrap({
    clientID: 'demo',
    key: 'very secret key',
  });

  install();

  chrome.tabs.onUpdated.addListener(async (tabId, changeInfo) => {
    if (changeInfo.status === 'complete') {
      startEngine(tabId);
    }
  });

  chrome.tabs.onReplaced.addListener(async (tabId) => {
    startEngine(tabId);
  });

  chrome.runtime.onMessage.addListener(
    async (message, sender, sendResponse) => {
      const tabId = sender?.tab?.id;
      if (!tabId) {
        return;
      }

      if (message.type === 'ready_to_CAA') {
        const codes = await requirePromocodes(tabId);
        if (codes.length) {
          setCodes(tabId, codes);
        }
      }

      if (message.type === 'check_adblock_cookie') {
        checkAdblockAndCookie()
          .then(({ isAdblockDisabled, isCookieEnabled }) => sendResponse({ isAdblockDisabled, isCookieEnabled }))
          .catch(err => console.log(err))
      }
    }
  );
})();

bootstrap takes three arguments – client ID, secret key (which is used for data decryption) and optional - serverUrl (not used by default). If you dont know your ID and secret key, contact SmartShopping tech support

It returns four functions:

  • install: () => Promise<void> uploads and stores merchants data; also sets up message passing between background and content parts of SmartShopping.

  • startEngine: (tabId: number) => Promise<void> identifies merchant in an active tab, uploads corresponding config and initializes Engine in a content script. Takes browser tab ID as an argument.

  • setCodes: (tabId: number, codes: string[]) => void sends to the Engine a list of coupons Takes browser tab ID and array of promo codes as an arguments

  • checkAdblockAndCookie: () => Promise<{ isAdblockDisabled: boolean; isCookieEnabled: boolean; }>; function checks if Adblock extension is disabled and checks if cookies are enabled and returns an object with two boolean keys.

In the example above requirePromocodes is a function defined by host extension, responsible for finding promocodes which will be passed to setCodes.

Content Script

In a content script you need to import an engine instance:

import { engine } from 'smartshopping-sdk';

engine receives config object from background script and manages coupon autoapply flow or detect a successful coupon.

Coupon autoapply flow stages:

  1. engine.inspect() – analyzing checkout page and collecting information;

  2. engine.apply() – applying promocodes and storing results into internal execution context;

  3. engine.applyBest() – choosing and applying best promocode;

All three stages can be executed consistently via engine.fullCycle().

Detect stage - engine.detect() – detects if a user tried to apply a coupons;

The execution of the stages: detect, apply, applyBest can be aborted using the engine.abort() method.

Since it is up to you to show the modal window with the suggestion to apply coupons, call the engine.notifyAboutShowModal() method before it is shown so that we can get these statistics.

And if the user closes the modal prompting them to apply codes, call the engine.notifyAboutCloseModal() method.

When a user tries to apply a third-party coupon, you can show them a modal window notifying them that they are trying to apply a third-party coupon, to collect statistics you can use methods:

  1. notifyAboutShow3dPartyModal - when opening the modal window;

  2. notifyAboutClose3dPartyModal - when closing the modal window;

  3. notifyAboutReactivate3dParty - when reactivating coupon (if you want to offer a user to reactivate a coupon);

Config object looks like this:

type EngineConfig {
  version: number;
  shopId: string;
  shopName: string;
  shopUrl: string;
  checkoutUrl: string;
  inspect: Array<Command>;
  detect: Array<Command>;
  apply: Array<Command>;
  applyBest: Array<Command>;
  selectorsToCheck: Array<string>;
}
  • version – version of config spec for intrinsic usage

  • shopId – merchant's unique ID in SmartShopping database

  • shopName – merchant's name

  • shopUrl – RegEx matching all merchant's URLs

  • checkoutUrl – RegEx matching merchant's checkout page

  • inspect, detect, apply and applyBest – arrays of commands for respective stages of auto apply flow.

  • selectorsToCheck – array of selectors which are necessary to proceed. If any of them are invalid, execution stops with an error.

engine stores info in the following properties:

  1. config: EngineConfig Config object
  2. progress: EngineProgress Execution status
 type EngineProgress =
  | 'IDLE'
  | 'INSPECT'
  | 'INSPECT_END'
  | 'DETECT'
  | 'APPLY'
  | 'APPLY_END'
  | 'APPLY-BEST'
  | 'APPLY-BEST_END'
  | 'ERROR'
  | 'CANCEL';
  1. checkoutState: EngineCheckoutState Info collected during inspect stage checkoutState.total – cart total before applying any codes
type EngineCheckoutState {
  total: number | null;
}
  1. finalCost: EngineFinalCost This object contains pairs "promocode": "cart total after applying promocode"
type EngineFinalCost = { [key: string]: number }
  1. promocodes: Array<string> Array of promocodes for testing
  2. currentCode: string Promocode currently being processed
  3. detectState: EngineDetectState Info collected during detect stage detectState.userCode - promocode entered by the user. If detectState.userCode === 'UNDEFINED_CODE' it means that we can't get the value of the code, but we know that it was entered detectState.isValid - validity of the code entered by the user. true if the code is successfully applied and false if the entered code turned out to be erroneous
type EngineDetectState {
  userCode: string | 'UNDEFINED_CODE';
  isValid: boolean;
}
  1. bestCode: string Most profitable promocode If none of the codes worked, bestCode === ''
  2. checkout: boolean | null The flag is null if you are on a page for which we don't have a config yet. In other cases, the flag has a boolean value and indicates whether you are on the checkout page

You can subscribe to those properties' changes via engine.subscribe()...

const unbinders = engine.subscribe(
    {
      config: configListener,
      checkoutState: checkoutStateListener,
      finalCost: finalCostListener,
      promocodes: promocodesListener,
      progress: progressListener,
      currentCode: currentCodeListener,
      detectState: detectStateListener,
      bestCode: bestCodeListener,
      checkout: checkoutListener,
    }
);

...and unsubscribe via engine.ubsubscribe(), passing return value of engine.subscribe() as an argument:

engine.unsubscribe(unbinders);

Subscribing for properties is optional so you may only choose ones you need and skip the rest:

const unbinders = engine.subscribe(
    {
      progress: listener1,
      currentCode: listener2,
      bestCode: listener3,
      checkout: listener4,
    }
);

listener - functions look like this:

listener: (value: %property_type%, state: EngineState) => void;

interface EngineState {
  checkoutState: EngineCheckoutState;
  finalCost: EngineFinalCost;
  progress: EngineProgress;
  config: EngineConfig;
  promocodes: Array<string>;
  detectState: EngineDetectState;
  bestCode: string;
  currentCode: string;
  checkout: boolean | null;
}

You can see more in our demo-extension

Changelog

[0.7.0] - 2023-11-16

Changed

  • Engine initialization

Added

  • Added support for user configs
  • Extended error log
  • SDK version in server request
  • Methods for 3d party coupons

[0.6.11] - 2023-07-10

Added

  • Added Edge supports for adblock check

[0.6.10] - 2023-07-06

Update

  • Update documentation
  • Update @types/chrome package

[0.6.9] - 2023-06-29

Added

  • Export 'AdblockAndCookieOutput' type

[0.6.8] - 2023-06-23

Changed

  • Now the checkout state is of type boolean | null. If we don't support the merchant from the page, we return null in the checkoutListener

[0.6.7] - 2023-06-21

Fixed

  • checkAdblockAndCookie for use with Manifest V3
  • Error in console
  • Update documentation

[0.6.6] - 2023-06-15

Fixed

  • Error in console

[0.6.5] - 2023-06-15

Added

  • Export checkAdblockAndCookie function

[0.6.4] - 2023-05-29

Added

  • Export BootstrapOutput type

[0.6.3] - 2023-05-26

Fixed

  • Optimizing the size of the data requested from the server

[0.6.2] - 2023-03-03

Changed

  • Change method name from sendСodes to setCodes

[0.6.1] - 2023-02-27

Added

  • README.md file with Changelog

[0.6.0] - 2023-02-16

Added

  • sendCodes method

Changed

  • Remove codes param from startEngine method

[0.5.21] - 2023-01-24

Fixed

  • Cache work