@oxyhq/core 2.4.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,511 @@
1
+ /**
2
+ * Applications Methods Mixin
3
+ *
4
+ * Provides methods for managing Oxy applications, their members, and their
5
+ * credentials via the `/applications` API. An application is a multi-user
6
+ * entity: membership (with a role) grants permissions; credentials
7
+ * (public/confidential/service) carry OAuth client identifiers and the
8
+ * service-token API key material.
9
+ *
10
+ * Reference applications by their Mongo `_id` (`applicationId`) and credentials
11
+ * by their `credentialId`. Never by name.
12
+ */
13
+ import type { OxyServicesBase } from '../OxyServices.base';
14
+ import { CACHE_TIMES } from './mixinHelpers';
15
+
16
+ /**
17
+ * Application classification. Set only by Oxy platform staff — never editable
18
+ * through the normal member-facing update path.
19
+ */
20
+ export type ApplicationType = 'first_party' | 'third_party' | 'internal' | 'system';
21
+
22
+ /** Lifecycle status of an application. */
23
+ export type ApplicationStatus = 'active' | 'suspended' | 'deleted' | 'pending_review';
24
+
25
+ /** Role a member holds within an application. */
26
+ export type ApplicationRole = 'owner' | 'admin' | 'developer' | 'viewer' | 'billing';
27
+
28
+ /** Membership lifecycle status. */
29
+ export type ApplicationMemberStatus = 'active' | 'invited' | 'removed';
30
+
31
+ /** Credential kind. `service` credentials mint service tokens. */
32
+ export type ApplicationCredentialType = 'public' | 'confidential' | 'service';
33
+
34
+ /** Deployment environment a credential is scoped to. */
35
+ export type ApplicationEnvironment = 'development' | 'staging' | 'production';
36
+
37
+ /** Credential lifecycle status. */
38
+ export type ApplicationCredentialStatus = 'active' | 'deprecated' | 'revoked';
39
+
40
+ /**
41
+ * Client-facing Application shape returned by the `/applications` API.
42
+ * Mirrors the server `Application` model with `_id` as a string and dates
43
+ * serialized to ISO strings.
44
+ */
45
+ export interface Application {
46
+ _id: string;
47
+ name: string;
48
+ description?: string;
49
+ websiteUrl?: string;
50
+ icon?: string;
51
+ type: ApplicationType;
52
+ status: ApplicationStatus;
53
+ isOfficial: boolean;
54
+ isInternal: boolean;
55
+ capabilities: string[];
56
+ redirectUris: string[];
57
+ scopes: string[];
58
+ webhookUrl?: string;
59
+ devWebhookUrl?: string;
60
+ createdByUserId: string;
61
+ createdAt: string;
62
+ updatedAt: string;
63
+ /**
64
+ * The calling user's own membership in this application, embedded by the API
65
+ * on list (`GET /applications`) and detail (`GET /applications/:appId`)
66
+ * responses. Use `callerMembership.permissions` to gate UI affordances.
67
+ */
68
+ callerMembership?: ApplicationMember;
69
+ }
70
+
71
+ /**
72
+ * Client-facing ApplicationMember shape. `permissions` is derived from `role`
73
+ * on the server at write time.
74
+ */
75
+ export interface ApplicationMember {
76
+ _id: string;
77
+ applicationId: string;
78
+ userId: string;
79
+ role: ApplicationRole;
80
+ permissions: string[];
81
+ invitedByUserId?: string;
82
+ joinedAt?: string;
83
+ status: ApplicationMemberStatus;
84
+ createdAt: string;
85
+ updatedAt: string;
86
+ }
87
+
88
+ /**
89
+ * Client-facing ApplicationCredential shape. The raw secret is NEVER part of
90
+ * this shape — it is returned exactly once, separately, at creation/rotation.
91
+ */
92
+ export interface ApplicationCredential {
93
+ _id: string;
94
+ applicationId: string;
95
+ name: string;
96
+ publicKey: string;
97
+ type: ApplicationCredentialType;
98
+ environment: ApplicationEnvironment;
99
+ scopes: string[];
100
+ status: ApplicationCredentialStatus;
101
+ lastUsedAt?: string;
102
+ expiresAt?: string;
103
+ createdByUserId: string;
104
+ createdAt: string;
105
+ updatedAt: string;
106
+ }
107
+
108
+ /** Input accepted by `createApplication`. Staff-only fields are not settable here. */
109
+ export interface CreateApplicationInput {
110
+ name: string;
111
+ description?: string;
112
+ websiteUrl?: string;
113
+ icon?: string;
114
+ redirectUris?: string[];
115
+ scopes?: string[];
116
+ }
117
+
118
+ /** Input accepted by `updateApplication`. Staff-only fields are not settable here. */
119
+ export interface UpdateApplicationInput {
120
+ name?: string;
121
+ description?: string;
122
+ websiteUrl?: string;
123
+ icon?: string;
124
+ redirectUris?: string[];
125
+ scopes?: string[];
126
+ webhookUrl?: string;
127
+ devWebhookUrl?: string;
128
+ status?: ApplicationStatus;
129
+ }
130
+
131
+ /** Input accepted by `inviteApplicationMember`. The owner role cannot be invited. */
132
+ export interface InviteApplicationMemberInput {
133
+ userId: string;
134
+ role: Exclude<ApplicationRole, 'owner'>;
135
+ }
136
+
137
+ /** Input accepted by `updateApplicationMember`. */
138
+ export interface UpdateApplicationMemberInput {
139
+ role: ApplicationRole;
140
+ }
141
+
142
+ /** Input accepted by `transferApplicationOwnership`. */
143
+ export interface TransferApplicationOwnershipInput {
144
+ userId: string;
145
+ }
146
+
147
+ /** Input accepted by `createApplicationCredential`. */
148
+ export interface CreateApplicationCredentialInput {
149
+ name: string;
150
+ type: ApplicationCredentialType;
151
+ environment: ApplicationEnvironment;
152
+ scopes?: string[];
153
+ }
154
+
155
+ /** Result of creating or rotating a credential — `secret` is returned ONCE. */
156
+ export interface ApplicationCredentialWithSecret {
157
+ credential: ApplicationCredential;
158
+ secret: string;
159
+ }
160
+
161
+ /** Time window for application usage statistics. */
162
+ export type ApplicationUsagePeriod = '24h' | '7d' | '30d' | '90d';
163
+
164
+ /** Aggregate totals for an application over the requested period. */
165
+ export interface ApplicationUsageSummary {
166
+ totalRequests: number;
167
+ totalTokens: number;
168
+ totalCredits: number;
169
+ avgResponseTime: number;
170
+ successfulRequests: number;
171
+ errorRequests: number;
172
+ }
173
+
174
+ /** Per-day usage bucket. `_id` is the day key (e.g. `YYYY-MM-DD`). */
175
+ export interface ApplicationUsageByDay {
176
+ _id: string;
177
+ requests: number;
178
+ tokens: number;
179
+ credits: number;
180
+ }
181
+
182
+ /** Per-endpoint usage bucket. `_id` is the endpoint identifier. */
183
+ export interface ApplicationUsageByEndpoint {
184
+ _id: string;
185
+ requests: number;
186
+ tokens: number;
187
+ }
188
+
189
+ /** Usage statistics for an application over a period. */
190
+ export interface ApplicationUsageStats {
191
+ summary: ApplicationUsageSummary;
192
+ byDay: ApplicationUsageByDay[];
193
+ byEndpoint: ApplicationUsageByEndpoint[];
194
+ }
195
+
196
+ /** Result of a delete/remove/revoke/transfer operation. */
197
+ export interface ApplicationSuccessResult {
198
+ success: boolean;
199
+ }
200
+
201
+ export function OxyServicesApplicationsMixin<T extends typeof OxyServicesBase>(Base: T) {
202
+ return class extends Base {
203
+ constructor(...args: any[]) {
204
+ super(...(args as [any]));
205
+ }
206
+
207
+ /**
208
+ * List applications the current user is an active member of.
209
+ */
210
+ async getApplications(): Promise<Application[]> {
211
+ try {
212
+ const res = await this.makeRequest<{ applications?: Application[] }>(
213
+ 'GET',
214
+ '/applications',
215
+ undefined,
216
+ { cache: true, cacheTTL: CACHE_TIMES.MEDIUM },
217
+ );
218
+ return res.applications ?? [];
219
+ } catch (error) {
220
+ throw this.handleError(error);
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Create a new application. The caller becomes its `owner`.
226
+ * @param data - Application configuration. Staff-only fields are ignored.
227
+ */
228
+ async createApplication(data: CreateApplicationInput): Promise<Application> {
229
+ try {
230
+ const res = await this.makeRequest<{ application: Application }>(
231
+ 'POST',
232
+ '/applications',
233
+ data,
234
+ { cache: false },
235
+ );
236
+ return res.application;
237
+ } catch (error) {
238
+ throw this.handleError(error);
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Fetch a single application by id.
244
+ * @param applicationId - The application's Mongo `_id`.
245
+ */
246
+ async getApplication(applicationId: string): Promise<Application> {
247
+ try {
248
+ const res = await this.makeRequest<{ application: Application }>(
249
+ 'GET',
250
+ `/applications/${applicationId}`,
251
+ undefined,
252
+ { cache: true, cacheTTL: CACHE_TIMES.LONG },
253
+ );
254
+ return res.application;
255
+ } catch (error) {
256
+ throw this.handleError(error);
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Update an application's mutable fields.
262
+ * @param applicationId - The application's Mongo `_id`.
263
+ * @param data - Subset of updatable fields. Staff-only fields are ignored.
264
+ */
265
+ async updateApplication(
266
+ applicationId: string,
267
+ data: UpdateApplicationInput,
268
+ ): Promise<Application> {
269
+ try {
270
+ const res = await this.makeRequest<{ application: Application }>(
271
+ 'PATCH',
272
+ `/applications/${applicationId}`,
273
+ data,
274
+ { cache: false },
275
+ );
276
+ return res.application;
277
+ } catch (error) {
278
+ throw this.handleError(error);
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Soft-delete an application (owner only).
284
+ * @param applicationId - The application's Mongo `_id`.
285
+ */
286
+ async deleteApplication(applicationId: string): Promise<ApplicationSuccessResult> {
287
+ try {
288
+ return await this.makeRequest<ApplicationSuccessResult>(
289
+ 'DELETE',
290
+ `/applications/${applicationId}`,
291
+ undefined,
292
+ { cache: false },
293
+ );
294
+ } catch (error) {
295
+ throw this.handleError(error);
296
+ }
297
+ }
298
+
299
+ /**
300
+ * List members of an application.
301
+ * @param applicationId - The application's Mongo `_id`.
302
+ */
303
+ async getApplicationMembers(applicationId: string): Promise<ApplicationMember[]> {
304
+ try {
305
+ const res = await this.makeRequest<{ members?: ApplicationMember[] }>(
306
+ 'GET',
307
+ `/applications/${applicationId}/members`,
308
+ undefined,
309
+ { cache: true, cacheTTL: CACHE_TIMES.MEDIUM },
310
+ );
311
+ return res.members ?? [];
312
+ } catch (error) {
313
+ throw this.handleError(error);
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Add a member to an application.
319
+ * @param applicationId - The application's Mongo `_id`.
320
+ * @param data - Target user id and role (never `owner`).
321
+ */
322
+ async inviteApplicationMember(
323
+ applicationId: string,
324
+ data: InviteApplicationMemberInput,
325
+ ): Promise<ApplicationMember> {
326
+ try {
327
+ const res = await this.makeRequest<{ member: ApplicationMember }>(
328
+ 'POST',
329
+ `/applications/${applicationId}/members`,
330
+ data,
331
+ { cache: false },
332
+ );
333
+ return res.member;
334
+ } catch (error) {
335
+ throw this.handleError(error);
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Change a member's role.
341
+ * @param applicationId - The application's Mongo `_id`.
342
+ * @param memberId - The member's Mongo `_id`.
343
+ * @param data - New role.
344
+ */
345
+ async updateApplicationMember(
346
+ applicationId: string,
347
+ memberId: string,
348
+ data: UpdateApplicationMemberInput,
349
+ ): Promise<ApplicationMember> {
350
+ try {
351
+ const res = await this.makeRequest<{ member: ApplicationMember }>(
352
+ 'PATCH',
353
+ `/applications/${applicationId}/members/${memberId}`,
354
+ data,
355
+ { cache: false },
356
+ );
357
+ return res.member;
358
+ } catch (error) {
359
+ throw this.handleError(error);
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Remove a member from an application.
365
+ * @param applicationId - The application's Mongo `_id`.
366
+ * @param memberId - The member's Mongo `_id`.
367
+ */
368
+ async removeApplicationMember(
369
+ applicationId: string,
370
+ memberId: string,
371
+ ): Promise<ApplicationSuccessResult> {
372
+ try {
373
+ return await this.makeRequest<ApplicationSuccessResult>(
374
+ 'DELETE',
375
+ `/applications/${applicationId}/members/${memberId}`,
376
+ undefined,
377
+ { cache: false },
378
+ );
379
+ } catch (error) {
380
+ throw this.handleError(error);
381
+ }
382
+ }
383
+
384
+ /**
385
+ * Transfer ownership of an application to another member (owner only).
386
+ * Demotes the current owner to `admin` and promotes the target to `owner`.
387
+ * @param applicationId - The application's Mongo `_id`.
388
+ * @param data - Target user id.
389
+ */
390
+ async transferApplicationOwnership(
391
+ applicationId: string,
392
+ data: TransferApplicationOwnershipInput,
393
+ ): Promise<ApplicationSuccessResult> {
394
+ try {
395
+ return await this.makeRequest<ApplicationSuccessResult>(
396
+ 'POST',
397
+ `/applications/${applicationId}/transfer-ownership`,
398
+ data,
399
+ { cache: false },
400
+ );
401
+ } catch (error) {
402
+ throw this.handleError(error);
403
+ }
404
+ }
405
+
406
+ /**
407
+ * List an application's credentials. The response NEVER includes secrets.
408
+ * @param applicationId - The application's Mongo `_id`.
409
+ */
410
+ async getApplicationCredentials(applicationId: string): Promise<ApplicationCredential[]> {
411
+ try {
412
+ const res = await this.makeRequest<{ credentials?: ApplicationCredential[] }>(
413
+ 'GET',
414
+ `/applications/${applicationId}/credentials`,
415
+ undefined,
416
+ { cache: true, cacheTTL: CACHE_TIMES.MEDIUM },
417
+ );
418
+ return res.credentials ?? [];
419
+ } catch (error) {
420
+ throw this.handleError(error);
421
+ }
422
+ }
423
+
424
+ /**
425
+ * Create a credential. The plaintext `secret` is returned exactly ONCE;
426
+ * the server stores only a hash and will never return it again.
427
+ * @param applicationId - The application's Mongo `_id`.
428
+ * @param data - Credential configuration.
429
+ */
430
+ async createApplicationCredential(
431
+ applicationId: string,
432
+ data: CreateApplicationCredentialInput,
433
+ ): Promise<ApplicationCredentialWithSecret> {
434
+ try {
435
+ return await this.makeRequest<ApplicationCredentialWithSecret>(
436
+ 'POST',
437
+ `/applications/${applicationId}/credentials`,
438
+ data,
439
+ { cache: false },
440
+ );
441
+ } catch (error) {
442
+ throw this.handleError(error);
443
+ }
444
+ }
445
+
446
+ /**
447
+ * Rotate a credential's secret. The new plaintext `secret` is returned
448
+ * exactly ONCE.
449
+ * @param applicationId - The application's Mongo `_id`.
450
+ * @param credentialId - The credential's Mongo `_id`.
451
+ */
452
+ async rotateApplicationCredential(
453
+ applicationId: string,
454
+ credentialId: string,
455
+ ): Promise<ApplicationCredentialWithSecret> {
456
+ try {
457
+ return await this.makeRequest<ApplicationCredentialWithSecret>(
458
+ 'POST',
459
+ `/applications/${applicationId}/credentials/${credentialId}/rotate`,
460
+ undefined,
461
+ { cache: false },
462
+ );
463
+ } catch (error) {
464
+ throw this.handleError(error);
465
+ }
466
+ }
467
+
468
+ /**
469
+ * Revoke a credential (`status='revoked'`). Revoked credentials can no
470
+ * longer authenticate.
471
+ * @param applicationId - The application's Mongo `_id`.
472
+ * @param credentialId - The credential's Mongo `_id`.
473
+ */
474
+ async revokeApplicationCredential(
475
+ applicationId: string,
476
+ credentialId: string,
477
+ ): Promise<ApplicationSuccessResult> {
478
+ try {
479
+ return await this.makeRequest<ApplicationSuccessResult>(
480
+ 'DELETE',
481
+ `/applications/${applicationId}/credentials/${credentialId}`,
482
+ undefined,
483
+ { cache: false },
484
+ );
485
+ } catch (error) {
486
+ throw this.handleError(error);
487
+ }
488
+ }
489
+
490
+ /**
491
+ * Fetch usage statistics for an application.
492
+ * @param applicationId - The application's Mongo `_id`.
493
+ * @param period - Time window (defaults to the server default).
494
+ */
495
+ async getApplicationUsage(
496
+ applicationId: string,
497
+ period?: ApplicationUsagePeriod,
498
+ ): Promise<ApplicationUsageStats> {
499
+ try {
500
+ return await this.makeRequest<ApplicationUsageStats>(
501
+ 'GET',
502
+ `/applications/${applicationId}/usage`,
503
+ period ? { period } : undefined,
504
+ { cache: true, cacheTTL: CACHE_TIMES.SHORT },
505
+ );
506
+ } catch (error) {
507
+ throw this.handleError(error);
508
+ }
509
+ }
510
+ };
511
+ }
@@ -157,8 +157,8 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
157
157
  * legitimate multi-tenant hosts that need to switch credentials cannot leak
158
158
  * one tenant's token to another tenant on the same instance.
159
159
  *
160
- * @param apiKey - DeveloperApp API key (oxy_dk_*)
161
- * @param apiSecret - DeveloperApp API secret
160
+ * @param apiKey - Application credential public key (oxy_dk_*)
161
+ * @param apiSecret - Application credential secret
162
162
  */
163
163
  configureServiceAuth(apiKey: string, apiSecret: string): void {
164
164
  this._serviceApiKey = apiKey;
@@ -181,8 +181,8 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
181
181
  * This prevents an attacker who learned a peer's apiKey from extracting
182
182
  * their service token by polling with a wrong secret.
183
183
  *
184
- * @param apiKey - DeveloperApp API key (optional if configureServiceAuth was called)
185
- * @param apiSecret - DeveloperApp API secret (optional if configureServiceAuth was called)
184
+ * @param apiKey - Application credential public key (optional if configureServiceAuth was called)
185
+ * @param apiSecret - Application credential secret (optional if configureServiceAuth was called)
186
186
  */
187
187
  async getServiceToken(apiKey?: string, apiSecret?: string): Promise<string> {
188
188
  const key = apiKey || this._serviceApiKey;
@@ -54,7 +54,7 @@ export interface ServiceActingAsVerification {
54
54
  /**
55
55
  * Service app metadata attached to requests authenticated with service tokens.
56
56
  * `scopes` reflects the scopes granted to the app at signup time (from the
57
- * `DeveloperApp.scopes` field); route-level checks can require additional
57
+ * `Application.scopes` field); route-level checks can require additional
58
58
  * scope-narrowing via `requireScope()`.
59
59
  */
60
60
  export interface ServiceApp {
@@ -17,7 +17,7 @@ import { OxyServicesLanguageMixin } from './OxyServices.language';
17
17
  import { OxyServicesPaymentMixin } from './OxyServices.payment';
18
18
  import { OxyServicesKarmaMixin } from './OxyServices.karma';
19
19
  import { OxyServicesAssetsMixin } from './OxyServices.assets';
20
- import { OxyServicesDeveloperMixin } from './OxyServices.developer';
20
+ import { OxyServicesApplicationsMixin } from './OxyServices.applications';
21
21
  import { OxyServicesLocationMixin } from './OxyServices.location';
22
22
  import { OxyServicesAnalyticsMixin } from './OxyServices.analytics';
23
23
  import { OxyServicesDevicesMixin } from './OxyServices.devices';
@@ -50,7 +50,7 @@ type AllMixinInstances =
50
50
  & InstanceType<ReturnType<typeof OxyServicesPaymentMixin<typeof OxyServicesBase>>>
51
51
  & InstanceType<ReturnType<typeof OxyServicesKarmaMixin<typeof OxyServicesBase>>>
52
52
  & InstanceType<ReturnType<typeof OxyServicesAssetsMixin<typeof OxyServicesBase>>>
53
- & InstanceType<ReturnType<typeof OxyServicesDeveloperMixin<typeof OxyServicesBase>>>
53
+ & InstanceType<ReturnType<typeof OxyServicesApplicationsMixin<typeof OxyServicesBase>>>
54
54
  & InstanceType<ReturnType<typeof OxyServicesLocationMixin<typeof OxyServicesBase>>>
55
55
  & InstanceType<ReturnType<typeof OxyServicesAnalyticsMixin<typeof OxyServicesBase>>>
56
56
  & InstanceType<ReturnType<typeof OxyServicesDevicesMixin<typeof OxyServicesBase>>>
@@ -114,7 +114,7 @@ const MIXIN_PIPELINE: MixinFunction[] = [
114
114
  OxyServicesPaymentMixin,
115
115
  OxyServicesKarmaMixin,
116
116
  OxyServicesAssetsMixin,
117
- OxyServicesDeveloperMixin,
117
+ OxyServicesApplicationsMixin,
118
118
  OxyServicesLocationMixin,
119
119
  OxyServicesAnalyticsMixin,
120
120
  OxyServicesDevicesMixin,
@@ -1,114 +0,0 @@
1
- /**
2
- * Developer API Methods Mixin
3
- *
4
- * Provides methods for managing developer applications and API keys
5
- */
6
- import type { OxyServicesBase } from '../OxyServices.base';
7
- import { CACHE_TIMES } from './mixinHelpers';
8
-
9
- export function OxyServicesDeveloperMixin<T extends typeof OxyServicesBase>(Base: T) {
10
- return class extends Base {
11
- constructor(...args: any[]) {
12
- super(...(args as [any]));
13
- }
14
-
15
- /**
16
- * Get developer apps for the current user
17
- * @returns Array of developer apps
18
- */
19
- async getDeveloperApps(): Promise<any[]> {
20
- try {
21
- const res = await this.makeRequest<{ apps?: any[] }>('GET', '/developer/apps', undefined, {
22
- cache: true,
23
- cacheTTL: CACHE_TIMES.MEDIUM,
24
- });
25
- return res.apps || [];
26
- } catch (error) {
27
- throw this.handleError(error);
28
- }
29
- }
30
-
31
- /**
32
- * Create a new developer app
33
- * @param data - Developer app configuration
34
- * @returns Created developer app
35
- */
36
- async createDeveloperApp(data: {
37
- name: string;
38
- description?: string;
39
- webhookUrl: string;
40
- devWebhookUrl?: string;
41
- scopes?: string[];
42
- }): Promise<any> {
43
- try {
44
- const res = await this.makeRequest<{ app: any }>('POST', '/developer/apps', data, { cache: false });
45
- return res.app;
46
- } catch (error) {
47
- throw this.handleError(error);
48
- }
49
- }
50
-
51
- /**
52
- * Get a specific developer app
53
- */
54
- async getDeveloperApp(appId: string): Promise<any> {
55
- try {
56
- const res = await this.makeRequest<{ app: any }>('GET', `/developer/apps/${appId}`, undefined, {
57
- cache: true,
58
- cacheTTL: CACHE_TIMES.LONG,
59
- });
60
- return res.app;
61
- } catch (error) {
62
- throw this.handleError(error);
63
- }
64
- }
65
-
66
- /**
67
- * Update a developer app
68
- * @param appId - The developer app ID
69
- * @param data - Updated app configuration
70
- * @returns Updated developer app
71
- */
72
- async updateDeveloperApp(appId: string, data: {
73
- name?: string;
74
- description?: string;
75
- webhookUrl?: string;
76
- devWebhookUrl?: string;
77
- scopes?: string[];
78
- }): Promise<any> {
79
- try {
80
- const res = await this.makeRequest<{ app: any }>('PATCH', `/developer/apps/${appId}`, data, { cache: false });
81
- return res.app;
82
- } catch (error) {
83
- throw this.handleError(error);
84
- }
85
- }
86
-
87
- /**
88
- * Regenerate API secret for a developer app
89
- * @param appId - The developer app ID
90
- * @returns App with new secret
91
- */
92
- async regenerateDeveloperAppSecret(appId: string): Promise<any> {
93
- try {
94
- return await this.makeRequest('POST', `/developer/apps/${appId}/regenerate-secret`, undefined, { cache: false });
95
- } catch (error) {
96
- throw this.handleError(error);
97
- }
98
- }
99
-
100
- /**
101
- * Delete a developer app
102
- * @param appId - The developer app ID
103
- * @returns Deletion result
104
- */
105
- async deleteDeveloperApp(appId: string): Promise<any> {
106
- try {
107
- return await this.makeRequest('DELETE', `/developer/apps/${appId}`, undefined, { cache: false });
108
- } catch (error) {
109
- throw this.handleError(error);
110
- }
111
- }
112
- };
113
- }
114
-