@blazeo.com/calendar-client 1.0.26 → 1.0.28

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
@@ -24,23 +24,19 @@ Configure once at app startup, then use models and their methods:
24
24
  ```js
25
25
  import {
26
26
  configure,
27
- setBaseUrl,
28
- setConsumer,
29
- setApiCredentials,
30
- fetchAccessToken,
27
+ setAccessToken,
28
+ setGetAccessToken,
31
29
  CalendarModel,
32
30
  createRootStore,
33
31
  } from '@blazeo.com/calendar-client';
34
32
 
35
- configure({ baseUrl: 'https://your-appointment-api.example.com' });
36
- // or: setBaseUrl('https://localhost:7051');
37
- setConsumer('my-app'); // optional: sent as Consumer header (e.g. for lead source)
38
-
39
- // API JWT (for Authorized routes such as lead export)
40
- setApiCredentials('your-api-key', 'your-api-secret');
41
- await fetchAccessToken();
42
- // Or set a token you obtained elsewhere:
43
- // setAccessToken('eyJ...', '2026-05-19T12:00:00Z');
33
+ configure({
34
+ baseUrl: 'https://your-appointment-api.example.com',
35
+ consumer: 'my-app', // optional Consumer header
36
+ accessToken: yourIdpAccessToken, // JWT from your identity provider
37
+ expiresAtUtc: '2026-05-21T12:00:00Z', // optional used before auto-refresh
38
+ getAccessToken: async () => yourIdp.getAccessToken(), // optional refresh callback
39
+ });
44
40
 
45
41
  // Calendar static methods (no store needed)
46
42
  const timezones = await CalendarModel.getTimeZones();
@@ -52,23 +48,22 @@ const cal = store.addCalendar({ calendarId: 'my-cal', name: 'My Calendar' });
52
48
  await cal.create(); // POST to backend
53
49
  ```
54
50
 
55
- ### API JWT authentication
51
+ ### JWT authentication
56
52
 
57
- The backend issues JWTs via `POST Api/Auth/Token` (`api_key` + `api_secret`). There is no refresh endpoint; when the token expires (~1 hour), call `fetchAccessToken()` again.
53
+ The Appointment API validates Bearer JWTs from your identity provider (`Authentication:Jwt:Authority` on the server). This package does **not** exchange api keys for tokens pass the JWT your app already has.
58
54
 
59
55
  | Function | Purpose |
60
56
  |----------|---------|
61
- | `setApiCredentials(apiKey, apiSecret)` | Store credentials for token exchange |
62
- | `fetchAccessToken()` | Get JWT from API and store on config |
63
- | `setAccessToken(token, expiresAtUtc?)` | Use a token you already have |
64
- | `ensureValidAccessToken()` | Fetch only if missing or near expiry |
65
- | `clearAuth()` | Clear token and credentials |
57
+ | `setAccessToken(token, expiresAtUtc?)` | Store JWT from your IdP |
58
+ | `setGetAccessToken(fn)` | Async callback to refresh when missing/near expiry |
59
+ | `ensureValidAccessToken()` | Resolve token before a request (uses callback if needed) |
60
+ | `clearAuth()` | Clear token and refresh callback |
66
61
 
67
- All `reqGet` / `reqPost` calls automatically attach `Authorization: Bearer …` and re-issue the token before requests when credentials are configured.
62
+ All `reqGet` / `reqPost` calls attach `Authorization: Bearer …` when a token is configured.
68
63
 
69
64
  ```js
70
- configure({ baseUrl: 'https://your-api', apiKey: 'key', apiSecret: 'secret' });
71
- await fetchAccessToken();
65
+ setAccessToken(session.accessToken, session.expiresAt);
66
+ setGetAccessToken(() => authService.acquireTokenSilent());
72
67
  await LeadModel.requestExport('company-key');
73
68
  ```
74
69
 
package/dist/index.d.ts CHANGED
@@ -1,17 +1,8 @@
1
1
  /** @blazeo.com/calendar-client - type declarations */
2
2
 
