@appeeky/spec 0.0.0-stage → 0.2.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 (111) hide show
  1. package/.github/assets/cover.gif +0 -0
  2. package/LICENSE +110 -0
  3. package/README.md +636 -2
  4. package/agents/appeeky-ads.md +50 -0
  5. package/agents/appeeky-aso.md +58 -0
  6. package/agents/appeeky-releases.md +47 -0
  7. package/agents/appeeky-reviews.md +53 -0
  8. package/agents/appeeky-social.md +54 -0
  9. package/agents/appeeky-ugc.md +56 -0
  10. package/agents/cofounder.md +36 -0
  11. package/dist/ads.d.ts +42 -0
  12. package/dist/ads.js +71 -0
  13. package/dist/agents.d.ts +47 -0
  14. package/dist/agents.js +88 -0
  15. package/dist/appeeky-api.d.ts +62 -0
  16. package/dist/appeeky-api.js +240 -0
  17. package/dist/attribution-setup.d.ts +28 -0
  18. package/dist/attribution-setup.js +65 -0
  19. package/dist/attribution.d.ts +121 -0
  20. package/dist/attribution.js +170 -0
  21. package/dist/bin.d.ts +2 -0
  22. package/dist/bin.js +4 -0
  23. package/dist/category.d.ts +71 -0
  24. package/dist/category.js +198 -0
  25. package/dist/cli.d.ts +3 -0
  26. package/dist/cli.js +1960 -0
  27. package/dist/competitors.d.ts +74 -0
  28. package/dist/competitors.js +143 -0
  29. package/dist/control.d.ts +21 -0
  30. package/dist/control.js +53 -0
  31. package/dist/core.d.ts +15 -0
  32. package/dist/core.js +15 -0
  33. package/dist/coverage.d.ts +46 -0
  34. package/dist/coverage.js +115 -0
  35. package/dist/data.d.ts +48 -0
  36. package/dist/data.js +298 -0
  37. package/dist/dataforseo.d.ts +139 -0
  38. package/dist/dataforseo.js +354 -0
  39. package/dist/diff.d.ts +11 -0
  40. package/dist/diff.js +33 -0
  41. package/dist/experiments.d.ts +115 -0
  42. package/dist/experiments.js +85 -0
  43. package/dist/files.d.ts +27 -0
  44. package/dist/files.js +129 -0
  45. package/dist/history.d.ts +43 -0
  46. package/dist/history.js +55 -0
  47. package/dist/index.d.ts +24 -0
  48. package/dist/index.js +24 -0
  49. package/dist/limits.d.ts +15 -0
  50. package/dist/limits.js +30 -0
  51. package/dist/lint.d.ts +16 -0
  52. package/dist/lint.js +159 -0
  53. package/dist/loops.d.ts +37 -0
  54. package/dist/loops.js +197 -0
  55. package/dist/measure.d.ts +40 -0
  56. package/dist/measure.js +159 -0
  57. package/dist/metrics.d.ts +290 -0
  58. package/dist/metrics.js +254 -0
  59. package/dist/output.d.ts +21 -0
  60. package/dist/output.js +79 -0
  61. package/dist/project.d.ts +19 -0
  62. package/dist/project.js +35 -0
  63. package/dist/report.d.ts +10 -0
  64. package/dist/report.js +113 -0
  65. package/dist/reviews.d.ts +130 -0
  66. package/dist/reviews.js +287 -0
  67. package/dist/schema.d.ts +612 -0
  68. package/dist/schema.js +253 -0
  69. package/dist/screenshots.d.ts +23 -0
  70. package/dist/screenshots.js +116 -0
  71. package/dist/search-ads.d.ts +137 -0
  72. package/dist/search-ads.js +354 -0
  73. package/dist/seo.d.ts +87 -0
  74. package/dist/seo.js +391 -0
  75. package/dist/setup.d.ts +45 -0
  76. package/dist/setup.js +259 -0
  77. package/dist/social.d.ts +129 -0
  78. package/dist/social.js +189 -0
  79. package/dist/storefronts.d.ts +15 -0
  80. package/dist/storefronts.js +89 -0
  81. package/dist/stores/app-store.d.ts +33 -0
  82. package/dist/stores/app-store.js +159 -0
  83. package/dist/stores/google-play.d.ts +13 -0
  84. package/dist/stores/google-play.js +61 -0
  85. package/dist/stores/types.d.ts +34 -0
  86. package/dist/stores/types.js +2 -0
  87. package/dist/suggest.d.ts +73 -0
  88. package/dist/suggest.js +135 -0
  89. package/dist/text.d.ts +18 -0
  90. package/dist/text.js +55 -0
  91. package/dist/transport.d.ts +99 -0
  92. package/dist/transport.js +170 -0
  93. package/dist/ugc-core.js +1 -0
  94. package/dist/ugc-local.d.ts +116 -0
  95. package/dist/ugc-local.js +174 -0
  96. package/dist/ugc.d.ts +149 -0
  97. package/dist/ugc.js +111 -0
  98. package/dist/verify.d.ts +70 -0
  99. package/dist/verify.js +134 -0
  100. package/dist/visibility-core.js +96 -0
  101. package/dist/visibility-local.d.ts +159 -0
  102. package/dist/visibility-local.js +246 -0
  103. package/dist/visibility.d.ts +152 -0
  104. package/dist/visibility.js +239 -0
  105. package/package.json +80 -4
  106. package/skills/appeeky-spec/SKILL.md +142 -0
  107. package/skills/appeeky-spec-experiments/SKILL.md +93 -0
  108. package/skills/appeeky-spec-localize/SKILL.md +52 -0
  109. package/skills/appeeky-spec-review/SKILL.md +75 -0
  110. package/skills/appeeky-spec-targets/SKILL.md +66 -0
  111. package/skills/appeeky-spec-visibility/SKILL.md +106 -0
