From 7ad6994fddbf2e85e0619d43cfb2917ba5b687f5 Mon Sep 17 00:00:00 2001 From: Alexander Freas Date: Sun, 5 Nov 2023 15:14:18 +0100 Subject: [PATCH] Move db access to tangential-core --- tangential/.env.dev | 6 +- tangential/.env.live | 2 +- tangential/.env.offline | 2 +- tangential/iam-role.yml | 5 + tangential/package.json | 8 +- tangential/serverless.yml | 18 ++-- tangential/src/config/config.ts | 6 +- tangential/src/utils/analysisStorage.ts | 7 +- tangential/src/utils/databaseWrapper.ts | 63 ------------- tangential/src/utils/jira.ts | 17 +++- tangential/src/utils/openAiWrapper.ts | 33 +++++++ tangential/yarn.lock | 118 +++++++++++++++++++++++- 12 files changed, 197 insertions(+), 88 deletions(-) create mode 100644 tangential/iam-role.yml delete mode 100644 tangential/src/utils/databaseWrapper.ts create mode 100644 tangential/src/utils/openAiWrapper.ts diff --git a/tangential/.env.dev b/tangential/.env.dev index 2f87396..a8cd7ef 100644 --- a/tangential/.env.dev +++ b/tangential/.env.dev @@ -1,5 +1,3 @@ -LOCAL_HTTP_PROXY=http://localhost:8081 -NODE_TLS_REJECT_UNAUTHORIZED=0 -MONGODB_URL="mongodb+srv://db:CsdfRb74SZldOODz@tangential-test.jgagw73.mongodb.net/?retryWrites=true&w=majority" +MONGODB_URI="mongodb+srv://db:CsdfRb74SZldOODz@tangential-test.jgagw73.mongodb.net/?retryWrites=true&w=majority" MONGODB_DATABASE=tangential-dev -awsRegion=us-east-1 +awsRegion=us-east-1 \ No newline at end of file diff --git a/tangential/.env.live b/tangential/.env.live index 5a479ed..375a76c 100644 --- a/tangential/.env.live +++ b/tangential/.env.live @@ -1,3 +1,3 @@ -MONGODB_URL="mongodb+srv://db:CsdfRb74SZldOODz@tangential-test.jgagw73.mongodb.net/?retryWrites=true&w=majority" +MONGODB_URI="mongodb+srv://db:CsdfRb74SZldOODz@tangential-test.jgagw73.mongodb.net/?retryWrites=true&w=majority" MONGODB_DATABASE=tangential-live awsRegion=us-east-1 diff --git a/tangential/.env.offline b/tangential/.env.offline index 661f1ce..fdef554 100644 --- a/tangential/.env.offline +++ b/tangential/.env.offline @@ -1,6 +1,6 @@ LOCAL_HTTP_PROXY=http://localhost:8081 NODE_TLS_REJECT_UNAUTHORIZED=0 -MONGODB_URL="mongodb+srv://db:CsdfRb74SZldOODz@tangential-test.jgagw73.mongodb.net/?retryWrites=true&w=majority" +MONGODB_URI="mongodb+srv://db:CsdfRb74SZldOODz@tangential-test.jgagw73.mongodb.net/?retryWrites=true&w=majority" MONGODB_DATABASE=tangential-offline awsRegion=us-east-1 recordJiraRequests=true diff --git a/tangential/iam-role.yml b/tangential/iam-role.yml new file mode 100644 index 0000000..26b0db1 --- /dev/null +++ b/tangential/iam-role.yml @@ -0,0 +1,5 @@ +- Effect: Allow + Action: + - sqs:SendMessage + Resource: + - !GetAtt ProjectAnalysisQueue.Arn diff --git a/tangential/package.json b/tangential/package.json index f0277c1..72a9344 100644 --- a/tangential/package.json +++ b/tangential/package.json @@ -4,7 +4,7 @@ "main": "index.js", "license": "MIT", "dependencies": { - "@akfreas/tangential-core": "^1.0.1", + "@akfreas/tangential-core": "^1.0.2", "@aws-sdk/client-comprehend": "^3.438.0", "@aws-sdk/client-s3": "^3.438.0", "@aws-sdk/client-secrets-manager": "^3.438.0", @@ -16,11 +16,12 @@ "aws-xray-sdk-core": "^3.5.3", "axios": "^1.5.1", "luxon": "^3.4.3", - "mongodb": "6.2" + "mongodb": "6.2", + "openai": "^4.15.0", + "qs": "^6.11.2" }, "devDependencies": { "@akfreas/serverless-offline-sqs": "^7.3.2", - "serverless-domain-manager": "^7.1.2", "@types/jest": "^29.5.7", "@types/luxon": "^3.3.3", "@types/node": "^20.8.10", @@ -30,6 +31,7 @@ "jest": "^29.7.0", "proxy-agent": "^6.3.1", "serverless": "^3.35.2", + "serverless-domain-manager": "^7.1.2", "serverless-dotenv-plugin": "^6.0.0", "serverless-offline": "^13.2.0", "serverless-plugin-typescript": "^2.1.5", diff --git a/tangential/serverless.yml b/tangential/serverless.yml index 3a9fbaf..8e2c489 100644 --- a/tangential/serverless.yml +++ b/tangential/serverless.yml @@ -15,6 +15,11 @@ provider: timeout: 60 stage: ${opt:stage, 'offline'} region: us-east-1 + profile: tangential + iam: + role: + statements: ${file(./iam-role.yml)} + environment: projectAnalysisQueueUrl: ${self:custom.projectAnalysisQueueUrl.${self:provider.stage}, self:custom.projectAnalysisQueueUrl.remote} httpApi: @@ -39,12 +44,13 @@ custom: debug: true customDomain: - domainName: api.tangential.app - stage: ${self:provider.stage} - basePath: ${self:provider.stage} - certificateArn: arn:aws:acm:us-east-1:556167323904:certificate/680b6cce-755d-403f-b116-4a1d3d88295a - createRoute53Record: true - endpointType: edge + domainName: ${self:provider.stage}.api.tangential.app + stage: $default + certificateArn: arn:aws:acm:us-east-1:556167323904:certificate/ba19fbb2-0c34-4cd6-984a-0c5562fd6e9d + endpointType: regional + hostedZoneId: Z091731134YSQCRRMM86I + autoDomain: true + apiType: http functions: startWorkspaceAnalysis: diff --git a/tangential/src/config/config.ts b/tangential/src/config/config.ts index 467a036..9b22a31 100644 --- a/tangential/src/config/config.ts +++ b/tangential/src/config/config.ts @@ -3,8 +3,6 @@ import { Agent as HttpAgent } from 'http'; import * as https from 'https'; import * as http from 'http'; -let HTTPSProxyAgent: typeof import('https-proxy-agent'); -let HTTPProxyAgent: typeof import('http-proxy-agent'); let agent: https.Agent; @@ -33,8 +31,8 @@ let httpInstance = new HttpAgent(); let elasticSearchHttpInstance = httpsInstance; if (process.env.LOCAL_HTTP_PROXY) { - HTTPSProxyAgent = require('https-proxy-agent'); - HTTPProxyAgent = require('http-proxy-agent'); + const HTTPSProxyAgent = require('https-proxy-agent'); + const HTTPProxyAgent = require('http-proxy-agent'); httpsInstance = new HTTPSProxyAgent.HttpsProxyAgent(process.env.LOCAL_HTTP_PROXY); httpInstance = new HTTPProxyAgent.HttpProxyAgent(process.env.LOCAL_HTTP_PROXY); diff --git a/tangential/src/utils/analysisStorage.ts b/tangential/src/utils/analysisStorage.ts index c272e4b..83817f7 100644 --- a/tangential/src/utils/analysisStorage.ts +++ b/tangential/src/utils/analysisStorage.ts @@ -1,6 +1,5 @@ -import MongoDBWrapper from "./databaseWrapper"; -import { doError, doLog, jsonLog } from "./logging"; -import { ProjectReport } from "@akfreas/tangential-core" + +import { ProjectReport, MongoDBWrapper } from "@akfreas/tangential-core" export async function storeProjectReport(report: ProjectReport): Promise { try { @@ -10,7 +9,7 @@ export async function storeProjectReport(report: ProjectReport): Promise { return; } - const dbWrapper = await MongoDBWrapper.getInstance(); + const dbWrapper = await MongoDBWrapper.getInstance(process.env.MONGODB_URI, process.env.MONGODB_DATABASE) const reportsCollection = dbWrapper.getCollection('reports'); // Storing the report in the database diff --git a/tangential/src/utils/databaseWrapper.ts b/tangential/src/utils/databaseWrapper.ts deleted file mode 100644 index 798c838..0000000 --- a/tangential/src/utils/databaseWrapper.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { - MongoClient, Db, Collection, - OptionalUnlessRequiredId, InsertOneResult, - ServerApiVersion, Document -} from 'mongodb'; -import { doLog, jsonLog } from './logging'; - -export default class MongoDBWrapper { - private static instance: MongoDBWrapper; - private client?: MongoClient; - public db?: Db; - - private constructor() { } - - public static async getInstance(): Promise { - if (!this.instance) { - this.instance = new MongoDBWrapper(); - await this.instance.connect(); - } - return this.instance; - } - - private async connect(): Promise { - try { - const url = process.env.MONGODB_URL as string; - let options = { - serverApi: { - version: ServerApiVersion.v1, - strict: true, - deprecationErrors: true, - } - } - // console.log('Connecting to MongoDB...', url); - // if (process.env.LOCAL_HTTP_PROXY) { - // options = { - // ...options, - // ...{ - // proxyHost: process.env.LOCAL_HTTP_PROXY.split(':')[0], - // proxyPort: parseInt(process.env.LOCAL_HTTP_PROXY.split(':')[2]) - // }, - // } - // } - this.client = new MongoClient(url, options); - this.db = this.client.db(process.env.MONGODB_DATABASE); // You can specify a database name here if needed - } catch (error) { - console.error('Failed to connect to MongoDB:', error); - } - } - - public getCollection(name: string): Collection { - if (!this.db) { - throw new Error('Database connection not established'); - } - return this.db.collection(name); - } - - public async storeDocument(collection: Collection, document: OptionalUnlessRequiredId): Promise { - const result: InsertOneResult = await collection.insertOne(document); - if (result.acknowledged !== true) { - throw new Error(`Failed to insert document into collection ${collection.collectionName}`); - } - } -} \ No newline at end of file diff --git a/tangential/src/utils/jira.ts b/tangential/src/utils/jira.ts index 928b76c..9f0fcc7 100644 --- a/tangential/src/utils/jira.ts +++ b/tangential/src/utils/jira.ts @@ -263,6 +263,14 @@ async function calculateVelocity( return await sumStoryPoints(combinedJql, pointsFields, auth); } +async function sumRemainingStoryPointsForEpic(epicId: string, pointsFields: PointsField[], auth: JiraRequestAuth): Promise { + // Formulate JQL for issues within an epic, excluding completed issues + const jql = `"Epic Link" = ${epicId} AND status != "Done"`; + + // Use the sumStoryPoints function to get the total of remaining points + return await sumStoryPoints(jql, pointsFields, auth); +} + interface IssueCommentsTimeline { beforeDate: IssueComment[]; @@ -455,6 +463,9 @@ export async function analyzeEpic( const velocity = await calculateVelocity(jql, 30, pointsFields, auth); // Assuming 30 days result.velocity = velocity; + const remainingPoints = await sumRemainingStoryPointsForEpic(epicKey, pointsFields, auth); + result.remainingPoints = remainingPoints; + // Fetch the changelog for that epic const changelogs = await fetchIssueChangelog(epicKey, auth); result.epic_changelog = changelogs.length ? changelogs[0] : null; @@ -466,7 +477,11 @@ export async function analyzeEpic( // Pull changelog and comments and filter out everything before last checked date const longRunningIssues: LongRunningIssue[] = []; - result.comments = await getCommentsTimeline(epicKey, auth, windowStartDate.toISO()!); + const comments = await getCommentsTimeline(epicKey, auth, windowStartDate.toISO()!); + + if (comments) { + result.comments = comments; + } for (const child of childIssues.issues) { const childData: any = { diff --git a/tangential/src/utils/openAiWrapper.ts b/tangential/src/utils/openAiWrapper.ts new file mode 100644 index 0000000..2230cd1 --- /dev/null +++ b/tangential/src/utils/openAiWrapper.ts @@ -0,0 +1,33 @@ +import OpenAI from 'openai'; +import { Agent } from 'https'; +import { httpsAgent } from '../config/config'; +import { doError, doLog } from './logging'; + +interface ChatCompletionParams { + messages: any[]; + model: string; + temperature?: number; + maxTokens?: number; +} + +export async function createChatCompletion({ + messages, + model, + temperature, + maxTokens, +}: ChatCompletionParams): Promise { + const apiKey = process.env.OPENAI_API_KEY; + if (!apiKey) { + throw new Error('No OpenAI API key found'); + } + const openai = new OpenAI({ + apiKey, + }); + + const completion = await openai.chat.completions.create({ + messages, + model, + }, { httpAgent: httpsAgent }); + + return completion; +} diff --git a/tangential/yarn.lock b/tangential/yarn.lock index 970b982..24216a3 100644 --- a/tangential/yarn.lock +++ b/tangential/yarn.lock @@ -3580,6 +3580,14 @@ resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz" integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== +"@types/node-fetch@^2.6.4": + version "2.6.8" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.8.tgz#9a2993583975849c2e1f360b6ca2f11755b2c504" + integrity sha512-nnH5lV9QCMPsbEVdTb5Y+F3GQxLSw1xQgIydrb2gSfEavRPs50FnMr+KUaa+LoPSqibm2N+ZZxH7lavZlAT4GA== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + "@types/node@*", "@types/node@^20.8.10": version "20.8.10" resolved "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz" @@ -3587,6 +3595,13 @@ dependencies: undici-types "~5.26.4" +"@types/node@^18.11.18": + version "18.18.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.8.tgz#2b285361f2357c8c8578ec86b5d097c7f464cfd6" + integrity sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ== + dependencies: + undici-types "~5.26.4" + "@types/qs@^6.9.9": version "6.9.9" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.9.tgz#66f7b26288f6799d279edf13da7ccd40d2fa9197" @@ -3670,6 +3685,13 @@ agent-base@^7.0.2, agent-base@^7.1.0: dependencies: debug "^4.3.4" +agentkeepalive@^4.2.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + ajv-formats@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz" @@ -4001,6 +4023,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-64@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" + integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA== + base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" @@ -4252,6 +4279,11 @@ chardet@^0.7.0: resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== + child-process-ext@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz" @@ -4546,6 +4578,11 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== + d@1, d@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/d/-/d-1.0.1.tgz" @@ -4720,6 +4757,14 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +digest-fetch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/digest-fetch/-/digest-fetch-1.3.0.tgz#898e69264d00012a23cf26e8a3e40320143fc661" + integrity sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA== + dependencies: + base-64 "^0.1.0" + md5 "^2.3.0" + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" @@ -5149,6 +5194,11 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" +form-data-encoder@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" + integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== + form-data@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" @@ -5158,6 +5208,14 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +formdata-node@^4.3.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" + integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== + dependencies: + node-domexception "1.0.0" + web-streams-polyfill "4.0.0-beta.3" + formidable@^2.0.1: version "2.1.2" resolved "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz" @@ -5508,6 +5566,13 @@ human-signals@^5.0.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz" integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" @@ -5612,6 +5677,11 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-buffer@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + is-callable@^1.1.3: version "1.2.7" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" @@ -6490,6 +6560,15 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + memoizee@^0.4.14, memoizee@^0.4.15: version "0.4.15" resolved "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz" @@ -6630,7 +6709,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.3: +ms@^2.0.0, ms@^2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -6686,6 +6765,11 @@ node-dir@^0.1.17: dependencies: minimatch "^3.0.2" +node-domexception@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + node-fetch@^2.6.11, node-fetch@^2.6.7, node-fetch@^2.6.8: version "2.7.0" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" @@ -6802,6 +6886,21 @@ open@^8.4.2: is-docker "^2.1.1" is-wsl "^2.2.0" +openai@^4.15.0: + version "4.15.0" + resolved "https://registry.yarnpkg.com/openai/-/openai-4.15.0.tgz#96a64fb829a56fe8a22231fffd790b6a63d5273d" + integrity sha512-LPNgtG9gxRphH+7AUM5Q/dS/iWuM0UOKf+723e2kvyENNVMjYFrnQjCdcb2nNJY7+ao+J2jP/PfsXBLN8Si7iA== + dependencies: + "@types/node" "^18.11.18" + "@types/node-fetch" "^2.6.4" + abort-controller "^3.0.0" + agentkeepalive "^4.2.1" + digest-fetch "^1.3.0" + form-data-encoder "1.7.2" + formdata-node "^4.3.2" + node-fetch "^2.6.7" + web-streams-polyfill "^3.2.1" + ora@^5.4.1: version "5.4.1" resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" @@ -7128,6 +7227,13 @@ qs@^6.10.3, qs@^6.11.0: dependencies: side-channel "^1.0.4" +qs@^6.11.2: + version "6.11.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" + querystring@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" @@ -8144,6 +8250,16 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" +web-streams-polyfill@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" + integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== + +web-streams-polyfill@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"