supython 0.1.10__tar.gz → 0.1.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {supython-0.1.10 → supython-0.1.11}/.gitignore +9 -1
- {supython-0.1.10 → supython-0.1.11}/CHANGELOG.md +44 -2
- {supython-0.1.10 → supython-0.1.11}/PKG-INFO +45 -152
- {supython-0.1.10 → supython-0.1.11}/README.md +44 -151
- {supython-0.1.10 → supython-0.1.11}/pyproject.toml +1 -1
- {supython-0.1.10 → supython-0.1.11}/src/supython/cli.py +30 -12
- supython-0.1.11/src/supython/extensions.py +68 -0
- supython-0.1.11/src/supython/scaffold/init_project.py +217 -0
- supython-0.1.11/src/supython/scaffold/templates/README.md.tmpl +32 -0
- supython-0.1.10/src/supython/scaffold/templates/apps_hooks.py.tmpl → supython-0.1.11/src/supython/scaffold/templates/apps_hooks_welcome.py.tmpl +1 -1
- supython-0.1.10/src/supython/scaffold/templates/apps_jobs.py.tmpl → supython-0.1.11/src/supython/scaffold/templates/apps_jobs_example.py.tmpl +1 -1
- supython-0.1.11/src/supython/scaffold/templates/package_hooks_init.py.tmpl +8 -0
- supython-0.1.11/src/supython/scaffold/templates/package_jobs_init.py.tmpl +8 -0
- supython-0.1.11/src/supython/scaffold/templates/pyproject.toml.tmpl +15 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/settings.py.tmpl +5 -1
- supython-0.1.10/src/supython/migrations/0003_demo_todos.sql → supython-0.1.11/src/supython/scaffold/templates/static/0001_create_todos.sql +10 -3
- supython-0.1.11/src/supython/scaffold/templates/static/functions_hello.py +13 -0
- supython-0.1.10/src/supython/extensions.py +0 -36
- supython-0.1.10/src/supython/scaffold/init_project.py +0 -144
- supython-0.1.10/src/supython/scaffold/templates/README.md.tmpl +0 -22
- supython-0.1.10/src/supython/scaffold/templates/migrations/.gitkeep +0 -0
- {supython-0.1.10 → supython-0.1.11}/LICENSE +0 -0
- {supython-0.1.10 → supython-0.1.11}/SECURITY.md +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/auth.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/auth_templates.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/auth_users.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/db.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/functions.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/jobs.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/ops.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/realtime.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/service_auth.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/service_auth_templates.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/service_auth_users.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/service_db.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/service_functions.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/service_jobs.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/service_ops.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/service_realtime.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/service_storage.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/storage.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/api/system.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/audit.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/deps.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/errors.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/schemas.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/session.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/spa.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Alert-dluGVkos.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Alert-dluGVkos.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Audit-Njung3HI.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Audit-Njung3HI.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Backups-DzPlFgrm.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Backups-DzPlFgrm.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Buckets-ByacGkU1.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Buckets-ByacGkU1.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Channels-BoIuTtam.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Channels-BoIuTtam.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/ChevronRight-CtQH1EQ1.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/ChevronRight-CtQH1EQ1.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/CodeViewer-Bqy7-wvH.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/CodeViewer-Bqy7-wvH.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Crons-B67vc39F.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Crons-B67vc39F.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/DashboardView-CUTFVL6k.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/DashboardView-CUTFVL6k.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/DataTable-COAAWEft.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/DataTable-COAAWEft.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/DescriptionsItem-P8JUDaBs.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/DescriptionsItem-P8JUDaBs.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/DrawerContent-TpYTFgF1.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/DrawerContent-TpYTFgF1.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Empty-cr2r7e2u.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Empty-cr2r7e2u.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/EmptyState-DeDck-OL.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/EmptyState-DeDck-OL.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Grid-hFkp9F4P.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Grid-hFkp9F4P.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Input-DppYTq9C.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Input-DppYTq9C.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Invoke-DW3Nveeh.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Invoke-DW3Nveeh.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/JsonField-DibyJgun.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/JsonField-DibyJgun.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/LoginView-BjLyE3Ds.css +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/LoginView-CoOjECT_.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/LoginView-CoOjECT_.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Logs-D9WYrnIT.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Logs-D9WYrnIT.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Logs-DS1XPa0h.css +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Migrations-DOSC2ddQ.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Migrations-DOSC2ddQ.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/ObjectBrowser-_5w8vOX8.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/ObjectBrowser-_5w8vOX8.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Queue-CywZs6vI.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Queue-CywZs6vI.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/RefreshTokens-Ccjr53jg.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/RefreshTokens-Ccjr53jg.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/RlsEditor-BSlH9vSc.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/RlsEditor-BSlH9vSc.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Routes-BiLXE49D.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Routes-BiLXE49D.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Routes-C-ianIGD.css +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/SchemaBrowser-DKy2_KQi.css +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/SchemaBrowser-XFvFbtDB.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/SchemaBrowser-XFvFbtDB.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Select-DIzZyRZb.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Select-DIzZyRZb.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Space-n5-XcguU.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Space-n5-XcguU.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/SqlEditor-b8pTsILY.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/SqlEditor-b8pTsILY.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/SqlWorkspace-BUS7IntH.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/SqlWorkspace-BUS7IntH.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/TableData-CQIagLKn.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/TableData-CQIagLKn.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Tag-D1fOKpTH.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Tag-D1fOKpTH.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Templates-BS-ugkdq.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Templates-BS-ugkdq.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Thing-CEAniuMg.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Thing-CEAniuMg.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Users-wzwajhlh.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/Users-wzwajhlh.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/_plugin-vue_export-helper-DGA9ry_j.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/dist-VXIJLCYq.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/dist-VXIJLCYq.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/format-length-CGCY1rMh.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/format-length-CGCY1rMh.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/get-Ca6unauB.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/get-Ca6unauB.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/index-CeE6v959.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/index-CeE6v959.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/pinia-COXwfrOX.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/pinia-COXwfrOX.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/resources-Bt6thQCD.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/resources-Bt6thQCD.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/use-locale-mtgM0a3a.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/use-locale-mtgM0a3a.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/use-merged-state-BvhkaHNX.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/use-merged-state-BvhkaHNX.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/useConfirm-tMjvBFXR.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/useConfirm-tMjvBFXR.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/useResource-C_rJCY8C.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/useResource-C_rJCY8C.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/useTable-CnZc5zhi.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/useTable-CnZc5zhi.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/useTable-Dg0XlRlq.css +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/useToast-DsZKx0IX.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/useToast-DsZKx0IX.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/utils-sbXoq7Ir.js +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/assets/utils-sbXoq7Ir.js.map +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/favicon.svg +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/icons.svg +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/admin/static/index.html +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/app.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/_email_job.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/claims.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/deps.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/providers/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/providers/github.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/providers/google.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/providers/oauth.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/providers/registry.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/ratelimit.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/router.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/schemas.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/auth/service.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/backups/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/backups/_backup_job.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/backups/schemas.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/backups/service.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/body_size.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/client/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/client/_auth.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/client/_client.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/client/_config.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/client/_functions.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/client/_storage.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/client/py.typed +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/db.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/db_admin.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/functions/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/functions/context.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/functions/loader.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/functions/router.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/functions/schemas.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/gen/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/gen/_introspect.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/gen/types_py.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/gen/types_ts.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/health.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/hooks.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/backends.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/context.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/cron.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/cron_inproc.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/decorators.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/registry.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/router.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/schemas.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/service.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jobs/worker.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/jwks.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/keyset.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/logging_config.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/mail.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/mailer.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrate.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0001_extensions_and_roles.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0002_auth_schema.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0004_auth_v0_2.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0005_storage_schema.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0006_realtime_schema.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0007_jobs_schema.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0008_jobs_last_error.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0009_auth_rate_limits.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0010_worker_heartbeat.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0011_admin_schema.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0012_auth_banned_until.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0013_email_templates.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0014_realtime_payload_warning.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/migrations/0015_backups_schema.sql +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/passwords.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/realtime/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/realtime/broker.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/realtime/protocol.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/realtime/router.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/realtime/schemas.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/realtime/service.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/realtime/topics.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/realtime/websocket.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/Caddyfile.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/asgi.py.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/docker-compose.prod.yml.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/docker-compose.yml.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/docker_postgres_Dockerfile.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/docker_postgres_postgresql.conf.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/env.example.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/functions_README.md.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/gitignore.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/manage.py.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/scaffold/templates/package_init.py.tmpl +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/secretset.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/security_headers.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/settings.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/settings_module.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/storage/__init__.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/storage/backends.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/storage/router.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/storage/schemas.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/storage/service.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/storage/signing.py +0 -0
- {supython-0.1.10 → supython-0.1.11}/src/supython/tokens.py +0 -0
|
@@ -29,7 +29,8 @@ dev-app/backups/
|
|
|
29
29
|
dev-app/__pycache__/
|
|
30
30
|
dev-app/functions/__pycache__/
|
|
31
31
|
dev-app/.tmp/
|
|
32
|
-
|
|
32
|
+
dev-app/
|
|
33
|
+
examples/
|
|
33
34
|
.references/
|
|
34
35
|
.references/*.md
|
|
35
36
|
.claude/
|
|
@@ -43,3 +44,10 @@ ts-sdk/*.log
|
|
|
43
44
|
.tmp/
|
|
44
45
|
|
|
45
46
|
admin-ui/node_modules/
|
|
47
|
+
|
|
48
|
+
/.supython/secrets/
|
|
49
|
+
/.supython/secrets.json
|
|
50
|
+
/.supython/jwt_private.pem
|
|
51
|
+
/.supython/keys/
|
|
52
|
+
/.supython/keyset.json
|
|
53
|
+
/.supython/jwks.json
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to supython are recorded here. The format follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
5
|
-
project uses **ZeroVer** (`0.x.y`)
|
|
6
|
-
what counts as a breaking change. There is no scheduled `1.0.0`; treat
|
|
5
|
+
project uses **ZeroVer** (`0.x.y`). There is no scheduled `1.0.0`; treat
|
|
7
6
|
every `MINOR` as a potential breaking release.
|
|
8
7
|
|
|
9
8
|
Categories used per release:
|
|
@@ -31,6 +30,48 @@ Each entry links the relevant `PROJECT.md` section and decision-log row
|
|
|
31
30
|
|
|
32
31
|
---
|
|
33
32
|
|
|
33
|
+
## [0.1.11] — 2026-06-13
|
|
34
|
+
|
|
35
|
+
Project-initialization ergonomics. `supython init` now produces a project that
|
|
36
|
+
boots with no manual setup.
|
|
37
|
+
|
|
38
|
+
### Breaking
|
|
39
|
+
|
|
40
|
+
- `supython init` arguments changed. The first argument is now the **importable
|
|
41
|
+
package name** (still required); the optional second argument is the **target
|
|
42
|
+
directory** (Django-style — `.` for the current directory), defaulting to
|
|
43
|
+
`./<name>`. The `--here` flag is **removed**: `supython init myapp --here`
|
|
44
|
+
becomes `supython init myapp .`.
|
|
45
|
+
- The scaffolded `jobs.py` and `hooks.py` single-file seeds are replaced by
|
|
46
|
+
auto-discovered **packages** `<name>/jobs/` and `<name>/hooks/`. Every module
|
|
47
|
+
inside each package is imported at boot, so jobs and hooks can be split across
|
|
48
|
+
files. `EXTENSIONS` in `settings.py` now points at the packages (`<name>.jobs`,
|
|
49
|
+
`<name>.hooks`) rather than the old modules.
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
|
|
53
|
+
- `supython init` generates a ready-to-run, gitignored `.env` (from the example
|
|
54
|
+
template) so the stack boots without a manual `cp .env.example .env` step.
|
|
55
|
+
- `supython init` generates a `pyproject.toml` that declares the project and
|
|
56
|
+
pins the installed supython version; install the scaffold with `pip install -e .`.
|
|
57
|
+
- The scaffold seeds an example edge function (`functions/hello.py`) and an
|
|
58
|
+
example application migration (`migrations/0001_create_todos.sql`).
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- Re-running `supython init` is now a safe top-up: existing files are skipped,
|
|
63
|
+
not overwritten, unless `--force` is passed.
|
|
64
|
+
- The generated JWT keypair and signing secrets under `.supython/` are **never**
|
|
65
|
+
overwritten — not even with `--force` — to avoid silently rotating keys and
|
|
66
|
+
invalidating live tokens, sessions, and signed URLs. Rotation has dedicated
|
|
67
|
+
homes: `supython keygen` and `supython secret rotate`.
|
|
68
|
+
- The scaffolded `todos` table moved out of supython's framework migrations into
|
|
69
|
+
the project's own `migrations/`. `supython migrate` applies only supython's
|
|
70
|
+
framework schemas (auth, storage, realtime, jobs); apply your application
|
|
71
|
+
migrations with a tool of your choice (dbmate recommended).
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
34
75
|
## [0.1.10] — 2026-06-12
|
|
35
76
|
|
|
36
77
|
### Added
|
|
@@ -257,6 +298,7 @@ v0.1–v0.7 plus a v1.1.x admin track; see §19 decision log
|
|
|
257
298
|
---
|
|
258
299
|
|
|
259
300
|
|
|
301
|
+
[0.1.11]: https://github.com/Tkeby/supython/releases/tag/v0.1.11
|
|
260
302
|
[0.1.10]: https://github.com/Tkeby/supython/releases/tag/v0.1.10
|
|
261
303
|
[0.1.9]: https://github.com/Tkeby/supython/releases/tag/v0.1.9
|
|
262
304
|
[0.1.0]: https://github.com/Tkeby/supython/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: supython
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: A lightweight Postgres-first BaaS framework for Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/Tkeby/supython
|
|
6
6
|
Project-URL: Repository, https://github.com/Tkeby/supython
|
|
@@ -153,20 +153,25 @@ python -m venv .venv && source .venv/bin/activate
|
|
|
153
153
|
pip install supython
|
|
154
154
|
|
|
155
155
|
# 2. scaffold a new project
|
|
156
|
+
# `myapp` is the importable package name. An optional second argument
|
|
157
|
+
# sets the target dir (`.` = current dir); it defaults to ./myapp.
|
|
156
158
|
supython init myapp
|
|
157
159
|
cd myapp
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
# the value PostgREST will use (docker-compose.yml injects it via env).
|
|
160
|
+
# install the project (and supython, pinned in the generated pyproject.toml)
|
|
161
|
+
pip install -e .
|
|
161
162
|
#
|
|
162
|
-
# The scaffold
|
|
163
|
-
#
|
|
163
|
+
# The scaffold generates a ready-to-run, gitignored .env plus a JWT keypair
|
|
164
|
+
# and signing secrets under .supython/ — no manual edits needed to boot.
|
|
165
|
+
# It also creates:
|
|
166
|
+
# pyproject.toml — declares this project, pins the supython version
|
|
164
167
|
# myapp/settings.py — declare EXTENSIONS, EXTRA_ROUTERS, EXTRA_MIDDLEWARE
|
|
165
|
-
# myapp/jobs
|
|
166
|
-
# myapp/hooks
|
|
168
|
+
# myapp/jobs/ — package of @job / @cron modules (all auto-imported)
|
|
169
|
+
# myapp/hooks/ — package of @on(...) lifecycle hooks (all auto-imported)
|
|
167
170
|
# myapp/asgi.py — optional entrypoint for uvicorn/gunicorn
|
|
171
|
+
# functions/hello.py — example edge function (GET /functions/hello)
|
|
172
|
+
# migrations/0001_create_todos.sql — example app migration (apply with dbmate)
|
|
168
173
|
|
|
169
|
-
# 3. boot Postgres + PostgREST and
|
|
174
|
+
# 3. boot Postgres + PostgREST and apply supython's framework migrations
|
|
170
175
|
supython up
|
|
171
176
|
|
|
172
177
|
# 4. run the auth/API service (separate terminal)
|
|
@@ -191,6 +196,10 @@ You should now have:
|
|
|
191
196
|
|
|
192
197
|
## End-to-end smoke test
|
|
193
198
|
|
|
199
|
+
This uses the scaffolded `todos` table, so first apply the example app migration
|
|
200
|
+
(`migrations/0001_create_todos.sql`) with [dbmate](https://github.com/amacneil/dbmate)
|
|
201
|
+
or your migration tool of choice — `supython migrate` only handles framework schemas.
|
|
202
|
+
|
|
194
203
|
```bash
|
|
195
204
|
# sign up
|
|
196
205
|
curl -sS -X POST http://localhost:8000/auth/v1/signup \
|
|
@@ -532,128 +541,31 @@ need to edit SQL.
|
|
|
532
541
|
|
|
533
542
|
```
|
|
534
543
|
supython/
|
|
535
|
-
├──
|
|
536
|
-
├──
|
|
537
|
-
├──
|
|
538
|
-
├──
|
|
539
|
-
├──
|
|
540
|
-
├──
|
|
541
|
-
│ ├──
|
|
542
|
-
│ ├──
|
|
543
|
-
│ ├──
|
|
544
|
-
│ ├──
|
|
545
|
-
│
|
|
546
|
-
├──
|
|
547
|
-
│ ├──
|
|
548
|
-
│ ├──
|
|
549
|
-
│ ├──
|
|
550
|
-
│ ├──
|
|
551
|
-
│ ├──
|
|
552
|
-
│
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
│ ├── 0014_realtime_payload_warning.sql # >8KB payload warning counter
|
|
561
|
-
│ └── 0015_backups_schema.sql # backups metadata
|
|
562
|
-
├── examples/
|
|
563
|
-
│ ├── todos.http # HTTP smoke tests (auth + PostgREST)
|
|
564
|
-
│ ├── storage.http # storage upload / signed URL examples
|
|
565
|
-
│ ├── functions.http # edge-function call examples
|
|
566
|
-
│ └── chat.html # two-browser realtime demo (vanilla JS, zero deps)
|
|
567
|
-
├── docs/
|
|
568
|
-
│ ├── PROJECT.md # architecture + roadmap (single source of truth)
|
|
569
|
-
│ ├── Installation.md # full install guide (dev, prod, managed Postgres)
|
|
570
|
-
│ └── admin-ui/
|
|
571
|
-
│ ├── admin-surface-plan.md # admin implementation plan + phase status
|
|
572
|
-
│ └── admin-surface.md # admin architecture + contracts
|
|
573
|
-
├── tests/
|
|
574
|
-
│ ├── conftest.py # cross-tree fixtures (keys, capturing mailer)
|
|
575
|
-
│ ├── _keys.py # JWT-forging helpers
|
|
576
|
-
│ ├── fixtures/ # test function modules, etc.
|
|
577
|
-
│ ├── unit/ # pure-Python tests (~6s, no Docker)
|
|
578
|
-
│ │ ├── test_admin_session.py
|
|
579
|
-
│ │ ├── test_admin_service_db.py
|
|
580
|
-
│ │ └── ...
|
|
581
|
-
│ └── integration/ # full ASGI + Postgres on port 54323
|
|
582
|
-
│ ├── conftest.py # pool, app, client, autouse DB cleaners
|
|
583
|
-
│ ├── test_auth_signup_login.py
|
|
584
|
-
│ ├── test_admin_auth.py
|
|
585
|
-
│ ├── test_admin_auth_users.py
|
|
586
|
-
│ ├── test_admin_db_rows.py
|
|
587
|
-
│ ├── test_admin_jobs.py
|
|
588
|
-
│ ├── test_admin_ops_backups.py
|
|
589
|
-
│ ├── test_admin_storage.py
|
|
590
|
-
│ ├── test_postgrest_rls.py
|
|
591
|
-
│ ├── test_realtime_ws.py
|
|
592
|
-
│ └── ...
|
|
593
|
-
├── admin-ui/ # Vue 3 + Vite SPA (built → src/supython/admin/static/)
|
|
594
|
-
│ └── src/
|
|
595
|
-
│ ├── api/ # single fetch seam
|
|
596
|
-
│ ├── components/ # shell, data, editors, feedback
|
|
597
|
-
│ ├── composables/ # useResource, useTable, useConfirm, useImpersonate, …
|
|
598
|
-
│ ├── stores/ # auth, ui
|
|
599
|
-
│ ├── views/ # Dashboard, db/, auth/, storage/, functions/, …
|
|
600
|
-
│ └── router/
|
|
601
|
-
└── src/supython/
|
|
602
|
-
├── __init__.py # single version string
|
|
603
|
-
├── settings.py # pydantic-settings, .env-driven
|
|
604
|
-
├── db.py # asyncpg pool + lifespan + as_role() / as_service_role()
|
|
605
|
-
├── mailer.py # ConsoleBackend / SmtpBackend
|
|
606
|
-
├── tokens.py # RS256/ES256 JWT + JWKS
|
|
607
|
-
├── passwords.py # argon2id
|
|
608
|
-
├── migrate.py # ~50-line SQL migration runner
|
|
609
|
-
├── app.py # FastAPI factory
|
|
610
|
-
├── cli.py # typer: up, dev, keygen, admin, worker, test, …
|
|
611
|
-
├── extensions.py # eager-import dotted module paths at boot
|
|
612
|
-
├── settings_module.py # user settings (EXTENSIONS, EXTRA_ROUTERS, …)
|
|
613
|
-
├── health.py # /livez, /readyz, /health endpoints
|
|
614
|
-
├── logging_config.py # structured JSON log setup
|
|
615
|
-
├── security_headers.py # HSTS, CSP, etc.
|
|
616
|
-
├── body_size.py # request body size guards
|
|
617
|
-
├── jwks.py # JWKS generation + rotation helpers
|
|
618
|
-
├── keyset.py # asymmetric key rotation manifest
|
|
619
|
-
├── secretset.py # symmetric secret rotation manifest
|
|
620
|
-
├── hooks.py # generic hook system: on() / fire()
|
|
621
|
-
├── mail.py # email send with job-retry fallback
|
|
622
|
-
├── auth/
|
|
623
|
-
│ ├── schemas.py
|
|
624
|
-
│ ├── service.py # full auth layer: signup / OAuth / OTP / recover …
|
|
625
|
-
│ ├── router.py # all /auth/v1/* routes
|
|
626
|
-
│ └── providers/ # Google, GitHub, OAuth2 helpers
|
|
627
|
-
├── storage/
|
|
628
|
-
│ ├── backends.py # LocalBackend, S3Backend
|
|
629
|
-
│ ├── service.py
|
|
630
|
-
│ └── router.py # /storage/v1/*
|
|
631
|
-
├── functions/
|
|
632
|
-
│ ├── loader.py # filesystem discovery + hot reload
|
|
633
|
-
│ └── router.py # /functions/v1/*
|
|
634
|
-
├── realtime/
|
|
635
|
-
│ ├── protocol.py # Phoenix Channels encode/decode
|
|
636
|
-
│ ├── broker.py # fan-out engine with RLS filtering
|
|
637
|
-
│ ├── websocket.py # WS route with JWT auth
|
|
638
|
-
│ └── router.py # /realtime/v1/*
|
|
639
|
-
├── jobs/
|
|
640
|
-
│ ├── registry.py # @job / @cron decorator store
|
|
641
|
-
│ ├── service.py # enqueue, claim_next, mark_*
|
|
642
|
-
│ ├── worker.py # long-running poll/dispatch/drain loop
|
|
643
|
-
│ ├── cron.py # pg_cron sync + InProcScheduler
|
|
644
|
-
│ └── router.py # /jobs/v1/*
|
|
645
|
-
├── admin/
|
|
646
|
-
│ ├── session.py # admin cookie session (SHA-256 hashed, 8h TTL)
|
|
647
|
-
│ ├── deps.py # require_admin dependency
|
|
648
|
-
│ ├── spa.py # static SPA mount + index.html fallback
|
|
649
|
-
│ ├── schemas.py # shared Pydantic models
|
|
650
|
-
│ ├── audit.py # admin audit log writer
|
|
651
|
-
│ ├── static/ # pre-built Vue 3 SPA bundle (committed)
|
|
652
|
-
│ └── api/ # /admin/api/v1/* route handlers
|
|
653
|
-
├── backups/ # pg_dump wrapper + restore
|
|
654
|
-
├── gen/ # supython gen types --lang py|ts
|
|
655
|
-
├── scaffold/ # supython init templates
|
|
656
|
-
└── client/ # Python SDK (optional [client] extra)
|
|
544
|
+
├── src/supython/ # the FastAPI service + CLI (the published package)
|
|
545
|
+
│ ├── app.py # FastAPI factory
|
|
546
|
+
│ ├── cli.py # typer CLI: init, up, dev, worker, migrate, gen, …
|
|
547
|
+
│ ├── db.py # asyncpg pool + as_role() / as_service_role()
|
|
548
|
+
│ ├── settings.py # pydantic-settings, .env-driven
|
|
549
|
+
│ ├── tokens.py # RS256/ES256 JWT + JWKS
|
|
550
|
+
│ ├── migrate.py # ~50-line SQL migration runner
|
|
551
|
+
│ ├── migrations/ # framework schema (auth, storage, realtime, jobs, …)
|
|
552
|
+
│ ├── auth/ # /auth/v1/* — signup, OAuth, OTP, recovery
|
|
553
|
+
│ ├── storage/ # /storage/v1/* — local + S3 backends
|
|
554
|
+
│ ├── functions/ # /functions/v1/* — filesystem-discovered handlers
|
|
555
|
+
│ ├── realtime/ # /realtime/v1/* — Phoenix Channels over LISTEN/NOTIFY
|
|
556
|
+
│ ├── jobs/ # /jobs/v1/* — queue, worker, pg_cron scheduling
|
|
557
|
+
│ ├── admin/ # /admin/api/v1/* + the built Vue SPA (static/)
|
|
558
|
+
│ ├── backups/ # pg_dump wrapper + restore
|
|
559
|
+
│ ├── gen/ # `supython gen types --lang py|ts`
|
|
560
|
+
│ ├── scaffold/ # `supython init` templates
|
|
561
|
+
│ └── client/ # optional Python SDK ([client] extra)
|
|
562
|
+
├── admin-ui/ # Vue 3 + Vite SPA, built → src/supython/admin/static/
|
|
563
|
+
├── ts-sdk/ # @supython/sdk — TypeScript SDK
|
|
564
|
+
├── dev-app/ # scaffolded sample project for local development
|
|
565
|
+
├── examples/ # .http smoke tests + chat.html realtime demo
|
|
566
|
+
├── tests/ # unit/ (no Docker) + integration/ (Postgres :54323)
|
|
567
|
+
├── Dockerfile
|
|
568
|
+
└── pyproject.toml
|
|
657
569
|
```
|
|
658
570
|
|
|
659
571
|
## Plugins & extensions
|
|
@@ -693,10 +605,10 @@ supython down # stop the stack (keeps data)
|
|
|
693
605
|
supython down --prod # stop the prod stack
|
|
694
606
|
supython reset # stop the stack and DELETE the volume (destructive)
|
|
695
607
|
supython reset --prod # stop prod stack and DELETE volumes
|
|
696
|
-
supython migrate # apply
|
|
608
|
+
supython migrate # apply supython's framework migrations (auth, storage, …)
|
|
697
609
|
supython info # print resolved settings
|
|
698
610
|
supython doctor # diagnose roles, extensions, JWKS, grants, migration drift
|
|
699
|
-
supython init <
|
|
611
|
+
supython init <pkg> [dir] # scaffold a project (pkg = package name; dir defaults to ./<pkg>)
|
|
700
612
|
supython gen types --lang py --out db_schema.py # emit typed dataclasses + TypedDicts
|
|
701
613
|
supython gen types --lang ts --out types.ts # emit TypeScript Database interface
|
|
702
614
|
|
|
@@ -819,25 +731,6 @@ unit tests always run in isolation.
|
|
|
819
731
|
**CI:** runners with Docker run `supython test up && supython test run`;
|
|
820
732
|
runners without Docker run `pytest tests/unit` for a meaningful subset.
|
|
821
733
|
|
|
822
|
-
## Roadmap
|
|
823
|
-
|
|
824
|
-
- ✅ Email/password auth, PostgREST contract, RLS demo
|
|
825
|
-
- ✅ OAuth, password reset, magic link, OTP, reuse detection, email backend, test suite
|
|
826
|
-
- ✅ Storage (S3/local) with RLS-on-metadata, edge-style functions from a `functions/` directory; `db.as_role(role, claims)` helper; `supython init` scaffold; `supython gen types --lang py`
|
|
827
|
-
- ✅ Realtime over `LISTEN/NOTIFY` with RLS-aware fan-out; Phoenix Channels wire format; broadcast + presence; `examples/chat.html` demo
|
|
828
|
-
- ✅ Job queue worker + `pg_cron` scheduling + hooks + CLI management commands
|
|
829
|
-
- ✅ Grooming + security foundation: unified versioning, CORS closed by default, RS256 JWT, rate limiting, `supython doctor`, pool sizing, statement timeout
|
|
830
|
-
- ✅ Production observable: structured JSON logs, `/livez`/`/readyz`/`/health`, security headers, input size guards, audit log completeness, OAuth PKCE, secret rotation runbooks
|
|
831
|
-
- ✅ (partial) Multi-arch Docker images, admin control plane (Vue 3 SPA — database, auth, storage, functions, realtime, jobs, backups, log tail), CI buildx workflow; benchmarks + security audit pass + dependency budget CI remaining
|
|
832
|
-
- *(deferred)* — Realtime v2 over logical replication
|
|
833
|
-
- ✅ **TypeScript SDK** — `@supython/sdk` wrapping `@supabase/postgrest-js` + `@supabase/realtime-js`
|
|
834
|
-
|
|
835
|
-
### Future
|
|
836
|
-
|
|
837
|
-
- **Admin control plane** polish (tests + remaining DoD items)
|
|
838
|
-
- **Realtime v2** — logical replication (demand-driven; swap when trigger overhead or >8KB payload data warrants it)
|
|
839
|
-
- **Prometheus `/metrics`** + **OpenTelemetry** — optional extras
|
|
840
|
-
|
|
841
734
|
## License
|
|
842
735
|
|
|
843
736
|
MIT
|
|
@@ -94,20 +94,25 @@ python -m venv .venv && source .venv/bin/activate
|
|
|
94
94
|
pip install supython
|
|
95
95
|
|
|
96
96
|
# 2. scaffold a new project
|
|
97
|
+
# `myapp` is the importable package name. An optional second argument
|
|
98
|
+
# sets the target dir (`.` = current dir); it defaults to ./myapp.
|
|
97
99
|
supython init myapp
|
|
98
100
|
cd myapp
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
# the value PostgREST will use (docker-compose.yml injects it via env).
|
|
101
|
+
# install the project (and supython, pinned in the generated pyproject.toml)
|
|
102
|
+
pip install -e .
|
|
102
103
|
#
|
|
103
|
-
# The scaffold
|
|
104
|
-
#
|
|
104
|
+
# The scaffold generates a ready-to-run, gitignored .env plus a JWT keypair
|
|
105
|
+
# and signing secrets under .supython/ — no manual edits needed to boot.
|
|
106
|
+
# It also creates:
|
|
107
|
+
# pyproject.toml — declares this project, pins the supython version
|
|
105
108
|
# myapp/settings.py — declare EXTENSIONS, EXTRA_ROUTERS, EXTRA_MIDDLEWARE
|
|
106
|
-
# myapp/jobs
|
|
107
|
-
# myapp/hooks
|
|
109
|
+
# myapp/jobs/ — package of @job / @cron modules (all auto-imported)
|
|
110
|
+
# myapp/hooks/ — package of @on(...) lifecycle hooks (all auto-imported)
|
|
108
111
|
# myapp/asgi.py — optional entrypoint for uvicorn/gunicorn
|
|
112
|
+
# functions/hello.py — example edge function (GET /functions/hello)
|
|
113
|
+
# migrations/0001_create_todos.sql — example app migration (apply with dbmate)
|
|
109
114
|
|
|
110
|
-
# 3. boot Postgres + PostgREST and
|
|
115
|
+
# 3. boot Postgres + PostgREST and apply supython's framework migrations
|
|
111
116
|
supython up
|
|
112
117
|
|
|
113
118
|
# 4. run the auth/API service (separate terminal)
|
|
@@ -132,6 +137,10 @@ You should now have:
|
|
|
132
137
|
|
|
133
138
|
## End-to-end smoke test
|
|
134
139
|
|
|
140
|
+
This uses the scaffolded `todos` table, so first apply the example app migration
|
|
141
|
+
(`migrations/0001_create_todos.sql`) with [dbmate](https://github.com/amacneil/dbmate)
|
|
142
|
+
or your migration tool of choice — `supython migrate` only handles framework schemas.
|
|
143
|
+
|
|
135
144
|
```bash
|
|
136
145
|
# sign up
|
|
137
146
|
curl -sS -X POST http://localhost:8000/auth/v1/signup \
|
|
@@ -473,128 +482,31 @@ need to edit SQL.
|
|
|
473
482
|
|
|
474
483
|
```
|
|
475
484
|
supython/
|
|
476
|
-
├──
|
|
477
|
-
├──
|
|
478
|
-
├──
|
|
479
|
-
├──
|
|
480
|
-
├──
|
|
481
|
-
├──
|
|
482
|
-
│ ├──
|
|
483
|
-
│ ├──
|
|
484
|
-
│ ├──
|
|
485
|
-
│ ├──
|
|
486
|
-
│
|
|
487
|
-
├──
|
|
488
|
-
│ ├──
|
|
489
|
-
│ ├──
|
|
490
|
-
│ ├──
|
|
491
|
-
│ ├──
|
|
492
|
-
│ ├──
|
|
493
|
-
│
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
│ ├── 0014_realtime_payload_warning.sql # >8KB payload warning counter
|
|
502
|
-
│ └── 0015_backups_schema.sql # backups metadata
|
|
503
|
-
├── examples/
|
|
504
|
-
│ ├── todos.http # HTTP smoke tests (auth + PostgREST)
|
|
505
|
-
│ ├── storage.http # storage upload / signed URL examples
|
|
506
|
-
│ ├── functions.http # edge-function call examples
|
|
507
|
-
│ └── chat.html # two-browser realtime demo (vanilla JS, zero deps)
|
|
508
|
-
├── docs/
|
|
509
|
-
│ ├── PROJECT.md # architecture + roadmap (single source of truth)
|
|
510
|
-
│ ├── Installation.md # full install guide (dev, prod, managed Postgres)
|
|
511
|
-
│ └── admin-ui/
|
|
512
|
-
│ ├── admin-surface-plan.md # admin implementation plan + phase status
|
|
513
|
-
│ └── admin-surface.md # admin architecture + contracts
|
|
514
|
-
├── tests/
|
|
515
|
-
│ ├── conftest.py # cross-tree fixtures (keys, capturing mailer)
|
|
516
|
-
│ ├── _keys.py # JWT-forging helpers
|
|
517
|
-
│ ├── fixtures/ # test function modules, etc.
|
|
518
|
-
│ ├── unit/ # pure-Python tests (~6s, no Docker)
|
|
519
|
-
│ │ ├── test_admin_session.py
|
|
520
|
-
│ │ ├── test_admin_service_db.py
|
|
521
|
-
│ │ └── ...
|
|
522
|
-
│ └── integration/ # full ASGI + Postgres on port 54323
|
|
523
|
-
│ ├── conftest.py # pool, app, client, autouse DB cleaners
|
|
524
|
-
│ ├── test_auth_signup_login.py
|
|
525
|
-
│ ├── test_admin_auth.py
|
|
526
|
-
│ ├── test_admin_auth_users.py
|
|
527
|
-
│ ├── test_admin_db_rows.py
|
|
528
|
-
│ ├── test_admin_jobs.py
|
|
529
|
-
│ ├── test_admin_ops_backups.py
|
|
530
|
-
│ ├── test_admin_storage.py
|
|
531
|
-
│ ├── test_postgrest_rls.py
|
|
532
|
-
│ ├── test_realtime_ws.py
|
|
533
|
-
│ └── ...
|
|
534
|
-
├── admin-ui/ # Vue 3 + Vite SPA (built → src/supython/admin/static/)
|
|
535
|
-
│ └── src/
|
|
536
|
-
│ ├── api/ # single fetch seam
|
|
537
|
-
│ ├── components/ # shell, data, editors, feedback
|
|
538
|
-
│ ├── composables/ # useResource, useTable, useConfirm, useImpersonate, …
|
|
539
|
-
│ ├── stores/ # auth, ui
|
|
540
|
-
│ ├── views/ # Dashboard, db/, auth/, storage/, functions/, …
|
|
541
|
-
│ └── router/
|
|
542
|
-
└── src/supython/
|
|
543
|
-
├── __init__.py # single version string
|
|
544
|
-
├── settings.py # pydantic-settings, .env-driven
|
|
545
|
-
├── db.py # asyncpg pool + lifespan + as_role() / as_service_role()
|
|
546
|
-
├── mailer.py # ConsoleBackend / SmtpBackend
|
|
547
|
-
├── tokens.py # RS256/ES256 JWT + JWKS
|
|
548
|
-
├── passwords.py # argon2id
|
|
549
|
-
├── migrate.py # ~50-line SQL migration runner
|
|
550
|
-
├── app.py # FastAPI factory
|
|
551
|
-
├── cli.py # typer: up, dev, keygen, admin, worker, test, …
|
|
552
|
-
├── extensions.py # eager-import dotted module paths at boot
|
|
553
|
-
├── settings_module.py # user settings (EXTENSIONS, EXTRA_ROUTERS, …)
|
|
554
|
-
├── health.py # /livez, /readyz, /health endpoints
|
|
555
|
-
├── logging_config.py # structured JSON log setup
|
|
556
|
-
├── security_headers.py # HSTS, CSP, etc.
|
|
557
|
-
├── body_size.py # request body size guards
|
|
558
|
-
├── jwks.py # JWKS generation + rotation helpers
|
|
559
|
-
├── keyset.py # asymmetric key rotation manifest
|
|
560
|
-
├── secretset.py # symmetric secret rotation manifest
|
|
561
|
-
├── hooks.py # generic hook system: on() / fire()
|
|
562
|
-
├── mail.py # email send with job-retry fallback
|
|
563
|
-
├── auth/
|
|
564
|
-
│ ├── schemas.py
|
|
565
|
-
│ ├── service.py # full auth layer: signup / OAuth / OTP / recover …
|
|
566
|
-
│ ├── router.py # all /auth/v1/* routes
|
|
567
|
-
│ └── providers/ # Google, GitHub, OAuth2 helpers
|
|
568
|
-
├── storage/
|
|
569
|
-
│ ├── backends.py # LocalBackend, S3Backend
|
|
570
|
-
│ ├── service.py
|
|
571
|
-
│ └── router.py # /storage/v1/*
|
|
572
|
-
├── functions/
|
|
573
|
-
│ ├── loader.py # filesystem discovery + hot reload
|
|
574
|
-
│ └── router.py # /functions/v1/*
|
|
575
|
-
├── realtime/
|
|
576
|
-
│ ├── protocol.py # Phoenix Channels encode/decode
|
|
577
|
-
│ ├── broker.py # fan-out engine with RLS filtering
|
|
578
|
-
│ ├── websocket.py # WS route with JWT auth
|
|
579
|
-
│ └── router.py # /realtime/v1/*
|
|
580
|
-
├── jobs/
|
|
581
|
-
│ ├── registry.py # @job / @cron decorator store
|
|
582
|
-
│ ├── service.py # enqueue, claim_next, mark_*
|
|
583
|
-
│ ├── worker.py # long-running poll/dispatch/drain loop
|
|
584
|
-
│ ├── cron.py # pg_cron sync + InProcScheduler
|
|
585
|
-
│ └── router.py # /jobs/v1/*
|
|
586
|
-
├── admin/
|
|
587
|
-
│ ├── session.py # admin cookie session (SHA-256 hashed, 8h TTL)
|
|
588
|
-
│ ├── deps.py # require_admin dependency
|
|
589
|
-
│ ├── spa.py # static SPA mount + index.html fallback
|
|
590
|
-
│ ├── schemas.py # shared Pydantic models
|
|
591
|
-
│ ├── audit.py # admin audit log writer
|
|
592
|
-
│ ├── static/ # pre-built Vue 3 SPA bundle (committed)
|
|
593
|
-
│ └── api/ # /admin/api/v1/* route handlers
|
|
594
|
-
├── backups/ # pg_dump wrapper + restore
|
|
595
|
-
├── gen/ # supython gen types --lang py|ts
|
|
596
|
-
├── scaffold/ # supython init templates
|
|
597
|
-
└── client/ # Python SDK (optional [client] extra)
|
|
485
|
+
├── src/supython/ # the FastAPI service + CLI (the published package)
|
|
486
|
+
│ ├── app.py # FastAPI factory
|
|
487
|
+
│ ├── cli.py # typer CLI: init, up, dev, worker, migrate, gen, …
|
|
488
|
+
│ ├── db.py # asyncpg pool + as_role() / as_service_role()
|
|
489
|
+
│ ├── settings.py # pydantic-settings, .env-driven
|
|
490
|
+
│ ├── tokens.py # RS256/ES256 JWT + JWKS
|
|
491
|
+
│ ├── migrate.py # ~50-line SQL migration runner
|
|
492
|
+
│ ├── migrations/ # framework schema (auth, storage, realtime, jobs, …)
|
|
493
|
+
│ ├── auth/ # /auth/v1/* — signup, OAuth, OTP, recovery
|
|
494
|
+
│ ├── storage/ # /storage/v1/* — local + S3 backends
|
|
495
|
+
│ ├── functions/ # /functions/v1/* — filesystem-discovered handlers
|
|
496
|
+
│ ├── realtime/ # /realtime/v1/* — Phoenix Channels over LISTEN/NOTIFY
|
|
497
|
+
│ ├── jobs/ # /jobs/v1/* — queue, worker, pg_cron scheduling
|
|
498
|
+
│ ├── admin/ # /admin/api/v1/* + the built Vue SPA (static/)
|
|
499
|
+
│ ├── backups/ # pg_dump wrapper + restore
|
|
500
|
+
│ ├── gen/ # `supython gen types --lang py|ts`
|
|
501
|
+
│ ├── scaffold/ # `supython init` templates
|
|
502
|
+
│ └── client/ # optional Python SDK ([client] extra)
|
|
503
|
+
├── admin-ui/ # Vue 3 + Vite SPA, built → src/supython/admin/static/
|
|
504
|
+
├── ts-sdk/ # @supython/sdk — TypeScript SDK
|
|
505
|
+
├── dev-app/ # scaffolded sample project for local development
|
|
506
|
+
├── examples/ # .http smoke tests + chat.html realtime demo
|
|
507
|
+
├── tests/ # unit/ (no Docker) + integration/ (Postgres :54323)
|
|
508
|
+
├── Dockerfile
|
|
509
|
+
└── pyproject.toml
|
|
598
510
|
```
|
|
599
511
|
|
|
600
512
|
## Plugins & extensions
|
|
@@ -634,10 +546,10 @@ supython down # stop the stack (keeps data)
|
|
|
634
546
|
supython down --prod # stop the prod stack
|
|
635
547
|
supython reset # stop the stack and DELETE the volume (destructive)
|
|
636
548
|
supython reset --prod # stop prod stack and DELETE volumes
|
|
637
|
-
supython migrate # apply
|
|
549
|
+
supython migrate # apply supython's framework migrations (auth, storage, …)
|
|
638
550
|
supython info # print resolved settings
|
|
639
551
|
supython doctor # diagnose roles, extensions, JWKS, grants, migration drift
|
|
640
|
-
supython init <
|
|
552
|
+
supython init <pkg> [dir] # scaffold a project (pkg = package name; dir defaults to ./<pkg>)
|
|
641
553
|
supython gen types --lang py --out db_schema.py # emit typed dataclasses + TypedDicts
|
|
642
554
|
supython gen types --lang ts --out types.ts # emit TypeScript Database interface
|
|
643
555
|
|
|
@@ -760,25 +672,6 @@ unit tests always run in isolation.
|
|
|
760
672
|
**CI:** runners with Docker run `supython test up && supython test run`;
|
|
761
673
|
runners without Docker run `pytest tests/unit` for a meaningful subset.
|
|
762
674
|
|
|
763
|
-
## Roadmap
|
|
764
|
-
|
|
765
|
-
- ✅ Email/password auth, PostgREST contract, RLS demo
|
|
766
|
-
- ✅ OAuth, password reset, magic link, OTP, reuse detection, email backend, test suite
|
|
767
|
-
- ✅ Storage (S3/local) with RLS-on-metadata, edge-style functions from a `functions/` directory; `db.as_role(role, claims)` helper; `supython init` scaffold; `supython gen types --lang py`
|
|
768
|
-
- ✅ Realtime over `LISTEN/NOTIFY` with RLS-aware fan-out; Phoenix Channels wire format; broadcast + presence; `examples/chat.html` demo
|
|
769
|
-
- ✅ Job queue worker + `pg_cron` scheduling + hooks + CLI management commands
|
|
770
|
-
- ✅ Grooming + security foundation: unified versioning, CORS closed by default, RS256 JWT, rate limiting, `supython doctor`, pool sizing, statement timeout
|
|
771
|
-
- ✅ Production observable: structured JSON logs, `/livez`/`/readyz`/`/health`, security headers, input size guards, audit log completeness, OAuth PKCE, secret rotation runbooks
|
|
772
|
-
- ✅ (partial) Multi-arch Docker images, admin control plane (Vue 3 SPA — database, auth, storage, functions, realtime, jobs, backups, log tail), CI buildx workflow; benchmarks + security audit pass + dependency budget CI remaining
|
|
773
|
-
- *(deferred)* — Realtime v2 over logical replication
|
|
774
|
-
- ✅ **TypeScript SDK** — `@supython/sdk` wrapping `@supabase/postgrest-js` + `@supabase/realtime-js`
|
|
775
|
-
|
|
776
|
-
### Future
|
|
777
|
-
|
|
778
|
-
- **Admin control plane** polish (tests + remaining DoD items)
|
|
779
|
-
- **Realtime v2** — logical replication (demand-driven; swap when trigger overhead or >8KB payload data warrants it)
|
|
780
|
-
- **Prometheus `/metrics`** + **OpenTelemetry** — optional extras
|
|
781
|
-
|
|
782
675
|
## License
|
|
783
676
|
|
|
784
677
|
MIT
|