diff --git a/sdk/confidentialledger/confidential-ledger-rest/CHANGELOG.md b/sdk/confidentialledger/confidential-ledger-rest/CHANGELOG.md index d326b6044f9c..ac750c474078 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/CHANGELOG.md +++ b/sdk/confidentialledger/confidential-ledger-rest/CHANGELOG.md @@ -1,14 +1,9 @@ # Release History -## 1.0.1 (Unreleased) +## 1.0.1 (2027-12-16) ### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- refresh @azure-rest/confidential-ledger sdk ## 1.0.0 (2022-07-18) - Pageable collections and consortium endpoints diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/clientDefinitions.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/clientDefinitions.ts similarity index 90% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/clientDefinitions.ts rename to sdk/confidentialledger/confidential-ledger-rest/generated/clientDefinitions.ts index 0d0d273f3079..254c2d2a657f 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/clientDefinitions.ts +++ b/sdk/confidentialledger/confidential-ledger-rest/generated/clientDefinitions.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. + import { GetConstitutionParameters, ListConsortiumMembersParameters, @@ -49,7 +50,7 @@ import { Client, StreamableMethod } from "@azure-rest/core-client"; export interface GetConstitution { /** The constitution is a script that assesses and applies proposals from consortium members. */ get( - options?: GetConstitutionParameters + options?: GetConstitutionParameters, ): StreamableMethod< GetConstitution200Response | GetConstitutionDefaultResponse >; @@ -58,7 +59,7 @@ export interface GetConstitution { export interface ListConsortiumMembers { /** Consortium members can manage the Confidential Ledger. */ get( - options?: ListConsortiumMembersParameters + options?: ListConsortiumMembersParameters, ): StreamableMethod< ListConsortiumMembers200Response | ListConsortiumMembersDefaultResponse >; @@ -67,7 +68,7 @@ export interface ListConsortiumMembers { export interface GetEnclaveQuotes { /** A quote is an SGX enclave measurement that can be used to verify the validity of a node and its enclave. */ get( - options?: GetEnclaveQuotesParameters + options?: GetEnclaveQuotesParameters, ): StreamableMethod< GetEnclaveQuotes200Response | GetEnclaveQuotesDefaultResponse >; @@ -76,7 +77,7 @@ export interface GetEnclaveQuotes { export interface ListCollections { /** Collection ids are user-created collections of ledger entries */ get( - options?: ListCollectionsParameters + options?: ListCollectionsParameters, ): StreamableMethod< ListCollections200Response | ListCollectionsDefaultResponse >; @@ -85,13 +86,13 @@ export interface ListCollections { export interface ListLedgerEntries { /** A collection id may optionally be specified. Only entries in the specified (or default) collection will be returned. */ get( - options?: ListLedgerEntriesParameters + options?: ListLedgerEntriesParameters, ): StreamableMethod< ListLedgerEntries200Response | ListLedgerEntriesDefaultResponse >; /** A collection id may optionally be specified. */ post( - options: CreateLedgerEntryParameters + options: CreateLedgerEntryParameters, ): StreamableMethod< CreateLedgerEntry200Response | CreateLedgerEntryDefaultResponse >; @@ -100,7 +101,7 @@ export interface ListLedgerEntries { export interface GetLedgerEntry { /** To return older ledger entries, the relevant sections of the ledger must be read from disk and validated. To prevent blocking within the enclave, the response will indicate whether the entry is ready and part of the response, or if the loading is still ongoing. */ get( - options?: GetLedgerEntryParameters + options?: GetLedgerEntryParameters, ): StreamableMethod< GetLedgerEntry200Response | GetLedgerEntryDefaultResponse >; @@ -109,14 +110,14 @@ export interface GetLedgerEntry { export interface GetReceipt { /** Gets a receipt certifying ledger contents at a particular transaction id. */ get( - options?: GetReceiptParameters + options?: GetReceiptParameters, ): StreamableMethod; } export interface GetTransactionStatus { /** Gets the status of an entry identified by a transaction id. */ get( - options?: GetTransactionStatusParameters + options?: GetTransactionStatusParameters, ): StreamableMethod< GetTransactionStatus200Response | GetTransactionStatusDefaultResponse >; @@ -125,7 +126,7 @@ export interface GetTransactionStatus { export interface GetCurrentLedgerEntry { /** A collection id may optionally be specified. */ get( - options?: GetCurrentLedgerEntryParameters + options?: GetCurrentLedgerEntryParameters, ): StreamableMethod< GetCurrentLedgerEntry200Response | GetCurrentLedgerEntryDefaultResponse >; @@ -134,15 +135,15 @@ export interface GetCurrentLedgerEntry { export interface DeleteUser { /** Deletes a user from the Confidential Ledger. */ delete( - options?: DeleteUserParameters + options?: DeleteUserParameters, ): StreamableMethod; /** Gets a user. */ get( - options?: GetUserParameters + options?: GetUserParameters, ): StreamableMethod; /** A JSON merge patch is applied for existing users */ patch( - options: CreateOrUpdateUserParameters + options: CreateOrUpdateUserParameters, ): StreamableMethod< CreateOrUpdateUser200Response | CreateOrUpdateUserDefaultResponse >; @@ -162,17 +163,17 @@ export interface Routes { /** Resource for '/app/transactions/\{transactionId\}' has methods for the following verbs: get */ ( path: "/app/transactions/{transactionId}", - transactionId: string + transactionId: string, ): GetLedgerEntry; /** Resource for '/app/transactions/\{transactionId\}/receipt' has methods for the following verbs: get */ ( path: "/app/transactions/{transactionId}/receipt", - transactionId: string + transactionId: string, ): GetReceipt; /** Resource for '/app/transactions/\{transactionId\}/status' has methods for the following verbs: get */ ( path: "/app/transactions/{transactionId}/status", - transactionId: string + transactionId: string, ): GetTransactionStatus; /** Resource for '/app/transactions/current' has methods for the following verbs: get */ (path: "/app/transactions/current"): GetCurrentLedgerEntry; diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/confidentialLedger.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/confidentialLedger.ts similarity index 52% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/confidentialLedger.ts rename to sdk/confidentialledger/confidential-ledger-rest/generated/confidentialLedger.ts index e6afb70fe170..3d183bfedbeb 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/confidentialLedger.ts +++ b/sdk/confidentialledger/confidential-ledger-rest/generated/confidentialLedger.ts @@ -6,6 +6,13 @@ import { logger } from "./logger.js"; import { TokenCredential } from "@azure/core-auth"; import { ConfidentialLedgerClient } from "./clientDefinitions.js"; + +/** The optional parameters for the client */ +export interface ConfidentialLedgerClientOptions extends ClientOptions { + /** The api version option of the client */ + apiVersion?: string; +} + /** * Initialize a new instance of `ConfidentialLedgerClient` * @param ledgerEndpoint - The Confidential Ledger URL, for example https://contoso.confidentialledger.azure.com @@ -15,19 +22,13 @@ import { ConfidentialLedgerClient } from "./clientDefinitions.js"; export default function createClient( ledgerEndpoint: string, credentials: TokenCredential, - options: ClientOptions = {} + { + apiVersion = "2022-05-13", + ...options + }: ConfidentialLedgerClientOptions = {}, ): ConfidentialLedgerClient { - const baseUrl = options.baseUrl ?? `${ledgerEndpoint}`; - options.apiVersion = options.apiVersion ?? "2022-05-13"; - options = { - ...options, - credentials: { - scopes: options.credentials?.scopes ?? [ - "https://confidential-ledger.azure.com/.default" - ] - } - }; - + const endpointUrl = + options.endpoint ?? options.baseUrl ?? `${ledgerEndpoint}`; const userAgentInfo = `azsdk-js-confidential-ledger-rest/1.0.1`; const userAgentPrefix = options.userAgentOptions && options.userAgentOptions.userAgentPrefix @@ -36,18 +37,38 @@ export default function createClient( options = { ...options, userAgentOptions: { - userAgentPrefix + userAgentPrefix, }, loggingOptions: { - logger: options.loggingOptions?.logger ?? logger.info - } + logger: options.loggingOptions?.logger ?? logger.info, + }, + credentials: { + scopes: options.credentials?.scopes ?? [ + "https://confidential-ledger.azure.com/.default", + ], + }, }; - const client = getClient( - baseUrl, + endpointUrl, credentials, - options + options, ) as ConfidentialLedgerClient; + client.pipeline.removePolicy({ name: "ApiVersionPolicy" }); + client.pipeline.addPolicy({ + name: "ClientApiVersionPolicy", + sendRequest: (req, next) => { + // Use the apiVersion defined in request url directly + // Append one if there is no apiVersion and we have one at client options + const url = new URL(req.url); + if (!url.searchParams.get("api-version") && apiVersion) { + req.url = `${req.url}${Array.from(url.searchParams.keys()).length > 0 ? "&" : "?" + }api-version=${apiVersion}`; + } + + return next(req); + }, + }); + return client; } diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/index.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/index.ts similarity index 100% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/index.ts rename to sdk/confidentialledger/confidential-ledger-rest/generated/index.ts diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/isUnexpected.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/isUnexpected.ts similarity index 93% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/isUnexpected.ts rename to sdk/confidentialledger/confidential-ledger-rest/generated/isUnexpected.ts index b6efcf318537..1634c4646b93 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/isUnexpected.ts +++ b/sdk/confidentialledger/confidential-ledger-rest/generated/isUnexpected.ts @@ -30,6 +30,7 @@ import { CreateOrUpdateUserDefaultResponse } from "./responses.js"; + const responseMap: Record = { "GET /app/governance/constitution": ["200"], "GET /app/governance/members": ["200"], @@ -43,53 +44,53 @@ const responseMap: Record = { "GET /app/transactions/current": ["200"], "DELETE /app/users/{userId}": ["204"], "GET /app/users/{userId}": ["200"], - "PATCH /app/users/{userId}": ["200"] + "PATCH /app/users/{userId}": ["200"], }; export function isUnexpected( - response: GetConstitution200Response | GetConstitutionDefaultResponse + response: GetConstitution200Response | GetConstitutionDefaultResponse, ): response is GetConstitutionDefaultResponse; export function isUnexpected( response: | ListConsortiumMembers200Response - | ListConsortiumMembersDefaultResponse + | ListConsortiumMembersDefaultResponse, ): response is ListConsortiumMembersDefaultResponse; export function isUnexpected( - response: GetEnclaveQuotes200Response | GetEnclaveQuotesDefaultResponse + response: GetEnclaveQuotes200Response | GetEnclaveQuotesDefaultResponse, ): response is GetEnclaveQuotesDefaultResponse; export function isUnexpected( - response: ListCollections200Response | ListCollectionsDefaultResponse + response: ListCollections200Response | ListCollectionsDefaultResponse, ): response is ListCollectionsDefaultResponse; export function isUnexpected( - response: ListLedgerEntries200Response | ListLedgerEntriesDefaultResponse + response: ListLedgerEntries200Response | ListLedgerEntriesDefaultResponse, ): response is ListLedgerEntriesDefaultResponse; export function isUnexpected( - response: CreateLedgerEntry200Response | CreateLedgerEntryDefaultResponse + response: CreateLedgerEntry200Response | CreateLedgerEntryDefaultResponse, ): response is CreateLedgerEntryDefaultResponse; export function isUnexpected( - response: GetLedgerEntry200Response | GetLedgerEntryDefaultResponse + response: GetLedgerEntry200Response | GetLedgerEntryDefaultResponse, ): response is GetLedgerEntryDefaultResponse; export function isUnexpected( - response: GetReceipt200Response | GetReceiptDefaultResponse + response: GetReceipt200Response | GetReceiptDefaultResponse, ): response is GetReceiptDefaultResponse; export function isUnexpected( response: | GetTransactionStatus200Response - | GetTransactionStatusDefaultResponse + | GetTransactionStatusDefaultResponse, ): response is GetTransactionStatusDefaultResponse; export function isUnexpected( response: | GetCurrentLedgerEntry200Response - | GetCurrentLedgerEntryDefaultResponse + | GetCurrentLedgerEntryDefaultResponse, ): response is GetCurrentLedgerEntryDefaultResponse; export function isUnexpected( - response: DeleteUser204Response | DeleteUserDefaultResponse + response: DeleteUser204Response | DeleteUserDefaultResponse, ): response is DeleteUserDefaultResponse; export function isUnexpected( - response: GetUser200Response | GetUserDefaultResponse + response: GetUser200Response | GetUserDefaultResponse, ): response is GetUserDefaultResponse; export function isUnexpected( - response: CreateOrUpdateUser200Response | CreateOrUpdateUserDefaultResponse + response: CreateOrUpdateUser200Response | CreateOrUpdateUserDefaultResponse, ): response is CreateOrUpdateUserDefaultResponse; export function isUnexpected( response: @@ -118,7 +119,7 @@ export function isUnexpected( | GetUser200Response | GetUserDefaultResponse | CreateOrUpdateUser200Response - | CreateOrUpdateUserDefaultResponse + | CreateOrUpdateUserDefaultResponse, ): response is | GetConstitutionDefaultResponse | ListConsortiumMembersDefaultResponse @@ -181,7 +182,7 @@ function getParametrizedPathSuccess(method: string, path: string): string[] { // {guid} ==> $ // {guid}:export ==> :export$ const isMatched = new RegExp( - `${candidateParts[i]?.slice(start, end)}` + `${candidateParts[i]?.slice(start, end)}`, ).test(pathParts[j] || ""); if (!isMatched) { diff --git a/sdk/confidentialledger/confidential-ledger-rest/generated/logger.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/logger.ts new file mode 100644 index 000000000000..4e3eb587d7d8 --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/generated/logger.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +import { createClientLogger } from "@azure/logger"; +export const logger = createClientLogger("confidential-ledger"); diff --git a/sdk/confidentialledger/confidential-ledger-rest/generated/models.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/models.ts new file mode 100644 index 000000000000..0f6b93825167 --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/generated/models.ts @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** An entry in the ledger. */ +export interface LedgerEntry { + /** Contents of the ledger entry. */ + contents: string; +} + + +/** Details about a Confidential Ledger user. */ +export interface LedgerUser { + /** Represents an assignable role. */ + assignedRole: "Administrator" | "Contributor" | "Reader"; +} diff --git a/sdk/confidentialledger/confidential-ledger-rest/generated/outputModels.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/outputModels.ts new file mode 100644 index 000000000000..157a00d935d3 --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/generated/outputModels.ts @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +/** The governance script for the application. */ +export interface ConstitutionOutput { + /** SHA256 digest of the constitution script. */ + digest: string; + /** Contents of the constitution. */ + script: string; +} + +/** An error response from Confidential Ledger. */ +export interface ConfidentialLedgerErrorOutput { + /** An error response from Confidential Ledger. */ + readonly error?: ConfidentialLedgerErrorBodyOutput; +} + +/** An error response from Confidential Ledger. */ +export interface ConfidentialLedgerErrorBodyOutput { + /** The error code. */ + readonly code?: string; + /** The error message. */ + readonly message?: string; +} + +/** List of members in the consortium. */ +export interface ConsortiumOutput { + members: Array; + /** Path from which to retrieve the next page of results. */ + nextLink?: string; +} + +/** Describes a member of the consortium. */ +export interface ConsortiumMemberOutput { + /** PEM-encoded certificate associated with the member. */ + certificate: string; + /** Identifier assigned to the member. */ + id: string; +} + +/** Information about the enclaves running the Confidential Ledger. */ +export interface ConfidentialLedgerEnclavesOutput { + /** Id of the Confidential Ledger node responding to the request. */ + currentNodeId: string; + /** Dictionary of enclave quotes, indexed by node id. */ + enclaveQuotes: Record; +} + +/** Contains the enclave quote. */ +export interface EnclaveQuoteOutput { + /** ID assigned to this node. */ + nodeId: string; + /** MRENCLAVE value of the code running in the enclave. */ + mrenclave?: string; + /** Version of the quote presented. */ + quoteVersion: string; + /** Raw SGX quote, parsable by tools like Open Enclave's oeverify. */ + raw: string; +} + +/** Paginated collections returned in response to a query. */ +export interface PagedCollectionsOutput { + collections: Array; + /** Path from which to retrieve the next page of results. */ + nextLink?: string; +} + +/** Identifier for collections. */ +export interface CollectionOutput { + collectionId: string; +} + +/** Paginated ledger entries returned in response to a query. */ +export interface PagedLedgerEntriesOutput { + /** State of a ledger query. */ + state: "Loading" | "Ready"; + /** Path from which to retrieve the next page of results. */ + nextLink?: string; + /** Array of ledger entries. */ + entries: Array; +} + +/** An entry in the ledger. */ +export interface LedgerEntryOutput { + /** Contents of the ledger entry. */ + contents: string; + readonly collectionId?: string; + /** A unique identifier for the state of the ledger. If returned as part of a LedgerEntry, it indicates the state from which the entry was read. */ + readonly transactionId?: string; +} + +/** Returned as a result of a write to the Confidential Ledger, the transaction id in the response indicates when the write will become durable. */ +export interface LedgerWriteResultOutput { + collectionId: string; +} + +/** The result of querying for a ledger entry from an older transaction id. The ledger entry is available in the response only if the returned state is Ready. */ +export interface LedgerQueryResultOutput { + /** State of a ledger query. */ + state: "Loading" | "Ready"; + /** The ledger entry found as a result of the query. This is only available if the query is in Ready state. */ + entry?: LedgerEntryOutput; +} + +/** A receipt certifying the transaction at the specified id. */ +export interface TransactionReceiptOutput { + receipt?: ReceiptContentsOutput; + /** State of a ledger query. */ + state: "Loading" | "Ready"; + /** A unique identifier for the state of the ledger. If returned as part of a LedgerEntry, it indicates the state from which the entry was read. */ + transactionId: string; +} + +export interface ReceiptContentsOutput { + cert?: string; + leaf?: string; + leafComponents?: ReceiptLeafComponentsOutput; + nodeId: string; + proof: Array; + root?: string; + serviceEndorsements?: Array; + signature: string; +} + +export interface ReceiptLeafComponentsOutput { + claimsDigest?: string; + commitEvidence?: string; + writeSetDigest?: string; +} + +export interface ReceiptElementOutput { + left?: string; + right?: string; +} + +/** Response returned to a query for the transaction status */ +export interface TransactionStatusOutput { + /** Represents the state of the transaction. */ + state: "Committed" | "Pending"; + /** A unique identifier for the state of the ledger. If returned as part of a LedgerEntry, it indicates the state from which the entry was read. */ + transactionId: string; +} + +/** Details about a Confidential Ledger user. */ +export interface LedgerUserOutput { + /** Represents an assignable role. */ + assignedRole: "Administrator" | "Contributor" | "Reader"; + /** Identifier for the user. This must either be an AAD object id or a certificate fingerprint. */ + readonly userId?: string; +} diff --git a/sdk/confidentialledger/confidential-ledger-rest/generated/paginateHelper.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/paginateHelper.ts new file mode 100644 index 000000000000..1e38724d738d --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/generated/paginateHelper.ts @@ -0,0 +1,354 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +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 + */ +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) => Promise<{ + page: TPage; + nextPageLink?: string; +}>; + +/** + * Options for the paging helper + */ +export interface PagingOptions { + /** + * Custom function to extract pagination details for crating the PagedAsyncIterableIterator + */ + customGetPage?: GetPage[]>; +} + +/** + * Helper type to infer the Type of the paged elements from the response type + * This type is generated based on the swagger information for x-ms-pageable + * specifically on the itemName property which indicates the property of the response + * where the page items are found. The default value is `value`. + * This type will allow us to provide strongly typed Iterator based on the response we get as second parameter + */ +export type PaginateReturn = TResult extends + | { + body: { value?: infer TPage }; + } + | { + body: { members?: infer TPage }; + } + | { + body: { collections?: infer TPage }; + } + | { + body: { entries?: infer TPage }; + } + ? GetArrayType + : Array; + +/** + * Helper to paginate results from an initial response that follows the specification of Autorest `x-ms-pageable` extension + * @param client - Client to use for sending the next page requests + * @param initialResponse - Initial response containing the nextLink and current page of elements + * @param customGetPage - Optional - Function to define how to extract the page and next link to be used to paginate the results + * @returns - PagedAsyncIterableIterator to iterate the elements + */ +export function paginate( + client: Client, + initialResponse: TResponse, + options: PagingOptions = {}, +): PagedAsyncIterableIterator> { + // Extract element type from initial response + type TElement = PaginateReturn; + let firstRun = true; + // We need to check the response for success before trying to inspect it looking for + // the properties to use for nextLink and itemName + checkPagingRequest(initialResponse); + const { itemName, nextLinkName } = getPaginationProperties(initialResponse); + const { customGetPage } = options; + const pagedResult: PagedResult = { + firstPageLink: "", + getPage: + typeof customGetPage === "function" + ? customGetPage + : async (pageLink: string) => { + const result = firstRun + ? initialResponse + : await client.pathUnchecked(pageLink).get(); + firstRun = false; + checkPagingRequest(result); + const nextLink = getNextLink(result.body, nextLinkName); + const values = getElements(result.body, itemName); + return { + page: values, + nextPageLink: nextLink, + }; + }, + }; + + return getPagedAsyncIterator(pagedResult); +} + +/** + * Gets for the value of nextLink in the body + */ +function getNextLink(body: unknown, nextLinkName?: string): string | undefined { + if (!nextLinkName) { + return 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`, + ); + } + + return nextLink; +} + +/** + * Gets the elements of the current request in the body. + */ +function getElements(body: unknown, itemName: string): T[] { + const value = (body as Record)[itemName] as T[]; + + // value has to be an array according to the x-ms-pageable extension. + // The fact that this must be an array is used above to calculate the + // type of elements in the page in PaginateReturn + if (!Array.isArray(value)) { + throw new Error( + `Couldn't paginate response\n Body doesn't contain an array property with name: ${itemName}`, + ); + } + + return value ?? []; +} + +/** + * Checks if a request failed + */ +function checkPagingRequest(response: PathUncheckedResponse): void { + 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}`, + response, + ); + } +} + +/** + * Extracts the itemName and nextLinkName from the initial response to use them for pagination + */ +function getPaginationProperties(initialResponse: PathUncheckedResponse) { + // Build a set with the passed custom nextLinkNames + const nextLinkNames = new Set(["nextLink", "@nextLink"]); + + // Build a set with the passed custom set of itemNames + const itemNames = new Set(["value", "members", "collections", "entries"]); + + let nextLinkName: string | undefined; + let itemName: string | undefined; + + for (const name of nextLinkNames) { + const nextLink = (initialResponse.body as Record)[ + name + ] as string; + if (nextLink) { + nextLinkName = name; + break; + } + } + + for (const name of itemNames) { + const item = (initialResponse.body as Record)[ + name + ] as string; + if (item) { + itemName = name; + break; + } + } + + if (!itemName) { + throw new Error( + `Couldn't paginate response\n Body doesn't contain an array property with name: ${[ + ...itemNames, + ].join(" OR ")}`, + ); + } + + return { itemName, nextLinkName }; +} diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/parameters.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/parameters.ts similarity index 99% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/parameters.ts rename to sdk/confidentialledger/confidential-ledger-rest/generated/parameters.ts index eaca363de5fe..d2de7c49f558 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/parameters.ts +++ b/sdk/confidentialledger/confidential-ledger-rest/generated/parameters.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. + import { RequestParameters } from "@azure-rest/core-client"; import { LedgerEntry, LedgerUser } from "./models.js"; diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/responses.ts b/sdk/confidentialledger/confidential-ledger-rest/generated/responses.ts similarity index 99% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/responses.ts rename to sdk/confidentialledger/confidential-ledger-rest/generated/responses.ts index 70ab81281bfb..eedc2854c96c 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/responses.ts +++ b/sdk/confidentialledger/confidential-ledger-rest/generated/responses.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. + import { RawHttpHeaders } from "@azure/core-rest-pipeline"; import { HttpResponse } from "@azure-rest/core-client"; import { diff --git a/sdk/confidentialledger/confidential-ledger-rest/karma.conf.js b/sdk/confidentialledger/confidential-ledger-rest/karma.conf.js new file mode 100644 index 000000000000..4fdf26c79ac0 --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/karma.conf.js @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// https://github.com/karma-runner/karma-chrome-launcher +process.env.CHROME_BIN = require("puppeteer").executablePath(); +require("dotenv").config(); +const { relativeRecordingsPath } = require("@azure-tools/test-recorder"); +process.env.RECORDINGS_RELATIVE_PATH = relativeRecordingsPath(); + +module.exports = function (config) { + config.set({ + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: "./", + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ["source-map-support", "mocha"], + + plugins: [ + "karma-mocha", + "karma-mocha-reporter", + "karma-chrome-launcher", + "karma-firefox-launcher", + "karma-env-preprocessor", + "karma-coverage", + "karma-sourcemap-loader", + "karma-junit-reporter", + "karma-source-map-support", + ], + + // list of files / patterns to load in the browser + files: [ + "dist-test/index.browser.js", + { + pattern: "dist-test/index.browser.js.map", + type: "html", + included: false, + served: true, + }, + ], + + // list of files / patterns to exclude + exclude: [], + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + "**/*.js": ["sourcemap", "env"], + // IMPORTANT: COMMENT following line if you want to debug in your browsers!! + // Preprocess source file to calculate code coverage, however this will make source file unreadable + // "dist-test/index.js": ["coverage"] + }, + + envPreprocessor: [ + "TEST_MODE", + "ENDPOINT", + "AZURE_CLIENT_SECRET", + "AZURE_CLIENT_ID", + "AZURE_TENANT_ID", + "SUBSCRIPTION_ID", + "RECORDINGS_RELATIVE_PATH", + ], + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ["mocha", "coverage", "junit"], + + coverageReporter: { + // specify a common output directory + dir: "coverage-browser/", + reporters: [ + { type: "json", subdir: ".", file: "coverage.json" }, + { type: "lcovonly", subdir: ".", file: "lcov.info" }, + { type: "html", subdir: "html" }, + { type: "cobertura", subdir: ".", file: "cobertura-coverage.xml" }, + ], + }, + + junitReporter: { + outputDir: "", // results will be saved as $outputDir/$browserName.xml + outputFile: "test-results.browser.xml", // if included, results will be saved as $outputDir/$browserName/$outputFile + suite: "", // suite will become the package name attribute in xml testsuite element + useBrowserName: false, // add browser name to report and classes names + nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element + classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element + properties: {}, // key value pair of properties to add to the section of the report + }, + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + // --no-sandbox allows our tests to run in Linux without having to change the system. + // --disable-web-security allows us to authenticate from the browser without having to write tests using interactive auth, which would be far more complex. + browsers: ["ChromeHeadlessNoSandbox"], + customLaunchers: { + ChromeHeadlessNoSandbox: { + base: "ChromeHeadless", + flags: ["--no-sandbox", "--disable-web-security"], + }, + }, + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: 1, + + browserNoActivityTimeout: 60000000, + browserDisconnectTimeout: 10000, + browserDisconnectTolerance: 3, + + client: { + mocha: { + // change Karma's debug.html to the mocha web reporter + reporter: "html", + timeout: "600000", + }, + }, + }); +}; diff --git a/sdk/confidentialledger/confidential-ledger-rest/package.json b/sdk/confidentialledger/confidential-ledger-rest/package.json index dc7a7c49e5b0..bbb4ceef82c1 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/package.json +++ b/sdk/confidentialledger/confidential-ledger-rest/package.json @@ -80,7 +80,6 @@ "dependencies": { "@azure-rest/core-client": "^2.3.1", "@azure/core-auth": "^1.9.0", - "@azure/core-paging": "^1.6.2", "@azure/core-rest-pipeline": "^1.18.0", "@azure/logger": "^1.1.4", "tslib": "^2.8.1" diff --git a/sdk/confidentialledger/confidential-ledger-rest/review/confidential-ledger.api.md b/sdk/confidentialledger/confidential-ledger-rest/review/confidential-ledger.api.md index 1e05c536d7bf..95f96ea8e96f 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/review/confidential-ledger.api.md +++ b/sdk/confidentialledger/confidential-ledger-rest/review/confidential-ledger.api.md @@ -4,14 +4,13 @@ ```ts -import { Client } from '@azure-rest/core-client'; +import type { Client } from '@azure-rest/core-client'; import type { ClientOptions } from '@azure-rest/core-client'; -import { HttpResponse } from '@azure-rest/core-client'; -import { PagedAsyncIterableIterator } from '@azure/core-paging'; -import { PathUncheckedResponse } from '@azure-rest/core-client'; -import { RawHttpHeaders } from '@azure/core-rest-pipeline'; -import { RequestParameters } from '@azure-rest/core-client'; -import { StreamableMethod } from '@azure-rest/core-client'; +import type { HttpResponse } from '@azure-rest/core-client'; +import type { PathUncheckedResponse } from '@azure-rest/core-client'; +import type { RawHttpHeaders } 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'; // @public @@ -32,6 +31,11 @@ export type ConfidentialLedgerClient = Client & { path: Routes; }; +// @public +export interface ConfidentialLedgerClientOptions extends ClientOptions { + apiVersion?: string; +} + // @public export interface ConfidentialLedgerEnclavesOutput { currentNodeId: string; @@ -301,7 +305,7 @@ export interface GetLedgerEntryQueryParamProperties { export function getLedgerIdentity(ledgerId: string, identityServiceBaseUrl?: string): Promise; // @public -export type GetPage = (pageLink: string, maxPageSize?: number) => Promise<{ +export type GetPage = (pageLink: string) => Promise<{ page: TPage; nextPageLink?: string; }>; @@ -545,6 +549,13 @@ export interface ListLedgerEntriesQueryParamProperties { toTransactionId?: string; } +// @public +export interface PagedAsyncIterableIterator { + [Symbol.asyncIterator](): PagedAsyncIterableIterator; + byPage: (settings?: TPageSettings) => AsyncIterableIterator; + next(): Promise>; +} + // @public export interface PagedCollectionsOutput { // (undocumented) @@ -559,6 +570,11 @@ export interface PagedLedgerEntriesOutput { state: "Loading" | "Ready"; } +// @public +export interface PageSettings { + continuationToken?: string; +} + // @public export function paginate(client: Client, initialResponse: TResponse, options?: PagingOptions): PagedAsyncIterableIterator>; diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/clientDefinitions.ts b/sdk/confidentialledger/confidential-ledger-rest/src/clientDefinitions.ts new file mode 100644 index 000000000000..388d010d0784 --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/src/clientDefinitions.ts @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { + GetConstitutionParameters, + ListConsortiumMembersParameters, + GetEnclaveQuotesParameters, + ListCollectionsParameters, + ListLedgerEntriesParameters, + CreateLedgerEntryParameters, + GetLedgerEntryParameters, + GetReceiptParameters, + GetTransactionStatusParameters, + GetCurrentLedgerEntryParameters, + DeleteUserParameters, + GetUserParameters, + CreateOrUpdateUserParameters, +} from "./parameters.js"; +import type { + GetConstitution200Response, + GetConstitutionDefaultResponse, + ListConsortiumMembers200Response, + ListConsortiumMembersDefaultResponse, + GetEnclaveQuotes200Response, + GetEnclaveQuotesDefaultResponse, + ListCollections200Response, + ListCollectionsDefaultResponse, + ListLedgerEntries200Response, + ListLedgerEntriesDefaultResponse, + CreateLedgerEntry200Response, + CreateLedgerEntryDefaultResponse, + GetLedgerEntry200Response, + GetLedgerEntryDefaultResponse, + GetReceipt200Response, + GetReceiptDefaultResponse, + GetTransactionStatus200Response, + GetTransactionStatusDefaultResponse, + GetCurrentLedgerEntry200Response, + GetCurrentLedgerEntryDefaultResponse, + DeleteUser204Response, + DeleteUserDefaultResponse, + GetUser200Response, + GetUserDefaultResponse, + CreateOrUpdateUser200Response, + CreateOrUpdateUserDefaultResponse, +} from "./responses.js"; +import type { Client, StreamableMethod } from "@azure-rest/core-client"; + +export interface GetConstitution { + /** The constitution is a script that assesses and applies proposals from consortium members. */ + get( + options?: GetConstitutionParameters, + ): StreamableMethod; +} + +export interface ListConsortiumMembers { + /** Consortium members can manage the Confidential Ledger. */ + get( + options?: ListConsortiumMembersParameters, + ): StreamableMethod; +} + +export interface GetEnclaveQuotes { + /** A quote is an SGX enclave measurement that can be used to verify the validity of a node and its enclave. */ + get( + options?: GetEnclaveQuotesParameters, + ): StreamableMethod; +} + +export interface ListCollections { + /** Collection ids are user-created collections of ledger entries */ + get( + options?: ListCollectionsParameters, + ): StreamableMethod; +} + +export interface ListLedgerEntries { + /** A collection id may optionally be specified. Only entries in the specified (or default) collection will be returned. */ + get( + options?: ListLedgerEntriesParameters, + ): StreamableMethod; + /** A collection id may optionally be specified. */ + post( + options: CreateLedgerEntryParameters, + ): StreamableMethod; +} + +export interface GetLedgerEntry { + /** To return older ledger entries, the relevant sections of the ledger must be read from disk and validated. To prevent blocking within the enclave, the response will indicate whether the entry is ready and part of the response, or if the loading is still ongoing. */ + get( + options?: GetLedgerEntryParameters, + ): StreamableMethod; +} + +export interface GetReceipt { + /** Gets a receipt certifying ledger contents at a particular transaction id. */ + get( + options?: GetReceiptParameters, + ): StreamableMethod; +} + +export interface GetTransactionStatus { + /** Gets the status of an entry identified by a transaction id. */ + get( + options?: GetTransactionStatusParameters, + ): StreamableMethod; +} + +export interface GetCurrentLedgerEntry { + /** A collection id may optionally be specified. */ + get( + options?: GetCurrentLedgerEntryParameters, + ): StreamableMethod; +} + +export interface DeleteUser { + /** Deletes a user from the Confidential Ledger. */ + delete( + options?: DeleteUserParameters, + ): StreamableMethod; + /** Gets a user. */ + get(options?: GetUserParameters): StreamableMethod; + /** A JSON merge patch is applied for existing users */ + patch( + options: CreateOrUpdateUserParameters, + ): StreamableMethod; +} + +export interface Routes { + /** Resource for '/app/governance/constitution' has methods for the following verbs: get */ + (path: "/app/governance/constitution"): GetConstitution; + /** Resource for '/app/governance/members' has methods for the following verbs: get */ + (path: "/app/governance/members"): ListConsortiumMembers; + /** Resource for '/app/enclaveQuotes' has methods for the following verbs: get */ + (path: "/app/enclaveQuotes"): GetEnclaveQuotes; + /** Resource for '/app/collections' has methods for the following verbs: get */ + (path: "/app/collections"): ListCollections; + /** Resource for '/app/transactions' has methods for the following verbs: get, post */ + (path: "/app/transactions"): ListLedgerEntries; + /** Resource for '/app/transactions/\{transactionId\}' has methods for the following verbs: get */ + (path: "/app/transactions/{transactionId}", transactionId: string): GetLedgerEntry; + /** Resource for '/app/transactions/\{transactionId\}/receipt' has methods for the following verbs: get */ + (path: "/app/transactions/{transactionId}/receipt", transactionId: string): GetReceipt; + /** Resource for '/app/transactions/\{transactionId\}/status' has methods for the following verbs: get */ + (path: "/app/transactions/{transactionId}/status", transactionId: string): GetTransactionStatus; + /** Resource for '/app/transactions/current' has methods for the following verbs: get */ + (path: "/app/transactions/current"): GetCurrentLedgerEntry; + /** Resource for '/app/users/\{userId\}' has methods for the following verbs: delete, get, patch */ + (path: "/app/users/{userId}", userId: string): DeleteUser; +} + +export type ConfidentialLedgerClient = Client & { + path: Routes; +}; diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/confidentialLedger.ts b/sdk/confidentialledger/confidential-ledger-rest/src/confidentialLedger.ts index de10978e2cb2..1118ae4ef1dd 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/src/confidentialLedger.ts +++ b/sdk/confidentialledger/confidential-ledger-rest/src/confidentialLedger.ts @@ -1,45 +1,65 @@ // 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 { logger } from "./logger.js"; import type { TokenCredential } from "@azure/core-auth"; -import { isTokenCredential } from "@azure/core-auth"; +import type { ConfidentialLedgerClient } from "./clientDefinitions.js"; -import type { ClientOptions } from "@azure-rest/core-client"; -import type { ConfidentialLedgerClient } from "./generated/src/clientDefinitions.js"; -import GeneratedConfidentialLedger from "./generated/src/confidentialLedger.js"; +/** The optional parameters for the client */ +export interface ConfidentialLedgerClientOptions extends ClientOptions { + /** The api version option of the client */ + apiVersion?: string; +} -export default function ConfidentialLedger( - ledgerEndpoint: string, - ledgerIdentityCertificate: string, - options?: ClientOptions, -): ConfidentialLedgerClient; -export default function ConfidentialLedger( +/** + * Initialize a new instance of `ConfidentialLedgerClient` + * @param ledgerEndpoint - The Confidential Ledger URL, for example https://contoso.confidentialledger.azure.com + * @param credentials - uniquely identify client credential + * @param options - the parameter for all optional parameters + */ +export default function createClient( ledgerEndpoint: string, - ledgerIdentityCertificate: string, credentials: TokenCredential, - options?: ClientOptions, -): ConfidentialLedgerClient; -export default function ConfidentialLedger( - ledgerEndpoint: string, - ledgerIdentityCertificate: string, - credentialsOrOptions?: TokenCredential | ClientOptions, - opts?: ClientOptions, + { apiVersion = "2022-05-13", ...options }: ConfidentialLedgerClientOptions = {}, ): ConfidentialLedgerClient { - let credentials: TokenCredential | undefined; - let options: ClientOptions; + const endpointUrl = options.endpoint ?? options.baseUrl ?? `${ledgerEndpoint}`; + const userAgentInfo = `azsdk-js-confidential-ledger-rest/1.0.1`; + const userAgentPrefix = + options.userAgentOptions && options.userAgentOptions.userAgentPrefix + ? `${options.userAgentOptions.userAgentPrefix} ${userAgentInfo}` + : `${userAgentInfo}`; + options = { + ...options, + userAgentOptions: { + userAgentPrefix, + }, + loggingOptions: { + logger: options.loggingOptions?.logger ?? logger.info, + }, + credentials: { + scopes: options.credentials?.scopes ?? ["https://confidential-ledger.azure.com/.default"], + }, + }; + const client = getClient(endpointUrl, credentials, options) as ConfidentialLedgerClient; - if (isTokenCredential(credentialsOrOptions)) { - credentials = credentialsOrOptions; - options = opts ?? {}; - } else { - options = credentialsOrOptions ?? {}; - } + client.pipeline.removePolicy({ name: "ApiVersionPolicy" }); + client.pipeline.addPolicy({ + name: "ClientApiVersionPolicy", + sendRequest: (req, next) => { + // Use the apiVersion defined in request url directly + // Append one if there is no apiVersion and we have one at client options + const url = new URL(req.url); + if (!url.searchParams.get("api-version") && apiVersion) { + req.url = `${req.url}${ + Array.from(url.searchParams.keys()).length > 0 ? "&" : "?" + }api-version=${apiVersion}`; + } - const tlsOptions = options?.tlsOptions ?? {}; - tlsOptions.ca = ledgerIdentityCertificate; - const confidentialLedger = GeneratedConfidentialLedger(ledgerEndpoint, credentials!, { - ...options, - tlsOptions, + return next(req); + }, }); - return confidentialLedger; + + return client; } diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/confidentialLedgerCustomization.ts b/sdk/confidentialledger/confidential-ledger-rest/src/confidentialLedgerCustomization.ts new file mode 100644 index 000000000000..a2cecbf1f7f3 --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/src/confidentialLedgerCustomization.ts @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { TokenCredential } from "@azure/core-auth"; +import { isTokenCredential } from "@azure/core-auth"; + +import type { ClientOptions } from "@azure-rest/core-client"; +import type { ConfidentialLedgerClient } from "./clientDefinitions.js"; +import GeneratedConfidentialLedger from "./confidentialLedger.js"; + +export default function ConfidentialLedger( + ledgerEndpoint: string, + ledgerIdentityCertificate: string, + options?: ClientOptions, +): ConfidentialLedgerClient; +export default function ConfidentialLedger( + ledgerEndpoint: string, + ledgerIdentityCertificate: string, + credentials: TokenCredential, + options?: ClientOptions, +): ConfidentialLedgerClient; +export default function ConfidentialLedger( + ledgerEndpoint: string, + ledgerIdentityCertificate: string, + credentialsOrOptions?: TokenCredential | ClientOptions, + opts?: ClientOptions, +): ConfidentialLedgerClient { + let credentials: TokenCredential | undefined; + let options: ClientOptions; + + if (isTokenCredential(credentialsOrOptions)) { + credentials = credentialsOrOptions; + options = opts ?? {}; + } else { + options = credentialsOrOptions ?? {}; + } + + const tlsOptions = options?.tlsOptions ?? {}; + tlsOptions.ca = ledgerIdentityCertificate; + const confidentialLedger = GeneratedConfidentialLedger(ledgerEndpoint, credentials!, { + ...options, + tlsOptions, + }); + return confidentialLedger; +} diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/index.ts b/sdk/confidentialledger/confidential-ledger-rest/src/index.ts index 798a7307441e..6aa447e750b0 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/src/index.ts +++ b/sdk/confidentialledger/confidential-ledger-rest/src/index.ts @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import ConfidentialLedger from "./confidentialLedger.js"; -export * from "./generated/src/confidentialLedger.js"; -export * from "./generated/src/models.js"; -export * from "./generated/src/parameters.js"; -export * from "./generated/src/responses.js"; -export * from "./generated/src/clientDefinitions.js"; -export * from "./generated/src/isUnexpected.js"; -export * from "./generated/src/outputModels.js"; -export * from "./generated/src/paginateHelper.js"; +import ConfidentialLedger from "./confidentialLedgerCustomization.js"; +export * from "./confidentialLedger.js"; +export * from "./models.js"; +export * from "./parameters.js"; +export * from "./responses.js"; +export * from "./clientDefinitions.js"; +export * from "./isUnexpected.js"; +export * from "./outputModels.js"; +export * from "./paginateHelper.js"; export { LedgerIdentity, getLedgerIdentity } from "./getLedgerIdentity.js"; export default ConfidentialLedger; diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/isUnexpected.ts b/sdk/confidentialledger/confidential-ledger-rest/src/isUnexpected.ts new file mode 100644 index 000000000000..62cc8cbe8519 --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/src/isUnexpected.ts @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { + GetConstitution200Response, + GetConstitutionDefaultResponse, + ListConsortiumMembers200Response, + ListConsortiumMembersDefaultResponse, + GetEnclaveQuotes200Response, + GetEnclaveQuotesDefaultResponse, + ListCollections200Response, + ListCollectionsDefaultResponse, + ListLedgerEntries200Response, + ListLedgerEntriesDefaultResponse, + CreateLedgerEntry200Response, + CreateLedgerEntryDefaultResponse, + GetLedgerEntry200Response, + GetLedgerEntryDefaultResponse, + GetReceipt200Response, + GetReceiptDefaultResponse, + GetTransactionStatus200Response, + GetTransactionStatusDefaultResponse, + GetCurrentLedgerEntry200Response, + GetCurrentLedgerEntryDefaultResponse, + DeleteUser204Response, + DeleteUserDefaultResponse, + GetUser200Response, + GetUserDefaultResponse, + CreateOrUpdateUser200Response, + CreateOrUpdateUserDefaultResponse, +} from "./responses.js"; + +const responseMap: Record = { + "GET /app/governance/constitution": ["200"], + "GET /app/governance/members": ["200"], + "GET /app/enclaveQuotes": ["200"], + "GET /app/collections": ["200"], + "GET /app/transactions": ["200"], + "POST /app/transactions": ["200"], + "GET /app/transactions/{transactionId}": ["200"], + "GET /app/transactions/{transactionId}/receipt": ["200"], + "GET /app/transactions/{transactionId}/status": ["200"], + "GET /app/transactions/current": ["200"], + "DELETE /app/users/{userId}": ["204"], + "GET /app/users/{userId}": ["200"], + "PATCH /app/users/{userId}": ["200"], +}; + +export function isUnexpected( + response: GetConstitution200Response | GetConstitutionDefaultResponse, +): response is GetConstitutionDefaultResponse; +export function isUnexpected( + response: ListConsortiumMembers200Response | ListConsortiumMembersDefaultResponse, +): response is ListConsortiumMembersDefaultResponse; +export function isUnexpected( + response: GetEnclaveQuotes200Response | GetEnclaveQuotesDefaultResponse, +): response is GetEnclaveQuotesDefaultResponse; +export function isUnexpected( + response: ListCollections200Response | ListCollectionsDefaultResponse, +): response is ListCollectionsDefaultResponse; +export function isUnexpected( + response: ListLedgerEntries200Response | ListLedgerEntriesDefaultResponse, +): response is ListLedgerEntriesDefaultResponse; +export function isUnexpected( + response: CreateLedgerEntry200Response | CreateLedgerEntryDefaultResponse, +): response is CreateLedgerEntryDefaultResponse; +export function isUnexpected( + response: GetLedgerEntry200Response | GetLedgerEntryDefaultResponse, +): response is GetLedgerEntryDefaultResponse; +export function isUnexpected( + response: GetReceipt200Response | GetReceiptDefaultResponse, +): response is GetReceiptDefaultResponse; +export function isUnexpected( + response: GetTransactionStatus200Response | GetTransactionStatusDefaultResponse, +): response is GetTransactionStatusDefaultResponse; +export function isUnexpected( + response: GetCurrentLedgerEntry200Response | GetCurrentLedgerEntryDefaultResponse, +): response is GetCurrentLedgerEntryDefaultResponse; +export function isUnexpected( + response: DeleteUser204Response | DeleteUserDefaultResponse, +): response is DeleteUserDefaultResponse; +export function isUnexpected( + response: GetUser200Response | GetUserDefaultResponse, +): response is GetUserDefaultResponse; +export function isUnexpected( + response: CreateOrUpdateUser200Response | CreateOrUpdateUserDefaultResponse, +): response is CreateOrUpdateUserDefaultResponse; +export function isUnexpected( + response: + | GetConstitution200Response + | GetConstitutionDefaultResponse + | ListConsortiumMembers200Response + | ListConsortiumMembersDefaultResponse + | GetEnclaveQuotes200Response + | GetEnclaveQuotesDefaultResponse + | ListCollections200Response + | ListCollectionsDefaultResponse + | ListLedgerEntries200Response + | ListLedgerEntriesDefaultResponse + | CreateLedgerEntry200Response + | CreateLedgerEntryDefaultResponse + | GetLedgerEntry200Response + | GetLedgerEntryDefaultResponse + | GetReceipt200Response + | GetReceiptDefaultResponse + | GetTransactionStatus200Response + | GetTransactionStatusDefaultResponse + | GetCurrentLedgerEntry200Response + | GetCurrentLedgerEntryDefaultResponse + | DeleteUser204Response + | DeleteUserDefaultResponse + | GetUser200Response + | GetUserDefaultResponse + | CreateOrUpdateUser200Response + | CreateOrUpdateUserDefaultResponse, +): response is + | GetConstitutionDefaultResponse + | ListConsortiumMembersDefaultResponse + | GetEnclaveQuotesDefaultResponse + | ListCollectionsDefaultResponse + | ListLedgerEntriesDefaultResponse + | CreateLedgerEntryDefaultResponse + | GetLedgerEntryDefaultResponse + | GetReceiptDefaultResponse + | GetTransactionStatusDefaultResponse + | GetCurrentLedgerEntryDefaultResponse + | DeleteUserDefaultResponse + | GetUserDefaultResponse + | CreateOrUpdateUserDefaultResponse { + const lroOriginal = response.headers["x-ms-original-url"]; + const url = new URL(lroOriginal ?? response.request.url); + const method = response.request.method; + let pathDetails = responseMap[`${method} ${url.pathname}`]; + if (!pathDetails) { + pathDetails = getParametrizedPathSuccess(method, url.pathname); + } + return !pathDetails.includes(response.status); +} + +function getParametrizedPathSuccess(method: string, path: string): string[] { + const pathParts = path.split("/"); + + // Traverse list to match the longest candidate + // matchedLen: the length of candidate path + // matchedValue: the matched status code array + let matchedLen = -1, + matchedValue: string[] = []; + + // Iterate the responseMap to find a match + for (const [key, value] of Object.entries(responseMap)) { + // Extracting the path from the map key which is in format + // GET /path/foo + if (!key.startsWith(method)) { + continue; + } + const candidatePath = getPathFromMapKey(key); + // Get each part of the url path + const candidateParts = candidatePath.split("/"); + + // 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) { + 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] || "", + ); + + if (!isMatched) { + found = false; + break; + } + continue; + } + + // If the candidate part is not a template and + // the parts don't match mark the candidate as not found + // to move on with the next candidate path. + if (candidateParts[i] !== pathParts[j]) { + found = false; + break; + } + } + + // We finished evaluating the current candidate parts + // Update the matched value if and only if we found the longer pattern + if (found && candidatePath.length > matchedLen) { + matchedLen = candidatePath.length; + matchedValue = value; + } + } + + return matchedValue; +} + +function getPathFromMapKey(mapKey: string): string { + const pathStart = mapKey.indexOf("/"); + return mapKey.slice(pathStart); +} diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/logger.ts b/sdk/confidentialledger/confidential-ledger-rest/src/logger.ts similarity index 100% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/logger.ts rename to sdk/confidentialledger/confidential-ledger-rest/src/logger.ts diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/models.ts b/sdk/confidentialledger/confidential-ledger-rest/src/models.ts similarity index 100% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/models.ts rename to sdk/confidentialledger/confidential-ledger-rest/src/models.ts diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/outputModels.ts b/sdk/confidentialledger/confidential-ledger-rest/src/outputModels.ts similarity index 100% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/outputModels.ts rename to sdk/confidentialledger/confidential-ledger-rest/src/outputModels.ts diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/paginateHelper.ts b/sdk/confidentialledger/confidential-ledger-rest/src/paginateHelper.ts similarity index 50% rename from sdk/confidentialledger/confidential-ledger-rest/src/generated/src/paginateHelper.ts rename to sdk/confidentialledger/confidential-ledger-rest/src/paginateHelper.ts index ecfdbc8ca60f..899f30811d31 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/src/generated/src/paginateHelper.ts +++ b/sdk/confidentialledger/confidential-ledger-rest/src/paginateHelper.ts @@ -1,16 +1,147 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { - getPagedAsyncIterator, - PagedAsyncIterableIterator, - PagedResult -} from "@azure/core-paging"; -import { - Client, - createRestError, - PathUncheckedResponse -} from "@azure-rest/core-client"; +import type { Client, PathUncheckedResponse } from "@azure-rest/core-client"; +import { createRestError } 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; + /** + * 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 @@ -20,10 +151,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; }>; @@ -71,7 +199,7 @@ export type PaginateReturn = TResult extends export function paginate( client: Client, initialResponse: TResponse, - options: PagingOptions = {} + options: PagingOptions = {}, ): PagedAsyncIterableIterator> { // Extract element type from initial response type TElement = PaginateReturn; @@ -87,18 +215,16 @@ 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); const values = getElements(result.body, itemName); return { page: values, - nextPageLink: nextLink + nextPageLink: nextLink, }; - } + }, }; return getPagedAsyncIterator(pagedResult); @@ -115,9 +241,7 @@ 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; @@ -134,7 +258,7 @@ function getElements(body: unknown, itemName: string): T[] { // type of elements in the page in PaginateReturn if (!Array.isArray(value)) { throw new Error( - `Couldn't paginate response\n Body doesn't contain an array property with name: ${itemName}` + `Couldn't paginate response\n Body doesn't contain an array property with name: ${itemName}`, ); } @@ -145,22 +269,11 @@ 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}`, - response + response, ); } } @@ -179,9 +292,7 @@ function getPaginationProperties(initialResponse: PathUncheckedResponse) { let itemName: string | undefined; for (const name of nextLinkNames) { - const nextLink = (initialResponse.body as Record)[ - name - ] as string; + const nextLink = (initialResponse.body as Record)[name] as string; if (nextLink) { nextLinkName = name; break; @@ -189,9 +300,7 @@ function getPaginationProperties(initialResponse: PathUncheckedResponse) { } for (const name of itemNames) { - const item = (initialResponse.body as Record)[ - name - ] as string; + const item = (initialResponse.body as Record)[name] as string; if (item) { itemName = name; break; @@ -201,8 +310,8 @@ function getPaginationProperties(initialResponse: PathUncheckedResponse) { if (!itemName) { throw new Error( `Couldn't paginate response\n Body doesn't contain an array property with name: ${[ - ...itemNames - ].join(" OR ")}` + ...itemNames, + ].join(" OR ")}`, ); } diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/parameters.ts b/sdk/confidentialledger/confidential-ledger-rest/src/parameters.ts new file mode 100644 index 000000000000..7160591bd389 --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/src/parameters.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { RequestParameters } from "@azure-rest/core-client"; +import type { LedgerEntry, LedgerUser } from "./models.js"; + +export type GetConstitutionParameters = RequestParameters; +export type ListConsortiumMembersParameters = RequestParameters; +export type GetEnclaveQuotesParameters = RequestParameters; +export type ListCollectionsParameters = RequestParameters; + +export interface ListLedgerEntriesQueryParamProperties { + /** The collection id. */ + collectionId?: string; + /** Specify the first transaction ID in a range. */ + fromTransactionId?: string; + /** Specify the last transaction ID in a range. */ + toTransactionId?: string; +} + +export interface ListLedgerEntriesQueryParam { + queryParameters?: ListLedgerEntriesQueryParamProperties; +} + +export type ListLedgerEntriesParameters = ListLedgerEntriesQueryParam & RequestParameters; + +export interface CreateLedgerEntryBodyParam { + /** Ledger entry. */ + body: LedgerEntry; +} + +export interface CreateLedgerEntryQueryParamProperties { + /** The collection id. */ + collectionId?: string; +} + +export interface CreateLedgerEntryQueryParam { + queryParameters?: CreateLedgerEntryQueryParamProperties; +} + +export interface CreateLedgerEntryMediaTypesParam { + /** Request content type */ + contentType?: "application/json"; +} + +export type CreateLedgerEntryParameters = CreateLedgerEntryQueryParam & + CreateLedgerEntryMediaTypesParam & + CreateLedgerEntryBodyParam & + RequestParameters; + +export interface GetLedgerEntryQueryParamProperties { + /** The collection id. */ + collectionId?: string; +} + +export interface GetLedgerEntryQueryParam { + queryParameters?: GetLedgerEntryQueryParamProperties; +} + +export type GetLedgerEntryParameters = GetLedgerEntryQueryParam & RequestParameters; +export type GetReceiptParameters = RequestParameters; +export type GetTransactionStatusParameters = RequestParameters; + +export interface GetCurrentLedgerEntryQueryParamProperties { + /** The collection id. */ + collectionId?: string; +} + +export interface GetCurrentLedgerEntryQueryParam { + queryParameters?: GetCurrentLedgerEntryQueryParamProperties; +} + +export type GetCurrentLedgerEntryParameters = GetCurrentLedgerEntryQueryParam & RequestParameters; +export type DeleteUserParameters = RequestParameters; +export type GetUserParameters = RequestParameters; +/** Details about a Confidential Ledger user. */ +export type LedgerUserResourceMergeAndPatch = Partial; + +export interface CreateOrUpdateUserBodyParam { + /** Details about a Confidential Ledger user. */ + body: LedgerUserResourceMergeAndPatch; +} + +export interface CreateOrUpdateUserMediaTypesParam { + /** Request content type */ + contentType?: "application/merge-patch+json"; +} + +export type CreateOrUpdateUserParameters = CreateOrUpdateUserMediaTypesParam & + CreateOrUpdateUserBodyParam & + RequestParameters; diff --git a/sdk/confidentialledger/confidential-ledger-rest/src/responses.ts b/sdk/confidentialledger/confidential-ledger-rest/src/responses.ts new file mode 100644 index 000000000000..9e1e5a37e2a0 --- /dev/null +++ b/sdk/confidentialledger/confidential-ledger-rest/src/responses.ts @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { RawHttpHeaders } from "@azure/core-rest-pipeline"; +import type { HttpResponse } from "@azure-rest/core-client"; +import type { + ConstitutionOutput, + ConfidentialLedgerErrorOutput, + ConsortiumOutput, + ConfidentialLedgerEnclavesOutput, + PagedCollectionsOutput, + PagedLedgerEntriesOutput, + LedgerWriteResultOutput, + LedgerQueryResultOutput, + TransactionReceiptOutput, + TransactionStatusOutput, + LedgerEntryOutput, + LedgerUserOutput, +} from "./outputModels.js"; + +/** The constitution is a script that assesses and applies proposals from consortium members. */ +export interface GetConstitution200Response extends HttpResponse { + status: "200"; + body: ConstitutionOutput; +} + +/** The constitution is a script that assesses and applies proposals from consortium members. */ +export interface GetConstitutionDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** Consortium members can manage the Confidential Ledger. */ +export interface ListConsortiumMembers200Response extends HttpResponse { + status: "200"; + body: ConsortiumOutput; +} + +/** Consortium members can manage the Confidential Ledger. */ +export interface ListConsortiumMembersDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** A quote is an SGX enclave measurement that can be used to verify the validity of a node and its enclave. */ +export interface GetEnclaveQuotes200Response extends HttpResponse { + status: "200"; + body: ConfidentialLedgerEnclavesOutput; +} + +/** A quote is an SGX enclave measurement that can be used to verify the validity of a node and its enclave. */ +export interface GetEnclaveQuotesDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** Collection ids are user-created collections of ledger entries */ +export interface ListCollections200Response extends HttpResponse { + status: "200"; + body: PagedCollectionsOutput; +} + +/** Collection ids are user-created collections of ledger entries */ +export interface ListCollectionsDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** A collection id may optionally be specified. Only entries in the specified (or default) collection will be returned. */ +export interface ListLedgerEntries200Response extends HttpResponse { + status: "200"; + body: PagedLedgerEntriesOutput; +} + +/** A collection id may optionally be specified. Only entries in the specified (or default) collection will be returned. */ +export interface ListLedgerEntriesDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +export interface CreateLedgerEntry200Headers { + /** The transaction id at which this write will become durable. */ + "x-ms-ccf-transaction-id"?: string; +} + +/** A collection id may optionally be specified. */ +export interface CreateLedgerEntry200Response extends HttpResponse { + status: "200"; + body: LedgerWriteResultOutput; + headers: RawHttpHeaders & CreateLedgerEntry200Headers; +} + +/** A collection id may optionally be specified. */ +export interface CreateLedgerEntryDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** To return older ledger entries, the relevant sections of the ledger must be read from disk and validated. To prevent blocking within the enclave, the response will indicate whether the entry is ready and part of the response, or if the loading is still ongoing. */ +export interface GetLedgerEntry200Response extends HttpResponse { + status: "200"; + body: LedgerQueryResultOutput; +} + +/** To return older ledger entries, the relevant sections of the ledger must be read from disk and validated. To prevent blocking within the enclave, the response will indicate whether the entry is ready and part of the response, or if the loading is still ongoing. */ +export interface GetLedgerEntryDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** Gets a receipt certifying ledger contents at a particular transaction id. */ +export interface GetReceipt200Response extends HttpResponse { + status: "200"; + body: TransactionReceiptOutput; +} + +/** Gets a receipt certifying ledger contents at a particular transaction id. */ +export interface GetReceiptDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** Gets the status of an entry identified by a transaction id. */ +export interface GetTransactionStatus200Response extends HttpResponse { + status: "200"; + body: TransactionStatusOutput; +} + +/** Gets the status of an entry identified by a transaction id. */ +export interface GetTransactionStatusDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** A collection id may optionally be specified. */ +export interface GetCurrentLedgerEntry200Response extends HttpResponse { + status: "200"; + body: LedgerEntryOutput; +} + +/** A collection id may optionally be specified. */ +export interface GetCurrentLedgerEntryDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** Deletes a user from the Confidential Ledger. */ +export interface DeleteUser204Response extends HttpResponse { + status: "204"; +} + +/** Deletes a user from the Confidential Ledger. */ +export interface DeleteUserDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** Gets a user. */ +export interface GetUser200Response extends HttpResponse { + status: "200"; + body: LedgerUserOutput; +} + +/** Gets a user. */ +export interface GetUserDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} + +/** A JSON merge patch is applied for existing users */ +export interface CreateOrUpdateUser200Response extends HttpResponse { + status: "200"; + body: LedgerUserOutput; +} + +/** A JSON merge patch is applied for existing users */ +export interface CreateOrUpdateUserDefaultResponse extends HttpResponse { + status: string; + body: ConfidentialLedgerErrorOutput; +} diff --git a/sdk/confidentialledger/confidential-ledger-rest/swagger/README.md b/sdk/confidentialledger/confidential-ledger-rest/swagger/README.md index 58cddb7430b9..8f9f084b6bbb 100644 --- a/sdk/confidentialledger/confidential-ledger-rest/swagger/README.md +++ b/sdk/confidentialledger/confidential-ledger-rest/swagger/README.md @@ -5,12 +5,16 @@ ## Configuration ```yaml +flavor: azure +openapi-type: data-plane +generate-test: true package-name: "@azure-rest/confidential-ledger" title: ConfidentialLedger description: The ConfidentialLedgerClient writes and retrieves ledger entries against the Confidential Ledger service. generate-metadata: false license-header: MICROSOFT_MIT_NO_VERSION -output-folder: ../src/generated +output-folder: ../ +source-code-folder-path: ../generated input-file: https://github.com/Azure/azure-rest-api-specs/blob/main/specification/confidentialledger/data-plane/Microsoft.ConfidentialLedger/stable/2022-05-13/confidentialledger.json package-version: 1.0.1 hide-clients: true @@ -18,7 +22,7 @@ rest-level-client: true security: "AADToken" security-scopes: "https://confidential-ledger.azure.com/.default" use-extension: - "@autorest/typescript": "6.0.5" + "@autorest/typescript": "latest" ``` ```yaml