@coxwave/tap-sdk 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@coxwave/tap-sdk",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "type": "module",
5
5
  "description": "A vanilla JS SDK",
6
- "main": "index.ts",
6
+ "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
8
8
  "types": "dist/index.d.ts",
9
9
  "exports": {
package/index.ts DELETED
@@ -1,285 +0,0 @@
1
- import ChatBodyMaker from "./chatBody";
2
- import FloatingButtonMaker from "./floatingButton";
3
- import { TapIframeBridge } from "./services/tap-iframe-bridge";
4
- import { EventManager } from "./services/event-manager";
5
- import showPopupWithHtml from "./popUpImage";
6
-
7
- import InitGA from "./ga";
8
-
9
- import {
10
- AlarmMessageInstanceType,
11
- ChatApiParamsType,
12
- TapSDKType,
13
- CustomStylesType,
14
- ShortcutKeyType,
15
- SeekTimelineParamsType,
16
- } from "./types";
17
-
18
- class TapSDK {
19
- private pluginKey: string;
20
- private iframeBridge: TapIframeBridge;
21
- public events: EventManager;
22
-
23
- private chatBody: HTMLElement | null = null;
24
- private chatBodyMaker: ChatBodyMaker;
25
- private floatingButtonMaker: FloatingButtonMaker;
26
- private shortcutKey: ShortcutKeyType = {
27
- openChat: { key: "/", modifier: "" },
28
- sendChat: { key: "Enter", modifier: "" },
29
- };
30
-
31
- private isProd: boolean;
32
- private isLocal: boolean;
33
-
34
- private isOpen: boolean;
35
- private isPdfOpen: boolean;
36
-
37
- constructor({ pluginKey, isProd = false, isLocal = false }: TapSDKType) {
38
- // protocol
39
- this.pluginKey = pluginKey;
40
- this.iframeBridge = new TapIframeBridge({
41
- hostClientUrl: window.location.origin,
42
- pluginKey: this.pluginKey,
43
- });
44
-
45
- // events
46
- this.events = new EventManager(this.iframeBridge);
47
-
48
- // render
49
- this.floatingButtonMaker = new FloatingButtonMaker();
50
- this.chatBodyMaker = new ChatBodyMaker();
51
-
52
- // ga log
53
- this.isProd = isProd;
54
- this.isLocal = isLocal;
55
-
56
- // state
57
- this.isOpen = false;
58
- this.isPdfOpen = false;
59
- }
60
-
61
- #isClient() {
62
- return typeof window !== "undefined" && typeof document !== "undefined";
63
- }
64
-
65
- private setIsOpen(isOpen: boolean) {
66
- this.isOpen = isOpen;
67
- }
68
-
69
- private setIsPdfOpen(isPdfOpen: boolean) {
70
- this.isPdfOpen = isPdfOpen;
71
- }
72
-
73
- private sendChatMessage(): void {
74
- const messageType = this.isOpen ? "chat:close" : "chat:open";
75
-
76
- try {
77
- const result = this.iframeBridge.postToTap({
78
- type: messageType,
79
- });
80
-
81
- if (!result) {
82
- console.error(`[TapSDK] Failed to send ${messageType} message`);
83
- } else {
84
- }
85
- } catch (error) {
86
- console.error("[TapSDK] Error sending chat message:", error);
87
- }
88
- }
89
-
90
- seekTimeline({ clipId, clipPlayHead }: SeekTimelineParamsType) {
91
- this.iframeBridge.postToTap({
92
- type: "timeline:seek",
93
- clipId,
94
- clipPlayHead,
95
- });
96
- }
97
-
98
- async initChat({
99
- chatApiParams,
100
- customStyles,
101
- shortcutKey,
102
- }: {
103
- chatApiParams: ChatApiParamsType;
104
- customStyles?: CustomStylesType;
105
- shortcutKey?: ShortcutKeyType;
106
- }) {
107
- if (!this.#isClient()) {
108
- console.error(
109
- "[TapSDK] Not running in client environment: window is not defined"
110
- );
111
- throw new Error("not client: window is not defined");
112
- }
113
-
114
- this.shortcutKey = {
115
- openChat: shortcutKey?.openChat ?? this.shortcutKey.openChat,
116
- sendChat: shortcutKey?.sendChat ?? this.shortcutKey.sendChat,
117
- };
118
-
119
- // chat body render
120
- if (!this.chatBody) {
121
- const createdChatBody = this.chatBodyMaker.createChatBody({
122
- ...(customStyles?.chatBody && {
123
- customChatBody: customStyles.chatBody,
124
- }),
125
- });
126
-
127
- if (!createdChatBody) {
128
- console.error("[TapSDK] Failed to create chat body");
129
- throw new Error("Failed to create chat body");
130
- }
131
-
132
- this.chatBody = createdChatBody;
133
- }
134
-
135
- // chat iframe
136
- if (!this.iframeBridge.hasIframe()) {
137
- await this.iframeBridge.renderIframe({
138
- chatBody: this.chatBody,
139
- isProd: this.isProd,
140
- isLocal: this.isLocal,
141
- });
142
- } else {
143
- }
144
-
145
- try {
146
- const initiatedMessage = await this.iframeBridge.performHandshake(
147
- {
148
- chatApiParams,
149
- customStyles,
150
- shortcutKey: this.shortcutKey,
151
- },
152
- {
153
- retryInterval: 500,
154
- maxRetries: 10,
155
- timeout: 10000,
156
- }
157
- );
158
-
159
-
160
- // Initialize GA with the received gaId
161
- new InitGA({ gaId: initiatedMessage.gaId });
162
- } catch (error) {
163
- console.error("[TapSDK] Handshake failed:", error);
164
- throw new Error(
165
- `Chat initialization failed: ${error instanceof Error ? error.message : "Unknown error"}`
166
- );
167
- }
168
-
169
- // floating button render
170
- this.floatingButtonMaker.render({
171
- ...(customStyles?.floatingButton && {
172
- customFloatingButton: customStyles.floatingButton,
173
- }),
174
- });
175
- this.floatingButtonMaker.addClickEvent({
176
- callback: () => {
177
-
178
- // Check if iframe exists before sending message
179
- if (!this.iframeBridge.hasIframe()) {
180
- console.warn("[TapSDK] Iframe not available, attempting to reinitialize...");
181
- // Try to recreate iframe if it's missing
182
- this.iframeBridge.renderIframe({
183
- chatBody: this.chatBody!,
184
- isProd: this.isProd,
185
- isLocal: this.isLocal,
186
- }).then(() => {
187
- this.sendChatMessage();
188
- }).catch((error) => {
189
- console.error("[TapSDK] Failed to recreate iframe:", error);
190
- });
191
- return;
192
- }
193
-
194
- this.sendChatMessage();
195
- },
196
- });
197
-
198
- this.floatingButtonMaker.addAlarmClickEvent({
199
- callback: (messageInfo: AlarmMessageInstanceType) => {
200
- this.iframeBridge.postToTap({ type: "chat:open", isAlarm: true });
201
- this.iframeBridge.postToTap({ type: "alarm:click", messageInfo });
202
- },
203
- });
204
-
205
- this.iframeBridge.listenToTap("chat:opened", () => {
206
- this.setIsOpen(true);
207
- this.chatBodyMaker.toggleVisibility(this.isOpen);
208
- this.floatingButtonMaker.alarmRemove();
209
- });
210
- this.iframeBridge.listenToTap("chat:closed", () => {
211
- this.setIsOpen(false);
212
- this.chatBodyMaker.toggleVisibility(this.isOpen);
213
- });
214
-
215
- // alarm
216
- this.iframeBridge.listenToTap("alarm:fadeIn", (data) => {
217
- if (this.isOpen) return;
218
- this.floatingButtonMaker.alarmFadeIn(data.messageInfo);
219
- });
220
-
221
- // popUp
222
- this.iframeBridge.listenToTap("popUp:open", (data) => {
223
- showPopupWithHtml({
224
- htmlString: data.popUpInfo.html,
225
- callback: () => this.iframeBridge.postToTap({ type: "popUp:close" }),
226
- ...(customStyles?.chatBody && { customStyles: customStyles.chatBody }),
227
- });
228
- });
229
-
230
- // pdf Open
231
- this.iframeBridge.listenToTap("pdf:open", () => {
232
- this.setIsPdfOpen(true);
233
- this.chatBodyMaker.resizeChatBody(this.isPdfOpen, customStyles?.chatBody);
234
- this.iframeBridge.postToTap({ type: "pdf:enlarged" });
235
- });
236
- this.iframeBridge.listenToTap("pdf:close", () => {
237
- this.setIsPdfOpen(false);
238
- this.chatBodyMaker.resizeChatBody(this.isPdfOpen, customStyles?.chatBody);
239
- this.iframeBridge.postToTap({ type: "pdf:shrinked" });
240
- });
241
-
242
- // if dev, attach alaram:fadeIn event
243
- if (this.isLocal) {
244
- this.iframeBridge.listenToTap("alarm:fadeIn", (data) => {
245
- this.floatingButtonMaker.alarmFadeIn(data.messageInfo);
246
- });
247
- }
248
- }
249
-
250
- removeChat() {
251
- if (!this.chatBody) throw new Error("chatBody is not initialized");
252
-
253
- this.chatBodyMaker.removeChatBody();
254
- this.floatingButtonMaker.alarmRemove();
255
- this.iframeBridge.removeIframe();
256
- this.chatBody = null;
257
- this.isOpen = false;
258
- }
259
-
260
- /**
261
- * @deprecated use `seekTimeline` method. gotta be expired at v1.0.0
262
- */
263
- postChatInfo({
264
- clipId,
265
- clipPlayHead,
266
- }: {
267
- clipId: string;
268
- clipPlayHead: number;
269
- }) {
270
- this.seekTimeline({ clipId, clipPlayHead });
271
- }
272
-
273
- /**
274
- * @deprecated use `events.onTimelineSeek` method. gotta be expired at v1.0.0
275
- */
276
- getTimelineInfo({
277
- callback,
278
- }: {
279
- callback: (clipPlayHead: number, clipId: string) => void;
280
- }) {
281
- this.events.onTimelineSeek(callback);
282
- }
283
- }
284
-
285
- export default TapSDK;