@typeb-digital/nucleus-sdk 0.0.1 → 0.0.2
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/dist/cjs/index.cjs +683 -0
- package/dist/cjs/index.d.cts +567 -0
- package/dist/cjs/index.d.cts.map +1 -0
- package/dist/es/index.d.ts +567 -0
- package/dist/es/index.d.ts.map +1 -0
- package/dist/es/index.js +683 -0
- package/package.json +4 -1
- package/src/apps.ts +0 -19
- package/src/client.ts +0 -75
- package/src/index.ts +0 -82
- package/src/resources/clients.ts +0 -65
- package/src/resources/currencies.ts +0 -41
- package/src/resources/departments.ts +0 -43
- package/src/resources/employees.ts +0 -65
- package/src/resources/files.ts +0 -105
- package/src/resources/generic-rates.ts +0 -43
- package/src/resources/partners.ts +0 -61
- package/src/resources/project-types.ts +0 -41
- package/src/resources/projects.ts +0 -65
- package/src/transform.ts +0 -266
- package/src/transport.ts +0 -145
- package/src/types.ts +0 -447
- package/tsconfig.json +0 -12
- package/tsconfig.verify.json +0 -11
- package/typeb-digital-nucleus-sdk-0.0.1.tgz +0 -0
- package/verify.ts +0 -182
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ScopeDeclaration,
|
|
3
|
-
ResolveProject,
|
|
4
|
-
ProjectExpandPath,
|
|
5
|
-
WithProjectExpand,
|
|
6
|
-
SingleResult,
|
|
7
|
-
PaginatedResult,
|
|
8
|
-
ErrorResult,
|
|
9
|
-
} from '../types';
|
|
10
|
-
import type { NucleusTransport } from '../transport';
|
|
11
|
-
import { transformProject } from '../transform';
|
|
12
|
-
|
|
13
|
-
export type ProjectListParams = {
|
|
14
|
-
search?: string;
|
|
15
|
-
status?: string;
|
|
16
|
-
clientId?: string;
|
|
17
|
-
page?: number;
|
|
18
|
-
pageSize?: number;
|
|
19
|
-
expand?: readonly ProjectExpandPath[];
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export class ProjectsAccessor<S extends ScopeDeclaration> {
|
|
23
|
-
constructor(private readonly transport: NucleusTransport) {}
|
|
24
|
-
|
|
25
|
-
async list<E extends readonly ProjectExpandPath[] = never[]>(
|
|
26
|
-
params?: ProjectListParams & { expand?: E },
|
|
27
|
-
): Promise<PaginatedResult<WithProjectExpand<ResolveProject<S>, E, S>>> {
|
|
28
|
-
const query: Record<string, string | number | undefined> = {};
|
|
29
|
-
if (params?.search) query['search'] = params.search;
|
|
30
|
-
if (params?.status) query['status'] = params.status;
|
|
31
|
-
if (params?.clientId) query['clientId'] = params.clientId;
|
|
32
|
-
if (params?.page) query['page'] = params.page;
|
|
33
|
-
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
34
|
-
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
35
|
-
|
|
36
|
-
const result = await this.transport.getList<unknown>('/api/v1/data/projects', query);
|
|
37
|
-
|
|
38
|
-
if ('error' in result) return result as ErrorResult;
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
data: result.data.map((r) => transformProject(r)) as WithProjectExpand<
|
|
42
|
-
ResolveProject<S>,
|
|
43
|
-
E,
|
|
44
|
-
S
|
|
45
|
-
>[],
|
|
46
|
-
meta: result.meta,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async getById<E extends readonly ProjectExpandPath[] = never[]>(
|
|
51
|
-
id: string,
|
|
52
|
-
options?: { expand?: E },
|
|
53
|
-
): Promise<SingleResult<WithProjectExpand<ResolveProject<S>, E, S>>> {
|
|
54
|
-
const query: Record<string, string | undefined> = {};
|
|
55
|
-
if (options?.expand?.length) query['expand'] = options.expand.join(',');
|
|
56
|
-
|
|
57
|
-
const result = await this.transport.get<unknown>(`/api/v1/data/projects/${id}`, query);
|
|
58
|
-
|
|
59
|
-
if ('error' in result) return result as ErrorResult;
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
data: transformProject(result.data) as WithProjectExpand<ResolveProject<S>, E, S>,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
}
|
package/src/transform.ts
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Transform utilities — map snake_case Prisma API responses to camelCase SDK types.
|
|
3
|
-
* Each function accepts `unknown` so it works regardless of which buckets were active.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
type Raw = Record<string, unknown>;
|
|
7
|
-
|
|
8
|
-
function str(v: unknown): string | null {
|
|
9
|
-
return typeof v === 'string' ? v : null;
|
|
10
|
-
}
|
|
11
|
-
function num(v: unknown): number | null {
|
|
12
|
-
return typeof v === 'number' ? v : null;
|
|
13
|
-
}
|
|
14
|
-
function bool(v: unknown): boolean {
|
|
15
|
-
return v === true;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function transformProfile(profile: unknown): Record<string, unknown> {
|
|
19
|
-
if (!profile || typeof profile !== 'object') return {};
|
|
20
|
-
const p = profile as Raw;
|
|
21
|
-
const out: Raw = {};
|
|
22
|
-
if ('phone' in p) out['phone'] = p['phone'];
|
|
23
|
-
if ('city' in p) out['city'] = p['city'];
|
|
24
|
-
if ('country' in p) out['country'] = p['country'];
|
|
25
|
-
if ('biography' in p) out['biography'] = p['biography'];
|
|
26
|
-
if ('emergency_contact_name' in p || 'emergency_contact_phone' in p) {
|
|
27
|
-
out['emergencyContact'] = {
|
|
28
|
-
name: str(p['emergency_contact_name']),
|
|
29
|
-
phone: str(p['emergency_contact_phone']),
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
return out;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function transformCompensation(raw: unknown): Record<string, unknown> | null {
|
|
36
|
-
if (!raw || typeof raw !== 'object') return null;
|
|
37
|
-
const r = raw as Raw;
|
|
38
|
-
return {
|
|
39
|
-
hourlyCostRate: num(r['hourly_cost_rate']),
|
|
40
|
-
hourlyBillableRate: num(r['hourly_billable_rate']),
|
|
41
|
-
monthlyCostRate: num(r['monthly_cost_rate']),
|
|
42
|
-
monthlyBillableRate: num(r['monthly_billable_rate']),
|
|
43
|
-
currencyCode: str(r['currency_code']) ?? 'USD',
|
|
44
|
-
effectiveFrom: str(r['effective_from']) ?? '',
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function transformCompensationHistoryEntry(raw: unknown): Record<string, unknown> {
|
|
49
|
-
const r = (raw ?? {}) as Raw;
|
|
50
|
-
return {
|
|
51
|
-
hourlyCostRate: num(r['hourly_cost_rate']),
|
|
52
|
-
hourlyBillableRate: num(r['hourly_billable_rate']),
|
|
53
|
-
monthlyCostRate: num(r['monthly_cost_rate']),
|
|
54
|
-
monthlyBillableRate: num(r['monthly_billable_rate']),
|
|
55
|
-
currencyCode: str(r['currency_code']) ?? 'USD',
|
|
56
|
-
effectiveFrom: str(r['effective_from']) ?? '',
|
|
57
|
-
effectiveTo: str(r['effective_to']),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function transformEmployee(raw: unknown): Record<string, unknown> {
|
|
62
|
-
if (!raw || typeof raw !== 'object') return {};
|
|
63
|
-
const r = raw as Raw;
|
|
64
|
-
const out: Raw = {};
|
|
65
|
-
|
|
66
|
-
// identity
|
|
67
|
-
if ('id' in r) out['id'] = r['id'];
|
|
68
|
-
if ('display_name' in r) out['displayName'] = str(r['display_name']);
|
|
69
|
-
if ('first_name' in r) out['firstName'] = str(r['first_name']);
|
|
70
|
-
if ('last_name' in r) out['lastName'] = str(r['last_name']);
|
|
71
|
-
if ('email' in r) out['email'] = str(r['email']);
|
|
72
|
-
if ('picture_url' in r) out['pictureUrl'] = str(r['picture_url']);
|
|
73
|
-
if ('job_title' in r) out['jobTitle'] = str(r['job_title']);
|
|
74
|
-
if ('department' in r) out['department'] = str(r['department']);
|
|
75
|
-
if ('employment_status' in r) out['employmentStatus'] = str(r['employment_status']);
|
|
76
|
-
if ('is_external' in r) out['isExternal'] = bool(r['is_external']);
|
|
77
|
-
|
|
78
|
-
// employment
|
|
79
|
-
if ('start_date' in r) out['startDate'] = str(r['start_date']);
|
|
80
|
-
if ('weekly_capacity' in r) out['weeklyCapacity'] = num(r['weekly_capacity']);
|
|
81
|
-
if ('manager_id' in r) out['managerId'] = str(r['manager_id']);
|
|
82
|
-
if ('partner_id' in r) out['partnerId'] = str(r['partner_id']);
|
|
83
|
-
if ('timezone' in r) out['timezone'] = str(r['timezone']);
|
|
84
|
-
|
|
85
|
-
// sensitive
|
|
86
|
-
if ('birthday' in r) out['birthday'] = str(r['birthday']);
|
|
87
|
-
if ('custom_fields' in r) out['customFields'] = r['custom_fields'];
|
|
88
|
-
|
|
89
|
-
// profile JSON (contact + employment.biography + sensitive.emergencyContact)
|
|
90
|
-
if ('profile' in r) {
|
|
91
|
-
out['profile'] = transformProfile(r['profile']);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// synthesised compensation (injected by Layer 3 interceptor)
|
|
95
|
-
if ('current_compensation' in r) {
|
|
96
|
-
out['currentCompensation'] = transformCompensation(r['current_compensation']);
|
|
97
|
-
}
|
|
98
|
-
if ('compensation_history' in r && Array.isArray(r['compensation_history'])) {
|
|
99
|
-
out['compensationHistory'] = (r['compensation_history'] as unknown[]).map(
|
|
100
|
-
transformCompensationHistoryEntry,
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Expand: manager / partner (recursively transformed)
|
|
105
|
-
if ('manager' in r) {
|
|
106
|
-
out['manager'] = r['manager'] ? transformEmployee(r['manager']) : null;
|
|
107
|
-
}
|
|
108
|
-
if ('partner' in r) {
|
|
109
|
-
out['partner'] = r['partner'] ? transformPartner(r['partner']) : null;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return out;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export function transformProject(raw: unknown): Record<string, unknown> {
|
|
116
|
-
if (!raw || typeof raw !== 'object') return {};
|
|
117
|
-
const r = raw as Raw;
|
|
118
|
-
const out: Raw = {};
|
|
119
|
-
|
|
120
|
-
// core
|
|
121
|
-
if ('id' in r) out['id'] = r['id'];
|
|
122
|
-
if ('name' in r) out['name'] = str(r['name']);
|
|
123
|
-
if ('status' in r) out['status'] = str(r['status']);
|
|
124
|
-
if ('color_tag' in r) out['colorTag'] = str(r['color_tag']);
|
|
125
|
-
if ('icon_name' in r) out['iconName'] = str(r['icon_name']);
|
|
126
|
-
if ('start_date' in r) out['startDate'] = str(r['start_date']);
|
|
127
|
-
if ('end_date' in r) out['endDate'] = str(r['end_date']);
|
|
128
|
-
if ('project_type_id' in r) out['projectTypeId'] = str(r['project_type_id']);
|
|
129
|
-
if ('client_id' in r) out['clientId'] = str(r['client_id']);
|
|
130
|
-
|
|
131
|
-
// team
|
|
132
|
-
if ('project_manager_id' in r) out['projectManagerId'] = str(r['project_manager_id']);
|
|
133
|
-
if ('engagement_lead_id' in r) out['engagementLeadId'] = str(r['engagement_lead_id']);
|
|
134
|
-
if ('memberships' in r && Array.isArray(r['memberships'])) {
|
|
135
|
-
out['memberships'] = (r['memberships'] as unknown[]).map((m) => {
|
|
136
|
-
const mem = (m ?? {}) as Raw;
|
|
137
|
-
const entry: Raw = {
|
|
138
|
-
employeeId: str(mem['employee_id']),
|
|
139
|
-
role: str(mem['role']),
|
|
140
|
-
};
|
|
141
|
-
if ('employee' in mem) {
|
|
142
|
-
entry['employee'] = mem['employee'] ? transformEmployee(mem['employee']) : null;
|
|
143
|
-
}
|
|
144
|
-
return entry;
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// integrations
|
|
149
|
-
if ('source' in r) out['source'] = str(r['source']);
|
|
150
|
-
if ('clockify_project_id' in r) out['clockifyProjectId'] = str(r['clockify_project_id']);
|
|
151
|
-
if ('clockify_workspace_id' in r) out['clockifyWorkspaceId'] = str(r['clockify_workspace_id']);
|
|
152
|
-
if ('apollo_deal_id' in r) out['apolloDealId'] = str(r['apollo_deal_id']);
|
|
153
|
-
|
|
154
|
-
// expand: client / projectType / projectManager / engagementLead
|
|
155
|
-
if ('client' in r) out['client'] = r['client'] ? transformClient(r['client']) : null;
|
|
156
|
-
if ('project_type' in r || 'projectType' in r) {
|
|
157
|
-
const pt = r['project_type'] ?? r['projectType'];
|
|
158
|
-
out['projectType'] = pt ? transformProjectType(pt) : null;
|
|
159
|
-
}
|
|
160
|
-
if ('project_manager' in r || 'projectManager' in r) {
|
|
161
|
-
const pm = r['project_manager'] ?? r['projectManager'];
|
|
162
|
-
out['projectManager'] = pm ? transformEmployee(pm) : null;
|
|
163
|
-
}
|
|
164
|
-
if ('engagement_lead' in r || 'engagementLead' in r) {
|
|
165
|
-
const el = r['engagement_lead'] ?? r['engagementLead'];
|
|
166
|
-
out['engagementLead'] = el ? transformEmployee(el) : null;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return out;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export function transformClient(raw: unknown): Record<string, unknown> {
|
|
173
|
-
if (!raw || typeof raw !== 'object') return {};
|
|
174
|
-
const r = raw as Raw;
|
|
175
|
-
const out: Raw = {};
|
|
176
|
-
|
|
177
|
-
if ('id' in r) out['id'] = r['id'];
|
|
178
|
-
if ('name' in r) out['name'] = str(r['name']);
|
|
179
|
-
if ('code' in r) out['code'] = str(r['code']);
|
|
180
|
-
if ('industry' in r) out['industry'] = str(r['industry']);
|
|
181
|
-
if ('website' in r) out['website'] = str(r['website']);
|
|
182
|
-
if ('country' in r) out['country'] = str(r['country']);
|
|
183
|
-
if ('primary_contact_name' in r) out['primaryContactName'] = str(r['primary_contact_name']);
|
|
184
|
-
if ('primary_contact_email' in r) out['primaryContactEmail'] = str(r['primary_contact_email']);
|
|
185
|
-
if ('contact_phone' in r) out['contactPhone'] = str(r['contact_phone']);
|
|
186
|
-
if ('default_currency' in r) out['defaultCurrency'] = str(r['default_currency']);
|
|
187
|
-
if ('notes' in r) out['notes'] = str(r['notes']);
|
|
188
|
-
if ('projects' in r && Array.isArray(r['projects'])) {
|
|
189
|
-
out['projects'] = (r['projects'] as unknown[]).map(transformProject);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return out;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
export function transformPartner(raw: unknown): Record<string, unknown> {
|
|
196
|
-
if (!raw || typeof raw !== 'object') return {};
|
|
197
|
-
const r = raw as Raw;
|
|
198
|
-
const out: Raw = {};
|
|
199
|
-
|
|
200
|
-
if ('id' in r) out['id'] = r['id'];
|
|
201
|
-
if ('name' in r) out['name'] = str(r['name']);
|
|
202
|
-
if ('contact_name' in r) out['contactName'] = str(r['contact_name']);
|
|
203
|
-
if ('contact_email' in r) out['contactEmail'] = str(r['contact_email']);
|
|
204
|
-
if ('contact_phone' in r) out['contactPhone'] = str(r['contact_phone']);
|
|
205
|
-
if ('notes' in r) out['notes'] = str(r['notes']);
|
|
206
|
-
if ('employees' in r && Array.isArray(r['employees'])) {
|
|
207
|
-
out['employees'] = (r['employees'] as unknown[]).map(transformEmployee);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return out;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export function transformDepartment(raw: unknown): Record<string, unknown> {
|
|
214
|
-
if (!raw || typeof raw !== 'object') return {};
|
|
215
|
-
const r = raw as Raw;
|
|
216
|
-
const out: Raw = {};
|
|
217
|
-
|
|
218
|
-
if ('id' in r) out['id'] = r['id'];
|
|
219
|
-
if ('name' in r) out['name'] = str(r['name']);
|
|
220
|
-
if ('titles' in r) out['titles'] = Array.isArray(r['titles']) ? r['titles'] : [];
|
|
221
|
-
if ('sort_order' in r) out['sortOrder'] = num(r['sort_order']) ?? 0;
|
|
222
|
-
|
|
223
|
-
return out;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export function transformProjectType(raw: unknown): Record<string, unknown> {
|
|
227
|
-
if (!raw || typeof raw !== 'object') return {};
|
|
228
|
-
const r = raw as Raw;
|
|
229
|
-
const out: Raw = {};
|
|
230
|
-
|
|
231
|
-
if ('id' in r) out['id'] = r['id'];
|
|
232
|
-
if ('name' in r) out['name'] = str(r['name']);
|
|
233
|
-
if ('description' in r) out['description'] = str(r['description']);
|
|
234
|
-
if ('sort_order' in r) out['sortOrder'] = num(r['sort_order']) ?? 0;
|
|
235
|
-
|
|
236
|
-
return out;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export function transformCurrency(raw: unknown): Record<string, unknown> {
|
|
240
|
-
if (!raw || typeof raw !== 'object') return {};
|
|
241
|
-
const r = raw as Raw;
|
|
242
|
-
const out: Raw = {};
|
|
243
|
-
|
|
244
|
-
if ('code' in r) out['code'] = r['code'];
|
|
245
|
-
if ('name' in r) out['name'] = str(r['name']);
|
|
246
|
-
if ('symbol' in r) out['symbol'] = str(r['symbol']);
|
|
247
|
-
if ('is_default' in r) out['isDefault'] = bool(r['is_default']);
|
|
248
|
-
if ('sort_order' in r) out['sortOrder'] = num(r['sort_order']) ?? 0;
|
|
249
|
-
|
|
250
|
-
return out;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export function transformGenericRate(raw: unknown): Record<string, unknown> {
|
|
254
|
-
if (!raw || typeof raw !== 'object') return {};
|
|
255
|
-
const r = raw as Raw;
|
|
256
|
-
const out: Raw = {};
|
|
257
|
-
|
|
258
|
-
if ('id' in r) out['id'] = r['id'];
|
|
259
|
-
if ('title' in r) out['title'] = str(r['title']);
|
|
260
|
-
if ('department' in r) out['department'] = str(r['department']);
|
|
261
|
-
if ('currency_code' in r) out['currencyCode'] = str(r['currency_code']);
|
|
262
|
-
if ('cost_rate' in r) out['costRate'] = num(r['cost_rate']);
|
|
263
|
-
if ('billable_rate' in r) out['billableRate'] = num(r['billable_rate']);
|
|
264
|
-
|
|
265
|
-
return out;
|
|
266
|
-
}
|
package/src/transport.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTTP transport — wraps ofetch so resource files never see raw network concerns.
|
|
3
|
-
* All methods return result objects; they never throw.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { $fetch, FetchError } from 'ofetch';
|
|
7
|
-
import type { ErrorCode, ErrorResult, SuccessResult, ListResult, ListMeta } from './types';
|
|
8
|
-
|
|
9
|
-
const DEFAULT_BASE_URL = 'https://nucleus.typeb.digital';
|
|
10
|
-
|
|
11
|
-
type ApiSuccessEnvelope<T> = { success: true; data: T };
|
|
12
|
-
type ApiPaginatedEnvelope<T> = {
|
|
13
|
-
success: true;
|
|
14
|
-
data: T[];
|
|
15
|
-
meta: { total: number; page: number; pageSize: number };
|
|
16
|
-
};
|
|
17
|
-
type ApiErrorEnvelope = { success: false; error: string };
|
|
18
|
-
|
|
19
|
-
function statusToCode(status: number, apiCode?: string): ErrorCode {
|
|
20
|
-
if (apiCode === 'INVALID_SCOPE') return 'INVALID_SCOPE';
|
|
21
|
-
if (status === 404) return 'NOT_FOUND';
|
|
22
|
-
if (status === 429) return 'RATE_LIMITED';
|
|
23
|
-
return 'FORBIDDEN';
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function makeErrorResult(code: ErrorCode, message: string): ErrorResult {
|
|
27
|
-
return { error: { code, message } };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class NucleusTransport {
|
|
31
|
-
private readonly headers: Record<string, string>;
|
|
32
|
-
private readonly baseUrl: string;
|
|
33
|
-
|
|
34
|
-
constructor(token: string, baseUrl?: string) {
|
|
35
|
-
this.headers = {
|
|
36
|
-
Authorization: `Bearer ${token}`,
|
|
37
|
-
'Content-Type': 'application/json',
|
|
38
|
-
};
|
|
39
|
-
this.baseUrl = (baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async get<T>(
|
|
43
|
-
path: string,
|
|
44
|
-
query?: Record<string, string | number | undefined>,
|
|
45
|
-
): Promise<SuccessResult<T> | ErrorResult> {
|
|
46
|
-
try {
|
|
47
|
-
const params = query
|
|
48
|
-
? Object.fromEntries(Object.entries(query).filter(([, v]) => v !== undefined))
|
|
49
|
-
: undefined;
|
|
50
|
-
|
|
51
|
-
const envelope = await $fetch<ApiSuccessEnvelope<T> | ApiErrorEnvelope>(
|
|
52
|
-
`${this.baseUrl}${path}`,
|
|
53
|
-
{ method: 'GET', headers: this.headers, params },
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
if (!envelope.success) {
|
|
57
|
-
return makeErrorResult('FORBIDDEN', envelope.error);
|
|
58
|
-
}
|
|
59
|
-
return { data: envelope.data };
|
|
60
|
-
} catch (err) {
|
|
61
|
-
if (err instanceof FetchError) {
|
|
62
|
-
const body = err.data as Partial<ApiErrorEnvelope> | undefined;
|
|
63
|
-
const code = statusToCode(err.status ?? 0, body?.error);
|
|
64
|
-
return makeErrorResult(code, err.message);
|
|
65
|
-
}
|
|
66
|
-
return makeErrorResult('NETWORK_ERROR', String(err));
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async post<T>(path: string, body: unknown): Promise<SuccessResult<T> | ErrorResult> {
|
|
71
|
-
try {
|
|
72
|
-
const envelope = await $fetch<ApiSuccessEnvelope<T> | ApiErrorEnvelope>(
|
|
73
|
-
`${this.baseUrl}${path}`,
|
|
74
|
-
{ method: 'POST', headers: this.headers, body: JSON.stringify(body) },
|
|
75
|
-
);
|
|
76
|
-
if (!envelope.success) return makeErrorResult('FORBIDDEN', envelope.error);
|
|
77
|
-
return { data: envelope.data };
|
|
78
|
-
} catch (err) {
|
|
79
|
-
if (err instanceof FetchError) {
|
|
80
|
-
const errBody = err.data as Partial<ApiErrorEnvelope> | undefined;
|
|
81
|
-
return makeErrorResult(statusToCode(err.status ?? 0, errBody?.error), err.message);
|
|
82
|
-
}
|
|
83
|
-
return makeErrorResult('NETWORK_ERROR', String(err));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async del<T = null>(
|
|
88
|
-
path: string,
|
|
89
|
-
query?: Record<string, string | undefined>,
|
|
90
|
-
): Promise<SuccessResult<T> | ErrorResult> {
|
|
91
|
-
try {
|
|
92
|
-
const params = query
|
|
93
|
-
? Object.fromEntries(Object.entries(query).filter(([, v]) => v !== undefined))
|
|
94
|
-
: undefined;
|
|
95
|
-
const envelope = await $fetch<ApiSuccessEnvelope<T> | ApiErrorEnvelope>(
|
|
96
|
-
`${this.baseUrl}${path}`,
|
|
97
|
-
{ method: 'DELETE', headers: this.headers, params },
|
|
98
|
-
);
|
|
99
|
-
if (!envelope.success) return makeErrorResult('FORBIDDEN', envelope.error);
|
|
100
|
-
return { data: envelope.data };
|
|
101
|
-
} catch (err) {
|
|
102
|
-
if (err instanceof FetchError) {
|
|
103
|
-
const errBody = err.data as Partial<ApiErrorEnvelope> | undefined;
|
|
104
|
-
return makeErrorResult(statusToCode(err.status ?? 0, errBody?.error), err.message);
|
|
105
|
-
}
|
|
106
|
-
return makeErrorResult('NETWORK_ERROR', String(err));
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async getList<T>(
|
|
111
|
-
path: string,
|
|
112
|
-
query?: Record<string, string | number | undefined>,
|
|
113
|
-
): Promise<ListResult<T> | ErrorResult> {
|
|
114
|
-
try {
|
|
115
|
-
const params = query
|
|
116
|
-
? Object.fromEntries(Object.entries(query).filter(([, v]) => v !== undefined))
|
|
117
|
-
: undefined;
|
|
118
|
-
|
|
119
|
-
const envelope = await $fetch<ApiPaginatedEnvelope<T> | ApiErrorEnvelope>(
|
|
120
|
-
`${this.baseUrl}${path}`,
|
|
121
|
-
{ method: 'GET', headers: this.headers, params },
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
if (!envelope.success) {
|
|
125
|
-
return makeErrorResult('FORBIDDEN', envelope.error);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const { data, meta } = envelope as ApiPaginatedEnvelope<T>;
|
|
129
|
-
const listMeta: ListMeta = {
|
|
130
|
-
total: meta.total,
|
|
131
|
-
page: meta.page,
|
|
132
|
-
pageSize: meta.pageSize,
|
|
133
|
-
hasMore: meta.page * meta.pageSize < meta.total,
|
|
134
|
-
};
|
|
135
|
-
return { data, meta: listMeta };
|
|
136
|
-
} catch (err) {
|
|
137
|
-
if (err instanceof FetchError) {
|
|
138
|
-
const body = err.data as Partial<ApiErrorEnvelope> | undefined;
|
|
139
|
-
const code = statusToCode(err.status ?? 0, body?.error);
|
|
140
|
-
return makeErrorResult(code, err.message);
|
|
141
|
-
}
|
|
142
|
-
return makeErrorResult('NETWORK_ERROR', String(err));
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|