@adstage/web-sdk 1.3.4 → 1.4.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.
Files changed (61) hide show
  1. package/README.md +178 -35
  2. package/dist/index.cjs.js +753 -509
  3. package/dist/index.d.ts +286 -97
  4. package/dist/index.esm.js +737 -485
  5. package/dist/index.standalone.js +737 -485
  6. package/package.json +1 -1
  7. package/src/constants/endpoints.ts +93 -0
  8. package/src/core/AdStage.ts +128 -0
  9. package/src/index.ts +14 -432
  10. package/src/managers/{slider-manager.ts → carousel-slider-manager.ts} +9 -8
  11. package/src/managers/event-tracker.ts +2 -4
  12. package/src/managers/{fade-slider-manager.ts → text-transition-manager.ts} +7 -7
  13. package/src/modules/ads/AdsModule.ts +525 -0
  14. package/src/modules/config/ConfigModule.ts +124 -0
  15. package/src/modules/deeplinks/DeeplinksModule.ts +0 -0
  16. package/src/modules/events/EventsModule.ts +106 -0
  17. package/src/types/config.ts +74 -3
  18. package/src/types/index.ts +2 -1
  19. package/src/utils/api-headers.ts +52 -0
  20. package/src/utils/dom-utils.ts +1 -1
  21. package/examples/README.md +0 -33
  22. package/examples/banner-ads.html +0 -512
  23. package/examples/index.html +0 -338
  24. package/examples/native-ads.html +0 -634
  25. package/examples/react-app/README.md +0 -70
  26. package/examples/react-app/index.html +0 -13
  27. package/examples/react-app/package-lock.json +0 -3042
  28. package/examples/react-app/package.json +0 -26
  29. package/examples/react-app/pnpm-lock.yaml +0 -1857
  30. package/examples/react-app/public/index.standalone.js +0 -2331
  31. package/examples/react-app/src/App.tsx +0 -226
  32. package/examples/react-app/src/index.css +0 -37
  33. package/examples/react-app/src/main.tsx +0 -10
  34. package/examples/react-app/tsconfig.json +0 -25
  35. package/examples/react-app/tsconfig.node.json +0 -10
  36. package/examples/react-app/vite.config.ts +0 -15
  37. package/examples/react-nextjs/app/globals.css +0 -200
  38. package/examples/react-nextjs/app/layout.tsx +0 -27
  39. package/examples/react-nextjs/app/page.tsx +0 -258
  40. package/examples/react-nextjs/next.config.js +0 -9
  41. package/examples/react-nextjs/package.json +0 -22
  42. package/examples/react-nextjs/pnpm-lock.yaml +0 -343
  43. package/examples/react-nextjs/tsconfig.json +0 -34
  44. package/examples/text-ads.html +0 -597
  45. package/examples/video-ads.html +0 -739
  46. package/src/react/components/AdErrorBoundary.tsx +0 -75
  47. package/src/react/components/AdSlot.tsx +0 -144
  48. package/src/react/components/BannerAd.tsx +0 -24
  49. package/src/react/components/InterstitialAd.tsx +0 -24
  50. package/src/react/components/NativeAd.tsx +0 -24
  51. package/src/react/components/TextAd.tsx +0 -24
  52. package/src/react/components/VideoAd.tsx +0 -24
  53. package/src/react/components/index.ts +0 -8
  54. package/src/react/hooks/index.ts +0 -4
  55. package/src/react/hooks/useAdSlot.ts +0 -83
  56. package/src/react/hooks/useAdStage.ts +0 -14
  57. package/src/react/hooks/useAdTracking.ts +0 -61
  58. package/src/react/index.ts +0 -4
  59. package/src/react/providers/AdStageProvider.tsx +0 -86
  60. package/src/react/providers/index.ts +0 -2
  61. package/src/utils/sdk-standalone.ts +0 -155
