@tappify/extension-sdk 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-2DBSVKAU.cjs +65 -0
  3. package/dist/chunk-2DBSVKAU.cjs.map +1 -0
  4. package/dist/chunk-3YWVYA42.cjs +142 -0
  5. package/dist/chunk-3YWVYA42.cjs.map +1 -0
  6. package/dist/chunk-4C5Z3CIK.mjs +26 -0
  7. package/dist/chunk-4C5Z3CIK.mjs.map +1 -0
  8. package/dist/chunk-5AAPD5WV.cjs +250 -0
  9. package/dist/chunk-5AAPD5WV.cjs.map +1 -0
  10. package/dist/chunk-7KIKOH5H.cjs +26 -0
  11. package/dist/chunk-7KIKOH5H.cjs.map +1 -0
  12. package/dist/chunk-BDCX6LRQ.mjs +250 -0
  13. package/dist/chunk-BDCX6LRQ.mjs.map +1 -0
  14. package/dist/chunk-CSTYBKZC.mjs +65 -0
  15. package/dist/chunk-CSTYBKZC.mjs.map +1 -0
  16. package/dist/chunk-IGK2AP6J.mjs +142 -0
  17. package/dist/chunk-IGK2AP6J.mjs.map +1 -0
  18. package/dist/chunk-MNDVYPEP.mjs +302 -0
  19. package/dist/chunk-MNDVYPEP.mjs.map +1 -0
  20. package/dist/chunk-OPPYEA7F.cjs +33 -0
  21. package/dist/chunk-OPPYEA7F.cjs.map +1 -0
  22. package/dist/chunk-PYJMJF44.cjs +302 -0
  23. package/dist/chunk-PYJMJF44.cjs.map +1 -0
  24. package/dist/chunk-QHM7XNRK.mjs +33 -0
  25. package/dist/chunk-QHM7XNRK.mjs.map +1 -0
  26. package/dist/chunk-RMUWRESK.cjs +365 -0
  27. package/dist/chunk-RMUWRESK.cjs.map +1 -0
  28. package/dist/chunk-ZT35X7KL.mjs +365 -0
  29. package/dist/chunk-ZT35X7KL.mjs.map +1 -0
  30. package/dist/codegen.cjs +300 -0
  31. package/dist/codegen.cjs.map +1 -0
  32. package/dist/codegen.d.cts +432 -0
  33. package/dist/codegen.d.ts +432 -0
  34. package/dist/codegen.mjs +272 -0
  35. package/dist/codegen.mjs.map +1 -0
  36. package/dist/constants-DJ_KgZpN.d.cts +449 -0
  37. package/dist/constants-DJ_KgZpN.d.ts +449 -0
  38. package/dist/context-Dt6xh_5t.d.cts +30 -0
  39. package/dist/context-Ml7k_V14.d.ts +30 -0
  40. package/dist/errors-COsBh7kd.d.cts +88 -0
  41. package/dist/errors-COsBh7kd.d.ts +88 -0
  42. package/dist/handler-CZIlZ5vu.d.ts +227 -0
  43. package/dist/handler-kU9Jf36K.d.cts +227 -0
  44. package/dist/host.cjs +24 -0
  45. package/dist/host.cjs.map +1 -0
  46. package/dist/host.d.cts +24 -0
  47. package/dist/host.d.ts +24 -0
  48. package/dist/host.mjs +24 -0
  49. package/dist/host.mjs.map +1 -0
  50. package/dist/index.cjs +698 -0
  51. package/dist/index.cjs.map +1 -0
  52. package/dist/index.d.cts +1016 -0
  53. package/dist/index.d.ts +1016 -0
  54. package/dist/index.mjs +698 -0
  55. package/dist/index.mjs.map +1 -0
  56. package/dist/manifest.cjs +872 -0
  57. package/dist/manifest.cjs.map +1 -0
  58. package/dist/manifest.d.cts +432 -0
  59. package/dist/manifest.d.ts +432 -0
  60. package/dist/manifest.mjs +872 -0
  61. package/dist/manifest.mjs.map +1 -0
  62. package/dist/matchers-Cz93AK1n.d.cts +74 -0
  63. package/dist/matchers-Cz93AK1n.d.ts +74 -0
  64. package/dist/server.cjs +210 -0
  65. package/dist/server.cjs.map +1 -0
  66. package/dist/server.d.cts +243 -0
  67. package/dist/server.d.ts +243 -0
  68. package/dist/server.mjs +210 -0
  69. package/dist/server.mjs.map +1 -0
  70. package/dist/styles.css +367 -0
  71. package/dist/testing/index.cjs +887 -0
  72. package/dist/testing/index.cjs.map +1 -0
  73. package/dist/testing/index.d.cts +512 -0
  74. package/dist/testing/index.d.ts +512 -0
  75. package/dist/testing/index.mjs +887 -0
  76. package/dist/testing/index.mjs.map +1 -0
  77. package/dist/testing/jest.cjs +17 -0
  78. package/dist/testing/jest.cjs.map +1 -0
  79. package/dist/testing/jest.d.cts +12 -0
  80. package/dist/testing/jest.d.ts +12 -0
  81. package/dist/testing/jest.mjs +17 -0
  82. package/dist/testing/jest.mjs.map +1 -0
  83. package/dist/testing/vitest.cjs +15 -0
  84. package/dist/testing/vitest.cjs.map +1 -0
  85. package/dist/testing/vitest.d.cts +10 -0
  86. package/dist/testing/vitest.d.ts +10 -0
  87. package/dist/testing/vitest.mjs +15 -0
  88. package/dist/testing/vitest.mjs.map +1 -0
  89. package/dist/types-DDAGLpov.d.ts +715 -0
  90. package/dist/types-DrpQSv_2.d.cts +715 -0
  91. package/dist/vite.cjs +1344 -0
  92. package/dist/vite.cjs.map +1 -0
  93. package/dist/vite.d.cts +434 -0
  94. package/dist/vite.d.ts +434 -0
  95. package/dist/vite.mjs +1314 -0
  96. package/dist/vite.mjs.map +1 -0
  97. package/package.json +268 -0
  98. package/schema/extension-v2.json +1500 -0
