Build apps
The project
The files of an app project: ledable.json, the README, and what stays local.
On this page
An app project is a directory with ledable.json at its root. Every ledable developer command
except init runs in that directory. ledable developer init creates one; this page goes through
what is in it.
| File | Kept in version control |
|---|---|
ledable.json | yes |
The entry module, such as index.tsx, and the modules it imports | yes |
README.md | yes |
| Assets: images, animations, the store icon and screenshots | yes |
package.json, package-lock.json, tsconfig.json, .gitignore | yes |
.ledable/ | no |
ledable.dev.json | no |
node_modules/ | no |
ledable.json
ledable.json says what the app is: its id and version, how the store lists it, which files make
it up, and what it may reach. It holds declarations only; settings are code, in the entry module.
A complete one looks like this:
{
"app_id": "tide-times",
"version": "1.2.0",
"entry": "./index.tsx",
"name": "Tide Times",
"description": "The next high and low tide at a harbour you pick.",
"category": "travel",
"tags": ["tides", "sea", "sailing"],
"website": "https://example.com/tide-times",
"contact": "tides@example.com",
"readme": "./README.md",
"icon": { "path": "assets/icon.webp" },
"screenshots": [
{ "path": "assets/screenshots/high-tide.webp" },
{ "path": "assets/screenshots/low-tide.webp" }
],
"secrets": ["TIDES_API_KEY"],
"network": { "allowed_hosts": ["api.tides.example.com"] }
}The ledable.json reference gives every field's exact rules. In short:
app_idis the app's id in the store, claimed once withledable developer createand never changed.versionis the version an upload publishes. A published version never changes, so anything that changes what the app draws needs a new number.entryis the module whose default export is the app.name,description,categoryandtagsare how the store lists the app. There is no author field: the store names the account that owns the app.websiteandcontacttell people where to find out more and how to reach you.readmeis the text of the app's store page, below.iconandscreenshotsare the listing's images, below.secretsnames the keys of your own that the app reads fromctx.secrets; see Secrets.network.allowed_hostslists every host the app requests, and an app that requests none lists none:"allowed_hosts": []. See Data and the network.
Paths in ledable.json are relative to the project and must stay inside it.
Listing limits
Every store client lays a listing out in the same space, so the store holds it to these limits, counted in characters. The CLI checks them before it builds, and the store checks every upload again:
| Part | At most |
|---|---|
name | 30 characters |
description | 120 characters |
| README | 4000 characters |
tags | 5 tags of 20 characters each |
screenshots | 6 |
The entry module
The entry module's default export is what defineApp from @ledable/sdk/app returns, as
How apps work describes. It may import other modules of the
project, packages it installs, and asset files, which become references the app reads through
ctx.assets (Images and assets). Every TypeScript file of the project is
type-checked in strict mode before every build, so a type error anywhere stops a build, a preview
and an upload; Testing shows how to keep test files out of it. The build
bundles what the entry module imports into one module and leaves out everything else.
The README
The file readme names is the app's page in the store: the LEDABLE app and the app's share page
show it. The store reads a small part of Markdown, and shows everything else as plain text:
- A line starting with
#,##or###and a space is a heading. - Lines starting with
-or*make a bulleted list, lines starting with a number, a full stop and a space (1.) a numbered list. - Other lines that follow each other make a paragraph; an empty line ends it.
- Within a line:
**bold**,*italic*or_italic_,`code`, and[text](https://…)links. A link must be HTTPS.
HTML, images, tables, quotes and code blocks are not read: they appear as the characters you wrote. The example apps on this site have READMEs written to this subset:
# Door Sign
A sign for the outside of your door. Pick whether you are **open**,
**busy** or **away**, choose a message to go with it and, while you are
away, the time you will be back.
## Settings
- **Status** and **Message**: the messages on offer follow the status.
- **Back at**: shown only while you are away.
- **Colour** and **Border**: how the sign looks.The listing's images
icon and each of the screenshots name a WebP file in the project. They are uploaded with the
version as assets, and unlike the app's other assets, the store serves them publicly with the
listing. ledable images convert turns a PNG, JPEG or GIF into a WebP the size of the panel,
which suits a screenshot; see Pictures.
Local files
Two things in a project belong to your machine only, and the .gitignore that developer init
writes keeps them out of version control:
.ledable/is written by the CLI: the compiler settings yourtsconfig.jsonextends, the type checker's state, the builddeveloper devruns and what its preview page is set to. Everydeveloper checkwrites it again, so a fresh clone of a project needs oneledable developer check, or any build, before an editor finds its types.ledable.dev.jsonholds your own keys and tokens for the local preview: values for the secrets the app declares, account tokens and credentials. See Local preview.
The SDK and the CLI versions
A project depends on @ledable/sdk, and developer init adds @ledable/cli beside it, so
npm run dev uses the CLI the project names. Imports resolve from the project as your editor
resolves them, so a build bundles the SDK version the project installed.
A CLI builds only an SDK of its own major version, and while the SDK is at 0.x, of its own
minor version too. Any other stops the build and says which side to upgrade: @ledable/sdk in
the project when it is older, @ledable/cli when it is newer.
Every upload records the SDK version it was built with, and the store refuses an upload built
with an SDK older than the oldest it still accepts.