@startsimpli/api 0.5.5 → 0.5.7

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startsimpli/api",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "Type-safe Django REST API client for StartSimpli apps",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -40,6 +40,10 @@ export const ENDPOINTS = {
40
40
  // Funnels
41
41
  FUNNELS: 'api/v1/funnels',
42
42
  FUNNEL: (id: string) => `api/v1/funnels/${id}`,
43
+ FUNNEL_PIPELINE: (id: string) => `api/v1/funnels/${id}/pipeline`,
44
+ FUNNEL_ADD_ENTITY: (id: string) => `api/v1/funnels/${id}/add_entity`,
45
+ FUNNEL_MOVE: (id: string) => `api/v1/funnels/${id}/move`,
46
+ FUNNEL_STATS: (id: string) => `api/v1/funnels/${id}/stats`,
43
47
  FUNNEL_RUN: (id: string) => `api/v1/funnels/${id}/run`,
44
48
  FUNNEL_RUNS: (id: string) => `api/v1/funnels/${id}/runs`,
45
49
  FUNNEL_RUN_ITEM: (funnelId: string, runId: string) => `api/v1/funnels/${funnelId}/runs/${runId}`,
@@ -49,6 +53,10 @@ export const ENDPOINTS = {
49
53
  FUNNEL_RUN_BY_ID: (runId: string) => `api/v1/funnel-runs/${runId}`,
50
54
  FUNNEL_RUN_CANCEL: (runId: string) => `api/v1/funnel-runs/${runId}/cancel`,
51
55
  FUNNEL_RUNS_GLOBAL: 'api/v1/funnel-runs',
56
+ // Enrichment
57
+ ENRICHMENT_QUEUE: 'api/v1/enrichment/start-processing',
58
+ CONTACT_ENRICH: (id: string) => `api/v1/contacts/${id}/enrich`,
59
+
52
60
  // Users
53
61
  USER_ME: 'api/v1/users/me',
54
62
  USER_CHANGE_PASSWORD: 'api/v1/users/me/change-password',
package/src/index.ts CHANGED
@@ -15,11 +15,29 @@ export { OrganizationsApi } from './lib/organizations-api';
15
15
  export { EntitiesApi } from './lib/entities-api';
16
16
  export { WorkflowsApi } from './lib/workflows-api';
17
17
  export { MessagesApi } from './lib/messages-api';
18
- export type { Message, MessageStatus as MessageApiStatus, MessageRecipient, MessagingChannel as MessagingChannelType } from './lib/messages-api';
18
+ export type { Message, MessageStatus as MessageApiStatus, MessageRecipient, MessagingChannel as MessagingChannelType, MessageFilters, CreateMessageInput, ScheduleMessageInput, SendTestInput } from './lib/messages-api';
19
+ export { MessageTemplatesApi } from './lib/message-templates-api';
20
+ export type { MessageTemplate, MessageTemplateFilters, CreateMessageTemplateInput } from './lib/message-templates-api';
19
21
  export { UsersApi } from './lib/users-api';
20
22
  export type { UserProfile, UpdateProfileRequest, ChangePasswordRequest, ChangePasswordResponse } from './types/user';
21
23
  export { FunnelsApi, isFunnelRunConflict, isFunnelValidationError } from './lib/funnels-api';
22
24
  export type { FunnelPreviewResult, FunnelRunFilters, FunnelTemplate } from './lib/funnels-api';
25
+ export { EnrichmentApi } from './lib/enrichment-api';
26
+ export { TargetListsApi } from './lib/target-lists-api';
27
+ export type {
28
+ TargetList,
29
+ TargetListMember,
30
+ CreateTargetListInput,
31
+ UpdateTargetListInput,
32
+ TargetListFilters,
33
+ TargetListMemberFilters,
34
+ TargetType,
35
+ ListSourceType,
36
+ RefreshStrategy,
37
+ AddMembersResult,
38
+ RemoveMembersResult,
39
+ RefreshResult,
40
+ } from './lib/target-lists-api';
23
41
 
24
42
  // Feature flags
25
43
  export { FeatureFlagsApi, FeatureFlagProvider, useFeatureFlags } from './lib/feature-flags';
@@ -129,6 +147,9 @@ import { MessagesApi } from './lib/messages-api';
129
147
  import { FunnelsApi } from './lib/funnels-api';
130
148
  import { FeatureFlagsApi } from './lib/feature-flags';
131
149
  import { UsersApi } from './lib/users-api';
150
+ import { EnrichmentApi } from './lib/enrichment-api';
151
+ import { TargetListsApi } from './lib/target-lists-api';
152
+ import { MessageTemplatesApi } from './lib/message-templates-api';
132
153
 
133
154
  import type { ApiClientConfig } from './lib/api-client';
134
155
 
@@ -149,5 +170,8 @@ export function createStartSimpliApi(config: ApiClientConfig = {}) {
149
170
  funnels: new FunnelsApi(client),
150
171
  featureFlags: new FeatureFlagsApi(client),
151
172
  users: new UsersApi(client),
173
+ enrichment: new EnrichmentApi(client),
174
+ targetLists: new TargetListsApi(client),
175
+ messageTemplates: new MessageTemplatesApi(client),
152
176
  };
153
177
  }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Enrichment API wrapper for /api/v1/enrichment/ and /api/v1/contacts/:id/enrich/
