@seekora-ai/search-sdk 0.2.3 → 0.2.4

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.
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Analytics V3 Query API client
3
+ * Calls POST /api/v1/analytics/v3/* (and GET for journey) with JWT auth.
4
+ * Use from backend or admin apps that have a JWT; not for browser public SDK usage.
5
+ */
6
+ import type { GenericResponse, SearchMetricsRequest, SearchMetrics, TopQueriesRequest, QueryMetric, ZeroResultQueriesRequest, ZeroResultQuery, ClickMetricsRequest, ClickMetrics, CTRByPositionRequest, PositionCTR, ConversionMetricsRequest, ConversionMetrics, RevenueAttributionRequest, RevenueAttribution, RecommendationMetricsRequest, RecommendationMetrics, RecommendationCTRRequest, RecommendationCTR, FunnelRequest, FunnelData, JourneyEvent } from './analytics-v3-types';
7
+ export type { GenericResponse } from './analytics-v3-types';
8
+ export interface AnalyticsV3ApiConfig {
9
+ /** Base URL of the API (e.g. https://api.seekora.ai) */
10
+ baseUrl: string;
11
+ /** Returns headers to attach (e.g. Authorization: Bearer <jwt>) */
12
+ getAuthHeaders: () => Promise<HeadersInit> | HeadersInit;
13
+ /** Optional fetch implementation (defaults to global fetch) */
14
+ fetch?: typeof fetch;
15
+ }
16
+ /**
17
+ * Client for Analytics V3 query endpoints.
18
+ * All POST endpoints expect JSON body with start_date, end_date (YYYY-MM-DD) and optional filters.
19
+ */
20
+ export declare class AnalyticsV3Api {
21
+ private readonly config;
22
+ constructor(config: AnalyticsV3ApiConfig);
23
+ private post;
24
+ private get;
25
+ /** POST /api/v1/analytics/v3/search/metrics */
26
+ getSearchMetrics(req: SearchMetricsRequest): Promise<GenericResponse<SearchMetrics>>;
27
+ /** POST /api/v1/analytics/v3/search/top-queries */
28
+ getTopQueries(req: TopQueriesRequest): Promise<GenericResponse<QueryMetric[]>>;
29
+ /** POST /api/v1/analytics/v3/search/zero-results */
30
+ getZeroResultQueries(req: ZeroResultQueriesRequest): Promise<GenericResponse<ZeroResultQuery[]>>;
31
+ /** POST /api/v1/analytics/v3/clicks/metrics */
32
+ getClickMetrics(req: ClickMetricsRequest): Promise<GenericResponse<ClickMetrics>>;
33
+ /** POST /api/v1/analytics/v3/clicks/ctr */
34
+ getCTRByPosition(req: CTRByPositionRequest): Promise<GenericResponse<PositionCTR[]>>;
35
+ /** POST /api/v1/analytics/v3/conversions/metrics */
36
+ getConversionMetrics(req: ConversionMetricsRequest): Promise<GenericResponse<ConversionMetrics>>;
37
+ /** POST /api/v1/analytics/v3/conversions/revenue */
38
+ getRevenueAttribution(req: RevenueAttributionRequest): Promise<GenericResponse<RevenueAttribution>>;
39
+ /** POST /api/v1/analytics/v3/recommendations/metrics */
40
+ getRecommendationMetrics(req: RecommendationMetricsRequest): Promise<GenericResponse<RecommendationMetrics>>;
41
+ /** POST /api/v1/analytics/v3/recommendations/ctr */
42
+ getRecommendationCTR(req: RecommendationCTRRequest): Promise<GenericResponse<RecommendationCTR[]>>;
43
+ /** POST /api/v1/analytics/v3/funnel */
44
+ getFunnelAnalysis(req: FunnelRequest): Promise<GenericResponse<FunnelData>>;
45
+ /** GET /api/v1/analytics/v3/journey/:userKey */
46
+ getUserJourney(userKey: string, limit?: number): Promise<GenericResponse<JourneyEvent[]>>;
47
+ }
48
+ /**
49
+ * Create an Analytics V3 API client.
50
+ * Requires baseUrl and a way to provide JWT headers (e.g. from your auth provider).
51
+ */
52
+ export declare function createAnalyticsV3Api(config: AnalyticsV3ApiConfig): AnalyticsV3Api;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ /**
3
+ * Analytics V3 Query API client
4
+ * Calls POST /api/v1/analytics/v3/* (and GET for journey) with JWT auth.
5
+ * Use from backend or admin apps that have a JWT; not for browser public SDK usage.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.AnalyticsV3Api = void 0;
9
+ exports.createAnalyticsV3Api = createAnalyticsV3Api;
10
+ const DEFAULT_PAGE_SIZE = 100;
11
+ const MAX_PAGE_SIZE = 1000;
12
+ function resolveAuthHeaders(getAuthHeaders) {
13
+ const v = getAuthHeaders();
14
+ return Promise.resolve(v);
15
+ }
16
+ async function request(config, method, path, body) {
17
+ const url = `${config.baseUrl.replace(/\/$/, '')}${path}`;
18
+ const headers = {
19
+ 'Content-Type': 'application/json',
20
+ ...(await resolveAuthHeaders(config.getAuthHeaders)),
21
+ };
22
+ const options = { method, headers };
23
+ if (body !== undefined && method === 'POST') {
24
+ options.body = JSON.stringify(body);
25
+ }
26
+ const fetchFn = config.fetch ?? (typeof fetch !== 'undefined' ? fetch : undefined);
27
+ if (!fetchFn) {
28
+ throw new Error('AnalyticsV3Api: fetch is not available. Provide config.fetch or use an environment with fetch.');
29
+ }
30
+ const res = await fetchFn(url, options);
31
+ const data = await res.json();
32
+ if (!res.ok) {
33
+ throw new Error(data?.message ?? `Analytics V3 API error: ${res.status}`);
34
+ }
35
+ return data;
36
+ }
37
+ /**
38
+ * Client for Analytics V3 query endpoints.
39
+ * All POST endpoints expect JSON body with start_date, end_date (YYYY-MM-DD) and optional filters.
40
+ */
41
+ class AnalyticsV3Api {
42
+ constructor(config) {
43
+ this.config = config;
44
+ }
45
+ post(path, body) {
46
+ return request(this.config, 'POST', path, body);
47
+ }
48
+ get(path) {
49
+ return request(this.config, 'GET', path);
50
+ }
51
+ /** POST /api/v1/analytics/v3/search/metrics */
52
+ getSearchMetrics(req) {
53
+ return this.post('/api/v1/analytics/v3/search/metrics', req);
54
+ }
55
+ /** POST /api/v1/analytics/v3/search/top-queries */
56
+ getTopQueries(req) {
57
+ return this.post('/api/v1/analytics/v3/search/top-queries', req);
58
+ }
59
+ /** POST /api/v1/analytics/v3/search/zero-results */
60
+ getZeroResultQueries(req) {
61
+ return this.post('/api/v1/analytics/v3/search/zero-results', req);
62
+ }
63
+ /** POST /api/v1/analytics/v3/clicks/metrics */
64
+ getClickMetrics(req) {
65
+ return this.post('/api/v1/analytics/v3/clicks/metrics', req);
66
+ }
67
+ /** POST /api/v1/analytics/v3/clicks/ctr */
68
+ getCTRByPosition(req) {
69
+ return this.post('/api/v1/analytics/v3/clicks/ctr', req);
70
+ }
71
+ /** POST /api/v1/analytics/v3/conversions/metrics */
72
+ getConversionMetrics(req) {
73
+ return this.post('/api/v1/analytics/v3/conversions/metrics', req);
74
+ }
75
+ /** POST /api/v1/analytics/v3/conversions/revenue */
76
+ getRevenueAttribution(req) {
77
+ return this.post('/api/v1/analytics/v3/conversions/revenue', req);
78
+ }
79
+ /** POST /api/v1/analytics/v3/recommendations/metrics */
80
+ getRecommendationMetrics(req) {
81
+ return this.post('/api/v1/analytics/v3/recommendations/metrics', req);
82
+ }
83
+ /** POST /api/v1/analytics/v3/recommendations/ctr */
84
+ getRecommendationCTR(req) {
85
+ return this.post('/api/v1/analytics/v3/recommendations/ctr', req);
86
+ }
87
+ /** POST /api/v1/analytics/v3/funnel */
88
+ getFunnelAnalysis(req) {
89
+ return this.post('/api/v1/analytics/v3/funnel', req);
90
+ }
91
+ /** GET /api/v1/analytics/v3/journey/:userKey */
92
+ getUserJourney(userKey, limit) {
93
+ const q = limit != null ? `?limit=${Math.min(limit, MAX_PAGE_SIZE)}` : '';
94
+ return this.get(`/api/v1/analytics/v3/journey/${encodeURIComponent(userKey)}${q}`);
95
+ }
96
+ }
97
+ exports.AnalyticsV3Api = AnalyticsV3Api;
98
+ /**
99
+ * Create an Analytics V3 API client.
100
+ * Requires baseUrl and a way to provide JWT headers (e.g. from your auth provider).
101
+ */
102
+ function createAnalyticsV3Api(config) {
103
+ return new AnalyticsV3Api(config);
104
+ }
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Analytics V3 API types
3
+ * Matches the Go backend v3 analytics structure: routes, requests, responses, and data types.
4
+ * Base path: POST /api/v1/analytics/v3/*
5
+ * Auth: JWT (Bearer).
6
+ */
7
+ export interface GenericResponse<T> {
8
+ status: number;
9
+ message: string;
10
+ data?: T;
11
+ }
12
+ export interface AnalyticsV3BaseRequest {
13
+ start_date: string;
14
+ end_date: string;
15
+ xstoreid?: string;
16
+ page?: number;
17
+ page_size?: number;
18
+ granularity?: 'hour' | 'day' | 'week' | 'month';
19
+ }
20
+ export interface TimeSeriesPoint {
21
+ timestamp: string;
22
+ value: number;
23
+ count?: number;
24
+ }
25
+ export interface SearchMetricsRequest extends AnalyticsV3BaseRequest {
26
+ surface?: string;
27
+ }
28
+ export interface SearchMetrics {
29
+ total_searches: number;
30
+ unique_users: number;
31
+ unique_sessions: number;
32
+ total_results: number;
33
+ zero_result_searches: number;
34
+ zero_result_rate: number;
35
+ avg_results_per_search: number;
36
+ avg_latency_ms: number;
37
+ p95_latency_ms: number;
38
+ p99_latency_ms: number;
39
+ time_series?: TimeSeriesPoint[];
40
+ }
41
+ export interface TopQueriesRequest extends AnalyticsV3BaseRequest {
42
+ limit?: number;
43
+ sort_by?: string;
44
+ min_count?: number;
45
+ surface?: string;
46
+ }
47
+ export interface QueryMetric {
48
+ query: string;
49
+ normalized_query?: string;
50
+ search_count: number;
51
+ unique_users: number;
52
+ avg_results: number;
53
+ zero_result_count: number;
54
+ click_count?: number;
55
+ conversion_count?: number;
56
+ ctr?: number;
57
+ conversion_rate?: number;
58
+ avg_latency_ms: number;
59
+ }
60
+ export interface ZeroResultQueriesRequest extends AnalyticsV3BaseRequest {
61
+ limit?: number;
62
+ min_count?: number;
63
+ }
64
+ export interface ZeroResultQuery {
65
+ query: string;
66
+ count: number;
67
+ unique_users: number;
68
+ last_seen: string;
69
+ }
70
+ export interface ClickMetricsRequest extends AnalyticsV3BaseRequest {
71
+ click_subtype?: string;
72
+ surface?: string;
73
+ }
74
+ export interface ClickMetrics {
75
+ total_clicks: number;
76
+ unique_users: number;
77
+ unique_sessions: number;
78
+ unique_items: number;
79
+ attributed_clicks: number;
80
+ attribution_rate: number;
81
+ avg_position: number;
82
+ clicks_by_subtype?: Record<string, number>;
83
+ time_series?: TimeSeriesPoint[];
84
+ }
85
+ export interface CTRByPositionRequest extends AnalyticsV3BaseRequest {
86
+ max_position?: number;
87
+ surface?: string;
88
+ }
89
+ export interface PositionCTR {
90
+ position: number;
91
+ impressions: number;
92
+ clicks: number;
93
+ ctr: number;
94
+ }
95
+ export interface ConversionMetricsRequest extends AnalyticsV3BaseRequest {
96
+ conversion_type?: string;
97
+ }
98
+ export interface ConversionMetrics {
99
+ total_conversions: number;
100
+ unique_users: number;
101
+ total_revenue: number;
102
+ avg_order_value: number;
103
+ attributed_conversions: number;
104
+ attribution_rate: number;
105
+ unique_orders: number;
106
+ total_quantity: number;
107
+ conversions_by_type?: Record<string, number>;
108
+ time_series?: TimeSeriesPoint[];
109
+ }
110
+ export interface RevenueAttributionRequest extends AnalyticsV3BaseRequest {
111
+ attributed_only?: boolean;
112
+ }
113
+ export interface RevenueAttribution {
114
+ total_revenue: number;
115
+ attributed_revenue: number;
116
+ search_attributed_revenue: number;
117
+ reco_attributed_revenue: number;
118
+ attribution_rate: number;
119
+ avg_order_value: number;
120
+ time_series?: TimeSeriesPoint[];
121
+ }
122
+ export interface RecommendationMetricsRequest extends AnalyticsV3BaseRequest {
123
+ recommendation_type?: string;
124
+ surface?: string;
125
+ }
126
+ export interface RecommendationMetrics {
127
+ total_requests: number;
128
+ unique_users: number;
129
+ total_recommendations: number;
130
+ avg_recs_per_request: number;
131
+ fallback_rate: number;
132
+ avg_latency_ms: number;
133
+ p95_latency_ms: number;
134
+ requests_by_type?: Record<string, number>;
135
+ requests_by_surface?: Record<string, number>;
136
+ time_series?: TimeSeriesPoint[];
137
+ }
138
+ export interface RecommendationCTRRequest extends AnalyticsV3BaseRequest {
139
+ recommendation_type?: string;
140
+ surface?: string;
141
+ max_position?: number;
142
+ }
143
+ export interface RecommendationCTR {
144
+ recommendation_type: string;
145
+ surface?: string;
146
+ impressions: number;
147
+ clicks: number;
148
+ conversions: number;
149
+ ctr: number;
150
+ conversion_rate: number;
151
+ }
152
+ export interface FunnelRequest extends AnalyticsV3BaseRequest {
153
+ funnel_steps?: string[];
154
+ }
155
+ export interface FunnelStepResult {
156
+ name: string;
157
+ count: number;
158
+ unique_users: number;
159
+ dropoff_rate: number;
160
+ conversion_rate_from_previous: number;
161
+ }
162
+ export interface FunnelData {
163
+ steps: FunnelStepResult[];
164
+ overall_conversion_rate: number;
165
+ }
166
+ export interface JourneyEvent {
167
+ event_id: string;
168
+ event_type: string;
169
+ event_ts: string;
170
+ session_id: string;
171
+ search_id?: string;
172
+ query?: string;
173
+ item_id?: string;
174
+ position?: number;
175
+ value?: number;
176
+ is_attributed: boolean;
177
+ surface?: string;
178
+ }
179
+ export interface AnalyticsV3EventPayload {
180
+ event_id?: string;
181
+ event_ts?: string;
182
+ event_name?: string;
183
+ correlation_id?: string;
184
+ orgcode?: string;
185
+ xstoreid?: string;
186
+ user_id?: string;
187
+ anonymous_id?: string;
188
+ session_id?: string;
189
+ journey_id?: string;
190
+ request_id?: string;
191
+ search_id?: string;
192
+ suggestion_id?: string;
193
+ recommendation_id?: string;
194
+ query?: string;
195
+ results_count?: number;
196
+ latency_ms?: number;
197
+ normalized_query?: string;
198
+ clicked_item_id?: string;
199
+ click_type?: string;
200
+ clicked_value?: string;
201
+ original_query?: string;
202
+ position?: number;
203
+ section?: string;
204
+ tab_id?: string;
205
+ tab_label?: string;
206
+ tab_filter?: string;
207
+ suggestion_type?: string;
208
+ suggestion_source?: string;
209
+ suggestion_popularity?: number;
210
+ total_suggestions?: number;
211
+ is_attributed?: number;
212
+ suggestions_count?: number;
213
+ products_count?: number;
214
+ categories_count?: number;
215
+ brands_count?: number;
216
+ trending_count?: number;
217
+ recent_count?: number;
218
+ has_dropdown?: number;
219
+ has_filtered_tabs?: number;
220
+ impression_duration_ms?: number;
221
+ ip?: string;
222
+ device_type?: string;
223
+ is_mobile?: number;
224
+ is_tablet?: number;
225
+ is_touch_device?: number;
226
+ platform?: string;
227
+ device_fingerprint?: string;
228
+ screen_width?: number;
229
+ screen_height?: number;
230
+ viewport_width?: number;
231
+ viewport_height?: number;
232
+ color_depth?: number;
233
+ pixel_ratio?: number;
234
+ browser_name?: string;
235
+ browser_version?: string;
236
+ browser_language?: string;
237
+ timezone?: string;
238
+ timezone_offset?: number;
239
+ page_url?: string;
240
+ page_path?: string;
241
+ page_title?: string;
242
+ page_referrer?: string;
243
+ country?: string;
244
+ country_code?: string;
245
+ region?: string;
246
+ city?: string;
247
+ utm_source?: string;
248
+ utm_medium?: string;
249
+ utm_campaign?: string;
250
+ utm_term?: string;
251
+ utm_content?: string;
252
+ value?: number;
253
+ currency?: string;
254
+ analytics_tags?: string[];
255
+ custom_json?: string;
256
+ metadata?: Record<string, unknown>;
257
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Analytics V3 API types
4
+ * Matches the Go backend v3 analytics structure: routes, requests, responses, and data types.
5
+ * Base path: POST /api/v1/analytics/v3/*
6
+ * Auth: JWT (Bearer).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/client.d.ts CHANGED
@@ -72,77 +72,23 @@ export interface SearchContext {
72
72
  anonId: string;
73
73
  /** Session ID */
74
74
  sessionId: string;
75
+ /** V3: organization code (optional, for analytics v3 backend) */
76
+ orgcode?: string;
77
+ /** V3: store identifier (optional, for analytics v3 backend) */
78
+ xstoreId?: string;
75
79
  }