@@ -0,0 +1,612 @@
1
+ import { z } from "zod";
2
+ /** Stores a spec can describe. The ids double as folder names under `appeeky/store/`. */
3
+ export declare const STORES: readonly ["app-store", "google-play"];
4
+ export type StoreId = (typeof STORES)[number];
5
+ /** How a store is reached: the local store CLI with your own key, or Appeeky's hosted gateway. */
6
+ export declare const transportMode: z.ZodEnum<["auto", "local", "hosted"]>;
7
+ export type TransportMode = z.infer<typeof transportMode>;
8
+ /** Store charts a category rank is read from. */
9
+ export declare const CHARTS: readonly ["top-free", "top-paid", "top-grossing"];
10
+ export type Chart = (typeof CHARTS)[number];
11
+ /** `appeeky.spec.yaml`: who the app is, where it ships, and what it should be found for. */
12
+ export declare const specFileSchema: z.ZodObject<{
13
+ version: z.ZodLiteral<1>;
14
+ app: z.ZodObject<{
15
+ name: z.ZodString;
16
+ /** Locale the store falls back to when a storefront has no localization of its own. */
17
+ primaryLocale: z.ZodDefault<z.ZodString>;
18
+ }, "strict", z.ZodTypeAny, {
19
+ name: string;
20
+ primaryLocale: string;
21
+ }, {
22
+ name: string;
23
+ primaryLocale?: string | undefined;
24
+ }>;
25
+ stores: z.ZodDefault<z.ZodObject<{
26
+ appStore: z.ZodOptional<z.ZodObject<{
27
+ /** Numeric App Store id (or a bundle id; the local CLI resolves it). */
28
+ appId: z.ZodString;
29
+ platform: z.ZodDefault<z.ZodEnum<["IOS", "MAC_OS", "TV_OS", "VISION_OS"]>>;
30
+ via: z.ZodDefault<z.ZodEnum<["auto", "local", "hosted"]>>;
31
+ /** Named account of the local `appstore` CLI. */
32
+ account: z.ZodOptional<z.ZodString>;
33
+ /**
34
+ * Apple Search Ads on your own API key (ASA_CLIENT_ID, ASA_TEAM_ID, ASA_KEY_ID, ASA_PRIVATE_KEY):
35
+ * `search-ads pull` reads this app's campaigns. Without it, Search Ads comes from Appeeky.
36
+ */
37
+ searchAds: z.ZodOptional<z.ZodObject<{
38
+ /** The organization, when the key reaches more than one. */
39
+ orgId: z.ZodOptional<z.ZodString>;
40
+ /** Only these campaign ids; default: every campaign for this app. */
41
+ campaigns: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
42
+ }, "strict", z.ZodTypeAny, {
43
+ orgId?: string | undefined;
44
+ campaigns?: string[] | undefined;
45
+ }, {
46
+ orgId?: string | undefined;
47
+ campaigns?: string[] | undefined;
48
+ }>>;
49
+ }, "strict", z.ZodTypeAny, {
50
+ appId: string;
51
+ platform: "IOS" | "MAC_OS" | "TV_OS" | "VISION_OS";
52
+ via: "auto" | "local" | "hosted";
53
+ account?: string | undefined;
54
+ searchAds?: {
55
+ orgId?: string | undefined;
56
+ campaigns?: string[] | undefined;
57
+ } | undefined;
58
+ }, {
59
+ appId: string;
60
+ platform?: "IOS" | "MAC_OS" | "TV_OS" | "VISION_OS" | undefined;
61
+ via?: "auto" | "local" | "hosted" | undefined;
62
+ account?: string | undefined;
63
+ searchAds?: {
64
+ orgId?: string | undefined;
65
+ campaigns?: string[] | undefined;
66
+ } | undefined;
67
+ }>>;
68
+ googlePlay: z.ZodOptional<z.ZodObject<{
69
+ packageName: z.ZodString;
70
+ via: z.ZodDefault<z.ZodEnum<["auto", "local", "hosted"]>>;
71
+ /** Named account of the local `gps` CLI (`gps accounts add`). */
72
+ account: z.ZodOptional<z.ZodString>;
73
+ /** Old name for `account`. */
74
+ profile: z.ZodOptional<z.ZodString>;
75
+ }, "strict", z.ZodTypeAny, {
76
+ via: "auto" | "local" | "hosted";
77
+ packageName: string;
78
+ account?: string | undefined;
79
+ profile?: string | undefined;
80
+ }, {
81
+ packageName: string;
82
+ via?: "auto" | "local" | "hosted" | undefined;
83
+ account?: string | undefined;
84
+ profile?: string | undefined;
85
+ }>>;
86
+ }, "strict", z.ZodTypeAny, {
87
+ appStore?: {
88
+ appId: string;
89
+ platform: "IOS" | "MAC_OS" | "TV_OS" | "VISION_OS";
90
+ via: "auto" | "local" | "hosted";
91
+ account?: string | undefined;
92
+ searchAds?: {
93
+ orgId?: string | undefined;
94
+ campaigns?: string[] | undefined;
95
+ } | undefined;
96
+ } | undefined;
97
+ googlePlay?: {
98
+ via: "auto" | "local" | "hosted";
99
+ packageName: string;
100
+ account?: string | undefined;
101
+ profile?: string | undefined;
102
+ } | undefined;
103
+ }, {
104
+ appStore?: {
105
+ appId: string;
106
+ platform?: "IOS" | "MAC_OS" | "TV_OS" | "VISION_OS" | undefined;
107
+ via?: "auto" | "local" | "hosted" | undefined;
108
+ account?: string | undefined;
109
+ searchAds?: {
110
+ orgId?: string | undefined;
111
+ campaigns?: string[] | undefined;
112
+ } | undefined;
113
+ } | undefined;
114
+ googlePlay?: {
115
+ packageName: string;
116
+ via?: "auto" | "local" | "hosted" | undefined;
117
+ account?: string | undefined;
118
+ profile?: string | undefined;
119
+ } | undefined;
120
+ }>>;
121
+ /** Target keywords per storefront: the searches this app should be found for. */
122
+ targets: z.ZodDefault<z.ZodRecord<z.ZodEffects<z.ZodString, string, string>, z.ZodDefault<z.ZodArray<z.ZodString, "many">>>>;
123
+ /** Override which listing locales a storefront indexes (App Store). */
124
+ storefronts: z.ZodDefault<z.ZodRecord<z.ZodEffects<z.ZodString, string, string>, z.ZodArray<z.ZodString, "many">>>;
125
+ /**
126
+ * Paid channels outside the store. Apple Search Ads needs nothing here: it is
127
+ * matched to the app in Appeeky. Meta and TikTok campaigns are listed by id.
128
+ */
129
+ ads: z.ZodDefault<z.ZodObject<{
130
+ meta: z.ZodOptional<z.ZodObject<{
131
+ /** Ad account (act_…); defaults to the one picked in Appeeky. */
132
+ adAccount: z.ZodOptional<z.ZodString>;
133
+ campaigns: z.ZodArray<z.ZodString, "many">;
134
+ }, "strict", z.ZodTypeAny, {
135
+ campaigns: string[];
136
+ adAccount?: string | undefined;
137
+ }, {
138
+ campaigns: string[];
139
+ adAccount?: string | undefined;
140
+ }>>;
141
+ tiktok: z.ZodOptional<z.ZodObject<{
142
+ /** Advertiser id; defaults to the one picked in Appeeky. */
143
+ advertiser: z.ZodOptional<z.ZodString>;
144
+ campaigns: z.ZodArray<z.ZodString, "many">;
145
+ }, "strict", z.ZodTypeAny, {
146
+ campaigns: string[];
147
+ advertiser?: string | undefined;
148
+ }, {
149
+ campaigns: string[];
150
+ advertiser?: string | undefined;
151
+ }>>;
152
+ }, "strict", z.ZodTypeAny, {
153
+ meta?: {
154
+ campaigns: string[];
155
+ adAccount?: string | undefined;
156
+ } | undefined;
157
+ tiktok?: {
158
+ campaigns: string[];
159
+ advertiser?: string | undefined;
160
+ } | undefined;
161
+ }, {
162
+ meta?: {
163
+ campaigns: string[];
164
+ adAccount?: string | undefined;
165
+ } | undefined;
166
+ tiktok?: {
167
+ campaigns: string[];
168
+ advertiser?: string | undefined;
169
+ } | undefined;
170
+ }>>;
171
+ /** Apps you compete with. `competitors pull` writes each one to appeeky/competitors/. */
172
+ competitors: z.ZodDefault<z.ZodArray<z.ZodEffects<z.ZodObject<{
173
+ name: z.ZodOptional<z.ZodString>;
174
+ appStore: z.ZodOptional<z.ZodString>;
175
+ googlePlay: z.ZodOptional<z.ZodString>;
176
+ }, "strict", z.ZodTypeAny, {
177
+ name?: string | undefined;
178
+ appStore?: string | undefined;
179
+ googlePlay?: string | undefined;
180
+ }, {
181
+ name?: string | undefined;
182
+ appStore?: string | undefined;
183
+ googlePlay?: string | undefined;
184
+ }>, {
185
+ name?: string | undefined;
186
+ appStore?: string | undefined;
187
+ googlePlay?: string | undefined;
188
+ }, {
189
+ name?: string | undefined;
190
+ appStore?: string | undefined;
191
+ googlePlay?: string | undefined;
192
+ }>, "many">>;
193
+ /**
194
+ * Install attribution from Appeeky Analytics: organic search, Search Ads keywords,
195
+ * smart links, with the revenue each led to. `via: self` reads your own server on
196
+ * Cloudflare (`url`, ATTRIBUTION_TOKEN); `via: hosted` reads Appeeky's (APPEEKY_API_KEY).
197
+ */
198
+ attribution: z.ZodOptional<z.ZodEffects<z.ZodObject<{
199
+ via: z.ZodDefault<z.ZodEnum<["self", "hosted"]>>;
200
+ url: z.ZodOptional<z.ZodString>;
201
+ /**
202
+ * The app's id in Appeeky Analytics. An app there is one platform, so an app on both
203
+ * stores gives one per store: `{ app-store: …, google-play: … }`.
204
+ */
205
+ app: z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodObject<{
206
+ "app-store": z.ZodOptional<z.ZodString>;
207
+ "google-play": z.ZodOptional<z.ZodString>;
208
+ }, "strict", z.ZodTypeAny, {
209
+ "app-store"?: string | undefined;
210
+ "google-play"?: string | undefined;
211
+ }, {
212
+ "app-store"?: string | undefined;
213
+ "google-play"?: string | undefined;
214
+ }>, {
215
+ "app-store"?: string | undefined;
216
+ "google-play"?: string | undefined;
217
+ }, {
218
+ "app-store"?: string | undefined;
219
+ "google-play"?: string | undefined;
220
+ }>]>;
221
+ }, "strict", z.ZodTypeAny, {
222
+ via: "hosted" | "self";
223
+ app: string | {
224
+ "app-store"?: string | undefined;
225
+ "google-play"?: string | undefined;
226
+ };
227
+ url?: string | undefined;
228
+ }, {
229
+ app: string | {
230
+ "app-store"?: string | undefined;
231
+ "google-play"?: string | undefined;
232
+ };
233
+ via?: "hosted" | "self" | undefined;
234
+ url?: string | undefined;
235
+ }>, {
236
+ via: "hosted" | "self";
237
+ app: string | {
238
+ "app-store"?: string | undefined;
239
+ "google-play"?: string | undefined;
240
+ };
241
+ url?: string | undefined;
242
+ }, {
243
+ app: string | {
244
+ "app-store"?: string | undefined;
245
+ "google-play"?: string | undefined;
246
+ };
247
+ via?: "hosted" | "self" | undefined;
248
+ url?: string | undefined;
249
+ }>>;
250
+ /**
251
+ * Where `data pull` writes store analytics, ads and revenue. They are your private
252
+ * business numbers, so by default they stay in .appeeky/data/ (gitignored).
253
+ * `commit: true` writes them to appeeky/data/ so they are versioned with the spec.
254
+ */
255
+ data: z.ZodDefault<z.ZodObject<{
256
+ commit: z.ZodDefault<z.ZodBoolean>;
257
+ }, "strict", z.ZodTypeAny, {
258
+ commit: boolean;
259
+ }, {
260
+ commit?: boolean | undefined;
261
+ }>>;
262
+ /**
263
+ * Whether ChatGPT, Claude, Gemini and Perplexity name the app when people ask
264
+ * for one like it. Intents are what people want ("fall asleep to rain sounds"),
265
+ * prompts are how they ask; both are tracked per storefront in Appeeky AI Visibility.
266
+ */
267
+ aiVisibility: z.ZodOptional<z.ZodObject<{
268
+ /** Which app to watch when it is on both stores; defaults to the App Store app. */
269
+ store: z.ZodOptional<z.ZodEnum<["app-store", "google-play"]>>;
270
+ /** Storefronts to watch; defaults to the first storefront under targets. */
271
+ countries: z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>;
272
+ /** What people ask AI assistants, per storefront. `visibility sync` sends them to Appeeky. */
273
+ intents: z.ZodDefault<z.ZodRecord<z.ZodEffects<z.ZodString, string, string>, z.ZodArray<z.ZodObject<{
274
+ label: z.ZodString;
275
+ description: z.ZodOptional<z.ZodString>;
276
+ prompts: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
277
+ }, "strict", z.ZodTypeAny, {
278
+ label: string;
279
+ prompts: string[];
280
+ description?: string | undefined;
281
+ }, {
282
+ label: string;
283
+ description?: string | undefined;
284
+ prompts?: string[] | undefined;
285
+ }>, "many">>>;
286
+ /** Assistants `visibility scan --local` asks, among those with a key set; defaults to all of them. */
287
+ models: z.ZodOptional<z.ZodArray<z.ZodEnum<["chatgpt", "claude", "gemini", "perplexity"]>, "many">>;
288
+ /** Other names the assistants may use for the app, e.g. the brand without the subtitle. */
289
+ aliases: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
290
+ }, "strict", z.ZodTypeAny, {
291
+ intents: Record<string, {
292
+ label: string;
293
+ prompts: string[];
294
+ description?: string | undefined;
295
+ }[]>;
296
+ store?: "app-store" | "google-play" | undefined;
297
+ countries?: string[] | undefined;
298
+ models?: ("chatgpt" | "claude" | "gemini" | "perplexity")[] | undefined;
299
+ aliases?: string[] | undefined;
300
+ }, {
301
+ store?: "app-store" | "google-play" | undefined;
302
+ countries?: string[] | undefined;
303
+ intents?: Record<string, {
304
+ label: string;
305
+ description?: string | undefined;
306
+ prompts?: string[] | undefined;
307
+ }[]> | undefined;
308
+ models?: ("chatgpt" | "claude" | "gemini" | "perplexity")[] | undefined;
309
+ aliases?: string[] | undefined;
310
+ }>>;
311
+ /**
312
+ * The app's website. `seo check` reads it for search and AI readiness; `seo pull` records
313
+ * its Google Search Console clicks with your own service account.
314
+ */
315
+ web: z.ZodOptional<z.ZodObject<{
316
+ url: z.ZodString;
317
+ /** Search Console property: "sc-domain:example.com" or "https://example.com/"; defaults to the url's domain. */
318
+ searchConsole: z.ZodOptional<z.ZodString>;
319
+ /** Google searches to watch with `seo ranks` and `seo keywords`, per storefront; default: the store targets. */
320
+ keywords: z.ZodOptional<z.ZodRecord<z.ZodEffects<z.ZodString, string, string>, z.ZodArray<z.ZodString, "many">>>;
321
+ /** Storefronts to watch; default: the first one under keywords or targets. */
322
+ countries: z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>;
323
+ /** The results page to read; default mobile, where people look for apps. */
324
+ device: z.ZodOptional<z.ZodEnum<["mobile", "desktop"]>>;
325
+ }, "strict", z.ZodTypeAny, {
326
+ url: string;
327
+ countries?: string[] | undefined;
328
+ searchConsole?: string | undefined;
329
+ keywords?: Record<string, string[]> | undefined;
330
+ device?: "mobile" | "desktop" | undefined;
331
+ }, {
332
+ url: string;
333
+ countries?: string[] | undefined;
334
+ searchConsole?: string | undefined;
335
+ keywords?: Record<string, string[]> | undefined;
336
+ device?: "mobile" | "desktop" | undefined;
337
+ }>>;
338
+ /** Rank in the app's category chart (top 100), recorded daily by `category pull`. */
339
+ category: z.ZodOptional<z.ZodObject<{
340
+ /** App Store genre id, e.g. "6013" for Health & Fitness; read from the app when left out. */
341
+ appStore: z.ZodOptional<z.ZodString>;
342
+ /** Google Play category, e.g. HEALTH_AND_FITNESS. */
343
+ googlePlay: z.ZodOptional<z.ZodString>;
344
+ /** Defaults to top-paid for a paid App Store app, top-free otherwise. */
345
+ chart: z.ZodOptional<z.ZodEnum<["top-free", "top-paid", "top-grossing"]>>;
346
+ /** Storefronts to record; defaults to the storefronts under targets. */
347
+ countries: z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>;
348
+ }, "strict", z.ZodTypeAny, {
349
+ appStore?: string | undefined;
350
+ googlePlay?: string | undefined;
351
+ countries?: string[] | undefined;
352
+ chart?: "top-free" | "top-paid" | "top-grossing" | undefined;
353
+ }, {
354
+ appStore?: string | undefined;
355
+ googlePlay?: string | undefined;
356
+ countries?: string[] | undefined;
357
+ chart?: "top-free" | "top-paid" | "top-grossing" | undefined;
358
+ }>>;
359
+ /** Who the app is for. Experiments, screenshots and UGC refer to these by id. */
360
+ personas: z.ZodDefault<z.ZodArray<z.ZodObject<{
361
+ id: z.ZodString;
362
+ name: z.ZodString;
363
+ description: z.ZodOptional<z.ZodString>;
364
+ /** How this persona searches: seeds for targets and keyword ideas. */
365
+ searches: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
366
+ }, "strict", z.ZodTypeAny, {
367
+ name: string;
368
+ id: string;
369
+ searches: string[];
370
+ description?: string | undefined;
371
+ }, {
372
+ name: string;
373
+ id: string;
374
+ description?: string | undefined;
375
+ searches?: string[] | undefined;
376
+ }>, "many">>;
377
+ }, "strict", z.ZodTypeAny, {
378
+ version: 1;
379
+ app: {
380
+ name: string;
381
+ primaryLocale: string;
382
+ };
383
+ stores: {
384
+ appStore?: {
385
+ appId: string;
386
+ platform: "IOS" | "MAC_OS" | "TV_OS" | "VISION_OS";
387
+ via: "auto" | "local" | "hosted";
388
+ account?: string | undefined;
389
+ searchAds?: {
390
+ orgId?: string | undefined;
391
+ campaigns?: string[] | undefined;
392
+ } | undefined;
393
+ } | undefined;
394
+ googlePlay?: {
395
+ via: "auto" | "local" | "hosted";
396
+ packageName: string;
397
+ account?: string | undefined;
398
+ profile?: string | undefined;
399
+ } | undefined;
400
+ };
401
+ targets: Record<string, string[]>;
402
+ storefronts: Record<string, string[]>;
403
+ ads: {
404
+ meta?: {
405
+ campaigns: string[];
406
+ adAccount?: string | undefined;
407
+ } | undefined;
408
+ tiktok?: {
409
+ campaigns: string[];
410
+ advertiser?: string | undefined;
411
+ } | undefined;
412
+ };
413
+ competitors: {
414
+ name?: string | undefined;
415
+ appStore?: string | undefined;
416
+ googlePlay?: string | undefined;
417
+ }[];
418
+ data: {
419
+ commit: boolean;
420
+ };
421
+ personas: {
422
+ name: string;
423
+ id: string;
424
+ searches: string[];
425
+ description?: string | undefined;
426
+ }[];
427
+ attribution?: {
428
+ via: "hosted" | "self";
429
+ app: string | {
430
+ "app-store"?: string | undefined;
431
+ "google-play"?: string | undefined;
432
+ };
433
+ url?: string | undefined;
434
+ } | undefined;
435
+ aiVisibility?: {
436
+ intents: Record<string, {
437
+ label: string;
438
+ prompts: string[];
439
+ description?: string | undefined;
440
+ }[]>;
441
+ store?: "app-store" | "google-play" | undefined;
442
+ countries?: string[] | undefined;
443
+ models?: ("chatgpt" | "claude" | "gemini" | "perplexity")[] | undefined;
444
+ aliases?: string[] | undefined;
445
+ } | undefined;
446
+ web?: {
447
+ url: string;
448
+ countries?: string[] | undefined;
449
+ searchConsole?: string | undefined;
450
+ keywords?: Record<string, string[]> | undefined;
451
+ device?: "mobile" | "desktop" | undefined;
452
+ } | undefined;
453
+ category?: {
454
+ appStore?: string | undefined;
455
+ googlePlay?: string | undefined;
456
+ countries?: string[] | undefined;
457
+ chart?: "top-free" | "top-paid" | "top-grossing" | undefined;
458
+ } | undefined;
459
+ }, {
460
+ version: 1;
461
+ app: {
462
+ name: string;
463
+ primaryLocale?: string | undefined;
464
+ };
465
+ stores?: {
466
+ appStore?: {
467
+ appId: string;
468
+ platform?: "IOS" | "MAC_OS" | "TV_OS" | "VISION_OS" | undefined;
469
+ via?: "auto" | "local" | "hosted" | undefined;
470
+ account?: string | undefined;
471
+ searchAds?: {
472
+ orgId?: string | undefined;
473
+ campaigns?: string[] | undefined;
474
+ } | undefined;
475
+ } | undefined;
476
+ googlePlay?: {
477
+ packageName: string;
478
+ via?: "auto" | "local" | "hosted" | undefined;
479
+ account?: string | undefined;
480
+ profile?: string | undefined;
481
+ } | undefined;
482
+ } | undefined;
483
+ targets?: Record<string, string[] | undefined> | undefined;
484
+ storefronts?: Record<string, string[]> | undefined;
485
+ ads?: {
486
+ meta?: {
487
+ campaigns: string[];
488
+ adAccount?: string | undefined;
489
+ } | undefined;
490
+ tiktok?: {
491
+ campaigns: string[];
492
+ advertiser?: string | undefined;
493
+ } | undefined;
494
+ } | undefined;
495
+ competitors?: {
496
+ name?: string | undefined;
497
+ appStore?: string | undefined;
498
+ googlePlay?: string | undefined;
499
+ }[] | undefined;
500
+ attribution?: {
501
+ app: string | {
502
+ "app-store"?: string | undefined;
503
+ "google-play"?: string | undefined;
504
+ };
505
+ via?: "hosted" | "self" | undefined;
506
+ url?: string | undefined;
507
+ } | undefined;
508
+ data?: {
509
+ commit?: boolean | undefined;
510
+ } | undefined;
511
+ aiVisibility?: {
512
+ store?: "app-store" | "google-play" | undefined;
513
+ countries?: string[] | undefined;
514
+ intents?: Record<string, {
515
+ label: string;
516
+ description?: string | undefined;
517
+ prompts?: string[] | undefined;
518
+ }[]> | undefined;
519
+ models?: ("chatgpt" | "claude" | "gemini" | "perplexity")[] | undefined;
520
+ aliases?: string[] | undefined;
521
+ } | undefined;
522
+ web?: {
523
+ url: string;
524
+ countries?: string[] | undefined;
525
+ searchConsole?: string | undefined;
526
+ keywords?: Record<string, string[]> | undefined;
527
+ device?: "mobile" | "desktop" | undefined;
528
+ } | undefined;
529
+ category?: {
530
+ appStore?: string | undefined;
531
+ googlePlay?: string | undefined;
532
+ countries?: string[] | undefined;
533
+ chart?: "top-free" | "top-paid" | "top-grossing" | undefined;
534
+ } | undefined;
535
+ personas?: {
536
+ name: string;
537
+ id: string;
538
+ description?: string | undefined;
539
+ searches?: string[] | undefined;
540
+ }[] | undefined;
541
+ }>;
542
+ export type SpecFile = z.infer<typeof specFileSchema>;
543
+ export type SpecFileInput = z.input<typeof specFileSchema>;
544
+ /**
545
+ * One App Store locale: `appeeky/store/app-store/<locale>.yaml`.
546
+ * A field left out is not managed by the spec: it is never diffed or pushed.
547
+ */
548
+ export declare const appStoreListingSchema: z.ZodObject<{
549
+ name: z.ZodOptional<z.ZodString>;
550
+ subtitle: z.ZodOptional<z.ZodString>;
551
+ keywords: z.ZodOptional<z.ZodString>;
552
+ promotionalText: z.ZodOptional<z.ZodString>;
553
+ description: z.ZodOptional<z.ZodString>;
554
+ whatsNew: z.ZodOptional<z.ZodString>;
555
+ marketingUrl: z.ZodOptional<z.ZodString>;
556
+ supportUrl: z.ZodOptional<z.ZodString>;
557
+ }, "strict", z.ZodTypeAny, {
558
+ description?: string | undefined;
559
+ name?: string | undefined;
560
+ keywords?: string | undefined;
561
+ subtitle?: string | undefined;
562
+ promotionalText?: string | undefined;
563
+ whatsNew?: string | undefined;
564
+ marketingUrl?: string | undefined;
565
+ supportUrl?: string | undefined;
566
+ }, {
567
+ description?: string | undefined;
568
+ name?: string | undefined;
569
+ keywords?: string | undefined;
570
+ subtitle?: string | undefined;
571
+ promotionalText?: string | undefined;
572
+ whatsNew?: string | undefined;
573
+ marketingUrl?: string | undefined;
574
+ supportUrl?: string | undefined;
575
+ }>;
576
+ export type AppStoreListing = z.infer<typeof appStoreListingSchema>;
577
+ /** One Google Play language: `appeeky/store/google-play/<language>.yaml`. */
578
+ export declare const googlePlayListingSchema: z.ZodObject<{
579
+ title: z.ZodOptional<z.ZodString>;
580
+ shortDescription: z.ZodOptional<z.ZodString>;
581
+ fullDescription: z.ZodOptional<z.ZodString>;
582
+ video: z.ZodOptional<z.ZodString>;
583
+ }, "strict", z.ZodTypeAny, {
584
+ title?: string | undefined;
585
+ shortDescription?: string | undefined;
586
+ fullDescription?: string | undefined;
587
+ video?: string | undefined;
588
+ }, {
589
+ title?: string | undefined;
590
+ shortDescription?: string | undefined;
591
+ fullDescription?: string | undefined;
592
+ video?: string | undefined;
593
+ }>;
594
+ export type GooglePlayListing = z.infer<typeof googlePlayListingSchema>;
595
+ export type Listing = AppStoreListing | GooglePlayListing;
596
+ export declare const APP_STORE_FIELDS: readonly ["name", "subtitle", "keywords", "promotionalText", "description", "whatsNew", "marketingUrl", "supportUrl"];
597
+ export declare const GOOGLE_PLAY_FIELDS: readonly ["title", "shortDescription", "fullDescription", "video"];
598
+ export type AppStoreField = (typeof APP_STORE_FIELDS)[number];
599
+ export type GooglePlayField = (typeof GOOGLE_PLAY_FIELDS)[number];
600
+ export declare function fieldsFor(store: StoreId): readonly string[];
601
+ /** Listings of one store, keyed by locale. */
602
+ export type StoreListings<T extends Listing = Listing> = Record<string, T>;
603
+ /** A whole spec as loaded from disk. */
604
+ export interface Project {
605
+ /** Folder that holds `appeeky.spec.yaml`. */
606
+ root: string;
607
+ spec: SpecFile;
608
+ listings: {
609
+ "app-store": StoreListings<AppStoreListing>;
610
+ "google-play": StoreListings<GooglePlayListing>;
611
+ };
612
+ }