@opencode/server 2.0.8 → 2.0.10
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/dist/api.d.ts +4 -4
- package/dist/api.js +10 -9
- package/dist/auth.js +12 -17
- package/dist/chunks/auth-0ar9gf7q.js +55 -0
- package/dist/chunks/auth-0qzy9yxk.js +163 -0
- package/dist/chunks/auth-1wj0ectp.js +22 -0
- package/dist/chunks/auth-23w8t84j.js +26 -0
- package/dist/chunks/auth-34e6wr3b.js +13 -0
- package/dist/chunks/auth-3582t7j8.js +139 -0
- package/dist/chunks/auth-40g8rvw4.js +59 -0
- package/dist/chunks/auth-5p62ed52.js +36 -0
- package/dist/chunks/auth-6aya8ky6.js +39 -0
- package/dist/chunks/auth-760vtqy2.js +29 -0
- package/dist/chunks/auth-7bj707s9.js +99 -0
- package/dist/chunks/auth-7qtja2kq.js +15 -0
- package/dist/chunks/auth-8e21y1bd.js +20 -0
- package/dist/chunks/auth-8nbs1vvt.js +34 -0
- package/dist/chunks/auth-8ygjd1s8.js +40 -0
- package/dist/chunks/auth-9rqn6x4v.js +16 -0
- package/dist/chunks/auth-b4atwt7w.js +37 -0
- package/dist/chunks/auth-bgzrbsek.js +13 -0
- package/dist/chunks/auth-bkb1xk38.js +42 -0
- package/dist/chunks/auth-bkk2wfbz.js +23 -0
- package/dist/chunks/auth-byzd2nk7.js +21 -0
- package/dist/chunks/auth-cm8xmqjn.js +13 -0
- package/dist/chunks/auth-d2g7egyw.js +25 -0
- package/dist/chunks/auth-e09mshwt.js +23 -0
- package/dist/chunks/auth-erwrh284.js +156 -0
- package/dist/chunks/auth-frv6gfy7.js +33 -0
- package/dist/chunks/auth-fyjxk8m3.js +22 -0
- package/dist/chunks/auth-gsks0nj8.js +149 -0
- package/dist/chunks/auth-hezj1jdf.js +7 -0
- package/dist/chunks/auth-kv6ycdgm.js +77 -0
- package/dist/chunks/auth-m6wvgbfq.js +60 -0
- package/dist/chunks/auth-p5hgn93y.js +26 -0
- package/dist/chunks/auth-pd1pbg0v.js +17 -0
- package/dist/chunks/auth-q4bn6dy8.js +39 -0
- package/dist/chunks/auth-r4dhhtgz.js +346 -0
- package/dist/chunks/auth-rjpqaa8h.js +83 -0
- package/dist/chunks/auth-smaf4a18.js +28 -0
- package/dist/chunks/auth-t8yzmczr.js +18 -0
- package/dist/chunks/auth-tk6nqkmh.js +22 -0
- package/dist/chunks/auth-txhx6f1m.js +13 -0
- package/dist/chunks/auth-vgxn80m1.js +61 -0
- package/dist/chunks/auth-xpxp1sqb.js +22 -0
- package/dist/chunks/auth-xsrtpxyd.js +23 -0
- package/dist/chunks/auth-yc7nft6q.js +5 -0
- package/dist/chunks/auth-z3nth2hg.js +35 -0
- package/dist/chunks/auth-z6kg9h7e.js +19 -0
- package/dist/chunks/auth-zw9j8b8g.js +32 -0
- package/dist/chunks/auth-zxvt7wd3.js +25 -0
- package/dist/chunks/auth-zyv89x5n.js +30 -0
- package/dist/cors.js +10 -36
- package/dist/event-feed.js +20 -60
- package/dist/fetch.js +53 -11
- package/dist/handlers/agent.js +11 -17
- package/dist/handlers/command.js +11 -5
- package/dist/handlers/config.js +11 -16
- package/dist/handlers/credential.js +11 -14
- package/dist/handlers/debug.js +11 -11
- package/dist/handlers/event.js +12 -27
- package/dist/handlers/form.js +11 -9
- package/dist/handlers/fs.js +11 -22
- package/dist/handlers/generate.js +11 -15
- package/dist/handlers/integration.js +10 -142
- package/dist/handlers/location.js +11 -16
- package/dist/handlers/mcp.js +11 -31
- package/dist/handlers/message.js +10 -42
- package/dist/handlers/migration.js +11 -7
- package/dist/handlers/model.js +11 -14
- package/dist/handlers/permission.js +11 -57
- package/dist/handlers/persistent-pty.js +12 -135
- package/dist/handlers/plugin.js +11 -47
- package/dist/handlers/project.js +11 -9
- package/dist/handlers/provider.js +11 -20
- package/dist/handlers/pty-socket.js +6 -4
- package/dist/handlers/pty.js +13 -107
- package/dist/handlers/reference.js +11 -5
- package/dist/handlers/rpc.js +11 -15
- package/dist/handlers/server.js +12 -13
- package/dist/handlers/session-error.js +12 -26
- package/dist/handlers/session.js +10 -311
- package/dist/handlers/shell.js +11 -25
- package/dist/handlers/skill.js +11 -5
- package/dist/handlers/vcs.js +11 -19
- package/dist/handlers/websearch.js +11 -31
- package/dist/handlers/worktree.js +11 -37
- package/dist/handlers.d.ts +1 -1
- package/dist/handlers.js +46 -33
- package/dist/location.js +15 -49
- package/dist/middleware/authorization.js +11 -49
- package/dist/middleware/form-location.js +10 -25
- package/dist/middleware/schema-error.js +8 -15
- package/dist/middleware/session-location.js +10 -19
- package/dist/options.js +5 -1
- package/dist/process.js +108 -28
- package/dist/pty-environment.js +12 -9
- package/dist/request-tracing.js +6 -2
- package/dist/routes.d.ts +2 -2
- package/dist/routes.js +52 -118
- package/dist/server-info.js +12 -22
- package/dist/service-status.js +8 -11
- package/dist/workerd.js +80 -12
- package/package.json +8 -8
package/dist/api.d.ts
CHANGED
|
@@ -6654,7 +6654,7 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
|
|
|
6654
6654
|
readonly [x: string]: unknown;
|
|
6655
6655
|
};
|
|
6656
6656
|
readonly command: string;
|
|
6657
|
-
readonly status: "
|
|
6657
|
+
readonly status: "timeout" | "running" | "exited" | "killed";
|
|
6658
6658
|
readonly time: {
|
|
6659
6659
|
readonly started: number;
|
|
6660
6660
|
readonly completed?: number | undefined;
|
|
@@ -6679,7 +6679,7 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
|
|
|
6679
6679
|
readonly id: string & import("effect/Brand").Brand<"Event.ID">;
|
|
6680
6680
|
readonly data: {
|
|
6681
6681
|
readonly id: string & import("effect/Brand").Brand<"Shell.ID">;
|
|
6682
|
-
readonly status: "
|
|
6682
|
+
readonly status: "timeout" | "running" | "exited" | "killed";
|
|
6683
6683
|
readonly exit?: number | undefined;
|
|
6684
6684
|
};
|
|
6685
6685
|
readonly type: "shell.exited";
|
|
@@ -7276,7 +7276,7 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
|
|
|
7276
7276
|
readonly [x: string]: unknown;
|
|
7277
7277
|
};
|
|
7278
7278
|
readonly command: string;
|
|
7279
|
-
readonly status: "
|
|
7279
|
+
readonly status: "timeout" | "running" | "exited" | "killed";
|
|
7280
7280
|
readonly time: {
|
|
7281
7281
|
readonly started: number;
|
|
7282
7282
|
readonly completed?: number | undefined;
|
|
@@ -7312,7 +7312,7 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
|
|
|
7312
7312
|
readonly [x: string]: unknown;
|
|
7313
7313
|
};
|
|
7314
7314
|
readonly command: string;
|
|
7315
|
-
readonly status: "
|
|
7315
|
+
readonly status: "timeout" | "running" | "exited" | "killed";
|
|
7316
7316
|
readonly time: {
|
|
7317
7317
|
readonly started: number;
|
|
7318
7318
|
readonly completed?: number | undefined;
|
package/dist/api.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import {
|
|
2
|
+
Api2
|
|
3
|
+
} from "./chunks/auth-z6kg9h7e.js";
|
|
4
|
+
import"./chunks/auth-23w8t84j.js";
|
|
5
|
+
import"./chunks/auth-frv6gfy7.js";
|
|
6
|
+
import"./chunks/auth-0ar9gf7q.js";
|
|
7
|
+
import"./chunks/auth-smaf4a18.js";
|
|
8
|
+
export {
|
|
9
|
+
Api2 as Api
|
|
10
|
+
};
|
package/dist/auth.js
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return Option.isSome(config.password) && config.password.value !== "";
|
|
14
|
-
}
|
|
15
|
-
export function authorized(credentials, config) {
|
|
16
|
-
return Option.isSome(config.password) && credentials.username === config.username && Redacted.value(credentials.password) === config.password.value;
|
|
17
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
Config2,
|
|
3
|
+
required2,
|
|
4
|
+
authorized2,
|
|
5
|
+
exports_auth
|
|
6
|
+
} from "./chunks/auth-zyv89x5n.js";
|
|
7
|
+
export {
|
|
8
|
+
Config2 as Config,
|
|
9
|
+
exports_auth as ServerAuth,
|
|
10
|
+
authorized2 as authorized,
|
|
11
|
+
required2 as required
|
|
12
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
missingSession2
|
|
3
|
+
} from "./auth-smaf4a18.js";
|
|
4
|
+
|
|
5
|
+
// src/location.ts
|
|
6
|
+
import { Location } from "@opencode/core/location";
|
|
7
|
+
import { LocationServiceMap } from "@opencode/core/location-services";
|
|
8
|
+
import { AbsolutePath } from "@opencode/core/schema";
|
|
9
|
+
import { Session } from "@opencode/core/session";
|
|
10
|
+
import { InvalidRequestError } from "@opencode/protocol/errors";
|
|
11
|
+
import { Effect, Layer, Schema } from "effect";
|
|
12
|
+
import { HttpServerRequest } from "effect/unstable/http";
|
|
13
|
+
import { HttpApiMiddleware } from "effect/unstable/httpapi";
|
|
14
|
+
class LocationMiddleware2 extends HttpApiMiddleware.Service()("@opencode/HttpApiLocation") {
|
|
15
|
+
}
|
|
16
|
+
function response2(data) {
|
|
17
|
+
return Effect.gen(function* () {
|
|
18
|
+
const location = yield* Location.Service;
|
|
19
|
+
return {
|
|
20
|
+
location: new Location.Info({
|
|
21
|
+
directory: location.directory,
|
|
22
|
+
project: location.project
|
|
23
|
+
}),
|
|
24
|
+
data: yield* data
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
var decodeSessionID = Schema.decodeUnknownEffect(Session.ID);
|
|
29
|
+
var sessionInfo2 = Effect.fnUntraced(function* (sessions, sessionID) {
|
|
30
|
+
const id = yield* decodeSessionID(sessionID).pipe(Effect.mapError(() => new InvalidRequestError({ message: "Invalid session ID", field: "sessionID" })));
|
|
31
|
+
return yield* sessions.get(id).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
|
|
32
|
+
});
|
|
33
|
+
function requestRef2(request) {
|
|
34
|
+
const query = new URL(request.url, "http://localhost").searchParams;
|
|
35
|
+
const directory = query.get("location[directory]") || (request.headers["x-opencode-directory"] ? decode(request.headers["x-opencode-directory"]) : process.cwd());
|
|
36
|
+
return Location.Ref.make({
|
|
37
|
+
directory: AbsolutePath.make(directory)
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function decode(input) {
|
|
41
|
+
try {
|
|
42
|
+
return decodeURIComponent(input);
|
|
43
|
+
} catch {
|
|
44
|
+
return input;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
var layer5 = Layer.effect(LocationMiddleware2, Effect.gen(function* () {
|
|
48
|
+
const locations = yield* LocationServiceMap.Service;
|
|
49
|
+
return LocationMiddleware2.of((effect) => Effect.gen(function* () {
|
|
50
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
51
|
+
return yield* effect.pipe(Effect.provide(locations.get(requestRef2(request))));
|
|
52
|
+
}));
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
export { LocationMiddleware2, response2, sessionInfo2, requestRef2, layer5 };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Api2
|
|
3
|
+
} from "./auth-z6kg9h7e.js";
|
|
4
|
+
import {
|
|
5
|
+
CorsConfig2,
|
|
6
|
+
isAllowedRequestOrigin2
|
|
7
|
+
} from "./auth-q4bn6dy8.js";
|
|
8
|
+
import {
|
|
9
|
+
runPtySocket2
|
|
10
|
+
} from "./auth-hezj1jdf.js";
|
|
11
|
+
|
|
12
|
+
// src/handlers/persistent-pty.ts
|
|
13
|
+
import { PersistentPty } from "@opencode/core/persistent-pty";
|
|
14
|
+
import { PtyTicket } from "@opencode/core/pty/ticket";
|
|
15
|
+
import { ForbiddenError, PtyNotFoundError, ServiceUnavailableError } from "@opencode/protocol/errors";
|
|
16
|
+
import {
|
|
17
|
+
PTY_CONNECT_TICKET_QUERY,
|
|
18
|
+
PTY_CONNECT_TOKEN_HEADER,
|
|
19
|
+
PTY_CONNECT_TOKEN_HEADER_VALUE
|
|
20
|
+
} from "@opencode/protocol/groups/persistent-pty";
|
|
21
|
+
import { Effect, Queue, Semaphore } from "effect";
|
|
22
|
+
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
23
|
+
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
|
|
24
|
+
import { Socket } from "effect/unstable/socket";
|
|
25
|
+
var PersistentPtyHandler2 = HttpApiBuilder.group(Api2, "server.experimental", (handlers) => Effect.gen(function* () {
|
|
26
|
+
const tickets = yield* PtyTicket.Service;
|
|
27
|
+
const cors = yield* CorsConfig2;
|
|
28
|
+
const pty = yield* PersistentPty.Service;
|
|
29
|
+
return handlers.handle("persistentPty.read", Effect.fn(function* (ctx) {
|
|
30
|
+
return { data: yield* pty.read(ctx.params.sessionID, ctx.query.lines).pipe(mapUnavailable) };
|
|
31
|
+
})).handle("persistentPty.list", Effect.fn(function* (ctx) {
|
|
32
|
+
return { data: yield* pty.list(ctx.params.sessionID).pipe(mapUnavailable) };
|
|
33
|
+
})).handle("persistentPty.create", Effect.fn(function* (ctx) {
|
|
34
|
+
return {
|
|
35
|
+
data: yield* pty.create(ctx.params.sessionID, {
|
|
36
|
+
command: ctx.payload.command,
|
|
37
|
+
args: ctx.payload.args,
|
|
38
|
+
cwd: ctx.payload.cwd,
|
|
39
|
+
title: ctx.payload.title,
|
|
40
|
+
env: ctx.payload.env,
|
|
41
|
+
cols: ctx.payload.size?.cols,
|
|
42
|
+
rows: ctx.payload.size?.rows
|
|
43
|
+
}).pipe(Effect.catchTag("PersistentPty.UnavailableError", unavailable))
|
|
44
|
+
};
|
|
45
|
+
})).handle("persistentPty.shutdown", Effect.fn(function* () {
|
|
46
|
+
yield* pty.shutdown().pipe(mapUnavailable);
|
|
47
|
+
return HttpApiSchema.NoContent.make();
|
|
48
|
+
})).handle("persistentPty.handoff", Effect.fn(function* () {
|
|
49
|
+
return { handoff: yield* pty.handoff().pipe(mapUnavailable) };
|
|
50
|
+
})).handle("persistentPty.get", Effect.fn(function* (ctx) {
|
|
51
|
+
return { data: yield* pty.get(ctx.params.ptyID).pipe(mapTerminalError) };
|
|
52
|
+
})).handle("persistentPty.update", Effect.fn(function* (ctx) {
|
|
53
|
+
yield* pty.resize(ctx.params.ptyID, ctx.payload.size.cols, ctx.payload.size.rows, ctx.payload.attachmentID).pipe(mapTerminalError);
|
|
54
|
+
return { data: yield* pty.get(ctx.params.ptyID).pipe(mapTerminalError) };
|
|
55
|
+
})).handle("persistentPty.snapshot", Effect.fn(function* (ctx) {
|
|
56
|
+
return { data: yield* pty.snapshot(ctx.params.ptyID).pipe(mapTerminalError) };
|
|
57
|
+
})).handle("persistentPty.remove", Effect.fn(function* (ctx) {
|
|
58
|
+
yield* pty.remove(ctx.params.ptyID).pipe(mapTerminalError);
|
|
59
|
+
return HttpApiSchema.NoContent.make();
|
|
60
|
+
})).handle("persistentPty.connectToken", Effect.fn(function* (ctx) {
|
|
61
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
62
|
+
if (request.headers[PTY_CONNECT_TOKEN_HEADER] !== PTY_CONNECT_TOKEN_HEADER_VALUE || !isAllowedRequestOrigin2(request.headers.origin, request.headers.host, cors))
|
|
63
|
+
return yield* new ForbiddenError({ message: "Invalid persistent PTY connect token request" });
|
|
64
|
+
yield* pty.get(ctx.params.ptyID).pipe(mapTerminalError);
|
|
65
|
+
return { data: yield* tickets.issue({ ptyID: ctx.params.ptyID }) };
|
|
66
|
+
})).handleRaw("persistentPty.connect", Effect.fn("PersistentPtyHandler.connect")(function* (ctx) {
|
|
67
|
+
const url = new URL(ctx.request.url, "http://localhost");
|
|
68
|
+
const ticket = url.searchParams.get(PTY_CONNECT_TICKET_QUERY);
|
|
69
|
+
if (ticket) {
|
|
70
|
+
const valid = isAllowedRequestOrigin2(ctx.request.headers.origin, ctx.request.headers.host, cors) ? yield* tickets.consume({ ticket, ptyID: ctx.params.ptyID }) : false;
|
|
71
|
+
if (!valid)
|
|
72
|
+
return HttpServerResponse.empty({ status: 403 });
|
|
73
|
+
}
|
|
74
|
+
const cursor = Number(url.searchParams.get("cursor") ?? "0");
|
|
75
|
+
const role = url.searchParams.get("role") === "observer" ? "observer" : "controller";
|
|
76
|
+
const framedInput = url.searchParams.get("input_protocol") === "1";
|
|
77
|
+
const attachmentID = url.searchParams.get("attachment_id") ?? crypto.randomUUID();
|
|
78
|
+
if (!Number.isSafeInteger(cursor) || cursor < 0)
|
|
79
|
+
return HttpServerResponse.empty({ status: 400 });
|
|
80
|
+
const socket = yield* Effect.orDie(ctx.request.upgrade);
|
|
81
|
+
const write = yield* socket.writer;
|
|
82
|
+
const outbox = yield* Queue.unbounded();
|
|
83
|
+
const input = yield* Semaphore.make(1);
|
|
84
|
+
let attachment;
|
|
85
|
+
const onOpen = Effect.gen(function* () {
|
|
86
|
+
attachment = yield* pty.attach(ctx.params.ptyID, {
|
|
87
|
+
cursor,
|
|
88
|
+
attachmentID,
|
|
89
|
+
role,
|
|
90
|
+
takeover: url.searchParams.get("takeover") === "true",
|
|
91
|
+
onEvent: (event) => {
|
|
92
|
+
if (event.type === "output")
|
|
93
|
+
Queue.offerUnsafe(outbox, event.data);
|
|
94
|
+
if (event.type === "resized")
|
|
95
|
+
Queue.offerUnsafe(outbox, JSON.stringify({ ...event, checkpoint: Buffer.from(event.checkpoint).toString("base64") }));
|
|
96
|
+
if (event.type !== "output" && event.type !== "resized")
|
|
97
|
+
Queue.offerUnsafe(outbox, JSON.stringify(event));
|
|
98
|
+
},
|
|
99
|
+
onEnd: () => Queue.offerUnsafe(outbox, new Socket.CloseEvent(1000))
|
|
100
|
+
}).pipe(Effect.catchTags({
|
|
101
|
+
"PersistentPty.NotFoundError": () => Effect.succeed(undefined),
|
|
102
|
+
"PersistentPty.UnavailableError": () => Effect.succeed(undefined)
|
|
103
|
+
}));
|
|
104
|
+
if (!attachment) {
|
|
105
|
+
Queue.offerUnsafe(outbox, new Socket.CloseEvent(4404, "terminal unavailable"));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
Queue.offerUnsafe(outbox, JSON.stringify({
|
|
109
|
+
type: "attached",
|
|
110
|
+
attachmentID,
|
|
111
|
+
inputProtocol: framedInput ? 1 : 0,
|
|
112
|
+
info: attachment.info,
|
|
113
|
+
role: attachment.role,
|
|
114
|
+
generation: attachment.generation,
|
|
115
|
+
replay: {
|
|
116
|
+
requestedOffset: attachment.replay.requestedOffset,
|
|
117
|
+
availableOffset: attachment.replay.availableOffset,
|
|
118
|
+
endOffset: attachment.replay.endOffset,
|
|
119
|
+
truncated: attachment.replay.truncated
|
|
120
|
+
}
|
|
121
|
+
}));
|
|
122
|
+
if (attachment.replay.data.length > 0)
|
|
123
|
+
Queue.offerUnsafe(outbox, attachment.replay.data);
|
|
124
|
+
Queue.offerUnsafe(outbox, JSON.stringify({ type: "replay_complete", endOffset: attachment.replay.endOffset }));
|
|
125
|
+
attachment.activate();
|
|
126
|
+
});
|
|
127
|
+
const drain = Effect.gen(function* () {
|
|
128
|
+
while (true) {
|
|
129
|
+
const item = yield* Queue.take(outbox);
|
|
130
|
+
yield* write(item);
|
|
131
|
+
if (item instanceof Socket.CloseEvent)
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
yield* runPtySocket2(drain, socket.runRaw((message) => input.withPermit(Effect.suspend(() => {
|
|
136
|
+
if (!attachment)
|
|
137
|
+
return Effect.void;
|
|
138
|
+
const data = typeof message === "string" ? Buffer.from(message) : message;
|
|
139
|
+
if (!framedInput)
|
|
140
|
+
return pty.input(ctx.params.ptyID, attachmentID, attachment.info.size.cols, attachment.info.size.rows, data).pipe(Effect.ignore);
|
|
141
|
+
if (data.byteLength < 5)
|
|
142
|
+
return Effect.void;
|
|
143
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
144
|
+
const type = data[0];
|
|
145
|
+
const cols = view.getUint16(1);
|
|
146
|
+
const rows = view.getUint16(3);
|
|
147
|
+
if (type !== 0 && type !== 1 || cols === 0 || rows === 0)
|
|
148
|
+
return Effect.void;
|
|
149
|
+
if (type === 0)
|
|
150
|
+
return pty.control(ctx.params.ptyID, attachmentID, cols, rows).pipe(Effect.ignore);
|
|
151
|
+
return pty.input(ctx.params.ptyID, attachmentID, cols, rows, data.subarray(5)).pipe(Effect.ignore);
|
|
152
|
+
})), { onOpen }), () => attachment?.detach()).pipe(Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.orDie);
|
|
153
|
+
return HttpServerResponse.empty();
|
|
154
|
+
}));
|
|
155
|
+
}));
|
|
156
|
+
var mapUnavailable = (effect) => effect.pipe(Effect.catchTag("PersistentPty.UnavailableError", unavailable));
|
|
157
|
+
var mapTerminalError = (effect) => effect.pipe(Effect.catchTags({
|
|
158
|
+
"PersistentPty.NotFoundError": (error) => new PtyNotFoundError({ ptyID: error.ptyID, message: `PTY session not found: ${error.ptyID}` }),
|
|
159
|
+
"PersistentPty.UnavailableError": unavailable
|
|
160
|
+
}));
|
|
161
|
+
var unavailable = (error) => new ServiceUnavailableError({ message: error.message, service: "opencode-pty" });
|
|
162
|
+
|
|
163
|
+
export { PersistentPtyHandler2 };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Api2
|
|
3
|
+
} from "./auth-z6kg9h7e.js";
|
|
4
|
+
|
|
5
|
+
// src/handlers/rpc.ts
|
|
6
|
+
import { Rpc } from "@opencode/core/rpc";
|
|
7
|
+
import { Plugin } from "@opencode/core/plugin";
|
|
8
|
+
import { RpcError, RpcInternalError } from "@opencode/protocol/errors";
|
|
9
|
+
import { Effect } from "effect";
|
|
10
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
11
|
+
var RpcHandler2 = HttpApiBuilder.group(Api2, "server.rpc", (handlers) => handlers.handle("rpc.call", ({ params, payload }) => Effect.gen(function* () {
|
|
12
|
+
yield* Plugin.awaitActivation;
|
|
13
|
+
const rpc = yield* Rpc.Service;
|
|
14
|
+
const output = yield* rpc.call(params.rpcID, params.method, payload.input);
|
|
15
|
+
return output === undefined ? {} : { output };
|
|
16
|
+
}).pipe(Effect.mapError((error) => error.type === "rpc.invalid_output" || error.type === "rpc.internal" ? new RpcInternalError({ type: error.type, message: error.message }) : new RpcError({
|
|
17
|
+
type: error.type,
|
|
18
|
+
message: error.message,
|
|
19
|
+
...error.data === undefined ? {} : { data: error.data }
|
|
20
|
+
})), Effect.catchDefect((defect) => Effect.logError("rpc call failed", { rpc: params.rpcID, method: params.method, defect }).pipe(Effect.andThen(Effect.fail(new RpcInternalError({ type: "rpc.internal", message: "RPC call failed" }))))))));
|
|
21
|
+
|
|
22
|
+
export { RpcHandler2 };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sessionInfo2
|
|
3
|
+
} from "./auth-0ar9gf7q.js";
|
|
4
|
+
|
|
5
|
+
// src/middleware/session-location.ts
|
|
6
|
+
import { Instance } from "@opencode/core/instance/service";
|
|
7
|
+
import { Session } from "@opencode/core/session";
|
|
8
|
+
import { Effect, Layer } from "effect";
|
|
9
|
+
import { HttpRouter } from "effect/unstable/http";
|
|
10
|
+
import { HttpApiMiddleware } from "effect/unstable/httpapi";
|
|
11
|
+
import { InvalidRequestError, SessionNotFoundError } from "@opencode/protocol/errors";
|
|
12
|
+
class SessionLocationMiddleware2 extends HttpApiMiddleware.Service()("@opencode/HttpApiSessionLocation", {
|
|
13
|
+
error: [InvalidRequestError, SessionNotFoundError]
|
|
14
|
+
}) {
|
|
15
|
+
}
|
|
16
|
+
var sessionLocationLayer2 = Layer.effect(SessionLocationMiddleware2, Effect.gen(function* () {
|
|
17
|
+
const sessions = yield* Session.Service;
|
|
18
|
+
const instances = yield* Instance.Service;
|
|
19
|
+
return SessionLocationMiddleware2.of((effect) => Effect.gen(function* () {
|
|
20
|
+
const route = yield* HttpRouter.RouteContext;
|
|
21
|
+
const session = yield* sessionInfo2(sessions, route.params.sessionID);
|
|
22
|
+
return yield* effect.pipe(instances.provide(session));
|
|
23
|
+
}));
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
export { SessionLocationMiddleware2, sessionLocationLayer2 };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
response2
|
|
3
|
+
} from "./auth-0ar9gf7q.js";
|
|
4
|
+
import {
|
|
5
|
+
Api2
|
|
6
|
+
} from "./auth-z6kg9h7e.js";
|
|
7
|
+
|
|
8
|
+
// src/handlers/skill.ts
|
|
9
|
+
import { Skill } from "@opencode/core/skill";
|
|
10
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
11
|
+
var SkillHandler2 = HttpApiBuilder.group(Api2, "server.skill", (handlers) => handlers.handle("skill.list", () => response2(Skill.Service.use((skill) => skill.list()))));
|
|
12
|
+
|
|
13
|
+
export { SkillHandler2 };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import {
|
|
2
|
+
response2
|
|
3
|
+
} from "./auth-0ar9gf7q.js";
|
|
4
|
+
import {
|
|
5
|
+
Api2
|
|
6
|
+
} from "./auth-z6kg9h7e.js";
|
|
7
|
+
import {
|
|
8
|
+
CorsConfig2,
|
|
9
|
+
isAllowedRequestOrigin2
|
|
10
|
+
} from "./auth-q4bn6dy8.js";
|
|
11
|
+
import {
|
|
12
|
+
Service2
|
|
13
|
+
} from "./auth-bkk2wfbz.js";
|
|
14
|
+
import {
|
|
15
|
+
runPtySocket2
|
|
16
|
+
} from "./auth-hezj1jdf.js";
|
|
17
|
+
|
|
18
|
+
// src/handlers/pty.ts
|
|
19
|
+
import { Pty } from "@opencode/core/pty";
|
|
20
|
+
import { PtyProtocol } from "@opencode/core/pty/protocol";
|
|
21
|
+
import { PtyTicket } from "@opencode/core/pty/ticket";
|
|
22
|
+
import { Location } from "@opencode/core/location";
|
|
23
|
+
import { Effect, Queue } from "effect";
|
|
24
|
+
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
25
|
+
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
|
|
26
|
+
import { Socket } from "effect/unstable/socket";
|
|
27
|
+
import { ForbiddenError, PtyNotFoundError } from "@opencode/protocol/errors";
|
|
28
|
+
import {
|
|
29
|
+
PTY_CONNECT_TICKET_QUERY,
|
|
30
|
+
PTY_CONNECT_TOKEN_HEADER,
|
|
31
|
+
PTY_CONNECT_TOKEN_HEADER_VALUE
|
|
32
|
+
} from "@opencode/protocol/groups/pty";
|
|
33
|
+
var ticketScope = Effect.gen(function* () {
|
|
34
|
+
const location = yield* Location.Service;
|
|
35
|
+
return { directory: location.directory, workspaceID: location.workspaceID };
|
|
36
|
+
});
|
|
37
|
+
var PtyHandler2 = HttpApiBuilder.group(Api2, "server.pty", (handlers) => Effect.gen(function* () {
|
|
38
|
+
const tickets = yield* PtyTicket.Service;
|
|
39
|
+
const cors = yield* CorsConfig2;
|
|
40
|
+
const environment = yield* Service2;
|
|
41
|
+
return handlers.handle("pty.list", Effect.fn(function* () {
|
|
42
|
+
const pty = yield* Pty.Service;
|
|
43
|
+
return yield* response2(pty.list());
|
|
44
|
+
})).handle("pty.create", Effect.fn(function* (ctx) {
|
|
45
|
+
const pty = yield* Pty.Service;
|
|
46
|
+
const location = yield* Location.Service;
|
|
47
|
+
const cwd = ctx.payload.cwd || location.directory;
|
|
48
|
+
return yield* response2(pty.create({
|
|
49
|
+
...ctx.payload,
|
|
50
|
+
args: ctx.payload.args ? [...ctx.payload.args] : undefined,
|
|
51
|
+
cwd,
|
|
52
|
+
env: {
|
|
53
|
+
...ctx.payload.env,
|
|
54
|
+
...yield* environment.get({ directory: location.directory, cwd })
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
})).handle("pty.get", Effect.fn(function* (ctx) {
|
|
58
|
+
const pty = yield* Pty.Service;
|
|
59
|
+
return yield* response2(pty.get(ctx.params.ptyID).pipe(Effect.catchTag("Pty.NotFoundError", () => new PtyNotFoundError({
|
|
60
|
+
ptyID: ctx.params.ptyID,
|
|
61
|
+
message: `PTY session not found: ${ctx.params.ptyID}`
|
|
62
|
+
}))));
|
|
63
|
+
})).handle("pty.update", Effect.fn(function* (ctx) {
|
|
64
|
+
const pty = yield* Pty.Service;
|
|
65
|
+
return yield* response2(pty.update(ctx.params.ptyID, {
|
|
66
|
+
...ctx.payload,
|
|
67
|
+
size: ctx.payload.size ? { ...ctx.payload.size } : undefined
|
|
68
|
+
}).pipe(Effect.catchTag("Pty.NotFoundError", () => new PtyNotFoundError({
|
|
69
|
+
ptyID: ctx.params.ptyID,
|
|
70
|
+
message: `PTY session not found: ${ctx.params.ptyID}`
|
|
71
|
+
}))));
|
|
72
|
+
})).handle("pty.remove", Effect.fn(function* (ctx) {
|
|
73
|
+
const pty = yield* Pty.Service;
|
|
74
|
+
yield* pty.remove(ctx.params.ptyID).pipe(Effect.catchTag("Pty.NotFoundError", () => new PtyNotFoundError({
|
|
75
|
+
ptyID: ctx.params.ptyID,
|
|
76
|
+
message: `PTY session not found: ${ctx.params.ptyID}`
|
|
77
|
+
})));
|
|
78
|
+
return HttpApiSchema.NoContent.make();
|
|
79
|
+
})).handle("pty.connectToken", Effect.fn(function* (ctx) {
|
|
80
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
81
|
+
if (request.headers[PTY_CONNECT_TOKEN_HEADER] !== PTY_CONNECT_TOKEN_HEADER_VALUE || !isAllowedRequestOrigin2(request.headers.origin, request.headers.host, cors))
|
|
82
|
+
return yield* new ForbiddenError({ message: "Invalid PTY connect token request" });
|
|
83
|
+
const pty = yield* Pty.Service;
|
|
84
|
+
yield* pty.get(ctx.params.ptyID).pipe(Effect.catchTag("Pty.NotFoundError", () => new PtyNotFoundError({
|
|
85
|
+
ptyID: ctx.params.ptyID,
|
|
86
|
+
message: `PTY session not found: ${ctx.params.ptyID}`
|
|
87
|
+
})));
|
|
88
|
+
return yield* response2(tickets.issue({ ptyID: ctx.params.ptyID, ...yield* ticketScope }));
|
|
89
|
+
})).handleRaw("pty.connect", Effect.fn("PtyHandler.connect")(function* (ctx) {
|
|
90
|
+
const pty = yield* Pty.Service;
|
|
91
|
+
const exists = yield* pty.get(ctx.params.ptyID).pipe(Effect.as(true), Effect.catchTag("Pty.NotFoundError", () => Effect.succeed(false)));
|
|
92
|
+
if (!exists)
|
|
93
|
+
return HttpServerResponse.empty({ status: 404 });
|
|
94
|
+
const url = new URL(ctx.request.url, "http://localhost");
|
|
95
|
+
const ticket = url.searchParams.get(PTY_CONNECT_TICKET_QUERY);
|
|
96
|
+
if (ticket) {
|
|
97
|
+
const valid = isAllowedRequestOrigin2(ctx.request.headers.origin, ctx.request.headers.host, cors) ? yield* tickets.consume({ ticket, ptyID: ctx.params.ptyID, ...yield* ticketScope }) : false;
|
|
98
|
+
if (!valid)
|
|
99
|
+
return HttpServerResponse.empty({ status: 403 });
|
|
100
|
+
}
|
|
101
|
+
const parsedCursor = url.searchParams.get("cursor");
|
|
102
|
+
const cursorNumber = parsedCursor === null ? undefined : Number(parsedCursor);
|
|
103
|
+
const cursor = cursorNumber !== undefined && Number.isSafeInteger(cursorNumber) && cursorNumber >= -1 ? cursorNumber : undefined;
|
|
104
|
+
const socket = yield* Effect.orDie(ctx.request.upgrade);
|
|
105
|
+
const write = yield* socket.writer;
|
|
106
|
+
const closeAccepted = (event) => socket.runRaw(() => Effect.void, { onOpen: write(event).pipe(Effect.catch(() => Effect.void)) }).pipe(Effect.timeout("1 second"), Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.catch(() => Effect.void));
|
|
107
|
+
const outbox = yield* Queue.unbounded();
|
|
108
|
+
const attachment = yield* pty.attach(ctx.params.ptyID, {
|
|
109
|
+
cursor,
|
|
110
|
+
onData: (chunk) => Queue.offerUnsafe(outbox, chunk),
|
|
111
|
+
onEnd: () => Queue.offerUnsafe(outbox, new Socket.CloseEvent(1000))
|
|
112
|
+
}).pipe(Effect.catchTags({
|
|
113
|
+
"Pty.NotFoundError": () => closeAccepted(new Socket.CloseEvent(4404, "session not found")).pipe(Effect.as(undefined)),
|
|
114
|
+
"Pty.ExitedError": () => closeAccepted(new Socket.CloseEvent(4404, "session exited")).pipe(Effect.as(undefined))
|
|
115
|
+
}));
|
|
116
|
+
if (!attachment)
|
|
117
|
+
return HttpServerResponse.empty();
|
|
118
|
+
for (const chunk of PtyProtocol.chunks(attachment.replay))
|
|
119
|
+
Queue.offerUnsafe(outbox, chunk);
|
|
120
|
+
Queue.offerUnsafe(outbox, PtyProtocol.metaFrame(attachment.cursor));
|
|
121
|
+
attachment.activate();
|
|
122
|
+
const drain = Effect.gen(function* () {
|
|
123
|
+
while (true) {
|
|
124
|
+
const item = yield* Queue.take(outbox);
|
|
125
|
+
yield* write(item);
|
|
126
|
+
if (item instanceof Socket.CloseEvent)
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
yield* runPtySocket2(drain, socket.runRaw((message) => {
|
|
131
|
+
const decoded = PtyProtocol.decodeInput(message);
|
|
132
|
+
if (decoded !== undefined)
|
|
133
|
+
attachment.write(decoded);
|
|
134
|
+
}), attachment.detach).pipe(Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.orDie);
|
|
135
|
+
return HttpServerResponse.empty();
|
|
136
|
+
}));
|
|
137
|
+
}));
|
|
138
|
+
|
|
139
|
+
export { PtyHandler2 };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
missingSession2,
|
|
3
|
+
failedMessageDecode2
|
|
4
|
+
} from "./auth-smaf4a18.js";
|
|
5
|
+
import {
|
|
6
|
+
Api2
|
|
7
|
+
} from "./auth-z6kg9h7e.js";
|
|
8
|
+
|
|
9
|
+
// src/handlers/message.ts
|
|
10
|
+
import { SessionMessage } from "@opencode/core/session/message";
|
|
11
|
+
import { Session } from "@opencode/core/session";
|
|
12
|
+
import { Effect, Schema } from "effect";
|
|
13
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
14
|
+
import { InvalidCursorError } from "@opencode/protocol/errors";
|
|
15
|
+
var DefaultMessagesLimit = 50;
|
|
16
|
+
var Cursor = Schema.Struct({
|
|
17
|
+
id: SessionMessage.ID,
|
|
18
|
+
order: Schema.Union([Schema.Literal("asc"), Schema.Literal("desc")]),
|
|
19
|
+
direction: Schema.Union([Schema.Literal("previous"), Schema.Literal("next")])
|
|
20
|
+
});
|
|
21
|
+
var decodeCursor = Schema.decodeUnknownSync(Cursor);
|
|
22
|
+
var cursor = {
|
|
23
|
+
encode(message, order, direction) {
|
|
24
|
+
return Buffer.from(JSON.stringify({ id: message.id, order, direction })).toString("base64url");
|
|
25
|
+
},
|
|
26
|
+
decode(input) {
|
|
27
|
+
return decodeCursor(JSON.parse(Buffer.from(input, "base64url").toString("utf8")));
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var MessageHandler2 = HttpApiBuilder.group(Api2, "server.message", (handlers) => Effect.gen(function* () {
|
|
31
|
+
const session = yield* Session.Service;
|
|
32
|
+
return handlers.handle("session.messages", Effect.fn(function* (ctx) {
|
|
33
|
+
if (ctx.query.cursor && ctx.query.order !== undefined)
|
|
34
|
+
return yield* new InvalidCursorError({ message: "Cursor cannot be combined with order" });
|
|
35
|
+
const decoded = yield* Effect.try({
|
|
36
|
+
try: () => ctx.query.cursor ? cursor.decode(ctx.query.cursor) : undefined,
|
|
37
|
+
catch: () => new InvalidCursorError({ message: "Invalid cursor" })
|
|
38
|
+
});
|
|
39
|
+
const order = decoded?.order ?? ctx.query.order ?? "desc";
|
|
40
|
+
const messages = yield* session.messages({
|
|
41
|
+
sessionID: ctx.params.sessionID,
|
|
42
|
+
limit: ctx.query.limit ?? DefaultMessagesLimit,
|
|
43
|
+
order,
|
|
44
|
+
type: ctx.query.type,
|
|
45
|
+
cursor: decoded ? { id: decoded.id, direction: decoded.direction } : undefined
|
|
46
|
+
}).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.MessageDecodeError", failedMessageDecode2));
|
|
47
|
+
const first = messages[0];
|
|
48
|
+
const last = messages.at(-1);
|
|
49
|
+
return {
|
|
50
|
+
data: messages,
|
|
51
|
+
cursor: {
|
|
52
|
+
previous: first ? cursor.encode(first, order, "previous") : undefined,
|
|
53
|
+
next: last ? cursor.encode(last, order, "next") : undefined
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}));
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
export { MessageHandler2 };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__export
|
|
3
|
+
} from "./auth-9rqn6x4v.js";
|
|
4
|
+
|
|
5
|
+
// src/server-info.ts
|
|
6
|
+
var exports_server_info = {};
|
|
7
|
+
__export(exports_server_info, {
|
|
8
|
+
ServerInfo: () => exports_server_info,
|
|
9
|
+
Service: () => Service4,
|
|
10
|
+
connectionURLs: () => connectionURLs2,
|
|
11
|
+
layer: () => layer4
|
|
12
|
+
});
|
|
13
|
+
import { Context, Layer } from "effect";
|
|
14
|
+
import { networkInterfaces } from "node:os";
|
|
15
|
+
|
|
16
|
+
class Service4 extends Context.Service()("@opencode/server/ServerInfo") {
|
|
17
|
+
}
|
|
18
|
+
function layer4(urls, tmp, app = {}) {
|
|
19
|
+
return Layer.succeed(Service4, Service4.of({ urls, app, paths: { tmp } }));
|
|
20
|
+
}
|
|
21
|
+
function connectionURLs2(value, requestedHostname) {
|
|
22
|
+
const url = new URL(value);
|
|
23
|
+
const hostname = requestedHostname ?? url.hostname;
|
|
24
|
+
const family = hostname === "0.0.0.0" ? "IPv4" : hostname === "::" || hostname === "[::]" ? "IPv6" : undefined;
|
|
25
|
+
if (family === undefined)
|
|
26
|
+
return [value];
|
|
27
|
+
return [
|
|
28
|
+
...new Set(Object.values(networkInterfaces()).flatMap((entries) => entries ?? []).filter((entry) => !entry.internal && entry.family === family).map((entry) => {
|
|
29
|
+
const result = new URL(value);
|
|
30
|
+
result.hostname = family === "IPv6" ? `[${entry.address}]` : entry.address;
|
|
31
|
+
return result.toString().replace(/\/$/, "");
|
|
32
|
+
}))
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { Service4, layer4, connectionURLs2, exports_server_info };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
response2
|
|
3
|
+
} from "./auth-0ar9gf7q.js";
|
|
4
|
+
import {
|
|
5
|
+
Api2
|
|
6
|
+
} from "./auth-z6kg9h7e.js";
|
|
7
|
+
|
|
8
|
+
// src/handlers/websearch.ts
|
|
9
|
+
import { WebSearch } from "@opencode/core/websearch";
|
|
10
|
+
import { InvalidRequestError, ServiceUnavailableError } from "@opencode/protocol/errors";
|
|
11
|
+
import { Effect } from "effect";
|
|
12
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
13
|
+
var WebSearchHandler2 = HttpApiBuilder.group(Api2, "server.websearch", (handlers) => Effect.gen(function* () {
|
|
14
|
+
return handlers.handle("websearch.providers", Effect.fn("server.websearch.providers")(function* () {
|
|
15
|
+
const websearch = yield* WebSearch.Service;
|
|
16
|
+
return yield* response2(websearch.providers());
|
|
17
|
+
})).handle("websearch.query", Effect.fn("server.websearch.query")(function* (request) {
|
|
18
|
+
const websearch = yield* WebSearch.Service;
|
|
19
|
+
return yield* response2(websearch.query(request.payload).pipe(Effect.catchTags({
|
|
20
|
+
"WebSearch.ProviderRequired": () => new InvalidRequestError({
|
|
21
|
+
message: "Web search provider is required",
|
|
22
|
+
kind: "websearch_provider_required",
|
|
23
|
+
field: "providerID"
|
|
24
|
+
}),
|
|
25
|
+
"WebSearch.ProviderNotFound": (error) => new InvalidRequestError({
|
|
26
|
+
message: `Web search provider not found: ${error.providerID}`,
|
|
27
|
+
kind: "websearch_provider_not_found",
|
|
28
|
+
field: "providerID"
|
|
29
|
+
}),
|
|
30
|
+
"WebSearch.Disabled": () => new InvalidRequestError({ message: "Web search is disabled", kind: "websearch_disabled" }),
|
|
31
|
+
"WebSearch.Request": (error) => new ServiceUnavailableError({
|
|
32
|
+
message: `Web search request failed: ${error.providerID}`,
|
|
33
|
+
service: error.providerID
|
|
34
|
+
})
|
|
35
|
+
})));
|
|
36
|
+
}));
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
export { WebSearchHandler2 };
|