@blazeo.com/appointment-client 1.0.6 → 1.0.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.
Files changed (60) hide show
  1. package/blazeo.com-appointment-client-1.0.7.tgz +0 -0
  2. package/dist/calendar/buildUnifiedCalendarView.d.ts +8 -0
  3. package/dist/calendar/buildUnifiedCalendarView.js +20 -5
  4. package/dist/calendar/fetchCalendarDetails.d.ts +8 -40
  5. package/dist/calendar/fetchCalendarDetails.js +116 -47
  6. package/dist/calendar/fetchCalendarWithOpeningHours.d.ts +1 -10
  7. package/dist/calendar/fetchCalendarWithOpeningHours.js +34 -15
  8. package/dist/calendar/getAllParticipantOpeningHours.d.ts +4 -1
  9. package/dist/calendar/getAllParticipantOpeningHours.js +6 -1
  10. package/dist/calendar/getOpeningHours.d.ts +4 -1
  11. package/dist/calendar/getOpeningHours.js +2 -2
  12. package/dist/calendar/getParticipantOpeningHours.js +9 -4
  13. package/dist/calendar/getParticipants.d.ts +4 -1
  14. package/dist/calendar/getParticipants.js +6 -1
  15. package/dist/calendar/mapToDesiredResponse.d.ts +70 -0
  16. package/dist/calendar/mapToDesiredResponse.js +99 -0
  17. package/dist/config/applyBlazeoDefaults.js +3 -2
  18. package/dist/config/blazeoClientDefaults.js +2 -2
  19. package/dist/config/ensureBlazeoHttpReady.d.ts +17 -0
  20. package/dist/config/ensureBlazeoHttpReady.js +31 -0
  21. package/dist/config/initializeAppointmentClient.d.ts +4 -0
  22. package/dist/config/initializeAppointmentClient.js +9 -3
  23. package/dist/config/syncBlazeoConnection.d.ts +6 -0
  24. package/dist/config/syncBlazeoConnection.js +18 -0
  25. package/dist/index.d.ts +4 -1
  26. package/dist/index.js +3 -1
  27. package/package.json +1 -1
  28. package/sample/.env.example +5 -0
  29. package/sample/package-lock.json +1 -1
  30. package/sample/src/AllParticipantOpeningHoursTab.jsx +13 -4
  31. package/sample/src/App2.jsx +22 -2
  32. package/sample/src/AvailabilityTab.jsx +8 -3
  33. package/sample/src/BlazeoConnectionSettings.jsx +16 -15
  34. package/sample/src/CreateCalendarTab.jsx +23 -6
  35. package/sample/src/EventTab.jsx +31 -8
  36. package/sample/src/FetchCalendarTab.jsx +70 -44
  37. package/sample/src/OpeningHoursTab.jsx +13 -4
  38. package/sample/src/ParticipantInfoTab.jsx +8 -3
  39. package/sample/src/ParticipantOpeningHoursTab.jsx +17 -7
  40. package/sample/src/ParticipantTab.jsx +13 -4
  41. package/sample/src/blazeoBootstrap.js +30 -0
  42. package/sample/src/blazeoDemoError.js +14 -0
  43. package/sample/src/blazeoPushConnection.js +23 -0
  44. package/sample/src/main.jsx +3 -3
  45. package/sample/vite.config.js +19 -5
  46. package/src/calendar/buildUnifiedCalendarView.ts +28 -5
  47. package/src/calendar/fetchCalendarDetails.ts +316 -226
  48. package/src/calendar/fetchCalendarWithOpeningHours.ts +130 -99
  49. package/src/calendar/getAllParticipantOpeningHours.ts +9 -1
  50. package/src/calendar/getOpeningHours.ts +2 -2
  51. package/src/calendar/getParticipantOpeningHours.ts +14 -5
  52. package/src/calendar/getParticipants.ts +9 -1
  53. package/src/calendar/mapToDesiredResponse.ts +104 -0
  54. package/src/config/applyBlazeoDefaults.ts +3 -2
  55. package/src/config/blazeoClientDefaults.ts +2 -2
  56. package/src/config/ensureBlazeoHttpReady.ts +41 -0
  57. package/src/config/initializeAppointmentClient.ts +9 -3
  58. package/src/config/syncBlazeoConnection.ts +19 -0
  59. package/src/index.ts +7 -1
  60. package/blazeo.com-appointment-client-1.0.6.tgz +0 -0
@@ -6,18 +6,26 @@ export interface UnifiedCalendarMember {
6
6
  status: number | null;
7
7
  /** Full row from Participants/GetInfo (plain object). */
8
8
  participantInfo?: Record<string, unknown> | null;
9
+ __typename?: string;
9
10
  }
