@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 +18 -23
- package/dist/index.d.ts +3 -19
- package/dist/index.js +25 -125
- package/dist/index.mjs +22 -119
- package/package.json +1 -1
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
|
-
|
|
28
|
-
|
|
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({
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
###
|
|
51
|
+
### JWT authentication
|
|
56
52
|
|
|
57
|
-
The
|
|
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
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
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
|
|
62
|
+
All `reqGet` / `reqPost` calls attach `Authorization: Bearer …` when a token is configured.
|
|
68
63
|
|
|
69
64
|
```js
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
27
|
-
|
|
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
|
|
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
|
-
|
|
88
|
-
|
|
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.
|
|
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
|
|
164
|
+
const { accessToken, tokenExpiresAt } = getAuthState();
|
|
260
165
|
if (accessToken && !isAccessTokenExpired(tokenExpiresAt)) {
|
|
261
166
|
return accessToken;
|
|
262
167
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
|
303
|
-
getConfigStore().
|
|
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
|
-
|
|
14
|
-
|
|
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.
|
|
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
|
|
93
|
+
const { accessToken, tokenExpiresAt } = getAuthState();
|
|
186
94
|
if (accessToken && !isAccessTokenExpired(tokenExpiresAt)) {
|
|
187
95
|
return accessToken;
|
|
188
96
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
|
229
|
-
getConfigStore().
|
|
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
|
};
|