@microsoft/agents-hosting 1.10.0-beta.8.g158a2c07ad → 1.10.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/README.md +41 -2
- package/dist/package.json +3 -3
- 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 +0 -8
- package/dist/src/auth/sidecar/sidecarHttpClient.js +2 -68
- package/dist/src/auth/sidecar/sidecarHttpClient.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.js +16 -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 +3 -3
- 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 +2 -62
- package/src/cards/taskModuleAction.ts +6 -0
- package/src/cloudAdapter.ts +30 -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
|
@@ -33,6 +33,7 @@ interface MemoryStorageState {
|
|
|
33
33
|
class MemoryStorageInternals {
|
|
34
34
|
private static readonly states = new WeakMap<object, MemoryStorageState>()
|
|
35
35
|
|
|
36
|
+
/** The shared values and metadata for this storage instance. */
|
|
36
37
|
readonly state: MemoryStorageState
|
|
37
38
|
|
|
38
39
|
/**
|
|
@@ -47,24 +48,53 @@ class MemoryStorageInternals {
|
|
|
47
48
|
this.state = state
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Saves a value and updates its version and expiration metadata.
|
|
53
|
+
*
|
|
54
|
+
* @param key The storage key.
|
|
55
|
+
* @param item The value to store.
|
|
56
|
+
* @param expiresAt The optional expiration time, expressed as Unix time in milliseconds.
|
|
57
|
+
* @returns The new version.
|
|
58
|
+
*/
|
|
50
59
|
save (key: string, item: unknown, expiresAt?: number): string {
|
|
51
60
|
const version = (this.state.etag++).toString()
|
|
52
61
|
this.state.memory[key] = JSON.stringify(item)
|
|
53
62
|
this.state.versions[key] = version
|
|
54
|
-
if (expiresAt === undefined)
|
|
55
|
-
|
|
63
|
+
if (expiresAt === undefined) {
|
|
64
|
+
delete this.state.expirations[key]
|
|
65
|
+
} else {
|
|
66
|
+
this.state.expirations[key] = expiresAt
|
|
67
|
+
}
|
|
56
68
|
return version
|
|
57
69
|
}
|
|
58
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Gets the version associated with a stored value.
|
|
73
|
+
*
|
|
74
|
+
* @param key The storage key.
|
|
75
|
+
* @param value The stored value.
|
|
76
|
+
* @returns The version, when available.
|
|
77
|
+
*/
|
|
59
78
|
getVersion (key: string, value: StoreItem): string | undefined {
|
|
60
79
|
return this.state.versions[key] ?? value.eTag as string | undefined
|
|
61
80
|
}
|
|
62
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Determines whether a stored value has expired.
|
|
84
|
+
*
|
|
85
|
+
* @param key The storage key.
|
|
86
|
+
* @returns `true` when the value has expired; otherwise, `false`.
|
|
87
|
+
*/
|
|
63
88
|
isExpired (key: string): boolean {
|
|
64
89
|
const expiresAt = this.state.expirations[key]
|
|
65
90
|
return expiresAt !== undefined && expiresAt <= Date.now()
|
|
66
91
|
}
|
|
67
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Removes a value and its version and expiration metadata.
|
|
95
|
+
*
|
|
96
|
+
* @param key The storage key.
|
|
97
|
+
*/
|
|
68
98
|
remove (key: string): void {
|
|
69
99
|
delete this.state.memory[key]
|
|
70
100
|
delete this.state.versions[key]
|
|
@@ -81,6 +111,11 @@ class MemoryStorageInternals {
|
|
|
81
111
|
export class MemoryStorage extends MemoryStorageInternals implements Storage {
|
|
82
112
|
private static instance: MemoryStorage
|
|
83
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Creates a legacy in-memory storage provider.
|
|
116
|
+
*
|
|
117
|
+
* @param memory Optional backing store to share with another in-memory storage instance.
|
|
118
|
+
*/
|
|
84
119
|
constructor (memory: { [key: string]: string } = {}) {
|
|
85
120
|
super(memory)
|
|
86
121
|
}
|
|
@@ -160,8 +195,11 @@ export class MemoryStorage extends MemoryStorageInternals implements Storage {
|
|
|
160
195
|
})
|
|
161
196
|
}
|
|
162
197
|
|
|
198
|
+
/** Returns the process-wide legacy memory storage instance. */
|
|
163
199
|
static getSingleInstance (): MemoryStorage {
|
|
164
|
-
if (!MemoryStorage.instance)
|
|
200
|
+
if (!MemoryStorage.instance) {
|
|
201
|
+
MemoryStorage.instance = new MemoryStorage()
|
|
202
|
+
}
|
|
165
203
|
return MemoryStorage.instance
|
|
166
204
|
}
|
|
167
205
|
}
|
|
@@ -323,8 +361,11 @@ export class MemoryStorageV2 extends StorageV2 {
|
|
|
323
361
|
})
|
|
324
362
|
}
|
|
325
363
|
|
|
364
|
+
/** Returns the process-wide V2 memory storage instance. */
|
|
326
365
|
static getSingleInstance (): MemoryStorageV2 {
|
|
327
|
-
if (!MemoryStorageV2.instance)
|
|
366
|
+
if (!MemoryStorageV2.instance) {
|
|
367
|
+
MemoryStorageV2.instance = new MemoryStorageV2()
|
|
368
|
+
}
|
|
328
369
|
return MemoryStorageV2.instance
|
|
329
370
|
}
|
|
330
371
|
}
|
package/src/storage/storage.ts
CHANGED
|
@@ -111,9 +111,13 @@ export interface Storage {
|
|
|
111
111
|
* available when `status` is {@link StorageOperationStatus.Succeeded}.
|
|
112
112
|
*/
|
|
113
113
|
export interface StorageReadResult<T extends object = Record<string, unknown>> {
|
|
114
|
+
/** The requested storage key. */
|
|
114
115
|
key: string;
|
|
116
|
+
/** The outcome of the read. */
|
|
115
117
|
status: StorageOperationStatus;
|
|
118
|
+
/** The stored value when the read succeeds. */
|
|
116
119
|
value?: T;
|
|
120
|
+
/** The stored version when available. */
|
|
117
121
|
version?: string;
|
|
118
122
|
}
|
|
119
123
|
|
|
@@ -121,8 +125,11 @@ export interface StorageReadResult<T extends object = Record<string, unknown>> {
|
|
|
121
125
|
* The result of a version 2 storage write operation.
|
|
122
126
|
*/
|
|
123
127
|
export interface StorageWriteResult {
|
|
128
|
+
/** The supplied storage key. */
|
|
124
129
|
key: string;
|
|
130
|
+
/** The outcome of the write. */
|
|
125
131
|
status: StorageOperationStatus;
|
|
132
|
+
/** The resulting or current storage version when available. */
|
|
126
133
|
version?: string;
|
|
127
134
|
}
|
|
128
135
|
|
|
@@ -130,8 +137,11 @@ export interface StorageWriteResult {
|
|
|
130
137
|
* The result of a version 2 storage delete operation.
|
|
131
138
|
*/
|
|
132
139
|
export interface StorageDeleteResult {
|
|
140
|
+
/** The supplied storage key. */
|
|
133
141
|
key: string;
|
|
142
|
+
/** The outcome of the delete. */
|
|
134
143
|
status: StorageOperationStatus;
|
|
144
|
+
/** The deleted or current storage version when available. */
|
|
135
145
|
version?: string;
|
|
136
146
|
}
|
|
137
147
|
|
|
@@ -146,16 +156,23 @@ export type StorageDeleteResults = Record<string, StorageDeleteResult>
|
|
|
146
156
|
|
|
147
157
|
/** The outcome of one version 2 storage operation. */
|
|
148
158
|
export enum StorageOperationStatus {
|
|
159
|
+
/** The operation completed successfully. */
|
|
149
160
|
Succeeded = 'succeeded',
|
|
161
|
+
/** No item exists for the key. */
|
|
150
162
|
NotFound = 'notFound',
|
|
163
|
+
/** A create-only operation found an existing item. */
|
|
151
164
|
Conflict = 'conflict',
|
|
165
|
+
/** The expected version did not match the current version. */
|
|
152
166
|
ConditionNotMet = 'conditionNotMet',
|
|
153
167
|
}
|
|
154
168
|
|
|
155
169
|
/** The write mode for a version 2 storage operation. */
|
|
156
170
|
export enum StorageWriteMode {
|
|
171
|
+
/** Creates a new item or replaces an existing item. */
|
|
157
172
|
Upsert = 'upsert',
|
|
173
|
+
/** Creates an item only when the key does not exist. */
|
|
158
174
|
CreateOnly = 'createOnly',
|
|
175
|
+
/** Replaces an item only when the key exists. */
|
|
159
176
|
Replace = 'replace',
|
|
160
177
|
}
|
|
161
178
|
|
|
@@ -168,12 +185,15 @@ export interface StorageWriteOptions {
|
|
|
168
185
|
* duration has elapsed. Values must be finite numbers greater than zero.
|
|
169
186
|
*/
|
|
170
187
|
ttl?: number;
|
|
188
|
+
/** The condition controlling whether existing items may be written. */
|
|
171
189
|
mode?: StorageWriteMode;
|
|
190
|
+
/** The storage version that must match before writing. */
|
|
172
191
|
expectedVersion?: string;
|
|
173
192
|
}
|
|
174
193
|
|
|
175
194
|
/** Options applied to every item in a version 2 delete operation. */
|
|
176
195
|
export interface StorageDeleteOptions {
|
|
196
|
+
/** The storage version that must match before deleting. */
|
|
177
197
|
expectedVersion?: string;
|
|
178
198
|
}
|
|
179
199
|
|
|
@@ -31,8 +31,12 @@ export function asStorageV2 (storage: StorageProvider): StorageV2 {
|
|
|
31
31
|
/** Returns a successful V2 read value, maps not-found to undefined, and rejects invalid results. */
|
|
32
32
|
export function getStorageReadValue<T extends object> (results: StorageReadResults<T> | null | undefined, key: string): T | undefined {
|
|
33
33
|
const result = results?.[key]
|
|
34
|
-
if (result?.status === StorageOperationStatus.NotFound)
|
|
35
|
-
|
|
34
|
+
if (result?.status === StorageOperationStatus.NotFound) {
|
|
35
|
+
return undefined
|
|
36
|
+
}
|
|
37
|
+
if (result?.status === StorageOperationStatus.Succeeded) {
|
|
38
|
+
return result.value
|
|
39
|
+
}
|
|
36
40
|
throwStorageResultError('read', key, result?.status)
|
|
37
41
|
}
|
|
38
42
|
|
|
@@ -44,7 +48,9 @@ class StorageToStorageV2Adapter extends StorageV2 {
|
|
|
44
48
|
|
|
45
49
|
async read<T extends object = Record<string, unknown>> (keys: string[]): Promise<StorageReadResults<T>> {
|
|
46
50
|
validateKeys(keys)
|
|
47
|
-
if (keys.length === 0)
|
|
51
|
+
if (keys.length === 0) {
|
|
52
|
+
return {}
|
|
53
|
+
}
|
|
48
54
|
|
|
49
55
|
const items = await this.storage.read(keys)
|
|
50
56
|
return Object.fromEntries(keys.map(key => {
|
|
@@ -64,7 +70,9 @@ class StorageToStorageV2Adapter extends StorageV2 {
|
|
|
64
70
|
throwUnsupportedOption('ttl')
|
|
65
71
|
}
|
|
66
72
|
validateExpectedVersion(options?.expectedVersion)
|
|
67
|
-
if (Object.keys(changes).length === 0)
|
|
73
|
+
if (Object.keys(changes).length === 0) {
|
|
74
|
+
return {}
|
|
75
|
+
}
|
|
68
76
|
const legacyChanges = Object.fromEntries(Object.entries(changes).map(([key, value]) => [
|
|
69
77
|
key,
|
|
70
78
|
options?.expectedVersion === undefined
|
|
@@ -81,7 +89,9 @@ class StorageToStorageV2Adapter extends StorageV2 {
|
|
|
81
89
|
if (options?.expectedVersion !== undefined) {
|
|
82
90
|
throwUnsupportedOption('expectedVersion')
|
|
83
91
|
}
|
|
84
|
-
if (keys.length === 0)
|
|
92
|
+
if (keys.length === 0) {
|
|
93
|
+
return {}
|
|
94
|
+
}
|
|
85
95
|
|
|
86
96
|
await this.storage.delete(keys)
|
|
87
97
|
return Object.fromEntries(keys.map(key => [key, { key, status: StorageOperationStatus.Succeeded }]))
|
|
@@ -116,7 +126,9 @@ function validateChanges (changes: Record<string, unknown>): void {
|
|
|
116
126
|
}
|
|
117
127
|
|
|
118
128
|
function removeLegacyETag<T> (value: T): T {
|
|
119
|
-
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
129
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
130
|
+
return value
|
|
131
|
+
}
|
|
120
132
|
const { eTag: _eTag, ...withoutETag } = value as Record<string, unknown>
|
|
121
133
|
return withoutETag as T
|
|
122
134
|
}
|
|
@@ -7,6 +7,13 @@ import { StorageWriteOptions } from './storage'
|
|
|
7
7
|
import { ExceptionHelper } from '@microsoft/agents-activity'
|
|
8
8
|
import { Errors } from '../errorHelper'
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Computes an absolute expiration time for a storage write.
|
|
12
|
+
*
|
|
13
|
+
* @param options The write options containing an optional TTL in seconds.
|
|
14
|
+
* @returns The expiration time in milliseconds since the Unix epoch, or `undefined` when no TTL is set.
|
|
15
|
+
* @throws A `RangeError` when the TTL is not finite or is not greater than zero.
|
|
16
|
+
*/
|
|
10
17
|
export function getStorageWriteExpiry (options?: StorageWriteOptions): number | undefined {
|
|
11
18
|
const ttl = options?.ttl
|
|
12
19
|
if (ttl === undefined) {
|
package/src/turnContext.ts
CHANGED
|
@@ -82,9 +82,16 @@ export class TurnContext {
|
|
|
82
82
|
*
|
|
83
83
|
* @param adapterOrContext The adapter that created this context, or another TurnContext to clone
|
|
84
84
|
* @param request The activity for the turn (required when first parameter is an adapter)
|
|
85
|
+
* @param identity The authenticated identity for the turn.
|
|
85
86
|
*/
|
|
86
87
|
constructor (adapterOrContext: BaseAdapter, request: Activity, identity?: JwtPayload)
|
|
88
|
+
/**
|
|
89
|
+
* Creates a context by copying another turn context.
|
|
90
|
+
*
|
|
91
|
+
* @param adapterOrContext The turn context to copy.
|
|
92
|
+
*/
|
|
87
93
|
constructor (adapterOrContext: TurnContext)
|
|
94
|
+
/** Implements the adapter and copy constructor overloads. */
|
|
88
95
|
constructor (adapterOrContext: BaseAdapter | TurnContext, request?: Activity, identity?: JwtPayload) {
|
|
89
96
|
if (adapterOrContext instanceof TurnContext) {
|
|
90
97
|
adapterOrContext.copyTo(this)
|
|
@@ -367,6 +374,7 @@ export class TurnContext {
|
|
|
367
374
|
return this._activity as Activity
|
|
368
375
|
}
|
|
369
376
|
|
|
377
|
+
/** Gets the authenticated identity for the turn. */
|
|
370
378
|
get identity (): JwtPayload {
|
|
371
379
|
return this._identity as JwtPayload
|
|
372
380
|
}
|
|
@@ -382,6 +390,7 @@ export class TurnContext {
|
|
|
382
390
|
return this._respondedRef.responded
|
|
383
391
|
}
|
|
384
392
|
|
|
393
|
+
/** Marks the turn as having sent a response. */
|
|
385
394
|
set responded (value: boolean) {
|
|
386
395
|
if (!value) {
|
|
387
396
|
throw ExceptionHelper.generateException(Error, Errors.CannotSetRespondedToFalse)
|
|
@@ -404,6 +413,7 @@ export class TurnContext {
|
|
|
404
413
|
return undefined
|
|
405
414
|
}
|
|
406
415
|
|
|
416
|
+
/** Sets the locale stored in the turn state. */
|
|
407
417
|
set locale (value: string | undefined) {
|
|
408
418
|
let turnObj = this._turnState.get(this._turn)
|
|
409
419
|
if (turnObj) {
|
|
@@ -426,6 +436,7 @@ export class TurnContext {
|
|
|
426
436
|
return this._turnState
|
|
427
437
|
}
|
|
428
438
|
|
|
439
|
+
/** Gets the streaming response associated with this context. */
|
|
429
440
|
get streamingResponse (): StreamingResponse {
|
|
430
441
|
return this._streamingResponse
|
|
431
442
|
}
|
package/src/utils/env.ts
CHANGED
|
@@ -87,11 +87,19 @@ export const envParserUtils = {
|
|
|
87
87
|
* unrecognized.
|
|
88
88
|
*/
|
|
89
89
|
export function parseBooleanEnv (value: string | undefined): boolean | undefined {
|
|
90
|
-
if (value === undefined)
|
|
90
|
+
if (value === undefined) {
|
|
91
|
+
return undefined
|
|
92
|
+
}
|
|
91
93
|
const v = value.trim().toLowerCase()
|
|
92
|
-
if (v === 'true' || v === '1')
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
if (v === 'true' || v === '1') {
|
|
95
|
+
return true
|
|
96
|
+
}
|
|
97
|
+
if (v === '') {
|
|
98
|
+
return undefined
|
|
99
|
+
}
|
|
100
|
+
if (v === 'false' || v === '0') {
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
95
103
|
return undefined
|
|
96
104
|
}
|
|
97
105
|
|
|
@@ -104,7 +112,9 @@ export function parseBooleanEnv (value: string | undefined): boolean | undefined
|
|
|
104
112
|
* @returns A finite integer, or `fallback` when the input cannot be parsed.
|
|
105
113
|
*/
|
|
106
114
|
export function parseIntEnv (value: string | undefined, fallback: number): number {
|
|
107
|
-
if (value === undefined || value.trim() === '')
|
|
115
|
+
if (value === undefined || value.trim() === '') {
|
|
116
|
+
return fallback
|
|
117
|
+
}
|
|
108
118
|
const parsed = parseInt(value, 10)
|
|
109
119
|
return Number.isNaN(parsed) ? fallback : parsed
|
|
110
120
|
}
|
|
@@ -132,7 +142,9 @@ export function suggestClosest (
|
|
|
132
142
|
candidates: readonly string[],
|
|
133
143
|
maxDistance = 2
|
|
134
144
|
): string | undefined {
|
|
135
|
-
if (!input)
|
|
145
|
+
if (!input) {
|
|
146
|
+
return undefined
|
|
147
|
+
}
|
|
136
148
|
const a = input.toLowerCase()
|
|
137
149
|
const cutoff = Math.min(maxDistance, Math.max(1, Math.ceil(a.length / 2)))
|
|
138
150
|
let best: { name: string, distance: number } | undefined
|
|
@@ -140,7 +152,9 @@ export function suggestClosest (
|
|
|
140
152
|
const d = levenshtein(a, candidate.toLowerCase())
|
|
141
153
|
if (d <= cutoff && (!best || d < best.distance)) {
|
|
142
154
|
best = { name: candidate, distance: d }
|
|
143
|
-
if (d === 0)
|
|
155
|
+
if (d === 0) {
|
|
156
|
+
break
|
|
157
|
+
}
|
|
144
158
|
}
|
|
145
159
|
}
|
|
146
160
|
return best?.name
|
|
@@ -148,11 +162,19 @@ export function suggestClosest (
|
|
|
148
162
|
|
|
149
163
|
/** Standard Levenshtein edit distance using a single-row dynamic-programming table. */
|
|
150
164
|
function levenshtein (a: string, b: string): number {
|
|
151
|
-
if (a === b)
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
if (a === b) {
|
|
166
|
+
return 0
|
|
167
|
+
}
|
|
168
|
+
if (a.length === 0) {
|
|
169
|
+
return b.length
|
|
170
|
+
}
|
|
171
|
+
if (b.length === 0) {
|
|
172
|
+
return a.length
|
|
173
|
+
}
|
|
154
174
|
const row = new Array<number>(b.length + 1)
|
|
155
|
-
for (let j = 0; j <= b.length; j++)
|
|
175
|
+
for (let j = 0; j <= b.length; j++) {
|
|
176
|
+
row[j] = j
|
|
177
|
+
}
|
|
156
178
|
for (let i = 1; i <= a.length; i++) {
|
|
157
179
|
let prev = i - 1
|
|
158
180
|
row[0] = i
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { isIP } from 'node:net'
|
|
7
|
+
|
|
8
|
+
function normalizeAddress (address: string): string | undefined {
|
|
9
|
+
const unwrapped = address.startsWith('[') && address.endsWith(']') ? address.slice(1, -1) : address
|
|
10
|
+
const version = isIP(unwrapped)
|
|
11
|
+
if (version === 0) {
|
|
12
|
+
return undefined
|
|
13
|
+
}
|
|
14
|
+
return version === 6 ? new URL(`http://[${unwrapped}]`).hostname.slice(1, -1) : unwrapped
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function mappedIPv4 (address: string): string | undefined {
|
|
18
|
+
const match = address.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/)
|
|
19
|
+
if (!match) {
|
|
20
|
+
return undefined
|
|
21
|
+
}
|
|
22
|
+
const high = parseInt(match[1], 16)
|
|
23
|
+
const low = parseInt(match[2], 16)
|
|
24
|
+
return `${high >> 8}.${high & 0xff}.${low >> 8}.${low & 0xff}`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isPrivateOrLoopbackAddress (address: string): boolean {
|
|
28
|
+
const normalized = normalizeAddress(address)
|
|
29
|
+
if (!normalized) {
|
|
30
|
+
return false
|
|
31
|
+
}
|
|
32
|
+
const ipv4 = mappedIPv4(normalized) ?? normalized
|
|
33
|
+
if (isIP(ipv4) === 4) {
|
|
34
|
+
const bytes = ipv4.split('.').map(Number)
|
|
35
|
+
return bytes[0] === 127 ||
|
|
36
|
+
bytes[0] === 10 ||
|
|
37
|
+
(bytes[0] === 172 && bytes[1] >= 16 && bytes[1] <= 31) ||
|
|
38
|
+
(bytes[0] === 192 && bytes[1] === 168) ||
|
|
39
|
+
(bytes[0] === 169 && bytes[1] === 254)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (normalized === '::1') {
|
|
43
|
+
return true
|
|
44
|
+
}
|
|
45
|
+
const firstHextet = parseInt(normalized.split(':')[0], 16)
|
|
46
|
+
return (firstHextet & 0xfe00) === 0xfc00 ||
|
|
47
|
+
(firstHextet & 0xffc0) === 0xfe80 ||
|
|
48
|
+
(firstHextet & 0xffc0) === 0xfec0
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isBlockedOutboundAddress (address: string): boolean {
|
|
52
|
+
const normalized = normalizeAddress(address)
|
|
53
|
+
if (!normalized) {
|
|
54
|
+
return true
|
|
55
|
+
}
|
|
56
|
+
const ipv4 = mappedIPv4(normalized) ?? normalized
|
|
57
|
+
const [first, second] = ipv4.split('.').map(Number)
|
|
58
|
+
// RFC 6598 shared space is outbound-only; it must not become trusted sidecar space.
|
|
59
|
+
return normalized === '::' ||
|
|
60
|
+
ipv4 === '0.0.0.0' ||
|
|
61
|
+
(first === 100 && second >= 64 && second <= 127) ||
|
|
62
|
+
isPrivateOrLoopbackAddress(normalized)
|
|
63
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { promises as dns } from 'node:dns'
|
|
7
|
+
import { isIP } from 'node:net'
|
|
8
|
+
import { debug } from '@microsoft/agents-telemetry'
|
|
9
|
+
import { isBlockedOutboundAddress } from './ipAddress'
|
|
10
|
+
|
|
11
|
+
const logger = debug('agents:outboundHostValidator')
|
|
12
|
+
|
|
13
|
+
export function getHttpsUrl (input: string | URL | null | undefined): URL | undefined {
|
|
14
|
+
if (!input) {
|
|
15
|
+
return undefined
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const url = input instanceof URL ? input : new URL(input)
|
|
19
|
+
return url.protocol === 'https:' && !url.username && !url.password ? url : undefined
|
|
20
|
+
} catch {
|
|
21
|
+
return undefined
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isLocalOrBlockedHost (host: string): boolean {
|
|
26
|
+
const unwrapped = host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host
|
|
27
|
+
return host === 'localhost' || host.endsWith('.localhost') ||
|
|
28
|
+
(isIP(unwrapped) !== 0 && isBlockedOutboundAddress(unwrapped))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function hasAllowedOutboundAddresses (url: URL, allowPrivateNetworkAddresses = false): Promise<boolean> {
|
|
32
|
+
if (allowPrivateNetworkAddresses) {
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
const host = url.hostname.replace(/^\[|\]$/g, '').replace(/\.$/, '')
|
|
36
|
+
if (isLocalOrBlockedHost(host)) {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
if (isIP(host) !== 0) {
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const addresses = await dns.lookup(host, { all: true })
|
|
45
|
+
return addresses.length > 0 && addresses.every(({ address }) => !isBlockedOutboundAddress(address))
|
|
46
|
+
} catch {
|
|
47
|
+
logger.warn(`Attachment destination DNS lookup failed. Host='${host}'`)
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -18,7 +18,9 @@ export const mergeDefined = <T extends Record<string, any>>(
|
|
|
18
18
|
): T => {
|
|
19
19
|
const result: Partial<T> = {}
|
|
20
20
|
for (const layer of layers) {
|
|
21
|
-
if (layer)
|
|
21
|
+
if (layer) {
|
|
22
|
+
Object.assign(result, prune(layer))
|
|
23
|
+
}
|
|
22
24
|
}
|
|
23
25
|
return result as T
|
|
24
26
|
}
|