@saeeol/sdk 7.3.3 → 7.3.5

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.
Files changed (39) hide show
  1. package/package.json +6 -3
  2. package/src/client.ts +64 -0
  3. package/src/gen/client/client.gen.ts +215 -0
  4. package/src/gen/client/index.ts +25 -0
  5. package/src/gen/client/types.gen.ts +222 -0
  6. package/src/gen/client/utils.gen.ts +287 -0
  7. package/src/gen/client.gen.ts +22 -0
  8. package/src/gen/core/auth.gen.ts +41 -0
  9. package/src/gen/core/bodySerializer.gen.ts +74 -0
  10. package/src/gen/core/params.gen.ts +144 -0
  11. package/src/gen/core/pathSerializer.gen.ts +167 -0
  12. package/src/gen/core/queryKeySerializer.gen.ts +111 -0
  13. package/src/gen/core/serverSentEvents.gen.ts +210 -0
  14. package/src/gen/core/types.gen.ts +91 -0
  15. package/src/gen/core/utils.gen.ts +109 -0
  16. package/src/gen/sdk.gen.ts +1197 -0
  17. package/src/gen/types.gen.ts +3905 -0
  18. package/src/index.ts +21 -0
  19. package/src/process.ts +31 -0
  20. package/src/server.ts +165 -0
  21. package/src/v2/client.ts +97 -0
  22. package/src/v2/data.ts +32 -0
  23. package/src/v2/gen/client/client.gen.ts +285 -0
  24. package/src/v2/gen/client/index.ts +25 -0
  25. package/src/v2/gen/client/types.gen.ts +202 -0
  26. package/src/v2/gen/client/utils.gen.ts +289 -0
  27. package/src/v2/gen/client.gen.ts +18 -0
  28. package/src/v2/gen/core/auth.gen.ts +41 -0
  29. package/src/v2/gen/core/bodySerializer.gen.ts +82 -0
  30. package/src/v2/gen/core/params.gen.ts +169 -0
  31. package/src/v2/gen/core/pathSerializer.gen.ts +167 -0
  32. package/src/v2/gen/core/queryKeySerializer.gen.ts +111 -0
  33. package/src/v2/gen/core/serverSentEvents.gen.ts +239 -0
  34. package/src/v2/gen/core/types.gen.ts +86 -0
  35. package/src/v2/gen/core/utils.gen.ts +137 -0
  36. package/src/v2/gen/sdk.gen.ts +6316 -0
  37. package/src/v2/gen/types.gen.ts +7495 -0
  38. package/src/v2/index.ts +23 -0
  39. package/src/v2/server.ts +163 -0
