@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.
Files changed (3) hide show
  1. package/dist/index.d.ts +101 -127
  2. package/dist/index.js +112 -172
  3. 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 _videoId - ID of the video to report
450
- * @param _reason - Report reason code
451
- * @param _description - Optional additional description
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(_videoId: string, _reason: string, _description?: string): Promise<void>;
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, CircuitBreaker, type CircuitBreakerConfig, type CircuitBreakerEvents, CircuitOpenError, type CircuitState, 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, getCircuitBreaker, getGlobalCircuitBreaker, resetAllCircuitBreakers };
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 _videoId - ID of the video to report
1111
- * @param _reason - Report reason code
1112
- * @param _description - Optional additional description
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(_videoId, _reason, _description) {
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
- // src/preset/http/CircuitBreaker.ts
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.10",
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.10"
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.1-beta.9"
33
+ "@xhub-short/vitest-config": "0.1.0-beta.10"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "tsup",