@pushary/server 1.3.3 → 1.4.0
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/README.md +54 -0
- package/dist/adapters.cjs +452 -0
- package/dist/adapters.cjs.map +1 -0
- package/dist/adapters.d.cts +158 -0
- package/dist/adapters.d.ts +158 -0
- package/dist/adapters.js +156 -0
- package/dist/adapters.js.map +1 -0
- package/dist/chunk-22FUZ6F5.js +274 -0
- package/dist/chunk-22FUZ6F5.js.map +1 -0
- package/dist/index.d.cts +2 -412
- package/dist/index.d.ts +2 -412
- package/dist/index.js +9 -265
- package/dist/index.js.map +1 -1
- package/dist/util-Ihfh4f82.d.cts +419 -0
- package/dist/util-Ihfh4f82.d.ts +419 -0
- package/package.json +6 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/error.ts","../src/request.ts","../src/resources/subscribers.ts","../src/resources/campaigns.ts","../src/resources/templates.ts","../src/resources/notifications.ts","../src/resources/flows.ts","../src/resources/decisions.ts","../src/util.ts","../src/resources/keys.ts","../src/client.ts","../src/webhook.ts"],"sourcesContent":["/**\n * Thrown for any non-2xx response from the API.\n *\n * Extends Error rather than replacing it, so every existing `catch (e)` that\n * reads `e.message` keeps working unchanged. What it adds is the thing callers\n * previously had to string-match the message for: an HTTP status they can branch\n * on. Telling a revoked key (401) apart from a plan limit (403), a bad argument\n * (400) and an outage (5xx) is the difference between \"stop and re-authenticate\"\n * and \"retry in a minute\", and message text is not a stable API to decide that on.\n */\nexport class PusharyApiError extends Error {\n /** HTTP status of the response that failed. */\n readonly status: number\n /** HTTP status text, when the runtime provides one. */\n readonly statusText: string\n /** The API's own machine-readable error code, when it sent one. */\n readonly code?: string\n /** The parsed response body, for anything the fields above do not cover. */\n readonly body?: unknown\n\n constructor(\n message: string,\n init: { status: number; statusText?: string; code?: string; body?: unknown }\n ) {\n super(message)\n this.name = 'PusharyApiError'\n this.status = init.status\n this.statusText = init.statusText ?? ''\n this.code = init.code\n this.body = init.body\n // Restores the prototype chain so `err instanceof PusharyApiError` holds\n // even when this package is consumed as ES5-targeted CommonJS.\n Object.setPrototypeOf(this, PusharyApiError.prototype)\n }\n\n /** The key is missing, malformed, or revoked. Re-authenticate; do not retry. */\n get isAuthError(): boolean {\n return this.status === 401 || this.status === 403\n }\n\n /** Rate limited. Back off and retry. */\n get isRateLimited(): boolean {\n return this.status === 429\n }\n\n /** Server-side fault. Safe to retry an idempotent call. */\n get isServerError(): boolean {\n return this.status >= 500\n }\n}\n","import type { RequestContext, RequestFn } from './types'\nimport { PusharyApiError } from './error'\n\nconst buildUrl = (baseUrl: string, path: string, params?: Record<string, unknown>): string => {\n // Build from the full absolute URL so the base path (e.g. /api/v1/server) is\n // preserved. `new URL(path, baseUrl)` treats a leading-slash path as absolute\n // and would drop that prefix, sending GET-with-query calls to the wrong URL.\n const url = new URL(`${baseUrl}${path}`)\n\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n })\n }\n \n return url.toString()\n}\n\nconst handleResponse = async <T>(response: Response): Promise<T> => {\n if (!response.ok) {\n // The API returns its reason under `error`; older paths use `message`. Read\n // both so callers get the real reason (e.g. \"No subscribers found\") instead\n // of a bare \"HTTP 400\" they cannot classify.\n const body = (await response.json().catch(() => ({}))) as {\n message?: string\n error?: string\n code?: string\n }\n // PusharyApiError extends Error, so an existing `catch (e) { e.message }`\n // is unaffected. It carries the status too, because the reason to branch on\n // a failure (re-authenticate vs back off vs retry) was previously only\n // recoverable by string-matching this message, which is not a stable API.\n throw new PusharyApiError(body.message || body.error || `HTTP ${response.status}`, {\n status: response.status,\n statusText: response.statusText,\n code: body.code,\n body,\n })\n }\n return response.json() as Promise<T>\n}\n\nexport const createRequest = (ctx: RequestContext): RequestFn =>\n async <T>(method: string, path: string, body?: unknown): Promise<T> => {\n const isGet = method === 'GET'\n const url = isGet && body \n ? buildUrl(ctx.baseUrl, path, body as Record<string, unknown>)\n : `${ctx.baseUrl}${path}`\n \n const response = await fetch(url, {\n method,\n headers: ctx.headers,\n body: !isGet && body ? JSON.stringify(body) : undefined,\n })\n \n return handleResponse<T>(response)\n }\n\n","import type {\n RequestFn,\n Subscriber,\n SubscriberListParams,\n UpdateSubscriber,\n PaginatedResponse,\n SubscriberCount,\n} from '../types'\n\nexport interface SubscribersResource {\n readonly list: (params?: SubscriberListParams) => Promise<PaginatedResponse<Subscriber>>\n readonly get: (id: string) => Promise<Subscriber>\n readonly update: (id: string, data: UpdateSubscriber) => Promise<Subscriber>\n readonly delete: (id: string) => Promise<void>\n readonly count: () => Promise<SubscriberCount>\n}\n\nexport const createSubscribersResource = (request: RequestFn): SubscribersResource =>\n Object.freeze({\n list: (params?: SubscriberListParams) =>\n request<PaginatedResponse<Subscriber>>('GET', '/subscribers', params),\n \n get: (id: string) =>\n request<Subscriber>('GET', `/subscribers/${id}`),\n \n update: (id: string, data: UpdateSubscriber) =>\n request<Subscriber>('PATCH', `/subscribers/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/subscribers/${id}`),\n \n count: () =>\n request<SubscriberCount>('GET', '/subscribers/count'),\n })\n\n","import type {\n RequestFn,\n Campaign,\n CreateCampaign,\n UpdateCampaign,\n ListParams,\n PaginatedResponse,\n CampaignStats,\n} from '../types'\n\nexport interface CampaignsResource {\n readonly list: (params?: ListParams) => Promise<PaginatedResponse<Campaign>>\n readonly create: (data: CreateCampaign) => Promise<Campaign>\n readonly get: (id: string) => Promise<Campaign>\n readonly update: (id: string, data: UpdateCampaign) => Promise<Campaign>\n readonly delete: (id: string) => Promise<void>\n readonly send: (id: string) => Promise<Campaign>\n readonly pause: (id: string) => Promise<Campaign>\n readonly resume: (id: string) => Promise<Campaign>\n readonly stats: (id: string) => Promise<CampaignStats>\n}\n\nexport const createCampaignsResource = (request: RequestFn): CampaignsResource =>\n Object.freeze({\n list: (params?: ListParams) =>\n request<PaginatedResponse<Campaign>>('GET', '/campaigns', params),\n \n create: (data: CreateCampaign) =>\n request<Campaign>('POST', '/campaigns', data),\n \n get: (id: string) =>\n request<Campaign>('GET', `/campaigns/${id}`),\n \n update: (id: string, data: UpdateCampaign) =>\n request<Campaign>('PATCH', `/campaigns/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/campaigns/${id}`),\n \n send: (id: string) =>\n request<Campaign>('POST', `/campaigns/${id}/send`),\n \n pause: (id: string) =>\n request<Campaign>('POST', `/campaigns/${id}/pause`),\n \n resume: (id: string) =>\n request<Campaign>('POST', `/campaigns/${id}/resume`),\n \n stats: (id: string) =>\n request<CampaignStats>('GET', `/campaigns/${id}/stats`),\n })\n\n","import type {\n RequestFn,\n Template,\n CreateTemplate,\n UpdateTemplate,\n ListParams,\n PaginatedResponse,\n} from '../types'\n\nexport interface TemplatesResource {\n readonly list: (params?: ListParams) => Promise<PaginatedResponse<Template>>\n readonly create: (data: CreateTemplate) => Promise<Template>\n readonly get: (id: string) => Promise<Template>\n readonly update: (id: string, data: UpdateTemplate) => Promise<Template>\n readonly delete: (id: string) => Promise<void>\n}\n\nexport const createTemplatesResource = (request: RequestFn): TemplatesResource =>\n Object.freeze({\n list: (params?: ListParams) =>\n request<PaginatedResponse<Template>>('GET', '/templates', params),\n \n create: (data: CreateTemplate) =>\n request<Template>('POST', '/templates', data),\n \n get: (id: string) =>\n request<Template>('GET', `/templates/${id}`),\n \n update: (id: string, data: UpdateTemplate) =>\n request<Template>('PATCH', `/templates/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/templates/${id}`),\n })\n\n","import type { RequestFn, SendNotification, SendResult } from '../types'\n\nexport interface NotificationsResource {\n readonly send: (data: SendNotification) => Promise<SendResult>\n}\n\nexport const createNotificationsResource = (request: RequestFn): NotificationsResource =>\n Object.freeze({\n send: (data: SendNotification) =>\n request<SendResult>('POST', '/send', data),\n })\n\n","import type {\n RequestFn,\n Flow,\n CreateFlow,\n UpdateFlow,\n FlowListParams,\n PaginatedResponse,\n} from '../types'\n\nexport interface FlowsResource {\n readonly list: (params?: FlowListParams) => Promise<PaginatedResponse<Flow>>\n readonly create: (data: CreateFlow) => Promise<Flow>\n readonly get: (id: string) => Promise<Flow>\n readonly update: (id: string, data: UpdateFlow) => Promise<Flow>\n readonly delete: (id: string) => Promise<void>\n readonly activate: (id: string) => Promise<Flow>\n readonly pause: (id: string) => Promise<Flow>\n}\n\nexport const createFlowsResource = (request: RequestFn): FlowsResource =>\n Object.freeze({\n list: (params?: FlowListParams) =>\n request<PaginatedResponse<Flow>>('GET', '/flows', params),\n \n create: (data: CreateFlow) =>\n request<Flow>('POST', '/flows', data),\n \n get: (id: string) =>\n request<Flow>('GET', `/flows/${id}`),\n \n update: (id: string, data: UpdateFlow) =>\n request<Flow>('PATCH', `/flows/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/flows/${id}`),\n \n activate: (id: string) =>\n request<Flow>('POST', `/flows/${id}/activate`),\n \n pause: (id: string) =>\n request<Flow>('POST', `/flows/${id}/pause`),\n })\n","import type {\n RequestFn,\n CreateDecision,\n DecisionResult,\n Decision,\n DecisionAnswerResult,\n CancelDecisionResult,\n WebhookSecret,\n AskDecision,\n AskResult,\n DecisionType,\n DecisionStatus,\n} from '../types'\nimport { randomUUID } from 'crypto'\nimport { isApproved } from '../util'\n\n// A single long-poll window. The server clamps GET ?wait to 55s, so ask() loops\n// windows of this size until the decision resolves or the caller deadline passes.\nconst POLL_WINDOW_SECONDS = 50\nconst DEFAULT_ASK_TIMEOUT_MS = 55_000\n\n// Human-in-the-loop decisions: ask a specific end-user to approve, then resume\n// on their answer via webhook or poll. See the Partner integration guide.\nexport interface DecisionsResource {\n // Create a decision. Defaults to async (returns immediately with a decisionId);\n // pass wait:true to block up to ~55s for a fast answer. Always pass\n // idempotencyKey so a retried call does not ask the same human twice.\n readonly create: (data: CreateDecision) => Promise<DecisionResult>\n // Poll for the outcome. opts.wait long-polls up to N seconds. Reads durably, so\n // it still resolves after the live window closes.\n readonly get: (id: string, opts?: { readonly wait?: number }) => Promise<Decision>\n // Create a decision and block until the human answers or the deadline passes,\n // polling durably (so a crashed/resumed process still gets the answer). Returns\n // a fail-closed `approved` flag. Default deadline 55s (serverless-safe); the\n // decision stays answerable for its full TTL, so an {answered:false} return is\n // resolvable later via get() or a callbackUrl. This is the one call most agents\n // need. Each call reaches the human: without an idempotencyKey a fresh unique\n // key is generated per call, so two asks with the same text never collapse into\n // one silent auto-approval. Pass your own stable idempotencyKey (tied to your\n // operation id) only when you WANT a retried call to dedupe.\n readonly ask: (data: AskDecision) => Promise<AskResult>\n // Relay the end-user's answer from your own authenticated app (delegated auth).\n readonly answer: (id: string, answer: string) => Promise<DecisionAnswerResult>\n readonly cancel: (id: string) => Promise<CancelDecisionResult>\n // Your webhook signing secret (created on first call). Verify callbacks with\n // verifyWebhookSignature(rawBody, header, secret).\n readonly getWebhookSecret: () => Promise<WebhookSecret>\n readonly rotateWebhookSecret: () => Promise<WebhookSecret>\n}\n\nexport const createDecisionsResource = (request: RequestFn): DecisionsResource => {\n const ask = async (data: AskDecision): Promise<AskResult> => {\n // Idempotency is caller intent, never inferred from content: two asks with the\n // same text are usually two distinct decisions, so a content hash would make\n // the second silently replay the first answer (auto-approving a second refund,\n // or blocking a re-ask for the server's whole idempotency window). Default to a\n // unique key per call so every ask reaches the human; callers wanting retry\n // dedup pass their own stable key tied to their operation.\n const idempotencyKey = data.idempotencyKey ?? randomUUID()\n\n const created = await request<DecisionResult>('POST', '/decisions', {\n question: data.question,\n type: data.type,\n options: data.options,\n externalId: data.externalId,\n email: data.email,\n agentName: data.agentName,\n context: data.context,\n placeholder: data.placeholder,\n expiresInSeconds: data.expiresInSeconds,\n poweredBy: data.poweredBy,\n callbackUrl: data.callbackUrl,\n requireReachable: data.requireReachable,\n idempotencyKey,\n wait: false,\n })\n\n const type: DecisionType = created.type ?? data.type ?? 'confirm'\n let status: DecisionStatus = created.status\n let answered = created.answered\n let value: string | null = created.value ?? null\n\n const deadline = Date.now() + Math.max(0, data.timeoutMs ?? DEFAULT_ASK_TIMEOUT_MS)\n while (status === 'pending' && Date.now() < deadline) {\n const waitSeconds = Math.max(\n 1,\n Math.min(POLL_WINDOW_SECONDS, Math.ceil((deadline - Date.now()) / 1000)),\n )\n const polled = await request<Decision>('GET', `/decisions/${created.decisionId}`, {\n wait: waitSeconds,\n })\n status = polled.status\n answered = polled.answered\n value = polled.value\n }\n\n return {\n decisionId: created.decisionId,\n status,\n answered,\n value,\n type,\n approved: isApproved({ status, type, value }),\n // Surfaced from the create response so a caller can tell an unanswered\n // decision that reached nobody (reachable:false) apart from a real decline.\n reachable: created.reachable,\n reachableChannels: created.reachableChannels,\n deviceCount: created.deviceCount,\n }\n }\n\n return Object.freeze({\n create: (data: CreateDecision) => request<DecisionResult>('POST', '/decisions', data),\n get: (id: string, opts?: { readonly wait?: number }) =>\n request<Decision>('GET', `/decisions/${id}`, opts?.wait ? { wait: opts.wait } : undefined),\n ask,\n answer: (id: string, answer: string) =>\n request<DecisionAnswerResult>('POST', `/decisions/${id}`, { answer }),\n cancel: (id: string) => request<CancelDecisionResult>('DELETE', `/decisions/${id}`),\n getWebhookSecret: () => request<WebhookSecret>('GET', '/webhook-secret'),\n rotateWebhookSecret: () => request<WebhookSecret>('POST', '/webhook-secret'),\n })\n}\n","import { createHash } from 'crypto'\nimport type { DecisionStatus, DecisionType } from './types'\n\n// A collision-safe idempotency key that is STABLE across process restarts\n// (unlike the builtin salted hash()), so a retried create reuses the same key\n// and never asks the same human twice. Pass the parts that make the ask unique\n// (e.g. [externalId, stepId, question]). Parts are joined with a NUL separator\n// so ['a', 'bc'] and ['ab', 'c'] never collide.\nexport const deterministicKey = (parts: readonly string[]): string =>\n createHash('sha256').update(parts.join('\\x00')).digest('hex').slice(0, 40)\n\nconst AFFIRMATIVE: ReadonlySet<string> = new Set([\n 'yes',\n 'y',\n 'approve',\n 'approved',\n 'ok',\n 'okay',\n 'confirm',\n 'accept',\n 'true',\n])\n\n// Fail-closed approval check. A `confirm` decision is approved ONLY on an\n// affirmative answer; `select`/`input` decisions are \"approved\" once answered.\n// Anything not answered — pending, expired, or cancelled — is NOT approved.\nexport const isApproved = (decision: {\n readonly status: DecisionStatus\n readonly type?: DecisionType\n readonly value: string | null\n}): boolean => {\n if (decision.status !== 'answered') return false\n if (decision.type && decision.type !== 'confirm') return true\n return decision.value != null && AFFIRMATIVE.has(decision.value.trim().toLowerCase())\n}\n","import type {\n RequestFn,\n IssueBoundKey,\n BoundKeyResult,\n BoundKeySummary,\n RevokeKeyResult,\n} from '../types'\n\n// Per-end-user (bound) key issuance for multi-tenant Partners. Call issue() from\n// your backend with your own (unbound, Partner-plan) key to mint a child key bound\n// to one end-user, hand that key to the agent runtime acting for that user, then\n// revoke() it when the session ends. A bound key can only create/resolve decisions\n// and enroll that exact end-user, so a prompt-injected agent can never reach\n// another of your users. Requires the Partner plan.\nexport interface KeysResource {\n // Mint a key bound to externalId. The full key is returned once in `apiKey` and\n // cannot be retrieved again — store it as the session credential.\n readonly issue: (data: IssueBoundKey) => Promise<BoundKeyResult>\n // List this site's bound keys (never the secret) for audit/rotation.\n readonly list: () => Promise<readonly BoundKeySummary[]>\n // Revoke (deactivate) a bound key by its prefix. Returns revoked:false if the\n // prefix is unknown or already inactive.\n readonly revoke: (keyPrefix: string) => Promise<RevokeKeyResult>\n}\n\nexport const createKeysResource = (request: RequestFn): KeysResource =>\n Object.freeze({\n issue: (data: IssueBoundKey) => request<BoundKeyResult>('POST', '/keys', data),\n list: () =>\n request<{ keys: readonly BoundKeySummary[] }>('GET', '/keys').then((r) => r.keys),\n revoke: (keyPrefix: string) =>\n request<RevokeKeyResult>('DELETE', `/keys/${encodeURIComponent(keyPrefix)}`),\n })\n","import type { PusharyConfig, RequestContext, EnrollResult } from './types'\nimport { createRequest } from './request'\nimport { createSubscribersResource, type SubscribersResource } from './resources/subscribers'\nimport { createCampaignsResource, type CampaignsResource } from './resources/campaigns'\nimport { createTemplatesResource, type TemplatesResource } from './resources/templates'\nimport { createNotificationsResource, type NotificationsResource } from './resources/notifications'\nimport { createFlowsResource, type FlowsResource } from './resources/flows'\nimport { createDecisionsResource, type DecisionsResource } from './resources/decisions'\nimport { createKeysResource, type KeysResource } from './resources/keys'\n\nconst DEFAULT_BASE_URL = 'https://pushary.com/api/v1/server'\n\nexport interface PusharyServer {\n readonly subscribers: SubscribersResource\n readonly campaigns: CampaignsResource\n readonly templates: TemplatesResource\n readonly notifications: NotificationsResource\n readonly flows: FlowsResource\n readonly decisions: DecisionsResource\n // Mint/rotate per-end-user bound keys for multi-tenant Partner integrations.\n readonly keys: KeysResource\n // Connect one of your end-users' phones (keyless, no Pushary account for them).\n // Returns a single-use universalLink to show them; one tap turns on approvals.\n // Requires the Partner plan.\n readonly enroll: (externalId: string) => Promise<EnrollResult>\n}\n\nconst validateApiKey = (apiKey: string): void => {\n if (!apiKey) {\n throw new Error('API key is required. Get your API key from https://pushary.com/dashboard/settings')\n }\n \n if (!apiKey.includes('.')) {\n throw new Error('Invalid API key format. Use the full API key (pk_xxx.sk_xxx)')\n }\n}\n\nconst createContext = (config: PusharyConfig): RequestContext => {\n validateApiKey(config.apiKey)\n \n return Object.freeze({\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n headers: Object.freeze({\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n }),\n })\n}\n\nexport const createPusharyServer = (config: PusharyConfig): PusharyServer => {\n const ctx = createContext(config)\n const request = createRequest(ctx)\n \n return Object.freeze({\n subscribers: createSubscribersResource(request),\n campaigns: createCampaignsResource(request),\n templates: createTemplatesResource(request),\n notifications: createNotificationsResource(request),\n flows: createFlowsResource(request),\n decisions: createDecisionsResource(request),\n keys: createKeysResource(request),\n enroll: (externalId: string) => request<EnrollResult>('POST', '/enroll', { externalId }),\n })\n}\n\n","import { createHmac, timingSafeEqual } from 'crypto'\nimport type { DecisionCallback } from './types'\n\n// The header carrying the HMAC-SHA256 signature of the raw callback body.\nexport const SIGNATURE_HEADER = 'x-pushary-signature'\n\n// Verify a Pushary webhook. Pass the RAW request body (not re-serialized JSON),\n// the X-Pushary-Signature header, and your webhook secret (decisions.getWebhookSecret()).\n// Constant-time comparison; returns false on any mismatch.\nexport const verifyWebhookSignature = (\n rawBody: string,\n signature: string | null | undefined,\n secret: string,\n): boolean => {\n if (!signature || !secret) return false\n const expected = createHmac('sha256', secret).update(rawBody).digest('hex')\n const a = Buffer.from(expected)\n const b = Buffer.from(signature)\n if (a.length !== b.length) return false\n return timingSafeEqual(a, b)\n}\n\n// Parse a verified decision callback body into a typed object. Returns null if the\n// body is not a decision callback (missing correlationId/answer). Verify the\n// signature FIRST — this does no verification. Read `answer` (canonical) keyed by\n// `correlationId`; `context` echoes what you passed at create time.\nexport const parseDecisionCallback = (rawBody: string): DecisionCallback | null => {\n let parsed: unknown\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return null\n }\n if (!parsed || typeof parsed !== 'object') return null\n const p = parsed as Record<string, unknown>\n if (typeof p.correlationId !== 'string' || typeof p.answer !== 'string') return null\n return {\n correlationId: p.correlationId,\n answer: p.answer,\n value: typeof p.value === 'string' ? p.value : p.answer,\n answeredAt: typeof p.answeredAt === 'string' ? p.answeredAt : '',\n ...(typeof p.context === 'string' ? { context: p.context } : {}),\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
interface PusharyConfig {
|
|
2
|
+
readonly apiKey: string;
|
|
3
|
+
readonly baseUrl?: string;
|
|
4
|
+
}
|
|
5
|
+
interface ListParams {
|
|
6
|
+
readonly limit?: number;
|
|
7
|
+
readonly cursor?: string;
|
|
8
|
+
}
|
|
9
|
+
interface PaginatedResponse<T> {
|
|
10
|
+
readonly data: readonly T[];
|
|
11
|
+
readonly nextCursor?: string;
|
|
12
|
+
readonly hasMore: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface Subscriber {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly siteId: string;
|
|
17
|
+
readonly endpoint: string;
|
|
18
|
+
readonly status: 'active' | 'unsubscribed' | 'expired' | 'bounced';
|
|
19
|
+
readonly browser?: string;
|
|
20
|
+
readonly os?: string;
|
|
21
|
+
readonly deviceType?: string;
|
|
22
|
+
readonly country?: string;
|
|
23
|
+
readonly city?: string;
|
|
24
|
+
readonly timezone?: string;
|
|
25
|
+
readonly language?: string;
|
|
26
|
+
readonly tags?: readonly string[];
|
|
27
|
+
readonly externalId?: string;
|
|
28
|
+
readonly createdAt: string;
|
|
29
|
+
readonly lastActiveAt?: string;
|
|
30
|
+
}
|
|
31
|
+
interface SubscriberListParams extends ListParams {
|
|
32
|
+
readonly status?: 'active' | 'unsubscribed' | 'expired' | 'bounced';
|
|
33
|
+
readonly tags?: readonly string[];
|
|
34
|
+
readonly externalId?: string;
|
|
35
|
+
}
|
|
36
|
+
interface UpdateSubscriber {
|
|
37
|
+
readonly tags?: readonly string[];
|
|
38
|
+
readonly externalId?: string;
|
|
39
|
+
readonly customData?: Readonly<Record<string, unknown>>;
|
|
40
|
+
}
|
|
41
|
+
interface Campaign {
|
|
42
|
+
readonly id: string;
|
|
43
|
+
readonly siteId: string;
|
|
44
|
+
readonly name: string;
|
|
45
|
+
readonly title: string;
|
|
46
|
+
readonly body: string;
|
|
47
|
+
readonly iconUrl?: string;
|
|
48
|
+
readonly imageUrl?: string;
|
|
49
|
+
readonly actionUrl?: string;
|
|
50
|
+
readonly status: 'draft' | 'scheduled' | 'sending' | 'active' | 'paused' | 'completed' | 'cancelled';
|
|
51
|
+
readonly scheduledAt?: string;
|
|
52
|
+
readonly totalTargeted: number;
|
|
53
|
+
readonly totalSent: number;
|
|
54
|
+
readonly totalDelivered: number;
|
|
55
|
+
readonly totalClicked: number;
|
|
56
|
+
readonly createdAt: string;
|
|
57
|
+
}
|
|
58
|
+
interface CreateCampaign {
|
|
59
|
+
readonly name: string;
|
|
60
|
+
readonly title: string;
|
|
61
|
+
readonly body: string;
|
|
62
|
+
readonly iconUrl?: string;
|
|
63
|
+
readonly imageUrl?: string;
|
|
64
|
+
readonly actionUrl?: string;
|
|
65
|
+
readonly scheduledAt?: string;
|
|
66
|
+
readonly segmentId?: string;
|
|
67
|
+
readonly tags?: readonly string[];
|
|
68
|
+
}
|
|
69
|
+
interface UpdateCampaign {
|
|
70
|
+
readonly name?: string;
|
|
71
|
+
readonly title?: string;
|
|
72
|
+
readonly body?: string;
|
|
73
|
+
readonly iconUrl?: string;
|
|
74
|
+
readonly imageUrl?: string;
|
|
75
|
+
readonly actionUrl?: string;
|
|
76
|
+
readonly scheduledAt?: string;
|
|
77
|
+
readonly status?: 'draft' | 'paused' | 'cancelled';
|
|
78
|
+
}
|
|
79
|
+
interface Template {
|
|
80
|
+
readonly id: string;
|
|
81
|
+
readonly siteId: string;
|
|
82
|
+
readonly name: string;
|
|
83
|
+
readonly title: string;
|
|
84
|
+
readonly body: string;
|
|
85
|
+
readonly iconUrl?: string;
|
|
86
|
+
readonly imageUrl?: string;
|
|
87
|
+
readonly actionUrl?: string;
|
|
88
|
+
readonly createdAt: string;
|
|
89
|
+
}
|
|
90
|
+
interface CreateTemplate {
|
|
91
|
+
readonly name: string;
|
|
92
|
+
readonly title: string;
|
|
93
|
+
readonly body: string;
|
|
94
|
+
readonly iconUrl?: string;
|
|
95
|
+
readonly imageUrl?: string;
|
|
96
|
+
readonly actionUrl?: string;
|
|
97
|
+
}
|
|
98
|
+
interface UpdateTemplate {
|
|
99
|
+
readonly name?: string;
|
|
100
|
+
readonly title?: string;
|
|
101
|
+
readonly body?: string;
|
|
102
|
+
readonly iconUrl?: string;
|
|
103
|
+
readonly imageUrl?: string;
|
|
104
|
+
readonly actionUrl?: string;
|
|
105
|
+
}
|
|
106
|
+
interface SendNotification {
|
|
107
|
+
readonly title: string;
|
|
108
|
+
readonly body: string;
|
|
109
|
+
readonly iconUrl?: string;
|
|
110
|
+
readonly imageUrl?: string;
|
|
111
|
+
readonly url?: string;
|
|
112
|
+
readonly subscriberIds?: readonly string[];
|
|
113
|
+
readonly externalIds?: readonly string[];
|
|
114
|
+
readonly tags?: readonly string[];
|
|
115
|
+
readonly data?: Readonly<Record<string, unknown>>;
|
|
116
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
117
|
+
/** Stable across retries of one logical send. Maximum 200 characters. */
|
|
118
|
+
readonly idempotencyKey?: string;
|
|
119
|
+
}
|
|
120
|
+
interface SendResult {
|
|
121
|
+
readonly success: boolean;
|
|
122
|
+
readonly campaignId?: string;
|
|
123
|
+
readonly status?: 'queued';
|
|
124
|
+
readonly queued?: number;
|
|
125
|
+
readonly duplicate?: boolean;
|
|
126
|
+
/** @deprecated This is the queued recipient count, not a device receipt. */
|
|
127
|
+
readonly sent: number;
|
|
128
|
+
readonly limits: {
|
|
129
|
+
readonly remaining: number;
|
|
130
|
+
readonly limit: number;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
interface SubscriberCount {
|
|
134
|
+
readonly total: number;
|
|
135
|
+
readonly active: number;
|
|
136
|
+
readonly unsubscribed: number;
|
|
137
|
+
}
|
|
138
|
+
interface CampaignStats {
|
|
139
|
+
readonly totalSent: number;
|
|
140
|
+
readonly totalDelivered: number;
|
|
141
|
+
readonly totalClicked: number;
|
|
142
|
+
readonly totalFailed: number;
|
|
143
|
+
readonly deliveryRate: number;
|
|
144
|
+
readonly clickRate: number;
|
|
145
|
+
}
|
|
146
|
+
type FlowTriggerType = 'notification_click' | 'notification_impression' | 'notification_dismiss' | 'subscription' | 'unsubscription';
|
|
147
|
+
type FlowStepType = 'send_notification' | 'delay' | 'exit';
|
|
148
|
+
type FlowStatus = 'draft' | 'active' | 'paused' | 'archived';
|
|
149
|
+
interface FlowStepConfig {
|
|
150
|
+
readonly notification?: {
|
|
151
|
+
readonly title: string;
|
|
152
|
+
readonly body: string;
|
|
153
|
+
readonly iconUrl?: string;
|
|
154
|
+
readonly imageUrl?: string;
|
|
155
|
+
readonly actionUrl?: string;
|
|
156
|
+
};
|
|
157
|
+
readonly delay?: {
|
|
158
|
+
readonly value: number;
|
|
159
|
+
readonly unit: 'seconds' | 'minutes' | 'hours' | 'days';
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
interface FlowStep {
|
|
163
|
+
readonly id: string;
|
|
164
|
+
readonly flowId: string;
|
|
165
|
+
readonly stepOrder: number;
|
|
166
|
+
readonly stepType: FlowStepType;
|
|
167
|
+
readonly config: FlowStepConfig;
|
|
168
|
+
readonly createdAt: string;
|
|
169
|
+
readonly updatedAt: string;
|
|
170
|
+
}
|
|
171
|
+
interface Flow {
|
|
172
|
+
readonly id: string;
|
|
173
|
+
readonly siteId: string;
|
|
174
|
+
readonly name: string;
|
|
175
|
+
readonly description?: string;
|
|
176
|
+
readonly triggerType: FlowTriggerType;
|
|
177
|
+
readonly triggerCampaignId?: string;
|
|
178
|
+
readonly status: FlowStatus;
|
|
179
|
+
readonly executionCount: number;
|
|
180
|
+
readonly createdBy?: string;
|
|
181
|
+
readonly createdAt: string;
|
|
182
|
+
readonly updatedAt: string;
|
|
183
|
+
readonly steps?: readonly FlowStep[];
|
|
184
|
+
}
|
|
185
|
+
interface FlowStepInput {
|
|
186
|
+
readonly stepType: FlowStepType;
|
|
187
|
+
readonly config: FlowStepConfig;
|
|
188
|
+
}
|
|
189
|
+
interface CreateFlow {
|
|
190
|
+
readonly name: string;
|
|
191
|
+
readonly description?: string;
|
|
192
|
+
readonly triggerType: FlowTriggerType;
|
|
193
|
+
readonly triggerCampaignId?: string;
|
|
194
|
+
readonly steps?: readonly FlowStepInput[];
|
|
195
|
+
}
|
|
196
|
+
interface UpdateFlow {
|
|
197
|
+
readonly name?: string;
|
|
198
|
+
readonly description?: string;
|
|
199
|
+
readonly triggerType?: FlowTriggerType;
|
|
200
|
+
readonly triggerCampaignId?: string;
|
|
201
|
+
readonly status?: FlowStatus;
|
|
202
|
+
readonly steps?: readonly FlowStepInput[];
|
|
203
|
+
}
|
|
204
|
+
interface FlowListParams extends ListParams {
|
|
205
|
+
readonly status?: FlowStatus;
|
|
206
|
+
}
|
|
207
|
+
type DecisionType = 'confirm' | 'select' | 'input';
|
|
208
|
+
type DecisionStatus = 'pending' | 'answered' | 'expired' | 'cancelled';
|
|
209
|
+
interface CreateDecision {
|
|
210
|
+
readonly question: string;
|
|
211
|
+
readonly type?: DecisionType;
|
|
212
|
+
readonly options?: readonly string[];
|
|
213
|
+
readonly externalId?: string;
|
|
214
|
+
readonly email?: string;
|
|
215
|
+
readonly callbackUrl?: string;
|
|
216
|
+
readonly agentName?: string;
|
|
217
|
+
readonly context?: string;
|
|
218
|
+
readonly placeholder?: string;
|
|
219
|
+
readonly expiresInSeconds?: number;
|
|
220
|
+
readonly wait?: boolean;
|
|
221
|
+
readonly timeoutSeconds?: number;
|
|
222
|
+
readonly idempotencyKey?: string;
|
|
223
|
+
readonly poweredBy?: boolean;
|
|
224
|
+
readonly requireReachable?: boolean;
|
|
225
|
+
}
|
|
226
|
+
interface DecisionReachability {
|
|
227
|
+
readonly reachable?: boolean;
|
|
228
|
+
readonly reachableChannels?: number;
|
|
229
|
+
readonly deviceCount?: number;
|
|
230
|
+
}
|
|
231
|
+
interface DecisionResult extends DecisionReachability {
|
|
232
|
+
readonly decisionId: string;
|
|
233
|
+
readonly status: DecisionStatus;
|
|
234
|
+
readonly answered: boolean;
|
|
235
|
+
readonly value?: string | null;
|
|
236
|
+
readonly type?: DecisionType;
|
|
237
|
+
readonly question?: string;
|
|
238
|
+
readonly pollUrl?: string;
|
|
239
|
+
readonly decisionPageUrl?: string;
|
|
240
|
+
readonly expiresInSeconds?: number;
|
|
241
|
+
readonly idempotent?: boolean;
|
|
242
|
+
readonly hint?: string;
|
|
243
|
+
}
|
|
244
|
+
interface Decision {
|
|
245
|
+
readonly decisionId: string;
|
|
246
|
+
readonly status: DecisionStatus;
|
|
247
|
+
readonly answered: boolean;
|
|
248
|
+
readonly value: string | null;
|
|
249
|
+
readonly type: DecisionType;
|
|
250
|
+
readonly question: string;
|
|
251
|
+
readonly options: readonly string[] | null;
|
|
252
|
+
readonly externalId: string | null;
|
|
253
|
+
readonly context: string | null;
|
|
254
|
+
readonly createdAt: string;
|
|
255
|
+
readonly answeredAt: string | null;
|
|
256
|
+
readonly expiresAt: string | null;
|
|
257
|
+
}
|
|
258
|
+
interface DecisionAnswerResult {
|
|
259
|
+
readonly decisionId: string;
|
|
260
|
+
readonly status: DecisionStatus;
|
|
261
|
+
readonly answered: boolean;
|
|
262
|
+
readonly value?: string | null;
|
|
263
|
+
}
|
|
264
|
+
interface CancelDecisionResult {
|
|
265
|
+
readonly decisionId: string;
|
|
266
|
+
readonly cancelled: boolean;
|
|
267
|
+
readonly status: string;
|
|
268
|
+
}
|
|
269
|
+
interface WebhookSecret {
|
|
270
|
+
readonly webhookSecret: string;
|
|
271
|
+
}
|
|
272
|
+
interface DecisionCallback {
|
|
273
|
+
readonly correlationId: string;
|
|
274
|
+
readonly answer: string;
|
|
275
|
+
readonly value: string;
|
|
276
|
+
readonly answeredAt: string;
|
|
277
|
+
readonly context?: string;
|
|
278
|
+
}
|
|
279
|
+
interface EnrollResult {
|
|
280
|
+
readonly externalId: string;
|
|
281
|
+
readonly token: string;
|
|
282
|
+
readonly deepLink: string;
|
|
283
|
+
readonly universalLink: string;
|
|
284
|
+
readonly expiresInSeconds: number;
|
|
285
|
+
}
|
|
286
|
+
interface AskDecision {
|
|
287
|
+
readonly question: string;
|
|
288
|
+
readonly type?: DecisionType;
|
|
289
|
+
readonly options?: readonly string[];
|
|
290
|
+
readonly externalId?: string;
|
|
291
|
+
readonly email?: string;
|
|
292
|
+
readonly agentName?: string;
|
|
293
|
+
readonly context?: string;
|
|
294
|
+
readonly placeholder?: string;
|
|
295
|
+
readonly expiresInSeconds?: number;
|
|
296
|
+
readonly idempotencyKey?: string;
|
|
297
|
+
readonly poweredBy?: boolean;
|
|
298
|
+
readonly callbackUrl?: string;
|
|
299
|
+
readonly requireReachable?: boolean;
|
|
300
|
+
readonly timeoutMs?: number;
|
|
301
|
+
}
|
|
302
|
+
interface AskResult extends DecisionReachability {
|
|
303
|
+
readonly decisionId: string;
|
|
304
|
+
readonly status: DecisionStatus;
|
|
305
|
+
readonly answered: boolean;
|
|
306
|
+
readonly value: string | null;
|
|
307
|
+
readonly type: DecisionType;
|
|
308
|
+
readonly approved: boolean;
|
|
309
|
+
}
|
|
310
|
+
interface IssueBoundKey {
|
|
311
|
+
readonly externalId: string;
|
|
312
|
+
readonly name?: string;
|
|
313
|
+
readonly expiresInSeconds?: number;
|
|
314
|
+
}
|
|
315
|
+
interface BoundKeyResult {
|
|
316
|
+
readonly apiKey: string;
|
|
317
|
+
readonly keyPrefix: string;
|
|
318
|
+
readonly scope: 'bound';
|
|
319
|
+
readonly boundExternalId: string;
|
|
320
|
+
readonly expiresAt: string | null;
|
|
321
|
+
}
|
|
322
|
+
interface BoundKeySummary {
|
|
323
|
+
readonly keyPrefix: string;
|
|
324
|
+
readonly name: string;
|
|
325
|
+
readonly boundExternalId: string | null;
|
|
326
|
+
readonly isActive: boolean;
|
|
327
|
+
readonly lastUsedAt: string | null;
|
|
328
|
+
readonly expiresAt: string | null;
|
|
329
|
+
readonly createdAt: string;
|
|
330
|
+
}
|
|
331
|
+
interface RevokeKeyResult {
|
|
332
|
+
readonly keyPrefix: string;
|
|
333
|
+
readonly revoked: boolean;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
interface SubscribersResource {
|
|
337
|
+
readonly list: (params?: SubscriberListParams) => Promise<PaginatedResponse<Subscriber>>;
|
|
338
|
+
readonly get: (id: string) => Promise<Subscriber>;
|
|
339
|
+
readonly update: (id: string, data: UpdateSubscriber) => Promise<Subscriber>;
|
|
340
|
+
readonly delete: (id: string) => Promise<void>;
|
|
341
|
+
readonly count: () => Promise<SubscriberCount>;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
interface CampaignsResource {
|
|
345
|
+
readonly list: (params?: ListParams) => Promise<PaginatedResponse<Campaign>>;
|
|
346
|
+
readonly create: (data: CreateCampaign) => Promise<Campaign>;
|
|
347
|
+
readonly get: (id: string) => Promise<Campaign>;
|
|
348
|
+
readonly update: (id: string, data: UpdateCampaign) => Promise<Campaign>;
|
|
349
|
+
readonly delete: (id: string) => Promise<void>;
|
|
350
|
+
readonly send: (id: string) => Promise<Campaign>;
|
|
351
|
+
readonly pause: (id: string) => Promise<Campaign>;
|
|
352
|
+
readonly resume: (id: string) => Promise<Campaign>;
|
|
353
|
+
readonly stats: (id: string) => Promise<CampaignStats>;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
interface TemplatesResource {
|
|
357
|
+
readonly list: (params?: ListParams) => Promise<PaginatedResponse<Template>>;
|
|
358
|
+
readonly create: (data: CreateTemplate) => Promise<Template>;
|
|
359
|
+
readonly get: (id: string) => Promise<Template>;
|
|
360
|
+
readonly update: (id: string, data: UpdateTemplate) => Promise<Template>;
|
|
361
|
+
readonly delete: (id: string) => Promise<void>;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
interface NotificationsResource {
|
|
365
|
+
readonly send: (data: SendNotification) => Promise<SendResult>;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
interface FlowsResource {
|
|
369
|
+
readonly list: (params?: FlowListParams) => Promise<PaginatedResponse<Flow>>;
|
|
370
|
+
readonly create: (data: CreateFlow) => Promise<Flow>;
|
|
371
|
+
readonly get: (id: string) => Promise<Flow>;
|
|
372
|
+
readonly update: (id: string, data: UpdateFlow) => Promise<Flow>;
|
|
373
|
+
readonly delete: (id: string) => Promise<void>;
|
|
374
|
+
readonly activate: (id: string) => Promise<Flow>;
|
|
375
|
+
readonly pause: (id: string) => Promise<Flow>;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
interface DecisionsResource {
|
|
379
|
+
readonly create: (data: CreateDecision) => Promise<DecisionResult>;
|
|
380
|
+
readonly get: (id: string, opts?: {
|
|
381
|
+
readonly wait?: number;
|
|
382
|
+
}) => Promise<Decision>;
|
|
383
|
+
readonly ask: (data: AskDecision) => Promise<AskResult>;
|
|
384
|
+
readonly answer: (id: string, answer: string) => Promise<DecisionAnswerResult>;
|
|
385
|
+
readonly cancel: (id: string) => Promise<CancelDecisionResult>;
|
|
386
|
+
readonly getWebhookSecret: () => Promise<WebhookSecret>;
|
|
387
|
+
readonly rotateWebhookSecret: () => Promise<WebhookSecret>;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
interface KeysResource {
|
|
391
|
+
readonly issue: (data: IssueBoundKey) => Promise<BoundKeyResult>;
|
|
392
|
+
readonly list: () => Promise<readonly BoundKeySummary[]>;
|
|
393
|
+
readonly revoke: (keyPrefix: string) => Promise<RevokeKeyResult>;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
interface PusharyServer {
|
|
397
|
+
readonly subscribers: SubscribersResource;
|
|
398
|
+
readonly campaigns: CampaignsResource;
|
|
399
|
+
readonly templates: TemplatesResource;
|
|
400
|
+
readonly notifications: NotificationsResource;
|
|
401
|
+
readonly flows: FlowsResource;
|
|
402
|
+
readonly decisions: DecisionsResource;
|
|
403
|
+
readonly keys: KeysResource;
|
|
404
|
+
readonly enroll: (externalId: string) => Promise<EnrollResult>;
|
|
405
|
+
}
|
|
406
|
+
declare const createPusharyServer: (config: PusharyConfig) => PusharyServer;
|
|
407
|
+
|
|
408
|
+
declare const SIGNATURE_HEADER = "x-pushary-signature";
|
|
409
|
+
declare const verifyWebhookSignature: (rawBody: string, signature: string | null | undefined, secret: string) => boolean;
|
|
410
|
+
declare const parseDecisionCallback: (rawBody: string) => DecisionCallback | null;
|
|
411
|
+
|
|
412
|
+
declare const deterministicKey: (parts: readonly string[]) => string;
|
|
413
|
+
declare const isApproved: (decision: {
|
|
414
|
+
readonly status: DecisionStatus;
|
|
415
|
+
readonly type?: DecisionType;
|
|
416
|
+
readonly value: string | null;
|
|
417
|
+
}) => boolean;
|
|
418
|
+
|
|
419
|
+
export { parseDecisionCallback as $, type DecisionAnswerResult as A, type CancelDecisionResult as B, type Campaign as C, type DecisionType as D, type DecisionCallback as E, type Flow as F, type EnrollResult as G, type AskDecision as H, type AskResult as I, type IssueBoundKey as J, type BoundKeyResult as K, type ListParams as L, type BoundKeySummary as M, type SubscribersResource as N, type CampaignsResource as O, type PusharyServer as P, type TemplatesResource as Q, type RevokeKeyResult as R, type Subscriber as S, type Template as T, type UpdateSubscriber as U, type NotificationsResource as V, type WebhookSecret as W, type FlowsResource as X, type DecisionsResource as Y, type KeysResource as Z, verifyWebhookSignature as _, type PusharyConfig as a, SIGNATURE_HEADER as a0, deterministicKey as a1, isApproved as a2, type SubscriberListParams as b, createPusharyServer as c, type SubscriberCount as d, type CreateCampaign as e, type UpdateCampaign as f, type CampaignStats as g, type CreateTemplate as h, type UpdateTemplate as i, type SendNotification as j, type SendResult as k, type CreateFlow as l, type UpdateFlow as m, type FlowListParams as n, type FlowTriggerType as o, type FlowStepType as p, type FlowStatus as q, type FlowStep as r, type FlowStepConfig as s, type FlowStepInput as t, type PaginatedResponse as u, type DecisionStatus as v, type CreateDecision as w, type DecisionReachability as x, type DecisionResult as y, type Decision as z };
|