@tappify/extension-sdk 2.1.0-beta.2 → 2.1.0-beta.4
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/{chunk-QJMZRV7A.mjs → chunk-6FASZFC4.mjs} +19 -7
- package/dist/chunk-6FASZFC4.mjs.map +1 -0
- package/dist/{chunk-EB5XWQAU.cjs → chunk-6MP5DKLZ.cjs} +28 -16
- package/dist/chunk-6MP5DKLZ.cjs.map +1 -0
- package/dist/{chunk-BPCGXXMD.cjs → chunk-AYYJCRS4.cjs} +10 -10
- package/dist/{chunk-BPCGXXMD.cjs.map → chunk-AYYJCRS4.cjs.map} +1 -1
- package/dist/{chunk-KZ5NGFUP.mjs → chunk-CEFLOQD4.mjs} +2 -2
- package/dist/{chunk-7YKH4LZN.cjs → chunk-EV3KKP62.cjs} +17 -6
- package/dist/chunk-EV3KKP62.cjs.map +1 -0
- package/dist/{chunk-SGCYEEXD.mjs → chunk-IHLK4I7J.mjs} +17 -6
- package/dist/chunk-IHLK4I7J.mjs.map +1 -0
- package/dist/{chunk-A74HCO6T.cjs → chunk-TEIGGORZ.cjs} +3 -3
- package/dist/{chunk-A74HCO6T.cjs.map → chunk-TEIGGORZ.cjs.map} +1 -1
- package/dist/{chunk-SWG7CNTZ.mjs → chunk-WW2D3N2T.mjs} +3 -3
- package/dist/{client-DE-vMgdO.d.cts → client-BLnec4SD.d.cts} +1 -1
- package/dist/{client-BO3kavn0.d.ts → client-BRxKTo-L.d.ts} +1 -1
- package/dist/codegen.d.cts +14 -5
- package/dist/codegen.d.ts +14 -5
- package/dist/{constants-Bh759FUI.d.cts → constants-CvHbO3ia.d.cts} +14 -5
- package/dist/{constants-Bh759FUI.d.ts → constants-CvHbO3ia.d.ts} +14 -5
- package/dist/{context-mr8R5CNt.d.ts → context-BjhW0QWy.d.ts} +1 -1
- package/dist/{context-DI0EJCRD.d.cts → context-CsviWecX.d.cts} +1 -1
- package/dist/host.d.cts +4 -4
- package/dist/host.d.ts +4 -4
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/manifest.cjs +16 -16
- package/dist/manifest.d.cts +10 -4
- package/dist/manifest.d.ts +10 -4
- package/dist/manifest.mjs +1 -1
- package/dist/server.cjs +8 -8
- package/dist/server.d.cts +5 -5
- package/dist/server.d.ts +5 -5
- package/dist/server.mjs +3 -3
- package/dist/testing/index.cjs +8 -8
- package/dist/testing/index.d.cts +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.mjs +4 -4
- package/dist/{types-BdDaLnqs.d.cts → types-C5k8VwaA.d.cts} +1 -1
- package/dist/{types-uGHrRaOj.d.ts → types-DBpDxGlT.d.ts} +1 -1
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/vite-preview-bootstrap.d.cts +2 -2
- package/dist/vite-preview-bootstrap.d.ts +2 -2
- package/dist/vite-preview.cjs +7 -7
- package/dist/vite-preview.cjs.map +1 -1
- package/dist/vite-preview.d.cts +3 -3
- package/dist/vite-preview.d.ts +3 -3
- package/dist/vite-preview.mjs +4 -4
- package/dist/vite-preview.mjs.map +1 -1
- package/dist/vite.cjs +16 -5
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.cts +14 -5
- package/dist/vite.d.ts +14 -5
- package/dist/vite.mjs +16 -5
- package/dist/vite.mjs.map +1 -1
- package/dist/{work-events-BlOVpK0k.d.ts → work-events-BYU25wmX.d.ts} +40 -8
- package/dist/{work-events-D97EoqvS.d.cts → work-events-CxFu-YZE.d.cts} +40 -8
- package/package.json +1 -1
- package/schema/extension-v2.json +75 -330
- package/dist/chunk-7YKH4LZN.cjs.map +0 -1
- package/dist/chunk-EB5XWQAU.cjs.map +0 -1
- package/dist/chunk-QJMZRV7A.mjs.map +0 -1
- package/dist/chunk-SGCYEEXD.mjs.map +0 -1
- /package/dist/{chunk-KZ5NGFUP.mjs.map → chunk-CEFLOQD4.mjs.map} +0 -0
- /package/dist/{chunk-SWG7CNTZ.mjs.map → chunk-WW2D3N2T.mjs.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-7YKH4LZN.cjs","../src/manifest/constants.ts"],"names":[],"mappings":"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","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-7YKH4LZN.cjs","sourcesContent":[null,"import type { ToolDeclaration } from './types';\n\nexport const SCOPES = [\n {\n key: 'ui:render',\n label: 'Render UI',\n description:\n 'Render the declared pages, tabs, widgets, row actions and settings panel, and open chat with a visible prompt',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'projects:read',\n label: 'Read the project',\n description: 'Project name, platforms and store identity',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'analytics:read',\n label: 'Read analytics',\n description: 'Downloads, impressions, page views and conversion series',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'store.metadata:read',\n label: 'Read store metadata',\n description: 'Listing metadata, keyword set and keyword positions',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'reviews:read',\n label: 'Read store reviews',\n description: 'Review text, ratings and replies',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'review.threads:read',\n label: 'Read Review threads',\n description:\n 'Review threads, comments, screenshot descriptors, build context and safe device context',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'crashes:read',\n label: 'Read crash data',\n description: 'Crash-free rate and issue counts',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'revenue:read',\n label: 'Read revenue',\n description: 'MRR, revenue series and refund counts',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'metrics:write',\n label: 'Write connector metrics',\n description:\n 'Write the metrics this extension declares into the metrics store',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'alerts:write',\n label: 'Raise alerts and banners',\n description:\n 'Turn declared webhooks into alerts and banners, at most three a day per project',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'insights:write',\n label: 'Post insights',\n description: 'Post insights to Home and to chat',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'ai:tools',\n label: 'Add assistant tools',\n description: 'Offer tools and mentions to the assistant',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'ai:actions',\n label: 'Run assistant actions',\n description: 'Run declared actions, each behind the approval card',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'store.metadata:write',\n label: 'Propose store metadata changes',\n description: 'Propose listing changes through a Tappify approval',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'autopilot:trigger',\n label: 'Trigger automated store actions',\n description: 'Start automated store actions on the owner’s behalf',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'work:create',\n label: 'Create work items',\n description: 'Create issues, pages or messages in the vendor’s system',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'work:sync',\n label: 'Sync work items',\n description: 'Sync comments and status on created work items',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'storage:write',\n label: 'Use hosted storage',\n description:\n 'Read and write this extension’s own hosted storage collections',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'messaging:send',\n label: 'Send messages to end users',\n description:\n 'Send messages or push notifications to the owner’s end users through owner-supplied credentials',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'ai:skills',\n label: 'Shape the assistant',\n description:\n 'Add skills, prompt templates and context providers that shape the assistant’s behaviour',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n] as const;\n\nexport type ScopeDefinition = (typeof SCOPES)[number];\n/** Every scope an extension can ask for under `scopes` in its manifest. */\nexport type ScopeKey = ScopeDefinition['key'];\n\nexport const SCOPE_KEYS: readonly ScopeKey[] = SCOPES.map(scope => scope.key);\n\nexport const SLOTS = [\n 'kpi-row',\n 'insights',\n 'sidebar',\n 'below-chart',\n 'below-list',\n] as const;\n/** The anchors on a host page a widget can be declared at. */\nexport type SlotId = (typeof SLOTS)[number];\n\nexport const CHARTS = [\n 'installs-activity',\n 'conversion',\n 'release-cadence',\n] as const;\nexport type HostChart = (typeof CHARTS)[number];\n\nexport const PAGES = [\n {\n key: 'overview',\n label: 'Home',\n route: '/projects/:id/overview',\n slots: ['kpi-row', 'insights', 'sidebar'],\n charts: ['installs-activity'],\n tabs: true,\n banners: true,\n },\n {\n key: 'analytics',\n label: 'Analytics',\n route: '/projects/:id/analytics',\n slots: ['kpi-row', 'below-chart', 'sidebar'],\n charts: ['installs-activity', 'conversion'],\n tabs: true,\n banners: true,\n },\n {\n key: 'deployments',\n label: 'Deployments',\n route: '/projects/:id/deployments',\n slots: ['sidebar', 'below-list'],\n charts: ['release-cadence'],\n tabs: true,\n banners: false,\n },\n {\n key: 'ai_chat',\n label: 'Assistant',\n route: 'chat',\n slots: [],\n charts: [],\n tabs: false,\n banners: false,\n },\n] as const;\n\nexport type PageDefinition = (typeof PAGES)[number];\n/** The host pages a contribution can attach a tab, widget or banner to. */\nexport type HostPage = PageDefinition['key'];\n\nexport const PAGE_KEYS: readonly HostPage[] = PAGES.map(page => page.key);\n\nexport const TABLES = [\n { key: 'analytics.keywords', label: 'Keywords' },\n { key: 'analytics.reviews', label: 'Reviews' },\n { key: 'deployments.releases', label: 'Releases' },\n { key: 'deployments.builds', label: 'Builds' },\n] as const;\n\nexport type TableDefinition = (typeof TABLES)[number];\nexport type HostTable = TableDefinition['key'];\n\nexport const TABLE_KEYS: readonly HostTable[] = TABLES.map(table => table.key);\n\nexport const KINDS = [\n 'page',\n 'tab',\n 'widget',\n 'series',\n 'banner',\n 'rowAction',\n 'marker',\n 'settings',\n 'storage',\n 'connector',\n 'webhook',\n 'tool',\n 'mention',\n 'action',\n 'knowledge',\n 'skill',\n 'prompt',\n 'context',\n 'work',\n] as const;\nexport type ContributionKind = (typeof KINDS)[number];\n\nexport const CATEGORIES = [\n 'market_data',\n 'subscriptions',\n 'product_analytics',\n 'crashes',\n 'attribution',\n 'experiments',\n 'messaging',\n 'session_replay',\n 'localization',\n 'design',\n 'ci_cd',\n 'trackers',\n 'support',\n 'chat',\n 'ad_monetization',\n 'warehouse',\n 'compliance',\n 'additional_stores',\n] as const;\nexport type ExtensionCategory = (typeof CATEGORIES)[number];\n\nexport const EVENTS = [\n 'release.shipped',\n 'metadata.changed',\n 'keyword.set_changed',\n 'screenshots.updated',\n 'price.changed',\n 'featuring.started',\n 'score.changed',\n 'incident.opened',\n 'incident.resolved',\n 'playbook.step_approved',\n 'review.thread_opened',\n 'review.thread_resolved',\n 'approval.requested',\n 'digest.sent',\n 'install.created',\n 'install.paused',\n 'install.resumed',\n 'install.revoked',\n 'install.token_rotated',\n 'scopes.changed',\n 'settings.changed',\n] as const;\n/** Every event Tappify emits, which a mount or a server can subscribe to. */\nexport type HostEventName = (typeof EVENTS)[number];\n\nexport const SERVED_SDK_MAJORS: readonly number[] = [2];\n\n/** The `kind` of every read `tap.data.query` accepts, one per scope it needs. */\nexport type DataQueryKind =\n | 'project'\n | 'series'\n | 'keywords'\n | 'listing'\n | 'reviews'\n | 'crashes'\n | 'revenue';\n\nexport const QUERY_SCOPES: Record<DataQueryKind, ScopeKey> = {\n project: 'projects:read',\n series: 'analytics:read',\n keywords: 'store.metadata:read',\n listing: 'store.metadata:read',\n reviews: 'reviews:read',\n crashes: 'crashes:read',\n revenue: 'revenue:read',\n};\n\n/**\n * The keys a tool's answer carries for each `returns` kind it may declare.\n * `validateToolResponse`, `tappify extension doctor` and the host all read\n * this one table, so a wrong body fails the same way wherever it is checked.\n */\nexport const CARD_KEYS: Record<ToolDeclaration['returns'], string[]> = {\n value: ['label', 'value'],\n series: ['label', 'points'],\n table: ['columns', 'rows'],\n list: ['items'],\n comparison: ['label', 'left', 'right'],\n};\n\nexport const findScope = (key: string): ScopeDefinition | undefined =>\n SCOPES.find(scope => scope.key === key);\n\nexport const findPage = (key: string): PageDefinition | undefined =>\n PAGES.find(page => page.key === key);\n\nexport const findTable = (key: string): TableDefinition | undefined =>\n TABLES.find(table => table.key === key);\n\nexport const slotsForPage = (page: string): readonly SlotId[] =>\n findPage(page)?.slots ?? [];\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-EB5XWQAU.cjs","../src/server/events.ts","../src/server/work-events.ts"],"names":[],"mappings":"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","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-EB5XWQAU.cjs","sourcesContent":[null,"import { TapServerError } from '../client/errors';\nimport type { WebhookName, WebhookPayload } from '../client/types';\nimport { SERVER_ERROR_CODES } from './codes';\nimport { readRecord, readText } from './wire';\n\n/** The body `sendEvent` posts to Tappify, and the body the signature covers. */\nexport interface WebhookEnvelope {\n /** The declared webhook name. */\n event: string;\n /** The extension id the event came from. */\n source: string;\n /** When the event happened, as an ISO timestamp. */\n occurredAt: string;\n /** The build the event belongs to, when it belongs to one. */\n build?: string;\n /** The key Tappify deduplicates on, so a retry is not counted twice. */\n dedupeKey: string;\n payload: Record<string, unknown>;\n}\n\n/** The third argument of `sendEvent`. */\nexport interface SendEventOptions {\n /** Which install the event belongs to. */\n installId: string;\n extensionId: string;\n /** The inbound signing secret from the extension's Server page. */\n secret: string;\n /** A full url to post to, which replaces `baseUrl` and the built path. */\n endpoint?: string;\n /** The Tappify origin to build the path under. Defaults to production. */\n baseUrl?: string;\n /** Defaults to a fresh UUID, so give your own to make a retry idempotent. */\n dedupeKey?: string;\n build?: string;\n /** Defaults to now, in ISO form. */\n occurredAt?: string;\n /** A `fetch` of your own, for a test or a proxy. Defaults to the global one. */\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.tappify.ai';\n\nfunction toHex(buffer: ArrayBuffer): string {\n return Array.from(new Uint8Array(buffer))\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Returns the hex HMAC-SHA-256 of a raw body under a shared secret.\n *\n * @remarks\n * This is the value `sendEvent` sends as `X-Tappify-Signature`, computed over the\n * exact bytes of the body it posts. Call it directly only when you build the\n * request yourself, and sign the serialised string you send rather than\n * re-serialising the object, because a different key order is a different\n * signature. Uses Web Crypto, so it runs on Node, Cloudflare Workers and Vercel\n * alike.\n *\n * @example\n * ```ts\n * import { signWebhook } from '@tappify/extension-sdk/server';\n *\n * async function signed(body: string): Promise<Record<string, string>> {\n * return { 'x-tappify-signature': await signWebhook('whsec_test', body) };\n * }\n * ```\n */\nexport async function signWebhook(\n secret: string,\n body: string,\n): Promise<string> {\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(body));\n return toHex(signature);\n}\n\nasync function rejectionCode(response: Response): Promise<string | null> {\n try {\n const payload: unknown = await response.json();\n return readText(readRecord(payload, 'error'), 'code');\n } catch {\n return null;\n }\n}\n\n/**\n * Posts one of your declared webhook events to Tappify, signed with the install's\n * inbound secret.\n *\n * @remarks\n * The name and the payload are narrowed by the `TapWebhookMap` augmentation\n * `tappify extension types` writes. It builds the envelope, signs the serialised\n * body and posts it to the install's hook path under `baseUrl`, or to `endpoint`\n * when you give one. A response Tappify did not accept rejects with a\n * `TapServerError` whose `code` is always `TAP_WEBHOOK_REJECTED`, carrying the HTTP\n * status, and with Tappify's own code in the message text rather than in `code`;\n * the two usual causes are the wrong signing\n * secret and an event the manifest does not declare. Pass your own `dedupeKey` to\n * make a retry idempotent, because the default is a fresh UUID.\n *\n * @example\n * ```ts\n * import { sendEvent } from '@tappify/extension-sdk/server';\n *\n * async function reportAnomaly(installId: string, why: string): Promise<void> {\n * await sendEvent('anomaly.detected', { why }, {\n * installId,\n * extensionId: 'starter',\n * secret: process.env.TAPPIFY_INBOUND_SECRET ?? '',\n * dedupeKey: `anomaly-${installId}-${why}`,\n * });\n * }\n * ```\n */\nexport async function sendEvent<E extends WebhookName>(\n name: E,\n payload: WebhookPayload<E>,\n options: SendEventOptions,\n): Promise<void> {\n const envelope: WebhookEnvelope = {\n event: name,\n source: options.extensionId,\n occurredAt: options.occurredAt ?? new Date().toISOString(),\n dedupeKey: options.dedupeKey ?? crypto.randomUUID(),\n payload: { ...payload },\n };\n\n if (options.build !== undefined) envelope.build = options.build;\n\n const body = JSON.stringify(envelope);\n const signature = await signWebhook(options.secret, body);\n const url =\n options.endpoint ??\n `${options.baseUrl ?? DEFAULT_BASE_URL}/api/v1/extensions/hooks/${options.extensionId}/${options.installId}`;\n\n const send = options.fetch ?? fetch;\n const response = await send(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-tappify-signature': signature,\n },\n body,\n });\n\n if (!response.ok) {\n const rejection = await rejectionCode(response);\n throw new TapServerError(\n SERVER_ERROR_CODES.WEBHOOK_REJECTED,\n `Tappify answered ${String(response.status)}${rejection === null ? '' : ` (${rejection})`} for ${name}. Check the inbound signing secret on the extension's Server page, and that the event is declared under contributes.webhooks.`,\n response.status,\n );\n }\n}\n","import { TapServerError } from '../client/errors';\nimport { SERVER_ERROR_CODES } from './codes';\nimport { signWebhook } from './events';\nimport { readRecord, readText, readUnknown } from './wire';\nimport type { WorkHydratedEvent, WorkHydratedEventBase } from './work';\n\n/** An opaque provider signal to hydrate using current install credentials. */\nexport interface WorkHydrationReferenceEvent extends WorkHydratedEventBase {\n type: WorkHydratedEvent['type'];\n /** A nonempty, short-lived reference resolved by the hydrate_event handler. */\n hydrateRef: string;\n /** Normalized comment content must not accompany a reference. */\n comment?: never;\n /** Normalized status content must not accompany a reference. */\n status?: never;\n}\n\n/** Complete normalized content or an opaque reference, with stable retry identity. */\nexport type WorkEvent =\n | (WorkHydratedEvent & { hydrateRef?: never })\n | WorkHydrationReferenceEvent;\n\n/** Install-specific delivery values provisioned through work configure. */\nexport interface SendWorkEventOptions {\n /** The exact provisioned callback URL; no production default is supplied. */\n callbackUrl: string;\n /** The per-install work-event signing secret provisioned with the callback. */\n secret: string;\n /** A transport for tests or a proxy; defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\nfunction nonempty(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction validEvent(event: WorkEvent): boolean {\n const type = readText(event, 'type');\n if (\n !['comment.created', 'status.changed', 'item.deleted'].includes(type ?? '')\n )\n return false;\n if (\n !['externalItemId', 'providerEventId', 'occurredAt', 'dedupeKey'].every(\n key => nonempty(readUnknown(event, key)),\n )\n )\n return false;\n\n const reference = readUnknown(event, 'hydrateRef');\n const comment = readUnknown(event, 'comment');\n const status = readUnknown(event, 'status');\n if (reference !== undefined)\n return nonempty(reference) && comment === undefined && status === undefined;\n\n if (type === 'item.deleted')\n return comment === undefined && status === undefined;\n if (type === 'status.changed') {\n const normalized = readRecord(event, 'status');\n return (\n comment === undefined &&\n nonempty(normalized.id) &&\n nonempty(normalized.label) &&\n typeof normalized.stage === 'string' &&\n ['open', 'in_progress', 'done'].includes(normalized.stage)\n );\n }\n\n const normalized = readRecord(event, 'comment');\n const author = readRecord(normalized, 'author');\n return (\n status === undefined &&\n nonempty(normalized.externalCommentId) &&\n typeof normalized.body === 'string' &&\n nonempty(normalized.createdAt) &&\n nonempty(author.id) &&\n nonempty(author.displayName)\n );\n}\n\n/**\n * Sends one provider work event to the callback provisioned for this install.\n *\n * @remarks\n * Pass the callbackUrl and secret received through configure unchanged. The\n * event's required dedupeKey identifies the logical provider signal and must be\n * reused on retries. Complete normalized content and an opaque hydrateRef are\n * mutually exclusive. The exact serialized UTF-8 body is signed with HMAC-SHA-256.\n * This callback is independent of declared alert and banner webhooks.\n */\nexport async function sendWorkEvent(\n event: WorkEvent,\n options: SendWorkEventOptions,\n): Promise<void> {\n if (!validEvent(event))\n throw new TypeError(\n 'Invalid work event: provide complete normalized content or a nonempty hydrateRef, with routing and identity fields.',\n );\n if (!nonempty(options.callbackUrl))\n throw new TypeError(\n 'A work event requires the callbackUrl provisioned through configure.',\n );\n\n const body = JSON.stringify(event);\n const signature = await signWebhook(options.secret, body);\n const response = await (options.fetch ?? fetch)(options.callbackUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-tappify-signature': signature,\n },\n body,\n });\n\n if (!response.ok) {\n let rejection: string | null = null;\n try {\n rejection = readText(readRecord(await response.json(), 'error'), 'code');\n } catch {\n // Proxies may return a non-JSON rejection body.\n }\n throw new TapServerError(\n SERVER_ERROR_CODES.WEBHOOK_REJECTED,\n `Tappify answered ${String(response.status)}${rejection === null ? '' : ` (${rejection})`} for work event ${event.type}. Check the callback URL and per-install work-event signing secret provisioned through configure.`,\n response.status,\n );\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/events.ts","../src/server/work-events.ts"],"sourcesContent":["import { TapServerError } from '../client/errors';\nimport type { WebhookName, WebhookPayload } from '../client/types';\nimport { SERVER_ERROR_CODES } from './codes';\nimport { readRecord, readText } from './wire';\n\n/** The body `sendEvent` posts to Tappify, and the body the signature covers. */\nexport interface WebhookEnvelope {\n /** The declared webhook name. */\n event: string;\n /** The extension id the event came from. */\n source: string;\n /** When the event happened, as an ISO timestamp. */\n occurredAt: string;\n /** The build the event belongs to, when it belongs to one. */\n build?: string;\n /** The key Tappify deduplicates on, so a retry is not counted twice. */\n dedupeKey: string;\n payload: Record<string, unknown>;\n}\n\n/** The third argument of `sendEvent`. */\nexport interface SendEventOptions {\n /** Which install the event belongs to. */\n installId: string;\n extensionId: string;\n /** The inbound signing secret from the extension's Server page. */\n secret: string;\n /** A full url to post to, which replaces `baseUrl` and the built path. */\n endpoint?: string;\n /** The Tappify origin to build the path under. Defaults to production. */\n baseUrl?: string;\n /** Defaults to a fresh UUID, so give your own to make a retry idempotent. */\n dedupeKey?: string;\n build?: string;\n /** Defaults to now, in ISO form. */\n occurredAt?: string;\n /** A `fetch` of your own, for a test or a proxy. Defaults to the global one. */\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.tappify.ai';\n\nfunction toHex(buffer: ArrayBuffer): string {\n return Array.from(new Uint8Array(buffer))\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Returns the hex HMAC-SHA-256 of a raw body under a shared secret.\n *\n * @remarks\n * This is the value `sendEvent` sends as `X-Tappify-Signature`, computed over the\n * exact bytes of the body it posts. Call it directly only when you build the\n * request yourself, and sign the serialised string you send rather than\n * re-serialising the object, because a different key order is a different\n * signature. Uses Web Crypto, so it runs on Node, Cloudflare Workers and Vercel\n * alike.\n *\n * @example\n * ```ts\n * import { signWebhook } from '@tappify/extension-sdk/server';\n *\n * async function signed(body: string): Promise<Record<string, string>> {\n * return { 'x-tappify-signature': await signWebhook('whsec_test', body) };\n * }\n * ```\n */\nexport async function signWebhook(\n secret: string,\n body: string,\n): Promise<string> {\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(body));\n return toHex(signature);\n}\n\nasync function rejectionCode(response: Response): Promise<string | null> {\n try {\n const payload: unknown = await response.json();\n return readText(readRecord(payload, 'error'), 'code');\n } catch {\n return null;\n }\n}\n\n/**\n * Posts one of your declared webhook events to Tappify, signed with the install's\n * inbound secret.\n *\n * @remarks\n * The name and the payload are narrowed by the `TapWebhookMap` augmentation\n * `tappify extension types` writes. It builds the envelope, signs the serialised\n * body and posts it to the install's hook path under `baseUrl`, or to `endpoint`\n * when you give one. A response Tappify did not accept rejects with a\n * `TapServerError` whose `code` is always `TAP_WEBHOOK_REJECTED`, carrying the HTTP\n * status, and with Tappify's own code in the message text rather than in `code`;\n * the two usual causes are the wrong signing\n * secret and an event the manifest does not declare. Pass your own `dedupeKey` to\n * make a retry idempotent, because the default is a fresh UUID.\n *\n * @example\n * ```ts\n * import { sendEvent } from '@tappify/extension-sdk/server';\n *\n * async function reportAnomaly(installId: string, why: string): Promise<void> {\n * await sendEvent('anomaly.detected', { why }, {\n * installId,\n * extensionId: 'starter',\n * secret: process.env.TAPPIFY_INBOUND_SECRET ?? '',\n * dedupeKey: `anomaly-${installId}-${why}`,\n * });\n * }\n * ```\n */\nexport async function sendEvent<E extends WebhookName>(\n name: E,\n payload: WebhookPayload<E>,\n options: SendEventOptions,\n): Promise<void> {\n const envelope: WebhookEnvelope = {\n event: name,\n source: options.extensionId,\n occurredAt: options.occurredAt ?? new Date().toISOString(),\n dedupeKey: options.dedupeKey ?? crypto.randomUUID(),\n payload: { ...payload },\n };\n\n if (options.build !== undefined) envelope.build = options.build;\n\n const body = JSON.stringify(envelope);\n const signature = await signWebhook(options.secret, body);\n const url =\n options.endpoint ??\n `${options.baseUrl ?? DEFAULT_BASE_URL}/api/v1/extensions/hooks/${options.extensionId}/${options.installId}`;\n\n const send = options.fetch ?? fetch;\n const response = await send(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-tappify-signature': signature,\n },\n body,\n });\n\n if (!response.ok) {\n const rejection = await rejectionCode(response);\n throw new TapServerError(\n SERVER_ERROR_CODES.WEBHOOK_REJECTED,\n `Tappify answered ${String(response.status)}${rejection === null ? '' : ` (${rejection})`} for ${name}. Check the inbound signing secret on the extension's Server page, and that the event is declared under contributes.webhooks.`,\n response.status,\n );\n }\n}\n","import { TapServerError } from '../client/errors';\nimport { SERVER_ERROR_CODES } from './codes';\nimport { signWebhook } from './events';\nimport { readRecord, readText, readUnknown } from './wire';\nimport type { WorkHydratedEvent, WorkHydratedEventBase } from './work';\n\n/** An opaque provider signal to hydrate using current install credentials. */\nexport interface WorkHydrationReferenceEvent extends WorkHydratedEventBase {\n type: WorkHydratedEvent['type'];\n /** A nonempty, short-lived reference resolved by the hydrate_event handler. */\n hydrateRef: string;\n /** Normalized comment content must not accompany a reference. */\n comment?: never;\n /** Normalized status content must not accompany a reference. */\n status?: never;\n}\n\n/** Complete normalized content or an opaque reference, with stable retry identity. */\nexport type WorkEvent =\n | (WorkHydratedEvent & { hydrateRef?: never })\n | WorkHydrationReferenceEvent;\n\n/** Install-specific delivery values provisioned through work configure. */\nexport interface SendWorkEventOptions {\n /** The exact provisioned callback URL; no production default is supplied. */\n callbackUrl: string;\n /** The per-install work-event signing secret provisioned with the callback. */\n secret: string;\n /** A transport for tests or a proxy; defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\nfunction nonempty(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction validEvent(event: WorkEvent): boolean {\n const type = readText(event, 'type');\n if (\n !['comment.created', 'status.changed', 'item.deleted'].includes(type ?? '')\n )\n return false;\n if (\n !['externalItemId', 'providerEventId', 'occurredAt', 'dedupeKey'].every(\n key => nonempty(readUnknown(event, key)),\n )\n )\n return false;\n\n const reference = readUnknown(event, 'hydrateRef');\n const comment = readUnknown(event, 'comment');\n const status = readUnknown(event, 'status');\n if (reference !== undefined)\n return nonempty(reference) && comment === undefined && status === undefined;\n\n if (type === 'item.deleted')\n return comment === undefined && status === undefined;\n if (type === 'status.changed') {\n const normalized = readRecord(event, 'status');\n return (\n comment === undefined &&\n nonempty(normalized.id) &&\n nonempty(normalized.label) &&\n typeof normalized.stage === 'string' &&\n ['open', 'in_progress', 'done'].includes(normalized.stage)\n );\n }\n\n const normalized = readRecord(event, 'comment');\n const author = readRecord(normalized, 'author');\n return (\n status === undefined &&\n nonempty(normalized.externalCommentId) &&\n typeof normalized.body === 'string' &&\n nonempty(normalized.createdAt) &&\n nonempty(author.id) &&\n nonempty(author.displayName)\n );\n}\n\n/**\n * Sends one provider work event to the callback provisioned for this install.\n *\n * @remarks\n * Pass the callbackUrl and secret received through configure unchanged. The\n * event's required dedupeKey identifies the logical provider signal and must be\n * reused on retries. Complete normalized content and an opaque hydrateRef are\n * mutually exclusive. The exact serialized UTF-8 body is signed with HMAC-SHA-256.\n * This callback is independent of declared alert and banner webhooks.\n */\nexport async function sendWorkEvent(\n event: WorkEvent,\n options: SendWorkEventOptions,\n): Promise<void> {\n if (!validEvent(event))\n throw new TypeError(\n 'Invalid work event: provide complete normalized content or a nonempty hydrateRef, with routing and identity fields.',\n );\n if (!nonempty(options.callbackUrl))\n throw new TypeError(\n 'A work event requires the callbackUrl provisioned through configure.',\n );\n\n const body = JSON.stringify(event);\n const signature = await signWebhook(options.secret, body);\n const response = await (options.fetch ?? fetch)(options.callbackUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-tappify-signature': signature,\n },\n body,\n });\n\n if (!response.ok) {\n let rejection: string | null = null;\n try {\n rejection = readText(readRecord(await response.json(), 'error'), 'code');\n } catch {\n // Proxies may return a non-JSON rejection body.\n }\n throw new TapServerError(\n SERVER_ERROR_CODES.WEBHOOK_REJECTED,\n `Tappify answered ${String(response.status)}${rejection === null ? '' : ` (${rejection})`} for work event ${event.type}. Check the callback URL and per-install work-event signing secret provisioned through configure.`,\n response.status,\n );\n }\n}\n"],"mappings":"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","names":["normalized"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/manifest/constants.ts"],"sourcesContent":["import type { ToolDeclaration } from './types';\n\nexport const SCOPES = [\n {\n key: 'ui:render',\n label: 'Render UI',\n description:\n 'Render the declared pages, tabs, widgets, row actions and settings panel, and open chat with a visible prompt',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'projects:read',\n label: 'Read the project',\n description: 'Project name, platforms and store identity',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'analytics:read',\n label: 'Read analytics',\n description: 'Downloads, impressions, page views and conversion series',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'store.metadata:read',\n label: 'Read store metadata',\n description: 'Listing metadata, keyword set and keyword positions',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'reviews:read',\n label: 'Read store reviews',\n description: 'Review text, ratings and replies',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'review.threads:read',\n label: 'Read Review threads',\n description:\n 'Review threads, comments, screenshot descriptors, build context and safe device context',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'crashes:read',\n label: 'Read crash data',\n description: 'Crash-free rate and issue counts',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'revenue:read',\n label: 'Read revenue',\n description: 'MRR, revenue series and refund counts',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'metrics:write',\n label: 'Write connector metrics',\n description:\n 'Write the metrics this extension declares into the metrics store',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'alerts:write',\n label: 'Raise alerts and banners',\n description:\n 'Turn declared webhooks into alerts and banners, at most three a day per project',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'insights:write',\n label: 'Post insights',\n description: 'Post insights to Home and to chat',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'ai:tools',\n label: 'Add assistant tools',\n description: 'Offer tools and mentions to the assistant',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'ai:actions',\n label: 'Run assistant actions',\n description: 'Run declared actions, each behind the approval card',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'store.metadata:write',\n label: 'Propose store metadata changes',\n description: 'Propose listing changes through a Tappify approval',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'autopilot:trigger',\n label: 'Trigger automated store actions',\n description: 'Start automated store actions on the owner’s behalf',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'work:create',\n label: 'Create work items',\n description: 'Create issues, pages or messages in the vendor’s system',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'work:sync',\n label: 'Sync work items',\n description: 'Sync comments and status on created work items',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n {\n key: 'storage:write',\n label: 'Use hosted storage',\n description:\n 'Read and write this extension’s own hosted storage collections',\n requiresSecurityReview: false,\n requiresJustification: false,\n },\n {\n key: 'messaging:send',\n label: 'Send messages to end users',\n description:\n 'Send messages or push notifications to the owner’s end users through owner-supplied credentials',\n requiresSecurityReview: true,\n requiresJustification: true,\n },\n {\n key: 'ai:skills',\n label: 'Shape the assistant',\n description:\n 'Add skills, prompt templates and context providers that shape the assistant’s behaviour',\n requiresSecurityReview: false,\n requiresJustification: true,\n },\n] as const;\n\nexport type ScopeDefinition = (typeof SCOPES)[number];\n/** Every scope an extension can ask for under `scopes` in its manifest. */\nexport type ScopeKey = ScopeDefinition['key'];\n\nexport const SCOPE_KEYS: readonly ScopeKey[] = SCOPES.map(scope => scope.key);\n\nexport const SLOTS = [\n 'kpi-row',\n 'insights',\n 'sidebar',\n 'below-chart',\n 'below-list',\n] as const;\n/** The anchors on a host page a widget can be declared at. */\nexport type SlotId = (typeof SLOTS)[number];\n\nexport const CHARTS = [\n 'installs-activity',\n 'conversion',\n 'release-cadence',\n] as const;\nexport type HostChart = (typeof CHARTS)[number];\n\nexport const PAGES = [\n {\n key: 'overview',\n label: 'Home',\n route: '/projects/:id/overview',\n slots: ['kpi-row', 'insights', 'sidebar'],\n charts: ['installs-activity'],\n tabs: true,\n banners: true,\n },\n {\n key: 'analytics',\n label: 'Analytics',\n route: '/projects/:id/analytics',\n slots: ['kpi-row', 'below-chart', 'sidebar'],\n charts: ['installs-activity', 'conversion'],\n tabs: true,\n banners: true,\n },\n {\n key: 'deployments',\n label: 'Deployments',\n route: '/projects/:id/deployments',\n slots: ['sidebar', 'below-list'],\n charts: ['release-cadence'],\n tabs: true,\n banners: false,\n },\n {\n key: 'ai_chat',\n label: 'Assistant',\n route: 'chat',\n slots: [],\n charts: [],\n tabs: false,\n banners: false,\n },\n] as const;\n\nexport type PageDefinition = (typeof PAGES)[number];\n/** The host pages a contribution can attach a tab, widget or banner to. */\nexport type HostPage = PageDefinition['key'];\n\nexport const PAGE_KEYS: readonly HostPage[] = PAGES.map(page => page.key);\n\nexport const TABLES = [\n { key: 'analytics.keywords', label: 'Keywords' },\n { key: 'analytics.reviews', label: 'Reviews' },\n { key: 'deployments.releases', label: 'Releases' },\n { key: 'deployments.builds', label: 'Builds' },\n] as const;\n\nexport type TableDefinition = (typeof TABLES)[number];\nexport type HostTable = TableDefinition['key'];\n\nexport const TABLE_KEYS: readonly HostTable[] = TABLES.map(table => table.key);\n\nexport const KINDS = [\n 'page',\n 'tab',\n 'widget',\n 'series',\n 'banner',\n 'rowAction',\n 'marker',\n 'settings',\n 'storage',\n 'connector',\n 'webhook',\n 'tool',\n 'mention',\n 'action',\n 'knowledge',\n 'skill',\n 'prompt',\n 'context',\n 'work',\n] as const;\nexport type ContributionKind = (typeof KINDS)[number];\n\nexport const CATEGORIES = [\n 'market_data',\n 'subscriptions',\n 'product_analytics',\n 'crashes',\n 'attribution',\n 'experiments',\n 'messaging',\n 'session_replay',\n 'localization',\n 'design',\n 'ci_cd',\n 'trackers',\n 'support',\n 'chat',\n 'ad_monetization',\n 'warehouse',\n 'compliance',\n 'additional_stores',\n] as const;\nexport type ExtensionCategory = (typeof CATEGORIES)[number];\n\nexport const EVENTS = [\n 'release.shipped',\n 'metadata.changed',\n 'keyword.set_changed',\n 'screenshots.updated',\n 'price.changed',\n 'featuring.started',\n 'score.changed',\n 'incident.opened',\n 'incident.resolved',\n 'playbook.step_approved',\n 'review.thread_opened',\n 'review.thread_resolved',\n 'approval.requested',\n 'digest.sent',\n 'install.created',\n 'install.paused',\n 'install.resumed',\n 'install.revoked',\n 'install.token_rotated',\n 'scopes.changed',\n 'settings.changed',\n] as const;\n/** Every event Tappify emits, which a mount or a server can subscribe to. */\nexport type HostEventName = (typeof EVENTS)[number];\n\nexport const SERVED_SDK_MAJORS: readonly number[] = [2];\n\n/** The `kind` of every read `tap.data.query` accepts, one per scope it needs. */\nexport type DataQueryKind =\n | 'project'\n | 'series'\n | 'keywords'\n | 'listing'\n | 'reviews'\n | 'crashes'\n | 'revenue';\n\nexport const QUERY_SCOPES: Record<DataQueryKind, ScopeKey> = {\n project: 'projects:read',\n series: 'analytics:read',\n keywords: 'store.metadata:read',\n listing: 'store.metadata:read',\n reviews: 'reviews:read',\n crashes: 'crashes:read',\n revenue: 'revenue:read',\n};\n\n/**\n * The keys a tool's answer carries for each `returns` kind it may declare.\n * `validateToolResponse`, `tappify extension doctor` and the host all read\n * this one table, so a wrong body fails the same way wherever it is checked.\n */\nexport const CARD_KEYS: Record<ToolDeclaration['returns'], string[]> = {\n value: ['label', 'value'],\n series: ['label', 'points'],\n table: ['columns', 'rows'],\n list: ['items'],\n comparison: ['label', 'left', 'right'],\n};\n\nexport const findScope = (key: string): ScopeDefinition | undefined =>\n SCOPES.find(scope => scope.key === key);\n\nexport const findPage = (key: string): PageDefinition | undefined =>\n PAGES.find(page => page.key === key);\n\nexport const findTable = (key: string): TableDefinition | undefined =>\n TABLES.find(table => table.key === key);\n\nexport const slotsForPage = (page: string): readonly SlotId[] =>\n findPage(page)?.slots ?? [];\n"],"mappings":"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","names":[]}
|
|
File without changes
|
|
File without changes
|