@coxwave/tap-sdk 0.2.8 → 0.3.1
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/README.md +117 -30
- package/dist/index.d.cts +35 -111
- package/dist/index.d.ts +35 -111
- package/dist/index.global.js +2 -2
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -4
- package/src/index.ts +21 -0
- package/src/loader.ts +185 -0
- package/src/sdk.ts +125 -0
- package/index.ts +0 -361
- package/types.ts +0 -65
package/index.ts
DELETED
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TapKit wrapper - npm package wrapper
|
|
3
|
-
*
|
|
4
|
-
* Simply loads the CDN loader which handles version management and SDK loading.
|
|
5
|
-
* This keeps the npm package minimal and allows instant updates via CDN.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type {
|
|
9
|
-
TapKitConfig,
|
|
10
|
-
TapKitInitParams,
|
|
11
|
-
Course,
|
|
12
|
-
ContainerStyle,
|
|
13
|
-
PositionType,
|
|
14
|
-
SeekTimelineParamsType,
|
|
15
|
-
AlarmMessageInstanceType,
|
|
16
|
-
AlarmType,
|
|
17
|
-
} from "./types";
|
|
18
|
-
|
|
19
|
-
// Version injected at build time via tsup define
|
|
20
|
-
declare const __PACKAGE_VERSION__: string;
|
|
21
|
-
|
|
22
|
-
const CDN_LOADER_URL = "https://files.edutap.ai/tap-sdk/loader.js";
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Base TapKit instance interface
|
|
26
|
-
* Shared properties and methods between core and wrapper
|
|
27
|
-
*/
|
|
28
|
-
interface TapKitBaseInstance {
|
|
29
|
-
events: {
|
|
30
|
-
seekTimeline: (params: SeekTimelineParamsType) => void;
|
|
31
|
-
onTimelineSeek: (
|
|
32
|
-
callback: (clipPlayHead: number, clipId: string) => void
|
|
33
|
-
) => void;
|
|
34
|
-
onChatInitiated: (handler: () => void) => void;
|
|
35
|
-
onChatOpened: (handler: () => void) => void;
|
|
36
|
-
onChatClosed: (handler: () => void) => void;
|
|
37
|
-
onAlarmFadeIn: (
|
|
38
|
-
handler: (messageInfo: AlarmMessageInstanceType) => void
|
|
39
|
-
) => void;
|
|
40
|
-
onPopUpOpen: (handler: (popUpInfo: any) => void) => void;
|
|
41
|
-
onPdfOpen: (handler: () => void) => void;
|
|
42
|
-
onPdfClose: (handler: () => void) => void;
|
|
43
|
-
};
|
|
44
|
-
isOpen: boolean;
|
|
45
|
-
isInitialized: boolean;
|
|
46
|
-
ready: Promise<void>;
|
|
47
|
-
init(params: TapKitInitParams): Promise<void>;
|
|
48
|
-
destroy(): void;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* TapKit instance type from tap-kit-core
|
|
53
|
-
* This matches the actual TapKit class exported from @coxwave/tap-kit-core
|
|
54
|
-
* Exported for advanced use cases (e.g., when using window.TapKit directly)
|
|
55
|
-
*/
|
|
56
|
-
export interface TapKitCoreInstance extends TapKitBaseInstance {}
|
|
57
|
-
|
|
58
|
-
// Global namespace for loaded SDK
|
|
59
|
-
// Export type for IIFE bundles loaded via window.TapKit
|
|
60
|
-
export type TapKitConstructor = new (
|
|
61
|
-
config: TapKitConfig
|
|
62
|
-
) => TapKitCoreInstance;
|
|
63
|
-
|
|
64
|
-
declare global {
|
|
65
|
-
interface Window {
|
|
66
|
-
TapKit?: TapKitConstructor;
|
|
67
|
-
__TAP_KIT_LOADER_LOADED__?: boolean;
|
|
68
|
-
__TAP_KIT_LOADER_LOADING__?: Promise<void>;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Public TapKit instance interface
|
|
74
|
-
* This is what users interact with when using the SDK
|
|
75
|
-
*/
|
|
76
|
-
export interface TapKitInstance extends TapKitBaseInstance {
|
|
77
|
-
// Wrapper-specific method
|
|
78
|
-
getVersion(): string;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Creates a SDK checker function with timeout and retry logic
|
|
83
|
-
*/
|
|
84
|
-
function createSDKChecker(
|
|
85
|
-
resolve: (value: void | PromiseLike<void>) => void,
|
|
86
|
-
reject: (reason?: any) => void
|
|
87
|
-
): () => void {
|
|
88
|
-
const MAX_RETRIES = 26; // 26 * 150ms ≈ 4 seconds max
|
|
89
|
-
const TIMEOUT_MS = 4000; // 4 seconds total timeout
|
|
90
|
-
let retryCount = 0;
|
|
91
|
-
const startTime = Date.now();
|
|
92
|
-
|
|
93
|
-
const checkSDK = (): void => {
|
|
94
|
-
if (window.TapKit) {
|
|
95
|
-
window.__TAP_KIT_LOADER_LOADED__ = true;
|
|
96
|
-
window.__TAP_KIT_LOADER_LOADING__ = undefined;
|
|
97
|
-
resolve();
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
retryCount++;
|
|
102
|
-
const elapsed = Date.now() - startTime;
|
|
103
|
-
|
|
104
|
-
// Check if exceeded timeout or max retries
|
|
105
|
-
if (elapsed > TIMEOUT_MS) {
|
|
106
|
-
window.__TAP_KIT_LOADER_LOADING__ = undefined;
|
|
107
|
-
reject(
|
|
108
|
-
new Error(
|
|
109
|
-
`TapKit loader timeout: SDK not available after ${TIMEOUT_MS}ms`
|
|
110
|
-
)
|
|
111
|
-
);
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (retryCount >= MAX_RETRIES) {
|
|
116
|
-
window.__TAP_KIT_LOADER_LOADING__ = undefined;
|
|
117
|
-
reject(
|
|
118
|
-
new Error(
|
|
119
|
-
`TapKit loader failed: SDK not available after ${retryCount} retries`
|
|
120
|
-
)
|
|
121
|
-
);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
setTimeout(checkSDK, 150);
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
return checkSDK;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Loads the CDN loader script
|
|
133
|
-
* The loader will then fetch versions.json and load the appropriate SDK version
|
|
134
|
-
*/
|
|
135
|
-
function loadCDNLoader(): Promise<void> {
|
|
136
|
-
// If already loaded, return immediately
|
|
137
|
-
if (window.__TAP_KIT_LOADER_LOADED__ && window.TapKit) {
|
|
138
|
-
return Promise.resolve();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// If currently loading, return the existing promise
|
|
142
|
-
if (window.__TAP_KIT_LOADER_LOADING__) {
|
|
143
|
-
return window.__TAP_KIT_LOADER_LOADING__;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Create loading promise
|
|
147
|
-
const loadingPromise = new Promise<void>((resolve, reject) => {
|
|
148
|
-
if (typeof document === "undefined") {
|
|
149
|
-
reject(
|
|
150
|
-
new Error("TapKit requires browser environment (document is undefined)")
|
|
151
|
-
);
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const script = document.createElement("script");
|
|
156
|
-
script.src = CDN_LOADER_URL;
|
|
157
|
-
script.async = true;
|
|
158
|
-
|
|
159
|
-
script.onload = () => {
|
|
160
|
-
// The loader script will load the actual SDK
|
|
161
|
-
// We need to wait a bit for the loader to fetch and load the SDK
|
|
162
|
-
const checkSDK = createSDKChecker(resolve, reject);
|
|
163
|
-
checkSDK();
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
script.onerror = () => {
|
|
167
|
-
window.__TAP_KIT_LOADER_LOADING__ = undefined;
|
|
168
|
-
reject(new Error(`Failed to load TapKit CDN loader: ${CDN_LOADER_URL}`));
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// Check if script already exists
|
|
172
|
-
const existingScript = document.querySelector(
|
|
173
|
-
`script[src="${CDN_LOADER_URL}"]`
|
|
174
|
-
);
|
|
175
|
-
if (existingScript) {
|
|
176
|
-
// Script already added but not yet loaded
|
|
177
|
-
existingScript.addEventListener("load", () => {
|
|
178
|
-
const checkSDK = createSDKChecker(resolve, reject);
|
|
179
|
-
checkSDK();
|
|
180
|
-
});
|
|
181
|
-
existingScript.addEventListener("error", () =>
|
|
182
|
-
reject(new Error(`Failed to load TapKit CDN loader: ${CDN_LOADER_URL}`))
|
|
183
|
-
);
|
|
184
|
-
} else {
|
|
185
|
-
document.head.appendChild(script);
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
window.__TAP_KIT_LOADER_LOADING__ = loadingPromise;
|
|
190
|
-
return loadingPromise;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Use Symbol to hide SDK instance from enumeration
|
|
194
|
-
const SDK_INSTANCE = Symbol("sdkInstance");
|
|
195
|
-
const SDK_INSTANCE_LOADING = Symbol("sdkInstanceLoading");
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* TapKit Wrapper Class
|
|
199
|
-
*
|
|
200
|
-
* Loads the CDN loader and proxies all calls to the actual SDK
|
|
201
|
-
*/
|
|
202
|
-
class TapKit implements TapKitInstance {
|
|
203
|
-
private [SDK_INSTANCE]?: TapKitCoreInstance;
|
|
204
|
-
private [SDK_INSTANCE_LOADING]: Promise<void>;
|
|
205
|
-
|
|
206
|
-
constructor(config: TapKitConfig) {
|
|
207
|
-
this[SDK_INSTANCE_LOADING] = this.loadAndInitialize(config);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private async loadAndInitialize(config: TapKitConfig): Promise<void> {
|
|
211
|
-
await loadCDNLoader();
|
|
212
|
-
|
|
213
|
-
if (!window.TapKit) {
|
|
214
|
-
throw new Error("TapKit not available after loading CDN loader");
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
this[SDK_INSTANCE] = new window.TapKit(config);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
private async ensureLoaded(): Promise<TapKitCoreInstance> {
|
|
221
|
-
await this[SDK_INSTANCE_LOADING]; // Wait for SDK instance to be created
|
|
222
|
-
|
|
223
|
-
if (!this[SDK_INSTANCE]) {
|
|
224
|
-
throw new Error("TapKit instance not initialized");
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return this[SDK_INSTANCE];
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Expose tap-kit-core's 'ready' promise as 'ready' for better API naming
|
|
231
|
-
// This resolves after init() is called and tap-kit-core is fully initialized
|
|
232
|
-
get ready(): Promise<void> {
|
|
233
|
-
return this.ensureLoaded().then((sdk) => sdk.ready);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Public API - all methods proxy to the loaded SDK
|
|
237
|
-
get events() {
|
|
238
|
-
return {
|
|
239
|
-
seekTimeline: (params: SeekTimelineParamsType) => {
|
|
240
|
-
this.ensureLoaded()
|
|
241
|
-
.then((sdk) => sdk.events.seekTimeline(params))
|
|
242
|
-
.catch((error) => {
|
|
243
|
-
console.error("[TapSDK] Failed to call seekTimeline:", error);
|
|
244
|
-
});
|
|
245
|
-
},
|
|
246
|
-
onTimelineSeek: (
|
|
247
|
-
callback: (clipPlayHead: number, clipId: string) => void
|
|
248
|
-
) => {
|
|
249
|
-
this.ensureLoaded()
|
|
250
|
-
.then((sdk) => sdk.events.onTimelineSeek(callback))
|
|
251
|
-
.catch((error) => {
|
|
252
|
-
console.error("[TapSDK] Failed to register onTimelineSeek:", error);
|
|
253
|
-
});
|
|
254
|
-
},
|
|
255
|
-
onChatInitiated: (handler: () => void) => {
|
|
256
|
-
this.ensureLoaded()
|
|
257
|
-
.then((sdk) => sdk.events.onChatInitiated(handler))
|
|
258
|
-
.catch((error) => {
|
|
259
|
-
console.error("[TapSDK] Failed to register onChatInitiated:", error);
|
|
260
|
-
});
|
|
261
|
-
},
|
|
262
|
-
onChatOpened: (handler: () => void) => {
|
|
263
|
-
this.ensureLoaded()
|
|
264
|
-
.then((sdk) => sdk.events.onChatOpened(handler))
|
|
265
|
-
.catch((error) => {
|
|
266
|
-
console.error("[TapSDK] Failed to register onChatOpened:", error);
|
|
267
|
-
});
|
|
268
|
-
},
|
|
269
|
-
onChatClosed: (handler: () => void) => {
|
|
270
|
-
this.ensureLoaded()
|
|
271
|
-
.then((sdk) => sdk.events.onChatClosed(handler))
|
|
272
|
-
.catch((error) => {
|
|
273
|
-
console.error("[TapSDK] Failed to register onChatClosed:", error);
|
|
274
|
-
});
|
|
275
|
-
},
|
|
276
|
-
onAlarmFadeIn: (
|
|
277
|
-
handler: (messageInfo: AlarmMessageInstanceType) => void
|
|
278
|
-
) => {
|
|
279
|
-
this.ensureLoaded()
|
|
280
|
-
.then((sdk) => sdk.events.onAlarmFadeIn(handler))
|
|
281
|
-
.catch((error) => {
|
|
282
|
-
console.error("[TapSDK] Failed to register onAlarmFadeIn:", error);
|
|
283
|
-
});
|
|
284
|
-
},
|
|
285
|
-
onPopUpOpen: (handler: (popUpInfo: any) => void) => {
|
|
286
|
-
this.ensureLoaded()
|
|
287
|
-
.then((sdk) => sdk.events.onPopUpOpen(handler))
|
|
288
|
-
.catch((error) => {
|
|
289
|
-
console.error("[TapSDK] Failed to register onPopUpOpen:", error);
|
|
290
|
-
});
|
|
291
|
-
},
|
|
292
|
-
onPdfOpen: (handler: () => void) => {
|
|
293
|
-
this.ensureLoaded()
|
|
294
|
-
.then((sdk) => sdk.events.onPdfOpen(handler))
|
|
295
|
-
.catch((error) => {
|
|
296
|
-
console.error("[TapSDK] Failed to register onPdfOpen:", error);
|
|
297
|
-
});
|
|
298
|
-
},
|
|
299
|
-
onPdfClose: (handler: () => void) => {
|
|
300
|
-
this.ensureLoaded()
|
|
301
|
-
.then((sdk) => sdk.events.onPdfClose(handler))
|
|
302
|
-
.catch((error) => {
|
|
303
|
-
console.error("[TapSDK] Failed to register onPdfClose:", error);
|
|
304
|
-
});
|
|
305
|
-
},
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
get isOpen(): boolean {
|
|
310
|
-
return this[SDK_INSTANCE]?.isOpen ?? false;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
get isInitialized(): boolean {
|
|
314
|
-
return this[SDK_INSTANCE]?.isInitialized ?? false;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
async init(params: TapKitInitParams): Promise<void> {
|
|
318
|
-
const sdk = await this.ensureLoaded();
|
|
319
|
-
return sdk.init(params);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
destroy(): void {
|
|
323
|
-
if (this[SDK_INSTANCE]) {
|
|
324
|
-
this[SDK_INSTANCE].destroy();
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
getVersion(): string {
|
|
329
|
-
// tap-kit-core doesn't expose getVersion, return SDK wrapper version
|
|
330
|
-
// The actual implementation is loaded from CDN dynamically
|
|
331
|
-
if (!this[SDK_INSTANCE]) {
|
|
332
|
-
return "Not initialized";
|
|
333
|
-
}
|
|
334
|
-
return `Loaded from CDN (tap-sdk wrapper v${__PACKAGE_VERSION__})`;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Custom object tag for better console display
|
|
339
|
-
*/
|
|
340
|
-
get [Symbol.toStringTag]() {
|
|
341
|
-
return "TapKit";
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Export the SDK class as default (for: import TapKit from '@coxwave/tap-sdk')
|
|
346
|
-
export default TapKit;
|
|
347
|
-
|
|
348
|
-
// TapKitInstance is already exported via the interface declaration above (line 72)
|
|
349
|
-
// Users can import it via: import type { TapKitInstance } from '@coxwave/tap-sdk'
|
|
350
|
-
|
|
351
|
-
// Re-export types for API compatibility
|
|
352
|
-
export type {
|
|
353
|
-
TapKitConfig,
|
|
354
|
-
TapKitInitParams,
|
|
355
|
-
Course,
|
|
356
|
-
ContainerStyle,
|
|
357
|
-
PositionType,
|
|
358
|
-
SeekTimelineParamsType,
|
|
359
|
-
AlarmMessageInstanceType,
|
|
360
|
-
AlarmType,
|
|
361
|
-
};
|
package/types.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TapKit Type Definitions
|
|
3
|
-
*
|
|
4
|
-
* Re-exported types for API compatibility with the loader.
|
|
5
|
-
* These types match the actual SDK implementation in tap-kit-core.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// Re-export alarm types from tap-messages
|
|
9
|
-
export type {
|
|
10
|
-
AlarmMessageInstanceType,
|
|
11
|
-
AlarmType,
|
|
12
|
-
} from '@coxwave/tap-messages';
|
|
13
|
-
|
|
14
|
-
// SDK Configuration
|
|
15
|
-
export type TapKitConfig = {
|
|
16
|
-
apiKey: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// SDK Initialization Parameters
|
|
20
|
-
export type TapKitInitParams = {
|
|
21
|
-
buttonId: string;
|
|
22
|
-
course: Course;
|
|
23
|
-
container?: ContainerStyle;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// Course Information
|
|
27
|
-
export type Course = {
|
|
28
|
-
userId: string;
|
|
29
|
-
courseId: string;
|
|
30
|
-
clipId: string;
|
|
31
|
-
clipPlayHead?: number;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// Container Styling
|
|
35
|
-
export type ContainerStyle = {
|
|
36
|
-
position?: PositionType;
|
|
37
|
-
width?: string;
|
|
38
|
-
height?: string;
|
|
39
|
-
borderRadius?: string;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export type PositionType = {
|
|
43
|
-
top?: string;
|
|
44
|
-
left?: string;
|
|
45
|
-
right?: string;
|
|
46
|
-
bottom?: string;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// Event Parameters
|
|
50
|
-
export type SeekTimelineParamsType = {
|
|
51
|
-
clipId: string;
|
|
52
|
-
clipPlayHead: number;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// Container Visibility State
|
|
56
|
-
export type ContainerVisibility = 'open' | 'closed';
|
|
57
|
-
|
|
58
|
-
// Flattened container styles (backward compatibility)
|
|
59
|
-
export type CustomStyles = ContainerStyle;
|
|
60
|
-
|
|
61
|
-
// Shortcut Key Configuration
|
|
62
|
-
export type ShortcutKeyPropertiesType = {
|
|
63
|
-
key: string;
|
|
64
|
-
modifier: 'ctrlKey' | 'altKey' | 'shiftKey' | 'metaKey' | '';
|
|
65
|
-
};
|