@blazeo.com/calendar-client 1.0.27 → 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 -21
- package/dist/index.js +23 -125
- package/dist/index.mjs +21 -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,19 +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
|
-
apiKey?: string;
|
|
15
|
-
apiSecret?: string;
|
|
16
|
-
hasApiCredentials: boolean;
|
|
17
6
|
};
|
|
18
7
|
|
|
19
8
|
export function configure(env: {
|
|
@@ -25,10 +14,8 @@ export function configure(env: {
|
|
|
25
14
|
expiresAtUtc?: string;
|
|
26
15
|
tokenExpiresAt?: string;
|
|
27
16
|
expires_at_utc?: string;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
apiSecret?: string;
|
|
31
|
-
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>;
|
|
32
19
|
}): void;
|
|
33
20
|
|
|
34
21
|
export function getConfig(): {
|
|
@@ -38,23 +25,18 @@ export function getConfig(): {
|
|
|
38
25
|
getDefaultOffset?: () => number;
|
|
39
26
|
accessToken?: string;
|
|
40
27
|
tokenExpiresAt?: string;
|
|
41
|
-
hasApiCredentials?: boolean;
|
|
42
28
|
} | null;
|
|
43
29
|
|
|
44
30
|
export function setBaseUrl(baseUrl: string): void;
|
|
45
31
|
export function setConsumer(consumer: string): void;
|
|
46
32
|
export function setAccessToken(accessToken: string, expiresAtUtc?: string): void;
|
|
47
33
|
export function clearAccessToken(): void;
|
|
48
|
-
export function
|
|
49
|
-
export function clearApiCredentials(): void;
|
|
34
|
+
export function setGetAccessToken(fn: () => Promise<string | undefined>): void;
|
|
50
35
|
export function clearAuth(): void;
|
|
51
36
|
export function getAuth(): AuthState;
|
|
52
|
-
export function fetchAccessToken(apiKey?: string, apiSecret?: string): Promise<AccessTokenResult>;
|
|
53
37
|
export function ensureValidAccessToken(): Promise<string | undefined>;
|
|
54
|
-
export function requestAccessToken(apiKey: string, apiSecret: string, opts?: { baseUrl?: string; fetch?: typeof fetch }): Promise<AccessTokenResult>;
|
|
55
38
|
export function isAccessTokenExpired(expiresAtUtc?: string | number | Date | null, skewMs?: number): boolean;
|
|
56
39
|
export function buildAuthHeaders(extra?: Record<string, string>): Record<string, string>;
|
|
57
|
-
export const TOKEN_PATH: '/Api/Auth/Token';
|
|
58
40
|
export const DEFAULT_TOKEN_REFRESH_SKEW_MS: number;
|
|
59
41
|
export function getConfigStore(): unknown;
|
|
60
42
|
|
package/dist/index.js
CHANGED
|
@@ -49,27 +49,23 @@ __export(index_exports, {
|
|
|
49
49
|
RecurringFrequency: () => RecurringFrequency,
|
|
50
50
|
RootStore: () => RootStore,
|
|
51
51
|
SettingModel: () => Setting_default,
|
|
52
|
-
TOKEN_PATH: () => TOKEN_PATH,
|
|
53
52
|
TimeFrameModel: () => TimeFrame_default,
|
|
54
53
|
TimeSlotModel: () => TimeSlot_default,
|
|
55
54
|
Unit: () => Unit,
|
|
56
55
|
buildAuthHeaders: () => buildAuthHeaders,
|
|
57
56
|
clearAccessToken: () => clearAccessToken,
|
|
58
|
-
clearApiCredentials: () => clearApiCredentials,
|
|
59
57
|
clearAuth: () => clearAuth,
|
|
60
58
|
configure: () => configure,
|
|
61
59
|
createRootStore: () => createRootStore,
|
|
62
60
|
ensureValidAccessToken: () => ensureValidAccessToken,
|
|
63
|
-
fetchAccessToken: () => fetchAccessToken2,
|
|
64
61
|
getAuth: () => getAuth,
|
|
65
62
|
getConfig: () => getConfig,
|
|
66
63
|
getConfigStore: () => getConfigStore,
|
|
67
64
|
isAccessTokenExpired: () => isAccessTokenExpired,
|
|
68
|
-
requestAccessToken: () => requestAccessToken,
|
|
69
65
|
setAccessToken: () => setAccessToken,
|
|
70
|
-
setApiCredentials: () => setApiCredentials,
|
|
71
66
|
setBaseUrl: () => setBaseUrl,
|
|
72
|
-
setConsumer: () => setConsumer
|
|
67
|
+
setConsumer: () => setConsumer,
|
|
68
|
+
setGetAccessToken: () => setGetAccessToken
|
|
73
69
|
});
|
|
74
70
|
module.exports = __toCommonJS(index_exports);
|
|
75
71
|
|
|
@@ -85,8 +81,8 @@ var ConfigModel = import_mobx_state_tree.types.model("Config", {
|
|
|
85
81
|
fetch: void 0,
|
|
86
82
|
accessToken: void 0,
|
|
87
83
|
tokenExpiresAt: void 0,
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
/** Host app supplies a fresh JWT (e.g. from your IdP) when the stored token is missing/expired. */
|
|
85
|
+
getAccessToken: void 0,
|
|
90
86
|
getDefaultOffset: () => -(/* @__PURE__ */ new Date()).getTimezoneOffset()
|
|
91
87
|
})).actions((self) => ({
|
|
92
88
|
setBaseUrl(url) {
|
|
@@ -101,6 +97,9 @@ var ConfigModel = import_mobx_state_tree.types.model("Config", {
|
|
|
101
97
|
setGetDefaultOffset(fn) {
|
|
102
98
|
self.getDefaultOffset = fn;
|
|
103
99
|
},
|
|
100
|
+
setGetAccessToken(fn) {
|
|
101
|
+
self.getAccessToken = fn;
|
|
102
|
+
},
|
|
104
103
|
setAccessToken(token, expiresAtUtc = void 0) {
|
|
105
104
|
self.accessToken = token ? String(token) : void 0;
|
|
106
105
|
self.tokenExpiresAt = expiresAtUtc != null && expiresAtUtc !== "" ? String(expiresAtUtc) : void 0;
|
|
@@ -109,40 +108,24 @@ var ConfigModel = import_mobx_state_tree.types.model("Config", {
|
|
|
109
108
|
self.accessToken = void 0;
|
|
110
109
|
self.tokenExpiresAt = void 0;
|
|
111
110
|
},
|
|
112
|
-
setApiCredentials(apiKey, apiSecret) {
|
|
113
|
-
self.apiKey = apiKey != null ? String(apiKey) : void 0;
|
|
114
|
-
self.apiSecret = apiSecret != null ? String(apiSecret) : void 0;
|
|
115
|
-
},
|
|
116
|
-
clearApiCredentials() {
|
|
117
|
-
self.apiKey = void 0;
|
|
118
|
-
self.apiSecret = void 0;
|
|
119
|
-
},
|
|
120
111
|
clearAuth() {
|
|
121
112
|
self.clearAccessToken();
|
|
122
|
-
self.
|
|
113
|
+
self.getAccessToken = void 0;
|
|
123
114
|
},
|
|
124
115
|
configure(env) {
|
|
125
116
|
if (env.baseUrl != null) self.baseUrl = env.baseUrl;
|
|
126
117
|
if (env.consumer != null) self.consumer = env.consumer;
|
|
127
118
|
if (env.fetch != null) self.fetch = env.fetch;
|
|
128
119
|
if (env.getDefaultOffset != null) self.getDefaultOffset = env.getDefaultOffset;
|
|
120
|
+
if (env.getAccessToken != null) self.getAccessToken = env.getAccessToken;
|
|
129
121
|
if (env.accessToken != null) {
|
|
130
122
|
self.setAccessToken(
|
|
131
123
|
env.accessToken,
|
|
132
124
|
env.expiresAtUtc ?? env.tokenExpiresAt ?? env.expires_at_utc
|
|
133
125
|
);
|
|
134
126
|
}
|
|
135
|
-
if (env.apiKey != null || env.api_key != null) {
|
|
136
|
-
self.apiKey = String(env.apiKey ?? env.api_key);
|
|
137
|
-
}
|
|
138
|
-
if (env.apiSecret != null || env.api_secret != null) {
|
|
139
|
-
self.apiSecret = String(env.apiSecret ?? env.api_secret);
|
|
140
|
-
}
|
|
141
127
|
}
|
|
142
128
|
})).views((self) => ({
|
|
143
|
-
get hasApiCredentials() {
|
|
144
|
-
return Boolean(self.apiKey && self.apiSecret);
|
|
145
|
-
},
|
|
146
129
|
getEnv() {
|
|
147
130
|
return {
|
|
148
131
|
baseUrl: self.baseUrl || void 0,
|
|
@@ -150,8 +133,7 @@ var ConfigModel = import_mobx_state_tree.types.model("Config", {
|
|
|
150
133
|
fetch: self.fetch,
|
|
151
134
|
getDefaultOffset: self.getDefaultOffset,
|
|
152
135
|
accessToken: self.accessToken,
|
|
153
|
-
tokenExpiresAt: self.tokenExpiresAt
|
|
154
|
-
hasApiCredentials: self.hasApiCredentials
|
|
136
|
+
tokenExpiresAt: self.tokenExpiresAt
|
|
155
137
|
};
|
|
156
138
|
}
|
|
157
139
|
}));
|
|
@@ -163,26 +145,7 @@ function getConfigStore() {
|
|
|
163
145
|
var ConfigModel_default = ConfigModel;
|
|
164
146
|
|
|
165
147
|
// src/apiAuth.js
|
|
166
|
-
var TOKEN_PATH = "/Api/Auth/Token";
|
|
167
148
|
var DEFAULT_TOKEN_REFRESH_SKEW_MS = 6e4;
|
|
168
|
-
function defaultFetch() {
|
|
169
|
-
if (typeof fetch === "undefined") {
|
|
170
|
-
throw new Error("fetch not available");
|
|
171
|
-
}
|
|
172
|
-
return fetch;
|
|
173
|
-
}
|
|
174
|
-
function pickTokenPayload(data) {
|
|
175
|
-
if (!data || typeof data !== "object") return null;
|
|
176
|
-
const nested = data.data && typeof data.data === "object" ? data.data : data;
|
|
177
|
-
const accessToken = nested.access_token ?? nested.accessToken ?? nested.AccessToken ?? null;
|
|
178
|
-
if (!accessToken) return null;
|
|
179
|
-
const expiresAtUtc = nested.expires_at_utc ?? nested.expiresAtUtc ?? nested.ExpiresAtUtc ?? null;
|
|
180
|
-
return {
|
|
181
|
-
accessToken: String(accessToken),
|
|
182
|
-
expiresAtUtc: expiresAtUtc != null ? String(expiresAtUtc) : null,
|
|
183
|
-
tokenType: nested.token_type ?? nested.tokenType ?? "Bearer"
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
149
|
function isAccessTokenExpired(expiresAtUtc, skewMs = DEFAULT_TOKEN_REFRESH_SKEW_MS) {
|
|
187
150
|
if (expiresAtUtc == null || expiresAtUtc === "") return false;
|
|
188
151
|
const expMs = new Date(expiresAtUtc).getTime();
|
|
@@ -193,77 +156,22 @@ function getAuthState() {
|
|
|
193
156
|
const store = getConfigStore();
|
|
194
157
|
return {
|
|
195
158
|
accessToken: store.accessToken ?? void 0,
|
|
196
|
-
tokenExpiresAt: store.tokenExpiresAt ?? void 0
|
|
197
|
-
apiKey: store.apiKey ?? void 0,
|
|
198
|
-
apiSecret: store.apiSecret ?? void 0,
|
|
199
|
-
hasApiCredentials: Boolean(store.apiKey && store.apiSecret)
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
async function requestAccessToken(apiKey, apiSecret, opts = {}) {
|
|
203
|
-
const store = getConfigStore();
|
|
204
|
-
const baseUrl = opts.baseUrl ?? store.baseUrl;
|
|
205
|
-
if (!baseUrl) {
|
|
206
|
-
return { status: "failure", message: "baseUrl required. Call configure({ baseUrl }) first." };
|
|
207
|
-
}
|
|
208
|
-
const key = apiKey != null ? String(apiKey).trim() : "";
|
|
209
|
-
const secret = apiSecret != null ? String(apiSecret).trim() : "";
|
|
210
|
-
if (!key || !secret) {
|
|
211
|
-
return { status: "failure", message: "api_key and api_secret are required" };
|
|
212
|
-
}
|
|
213
|
-
const fetchFn = opts.fetch ?? store.fetch ?? defaultFetch();
|
|
214
|
-
const url = `${String(baseUrl).replace(/\/+$/, "")}${TOKEN_PATH}`;
|
|
215
|
-
const httpRes = await fetchFn(url, {
|
|
216
|
-
method: "POST",
|
|
217
|
-
headers: { "Content-Type": "application/json" },
|
|
218
|
-
body: JSON.stringify({ api_key: key, api_secret: secret })
|
|
219
|
-
});
|
|
220
|
-
const text = await httpRes.text();
|
|
221
|
-
let body;
|
|
222
|
-
try {
|
|
223
|
-
body = JSON.parse(text);
|
|
224
|
-
} catch {
|
|
225
|
-
body = { status: "failure", message: text || httpRes.statusText };
|
|
226
|
-
}
|
|
227
|
-
if (!httpRes.ok && body.status !== "failure") {
|
|
228
|
-
body.status = "failure";
|
|
229
|
-
body.message = body.message ?? `HTTP ${httpRes.status}`;
|
|
230
|
-
}
|
|
231
|
-
if (body.status !== "success") {
|
|
232
|
-
return {
|
|
233
|
-
status: "failure",
|
|
234
|
-
message: body.message ?? "Failed to obtain access token"
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
const parsed = pickTokenPayload(body);
|
|
238
|
-
if (!parsed) {
|
|
239
|
-
return { status: "failure", message: "Token response missing access_token" };
|
|
240
|
-
}
|
|
241
|
-
return {
|
|
242
|
-
status: "success",
|
|
243
|
-
accessToken: parsed.accessToken,
|
|
244
|
-
expiresAtUtc: parsed.expiresAtUtc,
|
|
245
|
-
tokenType: parsed.tokenType
|
|
159
|
+
tokenExpiresAt: store.tokenExpiresAt ?? void 0
|
|
246
160
|
};
|
|
247
161
|
}
|
|
248
|
-
async function fetchAccessToken(apiKey, apiSecret) {
|
|
249
|
-
const store = getConfigStore();
|
|
250
|
-
const key = apiKey ?? store.apiKey;
|
|
251
|
-
const secret = apiSecret ?? store.apiSecret;
|
|
252
|
-
const result = await requestAccessToken(key, secret);
|
|
253
|
-
if (result.status === "success") {
|
|
254
|
-
store.setAccessToken(result.accessToken, result.expiresAtUtc);
|
|
255
|
-
}
|
|
256
|
-
return result;
|
|
257
|
-
}
|
|
258
162
|
async function ensureAccessToken() {
|
|
259
163
|
const store = getConfigStore();
|
|
260
|
-
const { accessToken, tokenExpiresAt
|
|
164
|
+
const { accessToken, tokenExpiresAt } = getAuthState();
|
|
261
165
|
if (accessToken && !isAccessTokenExpired(tokenExpiresAt)) {
|
|
262
166
|
return accessToken;
|
|
263
167
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
+
}
|
|
267
175
|
}
|
|
268
176
|
return accessToken;
|
|
269
177
|
}
|
|
@@ -300,11 +208,8 @@ function setAccessToken(accessToken, expiresAtUtc) {
|
|
|
300
208
|
function clearAccessToken() {
|
|
301
209
|
getConfigStore().clearAccessToken();
|
|
302
210
|
}
|
|
303
|
-
function
|
|
304
|
-
getConfigStore().
|
|
305
|
-
}
|
|
306
|
-
function clearApiCredentials() {
|
|
307
|
-
getConfigStore().clearApiCredentials();
|
|
211
|
+
function setGetAccessToken(fn) {
|
|
212
|
+
getConfigStore().setGetAccessToken(fn);
|
|
308
213
|
}
|
|
309
214
|
function clearAuth() {
|
|
310
215
|
getConfigStore().clearAuth();
|
|
@@ -312,9 +217,6 @@ function clearAuth() {
|
|
|
312
217
|
function getAuth() {
|
|
313
218
|
return getAuthState();
|
|
314
219
|
}
|
|
315
|
-
function fetchAccessToken2(apiKey, apiSecret) {
|
|
316
|
-
return fetchAccessToken(apiKey, apiSecret);
|
|
317
|
-
}
|
|
318
220
|
function ensureValidAccessToken() {
|
|
319
221
|
return ensureAccessToken();
|
|
320
222
|
}
|
|
@@ -3035,25 +2937,21 @@ function createRootStore(initialState = {}) {
|
|
|
3035
2937
|
RecurringFrequency,
|
|
3036
2938
|
RootStore,
|
|
3037
2939
|
SettingModel,
|
|
3038
|
-
TOKEN_PATH,
|
|
3039
2940
|
TimeFrameModel,
|
|
3040
2941
|
TimeSlotModel,
|
|
3041
2942
|
Unit,
|
|
3042
2943
|
buildAuthHeaders,
|
|
3043
2944
|
clearAccessToken,
|
|
3044
|
-
clearApiCredentials,
|
|
3045
2945
|
clearAuth,
|
|
3046
2946
|
configure,
|
|
3047
2947
|
createRootStore,
|
|
3048
2948
|
ensureValidAccessToken,
|
|
3049
|
-
fetchAccessToken,
|
|
3050
2949
|
getAuth,
|
|
3051
2950
|
getConfig,
|
|
3052
2951
|
getConfigStore,
|
|
3053
2952
|
isAccessTokenExpired,
|
|
3054
|
-
requestAccessToken,
|
|
3055
2953
|
setAccessToken,
|
|
3056
|
-
setApiCredentials,
|
|
3057
2954
|
setBaseUrl,
|
|
3058
|
-
setConsumer
|
|
2955
|
+
setConsumer,
|
|
2956
|
+
setGetAccessToken
|
|
3059
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
|
}
|
|
@@ -2959,25 +2865,21 @@ export {
|
|
|
2959
2865
|
RecurringFrequency,
|
|
2960
2866
|
RootStore,
|
|
2961
2867
|
Setting_default as SettingModel,
|
|
2962
|
-
TOKEN_PATH,
|
|
2963
2868
|
TimeFrame_default as TimeFrameModel,
|
|
2964
2869
|
TimeSlot_default as TimeSlotModel,
|
|
2965
2870
|
Unit,
|
|
2966
2871
|
buildAuthHeaders,
|
|
2967
2872
|
clearAccessToken,
|
|
2968
|
-
clearApiCredentials,
|
|
2969
2873
|
clearAuth,
|
|
2970
2874
|
configure,
|
|
2971
2875
|
createRootStore,
|
|
2972
2876
|
ensureValidAccessToken,
|
|
2973
|
-
fetchAccessToken2 as fetchAccessToken,
|
|
2974
2877
|
getAuth,
|
|
2975
2878
|
getConfig,
|
|
2976
2879
|
getConfigStore,
|
|
2977
2880
|
isAccessTokenExpired,
|
|
2978
|
-
requestAccessToken,
|
|
2979
2881
|
setAccessToken,
|
|
2980
|
-
setApiCredentials,
|
|
2981
2882
|
setBaseUrl,
|
|
2982
|
-
setConsumer
|
|
2883
|
+
setConsumer,
|
|
2884
|
+
setGetAccessToken
|
|
2983
2885
|
};
|