10
11
  export interface UnifiedParticipantWithHours extends UnifiedCalendarMember {
11
12
  openingHours: UnifiedOpeningHourRow[];
12
13
  }
13
14
  export interface UnifiedOpeningHourRow {
15
+ id?: number | string;
16
+ createdOn?: string;
17
+ modifiedOn?: string;
14
18
  member: number | string;
19
+ openingHourId?: string;
20
+ calendarId?: string;
21
+ participantId?: string;
15
22
  days: string[];
16
23
  startHour: number;
17
24
  startMinute: number;
18
25
  endHour: number;
19
26
  endMinute: number;
20
27
  off: boolean;
28
+ __typename?: string;
21
29
  }
22
30
  export type UnifiedCalendarView = Record<string, unknown> & {
23
31
  members: UnifiedCalendarMember[];
@@ -206,6 +206,7 @@ export function buildUnifiedCalendarView(calendarSnapshot, openingHoursRows, par
206
206
  email: email ?? null,
207
207
  status: deriveMemberStatus({}, inf),
208
208
  participantInfo: participantInfoPlain,
209
+ __typename: "Member",
209
210
  });
210
211
  }
211
212
  }
@@ -227,13 +228,20 @@ export function buildUnifiedCalendarView(calendarSnapshot, openingHoursRows, par
227
228
  const endMinute = Number(pick(row, "endMinute", "EndMinute", "end_minute") ?? 0) || 0;
228
229
  const off = Boolean(pick(row, "off", "Off"));
229
230
  openingHours.push({
231
+ id: pick(row, "id", "Id") ?? 0,
232
+ createdOn: pick(row, "createdOn", "CreatedOn", "created_on") ?? "0001-01-01T00:00:00.000Z",
233
+ modifiedOn: pick(row, "modifiedOn", "ModifiedOn", "modified_on") ?? "0001-01-01T00:00:00.000Z",
230
234
  member: memberId,
235
+ openingHourId: pick(row, "openingHourId", "OpeningHourId", "opening_hour_id") ?? "",
236
+ calendarId: pick(row, "calendarId", "CalendarId", "calendar_id") ?? "",
237
+ participantId: pick(row, "participantId", "ParticipantId", "participant_id") ?? "",
231
238
  days,
232
239
  startHour,
233
240
  startMinute,
234
241
  endHour,
235
242
  endMinute,
236
243
  off,
244
+ __typename: "OpeningHour",
237
245
  });
238
246
  }
239
247
  mergeOpeningHoursBySlot(openingHours);
@@ -242,6 +250,7 @@ export function buildUnifiedCalendarView(calendarSnapshot, openingHoursRows, par
242
250
  members,
243
251
  openingHours,
244
252
  participants: buildNestedParticipants(members, openingHours),
253
+ __typename: "Calendar",
245
254
  };
246
255
  return view;
247
256
  }