3
+ */
4
+
5
+ import type { EnrichmentResult, QueueStatus } from '../types';
6
+ import { ENDPOINTS } from '../constants/endpoints';
7
+ import type { ApiClient } from './api-client';
8
+
9
+ export class EnrichmentApi {
10
+ constructor(private client: ApiClient) {}
11
+
12
+ /**
13
+ * Enrich a single contact by ID
14
+ */
15
+ async enrich(contactId: string): Promise<EnrichmentResult> {
16
+ return this.client.fetch.post<EnrichmentResult>(
17
+ ENDPOINTS.CONTACT_ENRICH(contactId),
18
+ {}
19
+ );
20
+ }
21
+
22
+ /**
23
+ * Enrich multiple contacts. Calls the single-contact endpoint for each ID.
24
+ * Returns results in order, including failures.
25
+ */
26
+ async bulkEnrich(
27
+ contactIds: string[],
28
+ onProgress?: (completed: number, total: number) => void
29
+ ): Promise<EnrichmentResult[]> {
30
+ const results: EnrichmentResult[] = [];
31
+
32
+ for (let i = 0; i < contactIds.length; i++) {
33
+ try {
34
+ const result = await this.enrich(contactIds[i]);
35
+ results.push(result);
36
+ } catch (err: unknown) {
37
+ results.push({
38
+ contactId: contactIds[i],
39
+ contactName: '',
40
+ success: false,
41
+ fieldsUpdated: [],
42
+ error: err instanceof Error ? err.message : 'Enrichment failed',
43
+ });
44
+ }
45
+ onProgress?.(i + 1, contactIds.length);
46
+ }
47
+
48
+ return results;
49
+ }
50
+
51
+ /**
52
+ * Get the current enrichment queue status
53
+ */
54
+ async getQueueStatus(): Promise<QueueStatus> {
55
+ return this.client.fetch.get<QueueStatus>(ENDPOINTS.ENRICHMENT_QUEUE);
56
+ }
57
+ }
@@ -123,6 +123,44 @@ export class FunnelsApi {
123
123
  return this.client.delete<void>(ENDPOINTS.FUNNEL(id));
124
124
  }
125
125
 
126
+ // ── Generic pipeline actions (work with any funnel/profile) ──────────
127
+
128
+ /**
129
+ * Get entities grouped by stage (kanban view).
130
+ * Works for any funnel that has a membership run with entities in stages.
131
+ */
132
+ async pipeline(id: string): Promise<Record<string, FunnelResult[]>> {
133
+ return this.client.get<Record<string, FunnelResult[]>>(ENDPOINTS.FUNNEL_PIPELINE(id));
134
+ }
135
+
136
+ /**
137
+ * Add an entity to a funnel's membership run.
138
+ * Creates a FunnelResult with the entity + optional context (deal amount, notes, etc.)
139
+ */
140
+ async addEntity(
141
+ funnelId: string,
142
+ data: { entityId: string; stage?: string; context?: Record<string, unknown> }
143
+ ): Promise<FunnelResult> {
144
+ return this.client.post<FunnelResult>(ENDPOINTS.FUNNEL_ADD_ENTITY(funnelId), data);
145
+ }
146
+
147
+ /**
148
+ * Move an entity to a different stage within a funnel.
149
+ */
150
+ async move(
151
+ funnelId: string,
152
+ data: { entityId: string; newStage: string; context?: Record<string, unknown> }
153
+ ): Promise<FunnelResult> {
154
+ return this.client.post<FunnelResult>(ENDPOINTS.FUNNEL_MOVE(funnelId), data);
155
+ }
156
+
157
+ /**
158
+ * Get funnel statistics (stage counts, conversion rates, etc.)
159
+ */
160
+ async stats(funnelId: string): Promise<Record<string, unknown>> {
161
+ return this.client.get<Record<string, unknown>>(ENDPOINTS.FUNNEL_STATS(funnelId));
162
+ }
163
+
126
164
  /**
127
165
  * Execute a funnel run
128
166
  */
