@coxwave/tap-sdk 0.2.8 → 0.3.0

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts"],"names":["CDN_LOADER_URL","createSDKChecker","resolve","reject","retryCount","startTime","checkSDK","loadCDNLoader","loadingPromise","script","existingScript","SDK_INSTANCE","SDK_INSTANCE_LOADING","_a","_b","TapKit","config","__publicField","sdk","params","error","callback","handler","index_default"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * TapKit wrapper - npm package wrapper\n *\n * Simply loads the CDN loader which handles version management and SDK loading.\n * This keeps the npm package minimal and allows instant updates via CDN.\n */\n\nimport type {\n TapKitConfig,\n TapKitInitParams,\n Course,\n ContainerStyle,\n PositionType,\n SeekTimelineParamsType,\n AlarmMessageInstanceType,\n AlarmType,\n} from \"./types\";\n\n// Version injected at build time via tsup define\ndeclare const __PACKAGE_VERSION__: string;\n\nconst CDN_LOADER_URL = \"https://files.edutap.ai/tap-sdk/loader.js\";\n\n/**\n * Base TapKit instance interface\n * Shared properties and methods between core and wrapper\n */\ninterface TapKitBaseInstance {\n events: {\n seekTimeline: (params: SeekTimelineParamsType) => void;\n onTimelineSeek: (\n callback: (clipPlayHead: number, clipId: string) => void\n ) => void;\n onChatInitiated: (handler: () => void) => void;\n onChatOpened: (handler: () => void) => void;\n onChatClosed: (handler: () => void) => void;\n onAlarmFadeIn: (\n handler: (messageInfo: AlarmMessageInstanceType) => void\n ) => void;\n onPopUpOpen: (handler: (popUpInfo: any) => void) => void;\n onPdfOpen: (handler: () => void) => void;\n onPdfClose: (handler: () => void) => void;\n };\n isOpen: boolean;\n isInitialized: boolean;\n ready: Promise<void>;\n init(params: TapKitInitParams): Promise<void>;\n destroy(): void;\n}\n\n/**\n * TapKit instance type from tap-kit-core\n * This matches the actual TapKit class exported from @coxwave/tap-kit-core\n * Exported for advanced use cases (e.g., when using window.TapKit directly)\n */\nexport interface TapKitCoreInstance extends TapKitBaseInstance {}\n\n// Global namespace for loaded SDK\n// Export type for IIFE bundles loaded via window.TapKit\nexport type TapKitConstructor = new (\n config: TapKitConfig\n) => TapKitCoreInstance;\n\ndeclare global {\n interface Window {\n TapKit?: TapKitConstructor;\n __TAP_KIT_LOADER_LOADED__?: boolean;\n __TAP_KIT_LOADER_LOADING__?: Promise<void>;\n }\n}\n\n/**\n * Public TapKit instance interface\n * This is what users interact with when using the SDK\n */\nexport interface TapKitInstance extends TapKitBaseInstance {\n // Wrapper-specific method\n getVersion(): string;\n}\n\n/**\n * Creates a SDK checker function with timeout and retry logic\n */\nfunction createSDKChecker(\n resolve: (value: void | PromiseLike<void>) => void,\n reject: (reason?: any) => void\n): () => void {\n const MAX_RETRIES = 26; // 26 * 150ms ≈ 4 seconds max\n const TIMEOUT_MS = 4000; // 4 seconds total timeout\n let retryCount = 0;\n const startTime = Date.now();\n\n const checkSDK = (): void => {\n if (window.TapKit) {\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n return;\n }\n\n retryCount++;\n const elapsed = Date.now() - startTime;\n\n // Check if exceeded timeout or max retries\n if (elapsed > TIMEOUT_MS) {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(\n new Error(\n `TapKit loader timeout: SDK not available after ${TIMEOUT_MS}ms`\n )\n );\n return;\n }\n\n if (retryCount >= MAX_RETRIES) {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(\n new Error(\n `TapKit loader failed: SDK not available after ${retryCount} retries`\n )\n );\n return;\n }\n\n setTimeout(checkSDK, 150);\n };\n\n return checkSDK;\n}\n\n/**\n * Loads the CDN loader script\n * The loader will then fetch versions.json and load the appropriate SDK version\n */\nfunction loadCDNLoader(): Promise<void> {\n // If already loaded, return immediately\n if (window.__TAP_KIT_LOADER_LOADED__ && window.TapKit) {\n return Promise.resolve();\n }\n\n // If currently loading, return the existing promise\n if (window.__TAP_KIT_LOADER_LOADING__) {\n return window.__TAP_KIT_LOADER_LOADING__;\n }\n\n // Create loading promise\n const loadingPromise = new Promise<void>((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(\n new Error(\"TapKit requires browser environment (document is undefined)\")\n );\n return;\n }\n\n const script = document.createElement(\"script\");\n script.src = CDN_LOADER_URL;\n script.async = true;\n\n script.onload = () => {\n // The loader script will load the actual SDK\n // We need to wait a bit for the loader to fetch and load the SDK\n const checkSDK = createSDKChecker(resolve, reject);\n checkSDK();\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load TapKit CDN loader: ${CDN_LOADER_URL}`));\n };\n\n // Check if script already exists\n const existingScript = document.querySelector(\n `script[src=\"${CDN_LOADER_URL}\"]`\n );\n if (existingScript) {\n // Script already added but not yet loaded\n existingScript.addEventListener(\"load\", () => {\n const checkSDK = createSDKChecker(resolve, reject);\n checkSDK();\n });\n existingScript.addEventListener(\"error\", () =>\n reject(new Error(`Failed to load TapKit CDN loader: ${CDN_LOADER_URL}`))\n );\n } else {\n document.head.appendChild(script);\n }\n });\n\n window.__TAP_KIT_LOADER_LOADING__ = loadingPromise;\n return loadingPromise;\n}\n\n// Use Symbol to hide SDK instance from enumeration\nconst SDK_INSTANCE = Symbol(\"sdkInstance\");\nconst SDK_INSTANCE_LOADING = Symbol(\"sdkInstanceLoading\");\n\n/**\n * TapKit Wrapper Class\n *\n * Loads the CDN loader and proxies all calls to the actual SDK\n */\nclass TapKit implements TapKitInstance {\n private [SDK_INSTANCE]?: TapKitCoreInstance;\n private [SDK_INSTANCE_LOADING]: Promise<void>;\n\n constructor(config: TapKitConfig) {\n this[SDK_INSTANCE_LOADING] = this.loadAndInitialize(config);\n }\n\n private async loadAndInitialize(config: TapKitConfig): Promise<void> {\n await loadCDNLoader();\n\n if (!window.TapKit) {\n throw new Error(\"TapKit not available after loading CDN loader\");\n }\n\n this[SDK_INSTANCE] = new window.TapKit(config);\n }\n\n private async ensureLoaded(): Promise<TapKitCoreInstance> {\n await this[SDK_INSTANCE_LOADING]; // Wait for SDK instance to be created\n\n if (!this[SDK_INSTANCE]) {\n throw new Error(\"TapKit instance not initialized\");\n }\n\n return this[SDK_INSTANCE];\n }\n\n // Expose tap-kit-core's 'ready' promise as 'ready' for better API naming\n // This resolves after init() is called and tap-kit-core is fully initialized\n get ready(): Promise<void> {\n return this.ensureLoaded().then((sdk) => sdk.ready);\n }\n\n // Public API - all methods proxy to the loaded SDK\n get events() {\n return {\n seekTimeline: (params: SeekTimelineParamsType) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.seekTimeline(params))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to call seekTimeline:\", error);\n });\n },\n onTimelineSeek: (\n callback: (clipPlayHead: number, clipId: string) => void\n ) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onTimelineSeek(callback))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onTimelineSeek:\", error);\n });\n },\n onChatInitiated: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onChatInitiated(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onChatInitiated:\", error);\n });\n },\n onChatOpened: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onChatOpened(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onChatOpened:\", error);\n });\n },\n onChatClosed: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onChatClosed(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onChatClosed:\", error);\n });\n },\n onAlarmFadeIn: (\n handler: (messageInfo: AlarmMessageInstanceType) => void\n ) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onAlarmFadeIn(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onAlarmFadeIn:\", error);\n });\n },\n onPopUpOpen: (handler: (popUpInfo: any) => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onPopUpOpen(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onPopUpOpen:\", error);\n });\n },\n onPdfOpen: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onPdfOpen(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onPdfOpen:\", error);\n });\n },\n onPdfClose: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onPdfClose(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onPdfClose:\", error);\n });\n },\n };\n }\n\n get isOpen(): boolean {\n return this[SDK_INSTANCE]?.isOpen ?? false;\n }\n\n get isInitialized(): boolean {\n return this[SDK_INSTANCE]?.isInitialized ?? false;\n }\n\n async init(params: TapKitInitParams): Promise<void> {\n const sdk = await this.ensureLoaded();\n return sdk.init(params);\n }\n\n destroy(): void {\n if (this[SDK_INSTANCE]) {\n this[SDK_INSTANCE].destroy();\n }\n }\n\n getVersion(): string {\n // tap-kit-core doesn't expose getVersion, return SDK wrapper version\n // The actual implementation is loaded from CDN dynamically\n if (!this[SDK_INSTANCE]) {\n return \"Not initialized\";\n }\n return `Loaded from CDN (tap-sdk wrapper v${__PACKAGE_VERSION__})`;\n }\n\n /**\n * Custom object tag for better console display\n */\n get [Symbol.toStringTag]() {\n return \"TapKit\";\n }\n}\n\n// Export the SDK class as default (for: import TapKit from '@coxwave/tap-sdk')\nexport default TapKit;\n\n// TapKitInstance is already exported via the interface declaration above (line 72)\n// Users can import it via: import type { TapKitInstance } from '@coxwave/tap-sdk'\n\n// Re-export types for API compatibility\nexport type {\n TapKitConfig,\n TapKitInitParams,\n Course,\n ContainerStyle,\n PositionType,\n SeekTimelineParamsType,\n AlarmMessageInstanceType,\n AlarmType,\n};\n"]}
1
+ {"version":3,"sources":["../src/loader.ts","../src/sdk.ts"],"names":["DEFAULT_CDN_LOADER_URL","getLoaderURL","isLocalCoreMode","getLocalCoreURL","createSDKChecker","resolve","reject","timeoutMs","startTime","checkSDK","loadCDNLoader","loadingPromise","coreURL","script","loaderURL","existingScript","TAPKIT_CONFIG_SYMBOL","TapKit","config","__publicField","err","params","options"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * CDN loader for TapSDK\n * Dynamically loads the TapKit SDK from CDN\n *\n * For local testing, you can override the loader URL:\n * window.__TAP_KIT_LOADER_URL__ = '/tap-kit-core/loader.js';\n *\n * For local development (bypass loader, load IIFE directly):\n * window.__TAP_KIT_CORE_URL__ = '/packages/tap-kit-core/dist/index.global.js';\n */\n\nconst DEFAULT_CDN_LOADER_URL = \"https://files.edutap.ai/tap-sdk/loader.js\";\nconst DEFAULT_TIMEOUT_MS = 4000; // 4 seconds total timeout\nconst IDLE_CALLBACK_TIMEOUT_MS = 500; // 500ms for requestIdleCallback\n\n/**\n * Get the loader URL from window override or default CDN\n */\nfunction getLoaderURL(): string {\n return typeof window !== \"undefined\" && window.__TAP_KIT_LOADER_URL__\n ? window.__TAP_KIT_LOADER_URL__\n : DEFAULT_CDN_LOADER_URL;\n}\n\n/**\n * Check if local core mode is enabled\n * When __TAP_KIT_CORE_URL__ is set, directly load the IIFE bundle\n * This bypasses the loader.js and loads tap-kit-core directly\n */\nfunction isLocalCoreMode(): boolean {\n return typeof window !== \"undefined\" && !!window.__TAP_KIT_CORE_URL__;\n}\n\n/**\n * Get the local core URL\n */\nfunction getLocalCoreURL(): string {\n return window.__TAP_KIT_CORE_URL__ || \"\";\n}\n\n/**\n * Creates a SDK checker function with timeout and retry logic\n * Uses requestIdleCallback to avoid blocking browser rendering\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n * @param timeoutMs - Maximum time to wait for SDK to load (milliseconds)\n * @returns Checker function to be called repeatedly\n */\nfunction createSDKChecker(\n resolve: (value: void | PromiseLike<void>) => void,\n reject: (reason?: any) => void,\n timeoutMs: number\n): () => void {\n const startTime = Date.now();\n\n const checkSDK = (): void => {\n // Check if real TapKit is loaded (not just stub)\n // Stub has TapKitLoaded flag set to true by loader.js after real SDK loads\n if (window.TapKit && window.TapKitLoaded === true) {\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n return;\n }\n\n const elapsed = Date.now() - startTime;\n\n // Check if exceeded timeout\n if (elapsed > timeoutMs) {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`TapKit loader timeout: SDK not available after ${timeoutMs}ms`));\n return;\n }\n\n // Use requestIdleCallback for better performance\n // Falls back to setTimeout if not available\n if (typeof requestIdleCallback !== \"undefined\") {\n requestIdleCallback(checkSDK, { timeout: IDLE_CALLBACK_TIMEOUT_MS });\n } else {\n setTimeout(checkSDK, IDLE_CALLBACK_TIMEOUT_MS);\n }\n };\n\n return checkSDK;\n}\n\n/**\n * Loads the CDN loader script\n * The loader will then fetch versions.json and load the appropriate SDK version\n *\n * If __TAP_KIT_CORE_URL__ is set, bypasses loader and loads IIFE directly\n *\n * @param timeoutMs - Maximum time to wait for SDK to load (default: 4000ms)\n * @returns Promise that resolves when SDK is loaded\n * @throws {Error} If loader fails to load or times out\n */\nexport function loadCDNLoader(timeoutMs: number = DEFAULT_TIMEOUT_MS): Promise<void> {\n // If already loaded, return immediately\n if (window.__TAP_KIT_LOADER_LOADED__ && window.TapKit) {\n return Promise.resolve();\n }\n\n // If currently loading, return the existing promise\n if (window.__TAP_KIT_LOADER_LOADING__) {\n return window.__TAP_KIT_LOADER_LOADING__;\n }\n\n // Create loading promise\n const loadingPromise = new Promise<void>((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(new Error(\"TapKit requires browser environment (document is undefined)\"));\n return;\n }\n\n // Local core mode: Load IIFE directly\n if (isLocalCoreMode()) {\n const coreURL = getLocalCoreURL();\n console.log(\"[TapSDK] Loading local core:\", coreURL);\n\n const script = document.createElement(\"script\");\n script.src = coreURL;\n script.async = true;\n\n script.onload = () => {\n // IIFE directly sets window.TapKit\n // Set the loaded flag manually since we bypass loader.js\n if (window.TapKit) {\n window.TapKitLoaded = true;\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n console.log(\"[TapSDK] Local core loaded successfully\");\n resolve();\n } else {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(\"TapKit not available after loading local core\"));\n }\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load local TapKit core: ${coreURL}`));\n };\n\n document.head.appendChild(script);\n return;\n }\n\n // CDN mode: Load loader.js\n const loaderURL = getLoaderURL();\n const script = document.createElement(\"script\");\n script.src = loaderURL;\n script.async = true;\n\n script.onload = () => {\n // The loader script will load the actual SDK\n // We need to wait a bit for the loader to fetch and load the SDK\n const checkSDK = createSDKChecker(resolve, reject, timeoutMs);\n checkSDK();\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`));\n };\n\n // Check if script already exists\n const existingScript = document.querySelector(`script[src=\"${loaderURL}\"]`);\n\n if (existingScript) {\n // Script already added but not yet loaded\n existingScript.addEventListener(\"load\", () => {\n const checkSDK = createSDKChecker(resolve, reject, timeoutMs);\n checkSDK();\n });\n existingScript.addEventListener(\"error\", () =>\n reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`))\n );\n } else {\n document.head.appendChild(script);\n }\n });\n\n window.__TAP_KIT_LOADER_LOADING__ = loadingPromise;\n return loadingPromise;\n}\n","import type {\n TapKitConfig,\n TapKitInitParams,\n TapKitInstance,\n TapKitConfigOptions,\n TAPKIT_CONFIG_SYMBOL as TAPKIT_CONFIG_SYMBOL_TYPE,\n} from \"@coxwave/tap-kit-types\";\nimport { loadCDNLoader } from \"./loader\";\n\n/** @internal Symbol for internal configuration method */\nconst TAPKIT_CONFIG_SYMBOL: typeof TAPKIT_CONFIG_SYMBOL_TYPE = Symbol.for(\"tapkit.config\") as any;\n\n/**\n * TapSDK - Official TapKit Web SDK\n *\n * @example\n * ```typescript\n * import TapSDK from \"@coxwave/tap-sdk\";\n *\n * const sdk = new TapSDK({ apiKey: 'your-api-key' });\n *\n * await sdk.init({\n * buttonId: 'tap-button',\n * course: {\n * userId: 'user-123',\n * courseId: 'course-456',\n * clipId: 'clip-789',\n * },\n * container: {\n * position: { top: '64px', right: '32px' },\n * width: '360px',\n * height: 'calc(100% - 128px)',\n * },\n * });\n * ```\n */\nexport class TapKit implements TapKitInstance {\n private instance: TapKitInstance | null = null;\n private loading: Promise<void>;\n private config: TapKitConfig;\n\n constructor(config: TapKitConfig) {\n this.config = config;\n this.loading = this.load();\n }\n\n private async load(): Promise<void> {\n console.log(\"[TapSDK] Starting CDN loader...\");\n\n try {\n await loadCDNLoader();\n console.log(\"[TapSDK] CDN loader completed\");\n } catch (err) {\n console.error(\"[TapSDK] CDN loader failed:\", err);\n throw err;\n }\n\n if (!window.TapKit) {\n console.error(\"[TapSDK] window.TapKit not available after loading\");\n throw new Error(\"TapKit not available after loading CDN loader\");\n }\n\n console.log(\"[TapSDK] Creating TapKit instance from window.TapKit\");\n this.instance = new window.TapKit(this.config);\n console.log(\"[TapSDK] TapKit instance created successfully\");\n }\n\n get ready(): Promise<void> {\n return this.loading.then(() => {\n if (!this.instance) {\n throw new Error(\"TapKit instance not initialized\");\n }\n return this.instance.ready;\n });\n }\n\n get events() {\n if (!this.instance) {\n throw new Error(\"TapKit not loaded yet. Use await sdk.ready first.\");\n }\n return this.instance.events;\n }\n\n get isOpen(): boolean {\n return this.instance?.isOpen ?? false;\n }\n\n get isInitialized(): boolean {\n return this.instance?.isInitialized ?? false;\n }\n\n async init(params: TapKitInitParams): Promise<void> {\n await this.loading; // Wait for CDN loader to complete\n await this.instance!.init(params);\n }\n\n destroy(): void {\n if (this.instance) {\n this.instance.destroy();\n this.instance = null;\n }\n }\n\n [TAPKIT_CONFIG_SYMBOL](options: TapKitConfigOptions): void {\n if (!this.instance) {\n throw new Error(\"TapKit not loaded yet. Use await sdk.ready first.\");\n }\n this.instance[TAPKIT_CONFIG_SYMBOL]?.(options);\n }\n\n get [Symbol.toStringTag]() {\n return \"TapKit\";\n }\n}\n"]}
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- var m=Object.defineProperty;var I=(o,e,n)=>e in o?m(o,e,{enumerable:true,configurable:true,writable:true,value:n}):o[e]=n;var d=(o,e,n)=>I(o,typeof e!="symbol"?e+"":e,n);var a="https://files.edutap.ai/tap-sdk/loader.js";function T(o,e){let r=0,s=Date.now(),c=()=>{if(window.TapKit){window.__TAP_KIT_LOADER_LOADED__=true,window.__TAP_KIT_LOADER_LOADING__=void 0,o();return}if(r++,Date.now()-s>4e3){window.__TAP_KIT_LOADER_LOADING__=void 0,e(new Error("TapKit loader timeout: SDK not available after 4000ms"));return}if(r>=26){window.__TAP_KIT_LOADER_LOADING__=void 0,e(new Error(`TapKit loader failed: SDK not available after ${r} retries`));return}setTimeout(c,150);};return c}function v(){if(window.__TAP_KIT_LOADER_LOADED__&&window.TapKit)return Promise.resolve();if(window.__TAP_KIT_LOADER_LOADING__)return window.__TAP_KIT_LOADER_LOADING__;let o=new Promise((e,n)=>{if(typeof document>"u"){n(new Error("TapKit requires browser environment (document is undefined)"));return}let t=document.createElement("script");t.src=a,t.async=true,t.onload=()=>{T(e,n)();},t.onerror=()=>{window.__TAP_KIT_LOADER_LOADING__=void 0,n(new Error(`Failed to load TapKit CDN loader: ${a}`));};let r=document.querySelector(`script[src="${a}"]`);r?(r.addEventListener("load",()=>{T(e,n)();}),r.addEventListener("error",()=>n(new Error(`Failed to load TapKit CDN loader: ${a}`)))):document.head.appendChild(t);});return window.__TAP_KIT_LOADER_LOADING__=o,o}var i=Symbol("sdkInstance"),l=Symbol("sdkInstanceLoading"),_,h,p=class{constructor(e){d(this,h);d(this,_);this[l]=this.loadAndInitialize(e);}async loadAndInitialize(e){if(await v(),!window.TapKit)throw new Error("TapKit not available after loading CDN loader");this[i]=new window.TapKit(e);}async ensureLoaded(){if(await this[l],!this[i])throw new Error("TapKit instance not initialized");return this[i]}get ready(){return this.ensureLoaded().then(e=>e.ready)}get events(){return {seekTimeline:e=>{this.ensureLoaded().then(n=>n.events.seekTimeline(e)).catch(n=>{});},onTimelineSeek:e=>{this.ensureLoaded().then(n=>n.events.onTimelineSeek(e)).catch(n=>{});},onChatInitiated:e=>{this.ensureLoaded().then(n=>n.events.onChatInitiated(e)).catch(n=>{});},onChatOpened:e=>{this.ensureLoaded().then(n=>n.events.onChatOpened(e)).catch(n=>{});},onChatClosed:e=>{this.ensureLoaded().then(n=>n.events.onChatClosed(e)).catch(n=>{});},onAlarmFadeIn:e=>{this.ensureLoaded().then(n=>n.events.onAlarmFadeIn(e)).catch(n=>{});},onPopUpOpen:e=>{this.ensureLoaded().then(n=>n.events.onPopUpOpen(e)).catch(n=>{});},onPdfOpen:e=>{this.ensureLoaded().then(n=>n.events.onPdfOpen(e)).catch(n=>{});},onPdfClose:e=>{this.ensureLoaded().then(n=>n.events.onPdfClose(e)).catch(n=>{});}}}get isOpen(){return this[i]?.isOpen??false}get isInitialized(){return this[i]?.isInitialized??false}async init(e){return (await this.ensureLoaded()).init(e)}destroy(){this[i]&&this[i].destroy();}getVersion(){return this[i]?"Loaded from CDN (tap-sdk wrapper v0.2.8)":"Not initialized"}get[(h=i,_=l,Symbol.toStringTag)](){return "TapKit"}},A=p;
2
- export{A as default};//# sourceMappingURL=index.mjs.map
1
+ var w=Object.defineProperty;var K=(i,e,n)=>e in i?w(i,e,{enumerable:true,configurable:true,writable:true,value:n}):i[e]=n;var d=(i,e,n)=>K(i,typeof e!="symbol"?e+"":e,n);var u="https://files.edutap.ai/tap-sdk/loader.js";function L(){return typeof window<"u"&&window.__TAP_KIT_LOADER_URL__?window.__TAP_KIT_LOADER_URL__:u}function f(){return typeof window<"u"&&!!window.__TAP_KIT_CORE_URL__}function D(){return window.__TAP_KIT_CORE_URL__||""}function l(i,e,n){let t=Date.now(),o=()=>{if(window.TapKit&&window.TapKitLoaded===true){window.__TAP_KIT_LOADER_LOADED__=true,window.__TAP_KIT_LOADER_LOADING__=void 0,i();return}if(Date.now()-t>n){window.__TAP_KIT_LOADER_LOADING__=void 0,e(new Error(`TapKit loader timeout: SDK not available after ${n}ms`));return}typeof requestIdleCallback<"u"?requestIdleCallback(o,{timeout:500}):setTimeout(o,500);};return o}function T(i=4e3){if(window.__TAP_KIT_LOADER_LOADED__&&window.TapKit)return Promise.resolve();if(window.__TAP_KIT_LOADER_LOADING__)return window.__TAP_KIT_LOADER_LOADING__;let e=new Promise((n,t)=>{if(typeof document>"u"){t(new Error("TapKit requires browser environment (document is undefined)"));return}if(f()){let s=D(),r=document.createElement("script");r.src=s,r.async=true,r.onload=()=>{window.TapKit?(window.TapKitLoaded=true,window.__TAP_KIT_LOADER_LOADED__=true,window.__TAP_KIT_LOADER_LOADING__=void 0,n()):(window.__TAP_KIT_LOADER_LOADING__=void 0,t(new Error("TapKit not available after loading local core")));},r.onerror=()=>{window.__TAP_KIT_LOADER_LOADING__=void 0,t(new Error(`Failed to load local TapKit core: ${s}`));},document.head.appendChild(r);return}let o=L(),a=document.createElement("script");a.src=o,a.async=true,a.onload=()=>{l(n,t,i)();},a.onerror=()=>{window.__TAP_KIT_LOADER_LOADING__=void 0,t(new Error(`Failed to load TapKit CDN loader: ${o}`));};let _=document.querySelector(`script[src="${o}"]`);_?(_.addEventListener("load",()=>{l(n,t,i)();}),_.addEventListener("error",()=>t(new Error(`Failed to load TapKit CDN loader: ${o}`)))):document.head.appendChild(a);});return window.__TAP_KIT_LOADER_LOADING__=e,e}var p=Symbol.for("tapkit.config"),c=class{constructor(e){d(this,"instance",null);d(this,"loading");d(this,"config");this.config=e,this.loading=this.load();}async load(){try{await T();}catch(e){throw e}if(!window.TapKit)throw new Error("TapKit not available after loading CDN loader");this.instance=new window.TapKit(this.config);}get ready(){return this.loading.then(()=>{if(!this.instance)throw new Error("TapKit instance not initialized");return this.instance.ready})}get events(){if(!this.instance)throw new Error("TapKit not loaded yet. Use await sdk.ready first.");return this.instance.events}get isOpen(){return this.instance?.isOpen??false}get isInitialized(){return this.instance?.isInitialized??false}async init(e){await this.loading,await this.instance.init(e);}destroy(){this.instance&&(this.instance.destroy(),this.instance=null);}[p](e){if(!this.instance)throw new Error("TapKit not loaded yet. Use await sdk.ready first.");this.instance[p]?.(e);}get[Symbol.toStringTag](){return "TapKit"}};
2
+ export{c as default};//# sourceMappingURL=index.mjs.map
3
3
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts"],"names":["CDN_LOADER_URL","createSDKChecker","resolve","reject","retryCount","startTime","checkSDK","loadCDNLoader","loadingPromise","script","existingScript","SDK_INSTANCE","SDK_INSTANCE_LOADING","_a","_b","TapKit","config","__publicField","sdk","params","error","callback","handler","index_default"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * TapKit wrapper - npm package wrapper\n *\n * Simply loads the CDN loader which handles version management and SDK loading.\n * This keeps the npm package minimal and allows instant updates via CDN.\n */\n\nimport type {\n TapKitConfig,\n TapKitInitParams,\n Course,\n ContainerStyle,\n PositionType,\n SeekTimelineParamsType,\n AlarmMessageInstanceType,\n AlarmType,\n} from \"./types\";\n\n// Version injected at build time via tsup define\ndeclare const __PACKAGE_VERSION__: string;\n\nconst CDN_LOADER_URL = \"https://files.edutap.ai/tap-sdk/loader.js\";\n\n/**\n * Base TapKit instance interface\n * Shared properties and methods between core and wrapper\n */\ninterface TapKitBaseInstance {\n events: {\n seekTimeline: (params: SeekTimelineParamsType) => void;\n onTimelineSeek: (\n callback: (clipPlayHead: number, clipId: string) => void\n ) => void;\n onChatInitiated: (handler: () => void) => void;\n onChatOpened: (handler: () => void) => void;\n onChatClosed: (handler: () => void) => void;\n onAlarmFadeIn: (\n handler: (messageInfo: AlarmMessageInstanceType) => void\n ) => void;\n onPopUpOpen: (handler: (popUpInfo: any) => void) => void;\n onPdfOpen: (handler: () => void) => void;\n onPdfClose: (handler: () => void) => void;\n };\n isOpen: boolean;\n isInitialized: boolean;\n ready: Promise<void>;\n init(params: TapKitInitParams): Promise<void>;\n destroy(): void;\n}\n\n/**\n * TapKit instance type from tap-kit-core\n * This matches the actual TapKit class exported from @coxwave/tap-kit-core\n * Exported for advanced use cases (e.g., when using window.TapKit directly)\n */\nexport interface TapKitCoreInstance extends TapKitBaseInstance {}\n\n// Global namespace for loaded SDK\n// Export type for IIFE bundles loaded via window.TapKit\nexport type TapKitConstructor = new (\n config: TapKitConfig\n) => TapKitCoreInstance;\n\ndeclare global {\n interface Window {\n TapKit?: TapKitConstructor;\n __TAP_KIT_LOADER_LOADED__?: boolean;\n __TAP_KIT_LOADER_LOADING__?: Promise<void>;\n }\n}\n\n/**\n * Public TapKit instance interface\n * This is what users interact with when using the SDK\n */\nexport interface TapKitInstance extends TapKitBaseInstance {\n // Wrapper-specific method\n getVersion(): string;\n}\n\n/**\n * Creates a SDK checker function with timeout and retry logic\n */\nfunction createSDKChecker(\n resolve: (value: void | PromiseLike<void>) => void,\n reject: (reason?: any) => void\n): () => void {\n const MAX_RETRIES = 26; // 26 * 150ms ≈ 4 seconds max\n const TIMEOUT_MS = 4000; // 4 seconds total timeout\n let retryCount = 0;\n const startTime = Date.now();\n\n const checkSDK = (): void => {\n if (window.TapKit) {\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n return;\n }\n\n retryCount++;\n const elapsed = Date.now() - startTime;\n\n // Check if exceeded timeout or max retries\n if (elapsed > TIMEOUT_MS) {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(\n new Error(\n `TapKit loader timeout: SDK not available after ${TIMEOUT_MS}ms`\n )\n );\n return;\n }\n\n if (retryCount >= MAX_RETRIES) {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(\n new Error(\n `TapKit loader failed: SDK not available after ${retryCount} retries`\n )\n );\n return;\n }\n\n setTimeout(checkSDK, 150);\n };\n\n return checkSDK;\n}\n\n/**\n * Loads the CDN loader script\n * The loader will then fetch versions.json and load the appropriate SDK version\n */\nfunction loadCDNLoader(): Promise<void> {\n // If already loaded, return immediately\n if (window.__TAP_KIT_LOADER_LOADED__ && window.TapKit) {\n return Promise.resolve();\n }\n\n // If currently loading, return the existing promise\n if (window.__TAP_KIT_LOADER_LOADING__) {\n return window.__TAP_KIT_LOADER_LOADING__;\n }\n\n // Create loading promise\n const loadingPromise = new Promise<void>((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(\n new Error(\"TapKit requires browser environment (document is undefined)\")\n );\n return;\n }\n\n const script = document.createElement(\"script\");\n script.src = CDN_LOADER_URL;\n script.async = true;\n\n script.onload = () => {\n // The loader script will load the actual SDK\n // We need to wait a bit for the loader to fetch and load the SDK\n const checkSDK = createSDKChecker(resolve, reject);\n checkSDK();\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load TapKit CDN loader: ${CDN_LOADER_URL}`));\n };\n\n // Check if script already exists\n const existingScript = document.querySelector(\n `script[src=\"${CDN_LOADER_URL}\"]`\n );\n if (existingScript) {\n // Script already added but not yet loaded\n existingScript.addEventListener(\"load\", () => {\n const checkSDK = createSDKChecker(resolve, reject);\n checkSDK();\n });\n existingScript.addEventListener(\"error\", () =>\n reject(new Error(`Failed to load TapKit CDN loader: ${CDN_LOADER_URL}`))\n );\n } else {\n document.head.appendChild(script);\n }\n });\n\n window.__TAP_KIT_LOADER_LOADING__ = loadingPromise;\n return loadingPromise;\n}\n\n// Use Symbol to hide SDK instance from enumeration\nconst SDK_INSTANCE = Symbol(\"sdkInstance\");\nconst SDK_INSTANCE_LOADING = Symbol(\"sdkInstanceLoading\");\n\n/**\n * TapKit Wrapper Class\n *\n * Loads the CDN loader and proxies all calls to the actual SDK\n */\nclass TapKit implements TapKitInstance {\n private [SDK_INSTANCE]?: TapKitCoreInstance;\n private [SDK_INSTANCE_LOADING]: Promise<void>;\n\n constructor(config: TapKitConfig) {\n this[SDK_INSTANCE_LOADING] = this.loadAndInitialize(config);\n }\n\n private async loadAndInitialize(config: TapKitConfig): Promise<void> {\n await loadCDNLoader();\n\n if (!window.TapKit) {\n throw new Error(\"TapKit not available after loading CDN loader\");\n }\n\n this[SDK_INSTANCE] = new window.TapKit(config);\n }\n\n private async ensureLoaded(): Promise<TapKitCoreInstance> {\n await this[SDK_INSTANCE_LOADING]; // Wait for SDK instance to be created\n\n if (!this[SDK_INSTANCE]) {\n throw new Error(\"TapKit instance not initialized\");\n }\n\n return this[SDK_INSTANCE];\n }\n\n // Expose tap-kit-core's 'ready' promise as 'ready' for better API naming\n // This resolves after init() is called and tap-kit-core is fully initialized\n get ready(): Promise<void> {\n return this.ensureLoaded().then((sdk) => sdk.ready);\n }\n\n // Public API - all methods proxy to the loaded SDK\n get events() {\n return {\n seekTimeline: (params: SeekTimelineParamsType) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.seekTimeline(params))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to call seekTimeline:\", error);\n });\n },\n onTimelineSeek: (\n callback: (clipPlayHead: number, clipId: string) => void\n ) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onTimelineSeek(callback))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onTimelineSeek:\", error);\n });\n },\n onChatInitiated: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onChatInitiated(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onChatInitiated:\", error);\n });\n },\n onChatOpened: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onChatOpened(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onChatOpened:\", error);\n });\n },\n onChatClosed: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onChatClosed(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onChatClosed:\", error);\n });\n },\n onAlarmFadeIn: (\n handler: (messageInfo: AlarmMessageInstanceType) => void\n ) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onAlarmFadeIn(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onAlarmFadeIn:\", error);\n });\n },\n onPopUpOpen: (handler: (popUpInfo: any) => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onPopUpOpen(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onPopUpOpen:\", error);\n });\n },\n onPdfOpen: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onPdfOpen(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onPdfOpen:\", error);\n });\n },\n onPdfClose: (handler: () => void) => {\n this.ensureLoaded()\n .then((sdk) => sdk.events.onPdfClose(handler))\n .catch((error) => {\n console.error(\"[TapSDK] Failed to register onPdfClose:\", error);\n });\n },\n };\n }\n\n get isOpen(): boolean {\n return this[SDK_INSTANCE]?.isOpen ?? false;\n }\n\n get isInitialized(): boolean {\n return this[SDK_INSTANCE]?.isInitialized ?? false;\n }\n\n async init(params: TapKitInitParams): Promise<void> {\n const sdk = await this.ensureLoaded();\n return sdk.init(params);\n }\n\n destroy(): void {\n if (this[SDK_INSTANCE]) {\n this[SDK_INSTANCE].destroy();\n }\n }\n\n getVersion(): string {\n // tap-kit-core doesn't expose getVersion, return SDK wrapper version\n // The actual implementation is loaded from CDN dynamically\n if (!this[SDK_INSTANCE]) {\n return \"Not initialized\";\n }\n return `Loaded from CDN (tap-sdk wrapper v${__PACKAGE_VERSION__})`;\n }\n\n /**\n * Custom object tag for better console display\n */\n get [Symbol.toStringTag]() {\n return \"TapKit\";\n }\n}\n\n// Export the SDK class as default (for: import TapKit from '@coxwave/tap-sdk')\nexport default TapKit;\n\n// TapKitInstance is already exported via the interface declaration above (line 72)\n// Users can import it via: import type { TapKitInstance } from '@coxwave/tap-sdk'\n\n// Re-export types for API compatibility\nexport type {\n TapKitConfig,\n TapKitInitParams,\n Course,\n ContainerStyle,\n PositionType,\n SeekTimelineParamsType,\n AlarmMessageInstanceType,\n AlarmType,\n};\n"]}
1
+ {"version":3,"sources":["../src/loader.ts","../src/sdk.ts"],"names":["DEFAULT_CDN_LOADER_URL","getLoaderURL","isLocalCoreMode","getLocalCoreURL","createSDKChecker","resolve","reject","timeoutMs","startTime","checkSDK","loadCDNLoader","loadingPromise","coreURL","script","loaderURL","existingScript","TAPKIT_CONFIG_SYMBOL","TapKit","config","__publicField","err","params","options"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * CDN loader for TapSDK\n * Dynamically loads the TapKit SDK from CDN\n *\n * For local testing, you can override the loader URL:\n * window.__TAP_KIT_LOADER_URL__ = '/tap-kit-core/loader.js';\n *\n * For local development (bypass loader, load IIFE directly):\n * window.__TAP_KIT_CORE_URL__ = '/packages/tap-kit-core/dist/index.global.js';\n */\n\nconst DEFAULT_CDN_LOADER_URL = \"https://files.edutap.ai/tap-sdk/loader.js\";\nconst DEFAULT_TIMEOUT_MS = 4000; // 4 seconds total timeout\nconst IDLE_CALLBACK_TIMEOUT_MS = 500; // 500ms for requestIdleCallback\n\n/**\n * Get the loader URL from window override or default CDN\n */\nfunction getLoaderURL(): string {\n return typeof window !== \"undefined\" && window.__TAP_KIT_LOADER_URL__\n ? window.__TAP_KIT_LOADER_URL__\n : DEFAULT_CDN_LOADER_URL;\n}\n\n/**\n * Check if local core mode is enabled\n * When __TAP_KIT_CORE_URL__ is set, directly load the IIFE bundle\n * This bypasses the loader.js and loads tap-kit-core directly\n */\nfunction isLocalCoreMode(): boolean {\n return typeof window !== \"undefined\" && !!window.__TAP_KIT_CORE_URL__;\n}\n\n/**\n * Get the local core URL\n */\nfunction getLocalCoreURL(): string {\n return window.__TAP_KIT_CORE_URL__ || \"\";\n}\n\n/**\n * Creates a SDK checker function with timeout and retry logic\n * Uses requestIdleCallback to avoid blocking browser rendering\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n * @param timeoutMs - Maximum time to wait for SDK to load (milliseconds)\n * @returns Checker function to be called repeatedly\n */\nfunction createSDKChecker(\n resolve: (value: void | PromiseLike<void>) => void,\n reject: (reason?: any) => void,\n timeoutMs: number\n): () => void {\n const startTime = Date.now();\n\n const checkSDK = (): void => {\n // Check if real TapKit is loaded (not just stub)\n // Stub has TapKitLoaded flag set to true by loader.js after real SDK loads\n if (window.TapKit && window.TapKitLoaded === true) {\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n return;\n }\n\n const elapsed = Date.now() - startTime;\n\n // Check if exceeded timeout\n if (elapsed > timeoutMs) {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`TapKit loader timeout: SDK not available after ${timeoutMs}ms`));\n return;\n }\n\n // Use requestIdleCallback for better performance\n // Falls back to setTimeout if not available\n if (typeof requestIdleCallback !== \"undefined\") {\n requestIdleCallback(checkSDK, { timeout: IDLE_CALLBACK_TIMEOUT_MS });\n } else {\n setTimeout(checkSDK, IDLE_CALLBACK_TIMEOUT_MS);\n }\n };\n\n return checkSDK;\n}\n\n/**\n * Loads the CDN loader script\n * The loader will then fetch versions.json and load the appropriate SDK version\n *\n * If __TAP_KIT_CORE_URL__ is set, bypasses loader and loads IIFE directly\n *\n * @param timeoutMs - Maximum time to wait for SDK to load (default: 4000ms)\n * @returns Promise that resolves when SDK is loaded\n * @throws {Error} If loader fails to load or times out\n */\nexport function loadCDNLoader(timeoutMs: number = DEFAULT_TIMEOUT_MS): Promise<void> {\n // If already loaded, return immediately\n if (window.__TAP_KIT_LOADER_LOADED__ && window.TapKit) {\n return Promise.resolve();\n }\n\n // If currently loading, return the existing promise\n if (window.__TAP_KIT_LOADER_LOADING__) {\n return window.__TAP_KIT_LOADER_LOADING__;\n }\n\n // Create loading promise\n const loadingPromise = new Promise<void>((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(new Error(\"TapKit requires browser environment (document is undefined)\"));\n return;\n }\n\n // Local core mode: Load IIFE directly\n if (isLocalCoreMode()) {\n const coreURL = getLocalCoreURL();\n console.log(\"[TapSDK] Loading local core:\", coreURL);\n\n const script = document.createElement(\"script\");\n script.src = coreURL;\n script.async = true;\n\n script.onload = () => {\n // IIFE directly sets window.TapKit\n // Set the loaded flag manually since we bypass loader.js\n if (window.TapKit) {\n window.TapKitLoaded = true;\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n console.log(\"[TapSDK] Local core loaded successfully\");\n resolve();\n } else {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(\"TapKit not available after loading local core\"));\n }\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load local TapKit core: ${coreURL}`));\n };\n\n document.head.appendChild(script);\n return;\n }\n\n // CDN mode: Load loader.js\n const loaderURL = getLoaderURL();\n const script = document.createElement(\"script\");\n script.src = loaderURL;\n script.async = true;\n\n script.onload = () => {\n // The loader script will load the actual SDK\n // We need to wait a bit for the loader to fetch and load the SDK\n const checkSDK = createSDKChecker(resolve, reject, timeoutMs);\n checkSDK();\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`));\n };\n\n // Check if script already exists\n const existingScript = document.querySelector(`script[src=\"${loaderURL}\"]`);\n\n if (existingScript) {\n // Script already added but not yet loaded\n existingScript.addEventListener(\"load\", () => {\n const checkSDK = createSDKChecker(resolve, reject, timeoutMs);\n checkSDK();\n });\n existingScript.addEventListener(\"error\", () =>\n reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`))\n );\n } else {\n document.head.appendChild(script);\n }\n });\n\n window.__TAP_KIT_LOADER_LOADING__ = loadingPromise;\n return loadingPromise;\n}\n","import type {\n TapKitConfig,\n TapKitInitParams,\n TapKitInstance,\n TapKitConfigOptions,\n TAPKIT_CONFIG_SYMBOL as TAPKIT_CONFIG_SYMBOL_TYPE,\n} from \"@coxwave/tap-kit-types\";\nimport { loadCDNLoader } from \"./loader\";\n\n/** @internal Symbol for internal configuration method */\nconst TAPKIT_CONFIG_SYMBOL: typeof TAPKIT_CONFIG_SYMBOL_TYPE = Symbol.for(\"tapkit.config\") as any;\n\n/**\n * TapSDK - Official TapKit Web SDK\n *\n * @example\n * ```typescript\n * import TapSDK from \"@coxwave/tap-sdk\";\n *\n * const sdk = new TapSDK({ apiKey: 'your-api-key' });\n *\n * await sdk.init({\n * buttonId: 'tap-button',\n * course: {\n * userId: 'user-123',\n * courseId: 'course-456',\n * clipId: 'clip-789',\n * },\n * container: {\n * position: { top: '64px', right: '32px' },\n * width: '360px',\n * height: 'calc(100% - 128px)',\n * },\n * });\n * ```\n */\nexport class TapKit implements TapKitInstance {\n private instance: TapKitInstance | null = null;\n private loading: Promise<void>;\n private config: TapKitConfig;\n\n constructor(config: TapKitConfig) {\n this.config = config;\n this.loading = this.load();\n }\n\n private async load(): Promise<void> {\n console.log(\"[TapSDK] Starting CDN loader...\");\n\n try {\n await loadCDNLoader();\n console.log(\"[TapSDK] CDN loader completed\");\n } catch (err) {\n console.error(\"[TapSDK] CDN loader failed:\", err);\n throw err;\n }\n\n if (!window.TapKit) {\n console.error(\"[TapSDK] window.TapKit not available after loading\");\n throw new Error(\"TapKit not available after loading CDN loader\");\n }\n\n console.log(\"[TapSDK] Creating TapKit instance from window.TapKit\");\n this.instance = new window.TapKit(this.config);\n console.log(\"[TapSDK] TapKit instance created successfully\");\n }\n\n get ready(): Promise<void> {\n return this.loading.then(() => {\n if (!this.instance) {\n throw new Error(\"TapKit instance not initialized\");\n }\n return this.instance.ready;\n });\n }\n\n get events() {\n if (!this.instance) {\n throw new Error(\"TapKit not loaded yet. Use await sdk.ready first.\");\n }\n return this.instance.events;\n }\n\n get isOpen(): boolean {\n return this.instance?.isOpen ?? false;\n }\n\n get isInitialized(): boolean {\n return this.instance?.isInitialized ?? false;\n }\n\n async init(params: TapKitInitParams): Promise<void> {\n await this.loading; // Wait for CDN loader to complete\n await this.instance!.init(params);\n }\n\n destroy(): void {\n if (this.instance) {\n this.instance.destroy();\n this.instance = null;\n }\n }\n\n [TAPKIT_CONFIG_SYMBOL](options: TapKitConfigOptions): void {\n if (!this.instance) {\n throw new Error(\"TapKit not loaded yet. Use await sdk.ready first.\");\n }\n this.instance[TAPKIT_CONFIG_SYMBOL]?.(options);\n }\n\n get [Symbol.toStringTag]() {\n return \"TapKit\";\n }\n}\n"]}
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@coxwave/tap-sdk",
3
- "version": "0.2.8",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "TapSDK - Minimal wrapper that loads TapSDK from CDN",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
8
8
  "types": "dist/index.d.ts",
