From d820a39223b6c54c398c4bebbc70f6e0a160d688 Mon Sep 17 00:00:00 2001 From: Mo Elzubeir Date: Fri, 29 May 2026 13:46:11 -0500 Subject: [PATCH] chore: prepare JavaScript SDK for npm publish --- sdks/javascript/README.md | 7 +++++- sdks/javascript/docs/API.md | 45 +++++++++++++++++++++++++++++++++++- sdks/javascript/package.json | 10 +++++++- sdks/javascript/src/index.ts | 32 +++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 3 deletions(-) diff --git a/sdks/javascript/README.md b/sdks/javascript/README.md index cbb151c..afaa44b 100644 --- a/sdks/javascript/README.md +++ b/sdks/javascript/README.md @@ -99,6 +99,11 @@ pnpm build Publishing: +Preferred publish path is the release workflow, which runs with npm provenance from CI. Before publishing, verify npm authentication and `@socialhose` scope access: + ```bash -npm publish --access public --provenance +npm whoami +npm publish --dry-run --access public --provenance ``` + +For the actual release, publish from CI with provenance enabled. If you must publish locally, first confirm whether npm provenance is supported in that environment. diff --git a/sdks/javascript/docs/API.md b/sdks/javascript/docs/API.md index 246e8a5..774cd06 100644 --- a/sdks/javascript/docs/API.md +++ b/sdks/javascript/docs/API.md @@ -4,7 +4,7 @@ Public API reference for `@socialhose/api`, the TypeScript SDK for the Socialhos The SDK is intended for server-side JavaScript/TypeScript. It authenticates requests with an API key, wraps Socialhose REST endpoints, normalizes common response shapes, retries transient failures, applies request timeouts, and caches GET responses. -## Package exports +## Common imports ```ts import { @@ -18,9 +18,52 @@ import { type RequestOptions, type AnalyticsFilters, type MentionFilters, + type Mention, + type Paginated, + type EntityBrief, + type EntityStats, } from '@socialhose/api'; ``` +## Public exports + +Runtime exports: + +- `SocialhoseClient` +- `createSocialhoseClient` +- `SocialhoseError` +- `MemoryCache` +- `NoopCache` + +Type exports: + +- `AnalyticsFilters` +- `Cache` +- `Campaign` +- `EntityBrief` +- `EntityStats` +- `InviteOutcome` +- `InviteResult` +- `KeywordStat` +- `MailingList` +- `MailingListInvitation` +- `Mention` +- `MentionFilters` +- `Overview` +- `Paginated` +- `PlatformShare` +- `PlatformStat` +- `QueryParams` +- `QueryValue` +- `RequestOptions` +- `Sentiment` +- `SentimentSplit` +- `ShareOfVoiceItem` +- `SocialhoseClientOptions` +- `TimelinePoint` +- `TopMention` +- `TrendingItem` + ## Authentication Every request sends: diff --git a/sdks/javascript/package.json b/sdks/javascript/package.json index 5181475..59cada1 100644 --- a/sdks/javascript/package.json +++ b/sdks/javascript/package.json @@ -3,8 +3,16 @@ "version": "0.1.0", "description": "TypeScript SDK for the Socialhose Public API.", "license": "MIT", + "author": "Socialhose", "type": "module", "sideEffects": false, + "packageManager": "pnpm@9.15.0", + "repository": { + "type": "git", + "url": "git+ssh://git@git.elzubeir.com/socialhose/sdk.git", + "directory": "sdks/javascript" + }, + "homepage": "https://socialhose.net", "files": [ "dist", "docs", @@ -29,7 +37,7 @@ "build": "tsup src/index.ts --format esm,cjs --dts --sourcemap --clean", "test": "vitest run", "typecheck": "tsc --noEmit", - "prepublishOnly": "pnpm test && pnpm typecheck && pnpm build" + "prepublishOnly": "npm run test && npm run typecheck && npm run build" }, "keywords": [ "socialhose", diff --git a/sdks/javascript/src/index.ts b/sdks/javascript/src/index.ts index 0228e75..83e5701 100644 --- a/sdks/javascript/src/index.ts +++ b/sdks/javascript/src/index.ts @@ -4,8 +4,11 @@ import { type Cache, MemoryCache, NoopCache } from './cache'; /** Sentiment label assigned to a mention by Socialhose. */ export type Sentiment = 'positive' | 'negative' | 'neutral'; +/** Count distribution across positive, negative, and neutral sentiment labels. */ export type SentimentSplit = { positive: number; negative: number; neutral: number }; +/** Primitive value accepted as a query-string parameter. Nullish and empty-string values are omitted. */ export type QueryValue = string | number | boolean | null | undefined; +/** Query-string parameter map used by low-level GET calls. */ export type QueryParams = Record; /** Configuration for {@link SocialhoseClient}. */ @@ -34,6 +37,7 @@ export interface RequestOptions { headers?: Record; } +/** Campaign metadata returned by `/campaigns/`. */ export interface Campaign { id: string; name: string; @@ -44,6 +48,7 @@ export interface Campaign { tags: string[]; } +/** Aggregate metrics returned by `/analytics/overview/`. */ export interface Overview { total_mentions: number; total_authors: number; @@ -66,6 +71,7 @@ export interface Overview { }; } +/** One time bucket returned by `/analytics/timeline/`. */ export interface TimelinePoint { date: string; count: number; @@ -73,6 +79,7 @@ export interface TimelinePoint { engagement: number; } +/** Campaign comparison row returned by `/analytics/share-of-voice/`. */ export interface ShareOfVoiceItem { campaign_id: string; name: string; @@ -82,18 +89,21 @@ export interface ShareOfVoiceItem { sentiment: SentimentSplit; } +/** Mention and engagement totals for one platform. */ export interface PlatformStat { platform: string; count: number; engagement: number; } +/** Top-keyword row with mention count and sentiment split. */ export interface KeywordStat { keyword: string; count: number; sentiment: SentimentSplit; } +/** Trending-keyword row comparing current and previous mention volume. */ export interface TrendingItem { keyword: string; count: number; @@ -101,6 +111,7 @@ export interface TrendingItem { change_pct: number; } +/** Compact high-impact mention returned by the analytics top-mentions endpoint. */ export interface TopMention { id: string; platform: string; @@ -115,6 +126,7 @@ export interface TopMention { content_preview: string; } +/** Full mention record returned by `/mentions/`, including content, engagement, metadata, and author profile. */ export interface Mention { id: string; platform: string; @@ -147,6 +159,7 @@ export interface Mention { }; } +/** Mailing-list metadata returned by `/mailing-lists/`. */ export interface MailingList { id: string; campaign_id: string; @@ -157,6 +170,7 @@ export interface MailingList { email_template: string; } +/** Invitation state returned when adding a mailing-list member. */ export interface MailingListInvitation { id: string; email: string; @@ -169,14 +183,17 @@ export interface MailingListInvitation { accepted_at: string | null; } +/** Normalized mailing-list invite outcome. */ export type InviteOutcome = 'invited' | 'already' | 'error'; +/** Normalized response from {@link SocialhoseClient.inviteMailingListMember}. */ export interface InviteResult { outcome: InviteOutcome; invitation?: MailingListInvitation; detail?: string; } +/** Standard paginated response envelope used by list endpoints. */ export interface Paginated { count: number; next: string | null; @@ -184,6 +201,7 @@ export interface Paginated { results: T[]; } +/** Common filters accepted by analytics endpoints. Values are passed through as query parameters. */ export interface AnalyticsFilters { campaign_ids?: string; date_from?: string; @@ -192,6 +210,7 @@ export interface AnalyticsFilters { sentiments?: string; } +/** Filters accepted by `/mentions/`, extending common analytics filters with pagination, search, and ordering. */ export interface MentionFilters extends AnalyticsFilters { page?: number; content_search?: string; @@ -207,11 +226,13 @@ export interface MentionFilters extends AnalyticsFilters { // when count <= 20, which covers most entities at current volume); a few // count-only requests add precise week-over-week momentum. +/** Platform count pair used by entity analytics. */ export interface PlatformShare { platform: string; count: number; } +/** Compact analytics for one term from a single mention search. */ export interface EntityBrief { term: string; total: number; @@ -221,6 +242,7 @@ export interface EntityBrief { sample: Mention[]; // up to 20, ordered by engagement } +/** Rich entity dashboard assembled from multiple mention-search facets. */ export interface EntityStats extends EntityBrief { recent: Mention[]; // up to 20, newest first recent7d: number; @@ -391,6 +413,7 @@ export class SocialhoseClient { return { ...d, total_mentions: num(d.total_mentions), total_authors: num(d.total_authors) }; } + /** Fetch analytics time-series buckets; defaults to daily interval. */ async getTimeline( filters: AnalyticsFilters & { interval?: 'day' | 'week' | 'month' } = {}, options: RequestOptions = {}, @@ -403,6 +426,7 @@ export class SocialhoseClient { return d.series ?? []; } + /** Fetch overall and platform-specific sentiment distributions. */ getSentiment( filters: AnalyticsFilters = {}, options: RequestOptions = {}, @@ -410,6 +434,7 @@ export class SocialhoseClient { return this.get('/analytics/sentiment/', filters as QueryParams, options); } + /** Fetch campaign share-of-voice comparison metrics. */ getShareOfVoice( filters: AnalyticsFilters = {}, options: RequestOptions = {}, @@ -417,11 +442,13 @@ export class SocialhoseClient { return this.get('/analytics/share-of-voice/', filters as QueryParams, options); } + /** Fetch mention and engagement totals grouped by platform. */ async getPlatforms(filters: AnalyticsFilters = {}, options: RequestOptions = {}): Promise { const d = await this.get<{ platforms?: PlatformStat[] }>('/analytics/platforms/', filters as QueryParams, options); return d.platforms ?? []; } + /** Fetch top keywords; defaults to 12 items. */ async getTopKeywords( filters: AnalyticsFilters & { limit?: number } = {}, options: RequestOptions = {}, @@ -434,6 +461,7 @@ export class SocialhoseClient { return d.keywords ?? []; } + /** Fetch trending keywords; defaults to 8 items. */ async getTrending( filters: AnalyticsFilters & { limit?: number } = {}, options: RequestOptions = {}, @@ -446,6 +474,7 @@ export class SocialhoseClient { return d.trending ?? []; } + /** Fetch top mentions by impact; defaults to 6 items. */ async getTopMentions( filters: AnalyticsFilters & { limit?: number } = {}, options: RequestOptions = {}, @@ -458,6 +487,7 @@ export class SocialhoseClient { return d.mentions ?? []; } + /** Fetch a paginated mention page with campaign/date/platform/sentiment/search/order filters. */ getMentions( filters: MentionFilters = {}, optionsOrRevalidate: RequestOptions | number = {}, @@ -466,11 +496,13 @@ export class SocialhoseClient { return this.get>('/mentions/', { page: 1, ...filters }, options); } + /** Fetch the first page of mailing lists. */ async getMailingLists(options: RequestOptions = {}): Promise { const d = await this.get>('/mailing-lists/', { page: 1 }, options); return d.results; } + /** Invite a recipient to a mailing list and normalize invited/already/error outcomes. */ async inviteMailingListMember( listId: string, invite: { email: string; first_name?: string; last_name?: string; invitation_message?: string },