@@ -157,24 +195,26 @@ export class FunnelsApi {
157
195
  return this.client.get<FunnelRun>(ENDPOINTS.FUNNEL_RUN_BY_ID(runId));
158
196
  }
159
197
 
160
- // BEAD: fund-your-startup-rgi4 - funnels/{id}/results endpoint missing from Django FunnelViewSet
198
+ /**
199
+ * Get results (entities) from a funnel's latest completed run.
200
+ */
161
201
  async getResults(
162
- _funnelId: string,
163
- _pagination?: PaginationParams
202
+ funnelId: string,
203
+ pagination?: PaginationParams
164
204
  ): Promise<PaginatedResponse<FunnelResult>> {
165
- throw new Error('Not implemented - BEAD: fund-your-startup-rgi4. funnels/{id}/results action does not exist in Django.');
166
- // const params = new URLSearchParams();
167
- // if (_pagination?.page) params.append('page', String(_pagination.page));
168
- // if (_pagination?.pageSize) params.append('pageSize', String(_pagination.pageSize));
169
- // const query = params.toString();
170
- // const endpoint = query ? `${ENDPOINTS.FUNNEL_RESULTS(_funnelId)}?${query}` : ENDPOINTS.FUNNEL_RESULTS(_funnelId);
171
- // return this.client.get<PaginatedResponse<FunnelResult>>(endpoint);
172
- }
173
-
174
- // BEAD: fund-your-startup-rgi4 - funnels/{id}/preview endpoint missing. Django has /funnels/preview-icp/ (different signature).
175
- async preview(_funnelId: string, _stages?: Funnel['stages']): Promise<FunnelPreviewResult> {
176
- throw new Error('Not implemented - BEAD: fund-your-startup-rgi4. funnels/{id}/preview action does not exist in Django.');
177
- // return this.client.post<FunnelPreviewResult>(ENDPOINTS.FUNNEL_PREVIEW(_funnelId), { stages: _stages });
205
+ const params = new URLSearchParams();
206
+ if (pagination?.page) params.append('page', String(pagination.page));
207
+ if (pagination?.pageSize) params.append('page_size', String(pagination.pageSize));
208
+ const query = params.toString();
209
+ const endpoint = query ? `${ENDPOINTS.FUNNEL_RESULTS(funnelId)}?${query}` : ENDPOINTS.FUNNEL_RESULTS(funnelId);
210
+ return this.client.get<PaginatedResponse<FunnelResult>>(endpoint);
211
+ }
212
+
213
+ /**
214
+ * Preview funnel execution without persisting results.
215
+ */
216
+ async preview(funnelId: string, stages?: Funnel['stages']): Promise<FunnelPreviewResult> {
217
+ return this.client.post<FunnelPreviewResult>(ENDPOINTS.FUNNEL_PREVIEW(funnelId), { stages });
178
218
  }
179
219
 
