@tappify/extension-sdk 2.1.0-beta.1 → 2.1.0-beta.3

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.
Files changed (54) hide show
  1. package/dist/{chunk-QJMZRV7A.mjs → chunk-QQSCA6CC.mjs} +18 -6
  2. package/dist/chunk-QQSCA6CC.mjs.map +1 -0
  3. package/dist/{chunk-EB5XWQAU.cjs → chunk-SALMPL5V.cjs} +18 -6
  4. package/dist/chunk-SALMPL5V.cjs.map +1 -0
  5. package/dist/{client-CnlSHDWE.d.ts → client-BO3kavn0.d.ts} +1 -1
  6. package/dist/{client-CV1qzQgx.d.cts → client-DE-vMgdO.d.cts} +1 -1
  7. package/dist/codegen.d.cts +3 -0
  8. package/dist/codegen.d.ts +3 -0
  9. package/dist/{constants-BAimnqOK.d.cts → constants-Bh759FUI.d.cts} +4 -1
  10. package/dist/{constants-BAimnqOK.d.ts → constants-Bh759FUI.d.ts} +4 -1
  11. package/dist/{context-DJ3REtdT.d.cts → context-DI0EJCRD.d.cts} +1 -1
  12. package/dist/{context-Cr93B05o.d.ts → context-mr8R5CNt.d.ts} +1 -1
  13. package/dist/host.d.cts +4 -4
  14. package/dist/host.d.ts +4 -4
  15. package/dist/index.d.cts +4 -4
  16. package/dist/index.d.ts +4 -4
  17. package/dist/manifest.cjs +4 -1
  18. package/dist/manifest.cjs.map +1 -1
  19. package/dist/manifest.d.cts +6 -2
  20. package/dist/manifest.d.ts +6 -2
  21. package/dist/manifest.mjs +4 -1
  22. package/dist/manifest.mjs.map +1 -1
  23. package/dist/server.cjs +2 -2
  24. package/dist/server.d.cts +5 -5
  25. package/dist/server.d.ts +5 -5
  26. package/dist/server.mjs +1 -1
  27. package/dist/testing/index.cjs +2 -2
  28. package/dist/testing/index.d.cts +3 -3
  29. package/dist/testing/index.d.ts +3 -3
  30. package/dist/testing/index.mjs +1 -1
  31. package/dist/{types-I1JOZyI_.d.cts → types-BdDaLnqs.d.cts} +1 -1
  32. package/dist/{types-BYGcp5pZ.d.ts → types-uGHrRaOj.d.ts} +1 -1
  33. package/dist/ui.d.cts +1 -1
  34. package/dist/ui.d.ts +1 -1
  35. package/dist/vite-preview-bootstrap.d.cts +2 -2
  36. package/dist/vite-preview-bootstrap.d.ts +2 -2
  37. package/dist/vite-preview.cjs +1 -1
  38. package/dist/vite-preview.cjs.map +1 -1
  39. package/dist/vite-preview.d.cts +3 -3
  40. package/dist/vite-preview.d.ts +3 -3
  41. package/dist/vite-preview.mjs +1 -1
  42. package/dist/vite-preview.mjs.map +1 -1
  43. package/dist/vite.cjs +4 -1
  44. package/dist/vite.cjs.map +1 -1
  45. package/dist/vite.d.cts +3 -0
  46. package/dist/vite.d.ts +3 -0
  47. package/dist/vite.mjs +4 -1
  48. package/dist/vite.mjs.map +1 -1
  49. package/dist/{work-events-DB3WR468.d.ts → work-events-C5n497rx.d.ts} +40 -8
  50. package/dist/{work-events-Dxe7Djdy.d.cts → work-events-DSklu4t-.d.cts} +40 -8
  51. package/package.json +1 -1
  52. package/schema/extension-v2.json +8 -0
  53. package/dist/chunk-EB5XWQAU.cjs.map +0 -1
  54. package/dist/chunk-QJMZRV7A.mjs.map +0 -1
