diff --git a/.changeset/great-lemons-draw.md b/.changeset/great-lemons-draw.md new file mode 100644 index 00000000000..0565788e54a --- /dev/null +++ b/.changeset/great-lemons-draw.md @@ -0,0 +1,5 @@ +--- +"@audius/sdk": minor +--- + +Add register dev app key endpoint diff --git a/packages/sdk/src/sdk/api/developer-apps/DeveloperAppsApi.ts b/packages/sdk/src/sdk/api/developer-apps/DeveloperAppsApi.ts index 633ad1fcf78..d2296a586d4 100644 --- a/packages/sdk/src/sdk/api/developer-apps/DeveloperAppsApi.ts +++ b/packages/sdk/src/sdk/api/developer-apps/DeveloperAppsApi.ts @@ -96,12 +96,22 @@ export class DeveloperAppsApi extends GeneratedDeveloperAppsApi { ? (privateKey as string).slice(2).toLowerCase() : (privateKey as string).toLowerCase() - // Create api_access_key for the relay-created app (user from auth headers; indexer may lag, so retry) - const bearerToken = await this.createAccessKeyWithRetry({ + await this.registerDeveloperAppAPIKey({ address, - userId: userId.toString() + userId: userId.toString(), + metadata: { apiSecret } }) + const path = `/developer-apps/${encodeURIComponent(address)}/access-keys` + const res = await this.request({ + path, + method: 'POST', + headers: {}, + query: { user_id: userId.toString() } + }) + const json = (await res.json()) as { api_access_key: string } + const bearerToken = json.api_access_key ?? '' + return { ...response, apiKey, @@ -111,45 +121,6 @@ export class DeveloperAppsApi extends GeneratedDeveloperAppsApi { } } - /** - * Call POST /developer-apps/{address}/access-keys to create the first api_access_key - * for a relay-created app. User is identified from request auth headers. Retries on 404 - * while indexer processes the CreateDeveloperApp tx. - */ - private async createAccessKeyWithRetry(params: { - address: string - userId: string - }): Promise { - const { address, userId } = params - const maxAttempts = 5 - const delayMs = 2000 - - for (let attempt = 1; attempt <= maxAttempts; attempt++) { - try { - const path = `/developer-apps/${encodeURIComponent(address)}/access-keys` - const res = await this.request({ - path, - method: 'POST', - headers: {}, - query: { user_id: userId } - }) - const json = (await res.json()) as { api_access_key: string } - return json.api_access_key ?? '' - } catch (e: unknown) { - const status = - e && typeof e === 'object' && 'response' in e - ? (e as { response?: { status?: number } }).response?.status - : undefined - if (status === 404 && attempt < maxAttempts) { - await new Promise((resolve) => setTimeout(resolve, delayMs)) - continue - } - throw e - } - } - return '' - } - /** * Get developer apps with api_access_keys (bearer tokens). * Uses include=metrics to fetch bearer tokens from the API. diff --git a/packages/sdk/src/sdk/api/generated/default/.openapi-generator/FILES b/packages/sdk/src/sdk/api/generated/default/.openapi-generator/FILES index cfb055e06a1..19e7a47e8af 100644 --- a/packages/sdk/src/sdk/api/generated/default/.openapi-generator/FILES +++ b/packages/sdk/src/sdk/api/generated/default/.openapi-generator/FILES @@ -250,6 +250,8 @@ models/ReceiveTipNotification.ts models/ReceiveTipNotificationAction.ts models/ReceiveTipNotificationActionData.ts models/RedeemAmountResponse.ts +models/RegisterApiKeyRequestBody.ts +models/RegisterApiKeyResponse.ts models/Related.ts models/RelatedArtistResponse.ts models/Remix.ts diff --git a/packages/sdk/src/sdk/api/generated/default/apis/DeveloperAppsApi.ts b/packages/sdk/src/sdk/api/generated/default/apis/DeveloperAppsApi.ts index 55c1b45ea4f..594b5926914 100644 --- a/packages/sdk/src/sdk/api/generated/default/apis/DeveloperAppsApi.ts +++ b/packages/sdk/src/sdk/api/generated/default/apis/DeveloperAppsApi.ts @@ -23,6 +23,8 @@ import type { DeactivateAccessKeyResponse, DeveloperAppResponse, DeveloperAppsResponse, + RegisterApiKeyRequestBody, + RegisterApiKeyResponse, UpdateDeveloperAppRequestBody, WriteResponse, } from '../models'; @@ -41,6 +43,10 @@ import { DeveloperAppResponseToJSON, DeveloperAppsResponseFromJSON, DeveloperAppsResponseToJSON, + RegisterApiKeyRequestBodyFromJSON, + RegisterApiKeyRequestBodyToJSON, + RegisterApiKeyResponseFromJSON, + RegisterApiKeyResponseToJSON, UpdateDeveloperAppRequestBodyFromJSON, UpdateDeveloperAppRequestBodyToJSON, WriteResponseFromJSON, @@ -77,6 +83,12 @@ export interface GetDeveloperAppsRequest { include?: GetDeveloperAppsIncludeEnum; } +export interface RegisterDeveloperAppAPIKeyRequest { + userId: string; + address: string; + metadata: RegisterApiKeyRequestBody; +} + export interface UpdateDeveloperAppRequest { userId: string; address: string; @@ -320,6 +332,63 @@ export class DeveloperAppsApi extends runtime.BaseAPI { return await response.value(); } + /** + * @hidden + * Register api_key and api_secret in api_keys table for developer apps created via entity manager transactions. Use when the client sends raw ManageEntity tx instead of POST /developer-apps. Inserts with rps=10, rpm=500000. Requires the app to exist in developer_apps and belong to the authenticated user. + */ + async registerDeveloperAppAPIKeyRaw(params: RegisterDeveloperAppAPIKeyRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + if (params.userId === null || params.userId === undefined) { + throw new runtime.RequiredError('userId','Required parameter params.userId was null or undefined when calling registerDeveloperAppAPIKey.'); + } + + if (params.address === null || params.address === undefined) { + throw new runtime.RequiredError('address','Required parameter params.address was null or undefined when calling registerDeveloperAppAPIKey.'); + } + + if (params.metadata === null || params.metadata === undefined) { + throw new runtime.RequiredError('metadata','Required parameter params.metadata was null or undefined when calling registerDeveloperAppAPIKey.'); + } + + const queryParameters: any = {}; + + if (params.userId !== undefined) { + queryParameters['user_id'] = params.userId; + } + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && (this.configuration.username !== undefined || this.configuration.password !== undefined)) { + headerParameters["Authorization"] = "Basic " + btoa(this.configuration.username + ":" + this.configuration.password); + } + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token("BearerAuth", []); + + if (tokenString) { + headerParameters["Authorization"] = `Bearer ${tokenString}`; + } + } + const response = await this.request({ + path: `/developer-apps/{address}/register-api-key`.replace(`{${"address"}}`, encodeURIComponent(String(params.address))), + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: RegisterApiKeyRequestBodyToJSON(params.metadata), + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => RegisterApiKeyResponseFromJSON(jsonValue)); + } + + /** + * Register api_key and api_secret in api_keys table for developer apps created via entity manager transactions. Use when the client sends raw ManageEntity tx instead of POST /developer-apps. Inserts with rps=10, rpm=500000. Requires the app to exist in developer_apps and belong to the authenticated user. + */ + async registerDeveloperAppAPIKey(params: RegisterDeveloperAppAPIKeyRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.registerDeveloperAppAPIKeyRaw(params, initOverrides); + return await response.value(); + } + /** * @hidden * Updates a developer app. Indexer validates grants. diff --git a/packages/sdk/src/sdk/api/generated/default/models/RegisterApiKeyRequestBody.ts b/packages/sdk/src/sdk/api/generated/default/models/RegisterApiKeyRequestBody.ts new file mode 100644 index 00000000000..1663e694b28 --- /dev/null +++ b/packages/sdk/src/sdk/api/generated/default/models/RegisterApiKeyRequestBody.ts @@ -0,0 +1,67 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck +/** + * API + * Audius V1 API + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface RegisterApiKeyRequestBody + */ +export interface RegisterApiKeyRequestBody { + /** + * The API secret (private key hex) for the developer app + * @type {string} + * @memberof RegisterApiKeyRequestBody + */ + apiSecret: string; +} + +/** + * Check if a given object implements the RegisterApiKeyRequestBody interface. + */ +export function instanceOfRegisterApiKeyRequestBody(value: object): value is RegisterApiKeyRequestBody { + let isInstance = true; + isInstance = isInstance && "apiSecret" in value && value["apiSecret"] !== undefined; + + return isInstance; +} + +export function RegisterApiKeyRequestBodyFromJSON(json: any): RegisterApiKeyRequestBody { + return RegisterApiKeyRequestBodyFromJSONTyped(json, false); +} + +export function RegisterApiKeyRequestBodyFromJSONTyped(json: any, ignoreDiscriminator: boolean): RegisterApiKeyRequestBody { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'apiSecret': json['api_secret'], + }; +} + +export function RegisterApiKeyRequestBodyToJSON(value?: RegisterApiKeyRequestBody | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'api_secret': value.apiSecret, + }; +} + diff --git a/packages/sdk/src/sdk/api/generated/default/models/RegisterApiKeyResponse.ts b/packages/sdk/src/sdk/api/generated/default/models/RegisterApiKeyResponse.ts new file mode 100644 index 00000000000..dae75ab5f1f --- /dev/null +++ b/packages/sdk/src/sdk/api/generated/default/models/RegisterApiKeyResponse.ts @@ -0,0 +1,66 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck +/** + * API + * Audius V1 API + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface RegisterApiKeyResponse + */ +export interface RegisterApiKeyResponse { + /** + * Whether the registration was successful + * @type {boolean} + * @memberof RegisterApiKeyResponse + */ + success?: boolean; +} + +/** + * Check if a given object implements the RegisterApiKeyResponse interface. + */ +export function instanceOfRegisterApiKeyResponse(value: object): value is RegisterApiKeyResponse { + let isInstance = true; + + return isInstance; +} + +export function RegisterApiKeyResponseFromJSON(json: any): RegisterApiKeyResponse { + return RegisterApiKeyResponseFromJSONTyped(json, false); +} + +export function RegisterApiKeyResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): RegisterApiKeyResponse { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'success': !exists(json, 'success') ? undefined : json['success'], + }; +} + +export function RegisterApiKeyResponseToJSON(value?: RegisterApiKeyResponse | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'success': value.success, + }; +} + diff --git a/packages/sdk/src/sdk/api/generated/default/models/index.ts b/packages/sdk/src/sdk/api/generated/default/models/index.ts index 9b774e08134..74942aafb1d 100644 --- a/packages/sdk/src/sdk/api/generated/default/models/index.ts +++ b/packages/sdk/src/sdk/api/generated/default/models/index.ts @@ -229,6 +229,8 @@ export * from './ReceiveTipNotification'; export * from './ReceiveTipNotificationAction'; export * from './ReceiveTipNotificationActionData'; export * from './RedeemAmountResponse'; +export * from './RegisterApiKeyRequestBody'; +export * from './RegisterApiKeyResponse'; export * from './Related'; export * from './RelatedArtistResponse'; export * from './Remix';