feat(sdk): Effect v4 + @effect/openapi-generator; typed pf.api & example ladder
Drop Orval for the first-party @effect/openapi-generator (OpenAPI 3.1 -> Effect Schema + a typed HttpClient client) and bump effect 3.19 -> 4.0.0-beta.98. Port the hand-written surfaces to the v4 API (Result over Either, Context.Service, Codec, Literals/Union arrays, Stream/Schedule/ Effect renames). Transport (CA-pinning fetch) and the reconnecting SSE source are kept intact. Make the SDK approachable for non-Effect users: - Add pf.api.* on the Promise facade: the generated client surfaced as typed, Promise-native methods (await pf.api.listPairedClients()), so REST calls are autocompleted and checked instead of stringly-typed pf.request(method, path, body) + `as` casts. Zero-drift veneer over make(httpClient), backed by the same pinning fetch. pf.request stays as the untyped escape hatch. - Re-tier examples into a 1-4 complexity ladder, rewritten onto pf.api.* (the typed payloads caught a wrong `launch` shape in provider-sync); the Effect example is labelled advanced. Add examples/ to tsconfig so they are typechecked (stops rot). typecheck + 19 tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+14
-4
@@ -9,7 +9,8 @@
|
||||
// pf.events.on("pairing.pending", async (e) => {
|
||||
// await notifyPhone(`Pairing request from ${e.device.name}`);
|
||||
// });
|
||||
import type { Effect } from "effect";
|
||||
import { type Effect, Result } from "effect";
|
||||
import { type HostApi, makeHostApi } from "./api.js";
|
||||
import type { PunktfunkHost } from "./client.js";
|
||||
import {
|
||||
type ConnectOptions,
|
||||
@@ -26,6 +27,7 @@ import {
|
||||
kindMatches,
|
||||
} from "./wire.js";
|
||||
|
||||
export type { HostApi } from "./api.js";
|
||||
export { HttpStatusError } from "./core.js";
|
||||
export type { ConnectOptions } from "./config.js";
|
||||
export type {
|
||||
@@ -66,7 +68,13 @@ export interface PunktfunkEvents {
|
||||
export interface Punktfunk {
|
||||
/** Resolved connection (URL/token/CA). */
|
||||
readonly config: ResolvedConfig;
|
||||
/** One management-API request under `/api/v1` (`request("GET", "/status")`). */
|
||||
/**
|
||||
* The **typed** management API — every REST endpoint as an autocompletable method with
|
||||
* checked request/response types (`await pf.api.listPairedClients()`). This is the front
|
||||
* door; reach for [`request`] only for something the generated client doesn't cover.
|
||||
*/
|
||||
readonly api: HostApi;
|
||||
/** Untyped escape hatch: one raw `/api/v1` request (`request("GET", "/status")`). */
|
||||
request(method: string, path: string, body?: unknown): Promise<unknown>;
|
||||
/** The lifecycle-event subscription surface. */
|
||||
readonly events: PunktfunkEvents;
|
||||
@@ -83,6 +91,7 @@ export const connect = async (options?: ConnectOptions): Promise<Punktfunk> => {
|
||||
const cfg = await resolveConfig(options);
|
||||
// Fail fast on bad credentials/URL: one cheap authenticated probe.
|
||||
await httpRequest(cfg, "GET", "/host");
|
||||
const api = await makeHostApi(cfg);
|
||||
|
||||
const listeners = new Set<Listener>();
|
||||
let pump: AsyncGenerator<SseFrame> | undefined;
|
||||
@@ -118,11 +127,11 @@ export const connect = async (options?: ConnectOptions): Promise<Punktfunk> => {
|
||||
continue;
|
||||
}
|
||||
const decoded = decodeHostEvent(json);
|
||||
if (decoded._tag === "Left") {
|
||||
if (Result.isFailure(decoded)) {
|
||||
dispatch("unknown", json);
|
||||
continue;
|
||||
}
|
||||
dispatch(decoded.right.kind, decoded.right);
|
||||
dispatch(decoded.success.kind, decoded.success);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!closed) warn(`event stream stopped: ${e}`);
|
||||
@@ -132,6 +141,7 @@ export const connect = async (options?: ConnectOptions): Promise<Punktfunk> => {
|
||||
|
||||
return {
|
||||
config: cfg,
|
||||
api,
|
||||
request: (method, path, body) => httpRequest(cfg, method, path, body),
|
||||
events: {
|
||||
on(pattern: string, cb: (ev: never) => unknown) {
|
||||
|
||||
Reference in New Issue
Block a user