@mercury-fw/channel-http 0.12.0 → 0.13.0
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 +7 -0
- package/README.md +6 -2
- package/dist/http-provider.d.ts +2 -0
- package/dist/http-server.d.ts +3 -1
- package/dist/index.d.ts +1 -1
- package/http-provider.ts +3 -0
- package/http-server.ts +17 -1
- package/index.ts +2 -1
- package/openapi.yaml +22 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @mercury-fw/channel-http
|
|
2
2
|
|
|
3
|
+
## 0.13.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 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.
|
|
8
|
+
- 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.
|
|
9
|
+
|
|
3
10
|
## 0.12.0
|
|
4
11
|
|
|
5
12
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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
|
-
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.
|
|
5
|
+
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
6
|
|
|
7
7
|
```bash
|
|
8
8
|
bun add @mercury-fw/channel-http
|
|
@@ -29,7 +29,7 @@ It needs an auth provider next to it, or several (`auth: [a, b]`, tried in order
|
|
|
29
29
|
|
|
30
30
|
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
31
|
|
|
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.
|
|
32
|
+
**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
33
|
|
|
34
34
|
**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
35
|
|
|
@@ -119,3 +119,7 @@ All `GET`, all JSON, all reporting state already held in-process. They need an a
|
|
|
119
119
|
| `GET /openapi.yaml` | the OpenAPI document for this surface (`text/yaml`) |
|
|
120
120
|
|
|
121
121
|
Conversation history and the conversation list are backed by the durable verbatim archive; they degrade to empty when the vector store is unreachable.
|
|
122
|
+
|
|
123
|
+
## `GET /version`
|
|
124
|
+
|
|
125
|
+
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>`.
|
|
@@ -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>`.
|
|
@@ -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.0",
|
|
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.0",
|
|
25
|
+
"@mercury-fw/plugin-types": "0.59.0",
|
|
26
26
|
"@mercury-fw/typescript-config": "*",
|
|
27
27
|
"@types/bun": "^1.4.2",
|
|
28
28
|
"typescript": "^6.0.3"
|