@procedures/client 0.8.0 → 0.9.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.
Files changed (197) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +95 -8
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/adapters/http/client/transport.d.ts +4 -0
  5. package/dist/adapters/http/client/transport.d.ts.map +1 -1
  6. package/dist/adapters/http/client/transport.js +11 -1
  7. package/dist/adapters/http/client/transport.js.map +1 -1
  8. package/dist/adapters/http/client/types.d.ts +19 -0
  9. package/dist/adapters/http/client/types.d.ts.map +1 -1
  10. package/dist/adapters/http/server/cors.d.ts +64 -0
  11. package/dist/adapters/http/server/cors.d.ts.map +1 -0
  12. package/dist/adapters/http/server/cors.js +113 -0
  13. package/dist/adapters/http/server/cors.js.map +1 -0
  14. package/dist/adapters/http/server/handler.d.ts +136 -0
  15. package/dist/adapters/http/server/handler.d.ts.map +1 -0
  16. package/dist/adapters/http/server/handler.js +495 -0
  17. package/dist/adapters/http/server/handler.js.map +1 -0
  18. package/dist/adapters/http/server/strategies.d.ts +14 -5
  19. package/dist/adapters/http/server/strategies.d.ts.map +1 -1
  20. package/dist/adapters/http/server/strategies.js.map +1 -1
  21. package/dist/adapters/http/server/transport.d.ts +30 -46
  22. package/dist/adapters/http/server/transport.d.ts.map +1 -1
  23. package/dist/adapters/http/server/transport.js +48 -432
  24. package/dist/adapters/http/server/transport.js.map +1 -1
  25. package/dist/adapters/http/server/types.d.ts +13 -0
  26. package/dist/adapters/http/server/types.d.ts.map +1 -1
  27. package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
  28. package/dist/adapters/websocket/client/transport.js +4 -12
  29. package/dist/adapters/websocket/client/transport.js.map +1 -1
  30. package/dist/adapters/websocket/server/transport.d.ts +46 -1
  31. package/dist/adapters/websocket/server/transport.d.ts.map +1 -1
  32. package/dist/adapters/websocket/server/transport.js +152 -15
  33. package/dist/adapters/websocket/server/transport.js.map +1 -1
  34. package/dist/adapters/websocket/server/types.d.ts +10 -3
  35. package/dist/adapters/websocket/server/types.d.ts.map +1 -1
  36. package/dist/adapters/websocket/server/upgrade-router.d.ts +28 -0
  37. package/dist/adapters/websocket/server/upgrade-router.d.ts.map +1 -0
  38. package/dist/adapters/websocket/server/upgrade-router.js +62 -0
  39. package/dist/adapters/websocket/server/upgrade-router.js.map +1 -0
  40. package/dist/adapters/websocket/server/upgrade.d.ts +68 -0
  41. package/dist/adapters/websocket/server/upgrade.d.ts.map +1 -0
  42. package/dist/adapters/websocket/server/upgrade.js +49 -0
  43. package/dist/adapters/websocket/server/upgrade.js.map +1 -0
  44. package/dist/adapters/websocket/shared/rpc.d.ts +2 -0
  45. package/dist/adapters/websocket/shared/rpc.d.ts.map +1 -1
  46. package/dist/adapters/websocket/shared/rpc.js +8 -2
  47. package/dist/adapters/websocket/shared/rpc.js.map +1 -1
  48. package/dist/browser.d.ts +12 -4
  49. package/dist/browser.d.ts.map +1 -1
  50. package/dist/browser.js +13 -2
  51. package/dist/browser.js.map +1 -1
  52. package/dist/client/client.d.ts +43 -0
  53. package/dist/client/client.d.ts.map +1 -1
  54. package/dist/client/client.js +69 -1
  55. package/dist/client/client.js.map +1 -1
  56. package/dist/events/publisher.d.ts +25 -1
  57. package/dist/events/publisher.d.ts.map +1 -1
  58. package/dist/events/publisher.js +66 -9
  59. package/dist/events/publisher.js.map +1 -1
  60. package/dist/events/rows.d.ts +31 -0
  61. package/dist/events/rows.d.ts.map +1 -0
  62. package/dist/events/rows.js +39 -0
  63. package/dist/events/rows.js.map +1 -0
  64. package/dist/index.d.ts +1 -1
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +1 -1
  67. package/dist/index.js.map +1 -1
  68. package/dist/node.d.ts +14 -0
  69. package/dist/node.d.ts.map +1 -1
  70. package/dist/node.js +9 -0
  71. package/dist/node.js.map +1 -1
  72. package/dist/procedures/capability.d.ts +6 -0
  73. package/dist/procedures/capability.d.ts.map +1 -1
  74. package/dist/procedures/capability.js +25 -0
  75. package/dist/procedures/capability.js.map +1 -1
  76. package/dist/procedures/collection/changes.d.ts +94 -0
  77. package/dist/procedures/collection/changes.d.ts.map +1 -0
  78. package/dist/procedures/collection/changes.js +182 -0
  79. package/dist/procedures/collection/changes.js.map +1 -0
  80. package/dist/procedures/collection/index.d.ts +10 -3
  81. package/dist/procedures/collection/index.d.ts.map +1 -1
  82. package/dist/procedures/collection/index.js +8 -1
  83. package/dist/procedures/collection/index.js.map +1 -1
  84. package/dist/procedures/collection/partition.d.ts +67 -0
  85. package/dist/procedures/collection/partition.d.ts.map +1 -0
  86. package/dist/procedures/collection/partition.js +82 -0
  87. package/dist/procedures/collection/partition.js.map +1 -0
  88. package/dist/procedures/collection/procedures.d.ts +39 -2
  89. package/dist/procedures/collection/procedures.d.ts.map +1 -1
  90. package/dist/procedures/collection/procedures.js +147 -44
  91. package/dist/procedures/collection/procedures.js.map +1 -1
  92. package/dist/procedures/collection/query.d.ts +246 -0
  93. package/dist/procedures/collection/query.d.ts.map +1 -0
  94. package/dist/procedures/collection/query.js +854 -0
  95. package/dist/procedures/collection/query.js.map +1 -0
  96. package/dist/procedures/collection/schemas.d.ts +50 -0
  97. package/dist/procedures/collection/schemas.d.ts.map +1 -1
  98. package/dist/procedures/collection/schemas.js +144 -6
  99. package/dist/procedures/collection/schemas.js.map +1 -1
  100. package/dist/procedures/collection/storage.d.ts +58 -6
  101. package/dist/procedures/collection/storage.d.ts.map +1 -1
  102. package/dist/procedures/collection/storage.js +23 -0
  103. package/dist/procedures/collection/storage.js.map +1 -1
  104. package/dist/procedures/elicit.d.ts +190 -0
  105. package/dist/procedures/elicit.d.ts.map +1 -0
  106. package/dist/procedures/elicit.js +127 -0
  107. package/dist/procedures/elicit.js.map +1 -0
  108. package/dist/procedures/hints.d.ts +43 -0
  109. package/dist/procedures/hints.d.ts.map +1 -0
  110. package/dist/procedures/hints.js +74 -0
  111. package/dist/procedures/hints.js.map +1 -0
  112. package/dist/procedures/index.d.ts +9 -2
  113. package/dist/procedures/index.d.ts.map +1 -1
  114. package/dist/procedures/index.js +5 -1
  115. package/dist/procedures/index.js.map +1 -1
  116. package/dist/procedures/invoke.d.ts +24 -2
  117. package/dist/procedures/invoke.d.ts.map +1 -1
  118. package/dist/procedures/invoke.js +14 -1
  119. package/dist/procedures/invoke.js.map +1 -1
  120. package/dist/procedures/progress.d.ts +24 -0
  121. package/dist/procedures/progress.d.ts.map +1 -0
  122. package/dist/procedures/progress.js +11 -0
  123. package/dist/procedures/progress.js.map +1 -0
  124. package/dist/procedures/registry.d.ts.map +1 -1
  125. package/dist/procedures/registry.js +5 -0
  126. package/dist/procedures/registry.js.map +1 -1
  127. package/dist/procedures/types.d.ts +55 -0
  128. package/dist/procedures/types.d.ts.map +1 -1
  129. package/dist/procedures/types.js.map +1 -1
  130. package/dist/procedures/untrusted.d.ts +28 -0
  131. package/dist/procedures/untrusted.d.ts.map +1 -0
  132. package/dist/procedures/untrusted.js +32 -0
  133. package/dist/procedures/untrusted.js.map +1 -0
  134. package/dist/server/browser-guard.d.ts +12 -2
  135. package/dist/server/browser-guard.d.ts.map +1 -1
  136. package/dist/server/browser-guard.js +43 -6
  137. package/dist/server/browser-guard.js.map +1 -1
  138. package/dist/server/host-policy.d.ts +10 -1
  139. package/dist/server/host-policy.d.ts.map +1 -1
  140. package/dist/server/host-policy.js +5 -0
  141. package/dist/server/host-policy.js.map +1 -1
  142. package/dist/server/index.d.ts +1 -1
  143. package/dist/server/index.d.ts.map +1 -1
  144. package/dist/server/index.js.map +1 -1
  145. package/dist/server/procedure-server.d.ts +68 -7
  146. package/dist/server/procedure-server.d.ts.map +1 -1
  147. package/dist/server/procedure-server.js +124 -24
  148. package/dist/server/procedure-server.js.map +1 -1
  149. package/dist/server/request-auth.d.ts +51 -4
  150. package/dist/server/request-auth.d.ts.map +1 -1
  151. package/dist/server/request-auth.js +116 -5
  152. package/dist/server/request-auth.js.map +1 -1
  153. package/dist/server/types.d.ts +73 -5
  154. package/dist/server/types.d.ts.map +1 -1
  155. package/dist/server/types.js.map +1 -1
  156. package/package.json +7 -3
  157. package/src/adapters/http/client/transport.ts +11 -1
  158. package/src/adapters/http/client/types.ts +22 -0
  159. package/src/adapters/http/server/cors.ts +144 -0
  160. package/src/adapters/http/server/handler.ts +624 -0
  161. package/src/adapters/http/server/strategies.ts +16 -6
  162. package/src/adapters/http/server/transport.ts +55 -478
  163. package/src/adapters/http/server/types.ts +15 -0
  164. package/src/adapters/websocket/client/transport.ts +4 -12
  165. package/src/adapters/websocket/server/transport.ts +166 -16
  166. package/src/adapters/websocket/server/types.ts +11 -3
  167. package/src/adapters/websocket/server/upgrade-router.ts +77 -0
  168. package/src/adapters/websocket/server/upgrade.ts +88 -0
  169. package/src/adapters/websocket/shared/rpc.ts +9 -2
  170. package/src/browser.ts +85 -2
  171. package/src/client/client.ts +83 -1
  172. package/src/events/publisher.ts +75 -11
  173. package/src/events/rows.ts +48 -0
  174. package/src/index.ts +1 -1
  175. package/src/node.ts +21 -0
  176. package/src/procedures/capability.ts +21 -0
  177. package/src/procedures/collection/changes.ts +245 -0
  178. package/src/procedures/collection/index.ts +57 -1
  179. package/src/procedures/collection/partition.ts +123 -0
  180. package/src/procedures/collection/procedures.ts +206 -51
  181. package/src/procedures/collection/query.ts +1009 -0
  182. package/src/procedures/collection/schemas.ts +196 -7
  183. package/src/procedures/collection/storage.ts +78 -6
  184. package/src/procedures/elicit.ts +320 -0
  185. package/src/procedures/hints.ts +91 -0
  186. package/src/procedures/index.ts +83 -2
  187. package/src/procedures/invoke.ts +33 -2
  188. package/src/procedures/progress.ts +25 -0
  189. package/src/procedures/registry.ts +4 -0
  190. package/src/procedures/types.ts +65 -0
  191. package/src/procedures/untrusted.ts +50 -0
  192. package/src/server/browser-guard.ts +48 -6
  193. package/src/server/host-policy.ts +13 -1
  194. package/src/server/index.ts +3 -0
  195. package/src/server/procedure-server.ts +147 -26
  196. package/src/server/request-auth.ts +128 -6
  197. package/src/server/types.ts +82 -5
