@xhub-short/adapters 0.1.0-beta.10 → 0.1.0-beta.11
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.d.ts +101 -127
- package/dist/index.js +112 -172
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IDataSource, VideoItem, FeedResponse, ILogger, LogLevel, LogEntry, IStorage, ISessionStorage, SessionSnapshot, IInteraction, Comment, ICommentAdapter, MockCommentAdapterConfig, CommentListResponse, ReplyListResponse, PostCommentPayload, CommentItem, PostReplyPayload, ReplyItem, EditCommentPayload, DeleteCommentPayload, ReportCommentPayload, IAnalytics, AnalyticsEvent, INetworkAdapter, NetworkType, NetworkQuality, IVideoLoader, VideoSource, PreloadConfig, PreloadResult, PreloadStatus, IPosterLoader, CommentTransformers } from '@xhub-short/contracts';
|
|
1
|
+
import { IDataSource, VideoItem, FeedResponse, ILogger, LogLevel, LogEntry, IStorage, ISessionStorage, SessionSnapshot, IInteraction, Comment, ICommentAdapter, MockCommentAdapterConfig, CommentListResponse, ReplyListResponse, PostCommentPayload, CommentItem, PostReplyPayload, ReplyItem, EditCommentPayload, DeleteCommentPayload, ReportCommentPayload, IAnalytics, AnalyticsEvent, INetworkAdapter, NetworkType, NetworkQuality, IVideoLoader, VideoSource, PreloadConfig, PreloadResult, PreloadStatus, IPosterLoader, ReportReason, CommentTransformers } from '@xhub-short/contracts';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* MockDataAdapter - Development/Testing Data Source
|
|
@@ -446,11 +446,11 @@ declare class MockInteractionAdapter implements IInteraction {
|
|
|
446
446
|
/**
|
|
447
447
|
* Report a video
|
|
448
448
|
*
|
|
449
|
-
* @param
|
|
450
|
-
* @param
|
|
451
|
-
* @param
|
|
449
|
+
* @param videoId - ID of the video to report
|
|
450
|
+
* @param reason - Report reason code
|
|
451
|
+
* @param description - Optional additional description
|
|
452
452
|
*/
|
|
453
|
-
report(
|
|
453
|
+
report(videoId: string, reason: string, description?: string): Promise<void>;
|
|
454
454
|
/**
|
|
455
455
|
* Check if video is liked (for testing)
|
|
456
456
|
*
|
|
@@ -990,6 +990,12 @@ interface RESTEndpointMap {
|
|
|
990
990
|
deleteComment: string;
|
|
991
991
|
/** POST /videos/:id/share (optional) */
|
|
992
992
|
share?: string;
|
|
993
|
+
/** POST /content/:id/report (optional) */
|
|
994
|
+
report?: string;
|
|
995
|
+
/** GET /report-reasons (optional) */
|
|
996
|
+
reportReasons?: string;
|
|
997
|
+
/** POST /content/:id/not-interested (optional) */
|
|
998
|
+
notInterested?: string;
|
|
993
999
|
};
|
|
994
1000
|
/**
|
|
995
1001
|
* Analytics endpoints (optional) - BATCH mode
|
|
@@ -1100,6 +1106,14 @@ interface RetryConfig {
|
|
|
1100
1106
|
*/
|
|
1101
1107
|
exponentialBackoff?: boolean;
|
|
1102
1108
|
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Report reason from API
|
|
1111
|
+
*/
|
|
1112
|
+
interface ReportReasonItem {
|
|
1113
|
+
id: string;
|
|
1114
|
+
label: string;
|
|
1115
|
+
description?: string;
|
|
1116
|
+
}
|
|
1103
1117
|
/**
|
|
1104
1118
|
* Response transform configuration
|
|
1105
1119
|
*/
|
|
@@ -1118,6 +1132,41 @@ interface TransformConfig {
|
|
|
1118
1132
|
nextCursor: string | null;
|
|
1119
1133
|
hasMore: boolean;
|
|
1120
1134
|
};
|
|
1135
|
+
/**
|
|
1136
|
+
* Transform report reasons response from API
|
|
1137
|
+
* If not provided, uses default transform
|
|
1138
|
+
*
|
|
1139
|
+
* @example
|
|
1140
|
+
* ```ts
|
|
1141
|
+
* reportReasons: (response) => {
|
|
1142
|
+
* const data = response.data?.reasons || [];
|
|
1143
|
+
* return data.map(item => ({
|
|
1144
|
+
* id: item.id,
|
|
1145
|
+
* label: item.title,
|
|
1146
|
+
* description: item.description,
|
|
1147
|
+
* }));
|
|
1148
|
+
* }
|
|
1149
|
+
* ```
|
|
1150
|
+
*/
|
|
1151
|
+
reportReasons?: (apiResponse: unknown) => ReportReasonItem[];
|
|
1152
|
+
/**
|
|
1153
|
+
* Transform report request body before sending to API
|
|
1154
|
+
* If not provided, uses default format: { reason, description }
|
|
1155
|
+
*
|
|
1156
|
+
* @example
|
|
1157
|
+
* ```ts
|
|
1158
|
+
* reportBody: ({ contentId, reasonId, description }) => ({
|
|
1159
|
+
* video_id: contentId,
|
|
1160
|
+
* reason_id: reasonId,
|
|
1161
|
+
* description: description || '',
|
|
1162
|
+
* })
|
|
1163
|
+
* ```
|
|
1164
|
+
*/
|
|
1165
|
+
reportBody?: (input: {
|
|
1166
|
+
contentId: string;
|
|
1167
|
+
reasonId: string;
|
|
1168
|
+
description?: string;
|
|
1169
|
+
}) => Record<string, unknown>;
|
|
1121
1170
|
/**
|
|
1122
1171
|
* Field mapping for default transforms
|
|
1123
1172
|
* Used when API field names differ from defaults
|
|
@@ -2060,127 +2109,6 @@ declare class HttpClient {
|
|
|
2060
2109
|
private sleep;
|
|
2061
2110
|
}
|
|
2062
2111
|
|
|
2063
|
-
/**
|
|
2064
|
-
* CircuitBreaker - Prevents cascade failures
|
|
2065
|
-
*
|
|
2066
|
-
* State transitions:
|
|
2067
|
-
* CLOSED → (failures >= threshold) → OPEN
|
|
2068
|
-
* OPEN → (cooldown passes) → HALF_OPEN
|
|
2069
|
-
* HALF_OPEN → (success) → CLOSED
|
|
2070
|
-
* HALF_OPEN → (failure) → OPEN
|
|
2071
|
-
*
|
|
2072
|
-
* @packageDocumentation
|
|
2073
|
-
*/
|
|
2074
|
-
/**
|
|
2075
|
-
* Circuit breaker states
|
|
2076
|
-
*/
|
|
2077
|
-
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
2078
|
-
/**
|
|
2079
|
-
* Circuit breaker configuration
|
|
2080
|
-
*/
|
|
2081
|
-
interface CircuitBreakerConfig {
|
|
2082
|
-
/** Number of failures before opening (default: 5) */
|
|
2083
|
-
failureThreshold?: number;
|
|
2084
|
-
/** Time window for failure counting in ms (default: 30000) */
|
|
2085
|
-
failureWindow?: number;
|
|
2086
|
-
/** Cool-down period before half-open in ms (default: 30000) */
|
|
2087
|
-
cooldownPeriod?: number;
|
|
2088
|
-
/** Number of successes in half-open to close (default: 1) */
|
|
2089
|
-
successThreshold?: number;
|
|
2090
|
-
/** Name for logging */
|
|
2091
|
-
name?: string;
|
|
2092
|
-
}
|
|
2093
|
-
/**
|
|
2094
|
-
* Circuit breaker events
|
|
2095
|
-
*/
|
|
2096
|
-
interface CircuitBreakerEvents {
|
|
2097
|
-
stateChange: (state: CircuitState, previousState: CircuitState) => void;
|
|
2098
|
-
failure: (error: Error, failureCount: number) => void;
|
|
2099
|
-
success: () => void;
|
|
2100
|
-
rejected: () => void;
|
|
2101
|
-
}
|
|
2102
|
-
/**
|
|
2103
|
-
* Error thrown when circuit is open
|
|
2104
|
-
*/
|
|
2105
|
-
declare class CircuitOpenError extends Error {
|
|
2106
|
-
constructor(message?: string);
|
|
2107
|
-
}
|
|
2108
|
-
/**
|
|
2109
|
-
* CircuitBreaker - Prevents cascade failures
|
|
2110
|
-
*
|
|
2111
|
-
* @example
|
|
2112
|
-
* ```typescript
|
|
2113
|
-
* const breaker = new CircuitBreaker({ failureThreshold: 5 });
|
|
2114
|
-
*
|
|
2115
|
-
* async function fetchData() {
|
|
2116
|
-
* return breaker.execute(async () => {
|
|
2117
|
-
* const response = await fetch('/api/data');
|
|
2118
|
-
* return response.json();
|
|
2119
|
-
* });
|
|
2120
|
-
* }
|
|
2121
|
-
* ```
|
|
2122
|
-
*/
|
|
2123
|
-
declare class CircuitBreaker {
|
|
2124
|
-
private state;
|
|
2125
|
-
private failures;
|
|
2126
|
-
private lastFailureTime;
|
|
2127
|
-
private halfOpenSuccesses;
|
|
2128
|
-
private config;
|
|
2129
|
-
private listeners;
|
|
2130
|
-
constructor(config?: CircuitBreakerConfig);
|
|
2131
|
-
/**
|
|
2132
|
-
* Get current circuit state
|
|
2133
|
-
*/
|
|
2134
|
-
getState(): CircuitState;
|
|
2135
|
-
/**
|
|
2136
|
-
* Check if circuit allows requests
|
|
2137
|
-
*/
|
|
2138
|
-
isAllowed(): boolean;
|
|
2139
|
-
/**
|
|
2140
|
-
* Execute a function through the circuit breaker
|
|
2141
|
-
*/
|
|
2142
|
-
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
2143
|
-
/**
|
|
2144
|
-
* Record a successful call
|
|
2145
|
-
*/
|
|
2146
|
-
recordSuccess(): void;
|
|
2147
|
-
/**
|
|
2148
|
-
* Record a failed call
|
|
2149
|
-
*/
|
|
2150
|
-
recordFailure(error: Error): void;
|
|
2151
|
-
/**
|
|
2152
|
-
* Manually reset the circuit breaker
|
|
2153
|
-
*/
|
|
2154
|
-
reset(): void;
|
|
2155
|
-
/**
|
|
2156
|
-
* Subscribe to events
|
|
2157
|
-
*/
|
|
2158
|
-
on<K extends keyof CircuitBreakerEvents>(event: K, listener: CircuitBreakerEvents[K]): () => void;
|
|
2159
|
-
/**
|
|
2160
|
-
* Get failure count
|
|
2161
|
-
*/
|
|
2162
|
-
getFailureCount(): number;
|
|
2163
|
-
/**
|
|
2164
|
-
* Get config
|
|
2165
|
-
*/
|
|
2166
|
-
getConfig(): Required<CircuitBreakerConfig>;
|
|
2167
|
-
private updateState;
|
|
2168
|
-
private transitionTo;
|
|
2169
|
-
private emit;
|
|
2170
|
-
}
|
|
2171
|
-
/**
|
|
2172
|
-
* Get or create a circuit breaker by name
|
|
2173
|
-
*/
|
|
2174
|
-
declare function getCircuitBreaker(name?: string, config?: CircuitBreakerConfig): CircuitBreaker;
|
|
2175
|
-
/**
|
|
2176
|
-
* Reset all circuit breakers
|
|
2177
|
-
*/
|
|
2178
|
-
declare function resetAllCircuitBreakers(): void;
|
|
2179
|
-
/**
|
|
2180
|
-
* Get global circuit breaker (default)
|
|
2181
|
-
*/
|
|
2182
|
-
declare function getGlobalCircuitBreaker(): CircuitBreaker;
|
|
2183
|
-
|
|
2184
2112
|
/**
|
|
2185
2113
|
* Default Transforms - Auto-transform API responses to SDK format
|
|
2186
2114
|
*
|
|
@@ -2280,6 +2208,14 @@ declare class RESTDataAdapter implements IDataSource {
|
|
|
2280
2208
|
* - share (optional)
|
|
2281
2209
|
*/
|
|
2282
2210
|
|
|
2211
|
+
/**
|
|
2212
|
+
* Report body input from SDK
|
|
2213
|
+
*/
|
|
2214
|
+
interface ReportBodyInput {
|
|
2215
|
+
contentId: string;
|
|
2216
|
+
reasonId: string;
|
|
2217
|
+
description?: string;
|
|
2218
|
+
}
|
|
2283
2219
|
/**
|
|
2284
2220
|
* REST Interaction Adapter configuration
|
|
2285
2221
|
*/
|
|
@@ -2287,6 +2223,10 @@ interface RESTInteractionAdapterConfig {
|
|
|
2287
2223
|
httpClient: HttpClient;
|
|
2288
2224
|
endpoints: RESTEndpointMap['interaction'];
|
|
2289
2225
|
logger?: ILogger;
|
|
2226
|
+
/** Custom transform for report reasons response */
|
|
2227
|
+
transformReportReasons?: (apiResponse: unknown) => ReportReasonItem[];
|
|
2228
|
+
/** Custom transform for report request body */
|
|
2229
|
+
transformReportBody?: (input: ReportBodyInput) => Record<string, unknown>;
|
|
2290
2230
|
}
|
|
2291
2231
|
/**
|
|
2292
2232
|
* REST Interaction Adapter
|
|
@@ -2295,6 +2235,8 @@ declare class RESTInteractionAdapter implements IInteraction {
|
|
|
2295
2235
|
private readonly httpClient;
|
|
2296
2236
|
private readonly endpoints;
|
|
2297
2237
|
private readonly logger?;
|
|
2238
|
+
private readonly customTransformReportReasons?;
|
|
2239
|
+
private readonly customTransformReportBody?;
|
|
2298
2240
|
constructor(config: RESTInteractionAdapterConfig);
|
|
2299
2241
|
/**
|
|
2300
2242
|
* Like a video
|
|
@@ -2332,6 +2274,38 @@ declare class RESTInteractionAdapter implements IInteraction {
|
|
|
2332
2274
|
* Share a video (optional tracking)
|
|
2333
2275
|
*/
|
|
2334
2276
|
share(videoId: string, platform?: string): Promise<void>;
|
|
2277
|
+
/**
|
|
2278
|
+
* Report content (video or image post)
|
|
2279
|
+
*
|
|
2280
|
+
* @param contentId - ID of the content to report
|
|
2281
|
+
* @param reason - Report reason code/ID
|
|
2282
|
+
* @param description - Optional additional description
|
|
2283
|
+
*/
|
|
2284
|
+
report(contentId: string, reason: string, description?: string): Promise<void>;
|
|
2285
|
+
/**
|
|
2286
|
+
* Get available report reasons
|
|
2287
|
+
*
|
|
2288
|
+
* @returns Array of report reasons, or empty array if not configured
|
|
2289
|
+
*/
|
|
2290
|
+
getReportReasons(): Promise<ReportReason[]>;
|
|
2291
|
+
/**
|
|
2292
|
+
* Mark content as "not interested"
|
|
2293
|
+
*
|
|
2294
|
+
* Used for recommendation algorithm feedback.
|
|
2295
|
+
* Content should be hidden from feed after this action.
|
|
2296
|
+
*
|
|
2297
|
+
* @param contentId - ID of the content (video or image post)
|
|
2298
|
+
*/
|
|
2299
|
+
notInterested(contentId: string): Promise<void>;
|
|
2300
|
+
/**
|
|
2301
|
+
* Default transform for API report reasons response to ReportReason[]
|
|
2302
|
+
*
|
|
2303
|
+
* Expected format: [{ id, label, description }]
|
|
2304
|
+
* Or wrapped: { data: [{ id, label, description }] }
|
|
2305
|
+
*
|
|
2306
|
+
* For custom API formats, use `transforms.reportReasons` in preset config.
|
|
2307
|
+
*/
|
|
2308
|
+
private transformReportReasons;
|
|
2335
2309
|
/**
|
|
2336
2310
|
* Transform API comment response to Comment type
|
|
2337
2311
|
*/
|
|
@@ -2701,4 +2675,4 @@ declare class RESTCommentAdapter implements ICommentAdapter {
|
|
|
2701
2675
|
private unwrapResponse;
|
|
2702
2676
|
}
|
|
2703
2677
|
|
|
2704
|
-
export { type AuthConfig, type AuthError, type BatchAnalyticsConfig, type BatchAnalyticsContext, type BatchAnalyticsDeviceType, type BatchAnalyticsEventData, type BatchAnalyticsEventTransformer, type BatchAnalyticsEventType, type BatchAnalyticsNetworkType, type BatchAnalyticsRequestBody, type BatchAnalyticsRequestEvent, type BrowserAdaptersConfig, BrowserPosterLoader, BrowserVideoLoader, type BrowserVideoLoaderConfig,
|
|
2678
|
+
export { type AuthConfig, type AuthError, type BatchAnalyticsConfig, type BatchAnalyticsContext, type BatchAnalyticsDeviceType, type BatchAnalyticsEventData, type BatchAnalyticsEventTransformer, type BatchAnalyticsEventType, type BatchAnalyticsNetworkType, type BatchAnalyticsRequestBody, type BatchAnalyticsRequestEvent, type BrowserAdaptersConfig, BrowserPosterLoader, BrowserVideoLoader, type BrowserVideoLoaderConfig, DEFAULT_REQUEST_CONFIG, DEFAULT_RETRY_CONFIG, type FieldMapConfig, type FullPresetAdapters, HttpClient, HttpError, LocalSessionStorageAdapter, LocalStorageAdapter, type LocalStorageConfig, MockAnalyticsAdapter, type MockAnalyticsAdapterOptions, MockCommentAdapter, MockDataAdapter, type MockDataAdapterOptions, MockInteractionAdapter, type MockInteractionAdapterOptions, MockLoggerAdapter, type MockLoggerAdapterOptions, MockNetworkAdapter, type MockNetworkAdapterOptions, MockPosterLoader, MockSessionStorageAdapter, type MockSessionStorageAdapterOptions, MockStorageAdapter, type MockStorageAdapterOptions, MockVideoLoader, type MockVideoLoaderOptions, type PresetAdapters, RESTAnalyticsAdapter, type RESTAnalyticsAdapterConfig, RESTCommentAdapter, type RESTCommentAdapterConfig, RESTDataAdapter, type RESTEndpointMap, RESTInteractionAdapter, type RESTPresetConfig, type RESTRequestConfig, RESTViewTrackingAdapter, type RESTViewTrackingAdapterConfig, type ResolvedTransforms, type RetryConfig, type TransformConfig, type ViewEventData, type ViewEventRequestBody, type ViewEventTransformer, type ViewTrackingConfig, WebNetworkAdapter, type WebNetworkConfig, createBrowserAdapters, createBrowserPosterLoader, createBrowserVideoLoader, createLocalStorageAdapter, createNoOpAnalyticsAdapter, createRESTAdapters, createSessionStorageAdapter, createTransforms, createWebNetworkAdapter, defaultFeedResponseTransform, defaultVideoItemTransform };
|
package/dist/index.js
CHANGED
|
@@ -1107,13 +1107,14 @@ var MockInteractionAdapter = class {
|
|
|
1107
1107
|
/**
|
|
1108
1108
|
* Report a video
|
|
1109
1109
|
*
|
|
1110
|
-
* @param
|
|
1111
|
-
* @param
|
|
1112
|
-
* @param
|
|
1110
|
+
* @param videoId - ID of the video to report
|
|
1111
|
+
* @param reason - Report reason code
|
|
1112
|
+
* @param description - Optional additional description
|
|
1113
1113
|
*/
|
|
1114
|
-
async report(
|
|
1114
|
+
async report(videoId, reason, description) {
|
|
1115
1115
|
await this.simulateDelay();
|
|
1116
1116
|
this.maybeThrowError();
|
|
1117
|
+
console.log("[MockInteractionAdapter] Report called (mock)", { videoId, reason, description });
|
|
1117
1118
|
}
|
|
1118
1119
|
// ═══════════════════════════════════════════════════════════════
|
|
1119
1120
|
// TESTING HELPERS (not part of IInteraction interface)
|
|
@@ -2638,6 +2639,8 @@ var RESTInteractionAdapter = class {
|
|
|
2638
2639
|
this.httpClient = config.httpClient;
|
|
2639
2640
|
this.endpoints = config.endpoints;
|
|
2640
2641
|
this.logger = config.logger;
|
|
2642
|
+
this.customTransformReportReasons = config.transformReportReasons;
|
|
2643
|
+
this.customTransformReportBody = config.transformReportBody;
|
|
2641
2644
|
}
|
|
2642
2645
|
/**
|
|
2643
2646
|
* Like a video
|
|
@@ -2762,6 +2765,107 @@ var RESTInteractionAdapter = class {
|
|
|
2762
2765
|
this.logger?.warn("[RESTInteractionAdapter] share tracking failed", { error });
|
|
2763
2766
|
}
|
|
2764
2767
|
}
|
|
2768
|
+
/**
|
|
2769
|
+
* Report content (video or image post)
|
|
2770
|
+
*
|
|
2771
|
+
* @param contentId - ID of the content to report
|
|
2772
|
+
* @param reason - Report reason code/ID
|
|
2773
|
+
* @param description - Optional additional description
|
|
2774
|
+
*/
|
|
2775
|
+
async report(contentId, reason, description) {
|
|
2776
|
+
if (!this.endpoints.report) {
|
|
2777
|
+
this.logger?.warn("[RESTInteractionAdapter] report endpoint not configured");
|
|
2778
|
+
return;
|
|
2779
|
+
}
|
|
2780
|
+
try {
|
|
2781
|
+
const body = this.customTransformReportBody ? this.customTransformReportBody({ contentId, reasonId: reason, description }) : { reason, description };
|
|
2782
|
+
this.logger?.debug("[RESTInteractionAdapter] Sending report", {
|
|
2783
|
+
path: this.endpoints.report,
|
|
2784
|
+
contentId,
|
|
2785
|
+
body
|
|
2786
|
+
});
|
|
2787
|
+
await this.httpClient.request({
|
|
2788
|
+
method: "POST",
|
|
2789
|
+
path: this.endpoints.report,
|
|
2790
|
+
pathParams: { id: contentId },
|
|
2791
|
+
body
|
|
2792
|
+
});
|
|
2793
|
+
this.logger?.debug("[RESTInteractionAdapter] Report sent successfully");
|
|
2794
|
+
} catch (error) {
|
|
2795
|
+
this.logger?.error("[RESTInteractionAdapter] report failed", error);
|
|
2796
|
+
throw error;
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
/**
|
|
2800
|
+
* Get available report reasons
|
|
2801
|
+
*
|
|
2802
|
+
* @returns Array of report reasons, or empty array if not configured
|
|
2803
|
+
*/
|
|
2804
|
+
async getReportReasons() {
|
|
2805
|
+
if (!this.endpoints.reportReasons) {
|
|
2806
|
+
this.logger?.debug("[RESTInteractionAdapter] reportReasons endpoint not configured");
|
|
2807
|
+
return [];
|
|
2808
|
+
}
|
|
2809
|
+
try {
|
|
2810
|
+
const response = await this.httpClient.request({
|
|
2811
|
+
method: "GET",
|
|
2812
|
+
path: this.endpoints.reportReasons
|
|
2813
|
+
});
|
|
2814
|
+
if (this.customTransformReportReasons) {
|
|
2815
|
+
return this.customTransformReportReasons(response);
|
|
2816
|
+
}
|
|
2817
|
+
return this.transformReportReasons(response);
|
|
2818
|
+
} catch (error) {
|
|
2819
|
+
this.logger?.error("[RESTInteractionAdapter] getReportReasons failed", error);
|
|
2820
|
+
return [];
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
/**
|
|
2824
|
+
* Mark content as "not interested"
|
|
2825
|
+
*
|
|
2826
|
+
* Used for recommendation algorithm feedback.
|
|
2827
|
+
* Content should be hidden from feed after this action.
|
|
2828
|
+
*
|
|
2829
|
+
* @param contentId - ID of the content (video or image post)
|
|
2830
|
+
*/
|
|
2831
|
+
async notInterested(contentId) {
|
|
2832
|
+
if (!this.endpoints.notInterested) {
|
|
2833
|
+
this.logger?.warn("[RESTInteractionAdapter] notInterested endpoint not configured");
|
|
2834
|
+
return;
|
|
2835
|
+
}
|
|
2836
|
+
try {
|
|
2837
|
+
await this.httpClient.request({
|
|
2838
|
+
method: "POST",
|
|
2839
|
+
path: this.endpoints.notInterested,
|
|
2840
|
+
pathParams: { id: contentId }
|
|
2841
|
+
});
|
|
2842
|
+
} catch (error) {
|
|
2843
|
+
this.logger?.error("[RESTInteractionAdapter] notInterested failed", error);
|
|
2844
|
+
throw error;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
/**
|
|
2848
|
+
* Default transform for API report reasons response to ReportReason[]
|
|
2849
|
+
*
|
|
2850
|
+
* Expected format: [{ id, label, description }]
|
|
2851
|
+
* Or wrapped: { data: [{ id, label, description }] }
|
|
2852
|
+
*
|
|
2853
|
+
* For custom API formats, use `transforms.reportReasons` in preset config.
|
|
2854
|
+
*/
|
|
2855
|
+
transformReportReasons(response) {
|
|
2856
|
+
const data = this.unwrapResponse(response);
|
|
2857
|
+
if (!Array.isArray(data)) {
|
|
2858
|
+
return [];
|
|
2859
|
+
}
|
|
2860
|
+
return data.map((item) => {
|
|
2861
|
+
const obj = item;
|
|
2862
|
+
return {
|
|
2863
|
+
id: String(obj.id ?? obj.reason_id ?? ""),
|
|
2864
|
+
label: String(obj.label ?? obj.name ?? obj.title ?? ""),
|
|
2865
|
+
description: obj.description
|
|
2866
|
+
};
|
|
2867
|
+
});
|
|
2868
|
+
}
|
|
2765
2869
|
/**
|
|
2766
2870
|
* Transform API comment response to Comment type
|
|
2767
2871
|
*/
|
|
@@ -3506,7 +3610,9 @@ function createRESTAdapters(config) {
|
|
|
3506
3610
|
const interaction = new RESTInteractionAdapter({
|
|
3507
3611
|
httpClient,
|
|
3508
3612
|
endpoints: endpoints.interaction,
|
|
3509
|
-
logger
|
|
3613
|
+
logger,
|
|
3614
|
+
transformReportReasons: transforms?.reportReasons,
|
|
3615
|
+
transformReportBody: transforms?.reportBody
|
|
3510
3616
|
});
|
|
3511
3617
|
let analytics;
|
|
3512
3618
|
if (endpoints.viewTracking) {
|
|
@@ -4174,170 +4280,4 @@ function createBrowserAdapters(config) {
|
|
|
4174
4280
|
};
|
|
4175
4281
|
}
|
|
4176
4282
|
|
|
4177
|
-
|
|
4178
|
-
var DEFAULT_CONFIG3 = {
|
|
4179
|
-
failureThreshold: 5,
|
|
4180
|
-
failureWindow: 3e4,
|
|
4181
|
-
cooldownPeriod: 3e4,
|
|
4182
|
-
successThreshold: 1,
|
|
4183
|
-
name: "default"
|
|
4184
|
-
};
|
|
4185
|
-
var CircuitOpenError = class extends Error {
|
|
4186
|
-
constructor(message = "Circuit breaker is open") {
|
|
4187
|
-
super(message);
|
|
4188
|
-
this.name = "CircuitOpenError";
|
|
4189
|
-
}
|
|
4190
|
-
};
|
|
4191
|
-
var CircuitBreaker = class {
|
|
4192
|
-
constructor(config = {}) {
|
|
4193
|
-
this.state = "closed";
|
|
4194
|
-
this.failures = [];
|
|
4195
|
-
this.lastFailureTime = 0;
|
|
4196
|
-
this.halfOpenSuccesses = 0;
|
|
4197
|
-
this.listeners = /* @__PURE__ */ new Map();
|
|
4198
|
-
this.config = { ...DEFAULT_CONFIG3, ...config };
|
|
4199
|
-
}
|
|
4200
|
-
/**
|
|
4201
|
-
* Get current circuit state
|
|
4202
|
-
*/
|
|
4203
|
-
getState() {
|
|
4204
|
-
this.updateState();
|
|
4205
|
-
return this.state;
|
|
4206
|
-
}
|
|
4207
|
-
/**
|
|
4208
|
-
* Check if circuit allows requests
|
|
4209
|
-
*/
|
|
4210
|
-
isAllowed() {
|
|
4211
|
-
this.updateState();
|
|
4212
|
-
return this.state !== "open";
|
|
4213
|
-
}
|
|
4214
|
-
/**
|
|
4215
|
-
* Execute a function through the circuit breaker
|
|
4216
|
-
*/
|
|
4217
|
-
async execute(fn) {
|
|
4218
|
-
this.updateState();
|
|
4219
|
-
if (this.state === "open") {
|
|
4220
|
-
this.emit("rejected");
|
|
4221
|
-
throw new CircuitOpenError(`Circuit breaker [${this.config.name}] is open`);
|
|
4222
|
-
}
|
|
4223
|
-
try {
|
|
4224
|
-
const result = await fn();
|
|
4225
|
-
this.recordSuccess();
|
|
4226
|
-
return result;
|
|
4227
|
-
} catch (error) {
|
|
4228
|
-
this.recordFailure(error);
|
|
4229
|
-
throw error;
|
|
4230
|
-
}
|
|
4231
|
-
}
|
|
4232
|
-
/**
|
|
4233
|
-
* Record a successful call
|
|
4234
|
-
*/
|
|
4235
|
-
recordSuccess() {
|
|
4236
|
-
if (this.state === "half-open") {
|
|
4237
|
-
this.halfOpenSuccesses++;
|
|
4238
|
-
if (this.halfOpenSuccesses >= this.config.successThreshold) {
|
|
4239
|
-
this.transitionTo("closed");
|
|
4240
|
-
this.failures = [];
|
|
4241
|
-
this.halfOpenSuccesses = 0;
|
|
4242
|
-
}
|
|
4243
|
-
}
|
|
4244
|
-
this.emit("success");
|
|
4245
|
-
}
|
|
4246
|
-
/**
|
|
4247
|
-
* Record a failed call
|
|
4248
|
-
*/
|
|
4249
|
-
recordFailure(error) {
|
|
4250
|
-
const now = Date.now();
|
|
4251
|
-
this.failures.push(now);
|
|
4252
|
-
this.lastFailureTime = now;
|
|
4253
|
-
const cutoff = now - this.config.failureWindow;
|
|
4254
|
-
this.failures = this.failures.filter((t) => t > cutoff);
|
|
4255
|
-
this.emit("failure", error, this.failures.length);
|
|
4256
|
-
if (this.state === "half-open") {
|
|
4257
|
-
this.transitionTo("open");
|
|
4258
|
-
this.halfOpenSuccesses = 0;
|
|
4259
|
-
} else if (this.state === "closed" && this.failures.length >= this.config.failureThreshold) {
|
|
4260
|
-
this.transitionTo("open");
|
|
4261
|
-
}
|
|
4262
|
-
}
|
|
4263
|
-
/**
|
|
4264
|
-
* Manually reset the circuit breaker
|
|
4265
|
-
*/
|
|
4266
|
-
reset() {
|
|
4267
|
-
this.failures = [];
|
|
4268
|
-
this.halfOpenSuccesses = 0;
|
|
4269
|
-
this.transitionTo("closed");
|
|
4270
|
-
}
|
|
4271
|
-
/**
|
|
4272
|
-
* Subscribe to events
|
|
4273
|
-
*/
|
|
4274
|
-
on(event, listener) {
|
|
4275
|
-
if (!this.listeners.has(event)) {
|
|
4276
|
-
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
4277
|
-
}
|
|
4278
|
-
const listeners = this.listeners.get(event);
|
|
4279
|
-
if (listeners) {
|
|
4280
|
-
listeners.add(listener);
|
|
4281
|
-
}
|
|
4282
|
-
return () => {
|
|
4283
|
-
const listeners2 = this.listeners.get(event);
|
|
4284
|
-
if (listeners2) {
|
|
4285
|
-
listeners2.delete(listener);
|
|
4286
|
-
}
|
|
4287
|
-
};
|
|
4288
|
-
}
|
|
4289
|
-
/**
|
|
4290
|
-
* Get failure count
|
|
4291
|
-
*/
|
|
4292
|
-
getFailureCount() {
|
|
4293
|
-
return this.failures.length;
|
|
4294
|
-
}
|
|
4295
|
-
/**
|
|
4296
|
-
* Get config
|
|
4297
|
-
*/
|
|
4298
|
-
getConfig() {
|
|
4299
|
-
return { ...this.config };
|
|
4300
|
-
}
|
|
4301
|
-
updateState() {
|
|
4302
|
-
if (this.state === "open") {
|
|
4303
|
-
const timeSinceLastFailure = Date.now() - this.lastFailureTime;
|
|
4304
|
-
if (timeSinceLastFailure >= this.config.cooldownPeriod) {
|
|
4305
|
-
this.transitionTo("half-open");
|
|
4306
|
-
this.halfOpenSuccesses = 0;
|
|
4307
|
-
}
|
|
4308
|
-
}
|
|
4309
|
-
}
|
|
4310
|
-
transitionTo(newState) {
|
|
4311
|
-
if (this.state === newState) return;
|
|
4312
|
-
const previousState = this.state;
|
|
4313
|
-
this.state = newState;
|
|
4314
|
-
this.emit("stateChange", newState, previousState);
|
|
4315
|
-
}
|
|
4316
|
-
emit(event, ...args) {
|
|
4317
|
-
const listeners = this.listeners.get(event);
|
|
4318
|
-
if (listeners) {
|
|
4319
|
-
for (const listener of listeners) {
|
|
4320
|
-
listener(...args);
|
|
4321
|
-
}
|
|
4322
|
-
}
|
|
4323
|
-
}
|
|
4324
|
-
};
|
|
4325
|
-
var circuitBreakers = /* @__PURE__ */ new Map();
|
|
4326
|
-
function getCircuitBreaker(name = "default", config) {
|
|
4327
|
-
let breaker = circuitBreakers.get(name);
|
|
4328
|
-
if (!breaker) {
|
|
4329
|
-
breaker = new CircuitBreaker({ ...config, name });
|
|
4330
|
-
circuitBreakers.set(name, breaker);
|
|
4331
|
-
}
|
|
4332
|
-
return breaker;
|
|
4333
|
-
}
|
|
4334
|
-
function resetAllCircuitBreakers() {
|
|
4335
|
-
for (const breaker of circuitBreakers.values()) {
|
|
4336
|
-
breaker.reset();
|
|
4337
|
-
}
|
|
4338
|
-
}
|
|
4339
|
-
function getGlobalCircuitBreaker() {
|
|
4340
|
-
return getCircuitBreaker("global");
|
|
4341
|
-
}
|
|
4342
|
-
|
|
4343
|
-
export { BrowserPosterLoader, BrowserVideoLoader, CircuitBreaker, CircuitOpenError, DEFAULT_REQUEST_CONFIG, DEFAULT_RETRY_CONFIG, HttpClient, HttpError, LocalSessionStorageAdapter, LocalStorageAdapter, MockAnalyticsAdapter, MockCommentAdapter, MockDataAdapter, MockInteractionAdapter, MockLoggerAdapter, MockNetworkAdapter, MockPosterLoader, MockSessionStorageAdapter, MockStorageAdapter, MockVideoLoader, RESTAnalyticsAdapter, RESTCommentAdapter, RESTDataAdapter, RESTInteractionAdapter, RESTViewTrackingAdapter, WebNetworkAdapter, createBrowserAdapters, createBrowserPosterLoader, createBrowserVideoLoader, createLocalStorageAdapter, createNoOpAnalyticsAdapter, createRESTAdapters, createSessionStorageAdapter, createTransforms, createWebNetworkAdapter, defaultFeedResponseTransform, defaultVideoItemTransform, getCircuitBreaker, getGlobalCircuitBreaker, resetAllCircuitBreakers };
|
|
4283
|
+
export { BrowserPosterLoader, BrowserVideoLoader, DEFAULT_REQUEST_CONFIG, DEFAULT_RETRY_CONFIG, HttpClient, HttpError, LocalSessionStorageAdapter, LocalStorageAdapter, MockAnalyticsAdapter, MockCommentAdapter, MockDataAdapter, MockInteractionAdapter, MockLoggerAdapter, MockNetworkAdapter, MockPosterLoader, MockSessionStorageAdapter, MockStorageAdapter, MockVideoLoader, RESTAnalyticsAdapter, RESTCommentAdapter, RESTDataAdapter, RESTInteractionAdapter, RESTViewTrackingAdapter, WebNetworkAdapter, createBrowserAdapters, createBrowserPosterLoader, createBrowserVideoLoader, createLocalStorageAdapter, createNoOpAnalyticsAdapter, createRESTAdapters, createSessionStorageAdapter, createTransforms, createWebNetworkAdapter, defaultFeedResponseTransform, defaultVideoItemTransform };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xhub-short/adapters",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"version": "0.1.0-beta.
|
|
4
|
+
"version": "0.1.0-beta.11",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"dist"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@xhub-short/contracts": "0.1.0-beta.
|
|
23
|
+
"@xhub-short/contracts": "0.1.0-beta.11"
|
|
24
24
|
},
|
|
25
25
|
"optionalDependencies": {
|
|
26
26
|
"hls.js": "^1.5.0"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"typescript": "^5.7.0",
|
|
31
31
|
"vitest": "^2.1.0",
|
|
32
32
|
"@xhub-short/tsconfig": "0.0.0",
|
|
33
|
-
"@xhub-short/vitest-config": "0.0
|
|
33
|
+
"@xhub-short/vitest-config": "0.1.0-beta.10"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsup",
|