Skip to content

Releases: caplaz/PatternSpaceSDK

1.1.0

Choose a tag to compare

@acerbetti acerbetti released this 09 Oct 05:41
36c6e4f

Added

  • Optional device.signalSnapshot read route and DeviceNamespace.signalSnapshot() returning schema-1 immutable evidence separately from connection-bound probe authorization. The delegate receives the authenticated OutputRequestContext; reads remain available while the JSON source is inactive.
  • Optional pattern.displayProbe route and PatternNamespace.displayProbe(_:) carrying the existing patch shape plus a bounded opaque expectedContextGuard. The SDK reuses ordinary patch validation and forwards guard/context to the host for atomic authorization and admission. It never falls back to displayPatch.
  • Typed source samples, scalar stage observations, separate accepted/published identities, draw/mapping/presentation identities, capture intervals, explicit unknown/omission reasons, and forward-compatible open tokens. Evidence excludes guard and packed frame buffers. Encoded responses are bounded to 256 KiB; each stage retains at most 64 samples with explicit omitted counts. Oversized optional details are marked omitted; oversized identity fails safely.
  • Default unsupported delegate hooks and supportsSignalSnapshot / supportsSignalProbe opt-ins preserve 1.0.0 conformers. Optional CapabilityFeatures.signalSnapshot / signalProbe have trailing initializer defaults and decode absent from older hosts.

Changed

  • capabilities.list filters only unsupported new routes/flags, preserving all existing namespace entries. Unsupported new methods return method-not-found.
  • PatternSpaceProtocolMetadata.sdkVersion is now 1.1.0; JSON protocol remains 1.3. Existing routes, device bit-depth meaning, ACK behavior and global session timeout behavior remain unchanged.

Fixed

  • Both client transports now accept the full 256 KiB SDK response bound, so valid signal snapshots larger than 64 KiB work on native Network.framework endpoints as well as URLSession endpoints. Server incoming request limits remain unchanged.
  • Invalid mandatory capture timestamps fail validation rather than being replaced with zero. Unsupported evidence schema versions fail typed validation before evidence or probe authorization is decoded.

Host integration

  • Guards belong to the authenticated connection and stable expected target/configuration/ownership context, independent of snapshot revisions and new patches. Historical responses must have no authorization; stable Refresh must not rotate a current guard. Stale context uses displayError, a different connection uses notAuthorized, inactive source uses sourceNotActive, malformed guard uses invalidParams.
  • Share only evidence and apply host export redaction to identifiers/optional descriptions. The SDK does not inspect OS profiles, calculate SDI packing, attest physical transport, or supply a per-request timeout.

1.0.0

Choose a tag to compare

@acerbetti acerbetti released this 03 Oct 13:11

Added

  • output.blank and output.resume server routes under a new output namespace (listed in JSONRPCDispatcher.routeManifest and therefore in capabilities.list), with required delegate hooks blankOutput(context:) and resumeOutput(context:). Both return the resulting OutputStatus; both require an authenticated connection and an active JSON source (sourceNotActive otherwise), exactly like the pattern.* write methods.
  • OutputStatus schema with owner, ownerConnected, blankRequester, blanked, blankPending, failure, idleBlankSeconds, epoch, and revision, plus the enums PSOutputOwner, PSOutputBlankReason, and PSOutputFailure. Absent optional fields are encoded as explicit JSON null; decoders accept either a missing key or null.
  • Optional output: OutputStatus? on DeviceStatus (device.status), DeviceSnapshot (device.statusChanged), and ConnectionReadyParams (connectionReady). It decodes as nil from hosts that do not report it.
  • CapabilitiesResult.outputBlank: Bool? so clients can detect blank support before calling output.*; nil from older hosts.
  • PSErrorCode.outputNotConfirmed (-32013) for a blank that failed or an output whose state is unknown.
  • OutputRequestContext carrying the server-minted clientID of the authenticated connection that sent an output-write request. It is captured at dispatch and never read from JSON params.
  • PatternSpaceServer.onClientConnected: (UUID) -> Void, delivered once per authenticated client when it becomes the active client, with the same identity carried by its OutputRequestContext.
  • ClientDisconnectReason (closed, evicted, serverStopped).
  • Client client.output.blank() and client.output.resume() via the new OutputNamespace.

