andibase

Apps

Public mini apps stored inside a workspace and published at /apps/[handle]

Open Markdown

Apps are public mini apps that belong to one workspace.

Each app stores:

  • name
  • handle
  • optional description
  • code
  • memberRole
  • optional memberPermissions
  • optional publicRole
  • optional publicPermissions
  • runtimeKeyTtlMs

Public URL

Every app is published at:

/apps/[handle]

The public page renders the saved JSX inside a sandboxed iframe.

Code contract

For now, code must be a single JSX module that exports a default React component.

import { useState } from "react";

export default function App() {
  const [count, setCount] = useState(0);

  return (
    <main style={{ minHeight: "100vh", padding: 24 }}>
      <h1>Counter</h1>
      <button onClick={() => setCount((value) => value + 1)}>
        Count: {count}
      </button>
    </main>
  );
}

The renderer loads React from esm.sh, transpiles the JSX in-browser, and mounts the default export into the iframe root.

API endpoints

Apps are documented in the generated API reference:

  • GET /api/v1/experimental/apps: list apps for the current workspace
  • GET /api/v1/experimental/apps/:handle: get one public app by handle
  • POST /api/v1/experimental/apps/:handle/runtime-token: issue or refresh an embedded-app runtime key
  • POST /api/v1/experimental/apps: create an app in the current workspace
  • PATCH /api/v1/experimental/apps/:handle: update an app in the current workspace
  • DELETE /api/v1/experimental/apps/:handle: delete an app from the current workspace

Use the full request and response schemas here:

Runtime auth model

Public apps do not receive long-lived secrets in HTML or query params.

Instead, the host page waits for the iframe runtime to post andibase:ready, then it calls:

POST /api/v1/experimental/apps/:handle/runtime-token

The response includes:

  • apiKey
  • baseApiUrl
  • workspaceHandle
  • permissions
  • accessMode
  • expiresAt
  • refreshAfter
  • appSessionId

The iframe keeps that bootstrap in memory only and exposes it through window.andibase.

Member vs public access

  • Signed-in workspace members receive the app's member grant.
  • Anonymous viewers receive the app's public grant.
  • Signed-in non-members also receive the public grant.
  • New apps default the member grant to admin.
  • New apps default the public grant to no permissions.

Runtime permissions are recomputed from the app row on every bootstrap and refresh.

Refresh behavior

  • Runtime keys default to a 5 minute TTL.
  • refreshAfter is one minute before expiry for normal TTLs.
  • When the TTL is shorter than 2 minutes, refresh shifts to 80% of the lifetime.
  • The iframe asks the parent page for a replacement key before expiry.
  • The old key remains valid until its natural expiration, so in-flight requests can finish while new requests switch to the replacement key.
  • If refresh fails twice and the old key expires, the iframe enters an auth-expired state until the parent completes another bootstrap handshake.

Auth model

  • GET /api/v1/experimental/apps/:handle is public and does not return runtime grant fields.
  • Workspace management endpoints use the resolved workspace.
  • Session requests should send x-workspace-handle when needed.
  • Manual API keys still need apps.read or apps.write.

On this page