Rennko Cloud docs
Rennko Cloud gives your app auth, a realtime database that works offline, file storage and hosting. If you've used Firebase, most of this will look familiar.
Get started
- Sign up in the console and create a project, for example
my-app. It lives athttps://my-app.rennko.tech. - Import the SDK from your project. There's nothing to install:
<script type="module">
import { app } from 'https://my-app.rennko.tech/__/init.js'
// app.auth, app.db, app.storage are ready to use
</script>
Using a bundler, or several projects? Import the SDK directly:
import { initApp, serverTimestamp, increment, arrayUnion, arrayRemove, deleteField } from 'https://console.rennko.tech/rennko.js'
const app = initApp('https://my-app.rennko.tech')
Auth
await app.auth.signUp(email, password) // also upgrades an anonymous user in place
await app.auth.signIn(email, password)
await app.auth.signInAnonymously()
const { user, providerToken } = await app.auth.signInWithGitHub({ scopes: ['read:user'] })
await app.auth.signInWithGoogle()
await app.auth.linkWithGitHub() // add GitHub to the signed-in user
await app.auth.unlink('github')
app.auth.onAuthChange(user => { /* null when signed out; works offline */ })
await app.auth.signOut()
user has uid, email, name, photo, anon and providers (the GitHub and Google accounts linked to it). providerToken is the GitHub or Google access token, so you can call their APIs as the user.
To turn on GitHub or Google, open the console's Authentication tab. Register an OAuth app with the callback URL shown there, then paste its client ID and secret. Popup sign-in has to start from a click handler, or the browser blocks the popup.
Database
Data lives in documents (JSON objects up to 1 MB) inside collections. Paths alternate: posts/abc, users/u1/notes/n1.
const ref = app.db.doc('todos/abc')
await ref.set({ text: 'hi', done: false, at: serverTimestamp() })
await ref.set({ tags: ['x'] }, { merge: true })
await ref.update({ count: increment(1), 'meta.seen': true, tags: arrayUnion('y') })
await ref.delete()
const snap = await ref.get() // snap.exists, snap.data(), snap.metadata.fromCache
const todos = app.db.collection('todos')
const newRef = await todos.add({ text: 'buy milk' })
const q = todos.where('done', '==', false).orderBy('at', 'desc').limit(20)
const unsubscribe = q.onSnapshot(snap => {
for (const c of snap.docChanges()) console.log(c.type, c.doc.id, c.doc.data())
})
const batch = app.db.batch() // all or nothing
batch.set(app.db.doc('a/1'), { n: 1 }).delete(app.db.doc('a/2'))
await batch.commit()
Query operators: == != < <= > >= in not-in array-contains array-contains-any. Use the field __id for the document ID. You can also page with .offset(n).
Offline
Nothing to set up. In the browser the SDK keeps a copy of what you've read, plus a queue of your writes, in IndexedDB.
- Listeners fire right away from the cache.
snap.metadata.fromCacheandhasPendingWritessay what you're looking at. - Writes update every listener instantly. They sync when there's a connection, even after a reload or restart, and each one is applied exactly once.
- A write's promise resolves when the server confirms it. In an offline-friendly UI, don't wait on it before updating the screen.
app.onConnectionChange(online => …),app.disableNetwork(),app.enableNetwork()andapp.waitForPendingWrites()give you control.
Storage
const file = await app.storage.upload(`avatars/${user.uid}/me.png`, blob)
img.src = file.url // a shareable link
await app.storage.list(`avatars/${user.uid}/`)
await app.storage.download(path) // a Blob
await app.storage.delete(path)
Files can be up to 25 MB. Storage needs a connection.
Hosting
In the console's Hosting tab, drop your built site's folder (the one with index.html), or use the CLI. Turn on Single-page app for React/Vue routers, or Clean URLs to serve /about from about.html. A 404.html becomes your not-found page.
Hosted sites appear on Discover, ranked by how many people visited them today. A visit is the first page someone opens on your site that day, and bots don't count. Discover uses your index.html's <title>, <meta name="description"> and og:image. To hide your site, turn off Show in Discover in the Hosting tab.
Security rules
Rules decide who can read and write. Edit them in the console's Rules tab, or deploy a rules.json:
{
"db": {
"users/{uid}/**": { "read": "auth.uid == uid", "write": "auth.uid == uid" },
"posts/{id}": {
"read": "true",
"create": "data.owner == auth.uid && data.text.size() < 500",
"update": "doc.owner == auth.uid && data.owner == auth.uid",
"delete": "doc.owner == auth.uid"
}
},
"storage": {
"avatars/{uid}/**": { "read": "true", "write": "auth.uid == uid && data.size < 5000000", "delete": "auth.uid == uid" }
}
}
{name}matches one path segment.**matches the rest.- Actions:
read(orget,list) andwrite(orcreate,update,delete). If any matching rule allows it, it's allowed. - Conditions can use:
auth:uid,email,anonandprovider, ornullwhen signed out.doc: what's stored now.data: what's being written. It'snullon delete. For files it hassizeandtype.now, which equalsserverTimestamp()values in the same write.- Your
{name}variables.
- Operators:
== != < <= > >= && || ! + - in. Functions:.size() .includes(x) .startsWith(s) .endsWith(s) .keys() .hasAll(list) .hasAny(list) .hasOnly(list). - Queries only return documents the user may
list. - The console and the admin key skip rules.
CLI
npx github:learningnihongo934-byte/RennkoCloud login
npx github:learningnihongo934-byte/RennkoCloud create my-app
npx github:learningnihongo934-byte/RennkoCloud deploy --project my-app --dir dist --spa --rules rules.json
Put { "project": "my-app", "dir": "dist", "spa": true, "rules": "rules.json" } in a rennko.json to make plain rennko deploy work. In CI, set RENNKO_ADMIN_KEY (from the console's Overview tab) instead of logging in.
Run your own
Rennko Cloud is MIT-licensed and fits Cloudflare's free plan, with no card needed.
git clone https://github.com/learningnihongo934-byte/RennkoCloud && cd RennkoCloud
./build.sh # everything on http://localhost:8787, works with no internet
./build.sh test # end-to-end tests
./build.sh deploy # to your Cloudflare account
Limits
- Per account: 5 projects.
- Per project: 500 MB of storage.
- Per file: 25 MB.
- Per document: 1 MB.
- Per query: 1,000 documents.
The whole service shares Cloudflare's free daily quota. Not included yet: email verification and password-reset emails, server functions, and count queries.