180
220
  /**
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Message Templates API wrapper
3
+ *
4
+ * Provides type-safe access to Django Message Templates API
5
+ */
6
+
7
+ import type { ApiClient } from './api-client';
8
+
9
+ export interface MessageTemplate {
10
+ id: string;
11
+ name: string;
12
+ description: string | null;
13
+ subjectTemplate: string;
14
+ bodyTemplate: string;
15
+ channel: string | null;
16
+ entityType: string | null;
17
+ category: string | null;
18
+ isDefault: boolean;
19
+ useCount: number;
20
+ blocks: string | null;
21
+ createdAt: string;
22
+ updatedAt: string;
23
+ }
24
+
25
+ export interface MessageTemplateFilters {
26
+ channel?: string;
27
+ entityType?: string;
28
+ category?: string;
29
+ search?: string;
30
+ page?: number;
31
+ pageSize?: number;
32
+ ordering?: string;
33
+ }
34
+
35
+ export interface CreateMessageTemplateInput {
36
+ name: string;
37
+ description?: string;
38
+ subjectTemplate: string;
39
+ bodyTemplate: string;
40
+ channel?: string;
41
+ entityType?: string;
42
+ category?: string;
43
+ blocks?: string | null;
44
+ }
45
+
46
+ export class MessageTemplatesApi {
47
+ constructor(private client: ApiClient) {}
48
+
49
+ /**
50
+ * List message templates with optional filters
51
+ */
52
+ async list(filters?: MessageTemplateFilters) {
53
+ const params = new URLSearchParams();
54
+
55
+ if (filters?.channel) params.append('channel', filters.channel);
56
+ if (filters?.entityType) params.append('entityType', filters.entityType);
57
+ if (filters?.category) params.append('category', filters.category);
58
+ if (filters?.search) params.append('search', filters.search);
59
+ if (filters?.page) params.append('page', String(filters.page));
60
+ if (filters?.pageSize) params.append('pageSize', String(filters.pageSize));
61
+ if (filters?.ordering) params.append('ordering', filters.ordering);
62
+
63
+ return this.client.get<{ results: MessageTemplate[]; count: number; next: string | null; previous: string | null }>(
64
+ `/api/v1/message-templates/?${params.toString()}`
65
+ );
66
+ }
67
+
68
+ /**
69
+ * Get message template by ID
70
+ */
71
+ async get(id: string) {
72
+ return this.client.get<MessageTemplate>(`/api/v1/message-templates/${id}/`);
73
+ }
74
+
75
+ /**
76
+ * Create a new message template
77
+ */
78
+ async create(data: CreateMessageTemplateInput) {
79
+ return this.client.post<MessageTemplate>('/api/v1/message-templates/', data);
80
+ }
81
+
82
+ /**
83
+ * Update message template
84
+ */
85
+ async update(id: string, data: Partial<CreateMessageTemplateInput>) {
86
+ return this.client.patch<MessageTemplate>(`/api/v1/message-templates/${id}/`, data);
87
+ }
88
+
89
+ /**
90
+ * Delete message template
91
+ */
92
+ async delete(id: string) {
93
+ return this.client.delete(`/api/v1/message-templates/${id}/`);
94
+ }
95
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Target Lists API wrapper for /api/v1/targets/lists/
3
+ *
4
+ * Shared across all StartSimpli apps for managing contact/organization lists.
5
+ * All types use camelCase — FetchWrapper auto-converts snake_case↔camelCase.
6
+ */
7
+
8
+ import type { ApiClient } from './api-client';
9
+ import type { PaginatedResponse } from '../types';
10
+
11
+ // ── Types (camelCase — auto-converted from Django snake_case by FetchWrapper) ──
12
+
13
+ export type TargetType = 'contact' | 'organization';
14
+ export type ListSourceType = 'static' | 'funnel' | 'query';
15
+ export type RefreshStrategy = 'manual' | 'on_funnel_run' | 'scheduled';
16
+
17
+ export interface TargetList {
18
+ id: string;
19
+ name: string;
20
+ description: string;
21
+ targetType: TargetType;
22
+ sourceType: ListSourceType;
23
+ memberCount: number;
24
+ refreshStrategy: RefreshStrategy;
25
+ lastRefreshedAt: string | null;
26
+ createdAt: string;
27
+ updatedAt: string;
28
+ }
29
+
30
+ export interface TargetListMember {
31
+ id: string;
32
+ objectId: string;
33
+ contentType: string;
34
+ addedAt: string;
35
+ metadata: Record<string, unknown>;
36
+ name?: string;
37
+ email?: string;
38
+ firm?: string;
39
+ }
40
+
41
+ export interface CreateTargetListInput {
42
+ name: string;
43
+ description?: string;
44
+ targetType?: TargetType;
45
+ sourceType?: ListSourceType;
46
+ }
47
+
48
+ export interface UpdateTargetListInput {
49
+ name?: string;
50
+ description?: string;
51
+ }
52
+
53
+ export interface TargetListFilters {
54
+ targetType?: TargetType;
55
+ search?: string;
56
+ page?: number;
57
+ pageSize?: number;
58
+ ordering?: string;
59
+ }
60
+
61
+ export interface TargetListMemberFilters {
62
+ search?: string;
63
+ page?: number;
64
+ pageSize?: number;
65
+ ordering?: string;
66
+ }
67
+
68
+ export interface AddMembersResult {
69
+ added: number;
70
+ alreadyExists: number;
71
+ total: number;
72
+ }
73
+
74
+ export interface RemoveMembersResult {
75
+ removed: number;
76
+ total: number;
77
+ }
78
+
79
+ export interface RefreshResult {
80
+ added: number;
81
+ removed: number;
82
+ total: number;
83
+ }
84
+
85
+ // ── Endpoints ────────────────────────────────────────────────────────────
86
+
87
+ const LISTS_BASE = 'api/v1/targets/lists';
88
+ const LIST = (id: string) => `${LISTS_BASE}/${id}`;
89
+ const LIST_MEMBERS = (id: string) => `${LISTS_BASE}/${id}/members`;
90
+ const LIST_ADD_MEMBERS = (id: string) => `${LISTS_BASE}/${id}/add_members`;
91
+ const LIST_REMOVE_MEMBERS = (id: string) => `${LISTS_BASE}/${id}/remove_members`;
92
+ const LIST_REFRESH = (id: string) => `${LISTS_BASE}/${id}/refresh`;
93
+
94
+ // ── API Class ────────────────────────────────────────────────────────────
95
+
96
+ export class TargetListsApi {
97
+ constructor(private client: ApiClient) {}
98
+
99
+ /** List all target lists with pagination and filters */
100
+ async list(filters?: TargetListFilters): Promise<PaginatedResponse<TargetList>> {
101
+ // Query params use snake_case (sent directly to Django as URL params)
102
+ const params: Record<string, string> = {};
103
+ if (filters?.targetType) params.target_type = filters.targetType;
104
+ if (filters?.search) params.search = filters.search;
105
+ if (filters?.page) params.page = String(filters.page);
106
+ if (filters?.pageSize) params.page_size = String(filters.pageSize);
107
+ if (filters?.ordering) params.ordering = filters.ordering;
108
+
109
+ const response = await this.client.fetch.get<PaginatedResponse<TargetList> | TargetList[]>(
110
+ LISTS_BASE,
111
+ { params }
112
+ );
113
+
114
+ if (Array.isArray(response)) {
115
+ return { count: response.length, results: response, next: null, previous: null };
116
+ }
117
+ return response as PaginatedResponse<TargetList>;
118
+ }
119
+
120
+ /** Get a single target list by ID */
121
+ async get(id: string): Promise<TargetList> {
122
+ return this.client.fetch.get<TargetList>(LIST(id));
123
+ }
124
+
125
+ /** Create a new target list (camelCase body → auto-converted to snake_case by serializeBody) */
126
+ async create(data: CreateTargetListInput): Promise<TargetList> {
127
+ return this.client.fetch.post<TargetList>(LISTS_BASE, {
128
+ name: data.name,
129
+ description: data.description || '',
130
+ targetType: data.targetType || 'contact',
131
+ sourceType: data.sourceType || 'static',
132
+ });
133
+ }
134
+
135
+ /** Update an existing target list */
136
+ async update(id: string, data: UpdateTargetListInput): Promise<TargetList> {
137
+ return this.client.fetch.patch<TargetList>(LIST(id), data);
138
+ }
139
+
140
+ /** Delete a target list */
141
+ async delete(id: string): Promise<void> {
142
+ return this.client.fetch.delete(LIST(id));
143
+ }
144
+
145
+ /** Get members of a target list with pagination */
146
+ async getMembers(
147
+ listId: string,
148
+ filters?: TargetListMemberFilters
149
+ ): Promise<PaginatedResponse<TargetListMember>> {
150
+ const params: Record<string, string> = {};
151
+ if (filters?.search) params.search = filters.search;
152
+ if (filters?.page) params.page = String(filters.page);
153
+ if (filters?.pageSize) params.page_size = String(filters.pageSize);
154
+ if (filters?.ordering) params.ordering = filters.ordering;
155
+
156
+ const response = await this.client.fetch.get<PaginatedResponse<TargetListMember> | TargetListMember[]>(
157
+ LIST_MEMBERS(listId),
158
+ { params }
159
+ );
160
+
161
+ if (Array.isArray(response)) {
162
+ return { count: response.length, results: response, next: null, previous: null };
163
+ }
164
+ return response as PaginatedResponse<TargetListMember>;
165
+ }
166
+
167
+ /** Add members (camelCase body → auto-converted to snake_case) */
168
+ async addMembers(
169
+ listId: string,
170
+ objectIds: string[],
171
+ metadata?: Record<string, unknown>
172
+ ): Promise<AddMembersResult> {
173
+ return this.client.fetch.post<AddMembersResult>(LIST_ADD_MEMBERS(listId), {
174
+ objectIds,
175
+ ...(metadata ? { metadata } : {}),
176
+ });
177
+ }
178
+
179
+ /** Remove members */
180
+ async removeMembers(listId: string, objectIds: string[]): Promise<RemoveMembersResult> {
181
+ return this.client.fetch.post<RemoveMembersResult>(LIST_REMOVE_MEMBERS(listId), {
182
+ objectIds,
183
+ });
184
+ }
185
+
186
+ /** Refresh a funnel/query-based list */
187
+ async refresh(listId: string): Promise<RefreshResult> {
188
+ return this.client.fetch.post<RefreshResult>(LIST_REFRESH(listId));
189
+ }
190
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Enrichment types — shared across all StartSimpli apps
3
+ */
4
+
5
+ export interface EnrichmentResult {
6
+ contactId: string;
7
+ contactName: string;
8
+ success: boolean;
9
+ fieldsUpdated: string[];
10
+ error?: string;
11
+ }
12
+
13
+ export interface QueueStatus {
14
+ pending: number;
15
+ processing: number;
16
+ completed: number;
17
+ failed: number;
18
+ }
19
+
20
+ export type EnrichmentProvider = 'apollo' | 'hunter';
21
+
22
+ export interface IntegrationStatus {
23
+ name: string;
24
+ provider: EnrichmentProvider;
25
+ connected: boolean;
26
+ description: string;
27
+ lastSync?: string;
28
+ }
@@ -89,6 +89,14 @@ export type {
89
89
  ChangePasswordResponse,
90
90
  } from './user';
91
91
 
92
+ // Enrichment types
93
+ export type {
94
+ EnrichmentResult,
95
+ QueueStatus,
96
+ EnrichmentProvider,
97
+ IntegrationStatus,
98
+ } from './enrichment';
99
+
92
100
  // Error types
93
101
  export type {
94
102
  FieldError,
package/src/types/user.ts CHANGED
@@ -1,29 +1,30 @@
1
1
  /**
2
2
  * User types for /api/v1/users/ endpoints
3
+ * camelCase — FetchWrapper auto-converts snake_case↔camelCase at boundary
3
4
  */
4
5
 
5
6
  export interface UserProfile {
6
7
  id: string;
7
8
  email: string;
8
- first_name: string;
9
- last_name: string;
10
- full_name: string;
11
- is_email_verified: boolean;
9
+ firstName: string;
10
+ lastName: string;
11
+ fullName: string;
12
+ isEmailVerified: boolean;
12
13
  company: string | null;
13
- is_active: boolean;
14
- created_at: string;
15
- updated_at: string;
14
+ isActive: boolean;
15
+ createdAt: string;
16
+ updatedAt: string;
16
17
  }
17
18
 
18
19
  export interface UpdateProfileRequest {
19
- first_name?: string;
20
- last_name?: string;
20
+ firstName?: string;
21
+ lastName?: string;
21
22
  }
22
23
 
23
24
  export interface ChangePasswordRequest {
24
- old_password: string;
25
- new_password: string;
26
- new_password_confirm: string;
25
+ oldPassword: string;
26
+ newPassword: string;
27
+ newPasswordConfirm: string;
27
28
  }
28
29
 
29
30
  export interface ChangePasswordResponse {