@tappify/extension-sdk 2.1.0-beta.3 → 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.
Files changed (64) hide show
  1. package/dist/{chunk-QQSCA6CC.mjs → chunk-6FASZFC4.mjs} +2 -2
  2. package/dist/{chunk-SALMPL5V.cjs → chunk-6MP5DKLZ.cjs} +20 -20
  3. package/dist/{chunk-SALMPL5V.cjs.map → chunk-6MP5DKLZ.cjs.map} +1 -1
  4. package/dist/{chunk-BPCGXXMD.cjs → chunk-AYYJCRS4.cjs} +10 -10
  5. package/dist/{chunk-BPCGXXMD.cjs.map → chunk-AYYJCRS4.cjs.map} +1 -1
  6. package/dist/{chunk-KZ5NGFUP.mjs → chunk-CEFLOQD4.mjs} +2 -2
  7. package/dist/{chunk-7YKH4LZN.cjs → chunk-EV3KKP62.cjs} +17 -6
  8. package/dist/chunk-EV3KKP62.cjs.map +1 -0
  9. package/dist/{chunk-SGCYEEXD.mjs → chunk-IHLK4I7J.mjs} +17 -6
  10. package/dist/chunk-IHLK4I7J.mjs.map +1 -0
  11. package/dist/{chunk-A74HCO6T.cjs → chunk-TEIGGORZ.cjs} +3 -3
  12. package/dist/{chunk-A74HCO6T.cjs.map → chunk-TEIGGORZ.cjs.map} +1 -1
  13. package/dist/{chunk-SWG7CNTZ.mjs → chunk-WW2D3N2T.mjs} +3 -3
  14. package/dist/{client-DE-vMgdO.d.cts → client-BLnec4SD.d.cts} +1 -1
  15. package/dist/{client-BO3kavn0.d.ts → client-BRxKTo-L.d.ts} +1 -1
  16. package/dist/codegen.d.cts +14 -5
  17. package/dist/codegen.d.ts +14 -5
  18. package/dist/{constants-Bh759FUI.d.cts → constants-CvHbO3ia.d.cts} +14 -5
  19. package/dist/{constants-Bh759FUI.d.ts → constants-CvHbO3ia.d.ts} +14 -5
  20. package/dist/{context-mr8R5CNt.d.ts → context-BjhW0QWy.d.ts} +1 -1
  21. package/dist/{context-DI0EJCRD.d.cts → context-CsviWecX.d.cts} +1 -1
  22. package/dist/host.d.cts +4 -4
  23. package/dist/host.d.ts +4 -4
  24. package/dist/index.d.cts +4 -4
  25. package/dist/index.d.ts +4 -4
  26. package/dist/manifest.cjs +16 -16
  27. package/dist/manifest.d.cts +10 -4
  28. package/dist/manifest.d.ts +10 -4
  29. package/dist/manifest.mjs +1 -1
  30. package/dist/server.cjs +8 -8
  31. package/dist/server.d.cts +5 -5
  32. package/dist/server.d.ts +5 -5
  33. package/dist/server.mjs +3 -3
  34. package/dist/testing/index.cjs +8 -8
  35. package/dist/testing/index.d.cts +3 -3
  36. package/dist/testing/index.d.ts +3 -3
  37. package/dist/testing/index.mjs +4 -4
  38. package/dist/{types-BdDaLnqs.d.cts → types-C5k8VwaA.d.cts} +1 -1
  39. package/dist/{types-uGHrRaOj.d.ts → types-DBpDxGlT.d.ts} +1 -1
  40. package/dist/ui.d.cts +1 -1
  41. package/dist/ui.d.ts +1 -1
  42. package/dist/vite-preview-bootstrap.d.cts +2 -2
  43. package/dist/vite-preview-bootstrap.d.ts +2 -2
  44. package/dist/vite-preview.cjs +7 -7
  45. package/dist/vite-preview.cjs.map +1 -1
  46. package/dist/vite-preview.d.cts +3 -3
  47. package/dist/vite-preview.d.ts +3 -3
  48. package/dist/vite-preview.mjs +4 -4
  49. package/dist/vite-preview.mjs.map +1 -1
  50. package/dist/vite.cjs +16 -5
  51. package/dist/vite.cjs.map +1 -1
  52. package/dist/vite.d.cts +14 -5
  53. package/dist/vite.d.ts +14 -5
  54. package/dist/vite.mjs +16 -5
  55. package/dist/vite.mjs.map +1 -1
  56. package/dist/{work-events-C5n497rx.d.ts → work-events-BYU25wmX.d.ts} +2 -2
  57. package/dist/{work-events-DSklu4t-.d.cts → work-events-CxFu-YZE.d.cts} +2 -2
  58. package/package.json +1 -1
  59. package/schema/extension-v2.json +75 -330
  60. package/dist/chunk-7YKH4LZN.cjs.map +0 -1
  61. package/dist/chunk-SGCYEEXD.mjs.map +0 -1
  62. /package/dist/{chunk-QQSCA6CC.mjs.map → chunk-6FASZFC4.mjs.map} +0 -0
  63. /package/dist/{chunk-KZ5NGFUP.mjs.map → chunk-CEFLOQD4.mjs.map} +0 -0
  64. /package/dist/{chunk-SWG7CNTZ.mjs.map → chunk-WW2D3N2T.mjs.map} +0 -0
@@ -49,6 +49,13 @@ var SCOPES = [
49
49
  requiresSecurityReview: false,
50
50
  requiresJustification: false
51
51
  },
