Resolve #274: mistdemo web command with Hummingbird CRUD routes#333
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## 330-interactive-mistdemo #333 +/- ##
============================================================
- Coverage 70.24% 70.10% -0.15%
============================================================
Files 531 543 +12
Lines 14536 14965 +429
============================================================
+ Hits 10211 10491 +280
- Misses 4325 4474 +149
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Review: PR 333 — mistdemo web command with Hummingbird CRUD routesOverall the shape of this is good: clean protocol abstraction (WebDemoBackend), testable factory injection, actor-based token store, and solid router-level test coverage. One critical lifecycle bug needs fixing before this ships. Critical bug — server stops after ~1 secondWebDemoCommand.execute() puts both app.runService() and openBrowserIfNeeded() in the same ThrowingTaskGroup and calls group.next() after both are enqueued: openBrowserIfNeeded() sleeps 1 second, opens the browser, then returns Void. At that point group.next() unblocks, group.cancelAll() fires, and the server task is cancelled. The command exits roughly 1 second after the browser opens. The fix is to fire the browser open outside the group that controls server lifetime: try? on Task.sleep swallows cancellationIn openBrowserIfNeeded(): try? await Task.sleep(nanoseconds: 1_000_000_000) Ignoring the cancellation error means if the parent task is cancelled during the sleep the browser still opens. Use try await and let the error propagate so cancellation is respected promptly. Dead code in WebDemoServerTests.queryForwardsThe body variable is encoded but never used — jsonBody is the literal that is actually sent. Remove body and the _ = body suppression entirely. WebDemoConfig — double nil-coalescing and redundant alias
makeRouter() always throws for an unreachable errormakeRouter() throws only because JSONEncoder().encode(CloudKitClientConfig(...)) can theoretically throw. CloudKitClientConfig encodes three primitive-typed fields; in practice this call cannot fail. Consider try! with a comment, or restructure so configData is pre-encoded and throws can be dropped from the signature. stringFields could use mapValuesCan be written as raw.mapValues(FieldValue.string). Minor: @available on CloudKitService: WebDemoBackendVerify the @available(macOS 11.0, iOS 14.0, ...) on the conformance extension matches what CloudKitService itself already requires. If redundant, remove it. If narrower, document why. Summary
The HTML/JS page is well-structured, the mode toggle scaffolding for #329 is clean, and the test suite covers the important paths (pre-auth 401, backend errors as 500, all four CRUD operations). Fix the lifecycle bug and this is ready for another look. |
Introduces `mistdemo web`, a long-running server that serves an interactive page combining the CloudKit JS auth round trip with a CRUD UI driven by MistKit. The page also scaffolds the MistKit-vs-CloudKit-JS mode toggle; the CloudKit JS side stays disabled until #329. Layout: - `WebDemoCommand` owns lifecycle (signal handling, browser open). - `WebDemoServer` builds the router (index / config / authenticate + query / create / update / delete records). - `WebAuthTokenStore` is the shared actor holding the captured `ckWebAuthToken`; CRUD routes return 401 until it is set. - `WebDemoBackend` is a narrow protocol over the MistKit methods the routes need; `CloudKitService` conforms via extension. Tests inject a `MockBackend` actor through `WebDemoBackendFactory`. Field values in CRUD request bodies are limited to strings for the MVP demo. Wider FieldValue coverage can land alongside richer UI controls. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Foundational primitives for unifying mistdemo auth-token and web commands. WebAuthTokenStore now exposes an AsyncStream<String> consumers can await to learn about captured session tokens. withTimeoutAndSignals now accepts a nil seconds value, skipping the timeout race for long-running callers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
POST /api/authenticate now returns 204 (server staying up) or 205 (server about to shut down, controlled by a new terminatesAfterAuth flag) with an empty body. The previous JSON AuthResponse was never populated with anything past placeholder nils, so the body was inert; dropping it lets the same handler serve both the long-running web flow and the one-shot auth-token flow that lands in commit 3. The web HTML now branches on the response status: 205 renders a token- display state (unused in the web command, ready for auth-token); 204 proceeds to the existing CRUD UI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AuthTokenCommand now constructs a WebDemoServer with terminatesAfterAuth: true, observes WebAuthTokenStore.tokenUpdates for the first captured token, and exits after a 500ms grace period so the 205 response reaches the browser. AuthTokenConfig gains an --environment flag (default .development), wiring CloudKit JS through the unified /api/config payload and unblocking auth against production containers. Deletes the now-unreachable AuthTokenServer, AuthTokenIndexHTML, auth-token-index.html, AuthResponse, CloudKitData, and the corresponding server tests. The remaining auth response body was inert placeholder data; its rendering paths in the old HTML were dead code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0d67dca to
bb0923f
Compare
Code Review: PR #332 + PR #333 (mistdemo web command)Reviewed against the final stacked state on branch Code Quality and ConventionsPR #332 — Mostly excellent.
PR #333 — Good overall, a few rough spots.
Minor: Minor: In Architecture
Concern:
Concurrency Safety
Bug: group.addTask { try await app.runService() } // task A
group.addTask { await openBrowserIfNeeded() } // task B: returns immediately when noBrowser=true
try await group.next()
group.cancelAll()When group.addTask { try await app.runService() }
if !config.noBrowser {
group.addTask { await openBrowserIfNeeded() }
}
try await group.next()
group.cancelAll()
The old fire-and-forget
SecurityLoopback guard is applied consistently on all CRUD and auth routes.
XSS risk in card.innerHTML = `...<pre ...>${token}</pre>...`;A CloudKit web-auth token is an opaque string that will never contain HTML in practice, but interpolating any untrusted data into
No CSRF protection. Since the server binds exclusively to loopback and is a single-user demo tool, traditional CSRF is not a realistic threat, but a note in the server's doc comment would clarify this is an intentional decision. Test CoverageGood coverage of the happy paths. The 19 tests across Missing:
Summary
The 🤖 Generated with Claude Code |
Mirrors the existing Native-README.md convention at the MistDemo level. Documents prerequisites, every WebDemoConfig flag, the routes exposed by WebDemoServer, the MistKit / CloudKit JS mode toggle, direct curl usage, and the source layout for the web demo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- WebCommand.execute: use group.waitForAll() so the server keeps running after the browser-opener task returns (group.next() was cancelling the server as soon as openBrowserIfNeeded finished its 1s sleep). - Rename WebDemoCommand -> WebCommand and Resources/web-demo-index.html -> Resources/index.html; update Package.swift, Bundle.module loader, and command registration. - Move /api loopback enforcement out of six per-route guards into a LoopbackOnlyMiddleware applied once to the /api router group. Index route stays unguarded as before. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Rename WebDemo* types and files to Web* (WebDemoServer→WebServer, WebDemoBackend→WebBackend, WebDemoIndexHTML→WebIndexHTML, etc.) and drop the webDemo* prefix from WebBackend's protocol methods. - Split WebDemoRequests into WebRequests (Query/Create/Update/Delete) and a new WebResponse (Records/Delete/Error); drop the redundant *Request/*Response suffixes from the inner type names. - Extract WebBackendFactory into its own file (one_declaration_per_file). - Move WebServer's CRUD endpoint adders into WebServer+CRUD.swift and reorder type contents so static helpers precede instance methods (file_length + type_contents_order under --strict). - Split WebServerTests CRUD tests into WebServerTests+CRUD.swift to fit file_length / type_body_length; drop unused encode-placeholders that triggered multiline_arguments_brackets. - AuthTokenCommand: extract captureToken static helper for function_body_length; reorder to subtype → init → type_method → instance_method. - MockBackend: add explicit internal ACLs (13) and reorder so type methods precede instance methods. - WebAuthTokenStore: reorder properties → init → methods → deinit. - WebIndexHTML: replace try!/force-unwrap with precondition in loader. - TestIntegrationCommand / TestPrivateCommand: reformat --lookup-email help text to use 2-space indent on continuation lines. - MistDemoConfig+DatabaseConfiguration: move computed property before instance method. - WebCommand: split guard return onto own line. Branch now passes ./Scripts/lint.sh under LINT_MODE=STRICT (45 → 0 swiftlint violations); 918 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code Review: PR #333 — mistdemo web command with Hummingbird CRUD routesOverview: This PR adds Code Quality and Best PracticesStrengths:
Issues / Suggestions:
Potential Bugs / Issues
Security Considerations
Test CoverageGood overall. 13 new tests covering:
Gaps worth tracking (not blocking):
SummarySolid PR. Architecture is clean, the refactor from 🤖 Reviewed with Claude Code |
Pair the public-database integration command with its private-database sibling: TestIntegrationCommand → TestPublicCommand, TestIntegrationConfig → TestPublicConfig, TestIntegrationConfigTests → TestPublicConfigTests. Subcommand becomes `mistdemo test-public`, helpText title TEST-PUBLIC. Cross-refs in TestPrivateCommand's helpText and CLAUDE.md follow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitHub already renders the directory-level README automatically for the Examples/MistDemo/ link in the top-level README, so a single combined file is the natural landing page. Shared intro, prerequisites, and the three-row comparison table live up top; per-surface sections (CLI, web, native app) follow with the substantive content lifted verbatim from the original Web-README.md and Native-README.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code Review — PR #333:
|
Summary
Phase 2 of #330 — stacked on top of #332. Adds
mistdemo web, a long-running interactive demo combining the CloudKit JS auth round trip with a CRUD UI driven by MistKit on the server. The page also scaffolds the MistKit-vs-CloudKit-JS mode toggle; the CloudKit JS side stays disabled until #329 wires it.What lands
WebDemoCommand— long-running command (mistdemo web) that owns lifecycle: server task, browser open, signal handling.WebDemoServer— Hummingbird router covering/,/api/config,/api/authenticate, plus CRUD routes/api/records/{query,create,update,delete}.WebAuthTokenStore— actor holding the capturedckWebAuthToken; CRUD routes return 401 until it is set.WebDemoBackend— narrow protocol over the MistKit methods the routes need.CloudKitServiceconforms via extension; tests inject aMockBackendactor throughWebDemoBackendFactory.Resources/web-demo-index.html— interactive UI with mode toggle, auth area, and panels for each CRUD op.Scope notes
FieldValuecoverage can land alongside richer UI controls.Test plan
swift buildcleanswift test— 920 tests pass (13 new: 9 WebDemoServer + 4 WebAuthTokenStore)./Scripts/lint.sh— clean🤖 Generated with Claude Code
Perform an AI-assisted review on