9
9
  "unpkg": "dist/index.global.js",
10
+ "sideEffects": false,
10
11
  "exports": {
11
12
  ".": {
12
13
  "types": "./dist/index.d.ts",
@@ -18,7 +19,7 @@
18
19
  "build": "tsup",
19
20
  "build:analyze": "tsup --metafile",
20
21
  "dev": "tsup --watch",
21
- "prepare": "pnpm build",
22
+ "prepublishOnly": "pnpm build",
22
23
  "lint": "eslint .",
23
24
  "publish:npm": "./scripts/publish.sh"
24
25
  },
@@ -33,13 +34,13 @@
33
34
  "license": "MIT",
34
35
  "files": [
35
36
  "dist",
36
- "types.ts",
37
- "index.ts"
37
+ "src"
38
38
  ],
39
39
  "devDependencies": {
40
40
  "@coxwave/config-eslint": "workspace:*",
41
41
  "@coxwave/config-typescript": "workspace:*",
42
42
  "@coxwave/tap-messages": "workspace:*",
43
+ "@coxwave/tap-kit-types": "workspace:*",
43
44
  "tsup": "^8.5.0"
44
45
  }
45
46
  }
package/src/index.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * TapSDK - Official TapKit Web SDK
3
+ * @see https://edutap-docs.vercel.app
4
+ */
5
+
6
+ // Default export: TapKit class
7
+ export { TapKit as default } from "./sdk";
8
+
9
+ // Type definitions
10
+ export type {
11
+ TapKitConfig,
12
+ TapKitInitParams,
13
+ Course,
14
+ ContainerStyle,
15
+ PositionType,
16
+ SeekTimelineParamsType,
17
+ AlarmMessageInstanceType,
18
+ AlarmType,
19
+ TapKitInstance,
20
+ TapKitConstructor,
21
+ } from "@coxwave/tap-kit-types";
package/src/loader.ts ADDED
@@ -0,0 +1,185 @@
1
+ /**
2
+ * CDN loader for TapSDK
3
+ * Dynamically loads the TapKit SDK from CDN
4
+ *
5
+ * For local testing, you can override the loader URL:
6
+ * window.__TAP_KIT_LOADER_URL__ = '/tap-kit-core/loader.js';
7
+ *
8
+ * For local development (bypass loader, load IIFE directly):
9
+ * window.__TAP_KIT_CORE_URL__ = '/packages/tap-kit-core/dist/index.global.js';
10
+ */
11
+
12
+ const DEFAULT_CDN_LOADER_URL = "https://files.edutap.ai/tap-sdk/loader.js";
13
+ const DEFAULT_TIMEOUT_MS = 4000; // 4 seconds total timeout
14
+ const IDLE_CALLBACK_TIMEOUT_MS = 500; // 500ms for requestIdleCallback
15
+
16
+ /**
17
+ * Get the loader URL from window override or default CDN
18
+ */
19
+ function getLoaderURL(): string {
20
+ return typeof window !== "undefined" && window.__TAP_KIT_LOADER_URL__
21
+ ? window.__TAP_KIT_LOADER_URL__
22
+ : DEFAULT_CDN_LOADER_URL;
23
+ }
24
+
25
+ /**
26
+ * Check if local core mode is enabled
27
+ * When __TAP_KIT_CORE_URL__ is set, directly load the IIFE bundle
28
+ * This bypasses the loader.js and loads tap-kit-core directly
29
+ */
30
+ function isLocalCoreMode(): boolean {
31
+ return typeof window !== "undefined" && !!window.__TAP_KIT_CORE_URL__;
32
+ }
33
+
34
+ /**
35
+ * Get the local core URL
36
+ */
37
+ function getLocalCoreURL(): string {
38
+ return window.__TAP_KIT_CORE_URL__ || "";
39
+ }
40
+
41
+ /**
42
+ * Creates a SDK checker function with timeout and retry logic
43
+ * Uses requestIdleCallback to avoid blocking browser rendering
44
+ * @param resolve - Promise resolve function
45
+ * @param reject - Promise reject function
46
+ * @param timeoutMs - Maximum time to wait for SDK to load (milliseconds)
47
+ * @returns Checker function to be called repeatedly
48
+ */
49
+ function createSDKChecker(
50
+ resolve: (value: void | PromiseLike<void>) => void,
51
+ reject: (reason?: any) => void,
52
+ timeoutMs: number
53
+ ): () => void {
54
+ const startTime = Date.now();
55
+
56
+ const checkSDK = (): void => {
57
+ // Check if real TapKit is loaded (not just stub)
58
+ // Stub has TapKitLoaded flag set to true by loader.js after real SDK loads
59
+ if (window.TapKit && window.TapKitLoaded === true) {
60
+ window.__TAP_KIT_LOADER_LOADED__ = true;
61
+ window.__TAP_KIT_LOADER_LOADING__ = undefined;
62
+ resolve();
63
+ return;
64
+ }
65
+
66
+ const elapsed = Date.now() - startTime;
67
+
68
+ // Check if exceeded timeout
69
+ if (elapsed > timeoutMs) {
70
+ window.__TAP_KIT_LOADER_LOADING__ = undefined;
71
+ reject(new Error(`TapKit loader timeout: SDK not available after ${timeoutMs}ms`));
72
+ return;
73
+ }
74
+
75
+ // Use requestIdleCallback for better performance
76
+ // Falls back to setTimeout if not available
77
+ if (typeof requestIdleCallback !== "undefined") {
78
+ requestIdleCallback(checkSDK, { timeout: IDLE_CALLBACK_TIMEOUT_MS });
79
+ } else {
80
+ setTimeout(checkSDK, IDLE_CALLBACK_TIMEOUT_MS);
81
+ }
82
+ };
83
+
84
+ return checkSDK;
85
+ }
86
+
87
+ /**
88
+ * Loads the CDN loader script
89
+ * The loader will then fetch versions.json and load the appropriate SDK version
90
+ *
91
+ * If __TAP_KIT_CORE_URL__ is set, bypasses loader and loads IIFE directly
92
+ *
93
+ * @param timeoutMs - Maximum time to wait for SDK to load (default: 4000ms)
94
+ * @returns Promise that resolves when SDK is loaded
95
+ * @throws {Error} If loader fails to load or times out
96
+ */
97
+ export function loadCDNLoader(timeoutMs: number = DEFAULT_TIMEOUT_MS): Promise<void> {
98
+ // If already loaded, return immediately
99
+ if (window.__TAP_KIT_LOADER_LOADED__ && window.TapKit) {
100
+ return Promise.resolve();
101
+ }
102
+
103
+ // If currently loading, return the existing promise
104
+ if (window.__TAP_KIT_LOADER_LOADING__) {
105
+ return window.__TAP_KIT_LOADER_LOADING__;
106
+ }
107
+
108
+ // Create loading promise
109
+ const loadingPromise = new Promise<void>((resolve, reject) => {
110
+ if (typeof document === "undefined") {
111
+ reject(new Error("TapKit requires browser environment (document is undefined)"));
112
+ return;
113
+ }
114
+
115
+ // Local core mode: Load IIFE directly
116
+ if (isLocalCoreMode()) {
117
+ const coreURL = getLocalCoreURL();
118
+ console.log("[TapSDK] Loading local core:", coreURL);
119
+
120
+ const script = document.createElement("script");
121
+ script.src = coreURL;
122
+ script.async = true;
123
+
124
+ script.onload = () => {
125
+ // IIFE directly sets window.TapKit
126
+ // Set the loaded flag manually since we bypass loader.js
127
+ if (window.TapKit) {
128
+ window.TapKitLoaded = true;
129
+ window.__TAP_KIT_LOADER_LOADED__ = true;
130
+ window.__TAP_KIT_LOADER_LOADING__ = undefined;
131
+ console.log("[TapSDK] Local core loaded successfully");
132
+ resolve();
133
+ } else {
134
+ window.__TAP_KIT_LOADER_LOADING__ = undefined;
135
+ reject(new Error("TapKit not available after loading local core"));
136
+ }
137
+ };
138
+
139
+ script.onerror = () => {
140
+ window.__TAP_KIT_LOADER_LOADING__ = undefined;
141
+ reject(new Error(`Failed to load local TapKit core: ${coreURL}`));
142
+ };
143
+
144
+ document.head.appendChild(script);
145
+ return;
146
+ }
147
+
148
+ // CDN mode: Load loader.js
149
+ const loaderURL = getLoaderURL();
150
+ const script = document.createElement("script");
151
+ script.src = loaderURL;
152
+ script.async = true;
153
+
154
+ script.onload = () => {
155
+ // The loader script will load the actual SDK
156
+ // We need to wait a bit for the loader to fetch and load the SDK
157
+ const checkSDK = createSDKChecker(resolve, reject, timeoutMs);
158
+ checkSDK();
159
+ };
160
+
161
+ script.onerror = () => {
162
+ window.__TAP_KIT_LOADER_LOADING__ = undefined;
163
+ reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`));
164
+ };
165
+
166
+ // Check if script already exists
167
+ const existingScript = document.querySelector(`script[src="${loaderURL}"]`);
168
+
169
+ if (existingScript) {
170
+ // Script already added but not yet loaded
171
+ existingScript.addEventListener("load", () => {
172
+ const checkSDK = createSDKChecker(resolve, reject, timeoutMs);
173
+ checkSDK();
174
+ });
175
+ existingScript.addEventListener("error", () =>
176
+ reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`))
177
+ );
178
+ } else {
179
+ document.head.appendChild(script);
180
+ }
181
+ });
182
+
183
+ window.__TAP_KIT_LOADER_LOADING__ = loadingPromise;
184
+ return loadingPromise;
185
+ }
package/src/sdk.ts ADDED
@@ -0,0 +1,114 @@
1
+ import type {
2
+ TapKitConfig,
3
+ TapKitInitParams,
4
+ TapKitInstance,
5
+ TapKitConfigOptions,
6
+ TAPKIT_CONFIG_SYMBOL as TAPKIT_CONFIG_SYMBOL_TYPE,
7
+ } from "@coxwave/tap-kit-types";
8
+ import { loadCDNLoader } from "./loader";
9
+
10
+ /** @internal Symbol for internal configuration method */
11
+ const TAPKIT_CONFIG_SYMBOL: typeof TAPKIT_CONFIG_SYMBOL_TYPE = Symbol.for("tapkit.config") as any;
12
+
13
+ /**
14
+ * TapSDK - Official TapKit Web SDK
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import TapSDK from "@coxwave/tap-sdk";
19
+ *
20
+ * const sdk = new TapSDK({ apiKey: 'your-api-key' });
21
+ *
22
+ * await sdk.init({
23
+ * buttonId: 'tap-button',
24
+ * course: {
25
+ * userId: 'user-123',
26
+ * courseId: 'course-456',
27
+ * clipId: 'clip-789',
28
+ * },
29
+ * container: {
30
+ * position: { top: '64px', right: '32px' },
31
+ * width: '360px',
32
+ * height: 'calc(100% - 128px)',
33
+ * },
34
+ * });
35
+ * ```
36
+ */
37
+ export class TapKit implements TapKitInstance {
38
+ private instance: TapKitInstance | null = null;
39
+ private loading: Promise<void>;
40
+ private config: TapKitConfig;
41
+
42
+ constructor(config: TapKitConfig) {
43
+ this.config = config;
44
+ this.loading = this.load();
45
+ }
46
+
47
+ private async load(): Promise<void> {
48
+ console.log("[TapSDK] Starting CDN loader...");
49
+
50
+ try {
51
+ await loadCDNLoader();
52
+ console.log("[TapSDK] CDN loader completed");
53
+ } catch (err) {
54
+ console.error("[TapSDK] CDN loader failed:", err);
55
+ throw err;
56
+ }
57
+
58
+ if (!window.TapKit) {
59
+ console.error("[TapSDK] window.TapKit not available after loading");
60
+ throw new Error("TapKit not available after loading CDN loader");
61
+ }
62
+
63
+ console.log("[TapSDK] Creating TapKit instance from window.TapKit");
64
+ this.instance = new window.TapKit(this.config);
65
+ console.log("[TapSDK] TapKit instance created successfully");
66
+ }
67
+
68
+ get ready(): Promise<void> {
69
+ return this.loading.then(() => {
70
+ if (!this.instance) {
71
+ throw new Error("TapKit instance not initialized");
72
+ }
73
+ return this.instance.ready;
74
+ });
75
+ }
76
+
77
+ get events() {
78
+ if (!this.instance) {
79
+ throw new Error("TapKit not loaded yet. Use await sdk.ready first.");
80
+ }
81
+ return this.instance.events;
82
+ }
83
+
84
+ get isOpen(): boolean {
85
+ return this.instance?.isOpen ?? false;
86
+ }
87
+
88
+ get isInitialized(): boolean {
89
+ return this.instance?.isInitialized ?? false;
90
+ }
91
+
92
+ async init(params: TapKitInitParams): Promise<void> {
93
+ await this.loading; // Wait for CDN loader to complete
94
+ await this.instance!.init(params);
95
+ }
96
+
97
+ destroy(): void {
98
+ if (this.instance) {
99
+ this.instance.destroy();
100
+ this.instance = null;
101
+ }
102
+ }
103
+
104
+ [TAPKIT_CONFIG_SYMBOL](options: TapKitConfigOptions): void {
105
+ if (!this.instance) {
106
+ throw new Error("TapKit not loaded yet. Use await sdk.ready first.");
107
+ }
108
+ this.instance[TAPKIT_CONFIG_SYMBOL]?.(options);
109
+ }
110
+
111
+ get [Symbol.toStringTag]() {
112
+ return "TapKit";
113
+ }
114
+ }