MetaList 0.3.10__tar.gz → 0.3.12__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.
- {metalist-0.3.10 → metalist-0.3.12}/PKG-INFO +52 -69
- {metalist-0.3.10 → metalist-0.3.12}/README.md +47 -68
- {metalist-0.3.10 → metalist-0.3.12}/app/api/middleware/auth.py +30 -29
- {metalist-0.3.10 → metalist-0.3.12}/app/api/request_auth.py +12 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/api/routes/auth.py +21 -22
- {metalist-0.3.10 → metalist-0.3.12}/app/api/routes/backups.py +49 -39
- {metalist-0.3.10 → metalist-0.3.12}/app/api/routes/notes.py +74 -2
- metalist-0.3.12/app/api/routes/remote_images.py +88 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/config.py +5 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/file_session.py +2 -2
- {metalist-0.3.10 → metalist-0.3.12}/app/db/migrations.py +13 -3
- {metalist-0.3.10 → metalist-0.3.12}/app/db/schema.py +24 -0
- metalist-0.3.12/app/db/version.py +3 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/encryption_audit.py +123 -8
- {metalist-0.3.10 → metalist-0.3.12}/app/main.py +63 -42
- {metalist-0.3.10 → metalist-0.3.12}/app/models/database.py +2 -2
- {metalist-0.3.10 → metalist-0.3.12}/app/models/note_crud.py +6 -4
- {metalist-0.3.10 → metalist-0.3.12}/app/models/utils.py +22 -19
- metalist-0.3.12/app/security/http_headers.py +43 -0
- metalist-0.3.12/app/security/note_html.py +204 -0
- metalist-0.3.12/app/security/request_boundary.py +244 -0
- metalist-0.3.12/app/security/sensitive_logging.py +14 -0
- metalist-0.3.12/app/security/shell_execution.py +40 -0
- metalist-0.3.12/app/security/validation_errors.py +29 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/server_runtime.py +22 -95
- {metalist-0.3.10 → metalist-0.3.12}/app/services/auth_service.py +43 -8
- {metalist-0.3.10 → metalist-0.3.12}/app/services/base_service.py +5 -2
- {metalist-0.3.10 → metalist-0.3.12}/app/services/client_state_service.py +3 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/content_cache.py +4 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/services/content_formatting.py +459 -28
- {metalist-0.3.10 → metalist-0.3.12}/app/services/diagnostics.py +36 -28
- {metalist-0.3.10 → metalist-0.3.12}/app/services/embedded_references.py +21 -4
- {metalist-0.3.10 → metalist-0.3.12}/app/services/html_export.py +2 -2
- {metalist-0.3.10 → metalist-0.3.12}/app/services/hydration_state.py +10 -0
- metalist-0.3.12/app/services/image_size_formatting.py +325 -0
- metalist-0.3.12/app/services/inline_image_occurrences.py +31 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/link_titles.py +207 -22
- {metalist-0.3.10 → metalist-0.3.12}/app/services/namespace_deletion_worker.py +1 -3
- {metalist-0.3.10 → metalist-0.3.12}/app/services/namespace_rename_worker.py +0 -2
- {metalist-0.3.10 → metalist-0.3.12}/app/services/namespace_switcher.py +88 -75
- {metalist-0.3.10 → metalist-0.3.12}/app/services/ontology_rules_store.py +15 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/query_service.py +0 -2
- metalist-0.3.12/app/services/remote_image_proxy.py +299 -0
- metalist-0.3.12/app/services/runtime_lock.py +67 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/search_index.py +0 -3
- metalist-0.3.12/app/services/selected_text_tag.py +129 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/snapshot.py +0 -3
- {metalist-0.3.10 → metalist-0.3.12}/app/services/sync_state.py +8 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/tokens.py +4 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/transaction_manager.py +6 -3
- {metalist-0.3.10 → metalist-0.3.12}/app/services/undo_state.py +5 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/startup_sanity_config.py +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/config/command_palette_tags.json +6 -6
- {metalist-0.3.10 → metalist-0.3.12}/app/static/css/main.css +314 -159
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/main.js +3 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/api-client.js +43 -35
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/auth.js +24 -17
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/client-state-api.js +17 -2
- metalist-0.3.12/app/static/js/modules/command-palette/activation-auth-policy.js +27 -0
- metalist-0.3.12/app/static/js/modules/command-palette/backup-command-availability.js +49 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/command-palette/command-palette-controller.js +85 -18
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/command-palette/endpoint-registry.js +59 -14
- metalist-0.3.12/app/static/js/modules/command-palette/note-layout-preferences.js +66 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/command-palette/preferences-store.js +20 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/config.js +4 -5
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/connectivity-monitor.js +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/context-menu/context-menu-registry.js +177 -8
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/context-menu/context-menu-service.js +237 -12
- metalist-0.3.12/app/static/js/modules/context-menu/context-menu-target-service.js +6 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/dom-utils-fixed.js +0 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/dom-utils.js +0 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/error-handler.js +4 -4
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/login-namespace-picker.js +25 -7
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/backup-restore-modal.js +15 -7
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/backup-result-modal.js +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/backup-retention-modal.js +2 -2
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/backup-settings-modal.js +70 -29
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/base-modal.js +29 -2
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/delete-namespace-modal.js +57 -23
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/delete-namespace-validation.js +19 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/help-modal.js +7 -13
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/namespace-loading-page.js +14 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/namespace-modals.js +23 -42
- metalist-0.3.12/app/static/js/modules/modals/note-layout-appearance-modal.js +169 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/ontology-modal.js +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/password-modal.js +16 -12
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/random-password-modal.js +150 -10
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/reminder-modal.js +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/sound-manager-modal.js +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/version-info-modal.js +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/actions/content-actions.js +3 -2
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/actions/note-actions.js +89 -4
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/actions/ui-actions.js +2 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/events/context-menu-events.js +273 -75
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/events/keyboard-events.js +261 -311
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/events/mouse-events.js +6 -4
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/mode-context.js +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/mode-logger.js +7 -12
- metalist-0.3.12/app/static/js/modules/mode-manager/services/add-style-service.js +171 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +30 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +4 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/differential-view-service.js +47 -16
- metalist-0.3.12/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +33 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +10 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +37 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +6 -0
- metalist-0.3.12/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +31 -0
- metalist-0.3.12/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +216 -0
- metalist-0.3.12/app/static/js/modules/mode-manager/services/remove-formatting-service.js +502 -0
- metalist-0.3.12/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +207 -0
- metalist-0.3.12/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +63 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +47 -12
- metalist-0.3.12/app/static/js/modules/note-html-sanitizer.js +193 -0
- metalist-0.3.12/app/static/js/modules/password-policy.js +23 -0
- metalist-0.3.12/app/static/js/modules/password-strength.js +81 -0
- metalist-0.3.12/app/static/js/vendor/dompurify-3.4.12.LICENSE.txt +202 -0
- metalist-0.3.12/app/static/js/vendor/dompurify-3.4.12.min.js +3 -0
- metalist-0.3.12/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +20 -0
- metalist-0.3.12/app/static/js/vendor/zxcvbn-4.4.2.js +28 -0
- metalist-0.3.12/app/static/note-html-policy.json +99 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/templates/base.html +2 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/templates/locked.html +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/templates/maintenance.html +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/templates/namespace_deleted.html +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/templates/namespace_renamed.html +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/app/templates/notes_list.html +1 -5
- metalist-0.3.12/app/usecases/add_selected_text_tag.py +104 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/create_note.py +6 -2
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/delete_subtree.py +14 -3
- metalist-0.3.12/app/usecases/resize_image.py +83 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/run_shell.py +18 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/split_note.py +5 -3
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/unformat_content.py +12 -3
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/update_content.py +8 -5
- {metalist-0.3.10 → metalist-0.3.12}/app/version.py +1 -1
- {metalist-0.3.10 → metalist-0.3.12}/convert-from-legacy.py +2 -16
- {metalist-0.3.10 → metalist-0.3.12}/main.py +93 -202
- {metalist-0.3.10 → metalist-0.3.12}/metalist.egg-info/PKG-INFO +52 -69
- {metalist-0.3.10 → metalist-0.3.12}/metalist.egg-info/SOURCES.txt +35 -13
- {metalist-0.3.10 → metalist-0.3.12}/metalist.egg-info/entry_points.txt +0 -1
- {metalist-0.3.10 → metalist-0.3.12}/metalist.egg-info/requires.txt +4 -0
- metalist-0.3.12/metalist.egg-info/top_level.txt +2 -0
- {metalist-0.3.10 → metalist-0.3.12}/pyproject.toml +5 -2
- metalist-0.3.10/app/api/routes/mcp.py +0 -30
- metalist-0.3.10/app/api/routes/memory.py +0 -107
- metalist-0.3.10/app/mcp/__init__.py +0 -2
- metalist-0.3.10/app/mcp/__main__.py +0 -8
- metalist-0.3.10/app/mcp/errors.py +0 -18
- metalist-0.3.10/app/mcp/policy.py +0 -55
- metalist-0.3.10/app/mcp/read_service.py +0 -1124
- metalist-0.3.10/app/mcp/server.py +0 -230
- metalist-0.3.10/app/mcp/tools.py +0 -480
- metalist-0.3.10/app/services/memory.py +0 -9
- metalist-0.3.10/app/services/memory_service.py +0 -213
- metalist-0.3.10/app/static/js/modules/modals/memory-modal.js +0 -282
- metalist-0.3.10/mcp_client.py +0 -10083
- metalist-0.3.10/metalist.egg-info/top_level.txt +0 -3
- {metalist-0.3.10 → metalist-0.3.12}/MANIFEST.in +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/__init__.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/api/__init__.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/api/deps.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/api/dev.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/api/routes/files.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/api/routes/ontology.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/api/routes/reminders.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/api/routes/sounds.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/api/routes/test.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/api/transactions.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/__init__.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/backup_settings_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/engine.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/file_schema.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/files_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/link_titles_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/notes_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/ontology_rules_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/reminders_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/search_history_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/session.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/settings_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/sounds_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/db/tab_state_sql.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/models/commands.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/models/entities.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/models/enums.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/models/linked_list.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/models/list_operations.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/models/list_traversal.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/presentation/__init__.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/presentation/render/__init__.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/presentation/render/note_renderer.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/presentation/templates.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/security/encryption.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/__init__.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/auth.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/auth_cache_state.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/backlinks.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/backup_service.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/backup_settings_service.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/date_filtering.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/dependencies.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/encryption.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/exception_capture.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/file_registry.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/file_storage.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/html_unformatting.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/integrity.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/latex_rendering.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/login_rate_limit.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/maintenance_mode.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/markdown_rendering.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/namespace_deletion_jobs.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/namespace_rename_jobs.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/note_image_tags.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/note_service.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/note_store.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/reminders.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/root_sorting.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/runtime_hardening.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/search_history.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/search_query.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/search_text.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/self_update.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/session_timeout_service.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/shell_session_service.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/sound_storage.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/store.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/sync.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/tab_state.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/tag_case.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/tag_ontology.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/tag_rename.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/tag_suggestions.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/tag_term_matching.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/test_reset.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/undo_service.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/view_cache.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/view_diff.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/view_state.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/services/windows_process_control.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/startup_js_sanity.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/startup_sanity.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/css/forms.css +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/img/favicon.ico +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/locked.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/activity-tracker.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/async-result.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/client-state-migration.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/command-palette/usage-store.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/editor-commands.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/editor-selection.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/editor-toolbar.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/error-overlay.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/location-flags.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/prioritize-modal.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/date-filter-indicator-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/date-filter-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/rhs-panel-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/password-generator.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/reminder-store.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/reminder-surface-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/selection-markers.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/session-auth.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/sound-service.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/tag-token.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/modules/uuid.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/namespace-deleted.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/namespace-renamed.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/js/vendor/markdown-it.min.js +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/static/video/login-startup.mp4 +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/templates/index.html +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/__init__.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/alphabetize_root_notes.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/base.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/collapse.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/copy_note.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/create_child.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/create_sibling.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/expand.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/indent.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/lock.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/move.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/move_to_top.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/outdent.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/paste_child.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/paste_sibling.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/prioritize.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/record_edit_mode.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/redo.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/rename_tag.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/reset_updated_at.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/search_comment_autofill.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/search_context_tags.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/set_collapse_bulk.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/set_collapse_in_context.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/toggle_reference_mode.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/toggle_todo_done.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/undo.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/usecases/view.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/utils/__init__.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/utils/encryption.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/app/utils/text_utils.py +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/metalist.egg-info/dependency_links.txt +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/scripts/generate-lan-cert.sh +0 -0
- {metalist-0.3.10 → metalist-0.3.12}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metalist
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.12
|
|
4
4
|
Summary: A minimalist single-user note-taking app with SSR, fast in-memory tree operations, and efficient sync.
|
|
5
5
|
Project-URL: Homepage, https://github.com/evolvingstuff/metalist
|
|
6
6
|
Project-URL: Repository, https://github.com/evolvingstuff/metalist
|
|
@@ -10,11 +10,14 @@ Description-Content-Type: text/markdown
|
|
|
10
10
|
Requires-Dist: argon2-cffi==25.1.0
|
|
11
11
|
Requires-Dist: cryptography==50.0.0
|
|
12
12
|
Requires-Dist: fastapi==0.141.1
|
|
13
|
+
Requires-Dist: httpcore==1.0.9
|
|
13
14
|
Requires-Dist: httpx==0.28.1
|
|
14
15
|
Requires-Dist: latex2mathml==3.81.0
|
|
15
16
|
Requires-Dist: loguru==0.7.3
|
|
16
17
|
Requires-Dist: Mako==1.3.12
|
|
17
18
|
Requires-Dist: mutagen==1.48.1
|
|
19
|
+
Requires-Dist: nh3==0.3.6
|
|
20
|
+
Requires-Dist: pillow==12.3.0
|
|
18
21
|
Requires-Dist: pydantic==2.13.4
|
|
19
22
|
Requires-Dist: python-multipart==0.0.32
|
|
20
23
|
Requires-Dist: starlette==1.3.1
|
|
@@ -22,6 +25,7 @@ Requires-Dist: tqdm==4.70.0
|
|
|
22
25
|
Requires-Dist: tree-sitter==0.25.2
|
|
23
26
|
Requires-Dist: tree-sitter-javascript==0.25.0
|
|
24
27
|
Requires-Dist: uvicorn==0.52.0
|
|
28
|
+
Requires-Dist: zxcvbn==4.5.0
|
|
25
29
|
Provides-Extra: dev
|
|
26
30
|
Requires-Dist: hypothesis==6.164.0; extra == "dev"
|
|
27
31
|
Requires-Dist: pytest==9.1.1; extra == "dev"
|
|
@@ -35,7 +39,7 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
35
39
|
- Rich text editing (ContentEditable) with image support
|
|
36
40
|
- Drag-and-drop note reordering
|
|
37
41
|
- Real-time content saving
|
|
38
|
-
- Keyboard shortcuts (press `?` in the app)
|
|
42
|
+
- Keyboard shortcuts / cheatsheet (press `?` in the app)
|
|
39
43
|
- Linked-list ordering model for efficient reorders
|
|
40
44
|
- Optional password protection + encryption at rest (AES-GCM)
|
|
41
45
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
@@ -99,8 +103,22 @@ metalist
|
|
|
99
103
|
```
|
|
100
104
|
For source-checkout compatibility, `python main.py` performs the same orchestration. Use `metalist work`, `python main.py --namespace work`, or `python main.py work` when you want one foreground namespace process.
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
Shell execution is disabled by default. To enable `@shell` for every namespace
|
|
107
|
+
started by the top-level orchestrator, use either:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
metalist --enable-shell
|
|
111
|
+
python main.py --enable-shell
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This flag is propagated to every namespace child process. The top-level process
|
|
115
|
+
prints a conspicuous shell-enabled banner before its namespace launch results.
|
|
116
|
+
Use `python main.py work --enable-shell` for one foreground namespace. Shell
|
|
117
|
+
routes remain restricted to loopback clients using a loopback request host,
|
|
118
|
+
even when the rest of MetaList is intentionally exposed to a LAN.
|
|
119
|
+
|
|
120
|
+
`metalist` and explicit single-namespace source runs bind to loopback at `127.0.0.1:8000` by default. This keeps a normal laptop launch off LAN and public interfaces unless remote access is explicitly configured.
|
|
121
|
+
On first startup, MetaList also auto-generates a self-signed TLS pair at `~/MetaList/certs/metalist-cert.pem` and `~/MetaList/certs/metalist-key.pem`, then enables HTTPS on the same bind host at port `8443`. If you already have real PEM files, point `METALIST_TLS_CERT` and `METALIST_TLS_KEY` at them instead. Set `METALIST_AUTO_GENERATE_TLS=0` only if you explicitly want HTTP-only startup.
|
|
104
122
|
|
|
105
123
|
Database selection:
|
|
106
124
|
- No explicit namespace on a single-namespace launch: `~/MetaList/namespaces/default/default.metalist.db`
|
|
@@ -116,26 +134,40 @@ Useful env flags:
|
|
|
116
134
|
- `CRASH_SERVER_ON_FAIL=1` (default): fail-fast on validation errors
|
|
117
135
|
- `API_PREFIX=/api2`: override API prefix (client assumes `/api2` by default)
|
|
118
136
|
- `METALIST_NAMESPACE=work`: select `~/MetaList/namespaces/work/work.metalist.db`
|
|
119
|
-
- `METALIST_HOST=
|
|
137
|
+
- `METALIST_HOST=127.0.0.1` (default): bind the main app to a specific interface; use a LAN IP or `0.0.0.0` only for intentional remote access
|
|
138
|
+
- `METALIST_ALLOWED_HOSTS=notes.example.com,192.168.1.20`: comma-separated public/LAN hostnames accepted in HTTP `Host` headers; loopback aliases and a specific non-wildcard `METALIST_HOST` are accepted automatically
|
|
120
139
|
- `METALIST_PORT=8000` (default): bind the main app to a different port
|
|
121
140
|
- `METALIST_HTTPS_PORT=8443`: override the HTTPS port when TLS is enabled
|
|
122
|
-
- `MCP_AGENT_WEB_PORT=8765` (default): bind the MCP sidecar web UI to a different port
|
|
123
141
|
- `METALIST_TLS_CERT=/path/to/fullchain.pem` + `METALIST_TLS_KEY=/path/to/privkey.pem`: override TLS paths
|
|
124
142
|
- `METALIST_AUTO_GENERATE_TLS=0`: disable automatic creation of the default self-signed TLS pair
|
|
125
143
|
- default TLS paths: `~/MetaList/certs/metalist-cert.pem` and `~/MetaList/certs/metalist-key.pem`
|
|
126
144
|
- `METALIST_FORWARDED_ALLOW_IPS=127.0.0.1,::1` (default): trust proxy headers only from those reverse-proxy IPs
|
|
127
|
-
-
|
|
145
|
+
- `--enable-shell`: opt in to local `@shell` execution for this launch; shell routes require a loopback client and loopback request host, and the capability is never persisted in namespace data
|
|
128
146
|
|
|
129
147
|
### Remote Access / HTTPS
|
|
130
|
-
|
|
148
|
+
LAN or VPN access must be enabled explicitly. Prefer binding the machine's specific LAN address, which also adds that address to the accepted-host set:
|
|
131
149
|
```bash
|
|
132
|
-
metalist
|
|
150
|
+
METALIST_HOST=192.168.1.20 metalist
|
|
151
|
+
```
|
|
152
|
+
On a fresh machine, that first launch also creates the default TLS cert pair automatically. Then open either `http://192.168.1.20:8000` or `https://192.168.1.20:8443` from the other machine.
|
|
153
|
+
|
|
154
|
+
To keep `@shell` available on the host laptop while allowing another laptop to
|
|
155
|
+
use normal MetaList features, bind both interfaces and explicitly allow the LAN
|
|
156
|
+
address:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
METALIST_HOST=0.0.0.0 \
|
|
160
|
+
METALIST_ALLOWED_HOSTS=10.0.0.31 \
|
|
161
|
+
metalist --enable-shell
|
|
133
162
|
```
|
|
134
|
-
|
|
163
|
+
|
|
164
|
+
Use `http://127.0.0.1:<namespace-http-port>` on the host laptop when running
|
|
165
|
+
`@shell`. Other devices may use `https://10.0.0.31:<namespace-https-port>`, but
|
|
166
|
+
their shell start/status requests receive `403`.
|
|
135
167
|
|
|
136
168
|
Namespaced launch example:
|
|
137
169
|
```bash
|
|
138
|
-
metalist --namespace work --port 8001
|
|
170
|
+
metalist --namespace work --port 8001
|
|
139
171
|
```
|
|
140
172
|
This starts a separate process backed by `~/MetaList/namespaces/work/work.metalist.db` on `http://127.0.0.1:8001`.
|
|
141
173
|
Its backup snapshots live under `~/MetaList/namespaces/work/backups/` with filenames like `work-<timestamp>.metalist-backup.tar.gz`. New backups are versioned `.tar.gz` workspace archives; legacy `.bak` backups remain restorable.
|
|
@@ -144,11 +176,12 @@ After you launch a namespace once with explicit ports, MetaList remembers them i
|
|
|
144
176
|
```bash
|
|
145
177
|
metalist work
|
|
146
178
|
```
|
|
147
|
-
and MetaList will reuse the saved HTTP / HTTPS
|
|
179
|
+
and MetaList will reuse the saved HTTP / HTTPS ports for `work`. The same applies to the default namespace: `metalist` will reuse the saved default-namespace profile.
|
|
148
180
|
|
|
149
181
|
Equivalent explicit launch, if you want it:
|
|
150
182
|
```bash
|
|
151
183
|
METALIST_HOST=0.0.0.0 \
|
|
184
|
+
METALIST_ALLOWED_HOSTS=192.168.1.20 \
|
|
152
185
|
METALIST_PORT=8000 \
|
|
153
186
|
METALIST_HTTPS_PORT=8443 \
|
|
154
187
|
metalist
|
|
@@ -158,6 +191,7 @@ From the other machine, open `https://<laptop-ip>:8443`.
|
|
|
158
191
|
If you already have a real certificate and key, use the same dual-listener flow:
|
|
159
192
|
```bash
|
|
160
193
|
METALIST_HOST=0.0.0.0 \
|
|
194
|
+
METALIST_ALLOWED_HOSTS=192.168.1.20 \
|
|
161
195
|
METALIST_PORT=8000 \
|
|
162
196
|
METALIST_HTTPS_PORT=8443 \
|
|
163
197
|
METALIST_TLS_CERT=/path/to/fullchain.pem \
|
|
@@ -177,67 +211,16 @@ When HTTPS is enabled:
|
|
|
177
211
|
If TLS is terminated by a reverse proxy on the same machine instead, keep MetaList on loopback and let the proxy forward to it:
|
|
178
212
|
```bash
|
|
179
213
|
METALIST_HOST=127.0.0.1 \
|
|
214
|
+
METALIST_ALLOWED_HOSTS=notes.example.com \
|
|
180
215
|
METALIST_PORT=8000 \
|
|
181
216
|
METALIST_FORWARDED_ALLOW_IPS=127.0.0.1,::1 \
|
|
182
217
|
metalist
|
|
183
218
|
```
|
|
184
219
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
### MCP (Phase 1 Read-Only)
|
|
191
|
-
MCP is available automatically when you run:
|
|
192
|
-
```bash
|
|
193
|
-
metalist
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
`metalist` also auto-starts the agent web app sidecar and prints:
|
|
197
|
-
- `Agent web app: http://127.0.0.1:8765`
|
|
198
|
-
- The sidecar default MCP URL follows the resolved MetaList HTTP port for the current process.
|
|
199
|
-
- Use `--mcp-port` when you want multiple MetaList instances to auto-start sidecars without colliding on `8765`.
|
|
200
|
-
- On startup, local Ollama (`127.0.0.1`) is reset by default so a fresh runner is used.
|
|
201
|
-
- Sidecar Ollama auto-start uses `OLLAMA_CONTEXT_LENGTH=16384` by default.
|
|
202
|
-
|
|
203
|
-
Manual web mode (optional):
|
|
204
|
-
```bash
|
|
205
|
-
metalist-mcp web --port 8765
|
|
206
|
-
```
|
|
207
|
-
Then open `http://127.0.0.1:8765`.
|
|
208
|
-
|
|
209
|
-
Run direct MCP CLI calls:
|
|
210
|
-
```bash
|
|
211
|
-
metalist-mcp cli tools/list
|
|
212
|
-
metalist-mcp cli tools/call health_check '{}'
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
Compatibility shortcut (still works):
|
|
216
|
-
```bash
|
|
217
|
-
python mcp_client.py tools/list
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Disable auto sidecar if needed:
|
|
221
|
-
```bash
|
|
222
|
-
MCP_AGENT_WEB_ENABLED=0 metalist
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
Control Ollama startup behavior:
|
|
226
|
-
```bash
|
|
227
|
-
# disable Ollama reset-on-start (default is enabled)
|
|
228
|
-
MCP_AGENT_RESET_OLLAMA_ON_START=0 metalist
|
|
229
|
-
|
|
230
|
-
# override auto-start context length (default 16384)
|
|
231
|
-
MCP_AGENT_OLLAMA_CONTEXT_LENGTH=32768 metalist
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Optional: direct stdio transport (advanced/manual):
|
|
235
|
-
```bash
|
|
236
|
-
python -m app.mcp
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
Tool catalog and schemas:
|
|
240
|
-
- `docs/mcp_tools.md`
|
|
220
|
+
The reverse proxy must preserve the browser-facing `Host` header and set
|
|
221
|
+
`X-Forwarded-Proto`. MetaList never trusts `X-Forwarded-Host`; forwarded
|
|
222
|
+
scheme/client metadata is accepted only from `METALIST_FORWARDED_ALLOW_IPS`.
|
|
223
|
+
Do not widen that list beyond the actual proxy addresses.
|
|
241
224
|
|
|
242
225
|
### Legacy Import
|
|
243
226
|
`convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL`, clears its files/sounds sidecar, and imports notes from a legacy JSON export.
|
|
@@ -254,7 +237,7 @@ Target a namespaced database during import:
|
|
|
254
237
|
convert-from-legacy.py --namespace work --input /path/to/legacy-export.json
|
|
255
238
|
```
|
|
256
239
|
|
|
257
|
-
If `--namespace`, `--port`,
|
|
240
|
+
If `--namespace`, `--port`, or `--https-port` are omitted, the import script prompts for them and saves the resulting launch profile inside the target namespace DB. That means a one-time import into `work` can immediately seed later shorthand launches like `metalist work`.
|
|
258
241
|
|
|
259
242
|
### Publishing
|
|
260
243
|
For the real user-facing install flow:
|
|
@@ -6,7 +6,7 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
6
6
|
- Rich text editing (ContentEditable) with image support
|
|
7
7
|
- Drag-and-drop note reordering
|
|
8
8
|
- Real-time content saving
|
|
9
|
-
- Keyboard shortcuts (press `?` in the app)
|
|
9
|
+
- Keyboard shortcuts / cheatsheet (press `?` in the app)
|
|
10
10
|
- Linked-list ordering model for efficient reorders
|
|
11
11
|
- Optional password protection + encryption at rest (AES-GCM)
|
|
12
12
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
@@ -70,8 +70,22 @@ metalist
|
|
|
70
70
|
```
|
|
71
71
|
For source-checkout compatibility, `python main.py` performs the same orchestration. Use `metalist work`, `python main.py --namespace work`, or `python main.py work` when you want one foreground namespace process.
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
Shell execution is disabled by default. To enable `@shell` for every namespace
|
|
74
|
+
started by the top-level orchestrator, use either:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
metalist --enable-shell
|
|
78
|
+
python main.py --enable-shell
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This flag is propagated to every namespace child process. The top-level process
|
|
82
|
+
prints a conspicuous shell-enabled banner before its namespace launch results.
|
|
83
|
+
Use `python main.py work --enable-shell` for one foreground namespace. Shell
|
|
84
|
+
routes remain restricted to loopback clients using a loopback request host,
|
|
85
|
+
even when the rest of MetaList is intentionally exposed to a LAN.
|
|
86
|
+
|
|
87
|
+
`metalist` and explicit single-namespace source runs bind to loopback at `127.0.0.1:8000` by default. This keeps a normal laptop launch off LAN and public interfaces unless remote access is explicitly configured.
|
|
88
|
+
On first startup, MetaList also auto-generates a self-signed TLS pair at `~/MetaList/certs/metalist-cert.pem` and `~/MetaList/certs/metalist-key.pem`, then enables HTTPS on the same bind host at port `8443`. If you already have real PEM files, point `METALIST_TLS_CERT` and `METALIST_TLS_KEY` at them instead. Set `METALIST_AUTO_GENERATE_TLS=0` only if you explicitly want HTTP-only startup.
|
|
75
89
|
|
|
76
90
|
Database selection:
|
|
77
91
|
- No explicit namespace on a single-namespace launch: `~/MetaList/namespaces/default/default.metalist.db`
|
|
@@ -87,26 +101,40 @@ Useful env flags:
|
|
|
87
101
|
- `CRASH_SERVER_ON_FAIL=1` (default): fail-fast on validation errors
|
|
88
102
|
- `API_PREFIX=/api2`: override API prefix (client assumes `/api2` by default)
|
|
89
103
|
- `METALIST_NAMESPACE=work`: select `~/MetaList/namespaces/work/work.metalist.db`
|
|
90
|
-
- `METALIST_HOST=
|
|
104
|
+
- `METALIST_HOST=127.0.0.1` (default): bind the main app to a specific interface; use a LAN IP or `0.0.0.0` only for intentional remote access
|
|
105
|
+
- `METALIST_ALLOWED_HOSTS=notes.example.com,192.168.1.20`: comma-separated public/LAN hostnames accepted in HTTP `Host` headers; loopback aliases and a specific non-wildcard `METALIST_HOST` are accepted automatically
|
|
91
106
|
- `METALIST_PORT=8000` (default): bind the main app to a different port
|
|
92
107
|
- `METALIST_HTTPS_PORT=8443`: override the HTTPS port when TLS is enabled
|
|
93
|
-
- `MCP_AGENT_WEB_PORT=8765` (default): bind the MCP sidecar web UI to a different port
|
|
94
108
|
- `METALIST_TLS_CERT=/path/to/fullchain.pem` + `METALIST_TLS_KEY=/path/to/privkey.pem`: override TLS paths
|
|
95
109
|
- `METALIST_AUTO_GENERATE_TLS=0`: disable automatic creation of the default self-signed TLS pair
|
|
96
110
|
- default TLS paths: `~/MetaList/certs/metalist-cert.pem` and `~/MetaList/certs/metalist-key.pem`
|
|
97
111
|
- `METALIST_FORWARDED_ALLOW_IPS=127.0.0.1,::1` (default): trust proxy headers only from those reverse-proxy IPs
|
|
98
|
-
-
|
|
112
|
+
- `--enable-shell`: opt in to local `@shell` execution for this launch; shell routes require a loopback client and loopback request host, and the capability is never persisted in namespace data
|
|
99
113
|
|
|
100
114
|
### Remote Access / HTTPS
|
|
101
|
-
|
|
115
|
+
LAN or VPN access must be enabled explicitly. Prefer binding the machine's specific LAN address, which also adds that address to the accepted-host set:
|
|
102
116
|
```bash
|
|
103
|
-
metalist
|
|
117
|
+
METALIST_HOST=192.168.1.20 metalist
|
|
118
|
+
```
|
|
119
|
+
On a fresh machine, that first launch also creates the default TLS cert pair automatically. Then open either `http://192.168.1.20:8000` or `https://192.168.1.20:8443` from the other machine.
|
|
120
|
+
|
|
121
|
+
To keep `@shell` available on the host laptop while allowing another laptop to
|
|
122
|
+
use normal MetaList features, bind both interfaces and explicitly allow the LAN
|
|
123
|
+
address:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
METALIST_HOST=0.0.0.0 \
|
|
127
|
+
METALIST_ALLOWED_HOSTS=10.0.0.31 \
|
|
128
|
+
metalist --enable-shell
|
|
104
129
|
```
|
|
105
|
-
|
|
130
|
+
|
|
131
|
+
Use `http://127.0.0.1:<namespace-http-port>` on the host laptop when running
|
|
132
|
+
`@shell`. Other devices may use `https://10.0.0.31:<namespace-https-port>`, but
|
|
133
|
+
their shell start/status requests receive `403`.
|
|
106
134
|
|
|
107
135
|
Namespaced launch example:
|
|
108
136
|
```bash
|
|
109
|
-
metalist --namespace work --port 8001
|
|
137
|
+
metalist --namespace work --port 8001
|
|
110
138
|
```
|
|
111
139
|
This starts a separate process backed by `~/MetaList/namespaces/work/work.metalist.db` on `http://127.0.0.1:8001`.
|
|
112
140
|
Its backup snapshots live under `~/MetaList/namespaces/work/backups/` with filenames like `work-<timestamp>.metalist-backup.tar.gz`. New backups are versioned `.tar.gz` workspace archives; legacy `.bak` backups remain restorable.
|
|
@@ -115,11 +143,12 @@ After you launch a namespace once with explicit ports, MetaList remembers them i
|
|
|
115
143
|
```bash
|
|
116
144
|
metalist work
|
|
117
145
|
```
|
|
118
|
-
and MetaList will reuse the saved HTTP / HTTPS
|
|
146
|
+
and MetaList will reuse the saved HTTP / HTTPS ports for `work`. The same applies to the default namespace: `metalist` will reuse the saved default-namespace profile.
|
|
119
147
|
|
|
120
148
|
Equivalent explicit launch, if you want it:
|
|
121
149
|
```bash
|
|
122
150
|
METALIST_HOST=0.0.0.0 \
|
|
151
|
+
METALIST_ALLOWED_HOSTS=192.168.1.20 \
|
|
123
152
|
METALIST_PORT=8000 \
|
|
124
153
|
METALIST_HTTPS_PORT=8443 \
|
|
125
154
|
metalist
|
|
@@ -129,6 +158,7 @@ From the other machine, open `https://<laptop-ip>:8443`.
|
|
|
129
158
|
If you already have a real certificate and key, use the same dual-listener flow:
|
|
130
159
|
```bash
|
|
131
160
|
METALIST_HOST=0.0.0.0 \
|
|
161
|
+
METALIST_ALLOWED_HOSTS=192.168.1.20 \
|
|
132
162
|
METALIST_PORT=8000 \
|
|
133
163
|
METALIST_HTTPS_PORT=8443 \
|
|
134
164
|
METALIST_TLS_CERT=/path/to/fullchain.pem \
|
|
@@ -148,67 +178,16 @@ When HTTPS is enabled:
|
|
|
148
178
|
If TLS is terminated by a reverse proxy on the same machine instead, keep MetaList on loopback and let the proxy forward to it:
|
|
149
179
|
```bash
|
|
150
180
|
METALIST_HOST=127.0.0.1 \
|
|
181
|
+
METALIST_ALLOWED_HOSTS=notes.example.com \
|
|
151
182
|
METALIST_PORT=8000 \
|
|
152
183
|
METALIST_FORWARDED_ALLOW_IPS=127.0.0.1,::1 \
|
|
153
184
|
metalist
|
|
154
185
|
```
|
|
155
186
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
### MCP (Phase 1 Read-Only)
|
|
162
|
-
MCP is available automatically when you run:
|
|
163
|
-
```bash
|
|
164
|
-
metalist
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
`metalist` also auto-starts the agent web app sidecar and prints:
|
|
168
|
-
- `Agent web app: http://127.0.0.1:8765`
|
|
169
|
-
- The sidecar default MCP URL follows the resolved MetaList HTTP port for the current process.
|
|
170
|
-
- Use `--mcp-port` when you want multiple MetaList instances to auto-start sidecars without colliding on `8765`.
|
|
171
|
-
- On startup, local Ollama (`127.0.0.1`) is reset by default so a fresh runner is used.
|
|
172
|
-
- Sidecar Ollama auto-start uses `OLLAMA_CONTEXT_LENGTH=16384` by default.
|
|
173
|
-
|
|
174
|
-
Manual web mode (optional):
|
|
175
|
-
```bash
|
|
176
|
-
metalist-mcp web --port 8765
|
|
177
|
-
```
|
|
178
|
-
Then open `http://127.0.0.1:8765`.
|
|
179
|
-
|
|
180
|
-
Run direct MCP CLI calls:
|
|
181
|
-
```bash
|
|
182
|
-
metalist-mcp cli tools/list
|
|
183
|
-
metalist-mcp cli tools/call health_check '{}'
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
Compatibility shortcut (still works):
|
|
187
|
-
```bash
|
|
188
|
-
python mcp_client.py tools/list
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
Disable auto sidecar if needed:
|
|
192
|
-
```bash
|
|
193
|
-
MCP_AGENT_WEB_ENABLED=0 metalist
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
Control Ollama startup behavior:
|
|
197
|
-
```bash
|
|
198
|
-
# disable Ollama reset-on-start (default is enabled)
|
|
199
|
-
MCP_AGENT_RESET_OLLAMA_ON_START=0 metalist
|
|
200
|
-
|
|
201
|
-
# override auto-start context length (default 16384)
|
|
202
|
-
MCP_AGENT_OLLAMA_CONTEXT_LENGTH=32768 metalist
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
Optional: direct stdio transport (advanced/manual):
|
|
206
|
-
```bash
|
|
207
|
-
python -m app.mcp
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
Tool catalog and schemas:
|
|
211
|
-
- `docs/mcp_tools.md`
|
|
187
|
+
The reverse proxy must preserve the browser-facing `Host` header and set
|
|
188
|
+
`X-Forwarded-Proto`. MetaList never trusts `X-Forwarded-Host`; forwarded
|
|
189
|
+
scheme/client metadata is accepted only from `METALIST_FORWARDED_ALLOW_IPS`.
|
|
190
|
+
Do not widen that list beyond the actual proxy addresses.
|
|
212
191
|
|
|
213
192
|
### Legacy Import
|
|
214
193
|
`convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL`, clears its files/sounds sidecar, and imports notes from a legacy JSON export.
|
|
@@ -225,7 +204,7 @@ Target a namespaced database during import:
|
|
|
225
204
|
convert-from-legacy.py --namespace work --input /path/to/legacy-export.json
|
|
226
205
|
```
|
|
227
206
|
|
|
228
|
-
If `--namespace`, `--port`,
|
|
207
|
+
If `--namespace`, `--port`, or `--https-port` are omitted, the import script prompts for them and saves the resulting launch profile inside the target namespace DB. That means a one-time import into `work` can immediately seed later shorthand launches like `metalist work`.
|
|
229
208
|
|
|
230
209
|
### Publishing
|
|
231
210
|
For the real user-facing install flow:
|
|
@@ -7,32 +7,35 @@ from app.api.request_auth import read_request_auth_token
|
|
|
7
7
|
from app.services.tokens import token_service
|
|
8
8
|
from app.services.auth_service import AuthService
|
|
9
9
|
from app.services.maintenance_mode import maintenance_service
|
|
10
|
+
from app.services.runtime_lock import purge_decrypted_runtime_state
|
|
10
11
|
from app.models.database import SafeSession
|
|
11
12
|
from app.config import API_PREFIX, TEST_MODE
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class AuthMiddleware(BaseHTTPMiddleware):
|
|
15
16
|
"""Middleware to check authentication on protected routes."""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
PUBLIC_EXACT_PATHS = frozenset({
|
|
19
|
+
"/",
|
|
19
20
|
f"{API_PREFIX}/auth/login",
|
|
21
|
+
f"{API_PREFIX}/auth/login-namespaces",
|
|
22
|
+
f"{API_PREFIX}/auth/login-namespaces/open",
|
|
20
23
|
f"{API_PREFIX}/auth/status",
|
|
21
24
|
f"{API_PREFIX}/auth/session",
|
|
22
|
-
f"{API_PREFIX}/auth/namespaces/delete-jobs/",
|
|
23
|
-
f"{API_PREFIX}/auth/namespaces/rename-jobs/",
|
|
24
|
-
f"{API_PREFIX}/mcp",
|
|
25
|
-
"/mcp-client-v2",
|
|
26
|
-
"/mcp-client",
|
|
27
|
-
"/namespace-deleted",
|
|
28
|
-
"/namespace-renamed",
|
|
29
|
-
"/static/", # CSS/JS files needed for login page
|
|
30
25
|
"/favicon.ico",
|
|
31
26
|
"/locked",
|
|
32
|
-
|
|
27
|
+
"/namespace-deleted",
|
|
28
|
+
"/namespace-deleted/open",
|
|
29
|
+
"/namespace-renamed",
|
|
30
|
+
"/namespace-renamed/open",
|
|
31
|
+
} | ({f"{API_PREFIX}/test/reset"} if TEST_MODE else set()))
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
PUBLIC_PREFIX_PATHS = (
|
|
34
|
+
f"{API_PREFIX}/auth/namespaces/delete-jobs/",
|
|
35
|
+
f"{API_PREFIX}/auth/namespaces/rename-jobs/",
|
|
36
|
+
"/static/", # CSS/JS files needed for login page
|
|
37
|
+
)
|
|
38
|
+
assert all(path.endswith("/") for path in PUBLIC_PREFIX_PATHS)
|
|
36
39
|
|
|
37
40
|
# Paths to suppress verbose logging for (frequent polling endpoints)
|
|
38
41
|
QUIET_PATHS = [
|
|
@@ -46,11 +49,22 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
46
49
|
]
|
|
47
50
|
|
|
48
51
|
# Note: /api/notes/* paths are NOT in this list - they require auth when password is set
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def is_public_path(cls, *, path: str) -> bool:
|
|
55
|
+
if not isinstance(path, str) or not path.startswith("/"):
|
|
56
|
+
raise TypeError("path must be an absolute URL path")
|
|
57
|
+
if path in cls.PUBLIC_EXACT_PATHS:
|
|
58
|
+
return True
|
|
59
|
+
return any(path.startswith(prefix) for prefix in cls.PUBLIC_PREFIX_PATHS)
|
|
49
60
|
|
|
50
61
|
async def dispatch(self, request: Request, call_next):
|
|
51
62
|
"""Check authentication for protected routes."""
|
|
52
63
|
path = request.url.path
|
|
53
64
|
|
|
65
|
+
if not token_service.has_active_tokens():
|
|
66
|
+
purge_decrypted_runtime_state()
|
|
67
|
+
|
|
54
68
|
# Block any v1 API usage with an explicit 410 Gone (no DB access)
|
|
55
69
|
if path.startswith('/api') and not (path.startswith(API_PREFIX) or path == API_PREFIX):
|
|
56
70
|
ref = request.headers.get('referer', '-')
|
|
@@ -73,22 +87,9 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
73
87
|
if not is_quiet:
|
|
74
88
|
print(f"Middleware checking path: {path}")
|
|
75
89
|
|
|
76
|
-
|
|
77
|
-
public_match = None
|
|
78
|
-
|
|
79
|
-
# Handle exact root path match
|
|
80
|
-
if path == "/":
|
|
81
|
-
public_match = "/ (root)"
|
|
82
|
-
else:
|
|
83
|
-
# Check other public paths with startswith
|
|
84
|
-
for public in self.PUBLIC_PATHS:
|
|
85
|
-
if path.startswith(public):
|
|
86
|
-
public_match = public
|
|
87
|
-
break
|
|
88
|
-
|
|
89
|
-
if public_match:
|
|
90
|
+
if self.is_public_path(path=path):
|
|
90
91
|
if not is_quiet:
|
|
91
|
-
print(f"Path {path} is public
|
|
92
|
+
print(f"Path {path} is explicitly public, skipping auth")
|
|
92
93
|
return await call_next(request)
|
|
93
94
|
|
|
94
95
|
if not is_quiet:
|
|
@@ -2,8 +2,19 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from fastapi import HTTPException, Request, Response
|
|
4
4
|
|
|
5
|
+
from app.config import ACTIVE_NAMESPACE
|
|
6
|
+
from app.server_runtime import validate_namespace
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
|
|
9
|
+
AUTH_COOKIE_PREFIX = "metalist_auth"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def auth_cookie_name_for_namespace(namespace: str) -> str:
|
|
13
|
+
normalized_namespace = validate_namespace(namespace=namespace)
|
|
14
|
+
return f"{AUTH_COOKIE_PREFIX}_{normalized_namespace}"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
AUTH_COOKIE_NAME = auth_cookie_name_for_namespace(ACTIVE_NAMESPACE)
|
|
7
18
|
|
|
8
19
|
|
|
9
20
|
def read_request_auth_token(request: Request) -> tuple[str | None, str | None]:
|
|
@@ -52,9 +52,11 @@ from app.services.namespace_switcher import save_namespace_port_profiles
|
|
|
52
52
|
from app.services.namespace_deletion_jobs import load_namespace_deletion_job
|
|
53
53
|
from app.services.namespace_rename_jobs import load_namespace_rename_job
|
|
54
54
|
from app.server_runtime import NamespaceLaunchProfile
|
|
55
|
+
from app.server_runtime import load_all_namespace_launch_profiles
|
|
55
56
|
from app.server_runtime import resolve_namespace_directory
|
|
56
57
|
from app.server_runtime import resolve_namespaced_database_path
|
|
57
58
|
from app.server_runtime import validate_namespace
|
|
59
|
+
from app.security.sensitive_logging import traceback_frame_summary
|
|
58
60
|
from app.services.encryption import EncryptionService
|
|
59
61
|
from app.services.tokens import token_service
|
|
60
62
|
from app.services.note_store import store as note_store
|
|
@@ -67,6 +69,7 @@ from app.services.link_titles import link_title_store
|
|
|
67
69
|
from app.services.reminders import reminder_store
|
|
68
70
|
from app.services.search_history import search_history_store
|
|
69
71
|
from app.services.sound_storage import sound_store
|
|
72
|
+
from app.services.runtime_lock import purge_decrypted_runtime_state
|
|
70
73
|
from app.services.hydration_state import hydration_state
|
|
71
74
|
from app.services.file_registry import file_registry
|
|
72
75
|
from app.services.file_storage import bootstrap_file_registry
|
|
@@ -441,11 +444,11 @@ def _on_hydration_done(future: Future) -> None:
|
|
|
441
444
|
return
|
|
442
445
|
error = future.exception()
|
|
443
446
|
if error is not None:
|
|
444
|
-
error_message =
|
|
447
|
+
error_message = type(error).__name__
|
|
445
448
|
logger.error(
|
|
446
|
-
"Hydration worker failed: %s",
|
|
449
|
+
"Hydration worker failed: %s frames=%s",
|
|
447
450
|
error_message,
|
|
448
|
-
|
|
451
|
+
traceback_frame_summary(error.__traceback__),
|
|
449
452
|
)
|
|
450
453
|
hydration_state.fail(error_message)
|
|
451
454
|
|
|
@@ -538,17 +541,9 @@ def _client_info(request: Request) -> str:
|
|
|
538
541
|
|
|
539
542
|
|
|
540
543
|
def _login_rate_limit_key(request: Request) -> str:
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
if forwarded_for:
|
|
545
|
-
first_hop = forwarded_for.split(",")[0].strip()
|
|
546
|
-
if first_hop:
|
|
547
|
-
return f"ip:{first_hop}"
|
|
548
|
-
if request.client and request.client.host:
|
|
549
|
-
return f"ip:{request.client.host}"
|
|
550
|
-
user_agent = request.headers.get("user-agent", "Unknown")
|
|
551
|
-
return f"ua:{user_agent[:128]}"
|
|
544
|
+
if request.client is None or request.client.host == "":
|
|
545
|
+
raise RuntimeError("Login request is missing client metadata")
|
|
546
|
+
return f"ip:{request.client.host}"
|
|
552
547
|
|
|
553
548
|
|
|
554
549
|
def _require_tab_id(
|
|
@@ -681,8 +676,9 @@ def logout(
|
|
|
681
676
|
token: Annotated[str, Depends(_require_auth)],
|
|
682
677
|
):
|
|
683
678
|
token_service.revoke_token(token)
|
|
684
|
-
|
|
685
|
-
|
|
679
|
+
if not purge_decrypted_runtime_state():
|
|
680
|
+
clear_all_locks()
|
|
681
|
+
clear_encryption_key()
|
|
686
682
|
clear_auth_cookie(response=response)
|
|
687
683
|
return {"message": "Logout successful"}
|
|
688
684
|
|
|
@@ -882,7 +878,6 @@ def open_namespace(
|
|
|
882
878
|
namespace = _require_string_field(body, "namespace")
|
|
883
879
|
port = _require_int_field(body, "port")
|
|
884
880
|
https_port = _optional_int_field(body, "https_port")
|
|
885
|
-
mcp_port = _require_int_field(body, "mcp_port")
|
|
886
881
|
launch_capture = CapturedExceptionContext(
|
|
887
882
|
RuntimeError,
|
|
888
883
|
ValueError,
|
|
@@ -897,7 +892,6 @@ def open_namespace(
|
|
|
897
892
|
namespace=namespace,
|
|
898
893
|
port=port,
|
|
899
894
|
https_port=https_port,
|
|
900
|
-
mcp_port=mcp_port,
|
|
901
895
|
)
|
|
902
896
|
if launch_capture.captured_exception is not None:
|
|
903
897
|
exc = launch_capture.captured_exception
|
|
@@ -912,7 +906,6 @@ def open_namespace(
|
|
|
912
906
|
"namespace": result.saved_profile.namespace,
|
|
913
907
|
"port": result.saved_profile.port,
|
|
914
908
|
"https_port": result.saved_profile.https_port,
|
|
915
|
-
"mcp_port": result.saved_profile.mcp_port,
|
|
916
909
|
},
|
|
917
910
|
"saved_for_next_launch": result.saved_for_next_launch,
|
|
918
911
|
"message": result.message,
|
|
@@ -927,6 +920,10 @@ def save_namespace_ports(
|
|
|
927
920
|
):
|
|
928
921
|
body = _require_body_object(payload)
|
|
929
922
|
raw_profiles = _require_list_field(body, "profiles")
|
|
923
|
+
saved_profiles = {
|
|
924
|
+
profile.namespace: profile
|
|
925
|
+
for profile in load_all_namespace_launch_profiles()
|
|
926
|
+
}
|
|
930
927
|
requested_profiles: list[NamespaceLaunchProfile] = []
|
|
931
928
|
for raw_profile in raw_profiles:
|
|
932
929
|
if not isinstance(raw_profile, dict):
|
|
@@ -934,13 +931,16 @@ def save_namespace_ports(
|
|
|
934
931
|
namespace = _require_string_field(raw_profile, "namespace")
|
|
935
932
|
port = _require_int_field(raw_profile, "port")
|
|
936
933
|
https_port = _optional_int_field(raw_profile, "https_port")
|
|
937
|
-
|
|
934
|
+
saved_profile = saved_profiles.get(namespace)
|
|
935
|
+
legacy_mcp_port = None
|
|
936
|
+
if saved_profile is not None:
|
|
937
|
+
legacy_mcp_port = saved_profile.mcp_port
|
|
938
938
|
requested_profiles.append(
|
|
939
939
|
NamespaceLaunchProfile(
|
|
940
940
|
namespace=namespace,
|
|
941
941
|
port=port,
|
|
942
942
|
https_port=https_port,
|
|
943
|
-
mcp_port=
|
|
943
|
+
mcp_port=legacy_mcp_port,
|
|
944
944
|
)
|
|
945
945
|
)
|
|
946
946
|
|
|
@@ -968,7 +968,6 @@ def save_namespace_ports(
|
|
|
968
968
|
"namespace": profile.namespace,
|
|
969
969
|
"port": profile.port,
|
|
970
970
|
"https_port": profile.https_port,
|
|
971
|
-
"mcp_port": profile.mcp_port,
|
|
972
971
|
}
|
|
973
972
|
for profile in result.saved_profiles
|
|
974
973
|
],
|