Changed

  • BREAKING: The six output-write delegate methods are now required context-bearing methods with no default implementations and no context-free overloads: displayPattern(id:context:), displayColor(_:bitDepth:context:), displayPatch(_:context:), clearDisplay(context:), blankOutput(context:), and resumeOutput(context:). Hosts must compare the context with their current connection before mutating output so requests from an evicted or closed client cannot change output. Hosts without blank support must throw PSDispatchError(.methodNotFound) from blankOutput/resumeOutput and omit CapabilitiesResult.outputBlank.
  • BREAKING: JSONRPCDispatcher.dispatch(_:) is now dispatch(_:context:); output writes forward the context to the delegate and read handlers ignore it.
  • BREAKING: PatternSpaceServer.onClientDisconnected is now (UUID, ClientDisconnectReason) -> Void and is delivered exactly once for every client previously reported to onClientConnected, regardless of how many clients remain. On replacement the evicted client's .evicted callback is delivered before the replacement's onClientConnected; stop() reports .serverStopped for every client not yet reported. Rejected (unauthenticated) sockets never produce either callback, and connections accepted after stop() are fenced out.
  • Lifecycle callbacks are serialized on an internal queue in lifecycle order. Callbacks triggered by stop() run synchronously on the thread calling stop() after any in-progress callback finishes. Keep callbacks short and non-blocking (hop to your own actor or queue) and never call DispatchQueue.main.sync from one, or a stop() on the main thread will deadlock.
  • output.blank and output.resume accept absent params, {}, or []; non-empty params, null, and scalar params return invalidParams.
  • The client transport now fences message delivery by connection: connection replacement, identity validation, disconnect reporting, and message delivery share one serialization boundary, so no event from an old socket can be yielded after the new connection's connectionReady. This applies to both the URLSession and Network.framework transports.
  • PatternSpaceProtocolMetadata.sdkVersion is now 1.0.0; PatternSpace JSON protocol remains 1.3 (the output namespace is additive and discoverable through capabilities.list and outputBlank).

Fixed

  • Pending JSON-RPC calls now fail asynchronously when the connection drops, including when the PatternSpaceClient has already been released, instead of leaving awaiting callers suspended.
  • Native WebSocket close frames and send errors now end the socket and trigger auto-reconnect, rather than leaving the client attached to a dead connection.

Migration

  • Add a context: OutputRequestContext parameter to displayPattern, displayColor, displayPatch, and clearDisplay, and implement blankOutput(context:) and resumeOutput(context:) (throw methodNotFound if unsupported).
  • Replace onClientDisconnected = { ... } closures with the (UUID, ClientDisconnectReason) signature and track the active client with onClientConnected.
  • Pass a context to direct JSONRPCDispatcher.dispatch callers (for example in tests): dispatch(data, context: OutputRequestContext(clientID: UUID())).

0.7.6

Choose a tag to compare

@acerbetti acerbetti released this 10 Sep 22:08

Fixed

  • Made the WebSocket client integration test compatible with the Swift Testing version used by GitHub Actions. TaskGroup.next() is mutating and cannot be passed through that runner's #require macro; the test now unwraps its result with ordinary guard handling.

Changed

  • PatternSpaceProtocolMetadata.sdkVersion is now 0.7.6; PatternSpace JSON protocol remains 1.3.

0.7.5

Choose a tag to compare

@acerbetti acerbetti released this 10 Sep 22:00

Fixed

  • Explicit host/IP connections now use URLSessionWebSocketTask rather than NWProtocolWebSocket. On macOS 26, the latter could abort during the WebSocket upgrade against the PatternSpace server even while the server was listening and standards-compliant WebSocket clients connected successfully. Bonjour-discovered services retain the native Network.framework transport, which continues to resolve and connect correctly.
  • Explicit PatternSpaceClient.disconnect() now fails pending JSON-RPC requests, rather than leaving an awaiting caller suspended after the transport has been closed.

Changed

  • Added a client/server integration test that exercises an authenticated device.status request over a real loopback WebSocket connection.
  • PatternSpaceProtocolMetadata.sdkVersion is now 0.7.5; PatternSpace JSON protocol remains 1.3.

0.7.4

