@census-ai/census-sdk 0.2.0 → 0.2.2

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.cjs CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';var u="https://api.census.ai",a=class{constructor(e){this.currentUserId=null;if(!e.apiKey)throw new Error("Census: apiKey is required");["cs_live_","cs_test_","op_live_","op_test_"].some(t=>e.apiKey.startsWith(t))||console.warn('Census: API key should start with "cs_live_" or "cs_test_"'),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl||u,this.debug=e.debug||false,this.log("Initialized with base URL:",this.baseUrl);}async identify(e){if(!e.userId)throw new Error("Census: userId is required for identify()");this.currentUserId=e.userId,await this.request("/api/sdk/identify","POST",{userId:e.userId,email:e.email,name:e.name,avatarUrl:e.avatarUrl,metadata:e.metadata,organizationId:e.organizationId,organizationName:e.organizationName,organizationDomain:e.organizationDomain,organizationPlan:e.organizationPlan}),this.log("User identified:",e.userId);}reset(){this.currentUserId=null,this.log("User identity reset");}async submitFeedback(e){let s=["feedback","bug_report","feature_request","article_rating"];if(!e.type||!s.includes(e.type))throw new Error(`Census: type must be one of: ${s.join(", ")}`);if(e.type==="article_rating"){if(e.rating===void 0&&e.helpful===void 0)throw new Error("Census: article_rating requires rating or helpful field")}else if(!e.message)throw new Error("Census: message is required for this feedback type");let t=await this.request("/api/sdk/feedback","POST",{type:e.type,message:e.message,rating:e.rating,helpful:e.helpful,userId:this.currentUserId,articleId:e.articleId,pageUrl:typeof window<"u"?window.location.href:void 0,metadata:e.metadata});return this.log("Feedback submitted:",t.feedbackId),{feedbackId:t.feedbackId}}async getArticles(e){let s=new URLSearchParams;e?.category&&s.set("category",e.category),e?.search&&s.set("search",e.search),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let t=s.toString(),r=`/api/sdk/articles${t?`?${t}`:""}`,i=await this.request(r,"GET");return this.log("Fetched articles:",i.articles.length),i}async getArticle(e){try{let s=await this.request(`/api/sdk/articles/${encodeURIComponent(e)}`,"GET");return this.log("Fetched article:",e),s.article}catch(s){if(s.status===404)return null;throw s}}async getRequests(e){if(!this.currentUserId)throw new Error("Census: User must be identified before fetching requests. Call identify() first.");let s=new URLSearchParams;s.set("userId",this.currentUserId),e?.status&&s.set("status",e.status),e?.type&&s.set("type",e.type),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let t=await this.request(`/api/sdk/requests?${s.toString()}`,"GET");return this.log("Fetched requests:",t.requests.length),t}async track(e,s){if(!e)throw new Error("Census: eventType is required for track()");await this.request("/api/sdk/events","POST",{eventType:e,userId:this.currentUserId,properties:s}),this.log("Event tracked:",e);}async trackBatch(e){if(!e.events||e.events.length===0)throw new Error("Census: at least one event is required");if(e.events.length>100)throw new Error("Census: maximum 100 events per batch");let s=e.events.map(t=>({eventType:t.eventType,userId:this.currentUserId,articleId:t.articleId,featureId:t.featureId,properties:t.properties}));await this.request("/api/sdk/events","POST",{events:s}),this.log("Batch events tracked:",e.events.length);}async getGuides(){let e=new URLSearchParams;this.currentUserId&&e.set("userId",this.currentUserId);let s=e.toString(),t=`/api/sdk/guides${s?`?${s}`:""}`,r=await this.request(t,"GET");return this.log("Fetched guides:",r.guides.length),r}async getGuide(e){try{let s=new URLSearchParams;this.currentUserId&&s.set("userId",this.currentUserId);let t=s.toString(),r=`/api/sdk/guides/${encodeURIComponent(e)}${t?`?${t}`:""}`,i=await this.request(r,"GET");return this.log("Fetched guide:",e),i.guide}catch(s){if(s.status===404)return null;throw s}}async trackGuideEvent(e){if(!e.guideId||!e.eventType||!e.sessionId)throw new Error("Census: guideId, eventType, and sessionId are required for trackGuideEvent()");await this.request("/api/sdk/guides/events","POST",{guideId:e.guideId,eventType:e.eventType,stepId:e.stepId,stepIndex:e.stepIndex,pageUrl:e.pageUrl||(typeof window<"u"?window.location.href:void 0),sessionId:e.sessionId,userId:e.userId||this.currentUserId,metadata:e.metadata}),this.log("Guide event tracked:",e.eventType,e.guideId);}async markGuideCompleted(e){if(!e)throw new Error("Census: guideId is required for markGuideCompleted()");if(!this.currentUserId)throw new Error("Census: User must be identified before marking guides complete. Call identify() first.");await this.request("/api/sdk/guides/complete","POST",{guideId:e,userId:this.currentUserId}),this.log("Guide marked completed:",e);}getCurrentUserId(){return this.currentUserId}isIdentified(){return this.currentUserId!==null}async request(e,s,t){let r=`${this.baseUrl}${e}`,i={"X-Census-Key":this.apiKey};t&&(i["Content-Type"]="application/json"),this.log(`${s} ${e}`,t);let n=await fetch(r,{method:s,headers:i,body:t?JSON.stringify(t):void 0});if(!n.ok){let d=`Request failed with status ${n.status}`;try{d=(await n.json()).error||d;}catch{}throw {error:d,status:n.status}}return n.json()}log(...e){this.debug&&console.log("[Census]",...e);}};function c(o){return new a(o)}
1
+ 'use strict';var d="https://api.census.ai",a=class{constructor(e){this.currentUserId=null;if(!e.apiKey)throw new Error("Census: apiKey is required");["cs_live_","cs_test_","op_live_","op_test_"].some(t=>e.apiKey.startsWith(t))||console.warn('Census: API key should start with "cs_live_" or "cs_test_"'),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl||d,this.debug=e.debug||false,this.log("Initialized with base URL:",this.baseUrl);}async identify(e){if(!e.userId)throw new Error("Census: userId is required for identify()");this.currentUserId=e.userId,await this.request("/api/sdk/identify","POST",{userId:e.userId,email:e.email,name:e.name,avatarUrl:e.avatarUrl,metadata:e.metadata,organizationId:e.organizationId,organizationName:e.organizationName,organizationDomain:e.organizationDomain,organizationPlan:e.organizationPlan}),this.log("User identified:",e.userId);}reset(){this.currentUserId=null,this.log("User identity reset");}async submitFeedback(e){let s=["feedback","bug_report","feature_request","article_rating"];if(!e.type||!s.includes(e.type))throw new Error(`Census: type must be one of: ${s.join(", ")}`);if(e.type==="article_rating"){if(e.rating===void 0&&e.helpful===void 0)throw new Error("Census: article_rating requires rating or helpful field")}else if(!e.message)throw new Error("Census: message is required for this feedback type");let t=await this.request("/api/sdk/feedback","POST",{type:e.type,message:e.message,rating:e.rating,helpful:e.helpful,userId:this.currentUserId,articleId:e.articleId,pageUrl:typeof window<"u"?window.location.href:void 0,metadata:e.metadata});return this.log("Feedback submitted:",t.feedbackId),{feedbackId:t.feedbackId}}async getArticles(e){let s=new URLSearchParams;e?.category&&s.set("category",e.category),e?.search&&s.set("search",e.search),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let t=s.toString(),r=`/api/sdk/articles${t?`?${t}`:""}`,i=await this.request(r,"GET");return this.log("Fetched articles:",i.articles.length),i}async getArticle(e){try{let s=await this.request(`/api/sdk/articles/${encodeURIComponent(e)}`,"GET");return this.log("Fetched article:",e),s.article}catch(s){if(s.status===404)return null;throw s}}async getFeatureGroups(){let e=await this.request("/api/sdk/feature-groups","GET");return this.log("Fetched feature groups:",e.feature_groups.length),e}async getRequests(e){if(!this.currentUserId)throw new Error("Census: User must be identified before fetching requests. Call identify() first.");let s=new URLSearchParams;s.set("userId",this.currentUserId),e?.status&&s.set("status",e.status),e?.type&&s.set("type",e.type),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let t=await this.request(`/api/sdk/requests?${s.toString()}`,"GET");return this.log("Fetched requests:",t.requests.length),t}async vote(e){if(!this.currentUserId)throw new Error("Census: User must be identified before voting. Call identify() first.");if(!e)throw new Error("Census: feedbackId is required for vote()");let s=await this.request("/api/sdk/requests/vote","POST",{feedbackId:e,userId:this.currentUserId});return this.log("Vote result:",s.action,"for feedback:",e),s}async track(e,s){if(!e)throw new Error("Census: eventType is required for track()");await this.request("/api/sdk/events","POST",{eventType:e,userId:this.currentUserId,properties:s}),this.log("Event tracked:",e);}async trackBatch(e){if(!e.events||e.events.length===0)throw new Error("Census: at least one event is required");if(e.events.length>100)throw new Error("Census: maximum 100 events per batch");let s=e.events.map(t=>({eventType:t.eventType,userId:this.currentUserId,articleId:t.articleId,featureId:t.featureId,properties:t.properties}));await this.request("/api/sdk/events","POST",{events:s}),this.log("Batch events tracked:",e.events.length);}async getGuides(){let e=new URLSearchParams;this.currentUserId&&e.set("userId",this.currentUserId);let s=e.toString(),t=`/api/sdk/guides${s?`?${s}`:""}`,r=await this.request(t,"GET");return this.log("Fetched guides:",r.guides.length),r}async getGuide(e){try{let s=new URLSearchParams;this.currentUserId&&s.set("userId",this.currentUserId);let t=s.toString(),r=`/api/sdk/guides/${encodeURIComponent(e)}${t?`?${t}`:""}`,i=await this.request(r,"GET");return this.log("Fetched guide:",e),i.guide}catch(s){if(s.status===404)return null;throw s}}async trackGuideEvent(e){if(!e.guideId||!e.eventType||!e.sessionId)throw new Error("Census: guideId, eventType, and sessionId are required for trackGuideEvent()");await this.request("/api/sdk/guides/events","POST",{guideId:e.guideId,eventType:e.eventType,stepId:e.stepId,stepIndex:e.stepIndex,pageUrl:e.pageUrl||(typeof window<"u"?window.location.href:void 0),sessionId:e.sessionId,userId:e.userId||this.currentUserId,metadata:e.metadata}),this.log("Guide event tracked:",e.eventType,e.guideId);}async markGuideCompleted(e){if(!e)throw new Error("Census: guideId is required for markGuideCompleted()");if(!this.currentUserId)throw new Error("Census: User must be identified before marking guides complete. Call identify() first.");await this.request("/api/sdk/guides/complete","POST",{guideId:e,userId:this.currentUserId}),this.log("Guide marked completed:",e);}getCurrentUserId(){return this.currentUserId}isIdentified(){return this.currentUserId!==null}async request(e,s,t){let r=`${this.baseUrl}${e}`,i={"X-Census-Key":this.apiKey};t&&(i["Content-Type"]="application/json"),this.log(`${s} ${e}`,t);let n=await fetch(r,{method:s,headers:i,body:t?JSON.stringify(t):void 0});if(!n.ok){let o=`Request failed with status ${n.status}`;try{o=(await n.json()).error||o;}catch{}throw {error:o,status:n.status}}return n.json()}log(...e){this.debug&&console.log("[Census]",...e);}};function c(u){return new a(u)}
2
2
  exports.CensusClient=a;exports.createCensus=c;//# sourceMappingURL=index.cjs.map
