Create apps that live inside Datasette
Project description
datasette-apps
Create apps that live inside Datasette
Installation
Install this plugin in the same environment as Datasette.
datasette install datasette-apps
Usage
This plugin introduces a new interface at /-/apps for browsing and searching available apps.
There are two types of app:
- HTML and JavaScript apps managed by this plugin, which run in a sandbox that limits them to approved Datasette data access and blocks communication with external sites unless those hosts have been explicitly allowed.
- Apps provided by other plugins that are written in Python and HTML/JavaScript which are unrestricted but can do more things
This plugin allows you to create and modify HTML apps, and provides a plugin hook to enable other plugins to add their own Python apps to the system.
/-/appslets you browse available apps/-/apps/ULIDto interact with a full screen HTML app/-/apps/createfor creating a new app/-/apps/ULID/editto edit an existing app
Signed-in users get an "Apps" link in Datasette's top-right menu.
HTML apps managed by this plugin use lowercase monotonic ULIDs as their IDs and track every edit as a new row in app_revisions.
Sandboxed apps
Stored apps are rendered inside a sandboxed iframe. The plugin injects a Content Security Policy into the iframe srcdoc.
Direct network access is blocked unless the app has exact https:// origins configured. Those same origins are allowed for remote images, external script tags, and external stylesheet links/style elements. Localhost origins are never allowed. Local file previews using data: and blob: image URLs are allowed.
The iframe bridge reports JavaScript errors, unhandled promise rejections, CSP violations, failed resources, fetch failures, console.error() calls, and failed Datasette data queries back to the parent page. The app page shows these in a small expandable error panel above the iframe.
The bridge also replaces history.replaceState(), history.pushState(), history.back(), history.forward(), and history.go() with no-op functions inside the sandboxed iframe, avoiding browser errors from apps that try to manage URL state.
Data access
Stored apps can query Datasette data using the injected datasette.query(database, sql, params) helper.
They can also run allow-listed stored queries using datasette.storedQuery(database, query, params). The iframe sends those requests to the parent page with postMessage, and the parent page forwards them to an app-scoped query endpoint.
Apps have allow-lists configured on the edit page. If the requested database or stored query is allowed, the request is forwarded to Datasette's own JSON APIs using the current actor, so Datasette's normal SQL and query permissions still apply.
Failed stored-query attempts, including attempts to call a query that is not allow-listed or that the current actor cannot run, are reported in the app page error panel.
Stored query access is configured using a picker on the create and edit pages. The picker searches Datasette's /-/queries.json?q=search-term API and stores selected queries as database-name/query-name strings. Removing a query uses the x button next to that selected query. Additions and removals are not applied until the page is saved.
Permissions
The plugin registers Datasette permissions for create-app, view-app, edit-app, delete-app, and manage-app-access. Stored app owners can always view, edit, delete, and manage their own apps. Apps marked private are visible only to their owner, even if other users have broad view-app permission grants.
Deleting a stored app hides it from the catalog and disables access to its pages and query API. Its app_revisions rows remain in the database so a database administrator can recover it if needed.
Apps that are not private can be viewed by actors with the view-app permission. To let all signed-in users view all non-private apps, configure:
permissions:
view-app:
id: "*"
External apps registered by plugins are not private by default, so they also require view-app permission unless the registering plugin supplies its own permission rules.
Signed-in users can pin apps from the catalog and from individual stored app pages. Pinned apps appear first on /-/apps, and the three most recently used pinned apps are shown on the Datasette homepage using top_homepage().
The /-/apps catalog is searchable and paginated.
App authoring
The create and edit pages include a copyable prompt for an LLM. The prompt is assembled in the browser from the current form state, so unsaved changes to selected databases, stored queries, and network origins are reflected immediately. It explains the sandbox, the datasette.query() and datasette.storedQuery() bridges, CSP restrictions, the current schema summary, and only the stored queries selected for that app.
The create and edit pages use Datasette's existing bundled CodeMirror editor for the HTML source textarea.
The edit page includes a private checkbox, SQL query database access, stored query access, and allowed network origins.
Plugins can add their own apps to the central catalog during startup:
from datasette import hookimpl
from datasette_apps import Registry
@hookimpl
async def startup(datasette):
await Registry(datasette).add_app(
id="myplugin:example",
name="Example plugin app",
description="A plugin-owned app that appears in /-/apps",
path="/-/myplugin-example",
source="myplugin",
)
Plugins can remove a single external app from the catalog by ID:
await Registry(datasette).remove_app("myplugin:example")
Development
To set up this plugin locally, first checkout the code. You can confirm it is available like this:
cd datasette-apps
# Confirm the plugin is visible
uv run datasette plugins
To run the tests:
uv run pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file datasette_apps-0.1a0.tar.gz.
File metadata
- Download URL: datasette_apps-0.1a0.tar.gz
- Upload date:
- Size: 63.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0f42f1618615af6e191c0e07d5ac0cf4b2be216c978c88ec9bb19a36336dd2e
|
|
| MD5 |
70155e9e2e81a7a21fe00010e3e12418
|
|
| BLAKE2b-256 |
d87839ab38c26d362da4a06fe28b3cfd3f768c5be1060339bda346c3435f0820
|
Provenance
The following attestation bundles were made for datasette_apps-0.1a0.tar.gz:
Publisher:
publish.yml on datasette/datasette-apps
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
datasette_apps-0.1a0.tar.gz -
Subject digest:
e0f42f1618615af6e191c0e07d5ac0cf4b2be216c978c88ec9bb19a36336dd2e - Sigstore transparency entry: 1726081981
- Sigstore integration time:
-
Permalink:
datasette/datasette-apps@1cfe5fe9334146947517af6e713cc2a2e1dc25d4 -
Branch / Tag:
refs/tags/0.1a0 - Owner: https://github.com/datasette
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1cfe5fe9334146947517af6e713cc2a2e1dc25d4 -
Trigger Event:
release
-
Statement type:
File details
Details for the file datasette_apps-0.1a0-py3-none-any.whl.
File metadata
- Download URL: datasette_apps-0.1a0-py3-none-any.whl
- Upload date:
- Size: 50.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89e08b8ce4e6063ab4d04d08913001096f198f1b26cb2932f60b19a5c3f5db45
|
|
| MD5 |
8c38328da1f31dd6c01b1d94e2836eec
|
|
| BLAKE2b-256 |
4503b9e52c2e20b2552962f1787ec2d43cc758c32471137d5d88d74d0ca655b8
|
Provenance
The following attestation bundles were made for datasette_apps-0.1a0-py3-none-any.whl:
Publisher:
publish.yml on datasette/datasette-apps
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
datasette_apps-0.1a0-py3-none-any.whl -
Subject digest:
89e08b8ce4e6063ab4d04d08913001096f198f1b26cb2932f60b19a5c3f5db45 - Sigstore transparency entry: 1726082095
- Sigstore integration time:
-
Permalink:
datasette/datasette-apps@1cfe5fe9334146947517af6e713cc2a2e1dc25d4 -
Branch / Tag:
refs/tags/0.1a0 - Owner: https://github.com/datasette
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1cfe5fe9334146947517af6e713cc2a2e1dc25d4 -
Trigger Event:
release
-
Statement type: