@bookinglab/booking-journey-api 1.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,404 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import * as _tanstack_react_query from '@tanstack/react-query';
4
+
5
+ /**
6
+ * Core API Client Types
7
+ */
8
+ interface ApiClientConfig {
9
+ baseUrl: string;
10
+ headers?: Record<string, string>;
11
+ timeout?: number;
12
+ }
13
+ interface RequestOptions extends RequestInit {
14
+ params?: Record<string, string | number | boolean | undefined>;
15
+ }
16
+ interface ApiResponse<T = any> {
17
+ data: T;
18
+ status: number;
19
+ headers: Headers;
20
+ }
21
+ interface ApiError {
22
+ message: string;
23
+ status?: number;
24
+ code?: string;
25
+ details?: any;
26
+ }
27
+ /**
28
+ * JRNI Configuration
29
+ */
30
+ interface JrniConfig {
31
+ appId: string;
32
+ appKey: string;
33
+ }
34
+ /**
35
+ * JRNI API Types
36
+ */
37
+ interface LoginRequest {
38
+ email: string;
39
+ password: string;
40
+ }
41
+ interface LoginResponse {
42
+ email: string;
43
+ auth_token: string;
44
+ company_id: number;
45
+ path: string;
46
+ role?: string;
47
+ _embedded?: {
48
+ members?: Array<{
49
+ id: number;
50
+ name: string;
51
+ first_name: string;
52
+ last_name: string;
53
+ email: string;
54
+ [key: string]: any;
55
+ }>;
56
+ administrators?: any[];
57
+ };
58
+ _links?: any;
59
+ }
60
+ interface JrniService {
61
+ id: number;
62
+ name: string;
63
+ description: string;
64
+ durations: number[];
65
+ prices: number[];
66
+ detail_group_id: number;
67
+ listed_durations: any[];
68
+ extra: Record<string, any>;
69
+ booking_time_step: number;
70
+ can_refund_automatically: boolean;
71
+ is_event_group: boolean;
72
+ type: string;
73
+ group_id: number | null;
74
+ deleted: boolean;
75
+ queuing_disabled: boolean;
76
+ company_id: number;
77
+ min_advance_period: number;
78
+ max_advance_period: number;
79
+ min_cancel_period: number;
80
+ booking_type_public: string;
81
+ booking_type: number;
82
+ mbooking_type: number;
83
+ min_bookings: number;
84
+ max_bookings: number;
85
+ method_of_appointment: string;
86
+ groups: any[];
87
+ order: number;
88
+ child_level_service: boolean;
89
+ global_id: number;
90
+ availability: number;
91
+ prices_in_major_units: number[];
92
+ combine_resource_and_staff: boolean;
93
+ disabled: boolean;
94
+ _links: Record<string, any>;
95
+ }
96
+ interface ServicesResponse {
97
+ total_entries: number;
98
+ _embedded: {
99
+ services: JrniService[];
100
+ };
101
+ _links: Record<string, any>;
102
+ }
103
+ interface QuestionOption {
104
+ name: string;
105
+ price: number;
106
+ is_default: boolean;
107
+ id: number;
108
+ }
109
+ interface Question {
110
+ id: number;
111
+ name: string;
112
+ required: boolean;
113
+ important: boolean;
114
+ admin_only: boolean;
115
+ applies_to: number;
116
+ ask_member: boolean;
117
+ detail_type: string;
118
+ options?: QuestionOption[];
119
+ settings: Record<string, any>;
120
+ price: number;
121
+ price_per_booking: boolean;
122
+ outcome: boolean;
123
+ hide_on_customer_journey: boolean;
124
+ default?: string;
125
+ help_text?: string;
126
+ _links: Record<string, any>;
127
+ }
128
+ interface QuestionsResponse {
129
+ company_id: number;
130
+ questions: Question[];
131
+ name: string;
132
+ _links: Record<string, any>;
133
+ }
134
+ interface Location {
135
+ id: number;
136
+ name: string;
137
+ description: string;
138
+ company_type: string;
139
+ address: {
140
+ id: number;
141
+ address1: string;
142
+ address2: string;
143
+ address3: string;
144
+ address4: string;
145
+ address5: string;
146
+ postcode: string;
147
+ country: string;
148
+ };
149
+ }
150
+ interface LocationsResponse {
151
+ total_entries: number;
152
+ _embedded: {
153
+ resources: Location[];
154
+ };
155
+ _links: Record<string, any>;
156
+ }
157
+ interface Vehicle {
158
+ id: number;
159
+ name: string;
160
+ description: string;
161
+ type: string;
162
+ extra: {
163
+ vehicle_registration?: string;
164
+ vehicle_make?: string;
165
+ vehicle_model?: string;
166
+ vehicle_size?: string;
167
+ fuel_type?: string;
168
+ vehicle_brand?: string;
169
+ vehicle_transmission?: string;
170
+ base_location?: string;
171
+ driver_name?: string;
172
+ driver_email?: string;
173
+ };
174
+ group_id: number | null;
175
+ deleted: boolean;
176
+ disabled: boolean;
177
+ company_id: number;
178
+ order: number;
179
+ created_at: string;
180
+ updated_at: string;
181
+ _links: Record<string, any>;
182
+ }
183
+ interface VehiclesResponse {
184
+ total_entries: number;
185
+ _embedded: {
186
+ people: Vehicle[];
187
+ };
188
+ _links: Record<string, any>;
189
+ }
190
+ interface AddBasketItemRequest {
191
+ service_id: number;
192
+ start: string;
193
+ duration: number;
194
+ company_id: string;
195
+ person_id: number;
196
+ questions: Array<{
197
+ id: string;
198
+ answer: string;
199
+ }>;
200
+ }
201
+ interface AvailabilityTime {
202
+ start: string;
203
+ available: boolean;
204
+ durations: number[];
205
+ prices: number[];
206
+ _links: Record<string, any>;
207
+ }
208
+ interface AvailabilityTimesResponse {
209
+ times: AvailabilityTime[];
210
+ }
211
+ interface JrniBooking {
212
+ id: number;
213
+ full_describe: string;
214
+ describe: string;
215
+ person_name: string;
216
+ datetime: string;
217
+ end_datetime: string;
218
+ duration: number;
219
+ service_name: string;
220
+ service_id: number;
221
+ status: string;
222
+ is_cancelled: boolean;
223
+ min_cancellation_time?: number;
224
+ person_ids?: number[];
225
+ settings?: {
226
+ current_multi_stat?: string;
227
+ multi_stats?: Record<string, string>;
228
+ obfuscated_id?: string;
229
+ who_updated?: string;
230
+ };
231
+ questions: Record<string, {
232
+ answer: string;
233
+ answer_id: number | null;
234
+ name: string;
235
+ }>;
236
+ _embedded?: {
237
+ answers?: Array<{
238
+ id: number;
239
+ value: string;
240
+ question_text: string;
241
+ }>;
242
+ };
243
+ }
244
+ interface MemberBookingsResponse {
245
+ total_entries: number;
246
+ _embedded: {
247
+ bookings: JrniBooking[];
248
+ };
249
+ _links: Record<string, any>;
250
+ }
251
+ interface PersonImage {
252
+ id: number;
253
+ name: string;
254
+ url: string;
255
+ order: number;
256
+ person_id?: number;
257
+ }
258
+ interface PersonImagesResponse {
259
+ _embedded: {
260
+ images: PersonImage[];
261
+ };
262
+ _links: Record<string, any>;
263
+ }
264
+ interface UpdateClientDetailsData {
265
+ first_name: string;
266
+ last_name: string;
267
+ mobile: string;
268
+ questions?: Record<string, {
269
+ answer: string;
270
+ }>;
271
+ }
272
+ interface UpdateMemberDetailsData {
273
+ first_name: string;
274
+ last_name: string;
275
+ mobile?: string;
276
+ q?: Record<string, {
277
+ answer: string;
278
+ answer_id: number;
279
+ name: string;
280
+ }>;
281
+ answers?: Array<{
282
+ question_id: number;
283
+ name: string;
284
+ answer: string;
285
+ answer_id: number;
286
+ }>;
287
+ }
288
+
289
+ /**
290
+ * Core API Client
291
+ * Base class for making HTTP requests
292
+ */
293
+
294
+ declare class ApiClient {
295
+ protected baseUrl: string;
296
+ protected headers: Record<string, string>;
297
+ protected timeout: number;
298
+ constructor(config: ApiClientConfig);
299
+ /**
300
+ * Update client configuration
301
+ */
302
+ setConfig(config: Partial<ApiClientConfig>): void;
303
+ /**
304
+ * Set authorization token
305
+ */
306
+ setAuthToken(token: string): void;
307
+ /**
308
+ * Make an HTTP request
309
+ */
310
+ protected request<T>(endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>>;
311
+ /**
312
+ * GET request
313
+ */
314
+ protected get<T>(endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>>;
315
+ /**
316
+ * POST request
317
+ */
318
+ protected post<T>(endpoint: string, body?: any, options?: RequestOptions): Promise<ApiResponse<T>>;
319
+ /**
320
+ * PUT request
321
+ */
322
+ protected put<T>(endpoint: string, body?: any, options?: RequestOptions): Promise<ApiResponse<T>>;
323
+ /**
324
+ * DELETE request
325
+ */
326
+ protected delete<T>(endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>>;
327
+ /**
328
+ * Handle error responses
329
+ */
330
+ private handleError;
331
+ /**
332
+ * Normalize errors to consistent format
333
+ */
334
+ private normalizeError;
335
+ }
336
+
337
+ /**
338
+ * JRNI API Client
339
+ * Provides methods for interacting with the JRNI API
340
+ */
341
+
342
+ declare class JrniClient extends ApiClient {
343
+ private appId;
344
+ private appKey;
345
+ constructor(baseUrl: string, config: JrniConfig);
346
+ /**
347
+ * Login to JRNI
348
+ */
349
+ login(credentials: LoginRequest): Promise<ApiResponse<LoginResponse>>;
350
+ /**
351
+ * Update JRNI configuration
352
+ */
353
+ setJrniConfig(config: Partial<JrniConfig>): void;
354
+ }
355
+ /**
356
+ * Create a new JRNI client instance
357
+ */
358
+ declare function createJrniClient(baseUrl: string, config: JrniConfig): JrniClient;
359
+
360
+ interface ApiClientContextValue {
361
+ jrniClient: JrniClient | null;
362
+ }
363
+ interface ApiClientProviderProps {
364
+ children: ReactNode;
365
+ jrniBaseUrl?: string;
366
+ jrniConfig?: JrniConfig;
367
+ }
368
+ /**
369
+ * Combined provider for multiple API clients
370
+ */
371
+ declare function ApiClientProvider({ children, jrniBaseUrl, jrniConfig, }: ApiClientProviderProps): react_jsx_runtime.JSX.Element;
372
+ /**
373
+ * Hook to access API client context
374
+ */
375
+ declare function useApiClientContext(): ApiClientContextValue;
376
+
377
+ interface JrniProviderProps {
378
+ children: ReactNode;
379
+ baseUrl: string;
380
+ config: JrniConfig;
381
+ }
382
+ /**
383
+ * Provider component for JRNI client
384
+ */
385
+ declare function JrniProvider({ children, baseUrl, config }: JrniProviderProps): react_jsx_runtime.JSX.Element;
386
+ /**
387
+ * Hook to access JRNI client from context
388
+ */
389
+ declare function useJrniContext(): JrniClient;
390
+
391
+ /**
392
+ * Hook to access API clients from context
393
+ */
394
+ /**
395
+ * Hook to get JRNI client from either ApiClientProvider or JrniProvider
396
+ */
397
+ declare function useJrniClient(): JrniClient;
398
+
399
+ /**
400
+ * Hook for JRNI login
401
+ */
402
+ declare function useLogin(): _tanstack_react_query.UseMutationResult<LoginResponse, Error, LoginRequest, unknown>;
403
+
404
+ export { type AddBasketItemRequest, ApiClient, type ApiClientConfig, ApiClientProvider, type ApiError, type ApiResponse, type AvailabilityTime, type AvailabilityTimesResponse, type JrniBooking, JrniClient, type JrniConfig, JrniProvider, type JrniService, type Location, type LocationsResponse, type LoginRequest, type LoginResponse, type MemberBookingsResponse, type PersonImage, type PersonImagesResponse, type Question, type QuestionOption, type QuestionsResponse, type RequestOptions, type ServicesResponse, type UpdateClientDetailsData, type UpdateMemberDetailsData, type Vehicle, type VehiclesResponse, createJrniClient, useApiClientContext, useJrniClient, useJrniContext, useLogin };
package/dist/index.js ADDED
@@ -0,0 +1,254 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var reactQuery = require('@tanstack/react-query');
6
+
7
+ // src/core.ts
8
+ var ApiClient = class {
9
+ constructor(config) {
10
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
11
+ this.headers = config.headers || {};
12
+ this.timeout = config.timeout || 3e4;
13
+ }
14
+ /**
15
+ * Update client configuration
16
+ */
17
+ setConfig(config) {
18
+ if (config.baseUrl) this.baseUrl = config.baseUrl.replace(/\/$/, "");
19
+ if (config.headers) this.headers = { ...this.headers, ...config.headers };
20
+ if (config.timeout) this.timeout = config.timeout;
21
+ }
22
+ /**
23
+ * Set authorization token
24
+ */
25
+ setAuthToken(token) {
26
+ this.headers["Authorization"] = `Bearer ${token}`;
27
+ }
28
+ /**
29
+ * Make an HTTP request
30
+ */
31
+ async request(endpoint, options = {}) {
32
+ const { params, ...fetchOptions } = options;
33
+ let url = `${this.baseUrl}${endpoint}`;
34
+ if (params) {
35
+ const searchParams = new URLSearchParams();
36
+ Object.entries(params).forEach(([key, value]) => {
37
+ if (value !== void 0) {
38
+ searchParams.append(key, String(value));
39
+ }
40
+ });
41
+ const queryString = searchParams.toString();
42
+ if (queryString) {
43
+ url += `?${queryString}`;
44
+ }
45
+ }
46
+ const headers = {
47
+ "Content-Type": "application/json",
48
+ ...this.headers,
49
+ ...fetchOptions.headers || {}
50
+ };
51
+ const controller = new AbortController();
52
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
53
+ try {
54
+ const response = await fetch(url, {
55
+ ...fetchOptions,
56
+ headers,
57
+ signal: controller.signal
58
+ });
59
+ clearTimeout(timeoutId);
60
+ if (!response.ok) {
61
+ throw await this.handleError(response);
62
+ }
63
+ const data = await response.json();
64
+ return {
65
+ data,
66
+ status: response.status,
67
+ headers: response.headers
68
+ };
69
+ } catch (error) {
70
+ clearTimeout(timeoutId);
71
+ throw this.normalizeError(error);
72
+ }
73
+ }
74
+ /**
75
+ * GET request
76
+ */
77
+ async get(endpoint, options) {
78
+ return this.request(endpoint, { ...options, method: "GET" });
79
+ }
80
+ /**
81
+ * POST request
82
+ */
83
+ async post(endpoint, body, options) {
84
+ return this.request(endpoint, {
85
+ ...options,
86
+ method: "POST",
87
+ body: body ? JSON.stringify(body) : void 0
88
+ });
89
+ }
90
+ /**
91
+ * PUT request
92
+ */
93
+ async put(endpoint, body, options) {
94
+ return this.request(endpoint, {
95
+ ...options,
96
+ method: "PUT",
97
+ body: body ? JSON.stringify(body) : void 0
98
+ });
99
+ }
100
+ /**
101
+ * DELETE request
102
+ */
103
+ async delete(endpoint, options) {
104
+ return this.request(endpoint, { ...options, method: "DELETE" });
105
+ }
106
+ /**
107
+ * Handle error responses
108
+ */
109
+ async handleError(response) {
110
+ let message = `HTTP ${response.status}: ${response.statusText}`;
111
+ let details;
112
+ try {
113
+ details = await response.json();
114
+ if (details.message) {
115
+ message = details.message;
116
+ } else if (details.error) {
117
+ message = details.error;
118
+ }
119
+ } catch {
120
+ }
121
+ return {
122
+ message,
123
+ status: response.status,
124
+ details
125
+ };
126
+ }
127
+ /**
128
+ * Normalize errors to consistent format
129
+ */
130
+ normalizeError(error) {
131
+ if (error.name === "AbortError") {
132
+ return {
133
+ message: "Request timeout",
134
+ code: "TIMEOUT"
135
+ };
136
+ }
137
+ if ("status" in error) {
138
+ return error;
139
+ }
140
+ return {
141
+ message: error.message || "Unknown error",
142
+ code: "UNKNOWN"
143
+ };
144
+ }
145
+ };
146
+
147
+ // src/jrni.ts
148
+ var JrniClient = class extends ApiClient {
149
+ constructor(baseUrl, config) {
150
+ super({ baseUrl });
151
+ this.appId = config.appId;
152
+ this.appKey = config.appKey;
153
+ }
154
+ /**
155
+ * Login to JRNI
156
+ */
157
+ async login(credentials) {
158
+ return this.post("/login", credentials, {
159
+ headers: {
160
+ "Content-Type": "application/json",
161
+ "App-Id": this.appId,
162
+ "App-Key": this.appKey
163
+ }
164
+ });
165
+ }
166
+ /**
167
+ * Update JRNI configuration
168
+ */
169
+ setJrniConfig(config) {
170
+ if (config.appId) this.appId = config.appId;
171
+ if (config.appKey) this.appKey = config.appKey;
172
+ }
173
+ };
174
+ function createJrniClient(baseUrl, config) {
175
+ return new JrniClient(baseUrl, config);
176
+ }
177
+ var ApiClientContext = react.createContext(void 0);
178
+ function ApiClientProvider({
179
+ children,
180
+ jrniBaseUrl,
181
+ jrniConfig
182
+ }) {
183
+ const jrniClient = react.useMemo(() => {
184
+ if (jrniBaseUrl && jrniConfig) {
185
+ return new JrniClient(jrniBaseUrl, jrniConfig);
186
+ }
187
+ return null;
188
+ }, [jrniBaseUrl, jrniConfig?.appId, jrniConfig?.appKey]);
189
+ const value = react.useMemo(
190
+ () => ({
191
+ jrniClient
192
+ }),
193
+ [jrniClient]
194
+ );
195
+ return /* @__PURE__ */ jsxRuntime.jsx(ApiClientContext.Provider, { value, children });
196
+ }
197
+ function useApiClientContext() {
198
+ const context = react.useContext(ApiClientContext);
199
+ if (context === void 0) {
200
+ throw new Error("useApiClientContext must be used within an ApiClientProvider");
201
+ }
202
+ return context;
203
+ }
204
+ var JrniContext = react.createContext(void 0);
205
+ function JrniProvider({ children, baseUrl, config }) {
206
+ const client = react.useMemo(() => {
207
+ return new JrniClient(baseUrl, config);
208
+ }, [baseUrl, config.appId, config.appKey]);
209
+ const value = react.useMemo(() => ({ client }), [client]);
210
+ return /* @__PURE__ */ jsxRuntime.jsx(JrniContext.Provider, { value, children });
211
+ }
212
+ function useJrniContext() {
213
+ const context = react.useContext(JrniContext);
214
+ if (context === void 0) {
215
+ throw new Error("useJrniContext must be used within a JrniProvider");
216
+ }
217
+ return context.client;
218
+ }
219
+
220
+ // src/hooks/useApiClient.ts
221
+ function useJrniClient() {
222
+ try {
223
+ return useJrniContext();
224
+ } catch {
225
+ const context = useApiClientContext();
226
+ if (!context.jrniClient) {
227
+ throw new Error(
228
+ "JRNI client not configured. Wrap your app with ApiClientProvider or JrniProvider."
229
+ );
230
+ }
231
+ return context.jrniClient;
232
+ }
233
+ }
234
+ function useLogin() {
235
+ const client = useJrniClient();
236
+ return reactQuery.useMutation({
237
+ mutationFn: async (credentials) => {
238
+ const response = await client.login(credentials);
239
+ return response.data;
240
+ }
241
+ });
242
+ }
243
+
244
+ exports.ApiClient = ApiClient;
245
+ exports.ApiClientProvider = ApiClientProvider;
246
+ exports.JrniClient = JrniClient;
247
+ exports.JrniProvider = JrniProvider;
248
+ exports.createJrniClient = createJrniClient;
249
+ exports.useApiClientContext = useApiClientContext;
250
+ exports.useJrniClient = useJrniClient;
251
+ exports.useJrniContext = useJrniContext;
252
+ exports.useLogin = useLogin;
253
+ //# sourceMappingURL=index.js.map
254
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core.ts","../src/jrni.ts","../src/providers/ApiClientProvider.tsx","../src/providers/JrniProvider.tsx","../src/hooks/useApiClient.ts","../src/hooks/useJrni.ts"],"names":["createContext","useMemo","jsx","useContext","useMutation"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Core API Client\n * Base class for making HTTP requests\n */\n\nimport { ApiClientConfig, RequestOptions, ApiResponse, ApiError } from './types';\n\nexport class ApiClient {\n protected baseUrl: string;\n protected headers: Record<string, string>;\n protected timeout: number;\n\n constructor(config: ApiClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.headers = config.headers || {};\n this.timeout = config.timeout || 30000;\n }\n\n /**\n * Update client configuration\n */\n setConfig(config: Partial<ApiClientConfig>) {\n if (config.baseUrl) this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n if (config.headers) this.headers = { ...this.headers, ...config.headers };\n if (config.timeout) this.timeout = config.timeout;\n }\n\n /**\n * Set authorization token\n */\n setAuthToken(token: string) {\n this.headers['Authorization'] = `Bearer ${token}`;\n }\n\n /**\n * Make an HTTP request\n */\n protected async request<T>(\n endpoint: string,\n options: RequestOptions = {}\n ): Promise<ApiResponse<T>> {\n const { params, ...fetchOptions } = options;\n\n // Build URL with query parameters\n let url = `${this.baseUrl}${endpoint}`;\n if (params) {\n const searchParams = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n searchParams.append(key, String(value));\n }\n });\n const queryString = searchParams.toString();\n if (queryString) {\n url += `?${queryString}`;\n }\n }\n\n // Merge headers\n const headers = {\n 'Content-Type': 'application/json',\n ...this.headers,\n ...((fetchOptions.headers as Record<string, string>) || {}),\n };\n\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n ...fetchOptions,\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw await this.handleError(response);\n }\n\n const data = await response.json();\n\n return {\n data,\n status: response.status,\n headers: response.headers,\n };\n } catch (error) {\n clearTimeout(timeoutId);\n throw this.normalizeError(error as Error);\n }\n }\n\n /**\n * GET request\n */\n protected async get<T>(endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>> {\n return this.request<T>(endpoint, { ...options, method: 'GET' });\n }\n\n /**\n * POST request\n */\n protected async post<T>(\n endpoint: string,\n body?: any,\n options?: RequestOptions\n ): Promise<ApiResponse<T>> {\n return this.request<T>(endpoint, {\n ...options,\n method: 'POST',\n body: body ? JSON.stringify(body) : undefined,\n });\n }\n\n /**\n * PUT request\n */\n protected async put<T>(\n endpoint: string,\n body?: any,\n options?: RequestOptions\n ): Promise<ApiResponse<T>> {\n return this.request<T>(endpoint, {\n ...options,\n method: 'PUT',\n body: body ? JSON.stringify(body) : undefined,\n });\n }\n\n /**\n * DELETE request\n */\n protected async delete<T>(endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>> {\n return this.request<T>(endpoint, { ...options, method: 'DELETE' });\n }\n\n /**\n * Handle error responses\n */\n private async handleError(response: Response): Promise<ApiError> {\n let message = `HTTP ${response.status}: ${response.statusText}`;\n let details: any;\n\n try {\n details = await response.json();\n if (details.message) {\n message = details.message;\n } else if (details.error) {\n message = details.error;\n }\n } catch {\n // Response body is not JSON\n }\n\n return {\n message,\n status: response.status,\n details,\n };\n }\n\n /**\n * Normalize errors to consistent format\n */\n private normalizeError(error: Error): ApiError {\n if (error.name === 'AbortError') {\n return {\n message: 'Request timeout',\n code: 'TIMEOUT',\n };\n }\n\n if ('status' in error) {\n return error as ApiError;\n }\n\n return {\n message: error.message || 'Unknown error',\n code: 'UNKNOWN',\n };\n }\n}\n","/**\n * JRNI API Client\n * Provides methods for interacting with the JRNI API\n */\n\nimport { ApiClient } from './core';\nimport { LoginRequest, LoginResponse, ApiResponse, JrniConfig } from './types';\n\nexport class JrniClient extends ApiClient {\n private appId: string;\n private appKey: string;\n\n constructor(baseUrl: string, config: JrniConfig) {\n super({ baseUrl });\n this.appId = config.appId;\n this.appKey = config.appKey;\n }\n\n /**\n * Login to JRNI\n */\n async login(credentials: LoginRequest): Promise<ApiResponse<LoginResponse>> {\n return this.post<LoginResponse>('/login', credentials, {\n headers: {\n 'Content-Type': 'application/json',\n 'App-Id': this.appId,\n 'App-Key': this.appKey,\n },\n });\n }\n\n /**\n * Update JRNI configuration\n */\n setJrniConfig(config: Partial<JrniConfig>) {\n if (config.appId) this.appId = config.appId;\n if (config.appKey) this.appKey = config.appKey;\n }\n}\n\n/**\n * Create a new JRNI client instance\n */\nexport function createJrniClient(baseUrl: string, config: JrniConfig) {\n return new JrniClient(baseUrl, config);\n}\n","/**\n * React Context Provider for API Clients\n * Combined provider for applications using multiple API clients\n */\n\nimport React, { createContext, useContext, useMemo, ReactNode } from 'react';\nimport { JrniClient } from '../jrni';\nimport { JrniConfig } from '../types';\n\ninterface ApiClientContextValue {\n jrniClient: JrniClient | null;\n}\n\ninterface ApiClientProviderProps {\n children: ReactNode;\n jrniBaseUrl?: string;\n jrniConfig?: JrniConfig;\n}\n\nconst ApiClientContext = createContext<ApiClientContextValue | undefined>(undefined);\n\n/**\n * Combined provider for multiple API clients\n */\nexport function ApiClientProvider({\n children,\n jrniBaseUrl,\n jrniConfig,\n}: ApiClientProviderProps) {\n const jrniClient = useMemo(() => {\n if (jrniBaseUrl && jrniConfig) {\n return new JrniClient(jrniBaseUrl, jrniConfig);\n }\n return null;\n }, [jrniBaseUrl, jrniConfig?.appId, jrniConfig?.appKey]);\n\n const value = useMemo(\n () => ({\n jrniClient,\n }),\n [jrniClient]\n );\n\n return <ApiClientContext.Provider value={value}>{children}</ApiClientContext.Provider>;\n}\n\n/**\n * Hook to access API client context\n */\nexport function useApiClientContext() {\n const context = useContext(ApiClientContext);\n if (context === undefined) {\n throw new Error('useApiClientContext must be used within an ApiClientProvider');\n }\n return context;\n}\n","/**\n * React Context Provider for JRNI API Client\n * Standalone provider for apps that only use JRNI\n */\n\nimport React, { createContext, useContext, useMemo, ReactNode } from 'react';\nimport { JrniClient } from '../jrni';\nimport { JrniConfig } from '../types';\n\ninterface JrniContextValue {\n client: JrniClient;\n}\n\ninterface JrniProviderProps {\n children: ReactNode;\n baseUrl: string;\n config: JrniConfig;\n}\n\nconst JrniContext = createContext<JrniContextValue | undefined>(undefined);\n\n/**\n * Provider component for JRNI client\n */\nexport function JrniProvider({ children, baseUrl, config }: JrniProviderProps) {\n const client = useMemo(() => {\n return new JrniClient(baseUrl, config);\n }, [baseUrl, config.appId, config.appKey]);\n\n const value = useMemo(() => ({ client }), [client]);\n\n return <JrniContext.Provider value={value}>{children}</JrniContext.Provider>;\n}\n\n/**\n * Hook to access JRNI client from context\n */\nexport function useJrniContext() {\n const context = useContext(JrniContext);\n if (context === undefined) {\n throw new Error('useJrniContext must be used within a JrniProvider');\n }\n return context.client;\n}\n","/**\n * Hook to access API clients from context\n */\n\nimport { useApiClientContext } from '../providers/ApiClientProvider';\nimport { useJrniContext } from '../providers/JrniProvider';\n\n/**\n * Hook to get JRNI client from either ApiClientProvider or JrniProvider\n */\nexport function useJrniClient() {\n // Try to get from standalone provider first\n try {\n return useJrniContext();\n } catch {\n // Fall back to combined provider\n const context = useApiClientContext();\n if (!context.jrniClient) {\n throw new Error(\n 'JRNI client not configured. Wrap your app with ApiClientProvider or JrniProvider.'\n );\n }\n return context.jrniClient;\n }\n}\n","/**\n * React hooks for JRNI API\n */\n\nimport { useMutation } from '@tanstack/react-query';\nimport { useJrniClient } from './useApiClient';\nimport { LoginRequest, LoginResponse } from '../types';\n\n/**\n * Hook for JRNI login\n */\nexport function useLogin() {\n const client = useJrniClient();\n\n return useMutation({\n mutationFn: async (credentials: LoginRequest) => {\n const response = await client.login(credentials);\n return response.data;\n },\n });\n}\n"]}