@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.
- package/LICENSE +21 -0
- package/dist/chunk-2DBSVKAU.cjs +65 -0
- package/dist/chunk-2DBSVKAU.cjs.map +1 -0
- package/dist/chunk-3YWVYA42.cjs +142 -0
- package/dist/chunk-3YWVYA42.cjs.map +1 -0
- package/dist/chunk-4C5Z3CIK.mjs +26 -0
- package/dist/chunk-4C5Z3CIK.mjs.map +1 -0
- package/dist/chunk-5AAPD5WV.cjs +250 -0
- package/dist/chunk-5AAPD5WV.cjs.map +1 -0
- package/dist/chunk-7KIKOH5H.cjs +26 -0
- package/dist/chunk-7KIKOH5H.cjs.map +1 -0
- package/dist/chunk-BDCX6LRQ.mjs +250 -0
- package/dist/chunk-BDCX6LRQ.mjs.map +1 -0
- package/dist/chunk-CSTYBKZC.mjs +65 -0
- package/dist/chunk-CSTYBKZC.mjs.map +1 -0
- package/dist/chunk-IGK2AP6J.mjs +142 -0
- package/dist/chunk-IGK2AP6J.mjs.map +1 -0
- package/dist/chunk-MNDVYPEP.mjs +302 -0
- package/dist/chunk-MNDVYPEP.mjs.map +1 -0
- package/dist/chunk-OPPYEA7F.cjs +33 -0
- package/dist/chunk-OPPYEA7F.cjs.map +1 -0
- package/dist/chunk-PYJMJF44.cjs +302 -0
- package/dist/chunk-PYJMJF44.cjs.map +1 -0
- package/dist/chunk-QHM7XNRK.mjs +33 -0
- package/dist/chunk-QHM7XNRK.mjs.map +1 -0
- package/dist/chunk-RMUWRESK.cjs +365 -0
- package/dist/chunk-RMUWRESK.cjs.map +1 -0
- package/dist/chunk-ZT35X7KL.mjs +365 -0
- package/dist/chunk-ZT35X7KL.mjs.map +1 -0
- package/dist/codegen.cjs +300 -0
- package/dist/codegen.cjs.map +1 -0
- package/dist/codegen.d.cts +432 -0
- package/dist/codegen.d.ts +432 -0
- package/dist/codegen.mjs +272 -0
- package/dist/codegen.mjs.map +1 -0
- package/dist/constants-DJ_KgZpN.d.cts +449 -0
- package/dist/constants-DJ_KgZpN.d.ts +449 -0
- package/dist/context-Dt6xh_5t.d.cts +30 -0
- package/dist/context-Ml7k_V14.d.ts +30 -0
- package/dist/errors-COsBh7kd.d.cts +88 -0
- package/dist/errors-COsBh7kd.d.ts +88 -0
- package/dist/handler-CZIlZ5vu.d.ts +227 -0
- package/dist/handler-kU9Jf36K.d.cts +227 -0
- package/dist/host.cjs +24 -0
- package/dist/host.cjs.map +1 -0
- package/dist/host.d.cts +24 -0
- package/dist/host.d.ts +24 -0
- package/dist/host.mjs +24 -0
- package/dist/host.mjs.map +1 -0
- package/dist/index.cjs +698 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1016 -0
- package/dist/index.d.ts +1016 -0
- package/dist/index.mjs +698 -0
- package/dist/index.mjs.map +1 -0
- package/dist/manifest.cjs +872 -0
- package/dist/manifest.cjs.map +1 -0
- package/dist/manifest.d.cts +432 -0
- package/dist/manifest.d.ts +432 -0
- package/dist/manifest.mjs +872 -0
- package/dist/manifest.mjs.map +1 -0
- package/dist/matchers-Cz93AK1n.d.cts +74 -0
- package/dist/matchers-Cz93AK1n.d.ts +74 -0
- package/dist/server.cjs +210 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +243 -0
- package/dist/server.d.ts +243 -0
- package/dist/server.mjs +210 -0
- package/dist/server.mjs.map +1 -0
- package/dist/styles.css +367 -0
- package/dist/testing/index.cjs +887 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +512 -0
- package/dist/testing/index.d.ts +512 -0
- package/dist/testing/index.mjs +887 -0
- package/dist/testing/index.mjs.map +1 -0
- package/dist/testing/jest.cjs +17 -0
- package/dist/testing/jest.cjs.map +1 -0
- package/dist/testing/jest.d.cts +12 -0
- package/dist/testing/jest.d.ts +12 -0
- package/dist/testing/jest.mjs +17 -0
- package/dist/testing/jest.mjs.map +1 -0
- package/dist/testing/vitest.cjs +15 -0
- package/dist/testing/vitest.cjs.map +1 -0
- package/dist/testing/vitest.d.cts +10 -0
- package/dist/testing/vitest.d.ts +10 -0
- package/dist/testing/vitest.mjs +15 -0
- package/dist/testing/vitest.mjs.map +1 -0
- package/dist/types-DDAGLpov.d.ts +715 -0
- package/dist/types-DrpQSv_2.d.cts +715 -0
- package/dist/vite.cjs +1344 -0
- package/dist/vite.cjs.map +1 -0
- package/dist/vite.d.cts +434 -0
- package/dist/vite.d.ts +434 -0
- package/dist/vite.mjs +1314 -0
- package/dist/vite.mjs.map +1 -0
- package/package.json +268 -0
- package/schema/extension-v2.json +1500 -0
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
import { S as ScopeKey, H as HostEventName } from './constants-DJ_KgZpN.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The storage collections the manifest declares, keyed by collection name, which
|
|
5
|
+
* `tappify extension types` writes into `src/tappify.d.ts`.
|
|
6
|
+
*/
|
|
7
|
+
interface TapStorageMap {
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The procedures the manifest declares, each with its `input` and `output` type,
|
|
11
|
+
* which `tappify extension types` writes into `src/tappify.d.ts`.
|
|
12
|
+
*/
|
|
13
|
+
interface TapProcedureMap {
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The actions the manifest declares, each with its `input` type, which
|
|
17
|
+
* `tappify extension types` writes into `src/tappify.d.ts`.
|
|
18
|
+
*/
|
|
19
|
+
interface TapActionMap {
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The tools the manifest declares, each with its `input` type, which
|
|
23
|
+
* `tappify extension types` writes into `src/tappify.d.ts`.
|
|
24
|
+
*/
|
|
25
|
+
interface TapToolMap {
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The prompts the manifest declares, each with its `input` type, which
|
|
29
|
+
* `tappify extension types` writes into `src/tappify.d.ts`.
|
|
30
|
+
*/
|
|
31
|
+
interface TapPromptMap {
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The webhook events the manifest declares, keyed by event name and typed by
|
|
35
|
+
* payload, which `tappify extension types` writes into `src/tappify.d.ts`.
|
|
36
|
+
*/
|
|
37
|
+
interface TapWebhookMap {
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The narrowed payload types for the Tappify events the manifest subscribes to,
|
|
41
|
+
* which `tappify extension types` writes into `src/tappify.d.ts`.
|
|
42
|
+
*/
|
|
43
|
+
interface TapHostEventMap {
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The telemetry event names the manifest declares, which
|
|
47
|
+
* `tappify extension types` writes into `src/tappify.d.ts`.
|
|
48
|
+
*/
|
|
49
|
+
interface TapTelemetryEvents {
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The settings document the settings contribution's schema describes, which
|
|
53
|
+
* `tappify extension types` writes into `src/tappify.d.ts`.
|
|
54
|
+
*/
|
|
55
|
+
interface TapSettings {
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The credential names the manifest declares, which `tappify extension types`
|
|
59
|
+
* writes into `src/tappify.d.ts`.
|
|
60
|
+
*/
|
|
61
|
+
interface TapCredentials {
|
|
62
|
+
}
|
|
63
|
+
/** One of the two stores an owner's app ships to. */
|
|
64
|
+
type TapPlatform = 'ios' | 'android';
|
|
65
|
+
/** The platform the owner's filter bar is set to, or `all` for both. */
|
|
66
|
+
type TapPlatformFilter = TapPlatform | 'all';
|
|
67
|
+
/** The dates a read covers, as the host's filter bar holds them. */
|
|
68
|
+
interface TapDateRange {
|
|
69
|
+
/** Inclusive start, as `YYYY-MM-DD`. */
|
|
70
|
+
from: string;
|
|
71
|
+
/** Inclusive end, as `YYYY-MM-DD`. */
|
|
72
|
+
to: string;
|
|
73
|
+
/** Set when the owner picked one of the preset ranges rather than dates. */
|
|
74
|
+
preset?: '7d' | '30d' | '90d';
|
|
75
|
+
}
|
|
76
|
+
/** The filter bar above the surface a mount renders in. */
|
|
77
|
+
interface TapFilters {
|
|
78
|
+
range: TapDateRange;
|
|
79
|
+
platform: TapPlatformFilter;
|
|
80
|
+
/** An ISO country code, or `all` when the owner has not narrowed to one. */
|
|
81
|
+
country: string;
|
|
82
|
+
}
|
|
83
|
+
/** One of the owner's apps, as one store knows it. */
|
|
84
|
+
interface TapApp {
|
|
85
|
+
id: string;
|
|
86
|
+
name: string;
|
|
87
|
+
platform: TapPlatform;
|
|
88
|
+
/** The numeric App Store id on iOS, the package name on Android. */
|
|
89
|
+
storeId: string;
|
|
90
|
+
bundleId: string | null;
|
|
91
|
+
}
|
|
92
|
+
/** One version of an owner's app, as the store reports it. */
|
|
93
|
+
interface TapRelease {
|
|
94
|
+
id: string;
|
|
95
|
+
version: string;
|
|
96
|
+
build: string | null;
|
|
97
|
+
platform: TapPlatform;
|
|
98
|
+
/** The store's own state string, such as `ready_for_sale` or `published`. */
|
|
99
|
+
state: string;
|
|
100
|
+
/**
|
|
101
|
+
* When the store created the version. The type allows `null`, but the host
|
|
102
|
+
* always sends a timestamp today.
|
|
103
|
+
*/
|
|
104
|
+
shippedAt: string | null;
|
|
105
|
+
}
|
|
106
|
+
/** One term in the owner's tracked keyword set, on one platform and country. */
|
|
107
|
+
interface TapKeyword {
|
|
108
|
+
id: string;
|
|
109
|
+
term: string;
|
|
110
|
+
platform: TapPlatform;
|
|
111
|
+
country: string;
|
|
112
|
+
/** The rank the app holds for the term, or `null` when it does not rank. */
|
|
113
|
+
position: number | null;
|
|
114
|
+
/**
|
|
115
|
+
* Tappify's own traffic score for the term, on a 1 to 10 scale, or `null` when
|
|
116
|
+
* the term has not been scored. It is not a figure a store publishes: the host
|
|
117
|
+
* hands over the raw score, while Tappify's own surfaces rescale it to 0 to 100
|
|
118
|
+
* before drawing it.
|
|
119
|
+
*/
|
|
120
|
+
popularity: number | null;
|
|
121
|
+
}
|
|
122
|
+
/** The store metadata for one app, in one country and locale. */
|
|
123
|
+
interface TapListing {
|
|
124
|
+
platform: TapPlatform;
|
|
125
|
+
country: string;
|
|
126
|
+
locale: string;
|
|
127
|
+
title: string;
|
|
128
|
+
subtitle: string | null;
|
|
129
|
+
description: string;
|
|
130
|
+
/** The keyword field as the store holds it, split into terms. */
|
|
131
|
+
keywords: string[];
|
|
132
|
+
updatedAt: string;
|
|
133
|
+
}
|
|
134
|
+
/** One store review of the owner's app. */
|
|
135
|
+
interface TapReview {
|
|
136
|
+
id: string;
|
|
137
|
+
platform: TapPlatform;
|
|
138
|
+
country: string;
|
|
139
|
+
/** One to five stars. */
|
|
140
|
+
rating: number;
|
|
141
|
+
title: string | null;
|
|
142
|
+
body: string;
|
|
143
|
+
author: string | null;
|
|
144
|
+
submittedAt: string;
|
|
145
|
+
/** Whether the owner has answered the review. */
|
|
146
|
+
replied: boolean;
|
|
147
|
+
}
|
|
148
|
+
/** One crash group, with how often it has been seen. */
|
|
149
|
+
interface TapCrashIssue {
|
|
150
|
+
id: string;
|
|
151
|
+
title: string;
|
|
152
|
+
count: number;
|
|
153
|
+
build: string | null;
|
|
154
|
+
firstSeenAt: string;
|
|
155
|
+
lastSeenAt: string;
|
|
156
|
+
}
|
|
157
|
+
/** One day of a series. */
|
|
158
|
+
interface TapSeriesPoint {
|
|
159
|
+
/** The day, as `YYYY-MM-DD`. */
|
|
160
|
+
at: string;
|
|
161
|
+
value: number;
|
|
162
|
+
}
|
|
163
|
+
/** The metrics a `series` query can ask for. */
|
|
164
|
+
type TapSeriesMetric = 'downloads' | 'impressions' | 'page_views' | 'conversion_rate';
|
|
165
|
+
/**
|
|
166
|
+
* A read `tap.data.query` and `useTapQuery` accept, one member per kind of
|
|
167
|
+
* Tappify data.
|
|
168
|
+
*/
|
|
169
|
+
type TapQuery = {
|
|
170
|
+
kind: 'project';
|
|
171
|
+
} | {
|
|
172
|
+
kind: 'series';
|
|
173
|
+
metric: TapSeriesMetric;
|
|
174
|
+
range: TapDateRange;
|
|
175
|
+
platform?: TapPlatform;
|
|
176
|
+
} | {
|
|
177
|
+
kind: 'keywords';
|
|
178
|
+
} | {
|
|
179
|
+
kind: 'listing';
|
|
180
|
+
} | {
|
|
181
|
+
kind: 'reviews';
|
|
182
|
+
range: TapDateRange;
|
|
183
|
+
} | {
|
|
184
|
+
kind: 'crashes';
|
|
185
|
+
range: TapDateRange;
|
|
186
|
+
} | {
|
|
187
|
+
kind: 'revenue';
|
|
188
|
+
range: TapDateRange;
|
|
189
|
+
};
|
|
190
|
+
/** What a `project` query answers with. */
|
|
191
|
+
interface TapProjectResult {
|
|
192
|
+
project: {
|
|
193
|
+
id: string;
|
|
194
|
+
name: string;
|
|
195
|
+
platforms: TapPlatform[];
|
|
196
|
+
};
|
|
197
|
+
apps: TapApp[];
|
|
198
|
+
releases: TapRelease[];
|
|
199
|
+
}
|
|
200
|
+
/** What a `series` query answers with. */
|
|
201
|
+
interface TapSeriesResult {
|
|
202
|
+
metric: TapSeriesMetric;
|
|
203
|
+
/** `ratio` for `conversion_rate`, `count` for the other three metrics. */
|
|
204
|
+
unit: 'count' | 'ratio';
|
|
205
|
+
points: TapSeriesPoint[];
|
|
206
|
+
}
|
|
207
|
+
/** What a `keywords` query answers with. */
|
|
208
|
+
interface TapKeywordsResult {
|
|
209
|
+
keywords: TapKeyword[];
|
|
210
|
+
}
|
|
211
|
+
/** What a `listing` query answers with. */
|
|
212
|
+
interface TapListingResult {
|
|
213
|
+
listings: TapListing[];
|
|
214
|
+
}
|
|
215
|
+
/** What a `reviews` query answers with. */
|
|
216
|
+
interface TapReviewsResult {
|
|
217
|
+
/** The newest first, at most 200 of them. */
|
|
218
|
+
reviews: TapReview[];
|
|
219
|
+
/** The mean rating of the reviews the answer carries, or 0 when it carries none. */
|
|
220
|
+
averageRating: number;
|
|
221
|
+
/**
|
|
222
|
+
* How many reviews the answer carries, which is `reviews.length` today: the
|
|
223
|
+
* host reads at most 200 rows and counts what it returned, so this is not the
|
|
224
|
+
* number of reviews in the range.
|
|
225
|
+
*/
|
|
226
|
+
total: number;
|
|
227
|
+
}
|
|
228
|
+
/** What a `crashes` query answers with. */
|
|
229
|
+
interface TapCrashesResult {
|
|
230
|
+
/**
|
|
231
|
+
* The percentage of users who did not hit a crash, between 0 and 100, taken
|
|
232
|
+
* from the most recently measured crash group. `100` when nothing has been
|
|
233
|
+
* measured yet.
|
|
234
|
+
*/
|
|
235
|
+
crashFreeRate: number;
|
|
236
|
+
/** The project's crash groups, the most affected first, at most 100 of them. */
|
|
237
|
+
issues: TapCrashIssue[];
|
|
238
|
+
}
|
|
239
|
+
/** What a `revenue` query answers with. */
|
|
240
|
+
interface TapRevenueResult {
|
|
241
|
+
currency: string;
|
|
242
|
+
/**
|
|
243
|
+
* Monthly recurring revenue in the major unit of `currency`, so `41200` is
|
|
244
|
+
* 41,200 dollars and not 412 dollars. Summed across the project's apps from
|
|
245
|
+
* each one's latest subscription metric, which is not narrowed by the range.
|
|
246
|
+
*/
|
|
247
|
+
mrr: number;
|
|
248
|
+
/** How many refunded units fell in the range, across the project's apps. */
|
|
249
|
+
refunds: number;
|
|
250
|
+
points: TapSeriesPoint[];
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* The result type a query of kind `Q` answers with, which is what
|
|
254
|
+
* `tap.data.query` and `useTapQuery` return for it.
|
|
255
|
+
*/
|
|
256
|
+
type TapResult<Q extends TapQuery> = Q extends {
|
|
257
|
+
kind: 'project';
|
|
258
|
+
} ? TapProjectResult : Q extends {
|
|
259
|
+
kind: 'series';
|
|
260
|
+
} ? TapSeriesResult : Q extends {
|
|
261
|
+
kind: 'keywords';
|
|
262
|
+
} ? TapKeywordsResult : Q extends {
|
|
263
|
+
kind: 'listing';
|
|
264
|
+
} ? TapListingResult : Q extends {
|
|
265
|
+
kind: 'reviews';
|
|
266
|
+
} ? TapReviewsResult : Q extends {
|
|
267
|
+
kind: 'crashes';
|
|
268
|
+
} ? TapCrashesResult : Q extends {
|
|
269
|
+
kind: 'revenue';
|
|
270
|
+
} ? TapRevenueResult : never;
|
|
271
|
+
/**
|
|
272
|
+
* The handle `tap.storage.<name>` exposes for a singleton collection, which holds
|
|
273
|
+
* one document per scope key.
|
|
274
|
+
*
|
|
275
|
+
* @remarks
|
|
276
|
+
* A collection is a singleton when the manifest declares it with `singleton` set
|
|
277
|
+
* to `true`. Every call needs the `storage:write` scope, `get` included.
|
|
278
|
+
*/
|
|
279
|
+
interface TapSingleton<T> {
|
|
280
|
+
/** Resolves to `null` until the document has been written once. */
|
|
281
|
+
get(): Promise<T | null>;
|
|
282
|
+
/** Replaces the whole document. */
|
|
283
|
+
set(document: T): Promise<void>;
|
|
284
|
+
/** Merges the fields into the document and resolves to the merged document. */
|
|
285
|
+
patch(partial: Partial<T>): Promise<T>;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* The handle `tap.storage.<name>` exposes for an id-keyed collection, which holds
|
|
289
|
+
* many documents under ids you choose.
|
|
290
|
+
*
|
|
291
|
+
* @remarks
|
|
292
|
+
* A collection is id-keyed when the manifest leaves `singleton` off. Every call
|
|
293
|
+
* needs the `storage:write` scope, `list` and `get` included.
|
|
294
|
+
*/
|
|
295
|
+
interface TapCollection<T> {
|
|
296
|
+
/** Pass the `cursor` a previous page answered with to read the next one. */
|
|
297
|
+
list(options?: {
|
|
298
|
+
limit?: number;
|
|
299
|
+
cursor?: string;
|
|
300
|
+
}): Promise<{
|
|
301
|
+
items: (T & {
|
|
302
|
+
id: string;
|
|
303
|
+
})[];
|
|
304
|
+
cursor?: string;
|
|
305
|
+
}>;
|
|
306
|
+
/** Resolves to `null` when the collection holds no document under that id. */
|
|
307
|
+
get(id: string): Promise<T | null>;
|
|
308
|
+
/** Writes the document under that id, replacing any document already there. */
|
|
309
|
+
put(id: string, document: T): Promise<void>;
|
|
310
|
+
/** Resolves whether or not a document was there to remove. */
|
|
311
|
+
delete(id: string): Promise<void>;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* The `tap.storage` object, with one handle per collection the manifest
|
|
315
|
+
* declares, read from the `TapStorageMap` augmentation.
|
|
316
|
+
*/
|
|
317
|
+
type TapStorage = keyof TapStorageMap extends never ? Record<string, TapSingleton<unknown> | TapCollection<unknown>> : {
|
|
318
|
+
[K in keyof TapStorageMap]: TapStorageMap[K] extends {
|
|
319
|
+
kind: 'singleton';
|
|
320
|
+
document: infer D;
|
|
321
|
+
} ? TapSingleton<D> : TapStorageMap[K] extends {
|
|
322
|
+
kind: 'collection';
|
|
323
|
+
document: infer D;
|
|
324
|
+
} ? TapCollection<D> : never;
|
|
325
|
+
};
|
|
326
|
+
/**
|
|
327
|
+
* The names of the singleton collections in the `TapStorageMap` augmentation,
|
|
328
|
+
* which is what `useTapStorage` accepts.
|
|
329
|
+
*/
|
|
330
|
+
type TapSingletonName = keyof TapStorageMap extends never ? string : Extract<{
|
|
331
|
+
[K in keyof TapStorageMap]: TapStorageMap[K] extends {
|
|
332
|
+
kind: 'singleton';
|
|
333
|
+
} ? K : never;
|
|
334
|
+
}[keyof TapStorageMap], string>;
|
|
335
|
+
/**
|
|
336
|
+
* The document type collection `C` holds, read from the `TapStorageMap`
|
|
337
|
+
* augmentation.
|
|
338
|
+
*/
|
|
339
|
+
type TapSingletonDocument<C extends TapSingletonName> = C extends keyof TapStorageMap ? TapStorageMap[C] extends {
|
|
340
|
+
document: infer D;
|
|
341
|
+
} ? D : unknown : unknown;
|
|
342
|
+
type TapProcedureEntries = keyof TapProcedureMap extends never ? Record<string, {
|
|
343
|
+
input: unknown;
|
|
344
|
+
output: unknown;
|
|
345
|
+
}> : TapProcedureMap;
|
|
346
|
+
/**
|
|
347
|
+
* The procedure names in the `TapProcedureMap` augmentation, which is what
|
|
348
|
+
* `useTapServer` and `tap.invalidate` accept.
|
|
349
|
+
*/
|
|
350
|
+
type TapProcedureName = Extract<keyof TapProcedureEntries, string>;
|
|
351
|
+
/**
|
|
352
|
+
* The input type procedure `N` takes, read from the `TapProcedureMap`
|
|
353
|
+
* augmentation.
|
|
354
|
+
*/
|
|
355
|
+
type TapProcedureInput<N extends TapProcedureName> = (TapProcedureEntries[N] & {
|
|
356
|
+
input: unknown;
|
|
357
|
+
})['input'];
|
|
358
|
+
/**
|
|
359
|
+
* The output type procedure `N` resolves to, read from the `TapProcedureMap`
|
|
360
|
+
* augmentation.
|
|
361
|
+
*/
|
|
362
|
+
type TapProcedureOutput<N extends TapProcedureName> = (TapProcedureEntries[N] & {
|
|
363
|
+
output: unknown;
|
|
364
|
+
})['output'];
|
|
365
|
+
/**
|
|
366
|
+
* The `tap.server` object, with one call per procedure in the
|
|
367
|
+
* `TapProcedureMap` augmentation.
|
|
368
|
+
*/
|
|
369
|
+
type TapProcedures = {
|
|
370
|
+
[N in TapProcedureName]: (input: TapProcedureInput<N>) => Promise<TapProcedureOutput<N>>;
|
|
371
|
+
};
|
|
372
|
+
/**
|
|
373
|
+
* The action names in the `TapActionMap` augmentation, which is what
|
|
374
|
+
* `tap.actions.run` and the handler's `actions` table accept.
|
|
375
|
+
*/
|
|
376
|
+
type ActionId = keyof TapActionMap extends never ? string : Extract<keyof TapActionMap, string>;
|
|
377
|
+
/**
|
|
378
|
+
* The input type action `A` takes, read from the `TapActionMap` augmentation.
|
|
379
|
+
*/
|
|
380
|
+
type ActionInput<A extends ActionId> = A extends keyof TapActionMap ? TapActionMap[A] extends {
|
|
381
|
+
input: infer I;
|
|
382
|
+
} ? I : unknown : unknown;
|
|
383
|
+
/**
|
|
384
|
+
* The tool names in the `TapToolMap` augmentation, which is what the handler's
|
|
385
|
+
* `tools` table accepts.
|
|
386
|
+
*/
|
|
387
|
+
type ToolId = keyof TapToolMap extends never ? string : Extract<keyof TapToolMap, string>;
|
|
388
|
+
/** The input type tool `T` takes, read from the `TapToolMap` augmentation. */
|
|
389
|
+
type ToolInput<T extends ToolId> = T extends keyof TapToolMap ? TapToolMap[T] extends {
|
|
390
|
+
input: infer I;
|
|
391
|
+
} ? I : unknown : unknown;
|
|
392
|
+
/** The prompt names in the `TapPromptMap` augmentation. */
|
|
393
|
+
type PromptId = keyof TapPromptMap extends never ? string : Extract<keyof TapPromptMap, string>;
|
|
394
|
+
/**
|
|
395
|
+
* The input type prompt `P` takes, read from the `TapPromptMap` augmentation.
|
|
396
|
+
*/
|
|
397
|
+
type PromptInput<P extends PromptId> = P extends keyof TapPromptMap ? TapPromptMap[P] extends {
|
|
398
|
+
input: infer I;
|
|
399
|
+
} ? I : Record<string, never> : Record<string, unknown>;
|
|
400
|
+
/**
|
|
401
|
+
* The webhook event names in the `TapWebhookMap` augmentation, which is what
|
|
402
|
+
* `sendEvent` accepts.
|
|
403
|
+
*/
|
|
404
|
+
type WebhookName = keyof TapWebhookMap extends never ? string : Extract<keyof TapWebhookMap, string>;
|
|
405
|
+
/**
|
|
406
|
+
* The payload type webhook event `E` carries, read from the `TapWebhookMap`
|
|
407
|
+
* augmentation.
|
|
408
|
+
*/
|
|
409
|
+
type WebhookPayload<E extends WebhookName> = E extends keyof TapWebhookMap ? TapWebhookMap[E] : Record<string, unknown>;
|
|
410
|
+
/**
|
|
411
|
+
* Every Tappify event name with the payload it carries, narrowed by the
|
|
412
|
+
* `TapHostEventMap` augmentation and permissive for the rest.
|
|
413
|
+
*/
|
|
414
|
+
type TapHostEvents = Omit<Record<HostEventName, Record<string, unknown>>, keyof TapHostEventMap> & TapHostEventMap;
|
|
415
|
+
/**
|
|
416
|
+
* The telemetry names in the `TapTelemetryEvents` augmentation, which is what
|
|
417
|
+
* `tap.telemetry.event` accepts.
|
|
418
|
+
*/
|
|
419
|
+
type TelemetryEvent = keyof TapTelemetryEvents extends never ? string : Extract<keyof TapTelemetryEvents, string>;
|
|
420
|
+
/**
|
|
421
|
+
* The settings document, typed by the `TapSettings` augmentation, as
|
|
422
|
+
* `TapSettingsProps` carries it and the server reads it from `documents`.
|
|
423
|
+
*/
|
|
424
|
+
type TapSettingsValues = keyof TapSettings extends never ? Record<string, unknown> : TapSettings;
|
|
425
|
+
/**
|
|
426
|
+
* The credential values Tappify passes to the server, typed by the
|
|
427
|
+
* `TapCredentials` augmentation.
|
|
428
|
+
*/
|
|
429
|
+
type TapCredentialValues = keyof TapCredentials extends never ? Record<string, string> : TapCredentials;
|
|
430
|
+
/** How much room the mount has: a slot, the expand panel, or a whole page. */
|
|
431
|
+
type TapSize = 'slot' | 'panel' | 'page';
|
|
432
|
+
/** Which of the host's three toast styles `tap.ui.toast` raises. */
|
|
433
|
+
type TapToastTone = 'neutral' | 'success' | 'error';
|
|
434
|
+
/**
|
|
435
|
+
* A path `tap.nav.push` accepts: absolute under `/projects`, or relative to the
|
|
436
|
+
* extension's own pages.
|
|
437
|
+
*/
|
|
438
|
+
type TapPath = `/${string}`;
|
|
439
|
+
/** What the host's confirmation dialog shows for `tap.ui.confirm`. */
|
|
440
|
+
interface TapConfirmOptions {
|
|
441
|
+
title: string;
|
|
442
|
+
body?: string;
|
|
443
|
+
/** Labels the confirming button. The host labels it when this is left out. */
|
|
444
|
+
confirmLabel?: string;
|
|
445
|
+
/** Draws the confirming button in the host's destructive styling. */
|
|
446
|
+
destructive?: boolean;
|
|
447
|
+
}
|
|
448
|
+
/** One column of a `table` card sent to chat through `tap.ui.openInChat`. */
|
|
449
|
+
interface TapTableColumn {
|
|
450
|
+
/** The key to read from each row object. */
|
|
451
|
+
key: string;
|
|
452
|
+
label: string;
|
|
453
|
+
}
|
|
454
|
+
/** One side of a `comparison` card sent through `tap.ui.openInChat`. */
|
|
455
|
+
interface TapComparisonSide {
|
|
456
|
+
label: string;
|
|
457
|
+
value: string | number;
|
|
458
|
+
}
|
|
459
|
+
/** A card `tap.ui.openInChat` sends to the owner's chat, one member per shape. */
|
|
460
|
+
type TapChatCard = {
|
|
461
|
+
type: 'value';
|
|
462
|
+
label: string;
|
|
463
|
+
value: string | number;
|
|
464
|
+
delta?: number;
|
|
465
|
+
} | {
|
|
466
|
+
type: 'series';
|
|
467
|
+
label: string;
|
|
468
|
+
points: TapSeriesPoint[];
|
|
469
|
+
} | {
|
|
470
|
+
type: 'table';
|
|
471
|
+
columns: TapTableColumn[];
|
|
472
|
+
rows: Record<string, unknown>[];
|
|
473
|
+
} | {
|
|
474
|
+
type: 'list';
|
|
475
|
+
items: {
|
|
476
|
+
id: string;
|
|
477
|
+
label: string;
|
|
478
|
+
description?: string;
|
|
479
|
+
}[];
|
|
480
|
+
} | {
|
|
481
|
+
type: 'comparison';
|
|
482
|
+
label: string;
|
|
483
|
+
left: TapComparisonSide;
|
|
484
|
+
right: TapComparisonSide;
|
|
485
|
+
};
|
|
486
|
+
/**
|
|
487
|
+
* What `tap.actions.run` resolves to: the run the owner approves or rejects on
|
|
488
|
+
* the host's approval card.
|
|
489
|
+
*/
|
|
490
|
+
interface TapActionRun {
|
|
491
|
+
id: string;
|
|
492
|
+
actionId: ActionId;
|
|
493
|
+
status: 'pending' | 'approved' | 'rejected' | 'succeeded' | 'failed';
|
|
494
|
+
requestedAt: string;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* The `tap.format` helpers, which format in `tap.locale` and `tap.timezone` so a
|
|
498
|
+
* number or a date reads the way the rest of the host reads.
|
|
499
|
+
*
|
|
500
|
+
* @remarks
|
|
501
|
+
* The host takes both from the browser. The testing mock does not: it formats in
|
|
502
|
+
* `en-US` and UTC so an expected string does not move with the machine running the
|
|
503
|
+
* test, and its `date` and `relative` answer differently from the host's — `date`
|
|
504
|
+
* ignores `style` and returns `YYYY-MM-DD`, and `relative` returns a whole ISO
|
|
505
|
+
* timestamp rather than a phrase. Assert on your own formatting, not on either of
|
|
506
|
+
* those two strings.
|
|
507
|
+
*/
|
|
508
|
+
interface TapFormatters {
|
|
509
|
+
/** Groups digits the way the owner's locale does. */
|
|
510
|
+
number(value: number, options?: Intl.NumberFormatOptions): string;
|
|
511
|
+
/** `code` is an ISO currency code, such as `USD`. */
|
|
512
|
+
currency(value: number, code: string): string;
|
|
513
|
+
/**
|
|
514
|
+
* Formats the date alone, with no time part. In the host, `long` is the only
|
|
515
|
+
* style that changes anything: every other value renders the medium form.
|
|
516
|
+
*/
|
|
517
|
+
date(value: string | Date, style?: 'short' | 'long'): string;
|
|
518
|
+
/** In the host, the distance from now in whole days, such as `3 days ago`. */
|
|
519
|
+
relative(value: string | Date): string;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* The channels the host emits a change on, which every slice hook subscribes to.
|
|
523
|
+
*
|
|
524
|
+
* @remarks
|
|
525
|
+
* `state:<key>` and `storage:<collection>` carry the key or the collection name;
|
|
526
|
+
* the rest are fixed. The hooks subscribe through `tap.__subscribe`, so an
|
|
527
|
+
* extension does not name a channel itself.
|
|
528
|
+
*/
|
|
529
|
+
type TapChangeKey = 'auth' | 'project' | 'filters' | 'theme' | 'size' | 'params' | 'context' | `state:${string}` | `storage:${string}`;
|
|
530
|
+
/**
|
|
531
|
+
* The two members of `Tap` the host and the SDK's own hooks use. Extensions do
|
|
532
|
+
* not call these.
|
|
533
|
+
*/
|
|
534
|
+
interface TapInternals {
|
|
535
|
+
/**
|
|
536
|
+
* The portal node inside the mount's shadow root, or `null` until the shadow
|
|
537
|
+
* root exists.
|
|
538
|
+
*/
|
|
539
|
+
__portal: HTMLElement | null;
|
|
540
|
+
/**
|
|
541
|
+
* The host replaces the member a key names with a new object and only then
|
|
542
|
+
* calls the key's listeners; it never mutates a member in place, because the
|
|
543
|
+
* `useTap*` hooks compare snapshots by reference. Returns an unsubscribe
|
|
544
|
+
* function.
|
|
545
|
+
*/
|
|
546
|
+
__subscribe(key: TapChangeKey, listener: () => void): () => void;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* The bridge a mount talks to the host through, which `useTap` returns.
|
|
550
|
+
*
|
|
551
|
+
* @remarks
|
|
552
|
+
* The host replaces `auth`, `project`, `filters`, `theme`, `ui`, `params` and
|
|
553
|
+
* `context` with new objects rather than mutating them, so the `useTap*` hooks
|
|
554
|
+
* can compare snapshots by reference. Read a value through its hook when the
|
|
555
|
+
* component has to re-render on a change, and through `tap` when it does not.
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* ```tsx
|
|
559
|
+
* import { TapStat, useTap } from '@tappify/extension-sdk';
|
|
560
|
+
*
|
|
561
|
+
* function Installs({ count }: { count: number }) {
|
|
562
|
+
* const tap = useTap();
|
|
563
|
+
* return <TapStat label="Installs" value={tap.format.number(count)} />;
|
|
564
|
+
* }
|
|
565
|
+
* ```
|
|
566
|
+
*/
|
|
567
|
+
interface Tap extends TapInternals {
|
|
568
|
+
extension: {
|
|
569
|
+
id: string;
|
|
570
|
+
name: string;
|
|
571
|
+
installId: string;
|
|
572
|
+
/** `null` when the extension is installed on the workspace, not a project. */
|
|
573
|
+
projectId: string | null;
|
|
574
|
+
};
|
|
575
|
+
/** `dev` while the dev server serves the mount, else the install's channel. */
|
|
576
|
+
env: 'dev' | 'sandbox' | 'production';
|
|
577
|
+
host: {
|
|
578
|
+
version: string;
|
|
579
|
+
sdkMajors: number[];
|
|
580
|
+
};
|
|
581
|
+
auth: {
|
|
582
|
+
/** The install token to send to your own server as a bearer token. */
|
|
583
|
+
token: string;
|
|
584
|
+
user: {
|
|
585
|
+
id: string;
|
|
586
|
+
role: 'admin' | 'member';
|
|
587
|
+
};
|
|
588
|
+
organizationId: string;
|
|
589
|
+
scopes: ScopeKey[];
|
|
590
|
+
/** Whether the install granted the scope. */
|
|
591
|
+
can(scope: ScopeKey): boolean;
|
|
592
|
+
};
|
|
593
|
+
project: {
|
|
594
|
+
id: string;
|
|
595
|
+
name: string;
|
|
596
|
+
platforms: TapPlatform[];
|
|
597
|
+
apps: TapApp[];
|
|
598
|
+
releases: TapRelease[];
|
|
599
|
+
keywords: TapKeyword[];
|
|
600
|
+
};
|
|
601
|
+
filters: TapFilters;
|
|
602
|
+
theme: {
|
|
603
|
+
mode: 'light' | 'dark';
|
|
604
|
+
};
|
|
605
|
+
locale: string;
|
|
606
|
+
timezone: string;
|
|
607
|
+
format: TapFormatters;
|
|
608
|
+
nav: {
|
|
609
|
+
/** Refused with a toast when the path leaves the project or the extension. */
|
|
610
|
+
push(path: TapPath): void;
|
|
611
|
+
/** Sets the query string on the host's URL; a `null` drops that parameter. */
|
|
612
|
+
setSearch(params: Record<string, string | null>): void;
|
|
613
|
+
/** Opens the owner's settings page for this install. */
|
|
614
|
+
openSettings(): void;
|
|
615
|
+
/**
|
|
616
|
+
* Opens the owner's chat and fills the composer with the prompt. The owner
|
|
617
|
+
* reads it and sends it — nothing here sends by itself. The context goes
|
|
618
|
+
* under it as JSON on a visible `From <extension name>:` line the owner can
|
|
619
|
+
* edit or delete, cut to 2 KB, the same ceiling every vendor block the
|
|
620
|
+
* assistant reads is held to.
|
|
621
|
+
*/
|
|
622
|
+
openChat(prompt: string, context?: Record<string, unknown>): void;
|
|
623
|
+
/** Asks the owner to confirm, then opens the url in a new tab. */
|
|
624
|
+
openExternal(url: string): void;
|
|
625
|
+
};
|
|
626
|
+
data: {
|
|
627
|
+
/** Rejects with `TAP_SCOPE_MISSING` when the query's scope is not granted. */
|
|
628
|
+
query<Q extends TapQuery>(query: Q): Promise<TapResult<Q>>;
|
|
629
|
+
/** Returns an unsubscribe function; call it when the component unmounts. */
|
|
630
|
+
subscribe<E extends keyof TapHostEvents>(event: E, handler: (payload: TapHostEvents[E]) => void): () => void;
|
|
631
|
+
};
|
|
632
|
+
server: TapProcedures;
|
|
633
|
+
state: {
|
|
634
|
+
/**
|
|
635
|
+
* Returns the same reference for the same key until `set` replaces it, so
|
|
636
|
+
* `useTapState` can use the value as a `useSyncExternalStore` snapshot.
|
|
637
|
+
*/
|
|
638
|
+
get<T>(key: string): T | undefined;
|
|
639
|
+
/** Notifies every mount of the install that reads the same key. */
|
|
640
|
+
set<T>(key: string, value: T): void;
|
|
641
|
+
/** Returns an unsubscribe function. */
|
|
642
|
+
subscribe(key: string, handler: () => void): () => void;
|
|
643
|
+
};
|
|
644
|
+
ui: {
|
|
645
|
+
size: TapSize;
|
|
646
|
+
/** Raises a host toast; the tone defaults to `neutral`. */
|
|
647
|
+
toast(message: string, tone?: TapToastTone): void;
|
|
648
|
+
/** Resolves to what the owner chose in the host's confirmation dialog. */
|
|
649
|
+
confirm(options: TapConfirmOptions): Promise<boolean>;
|
|
650
|
+
/**
|
|
651
|
+
* Puts the card in the owner's chat, drawn by the host from the values you
|
|
652
|
+
* send. Needs `insights:write`; without it the host fills the composer with
|
|
653
|
+
* a sentence describing the card instead, and the owner sends that.
|
|
654
|
+
*/
|
|
655
|
+
openInChat(card: TapChatCard): void;
|
|
656
|
+
/** Opens the widget's expand panel. */
|
|
657
|
+
expand(): void;
|
|
658
|
+
/** Saves the blob to the owner's downloads under that filename. */
|
|
659
|
+
download(blob: Blob, filename: string): void;
|
|
660
|
+
/** Copies the text to the clipboard and toasts that it was copied. */
|
|
661
|
+
copy(text: string): Promise<void>;
|
|
662
|
+
};
|
|
663
|
+
/** What Expand carried in, or the row behind a row action. */
|
|
664
|
+
context: Record<string, unknown>;
|
|
665
|
+
/** A page's route: `pageId`, `path`, and one key per sub-path segment. */
|
|
666
|
+
params: Record<string, string>;
|
|
667
|
+
storage: TapStorage;
|
|
668
|
+
telemetry: {
|
|
669
|
+
/** Queued and sent by the host; the call itself does no network work. */
|
|
670
|
+
event(name: TelemetryEvent, props?: Record<string, string | number | boolean>): void;
|
|
671
|
+
};
|
|
672
|
+
actions: {
|
|
673
|
+
/**
|
|
674
|
+
* Creates the run and resolves with it as soon as it exists. `status` is
|
|
675
|
+
* `pending` while the owner has still to approve — the host draws the
|
|
676
|
+
* approval card — and `succeeded` or `failed` when the owner has turned
|
|
677
|
+
* asking off for this install, which no action-declaring extension can do
|
|
678
|
+
* today. Rejects with a `TapServerError` when the host refuses the run.
|
|
679
|
+
*/
|
|
680
|
+
run<A extends ActionId>(actionId: A, input: ActionInput<A>): Promise<TapActionRun>;
|
|
681
|
+
};
|
|
682
|
+
/**
|
|
683
|
+
* Drops the cached answers for one procedure, or for everything of yours when
|
|
684
|
+
* the name is left out, across every mount of the install.
|
|
685
|
+
*/
|
|
686
|
+
invalidate(name?: TapProcedureName): void;
|
|
687
|
+
}
|
|
688
|
+
/** The props the host renders a widget entry with. */
|
|
689
|
+
interface TapWidgetProps {
|
|
690
|
+
/** Reserved, and always an empty object today: the host puts nothing in it yet. */
|
|
691
|
+
config: Record<string, unknown>;
|
|
692
|
+
}
|
|
693
|
+
/** The props the host renders a tab entry with, which carries nothing. */
|
|
694
|
+
type TapTabProps = Record<string, never>;
|
|
695
|
+
/** The props the host renders a page entry with. */
|
|
696
|
+
interface TapPageProps {
|
|
697
|
+
/** The same value as `tap.params`: `pageId`, `path`, and one key per segment. */
|
|
698
|
+
params: Record<string, string>;
|
|
699
|
+
}
|
|
700
|
+
/** The props the host renders a row action entry with. */
|
|
701
|
+
interface TapRowActionProps {
|
|
702
|
+
/** The row the owner opened the action from. */
|
|
703
|
+
row: Record<string, unknown>;
|
|
704
|
+
}
|
|
705
|
+
/** The props the host renders a settings entry with. */
|
|
706
|
+
interface TapSettingsProps {
|
|
707
|
+
values: TapSettingsValues;
|
|
708
|
+
/**
|
|
709
|
+
* Hands the values to the host, which merges them into the settings document
|
|
710
|
+
* and validates them against the schema the manifest declares.
|
|
711
|
+
*/
|
|
712
|
+
onChange(values: TapSettingsValues): void;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export type { TapSettingsValues as $, ActionId as A, TapHostEventMap as B, TapInternals as C, TapKeyword as D, TapKeywordsResult as E, TapListing as F, TapListingResult as G, TapPageProps as H, TapPath as I, TapPlatform as J, TapPlatformFilter as K, TapProcedureMap as L, TapProcedures as M, TapProjectResult as N, TapPromptMap as O, PromptId as P, TapRelease as Q, TapRevenueResult as R, TapReview as S, Tap as T, TapReviewsResult as U, TapRowActionProps as V, TapSeriesMetric as W, TapSeriesPoint as X, TapSeriesResult as Y, TapSettings as Z, TapSettingsProps as _, TapFilters as a, TapSingleton as a0, TapStorage as a1, TapStorageMap as a2, TapTabProps as a3, TapTableColumn as a4, TapTelemetryEvents as a5, TapToastTone as a6, TapToolMap as a7, TapWebhookMap as a8, TapWidgetProps as a9, TelemetryEvent as aa, ToolId as ab, ToolInput as ac, WebhookName as ad, WebhookPayload as ae, TapSize as b, TapHostEvents as c, TapQuery as d, TapResult as e, TapProcedureName as f, TapProcedureInput as g, TapProcedureOutput as h, TapSingletonName as i, TapSingletonDocument as j, ActionInput as k, PromptInput as l, TapActionMap as m, TapActionRun as n, TapApp as o, TapChangeKey as p, TapChatCard as q, TapCollection as r, TapComparisonSide as s, TapConfirmOptions as t, TapCrashIssue as u, TapCrashesResult as v, TapCredentialValues as w, TapCredentials as x, TapDateRange as y, TapFormatters as z };
|