diff --git a/extensions/pvaPublish/package.json b/extensions/pvaPublish/package.json index 9c7d83b669..e413865d87 100644 --- a/extensions/pvaPublish/package.json +++ b/extensions/pvaPublish/package.json @@ -48,6 +48,7 @@ "@botframework-composer/test-utils": "^0.0.1", "@types/jest": "^26.0.15", "@types/node": "^14.11.2", + "@types/node-fetch": "^2.5.7", "cross-env": "^7.0.2", "jest": "^26.6.0", "mini-svg-data-uri": "^1.2.3", diff --git a/extensions/pvaPublish/src/node/publish.ts b/extensions/pvaPublish/src/node/publish.ts index cb2c2ed6cd..c89e30039f 100644 --- a/extensions/pvaPublish/src/node/publish.ts +++ b/extensions/pvaPublish/src/node/publish.ts @@ -26,8 +26,8 @@ export const publish = async ( config: PublishConfig, project: IBotProject, metadata: any, - _user: UserIdentity, - getAccessToken + _user?: UserIdentity, + getAccessToken? ): Promise => { const { // these are provided by Composer @@ -52,8 +52,8 @@ export const publish = async ( // write the .zip to a buffer in memory logger.log('Writing bot content to in-memory buffer.'); const botContentWriter = new stream.Writable(); - const botContentData = []; - botContentWriter._write = (chunk, encoding, callback) => { + const botContentData: Uint8Array[] = []; + botContentWriter._write = (chunk: Buffer, encoding, callback) => { botContentData.push(chunk); callback(); // let the internal write() call know that the _write() was successful }; @@ -88,8 +88,8 @@ export const publish = async ( headers: { ...getAuthHeaders(accessToken, tenantId), 'Content-Type': 'application/zip', - 'Content-Length': botContent.buffer.byteLength, - 'If-Match': project.eTag, + 'Content-Length': botContent.buffer.byteLength.toString(), + 'If-Match': project.eTag || '', }, }); if (res.status === 202) { @@ -100,14 +100,14 @@ export const publish = async ( const result = xformJobToResult(job); // add to publish history - const botProjectId = project.id; + const botProjectId = project.id || ''; ensurePublishProfileHistory(botProjectId, profileName); publishHistory[botProjectId][profileName].unshift(result); logger.log('Publish call successful.'); return { - status: result.status, + status: result.status as number, result, }; } else { @@ -136,8 +136,8 @@ export const publish = async ( export const getStatus = async ( config: PublishConfig, project: IBotProject, - user: UserIdentity, - getAccessToken + user?: UserIdentity, + getAccessToken? ): Promise => { const { // these are provided by Composer @@ -149,7 +149,7 @@ export const getStatus = async ( envId, tenantId, } = config; - const botProjectId = project.id; + const botProjectId = project.id || ''; const operationId = getOperationIdOfLastJob(botProjectId, profileName); if (!operationId) { @@ -174,7 +174,7 @@ export const getStatus = async ( method: 'GET', headers: { ...getAuthHeaders(accessToken, tenantId), - 'If-None-Match': project.eTag, + 'If-None-Match': project.eTag || '', }, }); const job: PVAPublishJob = await res.json(); @@ -187,14 +187,16 @@ export const getStatus = async ( const result = xformJobToResult(job); // update publish history - const botProjectId = project.id; + const botProjectId = project.id || ''; ensurePublishProfileHistory(botProjectId, profileName); const oldRecord = publishHistory[botProjectId][profileName].shift(); - result.comment = oldRecord.comment; // persist comment from initial publish + if (oldRecord) { + result.comment = oldRecord.comment; // persist comment from initial publish + } publishHistory[botProjectId][profileName].unshift(result); return { - status: result.status, + status: result.status as number, result, }; } catch (e) { @@ -210,8 +212,8 @@ export const getStatus = async ( export const history = async ( config: PublishConfig, _project: IBotProject, - _user: UserIdentity, - getAccessToken + _user?: UserIdentity, + getAccessToken? ): Promise => { const { // these are specific to the PVA publish profile shape @@ -245,8 +247,8 @@ export const history = async ( export const pull = async ( config: PublishConfig, _project: IBotProject, - _user: UserIdentity, - getAccessToken + _user?: UserIdentity, + getAccessToken? ): Promise => { const { // these are specific to the PVA publish profile shape @@ -348,7 +350,7 @@ const getOperationIdOfLastJob = (botProjectId: string, profileName: string): str !!publishHistory[botProjectId][profileName].length ) { const mostRecentJob = publishHistory[botProjectId][profileName][0]; - return mostRecentJob.id; + return mostRecentJob.id || ''; } // couldn't find any jobs for the bot project / profile name combo return ''; diff --git a/extensions/pvaPublish/src/node/types.ts b/extensions/pvaPublish/src/node/types.ts index 9af5613db5..6fc91e7b35 100644 --- a/extensions/pvaPublish/src/node/types.ts +++ b/extensions/pvaPublish/src/node/types.ts @@ -53,7 +53,7 @@ export interface PublishResult { message: string; status?: number; time?: Date; - action?: { href: string; label: string }; + action?: { href: string; label: string } | null; } /** Copied from @bfc/extension */ diff --git a/extensions/pvaPublish/src/node/utils.spec.ts b/extensions/pvaPublish/src/node/utils.spec.ts index e4cd943272..56c992e5d2 100644 --- a/extensions/pvaPublish/src/node/utils.spec.ts +++ b/extensions/pvaPublish/src/node/utils.spec.ts @@ -37,7 +37,7 @@ describe('should return the proper PVA base URL for the environment', () => { describe('it should return the proper PVA auth parameters for the base URL', () => { it('fallback to prod', () => { - let url = undefined; + let url: string | undefined = undefined; expect(getAuthCredentials(url)).toEqual(AUTH_CREDENTIALS.PROD); url = 'https://dev.botframework.com/'; diff --git a/extensions/pvaPublish/src/ui/pvaDialog.tsx b/extensions/pvaPublish/src/ui/pvaDialog.tsx index 427f1f13e3..e81e89db9a 100644 --- a/extensions/pvaPublish/src/ui/pvaDialog.tsx +++ b/extensions/pvaPublish/src/ui/pvaDialog.tsx @@ -32,9 +32,9 @@ export const PVADialog: FC = () => { const [token, setToken] = useState(''); const [tenantId, setTenantId] = useState(''); const [envs, setEnvs] = useState([]); - const [env, setEnv] = useState(null); + const [env, setEnv] = useState(undefined); const [bots, setBots] = useState([]); - const [bot, setBot] = useState(null); + const [bot, setBot] = useState(undefined); const [loggingIn, setLoggingIn] = useState(false); const [fetchingEnvironments, setFetchingEnvironments] = useState(false); const [fetchingBots, setFetchingBots] = useState(false); @@ -94,15 +94,19 @@ export const PVADialog: FC = () => { } }, [tenantId, token, pvaHeaders]); - const onSelectEnv = useCallback((event, item: IDropdownOption) => { - setEnv(item.key + ''); + const onSelectEnv = useCallback((event, item?: IDropdownOption) => { + if (item) { + setEnv(`${item.key}`); + } }, []); const onSelectBot = useCallback( - (event, item: IDropdownOption) => { - const botId = item.key + ''; - const bot = bots.find((bot) => bot.id === botId); - setBot(bot); + (event, item?: IDropdownOption) => { + if (item) { + const botId = `${item.key}`; + const bot = bots.find((bot) => bot.id === botId); + setBot(bot); + } }, [bots, env] ); @@ -120,7 +124,7 @@ export const PVADialog: FC = () => { if (bots && bots.length) { setBot(bots[0]); } else { - setBot(null); + setBot(undefined); } }; fetchBots(); diff --git a/extensions/pvaPublish/tsconfig.json b/extensions/pvaPublish/tsconfig.json index e139468fca..e157ebbc15 100644 --- a/extensions/pvaPublish/tsconfig.json +++ b/extensions/pvaPublish/tsconfig.json @@ -2,7 +2,10 @@ "compilerOptions": { "esModuleInterop": true, "jsx": "react", - "sourceMap": true + "noImplicitAny": false, + "noUnusedLocals": true, + "sourceMap": true, + "strict": true }, "include": [ "src/**/*", diff --git a/extensions/pvaPublish/yarn.lock b/extensions/pvaPublish/yarn.lock index 013dcceeca..1e5dbbbec9 100644 --- a/extensions/pvaPublish/yarn.lock +++ b/extensions/pvaPublish/yarn.lock @@ -1479,6 +1479,14 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q== +"@types/node-fetch@^2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" + integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + "@types/node@*": version "14.14.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.0.tgz#f1091b6ad5de18e8e91bdbd43ec63f13de372538" @@ -2539,7 +2547,7 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -3318,6 +3326,15 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" + integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"