feat(camera): close the gap between @rawback/ccapi-js and rawback camera - #87
Conversation
1.1.3 fixes several wire-format bugs the CLI was hitting on real bodies:
`camera status` reported recordable as null (1.1.2 read the wrong keys),
monitoring kept non-event units, and GPS was sent in a shape the camera
rejects.
- The catalogue swaps the deprecated liveview.getRTP (always empty) for
getRTPStatus, and requestAngleInformation takes start|stop.
- contents.setContentGPS accepts the { degree, minute, second } and
{ hour, minute, second } rationals 1.1.3 sends, as well as flat arrays,
and its placeholder shows the real shape.
- contents list rejects --order without --all: the camera refuses order
on a single page and 1.1.3 now drops it silently.
- Fixtures send recordable as recordableshots/remainingtime and
monitoring events as 0x02 units, as cameras do.
The lockfile still resolves @rawback/sdk 0.3.3 because 0.3.4 is not
published yet; that mismatch predates this change.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…keys - `settings list` read the decoded aggregate, whose camelCase keys (`shootingMode`) became paths the camera does not have when passed to `settings get`/`set`, and which dropped every setting it does not model. It now reads the raw aggregate, so every row round-trips; range abilities report `range`, and structured values print as JSON. - `shooting.setPictureStyleDetail` told users to send snake_case keys, which the library silently drops. Keys are now checked against the library's parameters, and the camera's spellings point at theirs. - `event.getPolling` in the catalogue takes `hold` instead of `continue`, which ver110+ bodies reject; `timeout` is limited to short|long. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`camera api` and the explorer now reach every non-deprecated JSON endpoint in @rawback/ccapi-js 1.1.3: - shooting: getShootingSettingsRaw, picture-style base, sound-recording mode/wind filter/attenuator, crop depth composite, the focus-bracketing flash interval, and the power-zoom adapter setting. - stillimagequality and wbshift are object-valued, and the camera rejects the string PUT the catalogue used to send; they now take a JSON object and read through the typed getters. - contents.setContentXMPDescription. - network: the connection, communication, function, Wi-Fi and connect setting setters, loading the deep network tables first as the getters do. JSON members are checked before the camera sees them, since the library drops unknown keys. The drift guard now counts an accessor rejecting its synthetic arguments as a failure, so every entry provably reaches the client. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Once Ink has loaded, Bun's console.log makes a single write to a pipe and drops whatever the pipe buffer did not take, so any `--json` document over 64 KiB was cut off when piped (`rawback camera api --list --json | jq` read truncated JSON). CommandOutput now writes to process.stdout and process.stderr, whose writes are queued and drained before exit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… detail The binary CCAPI endpoints the JSON catalogue cannot carry now have commands: - `camera cert <output>` saves the root TLS certificate and prints the openssl command that shows its fingerprint, so it can be checked against the camera before reaching for --insecure. - `camera rtp start|stop|status|sdp` streams live view over RTP and saves the session description a player needs. - `camera liveview frame --detail` reads flipdetail and reports the AF frames, level, zoom and histogram alongside the saved frame. - `camera liveview stream` falls back to the chunked scroll stream on a body that serves no multipart stream. Supporting changes: CameraSession.requireSupport refuses an unadvertised endpoint by name before any request (and `camera api` now uses it), and the overwrite guard moved to camera-files.ts so every file-writing command shares it. The fake camera can answer with a raw Response for binary bodies. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The controls a photographer reaches for most were only reachable as `camera api <id> --arg k=v`; they now have commands: - `camera record start|stop|status`, refusing to start outside movie mode unless --movie-mode switches it on first. - `camera focus af|stop|near|far [--steps 1-3]`. - `camera zoom [position|wide|tele|stop]`, reading every zoom control the body has when given no value. - `camera clock [sync]`, which sets the host's local time and full UTC offset with the camera's DST flag off, then reads the clock back. - `camera owner [set|clear]` for the copyright, author, owner name and nickname written into every file; set checks every field is supported before writing any. `camera status` also reports every battery including a grip's, the mounted lens, and a Power Zoom Adapter's state, as additive JSON keys. Every command that changes the camera confirms first unless --force. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- `camera contents protect|archive|rate|rotate|xmp|geotag` change one file on the card. `geotag` builds the full EXIF GPS block the camera requires from decimal degrees (DMS rationals rounded in hundredths of an arcsecond, so 59.999" carries into the minute), with the UTC time and date of --time. `xmp` inserts raw attributes into the file's XMP rdf:Description tag, which is what the camera's xmp_description action does — it is not a free-text caption. - `camera contents rmdir <storage> <directory>` deletes a directory through its ver140 folder. - `camera card format <storage>` checks the storage against the camera's own list, and without --force has the name typed back before erasing. Every edit confirms first unless --force, and values are validated before connecting. Also adds the missing tests for `contents dirs` and `contents info`, and brings the agent guide's command and test counts up to date. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f97a6fb0dd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| await withCameraSession(options, dependencies, async (session) => { | ||
| session.requireSupport(RTP, 'rawback camera rtp start') | ||
| await session.client.liveview.setRTP('start', options.ip) |
There was a problem hiding this comment.
Stop RTP in generic live-view cleanup
After camera rtp start, the documented recovery command camera liveview stop still releases only the multipart and scroll streams in runCameraLiveviewStop. Consequently, it can report success while the camera continues transmitting RTP and remains occupied; either include setRTP('stop') when the endpoint is advertised or narrow the documented cleanup guarantee.
AGENTS.md reference: AGENTS.md:L126-L127
Useful? React with 👍 / 👎.
| function rangeOf(ability: unknown): SettingRow['range'] { | ||
| if (typeof ability !== 'object' || ability === null || Array.isArray(ability)) return null | ||
| const { min, max, step } = ability as Record<string, unknown> | ||
| if (typeof min !== 'number' && typeof max !== 'number') return null |
There was a problem hiding this comment.
Preserve all-null locked ranges in settings list
When the aggregate settings response contains the documented locked shape ability: { min: null, max: null, step: null }, this condition discards it because neither bound is numeric. camera settings list therefore emits range: null and renders a dash instead of identifying the setting as locked, despite the presenter already supporting an all-null range; recognize objects containing the range keys even when every value is null.
Useful? React with 👍 / 👎.
Summary
The
camera apicatalogue already reached 231 of the library's 269 client methods; the gaps were an outdated pin, a few CLI bugs, binary endpoints the JSON catalogue cannot carry, and everyday controls with no command of their own. One commit per phase:chore(deps): bump@rawback/ccapi-jsto 1.1.3. 1.1.2 readrecordablefrom the wrong keys (socamera statusalways reportednull), sent GPS and object-valued settings in shapes cameras reject, and kept non-event units in monitoring.contents list --ordernow requires--all, because the camera rejectsorderon a single page.fix(camera).settings listprinted camelCase names thatsettings get/setthen sent as paths the camera does not have; it now reads the raw aggregate, so every row round-trips. Picture-style parameters are checked by name instead of silently dropped. The catalogue's event polling useshold, which works on every version.feat(camera): catalogue parity. Adds the remaining non-deprecated JSON endpoints: picture-style base, sound-recording settings, crop depth composite, focus-bracketing flash interval, power-zoom setting, typed still-image quality and WB shift, XMP description, and the network setters. The drift guard now fails when synthetic arguments never reach the client.fix(ui): any--jsondocument over 64 KiB was cut off when piped. Once Ink loads, Bun'sconsole.logdrops what a pipe buffer does not take.CommandOutputnow writes through the process streams; a test reproduces the bug through a realsh … | catpipe.feat(camera): binary endpoints.camera certsaves the root certificate and prints the command that shows its fingerprint.camera rtp start|stop|status|sdpstreams live view over RTP.liveview frame --detailreads the frame's AF frames, level, zoom and histogram.liveview streamfalls back to the scroll stream on bodies with no multipart stream.feat(camera): controls.record,focus,zoom,clock [sync], andowner [set|clear].statusgainsbatteries,lensandpowerZoomas additive JSON keys.feat(camera): content edits.contents protect|archive|rate|rotate|xmp|geotag|rmdir.card format, which must be typed back unless--forceis given.Every command that changes the camera confirms first, and needs
--forcetogether with--json.Needs attention before merging
bun install --frozen-lockfileuntil@rawback/sdk0.3.4 is published. This is already the case onmain, whosepackage.jsonpins 0.3.4. Merge rawback-app/sdk#46, then runbun installon this branch and commit the lockfile.clock syncsends the host's local time with its full UTC offset and the camera's daylight-saving flag off, then reads the clock back. This choice avoids adding an hour twice; please confirm it on a body while daylight saving is in effect.rtp,liveview frame --detailand the scroll fallback were only exercised against the fake camera.Test plan
bun test test/camera*: 267 passbun run lint,bun run format:checkmain:photos/spotsneed SDK 0.3.4, andbootstrapConfigfails when a long temp path wrapsbun run checkonce SDK 0.3.4 is installedcamera status --json:recordableis not nullcamera settings list, then pass a listed name tosettings getcamera clock synccamera liveview frame f.jpg --detailcamera rtp sdp s.sdpcamera contents rate <locator> 3🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.