76
80
  /**
77
- * Extended event payload with correlation_id, search_id, and browser context
78
- * (per identifier spec requirements)
79
- *
80
- * This extends the base DataTypesEventPayload to include:
81
- * - correlation_id: Required for linking events to search journeys
82
- * - search_id: Optional, but should be included when available
83
- * - Browser context: Screen, viewport, timezone, UTM, etc.
84
- *
85
- * Both correlation_id and search_id are set at the top level (not just in metadata) per spec.
81
+ * Extended event payload with correlation_id, search_id, browser context,
82
+ * and legacy anon_id for backward compatibility. DataTypesEventPayload (generated)
83
+ * already includes V3 fields: event_ts, anonymous_id, orgcode, xstoreid, is_mobile (0|1), etc.
86
84
  */
87
85
  export interface ExtendedEventPayload extends DataTypesEventPayload {
86
+ /** Legacy anonymous user ID (sent alongside anonymous_id for backward compat) */
87
+ anon_id?: string;
88
88
  /** Correlation ID for linking events to search journeys */
89
89
  correlation_id?: string;
90
90
  /** Search ID at top level (also in metadata for backward compat) */
91
91
  search_id?: string;
92
- /** Screen width in pixels */
93
- screen_width?: number;
94
- /** Screen height in pixels */
95
- screen_height?: number;
96
- /** Viewport width in pixels */
97
- viewport_width?: number;
98
- /** Viewport height in pixels */
99
- viewport_height?: number;
100
- /** Color depth */
101
- color_depth?: number;
102
- /** Device pixel ratio */
103
- pixel_ratio?: number;
104
- /** Device fingerprint (if enabled) */
105
- device_fingerprint?: string;
106
- /** Browser name (chrome, firefox, safari, etc.) */
107
- browser_name?: string;
108
- /** Browser version */
109
- browser_version?: string;
110
- /** Browser language */
111
- browser_language?: string;
112
- /** User timezone (e.g., "America/New_York") */
113
- timezone?: string;
114
- /** Timezone offset in minutes */
115
- timezone_offset?: number;
116
- /** Current page URL */
117
- page_url?: string;
118
- /** Current page path */
119
- page_path?: string;
120
- /** Current page title */
121
- page_title?: string;
122
- /** Page referrer URL */
123
- page_referrer?: string;
124
- /** UTM source parameter */
125
- utm_source?: string;
126
- /** UTM medium parameter */
127
- utm_medium?: string;
128
- /** UTM campaign parameter */
129
- utm_campaign?: string;
130
- /** UTM term parameter */
131
- utm_term?: string;
132
- /** UTM content parameter */
133
- utm_content?: string;
134
- /** Connection type (wifi, cellular, etc.) */
135
- connection_type?: string;
136
- /** Effective connection type (4g, 3g, 2g, slow-2g) */
137
- connection_effective_type?: string;
138
- /** Platform (windows, macos, linux, android, ios) */
139
- platform?: string;
140
- /** Is mobile device */
141
- is_mobile?: boolean;
142
- /** Is tablet device */
143
- is_tablet?: boolean;
144
- /** Is touch-capable device */
145
- is_touch_device?: boolean;
146
92
  }
