@jphil/bookwhen-client 0.2.6 → 0.3.1

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@jphil/bookwhen-client`
2
2
 
3
- An API client library for the [Bookwhen](https://www.bookwhen.com) booking platform [API (v2)](https://api.bookwhen.com/v2), written in Typescript for NodeJS. \[wip\]!
3
+ A universal API client library for the [Bookwhen](https://www.bookwhen.com) booking platform [API (v2)](https://api.bookwhen.com/v2), written in TypeScript for both NodeJS and browser environments.
4
4
 
5
5
  ## Table of Contents
6
6
 
@@ -19,7 +19,8 @@ You'll likely be at least somewhat familiar with the [Bookwhen](https://www.book
19
19
 
20
20
  ## Features
21
21
 
22
- - Provides an easy way to pull your data from Bookwhen for NodeJS environments
22
+ - Provides an easy way to access Bookwhen API from both NodeJS and browsers
23
+ - Browser-compatible with proper CORS handling
23
24
  - Provides fully typed methods for each model (so far just the Events model) provided in the Bookwhen API v2
24
25
 
25
26
  ## Installation
@@ -30,22 +31,32 @@ Install via pnpm:
30
31
  pnpm add @jphil/bookwhen-client
31
32
  ```
32
33
 
34
+ As `axios` and `zod` are peer dependencies, ensure they are also installed in your project:
35
+
36
+ ```bash
37
+ pnpm add axios zod
38
+ # or npm install axios zod
39
+ # or yarn add axios zod
40
+ ```
41
+
33
42
  ## Usage
34
43
 
