@microsoft/agents-hosting 1.9.1 → 1.10.0-beta.14.ge6d1defc27
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/README.md +83 -7
- package/dist/package.json +4 -4
- package/dist/src/activityHandler.js +6 -3
- package/dist/src/activityHandler.js.map +1 -1
- package/dist/src/agent-client/agentResponseHandler.d.ts +7 -0
- package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
- package/dist/src/agent-client/createAgentResponseHandler.d.ts +2 -0
- package/dist/src/agent-client/createAgentResponseHandler.js.map +1 -1
- package/dist/src/app/adaptiveCards/adaptiveCardsActions.d.ts +1 -0
- package/dist/src/app/adaptiveCards/adaptiveCardsActions.js +1 -0
- package/dist/src/app/adaptiveCards/adaptiveCardsActions.js.map +1 -1
- package/dist/src/app/attachmentDownloadHttpClient.d.ts +13 -0
- package/dist/src/app/attachmentDownloadHttpClient.js +80 -0
- package/dist/src/app/attachmentDownloadHttpClient.js.map +1 -0
- package/dist/src/app/attachmentDownloader.d.ts +2 -0
- package/dist/src/app/attachmentDownloader.js +6 -11
- package/dist/src/app/attachmentDownloader.js.map +1 -1
- package/dist/src/app/auth/authorization.d.ts +58 -0
- package/dist/src/app/auth/authorization.js.map +1 -1
- package/dist/src/app/proactive/conversation.d.ts +18 -0
- package/dist/src/app/proactive/conversation.js +6 -0
- package/dist/src/app/proactive/conversation.js.map +1 -1
- package/dist/src/app/proactive/conversationBuilder.js +2 -1
- package/dist/src/app/proactive/conversationBuilder.js.map +1 -1
- package/dist/src/app/proactive/conversationReferenceBuilder.js +8 -4
- package/dist/src/app/proactive/conversationReferenceBuilder.js.map +1 -1
- package/dist/src/app/proactive/createConversationOptionsBuilder.d.ts +1 -0
- package/dist/src/app/proactive/createConversationOptionsBuilder.js +2 -1
- package/dist/src/app/proactive/createConversationOptionsBuilder.js.map +1 -1
- package/dist/src/app/proactive/proactive.d.ts +6 -0
- package/dist/src/app/proactive/proactive.js +32 -1
- package/dist/src/app/proactive/proactive.js.map +1 -1
- package/dist/src/app/routeList.d.ts +21 -0
- package/dist/src/app/routeList.js +27 -3
- package/dist/src/app/routeList.js.map +1 -1
- package/dist/src/app/teamsAttachmentDownloader.d.ts +8 -0
- package/dist/src/app/teamsAttachmentDownloader.js +17 -12
- package/dist/src/app/teamsAttachmentDownloader.js.map +1 -1
- package/dist/src/auth/authConfiguration.d.ts +1 -0
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/authConstants.d.ts +7 -0
- package/dist/src/auth/authConstants.js +7 -0
- package/dist/src/auth/authConstants.js.map +1 -1
- package/dist/src/auth/authProvider.d.ts +36 -0
- package/dist/src/auth/connectionManager.js +2 -1
- package/dist/src/auth/connectionManager.js.map +1 -1
- package/dist/src/auth/connections.d.ts +1 -0
- package/dist/src/auth/msal/msalConnectionManager.d.ts +7 -0
- package/dist/src/auth/msal/msalConnectionManager.js +7 -0
- package/dist/src/auth/msal/msalConnectionManager.js.map +1 -1
- package/dist/src/auth/msal/msalTokenProvider.d.ts +44 -0
- package/dist/src/auth/msal/msalTokenProvider.js +43 -0
- package/dist/src/auth/msal/msalTokenProvider.js.map +1 -1
- package/dist/src/auth/settings.d.ts +28 -0
- package/dist/src/auth/settings.js +23 -0
- package/dist/src/auth/settings.js.map +1 -1
- package/dist/src/auth/sidecar/sidecarAuthProvider.d.ts +3 -0
- package/dist/src/auth/sidecar/sidecarAuthProvider.js.map +1 -1
- package/dist/src/auth/sidecar/sidecarHttpClient.d.ts +1 -9
- package/dist/src/auth/sidecar/sidecarHttpClient.js +3 -69
- package/dist/src/auth/sidecar/sidecarHttpClient.js.map +1 -1
- package/dist/src/baseAdapter.d.ts +6 -0
- package/dist/src/baseAdapter.js.map +1 -1
- package/dist/src/cards/taskModuleAction.d.ts +6 -0
- package/dist/src/cards/taskModuleAction.js +6 -0
- package/dist/src/cards/taskModuleAction.js.map +1 -1
- package/dist/src/cloudAdapter.d.ts +29 -0
- package/dist/src/cloudAdapter.js +45 -8
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/configuration/configuration.d.ts +1 -0
- package/dist/src/configuration/configuration.js +2 -1
- package/dist/src/configuration/configuration.js.map +1 -1
- package/dist/src/configuration/environmentConfiguration.js +1 -1
- package/dist/src/configuration/environmentConfiguration.js.map +1 -1
- package/dist/src/connector-client/connectorClient.d.ts +8 -0
- package/dist/src/connector-client/connectorClient.js +8 -0
- package/dist/src/connector-client/connectorClient.js.map +1 -1
- package/dist/src/createCloudAdapter.d.ts +2 -0
- package/dist/src/createCloudAdapter.js.map +1 -1
- package/dist/src/errorHelper.d.ts +1 -0
- package/dist/src/errorHelper.js +9 -0
- package/dist/src/errorHelper.js.map +1 -1
- package/dist/src/headerPropagation.d.ts +38 -0
- package/dist/src/headerPropagation.js +33 -0
- package/dist/src/headerPropagation.js.map +1 -1
- package/dist/src/httpClient.d.ts +58 -0
- package/dist/src/httpClient.js +40 -0
- package/dist/src/httpClient.js.map +1 -1
- package/dist/src/interfaces/webResponse.d.ts +7 -0
- package/dist/src/middlewareSet.d.ts +6 -0
- package/dist/src/middlewareSet.js.map +1 -1
- package/dist/src/oauth/userTokenClient.d.ts +6 -0
- package/dist/src/oauth/userTokenClient.js +12 -0
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/dist/src/outboundHostValidator.d.ts +33 -1
- package/dist/src/outboundHostValidator.js +60 -25
- package/dist/src/outboundHostValidator.js.map +1 -1
- package/dist/src/storage/fileStorage.d.ts +26 -0
- package/dist/src/storage/fileStorage.js +35 -6
- package/dist/src/storage/fileStorage.js.map +1 -1
- package/dist/src/storage/memoryStorage.d.ts +34 -0
- package/dist/src/storage/memoryStorage.js +41 -4
- package/dist/src/storage/memoryStorage.js.map +1 -1
- package/dist/src/storage/storage.d.ts +20 -0
- package/dist/src/storage/storage.js +7 -0
- package/dist/src/storage/storage.js.map +1 -1
- package/dist/src/storage/storageCompatibility.js +12 -6
- package/dist/src/storage/storageCompatibility.js.map +1 -1
- package/dist/src/storage/storageExpiry.d.ts +7 -0
- package/dist/src/storage/storageExpiry.js +7 -0
- package/dist/src/storage/storageExpiry.js.map +1 -1
- package/dist/src/turnContext.d.ts +10 -0
- package/dist/src/turnContext.js +5 -0
- package/dist/src/turnContext.js.map +1 -1
- package/dist/src/utils/env.js +22 -11
- package/dist/src/utils/env.js.map +1 -1
- package/dist/src/utils/ipAddress.d.ts +6 -0
- package/dist/src/utils/ipAddress.js +64 -0
- package/dist/src/utils/ipAddress.js.map +1 -0
- package/dist/src/utils/outboundUrl.d.ts +7 -0
- package/dist/src/utils/outboundUrl.js +52 -0
- package/dist/src/utils/outboundUrl.js.map +1 -0
- package/dist/src/utils.js +2 -1
- package/dist/src/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/activityHandler.ts +9 -3
- package/src/agent-client/agentResponseHandler.ts +7 -0
- package/src/agent-client/createAgentResponseHandler.ts +2 -0
- package/src/app/adaptiveCards/adaptiveCardsActions.ts +1 -0
- package/src/app/attachmentDownloadHttpClient.ts +80 -0
- package/src/app/attachmentDownloader.ts +6 -9
- package/src/app/auth/authorization.ts +58 -0
- package/src/app/proactive/conversation.ts +24 -0
- package/src/app/proactive/conversationBuilder.ts +3 -1
- package/src/app/proactive/conversationReferenceBuilder.ts +12 -4
- package/src/app/proactive/createConversationOptionsBuilder.ts +5 -1
- package/src/app/proactive/proactive.ts +33 -1
- package/src/app/routeList.ts +30 -3
- package/src/app/teamsAttachmentDownloader.ts +17 -10
- package/src/auth/authConfiguration.ts +1 -0
- package/src/auth/authConstants.ts +7 -0
- package/src/auth/authProvider.ts +36 -0
- package/src/auth/connectionManager.ts +3 -1
- package/src/auth/connections.ts +1 -0
- package/src/auth/msal/msalConnectionManager.ts +7 -0
- package/src/auth/msal/msalTokenProvider.ts +59 -0
- package/src/auth/settings.ts +28 -0
- package/src/auth/sidecar/sidecarAuthProvider.ts +4 -0
- package/src/auth/sidecar/sidecarHttpClient.ts +3 -63
- package/src/baseAdapter.ts +6 -0
- package/src/cards/taskModuleAction.ts +6 -0
- package/src/cloudAdapter.ts +59 -10
- package/src/configuration/configuration.ts +4 -2
- package/src/configuration/environmentConfiguration.ts +7 -1
- package/src/connector-client/connectorClient.ts +8 -0
- package/src/createCloudAdapter.ts +2 -0
- package/src/errorHelper.ts +11 -0
- package/src/headerPropagation.ts +38 -0
- package/src/httpClient.ts +58 -0
- package/src/interfaces/webResponse.ts +7 -0
- package/src/middlewareSet.ts +6 -0
- package/src/oauth/userTokenClient.ts +13 -0
- package/src/outboundHostValidator.ts +84 -23
- package/src/storage/fileStorage.ts +46 -6
- package/src/storage/memoryStorage.ts +45 -4
- package/src/storage/storage.ts +20 -0
- package/src/storage/storageCompatibility.ts +18 -6
- package/src/storage/storageExpiry.ts +7 -0
- package/src/turnContext.ts +11 -0
- package/src/utils/env.ts +33 -11
- package/src/utils/ipAddress.ts +63 -0
- package/src/utils/outboundUrl.ts +50 -0
- package/src/utils.ts +3 -1
package/src/auth/settings.ts
CHANGED
|
@@ -24,16 +24,28 @@ const AUTHORITY_DEFAULT = 'https://login.microsoftonline.com'
|
|
|
24
24
|
* (matched by audience and/or serviceUrl) to a named connection.
|
|
25
25
|
*/
|
|
26
26
|
export interface ConnectionMapItem {
|
|
27
|
+
/** Service URL pattern matched by this route. */
|
|
27
28
|
serviceUrl: string
|
|
29
|
+
/** Optional token audience matched by this route. */
|
|
28
30
|
audience?: string
|
|
31
|
+
/** Name of the connection selected by this route. */
|
|
29
32
|
connection: string
|
|
30
33
|
}
|
|
31
34
|
|
|
35
|
+
/** Default route that selects the standard service connection. */
|
|
32
36
|
export const DEFAULT_CONNECTION_MAP: ConnectionMapItem = { serviceUrl: '*', connection: DEFAULT_CONNECTION }
|
|
33
37
|
|
|
38
|
+
/** Property names accepted as connection-level settings. */
|
|
34
39
|
export type ConnectionKeys = keyof Omit<AuthConfiguration, 'connections' | 'connectionsMap'>
|
|
40
|
+
/** Property names accepted in a connection-map entry. */
|
|
35
41
|
export type ConnectionMapKeys = keyof ConnectionMapItem
|
|
36
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Applies authority, issuer, alias, and connection-map defaults to a configuration.
|
|
45
|
+
*
|
|
46
|
+
* @param config - Authentication configuration to normalize.
|
|
47
|
+
* @returns A normalized copy of the configuration.
|
|
48
|
+
*/
|
|
37
49
|
export function applyDefaultSettings (config: AuthConfiguration) {
|
|
38
50
|
const settings = { ...config }
|
|
39
51
|
settings.authorityEndpoint ??= settings.authority ?? AUTHORITY_DEFAULT
|
|
@@ -106,6 +118,13 @@ function trimTrailingSlashes (value: string): string {
|
|
|
106
118
|
return end === value.length ? value : value.slice(0, end)
|
|
107
119
|
}
|
|
108
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Builds the default trusted issuer list for a tenant and authority.
|
|
123
|
+
*
|
|
124
|
+
* @param tenantId - Microsoft Entra tenant ID.
|
|
125
|
+
* @param authority - Authority URL used to determine the cloud and effective tenant.
|
|
126
|
+
* @returns Trusted Bot Framework and Microsoft Entra issuer URLs.
|
|
127
|
+
*/
|
|
109
128
|
export function getDefaultIssuers (tenantId: string, authority: string) : string[] {
|
|
110
129
|
// Convert empty string to undefined so resolveAuthority applies its 'botframework.com' default
|
|
111
130
|
const t = getEffectiveTenant(tenantId || undefined, authority)
|
|
@@ -268,14 +287,23 @@ export interface AuthConfiguration extends ConnectionSettings {
|
|
|
268
287
|
* Supported authentication types for agent connections.
|
|
269
288
|
*/
|
|
270
289
|
export enum AuthType {
|
|
290
|
+
/** Client authentication using an X.509 certificate. */
|
|
271
291
|
Certificate = 'Certificate',
|
|
292
|
+
/** Client authentication using a certificate subject name. */
|
|
272
293
|
CertificateSubjectName = 'CertificateSubjectName',
|
|
294
|
+
/** Client authentication using a client secret. */
|
|
273
295
|
ClientSecret = 'ClientSecret',
|
|
296
|
+
/** Authentication using a user-assigned managed identity. */
|
|
274
297
|
UserManagedIdentity = 'UserManagedIdentity',
|
|
298
|
+
/** Authentication using a system-assigned managed identity. */
|
|
275
299
|
SystemManagedIdentity = 'SystemManagedIdentity',
|
|
300
|
+
/** Authentication using federated identity credentials. */
|
|
276
301
|
FederatedCredentials = 'FederatedCredentials',
|
|
302
|
+
/** Authentication using a workload identity token. */
|
|
277
303
|
WorkloadIdentity = 'WorkloadIdentity',
|
|
304
|
+
/** Authentication through Identity Proxy Manager. */
|
|
278
305
|
IdentityProxyManager = 'IdentityProxyManager',
|
|
306
|
+
/** Authentication through the Microsoft Entra authentication sidecar. */
|
|
279
307
|
EntraAuthSideCar = 'EntraAuthSideCar'
|
|
280
308
|
}
|
|
281
309
|
|
|
@@ -134,6 +134,10 @@ export class SidecarAuthProvider implements AuthProvider {
|
|
|
134
134
|
* On-behalf-of token exchange — not supported by the sidecar provider in Phase 1.
|
|
135
135
|
*/
|
|
136
136
|
async acquireTokenOnBehalfOf (scopes: string[], oboAssertion: string): Promise<string>
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* On-behalf-of token exchange with explicit authentication settings — not supported by the sidecar provider in Phase 1.
|
|
140
|
+
*/
|
|
137
141
|
async acquireTokenOnBehalfOf (authConfig: AuthConfiguration, scopes: string[], oboAssertion: string): Promise<string>
|
|
138
142
|
async acquireTokenOnBehalfOf (
|
|
139
143
|
_authConfigOrScopes: AuthConfiguration | string[],
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { isIP } from 'node:net'
|
|
7
6
|
import { debug } from '@microsoft/agents-telemetry'
|
|
8
7
|
import { ExceptionHelper } from '@microsoft/agents-activity'
|
|
9
8
|
import { Errors } from '../../errorHelper'
|
|
9
|
+
import { isPrivateOrLoopbackAddress } from '../../utils/ipAddress'
|
|
10
10
|
import {
|
|
11
11
|
DEFAULT_REQUEST_TIMEOUT_MS,
|
|
12
12
|
DEFAULT_RETRY_COUNT,
|
|
@@ -23,7 +23,7 @@ const DEFAULT_RETRY_BACKOFF_BASE_MS = 2000
|
|
|
23
23
|
/**
|
|
24
24
|
* Reusable HTTP client for communicating with the Microsoft Entra Agent ID sidecar (agent container).
|
|
25
25
|
* Handles URL construction, query parameter building, response parsing, retry, and SSRF-safe base
|
|
26
|
-
* URL validation.
|
|
26
|
+
* URL validation.
|
|
27
27
|
*/
|
|
28
28
|
export class SidecarHttpClient {
|
|
29
29
|
/** Default per-attempt request timeout (milliseconds). */
|
|
@@ -139,68 +139,8 @@ export class SidecarHttpClient {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
private static isLoopbackOrPrivateHost (host: string): boolean {
|
|
142
|
-
// URL.hostname wraps IPv6 literals in brackets (e.g. "[::1]"); strip them before classification.
|
|
143
|
-
const normalized = host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host
|
|
144
|
-
const ipVersion = isIP(normalized)
|
|
145
|
-
if (ipVersion === 0) {
|
|
146
|
-
// DNS host: only "localhost" (and subdomains) is treated as safe.
|
|
147
|
-
const lower = normalized.toLowerCase()
|
|
148
|
-
return lower === 'localhost' || lower.endsWith('.localhost')
|
|
149
|
-
}
|
|
150
|
-
if (ipVersion === 4) {
|
|
151
|
-
return SidecarHttpClient.isPrivateOrLoopbackIPv4(normalized)
|
|
152
|
-
}
|
|
153
|
-
return SidecarHttpClient.isPrivateOrLoopbackIPv6(normalized)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
private static isPrivateOrLoopbackIPv4 (host: string): boolean {
|
|
157
|
-
const b = host.split('.').map((p) => parseInt(p, 10))
|
|
158
|
-
if (b.length !== 4 || b.some((n) => Number.isNaN(n) || n < 0 || n > 255)) {
|
|
159
|
-
return false
|
|
160
|
-
}
|
|
161
|
-
if (b[0] === 127) return true // 127.0.0.0/8 loopback
|
|
162
|
-
if (b[0] === 10) return true // 10.0.0.0/8
|
|
163
|
-
if (b[0] === 172 && b[1] >= 16 && b[1] <= 31) return true // 172.16.0.0/12
|
|
164
|
-
if (b[0] === 192 && b[1] === 168) return true // 192.168.0.0/16
|
|
165
|
-
if (b[0] === 169 && b[1] === 254) return true // 169.254.0.0/16 link-local
|
|
166
|
-
return false
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private static isPrivateOrLoopbackIPv6 (host: string): boolean {
|
|
170
142
|
const lower = host.toLowerCase()
|
|
171
|
-
|
|
172
|
-
// IPv4-mapped/-translated addresses in either dotted (::ffff:127.0.0.1)
|
|
173
|
-
// or hex-compressed (::ffff:7f00:1) form.
|
|
174
|
-
const mappedIPv4 = SidecarHttpClient.extractMappedIPv4(lower)
|
|
175
|
-
if (mappedIPv4) {
|
|
176
|
-
return SidecarHttpClient.isPrivateOrLoopbackIPv4(mappedIPv4)
|
|
177
|
-
}
|
|
178
|
-
const firstHextet = parseInt(lower.split(':')[0], 16)
|
|
179
|
-
if (!Number.isNaN(firstHextet)) {
|
|
180
|
-
if ((firstHextet & 0xfe00) === 0xfc00) return true // fc00::/7 unique local
|
|
181
|
-
if ((firstHextet & 0xffc0) === 0xfe80) return true // fe80::/10 link-local
|
|
182
|
-
if ((firstHextet & 0xffc0) === 0xfec0) return true // fec0::/10 site-local (deprecated)
|
|
183
|
-
}
|
|
184
|
-
return false
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Extracts the embedded IPv4 address from an IPv4-mapped/-translated IPv6 literal, returning it
|
|
189
|
-
* in dotted-quad form, or `undefined` if `host` is not such an address. Handles both the dotted
|
|
190
|
-
* form (`::ffff:127.0.0.1`) and the hex-compressed form Node emits (`::ffff:7f00:1`).
|
|
191
|
-
*/
|
|
192
|
-
private static extractMappedIPv4 (host: string): string | undefined {
|
|
193
|
-
const dotted = host.match(/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/)
|
|
194
|
-
if (dotted) {
|
|
195
|
-
return dotted[1]
|
|
196
|
-
}
|
|
197
|
-
const hex = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/)
|
|
198
|
-
if (hex) {
|
|
199
|
-
const high = parseInt(hex[1], 16)
|
|
200
|
-
const low = parseInt(hex[2], 16)
|
|
201
|
-
return `${high >> 8}.${high & 0xff}.${low >> 8}.${low & 0xff}`
|
|
202
|
-
}
|
|
203
|
-
return undefined
|
|
143
|
+
return lower === 'localhost' || lower.endsWith('.localhost') || isPrivateOrLoopbackAddress(host)
|
|
204
144
|
}
|
|
205
145
|
|
|
206
146
|
/**
|
package/src/baseAdapter.ts
CHANGED
|
@@ -88,6 +88,12 @@ export abstract class BaseAdapter {
|
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
90
|
* Continues a conversation.
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
* Errors thrown by `logic` are passed to {@link onTurnError}. If the error handler completes
|
|
94
|
+
* normally, this method resolves. To observe the original error in the caller, catch it inside
|
|
95
|
+
* `logic` and throw it after this method completes.
|
|
96
|
+
*
|
|
91
97
|
* @param reference - The conversation reference to continue.
|
|
92
98
|
* @param logic - The logic to execute.
|
|
93
99
|
* @returns A promise representing the completion of the continue operation.
|
|
@@ -9,6 +9,12 @@ import { CardAction } from '@microsoft/agents-activity'
|
|
|
9
9
|
* Represents a task module action.
|
|
10
10
|
*/
|
|
11
11
|
export class TaskModuleAction implements CardAction {
|
|
12
|
+
/**
|
|
13
|
+
* Creates an action that invokes a `task/fetch` task module.
|
|
14
|
+
*
|
|
15
|
+
* @param title The action title.
|
|
16
|
+
* @param value The action data as an object or JSON string.
|
|
17
|
+
*/
|
|
12
18
|
constructor (title: string, value: any) {
|
|
13
19
|
this.type = 'invoke'
|
|
14
20
|
this.title = title
|
package/src/cloudAdapter.ts
CHANGED
|
@@ -152,7 +152,9 @@ function sanitizeForLog (value: string, max = 256): string {
|
|
|
152
152
|
function truncateActivityForLog (activity: unknown, max = 1024): string {
|
|
153
153
|
try {
|
|
154
154
|
const json = JSON.stringify(activity)
|
|
155
|
-
if (!json)
|
|
155
|
+
if (!json) {
|
|
156
|
+
return '<unserializable>'
|
|
157
|
+
}
|
|
156
158
|
// Strip C0/DEL/C1 controls + U+2028/U+2029 from the serialized form so
|
|
157
159
|
// attacker-controlled fields (e.g. activity.text) can't forge log lines.
|
|
158
160
|
// eslint-disable-next-line no-control-regex
|
|
@@ -651,18 +653,30 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
651
653
|
* should be rejected with a 400.
|
|
652
654
|
*/
|
|
653
655
|
private validateServiceUrl (identity: JwtPayload | undefined, activity: Activity): boolean {
|
|
654
|
-
if (!this.isOutboundServiceUrlAllowed(activity.serviceUrl))
|
|
656
|
+
if (!this.isOutboundServiceUrlAllowed(activity.serviceUrl)) {
|
|
657
|
+
return false
|
|
658
|
+
}
|
|
655
659
|
|
|
656
|
-
if (!identity)
|
|
657
|
-
|
|
660
|
+
if (!identity) {
|
|
661
|
+
return true
|
|
662
|
+
}
|
|
663
|
+
if (!activity.serviceUrl) {
|
|
664
|
+
return true
|
|
665
|
+
}
|
|
658
666
|
|
|
659
667
|
const claimValue = identity.serviceurl
|
|
660
|
-
if (typeof claimValue !== 'string')
|
|
668
|
+
if (typeof claimValue !== 'string') {
|
|
669
|
+
return true
|
|
670
|
+
}
|
|
661
671
|
|
|
662
672
|
let claimHost: string | undefined
|
|
663
673
|
let activityHost: string | undefined
|
|
664
|
-
try {
|
|
665
|
-
|
|
674
|
+
try {
|
|
675
|
+
claimHost = new URL(claimValue).hostname.toLowerCase()
|
|
676
|
+
} catch { /* invalid */ }
|
|
677
|
+
try {
|
|
678
|
+
activityHost = new URL(activity.serviceUrl).hostname.toLowerCase()
|
|
679
|
+
} catch { /* invalid */ }
|
|
666
680
|
|
|
667
681
|
if (claimHost && activityHost && claimHost === activityHost) {
|
|
668
682
|
return true
|
|
@@ -682,7 +696,9 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
682
696
|
* Applies the shared outbound host policy.
|
|
683
697
|
*/
|
|
684
698
|
private isOutboundServiceUrlAllowed (serviceUrl: string | undefined): boolean {
|
|
685
|
-
if (!this._hostValidator.enabled || !serviceUrl || this._hostValidator.isAllowed(serviceUrl))
|
|
699
|
+
if (!this._hostValidator.enabled || !serviceUrl || this._hostValidator.isAllowed(serviceUrl)) {
|
|
700
|
+
return true
|
|
701
|
+
}
|
|
686
702
|
|
|
687
703
|
logger.warn(`ServiceUrl host is not in the configured allowed hosts. ServiceUrl='${sanitizeForLog(serviceUrl)}'`)
|
|
688
704
|
return false
|
|
@@ -751,6 +767,35 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
751
767
|
|
|
752
768
|
/**
|
|
753
769
|
* Continues a conversation.
|
|
770
|
+
*
|
|
771
|
+
* @remarks
|
|
772
|
+
* Errors thrown by `logic` are passed to {@link BaseAdapter.onTurnError}. If the error handler
|
|
773
|
+
* completes normally, this method resolves. A `try`/`catch` around `continueConversation` will
|
|
774
|
+
* therefore not observe the original error.
|
|
775
|
+
*
|
|
776
|
+
* To observe an error from a proactive operation, catch it inside `logic` and throw it after
|
|
777
|
+
* `continueConversation` completes:
|
|
778
|
+
*
|
|
779
|
+
* ```typescript
|
|
780
|
+
* let operationFailed = false
|
|
781
|
+
* let operationError: unknown
|
|
782
|
+
*
|
|
783
|
+
* await adapter.continueConversation(botAppId, reference, async (context) => {
|
|
784
|
+
* try {
|
|
785
|
+
* await context.sendActivity('Proactive message')
|
|
786
|
+
* } catch (error) {
|
|
787
|
+
* operationFailed = true
|
|
788
|
+
* operationError = error
|
|
789
|
+
* }
|
|
790
|
+
* })
|
|
791
|
+
*
|
|
792
|
+
* if (operationFailed) {
|
|
793
|
+
* throw operationError
|
|
794
|
+
* }
|
|
795
|
+
* ```
|
|
796
|
+
*
|
|
797
|
+
* Catching the error inside `logic` prevents `onTurnError` from receiving that error.
|
|
798
|
+
*
|
|
754
799
|
* @param botAppIdOrIdentity - The bot identity to use when continuing the conversation. This can be either:
|
|
755
800
|
* a string containing the bot's App ID (botId) or a JwtPayload object containing identity claims (must include aud).
|
|
756
801
|
* @param reference - The conversation reference to continue.
|
|
@@ -891,8 +936,12 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
891
936
|
if (typeof serviceUrl !== 'string' || !serviceUrl) {
|
|
892
937
|
throw ExceptionHelper.generateException(TypeError, Errors.ServiceUrlRequired)
|
|
893
938
|
}
|
|
894
|
-
if (!conversationParameters)
|
|
895
|
-
|
|
939
|
+
if (!conversationParameters) {
|
|
940
|
+
throw ExceptionHelper.generateException(TypeError, Errors.ConversationParametersRequired)
|
|
941
|
+
}
|
|
942
|
+
if (!logic) {
|
|
943
|
+
throw ExceptionHelper.generateException(TypeError, Errors.LogicParameterRequired)
|
|
944
|
+
}
|
|
896
945
|
|
|
897
946
|
const identity = CloudAdapter.createIdentity(audience)
|
|
898
947
|
const restClient = await this.createConnectorClient(serviceUrl, audience, identity)
|
|
@@ -27,6 +27,7 @@ export type CloudAdapterConfigurationPatch = Partial<{
|
|
|
27
27
|
export type OutboundHostValidatorConfigurationPatch = Partial<{
|
|
28
28
|
enabled: boolean
|
|
29
29
|
includeDefaultMicrosoftHosts: boolean
|
|
30
|
+
allowPrivateNetworkAddresses: boolean
|
|
30
31
|
hosts: readonly string[]
|
|
31
32
|
}>
|
|
32
33
|
export type AuthorizationHandlerPatch = Record<string, unknown>
|
|
@@ -105,6 +106,7 @@ const connectionMapParsers = {
|
|
|
105
106
|
const outboundHostValidatorParsers = {
|
|
106
107
|
enabled: asBoolean,
|
|
107
108
|
includeDefaultMicrosoftHosts: asBoolean,
|
|
109
|
+
allowPrivateNetworkAddresses: asBoolean,
|
|
108
110
|
hosts: asList
|
|
109
111
|
} satisfies Record<string, (value: string) => unknown>
|
|
110
112
|
|
|
@@ -489,7 +491,7 @@ function parseValue (
|
|
|
489
491
|
? parseDocumentValue(parser, value)
|
|
490
492
|
: typeof value === 'string' ? parser(value) : undefined
|
|
491
493
|
if (parsed === undefined) {
|
|
492
|
-
if (key === 'validateIssuer') {
|
|
494
|
+
if (key === 'validateIssuer' || key === 'allowPrivateNetworkAddresses') {
|
|
493
495
|
throw ExceptionHelper.generateException(
|
|
494
496
|
TypeError,
|
|
495
497
|
Errors.InvalidBooleanConfigurationValue,
|
|
@@ -598,7 +600,7 @@ export function setConfigurationValue (
|
|
|
598
600
|
if (parsed.key === 'hosts') {
|
|
599
601
|
;(target.outboundHostValidator as OutboundHostValidatorConfigurationPatch).hosts = parsed.value as string[]
|
|
600
602
|
} else {
|
|
601
|
-
;(target.outboundHostValidator as OutboundHostValidatorConfigurationPatch)[parsed.key as 'enabled' | 'includeDefaultMicrosoftHosts'] = parsed.value as boolean
|
|
603
|
+
;(target.outboundHostValidator as OutboundHostValidatorConfigurationPatch)[parsed.key as 'enabled' | 'includeDefaultMicrosoftHosts' | 'allowPrivateNetworkAddresses'] = parsed.value as boolean
|
|
602
604
|
}
|
|
603
605
|
return
|
|
604
606
|
}
|
|
@@ -256,7 +256,13 @@ function bindOutboundHostValidator (
|
|
|
256
256
|
emitHierarchySuggestion(sourceName, [parts[0], suggestedProperty].join('__'), true)
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
|
-
trySet(
|
|
259
|
+
trySet(
|
|
260
|
+
layer,
|
|
261
|
+
`outboundHostValidator.${parts[1]}`,
|
|
262
|
+
value,
|
|
263
|
+
sourceName,
|
|
264
|
+
parts[1].toLowerCase() === 'allowprivatenetworkaddresses'
|
|
265
|
+
)
|
|
260
266
|
}
|
|
261
267
|
|
|
262
268
|
function bindAuthorizationHandler (
|
|
@@ -53,6 +53,7 @@ export class ConnectorClient {
|
|
|
53
53
|
this._httpClient = httpClient
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/** Gets the HTTP client used for Connector API requests. */
|
|
56
57
|
public get httpClient (): HttpClient {
|
|
57
58
|
return this._httpClient
|
|
58
59
|
}
|
|
@@ -127,6 +128,13 @@ export class ConnectorClient {
|
|
|
127
128
|
})
|
|
128
129
|
}
|
|
129
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Retrieves a member of a conversation.
|
|
133
|
+
*
|
|
134
|
+
* @param userId The member's channel user ID.
|
|
135
|
+
* @param conversationId The conversation ID.
|
|
136
|
+
* @returns The member's channel account.
|
|
137
|
+
*/
|
|
130
138
|
public async getConversationMember (userId: string, conversationId: string): Promise<ChannelAccount> {
|
|
131
139
|
return trace(ConnectorClientTraceDefinitions.getConversationMember, async ({ record }) => {
|
|
132
140
|
if (!userId || !conversationId) {
|
|
@@ -15,7 +15,9 @@ import { TurnState } from './app/turnState'
|
|
|
15
15
|
* Result of creating a CloudAdapter from an agent.
|
|
16
16
|
*/
|
|
17
17
|
export interface CloudAdapterResult {
|
|
18
|
+
/** The adapter to use for processing requests. */
|
|
18
19
|
adapter: CloudAdapter
|
|
20
|
+
/** The application's outbound header propagation callback, when configured. */
|
|
19
21
|
headerPropagation: HeaderPropagationDefinition | undefined
|
|
20
22
|
}
|
|
21
23
|
|
package/src/errorHelper.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { AgentErrorDefinition } from '@microsoft/agents-activity'
|
|
5
5
|
|
|
6
|
+
/** Error definitions used by the hosting package. */
|
|
6
7
|
export const Errors: { [key: string]: AgentErrorDefinition } = {
|
|
7
8
|
// ============================================================================
|
|
8
9
|
// TurnContext and Activity Errors (-120000 to -120090)
|
|
@@ -295,6 +296,16 @@ export const Errors: { [key: string]: AgentErrorDefinition } = {
|
|
|
295
296
|
description: 'HttpClient requires baseURL when using a relative URL: {url}'
|
|
296
297
|
},
|
|
297
298
|
|
|
299
|
+
AttachmentDownloadRedirectLimit: {
|
|
300
|
+
code: -120292,
|
|
301
|
+
description: 'Attachment download exceeded the maximum of 50 redirects.'
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
AttachmentDownloadInvalidRedirect: {
|
|
305
|
+
code: -120293,
|
|
306
|
+
description: 'Attachment download returned an invalid redirect URL.'
|
|
307
|
+
},
|
|
308
|
+
|
|
298
309
|
// ============================================================================
|
|
299
310
|
// Connection and Authentication Errors (-120300 to -120599)
|
|
300
311
|
// ============================================================================
|
package/src/headerPropagation.ts
CHANGED
|
@@ -17,14 +17,21 @@ export class HeaderPropagation implements HeaderPropagationCollection {
|
|
|
17
17
|
|
|
18
18
|
private _protectedHeaders = ['x-ms-correlation-id']
|
|
19
19
|
|
|
20
|
+
/** Gets the normalized headers received on the incoming request. */
|
|
20
21
|
public get incoming (): Record<string, string> {
|
|
21
22
|
return this._incomingRequests
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
/** Gets the headers selected for propagation to outgoing requests. */
|
|
24
26
|
public get outgoing (): Record<string, string> {
|
|
25
27
|
return this._outgoingHeaders
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Creates a header propagation collection from incoming request headers.
|
|
32
|
+
*
|
|
33
|
+
* @param headers The incoming headers, including optional multi-value headers.
|
|
34
|
+
*/
|
|
28
35
|
constructor (headers: Record<string, string | string[] | undefined>) {
|
|
29
36
|
if (!headers) {
|
|
30
37
|
throw ExceptionHelper.generateException(Error, Errors.HeadersRequired)
|
|
@@ -39,6 +46,11 @@ export class HeaderPropagation implements HeaderPropagationCollection {
|
|
|
39
46
|
this._protectedHeaders = protectedHeaders // Restore protected headers list after propagation
|
|
40
47
|
}
|
|
41
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Copies existing incoming header values to the outgoing collection.
|
|
51
|
+
*
|
|
52
|
+
* @param headers The header names to propagate.
|
|
53
|
+
*/
|
|
42
54
|
propagate (headers: string[]) {
|
|
43
55
|
this.process(headers.map(h => [h, '']), key => {
|
|
44
56
|
if (this._incomingRequests[key] && !this._outgoingHeaders[key]) {
|
|
@@ -47,6 +59,11 @@ export class HeaderPropagation implements HeaderPropagationCollection {
|
|
|
47
59
|
})
|
|
48
60
|
}
|
|
49
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Adds headers that do not already exist in either collection.
|
|
64
|
+
*
|
|
65
|
+
* @param headers The headers to add.
|
|
66
|
+
*/
|
|
50
67
|
add (headers: Record<string, string>) {
|
|
51
68
|
this.process(Object.entries(headers ?? {}), (key, value) => {
|
|
52
69
|
if (!this._incomingRequests[key] && !this._outgoingHeaders[key]) {
|
|
@@ -55,6 +72,11 @@ export class HeaderPropagation implements HeaderPropagationCollection {
|
|
|
55
72
|
})
|
|
56
73
|
}
|
|
57
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Appends values to headers that already exist in either collection.
|
|
77
|
+
*
|
|
78
|
+
* @param headers The values to append.
|
|
79
|
+
*/
|
|
58
80
|
concat (headers: Record<string, string>) {
|
|
59
81
|
this.process(Object.entries(headers ?? {}), (key, value) => {
|
|
60
82
|
if (this._incomingRequests[key] || this._outgoingHeaders[key]) {
|
|
@@ -63,12 +85,23 @@ export class HeaderPropagation implements HeaderPropagationCollection {
|
|
|
63
85
|
})
|
|
64
86
|
}
|
|
65
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Sets outgoing header values unless the headers are protected.
|
|
90
|
+
*
|
|
91
|
+
* @param headers The headers to set.
|
|
92
|
+
*/
|
|
66
93
|
override (headers: Record<string, string>) {
|
|
67
94
|
this.process(Object.entries(headers ?? {}), (key, value) => {
|
|
68
95
|
this._outgoingHeaders[key] = value
|
|
69
96
|
})
|
|
70
97
|
}
|
|
71
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Finds a known header name without regard to casing.
|
|
101
|
+
*
|
|
102
|
+
* @param key The header name to find.
|
|
103
|
+
* @returns The original-cased header name, or `undefined` when it is unknown.
|
|
104
|
+
*/
|
|
72
105
|
key (key: string) {
|
|
73
106
|
return this._keys.find(k => k.toLowerCase() === key.toLowerCase())
|
|
74
107
|
}
|
|
@@ -113,6 +146,11 @@ export class HeaderPropagation implements HeaderPropagationCollection {
|
|
|
113
146
|
* A function type that defines how headers should be propagated.
|
|
114
147
|
*/
|
|
115
148
|
export interface HeaderPropagationDefinition {
|
|
149
|
+
/**
|
|
150
|
+
* Configures outgoing headers for a request.
|
|
151
|
+
*
|
|
152
|
+
* @param headers The collection to configure.
|
|
153
|
+
*/
|
|
116
154
|
(headers: HeaderPropagationCollection): void
|
|
117
155
|
}
|
|
118
156
|
|
package/src/httpClient.ts
CHANGED
|
@@ -11,13 +11,21 @@ import { Errors } from './errorHelper'
|
|
|
11
11
|
* Configuration for an HTTP request.
|
|
12
12
|
*/
|
|
13
13
|
export interface HttpRequestConfig {
|
|
14
|
+
/** The HTTP method. */
|
|
14
15
|
method: string
|
|
16
|
+
/** The absolute URL or path relative to the client's base URL. */
|
|
15
17
|
url: string
|
|
18
|
+
/** Headers to merge with the client's default headers. */
|
|
16
19
|
headers?: Record<string, string>
|
|
20
|
+
/** The request body. */
|
|
17
21
|
data?: unknown
|
|
22
|
+
/** Query parameters to append to the URL. */
|
|
18
23
|
params?: Record<string, string | undefined>
|
|
24
|
+
/** The format used to read the response body. */
|
|
19
25
|
responseType?: 'json' | 'arraybuffer' | 'stream'
|
|
26
|
+
/** The request timeout in milliseconds. */
|
|
20
27
|
timeout?: number
|
|
28
|
+
/** A signal used to cancel the request. */
|
|
21
29
|
signal?: AbortSignal
|
|
22
30
|
}
|
|
23
31
|
|
|
@@ -25,10 +33,15 @@ export interface HttpRequestConfig {
|
|
|
25
33
|
* Represents an HTTP response.
|
|
26
34
|
*/
|
|
27
35
|
export interface HttpResponse<T = unknown> {
|
|
36
|
+
/** The parsed response body. */
|
|
28
37
|
data: T
|
|
38
|
+
/** The HTTP status code. */
|
|
29
39
|
status: number
|
|
40
|
+
/** The HTTP status text. */
|
|
30
41
|
statusText: string
|
|
42
|
+
/** The response headers. */
|
|
31
43
|
headers: Headers
|
|
44
|
+
/** The configuration used for the request. */
|
|
32
45
|
config: HttpRequestConfig
|
|
33
46
|
}
|
|
34
47
|
|
|
@@ -36,7 +49,9 @@ export interface HttpResponse<T = unknown> {
|
|
|
36
49
|
* Options for creating an HttpClient instance.
|
|
37
50
|
*/
|
|
38
51
|
export interface HttpClientOptions {
|
|
52
|
+
/** The base URL used for relative request URLs. */
|
|
39
53
|
baseURL?: string
|
|
54
|
+
/** Default headers included with every request. */
|
|
40
55
|
headers?: Record<string, string>
|
|
41
56
|
}
|
|
42
57
|
|
|
@@ -47,27 +62,48 @@ export class HttpClient {
|
|
|
47
62
|
private _baseURL: string
|
|
48
63
|
private _defaultHeaders: Record<string, string>
|
|
49
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Creates an HTTP client.
|
|
67
|
+
*
|
|
68
|
+
* @param options The base URL and default headers.
|
|
69
|
+
*/
|
|
50
70
|
constructor (options: HttpClientOptions = {}) {
|
|
51
71
|
this._baseURL = options.baseURL ?? ''
|
|
52
72
|
this._defaultHeaders = this.normalizeHeaders(options.headers)
|
|
53
73
|
}
|
|
54
74
|
|
|
75
|
+
/** Gets the base URL used for relative requests. */
|
|
55
76
|
get baseURL (): string {
|
|
56
77
|
return this._baseURL
|
|
57
78
|
}
|
|
58
79
|
|
|
80
|
+
/** Gets the normalized default request headers. */
|
|
59
81
|
get defaultHeaders (): Record<string, string> {
|
|
60
82
|
return this._defaultHeaders
|
|
61
83
|
}
|
|
62
84
|
|
|
85
|
+
/** Replaces the default request headers. */
|
|
63
86
|
set defaultHeaders (headers: Record<string, string>) {
|
|
64
87
|
this._defaultHeaders = this.normalizeHeaders(headers)
|
|
65
88
|
}
|
|
66
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Sets a default request header.
|
|
92
|
+
*
|
|
93
|
+
* @param name The header name.
|
|
94
|
+
* @param value The header value.
|
|
95
|
+
*/
|
|
67
96
|
setHeader (name: string, value: string): void {
|
|
68
97
|
this._defaultHeaders[name.toLowerCase()] = value
|
|
69
98
|
}
|
|
70
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Sends an HTTP request.
|
|
102
|
+
*
|
|
103
|
+
* @param config The request configuration.
|
|
104
|
+
* @returns The response with its parsed body.
|
|
105
|
+
* @throws An {@link HttpError} when the response status is not successful.
|
|
106
|
+
*/
|
|
71
107
|
async request<T = unknown> (config: HttpRequestConfig): Promise<HttpResponse<T>> {
|
|
72
108
|
const url = this.buildUrl(config.url, config.params)
|
|
73
109
|
const headers = this.normalizeHeaders({ ...this._defaultHeaders, ...config.headers })
|
|
@@ -142,6 +178,13 @@ export class HttpClient {
|
|
|
142
178
|
return httpResponse
|
|
143
179
|
}
|
|
144
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Sends an HTTP request, defaulting to GET.
|
|
183
|
+
*
|
|
184
|
+
* @param url The absolute URL or path relative to the client's base URL.
|
|
185
|
+
* @param options Additional request options. The `method` and `url` options override the defaults.
|
|
186
|
+
* @returns The response with its parsed body.
|
|
187
|
+
*/
|
|
145
188
|
async get<T = unknown> (url: string, options?: Partial<HttpRequestConfig>): Promise<HttpResponse<T>> {
|
|
146
189
|
return this.request<T>({ method: 'get', url, ...options })
|
|
147
190
|
}
|
|
@@ -192,10 +235,20 @@ export class HttpClient {
|
|
|
192
235
|
* Error thrown when an HTTP request fails.
|
|
193
236
|
*/
|
|
194
237
|
export class HttpError extends Error {
|
|
238
|
+
/** The unsuccessful HTTP response. */
|
|
195
239
|
public readonly response: HttpResponse
|
|
240
|
+
/** The configuration used for the request. */
|
|
196
241
|
public readonly config: HttpRequestConfig
|
|
242
|
+
/** The HTTP status code. */
|
|
197
243
|
public readonly status: number
|
|
198
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Creates an HTTP request error.
|
|
247
|
+
*
|
|
248
|
+
* @param message The error message.
|
|
249
|
+
* @param response The unsuccessful response.
|
|
250
|
+
* @param config The request configuration.
|
|
251
|
+
*/
|
|
199
252
|
constructor (message: string, response: HttpResponse, config: HttpRequestConfig) {
|
|
200
253
|
super(message)
|
|
201
254
|
this.name = 'HttpError'
|
|
@@ -204,6 +257,11 @@ export class HttpError extends Error {
|
|
|
204
257
|
this.status = response.status
|
|
205
258
|
}
|
|
206
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Returns a serializable representation of the error.
|
|
262
|
+
*
|
|
263
|
+
* @returns The error, request, and response details.
|
|
264
|
+
*/
|
|
207
265
|
toJSON (): Record<string, unknown> {
|
|
208
266
|
return {
|
|
209
267
|
message: this.message,
|
|
@@ -17,11 +17,17 @@
|
|
|
17
17
|
* longer needs to import types from `express` at compile time.
|
|
18
18
|
*/
|
|
19
19
|
export interface WebResponse {
|
|
20
|
+
/** Sets the HTTP status code. */
|
|
20
21
|
status (code: number): this
|
|
22
|
+
/** Sets a response header. */
|
|
21
23
|
setHeader (name: string, value: string): this
|
|
24
|
+
/** Sends an optional response body. */
|
|
22
25
|
send (body?: unknown): this
|
|
26
|
+
/** Ends the response. */
|
|
23
27
|
end (): this
|
|
28
|
+
/** Indicates whether response headers have been sent. */
|
|
24
29
|
headersSent: boolean
|
|
30
|
+
/** Indicates whether the response stream has ended. */
|
|
25
31
|
writableEnded: boolean
|
|
26
32
|
}
|
|
27
33
|
|
|
@@ -40,5 +46,6 @@ export type NextFunction = (err?: any) => void
|
|
|
40
46
|
* (`req.params.conversationId`) without coupling to Express's `Request` type.
|
|
41
47
|
*/
|
|
42
48
|
export interface WebRequestParamsCarrier {
|
|
49
|
+
/** Route parameters parsed from the request URL. */
|
|
43
50
|
params?: Record<string, string | undefined>
|
|
44
51
|
}
|