@@ -1,19 +1,41 @@
1
1
  /**
2
2
  * The credentials of a network request (roadmap R18). A server transport reads them into
3
- * `ServerRequest.credentials`, and leaves the secret headers out of the metadata, so a handler
4
- * and a nested call do not see them. `ProcedureServer` examines them.
3
+ * `ServerRequest.credentials`. It leaves the secret headers out of the metadata, so a handler and a
4
+ * nested call do not see them. `ProcedureServer` examines them.
5
+ *
6
+ * This module imports no Node code: a server in a browser or a worker can use it too.
5
7
  */
6
8
 
7
9
  import type { Credentials } from "./types.js";
8
10
 
9
11
  /** The headers that carry a secret. They do not go into the metadata of a request. */
10
- const SECRET_HEADERS = new Set(["authorization", "proxy-authorization", "cookie", "x-api-key"]);
12
+ const SECRET_HEADERS: ReadonlySet<string> = new Set(["authorization", "proxy-authorization", "cookie", "x-api-key"]);
11
13
 
12
- /** The headers without the secret ones, and without the headers that are not text. */
13
- export function withoutSecretHeaders(headers: Record<string, unknown>): Record<string, string> {
14
+ /**
15
+ * True when a header carries a secret: a header of the default list (`Authorization`,
16
+ * `Proxy-Authorization`, `Cookie`, `X-Api-Key`), or a header of `more`. The names are lower case.
17
+ */
18
+ export function isSecretHeader(name: string, more?: ReadonlySet<string>): boolean {
19
+ const key = name.toLowerCase();
20
+ return SECRET_HEADERS.has(key) || (more?.has(key) ?? false);
21
+ }
22
+
23
+ /** This function gives a set of lower-case header names. */
24
+ export function headerNames(names: Iterable<string> | undefined): ReadonlySet<string> {
25
+ const set = new Set<string>();
26
+ for (const name of names ?? []) set.add(name.toLowerCase());
27
+ return set;
28
+ }
29
+
30
+ /**
31
+ * The headers without the secret ones, and without the headers that are not text. `secret` names
32
+ * more headers that carry a secret, for example the token header of an application.
33
+ */
34
+ export function withoutSecretHeaders(headers: Record<string, unknown>, secret?: Iterable<string>): Record<string, string> {
35
+ const more = secret === undefined ? undefined : headerNames(secret);
14
36
  const out: Record<string, string> = {};
15
37
  for (const [key, value] of Object.entries(headers)) {
16
- if (!SECRET_HEADERS.has(key.toLowerCase()) && typeof value === "string") out[key] = value;
38
+ if (!isSecretHeader(key, more) && typeof value === "string") out[key] = value;
17
39
  }
18
40
  return out;
19
41
  }
@@ -33,3 +55,103 @@ export function credentialsOf(request: { headers: Record<string, unknown>; url?:
33
55
  const query = new URL(request.url ?? "/", "http://localhost").searchParams.get("token");
34
56
  return query === null ? {} : { bearer: query };
35
57
  }
58
+
59
+ /** The text of a header value: a list of values becomes one text, with ", " between the values. */
60
+ function headerText(value: unknown): string | undefined {
61
+ if (typeof value === "string") return value;
62
+ if (Array.isArray(value)) return value.filter((item): item is string => typeof item === "string").join(", ");
63
+ return undefined;
64
+ }
65
+
66
+ /** This function decodes a cookie value. A value that is not valid URI encoding stays as it is. */
67
+ function decodeCookieValue(value: string): string {
68
+ const unquoted = value.length >= 2 && value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
69
+ try {
70
+ return decodeURIComponent(unquoted);
71
+ } catch {
72
+ return unquoted;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * The cookies of a `Cookie` header, by name. The function decodes each URI-encoded value when it
78
+ * can. When two cookies have the same name, the first one stays: a browser sends the
79
+ * cookie of the longest path first. A part without `=` is not a cookie.
80
+ */
81
+ export function cookiesOf(header: unknown): Record<string, string> {
82
+ const text = Array.isArray(header) ? header.filter((item): item is string => typeof item === "string").join("; ") : header;
83
+ if (typeof text !== "string" || text === "") return {};
84
+ const cookies = new Map<string, string>();
85
+ for (const part of text.split(";")) {
86
+ const eq = part.indexOf("=");
87
+ if (eq <= 0) continue;
88
+ const name = part.slice(0, eq).trim();
89
+ if (name === "" || cookies.has(name)) continue;
90
+ cookies.set(name, decodeCookieValue(part.slice(eq + 1).trim()));
91
+ }
92
+ // fromEntries defines own properties: a cookie named "__proto__" changes no prototype
93
+ return Object.fromEntries(cookies);
94
+ }
95
+
96
+ /**
97
+ * The parts of a request URL: its path and its query. The function does not resolve the URL
98
+ * against a host, so a path that starts with "//" stays a path.
99
+ */
100
+ export function urlParts(url: string | undefined): { path: string; query: URLSearchParams } {
101
+ let raw = url ?? "/";
102
+ // The absolute form of a request line (a request through a proxy): the path and the query only
103
+ if (!raw.startsWith("/") && /^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) {
104
+ try {
105
+ const absolute = new URL(raw);
106
+ raw = `${absolute.pathname}${absolute.search}`;
107
+ } catch {
108
+ // Not a URL: the text stays a path
109
+ }
110
+ }
111
+ const mark = raw.indexOf("?");
112
+ return mark === -1 ? { path: raw, query: new URLSearchParams() } : { path: raw.slice(0, mark), query: new URLSearchParams(raw.slice(mark + 1)) };
113
+ }
114
+
115
+ /** The first value of each query parameter, by name. */
116
+ export function queryRecord(query: URLSearchParams): Record<string, string> {
117
+ const values = new Map<string, string>();
118
+ for (const [key, value] of query) if (!values.has(key)) values.set(key, value);
119
+ return Object.fromEntries(values);
120
+ }
121
+
122
+ /** The options of `requestCredentials`. */
123
+ export interface RequestCredentialsOptions {
124
+ /**
125
+ * The query parameter whose value is the bearer token of a request without an
126
+ * `Authorization: Bearer` header. A browser WebSocket cannot set headers, so the WebSocket
127
+ * server reads `token`. `false` reads no query parameter.
128
+ * @default false
129
+ */
130
+ readonly tokenQuery?: string | false | undefined;
131
+ }
132
+
133
+ /**
134
+ * The credentials of a network request (roadmap R18): the bearer token, the cookies, each header
135
+ * (the secret ones too) and the first value of each query parameter. The request hook of a server
136
+ * (`principalOf`) reads them. They are not in the metadata, so a handler does not see them.
137
+ */
138
+ export function requestCredentials(
139
+ request: { headers: Record<string, unknown>; url?: string | undefined },
140
+ options: RequestCredentialsOptions = {}
141
+ ): Credentials {
142
+ const headers = new Map<string, string>();
143
+ for (const [key, value] of Object.entries(request.headers)) {
144
+ const text = headerText(value);
145
+ if (text !== undefined) headers.set(key.toLowerCase(), text);
146
+ }
147
+ const { query } = urlParts(request.url);
148
+ const fromHeader = bearerOf(headers.get("authorization"));
149
+ const fromQuery = options.tokenQuery ? query.get(options.tokenQuery) ?? undefined : undefined;
150
+ const bearer = fromHeader ?? fromQuery;
151
+ return {
152
+ ...(bearer !== undefined ? { bearer } : {}),
153
+ cookies: cookiesOf(headers.get("cookie")),
154
+ headers: Object.fromEntries(headers),
155
+ query: queryRecord(query),
156
+ };
157
+ }
@@ -5,7 +5,10 @@
5
5
  * Enables handling HTTP, WebSocket, gRPC, etc. with unified RPC format.
6
6
  */
7
7
 
8
+ import type { Elicit } from "../procedures/elicit.js";
9
+ import type { ReportProgress } from "../procedures/progress.js";
8
10
  import type { Metadata, Status, Method } from "../client/types.js";
11
+ import type { CapabilityRequest } from "../procedures/types.js";
9
12
 
10
13
  // Re-export Method from client types
11
14
  export type { Method };
@@ -27,27 +30,86 @@ export interface ServerRequest<TReq = unknown> {
27
30
  /** Request metadata (headers, query params, etc.) */
28
31
  metadata: Metadata;
29
32
 
33
+ /**
34
+ * The function that asks the person at the caller, when the face can ask (MCP elicitation,
35
+ * CLI-12). The procedure gets it as `ctx.elicit`. It is not in the metadata, so a caller cannot
36
+ * send it.
37
+ */
38
+ elicit?: Elicit | undefined;
39
+
40
+ /**
41
+ * The function that tells the caller the progress of the call, when the caller asked for it
42
+ * (an MCP progress token). The procedure gets it as `ctx.progress`.
43
+ */
44
+ progress?: ReportProgress | undefined;
45
+
30
46
  /** Abort signal for cancellation */
31
47
  signal?: AbortSignal;
32
48
 
33
49
  /**
34
- * The credentials that a network transport read from the request: the bearer token of an
35
- * `Authorization` header, or of the `token` query of a WebSocket connection (roadmap R18). They
36
- * are not in the metadata, so a handler and a nested call do not see them. A request without
37
- * credentials comes from this process (a direct `handle()`, MCP over stdio).
50
+ * The credentials that a network transport read from the request (roadmap R18). They have the
51
+ * bearer token of an `Authorization` header, or of the `token` query of a WebSocket connection.
52
+ * They also have the cookies, the headers and the query of the request. They are not in the
53
+ * metadata, so a handler and a nested call do not see them. A request without credentials comes
54
+ * from this process (a direct `handle()`, MCP over stdio).
38
55
  */
39
56
  credentials?: Credentials | undefined;
40
57
 
41
58
  /** The principal of the request: who sends it. `ProcedureServer` sets it when it authenticates the request. */
42
59
  principal?: Principal | undefined;
60
+
61
+ /**
62
+ * A narrower capability that the request asks for. The request hook of the server
63
+ * (`principalOf`) can set it. The server narrows the capability of the call with it, so the
64
+ * capability does not become wider.
65
+ */
66
+ narrowing?: CapabilityRequest | undefined;
43
67
  }
44
68
 
45
- /** The credentials of a request. */
69
+ /**
70
+ * The credentials of a request. A network transport sets each field that it can read. The request
71
+ * hook of the server (`principalOf`) reads them.
72
+ */
46
73
  export interface Credentials {
47
74
  /** The bearer token that the request presents. */
48
75
  readonly bearer?: string | undefined;
76
+ /** The cookies of the request, by name (the `Cookie` header of an HTTP request or of an upgrade). */
77
+ readonly cookies?: Readonly<Record<string, string>> | undefined;
78
+ /** Each header of the request, the secret headers too, by lower-case name. */
79
+ readonly headers?: Readonly<Record<string, string>> | undefined;
80
+ /** The first value of each query parameter of the request URL, by name. */
81
+ readonly query?: Readonly<Record<string, string>> | undefined;
82
+ }
83
+
84
+ /**
85
+ * What the request hook of a server (`principalOf`) gives for a network request. Each field is
86
+ * optional: an empty object accepts the request without a principal.
87
+ */
88
+ export interface RequestIdentity {
89
+ /**
90
+ * The token to compare with the token of the server, for example the value of a cookie or of an
91
+ * application header. Without it, the server compares the bearer token of the credentials.
92
+ */
93
+ readonly bearer?: string | undefined;
94
+ /** The principal of the request. It replaces the principal of the token check. */
95
+ readonly principal?: Principal | undefined;
96
+ /**
97
+ * A narrower capability that the request asks for, for example a guest mode of a cookie. The
98
+ * server narrows the capability of the call with it. A request for more has no effect.
99
+ */
100
+ readonly narrowing?: CapabilityRequest | undefined;
49
101
  }
50
102
 
103
+ /**
104
+ * The request hook of a server: it reads the credentials of a network request (a cookie, a header,
105
+ * the query) and gives the identity of the request. Undefined, or an error, refuses the request
106
+ * with `UNAUTHORIZED`. The hook runs before the token check and before `authenticate`.
107
+ */
108
+ export type PrincipalOf = (
109
+ credentials: Credentials,
110
+ request: ServerRequest<unknown>
111
+ ) => RequestIdentity | undefined | Promise<RequestIdentity | undefined>;
112
+
51
113
  /** Who sends a request (roadmap R18). */
52
114
  export interface Principal {
53
115
  /** The id of the principal. With the token of a host: "token". */
@@ -66,8 +128,23 @@ export interface Principal {
66
128
  */
67
129
  export interface RequestHandler {
68
130
  handle(request: ServerRequest): Promise<ServerResponse>;
131
+ /**
132
+ * How the handler can authenticate a network request with ambient credentials: the cookies that
133
+ * a browser sends by itself, also for a request of another site (CSRF). A network face then
134
+ * trusts such a request only from a named origin. Absent: the handler reads no cookies.
135
+ */
136
+ readonly ambientCredentials?: AmbientCredentials | undefined;
69
137
  }
70
138
 
139
+ /**
140
+ * How a server can authenticate a request with ambient credentials (cookies):
141
+ * - `"always"`: each network request. The request hook `principalOf` reads the cookies, so a face
142
+ * trusts a request only from a named origin.
143
+ * - `"cookies"`: a request that carries a cookie. An `authenticate` function can read it, so a face
144
+ * trusts a request with a cookie only from a named origin.
145
+ */
146
+ export type AmbientCredentials = "always" | "cookies";
147
+
71
148
  /**
72
149
  * Server response in unified RPC format.
73
150
  * Converted by transport adapters to protocol-specific responses.