diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index beae7aa5a70c..8920e0e5f3b2 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -20500,10 +20500,11 @@ packages: dev: false file:projects/health-deidentification.tgz: - resolution: {integrity: sha512-6LdN/I3/IT+r5A4w8Ac5rRXYnfUzCGhSyEhSq0zB1vEsyX0oOz5viCnGYYqmiyOOfGvgqaMBOk4KwrCCeMcTOA==, tarball: file:projects/health-deidentification.tgz} + resolution: {integrity: sha512-UmI085QeO7kUZ6n5F6vQ4t4RZHOUNQpm74yjDIAgJcB17mb7QTqbzsMD6jlQJsGQfgY9EfB3QH40gPACmWumkA==, tarball: file:projects/health-deidentification.tgz} name: '@rush-temp/health-deidentification' version: 0.0.0 dependencies: + '@microsoft/api-extractor': 7.48.0(@types/node@18.19.67) '@types/node': 18.19.67 '@vitest/browser': 2.1.8(@types/node@18.19.67)(playwright@1.49.0)(typescript@5.6.3)(vitest@2.1.8) '@vitest/coverage-istanbul': 2.1.8(vitest@2.1.8) diff --git a/sdk/healthdataaiservices/azure-health-deidentification/CHANGELOG.md b/sdk/healthdataaiservices/azure-health-deidentification/CHANGELOG.md index f5986a61661e..24a4fcb06848 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/CHANGELOG.md +++ b/sdk/healthdataaiservices/azure-health-deidentification/CHANGELOG.md @@ -1,9 +1,7 @@ # Release History - -## 1.0.0-beta.1 (2024-08-15) - -- Azure Deidentification client library for JS. This package contains Microsoft Azure Deidentification client library. + +## 1.0.0 (2024-12-06) ### Features Added -- Azure Deidentification client library for JS. This package contains Microsoft Azure Deidentification client library. +The package of @azure-rest/health-deidentification is using our next generation design principles. To learn more, please refer to our documentation [Quick Start](https://aka.ms/azsdk/js/mgmt/quickstart). diff --git a/sdk/healthdataaiservices/azure-health-deidentification/README.md b/sdk/healthdataaiservices/azure-health-deidentification/README.md index ce0923b0f8ae..dc09ce4f0be6 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/README.md +++ b/sdk/healthdataaiservices/azure-health-deidentification/README.md @@ -1,12 +1,14 @@ # Azure Deidentification REST client library for JavaScript -`@azure-rest/health-deidentification` is a managed service that enables users to tag, redact, or surrogate health data. +Health Deidentification Service + +**Please rely heavily on our [REST client docs](https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/rest-clients.md) to use this library** - - Key links: +- [Source code](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/healthdataaiservices/azure-health-deidentification) - [Package (NPM)](https://www.npmjs.com/package/@azure-rest/health-deidentification) +- [API reference documentation](https://docs.microsoft.com/javascript/api/@azure-rest/health-deidentification?view=azure-node-preview) ## Getting started @@ -32,58 +34,12 @@ To use an [Azure Active Directory (AAD) token credential](https://github.com/Azu provide an instance of the desired credential type obtained from the [@azure/identity](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#credentials) library. -To authenticate with AAD, you must first `npm` install [`@azure/identity`](https://www.npmjs.com/package/@azure/identity) +To authenticate with AAD, you must first `npm` install [`@azure/identity`](https://www.npmjs.com/package/@azure/identity) After setup, you can choose which type of [credential](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#credentials) from `@azure/identity` to use. As an example, [DefaultAzureCredential](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#defaultazurecredential) can be used to authenticate the client. -Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables: -`AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET` - -Pull `ServiceUrl` from your created Deidentification Service. - -![Service Url Location](documentation/images/ServiceUrl_Location.png) - -Basic code snippet to create your Deidentification Client and Deidentify a string. - -```javascript -import createClient, { - DeidentificationContent, - isUnexpected, -} from "@azure-rest/health-deidentification"; -import { DefaultAzureCredential } from "@azure/identity"; -import * as dotenv from "dotenv"; -dotenv.config(); - -const credential = new DefaultAzureCredential(); -const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; -const client = createClient(serviceEndpoint, credential); - -const content: DeidentificationContent = { - inputText: "Hello John!" -}; - -const response = await client.path("/deid").post({ body: content }); - -if (isUnexpected(response)) { - throw response.body.error; -} - -console.log(response.body.outputText); // Hello, Tom! -``` - -## Key concept - -Operation Modes: - -- Tag: Will return a structure of offset and length with the PHI category of the related text spans. -- Redact: Will return output text with placeholder stubbed text. ex. `[name]` -- Surrogate: Will return output text with synthetic replacements. - - `My name is John Smith` - - `My name is Tom Jones` - ## Troubleshooting ### Logging diff --git a/sdk/healthdataaiservices/azure-health-deidentification/api-extractor.json b/sdk/healthdataaiservices/azure-health-deidentification/api-extractor.json index 5c52d7bd991b..3ad083c82add 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/api-extractor.json +++ b/sdk/healthdataaiservices/azure-health-deidentification/api-extractor.json @@ -1,18 +1,31 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", "mainEntryPointFilePath": "./dist/esm/index.d.ts", - "docModel": { "enabled": true }, - "apiReport": { "enabled": true, "reportFolder": "./review" }, + "docModel": { + "enabled": true + }, + "apiReport": { + "enabled": true, + "reportFolder": "./review" + }, "dtsRollup": { "enabled": true, "untrimmedFilePath": "", "publicTrimmedFilePath": "./types/health-deidentification.d.ts" }, "messages": { - "tsdocMessageReporting": { "default": { "logLevel": "none" } }, + "tsdocMessageReporting": { + "default": { + "logLevel": "none" + } + }, "extractorMessageReporting": { - "ae-missing-release-tag": { "logLevel": "none" }, - "ae-unresolved-link": { "logLevel": "none" } + "ae-missing-release-tag": { + "logLevel": "none" + }, + "ae-unresolved-link": { + "logLevel": "none" + } } } -} +} \ No newline at end of file diff --git a/sdk/healthdataaiservices/azure-health-deidentification/assets.json b/sdk/healthdataaiservices/azure-health-deidentification/assets.json deleted file mode 100644 index 31fc3d9e152c..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/assets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "AssetsRepo": "Azure/azure-sdk-assets", - "AssetsRepoPrefixPath": "js", - "TagPrefix": "js/healthdataaiservices/azure-health-deidentification", - "Tag": "js/healthdataaiservices/azure-health-deidentification_69c12d020a" -} diff --git a/sdk/healthdataaiservices/azure-health-deidentification/config/rush-project.json b/sdk/healthdataaiservices/azure-health-deidentification/config/rush-project.json deleted file mode 100644 index c53fef6ca15b..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/config/rush-project.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../../../common/config/rush-project.json", -} diff --git a/sdk/healthdataaiservices/azure-health-deidentification/documentation/images/ServiceUrl_Location.png b/sdk/healthdataaiservices/azure-health-deidentification/documentation/images/ServiceUrl_Location.png deleted file mode 100644 index 923747280e93..000000000000 Binary files a/sdk/healthdataaiservices/azure-health-deidentification/documentation/images/ServiceUrl_Location.png and /dev/null differ diff --git a/sdk/healthdataaiservices/azure-health-deidentification/eslint.config.mjs b/sdk/healthdataaiservices/azure-health-deidentification/eslint.config.mjs index 48206a891e00..113bdc3eaf5f 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/eslint.config.mjs +++ b/sdk/healthdataaiservices/azure-health-deidentification/eslint.config.mjs @@ -1,18 +1,17 @@ import azsdkEslint from "@azure/eslint-plugin-azure-sdk"; -export default azsdkEslint.config([ +export default [ + ...azsdkEslint.configs.recommended, { rules: { "@azure/azure-sdk/ts-modules-only-named": "warn", "@azure/azure-sdk/ts-apiextractor-json-types": "warn", "@azure/azure-sdk/ts-package-json-types": "warn", "@azure/azure-sdk/ts-package-json-engine-is-present": "warn", - "tsdoc/syntax": "warn", "@azure/azure-sdk/ts-package-json-module": "off", "@azure/azure-sdk/ts-package-json-files-required": "off", "@azure/azure-sdk/ts-package-json-main-is-cjs": "off", - "@azure/azure-sdk/ts-package-json-name": "warn", - "@azure/azure-sdk/ts-package-json-homepage": "warn", - }, - }, -]); + "tsdoc/syntax": "warn" + } + } +]; diff --git a/sdk/healthdataaiservices/azure-health-deidentification/package.json b/sdk/healthdataaiservices/azure-health-deidentification/package.json index 9e7f861696ef..c265e294fc98 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/package.json +++ b/sdk/healthdataaiservices/azure-health-deidentification/package.json @@ -1,7 +1,6 @@ { "name": "@azure-rest/health-deidentification", - "version": "1.0.0-beta.1", - "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/healthdataaiservices/azure-health-deidentification", + "version": "1.0.0", "description": "Health Deidentification Service", "engines": { "node": ">=18.0.0" @@ -38,82 +37,72 @@ "dist", "README.md", "LICENSE", - "review/*" + "review/*", + "CHANGELOG.md" ], "sdk-type": "client", "repository": "github:Azure/azure-sdk-for-js", "bugs": { "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, + "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/healthdataaiservices/azure-health-deidentification/README.md", "prettier": "@azure/eslint-plugin-azure-sdk/prettier.json", "//metadata": { "constantPaths": [ { "path": "src/deidentificationClient.ts", - "prefix": "package-version" + "prefix": "userAgentInfo" } - ], - "sampleConfiguration": { - "skipFolder": false, - "disableDocsMs": true, - "productName": "Health Deidentification Service", - "productSlugs": [], - "apiRefLink": "https://docs.microsoft.com/javascript/api/", - "requiredResources": { - "De-identification Service": "https://docs.microsoft.com/javascript/api/" - } - } + ] }, "dependencies": { - "@azure-rest/core-client": "^2.2.0", - "@azure/abort-controller": "^2.0.0", + "@azure-rest/core-client": "^2.3.1", "@azure/core-auth": "^1.6.0", - "@azure/core-lro": "^3.0.0", - "@azure/core-paging": "^1.6.2", "@azure/core-rest-pipeline": "^1.5.0", - "@azure/identity": "^4.4.0", "@azure/logger": "^1.0.0", - "dotenv": "^16.0.0", - "tslib": "^2.6.2" + "tslib": "^2.6.2", + "@azure/core-lro": "^3.1.0", + "@azure/abort-controller": "^2.1.2" }, "devDependencies": { - "@azure-tools/test-credential": "^2.1.0", - "@azure-tools/test-recorder": "^4.1.0", - "@azure/core-util": "^1.9.0", - "@azure/dev-tool": "^1.0.0", - "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "dotenv": "^16.0.0", + "@microsoft/api-extractor": "^7.40.3", "@types/node": "^18.0.0", + "eslint": "^9.9.0", + "typescript": "~5.6.2", + "@azure/identity": "^4.2.1", "@vitest/browser": "^2.0.5", "@vitest/coverage-istanbul": "^2.0.5", - "eslint": "^9.9.0", - "loupe": "~3.1.1", "playwright": "^1.41.2", - "typescript": "~5.6.2", - "vitest": "^2.0.5" + "vitest": "^2.0.5", + "@azure-tools/test-credential": "^2.0.0", + "@azure-tools/test-recorder": "^4.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0" }, "scripts": { - "build": "npm run clean && dev-tool run build-package && dev-tool run extract-api", - "build:node": "dev-tool run build-package", - "build:samples": "echo Obsolete.", - "build:test": "echo skipped. actual commands inlined in browser test scripts", - "check-format": "dev-tool run vendored prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\" \"samples-dev/**/*.ts\"", "clean": "dev-tool run vendored rimraf --glob dist dist-browser dist-esm test-dist temp types *.tgz *.log", - "execute:samples": "dev-tool samples run samples-dev", - "extract-api": "dev-tool run build-package && dev-tool run extract-api", - "format": "dev-tool run vendored prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\" \"samples-dev/**/*.ts\"", - "generate:client": "autorest --typescript ./swagger/README.md", - "integration-test": "npm run integration-test:node && npm run integration-test:browser", - "integration-test:browser": "dev-tool run build-package && dev-tool run build-test && dev-tool run test:vitest --browser", - "integration-test:node": "dev-tool run build-package && dev-tool run build-test && dev-tool run test:vitest", + "extract-api": "dev-tool run vendored rimraf review && dev-tool run vendored mkdirp ./review && dev-tool run extract-api", + "pack": "npm pack 2>&1", "lint": "eslint package.json api-extractor.json src test", "lint:fix": "eslint package.json api-extractor.json src test --fix --fix-type [problem,suggestion]", - "pack": "npm pack 2>&1", - "test": "npm run clean && dev-tool run build-package && npm run unit-test:node && dev-tool run bundle && npm run unit-test:browser", - "test:browser": "npm run clean && npm run build:test && npm run unit-test:browser", - "test:node": "npm run clean && dev-tool run build-package && npm run unit-test:node", "unit-test": "npm run unit-test:node && npm run unit-test:browser", - "unit-test:browser": "npm run integration-test:browser", - "unit-test:node": "npm run integration-test:node", + "unit-test:browser": "npm run build:test && dev-tool run test:vitest --browser", + "unit-test:node": "dev-tool run test:vitest", + "integration-test": "npm run integration-test:node && npm run integration-test:browser", + "integration-test:browser": "echo skipped", + "integration-test:node": "echo skipped", + "build:samples": "echo skipped", + "check-format": "dev-tool run vendored prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.{ts,cts,mts}\" \"test/**/*.{ts,cts,mts}\" \"*.{js,cjs,mjs,json}\" ", + "execute:samples": "echo skipped", + "format": "dev-tool run vendored prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.{ts,cts,mts}\" \"test/**/*.{ts,cts,mts}\" \"*.{js,cjs,mjs,json}\" ", + "generate:client": "echo skipped", + "test:browser": "npm run clean && npm run build:test && npm run unit-test:browser && npm run integration-test:browser", + "minify": "dev-tool run vendored uglifyjs -c -m --comments --source-map \"content='./dist/index.js.map'\" -o ./dist/index.min.js ./dist/index.js", + "build:test": "npm run clean && dev-tool run build-package && dev-tool run build-test", + "build": "npm run clean && dev-tool run build-package && dev-tool run vendored mkdirp ./review && dev-tool run extract-api", + "test:node": "npm run clean && dev-tool run build-package && npm run unit-test:node && npm run integration-test:node", + "test": "npm run clean && dev-tool run build-package && npm run unit-test:node && dev-tool run bundle && npm run unit-test:browser && npm run integration-test", "update-snippets": "echo skipped" }, "exports": { @@ -138,6 +127,5 @@ } }, "main": "./dist/commonjs/index.js", - "types": "./dist/commonjs/index.d.ts", - "module": "./dist/esm/index.js" -} + "types": "./dist/commonjs/index.d.ts" +} \ No newline at end of file diff --git a/sdk/healthdataaiservices/azure-health-deidentification/review/health-deidentification.api.md b/sdk/healthdataaiservices/azure-health-deidentification/review/health-deidentification.api.md index 2a20f945c003..b286afd277eb 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/review/health-deidentification.api.md +++ b/sdk/healthdataaiservices/azure-health-deidentification/review/health-deidentification.api.md @@ -4,23 +4,21 @@ ```ts -import type { AbortSignalLike } from '@azure/abort-controller'; -import type { CancelOnProgress } from '@azure/core-lro'; -import type { Client } from '@azure-rest/core-client'; -import type { ClientOptions } from '@azure-rest/core-client'; -import type { CreateHttpPollerOptions } from '@azure/core-lro'; -import type { ErrorModel } from '@azure-rest/core-client'; -import type { ErrorResponse } from '@azure-rest/core-client'; -import type { HttpResponse } from '@azure-rest/core-client'; -import type { OperationState } from '@azure/core-lro'; -import type { Paged } from '@azure/core-paging'; -import type { PagedAsyncIterableIterator } from '@azure/core-paging'; -import type { PathUncheckedResponse } from '@azure-rest/core-client'; -import type { RawHttpHeaders } from '@azure/core-rest-pipeline'; -import type { RawHttpHeadersInput } from '@azure/core-rest-pipeline'; -import type { RequestParameters } from '@azure-rest/core-client'; -import type { StreamableMethod } from '@azure-rest/core-client'; -import type { TokenCredential } from '@azure/core-auth'; +import { AbortSignalLike } from '@azure/abort-controller'; +import { CancelOnProgress } from '@azure/core-lro'; +import { Client } from '@azure-rest/core-client'; +import { ClientOptions } from '@azure-rest/core-client'; +import { CreateHttpPollerOptions } from '@azure/core-lro'; +import { ErrorModel } from '@azure-rest/core-client'; +import { ErrorResponse } from '@azure-rest/core-client'; +import { HttpResponse } from '@azure-rest/core-client'; +import { OperationState as OperationState_2 } from '@azure/core-lro'; +import { PathUncheckedResponse } from '@azure-rest/core-client'; +import { RawHttpHeaders } from '@azure/core-rest-pipeline'; +import { RawHttpHeadersInput } from '@azure/core-rest-pipeline'; +import { RequestParameters } from '@azure-rest/core-client'; +import { StreamableMethod } from '@azure-rest/core-client'; +import { TokenCredential } from '@azure/core-auth'; // @public (undocumented) export interface CancelJob { @@ -76,70 +74,173 @@ function createClient(endpointParam: string, credentials: TokenCredential, { api export default createClient; // @public (undocumented) -export interface CreateJob200Headers { +export type DeidentificationClient = Client & { + path: Routes; +}; + +// @public +export interface DeidentificationClientOptions extends ClientOptions { + apiVersion?: string; +} + +// @public +export interface DeidentificationContent { + customizations?: DeidentificationCustomizationOptions; + inputText: string; + operation?: DeidentificationOperationType; +} + +// @public +export interface DeidentificationCustomizationOptions { + redactionFormat?: string; + surrogateLocale?: string; +} + +// @public +export interface DeidentificationDocumentDetailsOutput { + error?: ErrorModel; + readonly id: string; + input: DeidentificationDocumentLocationOutput; + output?: DeidentificationDocumentLocationOutput; + status: OperationStateOutput; +} + +// @public +export interface DeidentificationDocumentLocationOutput { + readonly etag: string; + location: string; +} + +// @public +export interface DeidentificationJob { + customizations?: DeidentificationJobCustomizationOptions; + operation?: DeidentificationOperationType; + sourceLocation: SourceStorageLocation; + targetLocation: TargetStorageLocation; +} + +// @public +export interface DeidentificationJobCustomizationOptions { + redactionFormat?: string; + surrogateLocale?: string; +} + +// @public +export interface DeidentificationJobCustomizationOptionsOutput { + redactionFormat?: string; + surrogateLocale?: string; +} + +// @public +export interface DeidentificationJobOutput { + readonly createdAt: string; + customizations?: DeidentificationJobCustomizationOptionsOutput; + readonly error?: ErrorModel; + readonly lastUpdatedAt: string; + readonly name: string; + operation?: DeidentificationOperationTypeOutput; + sourceLocation: SourceStorageLocationOutput; + readonly startedAt?: string; + readonly status: OperationStateOutput; + readonly summary?: DeidentificationJobSummaryOutput; + targetLocation: TargetStorageLocationOutput; +} + +// @public +export interface DeidentificationJobSummary { + bytesProcessed: number; + canceled: number; + failed: number; + successful: number; + total: number; +} + +// @public +export interface DeidentificationJobSummaryOutput { + bytesProcessed: number; + canceled: number; + failed: number; + successful: number; + total: number; +} + +// @public +export type DeidentificationOperationType = string; + +// @public +export type DeidentificationOperationTypeOutput = string; + +// @public +export interface DeidentificationResultOutput { + outputText?: string; + taggerResult?: PhiTaggerResultOutput; +} + +// @public (undocumented) +export interface DeidentifyDocuments200Headers { "operation-location": string; "x-ms-client-request-id"?: string; } // @public -export interface CreateJob200Response extends HttpResponse { +export interface DeidentifyDocuments200Response extends HttpResponse { // (undocumented) body: DeidentificationJobOutput; // (undocumented) - headers: RawHttpHeaders & CreateJob200Headers; + headers: RawHttpHeaders & DeidentifyDocuments200Headers; // (undocumented) status: "200"; } // @public (undocumented) -export interface CreateJob201Headers { +export interface DeidentifyDocuments201Headers { "operation-location": string; "x-ms-client-request-id"?: string; } // @public -export interface CreateJob201Response extends HttpResponse { +export interface DeidentifyDocuments201Response extends HttpResponse { // (undocumented) body: DeidentificationJobOutput; // (undocumented) - headers: RawHttpHeaders & CreateJob201Headers; + headers: RawHttpHeaders & DeidentifyDocuments201Headers; // (undocumented) status: "201"; } // @public (undocumented) -export interface CreateJobBodyParam { +export interface DeidentifyDocumentsBodyParam { body: DeidentificationJob; } // @public (undocumented) -export interface CreateJobDefaultHeaders { +export interface DeidentifyDocumentsDefaultHeaders { "x-ms-error-code"?: string; } // @public (undocumented) -export interface CreateJobDefaultResponse extends HttpResponse { +export interface DeidentifyDocumentsDefaultResponse extends HttpResponse { // (undocumented) body: ErrorResponse; // (undocumented) - headers: RawHttpHeaders & CreateJobDefaultHeaders; + headers: RawHttpHeaders & DeidentifyDocumentsDefaultHeaders; // (undocumented) status: string; } // @public (undocumented) -export interface CreateJobHeaderParam { +export interface DeidentifyDocumentsHeaderParam { // (undocumented) - headers?: RawHttpHeadersInput & CreateJobHeaders; + headers?: RawHttpHeadersInput & DeidentifyDocumentsHeaders; } // @public (undocumented) -export interface CreateJobHeaders { +export interface DeidentifyDocumentsHeaders { "x-ms-client-request-id"?: string; } // @public -export interface CreateJobLogicalResponse extends HttpResponse { +export interface DeidentifyDocumentsLogicalResponse extends HttpResponse { // (undocumented) body: DeidentificationJobOutput; // (undocumented) @@ -147,92 +248,61 @@ export interface CreateJobLogicalResponse extends HttpResponse { } // @public (undocumented) -export type CreateJobParameters = CreateJobHeaderParam & CreateJobBodyParam & RequestParameters; +export type DeidentifyDocumentsParameters = DeidentifyDocumentsHeaderParam & DeidentifyDocumentsBodyParam & RequestParameters; // @public (undocumented) -export type DeidentificationClient = Client & { - path: Routes; -}; - -// @public -export interface DeidentificationClientOptions extends ClientOptions { - apiVersion?: string; -} - -// @public -export interface DeidentificationContent { - dataType?: DocumentDataType; - inputText: string; - operation?: OperationType; - redactionFormat?: string; -} - -// @public -export interface DeidentificationJob { - dataType?: DocumentDataType; - operation?: OperationType; - redactionFormat?: string; - sourceLocation: SourceStorageLocation; - targetLocation: TargetStorageLocation; -} - -// @public -export interface DeidentificationJobOutput { - readonly createdAt: string; - dataType?: DocumentDataTypeOutput; - readonly error?: ErrorModel; - readonly lastUpdatedAt: string; - readonly name: string; - operation?: OperationTypeOutput; - redactionFormat?: string; - sourceLocation: SourceStorageLocationOutput; - readonly startedAt?: string; - readonly status: JobStatusOutput; - readonly summary?: JobSummaryOutput; - targetLocation: TargetStorageLocationOutput; -} - -// @public -export interface DeidentificationResultOutput { - outputText?: string; - taggerResult?: PhiTaggerResultOutput; +export interface DeidentifyText { + post(options: DeidentifyTextParameters): StreamableMethod; } // @public (undocumented) -export interface Deidentify { - post(options: DeidentifyParameters): StreamableMethod; +export interface DeidentifyText200Headers { + "x-ms-client-request-id"?: string; } // @public -export interface Deidentify200Response extends HttpResponse { +export interface DeidentifyText200Response extends HttpResponse { // (undocumented) body: DeidentificationResultOutput; // (undocumented) + headers: RawHttpHeaders & DeidentifyText200Headers; + // (undocumented) status: "200"; } // @public (undocumented) -export interface DeidentifyBodyParam { +export interface DeidentifyTextBodyParam { body: DeidentificationContent; } // @public (undocumented) -export interface DeidentifyDefaultHeaders { +export interface DeidentifyTextDefaultHeaders { "x-ms-error-code"?: string; } // @public (undocumented) -export interface DeidentifyDefaultResponse extends HttpResponse { +export interface DeidentifyTextDefaultResponse extends HttpResponse { // (undocumented) body: ErrorResponse; // (undocumented) - headers: RawHttpHeaders & DeidentifyDefaultHeaders; + headers: RawHttpHeaders & DeidentifyTextDefaultHeaders; // (undocumented) status: string; } // @public (undocumented) -export type DeidentifyParameters = DeidentifyBodyParam & RequestParameters; +export interface DeidentifyTextHeaderParam { + // (undocumented) + headers?: RawHttpHeadersInput & DeidentifyTextHeaders; +} + +// @public (undocumented) +export interface DeidentifyTextHeaders { + "x-ms-client-request-id"?: string; +} + +// @public (undocumented) +export type DeidentifyTextParameters = DeidentifyTextHeaderParam & DeidentifyTextBodyParam & RequestParameters; // @public (undocumented) export interface DeleteJob204Headers { @@ -276,27 +346,6 @@ export interface DeleteJobHeaders { // @public (undocumented) export type DeleteJobParameters = DeleteJobHeaderParam & RequestParameters; -// @public -export type DocumentDataType = string; - -// @public -export type DocumentDataTypeOutput = string; - -// @public -export interface DocumentDetailsOutput { - error?: ErrorModel; - readonly id: string; - input: DocumentLocationOutput; - output?: DocumentLocationOutput; - status: OperationStateOutput; -} - -// @public -export interface DocumentLocationOutput { - readonly etag: string; - path: string; -} - // @public export type GetArrayType = T extends Array ? TData : never; @@ -304,7 +353,7 @@ export type GetArrayType = T extends Array ? TData : never; export interface GetJob { delete(options?: DeleteJobParameters): StreamableMethod; get(options?: GetJobParameters): StreamableMethod; - put(options: CreateJobParameters): StreamableMethod; + put(options: DeidentifyDocumentsParameters): StreamableMethod; } // @public (undocumented) @@ -352,10 +401,10 @@ export interface GetJobHeaders { export type GetJobParameters = GetJobHeaderParam & RequestParameters; // @public -export function getLongRunningPoller(client: Client, initialResponse: CreateJob200Response | CreateJob201Response | CreateJobDefaultResponse, options?: CreateHttpPollerOptions>): Promise, TResult>>; +export function getLongRunningPoller(client: Client, initialResponse: DeidentifyDocuments200Response | DeidentifyDocuments201Response | DeidentifyDocumentsDefaultResponse, options?: CreateHttpPollerOptions>): Promise, TResult>>; // @public -export type GetPage = (pageLink: string, maxPageSize?: number) => Promise<{ +export type GetPage = (pageLink: string) => Promise<{ page: TPage; nextPageLink?: string; }>; @@ -364,7 +413,7 @@ export type GetPage = (pageLink: string, maxPageSize?: number) => Promise export function isUnexpected(response: GetJob200Response | GetJobDefaultResponse): response is GetJobDefaultResponse; // @public (undocumented) -export function isUnexpected(response: CreateJob200Response | CreateJob201Response | CreateJobLogicalResponse | CreateJobDefaultResponse): response is CreateJobDefaultResponse; +export function isUnexpected(response: DeidentifyDocuments200Response | DeidentifyDocuments201Response | DeidentifyDocumentsLogicalResponse | DeidentifyDocumentsDefaultResponse): response is DeidentifyDocumentsDefaultResponse; // @public (undocumented) export function isUnexpected(response: DeleteJob204Response | DeleteJobDefaultResponse): response is DeleteJobDefaultResponse; @@ -379,31 +428,7 @@ export function isUnexpected(response: ListJobDocuments200Response | ListJobDocu export function isUnexpected(response: CancelJob200Response | CancelJobDefaultResponse): response is CancelJobDefaultResponse; // @public (undocumented) -export function isUnexpected(response: Deidentify200Response | DeidentifyDefaultResponse): response is DeidentifyDefaultResponse; - -// @public -export type JobStatus = string; - -// @public -export type JobStatusOutput = string; - -// @public -export interface JobSummary { - bytesProcessed: number; - canceled: number; - failed: number; - successful: number; - total: number; -} - -// @public -export interface JobSummaryOutput { - bytesProcessed: number; - canceled: number; - failed: number; - successful: number; - total: number; -} +export function isUnexpected(response: DeidentifyText200Response | DeidentifyTextDefaultResponse): response is DeidentifyTextDefaultResponse; // @public (undocumented) export interface ListJobDocuments { @@ -418,7 +443,7 @@ export interface ListJobDocuments200Headers { // @public export interface ListJobDocuments200Response extends HttpResponse { // (undocumented) - body: PagedDocumentDetailsOutput; + body: PagedDeidentificationDocumentDetailsOutput; // (undocumented) headers: RawHttpHeaders & ListJobDocuments200Headers; // (undocumented) @@ -527,20 +552,35 @@ export interface ListJobsQueryParamProperties { maxpagesize?: number; } +// @public +export type OperationState = string; + // @public export type OperationStateOutput = string; // @public -export type OperationType = string; +export interface PagedAsyncIterableIterator { + [Symbol.asyncIterator](): PagedAsyncIterableIterator; + byPage: (settings?: TPageSettings) => AsyncIterableIterator; + next(): Promise>; +} // @public -export type OperationTypeOutput = string; +export interface PagedDeidentificationDocumentDetailsOutput { + nextLink?: string; + value: Array; +} // @public -export type PagedDeidentificationJobOutput = Paged; +export interface PagedDeidentificationJobOutput { + nextLink?: string; + value: Array; +} // @public -export type PagedDocumentDetailsOutput = Paged; +export interface PageSettings { + continuationToken?: string; +} // @public export function paginate(client: Client, initialResponse: TResponse, options?: PagingOptions): PagedAsyncIterableIterator>; @@ -572,8 +612,6 @@ export interface PhiEntityOutput { // @public export interface PhiTaggerResultOutput { entities: Array; - etag?: string; - path?: string; } // @public (undocumented) @@ -582,11 +620,11 @@ export interface Routes { (path: "/jobs"): ListJobs; (path: "/jobs/{name}/documents", name: string): ListJobDocuments; (path: "/jobs/{name}:cancel", name: string): CancelJob; - (path: "/deid"): Deidentify; + (path: "/deid"): DeidentifyText; } // @public -export interface SimplePollerLike, TResult> { +export interface SimplePollerLike, TResult> { getOperationState(): TState; getResult(): TResult | undefined; isDone(): boolean; @@ -631,12 +669,14 @@ export interface StringIndexOutput { // @public export interface TargetStorageLocation { location: string; + overwrite?: boolean; prefix: string; } // @public export interface TargetStorageLocationOutput { location: string; + overwrite?: boolean; prefix: string; } diff --git a/sdk/healthdataaiservices/azure-health-deidentification/sample.env b/sdk/healthdataaiservices/azure-health-deidentification/sample.env index 2ff41595523b..508439fc7d62 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/sample.env +++ b/sdk/healthdataaiservices/azure-health-deidentification/sample.env @@ -1,5 +1 @@ -# Your De-identification Service URL can be found in the overview section of the Azure Portal. -DEID_SERVICE_ENDPOINT= -# Storage account and container name -STORAGE_ACCOUNT_NAME= -STORAGE_CONTAINER_NAME= +# Feel free to add your own environment variables. \ No newline at end of file diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/createJob.ts b/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/createJob.ts deleted file mode 100644 index 44b6b71301ad..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/createJob.ts +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to create a job which will deidentify all files within a blob storage container filtering via a prefix. - */ - -import createClient, { - DeidentificationJob, - isUnexpected, -} from "@azure-rest/health-deidentification"; -import { DefaultAzureCredential } from "@azure/identity"; -import * as dotenv from "dotenv"; -dotenv.config(); - -export async function main(): Promise { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const storageLocation = `https://${process.env["STORAGE_ACCOUNT_NAME"]}.blob.core.windows.net/${process.env["STORAGE_CONTAINER_NAME"]}`; - const location = storageLocation || "defaultSasUri"; - const OUTPUT_FOLDER = "_output"; - const inputPrefix = "example_patient_1"; - const client = createClient(serviceEndpoint, credential); - const jobName = "exampleJob"; - - const job: DeidentificationJob = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { location, prefix: inputPrefix }, - targetLocation: { location, prefix: OUTPUT_FOLDER }, - }; - const response = await client.path("/jobs/{name}", jobName).put({ body: job }); - - if (isUnexpected(response)) { - throw response.body.error; - } - - console.log(response.body); -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/helloWorld.ts b/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/helloWorld.ts deleted file mode 100644 index c96423ff88e9..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/helloWorld.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to create a `DeidentificationClient` and then deidentify a `string` - */ - -import createClient, { - DeidentificationContent, - isUnexpected, -} from "@azure-rest/health-deidentification"; -import { DefaultAzureCredential } from "@azure/identity"; -import * as dotenv from "dotenv"; -dotenv.config(); - -export async function main(): Promise { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const client = createClient(serviceEndpoint, credential); - - const content: DeidentificationContent = { - inputText: "Hello John!", - }; - - const response = await client.path("/deid").post({ body: content }); - - if (isUnexpected(response)) { - throw response.body.error; - } - - console.log(response.body.outputText); // Hello, Tom! -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/listCompletedFiles.ts b/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/listCompletedFiles.ts deleted file mode 100644 index 01e35025cffe..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/listCompletedFiles.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to list files that were completed by a job. - */ - -import createClient, { - DeidentificationJob, - isUnexpected, - paginate, -} from "@azure-rest/health-deidentification"; -import { DefaultAzureCredential } from "@azure/identity"; -import * as dotenv from "dotenv"; -dotenv.config(); - -export async function main(): Promise { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const storageLocation = `https://${process.env["STORAGE_ACCOUNT_NAME"]}.blob.core.windows.net/${process.env["STORAGE_CONTAINER_NAME"]}`; - const location = storageLocation || "defaultSasUri"; - const OUTPUT_FOLDER = "_output"; - const inputPrefix = "example_patient_1"; - const client = createClient(serviceEndpoint, credential); - const jobName = "exampleJob"; - - const job: DeidentificationJob = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { location, prefix: inputPrefix }, - targetLocation: { location, prefix: OUTPUT_FOLDER }, - }; - - await client.path("/jobs/{name}", jobName).put({ body: job }); - - const response = await client.path("/jobs/{name}/documents", jobName).get(); - - if (isUnexpected(response)) { - throw response.body.error; - } - - const items = []; - const iter = paginate(client, response); - - for await (const item of iter) { - items.push(item); - } - - console.log(items); // items will contain all the completed files -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/listJobs.ts b/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/listJobs.ts deleted file mode 100644 index 99301ef9eac5..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples-dev/listJobs.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to list jobs and iterate over them in a for loop. - */ - -import createClient, { isUnexpected, paginate } from "@azure-rest/health-deidentification"; -import { DefaultAzureCredential } from "@azure/identity"; -import * as dotenv from "dotenv"; -dotenv.config(); - -export async function main(): Promise { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const client = createClient(serviceEndpoint, credential); - - const response = await client.path("/jobs").get(); - - if (isUnexpected(response)) { - throw response.body.error; - } - - const items = []; - const iter = paginate(client, response); - for await (const item of iter) { - items.push(item); - } - - console.log(items); // items will contain all the jobs -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/README.md b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/README.md deleted file mode 100644 index c9fb5f4396ff..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# Health Deidentification Service client library samples for JavaScript (Beta) - -These sample programs show how to use the JavaScript client libraries for Health Deidentification Service in some common scenarios. - -| **File Name** | **Description** | -| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| [createJob.js][createjob] | This sample demonstrates how to create a job which will deidentify all files within a blob storage container filtering via a prefix. | -| [helloWorld.js][helloworld] | This sample demonstrates how to create a `DeidentificationClient` and then deidentify a `string` | -| [listCompletedFiles.js][listcompletedfiles] | This sample demonstrates how to list files that were completed by a job. | -| [listJobs.js][listjobs] | This sample demonstrates how to list jobs and iterate over them in a for loop. | - -## Prerequisites - -The sample programs are compatible with [LTS versions of Node.js](https://github.com/nodejs/release#release-schedule). - -You need [an Azure subscription][freesub] and the following Azure resources to run these sample programs: - -- [De-identification Service][createinstance_de-identificationservice] - -Samples retrieve credentials to access the service endpoint from environment variables. Alternatively, edit the source code to include the appropriate credentials. See each individual sample for details on which environment variables/credentials it requires to function. - -Adapting the samples to run in the browser may require some additional consideration. For details, please see the [package README][package]. - -## Setup - -To run the samples using the published version of the package: - -1. Install the dependencies using `npm`: - -```bash -npm install -``` - -2. Edit the file `sample.env`, adding the correct credentials to access the Azure service and run the samples. Then rename the file from `sample.env` to just `.env`. The sample programs will read this file automatically. - -3. Run whichever samples you like (note that some samples may require additional setup, see the table above): - -```bash -node createJob.js -``` - -Alternatively, run a single sample with the correct environment variables set (setting up the `.env` file is not required if you do this), for example (cross-platform): - -```bash -npx dev-tool run vendored cross-env DEID_SERVICE_ENDPOINT="" STORAGE_ACCOUNT_NAME="" STORAGE_CONTAINER_NAME="" node createJob.js -``` - -## Next Steps - -Take a look at our [API Documentation][apiref] for more information about the APIs that are available in the clients. - -[createjob]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/createJob.js -[helloworld]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/helloWorld.js -[listcompletedfiles]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/listCompletedFiles.js -[listjobs]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/listJobs.js -[apiref]: https://docs.microsoft.com/javascript/api/ -[freesub]: https://azure.microsoft.com/free/ -[createinstance_de-identificationservice]: https://docs.microsoft.com/javascript/api/ -[package]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/healthdataaiservices/azure-health-deidentification/README.md diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/createJob.js b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/createJob.js deleted file mode 100644 index cfc1a10ae227..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/createJob.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to create a job which will deidentify all files within a blob storage container filtering via a prefix. - */ - -const createClient = require("@azure-rest/health-deidentification").default, - { isUnexpected } = require("@azure-rest/health-deidentification"); -const { DefaultAzureCredential } = require("@azure/identity"); -require("dotenv").config(); - -async function main() { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const storageLocation = `https://${process.env["STORAGE_ACCOUNT_NAME"]}.blob.core.windows.net/${process.env["STORAGE_CONTAINER_NAME"]}`; - const location = storageLocation || "defaultSasUri"; - const OUTPUT_FOLDER = "_output"; - const inputPrefix = "example_patient_1"; - const client = createClient(serviceEndpoint, credential); - const jobName = "exampleJob"; - - const job = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { location, prefix: inputPrefix }, - targetLocation: { location, prefix: OUTPUT_FOLDER }, - }; - const response = await client.path("/jobs/{name}", jobName).put({ body: job }); - - if (isUnexpected(response)) { - throw response.body.error; - } - - console.log(response.body); -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); - -module.exports = { main }; diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/helloWorld.js b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/helloWorld.js deleted file mode 100644 index cd01a19b6e1c..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/helloWorld.js +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to create a `DeidentificationClient` and then deidentify a `string` - */ - -const createClient = require("@azure-rest/health-deidentification").default, - { isUnexpected } = require("@azure-rest/health-deidentification"); -const { DefaultAzureCredential } = require("@azure/identity"); -require("dotenv").config(); - -async function main() { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const client = createClient(serviceEndpoint, credential); - - const content = { - inputText: "Hello John!", - }; - - const response = await client.path("/deid").post({ body: content }); - - if (isUnexpected(response)) { - throw response.body.error; - } - - console.log(response.body.outputText); // Hello, Tom! -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); - -module.exports = { main }; diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/listCompletedFiles.js b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/listCompletedFiles.js deleted file mode 100644 index d44825fc5533..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/listCompletedFiles.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to list files that were completed by a job. - */ - -const createClient = require("@azure-rest/health-deidentification").default, - { isUnexpected, paginate } = require("@azure-rest/health-deidentification"); -const { DefaultAzureCredential } = require("@azure/identity"); -require("dotenv").config(); - -async function main() { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const storageLocation = `https://${process.env["STORAGE_ACCOUNT_NAME"]}.blob.core.windows.net/${process.env["STORAGE_CONTAINER_NAME"]}`; - const location = storageLocation || "defaultSasUri"; - const OUTPUT_FOLDER = "_output"; - const inputPrefix = "example_patient_1"; - const client = createClient(serviceEndpoint, credential); - const jobName = "exampleJob"; - - const job = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { location, prefix: inputPrefix }, - targetLocation: { location, prefix: OUTPUT_FOLDER }, - }; - - await client.path("/jobs/{name}", jobName).put({ body: job }); - - const response = await client.path("/jobs/{name}/documents", jobName).get(); - - if (isUnexpected(response)) { - throw response.body.error; - } - - const items = []; - const iter = paginate(client, response); - - for await (const item of iter) { - items.push(item); - } - - console.log(items); // items will contain all the completed files -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); - -module.exports = { main }; diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/listJobs.js b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/listJobs.js deleted file mode 100644 index aa5d0903082f..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/listJobs.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to list jobs and iterate over them in a for loop. - */ - -const createClient = require("@azure-rest/health-deidentification").default, - { isUnexpected, paginate } = require("@azure-rest/health-deidentification"); -const { DefaultAzureCredential } = require("@azure/identity"); -require("dotenv").config(); - -async function main() { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const client = createClient(serviceEndpoint, credential); - - const response = await client.path("/jobs").get(); - - if (isUnexpected(response)) { - throw response.body.error; - } - - const items = []; - const iter = paginate(client, response); - for await (const item of iter) { - items.push(item); - } - - console.log(items); // items will contain all the jobs -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); - -module.exports = { main }; diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/package.json b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/package.json deleted file mode 100644 index 2e6d1369680e..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "@azure-samples/health-deidentification-js-beta", - "private": true, - "version": "1.0.0", - "description": "Health Deidentification Service client library samples for JavaScript (Beta)", - "engines": { - "node": ">=18.0.0" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/Azure/azure-sdk-for-js.git", - "directory": "sdk/healthdataaiservices/azure-health-deidentification" - }, - "keywords": [ - "node", - "azure", - "cloud", - "typescript", - "browser", - "isomorphic" - ], - "author": "Microsoft Corporation", - "license": "MIT", - "bugs": { - "url": "https://github.com/Azure/azure-sdk-for-js/issues" - }, - "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/healthdataaiservices/azure-health-deidentification", - "dependencies": { - "@azure-rest/health-deidentification": "next", - "dotenv": "latest", - "@azure/identity": "~4.3.0-beta.1" - } -} diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/sample.env b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/sample.env deleted file mode 100644 index 2ff41595523b..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/javascript/sample.env +++ /dev/null @@ -1,5 +0,0 @@ -# Your De-identification Service URL can be found in the overview section of the Azure Portal. -DEID_SERVICE_ENDPOINT= -# Storage account and container name -STORAGE_ACCOUNT_NAME= -STORAGE_CONTAINER_NAME= diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/README.md b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/README.md deleted file mode 100644 index 6e0f5d676b73..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# Health Deidentification Service client library samples for TypeScript (Beta) - -These sample programs show how to use the TypeScript client libraries for Health Deidentification Service in some common scenarios. - -| **File Name** | **Description** | -| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| [createJob.ts][createjob] | This sample demonstrates how to create a job which will deidentify all files within a blob storage container filtering via a prefix. | -| [helloWorld.ts][helloworld] | This sample demonstrates how to create a `DeidentificationClient` and then deidentify a `string` | -| [listCompletedFiles.ts][listcompletedfiles] | This sample demonstrates how to list files that were completed by a job. | -| [listJobs.ts][listjobs] | This sample demonstrates how to list jobs and iterate over them in a for loop. | - -## Prerequisites - -The sample programs are compatible with [LTS versions of Node.js](https://github.com/nodejs/release#release-schedule). - -Before running the samples in Node, they must be compiled to JavaScript using the TypeScript compiler. For more information on TypeScript, see the [TypeScript documentation][typescript]. Install the TypeScript compiler using: - -```bash -npm install -g typescript -``` - -You need [an Azure subscription][freesub] and the following Azure resources to run these sample programs: - -- [De-identification Service][createinstance_de-identificationservice] - -Samples retrieve credentials to access the service endpoint from environment variables. Alternatively, edit the source code to include the appropriate credentials. See each individual sample for details on which environment variables/credentials it requires to function. - -Adapting the samples to run in the browser may require some additional consideration. For details, please see the [package README][package]. - -## Setup - -To run the samples using the published version of the package: - -1. Install the dependencies using `npm`: - -```bash -npm install -``` - -2. Compile the samples: - -```bash -npm run build -``` - -3. Edit the file `sample.env`, adding the correct credentials to access the Azure service and run the samples. Then rename the file from `sample.env` to just `.env`. The sample programs will read this file automatically. - -4. Run whichever samples you like (note that some samples may require additional setup, see the table above): - -```bash -node dist/createJob.js -``` - -Alternatively, run a single sample with the correct environment variables set (setting up the `.env` file is not required if you do this), for example (cross-platform): - -```bash -npx dev-tool run vendored cross-env DEID_SERVICE_ENDPOINT="" STORAGE_ACCOUNT_NAME="" STORAGE_CONTAINER_NAME="" node dist/createJob.js -``` - -## Next Steps - -Take a look at our [API Documentation][apiref] for more information about the APIs that are available in the clients. - -[createjob]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/createJob.ts -[helloworld]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/helloWorld.ts -[listcompletedfiles]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/listCompletedFiles.ts -[listjobs]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/listJobs.ts -[apiref]: https://docs.microsoft.com/javascript/api/ -[freesub]: https://azure.microsoft.com/free/ -[createinstance_de-identificationservice]: https://docs.microsoft.com/javascript/api/ -[package]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/healthdataaiservices/azure-health-deidentification/README.md -[typescript]: https://www.typescriptlang.org/docs/home.html diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/package.json b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/package.json deleted file mode 100644 index cf24dbdfb56c..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "@azure-samples/health-deidentification-ts-beta", - "private": true, - "version": "1.0.0", - "description": "Health Deidentification Service client library samples for TypeScript (Beta)", - "engines": { - "node": ">=18.0.0" - }, - "scripts": { - "build": "tsc", - "prebuild": "rimraf dist/" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/Azure/azure-sdk-for-js.git", - "directory": "sdk/healthdataaiservices/azure-health-deidentification" - }, - "keywords": [ - "node", - "azure", - "cloud", - "typescript", - "browser", - "isomorphic" - ], - "author": "Microsoft Corporation", - "license": "MIT", - "bugs": { - "url": "https://github.com/Azure/azure-sdk-for-js/issues" - }, - "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/healthdataaiservices/azure-health-deidentification", - "dependencies": { - "@azure-rest/health-deidentification": "next", - "dotenv": "latest", - "@azure/identity": "~4.3.0-beta.1" - }, - "devDependencies": { - "@types/node": "^18.0.0", - "typescript": "~5.6.2", - "rimraf": "latest" - } -} diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/sample.env b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/sample.env deleted file mode 100644 index 2ff41595523b..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/sample.env +++ /dev/null @@ -1,5 +0,0 @@ -# Your De-identification Service URL can be found in the overview section of the Azure Portal. -DEID_SERVICE_ENDPOINT= -# Storage account and container name -STORAGE_ACCOUNT_NAME= -STORAGE_CONTAINER_NAME= diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/createJob.ts b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/createJob.ts deleted file mode 100644 index 44b6b71301ad..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/createJob.ts +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to create a job which will deidentify all files within a blob storage container filtering via a prefix. - */ - -import createClient, { - DeidentificationJob, - isUnexpected, -} from "@azure-rest/health-deidentification"; -import { DefaultAzureCredential } from "@azure/identity"; -import * as dotenv from "dotenv"; -dotenv.config(); - -export async function main(): Promise { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const storageLocation = `https://${process.env["STORAGE_ACCOUNT_NAME"]}.blob.core.windows.net/${process.env["STORAGE_CONTAINER_NAME"]}`; - const location = storageLocation || "defaultSasUri"; - const OUTPUT_FOLDER = "_output"; - const inputPrefix = "example_patient_1"; - const client = createClient(serviceEndpoint, credential); - const jobName = "exampleJob"; - - const job: DeidentificationJob = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { location, prefix: inputPrefix }, - targetLocation: { location, prefix: OUTPUT_FOLDER }, - }; - const response = await client.path("/jobs/{name}", jobName).put({ body: job }); - - if (isUnexpected(response)) { - throw response.body.error; - } - - console.log(response.body); -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/helloWorld.ts b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/helloWorld.ts deleted file mode 100644 index c96423ff88e9..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/helloWorld.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to create a `DeidentificationClient` and then deidentify a `string` - */ - -import createClient, { - DeidentificationContent, - isUnexpected, -} from "@azure-rest/health-deidentification"; -import { DefaultAzureCredential } from "@azure/identity"; -import * as dotenv from "dotenv"; -dotenv.config(); - -export async function main(): Promise { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const client = createClient(serviceEndpoint, credential); - - const content: DeidentificationContent = { - inputText: "Hello John!", - }; - - const response = await client.path("/deid").post({ body: content }); - - if (isUnexpected(response)) { - throw response.body.error; - } - - console.log(response.body.outputText); // Hello, Tom! -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/listCompletedFiles.ts b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/listCompletedFiles.ts deleted file mode 100644 index 01e35025cffe..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/listCompletedFiles.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to list files that were completed by a job. - */ - -import createClient, { - DeidentificationJob, - isUnexpected, - paginate, -} from "@azure-rest/health-deidentification"; -import { DefaultAzureCredential } from "@azure/identity"; -import * as dotenv from "dotenv"; -dotenv.config(); - -export async function main(): Promise { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const storageLocation = `https://${process.env["STORAGE_ACCOUNT_NAME"]}.blob.core.windows.net/${process.env["STORAGE_CONTAINER_NAME"]}`; - const location = storageLocation || "defaultSasUri"; - const OUTPUT_FOLDER = "_output"; - const inputPrefix = "example_patient_1"; - const client = createClient(serviceEndpoint, credential); - const jobName = "exampleJob"; - - const job: DeidentificationJob = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { location, prefix: inputPrefix }, - targetLocation: { location, prefix: OUTPUT_FOLDER }, - }; - - await client.path("/jobs/{name}", jobName).put({ body: job }); - - const response = await client.path("/jobs/{name}/documents", jobName).get(); - - if (isUnexpected(response)) { - throw response.body.error; - } - - const items = []; - const iter = paginate(client, response); - - for await (const item of iter) { - items.push(item); - } - - console.log(items); // items will contain all the completed files -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/listJobs.ts b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/listJobs.ts deleted file mode 100644 index 99301ef9eac5..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/src/listJobs.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** - * @summary This sample demonstrates how to list jobs and iterate over them in a for loop. - */ - -import createClient, { isUnexpected, paginate } from "@azure-rest/health-deidentification"; -import { DefaultAzureCredential } from "@azure/identity"; -import * as dotenv from "dotenv"; -dotenv.config(); - -export async function main(): Promise { - const credential = new DefaultAzureCredential(); - const serviceEndpoint = - process.env["DEID_SERVICE_ENDPOINT"] || "https://example.api.cac001.deid.azure.com"; - const client = createClient(serviceEndpoint, credential); - - const response = await client.path("/jobs").get(); - - if (isUnexpected(response)) { - throw response.body.error; - } - - const items = []; - const iter = paginate(client, response); - for await (const item of iter) { - items.push(item); - } - - console.log(items); // items will contain all the jobs -} - -main().catch((err) => { - console.error("The sample encountered an error:", err); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/tsconfig.json b/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/tsconfig.json deleted file mode 100644 index 984eed535aa8..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/samples/v1-beta/typescript/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "commonjs", - "moduleResolution": "node", - "resolveJsonModule": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "alwaysStrict": true, - "outDir": "dist", - "rootDir": "src" - }, - "include": [ - "src/**/*.ts" - ] -} diff --git a/sdk/healthdataaiservices/azure-health-deidentification/src/clientDefinitions.ts b/sdk/healthdataaiservices/azure-health-deidentification/src/clientDefinitions.ts index c153bb2c1725..b549a35bfec3 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/src/clientDefinitions.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/src/clientDefinitions.ts @@ -1,21 +1,21 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { +import { GetJobParameters, - CreateJobParameters, + DeidentifyDocumentsParameters, DeleteJobParameters, ListJobsParameters, ListJobDocumentsParameters, CancelJobParameters, - DeidentifyParameters, + DeidentifyTextParameters, } from "./parameters.js"; -import type { +import { GetJob200Response, GetJobDefaultResponse, - CreateJob200Response, - CreateJob201Response, - CreateJobDefaultResponse, + DeidentifyDocuments200Response, + DeidentifyDocuments201Response, + DeidentifyDocumentsDefaultResponse, DeleteJob204Response, DeleteJobDefaultResponse, ListJobs200Response, @@ -24,18 +24,24 @@ import type { ListJobDocumentsDefaultResponse, CancelJob200Response, CancelJobDefaultResponse, - Deidentify200Response, - DeidentifyDefaultResponse, + DeidentifyText200Response, + DeidentifyTextDefaultResponse, } from "./responses.js"; -import type { Client, StreamableMethod } from "@azure-rest/core-client"; +import { Client, StreamableMethod } from "@azure-rest/core-client"; export interface GetJob { /** Resource read operation template. */ - get(options?: GetJobParameters): StreamableMethod; + get( + options?: GetJobParameters, + ): StreamableMethod; /** Long-running resource create or replace operation template. */ put( - options: CreateJobParameters, - ): StreamableMethod; + options: DeidentifyDocumentsParameters, + ): StreamableMethod< + | DeidentifyDocuments200Response + | DeidentifyDocuments201Response + | DeidentifyDocumentsDefaultResponse + >; /** Removes the record of the job from the service. Does not delete any documents. */ delete( options?: DeleteJobParameters, @@ -53,7 +59,9 @@ export interface ListJobDocuments { /** Resource list operation template. */ get( options?: ListJobDocumentsParameters, - ): StreamableMethod; + ): StreamableMethod< + ListJobDocuments200Response | ListJobDocumentsDefaultResponse + >; } export interface CancelJob { @@ -69,11 +77,13 @@ export interface CancelJob { ): StreamableMethod; } -export interface Deidentify { +export interface DeidentifyText { /** A remote procedure call (RPC) operation. */ post( - options: DeidentifyParameters, - ): StreamableMethod; + options: DeidentifyTextParameters, + ): StreamableMethod< + DeidentifyText200Response | DeidentifyTextDefaultResponse + >; } export interface Routes { @@ -86,7 +96,7 @@ export interface Routes { /** Resource for '/jobs/\{name\}:cancel' has methods for the following verbs: post */ (path: "/jobs/{name}:cancel", name: string): CancelJob; /** Resource for '/deid' has methods for the following verbs: post */ - (path: "/deid"): Deidentify; + (path: "/deid"): DeidentifyText; } export type DeidentificationClient = Client & { diff --git a/sdk/healthdataaiservices/azure-health-deidentification/src/deidentificationClient.ts b/sdk/healthdataaiservices/azure-health-deidentification/src/deidentificationClient.ts index b07991a8ff93..53ff9544f8c0 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/src/deidentificationClient.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/src/deidentificationClient.ts @@ -1,11 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { ClientOptions } from "@azure-rest/core-client"; -import { getClient } from "@azure-rest/core-client"; +import { getClient, ClientOptions } from "@azure-rest/core-client"; import { logger } from "./logger.js"; -import type { TokenCredential } from "@azure/core-auth"; -import type { DeidentificationClient } from "./clientDefinitions.js"; +import { TokenCredential } from "@azure/core-auth"; +import { DeidentificationClient } from "./clientDefinitions.js"; /** The optional parameters for the client */ export interface DeidentificationClientOptions extends ClientOptions { @@ -22,9 +21,9 @@ export interface DeidentificationClientOptions extends ClientOptions { export default function createClient( endpointParam: string, credentials: TokenCredential, - { apiVersion = "2024-07-12-preview", ...options }: DeidentificationClientOptions = {}, + { apiVersion = "2024-11-15", ...options }: DeidentificationClientOptions = {}, ): DeidentificationClient { - const endpointUrl = options.endpoint ?? options.baseUrl ?? `https://${endpointParam}`; + const endpointUrl = options.endpoint ?? options.baseUrl ?? `${endpointParam}`; const userAgentInfo = `azsdk-js-health-deidentification-rest/1.0.0-beta.1`; const userAgentPrefix = options.userAgentOptions && options.userAgentOptions.userAgentPrefix @@ -39,10 +38,16 @@ export default function createClient( logger: options.loggingOptions?.logger ?? logger.info, }, credentials: { - scopes: options.credentials?.scopes ?? ["https://deid.azure.com/.default"], + scopes: options.credentials?.scopes ?? [ + "https://deid.azure.com/.default", + ], }, }; - const client = getClient(endpointUrl, credentials, options) as DeidentificationClient; + const client = getClient( + endpointUrl, + credentials, + options, + ) as DeidentificationClient; client.pipeline.removePolicy({ name: "ApiVersionPolicy" }); client.pipeline.addPolicy({ @@ -60,5 +65,6 @@ export default function createClient( return next(req); }, }); + return client; } diff --git a/sdk/healthdataaiservices/azure-health-deidentification/src/isUnexpected.ts b/sdk/healthdataaiservices/azure-health-deidentification/src/isUnexpected.ts index b99766aa2f8b..12835714f387 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/src/isUnexpected.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/src/isUnexpected.ts @@ -1,13 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { +import { GetJob200Response, GetJobDefaultResponse, - CreateJob200Response, - CreateJob201Response, - CreateJobLogicalResponse, - CreateJobDefaultResponse, + DeidentifyDocuments200Response, + DeidentifyDocuments201Response, + DeidentifyDocumentsLogicalResponse, + DeidentifyDocumentsDefaultResponse, DeleteJob204Response, DeleteJobDefaultResponse, ListJobs200Response, @@ -16,8 +16,8 @@ import type { ListJobDocumentsDefaultResponse, CancelJob200Response, CancelJobDefaultResponse, - Deidentify200Response, - DeidentifyDefaultResponse, + DeidentifyText200Response, + DeidentifyTextDefaultResponse, } from "./responses.js"; const responseMap: Record = { @@ -35,11 +35,11 @@ export function isUnexpected( ): response is GetJobDefaultResponse; export function isUnexpected( response: - | CreateJob200Response - | CreateJob201Response - | CreateJobLogicalResponse - | CreateJobDefaultResponse, -): response is CreateJobDefaultResponse; + | DeidentifyDocuments200Response + | DeidentifyDocuments201Response + | DeidentifyDocumentsLogicalResponse + | DeidentifyDocumentsDefaultResponse, +): response is DeidentifyDocumentsDefaultResponse; export function isUnexpected( response: DeleteJob204Response | DeleteJobDefaultResponse, ): response is DeleteJobDefaultResponse; @@ -53,16 +53,16 @@ export function isUnexpected( response: CancelJob200Response | CancelJobDefaultResponse, ): response is CancelJobDefaultResponse; export function isUnexpected( - response: Deidentify200Response | DeidentifyDefaultResponse, -): response is DeidentifyDefaultResponse; + response: DeidentifyText200Response | DeidentifyTextDefaultResponse, +): response is DeidentifyTextDefaultResponse; export function isUnexpected( response: | GetJob200Response | GetJobDefaultResponse - | CreateJob200Response - | CreateJob201Response - | CreateJobLogicalResponse - | CreateJobDefaultResponse + | DeidentifyDocuments200Response + | DeidentifyDocuments201Response + | DeidentifyDocumentsLogicalResponse + | DeidentifyDocumentsDefaultResponse | DeleteJob204Response | DeleteJobDefaultResponse | ListJobs200Response @@ -71,16 +71,16 @@ export function isUnexpected( | ListJobDocumentsDefaultResponse | CancelJob200Response | CancelJobDefaultResponse - | Deidentify200Response - | DeidentifyDefaultResponse, + | DeidentifyText200Response + | DeidentifyTextDefaultResponse, ): response is | GetJobDefaultResponse - | CreateJobDefaultResponse + | DeidentifyDocumentsDefaultResponse | DeleteJobDefaultResponse | ListJobsDefaultResponse | ListJobDocumentsDefaultResponse | CancelJobDefaultResponse - | DeidentifyDefaultResponse { + | DeidentifyTextDefaultResponse { const lroOriginal = response.headers["x-ms-original-url"]; const url = new URL(lroOriginal ?? response.request.url); const method = response.request.method; @@ -113,17 +113,24 @@ function getParametrizedPathSuccess(method: string, path: string): string[] { // track if we have found a match to return the values found. let found = true; - for (let i = candidateParts.length - 1, j = pathParts.length - 1; i >= 1 && j >= 1; i--, j--) { - if (candidateParts[i]?.startsWith("{") && candidateParts[i]?.indexOf("}") !== -1) { + for ( + let i = candidateParts.length - 1, j = pathParts.length - 1; + i >= 1 && j >= 1; + i--, j-- + ) { + if ( + candidateParts[i]?.startsWith("{") && + candidateParts[i]?.indexOf("}") !== -1 + ) { const start = candidateParts[i]!.indexOf("}") + 1, end = candidateParts[i]?.length; // If the current part of the candidate is a "template" part // Try to use the suffix of pattern to match the path // {guid} ==> $ // {guid}:export ==> :export$ - const isMatched = new RegExp(`${candidateParts[i]?.slice(start, end)}`).test( - pathParts[j] || "", - ); + const isMatched = new RegExp( + `${candidateParts[i]?.slice(start, end)}`, + ).test(pathParts[j] || ""); if (!isMatched) { found = false; diff --git a/sdk/healthdataaiservices/azure-health-deidentification/src/models.ts b/sdk/healthdataaiservices/azure-health-deidentification/src/models.ts index 14f321c93294..616dded323f6 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/src/models.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/src/models.ts @@ -3,24 +3,18 @@ /** A job containing a batch of documents to de-identify. */ export interface DeidentificationJob { - /** Storage location to perform the operation on. */ - sourceLocation: SourceStorageLocation; - /** Target location to store output of operation. */ - targetLocation: TargetStorageLocation; /** * Operation to perform on the input documents. * * Possible values: "Redact", "Surrogate", "Tag" */ - operation?: OperationType; - /** - * Data type of the input documents. - * - * Possible values: "Plaintext" - */ - dataType?: DocumentDataType; - /** Format of the redacted output. Only valid when Operation is Redact. */ - redactionFormat?: string; + operation?: DeidentificationOperationType; + /** Storage location to perform the operation on. */ + sourceLocation: SourceStorageLocation; + /** Target location to store output of operation. */ + targetLocation: TargetStorageLocation; + /** Customization parameters to override default service behaviors. */ + customizations?: DeidentificationJobCustomizationOptions; } /** Storage location. */ @@ -37,12 +31,34 @@ export interface SourceStorageLocation { export interface TargetStorageLocation { /** URL to storage location. */ location: string; - /** Prefix to filter path by. */ + /** + * Replaces the input prefix of a file path with the output prefix, preserving the rest of the path structure. + * + * Example: + * File full path: documents/user/note.txt + * Input Prefix: "documents/user/" + * Output Prefix: "output_docs/" + * + * Output file: "output_docs/note.txt" + */ prefix: string; + /** When set to true during a job, the service will overwrite the output location if it already exists. */ + overwrite?: boolean; +} + +/** Customizations options to override default service behaviors for job usage. */ +export interface DeidentificationJobCustomizationOptions { + /** + * Format of the redacted output. Only valid when Operation is Redact. + * Please refer to https://learn.microsoft.com/en-us/azure/healthcare-apis/deidentification/redaction-format for more details. + */ + redactionFormat?: string; + /** Locale in which the output surrogates are written. */ + surrogateLocale?: string; } /** Summary metrics of a job. */ -export interface JobSummary { +export interface DeidentificationJobSummary { /** Number of documents that have completed. */ successful: number; /** Number of documents that have failed. */ @@ -60,24 +76,27 @@ export interface DeidentificationContent { /** Input text to de-identify. */ inputText: string; /** - * Operation to perform on the input. + * Operation to perform on the input documents. * * Possible values: "Redact", "Surrogate", "Tag" */ - operation?: OperationType; + operation?: DeidentificationOperationType; + /** Customization parameters to override default service behaviors. */ + customizations?: DeidentificationCustomizationOptions; +} + +/** Customizations options to override default service behaviors for synchronous usage. */ +export interface DeidentificationCustomizationOptions { /** - * Data type of the input. - * - * Possible values: "Plaintext" + * Format of the redacted output. Only valid when Operation is Redact. + * Please refer to https://learn.microsoft.com/en-us/azure/healthcare-apis/deidentification/redaction-format for more details. */ - dataType?: DocumentDataType; - /** Format of the redacted output. Only valid when OperationType is "Redact". */ redactionFormat?: string; + /** Locale in which the output surrogates are written. */ + surrogateLocale?: string; } -/** Alias for OperationType */ -export type OperationType = string; -/** Alias for DocumentDataType */ -export type DocumentDataType = string; -/** Alias for JobStatus */ -export type JobStatus = string; +/** Alias for DeidentificationOperationType */ +export type DeidentificationOperationType = string; +/** Alias for OperationState */ +export type OperationState = string; diff --git a/sdk/healthdataaiservices/azure-health-deidentification/src/outputModels.ts b/sdk/healthdataaiservices/azure-health-deidentification/src/outputModels.ts index a336f45fe532..d092a1df4d4f 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/src/outputModels.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/src/outputModels.ts @@ -1,37 +1,30 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { Paged } from "@azure/core-paging"; -import type { ErrorModel } from "@azure-rest/core-client"; +import { ErrorModel } from "@azure-rest/core-client"; /** A job containing a batch of documents to de-identify. */ export interface DeidentificationJobOutput { /** The name of a job. */ readonly name: string; - /** Storage location to perform the operation on. */ - sourceLocation: SourceStorageLocationOutput; - /** Target location to store output of operation. */ - targetLocation: TargetStorageLocationOutput; /** * Operation to perform on the input documents. * * Possible values: "Redact", "Surrogate", "Tag" */ - operation?: OperationTypeOutput; - /** - * Data type of the input documents. - * - * Possible values: "Plaintext" - */ - dataType?: DocumentDataTypeOutput; - /** Format of the redacted output. Only valid when Operation is Redact. */ - redactionFormat?: string; + operation?: DeidentificationOperationTypeOutput; + /** Storage location to perform the operation on. */ + sourceLocation: SourceStorageLocationOutput; + /** Target location to store output of operation. */ + targetLocation: TargetStorageLocationOutput; + /** Customization parameters to override default service behaviors. */ + customizations?: DeidentificationJobCustomizationOptionsOutput; /** * Current status of a job. * - * Possible values: "NotStarted", "Running", "Succeeded", "PartialFailed", "Failed", "Canceled" + * Possible values: "NotStarted", "Running", "Succeeded", "Failed", "Canceled" */ - readonly status: JobStatusOutput; + readonly status: OperationStateOutput; /** Error when job fails in it's entirety. */ readonly error?: ErrorModel; /** @@ -47,7 +40,7 @@ export interface DeidentificationJobOutput { /** Date and time when the job was started. */ readonly startedAt?: string; /** Summary of a job. Exists only when the job is completed. */ - readonly summary?: JobSummaryOutput; + readonly summary?: DeidentificationJobSummaryOutput; } /** Storage location. */ @@ -64,12 +57,34 @@ export interface SourceStorageLocationOutput { export interface TargetStorageLocationOutput { /** URL to storage location. */ location: string; - /** Prefix to filter path by. */ + /** + * Replaces the input prefix of a file path with the output prefix, preserving the rest of the path structure. + * + * Example: + * File full path: documents/user/note.txt + * Input Prefix: "documents/user/" + * Output Prefix: "output_docs/" + * + * Output file: "output_docs/note.txt" + */ prefix: string; + /** When set to true during a job, the service will overwrite the output location if it already exists. */ + overwrite?: boolean; +} + +/** Customizations options to override default service behaviors for job usage. */ +export interface DeidentificationJobCustomizationOptionsOutput { + /** + * Format of the redacted output. Only valid when Operation is Redact. + * Please refer to https://learn.microsoft.com/en-us/azure/healthcare-apis/deidentification/redaction-format for more details. + */ + redactionFormat?: string; + /** Locale in which the output surrogates are written. */ + surrogateLocale?: string; } /** Summary metrics of a job. */ -export interface JobSummaryOutput { +export interface DeidentificationJobSummaryOutput { /** Number of documents that have completed. */ successful: number; /** Number of documents that have failed. */ @@ -82,14 +97,30 @@ export interface JobSummaryOutput { bytesProcessed: number; } +/** Paged collection of DeidentificationJob items */ +export interface PagedDeidentificationJobOutput { + /** The DeidentificationJob items on this page */ + value: Array; + /** The link to the next page of items */ + nextLink?: string; +} + +/** Paged collection of DeidentificationDocumentDetails items */ +export interface PagedDeidentificationDocumentDetailsOutput { + /** The DeidentificationDocumentDetails items on this page */ + value: Array; + /** The link to the next page of items */ + nextLink?: string; +} + /** Details of a single document in a job. */ -export interface DocumentDetailsOutput { +export interface DeidentificationDocumentDetailsOutput { /** Id of the document details. */ readonly id: string; /** Location for the input. */ - input: DocumentLocationOutput; + input: DeidentificationDocumentLocationOutput; /** Location for the output. */ - output?: DocumentLocationOutput; + output?: DeidentificationDocumentLocationOutput; /** * Status of the document. * @@ -101,9 +132,9 @@ export interface DocumentDetailsOutput { } /** Location of a document. */ -export interface DocumentLocationOutput { - /** Path of document in storage. */ - path: string; +export interface DeidentificationDocumentLocationOutput { + /** Location of document in storage. */ + location: string; /** The entity tag for this resource. */ readonly etag: string; } @@ -120,10 +151,6 @@ export interface DeidentificationResultOutput { export interface PhiTaggerResultOutput { /** List of entities detected in the input. */ entities: Array; - /** Path to the document in storage. */ - path?: string; - /** The entity tag for this resource. */ - etag?: string; } /** PHI Entity tag in the input. */ @@ -162,16 +189,8 @@ export interface StringIndexOutput { codePoint: number; } -/** Alias for OperationTypeOutput */ -export type OperationTypeOutput = string; -/** Alias for DocumentDataTypeOutput */ -export type DocumentDataTypeOutput = string; -/** Alias for JobStatusOutput */ -export type JobStatusOutput = string; -/** Paged collection of DeidentificationJob items */ -export type PagedDeidentificationJobOutput = Paged; -/** Paged collection of DocumentDetails items */ -export type PagedDocumentDetailsOutput = Paged; +/** Alias for DeidentificationOperationTypeOutput */ +export type DeidentificationOperationTypeOutput = string; /** Alias for OperationStateOutput */ export type OperationStateOutput = string; /** Alias for PhiCategoryOutput */ diff --git a/sdk/healthdataaiservices/azure-health-deidentification/src/paginateHelper.ts b/sdk/healthdataaiservices/azure-health-deidentification/src/paginateHelper.ts index 5d541b4e406d..5ef95e5ea0a3 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/src/paginateHelper.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/src/paginateHelper.ts @@ -1,10 +1,162 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { PagedAsyncIterableIterator, PagedResult } from "@azure/core-paging"; -import { getPagedAsyncIterator } from "@azure/core-paging"; -import type { Client, PathUncheckedResponse } from "@azure-rest/core-client"; -import { createRestError } from "@azure-rest/core-client"; +import { + Client, + createRestError, + PathUncheckedResponse, +} from "@azure-rest/core-client"; + +/** + * returns an async iterator that iterates over results. It also has a `byPage` + * method that returns pages of items at once. + * + * @param pagedResult - an object that specifies how to get pages. + * @returns a paged async iterator that iterates over results. + */ +function getPagedAsyncIterator< + TElement, + TPage = TElement[], + TPageSettings = PageSettings, + TLink = string, +>( + pagedResult: PagedResult, +): PagedAsyncIterableIterator { + const iter = getItemAsyncIterator( + pagedResult, + ); + return { + next() { + return iter.next(); + }, + [Symbol.asyncIterator]() { + return this; + }, + byPage: + pagedResult?.byPage ?? + (((settings?: PageSettings) => { + const { continuationToken } = settings ?? {}; + return getPageAsyncIterator(pagedResult, { + pageLink: continuationToken as unknown as TLink | undefined, + }); + }) as unknown as ( + settings?: TPageSettings, + ) => AsyncIterableIterator), + }; +} + +async function* getItemAsyncIterator( + pagedResult: PagedResult, +): AsyncIterableIterator { + const pages = getPageAsyncIterator(pagedResult); + const firstVal = await pages.next(); + // if the result does not have an array shape, i.e. TPage = TElement, then we return it as is + if (!Array.isArray(firstVal.value)) { + // can extract elements from this page + const { toElements } = pagedResult; + if (toElements) { + yield* toElements(firstVal.value) as TElement[]; + for await (const page of pages) { + yield* toElements(page) as TElement[]; + } + } else { + yield firstVal.value; + // `pages` is of type `AsyncIterableIterator` but TPage = TElement in this case + yield* pages as unknown as AsyncIterableIterator; + } + } else { + yield* firstVal.value; + for await (const page of pages) { + // pages is of type `AsyncIterableIterator` so `page` is of type `TPage`. In this branch, + // it must be the case that `TPage = TElement[]` + yield* page as unknown as TElement[]; + } + } +} + +async function* getPageAsyncIterator( + pagedResult: PagedResult, + options: { + pageLink?: TLink; + } = {}, +): AsyncIterableIterator { + const { pageLink } = options; + let response = await pagedResult.getPage( + pageLink ?? pagedResult.firstPageLink, + ); + if (!response) { + return; + } + yield response.page; + while (response.nextPageLink) { + response = await pagedResult.getPage(response.nextPageLink); + if (!response) { + return; + } + yield response.page; + } +} + +/** + * An interface that tracks the settings for paged iteration + */ +export interface PageSettings { + /** + * The token that keeps track of where to continue the iterator + */ + continuationToken?: string; +} + +/** + * An interface that allows async iterable iteration both to completion and by page. + */ +export interface PagedAsyncIterableIterator< + TElement, + TPage = TElement[], + TPageSettings = PageSettings, +> { + /** + * The next method, part of the iteration protocol + */ + next(): Promise>; + /** + * The connection to the async iterator, part of the iteration protocol + */ + [Symbol.asyncIterator](): PagedAsyncIterableIterator< + TElement, + TPage, + TPageSettings + >; + /** + * Return an AsyncIterableIterator that works a page at a time + */ + byPage: (settings?: TPageSettings) => AsyncIterableIterator; +} + +/** + * An interface that describes how to communicate with the service. + */ +interface PagedResult { + /** + * Link to the first page of results. + */ + firstPageLink: TLink; + /** + * A method that returns a page of results. + */ + getPage: ( + pageLink: TLink, + ) => Promise<{ page: TPage; nextPageLink?: TLink } | undefined>; + /** + * a function to implement the `byPage` method on the paged async iterator. + */ + byPage?: (settings?: TPageSettings) => AsyncIterableIterator; + + /** + * A function to extract elements from a page. + */ + toElements?: (page: TPage) => unknown[]; +} /** * Helper type to extract the type of an array @@ -14,10 +166,7 @@ export type GetArrayType = T extends Array ? TData : never; /** * The type of a custom function that defines how to get a page and a link to the next one if any. */ -export type GetPage = ( - pageLink: string, - maxPageSize?: number, -) => Promise<{ +export type GetPage = (pageLink: string) => Promise<{ page: TPage; nextPageLink?: string; }>; @@ -69,7 +218,9 @@ export function paginate( typeof customGetPage === "function" ? customGetPage : async (pageLink: string) => { - const result = firstRun ? initialResponse : await client.pathUnchecked(pageLink).get(); + const result = firstRun + ? initialResponse + : await client.pathUnchecked(pageLink).get(); firstRun = false; checkPagingRequest(result); const nextLink = getNextLink(result.body, nextLinkName); @@ -95,7 +246,9 @@ function getNextLink(body: unknown, nextLinkName?: string): string | undefined { const nextLink = (body as Record)[nextLinkName]; if (typeof nextLink !== "string" && typeof nextLink !== "undefined") { - throw new Error(`Body Property ${nextLinkName} should be a string or undefined`); + throw new Error( + `Body Property ${nextLinkName} should be a string or undefined`, + ); } return nextLink; @@ -123,7 +276,18 @@ function getElements(body: unknown, itemName: string): T[] { * Checks if a request failed */ function checkPagingRequest(response: PathUncheckedResponse): void { - const Http2xxStatusCodes = ["200", "201", "202", "203", "204", "205", "206", "207", "208", "226"]; + const Http2xxStatusCodes = [ + "200", + "201", + "202", + "203", + "204", + "205", + "206", + "207", + "208", + "226", + ]; if (!Http2xxStatusCodes.includes(response.status)) { throw createRestError( `Pagination failed with unexpected statusCode ${response.status}`, diff --git a/sdk/healthdataaiservices/azure-health-deidentification/src/parameters.ts b/sdk/healthdataaiservices/azure-health-deidentification/src/parameters.ts index 22d840140ea7..60265ca9b199 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/src/parameters.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/src/parameters.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { RawHttpHeadersInput } from "@azure/core-rest-pipeline"; -import type { RequestParameters } from "@azure-rest/core-client"; -import type { DeidentificationJob, DeidentificationContent } from "./models.js"; +import { RawHttpHeadersInput } from "@azure/core-rest-pipeline"; +import { RequestParameters } from "@azure-rest/core-client"; +import { DeidentificationJob, DeidentificationContent } from "./models.js"; export interface GetJobHeaders { /** An opaque, globally-unique, client-generated string identifier for the request. */ @@ -16,21 +16,23 @@ export interface GetJobHeaderParam { export type GetJobParameters = GetJobHeaderParam & RequestParameters; -export interface CreateJobHeaders { +export interface DeidentifyDocumentsHeaders { /** An opaque, globally-unique, client-generated string identifier for the request. */ "x-ms-client-request-id"?: string; } -export interface CreateJobBodyParam { +export interface DeidentifyDocumentsBodyParam { /** The resource instance. */ body: DeidentificationJob; } -export interface CreateJobHeaderParam { - headers?: RawHttpHeadersInput & CreateJobHeaders; +export interface DeidentifyDocumentsHeaderParam { + headers?: RawHttpHeadersInput & DeidentifyDocumentsHeaders; } -export type CreateJobParameters = CreateJobHeaderParam & CreateJobBodyParam & RequestParameters; +export type DeidentifyDocumentsParameters = DeidentifyDocumentsHeaderParam & + DeidentifyDocumentsBodyParam & + RequestParameters; export interface ListJobsHeaders { /** An opaque, globally-unique, client-generated string identifier for the request. */ @@ -52,7 +54,9 @@ export interface ListJobsHeaderParam { headers?: RawHttpHeadersInput & ListJobsHeaders; } -export type ListJobsParameters = ListJobsQueryParam & ListJobsHeaderParam & RequestParameters; +export type ListJobsParameters = ListJobsQueryParam & + ListJobsHeaderParam & + RequestParameters; export interface ListJobDocumentsHeaders { /** An opaque, globally-unique, client-generated string identifier for the request. */ @@ -100,9 +104,20 @@ export interface DeleteJobHeaderParam { export type DeleteJobParameters = DeleteJobHeaderParam & RequestParameters; -export interface DeidentifyBodyParam { +export interface DeidentifyTextHeaders { + /** An opaque, globally-unique, client-generated string identifier for the request. */ + "x-ms-client-request-id"?: string; +} + +export interface DeidentifyTextBodyParam { /** Request body for de-identification operation. */ body: DeidentificationContent; } -export type DeidentifyParameters = DeidentifyBodyParam & RequestParameters; +export interface DeidentifyTextHeaderParam { + headers?: RawHttpHeadersInput & DeidentifyTextHeaders; +} + +export type DeidentifyTextParameters = DeidentifyTextHeaderParam & + DeidentifyTextBodyParam & + RequestParameters; diff --git a/sdk/healthdataaiservices/azure-health-deidentification/src/pollingHelper.ts b/sdk/healthdataaiservices/azure-health-deidentification/src/pollingHelper.ts index 5abda1a6550f..48668851dcac 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/src/pollingHelper.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/src/pollingHelper.ts @@ -1,27 +1,30 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { Client, HttpResponse } from "@azure-rest/core-client"; -import type { AbortSignalLike } from "@azure/abort-controller"; -import type { +import { Client, HttpResponse } from "@azure-rest/core-client"; +import { AbortSignalLike } from "@azure/abort-controller"; +import { CancelOnProgress, CreateHttpPollerOptions, RunningOperation, OperationResponse, OperationState, + createHttpPoller, } from "@azure/core-lro"; -import { createHttpPoller } from "@azure/core-lro"; -import type { - CreateJob200Response, - CreateJob201Response, - CreateJobDefaultResponse, - CreateJobLogicalResponse, +import { + DeidentifyDocuments200Response, + DeidentifyDocuments201Response, + DeidentifyDocumentsDefaultResponse, + DeidentifyDocumentsLogicalResponse, } from "./responses.js"; /** * A simple poller that can be used to poll a long running operation. */ -export interface SimplePollerLike, TResult> { +export interface SimplePollerLike< + TState extends OperationState, + TResult, +> { /** * Returns true if the poller has finished polling. */ @@ -45,7 +48,9 @@ export interface SimplePollerLike, TResul /** * Returns a promise that will resolve once the underlying operation is completed. */ - pollUntilDone(pollOptions?: { abortSignal?: AbortSignalLike }): Promise; + pollUntilDone(pollOptions?: { + abortSignal?: AbortSignalLike; + }): Promise; /** * Invokes the provided callback after each polling is completed, * sending the current state of the poller's operation. @@ -92,10 +97,15 @@ export interface SimplePollerLike, TResul * @returns - A poller object to poll for operation state updates and eventually get the final response. */ export async function getLongRunningPoller< - TResult extends CreateJobLogicalResponse | CreateJobDefaultResponse, + TResult extends + | DeidentifyDocumentsLogicalResponse + | DeidentifyDocumentsDefaultResponse, >( client: Client, - initialResponse: CreateJob200Response | CreateJob201Response | CreateJobDefaultResponse, + initialResponse: + | DeidentifyDocuments200Response + | DeidentifyDocuments201Response + | DeidentifyDocumentsDefaultResponse, options?: CreateHttpPollerOptions>, ): Promise, TResult>>; export async function getLongRunningPoller( @@ -111,7 +121,10 @@ export async function getLongRunningPoller( // response we were provided. return getLroResponse(initialResponse); }, - sendPollRequest: async (path: string, pollOptions?: { abortSignal?: AbortSignalLike }) => { + sendPollRequest: async ( + path: string, + pollOptions?: { abortSignal?: AbortSignalLike }, + ) => { // This is the callback that is going to be called to poll the service // to get the latest status. We use the client provided and the polling path // which is an opaque URL provided by caller, the service sends this in one of the following headers: operation-location, azure-asyncoperation or location @@ -137,7 +150,8 @@ export async function getLongRunningPoller( inputAbortSignal?.removeEventListener("abort", abortListener); } const lroResponse = getLroResponse(response as TResult); - lroResponse.rawResponse.headers["x-ms-original-url"] = initialResponse.request.url; + lroResponse.rawResponse.headers["x-ms-original-url"] = + initialResponse.request.url; return lroResponse; }, }; @@ -193,7 +207,9 @@ function getLroResponse( response: TResult, ): OperationResponse { if (Number.isNaN(response.status)) { - throw new TypeError(`Status code of the response is not a number. Value: ${response.status}`); + throw new TypeError( + `Status code of the response is not a number. Value: ${response.status}`, + ); } return { diff --git a/sdk/healthdataaiservices/azure-health-deidentification/src/responses.ts b/sdk/healthdataaiservices/azure-health-deidentification/src/responses.ts index 0db6d44e9749..54af3ed0d23b 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/src/responses.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/src/responses.ts @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { RawHttpHeaders } from "@azure/core-rest-pipeline"; -import type { HttpResponse, ErrorResponse } from "@azure-rest/core-client"; -import type { +import { RawHttpHeaders } from "@azure/core-rest-pipeline"; +import { HttpResponse, ErrorResponse } from "@azure-rest/core-client"; +import { DeidentificationJobOutput, PagedDeidentificationJobOutput, - PagedDocumentDetailsOutput, + PagedDeidentificationDocumentDetailsOutput, DeidentificationResultOutput, } from "./outputModels.js"; @@ -33,7 +33,7 @@ export interface GetJobDefaultResponse extends HttpResponse { headers: RawHttpHeaders & GetJobDefaultHeaders; } -export interface CreateJob200Headers { +export interface DeidentifyDocuments200Headers { /** An opaque, globally-unique, client-generated string identifier for the request. */ "x-ms-client-request-id"?: string; /** The location for monitoring the operation state. */ @@ -41,13 +41,13 @@ export interface CreateJob200Headers { } /** The request has succeeded. */ -export interface CreateJob200Response extends HttpResponse { +export interface DeidentifyDocuments200Response extends HttpResponse { status: "200"; body: DeidentificationJobOutput; - headers: RawHttpHeaders & CreateJob200Headers; + headers: RawHttpHeaders & DeidentifyDocuments200Headers; } -export interface CreateJob201Headers { +export interface DeidentifyDocuments201Headers { /** An opaque, globally-unique, client-generated string identifier for the request. */ "x-ms-client-request-id"?: string; /** The location for monitoring the operation state. */ @@ -55,25 +55,25 @@ export interface CreateJob201Headers { } /** The request has succeeded and a new resource has been created as a result. */ -export interface CreateJob201Response extends HttpResponse { +export interface DeidentifyDocuments201Response extends HttpResponse { status: "201"; body: DeidentificationJobOutput; - headers: RawHttpHeaders & CreateJob201Headers; + headers: RawHttpHeaders & DeidentifyDocuments201Headers; } -export interface CreateJobDefaultHeaders { +export interface DeidentifyDocumentsDefaultHeaders { /** String error code indicating what went wrong. */ "x-ms-error-code"?: string; } -export interface CreateJobDefaultResponse extends HttpResponse { +export interface DeidentifyDocumentsDefaultResponse extends HttpResponse { status: string; body: ErrorResponse; - headers: RawHttpHeaders & CreateJobDefaultHeaders; + headers: RawHttpHeaders & DeidentifyDocumentsDefaultHeaders; } -/** The final response for long-running createJob operation */ -export interface CreateJobLogicalResponse extends HttpResponse { +/** The final response for long-running deidentifyDocuments operation */ +export interface DeidentifyDocumentsLogicalResponse extends HttpResponse { status: "200"; body: DeidentificationJobOutput; } @@ -109,7 +109,7 @@ export interface ListJobDocuments200Headers { /** The request has succeeded. */ export interface ListJobDocuments200Response extends HttpResponse { status: "200"; - body: PagedDocumentDetailsOutput; + body: PagedDeidentificationDocumentDetailsOutput; headers: RawHttpHeaders & ListJobDocuments200Headers; } @@ -169,19 +169,25 @@ export interface DeleteJobDefaultResponse extends HttpResponse { headers: RawHttpHeaders & DeleteJobDefaultHeaders; } +export interface DeidentifyText200Headers { + /** An opaque, globally-unique, client-generated string identifier for the request. */ + "x-ms-client-request-id"?: string; +} + /** The request has succeeded. */ -export interface Deidentify200Response extends HttpResponse { +export interface DeidentifyText200Response extends HttpResponse { status: "200"; body: DeidentificationResultOutput; + headers: RawHttpHeaders & DeidentifyText200Headers; } -export interface DeidentifyDefaultHeaders { +export interface DeidentifyTextDefaultHeaders { /** String error code indicating what went wrong. */ "x-ms-error-code"?: string; } -export interface DeidentifyDefaultResponse extends HttpResponse { +export interface DeidentifyTextDefaultResponse extends HttpResponse { status: string; body: ErrorResponse; - headers: RawHttpHeaders & DeidentifyDefaultHeaders; + headers: RawHttpHeaders & DeidentifyTextDefaultHeaders; } diff --git a/sdk/healthdataaiservices/azure-health-deidentification/test-resources-post.ps1 b/sdk/healthdataaiservices/azure-health-deidentification/test-resources-post.ps1 deleted file mode 100644 index 3400bf3ec4ae..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/test-resources-post.ps1 +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -# This script is used to set up SIP Configuration domains for Azure Communication Services SIP Routing SDK GA tests - -# It is invoked by the https://github.com/Azure/azure-sdk-for-net/blob/main/eng/New-TestResources.ps1 -# script after the ARM template, defined in https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/test-resources.json, -# is finished being deployed. The ARM template is responsible for creating the Storage accounts needed for live tests. - -param ( - [hashtable] $DeploymentOutputs, - [string] $TenantId, - [string] $TestApplicationId, - [string] $TestApplicationSecret -) - -# Retrieve the connection string from environment variables -$resourceGroup = $DeploymentOutputs['HEALTHDATAAISERVICES_RESOURCE_GROUP'] -$endpoint = $DeploymentOutputs['HEALTHDATAAISERVICES_DEID_SERVICE_ENDPOINT'] -$storageAccountName = $DeploymentOutputs['HEALTHDATAAISERVICES_STORAGE_ACCOUNT_NAME'] -$containerName = $DeploymentOutputs['HEALTHDATAAISERVICES_STORAGE_CONTAINER_NAME'] -$testMode = "live" - -# Set the local folder path to upload -$localFolderPath = "test\public\data\example_patient_1" - -# Check if the connection string is present -if ([string]::IsNullOrWhiteSpace($storageAccountName)) { - Write-Host "Error: Azure Storage Name string not found in environment variables." - exit 1 -} - -# Load the Azure Storage module -Import-Module Az.Storage - -# Connect to the storage account -$storageContext = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount - -# FIXME Remove once vpn team fixes the network acl issue -$networkRuleSet = New-Object -TypeName Microsoft.Azure.Commands.Management.Storage.Models.PSNetworkRuleSet -$networkRuleSet.DefaultAction = "Allow" -Set-AzStorageAccount -ResourceGroupName $resourceGroup -Name $storageAccountName -NetworkRuleSet $networkRuleSet - -# Sleep for 15 seconds to allow the network rule to take effect -Write-Host "[Fix] Temporary sleep to allow network rule to take effect." -Start-Sleep -Seconds 30 - -Get-AzStorageContainer -Name $containerName -Context $storageContext - -# Upload the folder and its contents to the container -# Gets last folder name + filename. example_patient_1\doctor_dictation.txt -Get-ChildItem -Path $localFolderPath -Recurse | ForEach-Object { - $relativePath = $_.FullName - $relativePath = $relativePath.Replace("\\", "\") - $folderName = ($relativePath -split "\\")[-2] # Get only the folder name. - $blobName = ($relativePath -split "\\")[-1] # Get only the file name. - $destinationBlob = $blobName -replace ":", "" - - $destinationBlob = "$folderName\$destinationBlob" - Write-Host "Uploading file '$destinationBlob'" - Set-AzStorageBlobContent -File $_.FullName -Container $containerName -Blob $destinationBlob -Context $storageContext -Force -} - -Write-Host "Folder '$localFolderPath' uploaded to container '$containerName' successfully." - -$endpoint = $endpoint -replace '^https://', '' -# Create the content for the .env file -$content = @" -DEID_SERVICE_ENDPOINT=$endpoint -TEST_MODE=$testMode -STORAGE_ACCOUNT_NAME=$storageAccountName -STORAGE_CONTAINER_NAME=$containerName -"@ - -# Specify the path for the .env file -$envFilePath = ".\.env" - -# Write the content to the .env file, overwrite if it exists -$content | Out-File -FilePath $envFilePath -Force diff --git a/sdk/healthdataaiservices/azure-health-deidentification/test-resources.bicep b/sdk/healthdataaiservices/azure-health-deidentification/test-resources.bicep deleted file mode 100644 index 63e8f4e54d58..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/test-resources.bicep +++ /dev/null @@ -1,205 +0,0 @@ -// "id": "/subscriptions/d12535ed-5958-4ce6-8350-b17b3af1d6b1/resourceGroups/oro-billing-exhaust-test/providers/Microsoft.HealthDataAIServices/DeidServices/deid-billing-test", -// "name": "deid-billing-test", -// "type": "microsoft.healthdataaiservices/deidservices", -// "location": "East US 2 EUAP", -// "tags": {}, - -@minLength(10) -param testApplicationOid string - -@minLength(6) -@maxLength(50) -@description('The base resource name.') -param baseName string - -param location string = resourceGroup().location - -@description('The location of the resource. By default, this is the same as the resource group.') -param deidLocation string = 'eastus2euap' -param deidLocationShort string = 'eup' - -param deploymentTime string = utcNow('u') - -var realtimeDataUserRoleId = 'bb6577c4-ea0a-40b2-8962-ea18cb8ecd4e' -var batchDataOwnerRoleId = '8a90fa6b-6997-4a07-8a95-30633a7c97b9' -var storageBlobDataContributor = 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' - -var blobStorageName = take(toLower(replace('blob-${baseName}', '-', '')), 24) -var blobContainerName = 'container-${baseName}' -var deidServiceName = 'deid${baseName}${deidLocationShort}' - -resource storageAccount 'Microsoft.Storage/storageAccounts@2022-05-01' = { - name: blobStorageName - location: location - sku: { - name: 'Standard_LRS' - } - kind: 'StorageV2' - properties: { - minimumTlsVersion: 'TLS1_2' - networkAcls: { - bypass: 'AzureServices' - defaultAction: 'Deny' - ipRules: [ - { - action: 'Allow' - value: '4.0.0.0/8' - } - { - action: 'Allow' - value: '13.0.0.0/8' - } - { - action: 'Allow' - value: '20.0.0.0/8' - } - { - action: 'Allow' - value: '40.0.0.0/8' - } - { - action: 'Allow' - value: '51.0.0.0/8' - } - { - action: 'Allow' - value: '52.0.0.0/8' - } - { - action: 'Allow' - value: '65.0.0.0/8' - } - { - action: 'Allow' - value: '70.0.0.0/8' - } - { - action: 'Allow' - value: '74.234.0.0/16' - } - { - action: 'Allow' - value: '74.235.60.120/30' - } - { - action: 'Allow' - value: '94.245.0.0/16' - } - { - action: 'Allow' - value: '98.71.0.0/16' - } - { - action: 'Allow' - value: '102.133.0.0/16' - } - { - action: 'Allow' - value: '104.41.214.32/29' - } - { - action: 'Allow' - value: '104.44.0.0/16' - } - { - action: 'Allow' - value: '104.45.71.156/30' - } - { - action: 'Allow' - value: '104.208.0.0/12' - } - { - action: 'Allow' - value: '108.142.0.0/16' - } - { - action: 'Allow' - value: '131.107.0.0/16' - } - { - action: 'Allow' - value: '157.58.0.0/16' - } - { - action: 'Allow' - value: '167.220.0.0/16' - } - { - action: 'Allow' - value: '172.128.0.0/13' - } - { - action: 'Allow' - value: '191.234.97.0/26' - } - { - action: 'Allow' - value: '194.69.0.0/16' - } - { - action: 'Allow' - value: '207.46.0.0/16' - } - ] - } - } -} - -resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2022-05-01' = { - parent: storageAccount - name: 'default' -} - -resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2022-05-01' = { - parent: blobService - name: blobContainerName -} - -resource storageRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { - name: guid(resourceGroup().id, storageAccount.id, testApplicationOid, storageBlobDataContributor) - properties: { - roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', storageBlobDataContributor) - principalId: testApplicationOid - } - scope: storageAccount -} - -resource testDeidService 'microsoft.healthdataaiservices/deidservices@2024-02-28-preview' = { - name: deidServiceName - location: deidLocation - identity: { - type: 'SystemAssigned' - } -} - -resource storageMIRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { - name: guid(resourceGroup().id, storageAccount.id, testDeidService.id, storageBlobDataContributor) - properties: { - roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', storageBlobDataContributor) - principalId: testDeidService.identity.principalId - } - scope: storageAccount -} - -resource realtimeRole 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = { - name: guid(resourceGroup().id, testDeidService.id, testApplicationOid, realtimeDataUserRoleId) - scope: testDeidService - properties: { - roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', realtimeDataUserRoleId) - principalId: testApplicationOid - } -} - -resource batchRole 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = { - name: guid(resourceGroup().id, testDeidService.id, testApplicationOid, batchDataOwnerRoleId) - scope: testDeidService - properties: { - roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', batchDataOwnerRoleId) - principalId: testApplicationOid - } -} - -output HEALTHDATAAISERVICES_DEID_SERVICE_ENDPOINT string = testDeidService.properties.serviceUrl -output HEALTHDATAAISERVICES_STORAGE_ACCOUNT_NAME string = storageAccount.name -output HEALTHDATAAISERVICES_STORAGE_CONTAINER_NAME string = container.name diff --git a/sdk/healthdataaiservices/azure-health-deidentification/test/public/data/example_patient_1/doctor_dictation.txt b/sdk/healthdataaiservices/azure-health-deidentification/test/public/data/example_patient_1/doctor_dictation.txt deleted file mode 100644 index dfb10187f123..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/test/public/data/example_patient_1/doctor_dictation.txt +++ /dev/null @@ -1 +0,0 @@ -Mr. Doe is a 97-year-old gentleman who presented to the clinic today complaining of persistent lower back pain. He reports the pain as dull and achy, primarily localized to the lumbar region. Onset was approximately three weeks ago, following a period of heavy lifting during a recent move. The pain is exacerbated by prolonged sitting and relieved with rest. No associated symptoms of radiculopathy, such as numbness or weakness, were reported. diff --git a/sdk/healthdataaiservices/azure-health-deidentification/test/public/data/example_patient_1/visit_summary.txt b/sdk/healthdataaiservices/azure-health-deidentification/test/public/data/example_patient_1/visit_summary.txt deleted file mode 100644 index 427472ff8d1d..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/test/public/data/example_patient_1/visit_summary.txt +++ /dev/null @@ -1,8 +0,0 @@ -Patient Name: John Doe -Date of Visit: May 8, 2024 -Physician: Dr. Emily Carter - -Summary: - -Chief Complaint: -John Doe presented today with complaints of persistent lower back pain that has been bothering him for the past three weeks. He reports the pain as dull and achy, localized primarily to the lumbar region, exacerbated by prolonged sitting and relieved with rest. diff --git a/sdk/healthdataaiservices/azure-health-deidentification/test/public/jobOperationsTest.spec.ts b/sdk/healthdataaiservices/azure-health-deidentification/test/public/jobOperationsTest.spec.ts deleted file mode 100644 index fe2fc07180f2..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/test/public/jobOperationsTest.spec.ts +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - createRecordedDeidentificationClient, - createRecorder, - getStorageAccountLocation, - getTestEnvironment, -} from "./utils/recordedClient.js"; -import { assert, beforeEach, afterEach, it, describe } from "vitest"; -import type { DeidentificationClient } from "../../src/clientDefinitions.js"; -import { createTestCredential } from "@azure-tools/test-credential"; -import type { DeidentificationJob } from "../../src/models.js"; -import type { DeidentificationJobOutput, DocumentDetailsOutput } from "../../src/outputModels.js"; -import type { Recorder } from "@azure-tools/test-recorder"; -import { isPlaybackMode, isRecordMode } from "@azure-tools/test-recorder"; -import type { ErrorResponse } from "@azure-rest/core-client"; -import { getLongRunningPoller } from "../../src/pollingHelper.js"; -import { paginate } from "../../src/paginateHelper.js"; -import { isUnexpected } from "../../src/isUnexpected.js"; - -const testPollingOptions = { - intervalInMs: isPlaybackMode() ? 0 : undefined, -}; - -const TEST_TIMEOUT_MS: number = 200000; - -const fakeServiceEndpoint = "example.com"; -const replaceableVariables: Record = { - DEID_SERVICE_ENDPOINT: fakeServiceEndpoint, - STORAGE_ACCOUNT_LOCATION: - "https://fake_storage_account_sas_uri.blob.core.windows.net/container-sdk-dev-fakeid", -}; - -const generateJobName = (testName?: string): string => { - let jobName = "js-sdk-job-" + Date.now(); - if (isPlaybackMode() || isRecordMode()) { - jobName = `js-sdk-job-recorded-${testName}`; - } - return jobName; -}; - -const OUTPUT_FOLDER = "_output"; - -describe("Batch", () => { - let recorder: Recorder; - let client: DeidentificationClient; - const environment = getTestEnvironment(); - - beforeEach(async function (context) { - recorder = await createRecorder(context); - await recorder.start({ - envSetupForPlayback: replaceableVariables, - sanitizerOptions: { - bodyKeySanitizers: [ - { - value: replaceableVariables.STORAGE_ACCOUNT_LOCATION, - jsonPath: "$..location", - regex: "^(?!.*FAKE_STORAGE_ACCOUNT).*", - }, - ], - }, - removeCentralSanitizers: ["AZSDK4001", "AZSDK2030", "AZSDK3430", "AZSDK3493"], - }); - const credential = createTestCredential(); - if (process.env.DEID_SERVICE_ENDPOINT) { - client = await createRecordedDeidentificationClient(recorder, credential); - } else { - throw new Error("DEID_SERVICE_ENDPOINT is not set"); - } - }); - - afterEach(async function () { - await recorder.stop(); - }); - - // Note: When your re-run recording you need to update jobName to avoid conflict with existing job "environment" is either node or browser depending on the test mode - it( - "CreateJob returns expected", - async function () { - const jobName = generateJobName(`001-${environment}`); - const inputPrefix = "example_patient_1"; - const storageAccountLocation = isPlaybackMode() - ? replaceableVariables.STORAGE_ACCOUNT_LOCATION - : getStorageAccountLocation(); - - const job: DeidentificationJob = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { - location: storageAccountLocation, - prefix: inputPrefix, - extensions: ["*"], - }, - targetLocation: { location: storageAccountLocation, prefix: OUTPUT_FOLDER }, - }; - - const jobOutput = await client.path("/jobs/{name}", jobName).put({ body: job }); - - if (isUnexpected(jobOutput)) { - throw new Error("Unexpected job result"); - } - - assert.isNotNull(jobOutput); - assert.equal(jobName, jobOutput.body.name, "Job name should match"); - assert.isNotNull(jobOutput.body.createdAt, "Job should have createdAt"); - assert.isNotNull(jobOutput.body.lastUpdatedAt, "Job should have lastUpdatedAt"); - assert.isUndefined(jobOutput.body.startedAt, "Job should not have startedAt"); - assert.equal("NotStarted", jobOutput.body.status, "Job status should be NotStarted"); - assert.isUndefined(jobOutput.body.error, "Job should not have error"); - assert.isUndefined(jobOutput.body.redactionFormat, "Job should not have redactionFormat"); - assert.isUndefined(jobOutput.body.summary, "Job should not have summary"); - assert.equal( - inputPrefix, - jobOutput.body.sourceLocation.prefix, - "Job sourceLocation prefix should match", - ); - assert.isTrue( - storageAccountLocation.includes("blob.core.windows.net"), - "Storage account location should contain 'blob.core.windows.net'", - ); - assert.equal( - OUTPUT_FOLDER, - jobOutput.body.targetLocation.prefix, - "Job targetLocation prefix should match", - ); - assert.isTrue( - storageAccountLocation.includes("blob.core.windows.net"), - "Storage account location should contain 'blob.core.windows.net'", - ); - }, - TEST_TIMEOUT_MS, - ); - - it( - "CreateThenList returns expected", - async function () { - const jobName = generateJobName(`002-${environment}`); - const inputPrefix = "example_patient_1"; - const storageAccountLocation = isPlaybackMode() - ? replaceableVariables.STORAGE_ACCOUNT_LOCATION - : getStorageAccountLocation(); - - const job: DeidentificationJob = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { - location: storageAccountLocation, - prefix: inputPrefix, - extensions: ["*"], - }, - targetLocation: { location: storageAccountLocation, prefix: OUTPUT_FOLDER }, - }; - - const initialResponse = await client.path("/jobs/{name}", jobName).put({ body: job }); - const poller = await getLongRunningPoller(client, initialResponse, testPollingOptions); - await poller.poll(); - assert.equal(poller.getOperationState().status, "running"); - - // Test list jobs with pagination - const jobs = await client.path("/jobs").get(); - const items = []; - const iter = paginate(client, jobs); - for await (const item of iter) { - items.push(item); - } - const foundJob = (items as DeidentificationJobOutput[]).find((j) => j.name === jobName); - - assert.isTrue(foundJob !== undefined, "Job should be found"); - assert.isNotNull(foundJob!.createdAt, "Job should have createdAt"); - assert.isNotNull(foundJob!.lastUpdatedAt, "Job should have lastUpdatedAt"); - assert.isNotNull(foundJob!.startedAt, "Job should have startedAt"); - assert.equal("NotStarted", foundJob!.status, "Job status should be NotStarted"); - assert.isUndefined(foundJob!.error, "Job should not have error"); - assert.isUndefined(foundJob!.redactionFormat, "Job should not have redactionFormat"); - assert.isUndefined(foundJob!.summary, "Job should not have summary"); - assert.equal( - inputPrefix, - foundJob!.sourceLocation.prefix, - "Job sourceLocation prefix should match", - ); - assert.isTrue( - storageAccountLocation.includes("blob.core.windows.net"), - "Storage account location should contain 'blob.core.windows.net'", - ); - assert.equal( - OUTPUT_FOLDER, - foundJob!.targetLocation.prefix, - "Job targetLocation prefix should match", - ); - assert.isTrue( - storageAccountLocation.includes("blob.core.windows.net"), - "Storage account location should contain 'blob.core.windows.net", - ); - }, - TEST_TIMEOUT_MS, - ); - - it( - "JobE2E wait until success", - async function () { - const jobName = generateJobName(`003-${environment}`); - const inputPrefix = "example_patient_1"; - const storageAccountLocation = isPlaybackMode() - ? replaceableVariables.STORAGE_ACCOUNT_LOCATION - : getStorageAccountLocation(); - - const job: DeidentificationJob = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { - location: storageAccountLocation, - prefix: inputPrefix, - extensions: ["*"], - }, - targetLocation: { location: storageAccountLocation, prefix: OUTPUT_FOLDER }, - }; - - const initialResponse = await client.path("/jobs/{name}", jobName).put({ body: job }); - - const poller = await getLongRunningPoller(client, initialResponse, testPollingOptions); - const finalJobOutput = await poller.pollUntilDone(); - assert.equal(poller.getOperationState().status, "succeeded"); - - if (isUnexpected(finalJobOutput)) { - throw new Error("Unexpected error occurred"); - } - - assert.equal(finalJobOutput.body.status, "Succeeded", "Job status should be Succeeded"); - assert.notEqual(finalJobOutput.body.startedAt, null, "Job should have startedAt"); - assert.notEqual(finalJobOutput.body.summary, null, "Job should have summary"); - assert.equal(finalJobOutput.body.summary!.total, 2, "Job should have processed 2 documents"); - assert.equal( - finalJobOutput.body.summary!.successful, - 2, - "Job should have succeeded 2 documents", - ); - - const reports = await client.path("/jobs/{name}/documents", jobName).get(); - - if (isUnexpected(reports)) { - throw new Error("Unexpected error occurred"); - } - - const items = []; - const iter = paginate(client, reports); - - for await (const item of iter) { - items.push(item); - } - - assert.isTrue( - (items as unknown[] as DocumentDetailsOutput[]).length === 2, - "Should have 2 documents", - ); - assert.isTrue( - (items as unknown[] as DocumentDetailsOutput[]).every((obj) => obj.status === "Succeeded"), - "All documents should have succeeded", - ); - assert.isTrue( - (items as unknown[] as DocumentDetailsOutput[]).every((obj) => - obj.output!.path.startsWith(OUTPUT_FOLDER), - ), - "Output path should start with the output folder", - ); - assert.isTrue( - (items as unknown[] as DocumentDetailsOutput[]).every((obj) => obj.id.length === 36), - "Document id should be a GUID", - ); - }, - TEST_TIMEOUT_MS, - ); - - it( - "JobE2E cancel job then delete it deletes job", - async function () { - const jobName = generateJobName(`004-${environment}`); - const inputPrefix = "example_patient_1"; - const storageAccountLocation = isPlaybackMode() - ? replaceableVariables.STORAGE_ACCOUNT_LOCATION - : getStorageAccountLocation(); - - const job: DeidentificationJob = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { - location: storageAccountLocation, - prefix: inputPrefix, - extensions: ["*"], - }, - targetLocation: { location: storageAccountLocation, prefix: OUTPUT_FOLDER }, - }; - - const initialResponse = await client.path("/jobs/{name}", jobName).put({ body: job }); - const poller = await getLongRunningPoller(client, initialResponse, testPollingOptions); - await poller.poll(); - assert.equal(poller.getOperationState().status, "running", "Job should be running"); - - const cancelledJob = await client.path("/jobs/{name}:cancel", jobName).post(); - assert.equal(cancelledJob.status, "200", "Job should be canceled"); - - const cancelledJobOutput = cancelledJob.body as DeidentificationJobOutput; - assert.equal("Canceled", cancelledJobOutput.status, "Job status should be Canceled"); - - const deleteRequest = await client.path("/jobs/{name}", jobName).delete(); - assert.equal(deleteRequest.status, "204", "Job should be deleted"); - - const deletedJob = await client.path("/jobs/{name}", jobName).get(); - assert.equal(deletedJob.status, "404", "Job should not be found"); - }, - TEST_TIMEOUT_MS, - ); - - it( - "JobE2E cannot access storage create job returns 404", - async function () { - const jobName = generateJobName(`005-${environment}`); - const inputPrefix = "example_patient_1"; - const storageAccountLocation = "FAKE_STORAGE_ACCOUNT"; - - const job: DeidentificationJob = { - dataType: "Plaintext", - operation: "Surrogate", - sourceLocation: { - location: storageAccountLocation, - prefix: inputPrefix, - extensions: ["*"], - }, - targetLocation: { location: storageAccountLocation, prefix: OUTPUT_FOLDER }, - }; - - const initialResponse = await client.path("/jobs/{name}", jobName).put({ body: job }); - - const poller = await getLongRunningPoller(client, initialResponse, testPollingOptions); - - await poller.poll(); - assert.equal(poller.getOperationState().status, "failed", "Job should fail"); - - const createdJob = await client.path("/jobs/{name}", jobName).get(); - assert.equal(createdJob.status, "404", "Job should not be found"); - const createdJobOutput = createdJob.body as ErrorResponse; - assert.isNotNull(createdJobOutput.error, "Job should have error"); - assert.equal("JobNotFound", createdJobOutput.error.code, "Error code should be JobNotFound"); - assert.isTrue( - createdJobOutput.error!.message.length > 10, - "Error message should be descriptive", - ); - }, - TEST_TIMEOUT_MS, - ); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/test/public/realtimeOperationsTest.spec.ts b/sdk/healthdataaiservices/azure-health-deidentification/test/public/realtimeOperationsTest.spec.ts deleted file mode 100644 index 793a2bc36b90..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/test/public/realtimeOperationsTest.spec.ts +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { createRecordedDeidentificationClient, createRecorder } from "./utils/recordedClient.js"; -import { assert, beforeEach, afterEach, it, describe } from "vitest"; -import type { DeidentificationClient } from "../../src/clientDefinitions.js"; -import { createTestCredential } from "@azure-tools/test-credential"; - -import type { DeidentificationContent } from "../../src/models.js"; -import type { DeidentificationResultOutput } from "../../src/outputModels.js"; -import type { Recorder } from "@azure-tools/test-recorder"; - -const fakeServiceEndpoint = "example.com"; -const replaceableVariables: Record = { - DEID_SERVICE_ENDPOINT: fakeServiceEndpoint, -}; - -describe("Realtime", () => { - let recorder: Recorder; - let client: DeidentificationClient; - - beforeEach(async function (context) { - recorder = await createRecorder(context); - await recorder.start({ - envSetupForPlayback: replaceableVariables, - removeCentralSanitizers: ["AZSDK4001", "AZSDK2030", "AZSDK3430", "AZSDK3493"], - }); - const credential = createTestCredential(); - if (process.env.DEID_SERVICE_ENDPOINT) { - client = await createRecordedDeidentificationClient(recorder, credential); - } else { - throw new Error("DEID_SERVICE_ENDPOINT is not set"); - } - }); - - afterEach(async function () { - await recorder.stop(); - }); - - it("surrogate returns expected", async function () { - const content: DeidentificationContent = { - dataType: "Plaintext", - inputText: "Hello, my name is John Smith.", - operation: "Surrogate", - }; - const response = await client.path("/deid").post({ body: content }); - assert.equal(response.status, "200"); - const output = response.body as DeidentificationResultOutput; - assert.isUndefined( - output.taggerResult, - "On Surrogate Operation, expect TaggerResult to be null.", - ); - assert.isNotNull( - output.outputText, - "On Surrogate Operation, expect OutputText to be not null.", - ); - assert.isTrue( - (output.outputText as string).length > 21, - "Expected output text to be longer than the tag and a single character for each name token.", - ); - assert.notEqual( - content.inputText, - output.outputText, - "Expected output text to be different from input text.", - ); - }, 10000); - - it("tag returns expected", async function () { - const content: DeidentificationContent = { - dataType: "Plaintext", - inputText: "Hello, my name is John Smith.", - operation: "Tag", - }; - const response = await client.path("/deid").post({ body: content }); - assert.equal(response.status, "200"); - const output = response.body as DeidentificationResultOutput; - assert.isNotNull(output.taggerResult, "On Tag Operation, expect TaggerResult to be not null."); - assert.isObject(output.taggerResult, "On Tag Operation, expect TaggerResult to be not null."); - assert.isUndefined(output.outputText, "On Tag Operation, expect OutputText to be null."); - assert.isTrue(output.taggerResult!.etag === undefined, "Expected Etag to be null."); - assert.isTrue(output.taggerResult!.path === undefined, "Expected Path to be null."); - - assert.isTrue( - output.taggerResult!.entities.length > 0, - "Expected taggerResult to have at least one tag.", - ); - assert.isTrue( - output.taggerResult!.entities[0].category === "Doctor" || - output.taggerResult!.entities[0].category === "Patient", - "Expected first tag to be a patient/doctor.", - ); - assert.isTrue( - output.taggerResult!.entities[0].text === "John Smith", - "Expected first tag to be 'John Smith'.", - ); - assert.isTrue( - output.taggerResult!.entities[0].offset.utf8 === 18, - "Expected first tag to start at index 19.", - ); - assert.isTrue( - output.taggerResult!.entities[0].length.utf8 === 10, - "Expected first tag to be 10 characters long.", - ); - }, 10000); -}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/test/public/sampleTest.spec.ts b/sdk/healthdataaiservices/azure-health-deidentification/test/public/sampleTest.spec.ts new file mode 100644 index 000000000000..d4919ac91ac5 --- /dev/null +++ b/sdk/healthdataaiservices/azure-health-deidentification/test/public/sampleTest.spec.ts @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { createRecorder } from "./utils/recordedClient.js"; +import { assert, beforeEach, afterEach, it, describe } from "vitest"; + +describe("My test", () => { + // let recorder: Recorder; + + beforeEach(async function () { + // recorder = await createRecorder(this); + }); + + afterEach(async function () { + // await recorder.stop(); + }); + + it("sample test", async function () { + assert.equal(1, 1); + }); +}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/test/public/utils/recordedClient.ts b/sdk/healthdataaiservices/azure-health-deidentification/test/public/utils/recordedClient.ts index cdfad48924c2..6e425fdcfdf9 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/test/public/utils/recordedClient.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/test/public/utils/recordedClient.ts @@ -1,41 +1,29 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { VitestTestContext } from "@azure-tools/test-recorder"; -import { Recorder, assertEnvironmentVariable, isPlaybackMode } from "@azure-tools/test-recorder"; -import type { TokenCredential } from "@azure/core-auth"; -import type { DeidentificationClient } from "../../../src/clientDefinitions.js"; -import createClient from "../../../src/deidentificationClient.js"; +import { + Recorder, + RecorderStartOptions, + VitestTestContext, +} from "@azure-tools/test-recorder"; + +const replaceableVariables: Record = { + SUBSCRIPTION_ID: "azure_subscription_id", +}; + +const recorderEnvSetup: RecorderStartOptions = { + envSetupForPlayback: replaceableVariables, +}; /** * creates the recorder and reads the environment variables from the `.env` file. * Should be called first in the test suite to make sure environment variables are * read before they are being used. */ -export async function createRecorder(testContext: VitestTestContext): Promise { - return new Recorder(testContext); -} - -export function getStorageAccountLocation(): string { - return `https://${assertEnvironmentVariable("STORAGE_ACCOUNT_NAME")}.blob.core.windows.net/${assertEnvironmentVariable("STORAGE_CONTAINER_NAME")}`; -} - -export function getTestEnvironment(): string { - if (typeof process !== "undefined" && process.versions != null && process.versions.node != null) { - return "node"; - } - - return "browser"; -} - -export async function createRecordedDeidentificationClient( - recorder: Recorder, - credentials: TokenCredential, -): Promise { - const endpoint = isPlaybackMode() - ? "example.com" - : assertEnvironmentVariable("DEID_SERVICE_ENDPOINT"); - const client = await createClient(endpoint, credentials, recorder.configureClientOptions({})); - - return client; +export async function createRecorder( + context: VitestTestContext, +): Promise { + const recorder = new Recorder(context); + await recorder.start(recorderEnvSetup); + return recorder; } diff --git a/sdk/healthdataaiservices/azure-health-deidentification/tests.yml b/sdk/healthdataaiservices/azure-health-deidentification/tests.yml deleted file mode 100644 index f27af5d776b4..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/tests.yml +++ /dev/null @@ -1,8 +0,0 @@ -trigger: none - - -extends: - template: /eng/pipelines/templates/stages/archetype-sdk-tests.yml - parameters: - PackageName: "@azure-rest/health-deidentification" - ServiceDirectory: healthdataaiservices diff --git a/sdk/healthdataaiservices/azure-health-deidentification/tsconfig.browser.config.json b/sdk/healthdataaiservices/azure-health-deidentification/tsconfig.browser.config.json index 1b37aebc5457..091177fcb991 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/tsconfig.browser.config.json +++ b/sdk/healthdataaiservices/azure-health-deidentification/tsconfig.browser.config.json @@ -1,7 +1,7 @@ { "extends": "./.tshy/build.json", - "include": ["./src/**/*.ts", "./src/**/*.mts", "./test/**/*.spec.ts"], - "exclude": ["./test/**/node/**/*.ts"], + "include": ["src/**/*.ts", "src/**/*.mts", "test/**/*.spec.ts"], + "exclude": ["test/**/node/**/*.ts"], "compilerOptions": { "outDir": "./dist-test/browser", "rootDir": ".", diff --git a/sdk/healthdataaiservices/azure-health-deidentification/tsconfig.json b/sdk/healthdataaiservices/azure-health-deidentification/tsconfig.json index b495c1a46b90..71858ab903e4 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/tsconfig.json +++ b/sdk/healthdataaiservices/azure-health-deidentification/tsconfig.json @@ -1,19 +1,16 @@ { - "extends": "../../../tsconfig.json", + "extends": "../../../tsconfig", "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", "rootDir": ".", - "paths": { - "@azure/health-deidentification": ["./src/index"] - } + "skipLibCheck": true }, "include": [ - "./src/**/*.ts", - "./src/**/*.mts", - "./src/**/*.cts", + "src/**/*.ts", + "src/**/*.mts", + "src/**/*.cts", "test/**/*.ts", - "./test/**/*.ts", - "./samples-dev/**/*.ts" + "test/**/*.ts" ] -} +} \ No newline at end of file diff --git a/sdk/healthdataaiservices/azure-health-deidentification/tsdoc.json b/sdk/healthdataaiservices/azure-health-deidentification/tsdoc.json deleted file mode 100644 index 81c5a8a2aa2f..000000000000 --- a/sdk/healthdataaiservices/azure-health-deidentification/tsdoc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", - "extends": ["../../../tsdoc.json"] -} diff --git a/sdk/healthdataaiservices/azure-health-deidentification/tsp-location.yaml b/sdk/healthdataaiservices/azure-health-deidentification/tsp-location.yaml index bc53597e9692..8adfe6739aec 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/tsp-location.yaml +++ b/sdk/healthdataaiservices/azure-health-deidentification/tsp-location.yaml @@ -1,5 +1,4 @@ -repo: Azure/azure-rest-api-specs -additionalDirectories: [] -commit: dc4f9f316f20e45231df187971a4dad2e5dd8964 directory: specification/healthdataaiservices/HealthDataAIServices.DeidServices - +commit: d308ccfc5ababbeefc3e0884435674935eb493ab +repo: /mnt/vss/_work/1/s/azure-rest-api-specs +additionalDirectories: diff --git a/sdk/healthdataaiservices/azure-health-deidentification/vitest.browser.config.ts b/sdk/healthdataaiservices/azure-health-deidentification/vitest.browser.config.ts index 03b41edc2d8a..da68c1d231aa 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/vitest.browser.config.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/vitest.browser.config.ts @@ -1,17 +1,38 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { defineConfig, mergeConfig } from "vitest/config"; -import viteConfig from "../../../vitest.browser.shared.config.ts"; +import { defineConfig } from "vitest/config"; +import { relativeRecordingsPath } from "@azure-tools/test-recorder"; -export default mergeConfig( - viteConfig, - defineConfig({ - test: { - include: [ - "dist-test/browser/test/internal/**/*.spec.js", - "dist-test/browser/test/public/**/*.spec.js", - ], +process.env.RECORDINGS_RELATIVE_PATH = relativeRecordingsPath(); + +export default defineConfig({ + define: { + "process.env": process.env, + }, + test: { + reporters: ["basic", "junit"], + outputFile: { + junit: "test-results.browser.xml", + }, + browser: { + enabled: true, + headless: true, + name: "chromium", + provider: "playwright", + }, + fakeTimers: { + toFake: ["setTimeout", "Date"], + }, + watch: false, + include: ["dist-test/browser/**/*.spec.js"], + coverage: { + include: ["dist-test/browser/**/*.spec.js"], + provider: "istanbul", + reporter: ["text", "json", "html"], + reportsDirectory: "coverage-browser", }, - }), -); + testTimeout: 1200000, + hookTimeout: 1200000, + }, +}); diff --git a/sdk/healthdataaiservices/azure-health-deidentification/vitest.config.ts b/sdk/healthdataaiservices/azure-health-deidentification/vitest.config.ts index b60f0effa527..2cf5d0e02c2e 100644 --- a/sdk/healthdataaiservices/azure-health-deidentification/vitest.config.ts +++ b/sdk/healthdataaiservices/azure-health-deidentification/vitest.config.ts @@ -1,14 +1,34 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { defineConfig, mergeConfig } from "vitest/config"; -import viteConfig from "../../../vitest.shared.config.ts"; +import { defineConfig } from "vitest/config"; +import { relativeRecordingsPath } from "@azure-tools/test-recorder"; -export default mergeConfig( - viteConfig, - defineConfig({ - test: { - include: ["test/internal/**/*.spec.ts", "test/public/**/*.spec.ts"], +export default defineConfig({ + test: { + reporters: ["basic", "junit"], + outputFile: { + junit: "test-results.browser.xml", }, - }), -); + fakeTimers: { + toFake: ["setTimeout", "Date"], + }, + watch: false, + include: ["test/**/*.spec.ts"], + exclude: ["test/**/browser/*.spec.ts"], + coverage: { + include: ["src/**/*.ts"], + exclude: [ + "src/**/*-browser.mts", + "src/**/*-react-native.mts", + "vitest*.config.ts", + "samples-dev/**/*.ts", + ], + provider: "istanbul", + reporter: ["text", "json", "html"], + reportsDirectory: "coverage", + }, + testTimeout: 1200000, + hookTimeout: 1200000, + }, +}); diff --git a/sdk/healthdataaiservices/ci.yml b/sdk/healthdataaiservices/ci.yml index a95529288f3d..a859aa1b01ca 100644 --- a/sdk/healthdataaiservices/ci.yml +++ b/sdk/healthdataaiservices/ci.yml @@ -1,5 +1,5 @@ # NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file. - + trigger: branches: include: @@ -9,7 +9,6 @@ trigger: paths: include: - sdk/healthdataaiservices - pr: branches: include: @@ -17,20 +16,18 @@ pr: - feature/* - release/* - hotfix/* + exclude: + - feature/v4 paths: include: - sdk/healthdataaiservices - parameters: - # Switch to canary to test canary 1es branch. 1es template validation will set this parameter - # to canary on run. - name: oneESTemplateTag type: string default: release values: - release - canary - extends: template: ../../eng/pipelines/templates/stages/archetype-sdk-client.yml parameters: