Publishing
npx tinylib-sdk publish uploads your app's folder as a new version, a numbered copy of your files and rules that never changes. The newest version goes live for everyone at once. In a listed app, each new version first waits for Tinylib's review.
A run looks like this:
Every file in the folder and its subfolders ships, at the same path, except:
- files and folders whose names start with a dot, such as
.envand.git node_modulespackage.jsonandpackage-lock.jsontinylib.json,rules.jsorrules.ts, and files that only the rules import, since the rules run on Tinylib's servers and reach a device only if your page imports them
Every file that ships is public, a README or tsconfig.json included. Keep secrets out of the folder, or publish a bundler's output.
A version needs index.html and the icon tinylib.json names, a square PNG at least 512 pixels on each side. It's refused past 5 MB or 500 files, or past one of the other limits on versions.
publish builds each file the way npx tinylib-sdk dev serves it:
The rewrite covers src, srcset, poster, a <link>'s href, and url() in the page's styles, so img.png in sub/page.html loads sub/img.png at every address. Links in <a href> stay as written and resolve from the current address (Places).
Tinylib serves index.html at every address that has no file extension and isn't one of your files, such as game/abc. A missing file with an extension, such as img/cat.png, is a 404.
Paths your JavaScript builds aren't rewritten, so start them with /: fetch('/levels.json').
A page can load a TypeScript or JSX file directly:
Imports of npm packages resolve from node_modules, and imported JSON is inlined. TypeScript and JSX are compiled without checking types.
JSX compiles to React.createElement calls, so a file that uses JSX imports React. To use React's automatic JSX runtime instead, put a tsconfig.json in the folder:
A script that imports CSS or an image fails the build. Link stylesheets from the page, and load images by their path.
Every script in the folder is bundled, even one no page loads, so a test file that imports node:test stops publish with "path didn't build". Keep tests out of the folder you publish.
To use Vite or another bundler, publish its output folder. publish reads tinylib.json, the icon, and the rules from that folder, so put them and the files the rules import where the bundler copies files unchanged, like Vite's public/ folder:
Set the bundler's base path to /.
npx tinylib-sdk preview publishes the folder as your app's preview, a separate copy that only you and the testers you invite can open. Publish the app first.
Each tester gets an email with the preview's link and signs in to Tinylib with that address to open it. A preview has its own data and rooms.
An app has one preview. Running preview again replaces its client and rules and restarts its expiry. Its data, rooms, and testers stay, and its rooms move to the new rules as the live app's do.
A preview never becomes the live app: to go live, run publish. A preview ends when it expires or when you run npx tinylib-sdk preview --end, and its data and rooms go with it. The developer page can also add and remove testers and end the preview.
A new app starts unlisted. Choose who finds it on the developer page:
Listing an app asks for review. A person at Tinylib checks it against the Developer Terms. The app stays out of the directory until they approve it.
After that, each new version waits for the same review:
publishputs the new version in the app's preview, replacing what it held, so your testers try what Tinylib reviews.- Everyone keeps the current version until Tinylib approves the new one.
- On approval, the room check runs again and the version goes live.
Tinylib emails your contact address when it approves or rejects a version, and the developer page shows the reason for a rejection. To ask again, publish a fixed version.
Choosing Unlisted or Friends takes the app out of the directory and withdraws any version waiting for review; later versions go live at once. Listing the app again asks for a new review.
When a version goes live, a client open in a room reloads at its current address, with no event first, and any other client uses the new version at its next open. A client that was offline reloads once it's back online, and an action it sends before reloading is refused rather than run under the new rules. The reload loses anything kept only in the page's memory, so save a half-typed message to tinylib.data as the user types.
Rooms run the current version's rules on state that earlier rules may have written, so new rules must handle the old shape or rooms in progress break.
To reshape old state, give the kind a migrate handler. It runs once in each room under new rules, before anything else touches the state. fromVersion is the version whose rules last handled an input in the room, which can be several versions back.
Once migrate succeeds, ctx.version becomes the current version's number.
Before a version goes live, Tinylib runs a room check on every room that hasn't ended, idle ones included. It runs migrate on a copy of the room's state, then each member's view, status, and canInvite. If one of them throws, migrate refuses, or the result passes one of a room's limits, the version doesn't go live and nothing changes:
The check also runs for every preview and for every earlier version you make current again. It refuses a version that removes a kind while rooms of that kind haven't ended, or that has no rules.js while any room hasn't ended. To retire a kind, make its create refuse, and remove the kind once its last room has ended.
In an offline kind, an action a member made without signal under an earlier version is refused when it reaches the room, even when only the client changed. Tinylib takes it out of room.pending and tells the user a change couldn't be saved.
Publishing doesn't reshape the user's data, so a new client reads whatever shape earlier clients and rules wrote. Read old shapes as well as new ones:
The same goes for a member's data under rulesKeys and for room data: migrate reshapes only the room's state.
To undo a bad version, choose Make current beside an earlier version on the app's developer page. The command line has no rollback. Tinylib copies that version into a new one with the next number, which goes live like any other: it must pass the room check, and in a listed app it waits for review.
Rooms don't go back. They run the copy's migrate with fromVersion set to the version they ran last, so the earlier rules meet state that later rules may have reshaped. If they can't handle it, the room check refuses the rollback.
Both are on the developer page. After Unpublish, people who have the app keep using it, but nobody new can open it, and it leaves the directory and Discover. Publishing again brings it back, unlisted.
Delete deletes every version and everything people saved in the app, and removes it from every library. You can't undo it.
Your app's links carry the slug from tinylib.json, as in tinylib.app/tic-tac-toe, and the app's first version claims it. A slug that belongs to another developer's app or to one of Tinylib's own addresses is taken, and a slug is never used again, even after its app is deleted.
When the slug is taken the first time you publish, publish offers an available one like it, such as tic-tac-toe-k7q, and writes it to tinylib.json if you accept. Outside a terminal, it prints the available slug and stops.
A slug or a name that Tinylib's word filter catches, or that names Tinylib or another company, is refused as taken.
An app's slug can't change. A new slug in tinylib.json publishes a separate new app, and the old one stays as it was, with its users.