44
+ This library is distributed as an ES module. The following usage pattern applies to modern Node.js environments (with `type: "module"` in your `package.json` or when using `.mjs` files) and browser environments when using a bundler. For direct browser usage without a bundler, see the [Browser Usage](#browser-usage) section below.
45
+
35
46
  ```typescript
36
47
  // import the client factory
37
48
  import { createBookwhenClient } from '@jphil/bookwhen-client';
38
49
 
39
50
  // create the client
40
- const client = createBookwhenClient({
51
+ const client = createBookwhenClient({
41
52
  apiKey: 'your-API-key',
42
- debug: true // Optional: enables request logging
53
+ debug: true, // Optional: enables request logging
43
54
  });
44
55
 
45
56
  // Get a single event
46
57
  const event = await client.events.getById({
47
58
  eventId: 'some-id',
48
- includes: ['location', 'tickets'] // Optional: include related resources
59
+ includes: ['location', 'tickets'], // Optional: include related resources
49
60
  });
50
61
 
51
62
  // get all events
@@ -53,27 +64,112 @@ const events = await client.events.getMultiple();
53
64
 
54
65
  // get all events in 2025 tagged with 'workshop'
55
66
  const events_2025 = await client.events.getMultiple({
56
- filters: { // Optional: filter by various
67
+ filters: {
68
+ // Optional: filter by various
57
69
  from: '20250101',
58
70
  to: '20251231',
59
- tag: ['workshop']
71
+ tag: ['workshop'],
60
72
  },
61
- includes: ['location'] // Optional: Include related resources
73
+ includes: ['location'], // Optional: Include related resources
62
74
  });
63
-
64
75
  ```
65
76
 
66
77
  (N.B. Ensure you wrap the above statements in try/catch blocks to catch errors which could be thrown)
67
78
 
68
- Valid filters and includes for each method are detailed in the [API v2 docs](https://petstore.swagger.io/?url=https://api.bookwhen.com/v2/openapi.yaml)
79
+ Valid filters and includes for each method are detailed in the [API v2 docs](https://petstore.swagger.io/?url=https://api.bookwhen.com/v2/openapi.yaml)
69
80
 
70
81
  Services for the other models in the API are in the pipeline.
71
82
 
72
- N.B. This library is still a pre-1.0.0 WIP, please use accordingly, and pls make issues for any bugs!
83
+ N.B. This library is still a pre-1.0.0 WIP, please use accordingly, and pls submit issues for any bugs!
84
+
85
+ ## Browser Usage
86
+
87
+ The client is well-suited for browser environments.
88
+
89
+ ### With a Bundler (Recommended for Browser Projects)
90
+
91
+ If you are using a JavaScript bundler (like Webpack, Rollup, Vite, Parcel, etc.) in your browser project, you can import and use the client as shown in the main [Usage](#usage) section:
92
+
93
+ ```typescript
94
+ import { createBookwhenClient } from '@jphil/bookwhen-client';
95
+ // ... rest of your code
96
+ ```
97
+
98
+ Ensure that `axios` and `zod` are also installed in your project, as they are peer dependencies. Your bundler will typically handle resolving these.
99
+
100
+ ### Directly with `<script type="module">` (Advanced)
101
+
102
+ For direct usage in a browser via `<script type="module">` without a bundler, you will need to:
103
+
104
+ 1. Ensure ES module versions of `axios` and `zod` are accessible to your page (e.g., served locally or via a CDN).
105
+ 2. Use an [import map](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) to tell the browser how to resolve the module specifiers for `@jphil/bookwhen-client`, `axios`, and `zod`.
106
+
107
+ Example import map:
108
+
109
+ ```html
110
+ <script type="importmap">
111
+ {
112
+ "imports": {
113
+ "@jphil/bookwhen-client": "/node_modules/@jphil/bookwhen-client/dist/index.es.js",
114
+ "axios": "/node_modules/axios/dist/esm/axios.js",
115
+ "zod": "/node_modules/zod/lib/index.mjs"
116
+ }
117
+ }
118
+ </script>
119
+ <script type="module">
120
+ import { createBookwhenClient } from '@jphil/bookwhen-client';
121
+ // ...
122
+ </script>
123
+ ```
124
+
125
+ Note: The exact paths in the import map will depend on how you serve these dependencies. Usage with a bundler is generally simpler for browser projects.
126
+
127
+ ### Important Note on API Keys in Client-Side Usage
128
+
129
+ When using this library in a browser (client-side), your Bookwhen API key will necessarily be included in the client-side code and thus visible.
130
+
131
+ - It is crucial to use an API key that has the minimum necessary permissions for the operations you intend to perform from the client-side.
132
+ - This library enables access to Bookwhen API endpoints based on the permissions granted to the API key you provide.
133
+
134
+ ## Error Handling
135
+
136
+ The library provides comprehensive error handling that works consistently in both Node.js and browser environments. Custom error objects thrown by the library will have the following properties:
137
+
138
+ - `code`: An error code string identifying the type of error (e.g., `NETWORK_ERROR`, `API_ERROR`).
139
+ - `message`: A human-readable description of the error.
140
+ - `isBrowser`: A boolean indicating if the error occurred in a browser environment.
141
+ - `context`: An object containing additional details, which may include the original error, status codes, etc.
142
+ - `timestamp`: The time the error occurred.
143
+
144
+ ### Error Types
145
+
146
+ - `NETWORK_ERROR`: Indicates a failure in API communication (e.g., DNS resolution, connection refused).
147
+ - `SECURITY_ERROR`: Specific to browsers, indicates security restrictions prevented API access (e.g., CORS issues not handled by the server, mixed content).
148
+ - `API_ERROR`: The Bookwhen API returned an error response (e.g., 4xx or 5xx status code). The `context` may include `statusCode` and `responseData`.
149
+ - `CONFIG_ERROR`: The client was configured incorrectly (e.g., missing API key).
150
+ - `UNKNOWN_ERROR`: An unexpected error occurred within the library.
151
+
152
+ Example:
153
+
154
+ ```typescript
155
+ try {
156
+ await client.events.getById({ eventId: 'invalid-id' });
157
+ } catch (error: any) {
158
+ // It's good practice to type the error if you have custom error types defined
159
+ console.error(`Error Code: ${error.code}`);
160
+ console.error(`Message: ${error.message}`);
161
+ if (error.code === 'API_ERROR') {
162
+ console.error('API Error Details:', error.context?.responseData);
163
+ } else if (error.code === 'NETWORK_ERROR') {
164
+ // Handle network issues, maybe retry or inform user
165
+ }
166
+ // Other error handling...
167
+ }
168
+ ```
73
169
 
74
170
  ## Configuration
75
171
 
76
- Required configuration options:
172
+ Required configuration:
77
173
 
78
174
  - **apiKey**: Your Bookwhen API key (required)
79
175
 
@@ -85,6 +181,43 @@ API keys can be generated in the [API tokens setup area of your Bookwhen account
85
181
 
86
182
  Please see the docs in the CONTRIBUTIONS.md file, thanks!
87
183
 
184
+ ## Mainainter release process
185
+
186
+ [refining]
187
+
188
+ From main branch on local:
189
+
190
+ - Pull latest code
191
+ - git checkout -b some-new-branch
192
+ - git commit -m 'feat(context): my latest work on feature x'
193
+ - git push, copy URL
194
+
195
+ On github
196
+
197
+ > Open PR on github
198
+ > Perfect, merge when checks pass
199
+
200
+ On local:
201
+
202
+ - checkout main
203
+ - git pull
204
+ - git branch -d release (so we have a clean release branch)
205
+ - git checkout -b release
206
+ - pnpm changeset (provide changelog message, commit will occur after)
207
+ - pnpm changeset version (bumps version numbers, and updates changelog, and commits >>> note new version number)
208
+ - git push
209
+
210
+ On github:
211
+
212
+ - Open PR main <- release on github
213
+ > Perfect, merge when checks pass (check why no build)
214
+
215
+ On local:
216
+
217
+ - git checkout main
218
+ - git tag -a vx.x.x -m 'release vx.x.x'
219
+ - git push origin vx.x.x <<<< RELEASE to github and NPM
220
+
88
221
  ## Roadmap
89
222
 
90
223
  - Proceed towards a 1.0.0 with community feedback.
@@ -92,9 +225,7 @@ Please see the docs in the CONTRIBUTIONS.md file, thanks!
92
225
 
93
226
  ### Todos
94
227
 
95
- - [] create e2e test suite with github action workflow
96
- - [] put Zod in place in more areas to strengthen runtime type guards
97
- - [] write services for the other models in the API
228
+ @see the issue queue.
98
229
 
99
230
  ## License
100
231
 
package/dist/index.d.ts CHANGED
@@ -1,3 +1,199 @@
1
- export * from './types/GlobalTypes.js';
2
- export * from './services/event/EventInterfaces.js';
3
- export { createBookwhenClient } from './client/BookwhenClient.js';
1
+ import { AxiosInstance } from 'axios';
2
+ import { z } from 'zod';
3
+
4
+ /**
5
+ * Client for the Bookwhen API.
6
+ *
7
+ * @see https://petstore.swagger.io/?url=https://api.bookwhen.com/v2/openapi.yaml#/ClassPass/get_class_passes__class_pass_id_
8
+ */
9
+ declare class BookwhenClient {
10
+ private axiosInstance;
11
+ private eventService?;
12
+ private readonly isBrowser;
13
+ /**
14
+ * Creates a new instance of the BookwhenClient class.
15
+ * @param axiosInstance - Configured Axios instance for making HTTP requests.
16
+ * @throws Error if axiosInstance is not provided.
17
+ */
18
+ constructor(axiosInstance: AxiosInstance);
19
+ /**
20
+ * Gets the EventService instance.
21
+ *
22
+ * Available methods:
23
+ * - getById(params: GetEventByIdParams): Promise<BookwhenEvent>
24
+ * - getMultiple(params: GetMultipleEventsParams): Promise<BookwhenEvent[]>
25
+ *
26
+ * @returns The EventService instance.
27
+ */
28
+ get events(): EventService;
29
+ }
30
+
31
+ declare interface BookwhenClientOptions {
32
+ apiKey: string;
33
+ baseURL?: string;
34
+ debug?: boolean;
35
+ }
36
+
37
+ export declare interface BookwhenError {
38
+ code: 'NETWORK_ERROR' | 'SECURITY_ERROR' | 'API_ERROR' | 'CONFIG_ERROR' | 'UNKNOWN_ERROR';
39
+ message: string;
40
+ isBrowser: boolean;
41
+ context?: {
42
+ browser?: {
43
+ isSecure?: boolean;
44
+ userAgent?: string;
45
+ };
46
+ timestamp: number;
47
+ };
48
+ }
49
+
50
+ declare interface BookwhenEvent {
51
+ id: string;
52
+ type: string;
53
+ attributes: EventAttributes;
54
+ }
55
+
56
+ /**
57
+ * Creates an instance of Axios with the provided API key.
58
+ * @param apiKey - The API key used for authentication.
59
+ * @returns The Axios instance.
60
+ */
61
+ export declare function createBookwhenClient(options: BookwhenClientOptions): BookwhenClient;
62
+
63
+ declare interface EventAttributes {
64
+ title: string;
65
+ details: string;
66
+ all_day: boolean;
67
+ start_at: string;
68
+ end_at: string;
69
+ attendee_limit: number;
70
+ attendee_count: number;
71
+ waiting_list: boolean;
72
+ max_tickets_per_booking: number;
73
+ tags: string[];
74
+ event_image: EventImage;
75
+ }
76
+
77
+ export declare type EventFilters = {
78
+ [K in keyof EventFiltersMap]?: EventFiltersMap[K];
79
+ };
80
+
81
+ declare interface EventFiltersMap {
82
+ calendar?: string[];
83
+ entry?: string[];
84
+ location?: string[];
85
+ tag?: string[];
86
+ title?: string[];
87
+ detail?: string[];
88
+ from?: string;
89
+ to?: string;
90
+ compact?: boolean;
91
+ }
92
+
93
+ declare interface EventImage {
94
+ image_url: string;
95
+ alt_ratio_16x9_1x_url: string;
96
+ alt_ratio_16x9_2x_url: string;
97
+ alt_ratio_16x9_3x_url: string;
98
+ alt_ratio_4x3_1x_url: string;
99
+ alt_ratio_4x3_2x_url: string;
100
+ alt_ratio_4x3_3x_url: string;
101
+ alt_ratio_1x1_1x_url: string;
102
+ alt_ratio_1x1_2x_url: string;
103
+ alt_ratio_1x1_3x_url: string;
104
+ }
105
+
106
+ export declare type EventResource = 'location' | 'attachments' | 'tickets' | 'tickets.events' | 'tickets.class_passes';
107
+
108
+ /**
109
+ * Service class for managing events in the Bookwhen API.
110
+ */
111
+ declare class EventService implements IEventService {
112
+ private axiosInstance;
113
+ /**
114
+ * Initializes EventService with an Axios instance for dependency injection.
115
+ * @param axiosInstance - The Axios instance to use for API requests.
116
+ */
117
+ constructor(axiosInstance: AxiosInstance);
118
+ /**
119
+ * Retrieves a single event by its ID from the Bookwhen API.
120
+ *
121
+ * @param {Object} param - The parameters for retrieving an event.
122
+ * @param {string} param.eventId - The ID of the event to retrieve.
123
+ * @param {string} [param.include] - Optional parameter to include additional data.
124
+ * @returns {Promise<BookwhenEvent>} A Promise that resolves to the BookwhenEvent object.
125
+ */
126
+ getById(params: z.infer<typeof GetEventByIdParamsSchema>): Promise<BookwhenEvent>;
127
+ /**
128
+ * Retrieves multiple events based on filtering and pagination parameters.
129
+ *
130
+ * @param {GetMultipleEventsParams} params - Optional parameters for filtering and pagination.
131
+ * @return {Promise<BookwhenEvent[]>} A Promise that resolves to an array of BookwhenEvent objects.
132
+ */
133
+ getMultiple(params?: GetMultipleEventsParams): Promise<BookwhenEvent[]>;
134
+ }
135
+
136
+ export declare interface Filters {
137
+ [key: string]: string | string[] | boolean;
138
+ }
139
+
140
+ /**
141
+ * Parameters for querying a single event from the Bookwhen API, including optional include parameter.
142
+ * @param eventId The unique identifier of the event.
143
+ * @param include Optional parameter to include additional data.
144
+ */
145
+ export declare interface GetEventByIdParams {
146
+ eventId: string;
147
+ includes?: EventResource[];
148
+ }
149
+
150
+ declare const GetEventByIdParamsSchema: z.ZodObject<{
151
+ eventId: z.ZodString;
152
+ includes: z.ZodOptional<z.ZodArray<z.ZodEnum<["location", "attachments", "tickets", "tickets.events", "tickets.class_passes"]>, "many">>;
153
+ }, "strip", z.ZodTypeAny, {
154
+ eventId: string;
155
+ includes?: ("location" | "attachments" | "tickets" | "tickets.events" | "tickets.class_passes")[] | undefined;
156
+ }, {
157
+ eventId: string;
158
+ includes?: ("location" | "attachments" | "tickets" | "tickets.events" | "tickets.class_passes")[] | undefined;
159
+ }>;
160
+
161
+ /**
162
+ * Represents the parameters for getting multiple events.
163
+ * @param filter The filter parameters to apply to the query.
164
+ * @param include The data to side load and include with the returned events.
165
+ */
166
+ export declare interface GetMultipleEventsParams {
167
+ filters?: EventFilters;
168
+ includes?: EventResource[];
169
+ }
170
+
171
+ export declare interface HttpStatus {
172
+ code: number;
173
+ message: string;
174
+ }
175
+
176
+ /**
177
+ * Interface for services handling events via the Bookwhen API V2.
178
+ */
179
+ export declare interface IEventService {
180
+ /**
181
+ * Retrieves a single event by its ID.
182
+ * @param eventId The unique identifier of the event.
183
+ * @param include Optional parameter to include additional data.
184
+ * @returns A Promise that resolves to an Event object, as defined by the Bookwhen API data structure.
185
+ */
186
+ getById(params: GetEventByIdParams): Promise<BookwhenEvent>;
187
+ /**
188
+ * Retrieves multiple events based on specified parameters.
189
+ * @param params Optional parameters to filter and control the list of returned events, according to what the Bookwhen API supports.
190
+ * @returns A Promise that resolves to an array of Event objects.
191
+ */
192
+ getMultiple?(params?: GetMultipleEventsParams): Promise<BookwhenEvent[]>;
193
+ }
194
+
195
+ export declare type Resource = string;
196
+
197
+ export declare type Resources = Resource[];
198
+
199
+ export { }