Choose a tag to compare

@acerbetti acerbetti released this 23 Jun 21:48

Fixed

  • WebSocketFrameCodec.decode now decodes the second and later frames on a connection. It indexed with absolute Data offsets while comparing against Data.count, and returned consumed as an absolute index rather than a byte count. Because Data keeps a non-zero startIndex after removeFirst(_:), every frame after the first decoded as perpetually .incomplete, so a client sending more than one request on a single connection would hang waiting for a response that was never dispatched. Decoding is now fully relative to startIndex and consumed is a true byte count. Single-request connections were unaffected (their buffers always started at index 0), which is why this only surfaced with multi-request sessions.

Changed

  • PatternSpaceProtocolMetadata.sdkVersion is now 0.7.4; PatternSpace JSON protocol remains 1.3.

0.7.3

Choose a tag to compare

@acerbetti acerbetti released this 23 Jun 20:59

Fixed

  • PatternSpaceClient now emits .connectionFailed for clean server-side closes (WebSocket close frame, nil error), not only for transport errors. Previously a clean close was silent — the event stream yielded nothing, leaving UI consumers (e.g. the iOS Remote tab) stuck showing "Connected" while the client was silently retrying. With this fix any unintentional disconnect, clean or error, surfaces as .connectionFailed so consumers can transition to a failure state immediately. Auto-reconnect still fires; if the server comes back the next connectionReady notification returns the consumer to connected.
  • PatternSpaceClientError now conforms to LocalizedError, providing a readable errorDescription ("The server closed the connection") instead of the default Swift error description.

Changed

  • PatternSpaceProtocolMetadata.sdkVersion is now 0.7.3; PatternSpace JSON protocol remains 1.3.

0.7.2

Choose a tag to compare

@acerbetti acerbetti released this 23 Jun 20:56

Fixed

  • PatternSpaceServer now fires onClientDisconnected when the last active (upgraded) client disconnects. Previously the server silently removed the client from its tracking dict with no notification to the host, leaving the host app stuck in a "connected" state until a new client connected or the server restarted. The callback is suppressed when stop() drives the close (server shutdown already sets status to idle) and when a client is evicted by a new one (the new client is already active).

Changed

  • PatternSpaceProtocolMetadata.sdkVersion is now 0.7.2; PatternSpace JSON protocol remains 1.3.

0.7.1

Choose a tag to compare

@acerbetti acerbetti released this 23 Jun 20:36

Fixed

  • PatternSpaceServer now responds to WebSocket upgrade requests. Each incoming connection was released as soon as it was accepted — before its HTTP upgrade was processed — so the handshake never completed and clients timed out with no response. Connections are now retained until they upgrade or close.
  • WebSocket upgrades are accepted on any resource path. NWProtocolWebSocket clients connecting through a hostPort or Bonjour service endpoint upgrade against / (such endpoints cannot carry a path), which the server previously rejected with 400 Bad Request. The canonical path remains /patternspace, and the bearer token — not the path — stays the authentication boundary.

Changed

  • PatternSpaceProtocolMetadata.sdkVersion is now 0.7.1; PatternSpace JSON protocol remains 1.3.

0.7.0

Choose a tag to compare

@acerbetti acerbetti released this 20 Jun 03:00

Added

  • display.setMeasurementRange server route, delegate hook, client method, params, and result schemas
  • Additive selectedMeasurementRange fields on DisplayEntry and DeviceStatus

Changed

  • PatternSpaceProtocolMetadata.sdkVersion is now 0.7.0; PatternSpace JSON protocol is now 1.3

Removed

  • Per-preset measurementRange from OutputColorPresetConfig; measurement range is host-global runtime state

0.6.0

Choose a tag to compare

@acerbetti acerbetti released this 17 Jun 20:52

Added

  • Preset ID constants for three Linear HDR presets: extLinearSRGBHDR, linearHDRP3D65, linearHDRBT2020
  • OutputColorPresetFamily.linearHDR convenience constant for clients reading Linear HDR preset metadata

Changed

  • PatternSpaceProtocolMetadata.sdkVersion is now 0.6.0; PatternSpace JSON protocol remains 1.2
  • Protocol documentation and README examples now describe Linear HDR presets and Peak White gating semantics