vydanne 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.
@@ -0,0 +1,434 @@
1
+ # Getting started with vydanne
2
+
3
+ A step-by-step setup for **your** app — written so you can follow it without being a developer. Every
4
+ step is a command to paste or a button to click. Budget ~30 minutes the first time; after that a release
5
+ is three commands.
6
+
7
+ If you'd rather skim: [What vydanne does](#0-what-vydanne-does-and-what-stays-yours) →
8
+ [Accounts](#1-what-you-need-before-you-start) → [Install](#2-install-vydanne) →
9
+ [Apple key](#3-get-your-apple-credentials-once) → [Play key](#4-get-your-google-play-credentials-once-android-only) →
10
+ [Config](#5-write-the-config-file) → [Folders](#6-put-your-text-and-images-where-vydanne-looks) →
11
+ [Push it](#8-push-it-to-the-store).
12
+
13
+ ---
14
+
15
+ ## 0. What vydanne does, and what stays yours
16
+
17
+ vydanne fills in **an app record that already exists**. It does not create apps, build software, or
18
+ submit anything for review.
19
+
20
+ | vydanne does | You (or your developer) still do |
21
+ |---|---|
22
+ | Write/push the store text in every language | **Create the app record** in App Store Connect / Play Console |
23
+ | Upload screenshots, app previews, Play graphics | **Build and upload the binary** (`.ipa` / `.aab`) |
24
+ | Set age rating, App Review contact, IAP text | Answer **App Privacy** in Apple's web UI (see [step 9](#9-finish-in-the-browser-the-parts-no-api-can-do)) |
25
+ | Generate the US export-compliance PDF | Play **Data Safety** + content-rating questionnaires |
26
+ | Check everything is complete (`preflight`) | **Press Submit for Review** |
27
+
28
+ > **It never submits.** That's deliberate — a human should always be the one who ships.
29
+
30
+ ---
31
+
32
+ ## 1. What you need before you start
33
+
34
+ **For Apple (iPhone / iPad / Mac):**
35
+ 1. An **Apple Developer Program** membership (~$99/year) — [developer.apple.com/programs](https://developer.apple.com/programs/).
36
+ 2. An **app already created** in [App Store Connect](https://appstoreconnect.apple.com) → **My Apps → +**.
37
+ You need its **Bundle ID** (e.g. `com.example.myapp`).
38
+ 3. Permission to create API keys: your account must be **Account Holder** or **Admin**.
39
+
40
+ **For Google Play (Android)** — skip if you're iOS-only:
41
+ 1. A **Play Console** developer account (one-time $25) — [play.google.com/console](https://play.google.com/console).
42
+ 2. An **app already created** in Play Console, with its **package name** (e.g. `com.example.myapp`).
43
+ 3. For a brand-new app, upload your first build through the Play Console web UI once. The API can edit a
44
+ listing, but a never-released app has nothing to attach a listing to.
45
+
46
+ **On your computer:**
47
+ - **Node.js 20.9 or newer.** Check with `node -v`. If it's missing or older, install the LTS build from
48
+ [nodejs.org](https://nodejs.org).
49
+ - **macOS, Linux, or Windows** — vydanne runs on all three.
50
+
51
+ > **Windows users:** every step below shows both versions. Use the **PowerShell** one (open *Terminal* or
52
+ > *Windows PowerShell* from the Start menu). The commands are not interchangeable — `export` and
53
+ > `VAR=1 command` are Unix-only syntax and will fail in PowerShell.
54
+
55
+ ---
56
+
57
+ ## 2. Install vydanne
58
+
59
+ Open your terminal and go to your app's project folder (the top level — the folder you'd open in an editor):
60
+
61
+ ```sh
62
+ # macOS / Linux
63
+ cd /path/to/your-app
64
+ ```
65
+ ```powershell
66
+ # Windows PowerShell
67
+ cd C:\path\to\your-app
68
+ ```
69
+
70
+ If there's no `package.json` there yet, create one (harmless — it just records your tools):
71
+
72
+ ```sh
73
+ npm init -y
74
+ ```
75
+
76
+ Install vydanne and confirm it runs:
77
+
78
+ ```sh
79
+ npm i -D vydanne
80
+ npx vydanne version
81
+ ```
82
+
83
+ You should see something like `vydanne 0.1.0`.
84
+
85
+ > **Always run vydanne from this folder.** It reads `vydanne.config.mjs` and every file path relative to
86
+ > wherever you are. Running it from a subfolder will make it look in the wrong place.
87
+
88
+ ---
89
+
90
+ ## 3. Get your Apple credentials (once)
91
+
92
+ vydanne talks to Apple with an **API key** — three pieces: a `.p8` file, a **Key ID**, and an **Issuer ID**.
93
+
94
+ 1. Go to [App Store Connect](https://appstoreconnect.apple.com) → **Users and Access**.
95
+ 2. Open the **Integrations** tab → **App Store Connect API** → **Team Keys**.
96
+ 3. Click **+**, name it `vydanne`, and set **Access** to **App Manager**. *(Admin also works. Anything
97
+ lower can't edit a listing.)*
98
+ 4. Click **Generate**, then **Download the key**. ⚠️ **Apple lets you download it exactly once.** If you
99
+ lose it, revoke the key and make a new one.
100
+ 5. On that same page, copy the **Key ID** (next to your new key) and the **Issuer ID** (at the top of the
101
+ list — one per team, looks like `57246542-96fe-1a63-e053-0824d011072a`).
102
+
103
+ Now put the file where vydanne looks for it — inside a `.appstoreconnect\private_keys` folder in your
104
+ home directory. vydanne finds your home folder automatically on every operating system.
105
+
106
+ ```sh
107
+ # macOS / Linux
108
+ mkdir -p ~/.appstoreconnect/private_keys
109
+ mv ~/Downloads/AuthKey_*.p8 ~/.appstoreconnect/private_keys/
110
+ ```
111
+ ```powershell
112
+ # Windows PowerShell
113
+ New-Item -ItemType Directory -Force "$env:USERPROFILE\.appstoreconnect\private_keys"
114
+ Move-Item "$env:USERPROFILE\Downloads\AuthKey_*.p8" "$env:USERPROFILE\.appstoreconnect\private_keys\"
115
+ ```
116
+
117
+ Tell your terminal the two IDs (substitute your own values):
118
+
119
+ ```sh
120
+ # macOS / Linux
121
+ export ASC_KEY_ID=ABCD123456
122
+ export ASC_ISSUER_ID=57246542-96fe-1a63-e053-0824d011072a
123
+ ```
124
+ ```powershell
125
+ # Windows PowerShell
126
+ $env:ASC_KEY_ID = "ABCD123456"
127
+ $env:ASC_ISSUER_ID = "57246542-96fe-1a63-e053-0824d011072a"
128
+ ```
129
+
130
+ **To avoid retyping these every time you open a terminal:**
131
+
132
+ - **macOS / Linux** — append the same two `export` lines to `~/.zshrc` (or `~/.bashrc`), then run
133
+ `source ~/.zshrc`.
134
+ - **Windows** — save them permanently for your user account (run once; then reopen the terminal):
135
+ ```powershell
136
+ [Environment]::SetEnvironmentVariable("ASC_KEY_ID", "ABCD123456", "User")
137
+ [Environment]::SetEnvironmentVariable("ASC_ISSUER_ID", "57246542-96fe-1a63-e053-0824d011072a", "User")
138
+ ```
139
+
140
+ **Test it:**
141
+
142
+ ```sh
143
+ npx vydanne inspect
144
+ ```
145
+
146
+ If you see your app's current state, Apple is wired up. (Errors? See
147
+ [Troubleshooting](#troubleshooting).)
148
+
149
+ ---
150
+
151
+ ## 4. Get your Google Play credentials (once, Android only)
152
+
153
+ Play uses a **service account** — a robot Google account with a JSON key file.
154
+
155
+ 1. In [Play Console](https://play.google.com/console): **Setup → API access**. Link or create a Google
156
+ Cloud project if prompted.
157
+ 2. Click through to **Google Cloud → Service Accounts**, then **Create service account**. Name it
158
+ `vydanne`. You can skip the optional role/user steps.
159
+ 3. Open the new service account → **Keys → Add key → Create new key → JSON**. It downloads immediately —
160
+ this file is a password, keep it out of your project folder and out of git.
161
+ 4. Back in **Play Console → Users and permissions → Invite new user**. Paste the service account's email
162
+ (it looks like `vydanne@your-project.iam.gserviceaccount.com`).
163
+ 5. Give it access to **your app only**, with the **Edit store listing, pricing & distribution**
164
+ permission (and **Release** if you'll also push builds later). Send the invite — it's auto-accepted.
165
+
166
+ Point vydanne at the key — use the **full path**, not a shortcut like `~` (vydanne does not expand it):
167
+
168
+ ```sh
169
+ # macOS / Linux
170
+ export PLAY_JSON_KEY_FILE="$HOME/keys/play-service-account.json"
171
+ ```
172
+ ```powershell
173
+ # Windows PowerShell
174
+ $env:PLAY_JSON_KEY_FILE = "$env:USERPROFILE\keys\play-service-account.json"
175
+ ```
176
+
177
+ **Test it:**
178
+
179
+ ```sh
180
+ npx vydanne inspect --store google
181
+ ```
182
+
183
+ > vydanne is **scoped to the one `packageName`** in your config. Even a service-account key with wider
184
+ > access can't touch another app through vydanne.
185
+
186
+ ---
187
+
188
+ ## 5. Write the config file
189
+
190
+ Create a file named **`vydanne.config.mjs`** in your project folder. Start from the copy that ships
191
+ inside the package:
192
+
193
+ ```sh
194
+ # macOS / Linux
195
+ cp node_modules/vydanne/vydanne.config.example.mjs vydanne.config.mjs
196
+ ```
197
+ ```powershell
198
+ # Windows PowerShell
199
+ Copy-Item node_modules\vydanne\vydanne.config.example.mjs vydanne.config.mjs
200
+ ```
201
+
202
+ A minimal iPhone-only config looks like this — edit the values to match your app:
203
+
204
+ ```js
205
+ export default {
206
+ bundleId: "com.example.myapp", // exactly as registered with Apple
207
+ primaryLocale: "en-US", // your main language — MUST be filled in
208
+ platforms: ["IOS"], // add "MAC_OS" only if you also ship a Mac app
209
+ uiLocales: ["en", "de", "fr"], // the languages you'll publish
210
+ metadataDir: "fastlane/metadata",
211
+ rating: "4+",
212
+ };
213
+ ```
214
+
215
+ **The fields, in plain terms:**
216
+
217
+ | Field | What to put |
218
+ |---|---|
219
+ | `bundleId` | Your app's bundle identifier, exactly as Apple has it. |
220
+ | `primaryLocale` | Your main App Store language. Any language you *don't* translate falls back to this, so it must be complete. |
221
+ | `platforms` | `["IOS"]`, or `["IOS", "MAC_OS"]` if you ship a Mac app too. **Mac is a separate listing** — its text is not shared with iOS. |
222
+ | `uiLocales` | Short language codes you publish in. vydanne converts them to Apple's codes (`de` → `de-DE`) and warns about any language the App Store doesn't offer. |
223
+ | `metadataDir` | Where your listing text lives. `fastlane/metadata` is the default. |
224
+ | `rating` | Age rating, e.g. `"4+"`. |
225
+ | `asc` | Optional `{ keyId, issuerId }` — only if you'd rather not use environment variables. |
226
+ | `privacy` | What data actually leaves the device, e.g. `{ collected: ["CRASH_DATA"], tracking: false }`. |
227
+ | `iaps` | Your in-app purchases (name ≤30 chars, description ≤45). |
228
+ | `previews` | App Preview videos — see step 7. |
229
+ | `export` | Export-compliance details for the PDF: `{ encryption: "standard", appName, version, teamId }`. |
230
+ | `google` | The Play block — `{ packageName, metadataDir, defaultLocale }`. Omit it if you're iOS-only. |
231
+
232
+ Check your languages resolved correctly:
233
+
234
+ ```sh
235
+ npx vydanne locales
236
+ ```
237
+
238
+ Anything listed as *unsupported* has no App Store language and will fall back to your primary locale —
239
+ **don't** create a folder for it.
240
+
241
+ ---
242
+
243
+ ## 6. Put your text and images where vydanne looks
244
+
245
+ This is the part that trips people up. vydanne reads **plain `.txt` files in named folders**. One folder
246
+ per language, named with **Apple's** code (from `vydanne locales`).
247
+
248
+ ```
249
+ your-app/
250
+ ├─ vydanne.config.mjs
251
+ ├─ fastlane/
252
+ │ ├─ metadata/
253
+ │ │ ├─ en-US/ ← Apple's locale code, not "en"
254
+ │ │ │ ├─ name.txt (≤30) your app's store name
255
+ │ │ │ ├─ subtitle.txt (≤30) one benefit line
256
+ │ │ │ ├─ description.txt (≤4000)
257
+ │ │ │ ├─ keywords.txt (≤100) comma-separated, NO spaces
258
+ │ │ │ ├─ promotional_text.txt (≤170) editable anytime, no review
259
+ │ │ │ ├─ release_notes.txt what's new in this version
260
+ │ │ │ ├─ marketing_url.txt (optional)
261
+ │ │ │ └─ support_url.txt (optional)
262
+ │ │ ├─ de-DE/ …same files…
263
+ │ │ └─ review_information/ ← App Review contact. KEEP OUT OF GIT.
264
+ │ │ ├─ first_name.txt
265
+ │ │ ├─ last_name.txt
266
+ │ │ ├─ phone_number.txt
267
+ │ │ ├─ email_address.txt
268
+ │ │ └─ notes.txt how a reviewer tests your app
269
+ │ ├─ screenshots/ ← iPhone / iPad / Watch
270
+ │ │ └─ en-US/
271
+ │ │ ├─ iphone69_01.png
272
+ │ │ ├─ iphone69_02.png
273
+ │ │ └─ ipad13_01.png
274
+ │ └─ screenshots-macos/ ← Mac only
275
+ │ └─ en-US/
276
+ │ └─ macos_01.png
277
+ ```
278
+
279
+ **Screenshot file names matter.** The part **before the first underscore** tells vydanne which device the
280
+ image is for. Anything after it is yours — but files upload in alphabetical order, so number them
281
+ `_01`, `_02`, …
282
+
283
+ | Prefix | Device slot |
284
+ |---|---|
285
+ | `iphone69_` | iPhone 6.9″ |
286
+ | `iphone65_` | iPhone 6.5″ |
287
+ | `ipad13_` | iPad Pro 12.9″ |
288
+ | `watch_` | Apple Watch Ultra |
289
+ | `macos_` | Mac (in `screenshots-macos/`) |
290
+
291
+ A file whose prefix isn't in that table is **silently skipped** — if a screenshot doesn't appear, check
292
+ the name first.
293
+
294
+ > **Screenshots must be RGB PNGs with no transparency.** Simulator captures often have an alpha channel
295
+ > and Apple rejects those. `npx vydanne iap` with `VYDANNE_FLATTEN=path/to.png` converts one for you.
296
+
297
+ **Google Play** uses its **own** language codes (`de-DE`, `zh-CN`, `iw-IL`, `ar` — *not* Apple's
298
+ `zh-Hans`/`he`), and only three text files:
299
+
300
+ ```
301
+ fastlane/metadata/android/
302
+ └─ en-US/
303
+ ├─ title.txt (≤30)
304
+ ├─ short_description.txt (≤80)
305
+ └─ full_description.txt (≤4000)
306
+ ```
307
+
308
+ Play images are read from **fixed paths** (they're where [zdymak](https://www.npmjs.com/package/zdymak)
309
+ writes them). Each is uploaded only if the file exists, so a missing set never wipes what's live:
310
+
311
+ | Play asset | Path vydanne reads |
312
+ |---|---|
313
+ | Store icon (512×512) | `brand/icons/play/icon-512.png` |
314
+ | Feature graphic (1024×500) | `marketing/out/play-feature-graphic.png` |
315
+ | Phone screenshots | `marketing/out/play-phone-plain/` |
316
+ | 7″ tablet screenshots | `marketing/out/play-tablet7-plain/` |
317
+ | 10″ tablet screenshots | `marketing/out/play-tablet-plain/` |
318
+
319
+ *(These paths are not configurable yet — create the folders at those locations, or symlink them.)*
320
+
321
+ ---
322
+
323
+ ## 7. Optional extras
324
+
325
+ **App Preview videos** — add them to your config, then `npx vydanne previews`:
326
+
327
+ ```js
328
+ previews: [
329
+ { platform: "IOS", type: "IPHONE_67", file: "marketing/out/preview.mp4",
330
+ poster: "00:00:05:00", locales: ["en-US"] },
331
+ ],
332
+ ```
333
+
334
+ `poster` is the still frame shown before playback, as `HH:MM:SS:FF`. A locale that already has a preview
335
+ is skipped; set `VYDANNE_REPLACE=1` to swap in a new one.
336
+
337
+ **In-app purchases** — list them under `iaps` and run `npx vydanne iap` to validate the character limits
338
+ before you paste them into App Store Connect.
339
+
340
+ **Export compliance** — `npx vydanne compliance` writes the US self-classification PDF to
341
+ `export-compliance/`. Attach it in App Store Connect. If you set `france: true`, remember France needs a
342
+ separate ANSSI declaration.
343
+
344
+ ---
345
+
346
+ ## 8. Push it to the store
347
+
348
+ Always look before you leap:
349
+
350
+ ```sh
351
+ npx vydanne preflight # is anything missing or over a character limit?
352
+ npx vydanne diff # exactly what would change vs what's live now
353
+ ```
354
+
355
+ `preflight` must be **green**. Then:
356
+
357
+ ```sh
358
+ npx vydanne fill # text + screenshots (iOS and Mac both)
359
+ npx vydanne previews # App Preview videos
360
+ npx vydanne age-rating
361
+ npx vydanne review-contact
362
+ npx vydanne accessibility # saved as a draft; publishes only once your app is live
363
+ npx vydanne privacy # prints the answers to type into Apple's web UI
364
+ ```
365
+
366
+ **For Google Play**, `fill` is a **dry run by default** — it validates and throws the change away so a
367
+ half-finished local folder can't overwrite your live listing:
368
+
369
+ ```sh
370
+ # macOS / Linux
371
+ npx vydanne fill --store google # dry run: shows what would happen
372
+ VYDANNE_COMMIT=1 npx vydanne fill --store google # actually commit it
373
+ ```
374
+ ```powershell
375
+ # Windows PowerShell — set the variable first; the `VAR=1 command` form does NOT work here
376
+ npx vydanne fill --store google
377
+ $env:VYDANNE_COMMIT = "1"; npx vydanne fill --store google
378
+ Remove-Item Env:\VYDANNE_COMMIT # clear it so later runs stay dry
379
+ ```
380
+
381
+ Finally, run `npx vydanne diff` once more and eyeball one screenshot per platform in the web UI.
382
+
383
+ ---
384
+
385
+ ## 9. Finish in the browser (the parts no API can do)
386
+
387
+ 1. **App Privacy** (Apple) — Apple's privacy API isn't reachable with an API key, so `vydanne privacy`
388
+ prints the exact answers; you paste them into App Store Connect by hand.
389
+ 2. **Upload the binary** — Xcode, Transporter, or your CI. vydanne never touches your build.
390
+ 3. **Play Data Safety + content rating** — questionnaires in the Play Console.
391
+ 4. **Submit for Review** — yours to press.
392
+
393
+ ---
394
+
395
+ ## Troubleshooting
396
+
397
+ | What you see | What it means | Fix |
398
+ |---|---|---|
399
+ | `config not found at …` | You're in the wrong folder, or the file is misnamed. | `cd` to your project root; the file must be `vydanne.config.mjs`. |
400
+ | `ASC key not found at …` | The `.p8` isn't where vydanne looks. | The error prints the exact path it wants — move the file there. List it with `ls ~/.appstoreconnect/private_keys/` (macOS/Linux) or `dir "$env:USERPROFILE\.appstoreconnect\private_keys"` (Windows). |
401
+ | `app '…' not found for this ASC key` | The bundle ID is wrong, or the key's team doesn't own the app. | Check `bundleId` matches App Store Connect exactly. |
402
+ | `401` / `403` from Apple | Key lacks permission, or the IDs are swapped. | Key access must be **App Manager**+. Confirm `ASC_KEY_ID` vs `ASC_ISSUER_ID` aren't reversed. |
403
+ | `no editable version` | There's no version in an editable state. | In App Store Connect, create the next version (e.g. "1.0 Prepare for Submission"). |
404
+ | A locale was ignored | The folder name isn't an Apple code. | Run `npx vydanne locales` and rename the folder to the code shown. |
405
+ | Screenshots didn't upload | Wrong filename prefix, or the slot already has images. | Use the prefix table above. vydanne never overwrites a set that already has screenshots. |
406
+ | Apple rejects a screenshot | It has an alpha channel. | Flatten to RGB — macOS/Linux: `VYDANNE_FLATTEN=shot.png npx vydanne iap` · Windows: `$env:VYDANNE_FLATTEN="shot.png"; npx vydanne iap`. |
407
+ | `VYDANNE_… =1` "does nothing" on Windows | PowerShell doesn't support the Unix `VAR=1 command` form. | Set it first: `$env:VYDANNE_COMMIT = "1"`, then run the command. |
408
+ | `no google block in config` | Play isn't configured. | Add the `google` block and set `PLAY_JSON_KEY_FILE`. |
409
+ | Play changes didn't stick | `fill --store google` is dry by default. | Re-run with `VYDANNE_COMMIT=1`. |
410
+ | `accessibility` returns 409 | Labels can't publish before the app is live. | Leave it as a draft; publish after launch with `VYDANNE_A11Y_PUBLISH=1`. |
411
+
412
+ ---
413
+
414
+ ## Reference: environment variables
415
+
416
+ | Variable | Purpose |
417
+ |---|---|
418
+ | `ASC_KEY_ID`, `ASC_ISSUER_ID` | Apple API key identifiers (**required**). |
419
+ | `PLAY_JSON_KEY_FILE` | Path to the Play service-account JSON (**required for Play**). |
420
+ | `VYDANNE_CONFIG` | Use a different config file (same as `--config`). |
421
+ | `VYDANNE_SKIP_METADATA` / `VYDANNE_SKIP_SCREENSHOTS` | `fill`: push only one half. |
422
+ | `VYDANNE_COMMIT=1` | `fill --store google`: actually commit (otherwise dry). |
423
+ | `VYDANNE_REPLACE=1` | `previews`: delete the existing preview and upload a new one. |
424
+ | `VYDANNE_FLATTEN=<png>` | `iap`: convert an image to RGB (removes transparency). |
425
+ | `VYDANNE_A11Y_PUBLISH=1` | `accessibility`: publish the labels (only once the app is live). |
426
+
427
+ Set them with `export NAME=value` on macOS/Linux, or `$env:NAME = "value"` in Windows PowerShell.
428
+
429
+ Secrets — the `.p8`, the Play JSON, and `fastlane/metadata/review_information/` — should **never** be
430
+ committed to git. Add them to your `.gitignore`.
431
+
432
+ ---
433
+
434
+ Next: the [README](README.md) for the full command list and the store gotchas vydanne encodes.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vydanne contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,212 @@
1
+ # vydanne
2
+
3
+ **Fill in your app's App Store and Google Play listing — in every language — from files on your computer.**
4
+
5
+ Publishing an app means typing the same things into a web form over and over: a name, a subtitle, a
6
+ description, keywords, screenshots… once per language, twice per store, again for the Mac version. Miss a
7
+ box and the store quietly shows a blank page to half the world. Get a folder name wrong and the whole
8
+ upload fails.
9
+
10
+ vydanne does that typing for you, then **checks your work before Apple or Google does**.
11
+
12
+ > *выданне* (Belarusian) — "publishing".
13
+
14
+ <br>
15
+
16
+ ## Is this for me?
17
+
18
+ **Yes, if** you have an app and you're tired of the store's web forms — especially in more than one
19
+ language. You do not need to be a programmer: you write text files, and run three commands.
20
+
21
+ **Probably not, if** you publish one app in one language and never change it. The web form is fine.
22
+
23
+ **You'll still need** an Apple Developer account (and/or a Play Console account) and someone to build the
24
+ actual app. vydanne handles the *listing*, not the software.
25
+
26
+ <br>
27
+
28
+ ## The two halves of a release
29
+
30
+ vydanne has a sibling — **[zdymak](https://www.npmjs.com/package/zdymak)**. They split the job cleanly:
31
+
32
+ | | [zdymak](https://github.com/Lonli-Lokli/zdymak) 📸 | **vydanne** 📝 |
33
+ |---|---|---|
34
+ | Makes | The **pictures** — screenshots, App Preview videos, the Play feature graphic | The **words and the paperwork** — listing text, ratings, contacts, privacy, compliance |
35
+ | Ends with | Image and video files on disk | A listing filled in and verified, ready for a human to submit |
36
+
37
+ Use them together: zdymak produces the assets, vydanne uploads them alongside your text. Use vydanne
38
+ alone if you already have your screenshots.
39
+
40
+ <br>
41
+
42
+ ## Install
43
+
44
+ You need **Node.js 20.9 or newer** ([nodejs.org](https://nodejs.org) — the LTS build). Then, in your app's
45
+ folder:
46
+
47
+ ```sh
48
+ npm i -D vydanne
49
+ npx vydanne version
50
+ ```
51
+
52
+ Works on **macOS, Linux and Windows**. The examples below use macOS/Linux shell syntax; Windows
53
+ PowerShell equivalents are in [GETTING_STARTED.md](GETTING_STARTED.md) (`$env:NAME = "value"` instead of
54
+ `export`, and set variables on their own line — PowerShell has no `VAR=1 command` form).
55
+
56
+ <br>
57
+
58
+ ## Quick start
59
+
60
+ **→ First time? Follow [GETTING_STARTED.md](GETTING_STARTED.md).** It walks through every click:
61
+ getting your Apple API key, setting up a Play service account, where each file goes, and what to do when
62
+ something errors. This section is the short version for people who've done it before.
63
+
64
+ **1. Get a key from Apple.** App Store Connect → Users and Access → Integrations → App Store Connect API.
65
+ Download the `.p8` (once only!), then:
66
+
67
+ ```sh
68
+ mkdir -p ~/.appstoreconnect/private_keys
69
+ mv ~/Downloads/AuthKey_*.p8 ~/.appstoreconnect/private_keys/
70
+ export ASC_KEY_ID=… ASC_ISSUER_ID=…
71
+ ```
72
+ ```powershell
73
+ # Windows PowerShell
74
+ New-Item -ItemType Directory -Force "$env:USERPROFILE\.appstoreconnect\private_keys"
75
+ Move-Item "$env:USERPROFILE\Downloads\AuthKey_*.p8" "$env:USERPROFILE\.appstoreconnect\private_keys\"
76
+ $env:ASC_KEY_ID = "…"; $env:ASC_ISSUER_ID = "…"
77
+ ```
78
+
79
+ **2. Describe your app** in a `vydanne.config.mjs` file next to your project:
80
+
81
+ ```js
82
+ export default {
83
+ bundleId: "com.example.myapp",
84
+ primaryLocale: "en-US",
85
+ platforms: ["IOS"],
86
+ uiLocales: ["en", "de", "fr"],
87
+ metadataDir: "fastlane/metadata",
88
+ rating: "4+",
89
+ };
90
+ ```
91
+
92
+ **3. Write your listing** as plain text files, one folder per language:
93
+
94
+ ```
95
+ fastlane/metadata/en-US/name.txt ← "My App"
96
+ fastlane/metadata/en-US/subtitle.txt ← "The one-line pitch"
97
+ fastlane/metadata/en-US/description.txt
98
+ fastlane/metadata/en-US/keywords.txt
99
+ ```
100
+
101
+ **4. Check, then push:**
102
+
103
+ ```sh
104
+ npx vydanne preflight # anything missing or too long?
105
+ npx vydanne diff # what exactly would change?
106
+ npx vydanne fill # do it
107
+ ```
108
+
109
+ Run vydanne **from your project folder** — it finds everything relative to where you are.
110
+
111
+ <br>
112
+
113
+ ## What each command does
114
+
115
+ | Command | In plain English |
116
+ |---|---|
117
+ | `preflight` | **Run this first.** Checks the listing is complete and nothing is over a character limit. Green means submittable. |
118
+ | `diff` | Shows exactly what's different between your files and what's live. Nothing is changed — a safe preview. |
119
+ | `fill` | Uploads your listing text and screenshots. Handles iPhone, iPad and Mac. |
120
+ | `previews` | Uploads App Preview videos. |
121
+ | `inspect` | Shows the app's current state in the store. Read-only. |
122
+ | `locales` | Lists your languages and Apple's code for each — and warns about any language the App Store doesn't offer. |
123
+ | `age-rating` | Sets the age rating. |
124
+ | `review-contact` | Fills in the App Review contact details (who Apple calls if there's a problem). |
125
+ | `accessibility` | Saves Accessibility Nutrition Labels. Stays a draft until your app is live. |
126
+ | `privacy` | Prints the privacy answers to paste into Apple's website (Apple's privacy section has no API). |
127
+ | `iap` | Checks your in-app purchase text fits, and can strip transparency from an image. |
128
+ | `compliance` | Generates the US encryption self-classification PDF that Apple asks for. |
129
+ | `version` | Prints the version of vydanne. |
130
+
131
+ For **Google Play**, add `--store google` to `inspect`, `diff`, `preflight`, or `fill`.
132
+
133
+ <br>
134
+
135
+ ## Google Play
136
+
137
+ Add a `google` block to your config and point `PLAY_JSON_KEY_FILE` at a service-account key
138
+ ([how to get one](GETTING_STARTED.md#4-get-your-google-play-credentials-once-android-only)):
139
+
140
+ ```sh
141
+ npx vydanne preflight --store google
142
+ npx vydanne fill --store google # dry run — shows what would change
143
+ VYDANNE_COMMIT=1 npx vydanne fill --store google # actually do it
144
+ # Windows PowerShell: $env:VYDANNE_COMMIT = "1"; npx vydanne fill --store google
145
+ ```
146
+
147
+ **Play is dry by default on purpose.** Nothing goes live until you add `VYDANNE_COMMIT=1`, so a
148
+ half-finished folder can never overwrite a good listing. Play also uses its **own** language codes
149
+ (`zh-CN`, `iw-IL`) which are *not* Apple's — `vydanne locales` and the
150
+ [layout guide](GETTING_STARTED.md#6-put-your-text-and-images-where-vydanne-looks) keep them straight.
151
+
152
+ <br>
153
+
154
+ ## Your config, field by field
155
+
156
+ `bundleId` · `primaryLocale` (your main language — everything else falls back to it, so it must be
157
+ complete) · `asc` (Apple key IDs, if you'd rather not use environment variables) · `platforms` (iOS and
158
+ macOS are **separate listings**) · `uiLocales` (your languages, auto-translated to Apple's codes) ·
159
+ `metadataDir` (where your text lives) · `rating` · `privacy` (what data actually leaves the device) ·
160
+ `iaps` (in-app purchases) · `previews` (App Preview videos) · `export` (encryption compliance details) ·
161
+ `google` (the Play block).
162
+
163
+ A commented example ships with the package: **[`vydanne.config.example.mjs`](vydanne.config.example.mjs)**.
164
+
165
+ <br>
166
+
167
+ ## The mistakes it saves you from
168
+
169
+ Every one of these has cost somebody a rejected build or a blank store page. vydanne handles them so you
170
+ don't have to learn them the hard way.
171
+
172
+ | The trap | What vydanne does |
173
+ |---|---|
174
+ | A wrongly-named language folder aborts the **entire** upload | Maps your codes to Apple's and flags any language the store doesn't support |
175
+ | Your main language is left empty → most of the world sees a blank page | `preflight` refuses to pass |
176
+ | macOS is a **separate** listing; its text is not shared with iOS | Fills each platform independently |
177
+ | Apple's list endpoints return blank text, so tools "see" an empty listing | Reads each language individually |
178
+ | Screenshots with transparency get rejected | Converts them to RGB |
179
+ | Once a version is *Ready for Review*, most tools can no longer edit it | Uses a method that still works |
180
+ | Character limits (30 / 30 / 100 / 170; purchases 30 / 45) | Checked before upload, not after rejection |
181
+ | Apple's privacy section can't be reached by any API key | Prints the exact answers to paste in |
182
+ | Accessibility labels can't publish before launch | Saved as a draft automatically |
183
+ | In-app purchases need **two** different images, easily confused | Labels both slots |
184
+ | Play's language codes differ from Apple's | Documented and validated separately |
185
+ | A missing local screenshot folder deleting your live ones | Only uploads what exists — never deletes by omission |
186
+
187
+ <br>
188
+
189
+ ## What vydanne will never do
190
+
191
+ - **It never submits your app.** A human attaches the build and presses Submit. That's on purpose.
192
+ - It doesn't build, sign, or upload your app binary.
193
+ - It doesn't create the app record — make that in App Store Connect / Play Console first.
194
+
195
+ <br>
196
+
197
+ ## For developers & AI agents
198
+
199
+ The package ships **[SKILL.md](SKILL.md)** — a precise, agent-facing operating guide (exact file layout,
200
+ the store gotchas, the ASO rules) — plus TypeScript definitions
201
+ ([`types/index.d.ts`](types/index.d.ts), type `import('vydanne').VydanneConfig`).
202
+
203
+ Two guards keep the docs honest: `npm run check:docs` (every config field and command is documented) and
204
+ `npm run check:types` (every one is typed). Both run before publish, so the docs can't drift from the code.
205
+
206
+ Technically: native Node, no fastlane, Ruby, or Python. ES256 JWT via `node:crypto`, the App Store Connect
207
+ REST API over `fetch`, chunked uploads by hand, PDFs via `pdfkit`, image flattening via `sharp`. Android
208
+ goes through the Google Play Developer **Edits** API.
209
+
210
+ Releasing a new version: [RELEASING.md](RELEASING.md).
211
+
212
+ MIT.