package/src/index.ts ADDED
@@ -0,0 +1,21 @@
1
+ export * from "./client.js"
2
+ export * from "./server.js"
3
+
4
+ import { createSaeeolClient } from "./client.js"
5
+ import { createSaeeolServer } from "./server.js"
6
+ import type { ServerOptions } from "./server.js"
7
+
8
+ export async function createSaeeol(options?: ServerOptions) {
9
+ const server = await createSaeeolServer({
10
+ ...options,
11
+ })
12
+
13
+ const client = createSaeeolClient({
14
+ baseUrl: server.url,
15
+ })
16
+
17
+ return {
18
+ client,
19
+ server,
20
+ }
21
+ }
package/src/process.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { type ChildProcess, spawnSync } from "node:child_process"
2
+
3
+ // Duplicated from `packages/saeeol/src/util/process.ts` because the SDK cannot
4
+ // import `saeeol` without creating a cycle (`saeeol` depends on `@saeeol/sdk`).
5
+ export function stop(proc: ChildProcess) {
6
+ if (proc.exitCode !== null || proc.signalCode !== null) return
7
+ if (process.platform === "win32" && proc.pid) {
8
+ const out = spawnSync("taskkill", ["/pid", String(proc.pid), "/T", "/F"], { windowsHide: true })
9
+ if (!out.error && out.status === 0) return
10
+ }
11
+ proc.kill()
12
+ }
13
+
14
+ export function bindAbort(proc: ChildProcess, signal?: AbortSignal, onAbort?: () => void) {
15
+ if (!signal) return () => {}
16
+ const abort = () => {
17
+ clear()
18
+ stop(proc)
19
+ onAbort?.()
20
+ }
21
+ const clear = () => {
22
+ signal.removeEventListener("abort", abort)
23
+ proc.off("exit", clear)
24
+ proc.off("error", clear)
25
+ }
26
+ signal.addEventListener("abort", abort, { once: true })
27
+ proc.on("exit", clear)
28
+ proc.on("error", clear)
29
+ if (signal.aborted) abort()
30
+ return clear
31
+ }
package/src/server.ts ADDED
@@ -0,0 +1,165 @@
1
+ import launch from "cross-spawn"
2
+ import { type Config } from "./gen/types.gen.js"
3
+ import { stop, bindAbort } from "./process.js"
4
+ // This preserves Saeeol-injected modes when spawning nested CLI instances
5
+ function mergeConfig(existing: Config | undefined, incoming: Config | undefined): Config {
6
+ const base = existing ?? {}
7
+ const override = incoming ?? {}
8
+ return {
9
+ ...base,
10
+ ...override,
11
+ agent: { ...base.agent, ...override.agent },
12
+ command: { ...base.command, ...override.command },
13
+ mcp: { ...base.mcp, ...override.mcp },
14
+ mode: { ...base.mode, ...override.mode },
15
+ plugin: [...(base.plugin ?? []), ...(override.plugin ?? [])],
16
+ instructions: [...(base.instructions ?? []), ...(override.instructions ?? [])],
17
+ }
18
+ }
19
+
20
+ function parseExistingConfig(): Config | undefined {
21
+ const content = process.env.SAEEOL_CONFIG_CONTENT
22
+ if (!content) return undefined
23
+ try {
24
+ return JSON.parse(content)
25
+ } catch {
26
+ return undefined
27
+ }
28
+ }
29
+
30
+ export function buildConfigEnv(config?: Config): string {
31
+ const merged = mergeConfig(parseExistingConfig(), config)
32
+ return JSON.stringify(merged)
33
+ }
34
+
35
+ export type ServerOptions = {
36
+ hostname?: string
37
+ port?: number
38
+ signal?: AbortSignal
39
+ timeout?: number
40
+ config?: Config
41
+ }
42
+
43
+ export type TuiOptions = {
44
+ project?: string
45
+ model?: string
46
+ session?: string
47
+ agent?: string
48
+ signal?: AbortSignal
49
+ config?: Config
50
+ }
51
+
52
+ export async function createSaeeolServer(options?: ServerOptions) {
53
+ options = Object.assign(
54
+ {
55
+ hostname: "127.0.0.1",
56
+ port: 4096,
57
+ timeout: 5000,
58
+ },
59
+ options ?? {},
60
+ )
61
+
62
+ const args = [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`]
63
+ if (options.config?.logLevel) args.push(`--log-level=${options.config.logLevel}`)
64
+
65
+ const proc = launch(`saeeol`, args, {
66
+ env: {
67
+ ...process.env,
68
+ SAEEOL_CONFIG_CONTENT: buildConfigEnv(options.config),
69
+ },
70
+ })
71
+ let clear = () => {}
72
+
73
+ const url = await new Promise<string>((resolve, reject) => {
74
+ const id = setTimeout(() => {
75
+ clear()
76
+ stop(proc)
77
+ reject(new Error(`Timeout waiting for server to start after ${options.timeout}ms`))
78
+ }, options.timeout)
79
+ let output = ""
80
+ let resolved = false
81
+ proc.stdout?.on("data", (chunk) => {
82
+ if (resolved) return
83
+ output += chunk.toString()
84
+ const lines = output.split("\n")
85
+ for (const line of lines) {
86
+ if (line.startsWith("saeeol server listening")) {
87
+ const match = line.match(/on\s+(https?:\/\/[^\s]+)/)
88
+ if (!match) {
89
+ clear()
90
+ stop(proc)
91
+ clearTimeout(id)
92
+ reject(new Error(`Failed to parse server url from output: ${line}`))
93
+ return
94
+ }
95
+ clearTimeout(id)
96
+ resolved = true
97
+ resolve(match[1]!)
98
+ return
99
+ }
100
+ }
101
+ })
102
+ proc.stderr?.on("data", (chunk) => {
103
+ output += chunk.toString()
104
+ })
105
+ proc.on("exit", (code) => {
106
+ clearTimeout(id)
107
+ let msg = `Server exited with code ${code}`
108
+ if (output.trim()) {
109
+ msg += `\nServer output: ${output}`
110
+ }
111
+ reject(new Error(msg))
112
+ })
113
+ proc.on("error", (error) => {
114
+ clearTimeout(id)
115
+ reject(error)
116
+ })
117
+ clear = bindAbort(proc, options.signal, () => {
118
+ clearTimeout(id)
119
+ reject(options.signal?.reason)
120
+ })
121
+ })
122
+
123
+ return {
124
+ url,
125
+ close() {
126
+ clear()
127
+ stop(proc)
128
+ },
129
+ }
130
+ }
131
+
132
+ export function createSaeeolTui(options?: TuiOptions) {
133
+ const args = []
134
+
135
+ if (options?.project) {
136
+ args.push(`--project=${options.project}`)
137
+ }
138
+ if (options?.model) {
139
+ args.push(`--model=${options.model}`)
140
+ }
141
+ if (options?.session) {
142
+ args.push(`--session=${options.session}`)
143
+ }
144
+ if (options?.agent) {
145
+ args.push(`--agent=${options.agent}`)
146
+ }
147
+
148
+ const proc = launch(`saeeol`, args, {
149
+ stdio: "inherit",
150
+ windowsHide: true,
151
+ env: {
152
+ ...process.env,
153
+ SAEEOL_CONFIG_CONTENT: buildConfigEnv(options?.config),
154
+ },
155
+ })
156
+
157
+ const clear = bindAbort(proc, options?.signal)
158
+
159
+ return {
160
+ close() {
161
+ clear()
162
+ stop(proc)
163
+ },
164
+ }
165
+ }
@@ -0,0 +1,97 @@
1
+ export * from "./gen/types.gen.js"
2
+
3
+ import { createClient } from "./gen/client/client.gen.js"
4
+ import { type Config } from "./gen/client/types.gen.js"
5
+ import { SaeeolClient } from "./gen/sdk.gen.js"
6
+ export { type Config as SaeeolClientConfig, SaeeolClient }
7
+
8
+ function pick(value: string | null, fallback?: string, encode?: (value: string) => string) {
9
+ if (!value) return
10
+ if (!fallback) return value
11
+ if (value === fallback) return fallback
12
+ if (encode && value === encode(fallback)) return fallback
13
+ return value
14
+ }
15
+
16
+ function rewrite(request: Request, values: { directory?: string; workspace?: string }) {
17
+ if (request.method !== "GET" && request.method !== "HEAD") return request
18
+
19
+ const url = new URL(request.url)
20
+ let changed = false
21
+
22
+ for (const [name, key] of [
23
+ ["x-saeeol-directory", "directory"],
24
+ ["x-saeeol-workspace", "workspace"],
25
+ ] as const) {
26
+ const value = pick(
27
+ request.headers.get(name),
28
+ key === "directory" ? values.directory : values.workspace,
29
+ key === "directory" ? encodeURIComponent : undefined,
30
+ )
31
+ if (!value) continue
32
+ if (!url.searchParams.has(key)) {
33
+ url.searchParams.set(key, value)
34
+ }
35
+ changed = true
36
+ }
37
+
38
+ if (!changed) return request
39
+
40
+ const next = new Request(url, request)
41
+ next.headers.delete("x-saeeol-directory")
42
+ next.headers.delete("x-saeeol-workspace")
43
+ return next
44
+ }
45
+
46
+ export function createSaeeolClient(config?: Config & { directory?: string; experimental_workspaceID?: string }) {
47
+ if (!config?.fetch) {
48
+ const customFetch: any = (req: any) => {
49
+ // Pass duplex in the init arg so it survives VS Code's proxy-agent
50
+ // fetch wrapper, which calls originalFetch(request, { ...init, dispatcher })
51
+ // and would otherwise drop duplex from the cloned Request.
52
+ // timeout: false disables Bun's default request timeout for long-running
53
+ // streaming calls (replaces the old req.timeout = false assignment which
54
+ // wouldn't survive the clone triggered by passing an init object).
55
+ return fetch(req, { duplex: "half", timeout: false } as any)
56
+ }
57
+ config = {
58
+ ...config,
59
+ fetch: customFetch,
60
+ }
61
+ }
62
+
63
+ if (config?.directory) {
64
+ config.headers = {
65
+ ...config.headers,
66
+ "x-saeeol-directory": encodeURIComponent(config.directory),
67
+ }
68
+ }
69
+
70
+ if (config?.experimental_workspaceID) {
71
+ config.headers = {
72
+ ...config.headers,
73
+ "x-saeeol-workspace": config.experimental_workspaceID,
74
+ }
75
+ }
76
+
77
+ // Node.js/Electron require duplex: "half" when creating Request objects
78
+ // with a body. The option propagates through config → opts → requestInit
79
+ // and is harmless in environments that don't need it (Bun, browsers).
80
+ ;(config as any).duplex = "half"
81
+
82
+ const client = createClient(config)
83
+ client.interceptors.request.use((request) =>
84
+ rewrite(request, {
85
+ directory: config?.directory,
86
+ workspace: config?.experimental_workspaceID,
87
+ }),
88
+ )
89
+ client.interceptors.response.use((response) => {
90
+ const contentType = response.headers.get("content-type")
91
+ if (contentType === "text/html")
92
+ throw new Error("Request is not supported by this version of Saeeol Server (Server responded with text/html)")
93
+
94
+ return response
95
+ })
96
+ return new SaeeolClient({ client })
97
+ }
package/src/v2/data.ts ADDED
@@ -0,0 +1,32 @@
1
+ import type { Part, UserMessage } from "./client.js"
2
+
3
+ export const message = {
4
+ user(input: Omit<UserMessage, "role" | "time" | "id"> & { parts: Omit<Part, "id" | "sessionID" | "messageID">[] }): {
5
+ info: UserMessage
6
+ parts: Part[]
7
+ } {
8
+ const { parts: _parts, ...rest } = input
9
+
10
+ const info: UserMessage = {
11
+ ...rest,
12
+ id: "asdasd",
13
+ time: {
14
+ created: Date.now(),
15
+ },
16
+ role: "user",
17
+ }
18
+
19
+ return {
20
+ info,
21
+ parts: input.parts.map(
22
+ (part) =>
23
+ ({
24
+ ...part,
25
+ id: "asdasd",
26
+ messageID: info.id,
27
+ sessionID: info.sessionID,
28
+ }) as Part,
29
+ ),
30
+ }
31
+ },
32
+ }
@@ -0,0 +1,285 @@
1
+ // This file is auto-generated by @hey-api/openapi-ts
2
+
3
+ import { createSseClient } from "../core/serverSentEvents.gen.js"
4
+ import type { HttpMethod } from "../core/types.gen.js"
5
+ import { getValidRequestBody } from "../core/utils.gen.js"
6
+ import type { Client, Config, RequestOptions, ResolvedRequestOptions } from "./types.gen.js"
7
+ import {
8
+ buildUrl,
9
+ createConfig,
10
+ createInterceptors,
11
+ getParseAs,
12
+ mergeConfigs,
13
+ mergeHeaders,
14
+ setAuthParams,
15
+ } from "./utils.gen.js"
16
+
17
+ type ReqInit = Omit<RequestInit, "body" | "headers"> & {
18
+ body?: any
19
+ headers: ReturnType<typeof mergeHeaders>
20
+ }
21
+
22
+ export const createClient = (config: Config = {}): Client => {
23
+ let _config = mergeConfigs(createConfig(), config)
24
+
25
+ const getConfig = (): Config => ({ ..._config })
26
+
27
+ const setConfig = (config: Config): Config => {
28
+ _config = mergeConfigs(_config, config)
29
+ return getConfig()
30
+ }
31
+
32
+ const interceptors = createInterceptors<Request, Response, unknown, ResolvedRequestOptions>()
33
+
34
+ const beforeRequest = async (options: RequestOptions) => {
35
+ const opts = {
36
+ ..._config,
37
+ ...options,
38
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
39
+ headers: mergeHeaders(_config.headers, options.headers),
40
+ serializedBody: undefined,
41
+ }
42
+
43
+ if (opts.security) {
44
+ await setAuthParams({
45
+ ...opts,
46
+ security: opts.security,
47
+ })
48
+ }
49
+
50
+ if (opts.requestValidator) {
51
+ await opts.requestValidator(opts)
52
+ }
53
+
54
+ if (opts.body !== undefined && opts.bodySerializer) {
55
+ opts.serializedBody = opts.bodySerializer(opts.body)
56
+ }
57
+
58
+ // remove Content-Type header if body is empty to avoid sending invalid requests
59
+ if (opts.body === undefined || opts.serializedBody === "") {
60
+ opts.headers.delete("Content-Type")
61
+ }
62
+
63
+ const url = buildUrl(opts)
64
+
65
+ return { opts, url }
66
+ }
67
+
68
+ const request: Client["request"] = async (options) => {
69
+ // @ts-expect-error
70
+ const { opts, url } = await beforeRequest(options)
71
+ const requestInit: ReqInit = {
72
+ redirect: "follow",
73
+ ...opts,
74
+ body: getValidRequestBody(opts),
75
+ }
76
+
77
+ let request = new Request(url, requestInit)
78
+
79
+ for (const fn of interceptors.request.fns) {
80
+ if (fn) {
81
+ request = await fn(request, opts)
82
+ }
83
+ }
84
+
85
+ // fetch must be assigned here, otherwise it would throw the error:
86
+ // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
87
+ const _fetch = opts.fetch!
88
+ let response: Response
89
+
90
+ try {
91
+ response = await _fetch(request)
92
+ } catch (error) {
93
+ // Handle fetch exceptions (AbortError, network errors, etc.)
94
+ let finalError = error
95
+
96
+ for (const fn of interceptors.error.fns) {
97
+ if (fn) {
98
+ finalError = (await fn(error, undefined as any, request, opts)) as unknown
99
+ }
100
+ }
101
+
102
+ finalError = finalError || ({} as unknown)
103
+
104
+ if (opts.throwOnError) {
105
+ throw finalError
106
+ }
107
+
108
+ // Return error response
109
+ return opts.responseStyle === "data"
110
+ ? undefined
111
+ : {
112
+ error: finalError,
113
+ request,
114
+ response: undefined as any,
115
+ }
116
+ }
117
+
118
+ for (const fn of interceptors.response.fns) {
119
+ if (fn) {
120
+ response = await fn(response, request, opts)
121
+ }
122
+ }
123
+
124
+ const result = {
125
+ request,
126
+ response,
127
+ }
128
+
129
+ if (response.ok) {
130
+ const parseAs =
131
+ (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"
132
+
133
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
134
+ let emptyData: any
135
+ switch (parseAs) {
136
+ case "arrayBuffer":
137
+ case "blob":
138
+ case "text":
139
+ emptyData = await response[parseAs]()
140
+ break
141
+ case "formData":
142
+ emptyData = new FormData()
143
+ break
144
+ case "stream":
145
+ emptyData = response.body
146
+ break
147
+ case "json":
148
+ default:
149
+ emptyData = {}
150
+ break
151
+ }
152
+ return opts.responseStyle === "data"
153
+ ? emptyData
154
+ : {
155
+ data: emptyData,
156
+ ...result,
157
+ }
158
+ }
159
+
160
+ let data: any
161
+ switch (parseAs) {
162
+ case "arrayBuffer":
163
+ case "blob":
164
+ case "formData":
165
+ case "text":
166
+ data = await response[parseAs]()
167
+ break
168
+ case "json": {
169
+ // Some servers return 200 with no Content-Length and empty body.
170
+ // response.json() would throw; read as text and parse if non-empty.
171
+ const text = await response.text()
172
+ data = text ? JSON.parse(text) : {}
173
+ break
174
+ }
175
+ case "stream":
176
+ return opts.responseStyle === "data"
177
+ ? response.body
178
+ : {
179
+ data: response.body,
180
+ ...result,
181
+ }
182
+ }
183
+
184
+ if (parseAs === "json") {
185
+ if (opts.responseValidator) {
186
+ await opts.responseValidator(data)
187
+ }
188
+
189
+ if (opts.responseTransformer) {
190
+ data = await opts.responseTransformer(data)
191
+ }
192
+ }
193
+
194
+ return opts.responseStyle === "data"
195
+ ? data
196
+ : {
197
+ data,
198
+ ...result,
199
+ }
200
+ }
201
+
202
+ const textError = await response.text()
203
+ let jsonError: unknown
204
+
205
+ try {
206
+ jsonError = JSON.parse(textError)
207
+ } catch {
208
+ // noop
209
+ }
210
+
211
+ const error = jsonError ?? textError
212
+ let finalError = error
213
+
214
+ for (const fn of interceptors.error.fns) {
215
+ if (fn) {
216
+ finalError = (await fn(error, response, request, opts)) as string
217
+ }
218
+ }
219
+
220
+ finalError = finalError || ({} as string)
221
+
222
+ if (opts.throwOnError) {
223
+ throw finalError
224
+ }
225
+
226
+ // TODO: we probably want to return error and improve types
227
+ return opts.responseStyle === "data"
228
+ ? undefined
229
+ : {
230
+ error: finalError,
231
+ ...result,
232
+ }
233
+ }
234
+
235
+ const makeMethodFn = (method: Uppercase<HttpMethod>) => (options: RequestOptions) => request({ ...options, method })
236
+
237
+ const makeSseFn = (method: Uppercase<HttpMethod>) => async (options: RequestOptions) => {
238
+ const { opts, url } = await beforeRequest(options)
239
+ return createSseClient({
240
+ ...opts,
241
+ body: opts.body as BodyInit | null | undefined,
242
+ headers: opts.headers as unknown as Record<string, string>,
243
+ method,
244
+ onRequest: async (url, init) => {
245
+ let request = new Request(url, init)
246
+ for (const fn of interceptors.request.fns) {
247
+ if (fn) {
248
+ request = await fn(request, opts)
249
+ }
250
+ }
251
+ return request
252
+ },
253
+ serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined,
254
+ url,
255
+ })
256
+ }
257
+
258
+ return {
259
+ buildUrl,
260
+ connect: makeMethodFn("CONNECT"),
261
+ delete: makeMethodFn("DELETE"),
262
+ get: makeMethodFn("GET"),
263
+ getConfig,
264
+ head: makeMethodFn("HEAD"),
265
+ interceptors,
266
+ options: makeMethodFn("OPTIONS"),
267
+ patch: makeMethodFn("PATCH"),
268
+ post: makeMethodFn("POST"),
269
+ put: makeMethodFn("PUT"),
270
+ request,
271
+ setConfig,
272
+ sse: {
273
+ connect: makeSseFn("CONNECT"),
274
+ delete: makeSseFn("DELETE"),
275
+ get: makeSseFn("GET"),
276
+ head: makeSseFn("HEAD"),
277
+ options: makeSseFn("OPTIONS"),
278
+ patch: makeSseFn("PATCH"),
279
+ post: makeSseFn("POST"),
280
+ put: makeSseFn("PUT"),
281
+ trace: makeSseFn("TRACE"),
282
+ },
283
+ trace: makeMethodFn("TRACE"),
284
+ } as Client
285
+ }
@@ -0,0 +1,25 @@
1
+ // This file is auto-generated by @hey-api/openapi-ts
2
+
3
+ export type { Auth } from "../core/auth.gen.js"
4
+ export type { QuerySerializerOptions } from "../core/bodySerializer.gen.js"
5
+ export {
6
+ formDataBodySerializer,
7
+ jsonBodySerializer,
8
+ urlSearchParamsBodySerializer,
9
+ } from "../core/bodySerializer.gen.js"
10
+ export { buildClientParams } from "../core/params.gen.js"
11
+ export { serializeQueryKeyValue } from "../core/queryKeySerializer.gen.js"
12
+ export { createClient } from "./client.gen.js"
13
+ export type {
14
+ Client,
15
+ ClientOptions,
16
+ Config,
17
+ CreateClientConfig,
18
+ Options,
19
+ RequestOptions,
20
+ RequestResult,
21
+ ResolvedRequestOptions,
22
+ ResponseStyle,
23
+ TDataShape,
24
+ } from "./types.gen.js"
25
+ export { createConfig, mergeHeaders } from "./utils.gen.js"