From 1e2d0b222a39ebcf4efcf322d2d9b62eab6a05d3 Mon Sep 17 00:00:00 2001 From: Riley Love Date: Wed, 22 May 2024 20:44:07 -0500 Subject: [PATCH] feat(make transport package): make transport package ourside of react-provider --- packages/react-hooks/package.json | 3 +- packages/react-hooks/src/index.ts | 2 + .../src}/use-transport.ts | 4 +- packages/react-provider/package.json | 5 +- .../src/hooks/use-courier-actions.ts | 3 +- packages/react-provider/src/index.tsx | 7 +- .../react-provider/src/transports/index.ts | 2 - .../react-provider/src/transports/types.ts | 57 ----- packages/react-provider/src/types.ts | 6 +- packages/transport/babel.config.js | 16 ++ packages/transport/jest.config.js | 5 + packages/transport/package.json | 25 ++ .../src/transports => transport/src}/base.ts | 0 .../src}/courier/index.ts | 2 +- .../src}/courier/types.ts | 0 packages/transport/src/index.ts | 7 + packages/transport/src/types.ts | 216 ++++++++++++++++++ .../{react-provider => transport}/src/ws.ts | 2 +- packages/transport/tsconfig.json | 12 + 19 files changed, 299 insertions(+), 75 deletions(-) rename packages/{react-provider/src/hooks => react-hooks/src}/use-transport.ts (94%) delete mode 100644 packages/react-provider/src/transports/index.ts delete mode 100644 packages/react-provider/src/transports/types.ts create mode 100644 packages/transport/babel.config.js create mode 100644 packages/transport/jest.config.js create mode 100644 packages/transport/package.json rename packages/{react-provider/src/transports => transport/src}/base.ts (100%) rename packages/{react-provider/src/transports => transport/src}/courier/index.ts (98%) rename packages/{react-provider/src/transports => transport/src}/courier/types.ts (100%) create mode 100644 packages/transport/src/index.ts create mode 100644 packages/transport/src/types.ts rename packages/{react-provider => transport}/src/ws.ts (99%) create mode 100644 packages/transport/tsconfig.json diff --git a/packages/react-hooks/package.json b/packages/react-hooks/package.json index 9a1fe9e5..33a380a5 100644 --- a/packages/react-hooks/package.json +++ b/packages/react-hooks/package.json @@ -22,7 +22,8 @@ "dependencies": { "@trycourier/client-graphql": "^6.0.0", "deep-extend": "^0.6.0", - "rimraf": "^3.0.2" + "rimraf": "^3.0.2", + "jwt-decode": "^3.1.2" }, "peerDependencies": { "@trycourier/react-provider": ">=4.X.X", diff --git a/packages/react-hooks/src/index.ts b/packages/react-hooks/src/index.ts index ebb0810c..2a3a4887 100644 --- a/packages/react-hooks/src/index.ts +++ b/packages/react-hooks/src/index.ts @@ -4,3 +4,5 @@ export { UsePreferences, } from "./preferences/use-preferences"; export { PreferenceSection } from "./preferences/types"; + +export { default as useTransport } from "./use-transport"; diff --git a/packages/react-provider/src/hooks/use-transport.ts b/packages/react-hooks/src/use-transport.ts similarity index 94% rename from packages/react-provider/src/hooks/use-transport.ts rename to packages/react-hooks/src/use-transport.ts index dc53de91..27ab244d 100644 --- a/packages/react-provider/src/hooks/use-transport.ts +++ b/packages/react-hooks/src/use-transport.ts @@ -1,7 +1,7 @@ import { useMemo, useRef } from "react"; -import { CourierTransport, Transport } from "~/transports"; +import { CourierTransport, Transport } from "@trycourier/transport"; import jwtDecode from "jwt-decode"; -import { ITransportOptions } from "~/transports/courier/types"; +import { ITransportOptions } from "@trycourier/transport"; interface DecodedAuth { scope: string; tenantId: string; diff --git a/packages/react-provider/package.json b/packages/react-provider/package.json index c60f2dab..47b57733 100644 --- a/packages/react-provider/package.json +++ b/packages/react-provider/package.json @@ -18,16 +18,15 @@ "dependencies": { "@trycourier/courier-js": "^1.4.2", "@trycourier/client-graphql": "^6.0.0", + "@trycourier/transport": "^6.0.0", "buffer": "^6.0.3", - "jwt-decode": "^3.1.2", "react-use": "^17.2.1", - "reconnecting-websocket": "^4.4.0", "rimraf": "^3.0.2", "urql": "^2.0.1", "uuid": "^9.0.0" }, "peerDependencies": { - "react": ">=17.X.X", + "react": ">=17. X.X", "react-dom": ">=17.X.X" }, "files": [ diff --git a/packages/react-provider/src/hooks/use-courier-actions.ts b/packages/react-provider/src/hooks/use-courier-actions.ts index b5451d9c..50c65e64 100644 --- a/packages/react-provider/src/hooks/use-courier-actions.ts +++ b/packages/react-provider/src/hooks/use-courier-actions.ts @@ -5,7 +5,8 @@ import { Brands, Events, } from "@trycourier/client-graphql"; -import { Brand, CourierTransport } from ".."; +import { Brand } from ".."; +import { CourierTransport } from "@trycourier/transport"; import courier from "@trycourier/courier-js"; import { ICourierContext } from "~/types"; diff --git a/packages/react-provider/src/index.tsx b/packages/react-provider/src/index.tsx index e6e16e49..ea3954c2 100644 --- a/packages/react-provider/src/index.tsx +++ b/packages/react-provider/src/index.tsx @@ -28,14 +28,14 @@ import { ThemeVariables, WSOptions, } from "./types"; -import { CourierTransport } from "./transports/courier"; +import { CourierTransport } from "@trycourier/transport"; import { IActionElemental, ICourierEventMessage, IInboxMessagePreview, ITextElemental, Interceptor, -} from "./transports/types"; +} from "@trycourier/transport"; import reducer, { registerReducer as _registerReducer } from "./reducer"; import defaultMiddleware, { Middleware, @@ -43,13 +43,12 @@ import defaultMiddleware, { } from "./middleware"; import useCourierActions from "./hooks/use-courier-actions"; import { usePageVisible } from "./hooks/use-page-visible"; -import useTransport from "./hooks/use-transport"; +import { useTransport } from "@trycourier/react-hooks"; import useClientSourceId from "./hooks/use-client-source-id"; import deepExtend from "deep-extend"; import { darkVariables, lightVariables } from "./theme"; import { createGlobalStyle } from "styled-components"; -export * from "./transports"; export * from "./hooks"; export * from "./lib"; diff --git a/packages/react-provider/src/transports/index.ts b/packages/react-provider/src/transports/index.ts deleted file mode 100644 index e7cbe3a5..00000000 --- a/packages/react-provider/src/transports/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./courier"; -export * from "./base"; diff --git a/packages/react-provider/src/transports/types.ts b/packages/react-provider/src/transports/types.ts deleted file mode 100644 index ca678481..00000000 --- a/packages/react-provider/src/transports/types.ts +++ /dev/null @@ -1,57 +0,0 @@ -export interface ICourierEventMessage { - event: "read" | "unread" | "archive" | "mark-all-read" | "opened" | "unpin"; - type: "event"; - messageId?: string; - error?: string; -} - -export interface ITextElemental { - type: "text"; - content: string; -} - -export interface IActionElemental { - background_color?: string; - type: "action"; - content: string; - href: string; - data?: Record; -} - -export interface IInboxMessagePreview { - type: "message"; - archived?: string; - created: string; - messageId: string; - pinned?: { - slotId?: string; - }; - actions?: Array; - preview?: string; - icon?: string; - opened?: string; - data?: Record; - /** ISO 8601 date the message was read */ - read?: string; - tags?: string[]; - title?: string; - trackingIds?: { - openTrackingId?: string; - archiveTrackingId?: string; - clickTrackingId?: string; - deliverTrackingId?: string; - readTrackingId?: string; - unreadTrackingId?: string; - }; -} - -export interface ICourierEvent { - type?: "message" | "event"; - data?: IInboxMessagePreview | ICourierEventMessage; -} - -export type ICourierEventCallback = (event: ICourierEvent) => void; - -export type Interceptor = ( - message?: ICourierEventMessage | IInboxMessagePreview -) => IInboxMessagePreview | ICourierEventMessage | undefined; diff --git a/packages/react-provider/src/types.ts b/packages/react-provider/src/types.ts index dddbc880..630a42ed 100644 --- a/packages/react-provider/src/types.ts +++ b/packages/react-provider/src/types.ts @@ -1,9 +1,9 @@ import { ErrorEvent } from "reconnecting-websocket"; -import { CourierTransport, Transport } from "./transports"; -import { IInboxMessagePreview, Interceptor } from "./transports/types"; +import { CourierTransport, Transport } from "@trycourier/transport"; +import { IInboxMessagePreview, Interceptor } from "@trycourier/transport"; export { IInboxMessagePreview } from "@trycourier/client-graphql"; -export { Interceptor } from "./transports/types"; +export { Interceptor } from "@trycourier/transport"; export type ErrorEventHandler = (event: ErrorEvent) => void; export type PreferenceStatus = "OPTED_IN" | "OPTED_OUT" | "REQUIRED"; diff --git a/packages/transport/babel.config.js b/packages/transport/babel.config.js new file mode 100644 index 00000000..a02c9b26 --- /dev/null +++ b/packages/transport/babel.config.js @@ -0,0 +1,16 @@ +module.exports = { + sourceType: "unambiguous", + plugins: [ + "@babel/transform-runtime", + "transform-inline-environment-variables", + "transform-class-properties", + process.env.NODE_ENV !== "test" && [ + "babel-plugin-root-import", + { + rootPathSuffix: "./src", + rootPathPrefix: "~/", + }, + ], + ].filter(Boolean), + presets: ["@babel/preset-typescript", "@babel/preset-env"], +}; diff --git a/packages/transport/jest.config.js b/packages/transport/jest.config.js new file mode 100644 index 00000000..a72cbc55 --- /dev/null +++ b/packages/transport/jest.config.js @@ -0,0 +1,5 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const jestConfigBase = require("../../jest.config.base"); +const babelConfig = require("./babel.config.js"); + +module.exports = jestConfigBase(babelConfig); diff --git a/packages/transport/package.json b/packages/transport/package.json new file mode 100644 index 00000000..782b74ef --- /dev/null +++ b/packages/transport/package.json @@ -0,0 +1,25 @@ +{ + "name": "@trycourier/transport", + "version": "6.0.0", + "description": "", + "main": "dist/index.js", + "types": "typings/index.d.ts", + "scripts": { + "babel": "babel src -d dist --extensions \".ts\" --ignore \"src/**/__tests__/**\"", + "build:watch": "yarn babel --watch", + "build": "rimraf dist && yarn babel", + "clean": "rimraf dist && rimraf typings", + "test": "jest -c jest.config.js --runInBand", + "type-check": "tsc --noEmit", + "types": "tsc --emitDeclarationOnly" + }, + "license": "ISC", + "dependencies": { + "reconnecting-websocket": "^4.4.0", + "rimraf": "^3.0.2" + }, + "files": [ + "dist/", + "typings/" + ] +} diff --git a/packages/react-provider/src/transports/base.ts b/packages/transport/src/base.ts similarity index 100% rename from packages/react-provider/src/transports/base.ts rename to packages/transport/src/base.ts diff --git a/packages/react-provider/src/transports/courier/index.ts b/packages/transport/src/courier/index.ts similarity index 98% rename from packages/react-provider/src/transports/courier/index.ts rename to packages/transport/src/courier/index.ts index 66ff2e67..71e22ab4 100644 --- a/packages/react-provider/src/transports/courier/index.ts +++ b/packages/transport/src/courier/index.ts @@ -1,4 +1,4 @@ -import { WS } from "../../ws"; +import { WS } from "../ws"; import { Transport } from "../base"; import { Interceptor } from "../types"; import { ITransportOptions } from "./types"; diff --git a/packages/react-provider/src/transports/courier/types.ts b/packages/transport/src/courier/types.ts similarity index 100% rename from packages/react-provider/src/transports/courier/types.ts rename to packages/transport/src/courier/types.ts diff --git a/packages/transport/src/index.ts b/packages/transport/src/index.ts new file mode 100644 index 00000000..a95f89ae --- /dev/null +++ b/packages/transport/src/index.ts @@ -0,0 +1,7 @@ +import { ITransportOptions } from "./courier/types"; + +export * from "./courier"; +export * from "./base"; +export * from "./types"; + +export type { ITransportOptions }; diff --git a/packages/transport/src/types.ts b/packages/transport/src/types.ts new file mode 100644 index 00000000..a1ef8a45 --- /dev/null +++ b/packages/transport/src/types.ts @@ -0,0 +1,216 @@ +export interface ICourierEventMessage { + event: "read" | "unread" | "archive" | "mark-all-read" | "opened" | "unpin"; + type: "event"; + messageId?: string; + error?: string; +} + +export interface ITextElemental { + type: "text"; + content: string; +} + +export interface IActionElemental { + background_color?: string; + type: "action"; + content: string; + href: string; + data?: Record; +} + +export interface IInboxMessagePreview { + type: "message"; + archived?: string; + created: string; + messageId: string; + pinned?: { + slotId?: string; + }; + actions?: Array; + preview?: string; + icon?: string; + opened?: string; + data?: Record; + /** ISO 8601 date the message was read */ + read?: string; + tags?: string[]; + title?: string; + trackingIds?: { + openTrackingId?: string; + archiveTrackingId?: string; + clickTrackingId?: string; + deliverTrackingId?: string; + readTrackingId?: string; + unreadTrackingId?: string; + }; +} + +export interface ICourierEvent { + type?: "message" | "event"; + data?: IInboxMessagePreview | ICourierEventMessage; +} + +export type ICourierEventCallback = (event: ICourierEvent) => void; + +export type Interceptor = ( + message?: ICourierEventMessage | IInboxMessagePreview +) => IInboxMessagePreview | ICourierEventMessage | undefined; + +import { ErrorEvent } from "reconnecting-websocket"; +import { CourierTransport } from "./courier"; +import { Transport } from "./base"; +export type ErrorEventHandler = (event: ErrorEvent) => void; + +export type PreferenceStatus = "OPTED_IN" | "OPTED_OUT" | "REQUIRED"; + +export type RepeatOn = { + sunday?: boolean; + monday?: boolean; + tuesday?: boolean; + wednesday?: boolean; + thursday?: boolean; + friday?: boolean; + saturday?: boolean; +}; + +export interface DigestSchedule { + period: string; + repetition: string; + scheduleId: string; + default?: boolean; + start: string; + recurrence: string; + repeat?: { + frequency: number; + interval: "day" | "week" | "month" | "year"; + on?: string | RepeatOn; + }; + end?: number | string; +} + +export interface IPreferenceTemplate { + templateName: string; + templateId: string; + defaultStatus: PreferenceStatus; + digestSchedules?: DigestSchedule[]; +} + +export type WSOptions = { + url?: string; + onError?: ErrorEventHandler; + onClose?: () => void; + onReconnect?: () => void; + connectionTimeout?: number; +}; + +export type OnEvent = (eventParams: { + messageId?: string; + message?: IInboxMessagePreview; + event: EventType; + data?: Record; +}) => void; + +export interface PinDetails { + id: string; + label: { + value: string; + color: string; + }; + icon: { + value: string; + color: string; + }; +} +export interface Brand { + inapp?: { + disableCourierFooter?: boolean; + borderRadius?: string; + disableMessageIcon?: boolean; + placement?: "top" | "bottom" | "left" | "right"; + emptyState?: { + textColor?: string; + text?: string; + }; + widgetBackground?: { + topColor?: string; + bottomColor?: string; + }; + icons?: { + bell?: string; + message?: string; + }; + slots?: Array; + toast?: { + borderRadius?: string; + timerAutoClose?: number; + }; + renderActionsAsButtons?: boolean; + }; + preferenceTemplates?: Array; + colors?: { + primary?: string; + secondary?: string; + tertiary?: string; + }; +} + +export type EventType = + | "add-tag" + | "archive" + | "click" + | "mark-all-read" + | "opened" + | "read" + | "remove-tag" + | "unpin" + | "unread"; + +export interface ThemeVariables { + background?: string; + textColor?: string; + titleColor?: string; + textColorRead?: string; + structure?: string; + icon?: string; +} + +export interface ProviderTheme { + colorMode?: "dark" | "light"; + variables?: ThemeVariables; +} +export interface ICourierProviderProps { + apiUrl?: string; + applyMiddleware?: (defaultMiddleware: any) => any[]; + authorization?: string; + brand?: Brand; + brandId?: string; + clientKey?: string; + id?: string; + inboxApiUrl?: string; + localStorage?: Storage; + onMessage?: Interceptor; + onRouteChange?: (route: string) => void; + tenantId?: string; + theme?: ProviderTheme; + transport?: CourierTransport | Transport; + userId?: string; + userSignature?: string; + wsOptions?: WSOptions; +} +export interface ICourierContext extends ICourierProviderProps { + clientSourceId?: string; + dispatch: (action: { type: string; payload?: any; meta?: any }) => void; + getBrand: (brandId?: string) => void; + createTrackEvent: (trackingId: string) => void; + identify?: ( + userId: string, + payload: Record + ) => Promise; + subscribe: (userId: string, listId: string) => Promise; + track: (event: string, properties?: Record) => Promise; + unsubscribe: (userId: string, listId: string) => Promise; + renewSession: (token: string) => void; + pageVisible: () => void; + init: (payload: Partial) => Promise; + wsReconnected: () => void; +} diff --git a/packages/react-provider/src/ws.ts b/packages/transport/src/ws.ts similarity index 99% rename from packages/react-provider/src/ws.ts rename to packages/transport/src/ws.ts index 4eb0b7db..a8ed8c81 100644 --- a/packages/react-provider/src/ws.ts +++ b/packages/transport/src/ws.ts @@ -2,7 +2,7 @@ import { ICourierEventCallback, ICourierEventMessage, IInboxMessagePreview, -} from "./transports/types"; +} from "./types"; import ReconnectingWebSocket, { ErrorEvent } from "reconnecting-websocket"; import { ErrorEventHandler, WSOptions } from "./types"; diff --git a/packages/transport/tsconfig.json b/packages/transport/tsconfig.json new file mode 100644 index 00000000..062df5b9 --- /dev/null +++ b/packages/transport/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig-base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "declarationDir": "./typings", + "paths": { + "~/*": ["./src/*"] + } + }, + "include": ["../types/@types/*/index.d.ts", "./src/**/*.ts"] +}