chore: prepare JavaScript SDK for npm publish

This commit is contained in:
Mo Elzubeir
2026-05-29 13:46:11 -05:00
parent c860cf6d88
commit d820a39223
4 changed files with 91 additions and 3 deletions
+6 -1
View File
@@ -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.
+44 -1
View File
@@ -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:
+9 -1
View File
@@ -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",
+32
View File
@@ -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<string, QueryValue>;
/** Configuration for {@link SocialhoseClient}. */
@@ -34,6 +37,7 @@ export interface RequestOptions {
headers?: Record<string, string>;
}
/** 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<T> {
count: number;
next: string | null;
@@ -184,6 +201,7 @@ export interface Paginated<T> {
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<PlatformStat[]> {
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<Paginated<Mention>>('/mentions/', { page: 1, ...filters }, options);
}
/** Fetch the first page of mailing lists. */
async getMailingLists(options: RequestOptions = {}): Promise<MailingList[]> {
const d = await this.get<Paginated<MailingList>>('/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 },