@@ -249,17 +258,23 @@ export function buildUnifiedCalendarView(calendarSnapshot, openingHoursRows, par
249
258
  * Groups opening hours into their respective participant objects.
250
259
  */
251
260
  function buildNestedParticipants(members, openingHours) {
252
- return members.map((m) => {
253
- const hours = openingHours.filter((oh) => {
261
+ const nested = [];
262
+ members.forEach((m) => {
263
+ const hoursForThisMember = openingHours.filter((oh) => {
254
264
  const mid = String(oh.member).trim().toLowerCase();
255
265
  const pid = String(m.id).trim().toLowerCase();
256
266
  return mid === pid;
257
267
  });
258
268
  // Remove the 'member' field from the nested opening hours as it's redundant.
259
- const nestedHours = hours.map(({ member, ...rest }) => rest);
260
- return {
269
+ const nestedHours = hoursForThisMember.map(({ member, ...rest }) => ({
270
+ ...rest,
271
+ __typename: "OpeningHour"
272
+ }));
273
+ nested.push({
261
274
  ...m,
262
275
  openingHours: nestedHours,
263
- };
276
+ __typename: "Member",
277
+ });
264
278
  });
279
+ return nested;
265
280
  }
@@ -25,49 +25,17 @@ export declare function fetchCalendarDetails(calendarId: string, options?: {
25
25
  includeUnifiedCalendarView?: boolean;
26
26
  /** Prefer all-participant opening hours for **`calendarView`** when the API returns rows (default `true`). */
27
27
  preferAllParticipantOpeningHours?: boolean;
28
- }): Promise<{
29
- calendar: null;
30
- cal: null;
31
- calendarView: UnifiedCalendarView | null;
32
- openingHours: any[];
33
- participants: any[];
34
- participantsInfo: any;
35
- allParticipantOpeningHours: any[] | null;
36
- embeddedFromGet: any[];
37
- fromCalendarGet: boolean;
38
- fromParticipantApi: boolean;
39
- participantOpeningHoursResponse: any;
40
- rawGet: any;
41
- meta: {
42
- ok: false;
43
- reason: string;
44
- };
45
- } | {
46
- calendar: any;
47
- cal: any;
48
- calendarView: UnifiedCalendarView | null;
49
- openingHours: any[];
50
- participants: any[];
51
- participantsInfo: unknown;
52
- allParticipantOpeningHours: any[] | null;
53
- embeddedFromGet: any[];
54
- fromCalendarGet: boolean;
55
- fromParticipantApi: boolean;
56
- participantOpeningHoursResponse: any;
57
- meta: {
58
- calendarViewMemberCount?: number | undefined;
59
- calendarViewOpeningHourCount?: number | undefined;
60
- ok: true;
61
- /** `calendarView.openingHours` came from OpeningHours/All/Get */
62
- calendarViewUsedAllParticipantOpeningHours: boolean;
63
- reason?: undefined;
64
- };
65
- rawGet?: undefined;
66
- }>;
28
+ /** Optional; applied with `resolveBlazeoConnection` so `CalendarModel.get` sees `baseUrl` without prior global `configure`. */
29
+ baseUrl?: string;
30
+ consumer?: string;
31
+ }): Promise<any>;
67
32
  /**
68
33
  * Single return value only: unified calendar **`calendarView`** —
69
34
  * snapshot fields plus **`members`** (with **`participantInfo`**) plus **`openingHours`**
70
35
  * (prefers all-participant opening hours when available). Same shape as `fetchCalendarDetails().calendarView`.
71
36
  * Returns **`null`** if the calendar cannot be loaded (`CalendarModel.get`).
72
37
  */
73
- export declare function fetchCalendarBundle(calendarId: string): Promise<UnifiedCalendarView | null>;
38
+ export declare function fetchCalendarBundle(calendarId: string, connection?: {
39
+ baseUrl?: string;
40
+ consumer?: string;
41
+ }): Promise<UnifiedCalendarView | null>;
@@ -1,7 +1,8 @@
1
1
  import { CalendarModel } from "@blazeo.com/calendar-client";
2
- import { getSnapshot } from "mobx-state-tree";
2
+ import { ensureBlazeoHttpReady } from "../config/ensureBlazeoHttpReady.js";
3
3
  import { unwrapCalendarGetData, pickOpeningHoursArrayFromCalendarPayload, normalizeParticipantOpeningHoursResponse, } from "./fetchCalendarWithOpeningHours.js";
4
4
  import { buildUnifiedCalendarView } from "./buildUnifiedCalendarView.js";
5
+ import { mapToDesiredCalendarResponse } from "./mapToDesiredResponse.js";
5
6
  /**
6
7
  * Normalizes the REST envelope from `calendar.getParticipantOpeningHours()`
7
8
  * (`GET /Calendar/Participant/OpeningHours/Get`) into a plain row array.
@@ -83,21 +84,37 @@ function unwrapModelList(raw) {
83
84
  * Server still performs multiple HTTP calls; on the client, **`calendarView`** is returned as **one object**.
84
85
  */
85
86
  export async function fetchCalendarDetails(calendarId, options = {}) {
86
- const { includeParticipantsInfo = false, includeUnifiedCalendarView = true, preferAllParticipantOpeningHours = true, } = options;
87
+ const { includeParticipantsInfo = false, includeUnifiedCalendarView = true, preferAllParticipantOpeningHours = true, baseUrl: optBaseUrl, consumer: optConsumer, } = options;
88
+ const conn = ensureBlazeoHttpReady({ baseUrl: optBaseUrl, consumer: optConsumer });
89
+ if (!conn.ok) {
90
+ return {
91
+ calendar: null,
92
+ cal: null,
93
+ calendarView: null,
94
+ openingHours: [],
95
+ participants: [],
96
+ participantsInfo: null,
97
+ allParticipantOpeningHours: null,
98
+ embeddedFromGet: [],
99
+ fromCalendarGet: false,
100
+ fromParticipantApi: false,
101
+ participantOpeningHoursResponse: null,
102
+ rawGet: null,
103
+ meta: { ok: false, reason: "missing_base_url", detail: conn.error },
104
+ };
105
+ }
87
106
  const fetchParticipantsInfo = includeParticipantsInfo || includeUnifiedCalendarView;
88
107
  const fetchAllHours = includeUnifiedCalendarView && preferAllParticipantOpeningHours;
89
- // Calendar: `GET /Calendar/Get` is used twice (model + raw for embed) — run in parallel.
90
- const [cal, rawRes] = await Promise.all([
91
- CalendarModel.get(calendarId),
92
- CalendarModel.getRaw(calendarId),
93
- ]);
94
- if (cal == null) {
108
+ // Calendar: `GET /Calendar/Get` is used to get the raw data first.
109
+ const rawRes = await CalendarModel.getRaw(calendarId);
110
+ const payload = unwrapCalendarGetData(rawRes);
111
+ if (!payload) {
95
112
  return {
96
113
  calendar: null,
97
114
  cal: null,
98
115
  calendarView: null,
99
116
  openingHours: [],
100
- participants: [],
117
+ participants: null,
101
118
  participantsInfo: null,
102
119
  allParticipantOpeningHours: null,
103
120
  embeddedFromGet: [],
@@ -108,7 +125,9 @@ export async function fetchCalendarDetails(calendarId, options = {}) {
108
125
  meta: { ok: false, reason: "calendar_not_found" },
109
126
  };
110
127
  }
111
- const payload = unwrapCalendarGetData(rawRes);
128
+ // Build the model instance manually to ensure the environment is correctly set.
129
+ // The static CalendarModel.get in calendar-client has a bug where it wraps env in { env: ... }.
130
+ const cal = CalendarModel.create({ ...payload, calendarId }, { baseUrl: conn.baseUrl, consumer: conn.consumer });
112
131
  const embedded = pickOpeningHoursArrayFromCalendarPayload(payload) ?? [];
113
132
  let participantOpeningHoursResponse = null;
114
133
  let resolved = embedded.length > 0 ? embedded : null;
@@ -124,17 +143,69 @@ export async function fetchCalendarDetails(calendarId, options = {}) {
124
143
  const participantsViaGetPromise = includeUnifiedCalendarView && typeof getCalPart === "function"
125
144
  ? getCalPart.call(CalendarModel, calendarId)
126
145
  : Promise.resolve(null);
127
- const [participants, participantsViaGet, participantsInfo, allHoursRaw] = await Promise.all([
128
- CalendarModel.getParticipants(calendarId),
146
+ const [participantsRaw, participantsViaGet, participantsInfoRaw, allHoursRaw] = await Promise.all([
147
+ cal.getParticipants(),
129
148
  participantsViaGetPromise,
130
- fetchParticipantsInfo ? CalendarModel.getParticipantsInfo(calendarId) : Promise.resolve(null),
131
- fetchAllHours ? CalendarModel.getAllParticipantOpeningHours(calendarId) : Promise.resolve(null),
149
+ fetchParticipantsInfo ? cal.getParticipantsInfo() : Promise.resolve(null),
150
+ fetchAllHours ? cal.getAllParticipantOpeningHours() : Promise.resolve(null),
132
151
  ]);
133
- const snap = getSnapshot(cal);
134
- const calendar = { ...snap, openingHours };
135
- const participantList = mergeParticipantSnapshots(unwrapModelList(participants), unwrapModelList(participantsViaGet));
136
- const infoUnwrapped = fetchParticipantsInfo ? unwrapModelList(participantsInfo) : [];
137
- const infoListForView = infoUnwrapped.length > 0 ? infoUnwrapped : null;
152
+ const participantList = mergeParticipantSnapshots(unwrapModelList(participantsRaw), unwrapModelList(participantsViaGet));
153
+ const infoList = unwrapModelList(participantsInfoRaw);
154
+ // Merge participantList and infoList to ensure we have all members
155
+ const mergedParticipantsMap = new Map();
156
+ const getAnyId = (obj) => obj.id ?? obj.Id ?? obj.participantId ?? obj.ParticipantId ?? obj.participant_id;
157
+ // 1. Add from standard list
158
+ participantList.forEach((p) => {
159
+ const id = getAnyId(p);
160
+ if (id) {
161
+ mergedParticipantsMap.set(String(id).toLowerCase(), {
162
+ id: id,
163
+ name: p.name ?? p.Name ?? p.alias ?? p.Alias ?? "Member",
164
+ email: p.email ?? p.Email,
165
+ status: p.status ?? p.Status ?? 0,
166
+ });
167
+ }
168
+ });
169
+ // 2. Add from info list (fallback/enrich)
170
+ infoList.forEach((i) => {
171
+ const id = getAnyId(i);
172
+ if (!id)
173
+ return;
174
+ const key = String(id).toLowerCase();
175
+ const existing = mergedParticipantsMap.get(key);
176
+ if (!existing) {
177
+ mergedParticipantsMap.set(key, {
178
+ id: id,
179
+ name: i.alias || i.Alias || i.name || i.Name || "Member",
180
+ email: i.email || i.Email,
181
+ status: i.status ?? i.Status ?? (i.isApproved ? 1 : 0),
182
+ });
183
+ }
184
+ else {
185
+ // Enrich existing with email/name if missing
186
+ if (!existing.email)
187
+ existing.email = i.email || i.Email;
188
+ if (!existing.name || existing.name === "Member") {
189
+ existing.name = i.alias || i.Alias || i.name || i.Name || existing.name;
190
+ }
191
+ }
192
+ });
193
+ // 3. Synthetic Fallback: If openingHours reference a member we don't have, add them.
194
+ openingHours.forEach((oh) => {
195
+ const mid = oh.member ?? oh.Member ?? oh.participantId ?? oh.ParticipantId;
196
+ if (mid) {
197
+ const key = String(mid).toLowerCase();
198
+ if (!mergedParticipantsMap.has(key)) {
199
+ mergedParticipantsMap.set(key, {
200
+ id: mid,
201
+ name: "Member",
202
+ email: null,
203
+ status: 0,
204
+ });
205
+ }
206
+ }
207
+ });
208
+ const finalParticipantList = Array.from(mergedParticipantsMap.values());
138
209
  const allParticipantOpeningHours = fetchAllHours ? normalizeAllParticipantOpeningHoursResult(allHoursRaw) : null;
139
210
  const openingHoursForUnifiedView = includeUnifiedCalendarView &&
140
211
  preferAllParticipantOpeningHours &&
@@ -142,37 +213,34 @@ export async function fetchCalendarDetails(calendarId, options = {}) {
142
213
  allParticipantOpeningHours.length > 0
143
214
  ? allParticipantOpeningHours
144
215
  : openingHours;
145
- const calendarView = includeUnifiedCalendarView
146
- ? buildUnifiedCalendarView(snap, openingHoursForUnifiedView, participantList, infoListForView)
216
+ const calendarViewRaw = includeUnifiedCalendarView
217
+ ? buildUnifiedCalendarView(payload, openingHoursForUnifiedView, finalParticipantList, infoList)
147
218
  : null;
219
+ const calendarView = calendarViewRaw ? mapToDesiredCalendarResponse(calendarViewRaw, calendarViewRaw.openingHours, calendarViewRaw.members) : null;
148
220
  const unifiedUsedAllEndpoint = includeUnifiedCalendarView &&
149
221
  preferAllParticipantOpeningHours &&
150
222
  allParticipantOpeningHours != null &&
151
223
  allParticipantOpeningHours.length > 0;
152
- return {
153
- calendar,
154
- cal,
155
- calendarView,
156
- openingHours,
157
- participants: participantList,
158
- participantsInfo,
159
- allParticipantOpeningHours,
160
- embeddedFromGet: embedded,
161
- fromCalendarGet: embedded.length > 0,
162
- fromParticipantApi: embedded.length === 0 && openingHours.length > 0 && participantOpeningHoursResponse != null,
163
- participantOpeningHoursResponse,
164
- meta: {
165
- ok: true,
166
- /** `calendarView.openingHours` came from OpeningHours/All/Get */
167
- calendarViewUsedAllParticipantOpeningHours: unifiedUsedAllEndpoint,
168
- ...(calendarView != null
169
- ? {
170
- calendarViewMemberCount: calendarView.members.length,
171
- calendarViewOpeningHourCount: calendarView.openingHours.length,
172
- }
173
- : {}),
224
+ if (!calendarView)
225
+ return null;
226
+ // Attach metadata as non-enumerable properties so they don't show up in JSON.stringify
227
+ // but are still accessible for debugging if needed.
228
+ Object.defineProperties(calendarView, {
229
+ _cal: { value: cal, enumerable: false },
230
+ _participants: { value: participantList, enumerable: false },
231
+ _openingHours: { value: openingHours, enumerable: false },
232
+ _rawGet: { value: rawRes, enumerable: false },
233
+ _meta: {
234
+ value: {
235
+ ok: true,
236
+ calendarViewUsedAllParticipantOpeningHours: unifiedUsedAllEndpoint,
237
+ calendarViewMemberCount: calendarView.members.length,
238
+ calendarViewOpeningHourCount: calendarView.openingHours.length,
239
+ },
240
+ enumerable: false
174
241
  },
175
- };
242
+ });
243
+ return calendarView;
176
244
  }
177
245
  /**
178
246
  * Single return value only: unified calendar **`calendarView`** —
@@ -180,13 +248,14 @@ export async function fetchCalendarDetails(calendarId, options = {}) {
180
248
  * (prefers all-participant opening hours when available). Same shape as `fetchCalendarDetails().calendarView`.
181
249
  * Returns **`null`** if the calendar cannot be loaded (`CalendarModel.get`).
182
250
  */
183
- export async function fetchCalendarBundle(calendarId) {
251
+ export async function fetchCalendarBundle(calendarId, connection) {
184
252
  const d = await fetchCalendarDetails(calendarId, {
185
253
  includeUnifiedCalendarView: true,
186
254
  includeParticipantsInfo: true,
187
255
  preferAllParticipantOpeningHours: true,
256
+ ...connection,
188
257
  });
189
- if (!d.meta.ok)
258
+ if (!d)
190
259
  return null;
191
- return d.calendarView;
260
+ return d;
192
261
  }
@@ -22,13 +22,4 @@ export declare function normalizeParticipantOpeningHoursResponse(res: any): {
22
22
  * 1. Prefer rows embedded on **GET /Calendar/Get** (`CalendarModel.getRaw` payload — `@blazeo.com/calendar-client` MST omits them).
23
23
  * 2. If missing/empty, calls **`calendar.getParticipantOpeningHours()`** (`GET /Calendar/Participant/OpeningHours/Get`).
24
24
  */
25
- export declare function fetchCalendarWithOpeningHours(calendarId: string, options?: any): Promise<{
26
- rawGet?: any;
27
- calendar: any;
28
- cal: any;
29
- openingHours: any[];
30
- embeddedFromGet: any[];
31
- fromCalendarGet: boolean;
32
- fromParticipantApi: boolean;
33
- participantOpeningHoursResponse: any;
34
- }>;
25
+ export declare function fetchCalendarWithOpeningHours(calendarId: string, options?: any): Promise<any>;
@@ -1,5 +1,6 @@
1
1
  import { CalendarModel } from "@blazeo.com/calendar-client";
2
- import { getSnapshot } from "mobx-state-tree";
2
+ import { resolveBlazeoConnection } from "./createCalendar.js";
3
+ import { mapToDesiredCalendarResponse } from "./mapToDesiredResponse.js";
3
4
  /**
4
5
  * Unwrap nested REST shapes: `res.data`, `res.Data`, or `res.data.data`.
5
6
  */
@@ -65,10 +66,23 @@ export function normalizeParticipantOpeningHoursResponse(res) {
65
66
  * 2. If missing/empty, calls **`calendar.getParticipantOpeningHours()`** (`GET /Calendar/Participant/OpeningHours/Get`).
66
67
  */
67
68
  export async function fetchCalendarWithOpeningHours(calendarId, options = {}) {
68
- const { includeRawGet = false } = options;
69
+ const { includeRawGet = false, baseUrl, consumer } = options;
70
+ const { baseUrl: resolvedBase, consumer: resolvedConsumer } = resolveBlazeoConnection({ baseUrl, consumer });
69
71
  const rawRes = await CalendarModel.getRaw(calendarId);
70
- const cal = await CalendarModel.get(calendarId);
71
72
  const payload = unwrapCalendarGetData(rawRes);
73
+ let cal = null;
74
+ if (payload) {
75
+ // Manually create the model instance to fix a bug in calendar-client static get.
76
+ cal = CalendarModel.create({ ...payload, calendarId }, { baseUrl: resolvedBase, consumer: resolvedConsumer });
77
+ }
78
+ if (cal == null) {
79
+ return {
80
+ calendar: null,
81
+ openingHours: [],
82
+ raw: rawRes,
83
+ meta: { ok: false, reason: "calendar_not_found" },
84
+ };
85
+ }
72
86
  const embedded = pickOpeningHoursArrayFromCalendarPayload(payload) ?? [];
73
87
  let resolved = embedded.length > 0 ? embedded : null;
74
88
  let participantRes = null;
@@ -80,16 +94,21 @@ export async function fetchCalendarWithOpeningHours(calendarId, options = {}) {
80
94
  resolved = list;
81
95
  }
82
96
  const openingHours = Array.isArray(resolved) ? resolved : [];
83
- const snap = cal != null ? getSnapshot(cal) : null;
84
- const calendar = snap != null ? { ...snap, openingHours } : null;
85
- return {
86
- calendar,
87
- cal,
88
- openingHours,
89
- embeddedFromGet: embedded,
90
- fromCalendarGet: embedded.length > 0,
91
- fromParticipantApi: embedded.length === 0 && openingHours.length > 0 && participantRes != null,
92
- participantOpeningHoursResponse: participantRes,
93
- ...(includeRawGet ? { rawGet: rawRes } : {}),
94
- };
97
+ const mappedOpeningHours = openingHours.map(oh => ({
98
+ ...oh,
99
+ }));
100
+ const rawMembers = payload?.members ?? payload?.Members ?? payload?.participants ?? payload?.Participants;
101
+ const mappedMembers = Array.isArray(rawMembers)
102
+ ? rawMembers.map((m) => ({ ...m }))
103
+ : [];
104
+ const calendar = mapToDesiredCalendarResponse(payload, openingHours, mappedMembers);
105
+ if (!calendar)
106
+ return null;
107
+ Object.defineProperties(calendar, {
108
+ _cal: { value: cal, enumerable: false },
109
+ _openingHours: { value: openingHours, enumerable: false },
110
+ _embeddedFromGet: { value: embedded, enumerable: false },
111
+ _rawGet: { value: rawRes, enumerable: false },
112
+ });
113
+ return calendar;
95
114
  }
@@ -2,7 +2,10 @@
2
2
  * Fetch all participant opening hours for a calendar.
3
3
  * Uses `GET /Calendar/Participant/OpeningHours/All/Get`.
4
4
  */
5
- export declare function getAllParticipantOpeningHours(calendarId: string): Promise<{
5
+ export declare function getAllParticipantOpeningHours(calendarId: string, options?: {
6
+ baseUrl?: string;
7
+ consumer?: string;
8
+ }): Promise<{
6
9
  openingHours: any[];
7
10
  raw: any[];
8
11
  meta: {
@@ -1,10 +1,15 @@
1
1
  import { CalendarModel } from "@blazeo.com/calendar-client";
2
+ import { ensureBlazeoHttpReady } from "../config/ensureBlazeoHttpReady.js";
2
3
  import { normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpeningHours.js";
3
4
  /**
4
5
  * Fetch all participant opening hours for a calendar.
5
6
  * Uses `GET /Calendar/Participant/OpeningHours/All/Get`.
6
7
  */
7
- export async function getAllParticipantOpeningHours(calendarId) {
8
+ export async function getAllParticipantOpeningHours(calendarId, options = {}) {
9
+ const ready = ensureBlazeoHttpReady(options);
10
+ if (!ready.ok) {
11
+ throw new Error(ready.error);
12
+ }
8
13
  const raw = await CalendarModel.getAllParticipantOpeningHours(calendarId);
9
14
  // calendar-client static helper returns either `unknown[] | null` or an envelope depending on version/entrypoint.
10
15
  if (Array.isArray(raw)) {
@@ -2,4 +2,7 @@
2
2
  * Fetches opening hours for a calendar.
3
3
  * Automatically handles embedded calendar-level hours and participant-level fallbacks.
4
4
  */
5
- export declare function getOpeningHours(calendarId: string): Promise<any[]>;
5
+ export declare function getOpeningHours(calendarId: string, options?: {
6
+ baseUrl?: string;
7
+ consumer?: string;
8
+ }): Promise<any>;
@@ -3,7 +3,7 @@ import { fetchCalendarWithOpeningHours } from "./fetchCalendarWithOpeningHours.j
3
3
  * Fetches opening hours for a calendar.
4
4
  * Automatically handles embedded calendar-level hours and participant-level fallbacks.
5
5
  */
6
- export async function getOpeningHours(calendarId) {
7
- const result = await fetchCalendarWithOpeningHours(calendarId);
6
+ export async function getOpeningHours(calendarId, options = {}) {
7
+ const result = await fetchCalendarWithOpeningHours(calendarId, options);
8
8
  return result.openingHours;
9
9
  }
@@ -1,5 +1,6 @@
1
1
  import { CalendarModel } from "@blazeo.com/calendar-client";
2
- import { normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpeningHours.js";
2
+ import { resolveBlazeoConnection } from "./createCalendar.js";
3
+ import { unwrapCalendarGetData, normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpeningHours.js";
3
4
  /**
4
5
  * Direct wrapper around `calendar.getParticipantOpeningHours()` for a calendar id.
5
6
  *
@@ -8,15 +9,19 @@ import { normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpe
8
9
  */
9
10
  export async function getParticipantOpeningHours(calendarId, options = {}) {
10
11
  try {
11
- const cal = await CalendarModel.get(calendarId);
12
- if (cal == null) {
12
+ const { baseUrl, consumer, ...passThrough } = options;
13
+ const { baseUrl: resolvedBase, consumer: resolvedConsumer } = resolveBlazeoConnection({ baseUrl, consumer });
14
+ const rawRes = await CalendarModel.getRaw(calendarId);
15
+ const payload = unwrapCalendarGetData(rawRes);
16
+ if (!payload) {
13
17
  return {
14
18
  openingHours: [],
15
19
  raw: null,
16
20
  meta: { ok: false, reason: "calendar_not_found" },
17
21
  };
18
22
  }
19
- const raw = await cal.getParticipantOpeningHours({ calendarId, ...(options ?? {}) });
23
+ const cal = CalendarModel.create({ ...payload, calendarId }, { baseUrl: resolvedBase, consumer: resolvedConsumer });
24
+ const raw = await cal.getParticipantOpeningHours({ calendarId, ...(passThrough ?? {}) });
20
25
  const { list } = normalizeParticipantOpeningHoursResponse(raw);
21
26
  const openingHours = Array.isArray(list) ? list : [];
22
27
  return {
@@ -1,4 +1,7 @@
1
1
  /**
2
2
  * Fetches participants for a calendar.
3
3
  */
4
- export declare function getParticipants(calendarId: string): Promise<any[]>;
4
+ export declare function getParticipants(calendarId: string, options?: {
5
+ baseUrl?: string;
6
+ consumer?: string;
7
+ }): Promise<any[]>;
@@ -1,8 +1,13 @@
1
1
  import { CalendarModel } from "@blazeo.com/calendar-client";
2
+ import { ensureBlazeoHttpReady } from "../config/ensureBlazeoHttpReady.js";
2
3
  /**
3
4
  * Fetches participants for a calendar.
4
5
  */
5
- export async function getParticipants(calendarId) {
6
+ export async function getParticipants(calendarId, options = {}) {
7
+ const ready = ensureBlazeoHttpReady(options);
8
+ if (!ready.ok) {
9
+ throw new Error(ready.error);
10
+ }
6
11
  const participants = await CalendarModel.getParticipants(calendarId);
7
12
  return Array.isArray(participants) ? participants : [];
8
13
  }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Maps a raw Blazeo API calendar payload (often PascalCase) to the specific camelCase
3
+ * shape requested by the user, including typenames and normalized fields.
4
+ */
5
+ export declare function mapToDesiredCalendarResponse(payload: any, openingHours?: any[], members?: any[]): {
6
+ id: number | null;
7
+ durationUnit: number | null;
8
+ minimumBookingNotice: number | null;
9
+ minimumBookingNoticeUnit: number | null;
10
+ minimumCancelationNotice: number | null;
11
+ minimumCancelationNoticeUnit: number | null;
12
+ futureLimit: number | null;
13
+ futureLimitUnit: number | null;
14
+ bufferTime: number | null;
15
+ bufferTimeUnit: number | null;
16
+ calendarLink: any;
17
+ uuid: any;
18
+ location: any;
19
+ bookingPageTitle: any;
20
+ reminderChannelStatuses: {
21
+ id: any;
22
+ calendarId: any;
23
+ channelId: any;
24
+ status: boolean;
25
+ appointmentReminders: any;
26
+ __typename: string;
27
+ }[];
28
+ members: {
29
+ id: any;
30
+ name: any;
31
+ email: any;
32
+ status: any;
33
+ __typename: string;
34
+ }[];
35
+ createdOn: any;
36
+ modifiedOn: any;
37
+ name: any;
38
+ timeZoneId: any;
39
+ description: any;
40
+ assignmentType: number | null;
41
+ duration: number | null;
42
+ bookingLimit: number | null;
43
+ calendarJson: any;
44
+ isThirdPartySaved: boolean;
45
+ themeId: number | null;
46
+ theme: {
47
+ id: any;
48
+ color: any;
49
+ logoUrl: any;
50
+ __typename: string;
51
+ } | null;
52
+ openingHours: {
53
+ id: any;
54
+ createdOn: any;
55
+ modifiedOn: any;
56
+ member: any;
57
+ openingHourId: any;
58
+ calendarId: any;
59
+ participantId: any;
60
+ days: any;
61
+ startHour: any;
62
+ startMinute: any;
63
+ endHour: any;
64
+ endMinute: any;
65
+ off: boolean;
66
+ __typename: string;
67
+ }[];
68
+ appointmentUserDefinedFields: any;
69
+ __typename: string;
70
+ } | null;