storebase-cli 1.1.0 → 1.3.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/README.md +58 -1
- package/bin/storebase-keystore.js +89 -0
- package/bin/storebase-publish.js +21 -46
- package/bin/storebase-skill.js +63 -0
- package/lib/publisher.js +24 -29
- package/lib/secure-prompt.js +60 -0
- package/lib/signing-profiles.js +83 -0
- package/lib/signing-vault.js +372 -0
- package/package.json +11 -5
- package/skills/storebase/SKILL.md +88 -0
- package/skills/storebase/references/cli-workflows.md +171 -0
- package/skills/storebase/references/runtime-and-android.md +58 -0
- package/skills/storebase/references/updates-and-development.md +75 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# CLI workflows
|
|
2
|
+
|
|
3
|
+
## Install and inspect
|
|
4
|
+
|
|
5
|
+
Use Node.js 18+ for the published CLI. Use Java 21+ `keytool` and Android SDK Build Tools `apksigner` for signing verification/import. Node 22.12+ or another version supported by Vite 8 is needed for the frontend source build; do not confuse that with the CLI's Node 18 floor.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install --global storebase-cli
|
|
9
|
+
storebase-publish --help
|
|
10
|
+
storebase-keystore --help
|
|
11
|
+
storebase-telegram --help
|
|
12
|
+
storebase-skill --help
|
|
13
|
+
storebase-skill path
|
|
14
|
+
storebase-skill install --dir ./agent-skills
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`path` prints the installed `SKILL.md` path. `install --dir` treats the argument as a skills **root**, creates its `storebase` child, and refuses an existing destination. Choose the real root supported by the target agent; the command does not edit agent settings or activate skills. To update an existing copy, review/back it up and remove or move it explicitly before installing again. Global npm upgrades update the bundled skill, not separate copies.
|
|
18
|
+
|
|
19
|
+
For this source checkout use `npm ci` inside `cli/`, `npm test`, and optionally `npm install --global ./cli` from the repository root. Use quoted paths for spaces. Command examples below use POSIX line continuations; in PowerShell put each command on one line (or use PowerShell's backtick continuation). Profile prompts require a real interactive terminal.
|
|
20
|
+
|
|
21
|
+
## Choose configuration and authority
|
|
22
|
+
|
|
23
|
+
| Operation | Gateway default | Credentials on CLI side |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `list`, `metadata`, `download` | Encrypted reader bootstrap | No publisher token |
|
|
26
|
+
| `storebase-publish`, `pin` | Token-protected publisher bootstrap | Publisher token via hidden prompt or runtime environment |
|
|
27
|
+
| `--telegram-config local` reads | No gateway | API ID/hash, personal read session, channel |
|
|
28
|
+
| `--telegram-config local` writes | No gateway | API ID/hash, bot session (or initial bot token), personal read session, channel |
|
|
29
|
+
| `--storage local` publish | No Telegram storage | Signing input; writes local catalog/assets |
|
|
30
|
+
|
|
31
|
+
Use `STOREBASE_GATEWAY_URL` to override the default `https://storebase.wasmer.app`. Keep `STOREBASE_GATEWAY_PUBLISH_TOKEN` identical to the gateway secret. It must be a high-entropy value accepted by the gateway; use at least 32 URL-safe characters. Prefer a secret manager injecting environment values. Interactive write commands request a missing key without echo; non-interactive writes require it in the environment. Never put it in CLI arguments, output, source, or npm configuration.
|
|
32
|
+
|
|
33
|
+
For direct Telegram mode supply these **runtime environment** values:
|
|
34
|
+
|
|
35
|
+
- `STOREBASE_TELEGRAM_API_ID`: positive numeric Telegram app ID.
|
|
36
|
+
- `STOREBASE_TELEGRAM_API_HASH`: Telegram app hash.
|
|
37
|
+
- `STOREBASE_TELEGRAM_READ_SESSION`: authorized personal-user MTProto StringSession with channel read access; a bot cannot read history.
|
|
38
|
+
- `STOREBASE_TELEGRAM_CHANNEL`: broadcast channel username or ID.
|
|
39
|
+
- For writes, `STOREBASE_TELEGRAM_SESSION`: authorized admin-bot MTProto StringSession; alternatively `STOREBASE_TELEGRAM_BOT_TOKEN` can authorize a bot initially in local mode.
|
|
40
|
+
|
|
41
|
+
The bot must be channel administrator with posting permission. Reader and bot must resolve the same broadcast channel. A gateway deployment needs pre-provisioned bot and reader sessions; there is no `storebase login` or session-export CLI command. Provision them privately through trusted Telegram tooling, not repository files. The encrypted publisher envelope does not include the bot token or publisher token. The reader envelope excludes the bot session.
|
|
42
|
+
|
|
43
|
+
`dotenv` loads a current-directory `.env` for legacy/runtime configuration; do not print or commit it. Never save profile passphrases/signing passwords in it. Separate shell sessions are safer than switching production and local credentials in the same shell.
|
|
44
|
+
|
|
45
|
+
## Import and reuse a signing profile
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
storebase-keystore import release --file "/secure/path/release.jks" --alias release
|
|
49
|
+
storebase-keystore list
|
|
50
|
+
storebase-keystore location
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Import requests: a new vault passphrase (at least 12 characters, confirmed) or existing vault passphrase, keystore password, and private-key password. Enter at the private-key prompt to reuse the store password. Specify `--alias` when multiple private keys exist. Import validates keystore and private-key access with Java and copies the keystore into the encrypted vault; the original path need not remain available. Never upload the keystore.
|
|
54
|
+
|
|
55
|
+
Use a profile explicitly with `--signing-profile release`. Profiles are not automatically associated with an app/tag and there is no automatic default. Profile publishing verifies the APK's public signer certificate without extracting the stored private key. It cannot be combined with `--keystore` or `--alias`.
|
|
56
|
+
|
|
57
|
+
All profile operations except `location` need hidden interactive input. Do not pipe passphrases, invent password flags, set environment passwords for profile operations, or promise unattended profile publishing. For an explicitly approved non-interactive one-off workflow, the legacy `--keystore` path supports `STOREBASE_KEYSTORE_PASSWORD` at runtime; it still never signs an APK.
|
|
58
|
+
|
|
59
|
+
### Replace, rotate, rekey, remove
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
storebase-keystore import release --file "/secure/path/replacement.jks" --alias release --replace
|
|
63
|
+
storebase-keystore rekey
|
|
64
|
+
storebase-keystore remove release
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`--replace` requires an existing profile and typed `REPLACE release`; failed validation leaves the existing entry intact. Use replacement to update stored passwords or validated signing material. `rekey` unlocks with the old vault passphrase and asks for a new confirmed passphrase; it re-encrypts every profile without changing the keystore passwords or signing identity. `remove` requires typed `REMOVE release` and deletes only the current vault entry, not original files or backups.
|
|
68
|
+
|
|
69
|
+
Do not conflate these operations with Android key rotation: no signing lineage, APK re-signing, or Play App Signing migration is generated. A genuinely different certificate may prevent upgrades for existing users. Keep old key backups before replacing anything.
|
|
70
|
+
|
|
71
|
+
### Vault protection and recovery
|
|
72
|
+
|
|
73
|
+
Use `location` rather than guessing the path. Defaults:
|
|
74
|
+
|
|
75
|
+
- Linux: `~/.local/share/storebase-cli/signing-vault.json`.
|
|
76
|
+
- macOS: `~/Library/Application Support/storebase-cli/signing-vault.json`.
|
|
77
|
+
- Windows: `~/AppData/Local/storebase-cli/signing-vault.json`.
|
|
78
|
+
|
|
79
|
+
The vault lives outside the project and npm install directory, uses AES-256-GCM and scrypt (N=32768, r=8, p=1), and gets a fresh salt/nonce on write. Its contents include keystore bytes, passwords, alias and certificate. The master passphrase is never saved, and there is no recovery service or OS-keychain unlock. Keep encrypted backups and the passphrase separately. Writes are atomic/locked; POSIX requires private ownership/permissions (directory 0700, files 0600), rejecting unsafe or symlink paths. Restrict Windows user-data ACLs yourself.
|
|
80
|
+
|
|
81
|
+
Import uses a private temporary keystore copy for Java, removed and overwritten best-effort in cleanup. Java receives passwords in its child environment, not arguments/files. Abrupt termination may leave `storebase-signing-import-*` temporary directories; remove orphans securely. Encryption does not protect against compromised user processes, privileged memory inspection, swap, or all JS string copies. Removal/rekey do not erase old backups, journals, or snapshots.
|
|
82
|
+
|
|
83
|
+
## Publish an ordinary Android app
|
|
84
|
+
|
|
85
|
+
First obtain approval for this exact release. Build and sign it with the application's own build system; StoreBase does not provide a signing command.
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
storebase-publish --name "Example App" --avatar ./icon.png --version 1.0.0 --apk ./app-release.apk --category Productivity --description "A useful offline tool." --signing-profile release
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
One-off alternative: replace `--signing-profile release` with `--keystore /secure/path/release.jks --alias release`. Enter the store password at its hidden prompt (or inject the legacy runtime password variable for an authorized unattended run).
|
|
92
|
+
|
|
93
|
+
Input rules:
|
|
94
|
+
|
|
95
|
+
- Name: nonempty, at most 100 characters. The normalized lowercase name creates the catalog app ID (`Example App` → `example-app`), not the Android package name. Preserve it across releases; conflicting names with the same slug are refused.
|
|
96
|
+
- Version: 1–64 characters, starting with a letter/digit; subsequent letters/digits, `.`, `+`, `_`, `-` are allowed. It need not be semantic versioning.
|
|
97
|
+
- Icon (`--avatar`): actual PNG, JPEG, or WebP bytes, not just a renamed extension.
|
|
98
|
+
- APK: nonempty `.apk` with APK/ZIP header and valid signature accepted by `apksigner`.
|
|
99
|
+
- Description: nonempty, at most 1,000 characters; total manifest also must fit Telegram's 4,096-character message limit.
|
|
100
|
+
- Category: case-insensitive match to Education, Social, Productivity, Communication, Entertainment, Games, Business, Shopping, Finance, Utilities, Health & Fitness, Travel & Navigation, or AI & Machine Learning. Quote multiword categories.
|
|
101
|
+
|
|
102
|
+
Missing required app details prompt interactively; non-interactive runs must supply all. `keytool` inspects the selected private-key certificate and `apksigner verify --verbose --print-certs` must find a matching APK signer. A mismatch fails without catalog publication. This proves certificate matching, not ownership approval, malware safety, or the app's full runtime behavior.
|
|
103
|
+
|
|
104
|
+
### What publishing writes
|
|
105
|
+
|
|
106
|
+
The CLI uploads APK, icon, optional delta, and finally the `STOREBASE_MANIFEST_V1` JSON text message. The manifest is the release visibility boundary: interrupted uploads may leave orphan documents but are not listed as releases without a valid manifest. Store app metadata, signing-certificate SHA-256, timestamps, artifact message IDs, sizes and SHA-256 hashes. Never upload a keystore/password.
|
|
107
|
+
|
|
108
|
+
An identical app/version, metadata, signer and artifact content returns an idempotent existing release. Changed content under that version is rejected; publish a new version. Older manifests/artifacts remain. Newest means publish timestamp (message ID breaks ties), not highest semantic version. Inspect before retrying an ambiguous failure.
|
|
109
|
+
|
|
110
|
+
### StoreBase self-update release
|
|
111
|
+
|
|
112
|
+
Only the `storebase` app ID supports updater metadata and `.sbd` deltas. Supply the real APK version code, higher than every previously published StoreBase release. Optional minimum code must be nonnegative and no higher than target code. The code is supplied metadata; separately confirm it matches the APK/build.
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
storebase-publish --name StoreBase --avatar ./storebase-icon.png --version 2.0.0 --apk /secure/releases/StoreBase-release.apk --android-version-code 20 --category Utilities --description "Approved StoreBase update." --signing-profile storebase-release
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Optionally append `--minimum-android-version-code 10` and/or `--delta /secure/releases/base-to-target.sbd --delta-base-version-code 19`. A delta requires a lower positive base code, correct gzip `.sbd` format, and the exact signed target APK. Follow the updates reference; publishing does not validate every native patch operation or infer the actual APK version code. Do not use these flags for ordinary third-party apps.
|
|
119
|
+
|
|
120
|
+
## List, inspect, pin and download
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
storebase-telegram list
|
|
124
|
+
storebase-telegram metadata example-app
|
|
125
|
+
storebase-telegram metadata example-app --version 1.0.0
|
|
126
|
+
storebase-telegram download example-app --kind apk --out ./downloads
|
|
127
|
+
storebase-telegram download example-app --version 1.0.0 --kind all --out ./downloads
|
|
128
|
+
storebase-telegram pin example-app 1.0.0
|
|
129
|
+
storebase-telegram metadata example-app
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`list` prints JSON app IDs/names/categories, all versions, default version and whether pinned. `metadata` prints the selected manifest/message ID and current default. Reads use reader credentials only. `pin` requires write authority and an already existing exact release version. It appends a separate `STOREBASE_DEFAULT_VERSION_V1` record, never edits a manifest, and is idempotent for an already pinned target. There is no unpin/delete command. To choose a newer version later, pin it explicitly.
|
|
133
|
+
|
|
134
|
+
Omitting `--version` selects the latest pin, else the newest published release. Publishing a new release does not override an existing pin. A dangling pin to a missing release is an error. CLI pinning is a catalog pointer, not a Telegram UI pinned message, Android downgrade permission, or deletion of other releases.
|
|
135
|
+
|
|
136
|
+
Download kinds are `apk`, `avatar`, `delta`, `all` (default). Output defaults to `./storebase-downloads`. `all` includes an optional delta only when present; requesting a missing delta errors. Content-addressed filenames include app ID/version/kind/hash. Size and SHA-256 mismatches fail and remove the invalid output. These catalog hashes are integrity checks against the channel manifest, not independent signatures from a trusted authority.
|
|
137
|
+
|
|
138
|
+
For a local runtime Telegram environment append `--telegram-config local` to any catalog command or publisher command. Do not pass gateway credentials to a command that does not need them.
|
|
139
|
+
|
|
140
|
+
## Legacy local files mode
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
storebase-publish --storage local --name "Example App" --avatar ./icon.png --version 1.0.0 --apk ./app-release.apk --category Productivity --description "Local test release." --signing-profile release --catalog /private/output/catalog.json --assets-dir /private/output/assets
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Local mode performs the same APK certificate matching but writes JSON/files, not Telegram. Defaults are `storebase-app-list.json` and `storebase-app-assets` under the working directory. The catalog keeps one current record per app ID; content-addressed older artifact files may remain. This is **not** Telegram's immutable version-history/pin model, and catalog commands do not read this JSON. StoreBase Android version metadata/deltas are rejected in local storage mode. Keep generated APK/assets/catalog output outside Git and npm.
|
|
147
|
+
|
|
148
|
+
## Complete option checklist
|
|
149
|
+
|
|
150
|
+
- `storebase-publish`: `--name`, `--avatar`, `--version`, `--apk`, `--category`, `--description`, `--signing-profile` OR `--keystore`/`--alias`, `--storage telegram|local`, `--telegram-config gateway|local`, `--catalog`, `--assets-dir`, `--android-version-code`, `--minimum-android-version-code`, `--delta`, `--delta-base-version-code`, `--help`/`-h`.
|
|
151
|
+
- `storebase-keystore`: `import <profile> --file <keystore> [--alias <alias>] [--replace]`, `list`, `location`, `rekey`, `remove <profile>`, `--help`/`-h`. No password flags.
|
|
152
|
+
- `storebase-telegram`: `list`; `metadata <app-id> [--version <version>]`; `download <app-id> [--version <version>] [--kind apk|avatar|delta|all] [--out <directory>]`; `pin <app-id> <version>`. All accept `--telegram-config gateway|local`; top-level `--help`/`-h` shows usage.
|
|
153
|
+
- `storebase-skill`: `path`, `install --dir <skills-root>`, `--help`/`-h`.
|
|
154
|
+
|
|
155
|
+
## Troubleshoot in order
|
|
156
|
+
|
|
157
|
+
| Symptom | Action |
|
|
158
|
+
| --- | --- |
|
|
159
|
+
| Missing options or prompts unavailable | Use a TTY for profile operations; provide all nonsecret app flags for unattended one-off runs. |
|
|
160
|
+
| Gateway publisher authentication failure | Check runtime key and gateway secret match; never dump either. Reads do not need that key. |
|
|
161
|
+
| Reader cannot load history | Use an authorized personal-user session with channel access, not a bot session. |
|
|
162
|
+
| Bot cannot post | Check admin/post rights and broadcast channel identity; confirm both sessions resolve the same channel. |
|
|
163
|
+
| `keytool`/`apksigner` missing | Install Java/SDK tools; expose PATH or `ANDROID_SDK_ROOT`/`ANDROID_HOME`. Native Windows apksigner discovery is not validated by this release; do not claim full Windows publishing support. |
|
|
164
|
+
| Signer mismatch | Use the actual matching signing profile and correctly signed APK; never bypass verification or rotate a profile merely to silence it. |
|
|
165
|
+
| Wrong vault passphrase/corrupted vault | Retry correct passphrase or restore a known-good encrypted backup; there is no reset/recovery command. |
|
|
166
|
+
| Unsafe permissions/symlink/lock | Inspect user-data ownership and legitimate running processes; do not disable vault protections or blindly delete active locks. |
|
|
167
|
+
| Same version changed content | Increment version; do not overwrite immutable Telegram metadata. |
|
|
168
|
+
| Unexpected default after new publication | Inspect pin; explicitly pin approved new target if desired. |
|
|
169
|
+
| Hash/size mismatch | Stop, inspect source artifact/manifest and network outcome; do not install the bad file. |
|
|
170
|
+
| Delta unavailable or base mismatch | Use full APK fallback; regenerate from the exact installed base if preparing a release. |
|
|
171
|
+
| Existing skill destination | Review/move/back up the existing copy, then install; installer refuses overwrites. |
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# StoreBase runtime and Android reference
|
|
2
|
+
|
|
3
|
+
## Runtime topology
|
|
4
|
+
|
|
5
|
+
- `gateway/server.js` is a small Node HTTP server. `npm start` runs it; it reads `PORT` (default `8080`), validates the port, and binds `0.0.0.0`. It serves static files from `www/`, `GET /api/v1/health`, and the bootstrap endpoints. Build first (`npm run build`) so `www/index.html` and `www/telegram-direct.js` are current.
|
|
6
|
+
- Bootstrap returns encrypted Telegram settings only. The gateway does **not** proxy catalog messages, APKs, delta patches, icons, or update bytes. The app reads/downloads them from Telegram after bootstrap (gateway/README.md; gateway/server.js; src/telegram-direct.js).
|
|
7
|
+
- `app.yaml` identifies a Wasmer `App.v0` (`owner: tadi0781`, `name: storebase`, `package: .`) and declares a PostgreSQL capability. It contains no gateway entrypoint, deploy recipe, or secret declarations. The repository documents `STOREBASE_GATEWAY_PUBLISH_TOKEN` as a Wasmer secret, but does not document a Wasmer CLI deploy command. Do not infer one or deploy as part of local checks. The source-backed local run is `npm run build` then `npm start`; no Wasmer deployment is required.
|
|
8
|
+
|
|
9
|
+
## Bootstrap endpoints and runtime configuration
|
|
10
|
+
|
|
11
|
+
| Purpose | Endpoint | Settings returned | Required environment names |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| Catalog / Android read-only | `POST /api/v1/catalog/bootstrap`; legacy alias `POST /api/v1/telegram/bootstrap` | `schemaVersion: 1`, `settingsVersion: 1`, Telegram API ID/hash, **personal-user** read session, channel | `STOREBASE_TELEGRAM_API_ID`, `STOREBASE_TELEGRAM_API_HASH`, `STOREBASE_TELEGRAM_READ_SESSION`, `STOREBASE_TELEGRAM_CHANNEL` |
|
|
14
|
+
| CLI publisher | `POST /api/v1/publisher/bootstrap` | Above plus stored bot MTProto session (`botSession`); **does not return bot token** | Above plus `STOREBASE_TELEGRAM_SESSION`, `STOREBASE_GATEWAY_PUBLISH_TOKEN` |
|
|
15
|
+
|
|
16
|
+
`STOREBASE_TELEGRAM_SESSION` must be an authorized bot session whose bot is a channel administrator permitted to post. The read session must be an authorized personal MTProto user session with channel read access: Telegram bots cannot read channel history. `STOREBASE_TELEGRAM_BOT_TOKEN` is used by the CLI Telegram client only for initial/re-authentication when no valid stored bot session is available; it is not a bootstrap response or replacement for the stored session required by publisher bootstrap. `STOREBASE_GATEWAY_URL` is an optional CLI override (default `https://storebase.wasmer.app`); the CLI requires HTTPS except loopback and rejects URL credentials, query and fragment. `PORT` is optional for the server.
|
|
17
|
+
|
|
18
|
+
The publisher token must be high-entropy, 32–256 characters in `[A-Za-z0-9_-]`, kept separately in the gateway runtime and CLI runtime. Never put it in Android or the npm package. A missing/malformed gateway token leaves publisher bootstrap closed; publisher settings also require the saved bot session. `gateway/README.md`, `gateway/server.js`, `cli/lib/telegram-client.js`, and `cli/lib/gateway-client.js` are the configuration sources.
|
|
19
|
+
|
|
20
|
+
## Request and response security
|
|
21
|
+
|
|
22
|
+
The JSON POST is signed over newline-separated `STOREBASE_GATEWAY_V1`, method, **exact endpoint path**, app ID `com.nexuss0781.storebase`, UUID-v4 request ID, millisecond timestamp and DER/SPKI public key; publisher signatures also bind the token. Requests must be within five minutes of server time. The gateway checks RSA keys of at least 2048 bits, retains replay IDs for five minutes in process memory, and rate-limits each key fingerprint to 30 requests/minute by default. Each response uses a random AES-256-GCM content key wrapped with RSA-OAEP-SHA256; the envelope binds app ID, request ID and issuance time as authenticated data. Gateway settings are lazy-loaded/cached in process memory until restart; restart after credential changes or to clear that cache. Errors are intentionally generic to clients.
|
|
23
|
+
|
|
24
|
+
**Personal-use boundary, not production credential distribution:** the Android Keystore install key proves possession of that installation key, not that the requester is the official StoreBase APK. A client able to bootstrap can extract the read session. Anyone who gets the shared publisher token can obtain the bot session and publish to the channel. Limit and rotate that token if exposed; do not represent the Android bootstrap as app attestation. Response encryption protects transit/recipient binding; it does not make client-delivered credentials unextractable (gateway/README.md; gateway/protocol.js; SecureCatalogPlugin.java).
|
|
25
|
+
|
|
26
|
+
## Direct Telegram catalog and downloads
|
|
27
|
+
|
|
28
|
+
On Android, `SecureCatalog.getTelegramSettings` first reads its local encrypted cache; if absent/unreadable it calls the native gateway bootstrap. `src/telegram-direct.js` converts the Telethon-compatible session in memory, initializes `@mtcute/web` with `MemoryStorage`, verifies the account is a user (not bot), then searches the configured channel for `STOREBASE_MANIFEST_V1` messages (up to 5,000). It validates manifest IDs, versions, timestamps, hashes and artifact metadata; latest releases are sorted by publish time/message ID. It exposes `window.storeBaseCatalog`, `window.storeBaseTelegram` (`refreshCatalog`, `getRelease`, `downloadArtifact`, `disconnect`) and `storebase:catalog-ready` / download-progress events. Artifacts are fetched by Telegram message ID, cross-checked against the `STOREBASE_ARTIFACT_V1` caption, streamed to native storage, then checked against expected size and SHA-256. This is direct client-to-Telegram traffic, not a gateway catalog API.
|
|
29
|
+
|
|
30
|
+
The Android bridge keeps the install identity RSA key and cache AES key in Android Keystore. Cached settings are AES-GCM encrypted under a separate key in `noBackupFilesDir`; invalid cache data is deleted and triggers a fresh bootstrap. Converted Telegram authorization is in memory (not IndexedDB/localStorage). Android uses its legacy alias endpoint `/api/v1/telegram/bootstrap`; the catalog endpoint is the current API path.
|
|
31
|
+
|
|
32
|
+
## Frontend: working behavior vs mock UI
|
|
33
|
+
|
|
34
|
+
`index.html` implements the two-tab **visual** Apps/Explore shell: tab selection, arrow-key tab navigation, URL hash/query selection and scrolling/layout work. The displayed promotion, app rankings/recommendations, ratings, category examples, game cards, notification badge/profile and install labels are hard-coded mock content. Search/voice, chips, category/game cards, overflow, notifications/profile and install buttons have no action handlers; do not claim real search, filtering, installation, Play Store integration, or personalized discovery. The real Telegram catalog is initialized separately in Android and exposed as a JS global/event, but this HTML does not render it into those mock lists. In a normal browser there is no Capacitor native bridge, so Telegram catalog and update initialization are Android-only (`index.html`; `src/telegram-direct.js`).
|
|
35
|
+
|
|
36
|
+
## Android update, approval, reopen, limits
|
|
37
|
+
|
|
38
|
+
The update manager checks at startup and when returning to foreground after six hours. It gets the newest `storebase` release through the direct Telegram client. It chooses a delta only when its `fromVersionCode` exactly matches the installed version and the delta is smaller than the APK; otherwise it downloads the full APK. A `minimumVersionCode` above the installed code makes the dialog required/non-dismissible; optional updates can be deferred. Delta reconstruction or full APK staging and hash/package/version checks happen before launching Android’s package installer. Delta artifacts are limited to 256 MiB and APK/output to 1 GiB in the native update plugin.
|
|
39
|
+
|
|
40
|
+
On Android 8+ without “Install unknown apps” permission for StoreBase, the app opens that Android settings screen. The user must allow StoreBase, return to the app, and tap **Continue installation**. Android’s installer then requires user approval; StoreBase does not install silently. The `MY_PACKAGE_REPLACED` receiver attempts to relaunch StoreBase after replacement, but Android may defer/block background activity launches. If so, tap **Open** in the installer or launch StoreBase normally. The app checks package ID and version metadata; Android’s installer remains responsible for package signing continuity. Automatic reopening is best effort, not guaranteed (`src/update-manager.js`; StoreBaseUpdatePlugin.java; RelaunchAfterUpdateReceiver.java; AndroidManifest.xml; updates/README.md).
|
|
41
|
+
|
|
42
|
+
Troubleshooting: bootstrap may fail for bad/missing Telegram settings, invalid user session/channel access, stale clock (>5 minutes), a replayed request (409), rate limit (429), or unavailable settings (503). Verify that the reader session is a personal authorized user and resolves the same broadcast channel; the bot session must be authorized/admin for publishing. On update failure check Telegram access, manifest/artifact hashes and matching delta base; Android still requires unknown-app permission and installer confirmation. The gateway does not update catalog/release data itself.
|
|
43
|
+
|
|
44
|
+
## Operate locally, then deploy from a local checkout
|
|
45
|
+
|
|
46
|
+
Follow this ordered operator flow; deployment is a separate authorized action, never part of publishing an APK or installing this skill.
|
|
47
|
+
|
|
48
|
+
1. From the repository root run `npm ci`, `npm test`, and `npm run build`. Supply the gateway environment variables listed above from a private secret manager. The server does not load `.env` itself; inject environment variables using the environment's secret mechanism rather than assuming a file is loaded by `npm start`.
|
|
49
|
+
2. Run `npm start` and check `http://127.0.0.1:8080/api/v1/health` (adjust `PORT` if set). This health check is liveness, not proof the Telegram sessions are valid. Do not expose a local unprotected reader bootstrap to an untrusted network.
|
|
50
|
+
3. In another terminal set `STOREBASE_GATEWAY_URL=http://127.0.0.1:8080` through the shell's normal environment mechanism. Run `storebase-telegram list` to exercise reader bootstrap and Telegram authorization. Do not call the publisher route or upload a test app without write approval.
|
|
51
|
+
4. Before Wasmer deployment, install/authenticate the official Wasmer CLI and inspect `wasmer deploy --help`. Verify `app.yaml` targets the intended owner/app and that the account has permission. Do not change `owner` merely to make a command succeed. Inspect any database capability for operational/cost implications: this gateway does not itself use PostgreSQL.
|
|
52
|
+
5. Resolve the runtime packaging prerequisite **before** deployment. `package: .` points to local packaging, but this checkout contains no `wasmer.toml` or explicit Wasmer gateway entrypoint. A working Node local server is not proof that the selected Wasmer package runs `gateway/server.js`. Retrieve/review the existing app's actual runtime build configuration or use a supported Node-capable Wasmer template; ensure the package executes the gateway and includes built `www/`. Do not silently deploy a static-only frontend, guess a WASI runtime, or claim this missing recipe is already validated.
|
|
53
|
+
6. Configure all gateway secrets in the app's Wasmer dashboard under **Settings → Environment Vars**, then use **Save and Redeploy** when authorized. Include API ID/hash, bot session, personal read session, channel and publisher token; do not put them into `app.yaml` `env`, source, web bundles, or command arguments. `wasmer app secrets list` lists names without values; do not run `secrets reveal`. If a CLI-only setup is specifically required, the official `wasmer app secrets create --from-file=<private-file>` interface is available; keep that file outside source/package staging, restrict permissions, never print it, and remove it after use. Confirm flags against installed help.
|
|
54
|
+
7. Once the runtime package and secrets are ready and deployment is authorized, run `wasmer deploy` from the reviewed checkout/config directory. This may publish a runtime package and change the live app. Review prompts, intended owner/app and version; record the returned live URL. Inspect `wasmer app info` to confirm identity/URLs.
|
|
55
|
+
8. Check `<live-url>/api/v1/health`, set a client runtime `STOREBASE_GATEWAY_URL` to that HTTPS URL, and run a read-only catalog query. Test publisher authorization using automated mocked tests or an explicitly approved real release; do not publish an unapproved APK as a probe. Change the Android gateway URL only in native configuration/source if intentionally moving endpoints; a CLI environment override does not rewrite an installed Android app.
|
|
56
|
+
9. After rotating gateway sessions or publisher token, restart/redeploy to invalidate cached settings and update authorized CLI runtime secrets. Existing Android encrypted settings caches may retain the old reader session; clearing Android app data/reinstalling also changes local app state, so obtain approval and explain consequences before doing so.
|
|
57
|
+
|
|
58
|
+
Use [official Wasmer CLI deployment guidance](https://docs.wasmer.io/edge/cli/), [app configuration](https://docs.wasmer.io/edge/configuration/), and [secret management](https://docs.wasmer.io/edge/learn/secrets/) for the platform commands above. These are operator instructions, not a claim that a Wasmer deployment was executed or that the missing runtime packaging was repaired by this release.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# StoreBase updates and development reference
|
|
2
|
+
|
|
3
|
+
## Telegram release/update flow
|
|
4
|
+
|
|
5
|
+
1. Produce a **new signed APK** and retain the previous released APK if generating a delta. The app update metadata belongs to a `storebase` release and uses package `com.nexuss0781.storebase`, a higher Android version code, and optionally `minimumVersionCode`.
|
|
6
|
+
2. Generate and verify a local patch (below). Keep the full APK and any smaller patch; the helper never publishes.
|
|
7
|
+
3. Manually publish artifacts and post the versioned manifest **last** with `storebase-publish`. The gateway does not publish automatically. The documented release command is:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
storebase-publish \
|
|
11
|
+
--name StoreBase --avatar delivery/storebase-icon.png \
|
|
12
|
+
--version 1.1.0 --apk delivery/StoreBase-updater-debug.apk \
|
|
13
|
+
--android-version-code 2 \
|
|
14
|
+
--delta updates/releases/StoreBase-v1-to-v2-<hash>.sbd \
|
|
15
|
+
--delta-base-version-code 1 \
|
|
16
|
+
--category Utilities --description "StoreBase Android app" \
|
|
17
|
+
--keystore <release-keystore>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Use the actual new APK, release version/code, prior base code and generated patch path; the names/values above are the example in `updates/README.md`, not a recommendation to ship a debug build or use those version numbers. Omit the two delta flags for a full-APK-only release. The publisher uploads APK, optional delta and icon as Telegram channel documents, verifies hashes, then posts the manifest. **No Telegram publish or gateway deployment is done by local staging/build checks.**
|
|
21
|
+
|
|
22
|
+
## Delta tooling: exact interfaces
|
|
23
|
+
|
|
24
|
+
### Preferred release helper
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
python3 tools/create_update_release.py \
|
|
28
|
+
--apk NEW_SIGNED.apk \
|
|
29
|
+
--version-code NEW_POSITIVE_CODE \
|
|
30
|
+
--version-name NEW_VERSION_NAME \
|
|
31
|
+
--base-apk PREVIOUS_RELEASED.apk \
|
|
32
|
+
--base-version-code PREVIOUS_POSITIVE_CODE
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`--apk`, `--version-code`, and `--version-name` are required. `--base-apk` and `--base-version-code` must either both be supplied or both omitted; a supplied base must exist, be non-empty, and have a positive code lower than the new code. Optional `--output-dir DIR` defaults to `updates/releases`. Without a base, it reports full-APK-only staging. With a base, it generates a deterministic gzip-compressed SBD1 copy/insert patch, applies it locally to verify byte-for-byte reconstruction, and writes a hash-named `.sbd` only if the patch is smaller than the full APK; otherwise publish only the full APK. It prints the APK path and, when applicable, patch path and SHA-256. It does not publish.
|
|
36
|
+
|
|
37
|
+
The lower-level exact interface is positional:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
python3 tools/create_apk_delta.py OLD_APK NEW_APK OUTPUT_PATCH
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
It requires both APK inputs non-empty, writes the requested patch path (creating its parent directory), verifies round-trip reconstruction, and prints patch/full sizes. Unlike the release helper, it does **not** suppress a patch that is larger than the target APK; use the release helper for the supported release decision. Both scripts are source under `tools/`; tests are in `tools/test_apk_delta.py`.
|
|
44
|
+
|
|
45
|
+
The client uses a delta only if its manifest base code matches the installed version exactly and it is smaller than the APK; otherwise it downloads the full APK. Native reconstruction validates SBD1 structure, reconstructed APK size/hash, package ID and version before opening Android’s installer. Hashes prove agreement with the manifest metadata, not publisher identity by themselves. Android installer confirmation and signing rules still apply.
|
|
46
|
+
|
|
47
|
+
## Local build and checks
|
|
48
|
+
|
|
49
|
+
From the repository root, documented scripts are:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
npm install
|
|
53
|
+
npm test
|
|
54
|
+
npm run build
|
|
55
|
+
npm run android:build
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- `npm test` runs Node’s built-in test runner over `gateway/test/*.test.js` and `cli/test/*.test.js`, then Python `unittest` discovery for `tools/test_*.py`.
|
|
59
|
+
- `npm run build` copies `index.html` into `www/` and runs Vite to build `www/telegram-direct.js` and its assets.
|
|
60
|
+
- `npm run android:build` runs `npm run android:sync` (which builds and runs `cap sync android`) then `cd android && ./gradlew assembleDebug`. It produces a debug build, not a release-signed publishing APK.
|
|
61
|
+
|
|
62
|
+
Prerequisites evidenced by the project: Node.js/npm and installed project dependencies; Python 3 for the delta/unit tests; for Android, a working JDK/Android SDK with API 36 available and the Gradle wrapper’s configured Gradle 8.14.3 distribution (the wrapper can require network access). App min/target SDK values are 24/36. The root package does not declare a Node engine range; do not invent one. `npm test` does not run Gradle/Android instrumented tests.
|
|
63
|
+
|
|
64
|
+
For local gateway runtime, build the web assets first, then use the root `npm start` script (`node gateway/server.js`). It listens on `0.0.0.0`, using `PORT` or default `8080`, serves `www/`, and reads gateway runtime environment settings. This is a local Node run, not a Wasmer deployment. `app.yaml` contains only Wasmer App.v0 identity/package and a PostgreSQL capability; no local Wasmer deploy/run steps or gateway service entrypoint are specified in the inspected project. Do not guess a deploy command or perform deployment. Gateway configuration details and deployment/security boundary are in `gateway/README.md` and `runtime-and-android.md`.
|
|
65
|
+
|
|
66
|
+
## Common failure diagnosis
|
|
67
|
+
|
|
68
|
+
- **Release helper rejects arguments:** both base options are paired; base version is lower than the positive new version; version name matches `[A-Za-z0-9][A-Za-z0-9.+_-]{0,63}`; APK files exist and are non-empty.
|
|
69
|
+
- **No `.sbd` produced:** no base supplied or the verified patch is not smaller than the APK. Publish a full APK.
|
|
70
|
+
- **Tests fail:** confirm Node dependencies are installed and Python 3 is available; inspect failing Node/Python tests before changing release behavior.
|
|
71
|
+
- **Android build fails:** check JDK, SDK/API 36, Gradle wrapper download/network, then run the documented `android:sync`/`android:build` path rather than assuming stale web assets are synced.
|
|
72
|
+
- **Updates do not appear:** client update checks require Android native bridge and a readable Telegram manifest for `storebase`; browser UI is only a mock shell. Check correct package/version metadata, Telegram reader access, delta `fromVersionCode`, artifact size/hash and app installer permission. The app checks on launch and foreground return after six hours; it does not poll continuously.
|
|
73
|
+
- **Publishing/bootstrap fails:** check gateway reader and bot session roles, channel identity, and the separately configured publisher token. Never print/copy sessions or tokens into logs or packaged artifacts.
|
|
74
|
+
|
|
75
|
+
Source trail: `updates/README.md`, `tools/create_update_release.py`, `tools/create_apk_delta.py`, `tools/test_apk_delta.py`, root `package.json`, `vite.config.mjs`, `app.yaml`, `android/variables.gradle`, and `android/gradle/wrapper/gradle-wrapper.properties`.
|