Skip to content

Commit

Permalink
Merge pull request #9 from WunderbarNetwork/sdk-v1.2.0
Browse files Browse the repository at this point in the history
SDK v1.2.0
  • Loading branch information
MilosRandelovic committed Jun 29, 2023
2 parents 769d21a + ea699b9 commit 8c0da98
Show file tree
Hide file tree
Showing 19 changed files with 1,525 additions and 157 deletions.
4 changes: 2 additions & 2 deletions .eslintrc.json
Expand Up @@ -9,9 +9,9 @@
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"project": "tsconfig.json"
"project": "tsconfig.eslint.json"
},
"plugins": ["prettier"],
"plugins": ["prettier", "vitest"],
"rules": {
"prettier/prettier": ["warn"]
}
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/ci.yaml
@@ -0,0 +1,27 @@
name: Node.js CI

on:
pull_request:
branches: [ "main" ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x]

steps:
- uses: actions/checkout@v3

- name: Using Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- run: yarn --network-concurrency 8 || yarn --check-files --cache-folder .ycache && rm -rf .ycache
- run: yarn test
- run: yarn lint

1 change: 1 addition & 0 deletions .npmrc
@@ -0,0 +1 @@
@wunderbar-network:registry=https://registry.npmjs.org/
69 changes: 45 additions & 24 deletions README.md
@@ -1,45 +1,66 @@
# @wunderbar-network/mini-digital-sdk-js
# @wunderbar-network/mini-digital-sdk