3
- export type AccessTokenResult = {
4
- status: string;
5
- message?: string;
6
- accessToken?: string;
7
- expiresAtUtc?: string | null;
8
- tokenType?: string;
9
- };
10
-
11
3
  export type AuthState = {
12
4
  accessToken?: string;
13
5
  tokenExpiresAt?: string;
14
- hasApiCredentials: boolean;
15
6
  };
16
7
 
17
8
  export function configure(env: {
@@ -23,10 +14,8 @@ export function configure(env: {
23
14
  expiresAtUtc?: string;
24
15
  tokenExpiresAt?: string;
25
16
  expires_at_utc?: string;
26
- apiKey?: string;
27
- api_key?: string;
28
- apiSecret?: string;
29
- api_secret?: string;
17
+ /** Called when the stored JWT is missing or near expiry; return a fresh token from your IdP. */
18
+ getAccessToken?: () => Promise<string | undefined>;
30
19
  }): void;
31
20
 
32
21
  export function getConfig(): {
@@ -36,23 +25,18 @@ export function getConfig(): {
36
25
  getDefaultOffset?: () => number;
37
26
  accessToken?: string;
38
27
  tokenExpiresAt?: string;
39
- hasApiCredentials?: boolean;
40
28
  } | null;
41
29
 
42
30
  export function setBaseUrl(baseUrl: string): void;
43
31
  export function setConsumer(consumer: string): void;
44
32
  export function setAccessToken(accessToken: string, expiresAtUtc?: string): void;
45
33
  export function clearAccessToken(): void;
46
- export function setApiCredentials(apiKey: string, apiSecret: string): void;
47
- export function clearApiCredentials(): void;
34
+ export function setGetAccessToken(fn: () => Promise<string | undefined>): void;
48
35
  export function clearAuth(): void;
49
36
  export function getAuth(): AuthState;
50
- export function fetchAccessToken(apiKey?: string, apiSecret?: string): Promise<AccessTokenResult>;
51
37
  export function ensureValidAccessToken(): Promise<string | undefined>;
52
- export function requestAccessToken(apiKey: string, apiSecret: string, opts?: { baseUrl?: string; fetch?: typeof fetch }): Promise<AccessTokenResult>;
53
38
  export function isAccessTokenExpired(expiresAtUtc?: string | number | Date | null, skewMs?: number): boolean;
54
39
  export function buildAuthHeaders(extra?: Record<string, string>): Record<string, string>;
55
- export const TOKEN_PATH: '/Api/Auth/Token';
56
40
  export const DEFAULT_TOKEN_REFRESH_SKEW_MS: number;
57
41
  export function getConfigStore(): unknown;
58
42
 
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  CompanyModel: () => Company_default,
35
35
  ConfigModel: () => ConfigModel_default,
36
36
  CustomFieldModel: () => CustomField_default,
37
+ DEFAULT_TOKEN_REFRESH_SKEW_MS: () => DEFAULT_TOKEN_REFRESH_SKEW_MS,
37
38
  DayOfWeek: () => DayOfWeek,
38
39
  EmailProvider: () => EmailProvider,
39
40
  EventModel: () => Event_default,
@@ -48,27 +49,23 @@ __export(index_exports, {
48
49
  RecurringFrequency: () => RecurringFrequency,
49
50
  RootStore: () => RootStore,
50
51
  SettingModel: () => Setting_default,
51
- TOKEN_PATH: () => TOKEN_PATH,
52
52
  TimeFrameModel: () => TimeFrame_default,
53
53
  TimeSlotModel: () => TimeSlot_default,
54
54
  Unit: () => Unit,
55
55
  buildAuthHeaders: () => buildAuthHeaders,
56
56
  clearAccessToken: () => clearAccessToken,
57
- clearApiCredentials: () => clearApiCredentials,
58
57
  clearAuth: () => clearAuth,
59
58
  configure: () => configure,
60
59
  createRootStore: () => createRootStore,
61
60
  ensureValidAccessToken: () => ensureValidAccessToken,
62
- fetchAccessToken: () => fetchAccessToken2,
63
61
  getAuth: () => getAuth,
64
62
  getConfig: () => getConfig,
65
63
  getConfigStore: () => getConfigStore,
66
64
  isAccessTokenExpired: () => isAccessTokenExpired,
67
- requestAccessToken: () => requestAccessToken,
68
65
  setAccessToken: () => setAccessToken,
69
- setApiCredentials: () => setApiCredentials,
70
66
  setBaseUrl: () => setBaseUrl,
71
- setConsumer: () => setConsumer
67
+ setConsumer: () => setConsumer,
68
+ setGetAccessToken: () => setGetAccessToken
72
69
  });
73
70
  module.exports = __toCommonJS(index_exports);
74
71
 
@@ -84,8 +81,8 @@ var ConfigModel = import_mobx_state_tree.types.model("Config", {
84
81
  fetch: void 0,
85
82
  accessToken: void 0,
86
83
  tokenExpiresAt: void 0,
87
- apiKey: void 0,
88
- apiSecret: void 0,
84
+ /** Host app supplies a fresh JWT (e.g. from your IdP) when the stored token is missing/expired. */
85
+ getAccessToken: void 0,
89
86
  getDefaultOffset: () => -(/* @__PURE__ */ new Date()).getTimezoneOffset()
90
87
  })).actions((self) => ({
91
88
  setBaseUrl(url) {
@@ -100,6 +97,9 @@ var ConfigModel = import_mobx_state_tree.types.model("Config", {
100
97
  setGetDefaultOffset(fn) {
101
98
  self.getDefaultOffset = fn;
102
99
  },
100
+ setGetAccessToken(fn) {
101
+ self.getAccessToken = fn;
102
+ },
103
103
  setAccessToken(token, expiresAtUtc = void 0) {
104
104
  self.accessToken = token ? String(token) : void 0;
105
105
  self.tokenExpiresAt = expiresAtUtc != null && expiresAtUtc !== "" ? String(expiresAtUtc) : void 0;
@@ -108,40 +108,24 @@ var ConfigModel = import_mobx_state_tree.types.model("Config", {
108
108
  self.accessToken = void 0;
109
109
  self.tokenExpiresAt = void 0;
110
110
  },
111
- setApiCredentials(apiKey, apiSecret) {
112
- self.apiKey = apiKey != null ? String(apiKey) : void 0;
113
- self.apiSecret = apiSecret != null ? String(apiSecret) : void 0;
114
- },
115
- clearApiCredentials() {
116
- self.apiKey = void 0;
117
- self.apiSecret = void 0;
118
- },
119
111
  clearAuth() {
120
112
  self.clearAccessToken();
121
- self.clearApiCredentials();
113
+ self.getAccessToken = void 0;
122
114
  },
123
115
  configure(env) {
124
116
  if (env.baseUrl != null) self.baseUrl = env.baseUrl;
125
117
  if (env.consumer != null) self.consumer = env.consumer;
126
118
  if (env.fetch != null) self.fetch = env.fetch;
127
119
  if (env.getDefaultOffset != null) self.getDefaultOffset = env.getDefaultOffset;
120
+ if (env.getAccessToken != null) self.getAccessToken = env.getAccessToken;
128
121
  if (env.accessToken != null) {
129
122
  self.setAccessToken(
130
123
  env.accessToken,
131
124
  env.expiresAtUtc ?? env.tokenExpiresAt ?? env.expires_at_utc
132
125
  );
133
126
  }
134
- if (env.apiKey != null || env.api_key != null) {
135
- self.apiKey = String(env.apiKey ?? env.api_key);
136
- }
137
- if (env.apiSecret != null || env.api_secret != null) {
138
- self.apiSecret = String(env.apiSecret ?? env.api_secret);
139
- }
140
127
  }
141
128
  })).views((self) => ({
142
- get hasApiCredentials() {
143
- return Boolean(self.apiKey && self.apiSecret);
144
- },
145
129
  getEnv() {
146
130
  return {
147
131
  baseUrl: self.baseUrl || void 0,
@@ -149,8 +133,7 @@ var ConfigModel = import_mobx_state_tree.types.model("Config", {
149
133
  fetch: self.fetch,
150
134
  getDefaultOffset: self.getDefaultOffset,
151
135
  accessToken: self.accessToken,
152
- tokenExpiresAt: self.tokenExpiresAt,
153
- hasApiCredentials: self.hasApiCredentials
136
+ tokenExpiresAt: self.tokenExpiresAt
154
137
  };
155
138
  }
156
139
  }));
@@ -162,26 +145,7 @@ function getConfigStore() {
162
145
  var ConfigModel_default = ConfigModel;
163
146
 
164
147
  // src/apiAuth.js
165
- var TOKEN_PATH = "/Api/Auth/Token";
166
148
  var DEFAULT_TOKEN_REFRESH_SKEW_MS = 6e4;
167
- function defaultFetch() {
168
- if (typeof fetch === "undefined") {
169
- throw new Error("fetch not available");
170
- }
171
- return fetch;
172
- }
173
- function pickTokenPayload(data) {
174
- if (!data || typeof data !== "object") return null;
175
- const nested = data.data && typeof data.data === "object" ? data.data : data;
176
- const accessToken = nested.access_token ?? nested.accessToken ?? nested.AccessToken ?? null;
177
- if (!accessToken) return null;
178
- const expiresAtUtc = nested.expires_at_utc ?? nested.expiresAtUtc ?? nested.ExpiresAtUtc ?? null;
179
- return {
180
- accessToken: String(accessToken),
181
- expiresAtUtc: expiresAtUtc != null ? String(expiresAtUtc) : null,
182
- tokenType: nested.token_type ?? nested.tokenType ?? "Bearer"
183
- };
184
- }
185
149
  function isAccessTokenExpired(expiresAtUtc, skewMs = DEFAULT_TOKEN_REFRESH_SKEW_MS) {
186
150
  if (expiresAtUtc == null || expiresAtUtc === "") return false;
187
151
  const expMs = new Date(expiresAtUtc).getTime();
@@ -192,77 +156,22 @@ function getAuthState() {
192
156
  const store = getConfigStore();
193
157
  return {
194
158
  accessToken: store.accessToken ?? void 0,
195
- tokenExpiresAt: store.tokenExpiresAt ?? void 0,
196
- apiKey: store.apiKey ?? void 0,
197
- apiSecret: store.apiSecret ?? void 0,
198
- hasApiCredentials: Boolean(store.apiKey && store.apiSecret)
199
- };
200
- }
201
- async function requestAccessToken(apiKey, apiSecret, opts = {}) {
202
- const store = getConfigStore();
203
- const baseUrl = opts.baseUrl ?? store.baseUrl;
204
- if (!baseUrl) {
205
- return { status: "failure", message: "baseUrl required. Call configure({ baseUrl }) first." };
206
- }
207
- const key = apiKey != null ? String(apiKey).trim() : "";
208
- const secret = apiSecret != null ? String(apiSecret).trim() : "";
209
- if (!key || !secret) {
210
- return { status: "failure", message: "api_key and api_secret are required" };
211
- }
212
- const fetchFn = opts.fetch ?? store.fetch ?? defaultFetch();
213
- const url = `${String(baseUrl).replace(/\/+$/, "")}${TOKEN_PATH}`;
214
- const httpRes = await fetchFn(url, {
215
- method: "POST",
216
- headers: { "Content-Type": "application/json" },
217
- body: JSON.stringify({ api_key: key, api_secret: secret })
218
- });
219
- const text = await httpRes.text();
220
- let body;
221
- try {
222
- body = JSON.parse(text);
223
- } catch {
224
- body = { status: "failure", message: text || httpRes.statusText };
225
- }
226
- if (!httpRes.ok && body.status !== "failure") {
227
- body.status = "failure";
228
- body.message = body.message ?? `HTTP ${httpRes.status}`;
229
- }
230
- if (body.status !== "success") {
231
- return {
232
- status: "failure",
233
- message: body.message ?? "Failed to obtain access token"
234
- };
235
- }
236
- const parsed = pickTokenPayload(body);
237
- if (!parsed) {
238
- return { status: "failure", message: "Token response missing access_token" };
239
- }
240
- return {
241
- status: "success",
242
- accessToken: parsed.accessToken,
243
- expiresAtUtc: parsed.expiresAtUtc,
244
- tokenType: parsed.tokenType
159
+ tokenExpiresAt: store.tokenExpiresAt ?? void 0
245
160
  };
246
161
  }
247
- async function fetchAccessToken(apiKey, apiSecret) {
248
- const store = getConfigStore();
249
- const key = apiKey ?? store.apiKey;
250
- const secret = apiSecret ?? store.apiSecret;
251
- const result = await requestAccessToken(key, secret);
252
- if (result.status === "success") {
253
- store.setAccessToken(result.accessToken, result.expiresAtUtc);
254
- }
255
- return result;
256
- }
257
162
  async function ensureAccessToken() {
258
163
  const store = getConfigStore();
259
- const { accessToken, tokenExpiresAt, apiKey, apiSecret } = getAuthState();
164
+ const { accessToken, tokenExpiresAt } = getAuthState();
260
165
  if (accessToken && !isAccessTokenExpired(tokenExpiresAt)) {
261
166
  return accessToken;
262
167
  }
263
- if (apiKey && apiSecret) {
264
- const result = await fetchAccessToken(apiKey, apiSecret);
265
- if (result.status === "success") return result.accessToken;
168
+ const refresh = store.getAccessToken;
169
+ if (typeof refresh === "function") {
170
+ const next = await refresh();
171
+ if (next) {
172
+ store.setAccessToken(next);
173
+ return next;
174
+ }
266
175
  }
267
176
  return accessToken;
268
177
  }
@@ -299,11 +208,8 @@ function setAccessToken(accessToken, expiresAtUtc) {
299
208
  function clearAccessToken() {
300
209
  getConfigStore().clearAccessToken();
301
210
  }
302
- function setApiCredentials(apiKey, apiSecret) {
303
- getConfigStore().setApiCredentials(apiKey, apiSecret);
304
- }
305
- function clearApiCredentials() {
306
- getConfigStore().clearApiCredentials();
211
+ function setGetAccessToken(fn) {
212
+ getConfigStore().setGetAccessToken(fn);
307
213
  }
308
214
  function clearAuth() {
309
215
  getConfigStore().clearAuth();
@@ -311,9 +217,6 @@ function clearAuth() {
311
217
  function getAuth() {
312
218
  return getAuthState();
313
219
  }
314
- function fetchAccessToken2(apiKey, apiSecret) {
315
- return fetchAccessToken(apiKey, apiSecret);
316
- }
317
220
  function ensureValidAccessToken() {
318
221
  return ensureAccessToken();
319
222
  }
@@ -3019,6 +2922,7 @@ function createRootStore(initialState = {}) {
3019
2922
  CompanyModel,
3020
2923
  ConfigModel,
3021
2924
  CustomFieldModel,
2925
+ DEFAULT_TOKEN_REFRESH_SKEW_MS,
3022
2926
  DayOfWeek,
3023
2927
  EmailProvider,
3024
2928
  EventModel,
@@ -3033,25 +2937,21 @@ function createRootStore(initialState = {}) {
3033
2937
  RecurringFrequency,
3034
2938
  RootStore,
3035
2939
  SettingModel,
3036
- TOKEN_PATH,
3037
2940
  TimeFrameModel,
3038
2941
  TimeSlotModel,
3039
2942
  Unit,
3040
2943
  buildAuthHeaders,
3041
2944
  clearAccessToken,
3042
- clearApiCredentials,
3043
2945
  clearAuth,
3044
2946
  configure,
3045
2947
  createRootStore,
3046
2948
  ensureValidAccessToken,
3047
- fetchAccessToken,
3048
2949
  getAuth,
3049
2950
  getConfig,
3050
2951
  getConfigStore,
3051
2952
  isAccessTokenExpired,
3052
- requestAccessToken,
3053
2953
  setAccessToken,
3054
- setApiCredentials,
3055
2954
  setBaseUrl,
3056
- setConsumer
2955
+ setConsumer,
2956
+ setGetAccessToken
3057
2957
  });
package/dist/index.mjs CHANGED
@@ -10,8 +10,8 @@ var ConfigModel = types.model("Config", {
10
10
  fetch: void 0,
11
11
  accessToken: void 0,
12
12
  tokenExpiresAt: void 0,
13
- apiKey: void 0,
14
- apiSecret: void 0,
13
+ /** Host app supplies a fresh JWT (e.g. from your IdP) when the stored token is missing/expired. */
14
+ getAccessToken: void 0,
15
15
  getDefaultOffset: () => -(/* @__PURE__ */ new Date()).getTimezoneOffset()
16
16
  })).actions((self) => ({
17
17
  setBaseUrl(url) {
@@ -26,6 +26,9 @@ var ConfigModel = types.model("Config", {
26
26
  setGetDefaultOffset(fn) {
27
27
  self.getDefaultOffset = fn;
28
28
  },
29
+ setGetAccessToken(fn) {
30
+ self.getAccessToken = fn;
31
+ },
29
32
  setAccessToken(token, expiresAtUtc = void 0) {
30
33
  self.accessToken = token ? String(token) : void 0;
31
34
  self.tokenExpiresAt = expiresAtUtc != null && expiresAtUtc !== "" ? String(expiresAtUtc) : void 0;
@@ -34,40 +37,24 @@ var ConfigModel = types.model("Config", {
34
37
  self.accessToken = void 0;
35
38
  self.tokenExpiresAt = void 0;
36
39
  },
37
- setApiCredentials(apiKey, apiSecret) {
38
- self.apiKey = apiKey != null ? String(apiKey) : void 0;
39
- self.apiSecret = apiSecret != null ? String(apiSecret) : void 0;
40
- },
41
- clearApiCredentials() {
42
- self.apiKey = void 0;
43
- self.apiSecret = void 0;
44
- },
45
40
  clearAuth() {
46
41
  self.clearAccessToken();
47
- self.clearApiCredentials();
42
+ self.getAccessToken = void 0;
48
43
  },
49
44
  configure(env) {
50
45
  if (env.baseUrl != null) self.baseUrl = env.baseUrl;
51
46
  if (env.consumer != null) self.consumer = env.consumer;
52
47
  if (env.fetch != null) self.fetch = env.fetch;
53
48
  if (env.getDefaultOffset != null) self.getDefaultOffset = env.getDefaultOffset;
49
+ if (env.getAccessToken != null) self.getAccessToken = env.getAccessToken;
54
50
  if (env.accessToken != null) {
55
51
  self.setAccessToken(
56
52
  env.accessToken,
57
53
  env.expiresAtUtc ?? env.tokenExpiresAt ?? env.expires_at_utc
58
54
  );
59
55
  }
60
- if (env.apiKey != null || env.api_key != null) {
61
- self.apiKey = String(env.apiKey ?? env.api_key);
62
- }
63
- if (env.apiSecret != null || env.api_secret != null) {
64
- self.apiSecret = String(env.apiSecret ?? env.api_secret);
65
- }
66
56
  }
67
57
  })).views((self) => ({
68
- get hasApiCredentials() {
69
- return Boolean(self.apiKey && self.apiSecret);
70
- },
71
58
  getEnv() {
72
59
  return {
73
60
  baseUrl: self.baseUrl || void 0,
@@ -75,8 +62,7 @@ var ConfigModel = types.model("Config", {
75
62
  fetch: self.fetch,
76
63
  getDefaultOffset: self.getDefaultOffset,
77
64
  accessToken: self.accessToken,
78
- tokenExpiresAt: self.tokenExpiresAt,
79
- hasApiCredentials: self.hasApiCredentials
65
+ tokenExpiresAt: self.tokenExpiresAt
80
66
  };
81
67
  }
82
68
  }));
@@ -88,26 +74,7 @@ function getConfigStore() {
88
74
  var ConfigModel_default = ConfigModel;
89
75
 
90
76
  // src/apiAuth.js
91
- var TOKEN_PATH = "/Api/Auth/Token";
92
77
  var DEFAULT_TOKEN_REFRESH_SKEW_MS = 6e4;
93
- function defaultFetch() {
94
- if (typeof fetch === "undefined") {
95
- throw new Error("fetch not available");
96
- }
97
- return fetch;
98
- }
99
- function pickTokenPayload(data) {
100
- if (!data || typeof data !== "object") return null;
101
- const nested = data.data && typeof data.data === "object" ? data.data : data;
102
- const accessToken = nested.access_token ?? nested.accessToken ?? nested.AccessToken ?? null;
103
- if (!accessToken) return null;
104
- const expiresAtUtc = nested.expires_at_utc ?? nested.expiresAtUtc ?? nested.ExpiresAtUtc ?? null;
105
- return {
106
- accessToken: String(accessToken),
107
- expiresAtUtc: expiresAtUtc != null ? String(expiresAtUtc) : null,
108
- tokenType: nested.token_type ?? nested.tokenType ?? "Bearer"
109
- };
110
- }
111
78
  function isAccessTokenExpired(expiresAtUtc, skewMs = DEFAULT_TOKEN_REFRESH_SKEW_MS) {
112
79
  if (expiresAtUtc == null || expiresAtUtc === "") return false;
113
80
  const expMs = new Date(expiresAtUtc).getTime();
@@ -118,77 +85,22 @@ function getAuthState() {
118
85
  const store = getConfigStore();
119
86
  return {
120
87
  accessToken: store.accessToken ?? void 0,
121
- tokenExpiresAt: store.tokenExpiresAt ?? void 0,
122
- apiKey: store.apiKey ?? void 0,
123
- apiSecret: store.apiSecret ?? void 0,
124
- hasApiCredentials: Boolean(store.apiKey && store.apiSecret)
125
- };
126
- }
127
- async function requestAccessToken(apiKey, apiSecret, opts = {}) {
128
- const store = getConfigStore();
129
- const baseUrl = opts.baseUrl ?? store.baseUrl;
130
- if (!baseUrl) {
131
- return { status: "failure", message: "baseUrl required. Call configure({ baseUrl }) first." };
132
- }
133
- const key = apiKey != null ? String(apiKey).trim() : "";
134
- const secret = apiSecret != null ? String(apiSecret).trim() : "";
135
- if (!key || !secret) {
136
- return { status: "failure", message: "api_key and api_secret are required" };
137
- }
138
- const fetchFn = opts.fetch ?? store.fetch ?? defaultFetch();
139
- const url = `${String(baseUrl).replace(/\/+$/, "")}${TOKEN_PATH}`;
140
- const httpRes = await fetchFn(url, {
141
- method: "POST",
142
- headers: { "Content-Type": "application/json" },
143
- body: JSON.stringify({ api_key: key, api_secret: secret })
144
- });
145
- const text = await httpRes.text();
146
- let body;
147
- try {
148
- body = JSON.parse(text);
149
- } catch {
150
- body = { status: "failure", message: text || httpRes.statusText };
151
- }
152
- if (!httpRes.ok && body.status !== "failure") {
153
- body.status = "failure";
154
- body.message = body.message ?? `HTTP ${httpRes.status}`;
155
- }
156
- if (body.status !== "success") {
157
- return {
158
- status: "failure",
159
- message: body.message ?? "Failed to obtain access token"
160
- };
161
- }
162
- const parsed = pickTokenPayload(body);
163
- if (!parsed) {
164
- return { status: "failure", message: "Token response missing access_token" };
165
- }
166
- return {
167
- status: "success",
168
- accessToken: parsed.accessToken,
169
- expiresAtUtc: parsed.expiresAtUtc,
170
- tokenType: parsed.tokenType
88
+ tokenExpiresAt: store.tokenExpiresAt ?? void 0
171
89
  };
172
90
  }
173
- async function fetchAccessToken(apiKey, apiSecret) {
174
- const store = getConfigStore();
175
- const key = apiKey ?? store.apiKey;
176
- const secret = apiSecret ?? store.apiSecret;
177
- const result = await requestAccessToken(key, secret);
178
- if (result.status === "success") {
179
- store.setAccessToken(result.accessToken, result.expiresAtUtc);
180
- }
181
- return result;
182
- }
183
91
  async function ensureAccessToken() {
184
92
  const store = getConfigStore();
185
- const { accessToken, tokenExpiresAt, apiKey, apiSecret } = getAuthState();
93
+ const { accessToken, tokenExpiresAt } = getAuthState();
186
94
  if (accessToken && !isAccessTokenExpired(tokenExpiresAt)) {
187
95
  return accessToken;
188
96
  }
189
- if (apiKey && apiSecret) {
190
- const result = await fetchAccessToken(apiKey, apiSecret);
191
- if (result.status === "success") return result.accessToken;
97
+ const refresh = store.getAccessToken;
98
+ if (typeof refresh === "function") {
99
+ const next = await refresh();
100
+ if (next) {
101
+ store.setAccessToken(next);
102
+ return next;
103
+ }
192
104
  }
193
105
  return accessToken;
194
106
  }
@@ -225,11 +137,8 @@ function setAccessToken(accessToken, expiresAtUtc) {
225
137
  function clearAccessToken() {
226
138
  getConfigStore().clearAccessToken();
227
139
  }
228
- function setApiCredentials(apiKey, apiSecret) {
229
- getConfigStore().setApiCredentials(apiKey, apiSecret);
230
- }
231
- function clearApiCredentials() {
232
- getConfigStore().clearApiCredentials();
140
+ function setGetAccessToken(fn) {
141
+ getConfigStore().setGetAccessToken(fn);
233
142
  }
234
143
  function clearAuth() {
235
144
  getConfigStore().clearAuth();
@@ -237,9 +146,6 @@ function clearAuth() {
237
146
  function getAuth() {
238
147
  return getAuthState();
239
148
  }
240
- function fetchAccessToken2(apiKey, apiSecret) {
241
- return fetchAccessToken(apiKey, apiSecret);
242
- }
243
149
  function ensureValidAccessToken() {
244
150
  return ensureAccessToken();
245
151
  }
@@ -2944,6 +2850,7 @@ export {
2944
2850
  Company_default as CompanyModel,
2945
2851
  ConfigModel_default as ConfigModel,
2946
2852
  CustomField_default as CustomFieldModel,
2853
+ DEFAULT_TOKEN_REFRESH_SKEW_MS,
2947
2854
  DayOfWeek,
2948
2855
  EmailProvider,
2949
2856
  Event_default as EventModel,
@@ -2958,25 +2865,21 @@ export {
2958
2865
  RecurringFrequency,
2959
2866
  RootStore,
2960
2867
  Setting_default as SettingModel,
2961
- TOKEN_PATH,
2962
2868
  TimeFrame_default as TimeFrameModel,
2963
2869
  TimeSlot_default as TimeSlotModel,
2964
2870
  Unit,
2965
2871
  buildAuthHeaders,
2966
2872
  clearAccessToken,
2967
- clearApiCredentials,
2968
2873
  clearAuth,
2969
2874
  configure,
2970
2875
  createRootStore,
2971
2876
  ensureValidAccessToken,
2972
- fetchAccessToken2 as fetchAccessToken,
2973
2877
  getAuth,
2974
2878
  getConfig,
2975
2879
  getConfigStore,
2976
2880
  isAccessTokenExpired,
2977
- requestAccessToken,
2978
2881
  setAccessToken,
2979
- setApiCredentials,
2980
2882
  setBaseUrl,
2981
- setConsumer
2883
+ setConsumer,
2884
+ setGetAccessToken
2982
2885
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blazeo.com/calendar-client",
3
- "version": "1.0.26",
3
+ "version": "1.0.28",
4
4
  "description": "Blazeo Calendar / Appointment API client with MobX State Tree models",
5
5
  "exports": {
6
6
  ".": {