@promptlyapp/sdk
v0.3.0
Published
Typed wrappers over the window.Promptly host API injected into every Promptly mini-app WebView.
Readme
@promptlyapp/sdk
Typed wrappers over window.Promptly, the host API injected into every
Promptly app.
A Promptly app is a self-contained HTML/JS bundle running in a WebView on someone's phone. The
Promptly runtime injects a global, window.Promptly, and that global is how the app reaches
everything a sandbox cannot reach on its own: a shared database, the camera, payments, haptics,
the signed-in user's profile, an AI model, and about thirty other capabilities.
This package is the typed surface of that global: one module per capability, with the exact contract of each method in its TSDoc. It is thin on purpose. The injected JavaScript is the behaviour; the types are the product.
npm install @promptlyapp/sdkNot on the public npm registry yet. The first release has not been published, so that command answers
E404 Not Foundtoday. Until it lands, build a tarball from a checkout: Install in the repository README has the four commands, and everything below is identical either way.
Plain TypeScript compiled to ESM, so it imports under plain Node with no build step. svelte is
an optional peer dependency, needed only by @promptlyapp/sdk/stores.
Entry points
| Import | What it gives you |
|---|---|
| @promptlyapp/sdk | Every capability namespace: ready, storage, db, game, realtime, invites, net, share, clipboard, haptics, camera, scanner, media, speech, audio, tts, torch, screen, notifications, geolocation, maps, biometric, health, nfc, sensors, contacts, calendar, files, ai, ads, payments, profile, plus the shared types. |
| @promptlyapp/sdk/stores | Svelte-reactive helpers: theme, online, and watch() for a live db collection. |
| @promptlyapp/sdk/testing | createFakePromptly(), a complete scriptable in-memory host. |
| @promptlyapp/sdk/promptly-project.schema.json | The JSON Schema for a promptly.json project file. |
| @promptlyapp/sdk/host.css | The host's base stylesheet, for a local dev host to inject so a previewed app matches Promptly. Generated from hostBaseCss(). |
| @promptlyapp/sdk/design-tokens.json | The --promptly-* design tokens as data, for a non-JS consumer to read the palette without parsing CSS. |
The root export also carries the host contract the last two are generated from: hostBaseCss()
returns that stylesheet as a string (the single definition the local dev host, the gallery and the
starter all render against, so none of them keeps a copy that drifts from what Promptly serves), and
hostDesignTokens() returns the palettes behind it.
A minimal example that runs anywhere
Outside the Promptly runtime there is no window.Promptly, so every call would throw. Install
the fake host first and the same code runs under plain Node. Save as example.mjs, then
node example.mjs:
import { createFakePromptly } from "@promptlyapp/sdk/testing";
import { db, ready, storage } from "@promptlyapp/sdk";
const fake = createFakePromptly({
user: { username: "ada", displayName: "Ada", avatarUrl: null, bio: null },
});
fake.install(); // defines globalThis.Promptly, the same shape the runtime injects
const ctx = await ready();
console.log("running as", ctx.appId, "in", ctx.theme, "theme");
await storage.set("save", { level: 3 });
console.log("per-app storage:", await storage.get("save"));
const scores = db.collection("scores");
await scores.upsertMine({ score: 4820 }, { tag: "weekly", rank: 4820 });
const weekly = await scores.query({ tag: "weekly", orderBy: "rank", dir: "desc" });
console.log("leaderboard:", weekly.docs.map((doc) => [doc.owner?.username, doc.rank]));
fake.uninstall();Testing an app
The fake implements db, game, realtime and storage for real: owner semantics, watch
events on every write, and moves validated through your own game.define() spec. Everything a
user or a device would decide is a queue or a switch instead. An empty queue resolves that
call's documented cancel or deny default, so an untouched fake behaves like a user who says no
to everything.
import { createFakePromptly } from "@promptlyapp/sdk/testing";
const fake = createFakePromptly({ user: { username: "ada", displayName: "Ada", avatarUrl: null, bio: null } });
fake.install();
fake.enqueue.camera("data:image/png;base64,AA=="); // next capture() "takes" this photo
fake.enqueue.biometric({ verified: false, error: "locked_out" });
fake.setTheme("dark"); // the theme store flips live
fake.setOnline(false); // the online store flips live
fake.seedDoc("scores", { score: 99 }, { tag: "weekly", rank: 99 });
expect(fake.calls).toContainEqual({ method: "tts.speak", args: ["hello"] });
fake.uninstall();Permissions, cancellation and unavailability
Three things the types will make you handle, and the host will enforce whether you handle them or not:
- Permissions. Gated capabilities need a permission token declared in the app manifest. The
token for each namespace is recorded in that module's TSDoc:
camerafor bothcameraandscanner,photosformedia,microphoneforspeech, and so on.db,storage,game,realtime,net,themeandlocaleare ungated. - Cancellation. Every picker resolves
nullwhen the user cancels or denies, and the return type says so. There is no separate error path to catch. - Unavailability. Capabilities that a given device may simply not have (
health,nfc, and friends) can resolve anUnavailablevalue. Narrow it withisUnavailable().
Licence
MIT. Full documentation, including the components package and the gallery, is in the repository README.