147
93
  export interface SearchOptions {
148
94
  q: string;
package/dist/client.js CHANGED
@@ -1039,21 +1039,27 @@ class SeekoraClient {
1039
1039
  * Ensures user_id or anon_id is present, and sets correlation_id/search_id at top level
1040
1040
  */
1041
1041
  buildEventPayload(event, context) {
1042
+ const anonId = event.anonymous_id ?? event.anon_id ?? context?.anonId ?? this.anonId;
1042
1043
  const payload = {
1043
1044
  ...event,
1044
1045
  // Set identifiers from context or fall back to client defaults
1045
1046
  user_id: event.user_id || context?.userId || this.userId,
1046
- anon_id: event.anon_id || context?.anonId || this.anonId,
1047
+ anon_id: anonId,
1047
1048
  session_id: event.session_id || context?.sessionId || this.sessionId,
1048
1049
  // Set correlation_id at top level if provided (per identifier spec)
1049
1050
  correlation_id: event.correlation_id || context?.correlationId,
1050
1051
  // Set search_id at top level (not just in metadata) if provided (per identifier spec)
1051
1052
  search_id: event.search_id || context?.searchId,
1053
+ // V3 analytics: event timestamp (ISO) and anonymous_id alias for v3 backend compatibility
1054
+ event_ts: event.event_ts ?? new Date().toISOString(),
1055
+ anonymous_id: anonId,
1056
+ orgcode: event.orgcode ?? context?.orgcode,
1057
+ xstoreid: event.xstoreid ?? context?.xstoreId ?? this.storeId,
1052
1058
  };
1053
1059
  // Ensure either user_id or anon_id is present
1054
1060
  if (!payload.user_id && !payload.anon_id) {
1055
- // This should not happen as we always have anonId, but add check for safety
1056
1061
  payload.anon_id = this.anonId;
1062
+ payload.anonymous_id = this.anonId;
1057
1063
  }
1058
1064
  // Also include search_id in metadata for backward compatibility
1059
1065
  if (payload.search_id && !payload.metadata) {
@@ -1103,10 +1109,10 @@ class SeekoraClient {
1103
1109
  payload.connection_type = ctx.connection_type;
1104
1110
  if (ctx.connection_effective_type)
1105
1111
  payload.connection_effective_type = ctx.connection_effective_type;
1106
- // Platform info
1112
+ // Platform info (V3 API expects is_mobile/is_tablet as 0|1)
1107
1113
  payload.platform = ctx.platform;
1108
- payload.is_mobile = ctx.is_mobile;
1109
- payload.is_tablet = ctx.is_tablet;
1114
+ payload.is_mobile = ctx.is_mobile ? 1 : 0;
1115
+ payload.is_tablet = ctx.is_tablet ? 1 : 0;
1110
1116
  payload.is_touch_device = ctx.is_touch_device;
1111
1117
  }
1112
1118
  return payload;