3
3
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":["DEFAULT_BASE_URL","CensusClient","config","prefix","user","options","validTypes","response","params","queryString","url","slugOrId","error","eventType","properties","events","event","guideId","path","method","body","headers","errorMessage","args","createCensus"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n CensusConfig,\n UserIdentity,\n FeedbackOptions,\n ArticlesOptions,\n ArticlesResponse,\n Article,\n RequestsOptions,\n RequestsResponse,\n BatchEventsOptions,\n CensusError,\n Guide,\n GuidesResponse,\n GuideAnalyticsEvent,\n} from './types';\n\n/**\n * Default API base URL\n */\nconst DEFAULT_BASE_URL = 'https://api.census.ai';\n\n/**\n * Census SDK Client\n *\n * The main client for interacting with the Census API.\n * Use `createCensus()` to create an instance.\n *\n * @example\n * ```typescript\n * import { createCensus } from '@census-ai/census-sdk';\n *\n * const census = createCensus({ apiKey: 'cs_live_xxx' });\n *\n * await census.identify({ userId: 'user_123', email: 'user@example.com' });\n * await census.submitFeedback({ type: 'bug_report', message: 'Button is broken' });\n * ```\n */\nexport class CensusClient {\n private apiKey: string;\n private baseUrl: string;\n private debug: boolean;\n private currentUserId: string | null = null;\n\n constructor(config: CensusConfig) {\n if (!config.apiKey) {\n throw new Error('Census: apiKey is required');\n }\n\n // Support both new (cs_) and legacy (op_) key prefixes\n const validPrefixes = ['cs_live_', 'cs_test_', 'op_live_', 'op_test_'];\n if (!validPrefixes.some(prefix => config.apiKey.startsWith(prefix))) {\n console.warn('Census: API key should start with \"cs_live_\" or \"cs_test_\"');\n }\n\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;\n this.debug = config.debug || false;\n\n this.log('Initialized with base URL:', this.baseUrl);\n }\n\n /**\n * Identify a user for tracking purposes.\n * Call this when a user logs in or when you have user information.\n *\n * @param user - User identity information\n *\n * @example\n * ```typescript\n * await census.identify({\n * userId: 'user_123',\n * email: 'john@example.com',\n * name: 'John Doe',\n * organizationId: 'org_456',\n * organizationName: 'Acme Inc',\n * });\n * ```\n */\n async identify(user: UserIdentity): Promise<void> {\n if (!user.userId) {\n throw new Error('Census: userId is required for identify()');\n }\n\n this.currentUserId = user.userId;\n\n await this.request('/api/sdk/identify', 'POST', {\n userId: user.userId,\n email: user.email,\n name: user.name,\n avatarUrl: user.avatarUrl,\n metadata: user.metadata,\n organizationId: user.organizationId,\n organizationName: user.organizationName,\n organizationDomain: user.organizationDomain,\n organizationPlan: user.organizationPlan,\n });\n\n this.log('User identified:', user.userId);\n }\n\n /**\n * Clear the current user identity.\n * Call this when a user logs out.\n */\n reset(): void {\n this.currentUserId = null;\n this.log('User identity reset');\n }\n\n /**\n * Submit feedback, bug report, or feature request.\n *\n * @param options - Feedback options\n *\n * @example\n * ```typescript\n * // Submit a bug report\n * await census.submitFeedback({\n * type: 'bug_report',\n * message: 'The submit button is not working on Firefox',\n * });\n *\n * // Submit a feature request\n * await census.submitFeedback({\n * type: 'feature_request',\n * message: 'It would be great to have dark mode support',\n * });\n *\n * // Rate an article\n * await census.submitFeedback({\n * type: 'article_rating',\n * articleId: 'article_123',\n * helpful: true,\n * rating: 5,\n * });\n * ```\n */\n async submitFeedback(options: FeedbackOptions): Promise<{ feedbackId: string }> {\n const validTypes = ['feedback', 'bug_report', 'feature_request', 'article_rating'];\n if (!options.type || !validTypes.includes(options.type)) {\n throw new Error(`Census: type must be one of: ${validTypes.join(', ')}`);\n }\n\n if (options.type === 'article_rating') {\n if (options.rating === undefined && options.helpful === undefined) {\n throw new Error('Census: article_rating requires rating or helpful field');\n }\n } else if (!options.message) {\n throw new Error('Census: message is required for this feedback type');\n }\n\n const response = await this.request<{ success: boolean; feedbackId: string }>(\n '/api/sdk/feedback',\n 'POST',\n {\n type: options.type,\n message: options.message,\n rating: options.rating,\n helpful: options.helpful,\n userId: this.currentUserId,\n articleId: options.articleId,\n pageUrl: typeof window !== 'undefined' ? window.location.href : undefined,\n metadata: options.metadata,\n }\n );\n\n this.log('Feedback submitted:', response.feedbackId);\n return { feedbackId: response.feedbackId };\n }\n\n /**\n * Fetch published articles from the knowledge base.\n *\n * @param options - Query options\n * @returns Articles and pagination info\n *\n * @example\n * ```typescript\n * // Get all articles\n * const { articles } = await census.getArticles();\n *\n * // Search articles\n * const { articles } = await census.getArticles({ search: 'getting started' });\n *\n * // Filter by category\n * const { articles } = await census.getArticles({ category: 'guides' });\n * ```\n */\n async getArticles(options?: ArticlesOptions): Promise<ArticlesResponse> {\n const params = new URLSearchParams();\n if (options?.category) params.set('category', options.category);\n if (options?.search) params.set('search', options.search);\n if (options?.limit) params.set('limit', String(options.limit));\n if (options?.offset) params.set('offset', String(options.offset));\n\n const queryString = params.toString();\n const url = `/api/sdk/articles${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<ArticlesResponse>(url, 'GET');\n this.log('Fetched articles:', response.articles.length);\n return response;\n }\n\n /**\n * Fetch a single article by slug or ID.\n *\n * @param slugOrId - Article slug or ID\n * @returns Article or null if not found\n *\n * @example\n * ```typescript\n * const article = await census.getArticle('getting-started');\n * if (article) {\n * console.log(article.title, article.content_html);\n * }\n * ```\n */\n async getArticle(slugOrId: string): Promise<Article | null> {\n try {\n const response = await this.request<{ article: Article }>(\n `/api/sdk/articles/${encodeURIComponent(slugOrId)}`,\n 'GET'\n );\n this.log('Fetched article:', slugOrId);\n return response.article;\n } catch (error) {\n if ((error as CensusError).status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch the current user's submitted requests (feedback, bugs, feature requests).\n * Requires a user to be identified first.\n *\n * @param options - Query options\n * @returns Requests and pagination info\n *\n * @example\n * ```typescript\n * // Get all requests for the current user\n * const { requests } = await census.getRequests();\n *\n * // Filter by status\n * const { requests } = await census.getRequests({ status: 'in_progress' });\n *\n * // Filter by type\n * const { requests } = await census.getRequests({ type: 'bug_report' });\n * ```\n */\n async getRequests(options?: RequestsOptions): Promise<RequestsResponse> {\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before fetching requests. Call identify() first.');\n }\n\n const params = new URLSearchParams();\n params.set('userId', this.currentUserId);\n if (options?.status) params.set('status', options.status);\n if (options?.type) params.set('type', options.type);\n if (options?.limit) params.set('limit', String(options.limit));\n if (options?.offset) params.set('offset', String(options.offset));\n\n const response = await this.request<RequestsResponse>(\n `/api/sdk/requests?${params.toString()}`,\n 'GET'\n );\n this.log('Fetched requests:', response.requests.length);\n return response;\n }\n\n /**\n * Track a custom analytics event.\n *\n * @param eventType - Name of the event\n * @param properties - Additional event properties\n *\n * @example\n * ```typescript\n * // Track a button click\n * await census.track('button_clicked', { buttonId: 'submit-form' });\n *\n * // Track a page view\n * await census.track('page_viewed', { page: '/pricing' });\n * ```\n */\n async track(eventType: string, properties?: Record<string, unknown>): Promise<void> {\n if (!eventType) {\n throw new Error('Census: eventType is required for track()');\n }\n\n await this.request('/api/sdk/events', 'POST', {\n eventType,\n userId: this.currentUserId,\n properties,\n });\n\n this.log('Event tracked:', eventType);\n }\n\n /**\n * Track multiple events in a single request.\n * More efficient than calling track() multiple times.\n *\n * @param events - Array of events to track\n *\n * @example\n * ```typescript\n * await census.trackBatch({\n * events: [\n * { eventType: 'page_viewed', properties: { page: '/home' } },\n * { eventType: 'button_clicked', properties: { button: 'cta' } },\n * ],\n * });\n * ```\n */\n async trackBatch(options: BatchEventsOptions): Promise<void> {\n if (!options.events || options.events.length === 0) {\n throw new Error('Census: at least one event is required');\n }\n\n if (options.events.length > 100) {\n throw new Error('Census: maximum 100 events per batch');\n }\n\n const events = options.events.map((event) => ({\n eventType: event.eventType,\n userId: this.currentUserId,\n articleId: event.articleId,\n featureId: event.featureId,\n properties: event.properties,\n }));\n\n await this.request('/api/sdk/events', 'POST', { events });\n\n this.log('Batch events tracked:', options.events.length);\n }\n\n /**\n * Fetch available guides for the current user.\n * Returns guides that match the user's context and haven't been completed.\n *\n * @returns Guides and list of completed guide IDs\n *\n * @example\n * ```typescript\n * const { guides, completedGuides } = await census.getGuides();\n * guides.forEach(guide => console.log(guide.name));\n * ```\n */\n async getGuides(): Promise<GuidesResponse> {\n const params = new URLSearchParams();\n if (this.currentUserId) {\n params.set('userId', this.currentUserId);\n }\n\n const queryString = params.toString();\n const url = `/api/sdk/guides${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<GuidesResponse>(url, 'GET');\n this.log('Fetched guides:', response.guides.length);\n return response;\n }\n\n /**\n * Fetch a single guide by slug or ID.\n *\n * @param slugOrId - Guide slug or ID\n * @returns Guide or null if not found\n *\n * @example\n * ```typescript\n * const guide = await census.getGuide('onboarding-tour');\n * if (guide) {\n * console.log(guide.name, guide.guide_steps.length);\n * }\n * ```\n */\n async getGuide(slugOrId: string): Promise<Guide | null> {\n try {\n const params = new URLSearchParams();\n if (this.currentUserId) {\n params.set('userId', this.currentUserId);\n }\n\n const queryString = params.toString();\n const url = `/api/sdk/guides/${encodeURIComponent(slugOrId)}${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<{ guide: Guide }>(url, 'GET');\n this.log('Fetched guide:', slugOrId);\n return response.guide;\n } catch (error) {\n if ((error as CensusError).status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Track a guide analytics event.\n * Used to track user progress through guides.\n *\n * @param event - Guide analytics event\n *\n * @example\n * ```typescript\n * await census.trackGuideEvent({\n * guideId: 'guide_123',\n * eventType: 'step_completed',\n * stepId: 'step_456',\n * stepIndex: 2,\n * sessionId: 'session_789',\n * });\n * ```\n */\n async trackGuideEvent(event: GuideAnalyticsEvent): Promise<void> {\n if (!event.guideId || !event.eventType || !event.sessionId) {\n throw new Error('Census: guideId, eventType, and sessionId are required for trackGuideEvent()');\n }\n\n await this.request('/api/sdk/guides/events', 'POST', {\n guideId: event.guideId,\n eventType: event.eventType,\n stepId: event.stepId,\n stepIndex: event.stepIndex,\n pageUrl: event.pageUrl || (typeof window !== 'undefined' ? window.location.href : undefined),\n sessionId: event.sessionId,\n userId: event.userId || this.currentUserId,\n metadata: event.metadata,\n });\n\n this.log('Guide event tracked:', event.eventType, event.guideId);\n }\n\n /**\n * Mark a guide as completed for the current user.\n * Prevents the guide from showing again.\n *\n * @param guideId - ID of the guide to mark as completed\n *\n * @example\n * ```typescript\n * await census.markGuideCompleted('guide_123');\n * ```\n */\n async markGuideCompleted(guideId: string): Promise<void> {\n if (!guideId) {\n throw new Error('Census: guideId is required for markGuideCompleted()');\n }\n\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before marking guides complete. Call identify() first.');\n }\n\n await this.request('/api/sdk/guides/complete', 'POST', {\n guideId,\n userId: this.currentUserId,\n });\n\n this.log('Guide marked completed:', guideId);\n }\n\n /**\n * Get the current identified user ID\n */\n getCurrentUserId(): string | null {\n return this.currentUserId;\n }\n\n /**\n * Check if a user is currently identified\n */\n isIdentified(): boolean {\n return this.currentUserId !== null;\n }\n\n /**\n * Make an API request\n */\n private async request<T>(path: string, method: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n 'X-Census-Key': this.apiKey,\n };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n }\n\n this.log(`${method} ${path}`, body);\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n let errorMessage = `Request failed with status ${response.status}`;\n try {\n const errorData = await response.json();\n errorMessage = errorData.error || errorMessage;\n } catch {\n // Use default error message\n }\n\n const error: CensusError = {\n error: errorMessage,\n status: response.status,\n };\n throw error;\n }\n\n return response.json();\n }\n\n /**\n * Log debug messages\n */\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[Census]', ...args);\n }\n }\n}\n\n/**\n * Create a new Census SDK client.\n *\n * @param config - Configuration options\n * @returns Census client instance\n *\n * @example\n * ```typescript\n * import { createCensus } from '@census-ai/census-sdk';\n *\n * const census = createCensus({\n * apiKey: 'cs_live_your_key_here',\n * debug: true, // Enable debug logging\n * });\n * ```\n */\nexport function createCensus(config: CensusConfig): CensusClient {\n return new CensusClient(config);\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":["DEFAULT_BASE_URL","CensusClient","config","prefix","user","options","validTypes","response","params","queryString","url","slugOrId","error","feedbackId","eventType","properties","events","event","guideId","path","method","body","headers","errorMessage","args","createCensus"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n CensusConfig,\n UserIdentity,\n FeedbackOptions,\n ArticlesOptions,\n ArticlesResponse,\n Article,\n RequestsOptions,\n RequestsResponse,\n BatchEventsOptions,\n CensusError,\n Guide,\n GuidesResponse,\n GuideAnalyticsEvent,\n FeatureGroupsResponse,\n} from './types';\n\n/**\n * Default API base URL\n */\nconst DEFAULT_BASE_URL = 'https://api.census.ai';\n\n/**\n * Census SDK Client\n *\n * The main client for interacting with the Census API.\n * Use `createCensus()` to create an instance.\n *\n * @example\n * ```typescript\n * import { createCensus } from '@census-ai/census-sdk';\n *\n * const census = createCensus({ apiKey: 'cs_live_xxx' });\n *\n * await census.identify({ userId: 'user_123', email: 'user@example.com' });\n * await census.submitFeedback({ type: 'bug_report', message: 'Button is broken' });\n * ```\n */\nexport class CensusClient {\n private apiKey: string;\n private baseUrl: string;\n private debug: boolean;\n private currentUserId: string | null = null;\n\n constructor(config: CensusConfig) {\n if (!config.apiKey) {\n throw new Error('Census: apiKey is required');\n }\n\n // Support both new (cs_) and legacy (op_) key prefixes\n const validPrefixes = ['cs_live_', 'cs_test_', 'op_live_', 'op_test_'];\n if (!validPrefixes.some(prefix => config.apiKey.startsWith(prefix))) {\n console.warn('Census: API key should start with \"cs_live_\" or \"cs_test_\"');\n }\n\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;\n this.debug = config.debug || false;\n\n this.log('Initialized with base URL:', this.baseUrl);\n }\n\n /**\n * Identify a user for tracking purposes.\n * Call this when a user logs in or when you have user information.\n *\n * @param user - User identity information\n *\n * @example\n * ```typescript\n * await census.identify({\n * userId: 'user_123',\n * email: 'john@example.com',\n * name: 'John Doe',\n * organizationId: 'org_456',\n * organizationName: 'Acme Inc',\n * });\n * ```\n */\n async identify(user: UserIdentity): Promise<void> {\n if (!user.userId) {\n throw new Error('Census: userId is required for identify()');\n }\n\n this.currentUserId = user.userId;\n\n await this.request('/api/sdk/identify', 'POST', {\n userId: user.userId,\n email: user.email,\n name: user.name,\n avatarUrl: user.avatarUrl,\n metadata: user.metadata,\n organizationId: user.organizationId,\n organizationName: user.organizationName,\n organizationDomain: user.organizationDomain,\n organizationPlan: user.organizationPlan,\n });\n\n this.log('User identified:', user.userId);\n }\n\n /**\n * Clear the current user identity.\n * Call this when a user logs out.\n */\n reset(): void {\n this.currentUserId = null;\n this.log('User identity reset');\n }\n\n /**\n * Submit feedback, bug report, or feature request.\n *\n * @param options - Feedback options\n *\n * @example\n * ```typescript\n * // Submit a bug report\n * await census.submitFeedback({\n * type: 'bug_report',\n * message: 'The submit button is not working on Firefox',\n * });\n *\n * // Submit a feature request\n * await census.submitFeedback({\n * type: 'feature_request',\n * message: 'It would be great to have dark mode support',\n * });\n *\n * // Rate an article\n * await census.submitFeedback({\n * type: 'article_rating',\n * articleId: 'article_123',\n * helpful: true,\n * rating: 5,\n * });\n * ```\n */\n async submitFeedback(options: FeedbackOptions): Promise<{ feedbackId: string }> {\n const validTypes = ['feedback', 'bug_report', 'feature_request', 'article_rating'];\n if (!options.type || !validTypes.includes(options.type)) {\n throw new Error(`Census: type must be one of: ${validTypes.join(', ')}`);\n }\n\n if (options.type === 'article_rating') {\n if (options.rating === undefined && options.helpful === undefined) {\n throw new Error('Census: article_rating requires rating or helpful field');\n }\n } else if (!options.message) {\n throw new Error('Census: message is required for this feedback type');\n }\n\n const response = await this.request<{ success: boolean; feedbackId: string }>(\n '/api/sdk/feedback',\n 'POST',\n {\n type: options.type,\n message: options.message,\n rating: options.rating,\n helpful: options.helpful,\n userId: this.currentUserId,\n articleId: options.articleId,\n pageUrl: typeof window !== 'undefined' ? window.location.href : undefined,\n metadata: options.metadata,\n }\n );\n\n this.log('Feedback submitted:', response.feedbackId);\n return { feedbackId: response.feedbackId };\n }\n\n /**\n * Fetch published articles from the knowledge base.\n *\n * @param options - Query options\n * @returns Articles and pagination info\n *\n * @example\n * ```typescript\n * // Get all articles\n * const { articles } = await census.getArticles();\n *\n * // Search articles\n * const { articles } = await census.getArticles({ search: 'getting started' });\n *\n * // Filter by category\n * const { articles } = await census.getArticles({ category: 'guides' });\n * ```\n */\n async getArticles(options?: ArticlesOptions): Promise<ArticlesResponse> {\n const params = new URLSearchParams();\n if (options?.category) params.set('category', options.category);\n if (options?.search) params.set('search', options.search);\n if (options?.limit) params.set('limit', String(options.limit));\n if (options?.offset) params.set('offset', String(options.offset));\n\n const queryString = params.toString();\n const url = `/api/sdk/articles${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<ArticlesResponse>(url, 'GET');\n this.log('Fetched articles:', response.articles.length);\n return response;\n }\n\n /**\n * Fetch a single article by slug or ID.\n *\n * @param slugOrId - Article slug or ID\n * @returns Article or null if not found\n *\n * @example\n * ```typescript\n * const article = await census.getArticle('getting-started');\n * if (article) {\n * console.log(article.title, article.content_html);\n * }\n * ```\n */\n async getArticle(slugOrId: string): Promise<Article | null> {\n try {\n const response = await this.request<{ article: Article }>(\n `/api/sdk/articles/${encodeURIComponent(slugOrId)}`,\n 'GET'\n );\n this.log('Fetched article:', slugOrId);\n return response.article;\n } catch (error) {\n if ((error as CensusError).status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch feature groups with their features and article counts.\n * Used for navigation in the knowledge base.\n *\n * @returns Feature groups with nested features\n *\n * @example\n * ```typescript\n * const { feature_groups } = await census.getFeatureGroups();\n * feature_groups.forEach(group => {\n * console.log(group.name, group.features.length);\n * });\n * ```\n */\n async getFeatureGroups(): Promise<FeatureGroupsResponse> {\n const response = await this.request<FeatureGroupsResponse>(\n '/api/sdk/feature-groups',\n 'GET'\n );\n this.log('Fetched feature groups:', response.feature_groups.length);\n return response;\n }\n\n /**\n * Fetch the current user's submitted requests (feedback, bugs, feature requests).\n * Requires a user to be identified first.\n *\n * @param options - Query options\n * @returns Requests and pagination info\n *\n * @example\n * ```typescript\n * // Get all requests for the current user\n * const { requests } = await census.getRequests();\n *\n * // Filter by status\n * const { requests } = await census.getRequests({ status: 'in_progress' });\n *\n * // Filter by type\n * const { requests } = await census.getRequests({ type: 'bug_report' });\n * ```\n */\n async getRequests(options?: RequestsOptions): Promise<RequestsResponse> {\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before fetching requests. Call identify() first.');\n }\n\n const params = new URLSearchParams();\n params.set('userId', this.currentUserId);\n if (options?.status) params.set('status', options.status);\n if (options?.type) params.set('type', options.type);\n if (options?.limit) params.set('limit', String(options.limit));\n if (options?.offset) params.set('offset', String(options.offset));\n\n const response = await this.request<RequestsResponse>(\n `/api/sdk/requests?${params.toString()}`,\n 'GET'\n );\n this.log('Fetched requests:', response.requests.length);\n return response;\n }\n\n /**\n * Vote on a feedback request (toggle).\n * If the user has already voted, removes the vote.\n * If the user hasn't voted, adds a vote.\n *\n * @param feedbackId - ID of the feedback to vote on\n * @returns Vote result with action taken and new vote count\n *\n * @example\n * ```typescript\n * // Vote on a feedback request\n * const result = await census.vote('feedback-id-123');\n * console.log(result.action); // 'added' or 'removed'\n * console.log(result.vote_count); // 5\n * console.log(result.user_has_voted); // true\n * ```\n */\n async vote(feedbackId: string): Promise<{\n success: boolean;\n action: 'added' | 'removed';\n vote_count: number;\n user_has_voted: boolean;\n }> {\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before voting. Call identify() first.');\n }\n\n if (!feedbackId) {\n throw new Error('Census: feedbackId is required for vote()');\n }\n\n const response = await this.request<{\n success: boolean;\n action: 'added' | 'removed';\n vote_count: number;\n user_has_voted: boolean;\n }>('/api/sdk/requests/vote', 'POST', {\n feedbackId,\n userId: this.currentUserId,\n });\n\n this.log('Vote result:', response.action, 'for feedback:', feedbackId);\n return response;\n }\n\n /**\n * Track a custom analytics event.\n *\n * @param eventType - Name of the event\n * @param properties - Additional event properties\n *\n * @example\n * ```typescript\n * // Track a button click\n * await census.track('button_clicked', { buttonId: 'submit-form' });\n *\n * // Track a page view\n * await census.track('page_viewed', { page: '/pricing' });\n * ```\n */\n async track(eventType: string, properties?: Record<string, unknown>): Promise<void> {\n if (!eventType) {\n throw new Error('Census: eventType is required for track()');\n }\n\n await this.request('/api/sdk/events', 'POST', {\n eventType,\n userId: this.currentUserId,\n properties,\n });\n\n this.log('Event tracked:', eventType);\n }\n\n /**\n * Track multiple events in a single request.\n * More efficient than calling track() multiple times.\n *\n * @param events - Array of events to track\n *\n * @example\n * ```typescript\n * await census.trackBatch({\n * events: [\n * { eventType: 'page_viewed', properties: { page: '/home' } },\n * { eventType: 'button_clicked', properties: { button: 'cta' } },\n * ],\n * });\n * ```\n */\n async trackBatch(options: BatchEventsOptions): Promise<void> {\n if (!options.events || options.events.length === 0) {\n throw new Error('Census: at least one event is required');\n }\n\n if (options.events.length > 100) {\n throw new Error('Census: maximum 100 events per batch');\n }\n\n const events = options.events.map((event) => ({\n eventType: event.eventType,\n userId: this.currentUserId,\n articleId: event.articleId,\n featureId: event.featureId,\n properties: event.properties,\n }));\n\n await this.request('/api/sdk/events', 'POST', { events });\n\n this.log('Batch events tracked:', options.events.length);\n }\n\n /**\n * Fetch available guides for the current user.\n * Returns guides that match the user's context and haven't been completed.\n *\n * @returns Guides and list of completed guide IDs\n *\n * @example\n * ```typescript\n * const { guides, completedGuides } = await census.getGuides();\n * guides.forEach(guide => console.log(guide.name));\n * ```\n */\n async getGuides(): Promise<GuidesResponse> {\n const params = new URLSearchParams();\n if (this.currentUserId) {\n params.set('userId', this.currentUserId);\n }\n\n const queryString = params.toString();\n const url = `/api/sdk/guides${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<GuidesResponse>(url, 'GET');\n this.log('Fetched guides:', response.guides.length);\n return response;\n }\n\n /**\n * Fetch a single guide by slug or ID.\n *\n * @param slugOrId - Guide slug or ID\n * @returns Guide or null if not found\n *\n * @example\n * ```typescript\n * const guide = await census.getGuide('onboarding-tour');\n * if (guide) {\n * console.log(guide.name, guide.guide_steps.length);\n * }\n * ```\n */\n async getGuide(slugOrId: string): Promise<Guide | null> {\n try {\n const params = new URLSearchParams();\n if (this.currentUserId) {\n params.set('userId', this.currentUserId);\n }\n\n const queryString = params.toString();\n const url = `/api/sdk/guides/${encodeURIComponent(slugOrId)}${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<{ guide: Guide }>(url, 'GET');\n this.log('Fetched guide:', slugOrId);\n return response.guide;\n } catch (error) {\n if ((error as CensusError).status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Track a guide analytics event.\n * Used to track user progress through guides.\n *\n * @param event - Guide analytics event\n *\n * @example\n * ```typescript\n * await census.trackGuideEvent({\n * guideId: 'guide_123',\n * eventType: 'step_completed',\n * stepId: 'step_456',\n * stepIndex: 2,\n * sessionId: 'session_789',\n * });\n * ```\n */\n async trackGuideEvent(event: GuideAnalyticsEvent): Promise<void> {\n if (!event.guideId || !event.eventType || !event.sessionId) {\n throw new Error('Census: guideId, eventType, and sessionId are required for trackGuideEvent()');\n }\n\n await this.request('/api/sdk/guides/events', 'POST', {\n guideId: event.guideId,\n eventType: event.eventType,\n stepId: event.stepId,\n stepIndex: event.stepIndex,\n pageUrl: event.pageUrl || (typeof window !== 'undefined' ? window.location.href : undefined),\n sessionId: event.sessionId,\n userId: event.userId || this.currentUserId,\n metadata: event.metadata,\n });\n\n this.log('Guide event tracked:', event.eventType, event.guideId);\n }\n\n /**\n * Mark a guide as completed for the current user.\n * Prevents the guide from showing again.\n *\n * @param guideId - ID of the guide to mark as completed\n *\n * @example\n * ```typescript\n * await census.markGuideCompleted('guide_123');\n * ```\n */\n async markGuideCompleted(guideId: string): Promise<void> {\n if (!guideId) {\n throw new Error('Census: guideId is required for markGuideCompleted()');\n }\n\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before marking guides complete. Call identify() first.');\n }\n\n await this.request('/api/sdk/guides/complete', 'POST', {\n guideId,\n userId: this.currentUserId,\n });\n\n this.log('Guide marked completed:', guideId);\n }\n\n /**\n * Get the current identified user ID\n */\n getCurrentUserId(): string | null {\n return this.currentUserId;\n }\n\n /**\n * Check if a user is currently identified\n */\n isIdentified(): boolean {\n return this.currentUserId !== null;\n }\n\n /**\n * Make an API request\n */\n private async request<T>(path: string, method: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n 'X-Census-Key': this.apiKey,\n };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n }\n\n this.log(`${method} ${path}`, body);\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n let errorMessage = `Request failed with status ${response.status}`;\n try {\n const errorData = await response.json();\n errorMessage = errorData.error || errorMessage;\n } catch {\n // Use default error message\n }\n\n const error: CensusError = {\n error: errorMessage,\n status: response.status,\n };\n throw error;\n }\n\n return response.json();\n }\n\n /**\n * Log debug messages\n */\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[Census]', ...args);\n }\n }\n}\n\n/**\n * Create a new Census SDK client.\n *\n * @param config - Configuration options\n * @returns Census client instance\n *\n * @example\n * ```typescript\n * import { createCensus } from '@census-ai/census-sdk';\n *\n * const census = createCensus({\n * apiKey: 'cs_live_your_key_here',\n * debug: true, // Enable debug logging\n * });\n * ```\n */\nexport function createCensus(config: CensusConfig): CensusClient {\n return new CensusClient(config);\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -186,6 +186,21 @@ interface Request {
186
186
  rating: number | null;
187
187
  helpful: boolean | null;
188
188
  metadata: Record<string, unknown>;
189
+ vote_count: number;
190
+ user_has_voted: boolean;
191
+ is_own: boolean;
192
+ }
193
+ /**
194
+ * Feedback visibility setting
195
+ */
196
+ type FeedbackVisibility = 'own' | 'organization' | 'all';
197
+ /**
198
+ * Project settings for requests
199
+ */
200
+ interface RequestsSettings {
201
+ feedbackVisibility: FeedbackVisibility;
202
+ allowVoting: boolean;
203
+ allowRequestCreation: boolean;
189
204
  }
190
205
  /**
191
206
  * Options for fetching requests
@@ -221,6 +236,7 @@ interface RequestsResponse {
221
236
  offset: number;
222
237
  hasMore: boolean;
223
238
  };
239
+ settings: RequestsSettings;
224
240
  }
225
241
  /**
226
242
  * API error response
@@ -447,6 +463,36 @@ interface GuidesResponse {
447
463
  completedGuides: string[];
448
464
  }
449
465
  type GuideEventType = 'started' | 'step_viewed' | 'step_completed' | 'completed' | 'skipped' | 'dismissed';
466
+ /**
467
+ * A feature within a feature group
468
+ */
469
+ interface Feature {
470
+ id: string;
471
+ name: string;
472
+ slug: string;
473
+ description: string | null;
474
+ status: string;
475
+ article_count: number;
476
+ }
477
+ /**
478
+ * A group of related features
479
+ */
480
+ interface FeatureGroup {
481
+ id: string;
482
+ name: string;
483
+ slug: string;
484
+ description: string | null;
485
+ color: string | null;
486
+ features: Feature[];
487
+ feature_count: number;
488
+ article_count: number;
489
+ }
490
+ /**
491
+ * Response from feature groups endpoint
492
+ */
493
+ interface FeatureGroupsResponse {
494
+ feature_groups: FeatureGroup[];
495
+ }
450
496
  interface GuideAnalyticsEvent {
451
497
  guideId: string;
452
498
  eventType: GuideEventType;
@@ -577,6 +623,21 @@ declare class CensusClient {
577
623
  * ```
578
624
  */
579
625
  getArticle(slugOrId: string): Promise<Article | null>;
626
+ /**
627
+ * Fetch feature groups with their features and article counts.
628
+ * Used for navigation in the knowledge base.
629
+ *
630
+ * @returns Feature groups with nested features
631
+ *
632
+ * @example
633
+ * ```typescript
634
+ * const { feature_groups } = await census.getFeatureGroups();
635
+ * feature_groups.forEach(group => {
636
+ * console.log(group.name, group.features.length);
637
+ * });
638
+ * ```
639
+ */
640
+ getFeatureGroups(): Promise<FeatureGroupsResponse>;
580
641
  /**
581
642
  * Fetch the current user's submitted requests (feedback, bugs, feature requests).
582
643
  * Requires a user to be identified first.
@@ -597,6 +658,29 @@ declare class CensusClient {
597
658
  * ```
598
659
  */
599
660
  getRequests(options?: RequestsOptions): Promise<RequestsResponse>;
661
+ /**
662
+ * Vote on a feedback request (toggle).
663
+ * If the user has already voted, removes the vote.
664
+ * If the user hasn't voted, adds a vote.
665
+ *
666
+ * @param feedbackId - ID of the feedback to vote on
667
+ * @returns Vote result with action taken and new vote count
668
+ *
669
+ * @example
670
+ * ```typescript
671
+ * // Vote on a feedback request
672
+ * const result = await census.vote('feedback-id-123');
673
+ * console.log(result.action); // 'added' or 'removed'
674
+ * console.log(result.vote_count); // 5
675
+ * console.log(result.user_has_voted); // true
676
+ * ```
677
+ */
678
+ vote(feedbackId: string): Promise<{
679
+ success: boolean;
680
+ action: 'added' | 'removed';
681
+ vote_count: number;
682
+ user_has_voted: boolean;
683
+ }>;
600
684
  /**
601
685
  * Track a custom analytics event.
602
686
  *
package/dist/index.d.ts CHANGED
@@ -186,6 +186,21 @@ interface Request {
186
186
  rating: number | null;
187
187
  helpful: boolean | null;
188
188
  metadata: Record<string, unknown>;
189
+ vote_count: number;
190
+ user_has_voted: boolean;
191
+ is_own: boolean;
192
+ }
193
+ /**
194
+ * Feedback visibility setting
195
+ */
196
+ type FeedbackVisibility = 'own' | 'organization' | 'all';
197
+ /**
198
+ * Project settings for requests
199
+ */
200
+ interface RequestsSettings {
201
+ feedbackVisibility: FeedbackVisibility;
202
+ allowVoting: boolean;
203
+ allowRequestCreation: boolean;
189
204
  }
190
205
  /**
191
206
  * Options for fetching requests
@@ -221,6 +236,7 @@ interface RequestsResponse {
221
236
  offset: number;
222
237
  hasMore: boolean;
223
238
  };
239
+ settings: RequestsSettings;
224
240
  }
225
241
  /**
226
242
  * API error response
@@ -447,6 +463,36 @@ interface GuidesResponse {
447
463
  completedGuides: string[];
448
464
  }
449
465
  type GuideEventType = 'started' | 'step_viewed' | 'step_completed' | 'completed' | 'skipped' | 'dismissed';
466
+ /**
467
+ * A feature within a feature group
468
+ */
469
+ interface Feature {
470
+ id: string;
471
+ name: string;
472
+ slug: string;
473
+ description: string | null;
474
+ status: string;
475
+ article_count: number;
476
+ }
477
+ /**
478
+ * A group of related features
479
+ */
480
+ interface FeatureGroup {
481
+ id: string;
482
+ name: string;
483
+ slug: string;
484
+ description: string | null;
485
+ color: string | null;
486
+ features: Feature[];
487
+ feature_count: number;
488
+ article_count: number;
489
+ }
490
+ /**
491
+ * Response from feature groups endpoint
492
+ */
493
+ interface FeatureGroupsResponse {
494
+ feature_groups: FeatureGroup[];
495
+ }
450
496
  interface GuideAnalyticsEvent {
451
497
  guideId: string;
452
498
  eventType: GuideEventType;
@@ -577,6 +623,21 @@ declare class CensusClient {
577
623
  * ```
578
624
  */
579
625
  getArticle(slugOrId: string): Promise<Article | null>;
626
+ /**
627
+ * Fetch feature groups with their features and article counts.
628
+ * Used for navigation in the knowledge base.
629
+ *
630
+ * @returns Feature groups with nested features
631
+ *
632
+ * @example
633
+ * ```typescript
634
+ * const { feature_groups } = await census.getFeatureGroups();
635
+ * feature_groups.forEach(group => {
636
+ * console.log(group.name, group.features.length);
637
+ * });
638
+ * ```
639
+ */
640
+ getFeatureGroups(): Promise<FeatureGroupsResponse>;
580
641
  /**
581
642
  * Fetch the current user's submitted requests (feedback, bugs, feature requests).
582
643
  * Requires a user to be identified first.
@@ -597,6 +658,29 @@ declare class CensusClient {
597
658
  * ```
598
659
  */
599
660
  getRequests(options?: RequestsOptions): Promise<RequestsResponse>;
661
+ /**
662
+ * Vote on a feedback request (toggle).
663
+ * If the user has already voted, removes the vote.
664
+ * If the user hasn't voted, adds a vote.
665
+ *
666
+ * @param feedbackId - ID of the feedback to vote on
667
+ * @returns Vote result with action taken and new vote count
668
+ *
669
+ * @example
670
+ * ```typescript
671
+ * // Vote on a feedback request
672
+ * const result = await census.vote('feedback-id-123');
673
+ * console.log(result.action); // 'added' or 'removed'
674
+ * console.log(result.vote_count); // 5
675
+ * console.log(result.user_has_voted); // true
676
+ * ```
677
+ */
678
+ vote(feedbackId: string): Promise<{
679
+ success: boolean;
680
+ action: 'added' | 'removed';
681
+ vote_count: number;
682
+ user_has_voted: boolean;
683
+ }>;
600
684
  /**
601
685
  * Track a custom analytics event.
602
686
  *
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- var u="https://api.census.ai",a=class{constructor(e){this.currentUserId=null;if(!e.apiKey)throw new Error("Census: apiKey is required");["cs_live_","cs_test_","op_live_","op_test_"].some(t=>e.apiKey.startsWith(t))||console.warn('Census: API key should start with "cs_live_" or "cs_test_"'),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl||u,this.debug=e.debug||false,this.log("Initialized with base URL:",this.baseUrl);}async identify(e){if(!e.userId)throw new Error("Census: userId is required for identify()");this.currentUserId=e.userId,await this.request("/api/sdk/identify","POST",{userId:e.userId,email:e.email,name:e.name,avatarUrl:e.avatarUrl,metadata:e.metadata,organizationId:e.organizationId,organizationName:e.organizationName,organizationDomain:e.organizationDomain,organizationPlan:e.organizationPlan}),this.log("User identified:",e.userId);}reset(){this.currentUserId=null,this.log("User identity reset");}async submitFeedback(e){let s=["feedback","bug_report","feature_request","article_rating"];if(!e.type||!s.includes(e.type))throw new Error(`Census: type must be one of: ${s.join(", ")}`);if(e.type==="article_rating"){if(e.rating===void 0&&e.helpful===void 0)throw new Error("Census: article_rating requires rating or helpful field")}else if(!e.message)throw new Error("Census: message is required for this feedback type");let t=await this.request("/api/sdk/feedback","POST",{type:e.type,message:e.message,rating:e.rating,helpful:e.helpful,userId:this.currentUserId,articleId:e.articleId,pageUrl:typeof window<"u"?window.location.href:void 0,metadata:e.metadata});return this.log("Feedback submitted:",t.feedbackId),{feedbackId:t.feedbackId}}async getArticles(e){let s=new URLSearchParams;e?.category&&s.set("category",e.category),e?.search&&s.set("search",e.search),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let t=s.toString(),r=`/api/sdk/articles${t?`?${t}`:""}`,i=await this.request(r,"GET");return this.log("Fetched articles:",i.articles.length),i}async getArticle(e){try{let s=await this.request(`/api/sdk/articles/${encodeURIComponent(e)}`,"GET");return this.log("Fetched article:",e),s.article}catch(s){if(s.status===404)return null;throw s}}async getRequests(e){if(!this.currentUserId)throw new Error("Census: User must be identified before fetching requests. Call identify() first.");let s=new URLSearchParams;s.set("userId",this.currentUserId),e?.status&&s.set("status",e.status),e?.type&&s.set("type",e.type),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let t=await this.request(`/api/sdk/requests?${s.toString()}`,"GET");return this.log("Fetched requests:",t.requests.length),t}async track(e,s){if(!e)throw new Error("Census: eventType is required for track()");await this.request("/api/sdk/events","POST",{eventType:e,userId:this.currentUserId,properties:s}),this.log("Event tracked:",e);}async trackBatch(e){if(!e.events||e.events.length===0)throw new Error("Census: at least one event is required");if(e.events.length>100)throw new Error("Census: maximum 100 events per batch");let s=e.events.map(t=>({eventType:t.eventType,userId:this.currentUserId,articleId:t.articleId,featureId:t.featureId,properties:t.properties}));await this.request("/api/sdk/events","POST",{events:s}),this.log("Batch events tracked:",e.events.length);}async getGuides(){let e=new URLSearchParams;this.currentUserId&&e.set("userId",this.currentUserId);let s=e.toString(),t=`/api/sdk/guides${s?`?${s}`:""}`,r=await this.request(t,"GET");return this.log("Fetched guides:",r.guides.length),r}async getGuide(e){try{let s=new URLSearchParams;this.currentUserId&&s.set("userId",this.currentUserId);let t=s.toString(),r=`/api/sdk/guides/${encodeURIComponent(e)}${t?`?${t}`:""}`,i=await this.request(r,"GET");return this.log("Fetched guide:",e),i.guide}catch(s){if(s.status===404)return null;throw s}}async trackGuideEvent(e){if(!e.guideId||!e.eventType||!e.sessionId)throw new Error("Census: guideId, eventType, and sessionId are required for trackGuideEvent()");await this.request("/api/sdk/guides/events","POST",{guideId:e.guideId,eventType:e.eventType,stepId:e.stepId,stepIndex:e.stepIndex,pageUrl:e.pageUrl||(typeof window<"u"?window.location.href:void 0),sessionId:e.sessionId,userId:e.userId||this.currentUserId,metadata:e.metadata}),this.log("Guide event tracked:",e.eventType,e.guideId);}async markGuideCompleted(e){if(!e)throw new Error("Census: guideId is required for markGuideCompleted()");if(!this.currentUserId)throw new Error("Census: User must be identified before marking guides complete. Call identify() first.");await this.request("/api/sdk/guides/complete","POST",{guideId:e,userId:this.currentUserId}),this.log("Guide marked completed:",e);}getCurrentUserId(){return this.currentUserId}isIdentified(){return this.currentUserId!==null}async request(e,s,t){let r=`${this.baseUrl}${e}`,i={"X-Census-Key":this.apiKey};t&&(i["Content-Type"]="application/json"),this.log(`${s} ${e}`,t);let n=await fetch(r,{method:s,headers:i,body:t?JSON.stringify(t):void 0});if(!n.ok){let d=`Request failed with status ${n.status}`;try{d=(await n.json()).error||d;}catch{}throw {error:d,status:n.status}}return n.json()}log(...e){this.debug&&console.log("[Census]",...e);}};function c(o){return new a(o)}
1
+ var d="https://api.census.ai",a=class{constructor(e){this.currentUserId=null;if(!e.apiKey)throw new Error("Census: apiKey is required");["cs_live_","cs_test_","op_live_","op_test_"].some(t=>e.apiKey.startsWith(t))||console.warn('Census: API key should start with "cs_live_" or "cs_test_"'),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl||d,this.debug=e.debug||false,this.log("Initialized with base URL:",this.baseUrl);}async identify(e){if(!e.userId)throw new Error("Census: userId is required for identify()");this.currentUserId=e.userId,await this.request("/api/sdk/identify","POST",{userId:e.userId,email:e.email,name:e.name,avatarUrl:e.avatarUrl,metadata:e.metadata,organizationId:e.organizationId,organizationName:e.organizationName,organizationDomain:e.organizationDomain,organizationPlan:e.organizationPlan}),this.log("User identified:",e.userId);}reset(){this.currentUserId=null,this.log("User identity reset");}async submitFeedback(e){let s=["feedback","bug_report","feature_request","article_rating"];if(!e.type||!s.includes(e.type))throw new Error(`Census: type must be one of: ${s.join(", ")}`);if(e.type==="article_rating"){if(e.rating===void 0&&e.helpful===void 0)throw new Error("Census: article_rating requires rating or helpful field")}else if(!e.message)throw new Error("Census: message is required for this feedback type");let t=await this.request("/api/sdk/feedback","POST",{type:e.type,message:e.message,rating:e.rating,helpful:e.helpful,userId:this.currentUserId,articleId:e.articleId,pageUrl:typeof window<"u"?window.location.href:void 0,metadata:e.metadata});return this.log("Feedback submitted:",t.feedbackId),{feedbackId:t.feedbackId}}async getArticles(e){let s=new URLSearchParams;e?.category&&s.set("category",e.category),e?.search&&s.set("search",e.search),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let t=s.toString(),r=`/api/sdk/articles${t?`?${t}`:""}`,i=await this.request(r,"GET");return this.log("Fetched articles:",i.articles.length),i}async getArticle(e){try{let s=await this.request(`/api/sdk/articles/${encodeURIComponent(e)}`,"GET");return this.log("Fetched article:",e),s.article}catch(s){if(s.status===404)return null;throw s}}async getFeatureGroups(){let e=await this.request("/api/sdk/feature-groups","GET");return this.log("Fetched feature groups:",e.feature_groups.length),e}async getRequests(e){if(!this.currentUserId)throw new Error("Census: User must be identified before fetching requests. Call identify() first.");let s=new URLSearchParams;s.set("userId",this.currentUserId),e?.status&&s.set("status",e.status),e?.type&&s.set("type",e.type),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let t=await this.request(`/api/sdk/requests?${s.toString()}`,"GET");return this.log("Fetched requests:",t.requests.length),t}async vote(e){if(!this.currentUserId)throw new Error("Census: User must be identified before voting. Call identify() first.");if(!e)throw new Error("Census: feedbackId is required for vote()");let s=await this.request("/api/sdk/requests/vote","POST",{feedbackId:e,userId:this.currentUserId});return this.log("Vote result:",s.action,"for feedback:",e),s}async track(e,s){if(!e)throw new Error("Census: eventType is required for track()");await this.request("/api/sdk/events","POST",{eventType:e,userId:this.currentUserId,properties:s}),this.log("Event tracked:",e);}async trackBatch(e){if(!e.events||e.events.length===0)throw new Error("Census: at least one event is required");if(e.events.length>100)throw new Error("Census: maximum 100 events per batch");let s=e.events.map(t=>({eventType:t.eventType,userId:this.currentUserId,articleId:t.articleId,featureId:t.featureId,properties:t.properties}));await this.request("/api/sdk/events","POST",{events:s}),this.log("Batch events tracked:",e.events.length);}async getGuides(){let e=new URLSearchParams;this.currentUserId&&e.set("userId",this.currentUserId);let s=e.toString(),t=`/api/sdk/guides${s?`?${s}`:""}`,r=await this.request(t,"GET");return this.log("Fetched guides:",r.guides.length),r}async getGuide(e){try{let s=new URLSearchParams;this.currentUserId&&s.set("userId",this.currentUserId);let t=s.toString(),r=`/api/sdk/guides/${encodeURIComponent(e)}${t?`?${t}`:""}`,i=await this.request(r,"GET");return this.log("Fetched guide:",e),i.guide}catch(s){if(s.status===404)return null;throw s}}async trackGuideEvent(e){if(!e.guideId||!e.eventType||!e.sessionId)throw new Error("Census: guideId, eventType, and sessionId are required for trackGuideEvent()");await this.request("/api/sdk/guides/events","POST",{guideId:e.guideId,eventType:e.eventType,stepId:e.stepId,stepIndex:e.stepIndex,pageUrl:e.pageUrl||(typeof window<"u"?window.location.href:void 0),sessionId:e.sessionId,userId:e.userId||this.currentUserId,metadata:e.metadata}),this.log("Guide event tracked:",e.eventType,e.guideId);}async markGuideCompleted(e){if(!e)throw new Error("Census: guideId is required for markGuideCompleted()");if(!this.currentUserId)throw new Error("Census: User must be identified before marking guides complete. Call identify() first.");await this.request("/api/sdk/guides/complete","POST",{guideId:e,userId:this.currentUserId}),this.log("Guide marked completed:",e);}getCurrentUserId(){return this.currentUserId}isIdentified(){return this.currentUserId!==null}async request(e,s,t){let r=`${this.baseUrl}${e}`,i={"X-Census-Key":this.apiKey};t&&(i["Content-Type"]="application/json"),this.log(`${s} ${e}`,t);let n=await fetch(r,{method:s,headers:i,body:t?JSON.stringify(t):void 0});if(!n.ok){let o=`Request failed with status ${n.status}`;try{o=(await n.json()).error||o;}catch{}throw {error:o,status:n.status}}return n.json()}log(...e){this.debug&&console.log("[Census]",...e);}};function c(u){return new a(u)}
2
2
  export{a as CensusClient,c as createCensus};//# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":["DEFAULT_BASE_URL","CensusClient","config","prefix","user","options","validTypes","response","params","queryString","url","slugOrId","error","eventType","properties","events","event","guideId","path","method","body","headers","errorMessage","args","createCensus"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n CensusConfig,\n UserIdentity,\n FeedbackOptions,\n ArticlesOptions,\n ArticlesResponse,\n Article,\n RequestsOptions,\n RequestsResponse,\n BatchEventsOptions,\n CensusError,\n Guide,\n GuidesResponse,\n GuideAnalyticsEvent,\n} from './types';\n\n/**\n * Default API base URL\n */\nconst DEFAULT_BASE_URL = 'https://api.census.ai';\n\n/**\n * Census SDK Client\n *\n * The main client for interacting with the Census API.\n * Use `createCensus()` to create an instance.\n *\n * @example\n * ```typescript\n * import { createCensus } from '@census-ai/census-sdk';\n *\n * const census = createCensus({ apiKey: 'cs_live_xxx' });\n *\n * await census.identify({ userId: 'user_123', email: 'user@example.com' });\n * await census.submitFeedback({ type: 'bug_report', message: 'Button is broken' });\n * ```\n */\nexport class CensusClient {\n private apiKey: string;\n private baseUrl: string;\n private debug: boolean;\n private currentUserId: string | null = null;\n\n constructor(config: CensusConfig) {\n if (!config.apiKey) {\n throw new Error('Census: apiKey is required');\n }\n\n // Support both new (cs_) and legacy (op_) key prefixes\n const validPrefixes = ['cs_live_', 'cs_test_', 'op_live_', 'op_test_'];\n if (!validPrefixes.some(prefix => config.apiKey.startsWith(prefix))) {\n console.warn('Census: API key should start with \"cs_live_\" or \"cs_test_\"');\n }\n\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;\n this.debug = config.debug || false;\n\n this.log('Initialized with base URL:', this.baseUrl);\n }\n\n /**\n * Identify a user for tracking purposes.\n * Call this when a user logs in or when you have user information.\n *\n * @param user - User identity information\n *\n * @example\n * ```typescript\n * await census.identify({\n * userId: 'user_123',\n * email: 'john@example.com',\n * name: 'John Doe',\n * organizationId: 'org_456',\n * organizationName: 'Acme Inc',\n * });\n * ```\n */\n async identify(user: UserIdentity): Promise<void> {\n if (!user.userId) {\n throw new Error('Census: userId is required for identify()');\n }\n\n this.currentUserId = user.userId;\n\n await this.request('/api/sdk/identify', 'POST', {\n userId: user.userId,\n email: user.email,\n name: user.name,\n avatarUrl: user.avatarUrl,\n metadata: user.metadata,\n organizationId: user.organizationId,\n organizationName: user.organizationName,\n organizationDomain: user.organizationDomain,\n organizationPlan: user.organizationPlan,\n });\n\n this.log('User identified:', user.userId);\n }\n\n /**\n * Clear the current user identity.\n * Call this when a user logs out.\n */\n reset(): void {\n this.currentUserId = null;\n this.log('User identity reset');\n }\n\n /**\n * Submit feedback, bug report, or feature request.\n *\n * @param options - Feedback options\n *\n * @example\n * ```typescript\n * // Submit a bug report\n * await census.submitFeedback({\n * type: 'bug_report',\n * message: 'The submit button is not working on Firefox',\n * });\n *\n * // Submit a feature request\n * await census.submitFeedback({\n * type: 'feature_request',\n * message: 'It would be great to have dark mode support',\n * });\n *\n * // Rate an article\n * await census.submitFeedback({\n * type: 'article_rating',\n * articleId: 'article_123',\n * helpful: true,\n * rating: 5,\n * });\n * ```\n */\n async submitFeedback(options: FeedbackOptions): Promise<{ feedbackId: string }> {\n const validTypes = ['feedback', 'bug_report', 'feature_request', 'article_rating'];\n if (!options.type || !validTypes.includes(options.type)) {\n throw new Error(`Census: type must be one of: ${validTypes.join(', ')}`);\n }\n\n if (options.type === 'article_rating') {\n if (options.rating === undefined && options.helpful === undefined) {\n throw new Error('Census: article_rating requires rating or helpful field');\n }\n } else if (!options.message) {\n throw new Error('Census: message is required for this feedback type');\n }\n\n const response = await this.request<{ success: boolean; feedbackId: string }>(\n '/api/sdk/feedback',\n 'POST',\n {\n type: options.type,\n message: options.message,\n rating: options.rating,\n helpful: options.helpful,\n userId: this.currentUserId,\n articleId: options.articleId,\n pageUrl: typeof window !== 'undefined' ? window.location.href : undefined,\n metadata: options.metadata,\n }\n );\n\n this.log('Feedback submitted:', response.feedbackId);\n return { feedbackId: response.feedbackId };\n }\n\n /**\n * Fetch published articles from the knowledge base.\n *\n * @param options - Query options\n * @returns Articles and pagination info\n *\n * @example\n * ```typescript\n * // Get all articles\n * const { articles } = await census.getArticles();\n *\n * // Search articles\n * const { articles } = await census.getArticles({ search: 'getting started' });\n *\n * // Filter by category\n * const { articles } = await census.getArticles({ category: 'guides' });\n * ```\n */\n async getArticles(options?: ArticlesOptions): Promise<ArticlesResponse> {\n const params = new URLSearchParams();\n if (options?.category) params.set('category', options.category);\n if (options?.search) params.set('search', options.search);\n if (options?.limit) params.set('limit', String(options.limit));\n if (options?.offset) params.set('offset', String(options.offset));\n\n const queryString = params.toString();\n const url = `/api/sdk/articles${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<ArticlesResponse>(url, 'GET');\n this.log('Fetched articles:', response.articles.length);\n return response;\n }\n\n /**\n * Fetch a single article by slug or ID.\n *\n * @param slugOrId - Article slug or ID\n * @returns Article or null if not found\n *\n * @example\n * ```typescript\n * const article = await census.getArticle('getting-started');\n * if (article) {\n * console.log(article.title, article.content_html);\n * }\n * ```\n */\n async getArticle(slugOrId: string): Promise<Article | null> {\n try {\n const response = await this.request<{ article: Article }>(\n `/api/sdk/articles/${encodeURIComponent(slugOrId)}`,\n 'GET'\n );\n this.log('Fetched article:', slugOrId);\n return response.article;\n } catch (error) {\n if ((error as CensusError).status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch the current user's submitted requests (feedback, bugs, feature requests).\n * Requires a user to be identified first.\n *\n * @param options - Query options\n * @returns Requests and pagination info\n *\n * @example\n * ```typescript\n * // Get all requests for the current user\n * const { requests } = await census.getRequests();\n *\n * // Filter by status\n * const { requests } = await census.getRequests({ status: 'in_progress' });\n *\n * // Filter by type\n * const { requests } = await census.getRequests({ type: 'bug_report' });\n * ```\n */\n async getRequests(options?: RequestsOptions): Promise<RequestsResponse> {\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before fetching requests. Call identify() first.');\n }\n\n const params = new URLSearchParams();\n params.set('userId', this.currentUserId);\n if (options?.status) params.set('status', options.status);\n if (options?.type) params.set('type', options.type);\n if (options?.limit) params.set('limit', String(options.limit));\n if (options?.offset) params.set('offset', String(options.offset));\n\n const response = await this.request<RequestsResponse>(\n `/api/sdk/requests?${params.toString()}`,\n 'GET'\n );\n this.log('Fetched requests:', response.requests.length);\n return response;\n }\n\n /**\n * Track a custom analytics event.\n *\n * @param eventType - Name of the event\n * @param properties - Additional event properties\n *\n * @example\n * ```typescript\n * // Track a button click\n * await census.track('button_clicked', { buttonId: 'submit-form' });\n *\n * // Track a page view\n * await census.track('page_viewed', { page: '/pricing' });\n * ```\n */\n async track(eventType: string, properties?: Record<string, unknown>): Promise<void> {\n if (!eventType) {\n throw new Error('Census: eventType is required for track()');\n }\n\n await this.request('/api/sdk/events', 'POST', {\n eventType,\n userId: this.currentUserId,\n properties,\n });\n\n this.log('Event tracked:', eventType);\n }\n\n /**\n * Track multiple events in a single request.\n * More efficient than calling track() multiple times.\n *\n * @param events - Array of events to track\n *\n * @example\n * ```typescript\n * await census.trackBatch({\n * events: [\n * { eventType: 'page_viewed', properties: { page: '/home' } },\n * { eventType: 'button_clicked', properties: { button: 'cta' } },\n * ],\n * });\n * ```\n */\n async trackBatch(options: BatchEventsOptions): Promise<void> {\n if (!options.events || options.events.length === 0) {\n throw new Error('Census: at least one event is required');\n }\n\n if (options.events.length > 100) {\n throw new Error('Census: maximum 100 events per batch');\n }\n\n const events = options.events.map((event) => ({\n eventType: event.eventType,\n userId: this.currentUserId,\n articleId: event.articleId,\n featureId: event.featureId,\n properties: event.properties,\n }));\n\n await this.request('/api/sdk/events', 'POST', { events });\n\n this.log('Batch events tracked:', options.events.length);\n }\n\n /**\n * Fetch available guides for the current user.\n * Returns guides that match the user's context and haven't been completed.\n *\n * @returns Guides and list of completed guide IDs\n *\n * @example\n * ```typescript\n * const { guides, completedGuides } = await census.getGuides();\n * guides.forEach(guide => console.log(guide.name));\n * ```\n */\n async getGuides(): Promise<GuidesResponse> {\n const params = new URLSearchParams();\n if (this.currentUserId) {\n params.set('userId', this.currentUserId);\n }\n\n const queryString = params.toString();\n const url = `/api/sdk/guides${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<GuidesResponse>(url, 'GET');\n this.log('Fetched guides:', response.guides.length);\n return response;\n }\n\n /**\n * Fetch a single guide by slug or ID.\n *\n * @param slugOrId - Guide slug or ID\n * @returns Guide or null if not found\n *\n * @example\n * ```typescript\n * const guide = await census.getGuide('onboarding-tour');\n * if (guide) {\n * console.log(guide.name, guide.guide_steps.length);\n * }\n * ```\n */\n async getGuide(slugOrId: string): Promise<Guide | null> {\n try {\n const params = new URLSearchParams();\n if (this.currentUserId) {\n params.set('userId', this.currentUserId);\n }\n\n const queryString = params.toString();\n const url = `/api/sdk/guides/${encodeURIComponent(slugOrId)}${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<{ guide: Guide }>(url, 'GET');\n this.log('Fetched guide:', slugOrId);\n return response.guide;\n } catch (error) {\n if ((error as CensusError).status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Track a guide analytics event.\n * Used to track user progress through guides.\n *\n * @param event - Guide analytics event\n *\n * @example\n * ```typescript\n * await census.trackGuideEvent({\n * guideId: 'guide_123',\n * eventType: 'step_completed',\n * stepId: 'step_456',\n * stepIndex: 2,\n * sessionId: 'session_789',\n * });\n * ```\n */\n async trackGuideEvent(event: GuideAnalyticsEvent): Promise<void> {\n if (!event.guideId || !event.eventType || !event.sessionId) {\n throw new Error('Census: guideId, eventType, and sessionId are required for trackGuideEvent()');\n }\n\n await this.request('/api/sdk/guides/events', 'POST', {\n guideId: event.guideId,\n eventType: event.eventType,\n stepId: event.stepId,\n stepIndex: event.stepIndex,\n pageUrl: event.pageUrl || (typeof window !== 'undefined' ? window.location.href : undefined),\n sessionId: event.sessionId,\n userId: event.userId || this.currentUserId,\n metadata: event.metadata,\n });\n\n this.log('Guide event tracked:', event.eventType, event.guideId);\n }\n\n /**\n * Mark a guide as completed for the current user.\n * Prevents the guide from showing again.\n *\n * @param guideId - ID of the guide to mark as completed\n *\n * @example\n * ```typescript\n * await census.markGuideCompleted('guide_123');\n * ```\n */\n async markGuideCompleted(guideId: string): Promise<void> {\n if (!guideId) {\n throw new Error('Census: guideId is required for markGuideCompleted()');\n }\n\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before marking guides complete. Call identify() first.');\n }\n\n await this.request('/api/sdk/guides/complete', 'POST', {\n guideId,\n userId: this.currentUserId,\n });\n\n this.log('Guide marked completed:', guideId);\n }\n\n /**\n * Get the current identified user ID\n */\n getCurrentUserId(): string | null {\n return this.currentUserId;\n }\n\n /**\n * Check if a user is currently identified\n */\n isIdentified(): boolean {\n return this.currentUserId !== null;\n }\n\n /**\n * Make an API request\n */\n private async request<T>(path: string, method: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n 'X-Census-Key': this.apiKey,\n };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n }\n\n this.log(`${method} ${path}`, body);\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n let errorMessage = `Request failed with status ${response.status}`;\n try {\n const errorData = await response.json();\n errorMessage = errorData.error || errorMessage;\n } catch {\n // Use default error message\n }\n\n const error: CensusError = {\n error: errorMessage,\n status: response.status,\n };\n throw error;\n }\n\n return response.json();\n }\n\n /**\n * Log debug messages\n */\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[Census]', ...args);\n }\n }\n}\n\n/**\n * Create a new Census SDK client.\n *\n * @param config - Configuration options\n * @returns Census client instance\n *\n * @example\n * ```typescript\n * import { createCensus } from '@census-ai/census-sdk';\n *\n * const census = createCensus({\n * apiKey: 'cs_live_your_key_here',\n * debug: true, // Enable debug logging\n * });\n * ```\n */\nexport function createCensus(config: CensusConfig): CensusClient {\n return new CensusClient(config);\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":["DEFAULT_BASE_URL","CensusClient","config","prefix","user","options","validTypes","response","params","queryString","url","slugOrId","error","feedbackId","eventType","properties","events","event","guideId","path","method","body","headers","errorMessage","args","createCensus"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n CensusConfig,\n UserIdentity,\n FeedbackOptions,\n ArticlesOptions,\n ArticlesResponse,\n Article,\n RequestsOptions,\n RequestsResponse,\n BatchEventsOptions,\n CensusError,\n Guide,\n GuidesResponse,\n GuideAnalyticsEvent,\n FeatureGroupsResponse,\n} from './types';\n\n/**\n * Default API base URL\n */\nconst DEFAULT_BASE_URL = 'https://api.census.ai';\n\n/**\n * Census SDK Client\n *\n * The main client for interacting with the Census API.\n * Use `createCensus()` to create an instance.\n *\n * @example\n * ```typescript\n * import { createCensus } from '@census-ai/census-sdk';\n *\n * const census = createCensus({ apiKey: 'cs_live_xxx' });\n *\n * await census.identify({ userId: 'user_123', email: 'user@example.com' });\n * await census.submitFeedback({ type: 'bug_report', message: 'Button is broken' });\n * ```\n */\nexport class CensusClient {\n private apiKey: string;\n private baseUrl: string;\n private debug: boolean;\n private currentUserId: string | null = null;\n\n constructor(config: CensusConfig) {\n if (!config.apiKey) {\n throw new Error('Census: apiKey is required');\n }\n\n // Support both new (cs_) and legacy (op_) key prefixes\n const validPrefixes = ['cs_live_', 'cs_test_', 'op_live_', 'op_test_'];\n if (!validPrefixes.some(prefix => config.apiKey.startsWith(prefix))) {\n console.warn('Census: API key should start with \"cs_live_\" or \"cs_test_\"');\n }\n\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;\n this.debug = config.debug || false;\n\n this.log('Initialized with base URL:', this.baseUrl);\n }\n\n /**\n * Identify a user for tracking purposes.\n * Call this when a user logs in or when you have user information.\n *\n * @param user - User identity information\n *\n * @example\n * ```typescript\n * await census.identify({\n * userId: 'user_123',\n * email: 'john@example.com',\n * name: 'John Doe',\n * organizationId: 'org_456',\n * organizationName: 'Acme Inc',\n * });\n * ```\n */\n async identify(user: UserIdentity): Promise<void> {\n if (!user.userId) {\n throw new Error('Census: userId is required for identify()');\n }\n\n this.currentUserId = user.userId;\n\n await this.request('/api/sdk/identify', 'POST', {\n userId: user.userId,\n email: user.email,\n name: user.name,\n avatarUrl: user.avatarUrl,\n metadata: user.metadata,\n organizationId: user.organizationId,\n organizationName: user.organizationName,\n organizationDomain: user.organizationDomain,\n organizationPlan: user.organizationPlan,\n });\n\n this.log('User identified:', user.userId);\n }\n\n /**\n * Clear the current user identity.\n * Call this when a user logs out.\n */\n reset(): void {\n this.currentUserId = null;\n this.log('User identity reset');\n }\n\n /**\n * Submit feedback, bug report, or feature request.\n *\n * @param options - Feedback options\n *\n * @example\n * ```typescript\n * // Submit a bug report\n * await census.submitFeedback({\n * type: 'bug_report',\n * message: 'The submit button is not working on Firefox',\n * });\n *\n * // Submit a feature request\n * await census.submitFeedback({\n * type: 'feature_request',\n * message: 'It would be great to have dark mode support',\n * });\n *\n * // Rate an article\n * await census.submitFeedback({\n * type: 'article_rating',\n * articleId: 'article_123',\n * helpful: true,\n * rating: 5,\n * });\n * ```\n */\n async submitFeedback(options: FeedbackOptions): Promise<{ feedbackId: string }> {\n const validTypes = ['feedback', 'bug_report', 'feature_request', 'article_rating'];\n if (!options.type || !validTypes.includes(options.type)) {\n throw new Error(`Census: type must be one of: ${validTypes.join(', ')}`);\n }\n\n if (options.type === 'article_rating') {\n if (options.rating === undefined && options.helpful === undefined) {\n throw new Error('Census: article_rating requires rating or helpful field');\n }\n } else if (!options.message) {\n throw new Error('Census: message is required for this feedback type');\n }\n\n const response = await this.request<{ success: boolean; feedbackId: string }>(\n '/api/sdk/feedback',\n 'POST',\n {\n type: options.type,\n message: options.message,\n rating: options.rating,\n helpful: options.helpful,\n userId: this.currentUserId,\n articleId: options.articleId,\n pageUrl: typeof window !== 'undefined' ? window.location.href : undefined,\n metadata: options.metadata,\n }\n );\n\n this.log('Feedback submitted:', response.feedbackId);\n return { feedbackId: response.feedbackId };\n }\n\n /**\n * Fetch published articles from the knowledge base.\n *\n * @param options - Query options\n * @returns Articles and pagination info\n *\n * @example\n * ```typescript\n * // Get all articles\n * const { articles } = await census.getArticles();\n *\n * // Search articles\n * const { articles } = await census.getArticles({ search: 'getting started' });\n *\n * // Filter by category\n * const { articles } = await census.getArticles({ category: 'guides' });\n * ```\n */\n async getArticles(options?: ArticlesOptions): Promise<ArticlesResponse> {\n const params = new URLSearchParams();\n if (options?.category) params.set('category', options.category);\n if (options?.search) params.set('search', options.search);\n if (options?.limit) params.set('limit', String(options.limit));\n if (options?.offset) params.set('offset', String(options.offset));\n\n const queryString = params.toString();\n const url = `/api/sdk/articles${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<ArticlesResponse>(url, 'GET');\n this.log('Fetched articles:', response.articles.length);\n return response;\n }\n\n /**\n * Fetch a single article by slug or ID.\n *\n * @param slugOrId - Article slug or ID\n * @returns Article or null if not found\n *\n * @example\n * ```typescript\n * const article = await census.getArticle('getting-started');\n * if (article) {\n * console.log(article.title, article.content_html);\n * }\n * ```\n */\n async getArticle(slugOrId: string): Promise<Article | null> {\n try {\n const response = await this.request<{ article: Article }>(\n `/api/sdk/articles/${encodeURIComponent(slugOrId)}`,\n 'GET'\n );\n this.log('Fetched article:', slugOrId);\n return response.article;\n } catch (error) {\n if ((error as CensusError).status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch feature groups with their features and article counts.\n * Used for navigation in the knowledge base.\n *\n * @returns Feature groups with nested features\n *\n * @example\n * ```typescript\n * const { feature_groups } = await census.getFeatureGroups();\n * feature_groups.forEach(group => {\n * console.log(group.name, group.features.length);\n * });\n * ```\n */\n async getFeatureGroups(): Promise<FeatureGroupsResponse> {\n const response = await this.request<FeatureGroupsResponse>(\n '/api/sdk/feature-groups',\n 'GET'\n );\n this.log('Fetched feature groups:', response.feature_groups.length);\n return response;\n }\n\n /**\n * Fetch the current user's submitted requests (feedback, bugs, feature requests).\n * Requires a user to be identified first.\n *\n * @param options - Query options\n * @returns Requests and pagination info\n *\n * @example\n * ```typescript\n * // Get all requests for the current user\n * const { requests } = await census.getRequests();\n *\n * // Filter by status\n * const { requests } = await census.getRequests({ status: 'in_progress' });\n *\n * // Filter by type\n * const { requests } = await census.getRequests({ type: 'bug_report' });\n * ```\n */\n async getRequests(options?: RequestsOptions): Promise<RequestsResponse> {\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before fetching requests. Call identify() first.');\n }\n\n const params = new URLSearchParams();\n params.set('userId', this.currentUserId);\n if (options?.status) params.set('status', options.status);\n if (options?.type) params.set('type', options.type);\n if (options?.limit) params.set('limit', String(options.limit));\n if (options?.offset) params.set('offset', String(options.offset));\n\n const response = await this.request<RequestsResponse>(\n `/api/sdk/requests?${params.toString()}`,\n 'GET'\n );\n this.log('Fetched requests:', response.requests.length);\n return response;\n }\n\n /**\n * Vote on a feedback request (toggle).\n * If the user has already voted, removes the vote.\n * If the user hasn't voted, adds a vote.\n *\n * @param feedbackId - ID of the feedback to vote on\n * @returns Vote result with action taken and new vote count\n *\n * @example\n * ```typescript\n * // Vote on a feedback request\n * const result = await census.vote('feedback-id-123');\n * console.log(result.action); // 'added' or 'removed'\n * console.log(result.vote_count); // 5\n * console.log(result.user_has_voted); // true\n * ```\n */\n async vote(feedbackId: string): Promise<{\n success: boolean;\n action: 'added' | 'removed';\n vote_count: number;\n user_has_voted: boolean;\n }> {\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before voting. Call identify() first.');\n }\n\n if (!feedbackId) {\n throw new Error('Census: feedbackId is required for vote()');\n }\n\n const response = await this.request<{\n success: boolean;\n action: 'added' | 'removed';\n vote_count: number;\n user_has_voted: boolean;\n }>('/api/sdk/requests/vote', 'POST', {\n feedbackId,\n userId: this.currentUserId,\n });\n\n this.log('Vote result:', response.action, 'for feedback:', feedbackId);\n return response;\n }\n\n /**\n * Track a custom analytics event.\n *\n * @param eventType - Name of the event\n * @param properties - Additional event properties\n *\n * @example\n * ```typescript\n * // Track a button click\n * await census.track('button_clicked', { buttonId: 'submit-form' });\n *\n * // Track a page view\n * await census.track('page_viewed', { page: '/pricing' });\n * ```\n */\n async track(eventType: string, properties?: Record<string, unknown>): Promise<void> {\n if (!eventType) {\n throw new Error('Census: eventType is required for track()');\n }\n\n await this.request('/api/sdk/events', 'POST', {\n eventType,\n userId: this.currentUserId,\n properties,\n });\n\n this.log('Event tracked:', eventType);\n }\n\n /**\n * Track multiple events in a single request.\n * More efficient than calling track() multiple times.\n *\n * @param events - Array of events to track\n *\n * @example\n * ```typescript\n * await census.trackBatch({\n * events: [\n * { eventType: 'page_viewed', properties: { page: '/home' } },\n * { eventType: 'button_clicked', properties: { button: 'cta' } },\n * ],\n * });\n * ```\n */\n async trackBatch(options: BatchEventsOptions): Promise<void> {\n if (!options.events || options.events.length === 0) {\n throw new Error('Census: at least one event is required');\n }\n\n if (options.events.length > 100) {\n throw new Error('Census: maximum 100 events per batch');\n }\n\n const events = options.events.map((event) => ({\n eventType: event.eventType,\n userId: this.currentUserId,\n articleId: event.articleId,\n featureId: event.featureId,\n properties: event.properties,\n }));\n\n await this.request('/api/sdk/events', 'POST', { events });\n\n this.log('Batch events tracked:', options.events.length);\n }\n\n /**\n * Fetch available guides for the current user.\n * Returns guides that match the user's context and haven't been completed.\n *\n * @returns Guides and list of completed guide IDs\n *\n * @example\n * ```typescript\n * const { guides, completedGuides } = await census.getGuides();\n * guides.forEach(guide => console.log(guide.name));\n * ```\n */\n async getGuides(): Promise<GuidesResponse> {\n const params = new URLSearchParams();\n if (this.currentUserId) {\n params.set('userId', this.currentUserId);\n }\n\n const queryString = params.toString();\n const url = `/api/sdk/guides${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<GuidesResponse>(url, 'GET');\n this.log('Fetched guides:', response.guides.length);\n return response;\n }\n\n /**\n * Fetch a single guide by slug or ID.\n *\n * @param slugOrId - Guide slug or ID\n * @returns Guide or null if not found\n *\n * @example\n * ```typescript\n * const guide = await census.getGuide('onboarding-tour');\n * if (guide) {\n * console.log(guide.name, guide.guide_steps.length);\n * }\n * ```\n */\n async getGuide(slugOrId: string): Promise<Guide | null> {\n try {\n const params = new URLSearchParams();\n if (this.currentUserId) {\n params.set('userId', this.currentUserId);\n }\n\n const queryString = params.toString();\n const url = `/api/sdk/guides/${encodeURIComponent(slugOrId)}${queryString ? `?${queryString}` : ''}`;\n\n const response = await this.request<{ guide: Guide }>(url, 'GET');\n this.log('Fetched guide:', slugOrId);\n return response.guide;\n } catch (error) {\n if ((error as CensusError).status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Track a guide analytics event.\n * Used to track user progress through guides.\n *\n * @param event - Guide analytics event\n *\n * @example\n * ```typescript\n * await census.trackGuideEvent({\n * guideId: 'guide_123',\n * eventType: 'step_completed',\n * stepId: 'step_456',\n * stepIndex: 2,\n * sessionId: 'session_789',\n * });\n * ```\n */\n async trackGuideEvent(event: GuideAnalyticsEvent): Promise<void> {\n if (!event.guideId || !event.eventType || !event.sessionId) {\n throw new Error('Census: guideId, eventType, and sessionId are required for trackGuideEvent()');\n }\n\n await this.request('/api/sdk/guides/events', 'POST', {\n guideId: event.guideId,\n eventType: event.eventType,\n stepId: event.stepId,\n stepIndex: event.stepIndex,\n pageUrl: event.pageUrl || (typeof window !== 'undefined' ? window.location.href : undefined),\n sessionId: event.sessionId,\n userId: event.userId || this.currentUserId,\n metadata: event.metadata,\n });\n\n this.log('Guide event tracked:', event.eventType, event.guideId);\n }\n\n /**\n * Mark a guide as completed for the current user.\n * Prevents the guide from showing again.\n *\n * @param guideId - ID of the guide to mark as completed\n *\n * @example\n * ```typescript\n * await census.markGuideCompleted('guide_123');\n * ```\n */\n async markGuideCompleted(guideId: string): Promise<void> {\n if (!guideId) {\n throw new Error('Census: guideId is required for markGuideCompleted()');\n }\n\n if (!this.currentUserId) {\n throw new Error('Census: User must be identified before marking guides complete. Call identify() first.');\n }\n\n await this.request('/api/sdk/guides/complete', 'POST', {\n guideId,\n userId: this.currentUserId,\n });\n\n this.log('Guide marked completed:', guideId);\n }\n\n /**\n * Get the current identified user ID\n */\n getCurrentUserId(): string | null {\n return this.currentUserId;\n }\n\n /**\n * Check if a user is currently identified\n */\n isIdentified(): boolean {\n return this.currentUserId !== null;\n }\n\n /**\n * Make an API request\n */\n private async request<T>(path: string, method: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n 'X-Census-Key': this.apiKey,\n };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n }\n\n this.log(`${method} ${path}`, body);\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n let errorMessage = `Request failed with status ${response.status}`;\n try {\n const errorData = await response.json();\n errorMessage = errorData.error || errorMessage;\n } catch {\n // Use default error message\n }\n\n const error: CensusError = {\n error: errorMessage,\n status: response.status,\n };\n throw error;\n }\n\n return response.json();\n }\n\n /**\n * Log debug messages\n */\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[Census]', ...args);\n }\n }\n}\n\n/**\n * Create a new Census SDK client.\n *\n * @param config - Configuration options\n * @returns Census client instance\n *\n * @example\n * ```typescript\n * import { createCensus } from '@census-ai/census-sdk';\n *\n * const census = createCensus({\n * apiKey: 'cs_live_your_key_here',\n * debug: true, // Enable debug logging\n * });\n * ```\n */\nexport function createCensus(config: CensusConfig): CensusClient {\n return new CensusClient(config);\n}\n"]}