diff --git a/.vscode/launch.json b/.vscode/launch.json index 548c36ff..d4b13afb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,16 @@ { "version": "0.2.0", "configurations": [ + { + "name": "Current TS File", + "type": "node", + "request": "launch", + "args": ["${relativeFile}"], + "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], + "sourceMaps": true, + "cwd": "${workspaceRoot}", + "protocol": "inspector", + }, { "type": "node", "request": "launch", diff --git a/ExtractUserDataActivity/__tests__/handler.test.ts b/ExtractUserDataActivity/__tests__/handler.test.ts index 075d6fc3..8e820fd7 100644 --- a/ExtractUserDataActivity/__tests__/handler.test.ts +++ b/ExtractUserDataActivity/__tests__/handler.test.ts @@ -125,15 +125,9 @@ describe("createExtractUserDataActivityHandler", () => { const result = await handler(contextMock, input); - result.fold( - response => fail(`Failing result, response: ${JSON.stringify(response)}`), - response => { - ActivityResultSuccess.decode(response).fold( - err => - fail(`Failing decoding result, response: ${readableReport(err)}`), - e => expect(e.kind).toBe("SUCCESS") - ); - } + ActivityResultSuccess.decode(result).fold( + err => fail(`Failing decoding result, response: ${readableReport(err)}`), + e => expect(e.kind).toBe("SUCCESS") ); }); diff --git a/ExtractUserDataActivity/handler.ts b/ExtractUserDataActivity/handler.ts index 730288f1..10730fd3 100644 --- a/ExtractUserDataActivity/handler.ts +++ b/ExtractUserDataActivity/handler.ts @@ -531,10 +531,7 @@ export function createExtractUserDataActivityHandler( profileModel: ProfileModel, blobService: BlobService, userDataContainerName: NonEmptyString -): ( - context: Context, - input: unknown -) => Promise> { +): (context: Context, input: unknown) => Promise { return (context: Context, input: unknown) => fromEither( ActivityInput.decode(input).mapLeft( @@ -583,5 +580,6 @@ export function createExtractUserDataActivityHandler( value: archiveInfo }) ) - .run(); + .run() + .then(e => e.value); } diff --git a/SendUserDataDownloadMessageActivity/function.json b/SendUserDataDownloadMessageActivity/function.json new file mode 100644 index 00000000..73984b8f --- /dev/null +++ b/SendUserDataDownloadMessageActivity/function.json @@ -0,0 +1,10 @@ +{ + "bindings": [ + { + "name": "name", + "type": "activityTrigger", + "direction": "in" + } + ], + "scriptFile": "../dist/SendUserDataDownloadMessageActivity/index.js" +} \ No newline at end of file diff --git a/SendUserDataDownloadMessageActivity/handler.ts b/SendUserDataDownloadMessageActivity/handler.ts new file mode 100644 index 00000000..c74b5648 --- /dev/null +++ b/SendUserDataDownloadMessageActivity/handler.ts @@ -0,0 +1,148 @@ +import { Context } from "@azure/functions"; +import { NewMessage } from "io-functions-commons/dist/generated/definitions/NewMessage"; +import { readableReport } from "italia-ts-commons/lib/reporters"; + +import * as t from "io-ts"; +import { FiscalCode, NonEmptyString } from "italia-ts-commons/lib/strings"; + +// TODO: switch text based on user's preferred_language +const userDataDownloadMessage = ( + blobName: string, + password: string, + publicDownloadBaseUrl: string +) => + NewMessage.decode({ + content: { + markdown: `Caro/a Utente, +Abbiamo completato la gestione della tua richiesta di accesso. +Puoi scaricare al link che segue i tuoi dati personali che trattiamo tramite l’App IO utilizzando la relativa password. + +Se hai necessità di maggiori dettagli o informazioni su questi dati o vuoi riceverne dettaglio, +ti invitiamo a scrivere all’indirizzo email dpo@pagopa.it. + +Nel caso in cui tu non sia soddisfatto/a dalla modalità con cui abbiamo gestito la tua richiesta, +siamo a disposizione per risolvere domande o dubbi aggiuntivi, che puoi indicare scrivendo all’indirizzo email indicato sopra. + +[Link all'archivio ZIP](${publicDownloadBaseUrl}/${blobName}) + +Password dell'archivio ZIP: + +${password} + +Grazie ancora per aver utilizzato IO, +il Team Privacy di PagoPA +`, + subject: `IO App - richiesta di accesso ai dati` + } + }).getOrElseL(errs => { + throw new Error("Invalid MessageContent: " + readableReport(errs)); + }); + +/** + * Send a single user data download message + * using the IO Notification API (REST). + */ +async function sendMessage( + fiscalCode: FiscalCode, + apiUrl: string, + apiKey: string, + newMessage: NewMessage, + timeoutFetch: typeof fetch +): Promise { + const response = await timeoutFetch( + `${apiUrl}/api/v1/messages/${fiscalCode}`, + { + body: JSON.stringify(newMessage), + headers: { + "Content-Type": "application/json", + "Ocp-Apim-Subscription-Key": apiKey + }, + method: "POST" + } + ); + return response.status; +} + +// Activity result +const ActivityResultSuccess = t.interface({ + kind: t.literal("SUCCESS") +}); + +type ActivityResultSuccess = t.TypeOf; + +const ActivityResultFailure = t.interface({ + kind: t.literal("FAILURE"), + reason: t.string +}); + +type ActivityResultFailure = t.TypeOf; + +export const ActivityResult = t.taggedUnion("kind", [ + ActivityResultSuccess, + ActivityResultFailure +]); +export type ActivityResult = t.TypeOf; + +export const ActivityInput = t.interface({ + blobName: t.string, + fiscalCode: FiscalCode, + password: t.string +}); +export type ActivityInput = t.TypeOf; + +export const getActivityFunction = ( + publicApiUrl: NonEmptyString, + publicApiKey: NonEmptyString, + publicDownloadBaseUrl: NonEmptyString, + timeoutFetch: typeof fetch +) => (context: Context, input: unknown): Promise => { + const failure = (reason: string) => { + context.log.error(reason); + return ActivityResultFailure.encode({ + kind: "FAILURE", + reason + }); + }; + + const success = () => + ActivityResultSuccess.encode({ + kind: "SUCCESS" + }); + + return ActivityInput.decode(input).fold>( + async errs => + failure( + `SendUserDataDownloadMessageActivity|Cannot decode input|ERROR=${readableReport( + errs + )}|INPUT=${JSON.stringify(input)}` + ), + async ({ blobName, fiscalCode, password }) => { + const logPrefix = `SendUserDataDownloadMessageActivity|PROFILE=${fiscalCode}`; + context.log.verbose(`${logPrefix}|Sending user data download message`); + + // throws in case of timeout so + // the orchestrator can schedule a retry + const status = await sendMessage( + fiscalCode, + publicApiUrl, + publicApiKey, + userDataDownloadMessage(blobName, password, publicDownloadBaseUrl), + timeoutFetch + ); + + if (status !== 201) { + const msg = `${logPrefix}|ERROR=${status}`; + if (status >= 500) { + throw new Error(msg); + } else { + return failure(msg); + } + } + + context.log.verbose(`${logPrefix}|RESPONSE=${status}`); + return success(); + } + ); +}; + +export default getActivityFunction; diff --git a/SendUserDataDownloadMessageActivity/index.ts b/SendUserDataDownloadMessageActivity/index.ts new file mode 100644 index 00000000..1c364c0e --- /dev/null +++ b/SendUserDataDownloadMessageActivity/index.ts @@ -0,0 +1,36 @@ +import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; +import { agent } from "italia-ts-commons"; +import { + AbortableFetch, + setFetchTimeout, + toFetch +} from "italia-ts-commons/lib/fetch"; +import { Millisecond } from "italia-ts-commons/lib/units"; +import { getActivityFunction } from "./handler"; + +// HTTP external requests timeout in milliseconds +const DEFAULT_REQUEST_TIMEOUT_MS = 10000; + +// Needed to call notifications API +const publicApiUrl = getRequiredStringEnv("PUBLIC_API_URL"); +const publicApiKey = getRequiredStringEnv("PUBLIC_API_KEY"); +const publicDownloadBaseUrl = getRequiredStringEnv("PUBLIC_DOWNLOAD_BASE_URL"); + +// HTTP-only fetch with optional keepalive agent +// @see https://github.com/pagopa/io-ts-commons/blob/master/src/agent.ts#L10 +const httpApiFetch = agent.getHttpFetch(process.env); + +// a fetch that can be aborted and that gets cancelled after fetchTimeoutMs +const abortableFetch = AbortableFetch(httpApiFetch); +const timeoutFetch = toFetch( + setFetchTimeout(DEFAULT_REQUEST_TIMEOUT_MS as Millisecond, abortableFetch) +); + +const index = getActivityFunction( + publicApiUrl, + publicApiKey, + publicDownloadBaseUrl, + timeoutFetch +); + +export default index; diff --git a/SetUserDataProcessingStatusActivity/__tests__/handler.test.ts b/SetUserDataProcessingStatusActivity/__tests__/handler.test.ts index 39c6e2b9..d97ce826 100644 --- a/SetUserDataProcessingStatusActivity/__tests__/handler.test.ts +++ b/SetUserDataProcessingStatusActivity/__tests__/handler.test.ts @@ -36,12 +36,10 @@ describe("SetUserDataProcessingStatusActivityHandler", () => { }; const result = await handler(contextMock, input); - result.fold( - response => fail(`Failing result, reason: ${response.reason}`), - response => { - expect(response.value.status).toEqual(UserDataProcessingStatusEnum.WIP); - } - ); + expect(result.kind).toEqual("SUCCESS"); + if (result.kind === "SUCCESS") { + expect(result.value.status === UserDataProcessingStatusEnum.WIP); + } }); it("should handle a query error", async () => { @@ -63,17 +61,11 @@ describe("SetUserDataProcessingStatusActivityHandler", () => { }; const result = await handler(contextMock, input); - result.fold( - response => { - ActivityResultFailure.decode(response).fold( - err => - fail(`Failing decoding result, response: ${JSON.stringify(err)}`), - failure => { - expect(failure.kind).toEqual(expect.any(String)); - } - ); - }, - _ => fail(`Should not consider this a Right`) + ActivityResultFailure.decode(result).fold( + err => fail(`Failing decoding result, response: ${JSON.stringify(err)}`), + failure => { + expect(failure.kind).toEqual(expect.any(String)); + } ); }); @@ -94,17 +86,11 @@ describe("SetUserDataProcessingStatusActivityHandler", () => { }; const result = await handler(contextMock, input); - result.fold( - response => { - ActivityResultFailure.decode(response).fold( - err => - fail(`Failing decoding result, response: ${JSON.stringify(err)}`), - failure => { - expect(failure.kind).toEqual(expect.any(String)); - } - ); - }, - _ => fail(`Should not consider this a Right`) + ActivityResultFailure.decode(result).fold( + err => fail(`Failing decoding result, response: ${JSON.stringify(err)}`), + failure => { + expect(failure.kind).toEqual(expect.any(String)); + } ); }); @@ -118,17 +104,11 @@ describe("SetUserDataProcessingStatusActivityHandler", () => { invalid: "input" }); - result.fold( - response => { - ActivityResultFailure.decode(response).fold( - err => - fail(`Failing decoding result, response: ${JSON.stringify(err)}`), - failure => { - expect(failure.kind).toEqual(expect.any(String)); - } - ); - }, - _ => fail(`Should not consider this a Right`) + ActivityResultFailure.decode(result).fold( + err => fail(`Failing decoding result, response: ${JSON.stringify(err)}`), + failure => { + expect(failure.kind).toEqual(expect.any(String)); + } ); }); }); diff --git a/SetUserDataProcessingStatusActivity/handler.ts b/SetUserDataProcessingStatusActivity/handler.ts index 0b1489a4..992e26aa 100644 --- a/SetUserDataProcessingStatusActivity/handler.ts +++ b/SetUserDataProcessingStatusActivity/handler.ts @@ -170,5 +170,6 @@ export const createSetUserDataProcessingStatusActivityHandler = ( logFailure(context)(failure); return failure; }) - .run(); + .run() + .then(e => e.value); }; diff --git a/UserDataDownloadOrchestrator/cli.ts b/UserDataDownloadOrchestrator/cli.ts index 69243dad..810e016e 100644 --- a/UserDataDownloadOrchestrator/cli.ts +++ b/UserDataDownloadOrchestrator/cli.ts @@ -4,13 +4,15 @@ // tslint:disable: no-console no-any +import * as dotenv from "dotenv"; +dotenv.config(); + import { Context } from "@azure/functions"; -import { Either, toError } from "fp-ts/lib/Either"; -import { fromEither, TaskEither, tryCatch } from "fp-ts/lib/TaskEither"; import { readableReport } from "italia-ts-commons/lib/reporters"; import { FiscalCode } from "italia-ts-commons/lib/strings"; import extractUserDataActivity from "../ExtractUserDataActivity"; -import setUserDataProcessingStatusActivity from "../setUserDataProcessingStatusActivity"; +import sendUserDataDownloadMessageActivity from "../SendUserDataDownloadMessageActivity"; +import setUserDataProcessingStatusActivity from "../SetUserDataProcessingStatusActivity"; import { UserDataProcessingChoiceEnum } from "io-functions-commons/dist/generated/definitions/UserDataProcessingChoice"; import { UserDataProcessingStatusEnum } from "io-functions-commons/dist/generated/definitions/UserDataProcessingStatus"; @@ -18,30 +20,17 @@ import { makeUserDataProcessingId, UserDataProcessing } from "io-functions-commons/dist/src/models/user_data_processing"; -import { - ActivityResultFailure as UserDataExtractionFailure, - ActivityResultSuccess -} from "../ExtractUserDataActivity/handler"; -import { ActivityResultFailure as SetUserDataProcessingStatusFailure } from "../SetUserDataProcessingStatusActivity/handler"; const context = ({ - log: console + log: { + info: console.log, + verbose: console.log + } // tslint:disable-next-line: no-any } as any) as Context; -const fromPromiseEither = ( - lazyPromise: () => Promise> -): TaskEither => - tryCatch(lazyPromise, toError).chain((queryErrorOrRecord: Either) => - fromEither(queryErrorOrRecord) - ); - -async function run(): Promise< - Either< - UserDataExtractionFailure | SetUserDataProcessingStatusFailure, - ActivityResultSuccess - > -> { +// tslint:disable-next-line: max-union-size +async function run(): Promise { const fiscalCode = FiscalCode.decode(process.argv[2]).getOrElseL(reason => { throw new Error(`Invalid input: ${readableReport(reason)}`); }); @@ -60,28 +49,37 @@ async function run(): Promise< ); }); - const setToWipOrError = fromPromiseEither(() => - setUserDataProcessingStatusActivity(context, { - currentRecord: currentUserDataProcessing, - nextStatus: UserDataProcessingStatusEnum.WIP + return setUserDataProcessingStatusActivity(context, { + currentRecord: currentUserDataProcessing, + nextStatus: UserDataProcessingStatusEnum.WIP + }) + .then(userData => { + if (userData.kind === "SUCCESS") { + return extractUserDataActivity(context, { + fiscalCode + }); + } else { + throw new Error(userData.kind); + } }) - ); - - const createUserDataBundleOrError = fromPromiseEither(() => - extractUserDataActivity(context, { fiscalCode }) - ); - - const setToClosedOrError = fromPromiseEither(() => - setUserDataProcessingStatusActivity(context, { - currentRecord: currentUserDataProcessing, - nextStatus: UserDataProcessingStatusEnum.CLOSED + .then(bundle => { + if (bundle.kind === "SUCCESS") { + return sendUserDataDownloadMessageActivity(context, { + blobName: bundle.value.blobName, + fiscalCode: currentUserDataProcessing.fiscalCode, + password: bundle.value.password + }); + } else { + throw new Error(bundle.kind); + } }) - ); - - return setToWipOrError - .chain(() => createUserDataBundleOrError) - .chain(result => setToClosedOrError.map(() => result)) - .run(); + .then(() => + setUserDataProcessingStatusActivity(context, { + currentRecord: currentUserDataProcessing, + nextStatus: UserDataProcessingStatusEnum.CLOSED + }) + ) + .catch(console.error); } run() diff --git a/package.json b/package.json index 5a14617b..e93b6405 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "release-it": "^13.1.1", "shx": "^0.3.2", "ts-jest": "^24.0.2", + "ts-node": "^8.10.1", "tslint": "^5.17.0", "typescript": "^3.6.2" }, @@ -61,7 +62,7 @@ "io-functions-commons": "^9.0.0", "io-functions-express": "^0.1.0", "io-ts": "1.8.5", - "italia-ts-commons": "^5.1.11", + "italia-ts-commons": "^8.1.0", "randomstring": "^1.1.5", "ulid": "^2.3.0", "winston": "^3.2.1" diff --git a/yarn.lock b/yarn.lock index eb6ededa..393ec114 100644 --- a/yarn.lock +++ b/yarn.lock @@ -844,6 +844,13 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -914,6 +921,15 @@ agent-base@4, agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" +agentkeepalive@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.1.2.tgz#d7bc3bafd7ea88032f6be22b6f1389b3d42c9c91" + integrity sha512-waNHE7tQBBn+2qXucI8HY0o2Y0OBPWldWOWsZwY71JcCm4SvrPnWdceFfB5NIXSqE8Ewq6VR/Qt5b1i69P6KCQ== + dependencies: + debug "^4.1.0" + depd "^1.1.2" + humanize-ms "^1.2.1" + "agentkeepalive@https://github.com/pagopa/agentkeepalive#v4.1.1": version "4.1.0" resolved "https://github.com/pagopa/agentkeepalive#91309bcab216dccbd08631e227a974afbfe807fb" @@ -1092,6 +1108,11 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -2700,6 +2721,11 @@ diff@^3.0.0, diff@^3.2.0: resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -3009,6 +3035,11 @@ etag@^1.8.1, etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + exec-sh@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" @@ -4735,7 +4766,7 @@ istanbul-reports@^2.1.1: dependencies: handlebars "^4.1.2" -italia-ts-commons@^5.0.1, italia-ts-commons@^5.1.11: +italia-ts-commons@^5.0.1: version "5.1.11" resolved "https://registry.yarnpkg.com/italia-ts-commons/-/italia-ts-commons-5.1.11.tgz#323a5727371f995cd70c6f3b10a9407de687d83e" integrity sha512-8TPHDzK1mZtn4QRH6KypTfFBxYOEShsc8nVLCdVlwVAEJwMiFWr6bL2CeO5WZ+Dt3RmUZz0MXCpN5u8WPKGT5Q== @@ -4758,6 +4789,20 @@ italia-ts-commons@^7.0.1: node-fetch "^2.6.0" validator "^10.1.0" +italia-ts-commons@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/italia-ts-commons/-/italia-ts-commons-8.1.0.tgz#929c805a7d9e8877fef26436946bf3ee76a76c82" + integrity sha512-d03UKxjeIX+4otNgZaDoS8t1l+gVEHD/q/JsQox1CC3nAiKHQ9TFNv4BdHIiUIswgpx1szjT6lzeJQUCUL++YA== + dependencies: + abort-controller "^3.0.0" + agentkeepalive "^4.1.2" + applicationinsights "^1.7.4" + fp-ts "1.17.4" + io-ts "1.8.5" + json-set-map "^1.0.2" + node-fetch "^2.6.0" + validator "^10.1.0" + italia-tslint-rules@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/italia-tslint-rules/-/italia-tslint-rules-1.1.3.tgz#efac0c9638d14cef6cc907be74f0799b8bab0976" @@ -6005,6 +6050,11 @@ make-error@1.x: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" @@ -8209,6 +8259,14 @@ source-map-support@^0.4.15: dependencies: source-map "^0.5.6" +source-map-support@^0.5.17: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@^0.5.6: version "0.5.12" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" @@ -8746,6 +8804,17 @@ ts-jest@^24.0.2: semver "^5.5" yargs-parser "10.x" +ts-node@^8.10.1: + version "8.10.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.1.tgz#77da0366ff8afbe733596361d2df9a60fc9c9bd3" + integrity sha512-bdNz1L4ekHiJul6SHtZWs1ujEKERJnHs4HxN7rjTyyVOFf3HaJ6sLqe6aPG62XTzAB/63pKRh5jTSWL0D7bsvw== + dependencies: + arg "^4.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + tslib@1.9.0, tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1: version "1.9.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" @@ -9676,6 +9745,11 @@ yargs@^6.3.0: y18n "^3.2.1" yargs-parser "^4.2.0" +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + z-schema@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-4.1.1.tgz#f987f52142de54943bd85bb6f6d63bf44807fb6c"