- Update pyproject.toml version from 1.24.0 to 1.25.0
- Modify sandbox.html StarField instantiation to use 150 stars instead of 50
- Add changelog entry for version 1.25.0 documenting the HTML file update
Rename createChannel, inviteUser, leaveChannel, updateChannel to snake_case equivalents in src/snek/view/rpc.py; update pyproject.toml version from 1.22.0 to 1.23.0; add changelog entry for version 1.23.0
- Update pyproject.toml version from 1.20.0 to 1.21.0
- Change channel name source from subscription["label"] to subscription["description"] in src/snek/view/rpc.py RPCView class
- Update pyproject.toml version from 1.14.0 to 1.15.0
- Add changelog entry for version 1.15.0
- Convert .fug-grid from CSS grid with 6-column fixed layout to flexbox with wrap
- Remove fixed background color on .fug-root and set max-width to 100%
- Adjust tile width to 120px with flex-shrink: 0 and reduce padding/spacing values
Replace direct appending of stt, tts, and upload buttons with a centralized toolbar-menu component. This change moves button management into the new toolbar-menu element, which handles button registration via addButton calls and controls visibility during file upload states. The toolbar-menu is now shown/hidden instead of individual buttons, simplifying the chat input's DOM structure and preparing for future toolbar extensions.
When the user presses Enter while listening, the previous behavior stopped recognition entirely via _stopAndSend(). The new _sendKeepListening() method clears both final and interim transcripts while keeping the recognition session active, allowing continuous dictation across multiple Enter presses without restarting the speech-to-text engine.
- Remove snek-speaker element from chat-input.js and replace with tts-button
- Rewrite tts.js from a simple SnekSpeaker class to a full TTSButton custom element with voice selection, styling, and speech synthesis integration
- Fix goToLine in editor.js to use literal \n instead of broken template literal split
- Fix push.js alert string to include proper newline separator instead of broken concatenation
- Update web.html template to remove snek-speaker speak logic and always play message sound
The previous implementation incorrectly wired a TTS button to trigger speech synthesis instead of speech-to-text. This commit removes the misconfigured `ttsButton` and `snekSpeaker` elements, replacing them with a proper `sttButton` that creates an `STTButton` custom element. The `stt.js` module is fully rewritten to implement a functional Web Speech API-based speech recognition component, including start/stop listening, interim and final transcript handling, and keyboard event simulation for inserting recognized text into the chat input field.
Add an asyncio.Lock to SocketService to synchronize concurrent access to the users and sockets sets during connection and disconnection, preventing race conditions when multiple websocket connections are established or torn down simultaneously. In the frontend MessageList component, replace anonymous inline event listeners with named handler references stored as instance properties, and implement a disconnectedCallback lifecycle method that removes those event listeners and disconnects the MutationObserver, ensuring proper cleanup when the element is removed from the DOM.
Implement five new dialog interfaces (create, settings, delete, invite, leave) with corresponding CSS styling, JavaScript classes, and RPC integration. Add sidebar add-button styling, update help dialog with new slash commands, and bump version to 1.14.0.
Introduce a new Config class in snek/system/config.py that reads environment variables, including SNEK_REGISTRATION_OPEN, to control whether user registration is allowed. The Application now loads this config and passes it to templates and views. The register.html template conditionally shows either the registration form or an invitation-only message based on config.registration_open. The RegisterView returns a 403 JSON error when registration is closed. Version bumped to 1.11.0 and CHANGELOG updated accordingly.
- Fix UserPropertyModel value field name from "path" to "value" in user_property.py
- Add self.mapper.db.commit() call after upsert in UserPropertyService to persist changes
- Refactor CSS across base.css, buttons.css, inputs.css, generic-form.css, and fancy-button.js to unify dark theme with monospace font, consistent border-radius (4px), and transition effects
- Introduce new buttons.css and inputs.css stylesheets with reusable .btn, .input, .textarea, .select classes and variants (primary, secondary, danger, success, sizes)
- Update sidebar navigation styling with active state indicator and hover border-left highlight
- Revise dialog button styles to match new design system with border, background, and hover states
- Adjust generic-form and generic-field components to use new font, colors, and focus ring (box-shadow) instead of outline
The entire GIT_INTEGRATION.md file was deleted from src/snek/templates/,
removing the outdated Git integration documentation that covered repository
creation, cloning workflows, and web interface features. This file is no
longer needed as the integration details have been superseded by newer
documentation or the feature set has changed.
Add ProfilePageMapper, ProfilePageModel, and ProfilePageService to support user profile pages with slug-based routing, ordering, and publish state. Register profile page views in the application router. Implement automatic creation of a default "General Discussion" forum on startup if no active forums exist. Add bcrypt to core dependencies and pytest with asyncio support as optional test dependencies. Refactor forum event dispatch to use inspect for robust async/sync listener handling. Extend RepositoryModel with optional description field. Update SQL schema to include IP geolocation fields on user table and history_start on channel table.
The review now includes detailed analysis of every Python file in the project, covering Docker integration, Git support, system modules, and additional architectural patterns discovered during the comprehensive codebase examination.
This commit introduces a new review.md file that provides a detailed quality assessment of the Snek project, covering its modular architecture, asynchronous design, feature set, and identified weaknesses including syntax errors in serpentarium.py and sync.py, incomplete code summaries, potential security concerns with WebSocket authentication and raw SQL queries, and code quality issues.
Add `last_read_at` column to `channel_member` table and set it in `mark_as_read` service method. Implement `get_first_unread_message_uid` RPC endpoint that queries the first message after the member's last read timestamp. Introduce a "Jump to First Unread" button in the web template with `checkForUnreadMessages` and `jumpToUnread` JavaScript functions to show/hide the button and scroll to the unread message element.
- Remove unused `aiohttp_debugtoolbar` import and its commented-out setup call in `app.py`
- Increase sidebar top padding from 10px to 20px for better vertical rhythm
- Reduce heading font-size to 0.75em, add uppercase transform, letter-spacing, and margin-top
- Add `:first-child` rule to reset top margin on first sidebar heading
- Tighten list item spacing from 15px to 4px, reduce link font-size to 0.9em
- Add block display, padding, border-radius, and hover background transition to sidebar links
The cache is now disabled by default (self.enabled = False) to prevent stale data serving until explicitly enabled. Additionally, the inline comment documenting the version calculation was removed to clean up the code.
Replace the plain dict cache with an OrderedDict-based implementation that
provides O(1) LRU eviction by re-inserting accessed items at the end.
Introduce an asyncio.Lock to ensure thread-safe concurrent access during
get/set operations. Enable caching by default (self.enabled = True) and
add import for asyncio and OrderedDict.
Remove the entire `snek.system.stats` module including its middleware, statistics structure creation, and websocket stats tracking. This eliminates the `stats_middleware` from the application middleware chain, removes the `update_websocket_stats` calls from the RPC view handler, and deletes the 129-line stats module with its time-series SVG generation and granularity-based counter logic.
- Add performance timing with time.perf_counter() to render_template method in Application class, printing elapsed seconds to stdout
- Disable cache by setting self.enabled = False in Cache.__init__ to bypass caching behavior
- Add early return in ChannelMessageService.maintenance() to skip message iteration loop
- Remove default_limit class attribute assignment in BaseMapper.__init__ and add time import
- Refactor run_in_executor to execute synchronously with _execute() call and wrap semaphore around a second _execute() call instead of using thread pool executor
- Removed trailing semicolons from arrow function bodies in hiddenCompletions object
- Fixed inconsistent indentation for _leetSpeak toggle and textarea classList assignment
- Replaced spread operator with Object.assign for allAutoCompletions getter
- Truncated extractMentions regex pattern at diff boundary
Introduce a new `NewView` class in `src/snek/view/new.py` that renders the `new.html` template, requiring authentication. The template includes a custom `ChatWindow` web component that establishes a WebSocket connection via the `Socket` class, handles channel-based messaging with real-time updates, and supports sending messages on Enter key press while allowing Shift+Enter for multi-line input.
- Register NewView at /new.html endpoint in Application router
- Fix textToLeetAdvanced to require s.length > 1 for valid leet match
- Comment out event.waitUntil(reg) in service-worker push handler to prevent potential hang
- Added console.info call to log event name and data payload in the data handler
- Changed reconnect timeout from 0ms to 4000ms to introduce deliberate delay before reconnection attempt
The change reduces the default `max_workers` for `ProcessPoolExecutor` from 5 to 1 in the `get_or_executor` method of `ChannelMessageService`, and adds a debug print statement to log the number of available executors.
The change modifies the conditional logic in `MessageList.upsertMessage()` to only remove and nullify an existing message when `data.message` is falsy, instead of doing so when `data.is_final` is true or `data.message` is falsy. This ensures that non-final messages with content are not incorrectly removed from the DOM before being updated or re-inserted.
The change limits concurrent thread execution per user to a single worker,
preventing resource exhaustion from unbounded thread creation in the
get_or_create_executor method.
Remove the module-level `executor` variable and introduce instance-level `_executor_pools` dict with `get_or_create_executor` method that creates a `ThreadPoolExecutor(max_workers=5)` per user UID. Update all `run_in_executor` calls in `render_message` and `render_message_edit` to use the per-user executor instead of the shared global one, improving isolation and resource control across concurrent user requests.
The loop iterating over avatar elements now only assigns the first matching anchor to `lastElement`, ensuring the scroll target remains the earliest occurrence instead of being overwritten by subsequent matches.
Add a debug print statement in the `send` method's exception handler to log the exception message before deleting the socket, and update the existing debug print in the message processing loop to include a distinctive prefix for easier log filtering.
The method definition was incorrectly placed at module level instead of being properly indented as a member of the SocketService class. This fix moves the async def user_availability_service declaration one level deeper to align with the class body, restoring correct Python scoping and preventing AttributeError or runtime import failures when the service attempts to register or invoke this method.
Add detailed debug-level log statements throughout the
user_availability_service method to trace execution flow, including
entry into the main loop, socket iteration, connection status checks,
user update decisions, database save operations, and sleep intervals.
Replace the basic contenteditable editor with a full modal editor supporting insert, normal, and visual modes. Add a command-line interface at the bottom for executing commands like :w, :q, and :wq. Introduce mode-specific cursor styling, selection highlighting, and keyboard-driven navigation. The editor now tracks mode state, handles mode transitions via Escape and i/v keys, and displays the current mode in a status bar.
- Added sentry-sdk to project dependencies in pyproject.toml
- Imported and initialized sentry_sdk with DSN in main() function
- Added graceful fallback with print message if sentry_sdk import fails
- Imported `random` module to support randomized delay
- Inserted `await asyncio.sleep(random.uniform(0.1, 0.4))` before `await rpc(msg.json())` in the websocket message loop
- This introduces a jitter of 100-400ms to desynchronize concurrent RPC processing from multiple clients
The `endOfMessages.after(message)` call was placed after the `isScrolledToBottom()` check, causing the scroll position to be evaluated before the new message was inserted into the DOM. This resulted in incorrect scroll behavior when messages were added, as the scroll check would not account for the newly inserted element. Moving the insertion before the scroll check ensures the scroll position is evaluated after the DOM has been updated with the new message.
The diff shows a fix in the `upsertMessage` method of the `MessageList` class in `src/snek/static/message-list.js`. The original condition `(message && data.is_final) || !data.message` was incorrectly grouping the logical OR, causing messages to be removed only when `data.is_final` was true alongside a message, or when `data.message` was falsy regardless of message existence. The fix wraps the entire condition in parentheses: `(message && (data.is_final || !data.message))`, ensuring that a message is removed only if it exists AND either `data.is_final` is true or `data.message` is falsy. A comment `// TO force insert` was added to clarify the intent of nullifying the message reference after removal.
Previously, the upsertMessage method removed any existing message element from the DOM whenever a message with the same uid was received, regardless of whether the update represented a final version. This caused premature removal of messages that were still being streamed or updated incrementally. Now the removal is gated on the `data.is_final` property, ensuring that only completed messages are replaced in the DOM while in-progress messages remain visible until their final state arrives.
Add sanitize_html calls in ChannelMessageService for both render and save paths to strip script, iframe, object, embed tags and event handler attributes from rendered HTML templates. Refactor sanitize_html in template.py to use BeautifulSoup for tag removal and attribute cleaning, replacing the previous bleach-only implementation with a new sanitize_html2 function retained for compatibility.
The whitelist_attributes filter was applied to the rendered HTML output in both
the get_by_uid and save methods of ChannelMessageService. This filter was
stripping allowed HTML attributes from the message content, which could break
formatting or functionality in rendered messages. The fix removes the filter
call, allowing the full rendered template output to be stored and returned
without attribute sanitization.