@@ -1,75 +0,0 @@
1
- import React, { Component, ErrorInfo, ReactNode } from 'react';
2
-
3
- interface AdErrorBoundaryProps {
4
- children: ReactNode;
5
- fallback?: ReactNode;
6
- onError?: (error: Error, errorInfo: ErrorInfo) => void;
7
- }
8
-
9
- interface AdErrorBoundaryState {
10
- hasError: boolean;
11
- error: Error | null;
12
- }
13
-
14
- /**
15
- * 광고 컴포넌트에서 발생하는 오류를 포착하는 Error Boundary
16
- * 광고 로딩 실패 시 fallback UI를 표시하고 앱 전체가 크래시되는 것을 방지
17
- */
18
- export class AdErrorBoundary extends Component<AdErrorBoundaryProps, AdErrorBoundaryState> {
19
- constructor(props: AdErrorBoundaryProps) {
20
- super(props);
21
- this.state = { hasError: false, error: null };
22
- }
23
-
24
- static getDerivedStateFromError(error: Error): AdErrorBoundaryState {
25
- return { hasError: true, error };
26
- }
27
-
28
- componentDidCatch(error: Error, errorInfo: ErrorInfo) {
29
- console.error('AdStage Error Boundary caught an error:', error, errorInfo);
30
-
31
- // 사용자 정의 에러 핸들러 호출
32
- if (this.props.onError) {
33
- this.props.onError(error, errorInfo);
34
- }
35
- }
36
-
37
- render() {
38
- if (this.state.hasError) {
39
- // 사용자 정의 fallback이 있으면 사용, 없으면 기본 fallback 표시
40
- if (this.props.fallback) {
41
- return this.props.fallback;
42
- }
43
-
44
- return (
45
- <div
46
- style={{
47
- padding: '20px',
48
- textAlign: 'center',
49
- backgroundColor: '#fee',
50
- border: '1px solid #fcc',
51
- borderRadius: '4px',
52
- color: '#c00',
53
- }}
54
- >
55
- <h3>광고 로딩 오류</h3>
56
- <p>광고를 불러오는 중 문제가 발생했습니다.</p>
57
- <button
58
- onClick={() => this.setState({ hasError: false, error: null })}
59
- style={{
60
- padding: '8px 16px',
61
- backgroundColor: '#fff',
62
- border: '1px solid #ccc',
63
- borderRadius: '4px',
64
- cursor: 'pointer',
65
- }}
66
- >
67
- 다시 시도
68
- </button>
69
- </div>
70
- );
71
- }
72
-
73
- return this.props.children;
74
- }
75
- }
@@ -1,144 +0,0 @@
1
- import React, { useEffect, useRef, useMemo } from 'react';
2
- import { AdType } from '../../types/advertisement';
3
- import { useAdStage } from '../hooks/useAdStage';
4
-
5
- interface AdSlotProps {
6
- slotId: string;
7
- adType: AdType;
8
- width?: string | number;
9
- height?: string | number;
10
- className?: string;
11
- style?: React.CSSProperties;
12
- autoSlideInterval?: number;
13
- sliderEffect?: 'slide' | 'fade';
14
- language?: string;
15
- deviceType?: string;
16
- country?: string;
17
- }
18
-
19
- /**
20
- * 범용 광고 슬롯 컴포넌트
21
- * 모든 광고 타입을 지원하며 SSR 환경에서도 안전하게 동작
22
- */
23
- export const AdSlot: React.FC<AdSlotProps> = ({
24
- slotId,
25
- adType,
26
- width,
27
- height,
28
- className,
29
- style,
30
- autoSlideInterval = 3,
31
- sliderEffect = 'slide',
32
- language,
33
- deviceType,
34
- country,
35
- }) => {
36
- const containerRef = useRef<HTMLDivElement>(null);
37
- const { sdk, isLoading, error } = useAdStage();
38
-
39
- const containerId = useMemo(() => `adstage-${slotId}`, [slotId]);
40
-
41
- useEffect(() => {
42
- if (!sdk || !containerRef.current || isLoading || error) {
43
- return;
44
- }
45
-
46
- // 컨테이너에 ID 설정
47
- containerRef.current.id = containerId;
48
-
49
- // 광고 슬롯 생성
50
- const createSlot = async () => {
51
- try {
52
- await sdk.createSlot(slotId, containerId, adType, {
53
- width,
54
- height,
55
- language,
56
- deviceType,
57
- country,
58
- autoSlideInterval,
59
- sliderEffect,
60
- });
61
- } catch (err) {
62
- console.error(`Failed to create ad slot ${slotId}:`, err);
63
- }
64
- };
65
-
66
- createSlot();
67
-
68
- // 클린업 함수
69
- return () => {
70
- // SDK에 removeSlot 메서드가 없으므로 DOM 정리만 수행
71
- if (containerRef.current) {
72
- containerRef.current.innerHTML = '';
73
- }
74
- };
75
- }, [
76
- sdk,
77
- slotId,
78
- containerId,
79
- adType,
80
- width,
81
- height,
82
- language,
83
- deviceType,
84
- country,
85
- autoSlideInterval,
86
- sliderEffect,
87
- isLoading,
88
- error,
89
- ]);
90
-
91
- const containerStyle: React.CSSProperties = {
92
- width: typeof width === 'number' ? `${width}px` : width,
93
- height: typeof height === 'number' ? `${height}px` : height,
94
- ...style,
95
- };
96
-
97
- // 로딩 상태 표시
98
- if (isLoading) {
99
- return (
100
- <div
101
- className={className}
102
- style={{
103
- ...containerStyle,
104
- display: 'flex',
105
- alignItems: 'center',
106
- justifyContent: 'center',
107
- backgroundColor: '#f5f5f5',
108
- border: '1px dashed #ccc',
109
- color: '#999',
110
- }}
111
- >
112
- Loading Ad...
113
- </div>
114
- );
115
- }
116
-
117
- // 에러 상태 표시
118
- if (error) {
119
- return (
120
- <div
121
- className={className}
122
- style={{
123
- ...containerStyle,
124
- display: 'flex',
125
- alignItems: 'center',
126
- justifyContent: 'center',
127
- backgroundColor: '#fee',
128
- border: '1px solid #fcc',
129
- color: '#c00',
130
- }}
131
- >
132
- Ad Load Error
133
- </div>
134
- );
135
- }
136
-
137
- return (
138
- <div
139
- ref={containerRef}
140
- className={className}
141
- style={containerStyle}
142
- />
143
- );
144
- };
@@ -1,24 +0,0 @@
1
- import React from 'react';
2
- import { AdType } from '../../types/advertisement';
3
- import { AdSlot } from './AdSlot';
4
-
5
- interface BannerAdProps {
6
- slotId: string;
7
- width?: string | number;
8
- height?: string | number;
9
- className?: string;
10
- style?: React.CSSProperties;
11
- autoSlideInterval?: number;
12
- sliderEffect?: 'slide' | 'fade';
13
- language?: string;
14
- deviceType?: string;
15
- country?: string;
16
- }
17
-
18
- /**
19
- * 배너 광고 전용 컴포넌트
20
- * AdSlot의 래퍼로 adType이 BANNER로 고정됨
21
- */
22
- export const BannerAd: React.FC<BannerAdProps> = (props) => {
23
- return <AdSlot {...props} adType={AdType.BANNER} />;
24
- };
@@ -1,24 +0,0 @@
1
- import React from 'react';
2
- import { AdType } from '../../types/advertisement';
3
- import { AdSlot } from './AdSlot';
4
-
5
- interface InterstitialAdProps {
6
- slotId: string;
7
- width?: string | number;
8
- height?: string | number;
9
- className?: string;
10
- style?: React.CSSProperties;
11
- autoSlideInterval?: number;
12
- sliderEffect?: 'slide' | 'fade';
13
- language?: string;
14
- deviceType?: string;
15
- country?: string;
16
- }
17
-
18
- /**
19
- * 인터스티셜 광고 전용 컴포넌트
20
- * AdSlot의 래퍼로 adType이 INTERSTITIAL로 고정됨
21
- */
22
- export const InterstitialAd: React.FC<InterstitialAdProps> = (props) => {
23
- return <AdSlot {...props} adType={AdType.INTERSTITIAL} />;
24
- };
@@ -1,24 +0,0 @@
1
- import React from 'react';
2
- import { AdType } from '../../types/advertisement';
3
- import { AdSlot } from './AdSlot';
4
-
5
- interface NativeAdProps {
6
- slotId: string;
7
- width?: string | number;
8
- height?: string | number;
9
- className?: string;
10
- style?: React.CSSProperties;
11
- autoSlideInterval?: number;
12
- sliderEffect?: 'slide' | 'fade';
13
- language?: string;
14
- deviceType?: string;
15
- country?: string;
16
- }
17
-
18
- /**
19
- * 네이티브 광고 전용 컴포넌트
20
- * AdSlot의 래퍼로 adType이 NATIVE로 고정됨
21
- */
22
- export const NativeAd: React.FC<NativeAdProps> = (props) => {
23
- return <AdSlot {...props} adType={AdType.NATIVE} />;
24
- };
@@ -1,24 +0,0 @@
1
- import React from 'react';
2
- import { AdType } from '../../types/advertisement';
3
- import { AdSlot } from './AdSlot';
4
-
5
- interface TextAdProps {
6
- slotId: string;
7
- width?: string | number;
8
- height?: string | number;
9
- className?: string;
10
- style?: React.CSSProperties;
11
- autoSlideInterval?: number;
12
- sliderEffect?: 'slide' | 'fade';
13
- language?: string;
14
- deviceType?: string;
15
- country?: string;
16
- }
17
-
18
- /**
19
- * 텍스트 광고 전용 컴포넌트
20
- * AdSlot의 래퍼로 adType이 TEXT로 고정됨
21
- */
22
- export const TextAd: React.FC<TextAdProps> = (props) => {
23
- return <AdSlot {...props} adType={AdType.TEXT} />;
24
- };
@@ -1,24 +0,0 @@
1
- import React from 'react';
2
- import { AdType } from '../../types/advertisement';
3
- import { AdSlot } from './AdSlot';
4
-
5
- interface VideoAdProps {
6
- slotId: string;
7
- width?: string | number;
8
- height?: string | number;
9
- className?: string;
10
- style?: React.CSSProperties;
11
- autoSlideInterval?: number;
12
- sliderEffect?: 'slide' | 'fade';
13
- language?: string;
14
- deviceType?: string;
15
- country?: string;
16
- }
17
-
18
- /**
19
- * 비디오 광고 전용 컴포넌트
20
- * AdSlot의 래퍼로 adType이 VIDEO로 고정됨
21
- */
22
- export const VideoAd: React.FC<VideoAdProps> = (props) => {
23
- return <AdSlot {...props} adType={AdType.VIDEO} />;
24
- };
@@ -1,8 +0,0 @@
1
- // React 컴포넌트들
2
- export { AdSlot } from './AdSlot';
3
- export { BannerAd } from './BannerAd';
4
- export { TextAd } from './TextAd';
5
- export { NativeAd } from './NativeAd';
6
- export { VideoAd } from './VideoAd';
7
- export { InterstitialAd } from './InterstitialAd';
8
- export { AdErrorBoundary } from './AdErrorBoundary';
@@ -1,4 +0,0 @@
1
- // React Hook들
2
- export { useAdStage } from './useAdStage';
3
- export { useAdSlot } from './useAdSlot';
4
- export { useAdTracking } from './useAdTracking';
@@ -1,83 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { AdType } from '../../types/advertisement';
3
- import { useAdStage } from './useAdStage';
4
-
5
- interface UseAdSlotOptions {
6
- slotId: string;
7
- containerId: string;
8
- adType: AdType;
9
- width?: string | number;
10
- height?: string | number;
11
- language?: string;
12
- deviceType?: string;
13
- country?: string;
14
- autoSlideInterval?: number;
15
- sliderEffect?: 'slide' | 'fade';
16
- }
17
-
18
- interface UseAdSlotReturn {
19
- isLoading: boolean;
20
- error: string | null;
21
- isCreated: boolean;
22
- createSlot: () => Promise<void>;
23
- resetSlot: () => void;
24
- }
25
-
26
- /**
27
- * 광고 슬롯 생성 및 관리를 위한 Hook
28
- * 컴포넌트에서 직접 슬롯을 제어하고 싶을 때 사용
29
- */
30
- export const useAdSlot = (options: UseAdSlotOptions): UseAdSlotReturn => {
31
- const { sdk } = useAdStage();
32
- const [isLoading, setIsLoading] = useState(false);
33
- const [error, setError] = useState<string | null>(null);
34
- const [isCreated, setIsCreated] = useState(false);
35
-
36
- const createSlot = async () => {
37
- if (!sdk) {
38
- setError('SDK not initialized');
39
- return;
40
- }
41
-
42
- setIsLoading(true);
43
- setError(null);
44
-
45
- try {
46
- await sdk.createSlot(options.slotId, options.containerId, options.adType, {
47
- width: options.width,
48
- height: options.height,
49
- language: options.language,
50
- deviceType: options.deviceType,
51
- country: options.country,
52
- autoSlideInterval: options.autoSlideInterval,
53
- sliderEffect: options.sliderEffect,
54
- });
55
- setIsCreated(true);
56
- } catch (err) {
57
- const errorMessage = err instanceof Error ? err.message : '슬롯 생성 중 오류가 발생했습니다.';
58
- setError(errorMessage);
59
- setIsCreated(false);
60
- } finally {
61
- setIsLoading(false);
62
- }
63
- };
64
-
65
- const resetSlot = () => {
66
- setIsLoading(false);
67
- setError(null);
68
- setIsCreated(false);
69
- };
70
-
71
- // SDK가 변경되면 상태 초기화
72
- useEffect(() => {
73
- resetSlot();
74
- }, [sdk]);
75
-
76
- return {
77
- isLoading,
78
- error,
79
- isCreated,
80
- createSlot,
81
- resetSlot,
82
- };
83
- };
@@ -1,14 +0,0 @@
1
- import { useContext } from 'react';
2
- import { AdStageContext, type AdStageContextValue } from '../providers/AdStageProvider';
3
-
4
- /**
5
- * AdStage SDK 인스턴스에 접근하기 위한 Hook
6
- * AdStageProvider 내부에서만 사용 가능
7
- */
8
- export const useAdStage = (): AdStageContextValue => {
9
- const context = useContext(AdStageContext);
10
- if (!context) {
11
- throw new Error('useAdStage must be used within an AdStageProvider');
12
- }
13
- return context;
14
- };
@@ -1,61 +0,0 @@
1
- import { useCallback } from 'react';
2
- import { AdEventType } from '../../types/advertisement';
3
- import { useAdStage } from './useAdStage';
4
-
5
- interface UseAdTrackingReturn {
6
- trackEvent: (adId: string, slotId: string, eventType: AdEventType) => void;
7
- trackClick: (adId: string, slotId: string) => void;
8
- trackImpression: (adId: string, slotId: string) => void;
9
- trackView: (adId: string, slotId: string) => void;
10
- trackClose: (adId: string, slotId: string) => void;
11
- }
12
-
13
- /**
14
- * 광고 이벤트 추적을 위한 Hook
15
- * 커스텀 이벤트 추적이 필요할 때 사용
16
- */
17
- export const useAdTracking = (): UseAdTrackingReturn => {
18
- const { sdk } = useAdStage();
19
-
20
- const trackEvent = useCallback((adId: string, slotId: string, eventType: AdEventType) => {
21
- if (!sdk) {
22
- console.warn('SDK not initialized - cannot track event');
23
- return;
24
- }
25
-
26
- try {
27
- // SDK의 eventTracker에 직접 접근할 수 없으므로
28
- // 여기서는 console.log로 대체하거나 SDK에 public 메서드가 있다면 사용
29
- console.log('Ad Event Tracked:', { adId, slotId, eventType });
30
-
31
- // 실제 구현에서는 SDK에 trackEvent 메서드가 있다면 사용
32
- // sdk.trackEvent(adId, slotId, eventType);
33
- } catch (err) {
34
- console.error('Failed to track event:', err);
35
- }
36
- }, [sdk]);
37
-
38
- const trackClick = useCallback((adId: string, slotId: string) => {
39
- trackEvent(adId, slotId, AdEventType.CLICK);
40
- }, [trackEvent]);
41
-
42
- const trackImpression = useCallback((adId: string, slotId: string) => {
43
- trackEvent(adId, slotId, AdEventType.IMPRESSION);
44
- }, [trackEvent]);
45
-
46
- const trackView = useCallback((adId: string, slotId: string) => {
47
- trackEvent(adId, slotId, AdEventType.VIEWABLE);
48
- }, [trackEvent]);
49
-
50
- const trackClose = useCallback((adId: string, slotId: string) => {
51
- trackEvent(adId, slotId, AdEventType.COMPLETED);
52
- }, [trackEvent]);
53
-
54
- return {
55
- trackEvent,
56
- trackClick,
57
- trackImpression,
58
- trackView,
59
- trackClose,
60
- };
61
- };
@@ -1,4 +0,0 @@
1
- // React 관련 모든 exports
2
- export * from './components';
3
- export * from './hooks';
4
- export * from './providers';
@@ -1,86 +0,0 @@
1
- import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';
2
-
3
- // 타입만 import해서 circular dependency 방지
4
- import type { AdStageConfig } from '../../index';
5
-
6
- // AdStageSDK 클래스 타입 정의 (런타임에는 dynamic import 사용)
7
- interface AdStageSDKClass {
8
- init(config: AdStageConfig): AdStageSDKInstance;
9
- }
10
-
11
- interface AdStageSDKInstance {
12
- createSlot: (...args: any[]) => Promise<void>;
13
- removeSlot?: (slotId: string) => void;
14
- }
15
-
16
- export interface AdStageContextValue {
17
- sdk: AdStageSDKInstance | null;
18
- isLoading: boolean;
19
- error: string | null;
20
- isInitialized: boolean;
21
- }
22
-
23
- const AdStageContext = createContext<AdStageContextValue>({
24
- sdk: null,
25
- isLoading: true,
26
- error: null,
27
- isInitialized: false,
28
- });
29
-
30
- export { AdStageContext };
31
-
32
- interface AdStageProviderProps {
33
- config: AdStageConfig;
34
- children: ReactNode;
35
- autoInit?: boolean;
36
- }
37
-
38
- export const AdStageProvider: React.FC<AdStageProviderProps> = ({
39
- config,
40
- children,
41
- autoInit = true,
42
- }) => {
43
- const [sdk, setSdk] = useState<AdStageSDKInstance | null>(null);
44
- const [isLoading, setIsLoading] = useState(true);
45
- const [error, setError] = useState<string | null>(null);
46
- const [isInitialized, setIsInitialized] = useState(false);
47
-
48
- useEffect(() => {
49
- const initializeSDK = async () => {
50
- try {
51
- setIsLoading(true);
52
- setError(null);
53
-
54
- // Dynamic import를 사용해서 circular dependency 방지
55
- const { AdStageSDK } = await import('../../index');
56
-
57
- // SDK 인스턴스 생성
58
- const sdkInstance = AdStageSDK.init(config);
59
-
60
- setSdk(sdkInstance);
61
- setIsInitialized(true);
62
- setIsLoading(false);
63
- } catch (err) {
64
- const errorMessage = err instanceof Error ? err.message : 'SDK 초기화 중 오류가 발생했습니다.';
65
- setError(errorMessage);
66
- setIsLoading(false);
67
- console.error('AdStage SDK initialization failed:', err);
68
- }
69
- };
70
-
71
- initializeSDK();
72
- }, [config.apiKey, config.debug, autoInit]);
73
-
74
- const value: AdStageContextValue = {
75
- sdk,
76
- isLoading,
77
- error,
78
- isInitialized,
79
- };
80
-
81
- return (
82
- <AdStageContext.Provider value={value}>
83
- {children}
84
- </AdStageContext.Provider>
85
- );
86
- };
@@ -1,2 +0,0 @@
1
- // React Provider
2
- export { AdStageProvider } from './AdStageProvider';