Shared library that provides an interface for Event Tracking using the **Mini Digital Events API** to Node or browser-based TS/JS implementations.
Library that provides an interface to capture analytics events, and send them to [Mini Digital](https://mini.digital). This library can be used in either Node.js or browser-based TypeScript/JavaScript implementations (including frameworks like React or Vue).

## Usage
## Installation

### Node.js
To install the library, you can use npm or yarn. Run the following command:

Add the following to your `package.json`:
```shell
npm install @wunderbar-network/mini-digital-sdk
```

or

```json
{
// ...
"dependencies": {
"@wunderbar-network/mini-digital-sdk-js": "https://github.com/WunderbarNetwork/mini-digital-sdk-js.git",
},
// ...
}
```shell
yarn add @wunderbar-network/mini-digital-sdk
```

You can also include a specific branch by doing `repo.git#branch-name` at the end (e.g. `#v1.1.0`).
### Usage

You can then import classes and types directly into your project like so:
To send a quick event using the Mini Digital SDK, do the following:

```ts
import { EventTrackingService, EventTrackingUtil } from "@wunderbar-network/mini-digital-sdk-js";
import type { AnalyticsEvent } from "@wunderbar-network/mini-digital-sdk-js";
// Import the library
import { type AnalyticsEvent, EventTrackingService } from "@wunderbar-network/mini-digital-sdk";

// Declare event
const event: AnalyticsEvent = {
eventName: "my_first_mini_digital_event",
eventCategory: "system_outcome_event",
eventSource: "MyProject.EventTestingPlayground",
anonymousUser: true,
};

// Send event!
EventTrackingService.postEvent(event);
```

The `EventTrackingUtil` class has methods that could make capturing some of the fields for the `AnalyticsEvent` easier.
See our API reference to get a deeper understanding of the event schema.

### Browser
### Browser builds

If you are capturing events from the browser and want a browser-friendly build, this can be found in the `lib/browser` folder.
If you want a browser-friendly build to use directly into your HTML code, browser builds (CJS/ESM) can be found in the `lib/browser` folder.

### Mini Digital URL
### Config

If you wish to override the default Mini Digital URL (to point to e.g. a testing instance), you can do so by overriding the config namespace variable:
By default, the config is set to send events to the production Mini Digital endpoint. If you wish to override the default Mini Digital URL (to point to e.g. a testing instance), you can do so by overriding the config namespace variable:

```ts
import { EventTrackingConfig } from "@wunderbar-network/mini-digital-sdk-js";
import { EventTrackingConfig } from "@wunderbar-network/mini-digital-sdk";

// Override the default value
EventTrackingConfig.miniDigitalUrl = "https://test.api.mini.digital/";
EventTrackingConfig.miniDigitalUrl = "http://localhost:3333/";
```

You can also choose to _pause_ sending events (e.g. in your test suites), or not use cookies (to store anonymous tracking IDs):

```ts
import { EventTrackingConfig } from "@wunderbar-network/mini-digital-sdk";

// Override the default value
EventTrackingConfig.pauseTracking = true;
EventTrackingConfig.useCookies = false;
```

See our API reference for the full list of configuration options.
39 changes: 28 additions & 11 deletions package.json
@@ -1,7 +1,7 @@
{
"name": "@wunderbar-network/mini-digital-sdk-js",
"version": "1.1.0",
"description": "Event Tracking Service for back-end (Node) and front-end (JS) applications, to send events to the Mini.Digital ingress API",
"name": "@wunderbar-network/mini-digital-sdk",
"version": "1.2.0",
"description": "Event Tracking Service for back-end (Node) and front-end (JS) applications, to send analytics events to Mini.Digital",
"private": true,
"exports": {
".": {
Expand All @@ -27,34 +27,51 @@
"build:node": "npm run clean && tsc --build && mv lib/node/index.js lib/node/index.mjs && node post-build.js",
"build:browser": "rollup -c",
"prepare": "npm run build",
"test": "vitest run",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --ignore-path .gitignore"
},
"dependencies": {
"js-cookie": "^3.0.5",
"uuid": "^9.0.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^25.0.1",
"@rollup/plugin-commonjs": "^25.0.2",
"@rollup/plugin-node-resolve": "^15.1.0",
"@rollup/plugin-terser": "^0.4.3",
"@types/js-cookie": "^3.0.3",
"@types/jsdom": "^21.1.1",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^5.59.11",
"@typescript-eslint/parser": "^5.59.11",
"eslint": "^8.42.0",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-standard-with-typescript": "^35.0.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^16.0.0",
"eslint-plugin-jest": "^27.2.2",
"eslint-plugin-n": "^16.0.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vitest": "^0.2.6",
"jsdom": "^22.1.0",
"prettier": "^2.8.8",
"rollup": "^3.25.1",
"typescript": "^5.1.3"
"rollup": "^3.25.2",
"typescript": "^5.1.3",
"vitest": "^0.32.2",
"vitest-fetch-mock": "^0.2.2"
},
"repository": {
"type": "git",
"url": "git+https://github.com/WunderbarNetwork/mini-digital-sdk-js.git"
},
"homepage": "https://github.com/WunderbarNetwork/mini-digital-sdk-js#readme"
"homepage": "https://github.com/WunderbarNetwork/mini-digital-sdk-js#readme",
"bugs": {
"url": "https://github.com/WunderbarNetwork/mini-digital-sdk-js/issues"
},
"directories": {
"lib": "lib"
},
"contributors": [
"Miloš Ranđelović <milos@randelovic.me>"
],
"license": "MIT"
}
7 changes: 5 additions & 2 deletions src/index.ts
@@ -1,7 +1,10 @@
import { type AnalyticsEvent } from "./types/AnalyticsEvent.js";
import type { AnalyticsEvent } from "./types/AnalyticsEvent.js";
import type { EnrichedAnalyticsEvent } from "./types/EnrichedAnalyticsEvent.js";

import { config as EventTrackingConfig } from "./util/Config.js";

import * as EventTrackingService from "./services/EventTrackingService.js";
import * as EventTrackingUtil from "./util/ConsumerUtil.js";

export { type AnalyticsEvent, EventTrackingService, EventTrackingConfig, EventTrackingUtil };
export type { AnalyticsEvent, EnrichedAnalyticsEvent };
export { EventTrackingService, EventTrackingConfig, EventTrackingUtil };
4 changes: 3 additions & 1 deletion src/services/EventEnrichmentService.ts
Expand Up @@ -81,12 +81,14 @@ function determineIdentifiers(
// Tracking ID will only be stored if the event comes from the browser, and is not part of the "consumer" `AnalyticsEvent` schema
if (isBrowser) {
// Event from the browser, check if the tracking ID has been stored previously
trackingId = Cookies.get(COOKIE_NAME_TRACKING_ID);
trackingId = config.useCookies ? Cookies.get(COOKIE_NAME_TRACKING_ID) : undefined;

if (Util.isStringNullOrEmpty(trackingId)) {
// No previous tracking ID, generate a random UUID
trackingId = generateAnonymousUserId();
}

if (config.useCookies && trackingId !== undefined) {
// Save the tracking ID into a cookie
Cookies.set(COOKIE_NAME_TRACKING_ID, trackingId, {
domain: !Util.isStringNullOrEmpty(config.cookieDomain) ? config.cookieDomain : undefined,
Expand Down
12 changes: 8 additions & 4 deletions src/services/EventTrackingService.ts
Expand Up @@ -22,6 +22,8 @@ const isBrowser: boolean = typeof window !== "undefined" && typeof window.docume
* @param logResponse Optional - output to console when event has been successfully posted (default = false)
*/
export async function postEvent(event: AnalyticsEvent, logResponse: boolean = false): Promise<void> {
if (config.pauseTracking) return;

let miniDigitalUrl: string = config.miniDigitalUrl;

if (isStringNullOrEmpty(miniDigitalUrl)) {
Expand All @@ -38,7 +40,7 @@ export async function postEvent(event: AnalyticsEvent, logResponse: boolean = fa

if (isBrowser) {
// Check if a cookie exist with a jwtAuthorizationToken
jwtAuthorizationToken = Cookies.get(COOKIE_NAME_JWT_TOKEN);
jwtAuthorizationToken = config.useCookies ? Cookies.get(COOKIE_NAME_JWT_TOKEN) : undefined;

// Running from within a browser, use JWT
const response = await postEventJwt(analyticsEvent, false, miniDigitalUrl, logResponse);
Expand All @@ -50,7 +52,7 @@ export async function postEvent(event: AnalyticsEvent, logResponse: boolean = fa
if (response.statusCode === 401 && !isStringNullOrEmpty(response.authorizationToken)) {
jwtAuthorizationToken = response.authorizationToken;

if (!isStringNullOrEmpty(jwtAuthorizationToken) && jwtAuthorizationToken !== undefined) {
if (config.useCookies && !isStringNullOrEmpty(jwtAuthorizationToken) && jwtAuthorizationToken !== undefined) {
Cookies.set(COOKIE_NAME_JWT_TOKEN, jwtAuthorizationToken, {
domain: !isStringNullOrEmpty(config.cookieDomain) ? config.cookieDomain : undefined,
expires: config.cookieJwtTokenExpiration,
Expand Down Expand Up @@ -94,8 +96,10 @@ async function postEventJwt(
throw new Error("Error interfacing with Mini Digital.");
}

const responseAuthorizationToken = response.headers.get("Authorization");

if (!response.ok) {
if (response.status !== 401 || (response.status === 401 && forceErrorOn401)) {
if (response.status !== 401 || (response.status === 401 && (isStringNullOrEmpty(responseAuthorizationToken) || forceErrorOn401))) {
throw new Error(`Mini Digital POST error! Status: ${response.status}`);
}
}
Expand All @@ -105,7 +109,7 @@ async function postEventJwt(
const serviceResponse: ServiceResponse = {
message: responseBody.message,
statusCode: response.status,
authorizationToken: response.headers.get("Authorization") ?? undefined,
authorizationToken: responseAuthorizationToken ?? undefined,
};

if (logResponse) {
Expand Down
19 changes: 15 additions & 4 deletions src/util/Config.ts
Expand Up @@ -9,24 +9,35 @@ interface MiniDigitalConfig {
*/
cookieDomain?: string;
/**
* Expiration of the Cookie storing the JWT token (in seconds). Default = 1 day.
* Expiration of the Cookie storing the JWT token (in days). Default = 1 day.
*/
cookieJwtTokenExpiration: number;
/**
* Expiration of the Cookie storing the tracking Id (in seconds). Default = 30 days.
* Expiration of the Cookie storing the tracking Id (in days). Default = 30 days.
*/
cookieTrackingIdExpiration: number;
/**
* Default value for the Mini Digital Event Ingress URL, can be customized if needed.
*/
miniDigitalUrl: string;
/**
* Set to `true` to temporarily pause tracking (sending events to the server)
*/
pauseTracking: boolean;
/**
* Set to `false` to turn off storing a Mini Digital Tracking ID into a secure cookie.
* This will limit the ability to link events performed by anonymous (non logged-in) users.
*/
useCookies: boolean;
}

/** Mini Digital Config */
export const config: MiniDigitalConfig = {
cookieJwtTokenExpiration: 60 * 60 * 24,
cookieTrackingIdExpiration: 60 * 60 * 24 * 30,
cookieJwtTokenExpiration: 1,
cookieTrackingIdExpiration: 30,
miniDigitalUrl: "https://api.mini.digital",
pauseTracking: false,
useCookies: true,
};

/** The name & version to identify this SDK */
Expand Down

0 comments on commit 8c0da98

Please sign in to comment.