<feed xmlns='http://www.w3.org/2005/Atom'>
<title>domain-dig.git/LocalAPIService.swift, branch v5.0.1</title>
<subtitle>local-first ios domain inspection toolkit. dns, tls, rdap, audit.
</subtitle>
<id>http://git.krz.sh/krz/domain-dig.git/atom?h=v5.0.1</id>
<link rel='self' href='http://git.krz.sh/krz/domain-dig.git/atom?h=v5.0.1'/>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/'/>
<updated>2026-07-25T04:29:01+00:00</updated>
<entry>
<title>feat: stabilize and document the Local API v1 response contract (v5 step 3)</title>
<updated>2026-07-25T04:29:01+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-25T04:14:23+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=a52dee116d4066d1b59bd90b4ebc4def4e1597d6'/>
<id>urn:sha1:a52dee116d4066d1b59bd90b4ebc4def4e1597d6</id>
<content type='text'>
Second v5.0.0 roadmap item: make the Local API's public JSON contract explicit,
documented, and regression-locked, so external consumers (Shortcuts, scripts,
integrations) have a stable surface with a defined compatibility promise.

- LocalAPIContract: new single source of truth for the wire-format version
  ("v1") and the canonical JSON encoder (ISO-8601 dates, sorted keys). Both the
  success and error paths in LocalAPIService now route through it, so the format
  can't drift between them, and the ad-hoc per-call-site encoders are gone.

- The response envelope and every payload struct are promoted from `private` to
  internal so the contract is a first-class, testable part of the module. The
  transport/handler internals (request parser, HTTP response, secret store)
  stay private.

- Docs/local-api.md documents the base URL/auth, the envelope, the encoding
  conventions (notably: absent optionals are omitted, not null), every endpoint
  and its payload fields, the error codes, and the semantic-version-style
  compatibility policy (additive changes keep v1; renames/removals/type changes
  bump the version). Linked from the README.

- LocalAPIContractTests: 16 structure/"golden" tests pinning the envelope shape,
  each payload's field names, the enum encodings, and the ISO-8601 date format.
  They assert structure, not values, so ordinary behavior changes don't churn
  them but a renamed or dropped field fails CI. Full unit suite: 52 passing.
</content>
</entry>
<entry>
<title>feat: add Copy cURL Command button to the Local API page (#30)</title>
<updated>2026-07-25T00:09:01+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-24T23:46:47+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=22ad96331a4456662f740c48882cab8aadd6d0b4'/>
<id>urn:sha1:22ad96331a4456662f740c48882cab8aadd6d0b4</id>
<content type='text'>
Adds a one-tap way to get a working, authenticated request from the Local
API settings page. copyCurlCommand() copies a curl invocation using the
current bound address and token via the Authorization header:

  curl -H "Authorization: Bearer &lt;token&gt;" http://127.0.0.1:&lt;port&gt;/portfolio

Keeps the token in a header rather than a query string, so it stays out of
URLs, browser history, and the request-log view (which masks the token).
Guards on an empty token, matching copyToken().
</content>
</entry>
<entry>
<title>fix: surface the real NWListener error and drop conflicting requiredLocalEndpoint (#30)</title>
<updated>2026-07-25T00:09:01+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-24T23:34:35+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=5fe3aeb2cefc41b8b96d99d47d967eb7aa070c98'/>
<id>urn:sha1:5fe3aeb2cefc41b8b96d99d47d967eb7aa070c98</id>
<content type='text'>
The Local API failed to start with a generic "Could not start Local API on
port 47821" and no actionable cause. Two problems:

1. The NWListener construction catch discarded the caught error and
   substituted a generic string, so the real NWError was never surfaced or
   logged. Now the underlying error is logged via stateLogger (matching the
   .failed branch) and appended to the thrown message.

2. parameters.requiredLocalEndpoint pinned 127.0.0.1:&lt;port&gt; while the same
   port was passed as the listener's on: argument. Pinning a required local
   endpoint conflicts with the listener's own port assignment; acceptLocalOnly
   already constrains binding to the local link. Dropped requiredLocalEndpoint,
   keeping acceptLocalOnly + allowLocalEndpointReuse.
</content>
</entry>
<entry>
<title>fix: StoreKit config path and Swift 6 concurrency warnings</title>
<updated>2026-07-20T20:52:38+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-07-20T20:29:50+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=f834c8a8223c40bd17b90be8f6ab7db843d0914c'/>
<id>urn:sha1:f834c8a8223c40bd17b90be8f6ab7db843d0914c</id>
<content type='text'>
The StoreKitConfigurationFileReference added in #11 used one '../' too
many, resolving outside the repository. Xcode resolves it relative to
the .xcodeproj's xcshareddata directory, so two levels reaches the repo
root.

SweepActivityAttributes is now explicitly nonisolated. The app target
sets SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor while the widget target
does not, so a type shared by both inferred a main-actor-isolated
ActivityAttributes conformance that ActivityKit cannot use from its
concurrent contexts.

LocalAPIService's logger closures captured self strongly while their
inner Tasks declared [weak self]. The weak capture is now on the outer
closure and bound before the Task, so the concurrently-executing closure
references an immutable strong local rather than the weak capture.
</content>
</entry>
<entry>
<title>DomainDig v4.2.0: Add a local-only HTTP API layer for DomainDig</title>
<updated>2026-04-26T05:22:01+00:00</updated>
<author>
<name>Christian Cleberg</name>
<email>hello@cleberg.net</email>
</author>
<published>2026-04-26T05:22:01+00:00</published>
<link rel='alternate' type='text/html' href='http://git.krz.sh/krz/domain-dig.git/commit/?id=cc69cbd7e589ec4b065ce74d8c5e7714a040cfc5'/>
<id>urn:sha1:cc69cbd7e589ec4b065ce74d8c5e7714a040cfc5</id>
<content type='text'>
Expose DomainDig as a programmable local domain intelligence engine over
localhost with explicit user opt-in and token-based authentication.

Highlights:
- add a localhost-only API server with safe start/stop lifecycle
- require a local token for every request and store it in Keychain
- add read endpoints for portfolio, domains, history, events, and monitoring
- add inspection endpoints that reuse the existing inspection engine
- add monitoring enable/disable control endpoints
- add structured JSON response envelopes with API versioning
- add lightweight capped request logging with clear/reset support
- add a Settings UI for Local API enablement, token management, status, and logs
- start the server on launch only when enabled
- include Local API secrets in local data reset cleanup

This is the first programmability release for DomainDig and establishes the
foundation for Shortcuts, scripts, and other local automation workflows.
</content>
</entry>
</feed>