@@ -0,0 +1,432 @@
1
+ declare const SCOPES: readonly [{
2
+ readonly key: "ui:render";
3
+ readonly label: "Render UI";
4
+ readonly description: "Render the declared pages, tabs, widgets, row actions and settings panel, and open chat with a visible prompt";
5
+ readonly requiresSecurityReview: false;
6
+ readonly requiresJustification: false;
7
+ }, {
8
+ readonly key: "projects:read";
9
+ readonly label: "Read the project";
10
+ readonly description: "Project name, platforms and store identity";
11
+ readonly requiresSecurityReview: false;
12
+ readonly requiresJustification: false;
13
+ }, {
14
+ readonly key: "analytics:read";
15
+ readonly label: "Read analytics";
16
+ readonly description: "Downloads, impressions, page views and conversion series";
17
+ readonly requiresSecurityReview: false;
18
+ readonly requiresJustification: false;
19
+ }, {
20
+ readonly key: "store.metadata:read";
21
+ readonly label: "Read store metadata";
22
+ readonly description: "Listing metadata, keyword set and keyword positions";
23
+ readonly requiresSecurityReview: false;
24
+ readonly requiresJustification: false;
25
+ }, {
26
+ readonly key: "reviews:read";
27
+ readonly label: "Read store reviews";
28
+ readonly description: "Review text, ratings and replies";
29
+ readonly requiresSecurityReview: false;
30
+ readonly requiresJustification: false;
31
+ }, {
32
+ readonly key: "crashes:read";
33
+ readonly label: "Read crash data";
34
+ readonly description: "Crash-free rate and issue counts";
35
+ readonly requiresSecurityReview: false;
36
+ readonly requiresJustification: false;
37
+ }, {
38
+ readonly key: "revenue:read";
39
+ readonly label: "Read revenue";
40
+ readonly description: "MRR, revenue series and refund counts";
41
+ readonly requiresSecurityReview: false;
42
+ readonly requiresJustification: true;
43
+ }, {
44
+ readonly key: "metrics:write";
45
+ readonly label: "Write connector metrics";
46
+ readonly description: "Write the metrics this extension declares into the metrics store";
47
+ readonly requiresSecurityReview: false;
48
+ readonly requiresJustification: false;
49
+ }, {
50
+ readonly key: "alerts:write";
51
+ readonly label: "Raise alerts and banners";
52
+ readonly description: "Turn declared webhooks into alerts and banners, at most three a day per project";
53
+ readonly requiresSecurityReview: false;
54
+ readonly requiresJustification: true;
55
+ }, {
56
+ readonly key: "insights:write";
57
+ readonly label: "Post insights";
58
+ readonly description: "Post insights to Home and to chat";
59
+ readonly requiresSecurityReview: false;
60
+ readonly requiresJustification: true;
61
+ }, {
62
+ readonly key: "ai:tools";
63
+ readonly label: "Add assistant tools";
64
+ readonly description: "Offer tools and mentions to the assistant";
65
+ readonly requiresSecurityReview: false;
66
+ readonly requiresJustification: false;
67
+ }, {
68
+ readonly key: "ai:actions";
69
+ readonly label: "Run assistant actions";
70
+ readonly description: "Run declared actions, each behind the approval card";
71
+ readonly requiresSecurityReview: true;
72
+ readonly requiresJustification: true;
73
+ }, {
74
+ readonly key: "store.metadata:write";
75
+ readonly label: "Propose store metadata changes";
76
+ readonly description: "Propose listing changes through a Tappify approval";
77
+ readonly requiresSecurityReview: true;
78
+ readonly requiresJustification: true;
79
+ }, {
80
+ readonly key: "autopilot:trigger";
81
+ readonly label: "Trigger automated store actions";
82
+ readonly description: "Start automated store actions on the owner’s behalf";
83
+ readonly requiresSecurityReview: true;
84
+ readonly requiresJustification: true;
85
+ }, {
86
+ readonly key: "work:create";
87
+ readonly label: "Create work items";
88
+ readonly description: "Create issues, pages or messages in the vendor’s system";
89
+ readonly requiresSecurityReview: false;
90
+ readonly requiresJustification: true;
91
+ }, {
92
+ readonly key: "work:sync";
93
+ readonly label: "Sync work items";
94
+ readonly description: "Two-way comments and status on created work items";
95
+ readonly requiresSecurityReview: false;
96
+ readonly requiresJustification: true;
97
+ }, {
98
+ readonly key: "storage:write";
99
+ readonly label: "Use hosted storage";
100
+ readonly description: "Read and write this extension’s own hosted storage collections";
101
+ readonly requiresSecurityReview: false;
102
+ readonly requiresJustification: false;
103
+ }, {
104
+ readonly key: "messaging:send";
105
+ readonly label: "Send messages to end users";
106
+ readonly description: "Send messages or push notifications to the owner’s end users through owner-supplied credentials";
107
+ readonly requiresSecurityReview: true;
108
+ readonly requiresJustification: true;
109
+ }, {
110
+ readonly key: "ai:skills";
111
+ readonly label: "Shape the assistant";
112
+ readonly description: "Add skills, prompt templates and context providers that shape the assistant’s behaviour";
113
+ readonly requiresSecurityReview: false;
114
+ readonly requiresJustification: true;
115
+ }];
116
+ type ScopeDefinition = (typeof SCOPES)[number];
117
+ /** Every scope an extension can ask for under `scopes` in its manifest. */
118
+ type ScopeKey = ScopeDefinition['key'];
119
+ declare const SLOTS: readonly ["kpi-row", "insights", "sidebar", "below-chart", "below-list"];
120
+ /** The anchors on a host page a widget can be declared at. */
121
+ type SlotId = (typeof SLOTS)[number];
122
+ declare const CHARTS: readonly ["installs-activity", "conversion", "release-cadence"];
123
+ type HostChart = (typeof CHARTS)[number];
124
+ declare const PAGES: readonly [{
125
+ readonly key: "overview";
126
+ readonly label: "Home";
127
+ readonly route: "/projects/:id/overview";
128
+ readonly slots: readonly ["kpi-row", "insights", "sidebar"];
129
+ readonly charts: readonly ["installs-activity"];
130
+ readonly tabs: true;
131
+ readonly banners: true;
132
+ }, {
133
+ readonly key: "analytics";
134
+ readonly label: "Analytics";
135
+ readonly route: "/projects/:id/analytics";
136
+ readonly slots: readonly ["kpi-row", "below-chart", "sidebar"];
137
+ readonly charts: readonly ["installs-activity", "conversion"];
138
+ readonly tabs: true;
139
+ readonly banners: true;
140
+ }, {
141
+ readonly key: "deployments";
142
+ readonly label: "Deployments";
143
+ readonly route: "/projects/:id/deployments";
144
+ readonly slots: readonly ["sidebar", "below-list"];
145
+ readonly charts: readonly ["release-cadence"];
146
+ readonly tabs: true;
147
+ readonly banners: false;
148
+ }, {
149
+ readonly key: "ai_chat";
150
+ readonly label: "Assistant";
151
+ readonly route: "chat";
152
+ readonly slots: readonly [];
153
+ readonly charts: readonly [];
154
+ readonly tabs: false;
155
+ readonly banners: false;
156
+ }];
157
+ type PageDefinition = (typeof PAGES)[number];
158
+ /** The host pages a contribution can attach a tab, widget or banner to. */
159
+ type HostPage = PageDefinition['key'];
160
+ declare const TABLES: readonly [{
161
+ readonly key: "analytics.keywords";
162
+ readonly label: "Keywords";
163
+ }, {
164
+ readonly key: "analytics.reviews";
165
+ readonly label: "Reviews";
166
+ }, {
167
+ readonly key: "deployments.releases";
168
+ readonly label: "Releases";
169
+ }, {
170
+ readonly key: "deployments.builds";
171
+ readonly label: "Builds";
172
+ }];
173
+ type TableDefinition = (typeof TABLES)[number];
174
+ type HostTable = TableDefinition['key'];
175
+ 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"];
176
+ type ExtensionCategory = (typeof CATEGORIES)[number];
177
+ 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"];
178
+ /** Every event Tappify emits, which a mount or a server can subscribe to. */
179
+ type HostEventName = (typeof EVENTS)[number];
180
+
181
+ type JsonSchema = Record<string, unknown>;
182
+ type ExtensionVisibility = 'public' | 'unlisted' | 'private';
183
+ type ExtensionInstallScope = 'project' | 'organization';
184
+ interface ScopeEntry {
185
+ key: ScopeKey;
186
+ justification?: string;
187
+ }
188
+ interface ProcedureDeclaration {
189
+ input: JsonSchema;
190
+ output: JsonSchema;
191
+ cache?: '1m' | '5m' | '1h';
192
+ kind?: 'read' | 'write';
193
+ }
194
+ interface StorageCollection {
195
+ scope: 'user' | 'install' | 'organization';
196
+ singleton?: boolean;
197
+ schema: JsonSchema;
198
+ }
199
+ interface PageContribution {
200
+ id: string;
201
+ title: string;
202
+ entry: string;
203
+ nav?: boolean;
204
+ mobile?: boolean;
205
+ }
206
+ interface TabContribution {
207
+ id: string;
208
+ title: string;
209
+ entry: string;
210
+ page: HostPage;
211
+ mobile?: boolean;
212
+ }
213
+ interface WidgetContribution {
214
+ id: string;
215
+ title: string;
216
+ entry: string;
217
+ page: HostPage;
218
+ slot: SlotId;
219
+ size: '1x1' | '2x1' | '2x2';
220
+ expandable?: boolean;
221
+ }
222
+ interface SeriesContribution {
223
+ id: string;
224
+ label: string;
225
+ chart: HostChart;
226
+ metric: string;
227
+ }
228
+ interface BannerContribution {
229
+ id: string;
230
+ page: HostPage;
231
+ event: string;
232
+ }
233
+ interface RowActionContribution {
234
+ id: string;
235
+ title: string;
236
+ table: HostTable;
237
+ entry: string;
238
+ }
239
+ interface MarkerContribution {
240
+ id: string;
241
+ label: string;
242
+ chart: HostChart | '*';
243
+ event: string;
244
+ glyph: string;
245
+ }
246
+ interface SettingsContribution {
247
+ entry: string;
248
+ schema: JsonSchema;
249
+ }
250
+ interface CredentialField {
251
+ name: string;
252
+ label: string;
253
+ type: 'text' | 'password' | 'textarea' | 'file' | 'select';
254
+ required: boolean;
255
+ options?: string[];
256
+ help?: string;
257
+ }
258
+ interface ConnectorAuth {
259
+ method: 'none' | 'api_key' | 'oauth';
260
+ fields?: CredentialField[];
261
+ oauth?: {
262
+ authorizationUrl: string;
263
+ tokenUrl: string;
264
+ scopes: string[];
265
+ };
266
+ }
267
+ interface DimensionDeclaration {
268
+ key: string;
269
+ label: string;
270
+ }
271
+ interface MetricDeclaration {
272
+ key: string;
273
+ label: string;
274
+ unit: 'count' | 'ratio' | 'currency' | 'seconds' | 'bytes';
275
+ kind: 'gauge' | 'counter';
276
+ dimensions?: DimensionDeclaration[];
277
+ backfillDays?: number;
278
+ }
279
+ interface ConnectorContribution {
280
+ auth?: ConnectorAuth;
281
+ sync?: '5m' | '15m' | '1h' | '6h' | '24h';
282
+ metrics?: MetricDeclaration[];
283
+ }
284
+ interface WebhookContribution {
285
+ event: string;
286
+ as: 'alert' | 'banner' | 'event';
287
+ payload: JsonSchema;
288
+ }
289
+ interface ToolDeclaration {
290
+ id: string;
291
+ description: string;
292
+ input: JsonSchema;
293
+ returns: 'comparison' | 'table' | 'series' | 'list' | 'value';
294
+ cost: 'low' | 'medium' | 'high';
295
+ cache?: '1m' | '5m' | '1h';
296
+ }
297
+ interface MentionDeclaration {
298
+ id: string;
299
+ label: string;
300
+ list: string;
301
+ }
302
+ interface ActionDeclaration {
303
+ id: string;
304
+ description: string;
305
+ input: JsonSchema;
306
+ approval: true;
307
+ reversible: boolean;
308
+ scope: ScopeKey;
309
+ estimatesCost?: boolean;
310
+ }
311
+ interface KnowledgeDeclaration {
312
+ id: string;
313
+ category: 'metric_definitions' | 'gotchas' | 'setup';
314
+ file: string;
315
+ }
316
+ interface SkillDeclaration {
317
+ id: string;
318
+ name: string;
319
+ description: string;
320
+ file: string;
321
+ tools?: string[];
322
+ }
323
+ interface PromptDeclaration {
324
+ id: string;
325
+ title: string;
326
+ template: string;
327
+ surfaces: ('chat_suggestion' | 'widget' | 'page' | 'result_card')[];
328
+ after?: string[];
329
+ input?: JsonSchema;
330
+ }
331
+ interface ContextDeclaration {
332
+ id: string;
333
+ description: string;
334
+ when: ('turn_start' | 'mention')[];
335
+ cache?: '1m' | '5m' | '1h';
336
+ }
337
+ interface AiContribution {
338
+ tools?: ToolDeclaration[];
339
+ mentions?: MentionDeclaration[];
340
+ actions?: ActionDeclaration[];
341
+ knowledge?: KnowledgeDeclaration[];
342
+ skills?: SkillDeclaration[];
343
+ prompts?: PromptDeclaration[];
344
+ context?: ContextDeclaration[];
345
+ }
346
+ interface WorkContribution {
347
+ kind: 'tracker' | 'docs' | 'chat';
348
+ container: {
349
+ label: string;
350
+ list: string;
351
+ };
352
+ creates: ('issue' | 'page' | 'message')[];
353
+ fields: {
354
+ priority?: string[];
355
+ labels?: boolean;
356
+ assignee?: boolean;
357
+ required: string[];
358
+ };
359
+ attachments: ('image' | 'link')[];
360
+ comments: 'two-way' | 'none';
361
+ status?: {
362
+ webhook: string;
363
+ map: Record<'open' | 'in_progress' | 'done', string[]>;
364
+ };
365
+ identity: 'user' | 'install';
366
+ }
367
+ interface ExtensionListing {
368
+ longDescription?: string;
369
+ screenshots?: string[];
370
+ website?: string;
371
+ supportUrl?: string;
372
+ privacyUrl?: string;
373
+ }
374
+ interface ExtensionManifest {
375
+ $schema?: string;
376
+ id: string;
377
+ name: string;
378
+ description: string;
379
+ icon: string;
380
+ category: ExtensionCategory;
381
+ sdk: string;
382
+ visibility: ExtensionVisibility;
383
+ installScope: ExtensionInstallScope;
384
+ scopes: ScopeEntry[];
385
+ contributes: {
386
+ pages?: PageContribution[];
387
+ tabs?: TabContribution[];
388
+ widgets?: WidgetContribution[];
389
+ series?: SeriesContribution[];
390
+ banners?: BannerContribution[];
391
+ rowActions?: RowActionContribution[];
392
+ markers?: MarkerContribution[];
393
+ settings?: SettingsContribution;
394
+ storage?: Record<string, StorageCollection>;
395
+ connector?: ConnectorContribution;
396
+ webhooks?: WebhookContribution[];
397
+ ai?: AiContribution;
398
+ work?: WorkContribution;
399
+ };
400
+ server?: {
401
+ baseUrl: string;
402
+ sandboxBaseUrl?: string;
403
+ procedures?: Record<string, ProcedureDeclaration>;
404
+ events?: HostEventName[];
405
+ };
406
+ telemetry?: string[];
407
+ listing?: ExtensionListing;
408
+ pricing?: never;
409
+ score?: never;
410
+ }
411
+
412
+ declare const GENERATED_HEADER = "/* eslint-disable */\n/**\n * Generated by `tappify extension types`. Do not edit by hand.\n * Re-run the command after changing tappify.extension.json or any schema it points at.\n */";
413
+ interface RegistrySnapshot {
414
+ events: {
415
+ name: string;
416
+ payload?: JsonSchema;
417
+ }[];
418
+ }
419
+ interface GenerateTypesOptions {
420
+ manifest: ExtensionManifest;
421
+ registrySnapshot?: RegistrySnapshot;
422
+ readSchemaFile?(path: string): JsonSchema;
423
+ /**
424
+ * The extension root. A `$ref` inside a schema file resolves against that
425
+ * file's own directory under it, the way the host and the Tap Store read
426
+ * it; without a root the process directory stands in.
427
+ */
428
+ cwd?: string;
429
+ }
430
+ declare function generateTypes(options: GenerateTypesOptions): Promise<string>;
431
+
432
+ export { GENERATED_HEADER, type GenerateTypesOptions, type RegistrySnapshot, generateTypes };
@@ -0,0 +1,272 @@
1
+ // src/codegen/generate.ts
2
+ import { compile } from "json-schema-to-typescript";
3
+ import { dirname, join } from "path";
4
+
5
+ // src/client/errors.ts
6
+ var TAP_ERROR_CODES = [
7
+ "TAP_OUTSIDE_HOST",
8
+ "TAP_SCOPE_MISSING",
9
+ "TAP_UNKNOWN_COLLECTION",
10
+ "TAP_UNKNOWN_PROCEDURE",
11
+ "TAP_NO_PORTAL",
12
+ "TAP_NO_QUERY_CLIENT",
13
+ "TAP_MANIFEST_INVALID",
14
+ "TAP_ENTRY_MISSING",
15
+ "TAP_STYLES_UNRESOLVED",
16
+ "TAP_SCHEMA_UNRESOLVED",
17
+ "TAP_TOKEN_MISSING",
18
+ "TAP_TOKEN_INVALID",
19
+ "TAP_TOKEN_AUDIENCE",
20
+ "TAP_EVENT_ID_MISSING",
21
+ "TAP_BODY_INVALID",
22
+ "TAP_BODY_TOO_LARGE",
23
+ "TAP_ROUTE_UNKNOWN",
24
+ "TAP_HANDLER_MISSING",
25
+ "TAP_INTERNAL_ERROR",
26
+ "TAP_WEBHOOK_REJECTED",
27
+ "TAP_TEST_TARGET_INVALID"
28
+ ];
29
+ var CODE_SET = new Set(TAP_ERROR_CODES);
30
+ var TapError = class extends Error {
31
+ constructor(code, message) {
32
+ super(message);
33
+ this.name = "TapError";
34
+ this.code = code;
35
+ }
36
+ /**
37
+ * Narrows an unknown value to a `TapError`, by name and by a code it
38
+ * recognises, so it holds across module instances.
39
+ */
40
+ static is(value) {
41
+ return value instanceof Error && value.name === "TapError" && "code" in value && typeof value.code === "string" && CODE_SET.has(value.code);
42
+ }
43
+ };
44
+
45
+ // src/codegen/generate.ts
46
+ var GENERATED_HEADER = `/* eslint-disable */
47
+ /**
48
+ * Generated by \`tappify extension types\`. Do not edit by hand.
49
+ * Re-run the command after changing tappify.extension.json or any schema it points at.
50
+ */`;
51
+ var STYLE = {
52
+ bracketSpacing: true,
53
+ printWidth: 80,
54
+ semi: true,
55
+ singleQuote: true,
56
+ tabWidth: 2,
57
+ trailingComma: "all",
58
+ useTabs: false
59
+ };
60
+ function pascal(value) {
61
+ return value.split(/[^A-Za-z0-9]+/).filter((part) => part !== "").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
62
+ }
63
+ function createEmitter(resolveSchema) {
64
+ const used = /* @__PURE__ */ new Set();
65
+ const blocks = [];
66
+ return {
67
+ async declare(preferredName, schema) {
68
+ let name = pascal(preferredName);
69
+ let suffix = 2;
70
+ while (used.has(name)) {
71
+ name = `${pascal(preferredName)}${String(suffix)}`;
72
+ suffix += 1;
73
+ }
74
+ used.add(name);
75
+ const resolved = resolveSchema(schema);
76
+ const input = {
77
+ ...resolved.schema,
78
+ title: name
79
+ };
80
+ const text = await compile(input, name, {
81
+ bannerComment: "",
82
+ additionalProperties: false,
83
+ declareExternallyReferenced: true,
84
+ enableConstEnums: false,
85
+ format: true,
86
+ style: STYLE,
87
+ unknownAny: true,
88
+ ...resolved.cwd === void 0 ? {} : { cwd: resolved.cwd }
89
+ });
90
+ blocks.push(text.trim());
91
+ return name;
92
+ },
93
+ declarations() {
94
+ return blocks;
95
+ }
96
+ };
97
+ }
98
+ function credentialSchema(fields) {
99
+ const properties = {};
100
+ const required = [];
101
+ for (const field of fields) {
102
+ const property = field.type === "select" && field.options ? { type: "string", enum: field.options } : { type: "string" };
103
+ if (field.help !== void 0) property.description = field.help;
104
+ properties[field.name] = property;
105
+ if (field.required) required.push(field.name);
106
+ }
107
+ return { type: "object", properties, required, additionalProperties: false };
108
+ }
109
+ async function generateTypes(options) {
110
+ const { manifest, registrySnapshot } = options;
111
+ const contributes = manifest.contributes;
112
+ const resolveSchema = (schema) => {
113
+ const ref = schema.$ref;
114
+ if (typeof ref !== "string" || ref.startsWith("#")) {
115
+ return { schema, cwd: options.cwd };
116
+ }
117
+ if (options.readSchemaFile === void 0) {
118
+ throw new TapError(
119
+ "TAP_SCHEMA_UNRESOLVED",
120
+ `The manifest points at the schema file "${ref}", but this call passed no readSchemaFile. Run \`tappify extension types\`, which reads schema files from the extension directory, or supply readSchemaFile.`
121
+ );
122
+ }
123
+ return {
124
+ schema: options.readSchemaFile(ref),
125
+ cwd: options.cwd === void 0 ? void 0 : dirname(join(options.cwd, ref))
126
+ };
127
+ };
128
+ const emitter = createEmitter(resolveSchema);
129
+ const augmentations = [];
130
+ const storageEntries = Object.entries(contributes.storage ?? {});
131
+ if (storageEntries.length > 0) {
132
+ const lines = [];
133
+ for (const [name, collection] of storageEntries) {
134
+ const typeName = await emitter.declare(name, collection.schema);
135
+ const kind = collection.singleton === true ? "singleton" : "collection";
136
+ lines.push(
137
+ ` '${name}': { kind: '${kind}'; scope: '${collection.scope}'; document: ${typeName} };`
138
+ );
139
+ }
140
+ augmentations.push(` interface TapStorageMap {
141
+ ${lines.join("\n")}
142
+ }`);
143
+ }
144
+ const procedureEntries = Object.entries(manifest.server?.procedures ?? {});
145
+ if (procedureEntries.length > 0) {
146
+ const lines = [];
147
+ for (const [name, declaration] of procedureEntries) {
148
+ const inputName = await emitter.declare(
149
+ `${name}Input`,
150
+ declaration.input
151
+ );
152
+ const outputName = await emitter.declare(
153
+ `${name}Output`,
154
+ declaration.output
155
+ );
156
+ lines.push(
157
+ ` '${name}': { input: ${inputName}; output: ${outputName} };`
158
+ );
159
+ }
160
+ augmentations.push(
161
+ ` interface TapProcedureMap {
162
+ ${lines.join("\n")}
163
+ }`
164
+ );
165
+ }
166
+ const actions = contributes.ai?.actions ?? [];
167
+ if (actions.length > 0) {
168
+ const lines = [];
169
+ for (const action of actions) {
170
+ const name = await emitter.declare(`${action.id}Input`, action.input);
171
+ lines.push(` '${action.id}': { input: ${name} };`);
172
+ }
173
+ augmentations.push(` interface TapActionMap {
174
+ ${lines.join("\n")}
175
+ }`);
176
+ }
177
+ const tools = contributes.ai?.tools ?? [];
178
+ if (tools.length > 0) {
179
+ const lines = [];
180
+ for (const tool of tools) {
181
+ const name = await emitter.declare(`${tool.id}Input`, tool.input);
182
+ lines.push(` '${tool.id}': { input: ${name} };`);
183
+ }
184
+ augmentations.push(` interface TapToolMap {
185
+ ${lines.join("\n")}
186
+ }`);
187
+ }
188
+ const prompts = (contributes.ai?.prompts ?? []).filter(
189
+ (prompt) => prompt.input !== void 0
190
+ );
191
+ if (prompts.length > 0) {
192
+ const lines = [];
193
+ for (const prompt of prompts) {
194
+ const name = await emitter.declare(
195
+ `${prompt.id}PromptInput`,
196
+ prompt.input ?? { type: "object" }
197
+ );
198
+ lines.push(` '${prompt.id}': { input: ${name} };`);
199
+ }
200
+ augmentations.push(` interface TapPromptMap {
201
+ ${lines.join("\n")}
202
+ }`);
203
+ }
204
+ const webhooks = contributes.webhooks ?? [];
205
+ if (webhooks.length > 0) {
206
+ const lines = [];
207
+ for (const webhook of webhooks) {
208
+ const name = await emitter.declare(
209
+ `${webhook.event}Payload`,
210
+ webhook.payload
211
+ );
212
+ lines.push(` '${webhook.event}': ${name};`);
213
+ }
214
+ augmentations.push(` interface TapWebhookMap {
215
+ ${lines.join("\n")}
216
+ }`);
217
+ }
218
+ if (registrySnapshot !== void 0 && registrySnapshot.events.length > 0) {
219
+ const lines = [];
220
+ for (const event of registrySnapshot.events) {
221
+ const name = await emitter.declare(
222
+ `${event.name}Event`,
223
+ event.payload ?? { type: "object" }
224
+ );
225
+ lines.push(` '${event.name}': ${name};`);
226
+ }
227
+ augmentations.push(
228
+ ` interface TapHostEventMap {
229
+ ${lines.join("\n")}
230
+ }`
231
+ );
232
+ }
233
+ const telemetry = manifest.telemetry ?? [];
234
+ if (telemetry.length > 0) {
235
+ const lines = telemetry.map((name) => ` '${name}': true;`);
236
+ augmentations.push(
237
+ ` interface TapTelemetryEvents {
238
+ ${lines.join("\n")}
239
+ }`
240
+ );
241
+ }
242
+ if (contributes.settings) {
243
+ const name = await emitter.declare("Settings", contributes.settings.schema);
244
+ augmentations.push(` interface TapSettings extends ${name} {}`);
245
+ }
246
+ const credentialFields = contributes.connector?.auth?.fields ?? [];
247
+ if (credentialFields.length > 0) {
248
+ const name = await emitter.declare(
249
+ "Credentials",
250
+ credentialSchema(credentialFields)
251
+ );
252
+ augmentations.push(` interface TapCredentials extends ${name} {}`);
253
+ }
254
+ const declarations = emitter.declarations();
255
+ const module = augmentations.length === 0 ? "declare module '@tappify/extension-sdk' {}" : `declare module '@tappify/extension-sdk' {
256
+ ${augmentations.join("\n\n")}
257
+ }`;
258
+ return [
259
+ GENERATED_HEADER,
260
+ "",
261
+ ...declarations.length > 0 ? [declarations.join("\n\n"), ""] : [],
262
+ module,
263
+ "",
264
+ "export {};",
265
+ ""
266
+ ].join("\n");
267
+ }
268
+ export {
269
+ GENERATED_HEADER,
270
+ generateTypes
271
+ };
272
+ //# sourceMappingURL=codegen.mjs.map