From 43dbec105d2ac6a69bfeef59d9862da93d61c2c4 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Mon, 9 Nov 2026 18:58:56 -0800 Subject: [PATCH 01/13] Ship real type declarations for botframework-directlinespeech-sdk --- packages/directlinespeech/package.json | 3 +- packages/directlinespeech/src/index.d.ts | 90 ++++++++++++++++++++++++ packages/directlinespeech/tsup.config.ts | 6 ++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 packages/directlinespeech/src/index.d.ts diff --git a/packages/directlinespeech/package.json b/packages/directlinespeech/package.json index 0804fc19c7..69a83d8c00 100644 --- a/packages/directlinespeech/package.json +++ b/packages/directlinespeech/package.json @@ -8,6 +8,7 @@ "./src/**/*" ], "main": "./lib/index.js", + "types": "./dist/botframework-directlinespeech-sdk.d.ts", "exports": { ".": { "import": { @@ -15,7 +16,7 @@ "default": "./dist/botframework-directlinespeech-sdk.mjs" }, "require": { - "types": "./lib/index.d.ts", + "types": "./dist/botframework-directlinespeech-sdk.d.ts", "default": "./lib/index.js" } } diff --git a/packages/directlinespeech/src/index.d.ts b/packages/directlinespeech/src/index.d.ts new file mode 100644 index 0000000000..45dc133349 --- /dev/null +++ b/packages/directlinespeech/src/index.d.ts @@ -0,0 +1,90 @@ +// Type declarations for the JavaScript entry point (`index.js`), keep them in sync. + +import type { AudioConfig } from 'microsoft-cognitiveservices-speech-sdk'; +import type { createSpeechRecognitionPonyfillFromRecognizer } from 'web-speech-cognitive-services'; + +type Activity = { [key: string]: unknown; type?: string | undefined }; + +type Observer = { + complete?(): void; + error?(error: unknown): void; + next?(value: T): void; +}; + +type Subscription = { readonly closed: boolean; unsubscribe(): void }; + +type Observable = { + subscribe(observer: Observer): Subscription; + subscribe(next: (value: T) => void, error?: (error: unknown) => void, complete?: () => void): Subscription; +}; + +type DirectLineSpeechCredentials = { + /** Authorization token, mutually exclusive with `subscriptionKey`. */ + authorizationToken?: string | undefined; + /** Host name of the Direct Line Speech channel, mutually exclusive with `region`. */ + directLineSpeechHostname?: string | undefined; + /** Direct Line token, required when `enableInternalHTTPSupport` is set. */ + directLineToken?: string | undefined; + /** Azure region of the Speech resource, mutually exclusive with `directLineSpeechHostname`. */ + region?: string | undefined; + /** Subscription key, mutually exclusive with `authorizationToken`. */ + subscriptionKey?: string | undefined; +}; + +type CreateAdaptersInit = { + audioConfig?: AudioConfig | undefined; + audioContext?: AudioContext | undefined; + audioInputDeviceId?: string | undefined; + enableInternalHTTPSupport?: boolean | undefined; + /** Not supported yet, ignored with a warning. */ + enableTelemetry?: boolean | undefined; + /** Credentials, or a function returning them. Called again on every token renewal. */ + fetchCredentials: + | DirectLineSpeechCredentials + | Promise + | (() => DirectLineSpeechCredentials | Promise); + /** Not supported yet, ignored with a warning. */ + speechRecognitionEndpointId?: string | undefined; + speechRecognitionLanguage?: string | undefined; + /** Not supported yet, ignored with a warning. */ + speechSynthesisDeploymentId?: string | undefined; + /** Not supported yet, ignored with a warning. */ + speechSynthesisOutputFormat?: string | undefined; + /** Not supported yet, ignored with a warning. */ + textNormalization?: 'display' | 'itn' | 'lexical' | 'maskeditn' | undefined; + /** Not supported yet, ignored with a warning. */ + userID?: string | undefined; + /** Not supported yet, ignored with a warning. */ + username?: string | undefined; +}; + +type DirectLineSpeech = { + readonly activity$: Observable; + /** Values of `ConnectionStatus` in `botframework-directlinejs`. */ + readonly connectionStatus$: Observable; + end(): void; + postActivity(activity: Activity): Observable; +}; + +/** Empty when the browser does not support Web Audio API. */ +type WebSpeechPonyfill = Partial< + ReturnType & { + speechSynthesis: SpeechSynthesis; + SpeechSynthesisUtterance: typeof SpeechSynthesisUtterance; + } +>; + +declare const buildInfo: { + readonly buildTool: string | undefined; + readonly moduleFormat: string | undefined; + readonly version: string | undefined; +}; + +declare function createAdapters(init: CreateAdaptersInit): Promise<{ + directLine: DirectLineSpeech; + webSpeechPonyfillFactory: () => WebSpeechPonyfill; +}>; + +export { buildInfo, createAdapters }; + +export type { CreateAdaptersInit, DirectLineSpeech, DirectLineSpeechCredentials, WebSpeechPonyfill }; diff --git a/packages/directlinespeech/tsup.config.ts b/packages/directlinespeech/tsup.config.ts index 00fe52d763..535052d6e9 100644 --- a/packages/directlinespeech/tsup.config.ts +++ b/packages/directlinespeech/tsup.config.ts @@ -4,6 +4,12 @@ import { applyConfig } from '../../tsup.base.config'; const config = applyConfig(config => ({ ...config, + // The entry point is JavaScript, its types are written by hand. + dts: { + entry: { + 'botframework-directlinespeech-sdk': './src/index.d.ts' + } + }, entry: { 'botframework-directlinespeech-sdk': './src/index.js' }, From 0957e4d985910634255874765ac72facfe525310 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Mon, 9 Nov 2026 19:03:36 -0800 Subject: [PATCH 02/13] Fix the return type of createDirectLineSpeechAdapters --- .../bundle/src/createDirectLineSpeechAdapters.ts | 6 +++--- .../create-direct-line-speech-adapters.test-d.ts | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 packages/bundle/test-d/pass/create-direct-line-speech-adapters.test-d.ts diff --git a/packages/bundle/src/createDirectLineSpeechAdapters.ts b/packages/bundle/src/createDirectLineSpeechAdapters.ts index 51ccb4aa49..5bf1fe6d37 100644 --- a/packages/bundle/src/createDirectLineSpeechAdapters.ts +++ b/packages/bundle/src/createDirectLineSpeechAdapters.ts @@ -1,5 +1,5 @@ import { createAdapters } from 'botframework-directlinespeech-sdk'; -import { WebSpeechPonyfill } from 'botframework-webchat-api'; +import { WebSpeechPonyfillFactory } from 'botframework-webchat-api'; import type { DirectLineJSBotConnection } from 'botframework-webchat-core'; import { AudioConfig } from 'microsoft-cognitiveservices-speech-sdk'; @@ -41,7 +41,7 @@ export default function createDirectLineSpeechAdapters({ username?: string; }): Promise<{ directLine: DirectLineJSBotConnection; - webSpeechPonyfill: WebSpeechPonyfill; + webSpeechPonyfillFactory: WebSpeechPonyfillFactory; }> { if (audioConfig) { audioInputDeviceId && @@ -81,6 +81,6 @@ export default function createDirectLineSpeechAdapters({ textNormalization, userID, username - // TODO: [P1] Need to port Direct Line Speech SDK to TypeScript to remove this any. + // TODO: Remove "as any" when web-speech-cognitive-services types its ponyfill as "typeof SpeechRecognition". }) as any; } diff --git a/packages/bundle/test-d/pass/create-direct-line-speech-adapters.test-d.ts b/packages/bundle/test-d/pass/create-direct-line-speech-adapters.test-d.ts new file mode 100644 index 0000000000..96060b1367 --- /dev/null +++ b/packages/bundle/test-d/pass/create-direct-line-speech-adapters.test-d.ts @@ -0,0 +1,15 @@ +import '../setup'; + +import { type WebSpeechPonyfillFactory } from 'botframework-webchat-api'; +import { expectType } from 'tsd'; + +import { createDirectLineSpeechAdapters } from '../../src/boot/exports/index'; + +(async () => { + const { webSpeechPonyfillFactory } = await createDirectLineSpeechAdapters({ + fetchCredentials: { authorizationToken: '...', region: 'westus2' } + }); + + // Same name as the `webSpeechPonyfillFactory` prop, so the adapters can be spread into it. + expectType(webSpeechPonyfillFactory); +})(); From 7499413f7f46c33df1e78999f6dff34b08df664e Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Mon, 9 Nov 2026 19:17:22 -0800 Subject: [PATCH 03/13] Accept interface-typed activities and match the speech ponyfill type to the runtime --- packages/directlinespeech/src/index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/directlinespeech/src/index.d.ts b/packages/directlinespeech/src/index.d.ts index 45dc133349..071a5fb417 100644 --- a/packages/directlinespeech/src/index.d.ts +++ b/packages/directlinespeech/src/index.d.ts @@ -3,7 +3,7 @@ import type { AudioConfig } from 'microsoft-cognitiveservices-speech-sdk'; import type { createSpeechRecognitionPonyfillFromRecognizer } from 'web-speech-cognitive-services'; -type Activity = { [key: string]: unknown; type?: string | undefined }; +type Activity = { [key: string]: any; type?: string | undefined }; type Observer = { complete?(): void; @@ -52,7 +52,7 @@ type CreateAdaptersInit = { speechSynthesisOutputFormat?: string | undefined; /** Not supported yet, ignored with a warning. */ textNormalization?: 'display' | 'itn' | 'lexical' | 'maskeditn' | undefined; - /** Not supported yet, ignored with a warning. */ + /** Sent as the conversation's "from" ID, although a warning says custom user IDs are not supported. */ userID?: string | undefined; /** Not supported yet, ignored with a warning. */ username?: string | undefined; @@ -68,7 +68,7 @@ type DirectLineSpeech = { /** Empty when the browser does not support Web Audio API. */ type WebSpeechPonyfill = Partial< - ReturnType & { + Pick, 'SpeechGrammarList' | 'SpeechRecognition'> & { speechSynthesis: SpeechSynthesis; SpeechSynthesisUtterance: typeof SpeechSynthesisUtterance; } From 570df3e7879dcab17f24b5cffb67649d293b5bbb Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Mon, 9 Nov 2026 19:17:57 -0800 Subject: [PATCH 04/13] Add the changelog fragment --- .changelog/6037-fix-directlinespeech-types.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/6037-fix-directlinespeech-types.md diff --git a/.changelog/6037-fix-directlinespeech-types.md b/.changelog/6037-fix-directlinespeech-types.md new file mode 100644 index 0000000000..6a03a38dd1 --- /dev/null +++ b/.changelog/6037-fix-directlinespeech-types.md @@ -0,0 +1,3 @@ +### Fixed + +- Fixed `botframework-directlinespeech-sdk` shipping JavaScript as type declarations, and the `createDirectLineSpeechAdapters` return type naming `webSpeechPonyfill` instead of `webSpeechPonyfillFactory`, in PR [#6037](https://github.com/microsoft/BotFramework-WebChat/pull/6037), by [@OEvgeny](https://github.com/OEvgeny) From 3477ecdfecbdca9df529ba3e0b68a3279f82d54f Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Mon, 9 Nov 2026 20:54:03 -0800 Subject: [PATCH 05/13] Test the type declarations of botframework-directlinespeech-sdk with tsd --- .github/workflows/pull-request-validation.yml | 4 ++ package-lock.json | 1 + packages/directlinespeech/package.json | 10 ++++- .../test-d/build-info.test-d.ts | 9 +++++ ...reate-adapters-fetch-credentials.test-d.ts | 12 ++++++ .../create-adapters-invalid-options.test-d.ts | 13 +++++++ .../test-d/create-adapters-result.test-d.ts | 37 +++++++++++++++++++ 7 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 packages/directlinespeech/test-d/build-info.test-d.ts create mode 100644 packages/directlinespeech/test-d/create-adapters-fetch-credentials.test-d.ts create mode 100644 packages/directlinespeech/test-d/create-adapters-invalid-options.test-d.ts create mode 100644 packages/directlinespeech/test-d/create-adapters-result.test-d.ts diff --git a/.github/workflows/pull-request-validation.yml b/.github/workflows/pull-request-validation.yml index 9c0ad29714..868ee405c0 100644 --- a/.github/workflows/pull-request-validation.yml +++ b/.github/workflows/pull-request-validation.yml @@ -331,6 +331,10 @@ jobs: run: ../../node_modules/.bin/tsd -t ./dist/botframework-webchat-core.d.mts working-directory: ./packages/core + - name: Run tsd under packages/directlinespeech + run: ../../node_modules/.bin/tsd + working-directory: ./packages/directlinespeech + # The steps above use @types/react@16 (our baseline), check with the types of the latest React too. # In every workspace: packages that declare @types/react@16 would otherwise keep their own copy. - name: Install @types/react@19 and @types/react-dom@19 diff --git a/package-lock.json b/package-lock.json index c722714bcf..e0316ca242 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21451,6 +21451,7 @@ "prettier": "^3.8.3", "simple-update-in": "^2.2.0", "source-map-loader": "^5.0.0", + "tsd": "^0.33.0", "webpack": "^5.107.2", "webpack-cli": "^7.0.3", "webpack-stats-plugin": "^1.1.3" diff --git a/packages/directlinespeech/package.json b/packages/directlinespeech/package.json index 69a83d8c00..366ccd297a 100644 --- a/packages/directlinespeech/package.json +++ b/packages/directlinespeech/package.json @@ -24,6 +24,12 @@ "engines": { "node": ">= 10.14.2" }, + "tsd": { + "compilerOptions": { + "module": "NodeNext", + "strict": true + } + }, "scripts": { "build": "npm run --if-present build:pre && npm run build:run && npm run --if-present build:post", "build:pre": "npm run build:pre:local-dependencies && npm run build:pre:watch", @@ -43,7 +49,8 @@ "prettier": "prettier --check src/**/*.{js,ts}", "preversion": "../../scripts/npm/preversion.sh", "start": "../../scripts/npm/notify-build.sh \"src\"", - "test": "jest --watch" + "test": "jest --watch", + "test:tsd": "tsd" }, "author": "Microsoft Corporation", "license": "MIT", @@ -98,6 +105,7 @@ "prettier": "^3.8.3", "simple-update-in": "^2.2.0", "source-map-loader": "^5.0.0", + "tsd": "^0.33.0", "webpack": "^5.107.2", "webpack-cli": "^7.0.3", "webpack-stats-plugin": "^1.1.3" diff --git a/packages/directlinespeech/test-d/build-info.test-d.ts b/packages/directlinespeech/test-d/build-info.test-d.ts new file mode 100644 index 0000000000..f688792145 --- /dev/null +++ b/packages/directlinespeech/test-d/build-info.test-d.ts @@ -0,0 +1,9 @@ +import { buildInfo } from 'botframework-directlinespeech-sdk'; +import { expectError, expectType } from 'tsd'; + +expectType(buildInfo.buildTool); +expectType(buildInfo.moduleFormat); +expectType(buildInfo.version); + +// Read-only. +expectError((buildInfo.version = '1.0.0')); diff --git a/packages/directlinespeech/test-d/create-adapters-fetch-credentials.test-d.ts b/packages/directlinespeech/test-d/create-adapters-fetch-credentials.test-d.ts new file mode 100644 index 0000000000..561307454b --- /dev/null +++ b/packages/directlinespeech/test-d/create-adapters-fetch-credentials.test-d.ts @@ -0,0 +1,12 @@ +import { createAdapters, type DirectLineSpeechCredentials } from 'botframework-directlinespeech-sdk'; +import { expectAssignable } from 'tsd'; + +type CreateAdaptersInit = Parameters[0]; + +const credentials: DirectLineSpeechCredentials = { authorizationToken: '...', region: 'westus2' }; + +// `fetchCredentials` can be the credentials, a promise of them, or a function returning either. +expectAssignable({ fetchCredentials: credentials }); +expectAssignable({ fetchCredentials: Promise.resolve(credentials) }); +expectAssignable({ fetchCredentials: () => credentials }); +expectAssignable({ fetchCredentials: async () => credentials }); diff --git a/packages/directlinespeech/test-d/create-adapters-invalid-options.test-d.ts b/packages/directlinespeech/test-d/create-adapters-invalid-options.test-d.ts new file mode 100644 index 0000000000..4aad95049d --- /dev/null +++ b/packages/directlinespeech/test-d/create-adapters-invalid-options.test-d.ts @@ -0,0 +1,13 @@ +import { createAdapters } from 'botframework-directlinespeech-sdk'; +import { expectError } from 'tsd'; + +const fetchCredentials = { authorizationToken: '...', region: 'westus2' }; + +// Misspelled option. +expectError(createAdapters({ fetchCredentials, speechRecognitionLangauge: 'en-US' })); + +// Missing the only required option. +expectError(createAdapters({ speechRecognitionLanguage: 'en-US' })); + +// Wrong type: the device ID is a string. +expectError(createAdapters({ audioInputDeviceId: 1, fetchCredentials })); diff --git a/packages/directlinespeech/test-d/create-adapters-result.test-d.ts b/packages/directlinespeech/test-d/create-adapters-result.test-d.ts new file mode 100644 index 0000000000..941d4eb944 --- /dev/null +++ b/packages/directlinespeech/test-d/create-adapters-result.test-d.ts @@ -0,0 +1,37 @@ +import { createAdapters } from 'botframework-directlinespeech-sdk'; +import { expectError, expectType } from 'tsd'; + +// Declared as an interface (without an index signature), like `Activity` in `botframework-directlinejs`. +interface MessageActivity { + from: { id: string; role?: 'bot' | 'user' }; + text: string; + type: 'message'; +} + +(async () => { + const { directLine, webSpeechPonyfillFactory } = await createAdapters({ + fetchCredentials: { authorizationToken: '...', region: 'westus2' } + }); + + directLine.activity$.subscribe(activity => expectType(activity.type)); + directLine.connectionStatus$.subscribe(connectionStatus => expectType(connectionStatus)); + + const activity: MessageActivity = { from: { id: 'u00001', role: 'user' }, text: 'Hello, World!', type: 'message' }; + + directLine.postActivity(activity).subscribe(id => expectType(id)); + + expectType(directLine.end()); + + const { SpeechGrammarList, SpeechRecognition, speechSynthesis, SpeechSynthesisUtterance } = + webSpeechPonyfillFactory(); + + // Empty when the browser does not support Web Audio API. + expectType(speechSynthesis); + expectType(SpeechSynthesisUtterance); + + SpeechGrammarList && new SpeechGrammarList(); + SpeechRecognition && new SpeechRecognition(); + + // The factory does not return `SpeechRecognitionEvent`. + expectError(webSpeechPonyfillFactory().SpeechRecognitionEvent); +})(); From eea401a01d08916b18c62cfe9c5b1a2d92a74a2f Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Mon, 9 Nov 2026 21:06:30 -0800 Subject: [PATCH 06/13] Build botframework-directlinespeech-sdk with tsup only One tsup config now emits the ES module, the CommonJS file and both browser scripts (window.DirectLineSpeech). main and the require condition point to tsup's CommonJS file instead of Babel's lib/; Babel (lib/) and webpack are no longer used to build. --- package-lock.json | 37 +--------------- packages/directlinespeech/package.json | 20 ++------- packages/directlinespeech/tsup.config.ts | 40 +++++++++++++++++ packages/directlinespeech/webpack.config.js | 48 --------------------- 4 files changed, 46 insertions(+), 99 deletions(-) delete mode 100644 packages/directlinespeech/webpack.config.js diff --git a/package-lock.json b/package-lock.json index e0316ca242..355a2158f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11273,6 +11273,7 @@ "version": "0.6.3", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -18430,27 +18431,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", - "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.72.1" - } - }, "node_modules/source-map-support": { "version": "0.5.13", "dev": true, @@ -20380,13 +20360,6 @@ "node": ">=10.13.0" } }, - "node_modules/webpack-stats-plugin": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/webpack-stats-plugin/-/webpack-stats-plugin-1.1.3.tgz", - "integrity": "sha512-yUKYyy+e0iF/w31QdfioRKY+h3jDBRpthexBOWGKda99iu2l/wxYsI/XqdlP5IU58/0KB9CsJZgWNAl+/MPkRw==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", @@ -21428,7 +21401,6 @@ "web-speech-cognitive-services": "8.1.4" }, "devDependencies": { - "@babel/cli": "^7.29.7", "@babel/core": "^7.29.7", "@babel/plugin-transform-runtime": "^7.29.7", "@babel/preset-env": "^7.29.7", @@ -21439,7 +21411,6 @@ "babel-jest": "^29.7.0", "babel-plugin-istanbul": "^8.0.0", "babel-plugin-transform-inline-environment-variables": "^0.4.4", - "cross-env": "^10.1.0", "dotenv": "^17.4.2", "eslint": "^8.57.1", "eslint-plugin-node": "^11.1.0", @@ -21450,11 +21421,7 @@ "jest": "^29.7.0", "prettier": "^3.8.3", "simple-update-in": "^2.2.0", - "source-map-loader": "^5.0.0", - "tsd": "^0.33.0", - "webpack": "^5.107.2", - "webpack-cli": "^7.0.3", - "webpack-stats-plugin": "^1.1.3" + "tsd": "^0.33.0" }, "engines": { "node": ">= 10.14.2" diff --git a/packages/directlinespeech/package.json b/packages/directlinespeech/package.json index 366ccd297a..0fa78b3261 100644 --- a/packages/directlinespeech/package.json +++ b/packages/directlinespeech/package.json @@ -4,10 +4,9 @@ "description": "Direct Line Speech SDK", "files": [ "./dist/**/*", - "./lib/**/*", "./src/**/*" ], - "main": "./lib/index.js", + "main": "./dist/botframework-directlinespeech-sdk.js", "types": "./dist/botframework-directlinespeech-sdk.d.ts", "exports": { ".": { @@ -17,7 +16,7 @@ }, "require": { "types": "./dist/botframework-directlinespeech-sdk.d.ts", - "default": "./lib/index.js" + "default": "./dist/botframework-directlinespeech-sdk.js" } } }, @@ -35,12 +34,7 @@ "build:pre": "npm run build:pre:local-dependencies && npm run build:pre:watch", "build:pre:local-dependencies": "../../scripts/npm/build-local-dependencies.sh", "build:pre:watch": "../../scripts/npm/build-watch.sh", - "build:run": "npm run build:run:tsup && npm run build:run:babel && npm run build:run:webpack", - "build:run:babel": "cross-env build_tool=babel module_format=commonjs babel src --ignore **/*.spec.js,**/*.test.js,__tests__/**/*.js --out-dir lib --verbose", - "build:run:tsup": "tsup", - "build:run:webpack": "npm run build:run:webpack:development && npm run build:run:webpack:production", - "build:run:webpack:development": "cross-env node_env=development webpack-cli", - "build:run:webpack:production": "cross-env node_env=production webpack-cli", + "build:run": "tsup", "bump": "vg bump prod && vg bump dev && (npm audit fix || exit 0)", "eslint": "npm run precommit", "postversion": "../../scripts/npm/postversion.sh", @@ -82,7 +76,6 @@ }, "localDependencies": {}, "devDependencies": { - "@babel/cli": "^7.29.7", "@babel/core": "^7.29.7", "@babel/plugin-transform-runtime": "^7.29.7", "@babel/preset-env": "^7.29.7", @@ -93,7 +86,6 @@ "babel-jest": "^29.7.0", "babel-plugin-istanbul": "^8.0.0", "babel-plugin-transform-inline-environment-variables": "^0.4.4", - "cross-env": "^10.1.0", "dotenv": "^17.4.2", "eslint": "^8.57.1", "eslint-plugin-node": "^11.1.0", @@ -104,11 +96,7 @@ "jest": "^29.7.0", "prettier": "^3.8.3", "simple-update-in": "^2.2.0", - "source-map-loader": "^5.0.0", - "tsd": "^0.33.0", - "webpack": "^5.107.2", - "webpack-cli": "^7.0.3", - "webpack-stats-plugin": "^1.1.3" + "tsd": "^0.33.0" }, "dependencies": { "@babel/runtime": "7.29.7", diff --git a/packages/directlinespeech/tsup.config.ts b/packages/directlinespeech/tsup.config.ts index 535052d6e9..b1728dd7e4 100644 --- a/packages/directlinespeech/tsup.config.ts +++ b/packages/directlinespeech/tsup.config.ts @@ -21,6 +21,18 @@ const config = applyConfig(config => ({ noExternal: [...(config.noExternal ?? []), 'event-target-shim'] })); +// Browser scripts exposing `window.DirectLineSpeech`, with every dependency bundled. +const iifeConfig = { + ...config, + dts: false, + format: 'iife', + globalName: 'DirectLineSpeech', + outExtension() { + return { js: '.js' }; + }, + target: [...config.target, 'es2019'] +} satisfies typeof config; + export default defineConfig([ { ...config, @@ -39,5 +51,33 @@ export default defineConfig([ }, format: 'cjs', target: [...config.target, 'es2019'] + }, + { + ...iifeConfig, + entry: { + 'directlinespeech.development': './src/index.js' + }, + env: { + ...iifeConfig.env, + module_format: 'global', + node_env: 'development', + NODE_ENV: 'development' + }, + // Both browser scripts would write the same metafile-iife.json, keep the production one. + metafile: false, + minify: false + }, + { + ...iifeConfig, + entry: { + 'directlinespeech.production.min': './src/index.js' + }, + env: { + ...iifeConfig.env, + module_format: 'global', + node_env: 'production', + NODE_ENV: 'production' + }, + minify: true } ]); diff --git a/packages/directlinespeech/webpack.config.js b/packages/directlinespeech/webpack.config.js deleted file mode 100644 index 7446e329c4..0000000000 --- a/packages/directlinespeech/webpack.config.js +++ /dev/null @@ -1,48 +0,0 @@ -const { join } = require('path'); -const { StatsWriterPlugin } = require('webpack-stats-plugin'); - -let config = { - entry: './lib/index', - mode: 'production', - output: { - filename: 'directlinespeech.production.min.js', - library: 'DirectLineSpeech', - libraryTarget: 'window' - }, - plugins: [ - new StatsWriterPlugin({ - filename: 'stats.json', - transform: (_, opts) => JSON.stringify(opts.compiler.getStats().toJson({ chunkModules: true }), null, 2) - }) - ] -}; - -// VSTS always emits uppercase environment variables. -const node_env = process.env.node_env || process.env.NODE_ENV; - -if (node_env !== 'production' && node_env !== 'test') { - config = { - ...config, - devtool: 'eval-source-map', - mode: 'development', - module: { - ...config.module, - rules: [ - ...((config.module || {}).rules || []), - { - enforce: 'pre', - include: [join(__dirname, './lib')], - test: /\.js$/, - use: ['source-map-loader'] - } - ] - }, - output: { - ...config.output, - devtoolNamespace: 'botframework-directlinespeech-sdk', - filename: 'directlinespeech.development.js' - } - }; -} - -module.exports = config; From 4c92fecaa04d57411c34fcc649ec76fc07aa4892 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Mon, 9 Nov 2026 21:06:34 -0800 Subject: [PATCH 07/13] Do not publish tests and esbuild metafiles in botframework-directlinespeech-sdk --- packages/directlinespeech/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/directlinespeech/package.json b/packages/directlinespeech/package.json index 0fa78b3261..3cc9409850 100644 --- a/packages/directlinespeech/package.json +++ b/packages/directlinespeech/package.json @@ -4,7 +4,10 @@ "description": "Direct Line Speech SDK", "files": [ "./dist/**/*", - "./src/**/*" + "./src/**/*", + "!dist/metafile-*.json", + "!src/**/*.spec.*", + "!src/**/__tests__/**" ], "main": "./dist/botframework-directlinespeech-sdk.js", "types": "./dist/botframework-directlinespeech-sdk.d.ts", From 984c3a41bd4eabf5efd83a5f3dfc86a2d18f295d Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Mon, 9 Nov 2026 21:09:44 -0800 Subject: [PATCH 08/13] Assign window.DirectLineSpeech explicitly in the browser scripts tsup's globalName declares a top-level var, which is not global when the script runs inside a module wrapper; webpack assigned window.DirectLineSpeech. --- .../src/__tests__/addMetaTag.iife.spec.js | 18 ++++++++++++++++++ packages/directlinespeech/src/bundle.js | 4 ++++ packages/directlinespeech/tsup.config.ts | 5 ++--- 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 packages/directlinespeech/src/__tests__/addMetaTag.iife.spec.js create mode 100644 packages/directlinespeech/src/bundle.js diff --git a/packages/directlinespeech/src/__tests__/addMetaTag.iife.spec.js b/packages/directlinespeech/src/__tests__/addMetaTag.iife.spec.js new file mode 100644 index 0000000000..8229801976 --- /dev/null +++ b/packages/directlinespeech/src/__tests__/addMetaTag.iife.spec.js @@ -0,0 +1,18 @@ +/** @jest-environment @happy-dom/jest-environment */ +/// + +beforeEach(() => { + delete window.DirectLineSpeech; +}); + +test.each([['directlinespeech.development.js'], ['directlinespeech.production.min.js']])( + '%s should set window.DirectLineSpeech with matching buildInfo', + filename => { + // Loaded as a module (inside a function), not as a classic