@tuvl/client 2026.2.1-beta.1 → 2026.2.3-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +70 -1
- package/dist/index.d.mts +183 -40
- package/dist/index.d.ts +183 -40
- package/dist/index.js +152 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +152 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -11
package/dist/index.js
CHANGED
|
@@ -123,6 +123,91 @@ var init_grpc = __esm({
|
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
+
// src/crud.ts
|
|
127
|
+
var CrudClient = class {
|
|
128
|
+
constructor(transport, modelName) {
|
|
129
|
+
this.transport = transport;
|
|
130
|
+
this.basePath = `/models/${modelName.toLowerCase()}`;
|
|
131
|
+
}
|
|
132
|
+
// ── Private helpers ──────────────────────────────────────────────────────
|
|
133
|
+
/** Build query string from list options. */
|
|
134
|
+
_buildQuery(options) {
|
|
135
|
+
const params = new URLSearchParams();
|
|
136
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
137
|
+
if (options.offset !== void 0) params.set("offset", String(options.offset));
|
|
138
|
+
if (options.filters) {
|
|
139
|
+
for (const [key, value] of Object.entries(options.filters)) {
|
|
140
|
+
params.set(`filter[${key}]`, value);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (options.include && options.include.length > 0) {
|
|
144
|
+
params.set("include", options.include.join(","));
|
|
145
|
+
}
|
|
146
|
+
const qs = params.toString();
|
|
147
|
+
return qs ? `?${qs}` : "";
|
|
148
|
+
}
|
|
149
|
+
/** Build ?include= query string for get-by-id calls. */
|
|
150
|
+
_buildGetQuery(options) {
|
|
151
|
+
if (!options.include || options.include.length === 0) return "";
|
|
152
|
+
const params = new URLSearchParams({ include: options.include.join(",") });
|
|
153
|
+
return `?${params.toString()}`;
|
|
154
|
+
}
|
|
155
|
+
// ── Public CRUD methods ──────────────────────────────────────────────────
|
|
156
|
+
/**
|
|
157
|
+
* GET /models/{model}/
|
|
158
|
+
* Returns all records matching the given filters (server default: up to 100).
|
|
159
|
+
*/
|
|
160
|
+
async list(options = {}) {
|
|
161
|
+
const qs = this._buildQuery(options);
|
|
162
|
+
return this.transport.get(`${this.basePath}/${qs}`, {
|
|
163
|
+
token: options.token,
|
|
164
|
+
signal: options.signal
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* GET /models/{model}/{id}
|
|
169
|
+
* Returns a single record by UUID, optionally with embedded relations.
|
|
170
|
+
*/
|
|
171
|
+
async get(id, options = {}) {
|
|
172
|
+
const qs = this._buildGetQuery(options);
|
|
173
|
+
return this.transport.get(`${this.basePath}/${encodeURIComponent(id)}${qs}`, {
|
|
174
|
+
token: options.token,
|
|
175
|
+
signal: options.signal
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* POST /models/{model}/
|
|
180
|
+
* Creates a new record and returns the created resource (HTTP 201).
|
|
181
|
+
*/
|
|
182
|
+
async create(body, options = {}) {
|
|
183
|
+
return this.transport.post(`${this.basePath}/`, body, {
|
|
184
|
+
token: options.token,
|
|
185
|
+
signal: options.signal
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* PATCH /models/{model}/{id}
|
|
190
|
+
* Partially updates a record (only fields present in `body` are changed).
|
|
191
|
+
*/
|
|
192
|
+
async update(id, body, options = {}) {
|
|
193
|
+
return this.transport.patch(
|
|
194
|
+
`${this.basePath}/${encodeURIComponent(id)}`,
|
|
195
|
+
body,
|
|
196
|
+
{ token: options.token, signal: options.signal }
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* DELETE /models/{model}/{id}
|
|
201
|
+
* Deletes a record (HTTP 204). Throws if the record is not found.
|
|
202
|
+
*/
|
|
203
|
+
async delete(id, options = {}) {
|
|
204
|
+
return this.transport.delete(`${this.basePath}/${encodeURIComponent(id)}`, {
|
|
205
|
+
token: options.token,
|
|
206
|
+
signal: options.signal
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
|
|
126
211
|
// src/sse.ts
|
|
127
212
|
async function* parseSseStream(response, signal) {
|
|
128
213
|
if (!response.body) {
|
|
@@ -256,6 +341,41 @@ var Transport = class {
|
|
|
256
341
|
}
|
|
257
342
|
return response.json();
|
|
258
343
|
}
|
|
344
|
+
/** Perform a JSON PATCH and return the parsed response body. */
|
|
345
|
+
async patch(path, body, options) {
|
|
346
|
+
const headers = {
|
|
347
|
+
"Content-Type": "application/json",
|
|
348
|
+
Accept: "application/json"
|
|
349
|
+
};
|
|
350
|
+
const auth = this.authHeader(options?.token);
|
|
351
|
+
if (auth) headers["Authorization"] = auth;
|
|
352
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
353
|
+
method: "PATCH",
|
|
354
|
+
headers,
|
|
355
|
+
body: JSON.stringify(body),
|
|
356
|
+
signal: options?.signal
|
|
357
|
+
});
|
|
358
|
+
if (!response.ok) {
|
|
359
|
+
const text = await response.text();
|
|
360
|
+
throw new Error(`tuvl PATCH ${path} \u2192 HTTP ${response.status}: ${text}`);
|
|
361
|
+
}
|
|
362
|
+
return response.json();
|
|
363
|
+
}
|
|
364
|
+
/** Perform a DELETE request. Expects a 204 No Content response. */
|
|
365
|
+
async delete(path, options) {
|
|
366
|
+
const headers = {};
|
|
367
|
+
const auth = this.authHeader(options?.token);
|
|
368
|
+
if (auth) headers["Authorization"] = auth;
|
|
369
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
370
|
+
method: "DELETE",
|
|
371
|
+
headers,
|
|
372
|
+
signal: options?.signal
|
|
373
|
+
});
|
|
374
|
+
if (!response.ok) {
|
|
375
|
+
const text = await response.text();
|
|
376
|
+
throw new Error(`tuvl DELETE ${path} \u2192 HTTP ${response.status}: ${text}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
259
379
|
};
|
|
260
380
|
|
|
261
381
|
// src/types.ts
|
|
@@ -556,6 +676,37 @@ var TuvlClient = class {
|
|
|
556
676
|
}
|
|
557
677
|
return envelope.data ?? envelope;
|
|
558
678
|
}
|
|
679
|
+
// ── CRUD ──────────────────────────────────────────────────────────────────
|
|
680
|
+
/**
|
|
681
|
+
* Return a typed CRUD client for a tuvl model endpoint.
|
|
682
|
+
*
|
|
683
|
+
* The returned client targets `/models/{modelName}/` and shares the
|
|
684
|
+
* same transport (base URL + auth token) as this TuvlClient instance.
|
|
685
|
+
*
|
|
686
|
+
* @example
|
|
687
|
+
* ```ts
|
|
688
|
+
* // List all candidates
|
|
689
|
+
* const all = await client.crud("candidate").list();
|
|
690
|
+
*
|
|
691
|
+
* // With filters + embedded relations
|
|
692
|
+
* const results = await client.crud("candidate").list({
|
|
693
|
+
* filters: { stage: "screening" },
|
|
694
|
+
* include: ["posting"],
|
|
695
|
+
* limit: 50,
|
|
696
|
+
* });
|
|
697
|
+
*
|
|
698
|
+
* // Get one record
|
|
699
|
+
* const c = await client.crud("candidate").get("uuid-here");
|
|
700
|
+
*
|
|
701
|
+
* // Strongly-typed variant
|
|
702
|
+
* const c2 = await client
|
|
703
|
+
* .crud<CandidateRead, CandidateCreate>("candidate")
|
|
704
|
+
* .create({ name: "Alice", email: "alice@example.com" });
|
|
705
|
+
* ```
|
|
706
|
+
*/
|
|
707
|
+
crud(modelName) {
|
|
708
|
+
return new CrudClient(this.transport, modelName);
|
|
709
|
+
}
|
|
559
710
|
};
|
|
560
711
|
|
|
561
712
|
// src/auth.ts
|
|
@@ -686,6 +837,7 @@ var TuvlAuth = class {
|
|
|
686
837
|
// src/index.ts
|
|
687
838
|
init_grpc();
|
|
688
839
|
|
|
840
|
+
exports.CrudClient = CrudClient;
|
|
689
841
|
exports.Transport = Transport;
|
|
690
842
|
exports.TuvlAuth = TuvlAuth;
|
|
691
843
|
exports.TuvlClient = TuvlClient;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/grpc.ts","../src/sse.ts","../src/transport.ts","../src/types.ts","../src/client.ts","../src/auth.ts","../src/index.ts"],"names":["openGrpcStream"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * gRPC-Web transport for @tuvl/client.\n *\n * This module is an OPTIONAL transport that requires the peer dependencies:\n * @protobuf-ts/grpcweb-transport\n * @protobuf-ts/runtime-rpc\n *\n * It uses dynamic import() so the main bundle has zero overhead if you never\n * use mode=\"grpc\". The protobuf definitions are created inline rather than\n * from generated stubs, keeping the SDK self-contained (no make proto step\n * required on the client side).\n *\n * The wire format matches execution.proto:\n * service ExecutionService { rpc RunWorkflow(RunRequest) → stream StepEvent }\n */\n\n/**\n * gRPC StepEvent on the wire. Unlike the typed SSE `StepEvent` (which is\n * narrowed to `event_type: \"step\"`), this can carry \"step\" | \"done\" |\n * \"error\" | \"suspended\" — the discriminator the servicer chose.\n */\nexport interface GrpcStepEvent {\n event_type: \"step\" | \"done\" | \"error\" | \"suspended\";\n step_id: string;\n kind: string;\n signal: string;\n /** Decoded from `snapshot_json` on the wire. */\n snapshot: Record<string, unknown>;\n duration_ms: number;\n error_detail?: string;\n}\n\nexport interface GrpcRunOptions {\n baseUrl: string;\n workflowName: string;\n payloadJson: string;\n tokenFallback?: string;\n token?: string;\n signal?: AbortSignal;\n}\n\n/**\n * Open a gRPC-Web server-streaming call to ExecutionService.RunWorkflow.\n *\n * Yields `GrpcStepEvent` objects (with `snapshot_json` already parsed into\n * `snapshot`). The caller decides what each `event_type` means.\n *\n * Throws if the peer deps are not installed.\n */\nexport async function* openGrpcStream(\n options: GrpcRunOptions,\n): AsyncGenerator<GrpcStepEvent> {\n // Dynamically import peer deps — zero cost when not used\n let GrpcWebFetchTransport: { new (opts: { baseUrl: string }): unknown };\n try {\n const mod = await import(\"@protobuf-ts/grpcweb-transport\");\n GrpcWebFetchTransport = (mod as { GrpcWebFetchTransport: typeof GrpcWebFetchTransport }).GrpcWebFetchTransport;\n } catch {\n throw new Error(\n \"@tuvl/client: gRPC mode requires @protobuf-ts/grpcweb-transport. \" +\n \"Install it with: npm i @protobuf-ts/grpcweb-transport @protobuf-ts/runtime-rpc\",\n );\n }\n\n const { BinaryWriter, BinaryReader, WireType } = await import(\n \"@protobuf-ts/runtime\"\n );\n\n // ── Minimal inline protobuf encode/decode for RunRequest / StepEvent ───────\n\n function encodeRunRequest(\n workflowName: string,\n payloadJson: string,\n tokenFallback: string,\n ): Uint8Array {\n const writer = new BinaryWriter();\n writer.tag(1, WireType.LengthDelimited).string(workflowName);\n writer.tag(2, WireType.LengthDelimited).string(payloadJson);\n if (tokenFallback) {\n writer.tag(3, WireType.LengthDelimited).string(tokenFallback);\n }\n return writer.finish();\n }\n\n function decodeStepEvent(bytes: Uint8Array): GrpcStepEvent {\n const reader = new BinaryReader(bytes);\n let eventType = \"\";\n let stepId = \"\";\n let kind = \"\";\n let signal = \"\";\n let snapshotJson = \"\";\n let durationMs = 0;\n let errorDetail = \"\";\n\n while (reader.pos < reader.len) {\n const [fieldNo, wireType] = reader.tag();\n switch (fieldNo) {\n case 1: eventType = reader.string(); break;\n case 2: stepId = reader.string(); break;\n case 3: kind = reader.string(); break;\n case 4: signal = reader.string(); break;\n case 5: snapshotJson = reader.string(); break;\n case 6: durationMs = reader.float(); break;\n case 7: errorDetail = reader.string(); break;\n default: reader.skip(wireType);\n }\n }\n\n let snapshot: Record<string, unknown> = {};\n if (snapshotJson) {\n try {\n snapshot = JSON.parse(snapshotJson) as Record<string, unknown>;\n } catch {\n // ignore malformed snapshot\n }\n }\n\n // Default to \"step\" if the server didn't stamp event_type (shouldn't happen\n // — every emitted message sets the field — but stay defensive).\n const et = (eventType || \"step\") as GrpcStepEvent[\"event_type\"];\n\n return {\n event_type: et,\n step_id: stepId,\n kind,\n signal,\n snapshot,\n duration_ms: durationMs,\n error_detail: errorDetail || undefined,\n };\n }\n\n // ── gRPC-Web call ─────────────────────────────────────────────────────────\n\n const transport = new (GrpcWebFetchTransport as { new (opts: { baseUrl: string; fetchInit?: RequestInit }): { serverStreaming: (descriptor: unknown, input: unknown, options?: unknown) => { responses: AsyncIterable<Uint8Array> } } })({\n baseUrl: options.baseUrl,\n fetchInit: options.token\n ? { headers: { Authorization: `Bearer ${options.token}` } }\n : undefined,\n });\n\n const methodDescriptor = {\n name: \"/tuvl.v1.ExecutionService/RunWorkflow\",\n clientStreaming: false,\n serverStreaming: true,\n I: { create: () => ({}) } as unknown,\n O: { create: () => ({}) } as unknown,\n options: {},\n };\n\n const requestBytes = encodeRunRequest(\n options.workflowName,\n options.payloadJson,\n options.tokenFallback ?? \"\",\n );\n\n const call = transport.serverStreaming(methodDescriptor, requestBytes, {\n abort: options.signal,\n });\n\n for await (const responseBytes of call.responses) {\n const event = decodeStepEvent(responseBytes as Uint8Array);\n yield event;\n if (\n event.event_type === \"done\" ||\n event.event_type === \"error\" ||\n event.event_type === \"suspended\"\n ) {\n break;\n }\n }\n}\n","/**\n * SSE transport for @tuvl/client.\n *\n * Uses the Fetch API ReadableStream to parse SSE frames from a POST response\n * opened by Transport.postStream(). This avoids the browser's native\n * EventSource (which only supports GET) and works in Node 18+.\n *\n * Wire format produced by tuvl.core.engine.streaming:\n *\n * event: step data: {step_id, kind, signal, snapshot, duration_ms, error_detail}\n * event: suspended data: {<hitl_request payload>}\n * event: done data: {success, data, error}\n * event: error data: {message, details}\n *\n * The JSON body has NO `event_type` field — it lives only on the `event:`\n * line. This parser injects the event name as `event_type` into the yielded\n * object so downstream consumers can switch on a single discriminator.\n */\n\nimport type { DoneEvent, ErrorEvent, StepEvent, SuspendedEvent } from \"./types\";\n\nexport type SseFrame = StepEvent | DoneEvent | ErrorEvent | SuspendedEvent;\n\n/**\n * Parse an SSE stream from a Fetch Response body.\n *\n * Yields typed frames as they arrive. The generator terminates when it\n * receives an event with event_type \"done\", \"error\", or \"suspended\", or\n * when the stream closes.\n */\nexport async function* parseSseStream(\n response: Response,\n signal?: AbortSignal,\n): AsyncGenerator<SseFrame> {\n if (!response.body) {\n throw new Error(\"SSE response has no body\");\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder(\"utf-8\");\n\n let buffer = \"\";\n let currentEventType = \"message\";\n let currentDataLines: string[] = [];\n\n const flush = function* (): Generator<SseFrame> {\n const dataStr = currentDataLines.join(\"\\n\");\n const eventType = currentEventType;\n currentDataLines = [];\n currentEventType = \"message\";\n\n if (!dataStr) return;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(dataStr);\n } catch {\n // Non-JSON data frame — skip silently\n return;\n }\n\n if (typeof parsed !== \"object\" || parsed === null) return;\n\n // Inject the SSE event name as the discriminator. The wire body itself\n // does not carry it (the server stamps it only on the `event:` line),\n // so downstream code cannot distinguish frames otherwise.\n const frame = { ...(parsed as Record<string, unknown>), event_type: eventType };\n yield frame as SseFrame;\n };\n\n try {\n while (true) {\n if (signal?.aborted) break;\n\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n // Last element may be incomplete — keep it in the buffer\n buffer = lines.pop() ?? \"\";\n\n for (const rawLine of lines) {\n // Trim a trailing \\r in case the server (or proxy) emits CRLF.\n const line = rawLine.endsWith(\"\\r\") ? rawLine.slice(0, -1) : rawLine;\n\n if (line.startsWith(\"event:\")) {\n currentEventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n currentDataLines.push(line.slice(5).trim());\n } else if (line === \"\") {\n // End of frame\n for (const frame of flush()) {\n yield frame;\n if (\n frame.event_type === \"done\" ||\n frame.event_type === \"error\" ||\n frame.event_type === \"suspended\"\n ) {\n return;\n }\n }\n }\n // Comments (:) and retry: lines are intentionally ignored\n }\n }\n\n // Flush any remaining buffered frame\n for (const frame of flush()) {\n yield frame;\n }\n } finally {\n reader.releaseLock();\n }\n}\n","/**\n * Low-level HTTP transport for @tuvl/client.\n *\n * Handles auth header injection, JSON serialisation, and returns raw\n * Response objects so higher-level transports (SSE, gRPC) can consume them.\n */\n\nexport interface TransportOptions {\n baseUrl: string;\n defaultToken?: string;\n}\n\nexport class Transport {\n /** Public so TuvlClient can forward it to the gRPC subtransport. */\n readonly baseUrl: string;\n private defaultToken: string | undefined;\n\n constructor(options: TransportOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.defaultToken = options.defaultToken;\n }\n\n /** Update the default token (e.g. after refresh). */\n setToken(token: string): void {\n this.defaultToken = token;\n }\n\n /** Build the Authorization header value, or undefined if no token. */\n private authHeader(overrideToken?: string): string | undefined {\n const tok = overrideToken ?? this.defaultToken;\n return tok ? `Bearer ${tok}` : undefined;\n }\n\n /** Perform a plain JSON POST and return the parsed response body. */\n async post<TBody = unknown, TResponse = unknown>(\n path: string,\n body: TBody,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<TResponse> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n const auth = this.authHeader(options?.token);\n if (auth) headers[\"Authorization\"] = auth;\n\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl POST ${path} → HTTP ${response.status}: ${text}`);\n }\n\n return response.json() as Promise<TResponse>;\n }\n\n /**\n * Open an SSE-capable stream and return the raw Response.\n * Callers are responsible for reading `response.body`.\n */\n async postStream(\n path: string,\n body: unknown,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<Response> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n };\n const auth = this.authHeader(options?.token);\n if (auth) headers[\"Authorization\"] = auth;\n\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl SSE ${path} → HTTP ${response.status}: ${text}`);\n }\n\n return response;\n }\n\n /** Simple GET returning parsed JSON. */\n async get<TResponse = unknown>(\n path: string,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<TResponse> {\n const headers: Record<string, string> = { Accept: \"application/json\" };\n const auth = this.authHeader(options?.token);\n if (auth) headers[\"Authorization\"] = auth;\n\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: \"GET\",\n headers,\n signal: options?.signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl GET ${path} → HTTP ${response.status}: ${text}`);\n }\n\n return response.json() as Promise<TResponse>;\n }\n}\n","/**\n * Shared types for @tuvl/client.\n *\n * Mirrors the Python-side StepEvent dataclass, the SSE envelope produced by\n * tuvl.core.engine.streaming, and the system_router manifest shapes.\n */\n\n/** Returned by all /auth/* login and refresh endpoints. */\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n}\n\n/**\n * Decoded identity and permissions for the currently authenticated user.\n * Returned by GET /auth/me.\n */\nexport interface MeResponse {\n /** User UUID extracted from the `user()` Datalog fact in the token. */\n user_id: string;\n /** Role names from all `group()` facts — e.g. [\"hr_manager\", \"member\"]. */\n groups: string[];\n /** Permission scopes from all `scope()` facts — e.g. [\"candidate:read\"]. */\n scopes: string[];\n}\n\n/** A single execution event streamed by the tuvl server (SSE or gRPC). */\nexport interface StepEvent {\n event_type: \"step\";\n step_id: string;\n kind: string;\n signal: string;\n snapshot: Record<string, unknown>;\n duration_ms: number;\n error_detail?: string | null;\n}\n\n/**\n * Terminal event emitted when the workflow finishes (success OR business failure).\n * Wire shape from tuvl.core.api.manager._sse_generator:\n * {success: true, data: <output>, error: null}\n * {success: false, data: <partial>, error: {...workflow error...}}\n */\nexport interface DoneEvent {\n event_type: \"done\";\n success: boolean;\n data: unknown;\n error: WorkflowErrorPayload | null;\n}\n\n/** Terminal event emitted when the workflow engine itself raised an exception. */\nexport interface ErrorEvent {\n event_type: \"error\";\n message: string;\n details?: string | null;\n}\n\n/** Terminal event emitted when a workflow hits a Human-in-the-Loop step. */\nexport interface SuspendedEvent {\n event_type: \"suspended\";\n instance_id?: string;\n paused_step_id?: string;\n ui?: unknown;\n schema?: unknown;\n context_data?: Record<string, unknown>;\n output_key?: string;\n [key: string]: unknown;\n}\n\n/** Shape of the `error` field on a non-success DoneEvent / REST envelope. */\nexport interface WorkflowErrorPayload {\n code?: string;\n message?: string;\n details?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * Shape of the plain REST response body returned by\n * `POST <workflow_trigger_path>` (and the versioned variant).\n *\n * `execute()` unwraps this and returns just `data` on success, throwing\n * `TuvlWorkflowError` on `success === false`.\n */\nexport interface RestEnvelope<TData = unknown> {\n success: boolean;\n status_code: number;\n data: TData | null;\n error: WorkflowErrorPayload | null;\n}\n\n/** Manifest for a single workflow (from GET /api/_system/workflows/{name}). */\nexport interface WorkflowManifest {\n name: string;\n trigger_path: string;\n trigger_method: string;\n has_slow_steps: boolean;\n slow_kinds_present: string[];\n required_scope: string | null;\n required_group: string | null;\n steps: Array<{ id: string; kind: string }>;\n}\n\n/** Map of workflow manifests (from GET /api/_system/workflows). */\nexport type WorkflowManifestMap = Record<string, Omit<WorkflowManifest, \"name\" | \"steps\">>;\n\n/** Options passed to TuvlClient.execute(). */\nexport interface ExecuteOptions<_TOutput = unknown> {\n payload?: Record<string, unknown>;\n onProgress?: (event: StepEvent) => void;\n onSuspended?: (event: SuspendedEvent) => void;\n mode?: \"sse\" | \"grpc\" | \"rest\";\n token?: string;\n signal?: AbortSignal;\n}\n\n/** Options passed to TuvlClient.executeVersioned(). */\nexport interface ExecuteVersionedOptions<_TOutput = unknown> extends ExecuteOptions<_TOutput> {\n /** The workflow's schema_version, e.g. \"v2\". Calls /{version}/run/{name}. */\n version: string;\n}\n\n/** Body sent to POST /api/workflows/resume. */\nexport interface ResumeRequest {\n instance_id: string;\n human_input?: Record<string, unknown>;\n}\n\n/** Options passed to TuvlClient.resumeWorkflow(). */\nexport interface ResumeOptions<_TOutput = unknown> {\n instanceId: string;\n humanInput?: Record<string, unknown>;\n onProgress?: (event: StepEvent) => void;\n onSuspended?: (event: SuspendedEvent) => void;\n mode?: \"sse\" | \"rest\";\n token?: string;\n signal?: AbortSignal;\n}\n\n/** Options passed to TuvlClient constructor. */\nexport interface TuvlClientOptions {\n baseUrl: string;\n token?: string;\n manifestCacheTtl?: number;\n}\n\n// ── Errors ────────────────────────────────────────────────────────────────────\n\n/**\n * Thrown by `execute()` when a workflow finishes with `success: false`.\n */\nexport class TuvlWorkflowError extends Error {\n readonly data: unknown;\n readonly error: WorkflowErrorPayload | null;\n constructor(message: string, data: unknown, error: WorkflowErrorPayload | null) {\n super(message);\n this.name = \"TuvlWorkflowError\";\n this.data = data;\n this.error = error;\n }\n}\n\n/**\n * Thrown by `execute()` when a workflow suspends at a Human-in-the-Loop step.\n */\nexport class TuvlWorkflowSuspendedError extends Error {\n readonly suspended: SuspendedEvent;\n constructor(suspended: SuspendedEvent) {\n super(`tuvl workflow suspended at step '${suspended.paused_step_id ?? \"?\"}'`);\n this.name = \"TuvlWorkflowSuspendedError\";\n this.suspended = suspended;\n }\n}\n","/**\n * TuvlClient — the main entry point for @tuvl/client.\n *\n * Auto-detects the best transport for each workflow call:\n *\n * mode=\"rest\" (default) → plain POST, unwraps the REST envelope\n * mode=\"sse\" (auto) → SSE streaming when onProgress is provided\n * AND the workflow has_slow_steps === true\n * mode=\"grpc\" → gRPC-Web via sonora (requires peer deps)\n *\n * Return-value contract — IDENTICAL across all three transports:\n *\n * • on success → resolves with the `data` value\n * • on workflow-business error → rejects with `TuvlWorkflowError`\n * • on HITL suspension → rejects with `TuvlWorkflowSuspendedError`\n * • on transport / engine error → rejects with a plain `Error`\n *\n * Manifest caching avoids extra round-trips on repeated calls to the same\n * workflow. TTL defaults to 60 s and is configurable.\n */\n\nimport { parseSseStream } from \"./sse\";\nimport { Transport } from \"./transport\";\nimport {\n TuvlWorkflowError,\n TuvlWorkflowSuspendedError,\n type DoneEvent,\n type ErrorEvent,\n type ExecuteOptions,\n type ExecuteVersionedOptions,\n type ResumeOptions,\n type ResumeRequest,\n type RestEnvelope,\n type StepEvent,\n type SuspendedEvent,\n type TuvlClientOptions,\n type WorkflowManifest,\n type WorkflowManifestMap,\n} from \"./types\";\n\ninterface CacheEntry {\n manifest: WorkflowManifest;\n expiresAt: number;\n}\n\nexport class TuvlClient {\n private readonly transport: Transport;\n private readonly manifestCache = new Map<string, CacheEntry>();\n private readonly manifestCacheTtl: number;\n\n constructor(options: TuvlClientOptions) {\n this.transport = new Transport({\n baseUrl: options.baseUrl,\n defaultToken: options.token,\n });\n this.manifestCacheTtl = options.manifestCacheTtl ?? 60_000;\n }\n\n /** Update the default auth token (e.g. after token refresh). */\n setToken(token: string): void {\n this.transport.setToken(token);\n }\n\n /** Expose the base URL for callers that need raw access (e.g. gRPC). */\n get baseUrl(): string {\n return this.transport.baseUrl;\n }\n\n // ── Manifest ──────────────────────────────────────────────────────────────\n\n /** Fetch (and cache) the manifest for a single workflow. */\n async getManifest(\n workflowName: string,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<WorkflowManifest> {\n const cached = this.manifestCache.get(workflowName);\n if (cached && Date.now() < cached.expiresAt) {\n return cached.manifest;\n }\n\n const manifest = await this.transport.get<WorkflowManifest>(\n `/api/_system/workflows/${encodeURIComponent(workflowName)}`,\n options,\n );\n\n if (this.manifestCacheTtl > 0) {\n this.manifestCache.set(workflowName, {\n manifest,\n expiresAt: Date.now() + this.manifestCacheTtl,\n });\n }\n\n return manifest;\n }\n\n /** Fetch manifests for all registered workflows. */\n async listWorkflows(\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<WorkflowManifestMap> {\n return this.transport.get<WorkflowManifestMap>(\"/api/_system/workflows\", options);\n }\n\n /** Invalidate the cached manifest for a workflow (or all if no name given). */\n invalidateManifest(workflowName?: string): void {\n if (workflowName) {\n this.manifestCache.delete(workflowName);\n } else {\n this.manifestCache.clear();\n }\n }\n\n // ── Execute ───────────────────────────────────────────────────────────────\n\n /**\n * Execute a workflow and return its `data` payload.\n *\n * Transport selection:\n * 1. mode=\"grpc\" → gRPC-Web (always, regardless of onProgress)\n * 2. mode=\"sse\" → SSE stream\n * 3. onProgress provided → SSE if workflow has_slow_steps, else REST\n * 4. default → REST\n *\n * @throws {TuvlWorkflowError} when the workflow returns success=false\n * @throws {TuvlWorkflowSuspendedError} when the workflow suspends at HITL\n * @throws {Error} on transport / engine failures\n */\n async execute<TOutput = unknown>(\n workflowName: string,\n options: ExecuteOptions<TOutput> = {},\n ): Promise<TOutput> {\n const { payload = {}, onProgress, onSuspended, mode, token, signal } = options;\n\n // Fetch manifest to resolve trigger_path and streaming hints\n const manifest = await this.getManifest(workflowName, { token, signal });\n\n const useSse =\n mode === \"sse\" ||\n (mode !== \"rest\" && mode !== \"grpc\" && !!onProgress && manifest.has_slow_steps);\n\n if (mode === \"grpc\") {\n return this._executeGrpc<TOutput>(manifest, payload, onProgress, onSuspended, token, signal);\n }\n\n if (useSse) {\n return this._executeSse<TOutput>(manifest, payload, onProgress, onSuspended, token, signal);\n }\n\n // Plain REST — server returns RestEnvelope; unwrap it.\n const envelope = await this.transport.post<Record<string, unknown>, RestEnvelope<TOutput>>(\n manifest.trigger_path,\n payload,\n { token, signal },\n );\n return this._unwrapRest<TOutput>(envelope, manifest.name);\n }\n\n /**\n * Execute a specific version of a workflow via `/{version}/run/{name}`.\n *\n * Useful when you want to pin to a particular schema_version without\n * relying on the currently-active default trigger path.\n *\n * @throws {TuvlWorkflowError} when the workflow returns success=false\n * @throws {TuvlWorkflowSuspendedError} when the workflow suspends at HITL\n * @throws {Error} on transport / engine failures\n */\n async executeVersioned<TOutput = unknown>(\n workflowName: string,\n version: string,\n options: ExecuteVersionedOptions<TOutput> | ExecuteOptions<TOutput> = {},\n ): Promise<TOutput> {\n const { payload = {}, onProgress, onSuspended, mode, token, signal } = options;\n const triggerPath = `/${version}/run/${workflowName}`;\n\n // Best-effort: fetch manifest to determine has_slow_steps for SSE auto-upgrade.\n let cachedManifest: WorkflowManifest | undefined;\n try {\n cachedManifest = await this.getManifest(workflowName, { token, signal });\n } catch {\n // If manifest fetch fails, fall back to the caller's explicit mode.\n }\n\n const syntheticManifest: WorkflowManifest = {\n name: workflowName,\n trigger_path: triggerPath,\n trigger_method: \"POST\",\n has_slow_steps: cachedManifest?.has_slow_steps ?? false,\n slow_kinds_present: cachedManifest?.slow_kinds_present ?? [],\n required_scope: cachedManifest?.required_scope ?? null,\n required_group: cachedManifest?.required_group ?? null,\n steps: cachedManifest?.steps ?? [],\n };\n\n const useSse =\n mode === \"sse\" ||\n (mode !== \"rest\" && mode !== \"grpc\" && !!onProgress && syntheticManifest.has_slow_steps);\n\n if (mode === \"grpc\") {\n return this._executeGrpc<TOutput>(\n syntheticManifest,\n payload,\n onProgress,\n onSuspended,\n token,\n signal,\n );\n }\n\n if (useSse) {\n return this._executeSse<TOutput>(\n syntheticManifest,\n payload,\n onProgress,\n onSuspended,\n token,\n signal,\n );\n }\n\n const envelope = await this.transport.post<Record<string, unknown>, RestEnvelope<TOutput>>(\n triggerPath,\n payload,\n { token, signal },\n );\n return this._unwrapRest<TOutput>(envelope, workflowName);\n }\n\n /**\n * Resume a HITL-suspended workflow instance.\n *\n * After the workflow throws `TuvlWorkflowSuspendedError`, capture the\n * `event.instance_id` from the suspended event and pass it here along with\n * the human-provided data to continue execution.\n *\n * @throws {TuvlWorkflowError} when the resumed workflow returns success=false\n * @throws {TuvlWorkflowSuspendedError} when the workflow suspends again at another HITL step\n * @throws {Error} on transport / engine failures\n */\n async resumeWorkflow<TOutput = unknown>(\n options: ResumeOptions<TOutput>,\n ): Promise<TOutput> {\n const { instanceId, humanInput = {}, onProgress, onSuspended, mode, token, signal } = options;\n\n const body: ResumeRequest = {\n instance_id: instanceId,\n human_input: humanInput,\n };\n\n if (mode === \"sse\" || (mode !== \"rest\" && !!onProgress)) {\n // Wrap in a synthetic manifest so we can reuse _executeSse.\n // The server's resume SSE path mirrors the trigger SSE path.\n const syntheticManifest: WorkflowManifest = {\n name: `(resumed:${instanceId})`,\n trigger_path: \"/api/workflows/resume\",\n trigger_method: \"POST\",\n has_slow_steps: true,\n slow_kinds_present: [],\n required_scope: null,\n required_group: null,\n steps: [],\n };\n return this._executeSse<TOutput>(\n syntheticManifest,\n body as unknown as Record<string, unknown>,\n onProgress,\n onSuspended,\n token,\n signal,\n );\n }\n\n // Plain REST resume — returns RestEnvelope<TOutput>.\n const envelope = await this.transport.post<ResumeRequest, RestEnvelope<TOutput>>(\n \"/api/workflows/resume\",\n body,\n { token, signal },\n );\n return this._unwrapRest<TOutput>(envelope, `(resumed:${instanceId})`);\n }\n\n // ── SSE transport ─────────────────────────────────────────────────────────\n\n private async _executeSse<TOutput>(\n manifest: WorkflowManifest,\n payload: Record<string, unknown>,\n onProgress: ((event: StepEvent) => void) | undefined,\n onSuspended: ((event: SuspendedEvent) => void) | undefined,\n token: string | undefined,\n signal: AbortSignal | undefined,\n ): Promise<TOutput> {\n const response = await this.transport.postStream(manifest.trigger_path, payload, {\n token,\n signal,\n });\n\n let done: DoneEvent | undefined;\n\n for await (const frame of parseSseStream(response, signal)) {\n switch (frame.event_type) {\n case \"step\":\n onProgress?.(frame);\n break;\n case \"done\":\n done = frame;\n break;\n case \"suspended\":\n onSuspended?.(frame);\n throw new TuvlWorkflowSuspendedError(frame);\n case \"error\": {\n const err = frame as ErrorEvent;\n throw new Error(\n `tuvl workflow '${manifest.name}' engine error: ${err.message}` +\n (err.details ? ` — ${err.details}` : \"\"),\n );\n }\n }\n }\n\n if (!done) {\n throw new Error(`tuvl SSE stream for '${manifest.name}' ended without a done event`);\n }\n\n if (!done.success) {\n throw new TuvlWorkflowError(\n `tuvl workflow '${manifest.name}' failed`,\n done.data,\n done.error,\n );\n }\n\n return done.data as TOutput;\n }\n\n // ── gRPC-Web transport ────────────────────────────────────────────────────\n\n private async _executeGrpc<TOutput>(\n manifest: WorkflowManifest,\n payload: Record<string, unknown>,\n onProgress: ((event: StepEvent) => void) | undefined,\n onSuspended: ((event: SuspendedEvent) => void) | undefined,\n token: string | undefined,\n signal: AbortSignal | undefined,\n ): Promise<TOutput> {\n const { openGrpcStream } = await import(\"./grpc\");\n\n let finalSnapshot: Record<string, unknown> | undefined;\n\n for await (const event of openGrpcStream({\n baseUrl: this.baseUrl,\n workflowName: manifest.name,\n payloadJson: JSON.stringify(payload),\n token,\n signal,\n })) {\n switch (event.event_type) {\n case \"step\":\n onProgress?.(event as StepEvent);\n break;\n case \"done\":\n // gRPC servicer emits the last-step snapshot as `snapshot_json`.\n // It is NOT pre-wrapped in {success, data, error} like SSE.\n finalSnapshot = (event as unknown as { snapshot: Record<string, unknown> }).snapshot;\n break;\n case \"suspended\": {\n // The gRPC servicer stuffs the HITL payload into snapshot_json.\n const snap = (event as unknown as { snapshot: Record<string, unknown> }).snapshot;\n const suspended: SuspendedEvent = {\n event_type: \"suspended\",\n paused_step_id: (event as unknown as { step_id?: string }).step_id,\n ...snap,\n };\n onSuspended?.(suspended);\n throw new TuvlWorkflowSuspendedError(suspended);\n }\n case \"error\":\n throw new Error(\n `tuvl workflow '${manifest.name}' gRPC error: ${event.error_detail ?? \"unknown\"}`,\n );\n }\n }\n\n if (finalSnapshot === undefined) {\n throw new Error(`tuvl gRPC stream for '${manifest.name}' ended without a done event`);\n }\n\n // gRPC mirrors the REST workflow contract via the workflow snapshot:\n // a `_last_error` key in context signals a business failure.\n if (\"_last_error\" in finalSnapshot) {\n throw new TuvlWorkflowError(\n `tuvl workflow '${manifest.name}' failed`,\n finalSnapshot,\n (finalSnapshot._last_error as never) ?? null,\n );\n }\n\n // Prefer the `_response` key when the workflow set one; else return the\n // full public snapshot. This mirrors the REST envelope's `data` semantics.\n if (\"_response\" in finalSnapshot) {\n return finalSnapshot._response as TOutput;\n }\n return finalSnapshot as TOutput;\n }\n\n // ── REST envelope ─────────────────────────────────────────────────────────\n\n private _unwrapRest<TOutput>(envelope: RestEnvelope<TOutput>, workflowName: string): TOutput {\n if (!envelope || typeof envelope !== \"object\") {\n // Server returned a bare body (older endpoint, or HITL 202 etc.) —\n // hand it back verbatim.\n return envelope as unknown as TOutput;\n }\n\n if (envelope.success === false) {\n throw new TuvlWorkflowError(\n `tuvl workflow '${workflowName}' failed`,\n envelope.data,\n envelope.error,\n );\n }\n\n // success===true OR envelope-shape mismatch (no `success` key) → return data\n // when present, else the whole body.\n return (envelope.data ?? (envelope as unknown)) as TOutput;\n }\n}\n","/**\n * TuvlAuth — authentication helpers for @tuvl/client.\n *\n * Wraps the most common /auth/* endpoints (login, refresh, logout, who-am-I,\n * OAuth start, bootstrap) so consumers never have to manually construct\n * form-encoded bodies or manage Bearer headers for auth operations.\n *\n * Admin endpoints (user/role/scope CRUD, federation config) are NOT wrapped\n * — call them directly via `Transport` or `fetch` with the token.\n */\n\nimport type { MeResponse, TokenResponse } from \"./types\";\n\nexport interface TuvlAuthOptions {\n /** Base URL of the tuvl server. Trailing slash is stripped automatically. */\n baseUrl: string;\n}\n\nexport interface BootstrapRequest {\n email: string;\n password: string;\n /** Optional extra scope to grant the superadmin role on creation. */\n admin_scope?: string;\n}\n\nexport class TuvlAuth {\n private readonly baseUrl: string;\n\n constructor(options: TuvlAuthOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n }\n\n /**\n * Decode the current token server-side and return the user's identity,\n * role memberships (`groups`), and permission scopes.\n *\n * Biscuit tokens are protobuf-encoded and cannot be decoded in pure JS,\n * so this is the correct way to read \"who is logged in\" and \"what can\n * they do\" from the TypeScript SDK.\n *\n * @throws if the token is invalid, expired, or revoked.\n */\n async getMe(token: string): Promise<MeResponse> {\n const response = await fetch(`${this.baseUrl}/auth/me`, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl getMe failed (HTTP ${response.status}): ${text}`);\n }\n\n return response.json() as Promise<MeResponse>;\n }\n\n /**\n * Exchange an email + password for a Biscuit bearer token.\n *\n * Calls `POST /auth/token` with an `application/x-www-form-urlencoded`\n * body (OAuth2 password-grant). The `username` field must be the user's\n * email address.\n */\n async loginWithPassword(email: string, password: string): Promise<TokenResponse> {\n const body = new URLSearchParams({ username: email, password });\n\n const response = await fetch(`${this.baseUrl}/auth/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl login failed (HTTP ${response.status}): ${text}`);\n }\n\n return response.json() as Promise<TokenResponse>;\n }\n\n /**\n * Create the first superadmin user (one-time IAM bootstrap).\n *\n * Calls `POST /auth/bootstrap`. Returns 409 on every subsequent call\n * once any user exists.\n */\n async bootstrap(req: BootstrapRequest): Promise<TokenResponse> {\n const response = await fetch(`${this.baseUrl}/auth/bootstrap`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify(req),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl bootstrap failed (HTTP ${response.status}): ${text}`);\n }\n\n return response.json() as Promise<TokenResponse>;\n }\n\n /**\n * Return the URL the browser should navigate to in order to start an\n * OAuth2 login flow for the given provider.\n *\n * Supported built-ins: `\"google\"`, `\"github\"`, `\"microsoft\"`. Any\n * provider configured in the project's `federation/` directory also\n * works.\n *\n * After the OAuth dance the server either:\n * - redirects to `TUVL_OAUTH_UI_REDIRECT_URL?token=<biscuit_b64>`, OR\n * - returns a JSON `{access_token, token_type}` body (CLI / server flows).\n */\n getOAuthLoginUrl(provider: string): string {\n return `${this.baseUrl}/auth/oauth/${encodeURIComponent(provider)}/start`;\n }\n\n /**\n * Exchange a valid (non-expired, non-revoked) token for a fresh one.\n * The old token is immediately blacklisted — discard it after this call.\n */\n async refresh(token: string): Promise<TokenResponse> {\n const response = await fetch(`${this.baseUrl}/auth/refresh`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl token refresh failed (HTTP ${response.status}): ${text}`);\n }\n\n return response.json() as Promise<TokenResponse>;\n }\n\n /**\n * Revoke the given token (logout). After this the token is blacklisted\n * across all workers that share a Redis instance. Resolves silently on\n * success (HTTP 204).\n */\n async logout(token: string): Promise<void> {\n const response = await fetch(`${this.baseUrl}/auth/logout`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok && response.status !== 204) {\n const text = await response.text();\n throw new Error(`tuvl logout failed (HTTP ${response.status}): ${text}`);\n }\n }\n}\n","/**\n * @tuvl/client — TypeScript client SDK for the tuvl workflow engine.\n *\n * @example\n * ```ts\n * import { TuvlClient } from \"@tuvl/client\";\n *\n * const client = new TuvlClient({ baseUrl: \"http://localhost:8000\", token });\n *\n * // Plain REST call\n * const result = await client.execute(\"my-workflow\", { payload: { id: 1 } });\n *\n * // SSE streaming (auto-detected when onProgress is provided)\n * const result = await client.execute(\"my-workflow\", {\n * payload: { id: 1 },\n * onProgress: (ev) => console.log(`[${ev.step_id}] ${ev.signal} (${ev.duration_ms}ms)`),\n * });\n * ```\n */\n\nexport { TuvlClient } from \"./client\";\nexport { TuvlAuth } from \"./auth\";\nexport type { TuvlAuthOptions, BootstrapRequest } from \"./auth\";\nexport { parseSseStream } from \"./sse\";\nexport { openGrpcStream } from \"./grpc\";\nexport { Transport } from \"./transport\";\nexport {\n TuvlWorkflowError,\n TuvlWorkflowSuspendedError,\n} from \"./types\";\nexport type {\n TokenResponse,\n MeResponse,\n StepEvent,\n DoneEvent,\n ErrorEvent,\n SuspendedEvent,\n WorkflowErrorPayload,\n RestEnvelope,\n WorkflowManifest,\n WorkflowManifestMap,\n ExecuteOptions,\n ExecuteVersionedOptions,\n ResumeOptions,\n ResumeRequest,\n TuvlClientOptions,\n} from \"./types\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/grpc.ts","../src/crud.ts","../src/sse.ts","../src/transport.ts","../src/types.ts","../src/client.ts","../src/auth.ts","../src/index.ts"],"names":["openGrpcStream"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * gRPC-Web transport for @tuvl/client.\n *\n * This module is an OPTIONAL transport that requires the peer dependencies:\n * @protobuf-ts/grpcweb-transport\n * @protobuf-ts/runtime-rpc\n *\n * It uses dynamic import() so the main bundle has zero overhead if you never\n * use mode=\"grpc\". The protobuf definitions are created inline rather than\n * from generated stubs, keeping the SDK self-contained (no make proto step\n * required on the client side).\n *\n * The wire format matches execution.proto:\n * service ExecutionService { rpc RunWorkflow(RunRequest) → stream StepEvent }\n */\n\n/**\n * gRPC StepEvent on the wire. Unlike the typed SSE `StepEvent` (which is\n * narrowed to `event_type: \"step\"`), this can carry \"step\" | \"done\" |\n * \"error\" | \"suspended\" — the discriminator the servicer chose.\n */\nexport interface GrpcStepEvent {\n event_type: \"step\" | \"done\" | \"error\" | \"suspended\";\n step_id: string;\n kind: string;\n signal: string;\n /** Decoded from `snapshot_json` on the wire. */\n snapshot: Record<string, unknown>;\n duration_ms: number;\n error_detail?: string;\n}\n\nexport interface GrpcRunOptions {\n baseUrl: string;\n workflowName: string;\n payloadJson: string;\n tokenFallback?: string;\n token?: string;\n signal?: AbortSignal;\n}\n\n/**\n * Open a gRPC-Web server-streaming call to ExecutionService.RunWorkflow.\n *\n * Yields `GrpcStepEvent` objects (with `snapshot_json` already parsed into\n * `snapshot`). The caller decides what each `event_type` means.\n *\n * Throws if the peer deps are not installed.\n */\nexport async function* openGrpcStream(\n options: GrpcRunOptions,\n): AsyncGenerator<GrpcStepEvent> {\n // Dynamically import peer deps — zero cost when not used\n let GrpcWebFetchTransport: { new (opts: { baseUrl: string }): unknown };\n try {\n const mod = await import(\"@protobuf-ts/grpcweb-transport\");\n GrpcWebFetchTransport = (mod as { GrpcWebFetchTransport: typeof GrpcWebFetchTransport }).GrpcWebFetchTransport;\n } catch {\n throw new Error(\n \"@tuvl/client: gRPC mode requires @protobuf-ts/grpcweb-transport. \" +\n \"Install it with: npm i @protobuf-ts/grpcweb-transport @protobuf-ts/runtime-rpc\",\n );\n }\n\n const { BinaryWriter, BinaryReader, WireType } = await import(\n \"@protobuf-ts/runtime\"\n );\n\n // ── Minimal inline protobuf encode/decode for RunRequest / StepEvent ───────\n\n function encodeRunRequest(\n workflowName: string,\n payloadJson: string,\n tokenFallback: string,\n ): Uint8Array {\n const writer = new BinaryWriter();\n writer.tag(1, WireType.LengthDelimited).string(workflowName);\n writer.tag(2, WireType.LengthDelimited).string(payloadJson);\n if (tokenFallback) {\n writer.tag(3, WireType.LengthDelimited).string(tokenFallback);\n }\n return writer.finish();\n }\n\n function decodeStepEvent(bytes: Uint8Array): GrpcStepEvent {\n const reader = new BinaryReader(bytes);\n let eventType = \"\";\n let stepId = \"\";\n let kind = \"\";\n let signal = \"\";\n let snapshotJson = \"\";\n let durationMs = 0;\n let errorDetail = \"\";\n\n while (reader.pos < reader.len) {\n const [fieldNo, wireType] = reader.tag();\n switch (fieldNo) {\n case 1: eventType = reader.string(); break;\n case 2: stepId = reader.string(); break;\n case 3: kind = reader.string(); break;\n case 4: signal = reader.string(); break;\n case 5: snapshotJson = reader.string(); break;\n case 6: durationMs = reader.float(); break;\n case 7: errorDetail = reader.string(); break;\n default: reader.skip(wireType);\n }\n }\n\n let snapshot: Record<string, unknown> = {};\n if (snapshotJson) {\n try {\n snapshot = JSON.parse(snapshotJson) as Record<string, unknown>;\n } catch {\n // ignore malformed snapshot\n }\n }\n\n // Default to \"step\" if the server didn't stamp event_type (shouldn't happen\n // — every emitted message sets the field — but stay defensive).\n const et = (eventType || \"step\") as GrpcStepEvent[\"event_type\"];\n\n return {\n event_type: et,\n step_id: stepId,\n kind,\n signal,\n snapshot,\n duration_ms: durationMs,\n error_detail: errorDetail || undefined,\n };\n }\n\n // ── gRPC-Web call ─────────────────────────────────────────────────────────\n\n const transport = new (GrpcWebFetchTransport as { new (opts: { baseUrl: string; fetchInit?: RequestInit }): { serverStreaming: (descriptor: unknown, input: unknown, options?: unknown) => { responses: AsyncIterable<Uint8Array> } } })({\n baseUrl: options.baseUrl,\n fetchInit: options.token\n ? { headers: { Authorization: `Bearer ${options.token}` } }\n : undefined,\n });\n\n const methodDescriptor = {\n name: \"/tuvl.v1.ExecutionService/RunWorkflow\",\n clientStreaming: false,\n serverStreaming: true,\n I: { create: () => ({}) } as unknown,\n O: { create: () => ({}) } as unknown,\n options: {},\n };\n\n const requestBytes = encodeRunRequest(\n options.workflowName,\n options.payloadJson,\n options.tokenFallback ?? \"\",\n );\n\n const call = transport.serverStreaming(methodDescriptor, requestBytes, {\n abort: options.signal,\n });\n\n for await (const responseBytes of call.responses) {\n const event = decodeStepEvent(responseBytes as Uint8Array);\n yield event;\n if (\n event.event_type === \"done\" ||\n event.event_type === \"error\" ||\n event.event_type === \"suspended\"\n ) {\n break;\n }\n }\n}\n","/**\n * CrudClient — typed CRUD access for tuvl model endpoints.\n *\n * The tuvl server mounts auto-generated CRUD routers at:\n * /models/{modelname}/ (list, create)\n * /models/{modelname}/{id} (get, update, delete)\n *\n * Usage via TuvlClient.crud():\n *\n * ```ts\n * const client = new TuvlClient({ baseUrl: \"http://localhost:8000\", token });\n *\n * // List all candidates\n * const all = await client.crud(\"candidate\").list();\n *\n * // Filter + embed relations\n * const results = await client.crud(\"candidate\").list({\n * filters: { stage: \"screening\" },\n * include: [\"posting\"],\n * limit: 50,\n * });\n *\n * // Get one\n * const c = await client.crud(\"candidate\").get(\"uuid-here\");\n *\n * // Create\n * const created = await client.crud<CandidateRead, CandidateCreate>(\"candidate\")\n * .create({ name: \"Alice\", email: \"alice@example.com\" });\n *\n * // Update\n * const updated = await client.crud(\"candidate\").update(\"uuid\", { stage: \"interview\" });\n *\n * // Delete\n * await client.crud(\"candidate\").delete(\"uuid\");\n * ```\n *\n * Type parameters:\n * TRead — shape returned by GET / POST / PATCH (defaults to `unknown`)\n * TCreate — body for POST (defaults to `Partial<TRead>`)\n * TUpdate — body for PATCH (defaults to `Partial<TRead>`)\n */\n\nimport type { Transport } from \"./transport\";\nimport type { CrudGetOptions, CrudListOptions, CrudMutateOptions } from \"./types\";\n\nexport class CrudClient<\n TRead = unknown,\n TCreate = Partial<TRead>,\n TUpdate = Partial<TRead>,\n> {\n private readonly basePath: string;\n\n constructor(\n private readonly transport: Transport,\n modelName: string,\n ) {\n this.basePath = `/models/${modelName.toLowerCase()}`;\n }\n\n // ── Private helpers ──────────────────────────────────────────────────────\n\n /** Build query string from list options. */\n private _buildQuery(options: CrudListOptions): string {\n const params = new URLSearchParams();\n\n if (options.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options.offset !== undefined) params.set(\"offset\", String(options.offset));\n\n if (options.filters) {\n for (const [key, value] of Object.entries(options.filters)) {\n params.set(`filter[${key}]`, value);\n }\n }\n\n if (options.include && options.include.length > 0) {\n params.set(\"include\", options.include.join(\",\"));\n }\n\n const qs = params.toString();\n return qs ? `?${qs}` : \"\";\n }\n\n /** Build ?include= query string for get-by-id calls. */\n private _buildGetQuery(options: CrudGetOptions): string {\n if (!options.include || options.include.length === 0) return \"\";\n const params = new URLSearchParams({ include: options.include.join(\",\") });\n return `?${params.toString()}`;\n }\n\n // ── Public CRUD methods ──────────────────────────────────────────────────\n\n /**\n * GET /models/{model}/\n * Returns all records matching the given filters (server default: up to 100).\n */\n async list(options: CrudListOptions = {}): Promise<TRead[]> {\n const qs = this._buildQuery(options);\n return this.transport.get<TRead[]>(`${this.basePath}/${qs}`, {\n token: options.token,\n signal: options.signal,\n });\n }\n\n /**\n * GET /models/{model}/{id}\n * Returns a single record by UUID, optionally with embedded relations.\n */\n async get(id: string, options: CrudGetOptions = {}): Promise<TRead> {\n const qs = this._buildGetQuery(options);\n return this.transport.get<TRead>(`${this.basePath}/${encodeURIComponent(id)}${qs}`, {\n token: options.token,\n signal: options.signal,\n });\n }\n\n /**\n * POST /models/{model}/\n * Creates a new record and returns the created resource (HTTP 201).\n */\n async create(body: TCreate, options: CrudMutateOptions = {}): Promise<TRead> {\n return this.transport.post<TCreate, TRead>(`${this.basePath}/`, body, {\n token: options.token,\n signal: options.signal,\n });\n }\n\n /**\n * PATCH /models/{model}/{id}\n * Partially updates a record (only fields present in `body` are changed).\n */\n async update(id: string, body: TUpdate, options: CrudMutateOptions = {}): Promise<TRead> {\n return this.transport.patch<TUpdate, TRead>(\n `${this.basePath}/${encodeURIComponent(id)}`,\n body,\n { token: options.token, signal: options.signal },\n );\n }\n\n /**\n * DELETE /models/{model}/{id}\n * Deletes a record (HTTP 204). Throws if the record is not found.\n */\n async delete(id: string, options: CrudMutateOptions = {}): Promise<void> {\n return this.transport.delete(`${this.basePath}/${encodeURIComponent(id)}`, {\n token: options.token,\n signal: options.signal,\n });\n }\n}\n","/**\n * SSE transport for @tuvl/client.\n *\n * Uses the Fetch API ReadableStream to parse SSE frames from a POST response\n * opened by Transport.postStream(). This avoids the browser's native\n * EventSource (which only supports GET) and works in Node 18+.\n *\n * Wire format produced by tuvl.core.engine.streaming:\n *\n * event: step data: {step_id, kind, signal, snapshot, duration_ms, error_detail}\n * event: suspended data: {<hitl_request payload>}\n * event: done data: {success, data, error}\n * event: error data: {message, details}\n *\n * The JSON body has NO `event_type` field — it lives only on the `event:`\n * line. This parser injects the event name as `event_type` into the yielded\n * object so downstream consumers can switch on a single discriminator.\n */\n\nimport type { DoneEvent, ErrorEvent, StepEvent, SuspendedEvent } from \"./types\";\n\nexport type SseFrame = StepEvent | DoneEvent | ErrorEvent | SuspendedEvent;\n\n/**\n * Parse an SSE stream from a Fetch Response body.\n *\n * Yields typed frames as they arrive. The generator terminates when it\n * receives an event with event_type \"done\", \"error\", or \"suspended\", or\n * when the stream closes.\n */\nexport async function* parseSseStream(\n response: Response,\n signal?: AbortSignal,\n): AsyncGenerator<SseFrame> {\n if (!response.body) {\n throw new Error(\"SSE response has no body\");\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder(\"utf-8\");\n\n let buffer = \"\";\n let currentEventType = \"message\";\n let currentDataLines: string[] = [];\n\n const flush = function* (): Generator<SseFrame> {\n const dataStr = currentDataLines.join(\"\\n\");\n const eventType = currentEventType;\n currentDataLines = [];\n currentEventType = \"message\";\n\n if (!dataStr) return;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(dataStr);\n } catch {\n // Non-JSON data frame — skip silently\n return;\n }\n\n if (typeof parsed !== \"object\" || parsed === null) return;\n\n // Inject the SSE event name as the discriminator. The wire body itself\n // does not carry it (the server stamps it only on the `event:` line),\n // so downstream code cannot distinguish frames otherwise.\n const frame = { ...(parsed as Record<string, unknown>), event_type: eventType };\n yield frame as SseFrame;\n };\n\n try {\n while (true) {\n if (signal?.aborted) break;\n\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n // Last element may be incomplete — keep it in the buffer\n buffer = lines.pop() ?? \"\";\n\n for (const rawLine of lines) {\n // Trim a trailing \\r in case the server (or proxy) emits CRLF.\n const line = rawLine.endsWith(\"\\r\") ? rawLine.slice(0, -1) : rawLine;\n\n if (line.startsWith(\"event:\")) {\n currentEventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n currentDataLines.push(line.slice(5).trim());\n } else if (line === \"\") {\n // End of frame\n for (const frame of flush()) {\n yield frame;\n if (\n frame.event_type === \"done\" ||\n frame.event_type === \"error\" ||\n frame.event_type === \"suspended\"\n ) {\n return;\n }\n }\n }\n // Comments (:) and retry: lines are intentionally ignored\n }\n }\n\n // Flush any remaining buffered frame\n for (const frame of flush()) {\n yield frame;\n }\n } finally {\n reader.releaseLock();\n }\n}\n","/**\n * Low-level HTTP transport for @tuvl/client.\n *\n * Handles auth header injection, JSON serialisation, and returns raw\n * Response objects so higher-level transports (SSE, gRPC) can consume them.\n */\n\nexport interface TransportOptions {\n baseUrl: string;\n defaultToken?: string;\n}\n\nexport class Transport {\n /** Public so TuvlClient can forward it to the gRPC subtransport. */\n readonly baseUrl: string;\n private defaultToken: string | undefined;\n\n constructor(options: TransportOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.defaultToken = options.defaultToken;\n }\n\n /** Update the default token (e.g. after refresh). */\n setToken(token: string): void {\n this.defaultToken = token;\n }\n\n /** Build the Authorization header value, or undefined if no token. */\n private authHeader(overrideToken?: string): string | undefined {\n const tok = overrideToken ?? this.defaultToken;\n return tok ? `Bearer ${tok}` : undefined;\n }\n\n /** Perform a plain JSON POST and return the parsed response body. */\n async post<TBody = unknown, TResponse = unknown>(\n path: string,\n body: TBody,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<TResponse> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n const auth = this.authHeader(options?.token);\n if (auth) headers[\"Authorization\"] = auth;\n\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl POST ${path} → HTTP ${response.status}: ${text}`);\n }\n\n return response.json() as Promise<TResponse>;\n }\n\n /**\n * Open an SSE-capable stream and return the raw Response.\n * Callers are responsible for reading `response.body`.\n */\n async postStream(\n path: string,\n body: unknown,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<Response> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n };\n const auth = this.authHeader(options?.token);\n if (auth) headers[\"Authorization\"] = auth;\n\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl SSE ${path} → HTTP ${response.status}: ${text}`);\n }\n\n return response;\n }\n\n /** Simple GET returning parsed JSON. */\n async get<TResponse = unknown>(\n path: string,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<TResponse> {\n const headers: Record<string, string> = { Accept: \"application/json\" };\n const auth = this.authHeader(options?.token);\n if (auth) headers[\"Authorization\"] = auth;\n\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: \"GET\",\n headers,\n signal: options?.signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl GET ${path} → HTTP ${response.status}: ${text}`);\n }\n\n return response.json() as Promise<TResponse>;\n }\n\n /** Perform a JSON PATCH and return the parsed response body. */\n async patch<TBody = unknown, TResponse = unknown>(\n path: string,\n body: TBody,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<TResponse> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n const auth = this.authHeader(options?.token);\n if (auth) headers[\"Authorization\"] = auth;\n\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: \"PATCH\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl PATCH ${path} → HTTP ${response.status}: ${text}`);\n }\n\n return response.json() as Promise<TResponse>;\n }\n\n /** Perform a DELETE request. Expects a 204 No Content response. */\n async delete(\n path: string,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<void> {\n const headers: Record<string, string> = {};\n const auth = this.authHeader(options?.token);\n if (auth) headers[\"Authorization\"] = auth;\n\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: \"DELETE\",\n headers,\n signal: options?.signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl DELETE ${path} → HTTP ${response.status}: ${text}`);\n }\n }\n}\n","/**\n * Shared types for @tuvl/client.\n *\n * Mirrors the Python-side StepEvent dataclass, the SSE envelope produced by\n * tuvl.core.engine.streaming, and the system_router manifest shapes.\n */\n\n/** Returned by all /auth/* login and refresh endpoints. */\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n}\n\n/**\n * Decoded identity and permissions for the currently authenticated user.\n * Returned by GET /auth/me.\n */\nexport interface MeResponse {\n /** User UUID extracted from the `user()` Datalog fact in the token. */\n user_id: string;\n /** Role names from all `group()` facts — e.g. [\"hr_manager\", \"member\"]. */\n groups: string[];\n /** Permission scopes from all `scope()` facts — e.g. [\"candidate:read\"]. */\n scopes: string[];\n}\n\n/** A single execution event streamed by the tuvl server (SSE or gRPC). */\nexport interface StepEvent {\n event_type: \"step\";\n step_id: string;\n kind: string;\n signal: string;\n snapshot: Record<string, unknown>;\n duration_ms: number;\n error_detail?: string | null;\n}\n\n/**\n * Terminal event emitted when the workflow finishes (success OR business failure).\n * Wire shape from tuvl.core.api.manager._sse_generator:\n * {success: true, data: <output>, error: null}\n * {success: false, data: <partial>, error: {...workflow error...}}\n */\nexport interface DoneEvent {\n event_type: \"done\";\n success: boolean;\n data: unknown;\n error: WorkflowErrorPayload | null;\n}\n\n/** Terminal event emitted when the workflow engine itself raised an exception. */\nexport interface ErrorEvent {\n event_type: \"error\";\n message: string;\n details?: string | null;\n}\n\n/** Terminal event emitted when a workflow hits a Human-in-the-Loop step. */\nexport interface SuspendedEvent {\n event_type: \"suspended\";\n instance_id?: string;\n paused_step_id?: string;\n ui?: unknown;\n schema?: unknown;\n context_data?: Record<string, unknown>;\n output_key?: string;\n [key: string]: unknown;\n}\n\n/** Shape of the `error` field on a non-success DoneEvent / REST envelope. */\nexport interface WorkflowErrorPayload {\n code?: string;\n message?: string;\n details?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * Shape of the plain REST response body returned by\n * `POST <workflow_trigger_path>` (and the versioned variant).\n *\n * `execute()` unwraps this and returns just `data` on success, throwing\n * `TuvlWorkflowError` on `success === false`.\n */\nexport interface RestEnvelope<TData = unknown> {\n success: boolean;\n status_code: number;\n data: TData | null;\n error: WorkflowErrorPayload | null;\n}\n\n/** Manifest for a single workflow (from GET /api/_system/workflows/{name}). */\nexport interface WorkflowManifest {\n name: string;\n trigger_path: string;\n trigger_method: string;\n has_slow_steps: boolean;\n slow_kinds_present: string[];\n required_scope: string | null;\n required_group: string | null;\n steps: Array<{ id: string; kind: string }>;\n}\n\n/** Map of workflow manifests (from GET /api/_system/workflows). */\nexport type WorkflowManifestMap = Record<string, Omit<WorkflowManifest, \"name\" | \"steps\">>;\n\n/** Options passed to TuvlClient.execute(). */\nexport interface ExecuteOptions<_TOutput = unknown> {\n payload?: Record<string, unknown>;\n onProgress?: (event: StepEvent) => void;\n onSuspended?: (event: SuspendedEvent) => void;\n mode?: \"sse\" | \"grpc\" | \"rest\";\n token?: string;\n signal?: AbortSignal;\n}\n\n/** Options passed to TuvlClient.executeVersioned(). */\nexport interface ExecuteVersionedOptions<_TOutput = unknown> extends ExecuteOptions<_TOutput> {\n /** The workflow's schema_version, e.g. \"v2\". Calls /{version}/run/{name}. */\n version: string;\n}\n\n/** Body sent to POST /api/workflows/resume. */\nexport interface ResumeRequest {\n instance_id: string;\n human_input?: Record<string, unknown>;\n}\n\n/** Options passed to TuvlClient.resumeWorkflow(). */\nexport interface ResumeOptions<_TOutput = unknown> {\n instanceId: string;\n humanInput?: Record<string, unknown>;\n onProgress?: (event: StepEvent) => void;\n onSuspended?: (event: SuspendedEvent) => void;\n mode?: \"sse\" | \"rest\";\n token?: string;\n signal?: AbortSignal;\n}\n\n/** Options passed to TuvlClient constructor. */\nexport interface TuvlClientOptions {\n baseUrl: string;\n token?: string;\n manifestCacheTtl?: number;\n}\n\n// ── CRUD types ────────────────────────────────────────────────────────────────\n\n/**\n * Options for listing records from a CRUD model endpoint.\n *\n * `filters` maps to bracket-notation query params: `filter[key]=value`.\n * `include` maps to `?include=relation1,relation2` for eager-loading relations.\n */\nexport interface CrudListOptions {\n limit?: number;\n offset?: number;\n /** Server-side field filters: { stage: \"screening\" } → `?filter[stage]=screening` */\n filters?: Record<string, string>;\n /** Relation names to embed: [\"posting\"] → `?include=posting` */\n include?: string[];\n token?: string;\n signal?: AbortSignal;\n}\n\n/** Options for retrieving a single CRUD record. */\nexport interface CrudGetOptions {\n /** Relation names to embed: [\"candidate\"] → `?include=candidate` */\n include?: string[];\n token?: string;\n signal?: AbortSignal;\n}\n\n/** Options for create / update / delete calls. */\nexport interface CrudMutateOptions {\n token?: string;\n signal?: AbortSignal;\n}\n\n// ── Errors ────────────────────────────────────────────────────────────────────\n\n/**\n * Thrown by `execute()` when a workflow finishes with `success: false`.\n */\nexport class TuvlWorkflowError extends Error {\n readonly data: unknown;\n readonly error: WorkflowErrorPayload | null;\n constructor(message: string, data: unknown, error: WorkflowErrorPayload | null) {\n super(message);\n this.name = \"TuvlWorkflowError\";\n this.data = data;\n this.error = error;\n }\n}\n\n/**\n * Thrown by `execute()` when a workflow suspends at a Human-in-the-Loop step.\n */\nexport class TuvlWorkflowSuspendedError extends Error {\n readonly suspended: SuspendedEvent;\n constructor(suspended: SuspendedEvent) {\n super(`tuvl workflow suspended at step '${suspended.paused_step_id ?? \"?\"}'`);\n this.name = \"TuvlWorkflowSuspendedError\";\n this.suspended = suspended;\n }\n}\n","/**\n * TuvlClient — the main entry point for @tuvl/client.\n *\n * Auto-detects the best transport for each workflow call:\n *\n * mode=\"rest\" (default) → plain POST, unwraps the REST envelope\n * mode=\"sse\" (auto) → SSE streaming when onProgress is provided\n * AND the workflow has_slow_steps === true\n * mode=\"grpc\" → gRPC-Web via sonora (requires peer deps)\n *\n * Return-value contract — IDENTICAL across all three transports:\n *\n * • on success → resolves with the `data` value\n * • on workflow-business error → rejects with `TuvlWorkflowError`\n * • on HITL suspension → rejects with `TuvlWorkflowSuspendedError`\n * • on transport / engine error → rejects with a plain `Error`\n *\n * Manifest caching avoids extra round-trips on repeated calls to the same\n * workflow. TTL defaults to 60 s and is configurable.\n */\n\nimport { CrudClient } from \"./crud\";\nimport { parseSseStream } from \"./sse\";\nimport { Transport } from \"./transport\";\nimport {\n TuvlWorkflowError,\n TuvlWorkflowSuspendedError,\n type DoneEvent,\n type ErrorEvent,\n type ExecuteOptions,\n type ExecuteVersionedOptions,\n type ResumeOptions,\n type ResumeRequest,\n type RestEnvelope,\n type StepEvent,\n type SuspendedEvent,\n type TuvlClientOptions,\n type WorkflowManifest,\n type WorkflowManifestMap,\n} from \"./types\";\n\ninterface CacheEntry {\n manifest: WorkflowManifest;\n expiresAt: number;\n}\n\nexport class TuvlClient {\n private readonly transport: Transport;\n private readonly manifestCache = new Map<string, CacheEntry>();\n private readonly manifestCacheTtl: number;\n\n constructor(options: TuvlClientOptions) {\n this.transport = new Transport({\n baseUrl: options.baseUrl,\n defaultToken: options.token,\n });\n this.manifestCacheTtl = options.manifestCacheTtl ?? 60_000;\n }\n\n /** Update the default auth token (e.g. after token refresh). */\n setToken(token: string): void {\n this.transport.setToken(token);\n }\n\n /** Expose the base URL for callers that need raw access (e.g. gRPC). */\n get baseUrl(): string {\n return this.transport.baseUrl;\n }\n\n // ── Manifest ──────────────────────────────────────────────────────────────\n\n /** Fetch (and cache) the manifest for a single workflow. */\n async getManifest(\n workflowName: string,\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<WorkflowManifest> {\n const cached = this.manifestCache.get(workflowName);\n if (cached && Date.now() < cached.expiresAt) {\n return cached.manifest;\n }\n\n const manifest = await this.transport.get<WorkflowManifest>(\n `/api/_system/workflows/${encodeURIComponent(workflowName)}`,\n options,\n );\n\n if (this.manifestCacheTtl > 0) {\n this.manifestCache.set(workflowName, {\n manifest,\n expiresAt: Date.now() + this.manifestCacheTtl,\n });\n }\n\n return manifest;\n }\n\n /** Fetch manifests for all registered workflows. */\n async listWorkflows(\n options?: { token?: string; signal?: AbortSignal },\n ): Promise<WorkflowManifestMap> {\n return this.transport.get<WorkflowManifestMap>(\"/api/_system/workflows\", options);\n }\n\n /** Invalidate the cached manifest for a workflow (or all if no name given). */\n invalidateManifest(workflowName?: string): void {\n if (workflowName) {\n this.manifestCache.delete(workflowName);\n } else {\n this.manifestCache.clear();\n }\n }\n\n // ── Execute ───────────────────────────────────────────────────────────────\n\n /**\n * Execute a workflow and return its `data` payload.\n *\n * Transport selection:\n * 1. mode=\"grpc\" → gRPC-Web (always, regardless of onProgress)\n * 2. mode=\"sse\" → SSE stream\n * 3. onProgress provided → SSE if workflow has_slow_steps, else REST\n * 4. default → REST\n *\n * @throws {TuvlWorkflowError} when the workflow returns success=false\n * @throws {TuvlWorkflowSuspendedError} when the workflow suspends at HITL\n * @throws {Error} on transport / engine failures\n */\n async execute<TOutput = unknown>(\n workflowName: string,\n options: ExecuteOptions<TOutput> = {},\n ): Promise<TOutput> {\n const { payload = {}, onProgress, onSuspended, mode, token, signal } = options;\n\n // Fetch manifest to resolve trigger_path and streaming hints\n const manifest = await this.getManifest(workflowName, { token, signal });\n\n const useSse =\n mode === \"sse\" ||\n (mode !== \"rest\" && mode !== \"grpc\" && !!onProgress && manifest.has_slow_steps);\n\n if (mode === \"grpc\") {\n return this._executeGrpc<TOutput>(manifest, payload, onProgress, onSuspended, token, signal);\n }\n\n if (useSse) {\n return this._executeSse<TOutput>(manifest, payload, onProgress, onSuspended, token, signal);\n }\n\n // Plain REST — server returns RestEnvelope; unwrap it.\n const envelope = await this.transport.post<Record<string, unknown>, RestEnvelope<TOutput>>(\n manifest.trigger_path,\n payload,\n { token, signal },\n );\n return this._unwrapRest<TOutput>(envelope, manifest.name);\n }\n\n /**\n * Execute a specific version of a workflow via `/{version}/run/{name}`.\n *\n * Useful when you want to pin to a particular schema_version without\n * relying on the currently-active default trigger path.\n *\n * @throws {TuvlWorkflowError} when the workflow returns success=false\n * @throws {TuvlWorkflowSuspendedError} when the workflow suspends at HITL\n * @throws {Error} on transport / engine failures\n */\n async executeVersioned<TOutput = unknown>(\n workflowName: string,\n version: string,\n options: ExecuteVersionedOptions<TOutput> | ExecuteOptions<TOutput> = {},\n ): Promise<TOutput> {\n const { payload = {}, onProgress, onSuspended, mode, token, signal } = options;\n const triggerPath = `/${version}/run/${workflowName}`;\n\n // Best-effort: fetch manifest to determine has_slow_steps for SSE auto-upgrade.\n let cachedManifest: WorkflowManifest | undefined;\n try {\n cachedManifest = await this.getManifest(workflowName, { token, signal });\n } catch {\n // If manifest fetch fails, fall back to the caller's explicit mode.\n }\n\n const syntheticManifest: WorkflowManifest = {\n name: workflowName,\n trigger_path: triggerPath,\n trigger_method: \"POST\",\n has_slow_steps: cachedManifest?.has_slow_steps ?? false,\n slow_kinds_present: cachedManifest?.slow_kinds_present ?? [],\n required_scope: cachedManifest?.required_scope ?? null,\n required_group: cachedManifest?.required_group ?? null,\n steps: cachedManifest?.steps ?? [],\n };\n\n const useSse =\n mode === \"sse\" ||\n (mode !== \"rest\" && mode !== \"grpc\" && !!onProgress && syntheticManifest.has_slow_steps);\n\n if (mode === \"grpc\") {\n return this._executeGrpc<TOutput>(\n syntheticManifest,\n payload,\n onProgress,\n onSuspended,\n token,\n signal,\n );\n }\n\n if (useSse) {\n return this._executeSse<TOutput>(\n syntheticManifest,\n payload,\n onProgress,\n onSuspended,\n token,\n signal,\n );\n }\n\n const envelope = await this.transport.post<Record<string, unknown>, RestEnvelope<TOutput>>(\n triggerPath,\n payload,\n { token, signal },\n );\n return this._unwrapRest<TOutput>(envelope, workflowName);\n }\n\n /**\n * Resume a HITL-suspended workflow instance.\n *\n * After the workflow throws `TuvlWorkflowSuspendedError`, capture the\n * `event.instance_id` from the suspended event and pass it here along with\n * the human-provided data to continue execution.\n *\n * @throws {TuvlWorkflowError} when the resumed workflow returns success=false\n * @throws {TuvlWorkflowSuspendedError} when the workflow suspends again at another HITL step\n * @throws {Error} on transport / engine failures\n */\n async resumeWorkflow<TOutput = unknown>(\n options: ResumeOptions<TOutput>,\n ): Promise<TOutput> {\n const { instanceId, humanInput = {}, onProgress, onSuspended, mode, token, signal } = options;\n\n const body: ResumeRequest = {\n instance_id: instanceId,\n human_input: humanInput,\n };\n\n if (mode === \"sse\" || (mode !== \"rest\" && !!onProgress)) {\n // Wrap in a synthetic manifest so we can reuse _executeSse.\n // The server's resume SSE path mirrors the trigger SSE path.\n const syntheticManifest: WorkflowManifest = {\n name: `(resumed:${instanceId})`,\n trigger_path: \"/api/workflows/resume\",\n trigger_method: \"POST\",\n has_slow_steps: true,\n slow_kinds_present: [],\n required_scope: null,\n required_group: null,\n steps: [],\n };\n return this._executeSse<TOutput>(\n syntheticManifest,\n body as unknown as Record<string, unknown>,\n onProgress,\n onSuspended,\n token,\n signal,\n );\n }\n\n // Plain REST resume — returns RestEnvelope<TOutput>.\n const envelope = await this.transport.post<ResumeRequest, RestEnvelope<TOutput>>(\n \"/api/workflows/resume\",\n body,\n { token, signal },\n );\n return this._unwrapRest<TOutput>(envelope, `(resumed:${instanceId})`);\n }\n\n // ── SSE transport ─────────────────────────────────────────────────────────\n\n private async _executeSse<TOutput>(\n manifest: WorkflowManifest,\n payload: Record<string, unknown>,\n onProgress: ((event: StepEvent) => void) | undefined,\n onSuspended: ((event: SuspendedEvent) => void) | undefined,\n token: string | undefined,\n signal: AbortSignal | undefined,\n ): Promise<TOutput> {\n const response = await this.transport.postStream(manifest.trigger_path, payload, {\n token,\n signal,\n });\n\n let done: DoneEvent | undefined;\n\n for await (const frame of parseSseStream(response, signal)) {\n switch (frame.event_type) {\n case \"step\":\n onProgress?.(frame);\n break;\n case \"done\":\n done = frame;\n break;\n case \"suspended\":\n onSuspended?.(frame);\n throw new TuvlWorkflowSuspendedError(frame);\n case \"error\": {\n const err = frame as ErrorEvent;\n throw new Error(\n `tuvl workflow '${manifest.name}' engine error: ${err.message}` +\n (err.details ? ` — ${err.details}` : \"\"),\n );\n }\n }\n }\n\n if (!done) {\n throw new Error(`tuvl SSE stream for '${manifest.name}' ended without a done event`);\n }\n\n if (!done.success) {\n throw new TuvlWorkflowError(\n `tuvl workflow '${manifest.name}' failed`,\n done.data,\n done.error,\n );\n }\n\n return done.data as TOutput;\n }\n\n // ── gRPC-Web transport ────────────────────────────────────────────────────\n\n private async _executeGrpc<TOutput>(\n manifest: WorkflowManifest,\n payload: Record<string, unknown>,\n onProgress: ((event: StepEvent) => void) | undefined,\n onSuspended: ((event: SuspendedEvent) => void) | undefined,\n token: string | undefined,\n signal: AbortSignal | undefined,\n ): Promise<TOutput> {\n const { openGrpcStream } = await import(\"./grpc\");\n\n let finalSnapshot: Record<string, unknown> | undefined;\n\n for await (const event of openGrpcStream({\n baseUrl: this.baseUrl,\n workflowName: manifest.name,\n payloadJson: JSON.stringify(payload),\n token,\n signal,\n })) {\n switch (event.event_type) {\n case \"step\":\n onProgress?.(event as StepEvent);\n break;\n case \"done\":\n // gRPC servicer emits the last-step snapshot as `snapshot_json`.\n // It is NOT pre-wrapped in {success, data, error} like SSE.\n finalSnapshot = (event as unknown as { snapshot: Record<string, unknown> }).snapshot;\n break;\n case \"suspended\": {\n // The gRPC servicer stuffs the HITL payload into snapshot_json.\n const snap = (event as unknown as { snapshot: Record<string, unknown> }).snapshot;\n const suspended: SuspendedEvent = {\n event_type: \"suspended\",\n paused_step_id: (event as unknown as { step_id?: string }).step_id,\n ...snap,\n };\n onSuspended?.(suspended);\n throw new TuvlWorkflowSuspendedError(suspended);\n }\n case \"error\":\n throw new Error(\n `tuvl workflow '${manifest.name}' gRPC error: ${event.error_detail ?? \"unknown\"}`,\n );\n }\n }\n\n if (finalSnapshot === undefined) {\n throw new Error(`tuvl gRPC stream for '${manifest.name}' ended without a done event`);\n }\n\n // gRPC mirrors the REST workflow contract via the workflow snapshot:\n // a `_last_error` key in context signals a business failure.\n if (\"_last_error\" in finalSnapshot) {\n throw new TuvlWorkflowError(\n `tuvl workflow '${manifest.name}' failed`,\n finalSnapshot,\n (finalSnapshot._last_error as never) ?? null,\n );\n }\n\n // Prefer the `_response` key when the workflow set one; else return the\n // full public snapshot. This mirrors the REST envelope's `data` semantics.\n if (\"_response\" in finalSnapshot) {\n return finalSnapshot._response as TOutput;\n }\n return finalSnapshot as TOutput;\n }\n\n // ── REST envelope ─────────────────────────────────────────────────────────\n\n private _unwrapRest<TOutput>(envelope: RestEnvelope<TOutput>, workflowName: string): TOutput {\n if (!envelope || typeof envelope !== \"object\") {\n // Server returned a bare body (older endpoint, or HITL 202 etc.) —\n // hand it back verbatim.\n return envelope as unknown as TOutput;\n }\n\n if (envelope.success === false) {\n throw new TuvlWorkflowError(\n `tuvl workflow '${workflowName}' failed`,\n envelope.data,\n envelope.error,\n );\n }\n\n // success===true OR envelope-shape mismatch (no `success` key) → return data\n // when present, else the whole body.\n return (envelope.data ?? (envelope as unknown)) as TOutput;\n }\n\n // ── CRUD ──────────────────────────────────────────────────────────────────\n\n /**\n * Return a typed CRUD client for a tuvl model endpoint.\n *\n * The returned client targets `/models/{modelName}/` and shares the\n * same transport (base URL + auth token) as this TuvlClient instance.\n *\n * @example\n * ```ts\n * // List all candidates\n * const all = await client.crud(\"candidate\").list();\n *\n * // With filters + embedded relations\n * const results = await client.crud(\"candidate\").list({\n * filters: { stage: \"screening\" },\n * include: [\"posting\"],\n * limit: 50,\n * });\n *\n * // Get one record\n * const c = await client.crud(\"candidate\").get(\"uuid-here\");\n *\n * // Strongly-typed variant\n * const c2 = await client\n * .crud<CandidateRead, CandidateCreate>(\"candidate\")\n * .create({ name: \"Alice\", email: \"alice@example.com\" });\n * ```\n */\n crud<TRead = unknown, TCreate = Partial<TRead>, TUpdate = Partial<TRead>>(\n modelName: string,\n ): CrudClient<TRead, TCreate, TUpdate> {\n return new CrudClient<TRead, TCreate, TUpdate>(this.transport, modelName);\n }\n}\n","/**\n * TuvlAuth — authentication helpers for @tuvl/client.\n *\n * Wraps the most common /auth/* endpoints (login, refresh, logout, who-am-I,\n * OAuth start, bootstrap) so consumers never have to manually construct\n * form-encoded bodies or manage Bearer headers for auth operations.\n *\n * Admin endpoints (user/role/scope CRUD, federation config) are NOT wrapped\n * — call them directly via `Transport` or `fetch` with the token.\n */\n\nimport type { MeResponse, TokenResponse } from \"./types\";\n\nexport interface TuvlAuthOptions {\n /** Base URL of the tuvl server. Trailing slash is stripped automatically. */\n baseUrl: string;\n}\n\nexport interface BootstrapRequest {\n email: string;\n password: string;\n /** Optional extra scope to grant the superadmin role on creation. */\n admin_scope?: string;\n}\n\nexport class TuvlAuth {\n private readonly baseUrl: string;\n\n constructor(options: TuvlAuthOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n }\n\n /**\n * Decode the current token server-side and return the user's identity,\n * role memberships (`groups`), and permission scopes.\n *\n * Biscuit tokens are protobuf-encoded and cannot be decoded in pure JS,\n * so this is the correct way to read \"who is logged in\" and \"what can\n * they do\" from the TypeScript SDK.\n *\n * @throws if the token is invalid, expired, or revoked.\n */\n async getMe(token: string): Promise<MeResponse> {\n const response = await fetch(`${this.baseUrl}/auth/me`, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl getMe failed (HTTP ${response.status}): ${text}`);\n }\n\n return response.json() as Promise<MeResponse>;\n }\n\n /**\n * Exchange an email + password for a Biscuit bearer token.\n *\n * Calls `POST /auth/token` with an `application/x-www-form-urlencoded`\n * body (OAuth2 password-grant). The `username` field must be the user's\n * email address.\n */\n async loginWithPassword(email: string, password: string): Promise<TokenResponse> {\n const body = new URLSearchParams({ username: email, password });\n\n const response = await fetch(`${this.baseUrl}/auth/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl login failed (HTTP ${response.status}): ${text}`);\n }\n\n return response.json() as Promise<TokenResponse>;\n }\n\n /**\n * Create the first superadmin user (one-time IAM bootstrap).\n *\n * Calls `POST /auth/bootstrap`. Returns 409 on every subsequent call\n * once any user exists.\n */\n async bootstrap(req: BootstrapRequest): Promise<TokenResponse> {\n const response = await fetch(`${this.baseUrl}/auth/bootstrap`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify(req),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl bootstrap failed (HTTP ${response.status}): ${text}`);\n }\n\n return response.json() as Promise<TokenResponse>;\n }\n\n /**\n * Return the URL the browser should navigate to in order to start an\n * OAuth2 login flow for the given provider.\n *\n * Supported built-ins: `\"google\"`, `\"github\"`, `\"microsoft\"`. Any\n * provider configured in the project's `federation/` directory also\n * works.\n *\n * After the OAuth dance the server either:\n * - redirects to `TUVL_OAUTH_UI_REDIRECT_URL?token=<biscuit_b64>`, OR\n * - returns a JSON `{access_token, token_type}` body (CLI / server flows).\n */\n getOAuthLoginUrl(provider: string): string {\n return `${this.baseUrl}/auth/oauth/${encodeURIComponent(provider)}/start`;\n }\n\n /**\n * Exchange a valid (non-expired, non-revoked) token for a fresh one.\n * The old token is immediately blacklisted — discard it after this call.\n */\n async refresh(token: string): Promise<TokenResponse> {\n const response = await fetch(`${this.baseUrl}/auth/refresh`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`tuvl token refresh failed (HTTP ${response.status}): ${text}`);\n }\n\n return response.json() as Promise<TokenResponse>;\n }\n\n /**\n * Revoke the given token (logout). After this the token is blacklisted\n * across all workers that share a Redis instance. Resolves silently on\n * success (HTTP 204).\n */\n async logout(token: string): Promise<void> {\n const response = await fetch(`${this.baseUrl}/auth/logout`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok && response.status !== 204) {\n const text = await response.text();\n throw new Error(`tuvl logout failed (HTTP ${response.status}): ${text}`);\n }\n }\n}\n","/**\n * @tuvl/client — TypeScript client SDK for the tuvl workflow engine.\n *\n * @example\n * ```ts\n * import { TuvlClient } from \"@tuvl/client\";\n *\n * const client = new TuvlClient({ baseUrl: \"http://localhost:8000\", token });\n *\n * // Plain REST call\n * const result = await client.execute(\"my-workflow\", { payload: { id: 1 } });\n *\n * // SSE streaming (auto-detected when onProgress is provided)\n * const result = await client.execute(\"my-workflow\", {\n * payload: { id: 1 },\n * onProgress: (ev) => console.log(`[${ev.step_id}] ${ev.signal} (${ev.duration_ms}ms)`),\n * });\n * ```\n */\n\nexport { TuvlClient } from \"./client\";\nexport { TuvlAuth } from \"./auth\";\nexport type { TuvlAuthOptions, BootstrapRequest } from \"./auth\";\nexport { CrudClient } from \"./crud\";\nexport { parseSseStream } from \"./sse\";\nexport { openGrpcStream } from \"./grpc\";\nexport { Transport } from \"./transport\";\nexport {\n TuvlWorkflowError,\n TuvlWorkflowSuspendedError,\n} from \"./types\";\nexport type {\n TokenResponse,\n MeResponse,\n StepEvent,\n DoneEvent,\n ErrorEvent,\n SuspendedEvent,\n WorkflowErrorPayload,\n RestEnvelope,\n WorkflowManifest,\n WorkflowManifestMap,\n ExecuteOptions,\n ExecuteVersionedOptions,\n ResumeOptions,\n ResumeRequest,\n TuvlClientOptions,\n CrudListOptions,\n CrudGetOptions,\n CrudMutateOptions,\n} from \"./types\";\n"]}
|