@villagehq/extension-sdk
Version:
Village Chrome Extension SDK for Partner Integrations
275 lines (253 loc) • 8.44 kB
TypeScript
/**
* Accepted shapes for `bindExtension`. The new shape is `{ enabled: boolean }`.
*
* The `string` arm is a one-release backwards-compatibility shim: pre-B-2
* hosts in the wild send a JSON-stringified boolean (`"true"` or `"false"`)
* because of a contract bug. Drop the string arm in Phase C once telemetry
* confirms zero string-shape callers.
*
* @deprecated The `string` form is legacy — send `{ enabled: boolean }`.
*/
export declare type BindExtensionInput = {
enabled: boolean;
} | string;
/**
* Result of a `checkPaths` lookup. Either a relationship payload (with token
* and userReference attached) or a redirect prompt when the user isn't
* signed in to Village.
*/
declare type CheckPathsResult = {
relationship?: {
warmth_score?: number;
paths?: {
count?: number;
avatars?: string[];
};
[key: string]: unknown;
};
token?: string | false;
userReference?: string;
[key: string]: unknown;
} | {
message: string;
redirect: true;
} | null;
declare type ExternalCommand = ExternalRequest['message'];
declare type ExternalRequest = {
message: 'getExtensionStatus';
shouldTriggerReset?: boolean;
} | {
message: 'livelinessCheck';
} | {
message: 'fillUpEmail';
email: string;
} | {
message: 'GET_MUTUAL_CONNECTIONS';
profileSlug: string;
};
declare type ExternalResponse = ExternalResponseMap[ExternalCommand];
declare type ExternalResponseMap = {
getExtensionStatus: UiSettings;
livelinessCheck: {
getProfileUserDetails: boolean;
getContactInfo: boolean;
getLinkedinLoggedinUserInfo: boolean;
getProfileConnections: boolean;
};
fillUpEmail: {
success: true;
};
GET_MUTUAL_CONNECTIONS: MutualConnectionsResult | {
error: true;
message: string;
};
};
/**
* Proxy CLIENT — call from popup, content script, or partner tooling.
* Returns a strongly-typed `VillageService` whose methods marshal arguments
* through `browser.runtime.sendMessage`.
*/
export declare function getVillageService(): VillageService;
declare type InternalCommand = InternalRequest['command'];
declare type InternalRequest = {
command: 'village:bind:extension';
data: VillageBindSettings;
} | {
command: 'saveUISettings';
data: UserLoggedObj;
} | {
command: 'getUserIntegration';
} | {
command: 'getSettings';
} | {
command: 'checkPaths';
url: string;
} | {
command: 'tracking';
eventName: string;
properties?: Record<string, unknown>;
/**
* @deprecated Ignored since anonymous capture was removed — events
* without a logged-in user id are always dropped. Kept so pre-existing
* hosts sending `force` still typecheck against this wire format.
*/
force?: boolean;
} | {
command: 'bridge:relay';
payload: ExternalRequest;
};
declare type InternalResponseMap = {
'village:bind:extension': {
success: true;
} | {
error: string;
};
saveUISettings: {
success: true;
} | {
error: string;
};
getUserIntegration: {
success: true;
} | {
error: string;
};
getSettings: {
uiSettings: UiSettings;
};
checkPaths: CheckPathsResult;
tracking: {
success: true;
} | {
error: string;
};
'bridge:relay': ExternalResponse | {
error: string;
} | undefined;
};
/**
* Result of `GET_MUTUAL_CONNECTIONS` — array of normalized connection objects
* pulled from LinkedIn voyager. Order and field availability depend on the
* endpoint variant (current vs legacy) — fields are best-effort.
*/
declare type MutualConnection = {
name?: string;
slug?: string;
headline?: string;
location?: string;
profileUrl?: string;
distance?: string;
};
declare type MutualConnectionsResult = MutualConnection[];
/**
* Sender-aware client for the bridge-relay path. Used only by the SDK's
* content script — partner tooling has no reason to reach this surface
* directly. Callers receive the same response shape the SW would have
* returned for the underlying external command.
*/
export declare function relayBridgeMessage(payload: ExternalRequest): Promise<ExternalResponse | {
error: string;
} | undefined>;
declare type RequestFor<C extends InternalCommand> = Extract<InternalRequest, {
command: C;
}>;
declare type ResponseFor<C extends InternalCommand> = InternalResponseMap[C];
/**
* @deprecated since 0.3.0 — use `getVillageService()` and call methods
* directly. This shim maps old `{ command, ...fields }` payloads onto the new
* proxy service so pre-0.3.0 hosts keep working for one release. Will be
* removed in 0.4.0.
*
* Migration:
* - `sendMessage({ command: 'getSettings' })`
* → `getVillageService().getSettings()`
* - `sendMessage({ command: 'saveUISettings', data })`
* → `getVillageService().saveUISettings(data)`
* - `sendMessage({ command: 'tracking', eventName, properties })`
* → `getVillageService().tracking(eventName, properties)`
*/
export declare function sendMessage<C extends InternalCommand>(msg: RequestFor<C>): Promise<ResponseFor<C>>;
/**
* Tracking Events Constants for Extension SDK
*
* Subset of events used by the extension SDK. Names follow the main app's
* typed-tracking convention (yalla PR #556): snake_case, past-tense outcome
* verbs. `paths_viewed` intentionally matches the webapp's event of the same
* name so both surfaces land in one stream.
*/
export declare const TRACKING_EVENTS: {
PATHS_VIEWED: string;
PATHS_PREVIEWED: string;
PATHS_EVERYWHERE_FLOATING_ICON_SHOWN: string;
PATHS_EVERYWHERE_SHOWN: string;
PATHS_EVERYWHERE_HIDDEN: string;
PATHS_EVERYWHERE_ACTIVATED: string;
PATHS_EVERYWHERE_DEACTIVATED: string;
EXTENSION_DAILY_REPORT: string;
};
/**
* Snapshot of login + manifest state returned by `getSettings` / the
* `getExtensionStatus` external command. Boolean-ish because the underlying
* storage values may be `null` when never written.
*/
declare interface UiSettings {
linkedin_login: boolean | null;
linkedin_loggedin_email: string | null;
frontend_login: boolean | null;
user_logged_obj: UserLoggedObj | null;
version: string;
}
/**
* Domain object shapes used by the message map.
*
* These are the runtime shapes the SDK observes from the Village backend and
* LinkedIn voyager API. They're intentionally permissive: most are partial
* snapshots of opaque server responses. Phase B will tighten these once the
* backend ships proper schemas.
*/
/**
* Authenticated Village user, persisted under the `user_logged_obj` storage
* key. The SDK reads `id`, `name`, and `app.config.*` for paths-everywhere
* branding; everything else is forwarded to partner code as-is.
*/
declare interface UserLoggedObj {
id?: string;
name?: string;
email?: string;
app?: Record<string, unknown>;
cacheDate?: string;
[key: string]: unknown;
}
/**
* Settings stored under the `village:bind:extension` sync-storage key.
* Re-declared (instead of imported from `messages.ts`) to keep this module
* free of cross-imports from the message map.
*/
declare interface VillageBindSettings {
enabled: boolean;
}
/**
* Public-facing shape of the proxied service. Each method maps 1:1 to a
* Phase A internal command. Method names are camelCase; the legacy command
* strings (`village:bind:extension`, `getUserIntegration`, etc.) survive only
* inside the deprecation shim in `messaging.ts`.
*/
export declare interface VillageService {
bindExtension(input: BindExtensionInput): Promise<{
success: true;
}>;
saveUISettings(data: UserLoggedObj): Promise<{
success: true;
}>;
getUserIntegration(): Promise<{
success: true;
}>;
getSettings(): Promise<{
uiSettings: UiSettings;
}>;
checkPaths(url: string): Promise<CheckPathsResult>;
tracking(eventName: string, properties?: Record<string, unknown>): Promise<{
success: true;
}>;
}
export { }