@@ -68,6 +68,20 @@ async function sendEvent(name, payload, options) {
68
68
  function nonempty(value) {
69
69
  return typeof value === "string" && value.trim().length > 0;
70
70
  }
71
+ function validPerson(person) {
72
+ const email = readUnknown(person, "email");
73
+ return nonempty(readUnknown(person, "id")) && nonempty(readUnknown(person, "displayName")) && (email === void 0 || nonempty(email) && email === email.trim() && email.split("@").length === 2);
74
+ }
75
+ function validSegment(segment) {
76
+ const type = readUnknown(segment, "type");
77
+ if (type === "text") return typeof readUnknown(segment, "text") === "string";
78
+ return type === "user_mention" && validPerson(readUnknown(segment, "person")) && nonempty(readUnknown(segment, "fallback"));
79
+ }
80
+ function validComment(comment) {
81
+ const author = readUnknown(comment, "author");
82
+ const segments = readUnknown(comment, "segments");
83
+ return nonempty(readUnknown(comment, "externalCommentId")) && typeof readUnknown(comment, "body") === "string" && nonempty(readUnknown(comment, "createdAt")) && validPerson(author) && (segments === void 0 ? readUnknown(author, "email") === void 0 : Array.isArray(segments) && Array.from(segments).every(validSegment));
84
+ }
71
85
  function validEvent(event) {
72
86
  const type = readText(event, "type");
73
87
  if (!["comment.created", "status.changed", "item.deleted"].includes(type ?? ""))
@@ -84,12 +98,10 @@ function validEvent(event) {
84
98
  if (type === "item.deleted")
85
99
  return comment === void 0 && status === void 0;
86
100
  if (type === "status.changed") {
87
- const normalized2 = readRecord(event, "status");
88
- return comment === void 0 && nonempty(normalized2.id) && nonempty(normalized2.label) && typeof normalized2.stage === "string" && ["open", "in_progress", "done"].includes(normalized2.stage);
101
+ const normalized = readRecord(event, "status");
102
+ return comment === void 0 && nonempty(normalized.id) && nonempty(normalized.label) && typeof normalized.stage === "string" && ["open", "in_progress", "done"].includes(normalized.stage);
89
103
  }
90
- const normalized = readRecord(event, "comment");
91
- const author = readRecord(normalized, "author");
92
- return status === void 0 && nonempty(normalized.externalCommentId) && typeof normalized.body === "string" && nonempty(normalized.createdAt) && nonempty(author.id) && nonempty(author.displayName);
104
+ return status === void 0 && validComment(comment);
93
105
  }
94
106
  async function sendWorkEvent(event, options) {
95
107
  if (!validEvent(event))
@@ -129,4 +141,4 @@ export {
129
141
  sendEvent,
130
142
  sendWorkEvent
131
143
  };
132
- //# sourceMappingURL=chunk-QJMZRV7A.mjs.map
144
+ //# sourceMappingURL=chunk-QQSCA6CC.mjs.map
@@ -0,0 +1 @@
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 validPerson(person: unknown): boolean {\n const email = readUnknown(person, 'email');\n return (\n nonempty(readUnknown(person, 'id')) &&\n nonempty(readUnknown(person, 'displayName')) &&\n (email === undefined ||\n (nonempty(email) &&\n email === email.trim() &&\n email.split('@').length === 2))\n );\n}\n\nfunction validSegment(segment: unknown): boolean {\n const type = readUnknown(segment, 'type');\n if (type === 'text') return typeof readUnknown(segment, 'text') === 'string';\n return (\n type === 'user_mention' &&\n validPerson(readUnknown(segment, 'person')) &&\n nonempty(readUnknown(segment, 'fallback'))\n );\n}\n\nfunction validComment(comment: unknown): boolean {\n const author = readUnknown(comment, 'author');\n const segments = readUnknown(comment, 'segments');\n return (\n nonempty(readUnknown(comment, 'externalCommentId')) &&\n typeof readUnknown(comment, 'body') === 'string' &&\n nonempty(readUnknown(comment, 'createdAt')) &&\n validPerson(author) &&\n (segments === undefined\n ? readUnknown(author, 'email') === undefined\n : Array.isArray(segments) && Array.from(segments).every(validSegment))\n );\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 return status === undefined && validComment(comment);\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":[]}
@@ -68,6 +68,20 @@ async function sendEvent(name, payload, options) {
68
68
  function nonempty(value) {
69
69
  return typeof value === "string" && value.trim().length > 0;
70
70
  }
71
+ function validPerson(person) {
72
+ const email = _chunkA74HCO6Tcjs.readUnknown.call(void 0, person, "email");
73
+ return nonempty(_chunkA74HCO6Tcjs.readUnknown.call(void 0, person, "id")) && nonempty(_chunkA74HCO6Tcjs.readUnknown.call(void 0, person, "displayName")) && (email === void 0 || nonempty(email) && email === email.trim() && email.split("@").length === 2);
74
+ }
75
+ function validSegment(segment) {
76
+ const type = _chunkA74HCO6Tcjs.readUnknown.call(void 0, segment, "type");
77
+ if (type === "text") return typeof _chunkA74HCO6Tcjs.readUnknown.call(void 0, segment, "text") === "string";
78
+ return type === "user_mention" && validPerson(_chunkA74HCO6Tcjs.readUnknown.call(void 0, segment, "person")) && nonempty(_chunkA74HCO6Tcjs.readUnknown.call(void 0, segment, "fallback"));
79
+ }
80
+ function validComment(comment) {
81
+ const author = _chunkA74HCO6Tcjs.readUnknown.call(void 0, comment, "author");
82
+ const segments = _chunkA74HCO6Tcjs.readUnknown.call(void 0, comment, "segments");
83
+ return nonempty(_chunkA74HCO6Tcjs.readUnknown.call(void 0, comment, "externalCommentId")) && typeof _chunkA74HCO6Tcjs.readUnknown.call(void 0, comment, "body") === "string" && nonempty(_chunkA74HCO6Tcjs.readUnknown.call(void 0, comment, "createdAt")) && validPerson(author) && (segments === void 0 ? _chunkA74HCO6Tcjs.readUnknown.call(void 0, author, "email") === void 0 : Array.isArray(segments) && Array.from(segments).every(validSegment));
84
+ }
71
85
  function validEvent(event) {
72
86
  const type = _chunkA74HCO6Tcjs.readText.call(void 0, event, "type");
73
87
  if (!["comment.created", "status.changed", "item.deleted"].includes(_nullishCoalesce(type, () => ( ""))))
@@ -84,12 +98,10 @@ function validEvent(event) {
84
98
  if (type === "item.deleted")
85
99
  return comment === void 0 && status === void 0;
86
100
  if (type === "status.changed") {
87
- const normalized2 = _chunkA74HCO6Tcjs.readRecord.call(void 0, event, "status");
88
- return comment === void 0 && nonempty(normalized2.id) && nonempty(normalized2.label) && typeof normalized2.stage === "string" && ["open", "in_progress", "done"].includes(normalized2.stage);
101
+ const normalized = _chunkA74HCO6Tcjs.readRecord.call(void 0, event, "status");
102
+ return comment === void 0 && nonempty(normalized.id) && nonempty(normalized.label) && typeof normalized.stage === "string" && ["open", "in_progress", "done"].includes(normalized.stage);
89
103
  }
90
- const normalized = _chunkA74HCO6Tcjs.readRecord.call(void 0, event, "comment");
91
- const author = _chunkA74HCO6Tcjs.readRecord.call(void 0, normalized, "author");
92
- return status === void 0 && nonempty(normalized.externalCommentId) && typeof normalized.body === "string" && nonempty(normalized.createdAt) && nonempty(author.id) && nonempty(author.displayName);
104
+ return status === void 0 && validComment(comment);
93
105
  }
94
106
  async function sendWorkEvent(event, options) {
95
107
  if (!validEvent(event))
@@ -129,4 +141,4 @@ async function sendWorkEvent(event, options) {
129
141
 
130
142
 
131
143
  exports.signWebhook = signWebhook; exports.sendEvent = sendEvent; exports.sendWorkEvent = sendWorkEvent;
132
- //# sourceMappingURL=chunk-EB5XWQAU.cjs.map
144
+ //# sourceMappingURL=chunk-SALMPL5V.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-SALMPL5V.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-SALMPL5V.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 validPerson(person: unknown): boolean {\n const email = readUnknown(person, 'email');\n return (\n nonempty(readUnknown(person, 'id')) &&\n nonempty(readUnknown(person, 'displayName')) &&\n (email === undefined ||\n (nonempty(email) &&\n email === email.trim() &&\n email.split('@').length === 2))\n );\n}\n\nfunction validSegment(segment: unknown): boolean {\n const type = readUnknown(segment, 'type');\n if (type === 'text') return typeof readUnknown(segment, 'text') === 'string';\n return (\n type === 'user_mention' &&\n validPerson(readUnknown(segment, 'person')) &&\n nonempty(readUnknown(segment, 'fallback'))\n );\n}\n\nfunction validComment(comment: unknown): boolean {\n const author = readUnknown(comment, 'author');\n const segments = readUnknown(comment, 'segments');\n return (\n nonempty(readUnknown(comment, 'externalCommentId')) &&\n typeof readUnknown(comment, 'body') === 'string' &&\n nonempty(readUnknown(comment, 'createdAt')) &&\n validPerson(author) &&\n (segments === undefined\n ? readUnknown(author, 'email') === undefined\n : Array.isArray(segments) && Array.from(segments).every(validSegment))\n );\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 return status === undefined && validComment(comment);\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,6 +1,6 @@
1
1
  import { ComponentType } from 'react';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
- import { E as ExtensionManifest } from './constants-BAimnqOK.js';
3
+ import { E as ExtensionManifest } from './constants-Bh759FUI.js';
4
4
 
5
5
  interface PreviewLoadRequest {
6
6
  extensionId: string;
@@ -1,6 +1,6 @@
1
1
  import { ComponentType } from 'react';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
- import { E as ExtensionManifest } from './constants-BAimnqOK.cjs';
3
+ import { E as ExtensionManifest } from './constants-Bh759FUI.cjs';
4
4
 
5
5
  interface PreviewLoadRequest {
6
6
  extensionId: string;
@@ -261,6 +261,7 @@ interface CredentialField {
261
261
  options?: string[];
262
262
  help?: string;
263
263
  }
264
+ type OAuthTokenRequestEncoding = 'form' | 'json';
264
265
  interface ConnectorAuth {
265
266
  method: 'none' | 'api_key' | 'oauth';
266
267
  fields?: CredentialField[];
@@ -268,6 +269,8 @@ interface ConnectorAuth {
268
269
  authorizationUrl: string;
269
270
  tokenUrl: string;
270
271
  scopes: string[];
272
+ /** The token request body encoding. When omitted, uses form encoding. */
273
+ tokenRequestEncoding?: OAuthTokenRequestEncoding;
271
274
  };
272
275
  }
273
276
  interface DimensionDeclaration {
package/dist/codegen.d.ts CHANGED
@@ -261,6 +261,7 @@ interface CredentialField {
261
261
  options?: string[];
262
262
  help?: string;
263
263
  }
264
+ type OAuthTokenRequestEncoding = 'form' | 'json';
264
265
  interface ConnectorAuth {
265
266
  method: 'none' | 'api_key' | 'oauth';
266
267
  fields?: CredentialField[];
@@ -268,6 +269,8 @@ interface ConnectorAuth {
268
269
  authorizationUrl: string;
269
270
  tokenUrl: string;
270
271
  scopes: string[];
272
+ /** The token request body encoding. When omitted, uses form encoding. */
273
+ tokenRequestEncoding?: OAuthTokenRequestEncoding;
271
274
  };
272
275
  }
273
276
  interface DimensionDeclaration {
@@ -75,6 +75,7 @@ interface CredentialField {
75
75
  options?: string[];
76
76
  help?: string;
77
77
  }
78
+ type OAuthTokenRequestEncoding = 'form' | 'json';
78
79
  interface ConnectorAuth {
79
80
  method: 'none' | 'api_key' | 'oauth';
80
81
  fields?: CredentialField[];
@@ -82,6 +83,8 @@ interface ConnectorAuth {
82
83
  authorizationUrl: string;
83
84
  tokenUrl: string;
84
85
  scopes: string[];
86
+ /** The token request body encoding. When omitted, uses form encoding. */
87
+ tokenRequestEncoding?: OAuthTokenRequestEncoding;
85
88
  };
86
89
  }
87
90
  interface DimensionDeclaration {
@@ -479,4 +482,4 @@ declare const findPage: (key: string) => PageDefinition | undefined;
479
482
  declare const findTable: (key: string) => TableDefinition | undefined;
480
483
  declare const slotsForPage: (page: string) => readonly SlotId[];
481
484
 
482
- export { type StorageCollection as $, type ActionDeclaration as A, type BannerContribution as B, CARD_KEYS as C, type DataQueryKind as D, type ExtensionManifest as E, type PageDefinition as F, type ProcedureDeclaration as G, type HostEventName as H, type PromptDeclaration as I, type JsonSchema as J, KINDS as K, type LegacyWorkContribution as L, type ManifestValidation as M, SCOPES as N, SCOPE_KEYS as O, PAGES as P, QUERY_SCOPES as Q, type RowActionContribution as R, type ScopeKey as S, SERVED_SDK_MAJORS as T, type UiContributionRef as U, SLOTS as V, type ScopeDefinition as W, type ScopeEntry as X, type SeriesContribution as Y, type SettingsContribution as Z, type SkillDeclaration as _, type HostPage as a, TABLES as a0, TABLE_KEYS as a1, type TabContribution as a2, type TableDefinition as a3, type ToolDeclaration as a4, type WebhookContribution as a5, type WidgetContribution as a6, type WorkAuth as a7, type WorkContribution as a8, type WorkDirection as a9, findPage as aa, findScope as ab, findTable as ac, slotsForPage as ad, type SlotId as b, type ExposableKind as c, type ManifestIssue as d, type AiContribution as e, CATEGORIES as f, CHARTS as g, type ConnectorAuth as h, type ConnectorContribution as i, type ContextDeclaration as j, type ContributionKind as k, type CredentialField as l, type DimensionDeclaration as m, EVENTS as n, type ExtensionCategory as o, type ExtensionInstallScope as p, type ExtensionListing as q, type ExtensionVisibility as r, type HostChart as s, type HostTable as t, type KnowledgeDeclaration as u, type MarkerContribution as v, type MentionDeclaration as w, type MetricDeclaration as x, PAGE_KEYS as y, type PageContribution as z };
485
+ export { type SkillDeclaration as $, type ActionDeclaration as A, type BannerContribution as B, CARD_KEYS as C, type DataQueryKind as D, type ExtensionManifest as E, type PageDefinition as F, type ProcedureDeclaration as G, type HostEventName as H, type PromptDeclaration as I, type JsonSchema as J, KINDS as K, type LegacyWorkContribution as L, type ManifestValidation as M, SCOPES as N, type OAuthTokenRequestEncoding as O, PAGES as P, QUERY_SCOPES as Q, type RowActionContribution as R, type ScopeKey as S, SCOPE_KEYS as T, type UiContributionRef as U, SERVED_SDK_MAJORS as V, SLOTS as W, type ScopeDefinition as X, type ScopeEntry as Y, type SeriesContribution as Z, type SettingsContribution as _, type HostPage as a, type StorageCollection as a0, TABLES as a1, TABLE_KEYS as a2, type TabContribution as a3, type TableDefinition as a4, type ToolDeclaration as a5, type WebhookContribution as a6, type WidgetContribution as a7, type WorkAuth as a8, type WorkContribution as a9, type WorkDirection as aa, findPage as ab, findScope as ac, findTable as ad, slotsForPage as ae, type SlotId as b, type ExposableKind as c, type ManifestIssue as d, type AiContribution as e, CATEGORIES as f, CHARTS as g, type ConnectorAuth as h, type ConnectorContribution as i, type ContextDeclaration as j, type ContributionKind as k, type CredentialField as l, type DimensionDeclaration as m, EVENTS as n, type ExtensionCategory as o, type ExtensionInstallScope as p, type ExtensionListing as q, type ExtensionVisibility as r, type HostChart as s, type HostTable as t, type KnowledgeDeclaration as u, type MarkerContribution as v, type MentionDeclaration as w, type MetricDeclaration as x, PAGE_KEYS as y, type PageContribution as z };
@@ -75,6 +75,7 @@ interface CredentialField {
75
75
  options?: string[];
76
76
  help?: string;
77
77
  }
78
+ type OAuthTokenRequestEncoding = 'form' | 'json';
78
79
  interface ConnectorAuth {
79
80
  method: 'none' | 'api_key' | 'oauth';
80
81
  fields?: CredentialField[];
@@ -82,6 +83,8 @@ interface ConnectorAuth {
82
83
  authorizationUrl: string;
83
84
  tokenUrl: string;
84
85
  scopes: string[];
86
+ /** The token request body encoding. When omitted, uses form encoding. */
87
+ tokenRequestEncoding?: OAuthTokenRequestEncoding;
85
88
  };
86
89
  }
87
90
  interface DimensionDeclaration {
@@ -479,4 +482,4 @@ declare const findPage: (key: string) => PageDefinition | undefined;
479
482
  declare const findTable: (key: string) => TableDefinition | undefined;
480
483
  declare const slotsForPage: (page: string) => readonly SlotId[];
481
484
 
482
- export { type StorageCollection as $, type ActionDeclaration as A, type BannerContribution as B, CARD_KEYS as C, type DataQueryKind as D, type ExtensionManifest as E, type PageDefinition as F, type ProcedureDeclaration as G, type HostEventName as H, type PromptDeclaration as I, type JsonSchema as J, KINDS as K, type LegacyWorkContribution as L, type ManifestValidation as M, SCOPES as N, SCOPE_KEYS as O, PAGES as P, QUERY_SCOPES as Q, type RowActionContribution as R, type ScopeKey as S, SERVED_SDK_MAJORS as T, type UiContributionRef as U, SLOTS as V, type ScopeDefinition as W, type ScopeEntry as X, type SeriesContribution as Y, type SettingsContribution as Z, type SkillDeclaration as _, type HostPage as a, TABLES as a0, TABLE_KEYS as a1, type TabContribution as a2, type TableDefinition as a3, type ToolDeclaration as a4, type WebhookContribution as a5, type WidgetContribution as a6, type WorkAuth as a7, type WorkContribution as a8, type WorkDirection as a9, findPage as aa, findScope as ab, findTable as ac, slotsForPage as ad, type SlotId as b, type ExposableKind as c, type ManifestIssue as d, type AiContribution as e, CATEGORIES as f, CHARTS as g, type ConnectorAuth as h, type ConnectorContribution as i, type ContextDeclaration as j, type ContributionKind as k, type CredentialField as l, type DimensionDeclaration as m, EVENTS as n, type ExtensionCategory as o, type ExtensionInstallScope as p, type ExtensionListing as q, type ExtensionVisibility as r, type HostChart as s, type HostTable as t, type KnowledgeDeclaration as u, type MarkerContribution as v, type MentionDeclaration as w, type MetricDeclaration as x, PAGE_KEYS as y, type PageContribution as z };
485
+ export { type SkillDeclaration as $, type ActionDeclaration as A, type BannerContribution as B, CARD_KEYS as C, type DataQueryKind as D, type ExtensionManifest as E, type PageDefinition as F, type ProcedureDeclaration as G, type HostEventName as H, type PromptDeclaration as I, type JsonSchema as J, KINDS as K, type LegacyWorkContribution as L, type ManifestValidation as M, SCOPES as N, type OAuthTokenRequestEncoding as O, PAGES as P, QUERY_SCOPES as Q, type RowActionContribution as R, type ScopeKey as S, SCOPE_KEYS as T, type UiContributionRef as U, SERVED_SDK_MAJORS as V, SLOTS as W, type ScopeDefinition as X, type ScopeEntry as Y, type SeriesContribution as Z, type SettingsContribution as _, type HostPage as a, type StorageCollection as a0, TABLES as a1, TABLE_KEYS as a2, type TabContribution as a3, type TableDefinition as a4, type ToolDeclaration as a5, type WebhookContribution as a6, type WidgetContribution as a7, type WorkAuth as a8, type WorkContribution as a9, type WorkDirection as aa, findPage as ab, findScope as ac, findTable as ad, slotsForPage as ae, type SlotId as b, type ExposableKind as c, type ManifestIssue as d, type AiContribution as e, CATEGORIES as f, CHARTS as g, type ConnectorAuth as h, type ConnectorContribution as i, type ContextDeclaration as j, type ContributionKind as k, type CredentialField as l, type DimensionDeclaration as m, EVENTS as n, type ExtensionCategory as o, type ExtensionInstallScope as p, type ExtensionListing as q, type ExtensionVisibility as r, type HostChart as s, type HostTable as t, type KnowledgeDeclaration as u, type MarkerContribution as v, type MentionDeclaration as w, type MetricDeclaration as x, PAGE_KEYS as y, type PageContribution as z };
@@ -1,5 +1,5 @@
1
1
  import { Context } from 'react';
2
- import { T as Tap } from './types-I1JOZyI_.cjs';
2
+ import { T as Tap } from './types-BdDaLnqs.cjs';
3
3
 
4
4
  declare const TapContext: Context<Tap | null>;
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { Context } from 'react';
2
- import { T as Tap } from './types-BYGcp5pZ.js';
2
+ import { T as Tap } from './types-uGHrRaOj.js';
3
3
 
4
4
  declare const TapContext: Context<Tap | null>;
5
5
  /**
package/dist/host.d.cts CHANGED
@@ -1,9 +1,9 @@
1
- export { T as TapContext } from './context-DJ3REtdT.cjs';
2
- import { T as Tap } from './types-I1JOZyI_.cjs';
3
- export { A as ActionId, k as ActionInput, P as PromptId, l as PromptInput, m as TapActionMap, n as TapActionRun, o as TapApp, p as TapChangeKey, q as TapChatCard, r as TapCollection, s as TapComparisonSide, t as TapConfirmOptions, u as TapCrashIssue, v as TapCrashesResult, w as TapCredentialValues, x as TapCredentials, y as TapDateRange, a as TapFilters, z as TapFormatters, B as TapHostEventMap, c as TapHostEvents, C as TapInternals, D as TapKeyword, E as TapKeywordsResult, F as TapListing, G as TapListingResult, H as TapPageProps, I as TapPath, J as TapPlatform, K as TapPlatformFilter, g as TapProcedureInput, L as TapProcedureMap, f as TapProcedureName, h as TapProcedureOutput, M as TapProcedures, N as TapProjectResult, O as TapPromptMap, d as TapQuery, Q as TapRelease, e as TapResult, R as TapRevenueResult, S as TapReview, U as TapReviewsResult, V as TapRowActionProps, W as TapSeriesMetric, X as TapSeriesPoint, Y as TapSeriesResult, Z as TapSettings, _ as TapSettingsProps, $ as TapSettingsValues, a0 as TapSingleton, j as TapSingletonDocument, i as TapSingletonName, b as TapSize, a1 as TapStorage, a2 as TapStorageMap, a3 as TapTabProps, a4 as TapTableColumn, a5 as TapTelemetryEvents, a6 as TapToastTone, a7 as TapToolMap, a8 as TapWebhookMap, a9 as TapWidgetProps, aa as TelemetryEvent, ab as ToolId, ac as ToolInput, ad as WebhookName, ae as WebhookPayload } from './types-I1JOZyI_.cjs';
1
+ export { T as TapContext } from './context-DI0EJCRD.cjs';
2
+ import { T as Tap } from './types-BdDaLnqs.cjs';
3
+ export { A as ActionId, k as ActionInput, P as PromptId, l as PromptInput, m as TapActionMap, n as TapActionRun, o as TapApp, p as TapChangeKey, q as TapChatCard, r as TapCollection, s as TapComparisonSide, t as TapConfirmOptions, u as TapCrashIssue, v as TapCrashesResult, w as TapCredentialValues, x as TapCredentials, y as TapDateRange, a as TapFilters, z as TapFormatters, B as TapHostEventMap, c as TapHostEvents, C as TapInternals, D as TapKeyword, E as TapKeywordsResult, F as TapListing, G as TapListingResult, H as TapPageProps, I as TapPath, J as TapPlatform, K as TapPlatformFilter, g as TapProcedureInput, L as TapProcedureMap, f as TapProcedureName, h as TapProcedureOutput, M as TapProcedures, N as TapProjectResult, O as TapPromptMap, d as TapQuery, Q as TapRelease, e as TapResult, R as TapRevenueResult, S as TapReview, U as TapReviewsResult, V as TapRowActionProps, W as TapSeriesMetric, X as TapSeriesPoint, Y as TapSeriesResult, Z as TapSettings, _ as TapSettingsProps, $ as TapSettingsValues, a0 as TapSingleton, j as TapSingletonDocument, i as TapSingletonName, b as TapSize, a1 as TapStorage, a2 as TapStorageMap, a3 as TapTabProps, a4 as TapTableColumn, a5 as TapTelemetryEvents, a6 as TapToastTone, a7 as TapToolMap, a8 as TapWebhookMap, a9 as TapWidgetProps, aa as TelemetryEvent, ab as ToolId, ac as ToolInput, ad as WebhookName, ae as WebhookPayload } from './types-BdDaLnqs.cjs';
4
4
  import { QueryClient } from '@tanstack/react-query';
5
5
  import { ReactNode, ReactElement } from 'react';
6
- export { D as DataQueryKind, H as HostEventName, a as HostPage, S as ScopeKey, b as SlotId } from './constants-BAimnqOK.cjs';
6
+ export { D as DataQueryKind, H as HostEventName, a as HostPage, S as ScopeKey, b as SlotId } from './constants-Bh759FUI.cjs';
7
7
 
8
8
  declare function collectStyles(remoteModule: unknown): string[];
9
9
 
package/dist/host.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { T as TapContext } from './context-Cr93B05o.js';
2
- import { T as Tap } from './types-BYGcp5pZ.js';
3
- export { A as ActionId, k as ActionInput, P as PromptId, l as PromptInput, m as TapActionMap, n as TapActionRun, o as TapApp, p as TapChangeKey, q as TapChatCard, r as TapCollection, s as TapComparisonSide, t as TapConfirmOptions, u as TapCrashIssue, v as TapCrashesResult, w as TapCredentialValues, x as TapCredentials, y as TapDateRange, a as TapFilters, z as TapFormatters, B as TapHostEventMap, c as TapHostEvents, C as TapInternals, D as TapKeyword, E as TapKeywordsResult, F as TapListing, G as TapListingResult, H as TapPageProps, I as TapPath, J as TapPlatform, K as TapPlatformFilter, g as TapProcedureInput, L as TapProcedureMap, f as TapProcedureName, h as TapProcedureOutput, M as TapProcedures, N as TapProjectResult, O as TapPromptMap, d as TapQuery, Q as TapRelease, e as TapResult, R as TapRevenueResult, S as TapReview, U as TapReviewsResult, V as TapRowActionProps, W as TapSeriesMetric, X as TapSeriesPoint, Y as TapSeriesResult, Z as TapSettings, _ as TapSettingsProps, $ as TapSettingsValues, a0 as TapSingleton, j as TapSingletonDocument, i as TapSingletonName, b as TapSize, a1 as TapStorage, a2 as TapStorageMap, a3 as TapTabProps, a4 as TapTableColumn, a5 as TapTelemetryEvents, a6 as TapToastTone, a7 as TapToolMap, a8 as TapWebhookMap, a9 as TapWidgetProps, aa as TelemetryEvent, ab as ToolId, ac as ToolInput, ad as WebhookName, ae as WebhookPayload } from './types-BYGcp5pZ.js';
1
+ export { T as TapContext } from './context-mr8R5CNt.js';
2
+ import { T as Tap } from './types-uGHrRaOj.js';
3
+ export { A as ActionId, k as ActionInput, P as PromptId, l as PromptInput, m as TapActionMap, n as TapActionRun, o as TapApp, p as TapChangeKey, q as TapChatCard, r as TapCollection, s as TapComparisonSide, t as TapConfirmOptions, u as TapCrashIssue, v as TapCrashesResult, w as TapCredentialValues, x as TapCredentials, y as TapDateRange, a as TapFilters, z as TapFormatters, B as TapHostEventMap, c as TapHostEvents, C as TapInternals, D as TapKeyword, E as TapKeywordsResult, F as TapListing, G as TapListingResult, H as TapPageProps, I as TapPath, J as TapPlatform, K as TapPlatformFilter, g as TapProcedureInput, L as TapProcedureMap, f as TapProcedureName, h as TapProcedureOutput, M as TapProcedures, N as TapProjectResult, O as TapPromptMap, d as TapQuery, Q as TapRelease, e as TapResult, R as TapRevenueResult, S as TapReview, U as TapReviewsResult, V as TapRowActionProps, W as TapSeriesMetric, X as TapSeriesPoint, Y as TapSeriesResult, Z as TapSettings, _ as TapSettingsProps, $ as TapSettingsValues, a0 as TapSingleton, j as TapSingletonDocument, i as TapSingletonName, b as TapSize, a1 as TapStorage, a2 as TapStorageMap, a3 as TapTabProps, a4 as TapTableColumn, a5 as TapTelemetryEvents, a6 as TapToastTone, a7 as TapToolMap, a8 as TapWebhookMap, a9 as TapWidgetProps, aa as TelemetryEvent, ab as ToolId, ac as ToolInput, ad as WebhookName, ae as WebhookPayload } from './types-uGHrRaOj.js';
4
4
  import { QueryClient } from '@tanstack/react-query';
5
5
  import { ReactNode, ReactElement } from 'react';
6
- export { D as DataQueryKind, H as HostEventName, a as HostPage, S as ScopeKey, b as SlotId } from './constants-BAimnqOK.js';
6
+ export { D as DataQueryKind, H as HostEventName, a as HostPage, S as ScopeKey, b as SlotId } from './constants-Bh759FUI.js';
7
7
 
8
8
  declare function collectStyles(remoteModule: unknown): string[];
9
9
 
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- export { u as useTap } from './context-DJ3REtdT.cjs';
1
+ export { u as useTap } from './context-DI0EJCRD.cjs';
2
2
  export { T as TAP_ERROR_CODES, a as TapError, b as TapErrorCode, c as TapServerError } from './errors-Cqh0wrqt.cjs';
3
- import { T as Tap, a as TapFilters, b as TapSize, c as TapHostEvents, d as TapQuery, e as TapResult, f as TapProcedureName, g as TapProcedureInput, h as TapProcedureOutput, i as TapSingletonName, j as TapSingletonDocument } from './types-I1JOZyI_.cjs';
4
- export { A as ActionId, k as ActionInput, P as PromptId, l as PromptInput, m as TapActionMap, n as TapActionRun, o as TapApp, p as TapChangeKey, q as TapChatCard, r as TapCollection, s as TapComparisonSide, t as TapConfirmOptions, u as TapCrashIssue, v as TapCrashesResult, w as TapCredentialValues, x as TapCredentials, y as TapDateRange, z as TapFormatters, B as TapHostEventMap, C as TapInternals, D as TapKeyword, E as TapKeywordsResult, F as TapListing, G as TapListingResult, H as TapPageProps, I as TapPath, J as TapPlatform, K as TapPlatformFilter, L as TapProcedureMap, M as TapProcedures, N as TapProjectResult, O as TapPromptMap, Q as TapRelease, R as TapRevenueResult, S as TapReview, U as TapReviewsResult, V as TapRowActionProps, W as TapSeriesMetric, X as TapSeriesPoint, Y as TapSeriesResult, Z as TapSettings, _ as TapSettingsProps, $ as TapSettingsValues, a0 as TapSingleton, a1 as TapStorage, a2 as TapStorageMap, a3 as TapTabProps, a4 as TapTableColumn, a5 as TapTelemetryEvents, a6 as TapToastTone, a7 as TapToolMap, a8 as TapWebhookMap, a9 as TapWidgetProps, aa as TelemetryEvent, ab as ToolId, ac as ToolInput, ad as WebhookName, ae as WebhookPayload } from './types-I1JOZyI_.cjs';
5
- export { D as DataQueryKind, H as HostEventName, a as HostPage, S as ScopeKey, b as SlotId } from './constants-BAimnqOK.cjs';
3
+ import { T as Tap, a as TapFilters, b as TapSize, c as TapHostEvents, d as TapQuery, e as TapResult, f as TapProcedureName, g as TapProcedureInput, h as TapProcedureOutput, i as TapSingletonName, j as TapSingletonDocument } from './types-BdDaLnqs.cjs';
4
+ export { A as ActionId, k as ActionInput, P as PromptId, l as PromptInput, m as TapActionMap, n as TapActionRun, o as TapApp, p as TapChangeKey, q as TapChatCard, r as TapCollection, s as TapComparisonSide, t as TapConfirmOptions, u as TapCrashIssue, v as TapCrashesResult, w as TapCredentialValues, x as TapCredentials, y as TapDateRange, z as TapFormatters, B as TapHostEventMap, C as TapInternals, D as TapKeyword, E as TapKeywordsResult, F as TapListing, G as TapListingResult, H as TapPageProps, I as TapPath, J as TapPlatform, K as TapPlatformFilter, L as TapProcedureMap, M as TapProcedures, N as TapProjectResult, O as TapPromptMap, Q as TapRelease, R as TapRevenueResult, S as TapReview, U as TapReviewsResult, V as TapRowActionProps, W as TapSeriesMetric, X as TapSeriesPoint, Y as TapSeriesResult, Z as TapSettings, _ as TapSettingsProps, $ as TapSettingsValues, a0 as TapSingleton, a1 as TapStorage, a2 as TapStorageMap, a3 as TapTabProps, a4 as TapTableColumn, a5 as TapTelemetryEvents, a6 as TapToastTone, a7 as TapToolMap, a8 as TapWebhookMap, a9 as TapWidgetProps, aa as TelemetryEvent, ab as ToolId, ac as ToolInput, ad as WebhookName, ae as WebhookPayload } from './types-BdDaLnqs.cjs';
5
+ export { D as DataQueryKind, H as HostEventName, a as HostPage, S as ScopeKey, b as SlotId } from './constants-Bh759FUI.cjs';
6
6
  import 'react';
7
7
 
8
8
  /**
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export { u as useTap } from './context-Cr93B05o.js';
1
+ export { u as useTap } from './context-mr8R5CNt.js';
2
2
  export { T as TAP_ERROR_CODES, a as TapError, b as TapErrorCode, c as TapServerError } from './errors-Cqh0wrqt.js';
3
- import { T as Tap, a as TapFilters, b as TapSize, c as TapHostEvents, d as TapQuery, e as TapResult, f as TapProcedureName, g as TapProcedureInput, h as TapProcedureOutput, i as TapSingletonName, j as TapSingletonDocument } from './types-BYGcp5pZ.js';
4
- export { A as ActionId, k as ActionInput, P as PromptId, l as PromptInput, m as TapActionMap, n as TapActionRun, o as TapApp, p as TapChangeKey, q as TapChatCard, r as TapCollection, s as TapComparisonSide, t as TapConfirmOptions, u as TapCrashIssue, v as TapCrashesResult, w as TapCredentialValues, x as TapCredentials, y as TapDateRange, z as TapFormatters, B as TapHostEventMap, C as TapInternals, D as TapKeyword, E as TapKeywordsResult, F as TapListing, G as TapListingResult, H as TapPageProps, I as TapPath, J as TapPlatform, K as TapPlatformFilter, L as TapProcedureMap, M as TapProcedures, N as TapProjectResult, O as TapPromptMap, Q as TapRelease, R as TapRevenueResult, S as TapReview, U as TapReviewsResult, V as TapRowActionProps, W as TapSeriesMetric, X as TapSeriesPoint, Y as TapSeriesResult, Z as TapSettings, _ as TapSettingsProps, $ as TapSettingsValues, a0 as TapSingleton, a1 as TapStorage, a2 as TapStorageMap, a3 as TapTabProps, a4 as TapTableColumn, a5 as TapTelemetryEvents, a6 as TapToastTone, a7 as TapToolMap, a8 as TapWebhookMap, a9 as TapWidgetProps, aa as TelemetryEvent, ab as ToolId, ac as ToolInput, ad as WebhookName, ae as WebhookPayload } from './types-BYGcp5pZ.js';
5
- export { D as DataQueryKind, H as HostEventName, a as HostPage, S as ScopeKey, b as SlotId } from './constants-BAimnqOK.js';
3
+ import { T as Tap, a as TapFilters, b as TapSize, c as TapHostEvents, d as TapQuery, e as TapResult, f as TapProcedureName, g as TapProcedureInput, h as TapProcedureOutput, i as TapSingletonName, j as TapSingletonDocument } from './types-uGHrRaOj.js';
4
+ export { A as ActionId, k as ActionInput, P as PromptId, l as PromptInput, m as TapActionMap, n as TapActionRun, o as TapApp, p as TapChangeKey, q as TapChatCard, r as TapCollection, s as TapComparisonSide, t as TapConfirmOptions, u as TapCrashIssue, v as TapCrashesResult, w as TapCredentialValues, x as TapCredentials, y as TapDateRange, z as TapFormatters, B as TapHostEventMap, C as TapInternals, D as TapKeyword, E as TapKeywordsResult, F as TapListing, G as TapListingResult, H as TapPageProps, I as TapPath, J as TapPlatform, K as TapPlatformFilter, L as TapProcedureMap, M as TapProcedures, N as TapProjectResult, O as TapPromptMap, Q as TapRelease, R as TapRevenueResult, S as TapReview, U as TapReviewsResult, V as TapRowActionProps, W as TapSeriesMetric, X as TapSeriesPoint, Y as TapSeriesResult, Z as TapSettings, _ as TapSettingsProps, $ as TapSettingsValues, a0 as TapSingleton, a1 as TapStorage, a2 as TapStorageMap, a3 as TapTabProps, a4 as TapTableColumn, a5 as TapTelemetryEvents, a6 as TapToastTone, a7 as TapToolMap, a8 as TapWebhookMap, a9 as TapWidgetProps, aa as TelemetryEvent, ab as ToolId, ac as ToolInput, ad as WebhookName, ae as WebhookPayload } from './types-uGHrRaOj.js';
5
+ export { D as DataQueryKind, H as HostEventName, a as HostPage, S as ScopeKey, b as SlotId } from './constants-Bh759FUI.js';
6
6
  import 'react';
7
7
 
8
8
  /**
package/dist/manifest.cjs CHANGED
@@ -198,7 +198,10 @@ var connectorContribution = _zod.z.object({
198
198
  ),
199
199
  scopes: _zod.z.array(_zod.z.string()).describe(
200
200
  "The scopes asked of the outside service. These are that service's scopes, not Tappify's."
201
- )
201
+ ),
202
+ tokenRequestEncoding: _zod.z.enum(["form", "json"]).describe(
203
+ "The request body encoding for authorization-code and refresh token exchanges. When omitted, uses form encoding (application/x-www-form-urlencoded); json uses application/json."
204
+ ).optional()
202
205
  }).strict().describe('The endpoints, for `method: "oauth"`.').optional()
203
206
  }).strict().describe("How owners authenticate this connector.").optional(),
204
207
  sync: _zod.z.enum(["5m", "15m", "1h", "6h", "24h"]).describe("How often Tappify asks your server to sync.").optional(),