@mercury-fw/channel-http 0.12.0 → 0.13.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/CHANGELOG.md +13 -0
- package/README.md +9 -3
- package/dist/http-provider.d.ts +2 -0
- package/dist/http-server.d.ts +6 -4
- package/dist/index.d.ts +1 -1
- package/http-provider.ts +3 -0
- package/http-server.ts +20 -4
- package/index.ts +2 -1
- package/openapi.yaml +22 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @mercury-fw/channel-http
|
|
2
2
|
|
|
3
|
+
## 0.13.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f631dd5: README: a link to the package's page on Mercury's documentation site (https://lucabro81.github.io/mercury-fw/), published from this release on. The HTTP channel's README points to the HTTP API reference there, and the core's memory section to the page that explains it.
|
|
8
|
+
|
|
9
|
+
## 0.13.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 7c9a038: - `GET /version` answers the framework's version (`{ ok: true, version: "0.59.0" }`) with no token, for a UI to show which Mercury it's talking to.
|
|
14
|
+
- The channel now needs the framework at 0.59 or later (peer range `>=0.59.0 <1.0.0`), the first whose core gives channels its version.
|
|
15
|
+
|
|
3
16
|
## 0.12.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Gives a [Mercury](https://github.com/lucabro81/mercury-fw) agent an HTTP surface to build a custom UI on: one conversational turn per request, streamed back as Server-Sent Events, plus confirmation and read-only routes over what the agent holds (conversations, the wiki, memory, its plugins).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
On Mercury's documentation site: [its page](https://lucabro81.github.io/mercury-fw/plugins/channel-http/).
|
|
6
|
+
|
|
7
|
+
This version is written for version 6 of the channel contract, the one that brings the channels' texts in the person's language, and needs the framework at 0.59 or later, the first whose core gives channels its version (`GET /version`). A core with an older contract skips it, and the log says why.
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
10
|
bun add @mercury-fw/channel-http
|
|
@@ -29,13 +31,13 @@ It needs an auth provider next to it, or several (`auth: [a, b]`, tried in order
|
|
|
29
31
|
|
|
30
32
|
It's active whenever it's declared in `mercury.config.ts`'s `channels` with an auth provider; remove it there to turn the surface off. It listens on `HTTP_SURFACE_PORT` (default `4100`). Base URL `http://<host>:<port>`.
|
|
31
33
|
|
|
32
|
-
**Authentication.** Every route except `GET /openapi.yaml`, `GET /login/callback` and the `OPTIONS` preflights needs `Authorization: Bearer <token>`, and the auth providers decide who the token belongs to: the first that recognizes it. A missing or refused token gets `401` with `WWW-Authenticate: Bearer` before anything runs. Then the core decides whether it talks to that person at all: someone the app's directory doesn't know gets `403` (unless the app lets unknown people in), and `503` when the directory can't be reached, both with `{ ok: false, error, reason }`, where `error` is what to tell them.
|
|
34
|
+
**Authentication.** Every route except `GET /openapi.yaml`, `GET /version`, `GET /login/callback` and the `OPTIONS` preflights needs `Authorization: Bearer <token>`, and the auth providers decide who the token belongs to: the first that recognizes it. A missing or refused token gets `401` with `WWW-Authenticate: Bearer` before anything runs. Then the core decides whether it talks to that person at all: someone the app's directory doesn't know gets `403` (unless the app lets unknown people in), and `503` when the directory can't be reached, both with `{ ok: false, error, reason }`, where `error` is what to tell them.
|
|
33
35
|
|
|
34
36
|
**Conversations belong to whoever opened them.** The session key is `<caller id>:<conversationId>`, so the same `conversationId` sent by someone else is a conversation of their own, and a confirmation token staged in your conversation can't be confirmed from theirs. Each authenticated caller also gets their own episodic memory and wiki area, as on Google Chat.
|
|
35
37
|
|
|
36
38
|
**CORS** is enabled on every response and every route answers an `OPTIONS` preflight, so a browser UI on another origin can call it. The allowed origin is `HTTP_SURFACE_CORS_ORIGIN` (default `*`: the token travels in a header, never in a cookie the browser would send on its own).
|
|
37
39
|
|
|
38
|
-
The full contract is described by an **OpenAPI document**, served raw at `GET /openapi.yaml` and published as
|
|
40
|
+
The full contract is described by an **OpenAPI document**, served raw at `GET /openapi.yaml` and published as [the HTTP API reference](https://lucabro81.github.io/mercury-fw/reference/http-api/) on the documentation site (see `packages/channels/channel-http/openapi.yaml`, the single source of truth).
|
|
39
41
|
|
|
40
42
|
All responses are JSON except `POST /turn`, which streams `text/event-stream`. Every JSON response is either `{ "ok": true, ... }` or, on error, `{ "ok": false, "error": "<message>" }` with HTTP `400`/`401`/`500`.
|
|
41
43
|
|
|
@@ -119,3 +121,7 @@ All `GET`, all JSON, all reporting state already held in-process. They need an a
|
|
|
119
121
|
| `GET /openapi.yaml` | the OpenAPI document for this surface (`text/yaml`) |
|
|
120
122
|
|
|
121
123
|
Conversation history and the conversation list are backed by the durable verbatim archive; they degrade to empty when the vector store is unreachable.
|
|
124
|
+
|
|
125
|
+
## `GET /version`
|
|
126
|
+
|
|
127
|
+
Which Mercury this is, for a UI to show: `{ ok: true, version }`, the framework's version as `major.minor.patch` (`"0.59.0"`), the one of `@mercury-fw/core`, not this channel's own. It needs no token.
|
package/dist/http-provider.d.ts
CHANGED
|
@@ -42,6 +42,8 @@ export type HttpProviderDeps = {
|
|
|
42
42
|
assistantName?: string;
|
|
43
43
|
/** The texts in each caller's language (`ctx.i18n`). */
|
|
44
44
|
i18n?: ChannelI18n;
|
|
45
|
+
/** The framework's version, served on `/version` (`ctx.frameworkVersion`). */
|
|
46
|
+
version?: string;
|
|
45
47
|
};
|
|
46
48
|
export declare function createHttpProvider(deps: HttpProviderDeps): Provider & {
|
|
47
49
|
stop(): Promise<void>;
|
package/dist/http-server.d.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* `/login/callback` is where a person's browser comes back after logging in to
|
|
16
16
|
* a service a plugin acts on as them; the single-use state is its credential.
|
|
17
17
|
*
|
|
18
|
-
* Every route but the OpenAPI document, the login callback and the CORS
|
|
18
|
+
* Every route but the OpenAPI document, `/version`, the login callback and the CORS
|
|
19
19
|
* preflights asks the injected `authenticate` (the auth provider the app declares) who is calling
|
|
20
20
|
* before anything runs, and answers 401 when nobody is. A conversation belongs
|
|
21
21
|
* to whoever opened it: the session key is `<principal.id>:<conversationId>`.
|
|
@@ -47,9 +47,9 @@ export type TurnRequestDeps = {
|
|
|
47
47
|
};
|
|
48
48
|
/**
|
|
49
49
|
* Serves the OpenAPI document that describes this surface — the single source
|
|
50
|
-
* of truth in this package's `openapi.yaml`, also rendered as the
|
|
51
|
-
* API
|
|
52
|
-
* tooling (Redoc, Swagger UI, Postman) reads YAML directly.
|
|
50
|
+
* of truth in this package's `openapi.yaml`, also rendered as the docs site's
|
|
51
|
+
* HTTP API reference. Served raw as `text/yaml` (no YAML parser needed at
|
|
52
|
+
* runtime); most tooling (Redoc, Swagger UI, Postman) reads YAML directly.
|
|
53
53
|
*/
|
|
54
54
|
export declare function openApiResponse(corsOrigin?: string): Response;
|
|
55
55
|
/**
|
|
@@ -157,6 +157,8 @@ export type HttpServerDeps = TurnRequestDeps & {
|
|
|
157
157
|
settings?: ChannelSettings;
|
|
158
158
|
/** What the pages people read call the assistant. */
|
|
159
159
|
assistantName?: string;
|
|
160
|
+
/** The framework's version; `/version` is mounted only with it. */
|
|
161
|
+
version?: string;
|
|
160
162
|
};
|
|
161
163
|
/** Starts the HTTP surface: `POST /turn` (4a) plus the read-only routes (4b)
|
|
162
164
|
* when `reads` is supplied. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The HTTP channel plugin: an opt-in conversational HTTP surface (SSE `/turn`,
|
|
3
|
-
* `/confirm`, read-only introspection routes, the OpenAPI doc) that a custom UI
|
|
3
|
+
* `/confirm`, read-only introspection routes, the OpenAPI doc, `/version`) that a custom UI
|
|
4
4
|
* calls. Exported as a `ChannelPlugin` the core's channel loader consumes; it
|
|
5
5
|
* does not import the app. Enabled by listing it in `mercury.config.ts` — there
|
|
6
6
|
* is no runtime inert condition (unlike Google Chat's subscription): if it's
|
package/http-provider.ts
CHANGED
|
@@ -39,6 +39,8 @@ export type HttpProviderDeps = {
|
|
|
39
39
|
assistantName?: string;
|
|
40
40
|
/** The texts in each caller's language (`ctx.i18n`). */
|
|
41
41
|
i18n?: ChannelI18n;
|
|
42
|
+
/** The framework's version, served on `/version` (`ctx.frameworkVersion`). */
|
|
43
|
+
version?: string;
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
export function createHttpProvider(deps: HttpProviderDeps): Provider & { stop(): Promise<void> } {
|
|
@@ -60,6 +62,7 @@ export function createHttpProvider(deps: HttpProviderDeps): Provider & { stop():
|
|
|
60
62
|
...(deps.resumeMaxChars === undefined ? {} : { resumeMaxChars: deps.resumeMaxChars }),
|
|
61
63
|
...(deps.assistantName === undefined ? {} : { assistantName: deps.assistantName }),
|
|
62
64
|
...(deps.i18n === undefined ? {} : { i18n: deps.i18n }),
|
|
65
|
+
...(deps.version === undefined ? {} : { version: deps.version }),
|
|
63
66
|
});
|
|
64
67
|
deps.logins?.accept(deps.logins.callbackUrl);
|
|
65
68
|
},
|
package/http-server.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* `/login/callback` is where a person's browser comes back after logging in to
|
|
16
16
|
* a service a plugin acts on as them; the single-use state is its credential.
|
|
17
17
|
*
|
|
18
|
-
* Every route but the OpenAPI document, the login callback and the CORS
|
|
18
|
+
* Every route but the OpenAPI document, `/version`, the login callback and the CORS
|
|
19
19
|
* preflights asks the injected `authenticate` (the auth provider the app declares) who is calling
|
|
20
20
|
* before anything runs, and answers 401 when nobody is. A conversation belongs
|
|
21
21
|
* to whoever opened it: the session key is `<principal.id>:<conversationId>`.
|
|
@@ -153,9 +153,9 @@ function preflight(origin: string): Response {
|
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
155
|
* Serves the OpenAPI document that describes this surface — the single source
|
|
156
|
-
* of truth in this package's `openapi.yaml`, also rendered as the
|
|
157
|
-
* API
|
|
158
|
-
* tooling (Redoc, Swagger UI, Postman) reads YAML directly.
|
|
156
|
+
* of truth in this package's `openapi.yaml`, also rendered as the docs site's
|
|
157
|
+
* HTTP API reference. Served raw as `text/yaml` (no YAML parser needed at
|
|
158
|
+
* runtime); most tooling (Redoc, Swagger UI, Postman) reads YAML directly.
|
|
159
159
|
*/
|
|
160
160
|
export function openApiResponse(corsOrigin = "*"): Response {
|
|
161
161
|
const file = Bun.file(new URL("./openapi.yaml", import.meta.url));
|
|
@@ -579,6 +579,19 @@ export function readRoutes(
|
|
|
579
579
|
};
|
|
580
580
|
}
|
|
581
581
|
|
|
582
|
+
/**
|
|
583
|
+
* `GET /version`: which Mercury this is (the framework's version), for any
|
|
584
|
+
* front end to show. Nobody is asked who they are, like `/openapi.yaml`.
|
|
585
|
+
*/
|
|
586
|
+
function versionRoutes(version: string, corsOrigin = "*"): Record<string, ReadRoute> {
|
|
587
|
+
return {
|
|
588
|
+
"/version": {
|
|
589
|
+
GET: () => Response.json({ ok: true, version }, { headers: corsHeaders(corsOrigin) }),
|
|
590
|
+
OPTIONS: () => preflight(corsOrigin),
|
|
591
|
+
},
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
|
|
582
595
|
export type HttpServerDeps = TurnRequestDeps & {
|
|
583
596
|
port: number;
|
|
584
597
|
reads?: ChannelHostReads;
|
|
@@ -592,6 +605,8 @@ export type HttpServerDeps = TurnRequestDeps & {
|
|
|
592
605
|
settings?: ChannelSettings;
|
|
593
606
|
/** What the pages people read call the assistant. */
|
|
594
607
|
assistantName?: string;
|
|
608
|
+
/** The framework's version; `/version` is mounted only with it. */
|
|
609
|
+
version?: string;
|
|
595
610
|
};
|
|
596
611
|
|
|
597
612
|
/** Starts the HTTP surface: `POST /turn` (4a) plus the read-only routes (4b)
|
|
@@ -623,6 +638,7 @@ export function startHttpServer(deps: HttpServerDeps): ReturnType<typeof Bun.ser
|
|
|
623
638
|
OPTIONS: () => preflight(origin),
|
|
624
639
|
},
|
|
625
640
|
"/openapi.yaml": { GET: () => openApiResponse(origin), OPTIONS: () => preflight(origin) },
|
|
641
|
+
...(deps.version === undefined ? {} : versionRoutes(deps.version, origin)),
|
|
626
642
|
...(deps.reads ? readRoutes(deps.reads, deps.authenticate, origin, deps.admit, deps.settings) : {}),
|
|
627
643
|
...(deps.completeLogin ? loginRoutes(deps.completeLogin, deps.assistantName, deps.i18n) : {}),
|
|
628
644
|
...(deps.linking ? linkRoutes({ ...deps, start: deps.linking.start, corsOrigin: origin }) : {}),
|
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The HTTP channel plugin: an opt-in conversational HTTP surface (SSE `/turn`,
|
|
3
|
-
* `/confirm`, read-only introspection routes, the OpenAPI doc) that a custom UI
|
|
3
|
+
* `/confirm`, read-only introspection routes, the OpenAPI doc, `/version`) that a custom UI
|
|
4
4
|
* calls. Exported as a `ChannelPlugin` the core's channel loader consumes; it
|
|
5
5
|
* does not import the app. Enabled by listing it in `mercury.config.ts` — there
|
|
6
6
|
* is no runtime inert condition (unlike Google Chat's subscription): if it's
|
|
@@ -51,6 +51,7 @@ export const httpChannel: ChannelPlugin = {
|
|
|
51
51
|
...(ctx.settings === undefined ? {} : { settings: ctx.settings }),
|
|
52
52
|
...(resumeMaxChars === undefined ? {} : { resumeMaxChars }),
|
|
53
53
|
...(ctx.assistantName === undefined ? {} : { assistantName: ctx.assistantName }),
|
|
54
|
+
...(ctx.frameworkVersion === undefined ? {} : { version: ctx.frameworkVersion }),
|
|
54
55
|
...(logins ? { logins: { callbackUrl: `${publicUrl}/login/callback`, accept: logins.accept, complete: logins.complete } } : {}),
|
|
55
56
|
});
|
|
56
57
|
},
|
package/openapi.yaml
CHANGED
|
@@ -14,7 +14,7 @@ info:
|
|
|
14
14
|
|
|
15
15
|
## Authentication
|
|
16
16
|
|
|
17
|
-
Every route except this document and the `OPTIONS` preflights needs
|
|
17
|
+
Every route except this document, `/version` and the `OPTIONS` preflights needs
|
|
18
18
|
`Authorization: Bearer <token>`. The app's auth provider decides what a
|
|
19
19
|
valid token is (an OpenID Connect access token, a static test token); a
|
|
20
20
|
missing or refused one gets `401` with `WWW-Authenticate: Bearer`, before
|
|
@@ -589,6 +589,27 @@ paths:
|
|
|
589
589
|
content:
|
|
590
590
|
text/plain:
|
|
591
591
|
schema: { type: string }
|
|
592
|
+
/version:
|
|
593
|
+
get:
|
|
594
|
+
summary: Which Mercury this is
|
|
595
|
+
description: >
|
|
596
|
+
The framework's version, `major.minor.patch`, for a UI to show. Needs
|
|
597
|
+
no bearer token.
|
|
598
|
+
security: []
|
|
599
|
+
responses:
|
|
600
|
+
"200":
|
|
601
|
+
description: The framework's version.
|
|
602
|
+
content:
|
|
603
|
+
application/json:
|
|
604
|
+
schema:
|
|
605
|
+
type: object
|
|
606
|
+
required: [ok, version]
|
|
607
|
+
properties:
|
|
608
|
+
ok: { type: boolean, const: true }
|
|
609
|
+
version:
|
|
610
|
+
type: string
|
|
611
|
+
pattern: '^\d+\.\d+\.\d+$'
|
|
612
|
+
examples: ["0.59.0"]
|
|
592
613
|
/openapi.yaml:
|
|
593
614
|
get:
|
|
594
615
|
summary: This OpenAPI document
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mercury-fw/channel-http",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
|
-
"@mercury-fw/channel-types": ">=0.
|
|
21
|
+
"@mercury-fw/channel-types": ">=0.59.0 <1.0.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@mercury-fw/channel-types": "0.
|
|
25
|
-
"@mercury-fw/plugin-types": "0.
|
|
24
|
+
"@mercury-fw/channel-types": "0.59.2",
|
|
25
|
+
"@mercury-fw/plugin-types": "0.59.2",
|
|
26
26
|
"@mercury-fw/typescript-config": "*",
|
|
27
27
|
"@types/bun": "^1.4.2",
|
|
28
28
|
"typescript": "^6.0.3"
|