52
+ {
53
+ key: "builds:read",
54
+ label: "Read builds",
55
+ description: "Build results: branch, commit, version, build number, duration and failure reason",
56
+ requiresSecurityReview: false,
57
+ requiresJustification: false
58
+ },
52
59
  {
53
60
  key: "revenue:read",
54
61
  label: "Read revenue",
@@ -160,7 +167,7 @@ var PAGES = [
160
167
  label: "Home",
161
168
  route: "/projects/:id/overview",
162
169
  slots: ["kpi-row", "insights", "sidebar"],
163
- charts: ["installs-activity"],
170
+ charts: ["installs-activity", "release-cadence"],
164
171
  tabs: true,
165
172
  banners: true
166
173
  },
@@ -175,10 +182,10 @@ var PAGES = [
175
182
  },
176
183
  {
177
184
  key: "deployments",
178
- label: "Deployments",
179
- route: "/projects/:id/deployments",
185
+ label: "Builds",
186
+ route: "/projects/:id/builds",
180
187
  slots: ["sidebar", "below-list"],
181
- charts: ["release-cadence"],
188
+ charts: [],
182
189
  tabs: true,
183
190
  banners: false
184
191
  },
@@ -197,7 +204,8 @@ var TABLES = [
197
204
  { key: "analytics.keywords", label: "Keywords" },
198
205
  { key: "analytics.reviews", label: "Reviews" },
199
206
  { key: "deployments.releases", label: "Releases" },
200
- { key: "deployments.builds", label: "Builds" }
207
+ { key: "deployments.builds", label: "TestFlight builds" },
208
+ { key: "deployments.runs", label: "Builds" }
201
209
  ];
202
210
  var TABLE_KEYS = TABLES.map((table) => table.key);
203
211
  var KINDS = [
@@ -247,6 +255,9 @@ var EVENTS = [
247
255
  "keyword.set_changed",
248
256
  "screenshots.updated",
249
257
  "price.changed",
258
+ "build.succeeded",
259
+ "build.failed",
260
+ "build.uploaded",
250
261
  "featuring.started",
251
262
  "score.changed",
252
263
  "incident.opened",
@@ -306,4 +317,4 @@ var slotsForPage = (page) => _nullishCoalesce(_optionalChain([findPage, 'call',
306
317
 
307
318
 
308
319
  exports.SCOPES = SCOPES; exports.SCOPE_KEYS = SCOPE_KEYS; exports.SLOTS = SLOTS; exports.CHARTS = CHARTS; exports.PAGES = PAGES; exports.PAGE_KEYS = PAGE_KEYS; exports.TABLES = TABLES; exports.TABLE_KEYS = TABLE_KEYS; exports.KINDS = KINDS; exports.CATEGORIES = CATEGORIES; exports.EVENTS = EVENTS; exports.SERVED_SDK_MAJORS = SERVED_SDK_MAJORS; exports.QUERY_SCOPES = QUERY_SCOPES; exports.CARD_KEYS = CARD_KEYS; exports.findScope = findScope; exports.findPage = findPage; exports.findTable = findTable; exports.slotsForPage = slotsForPage;
309
- //# sourceMappingURL=chunk-7YKH4LZN.cjs.map
320
+ //# sourceMappingURL=chunk-EV3KKP62.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-EV3KKP62.cjs","../src/manifest/constants.ts"],"names":[],"mappings":"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","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-EV3KKP62.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: 'builds:read',\n label: 'Read builds',\n description:\n 'Build results: branch, commit, version, build number, duration and failure reason',\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', 'release-cadence'],\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: 'Builds',\n route: '/projects/:id/builds',\n slots: ['sidebar', 'below-list'],\n charts: [],\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: 'TestFlight builds' },\n { key: 'deployments.runs', 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 'build.succeeded',\n 'build.failed',\n 'build.uploaded',\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"]}
@@ -49,6 +49,13 @@ var SCOPES = [
49
49
  requiresSecurityReview: false,
50
50
  requiresJustification: false
51
51
  },
52
+ {
53
+ key: "builds:read",
54
+ label: "Read builds",
55
+ description: "Build results: branch, commit, version, build number, duration and failure reason",
56
+ requiresSecurityReview: false,
57
+ requiresJustification: false
58
+ },
52
59
  {
53
60
  key: "revenue:read",
54
61
  label: "Read revenue",
@@ -160,7 +167,7 @@ var PAGES = [
160
167
  label: "Home",
161
168
  route: "/projects/:id/overview",
162
169
  slots: ["kpi-row", "insights", "sidebar"],
163
- charts: ["installs-activity"],
170
+ charts: ["installs-activity", "release-cadence"],
164
171
  tabs: true,
165
172
  banners: true
166
173
  },
@@ -175,10 +182,10 @@ var PAGES = [
175
182
  },
176
183
  {
177
184
  key: "deployments",
178
- label: "Deployments",
179
- route: "/projects/:id/deployments",
185
+ label: "Builds",
186
+ route: "/projects/:id/builds",
180
187
  slots: ["sidebar", "below-list"],
181
- charts: ["release-cadence"],
188
+ charts: [],
182
189
  tabs: true,
183
190
  banners: false
184
191
  },
@@ -197,7 +204,8 @@ var TABLES = [
197
204
  { key: "analytics.keywords", label: "Keywords" },
198
205
  { key: "analytics.reviews", label: "Reviews" },
199
206
  { key: "deployments.releases", label: "Releases" },
200
- { key: "deployments.builds", label: "Builds" }
207
+ { key: "deployments.builds", label: "TestFlight builds" },
208
+ { key: "deployments.runs", label: "Builds" }
201
209
  ];
202
210
  var TABLE_KEYS = TABLES.map((table) => table.key);
203
211
  var KINDS = [
@@ -247,6 +255,9 @@ var EVENTS = [
247
255
  "keyword.set_changed",
248
256
  "screenshots.updated",
249
257
  "price.changed",
258
+ "build.succeeded",
259
+ "build.failed",
260
+ "build.uploaded",
250
261
  "featuring.started",
251
262
  "score.changed",
252
263
  "incident.opened",
@@ -306,4 +317,4 @@ export {
306
317
  findTable,
307
318
  slotsForPage
308
319
  };
309
- //# sourceMappingURL=chunk-SGCYEEXD.mjs.map
320
+ //# sourceMappingURL=chunk-IHLK4I7J.mjs.map
@@ -0,0 +1 @@
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: 'builds:read',\n label: 'Read builds',\n description:\n 'Build results: branch, commit, version, build number, duration and failure reason',\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', 'release-cadence'],\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: 'Builds',\n route: '/projects/:id/builds',\n slots: ['sidebar', 'below-list'],\n charts: [],\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: 'TestFlight builds' },\n { key: 'deployments.runs', 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 'build.succeeded',\n 'build.failed',\n 'build.uploaded',\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":[]}
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunk7YKH4LZNcjs = require('./chunk-7YKH4LZN.cjs');
3
+ var _chunkEV3KKP62cjs = require('./chunk-EV3KKP62.cjs');
4
4
 
5
5
 
6
6
 
@@ -265,7 +265,7 @@ function resolveRoute(options, method, segments, url, payload) {
265
265
  400
266
266
  );
267
267
  }
268
- const declared = _chunk7YKH4LZNcjs.EVENTS.find((candidate) => candidate === eventName);
268
+ const declared = _chunkEV3KKP62cjs.EVENTS.find((candidate) => candidate === eventName);
269
269
  return route(
270
270
  declared === void 0 ? void 0 : _optionalChain([options, 'access', _6 => _6.events, 'optionalAccess', _7 => _7[declared]]),
271
271
  void 0,
@@ -375,4 +375,4 @@ function createTappifyHandler(options) {
375
375
 
376
376
 
377
377
  exports.SERVER_ERROR_CODES = SERVER_ERROR_CODES; exports.DEFAULT_JWKS_URL = DEFAULT_JWKS_URL; exports.verifyTappifyToken = verifyTappifyToken; exports.INTERNAL_MESSAGE = INTERNAL_MESSAGE; exports.wireError = wireError; exports.readUnknown = readUnknown; exports.readRecord = readRecord; exports.readText = readText; exports.createTappifyHandler = createTappifyHandler;
378
- //# sourceMappingURL=chunk-A74HCO6T.cjs.map
378
+ //# sourceMappingURL=chunk-TEIGGORZ.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-A74HCO6T.cjs","../src/server/codes.ts","../src/server/token.ts","../src/server/wire.ts","../src/server/handler.ts"],"names":[],"mappings":"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","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-A74HCO6T.cjs","sourcesContent":[null,"import type { TapErrorCode } from '../client/errors';\n\n/**\n * The codes `createTappifyHandler` answers with itself, keyed by a short name.\n *\n * @remarks\n * Every one of these comes from the SDK, not from your own handlers: a route or\n * handler that is not there, a token that is missing or does not verify, a missing\n * event id, a body that is not JSON or is over 1 MB, a webhook Tappify rejected,\n * and the catch-all for an error a handler let escape. Throw a `TapServerError`\n * with a code of your own for anything your server decides.\n */\nexport const SERVER_ERROR_CODES = {\n ROUTE_UNKNOWN: 'TAP_ROUTE_UNKNOWN',\n HANDLER_MISSING: 'TAP_HANDLER_MISSING',\n INTERNAL_ERROR: 'TAP_INTERNAL_ERROR',\n TOKEN_MISSING: 'TAP_TOKEN_MISSING',\n TOKEN_INVALID: 'TAP_TOKEN_INVALID',\n TOKEN_AUDIENCE: 'TAP_TOKEN_AUDIENCE',\n EVENT_ID_MISSING: 'TAP_EVENT_ID_MISSING',\n BODY_INVALID: 'TAP_BODY_INVALID',\n BODY_TOO_LARGE: 'TAP_BODY_TOO_LARGE',\n WEBHOOK_REJECTED: 'TAP_WEBHOOK_REJECTED',\n} as const satisfies Record<string, TapErrorCode>;\n\n/** Every code the handler answers with itself, as a union of its own values. */\nexport type TapServerErrorCode =\n (typeof SERVER_ERROR_CODES)[keyof typeof SERVER_ERROR_CODES];\n","import {\n createLocalJWKSet,\n createRemoteJWKSet,\n jwtVerify,\n type JWTPayload,\n type JWTVerifyGetKey,\n} from 'jose';\nimport { TapError } from '../client/errors';\nimport type { TappifyClaims, VerifyTokenOptions } from './types';\n\n/**\n * The key set `verifyTappifyToken` fetches when no `jwksUrl` or `jwks` is given.\n *\n * @remarks\n * This is production. Point `jwksUrl` at the environment that is calling you when\n * you run against another one, and pass `jwks` in tests.\n */\nexport const DEFAULT_JWKS_URL =\n 'https://api.tappify.ai/api/v1/extensions/.well-known/jwks.json';\n\nconst CLOCK_TOLERANCE_SECONDS = 60;\n\nconst remoteSets = new Map<string, JWTVerifyGetKey>();\n\nfunction keySet(options: VerifyTokenOptions): JWTVerifyGetKey {\n if (options.jwks) return createLocalJWKSet(options.jwks);\n\n const url = options.jwksUrl ?? DEFAULT_JWKS_URL;\n const cached = remoteSets.get(url);\n if (cached) return cached;\n\n const created = createRemoteJWKSet(new URL(url));\n remoteSets.set(url, created);\n return created;\n}\n\nfunction readString(payload: JWTPayload, key: string): string | undefined {\n const value = payload[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction toClaims(payload: JWTPayload, audience: string): TappifyClaims {\n const aud = payload.aud;\n const matches =\n aud === audience || (Array.isArray(aud) && aud.includes(audience));\n\n if (!matches) {\n throw new TapError(\n 'TAP_TOKEN_AUDIENCE',\n `This install token was issued for a different extension. Create the handler with the same extensionId as the \"id\" in tappify.extension.json, so its audience is \"${audience}\".`,\n );\n }\n\n const installId = readString(payload, 'installId');\n const extensionId = readString(payload, 'extensionId');\n const organizationId = readString(payload, 'organizationId');\n\n if (\n installId === undefined ||\n extensionId === undefined ||\n organizationId === undefined\n ) {\n throw new TapError(\n 'TAP_TOKEN_INVALID',\n `The install token is missing the installId, extensionId or organizationId claim. Verify against ${DEFAULT_JWKS_URL} and do not reuse tokens across environments.`,\n );\n }\n\n const scopes = payload.scopes;\n const userId = readString(payload, 'userId');\n\n const claims: TappifyClaims = {\n iss: readString(payload, 'iss') ?? '',\n aud: audience,\n exp: typeof payload.exp === 'number' ? payload.exp : 0,\n iat: typeof payload.iat === 'number' ? payload.iat : 0,\n installId,\n extensionId,\n projectId: readString(payload, 'projectId') ?? null,\n organizationId,\n scopes: Array.isArray(scopes)\n ? scopes.filter((scope): scope is string => typeof scope === 'string')\n : [],\n };\n\n if (userId !== undefined) claims.userId = userId;\n return claims;\n}\n\n/**\n * Verifies an install token against Tappify's signing keys and returns its\n * claims.\n *\n * @remarks\n * Checks the RS256 signature, the expiry with 60 seconds of clock tolerance, and\n * that the audience is `ext:<extensionId>`. Rejects with a `TapError` carrying\n * `TAP_TOKEN_INVALID` when the signature, the expiry or a required claim is wrong,\n * and `TAP_TOKEN_AUDIENCE` when the token was issued for another extension. A\n * remote key set is fetched once per url and cached for the process, so calling\n * this per request costs nothing after the first. `createTappifyHandler` already\n * verifies every route but health, so call this only outside the handler, or\n * where you accept a Tappify token on a route of your own.\n *\n * @example\n * ```ts\n * import { verifyTappifyToken } from '@tappify/extension-sdk/server';\n *\n * async function whoCalled(request: Request): Promise<string> {\n * const token = (request.headers.get('authorization') ?? '').replace('Bearer ', '');\n * const claims = await verifyTappifyToken(token, { extensionId: 'starter' });\n * return claims.installId;\n * }\n * ```\n */\nexport async function verifyTappifyToken(\n token: string,\n options: VerifyTokenOptions,\n): Promise<TappifyClaims> {\n const audience = `ext:${options.extensionId}`;\n\n let payload: JWTPayload;\n try {\n const verified = await jwtVerify(token, keySet(options), {\n algorithms: ['RS256'],\n clockTolerance: CLOCK_TOLERANCE_SECONDS,\n });\n payload = verified.payload;\n } catch {\n throw new TapError(\n 'TAP_TOKEN_INVALID',\n 'The install token did not verify. Check that your server reads the Authorization header unchanged, that its clock is correct, and that jwksUrl points at the Tappify environment that called you.',\n );\n }\n\n return toClaims(payload, audience);\n}\n","import type { TapServerErrorCode } from './codes';\n\nexport const INTERNAL_MESSAGE =\n 'The extension server failed to handle this call. Check your own logs; Tappify records the failure against your extension.';\n\nexport function json(data: unknown, status = 200): Response {\n return new Response(JSON.stringify(data), {\n status,\n headers: { 'content-type': 'application/json' },\n });\n}\n\nexport function wireError(\n code: string,\n message: string,\n status: number,\n): Response {\n return json({ error: { code, message } }, status);\n}\n\nexport function failure(\n code: TapServerErrorCode,\n message: string,\n status: number,\n): Response {\n return wireError(code, message, status);\n}\n\nexport function readUnknown(value: unknown, key: string): unknown {\n if (typeof value !== 'object' || value === null) return undefined;\n return (value as Record<string, unknown>)[key];\n}\n\nexport function readRecord(\n value: unknown,\n key: string,\n): Record<string, unknown> {\n const nested = readUnknown(value, key);\n return typeof nested === 'object' && nested !== null\n ? (nested as Record<string, unknown>)\n : {};\n}\n\nexport function readText(value: unknown, key: string): string | null {\n const nested = readUnknown(value, key);\n return typeof nested === 'string' ? nested : null;\n}\n","import { TapError, TapServerError } from '../client/errors';\nimport type { TapCredentialValues, TapDateRange } from '../client/types';\nimport { EVENTS } from '../manifest/constants';\nimport { SERVER_ERROR_CODES, type TapServerErrorCode } from './codes';\nimport { verifyTappifyToken } from './token';\nimport type {\n ContextBlock,\n LegacyWorkHandlers,\n MentionItems,\n MetricsInput,\n MetricsResponse,\n TappifyCallContext,\n TappifyClaims,\n TappifyDocuments,\n TappifyHandlerOptions,\n TappifyHealth,\n TappifyInstall,\n TappifyRequest,\n WorkOperation,\n} from './types';\nimport {\n INTERNAL_MESSAGE,\n failure,\n json,\n readRecord,\n readText,\n readUnknown,\n wireError,\n} from './wire';\n\n/**\n * What `createTappifyHandler` returns: a `fetch` handler, which is what Cloudflare\n * Workers, Vercel and the two adapters all take.\n */\nexport type TappifyFetchHandler = (request: Request) => Promise<Response>;\n\nconst MAX_BODY_BYTES = 1_048_576;\n\nconst WORK_OPERATIONS: readonly (WorkOperation | keyof LegacyWorkHandlers)[] = [\n 'configure',\n 'list_containers',\n 'describe_container',\n 'create',\n 'attach',\n 'comment',\n 'set_status',\n 'hydrate_event',\n 'disconnect',\n 'status',\n 'resolve',\n];\n\nconst TOKEN_FAILURES: readonly TapServerErrorCode[] = [\n SERVER_ERROR_CODES.TOKEN_INVALID,\n SERVER_ERROR_CODES.TOKEN_AUDIENCE,\n];\n\n/**\n * The token is signed by Tappify and the body is not, so the claims win wherever\n * they carry a value and the body only fills what the token leaves out.\n */\nfunction toInstall(payload: unknown, claims: TappifyClaims): TappifyInstall {\n const raw = readRecord(payload, 'install');\n return {\n id: claims.installId,\n extensionId: claims.extensionId,\n projectId: claims.projectId ?? readText(raw, 'projectId'),\n organizationId: claims.organizationId,\n };\n}\n\nfunction toPlatform(value: string | null): TappifyCallContext['platform'] {\n return value === 'ios' || value === 'android' ? value : 'all';\n}\n\nfunction toPreset(value: string | null): TapDateRange['preset'] {\n return value === '7d' || value === '30d' || value === '90d'\n ? value\n : undefined;\n}\n\nfunction toContext(payload: unknown): TappifyCallContext {\n const raw = readRecord(payload, 'context');\n const filters = readRecord(raw, 'filters');\n const rawRange = readRecord(filters, 'range');\n const from = readText(raw, 'from') ?? readText(rawRange, 'from') ?? '';\n const to = readText(raw, 'to') ?? readText(rawRange, 'to') ?? '';\n\n const range: TapDateRange = {\n from: readText(rawRange, 'from') ?? from,\n to: readText(rawRange, 'to') ?? to,\n };\n\n const preset = toPreset(readText(rawRange, 'preset'));\n if (preset !== undefined) range.preset = preset;\n\n return {\n projectId: readText(raw, 'projectId'),\n platform: toPlatform(readText(raw, 'platform')),\n from,\n to,\n filters: {\n range,\n platform: toPlatform(readText(filters, 'platform')),\n country: readText(filters, 'country') ?? 'all',\n },\n };\n}\n\nfunction toCredentials(payload: unknown): TapCredentialValues {\n const raw = readRecord(payload, 'credentials');\n const credentials: Record<string, string> = {};\n for (const [name, value] of Object.entries(raw)) {\n if (typeof value === 'string') credentials[name] = value;\n }\n return credentials;\n}\n\nfunction tooLarge(): TapServerError {\n return new TapServerError(\n SERVER_ERROR_CODES.BODY_TOO_LARGE,\n 'A Tappify request body is at most 1 MB. Return a cursor or an id the host can follow instead of inlining the payload.',\n 413,\n );\n}\n\nasync function readBody(request: Request): Promise<unknown> {\n if (request.method === 'GET' || request.method === 'HEAD') return {};\n\n const length = request.headers.get('content-length');\n if (length !== null && Number(length) > MAX_BODY_BYTES) throw tooLarge();\n\n const bytes = await request.arrayBuffer();\n if (bytes.byteLength > MAX_BODY_BYTES) throw tooLarge();\n if (bytes.byteLength === 0) return {};\n\n const text = new TextDecoder().decode(bytes);\n try {\n return JSON.parse(text);\n } catch {\n throw new TapServerError(\n SERVER_ERROR_CODES.BODY_INVALID,\n 'The request body was not JSON. Do not parse or re-encode the body before handing the Request to createTappifyHandler().',\n 400,\n );\n }\n}\n\n/**\n * The route table holds handlers whose declared input and event types the\n * manifest augmentations narrow. Method syntax keeps the parameter bivariant,\n * so a narrowed handler still fits a table the wire types as `unknown`.\n */\ntype AnyRouteHandler = {\n route(request: TappifyRequest<unknown, unknown>): unknown;\n}['route'];\n\ninterface Route {\n handler: AnyRouteHandler | undefined;\n input: unknown;\n event: unknown;\n noContent: boolean;\n}\n\nfunction route(\n handler: AnyRouteHandler | undefined,\n input: unknown,\n event?: unknown,\n noContent = false,\n): Route {\n return { handler, input, event, noContent };\n}\n\nfunction handlerFor(\n map: Partial<Record<string, AnyRouteHandler>> | undefined,\n name: string,\n): AnyRouteHandler | undefined {\n return map?.[name];\n}\n\nfunction resolveRoute(\n options: TappifyHandlerOptions,\n method: string,\n segments: string[],\n url: URL,\n payload: unknown,\n): Route | null {\n const [head, name] = segments;\n const bodyInput = readUnknown(payload, 'input') ?? {};\n\n if (head === 'metrics' && method === 'POST') {\n return route(options.metrics, bodyInput);\n }\n if (head === 'tools' && method === 'POST' && name !== undefined) {\n return route(handlerFor(options.tools, name), bodyInput);\n }\n if (head === 'mentions' && method === 'GET' && name !== undefined) {\n return route(handlerFor(options.mentions, name), {\n q: url.searchParams.get('q') ?? '',\n });\n }\n if (head === 'actions' && method === 'POST' && name !== undefined) {\n return route(handlerFor(options.actions, name), bodyInput);\n }\n if (head === 'procedures' && method === 'POST' && name !== undefined) {\n return route(handlerFor(options.procedures, name), bodyInput);\n }\n if (head === 'context' && method === 'GET' && name !== undefined) {\n return route(handlerFor(options.context, name), undefined);\n }\n if (head === 'work' && method === 'POST' && name !== undefined) {\n const operation = WORK_OPERATIONS.find(candidate => candidate === name);\n const handler =\n operation === undefined ? undefined : options.work?.[operation];\n if (operation === 'set_status' && handler === undefined) {\n const input = readRecord(payload, 'input');\n if (readText(input, 'tappifyStatus') === 'resolved') {\n // SDK v2 resolve handlers conventionally read the provider item as id.\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- SDK v2 compatibility adapter.\n return route(options.work?.resolve, {\n ...input,\n id: readUnknown(input, 'externalItemId'),\n });\n }\n }\n return route(handler, bodyInput);\n }\n if (head === 'events' && method === 'POST') {\n const envelope = readRecord(payload, 'event');\n const eventName = readText(envelope, 'name');\n if (eventName === null) {\n throw new TapServerError(\n SERVER_ERROR_CODES.BODY_INVALID,\n 'The events body has no event.name. Post the envelope Tappify sends unchanged, with the event name under \"event\".',\n 400,\n );\n }\n const declared = EVENTS.find(candidate => candidate === eventName);\n return route(\n declared === undefined ? undefined : options.events?.[declared],\n undefined,\n readUnknown(envelope, 'payload') ?? {},\n true,\n );\n }\n\n return null;\n}\n\n/**\n * Builds the one `fetch` handler that answers every route Tappify calls on your\n * server.\n *\n * @remarks\n * It routes the paths under `/tappify`, minus `basePath` when your framework mounts\n * it under a prefix, and hands each matched handler a `TappifyRequest`. Every\n * route but `GET /tappify/health` needs a bearer install token, which it verifies\n * with `verifyTappifyToken`, and an `X-Tappify-Event-Id` header; a missing token is\n * 401 `TAP_TOKEN_MISSING`, a missing id 400 `TAP_EVENT_ID_MISSING`, an unknown path\n * 404 `TAP_ROUTE_UNKNOWN` and a declared name with no handler 404\n * `TAP_HANDLER_MISSING`. A body that is not JSON is 400 `TAP_BODY_INVALID` and one\n * over 1 MB is 413 `TAP_BODY_TOO_LARGE`. A `TapServerError` a handler throws is\n * answered with its own code and status, and a `TapError` other than the two token\n * failures with its own code and 400; anything else becomes 500\n * `TAP_INTERNAL_ERROR` with a fixed message, so an internal failure never reaches\n * the owner. An events route answers 204 with no body, and every other route\n * answers the handler's return value as JSON. Export the options object as well as\n * the handler: `createTestClient` takes the options.\n *\n * @example\n * ```ts\n * import {\n * createTappifyHandler,\n * type TappifyHandlerOptions,\n * } from '@tappify/extension-sdk/server';\n *\n * const handlerOptions: TappifyHandlerOptions = {\n * extensionId: 'starter',\n * health: () => ({ ok: true, version: '0.1.0' }),\n * procedures: {\n * getSummary: () => ({ installs: 1260, delta: 0.087, topKeyword: 'photo editor' }),\n * },\n * };\n *\n * const handler = createTappifyHandler(handlerOptions);\n * ```\n */\nexport function createTappifyHandler(\n options: TappifyHandlerOptions,\n): TappifyFetchHandler {\n const basePath = options.basePath ?? '';\n\n return async function handle(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const path = url.pathname.startsWith(basePath)\n ? url.pathname.slice(basePath.length)\n : url.pathname;\n\n const segments = path.split('/').filter(segment => segment !== '');\n if (segments[0] !== 'tappify') {\n return failure(\n SERVER_ERROR_CODES.ROUTE_UNKNOWN,\n `Nothing is mounted at ${path}. Tappify calls paths under /tappify; set basePath if your framework mounts the handler under a prefix.`,\n 404,\n );\n }\n\n const rest = segments.slice(1);\n\n if (rest[0] === 'health' && request.method === 'GET') {\n const health: TappifyHealth = options.health\n ? await options.health()\n : { ok: true };\n return json(health);\n }\n\n const authorization = request.headers.get('authorization') ?? '';\n const token = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : '';\n\n if (token === '') {\n return failure(\n SERVER_ERROR_CODES.TOKEN_MISSING,\n 'This route needs an install token. Tappify sends it as Authorization: Bearer <token>; forward the header unchanged from your framework.',\n 401,\n );\n }\n\n const eventId = request.headers.get('x-tappify-event-id');\n if (eventId === null || eventId === '') {\n return failure(\n SERVER_ERROR_CODES.EVENT_ID_MISSING,\n 'Every Tappify call carries X-Tappify-Event-Id for idempotency. Forward the header unchanged, and use it as the key when you deduplicate.',\n 400,\n );\n }\n\n try {\n const claims = await verifyTappifyToken(token, {\n extensionId: options.extensionId,\n jwksUrl: options.jwksUrl,\n jwks: options.jwks,\n });\n\n const payload = await readBody(request);\n const matched = resolveRoute(options, request.method, rest, url, payload);\n\n if (matched === null) {\n return failure(\n SERVER_ERROR_CODES.ROUTE_UNKNOWN,\n `Tappify has no ${request.method} ${path} route. The paths it calls are listed under \"Vendor server endpoints\" in the reference; check the method and the spelling.`,\n 404,\n );\n }\n\n if (matched.handler === undefined) {\n return failure(\n SERVER_ERROR_CODES.HANDLER_MISSING,\n `No handler is registered for ${request.method} ${path}. Add it to createTappifyHandler(), or remove the contribution from tappify.extension.json.`,\n 404,\n );\n }\n\n const documents = readRecord(payload, 'documents');\n\n const typed: TappifyRequest<unknown, unknown> = {\n install: toInstall(payload, claims),\n context: toContext(payload),\n input: matched.input,\n credentials: toCredentials(payload),\n documents: documents as TappifyDocuments,\n event: matched.event,\n eventId,\n claims,\n request,\n };\n\n const result = await matched.handler(typed);\n return matched.noContent\n ? new Response(null, { status: 204 })\n : json(result);\n } catch (error) {\n if (TapServerError.is(error)) {\n return wireError(error.code, error.message, error.status ?? 400);\n }\n if (TapError.is(error)) {\n const tokenFailure = TOKEN_FAILURES.find(\n candidate => candidate === error.code,\n );\n if (tokenFailure !== undefined) {\n return failure(tokenFailure, error.message, 401);\n }\n return wireError(error.code, error.message, 400);\n }\n return failure(SERVER_ERROR_CODES.INTERNAL_ERROR, INTERNAL_MESSAGE, 500);\n }\n };\n}\n\nexport type {\n ContextBlock,\n MentionItems,\n MetricsInput,\n MetricsResponse,\n TappifyClaims,\n};\n"]}
1
+ {"version":3,"sources":["/home/runner/work/extension-sdk/extension-sdk/dist/chunk-TEIGGORZ.cjs","../src/server/codes.ts","../src/server/token.ts","../src/server/wire.ts","../src/server/handler.ts"],"names":[],"mappings":"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","file":"/home/runner/work/extension-sdk/extension-sdk/dist/chunk-TEIGGORZ.cjs","sourcesContent":[null,"import type { TapErrorCode } from '../client/errors';\n\n/**\n * The codes `createTappifyHandler` answers with itself, keyed by a short name.\n *\n * @remarks\n * Every one of these comes from the SDK, not from your own handlers: a route or\n * handler that is not there, a token that is missing or does not verify, a missing\n * event id, a body that is not JSON or is over 1 MB, a webhook Tappify rejected,\n * and the catch-all for an error a handler let escape. Throw a `TapServerError`\n * with a code of your own for anything your server decides.\n */\nexport const SERVER_ERROR_CODES = {\n ROUTE_UNKNOWN: 'TAP_ROUTE_UNKNOWN',\n HANDLER_MISSING: 'TAP_HANDLER_MISSING',\n INTERNAL_ERROR: 'TAP_INTERNAL_ERROR',\n TOKEN_MISSING: 'TAP_TOKEN_MISSING',\n TOKEN_INVALID: 'TAP_TOKEN_INVALID',\n TOKEN_AUDIENCE: 'TAP_TOKEN_AUDIENCE',\n EVENT_ID_MISSING: 'TAP_EVENT_ID_MISSING',\n BODY_INVALID: 'TAP_BODY_INVALID',\n BODY_TOO_LARGE: 'TAP_BODY_TOO_LARGE',\n WEBHOOK_REJECTED: 'TAP_WEBHOOK_REJECTED',\n} as const satisfies Record<string, TapErrorCode>;\n\n/** Every code the handler answers with itself, as a union of its own values. */\nexport type TapServerErrorCode =\n (typeof SERVER_ERROR_CODES)[keyof typeof SERVER_ERROR_CODES];\n","import {\n createLocalJWKSet,\n createRemoteJWKSet,\n jwtVerify,\n type JWTPayload,\n type JWTVerifyGetKey,\n} from 'jose';\nimport { TapError } from '../client/errors';\nimport type { TappifyClaims, VerifyTokenOptions } from './types';\n\n/**\n * The key set `verifyTappifyToken` fetches when no `jwksUrl` or `jwks` is given.\n *\n * @remarks\n * This is production. Point `jwksUrl` at the environment that is calling you when\n * you run against another one, and pass `jwks` in tests.\n */\nexport const DEFAULT_JWKS_URL =\n 'https://api.tappify.ai/api/v1/extensions/.well-known/jwks.json';\n\nconst CLOCK_TOLERANCE_SECONDS = 60;\n\nconst remoteSets = new Map<string, JWTVerifyGetKey>();\n\nfunction keySet(options: VerifyTokenOptions): JWTVerifyGetKey {\n if (options.jwks) return createLocalJWKSet(options.jwks);\n\n const url = options.jwksUrl ?? DEFAULT_JWKS_URL;\n const cached = remoteSets.get(url);\n if (cached) return cached;\n\n const created = createRemoteJWKSet(new URL(url));\n remoteSets.set(url, created);\n return created;\n}\n\nfunction readString(payload: JWTPayload, key: string): string | undefined {\n const value = payload[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction toClaims(payload: JWTPayload, audience: string): TappifyClaims {\n const aud = payload.aud;\n const matches =\n aud === audience || (Array.isArray(aud) && aud.includes(audience));\n\n if (!matches) {\n throw new TapError(\n 'TAP_TOKEN_AUDIENCE',\n `This install token was issued for a different extension. Create the handler with the same extensionId as the \"id\" in tappify.extension.json, so its audience is \"${audience}\".`,\n );\n }\n\n const installId = readString(payload, 'installId');\n const extensionId = readString(payload, 'extensionId');\n const organizationId = readString(payload, 'organizationId');\n\n if (\n installId === undefined ||\n extensionId === undefined ||\n organizationId === undefined\n ) {\n throw new TapError(\n 'TAP_TOKEN_INVALID',\n `The install token is missing the installId, extensionId or organizationId claim. Verify against ${DEFAULT_JWKS_URL} and do not reuse tokens across environments.`,\n );\n }\n\n const scopes = payload.scopes;\n const userId = readString(payload, 'userId');\n\n const claims: TappifyClaims = {\n iss: readString(payload, 'iss') ?? '',\n aud: audience,\n exp: typeof payload.exp === 'number' ? payload.exp : 0,\n iat: typeof payload.iat === 'number' ? payload.iat : 0,\n installId,\n extensionId,\n projectId: readString(payload, 'projectId') ?? null,\n organizationId,\n scopes: Array.isArray(scopes)\n ? scopes.filter((scope): scope is string => typeof scope === 'string')\n : [],\n };\n\n if (userId !== undefined) claims.userId = userId;\n return claims;\n}\n\n/**\n * Verifies an install token against Tappify's signing keys and returns its\n * claims.\n *\n * @remarks\n * Checks the RS256 signature, the expiry with 60 seconds of clock tolerance, and\n * that the audience is `ext:<extensionId>`. Rejects with a `TapError` carrying\n * `TAP_TOKEN_INVALID` when the signature, the expiry or a required claim is wrong,\n * and `TAP_TOKEN_AUDIENCE` when the token was issued for another extension. A\n * remote key set is fetched once per url and cached for the process, so calling\n * this per request costs nothing after the first. `createTappifyHandler` already\n * verifies every route but health, so call this only outside the handler, or\n * where you accept a Tappify token on a route of your own.\n *\n * @example\n * ```ts\n * import { verifyTappifyToken } from '@tappify/extension-sdk/server';\n *\n * async function whoCalled(request: Request): Promise<string> {\n * const token = (request.headers.get('authorization') ?? '').replace('Bearer ', '');\n * const claims = await verifyTappifyToken(token, { extensionId: 'starter' });\n * return claims.installId;\n * }\n * ```\n */\nexport async function verifyTappifyToken(\n token: string,\n options: VerifyTokenOptions,\n): Promise<TappifyClaims> {\n const audience = `ext:${options.extensionId}`;\n\n let payload: JWTPayload;\n try {\n const verified = await jwtVerify(token, keySet(options), {\n algorithms: ['RS256'],\n clockTolerance: CLOCK_TOLERANCE_SECONDS,\n });\n payload = verified.payload;\n } catch {\n throw new TapError(\n 'TAP_TOKEN_INVALID',\n 'The install token did not verify. Check that your server reads the Authorization header unchanged, that its clock is correct, and that jwksUrl points at the Tappify environment that called you.',\n );\n }\n\n return toClaims(payload, audience);\n}\n","import type { TapServerErrorCode } from './codes';\n\nexport const INTERNAL_MESSAGE =\n 'The extension server failed to handle this call. Check your own logs; Tappify records the failure against your extension.';\n\nexport function json(data: unknown, status = 200): Response {\n return new Response(JSON.stringify(data), {\n status,\n headers: { 'content-type': 'application/json' },\n });\n}\n\nexport function wireError(\n code: string,\n message: string,\n status: number,\n): Response {\n return json({ error: { code, message } }, status);\n}\n\nexport function failure(\n code: TapServerErrorCode,\n message: string,\n status: number,\n): Response {\n return wireError(code, message, status);\n}\n\nexport function readUnknown(value: unknown, key: string): unknown {\n if (typeof value !== 'object' || value === null) return undefined;\n return (value as Record<string, unknown>)[key];\n}\n\nexport function readRecord(\n value: unknown,\n key: string,\n): Record<string, unknown> {\n const nested = readUnknown(value, key);\n return typeof nested === 'object' && nested !== null\n ? (nested as Record<string, unknown>)\n : {};\n}\n\nexport function readText(value: unknown, key: string): string | null {\n const nested = readUnknown(value, key);\n return typeof nested === 'string' ? nested : null;\n}\n","import { TapError, TapServerError } from '../client/errors';\nimport type { TapCredentialValues, TapDateRange } from '../client/types';\nimport { EVENTS } from '../manifest/constants';\nimport { SERVER_ERROR_CODES, type TapServerErrorCode } from './codes';\nimport { verifyTappifyToken } from './token';\nimport type {\n ContextBlock,\n LegacyWorkHandlers,\n MentionItems,\n MetricsInput,\n MetricsResponse,\n TappifyCallContext,\n TappifyClaims,\n TappifyDocuments,\n TappifyHandlerOptions,\n TappifyHealth,\n TappifyInstall,\n TappifyRequest,\n WorkOperation,\n} from './types';\nimport {\n INTERNAL_MESSAGE,\n failure,\n json,\n readRecord,\n readText,\n readUnknown,\n wireError,\n} from './wire';\n\n/**\n * What `createTappifyHandler` returns: a `fetch` handler, which is what Cloudflare\n * Workers, Vercel and the two adapters all take.\n */\nexport type TappifyFetchHandler = (request: Request) => Promise<Response>;\n\nconst MAX_BODY_BYTES = 1_048_576;\n\nconst WORK_OPERATIONS: readonly (WorkOperation | keyof LegacyWorkHandlers)[] = [\n 'configure',\n 'list_containers',\n 'describe_container',\n 'create',\n 'attach',\n 'comment',\n 'set_status',\n 'hydrate_event',\n 'disconnect',\n 'status',\n 'resolve',\n];\n\nconst TOKEN_FAILURES: readonly TapServerErrorCode[] = [\n SERVER_ERROR_CODES.TOKEN_INVALID,\n SERVER_ERROR_CODES.TOKEN_AUDIENCE,\n];\n\n/**\n * The token is signed by Tappify and the body is not, so the claims win wherever\n * they carry a value and the body only fills what the token leaves out.\n */\nfunction toInstall(payload: unknown, claims: TappifyClaims): TappifyInstall {\n const raw = readRecord(payload, 'install');\n return {\n id: claims.installId,\n extensionId: claims.extensionId,\n projectId: claims.projectId ?? readText(raw, 'projectId'),\n organizationId: claims.organizationId,\n };\n}\n\nfunction toPlatform(value: string | null): TappifyCallContext['platform'] {\n return value === 'ios' || value === 'android' ? value : 'all';\n}\n\nfunction toPreset(value: string | null): TapDateRange['preset'] {\n return value === '7d' || value === '30d' || value === '90d'\n ? value\n : undefined;\n}\n\nfunction toContext(payload: unknown): TappifyCallContext {\n const raw = readRecord(payload, 'context');\n const filters = readRecord(raw, 'filters');\n const rawRange = readRecord(filters, 'range');\n const from = readText(raw, 'from') ?? readText(rawRange, 'from') ?? '';\n const to = readText(raw, 'to') ?? readText(rawRange, 'to') ?? '';\n\n const range: TapDateRange = {\n from: readText(rawRange, 'from') ?? from,\n to: readText(rawRange, 'to') ?? to,\n };\n\n const preset = toPreset(readText(rawRange, 'preset'));\n if (preset !== undefined) range.preset = preset;\n\n return {\n projectId: readText(raw, 'projectId'),\n platform: toPlatform(readText(raw, 'platform')),\n from,\n to,\n filters: {\n range,\n platform: toPlatform(readText(filters, 'platform')),\n country: readText(filters, 'country') ?? 'all',\n },\n };\n}\n\nfunction toCredentials(payload: unknown): TapCredentialValues {\n const raw = readRecord(payload, 'credentials');\n const credentials: Record<string, string> = {};\n for (const [name, value] of Object.entries(raw)) {\n if (typeof value === 'string') credentials[name] = value;\n }\n return credentials;\n}\n\nfunction tooLarge(): TapServerError {\n return new TapServerError(\n SERVER_ERROR_CODES.BODY_TOO_LARGE,\n 'A Tappify request body is at most 1 MB. Return a cursor or an id the host can follow instead of inlining the payload.',\n 413,\n );\n}\n\nasync function readBody(request: Request): Promise<unknown> {\n if (request.method === 'GET' || request.method === 'HEAD') return {};\n\n const length = request.headers.get('content-length');\n if (length !== null && Number(length) > MAX_BODY_BYTES) throw tooLarge();\n\n const bytes = await request.arrayBuffer();\n if (bytes.byteLength > MAX_BODY_BYTES) throw tooLarge();\n if (bytes.byteLength === 0) return {};\n\n const text = new TextDecoder().decode(bytes);\n try {\n return JSON.parse(text);\n } catch {\n throw new TapServerError(\n SERVER_ERROR_CODES.BODY_INVALID,\n 'The request body was not JSON. Do not parse or re-encode the body before handing the Request to createTappifyHandler().',\n 400,\n );\n }\n}\n\n/**\n * The route table holds handlers whose declared input and event types the\n * manifest augmentations narrow. Method syntax keeps the parameter bivariant,\n * so a narrowed handler still fits a table the wire types as `unknown`.\n */\ntype AnyRouteHandler = {\n route(request: TappifyRequest<unknown, unknown>): unknown;\n}['route'];\n\ninterface Route {\n handler: AnyRouteHandler | undefined;\n input: unknown;\n event: unknown;\n noContent: boolean;\n}\n\nfunction route(\n handler: AnyRouteHandler | undefined,\n input: unknown,\n event?: unknown,\n noContent = false,\n): Route {\n return { handler, input, event, noContent };\n}\n\nfunction handlerFor(\n map: Partial<Record<string, AnyRouteHandler>> | undefined,\n name: string,\n): AnyRouteHandler | undefined {\n return map?.[name];\n}\n\nfunction resolveRoute(\n options: TappifyHandlerOptions,\n method: string,\n segments: string[],\n url: URL,\n payload: unknown,\n): Route | null {\n const [head, name] = segments;\n const bodyInput = readUnknown(payload, 'input') ?? {};\n\n if (head === 'metrics' && method === 'POST') {\n return route(options.metrics, bodyInput);\n }\n if (head === 'tools' && method === 'POST' && name !== undefined) {\n return route(handlerFor(options.tools, name), bodyInput);\n }\n if (head === 'mentions' && method === 'GET' && name !== undefined) {\n return route(handlerFor(options.mentions, name), {\n q: url.searchParams.get('q') ?? '',\n });\n }\n if (head === 'actions' && method === 'POST' && name !== undefined) {\n return route(handlerFor(options.actions, name), bodyInput);\n }\n if (head === 'procedures' && method === 'POST' && name !== undefined) {\n return route(handlerFor(options.procedures, name), bodyInput);\n }\n if (head === 'context' && method === 'GET' && name !== undefined) {\n return route(handlerFor(options.context, name), undefined);\n }\n if (head === 'work' && method === 'POST' && name !== undefined) {\n const operation = WORK_OPERATIONS.find(candidate => candidate === name);\n const handler =\n operation === undefined ? undefined : options.work?.[operation];\n if (operation === 'set_status' && handler === undefined) {\n const input = readRecord(payload, 'input');\n if (readText(input, 'tappifyStatus') === 'resolved') {\n // SDK v2 resolve handlers conventionally read the provider item as id.\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- SDK v2 compatibility adapter.\n return route(options.work?.resolve, {\n ...input,\n id: readUnknown(input, 'externalItemId'),\n });\n }\n }\n return route(handler, bodyInput);\n }\n if (head === 'events' && method === 'POST') {\n const envelope = readRecord(payload, 'event');\n const eventName = readText(envelope, 'name');\n if (eventName === null) {\n throw new TapServerError(\n SERVER_ERROR_CODES.BODY_INVALID,\n 'The events body has no event.name. Post the envelope Tappify sends unchanged, with the event name under \"event\".',\n 400,\n );\n }\n const declared = EVENTS.find(candidate => candidate === eventName);\n return route(\n declared === undefined ? undefined : options.events?.[declared],\n undefined,\n readUnknown(envelope, 'payload') ?? {},\n true,\n );\n }\n\n return null;\n}\n\n/**\n * Builds the one `fetch` handler that answers every route Tappify calls on your\n * server.\n *\n * @remarks\n * It routes the paths under `/tappify`, minus `basePath` when your framework mounts\n * it under a prefix, and hands each matched handler a `TappifyRequest`. Every\n * route but `GET /tappify/health` needs a bearer install token, which it verifies\n * with `verifyTappifyToken`, and an `X-Tappify-Event-Id` header; a missing token is\n * 401 `TAP_TOKEN_MISSING`, a missing id 400 `TAP_EVENT_ID_MISSING`, an unknown path\n * 404 `TAP_ROUTE_UNKNOWN` and a declared name with no handler 404\n * `TAP_HANDLER_MISSING`. A body that is not JSON is 400 `TAP_BODY_INVALID` and one\n * over 1 MB is 413 `TAP_BODY_TOO_LARGE`. A `TapServerError` a handler throws is\n * answered with its own code and status, and a `TapError` other than the two token\n * failures with its own code and 400; anything else becomes 500\n * `TAP_INTERNAL_ERROR` with a fixed message, so an internal failure never reaches\n * the owner. An events route answers 204 with no body, and every other route\n * answers the handler's return value as JSON. Export the options object as well as\n * the handler: `createTestClient` takes the options.\n *\n * @example\n * ```ts\n * import {\n * createTappifyHandler,\n * type TappifyHandlerOptions,\n * } from '@tappify/extension-sdk/server';\n *\n * const handlerOptions: TappifyHandlerOptions = {\n * extensionId: 'starter',\n * health: () => ({ ok: true, version: '0.1.0' }),\n * procedures: {\n * getSummary: () => ({ installs: 1260, delta: 0.087, topKeyword: 'photo editor' }),\n * },\n * };\n *\n * const handler = createTappifyHandler(handlerOptions);\n * ```\n */\nexport function createTappifyHandler(\n options: TappifyHandlerOptions,\n): TappifyFetchHandler {\n const basePath = options.basePath ?? '';\n\n return async function handle(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const path = url.pathname.startsWith(basePath)\n ? url.pathname.slice(basePath.length)\n : url.pathname;\n\n const segments = path.split('/').filter(segment => segment !== '');\n if (segments[0] !== 'tappify') {\n return failure(\n SERVER_ERROR_CODES.ROUTE_UNKNOWN,\n `Nothing is mounted at ${path}. Tappify calls paths under /tappify; set basePath if your framework mounts the handler under a prefix.`,\n 404,\n );\n }\n\n const rest = segments.slice(1);\n\n if (rest[0] === 'health' && request.method === 'GET') {\n const health: TappifyHealth = options.health\n ? await options.health()\n : { ok: true };\n return json(health);\n }\n\n const authorization = request.headers.get('authorization') ?? '';\n const token = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : '';\n\n if (token === '') {\n return failure(\n SERVER_ERROR_CODES.TOKEN_MISSING,\n 'This route needs an install token. Tappify sends it as Authorization: Bearer <token>; forward the header unchanged from your framework.',\n 401,\n );\n }\n\n const eventId = request.headers.get('x-tappify-event-id');\n if (eventId === null || eventId === '') {\n return failure(\n SERVER_ERROR_CODES.EVENT_ID_MISSING,\n 'Every Tappify call carries X-Tappify-Event-Id for idempotency. Forward the header unchanged, and use it as the key when you deduplicate.',\n 400,\n );\n }\n\n try {\n const claims = await verifyTappifyToken(token, {\n extensionId: options.extensionId,\n jwksUrl: options.jwksUrl,\n jwks: options.jwks,\n });\n\n const payload = await readBody(request);\n const matched = resolveRoute(options, request.method, rest, url, payload);\n\n if (matched === null) {\n return failure(\n SERVER_ERROR_CODES.ROUTE_UNKNOWN,\n `Tappify has no ${request.method} ${path} route. The paths it calls are listed under \"Vendor server endpoints\" in the reference; check the method and the spelling.`,\n 404,\n );\n }\n\n if (matched.handler === undefined) {\n return failure(\n SERVER_ERROR_CODES.HANDLER_MISSING,\n `No handler is registered for ${request.method} ${path}. Add it to createTappifyHandler(), or remove the contribution from tappify.extension.json.`,\n 404,\n );\n }\n\n const documents = readRecord(payload, 'documents');\n\n const typed: TappifyRequest<unknown, unknown> = {\n install: toInstall(payload, claims),\n context: toContext(payload),\n input: matched.input,\n credentials: toCredentials(payload),\n documents: documents as TappifyDocuments,\n event: matched.event,\n eventId,\n claims,\n request,\n };\n\n const result = await matched.handler(typed);\n return matched.noContent\n ? new Response(null, { status: 204 })\n : json(result);\n } catch (error) {\n if (TapServerError.is(error)) {\n return wireError(error.code, error.message, error.status ?? 400);\n }\n if (TapError.is(error)) {\n const tokenFailure = TOKEN_FAILURES.find(\n candidate => candidate === error.code,\n );\n if (tokenFailure !== undefined) {\n return failure(tokenFailure, error.message, 401);\n }\n return wireError(error.code, error.message, 400);\n }\n return failure(SERVER_ERROR_CODES.INTERNAL_ERROR, INTERNAL_MESSAGE, 500);\n }\n };\n}\n\nexport type {\n ContextBlock,\n MentionItems,\n MetricsInput,\n MetricsResponse,\n TappifyClaims,\n};\n"]}
@@ -3,11 +3,11 @@ import {
3
3
  createTappifyHandler,
4
4
  readRecord,
5
5
  readText
6
- } from "./chunk-KZ5NGFUP.mjs";
6
+ } from "./chunk-CEFLOQD4.mjs";
7
7
  import {
8
8
  QUERY_SCOPES,
9
9
  SCOPE_KEYS
10
- } from "./chunk-SGCYEEXD.mjs";
10
+ } from "./chunk-IHLK4I7J.mjs";
11
11
  import {
12
12
  TapError,
13
13
  TapServerError
@@ -778,4 +778,4 @@ export {
778
778
  createTestClient,
779
779
  createTapMock
780
780
  };
781
- //# sourceMappingURL=chunk-SWG7CNTZ.mjs.map
781
+ //# sourceMappingURL=chunk-WW2D3N2T.mjs.map
@@ -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-Bh759FUI.cjs';
3
+ import { E as ExtensionManifest } from './constants-CvHbO3ia.cjs';
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-Bh759FUI.js';
3
+ import { E as ExtensionManifest } from './constants-CvHbO3ia.js';
4
4
 
5
5
  interface PreviewLoadRequest {
6
6
  extensionId: string;
@@ -40,6 +40,12 @@ declare const SCOPES: readonly [{
40
40
  readonly description: "Crash-free rate and issue counts";
41
41
  readonly requiresSecurityReview: false;
42
42
  readonly requiresJustification: false;
43
+ }, {
44
+ readonly key: "builds:read";
45
+ readonly label: "Read builds";
46
+ readonly description: "Build results: branch, commit, version, build number, duration and failure reason";
47
+ readonly requiresSecurityReview: false;
48
+ readonly requiresJustification: false;
43
49
  }, {
44
50
  readonly key: "revenue:read";
45
51
  readonly label: "Read revenue";
@@ -132,7 +138,7 @@ declare const PAGES: readonly [{
132
138
  readonly label: "Home";
133
139
  readonly route: "/projects/:id/overview";
134
140
  readonly slots: readonly ["kpi-row", "insights", "sidebar"];
135
- readonly charts: readonly ["installs-activity"];
141
+ readonly charts: readonly ["installs-activity", "release-cadence"];
136
142
  readonly tabs: true;
137
143
  readonly banners: true;
138
144
  }, {
@@ -145,10 +151,10 @@ declare const PAGES: readonly [{
145
151
  readonly banners: true;
146
152
  }, {
147
153
  readonly key: "deployments";
148
- readonly label: "Deployments";
149
- readonly route: "/projects/:id/deployments";
154
+ readonly label: "Builds";
155
+ readonly route: "/projects/:id/builds";
150
156
  readonly slots: readonly ["sidebar", "below-list"];
151
- readonly charts: readonly ["release-cadence"];
157
+ readonly charts: readonly [];
152
158
  readonly tabs: true;
153
159
  readonly banners: false;
154
160
  }, {
@@ -174,13 +180,16 @@ declare const TABLES: readonly [{
174
180
  readonly label: "Releases";
175
181
  }, {
176
182
  readonly key: "deployments.builds";
183
+ readonly label: "TestFlight builds";
184
+ }, {
185
+ readonly key: "deployments.runs";
177
186
  readonly label: "Builds";
178
187
  }];
179
188
  type TableDefinition = (typeof TABLES)[number];
180
189
  type HostTable = TableDefinition['key'];
181
190
  declare const CATEGORIES: readonly ["market_data", "subscriptions", "product_analytics", "crashes", "attribution", "experiments", "messaging", "session_replay", "localization", "design", "ci_cd", "trackers", "support", "chat", "ad_monetization", "warehouse", "compliance", "additional_stores"];
182
191
  type ExtensionCategory = (typeof CATEGORIES)[number];
183
- declare const EVENTS: readonly ["release.shipped", "metadata.changed", "keyword.set_changed", "screenshots.updated", "price.changed", "featuring.started", "score.changed", "incident.opened", "incident.resolved", "playbook.step_approved", "review.thread_opened", "review.thread_resolved", "approval.requested", "digest.sent", "install.created", "install.paused", "install.resumed", "install.revoked", "install.token_rotated", "scopes.changed", "settings.changed"];
192
+ declare const EVENTS: readonly ["release.shipped", "metadata.changed", "keyword.set_changed", "screenshots.updated", "price.changed", "build.succeeded", "build.failed", "build.uploaded", "featuring.started", "score.changed", "incident.opened", "incident.resolved", "playbook.step_approved", "review.thread_opened", "review.thread_resolved", "approval.requested", "digest.sent", "install.created", "install.paused", "install.resumed", "install.revoked", "install.token_rotated", "scopes.changed", "settings.changed"];
184
193
  /** Every event Tappify emits, which a mount or a server can subscribe to. */
185
194
  type HostEventName = (typeof EVENTS)[number];
186
195
 
package/dist/codegen.d.ts CHANGED
@@ -40,6 +40,12 @@ declare const SCOPES: readonly [{
40
40
  readonly description: "Crash-free rate and issue counts";
41
41
  readonly requiresSecurityReview: false;
42
42
  readonly requiresJustification: false;
43
+ }, {
44
+ readonly key: "builds:read";
45
+ readonly label: "Read builds";
46
+ readonly description: "Build results: branch, commit, version, build number, duration and failure reason";
47
+ readonly requiresSecurityReview: false;
48
+ readonly requiresJustification: false;
43
49
  }, {
44
50
  readonly key: "revenue:read";
45
51
  readonly label: "Read revenue";
@@ -132,7 +138,7 @@ declare const PAGES: readonly [{
132
138
  readonly label: "Home";
133
139
  readonly route: "/projects/:id/overview";
134
140
  readonly slots: readonly ["kpi-row", "insights", "sidebar"];
135
- readonly charts: readonly ["installs-activity"];
141
+ readonly charts: readonly ["installs-activity", "release-cadence"];
136
142
  readonly tabs: true;
137
143
  readonly banners: true;
138
144
  }, {
@@ -145,10 +151,10 @@ declare const PAGES: readonly [{
145
151
  readonly banners: true;
146
152
  }, {
147
153
  readonly key: "deployments";
148
- readonly label: "Deployments";
149
- readonly route: "/projects/:id/deployments";
154
+ readonly label: "Builds";
155
+ readonly route: "/projects/:id/builds";
150
156
  readonly slots: readonly ["sidebar", "below-list"];
151
- readonly charts: readonly ["release-cadence"];
157
+ readonly charts: readonly [];
152
158
  readonly tabs: true;
153
159
  readonly banners: false;
154
160
  }, {
@@ -174,13 +180,16 @@ declare const TABLES: readonly [{
174
180
  readonly label: "Releases";
175
181
  }, {
176
182
  readonly key: "deployments.builds";
183
+ readonly label: "TestFlight builds";
184
+ }, {
185
+ readonly key: "deployments.runs";
177
186
  readonly label: "Builds";
178
187
  }];
179
188
  type TableDefinition = (typeof TABLES)[number];
180
189
  type HostTable = TableDefinition['key'];
181
190
  declare const CATEGORIES: readonly ["market_data", "subscriptions", "product_analytics", "crashes", "attribution", "experiments", "messaging", "session_replay", "localization", "design", "ci_cd", "trackers", "support", "chat", "ad_monetization", "warehouse", "compliance", "additional_stores"];
182
191
  type ExtensionCategory = (typeof CATEGORIES)[number];
183
- declare const EVENTS: readonly ["release.shipped", "metadata.changed", "keyword.set_changed", "screenshots.updated", "price.changed", "featuring.started", "score.changed", "incident.opened", "incident.resolved", "playbook.step_approved", "review.thread_opened", "review.thread_resolved", "approval.requested", "digest.sent", "install.created", "install.paused", "install.resumed", "install.revoked", "install.token_rotated", "scopes.changed", "settings.changed"];
192
+ declare const EVENTS: readonly ["release.shipped", "metadata.changed", "keyword.set_changed", "screenshots.updated", "price.changed", "build.succeeded", "build.failed", "build.uploaded", "featuring.started", "score.changed", "incident.opened", "incident.resolved", "playbook.step_approved", "review.thread_opened", "review.thread_resolved", "approval.requested", "digest.sent", "install.created", "install.paused", "install.resumed", "install.revoked", "install.token_rotated", "scopes.changed", "settings.changed"];
184
193
  /** Every event Tappify emits, which a mount or a server can subscribe to. */
185
194
  type HostEventName = (typeof EVENTS)[number];
186
195
 
@@ -319,6 +319,12 @@ declare const SCOPES: readonly [{
319
319
  readonly description: "Crash-free rate and issue counts";
320
320
  readonly requiresSecurityReview: false;
321
321
  readonly requiresJustification: false;
322
+ }, {
323
+ readonly key: "builds:read";
324
+ readonly label: "Read builds";
325
+ readonly description: "Build results: branch, commit, version, build number, duration and failure reason";
326
+ readonly requiresSecurityReview: false;
327
+ readonly requiresJustification: false;
322
328
  }, {
323
329
  readonly key: "revenue:read";
324
330
  readonly label: "Read revenue";
@@ -412,7 +418,7 @@ declare const PAGES: readonly [{
412
418
  readonly label: "Home";
413
419
  readonly route: "/projects/:id/overview";
414
420
  readonly slots: readonly ["kpi-row", "insights", "sidebar"];
415
- readonly charts: readonly ["installs-activity"];
421
+ readonly charts: readonly ["installs-activity", "release-cadence"];
416
422
  readonly tabs: true;
417
423
  readonly banners: true;
418
424
  }, {
@@ -425,10 +431,10 @@ declare const PAGES: readonly [{
425
431
  readonly banners: true;
426
432
  }, {
427
433
  readonly key: "deployments";
428
- readonly label: "Deployments";
429
- readonly route: "/projects/:id/deployments";
434
+ readonly label: "Builds";
435
+ readonly route: "/projects/:id/builds";
430
436
  readonly slots: readonly ["sidebar", "below-list"];
431
- readonly charts: readonly ["release-cadence"];
437
+ readonly charts: readonly [];
432
438
  readonly tabs: true;
433
439
  readonly banners: false;
434
440
  }, {
@@ -455,6 +461,9 @@ declare const TABLES: readonly [{
455
461
  readonly label: "Releases";
456
462
  }, {
457
463
  readonly key: "deployments.builds";
464
+ readonly label: "TestFlight builds";
465
+ }, {
466
+ readonly key: "deployments.runs";
458
467
  readonly label: "Builds";
459
468
  }];
460
469
  type TableDefinition = (typeof TABLES)[number];
@@ -464,7 +473,7 @@ declare const KINDS: readonly ["page", "tab", "widget", "series", "banner", "row
464
473
  type ContributionKind = (typeof KINDS)[number];
465
474
  declare const CATEGORIES: readonly ["market_data", "subscriptions", "product_analytics", "crashes", "attribution", "experiments", "messaging", "session_replay", "localization", "design", "ci_cd", "trackers", "support", "chat", "ad_monetization", "warehouse", "compliance", "additional_stores"];
466
475
  type ExtensionCategory = (typeof CATEGORIES)[number];
467
- declare const EVENTS: readonly ["release.shipped", "metadata.changed", "keyword.set_changed", "screenshots.updated", "price.changed", "featuring.started", "score.changed", "incident.opened", "incident.resolved", "playbook.step_approved", "review.thread_opened", "review.thread_resolved", "approval.requested", "digest.sent", "install.created", "install.paused", "install.resumed", "install.revoked", "install.token_rotated", "scopes.changed", "settings.changed"];
476
+ declare const EVENTS: readonly ["release.shipped", "metadata.changed", "keyword.set_changed", "screenshots.updated", "price.changed", "build.succeeded", "build.failed", "build.uploaded", "featuring.started", "score.changed", "incident.opened", "incident.resolved", "playbook.step_approved", "review.thread_opened", "review.thread_resolved", "approval.requested", "digest.sent", "install.created", "install.paused", "install.resumed", "install.revoked", "install.token_rotated", "scopes.changed", "settings.changed"];
468
477
  /** Every event Tappify emits, which a mount or a server can subscribe to. */
469
478
  type HostEventName = (typeof EVENTS)[number];
470
479
  declare const SERVED_SDK_MAJORS: readonly number[];