een-api-toolkit 0.0.5

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/dist/index.js ADDED
@@ -0,0 +1,467 @@
1
+ import { defineStore as J } from "pinia";
2
+ import { ref as i, computed as U, onMounted as F } from "vue";
3
+ const f = {};
4
+ let p = {};
5
+ function de(e = {}) {
6
+ p = {
7
+ proxyUrl: e.proxyUrl ?? (f == null ? void 0 : f.VITE_PROXY_URL),
8
+ clientId: e.clientId ?? (f == null ? void 0 : f.VITE_EEN_CLIENT_ID),
9
+ redirectUri: e.redirectUri ?? (f == null ? void 0 : f.VITE_REDIRECT_URI),
10
+ debug: e.debug ?? (f == null ? void 0 : f.VITE_DEBUG) === "true"
11
+ };
12
+ }
13
+ function he() {
14
+ return p;
15
+ }
16
+ function N() {
17
+ return p.proxyUrl ?? (f == null ? void 0 : f.VITE_PROXY_URL);
18
+ }
19
+ function Z() {
20
+ return p.clientId ?? (f == null ? void 0 : f.VITE_EEN_CLIENT_ID);
21
+ }
22
+ function B() {
23
+ return p.redirectUri ?? (f == null ? void 0 : f.VITE_REDIRECT_URI) ?? "http://127.0.0.1:3333";
24
+ }
25
+ function R(e) {
26
+ return { data: e, error: null };
27
+ }
28
+ function c(e, t, r, n) {
29
+ return { data: null, error: { code: e, message: t, status: r, details: n } };
30
+ }
31
+ const O = { BASE_URL: "/", DEV: !1, MODE: "production", PROD: !0, SSR: !1 }, _ = () => {
32
+ try {
33
+ return (O == null ? void 0 : O.VITE_DEBUG) === "true";
34
+ } catch {
35
+ return !1;
36
+ }
37
+ };
38
+ function u(...e) {
39
+ _() && console.log("[een-api-toolkit]", ...e);
40
+ }
41
+ const S = J("een-auth", () => {
42
+ const e = i(null), t = i(null), r = i(null), n = i(null), o = i(null), a = i(443), l = i(null), d = i(null), E = i(!1);
43
+ let T = null;
44
+ const v = i(!1), g = i(null), P = U(() => !!e.value), x = U(() => o.value ? a.value === 443 ? `https://${o.value}` : `https://${o.value}:${a.value}` : null), k = U(() => t.value ? Date.now() >= t.value : !0), w = U(() => t.value ? Math.max(0, t.value - Date.now()) : 0);
45
+ function A(s, h) {
46
+ e.value = s, t.value = Date.now() + h * 1e3, y(), L(), u("Token set, expires in", h, "seconds");
47
+ }
48
+ function D(s) {
49
+ r.value = s, y();
50
+ }
51
+ function I(s) {
52
+ n.value = s, y();
53
+ }
54
+ function j(s) {
55
+ if (typeof s == "string")
56
+ try {
57
+ const h = new URL(s.startsWith("http") ? s : `https://${s}`);
58
+ o.value = h.hostname, a.value = h.port ? parseInt(h.port, 10) : 443;
59
+ } catch (h) {
60
+ u("Failed to parse URL, using as hostname:", h instanceof Error ? h.message : String(h)), o.value = s, a.value = 443;
61
+ }
62
+ else
63
+ o.value = s.hostname, a.value = s.port ?? 443;
64
+ y(), u("Base URL set:", x.value);
65
+ }
66
+ function H(s) {
67
+ l.value = s, y();
68
+ }
69
+ function L() {
70
+ if (d.value && (clearTimeout(d.value), d.value = null), !t.value || !e.value)
71
+ return;
72
+ const s = Date.now(), m = t.value - s, G = 5 * 60 * 1e3, K = m / 2, X = Math.min(G, K), Y = Math.max(m - X, 60 * 1e3), b = Math.max(Y, 5e3);
73
+ u("Auto-refresh scheduled in", Math.round(b / 1e3), "seconds"), d.value = setTimeout(async () => {
74
+ await z();
75
+ }, b);
76
+ }
77
+ async function z() {
78
+ return T ? (u("Refresh already in progress, waiting for existing refresh"), T) : (E.value = !0, u("Performing auto-refresh"), T = (async () => {
79
+ try {
80
+ const { refreshToken: s } = await Promise.resolve().then(() => se), h = await s();
81
+ h.error ? (v.value = !0, g.value = h.error.message, u("Auto-refresh failed:", h.error.message)) : (v.value = !1, g.value = null, u("Auto-refresh successful"));
82
+ } catch (s) {
83
+ v.value = !0, g.value = s instanceof Error ? s.message : String(s), u("Auto-refresh error:", s);
84
+ } finally {
85
+ E.value = !1, T = null;
86
+ }
87
+ })(), T);
88
+ }
89
+ function V() {
90
+ v.value = !1, g.value = null;
91
+ }
92
+ function C() {
93
+ d.value && (clearTimeout(d.value), d.value = null), e.value = null, t.value = null, r.value = null, n.value = null, o.value = null, a.value = 443, l.value = null, v.value = !1, g.value = null, W(), u("Logged out");
94
+ }
95
+ function q() {
96
+ Q(), e.value && !k.value ? (L(), u("Initialized from storage")) : e.value && k.value && (u("Stored token expired, clearing"), C());
97
+ }
98
+ function y() {
99
+ try {
100
+ e.value && localStorage.setItem("een_token", e.value), t.value && localStorage.setItem("een_tokenExpiration", String(t.value)), r.value && localStorage.setItem("een_refreshTokenMarker", r.value), n.value && localStorage.setItem("een_sessionId", n.value), o.value && localStorage.setItem("een_hostname", o.value), a.value !== 443 && localStorage.setItem("een_port", String(a.value)), l.value && localStorage.setItem("een_userProfile", JSON.stringify(l.value));
101
+ } catch (s) {
102
+ u("Failed to save to localStorage:", s instanceof Error ? s.message : String(s));
103
+ }
104
+ }
105
+ function Q() {
106
+ try {
107
+ e.value = localStorage.getItem("een_token");
108
+ const s = localStorage.getItem("een_tokenExpiration");
109
+ t.value = s ? parseInt(s, 10) : null, r.value = localStorage.getItem("een_refreshTokenMarker"), n.value = localStorage.getItem("een_sessionId"), o.value = localStorage.getItem("een_hostname");
110
+ const h = localStorage.getItem("een_port");
111
+ a.value = h ? parseInt(h, 10) : 443;
112
+ const m = localStorage.getItem("een_userProfile");
113
+ l.value = m ? JSON.parse(m) : null;
114
+ } catch (s) {
115
+ u("Failed to load from localStorage:", s instanceof Error ? s.message : String(s));
116
+ }
117
+ }
118
+ function W() {
119
+ try {
120
+ localStorage.removeItem("een_token"), localStorage.removeItem("een_tokenExpiration"), localStorage.removeItem("een_refreshTokenMarker"), localStorage.removeItem("een_sessionId"), localStorage.removeItem("een_hostname"), localStorage.removeItem("een_port"), localStorage.removeItem("een_userProfile");
121
+ } catch (s) {
122
+ u("Failed to clear localStorage:", s instanceof Error ? s.message : String(s));
123
+ }
124
+ }
125
+ return {
126
+ // State
127
+ token: e,
128
+ tokenExpiration: t,
129
+ refreshTokenMarker: r,
130
+ sessionId: n,
131
+ hostname: o,
132
+ port: a,
133
+ userProfile: l,
134
+ isRefreshing: E,
135
+ refreshFailed: v,
136
+ refreshFailedMessage: g,
137
+ // Computed
138
+ isAuthenticated: P,
139
+ baseUrl: x,
140
+ isTokenExpired: k,
141
+ tokenExpiresIn: w,
142
+ // Actions
143
+ setToken: A,
144
+ setRefreshTokenMarker: D,
145
+ setSessionId: I,
146
+ setBaseUrl: j,
147
+ setUserProfile: H,
148
+ setupAutoRefresh: L,
149
+ clearRefreshFailed: V,
150
+ logout: C,
151
+ initialize: q
152
+ };
153
+ }), ee = "https://auth.eagleeyenetworks.com/oauth2/authorize";
154
+ function te() {
155
+ const e = Z();
156
+ if (!e)
157
+ throw new Error("Client ID not configured. Call initEenToolkit() or set VITE_EEN_CLIENT_ID");
158
+ const t = crypto.randomUUID();
159
+ try {
160
+ sessionStorage.setItem("een_oauth_state", t);
161
+ } catch {
162
+ }
163
+ const r = new URLSearchParams({
164
+ client_id: e,
165
+ response_type: "code",
166
+ scope: "vms.all",
167
+ redirect_uri: B(),
168
+ state: t
169
+ });
170
+ return u("Generated auth URL with state:", t), `${ee}?${r.toString()}`;
171
+ }
172
+ async function M(e) {
173
+ const t = N();
174
+ if (!t)
175
+ return c("AUTH_FAILED", "Proxy URL not configured. Call initEenToolkit() or set VITE_PROXY_URL");
176
+ const r = new URLSearchParams({
177
+ code: e,
178
+ redirect_uri: B()
179
+ });
180
+ try {
181
+ const n = await fetch(`${t}/proxy/getAccessToken?${r.toString()}`, {
182
+ method: "POST",
183
+ credentials: "include",
184
+ headers: {
185
+ Accept: "application/json"
186
+ }
187
+ });
188
+ if (!n.ok) {
189
+ const a = await n.text().catch(() => "Unknown error");
190
+ return c("AUTH_FAILED", `Token exchange failed: ${a}`, n.status);
191
+ }
192
+ const o = await n.json();
193
+ return u("Token received, expires in:", o.expiresIn), R(o);
194
+ } catch (n) {
195
+ return c("NETWORK_ERROR", `Failed to exchange code: ${String(n)}`);
196
+ }
197
+ }
198
+ async function re() {
199
+ const e = N();
200
+ if (!e)
201
+ return c("AUTH_FAILED", "Proxy URL not configured");
202
+ const t = S();
203
+ try {
204
+ const r = {
205
+ Accept: "application/json"
206
+ };
207
+ t.sessionId && (r.Authorization = `Bearer ${t.sessionId}`);
208
+ const n = await fetch(`${e}/proxy/refreshAccessToken`, {
209
+ method: "POST",
210
+ credentials: "include",
211
+ headers: r
212
+ });
213
+ if (!n.ok) {
214
+ const a = await n.text().catch(() => "Unknown error");
215
+ return c("AUTH_FAILED", `Token refresh failed: ${a}`, n.status);
216
+ }
217
+ const o = await n.json();
218
+ return t.setToken(o.accessToken, o.expiresIn), u("Token refreshed, expires in:", o.expiresIn), R(o);
219
+ } catch (r) {
220
+ return c("NETWORK_ERROR", `Failed to refresh token: ${String(r)}`);
221
+ }
222
+ }
223
+ async function ne() {
224
+ const e = N();
225
+ if (!e)
226
+ return c("AUTH_FAILED", "Proxy URL not configured");
227
+ const t = S();
228
+ try {
229
+ const r = {
230
+ Accept: "application/json"
231
+ };
232
+ t.sessionId && (r.Authorization = `Bearer ${t.sessionId}`);
233
+ const n = await fetch(`${e}/proxy/revoke`, {
234
+ method: "POST",
235
+ credentials: "include",
236
+ headers: r
237
+ });
238
+ if (t.logout(), !n.ok) {
239
+ const o = await n.text().catch(() => "Unknown error");
240
+ return c("AUTH_FAILED", `Token revocation failed: ${o}`, n.status);
241
+ }
242
+ return u("Token revoked"), R(void 0);
243
+ } catch (r) {
244
+ return t.logout(), c("NETWORK_ERROR", `Failed to revoke token: ${String(r)}`);
245
+ }
246
+ }
247
+ async function oe(e, t) {
248
+ let r = null;
249
+ try {
250
+ r = sessionStorage.getItem("een_oauth_state"), sessionStorage.removeItem("een_oauth_state");
251
+ } catch {
252
+ }
253
+ if (!r)
254
+ return c("AUTH_FAILED", "No OAuth state found. Please restart the login process.");
255
+ if (!ae(t, r))
256
+ return c("AUTH_FAILED", "Invalid OAuth state. Possible CSRF attack.");
257
+ u("State validated, exchanging code for token");
258
+ const n = await M(e);
259
+ if (n.error)
260
+ return n;
261
+ const o = S(), a = n.data;
262
+ return o.setToken(a.accessToken, a.expiresIn), o.setRefreshTokenMarker("present"), o.setSessionId(a.sessionId), o.setBaseUrl(a.httpsBaseUrl), u("Auth callback complete, user:", a.userEmail), R(a);
263
+ }
264
+ function ae(e, t) {
265
+ if (e.length !== t.length)
266
+ return !1;
267
+ let r = 0;
268
+ for (let n = 0; n < e.length; n++)
269
+ r |= e.charCodeAt(n) ^ t.charCodeAt(n);
270
+ return r === 0;
271
+ }
272
+ const se = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
273
+ __proto__: null,
274
+ getAccessToken: M,
275
+ getAuthUrl: te,
276
+ handleAuthCallback: oe,
277
+ refreshToken: re,
278
+ revokeToken: ne
279
+ }, Symbol.toStringTag, { value: "Module" }));
280
+ async function le() {
281
+ const e = S();
282
+ if (!e.isAuthenticated)
283
+ return c("AUTH_REQUIRED", "Authentication required");
284
+ if (!e.baseUrl)
285
+ return c("AUTH_REQUIRED", "Base URL not configured");
286
+ const t = `${e.baseUrl}/api/v3.0/users/self`;
287
+ u("Fetching current user:", t);
288
+ try {
289
+ const r = await fetch(t, {
290
+ method: "GET",
291
+ headers: {
292
+ Accept: "application/json",
293
+ Authorization: `Bearer ${e.token}`
294
+ }
295
+ });
296
+ if (!r.ok)
297
+ return $(r);
298
+ const n = await r.json();
299
+ return u("Current user fetched:", n.email), e.setUserProfile(n), R(n);
300
+ } catch (r) {
301
+ return c("NETWORK_ERROR", `Failed to fetch current user: ${String(r)}`);
302
+ }
303
+ }
304
+ async function ue(e) {
305
+ var a;
306
+ const t = S();
307
+ if (!t.isAuthenticated)
308
+ return c("AUTH_REQUIRED", "Authentication required");
309
+ if (!t.baseUrl)
310
+ return c("AUTH_REQUIRED", "Base URL not configured");
311
+ const r = new URLSearchParams();
312
+ e != null && e.pageSize && r.append("pageSize", String(e.pageSize)), e != null && e.pageToken && r.append("pageToken", e.pageToken), e != null && e.include && e.include.length > 0 && r.append("include", e.include.join(","));
313
+ const n = r.toString(), o = `${t.baseUrl}/api/v3.0/users${n ? `?${n}` : ""}`;
314
+ u("Fetching users:", o);
315
+ try {
316
+ const l = await fetch(o, {
317
+ method: "GET",
318
+ headers: {
319
+ Accept: "application/json",
320
+ Authorization: `Bearer ${t.token}`
321
+ }
322
+ });
323
+ if (!l.ok)
324
+ return $(l);
325
+ const d = await l.json();
326
+ return u("Users fetched:", ((a = d.results) == null ? void 0 : a.length) ?? 0, "users"), R(d);
327
+ } catch (l) {
328
+ return c("NETWORK_ERROR", `Failed to fetch users: ${String(l)}`);
329
+ }
330
+ }
331
+ async function ce(e, t) {
332
+ const r = S();
333
+ if (!r.isAuthenticated)
334
+ return c("AUTH_REQUIRED", "Authentication required");
335
+ if (!r.baseUrl)
336
+ return c("AUTH_REQUIRED", "Base URL not configured");
337
+ if (!e)
338
+ return c("VALIDATION_ERROR", "User ID is required");
339
+ const n = new URLSearchParams();
340
+ t != null && t.include && t.include.length > 0 && n.append("include", t.include.join(","));
341
+ const o = n.toString(), a = `${r.baseUrl}/api/v3.0/users/${encodeURIComponent(e)}${o ? `?${o}` : ""}`;
342
+ u("Fetching user:", a);
343
+ try {
344
+ const l = await fetch(a, {
345
+ method: "GET",
346
+ headers: {
347
+ Accept: "application/json",
348
+ Authorization: `Bearer ${r.token}`
349
+ }
350
+ });
351
+ if (!l.ok)
352
+ return $(l);
353
+ const d = await l.json();
354
+ return u("User fetched:", d.email), R(d);
355
+ } catch (l) {
356
+ return c("NETWORK_ERROR", `Failed to fetch user: ${String(l)}`);
357
+ }
358
+ }
359
+ async function $(e) {
360
+ const t = e.status;
361
+ let r;
362
+ try {
363
+ const n = await e.json();
364
+ r = n.message ?? n.error ?? e.statusText;
365
+ } catch {
366
+ r = e.statusText || "Unknown error";
367
+ }
368
+ switch (t) {
369
+ case 401:
370
+ return c("AUTH_REQUIRED", `Authentication failed: ${r}`, t);
371
+ case 403:
372
+ return c("FORBIDDEN", `Access denied: ${r}`, t);
373
+ case 404:
374
+ return c("NOT_FOUND", `Not found: ${r}`, t);
375
+ case 429:
376
+ return c("RATE_LIMITED", `Rate limited: ${r}`, t);
377
+ default:
378
+ return c("API_ERROR", `API error: ${r}`, t);
379
+ }
380
+ }
381
+ function ge(e) {
382
+ const t = i(null), r = i(!1), n = i(null), o = async () => {
383
+ r.value = !0, n.value = null;
384
+ const l = await le();
385
+ return l.error ? (n.value = l.error, t.value = null) : t.value = l.data, r.value = !1, l;
386
+ }, a = o;
387
+ return (e == null ? void 0 : e.immediate) !== !1 && F(o), {
388
+ user: t,
389
+ loading: r,
390
+ error: n,
391
+ fetch: o,
392
+ refresh: a
393
+ };
394
+ }
395
+ function ve(e, t) {
396
+ const r = i([]), n = i(!1), o = i(null), a = i(void 0), l = i(void 0), d = i(void 0), E = U(() => !!a.value), T = U(() => !!l.value), v = i(e ?? {}), g = async (A) => {
397
+ n.value = !0, o.value = null;
398
+ const D = { ...v.value, ...A }, I = await ue(D);
399
+ return I.error ? (o.value = I.error, r.value = [], a.value = void 0, l.value = void 0, d.value = void 0) : (r.value = I.data.results, a.value = I.data.nextPageToken, l.value = I.data.prevPageToken, d.value = I.data.totalSize), n.value = !1, I;
400
+ }, P = () => g(), x = async () => {
401
+ if (a.value)
402
+ return g({ ...v.value, pageToken: a.value });
403
+ }, k = async () => {
404
+ if (l.value)
405
+ return g({ ...v.value, pageToken: l.value });
406
+ }, w = (A) => {
407
+ v.value = A;
408
+ };
409
+ return (t == null ? void 0 : t.immediate) !== !1 && F(g), {
410
+ users: r,
411
+ loading: n,
412
+ error: o,
413
+ nextPageToken: a,
414
+ prevPageToken: l,
415
+ totalSize: d,
416
+ hasNextPage: E,
417
+ hasPrevPage: T,
418
+ params: v,
419
+ fetch: g,
420
+ refresh: P,
421
+ fetchNextPage: x,
422
+ fetchPrevPage: k,
423
+ setParams: w
424
+ };
425
+ }
426
+ function Te(e, t) {
427
+ const r = i(null), n = i(!1), o = i(null), a = () => typeof e == "function" ? e() : e, l = async (E) => {
428
+ const T = a();
429
+ if (!T)
430
+ return o.value = { code: "VALIDATION_ERROR", message: "User ID is required" }, { data: null, error: o.value };
431
+ n.value = !0, o.value = null;
432
+ const v = {
433
+ include: t == null ? void 0 : t.include,
434
+ ...E
435
+ }, g = await ce(T, v);
436
+ return g.error ? (o.value = g.error, r.value = null) : r.value = g.data, n.value = !1, g;
437
+ }, d = () => l();
438
+ return (t == null ? void 0 : t.immediate) !== !1 && a() && F(l), {
439
+ user: r,
440
+ loading: n,
441
+ error: o,
442
+ fetch: l,
443
+ refresh: d
444
+ };
445
+ }
446
+ export {
447
+ c as failure,
448
+ M as getAccessToken,
449
+ te as getAuthUrl,
450
+ Z as getClientId,
451
+ he as getConfig,
452
+ le as getCurrentUser,
453
+ N as getProxyUrl,
454
+ B as getRedirectUri,
455
+ ce as getUser,
456
+ ue as getUsers,
457
+ oe as handleAuthCallback,
458
+ de as initEenToolkit,
459
+ re as refreshToken,
460
+ ne as revokeToken,
461
+ R as success,
462
+ S as useAuthStore,
463
+ ge as useCurrentUser,
464
+ Te as useUser,
465
+ ve as useUsers
466
+ };
467
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/config.ts","../src/types/common.ts","../src/utils/debug.ts","../src/auth/store.ts","../src/auth/service.ts","../src/users/service.ts","../src/users/composables.ts"],"sourcesContent":["import type { EenToolkitConfig } from './types'\n\n/**\n * Global toolkit configuration\n */\nlet config: EenToolkitConfig = {}\n\n/**\n * Initialize the EEN API Toolkit\n */\nexport function initEenToolkit(options: EenToolkitConfig = {}): void {\n config = {\n proxyUrl: options.proxyUrl ?? import.meta.env?.VITE_PROXY_URL,\n clientId: options.clientId ?? import.meta.env?.VITE_EEN_CLIENT_ID,\n redirectUri: options.redirectUri ?? import.meta.env?.VITE_REDIRECT_URI,\n debug: options.debug ?? import.meta.env?.VITE_DEBUG === 'true'\n }\n}\n\n/**\n * Get the current configuration\n */\nexport function getConfig(): EenToolkitConfig {\n return config\n}\n\n/**\n * Get the proxy URL\n */\nexport function getProxyUrl(): string | undefined {\n return config.proxyUrl ?? import.meta.env?.VITE_PROXY_URL\n}\n\n/**\n * Get the client ID\n */\nexport function getClientId(): string | undefined {\n return config.clientId ?? import.meta.env?.VITE_EEN_CLIENT_ID\n}\n\n/**\n * Get the redirect URI\n */\nexport function getRedirectUri(): string {\n return config.redirectUri ?? import.meta.env?.VITE_REDIRECT_URI ?? 'http://127.0.0.1:3333'\n}\n","/**\n * Error codes returned by the toolkit.\n *\n * @remarks\n * All API functions return a {@link Result} type that contains either data or an error.\n * The error code helps you determine how to handle the failure.\n *\n * @category Types\n */\nexport type ErrorCode =\n | 'AUTH_REQUIRED'\n | 'AUTH_FAILED'\n | 'TOKEN_EXPIRED'\n | 'API_ERROR'\n | 'NETWORK_ERROR'\n | 'VALIDATION_ERROR'\n | 'NOT_FOUND'\n | 'FORBIDDEN'\n | 'RATE_LIMITED'\n | 'UNKNOWN_ERROR'\n\n/**\n * Error object returned when an operation fails.\n *\n * @remarks\n * Contains structured error information including a machine-readable code,\n * human-readable message, and optional HTTP status code.\n *\n * @example\n * ```typescript\n * const { error } = await getUsers()\n * if (error) {\n * console.error(`${error.code}: ${error.message}`)\n * if (error.status === 401) {\n * redirectToLogin()\n * }\n * }\n * ```\n *\n * @category Types\n */\nexport interface EenError {\n /** Machine-readable error code for programmatic handling */\n code: ErrorCode\n /** Human-readable error message */\n message: string\n /** HTTP status code if the error came from an API response */\n status?: number\n /** Additional error details (varies by error type) */\n details?: unknown\n}\n\n/**\n * Result type for all API operations - functions never throw exceptions.\n *\n * @remarks\n * This is a discriminated union type. When `error` is `null`, `data` contains\n * the successful result. When `error` is not `null`, `data` is `null`.\n * TypeScript will narrow the type correctly after checking for errors.\n *\n * @example\n * ```typescript\n * const { data, error } = await getUsers()\n *\n * if (error) {\n * // TypeScript knows: data is null, error is EenError\n * console.error(error.message)\n * return\n * }\n *\n * // TypeScript knows: data is not null, error is null\n * console.log(data.results)\n * ```\n *\n * @typeParam T - The type of the data on success\n * @category Types\n */\nexport type Result<T> =\n | { data: T; error: null }\n | { data: null; error: EenError }\n\n/**\n * Pagination parameters for list operations.\n *\n * @remarks\n * Most list APIs in the EEN platform support pagination. Use `pageSize` to\n * control how many results are returned, and `pageToken` to fetch subsequent pages.\n *\n * @example\n * ```typescript\n * // First page\n * const { data } = await getUsers({ pageSize: 50 })\n *\n * // Next page (if available)\n * if (data.nextPageToken) {\n * const { data: page2 } = await getUsers({\n * pageSize: 50,\n * pageToken: data.nextPageToken\n * })\n * }\n * ```\n *\n * @category Types\n */\nexport interface PaginationParams {\n /** Number of results per page (default varies by endpoint, typically 100) */\n pageSize?: number\n /** Token for fetching a specific page (from previous response's nextPageToken) */\n pageToken?: string\n}\n\n/**\n * Paginated response from list operations.\n *\n * @remarks\n * Contains the results array and optional pagination tokens for navigating\n * through large result sets.\n *\n * @typeParam T - The type of items in the results array\n * @category Types\n */\nexport interface PaginatedResult<T> {\n /** Array of items for this page */\n results: T[]\n /** Token to fetch the next page (undefined if no more pages) */\n nextPageToken?: string\n /** Token to fetch the previous page (undefined if on first page) */\n prevPageToken?: string\n /** Total number of items across all pages (may not be provided by all endpoints) */\n totalSize?: number\n}\n\n/**\n * Configuration for initializing the toolkit.\n *\n * @remarks\n * Pass this to {@link initEenToolkit} to configure the library. All options\n * can also be set via environment variables (VITE_PROXY_URL, VITE_EEN_CLIENT_ID,\n * VITE_REDIRECT_URI, VITE_DEBUG).\n *\n * @example\n * ```typescript\n * import { initEenToolkit } from 'een-api-toolkit'\n *\n * initEenToolkit({\n * proxyUrl: 'https://your-proxy.workers.dev',\n * clientId: 'your-een-client-id',\n * redirectUri: 'http://localhost:5173/callback',\n * debug: true\n * })\n * ```\n *\n * @category Configuration\n */\nexport interface EenToolkitConfig {\n /** URL of the OAuth proxy server (required for API calls) */\n proxyUrl?: string\n /** EEN OAuth client ID (required for authentication) */\n clientId?: string\n /** OAuth redirect URI (default: http://127.0.0.1:3333) */\n redirectUri?: string\n /** Enable debug logging to console */\n debug?: boolean\n}\n\n/**\n * Helper to create a success result.\n *\n * @param data - The successful result data\n * @returns A Result object with data and null error\n *\n * @internal\n */\nexport function success<T>(data: T): Result<T> {\n return { data, error: null }\n}\n\n/**\n * Helper to create an error result.\n *\n * @param code - The error code\n * @param message - Human-readable error message\n * @param status - Optional HTTP status code\n * @param details - Optional additional error details\n * @returns A Result object with null data and error\n *\n * @internal\n */\nexport function failure<T>(code: ErrorCode, message: string, status?: number, details?: unknown): Result<T> {\n return { data: null, error: { code, message, status, details } }\n}\n","/**\n * Debug logging utility\n * Enabled when VITE_DEBUG=true in environment\n */\n\nconst isDebugEnabled = (): boolean => {\n try {\n return import.meta.env?.VITE_DEBUG === 'true'\n } catch {\n return false\n }\n}\n\nexport function debug(...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.log('[een-api-toolkit]', ...args)\n }\n}\n\nexport function debugWarn(...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.warn('[een-api-toolkit]', ...args)\n }\n}\n\nexport function debugError(...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.error('[een-api-toolkit]', ...args)\n }\n}\n","import { defineStore } from 'pinia'\nimport { ref, computed } from 'vue'\nimport type { UserProfile } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * Pinia store for authentication state management\n */\nexport const useAuthStore = defineStore('een-auth', () => {\n // State\n const token = ref<string | null>(null)\n const tokenExpiration = ref<number | null>(null)\n const refreshTokenMarker = ref<string | null>(null)\n const sessionId = ref<string | null>(null)\n const hostname = ref<string | null>(null)\n const port = ref<number>(443)\n const userProfile = ref<UserProfile | null>(null)\n const refreshTimerId = ref<ReturnType<typeof setTimeout> | null>(null)\n const isRefreshing = ref(false)\n let refreshPromise: Promise<void> | null = null\n const refreshFailed = ref(false)\n const refreshFailedMessage = ref<string | null>(null)\n\n // Computed\n const isAuthenticated = computed(() => !!token.value)\n\n const baseUrl = computed(() => {\n if (!hostname.value) return null\n return port.value === 443\n ? `https://${hostname.value}`\n : `https://${hostname.value}:${port.value}`\n })\n\n const isTokenExpired = computed(() => {\n if (!tokenExpiration.value) return true\n return Date.now() >= tokenExpiration.value\n })\n\n const tokenExpiresIn = computed(() => {\n if (!tokenExpiration.value) return 0\n return Math.max(0, tokenExpiration.value - Date.now())\n })\n\n // Actions\n function setToken(newToken: string, expiresIn: number) {\n token.value = newToken\n tokenExpiration.value = Date.now() + expiresIn * 1000\n saveToStorage()\n setupAutoRefresh()\n debug('Token set, expires in', expiresIn, 'seconds')\n }\n\n function setRefreshTokenMarker(marker: string) {\n refreshTokenMarker.value = marker\n saveToStorage()\n }\n\n function setSessionId(newSessionId: string) {\n sessionId.value = newSessionId\n saveToStorage()\n }\n\n function setBaseUrl(data: string | { hostname: string; port?: number }) {\n if (typeof data === 'string') {\n // Parse URL string\n try {\n const url = new URL(data.startsWith('http') ? data : `https://${data}`)\n hostname.value = url.hostname\n port.value = url.port ? parseInt(url.port, 10) : 443\n } catch (err: unknown) {\n // Invalid URL format, use as hostname directly\n debug('Failed to parse URL, using as hostname:', err instanceof Error ? err.message : String(err))\n hostname.value = data\n port.value = 443\n }\n } else {\n hostname.value = data.hostname\n port.value = data.port ?? 443\n }\n saveToStorage()\n debug('Base URL set:', baseUrl.value)\n }\n\n function setUserProfile(profile: UserProfile) {\n userProfile.value = profile\n saveToStorage()\n }\n\n function setupAutoRefresh() {\n // Clear existing timer\n if (refreshTimerId.value) {\n clearTimeout(refreshTimerId.value)\n refreshTimerId.value = null\n }\n\n if (!tokenExpiration.value || !token.value) {\n return\n }\n\n const now = Date.now()\n const expiresAt = tokenExpiration.value\n const timeUntilExpiry = expiresAt - now\n\n // Calculate refresh time: 5 minutes before expiration or 50% of TTL, whichever is earlier\n // Minimum: 1 minute before expiration, minimum timeout: 5 seconds\n const fiveMinutes = 5 * 60 * 1000\n const halfTtl = timeUntilExpiry / 2\n const refreshBuffer = Math.min(fiveMinutes, halfTtl)\n const refreshTime = Math.max(timeUntilExpiry - refreshBuffer, 60 * 1000)\n const timeout = Math.max(refreshTime, 5000)\n\n debug('Auto-refresh scheduled in', Math.round(timeout / 1000), 'seconds')\n\n refreshTimerId.value = setTimeout(async () => {\n await performAutoRefresh()\n }, timeout)\n }\n\n async function performAutoRefresh(): Promise<void> {\n // If refresh is already in progress, wait for the existing promise\n if (refreshPromise) {\n debug('Refresh already in progress, waiting for existing refresh')\n return refreshPromise\n }\n\n isRefreshing.value = true\n debug('Performing auto-refresh')\n\n refreshPromise = (async () => {\n try {\n // Import dynamically to avoid circular dependency\n const { refreshToken } = await import('./service')\n const result = await refreshToken()\n\n if (result.error) {\n refreshFailed.value = true\n refreshFailedMessage.value = result.error.message\n debug('Auto-refresh failed:', result.error.message)\n } else {\n refreshFailed.value = false\n refreshFailedMessage.value = null\n debug('Auto-refresh successful')\n }\n } catch (err: unknown) {\n refreshFailed.value = true\n refreshFailedMessage.value = err instanceof Error ? err.message : String(err)\n debug('Auto-refresh error:', err)\n } finally {\n isRefreshing.value = false\n refreshPromise = null\n }\n })()\n\n return refreshPromise\n }\n\n function clearRefreshFailed() {\n refreshFailed.value = false\n refreshFailedMessage.value = null\n }\n\n function logout() {\n // Clear timer\n if (refreshTimerId.value) {\n clearTimeout(refreshTimerId.value)\n refreshTimerId.value = null\n }\n\n // Clear state\n token.value = null\n tokenExpiration.value = null\n refreshTokenMarker.value = null\n sessionId.value = null\n hostname.value = null\n port.value = 443\n userProfile.value = null\n refreshFailed.value = false\n refreshFailedMessage.value = null\n\n // Clear storage\n clearStorage()\n debug('Logged out')\n }\n\n function initialize() {\n loadFromStorage()\n if (token.value && !isTokenExpired.value) {\n setupAutoRefresh()\n debug('Initialized from storage')\n } else if (token.value && isTokenExpired.value) {\n debug('Stored token expired, clearing')\n logout()\n }\n }\n\n // Storage helpers\n function saveToStorage() {\n try {\n if (token.value) localStorage.setItem('een_token', token.value)\n if (tokenExpiration.value) localStorage.setItem('een_tokenExpiration', String(tokenExpiration.value))\n if (refreshTokenMarker.value) localStorage.setItem('een_refreshTokenMarker', refreshTokenMarker.value)\n if (sessionId.value) localStorage.setItem('een_sessionId', sessionId.value)\n if (hostname.value) localStorage.setItem('een_hostname', hostname.value)\n if (port.value !== 443) localStorage.setItem('een_port', String(port.value))\n if (userProfile.value) localStorage.setItem('een_userProfile', JSON.stringify(userProfile.value))\n } catch (err: unknown) {\n // localStorage might not be available (SSR, private browsing, etc.)\n debug('Failed to save to localStorage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function loadFromStorage() {\n try {\n token.value = localStorage.getItem('een_token')\n const expStr = localStorage.getItem('een_tokenExpiration')\n tokenExpiration.value = expStr ? parseInt(expStr, 10) : null\n refreshTokenMarker.value = localStorage.getItem('een_refreshTokenMarker')\n sessionId.value = localStorage.getItem('een_sessionId')\n hostname.value = localStorage.getItem('een_hostname')\n const portStr = localStorage.getItem('een_port')\n port.value = portStr ? parseInt(portStr, 10) : 443\n const profileStr = localStorage.getItem('een_userProfile')\n userProfile.value = profileStr ? JSON.parse(profileStr) : null\n } catch (err: unknown) {\n // localStorage might not be available (SSR, private browsing, etc.)\n debug('Failed to load from localStorage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function clearStorage() {\n try {\n localStorage.removeItem('een_token')\n localStorage.removeItem('een_tokenExpiration')\n localStorage.removeItem('een_refreshTokenMarker')\n localStorage.removeItem('een_sessionId')\n localStorage.removeItem('een_hostname')\n localStorage.removeItem('een_port')\n localStorage.removeItem('een_userProfile')\n } catch (err: unknown) {\n // localStorage might not be available (SSR, private browsing, etc.)\n debug('Failed to clear localStorage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n return {\n // State\n token,\n tokenExpiration,\n refreshTokenMarker,\n sessionId,\n hostname,\n port,\n userProfile,\n isRefreshing,\n refreshFailed,\n refreshFailedMessage,\n\n // Computed\n isAuthenticated,\n baseUrl,\n isTokenExpired,\n tokenExpiresIn,\n\n // Actions\n setToken,\n setRefreshTokenMarker,\n setSessionId,\n setBaseUrl,\n setUserProfile,\n setupAutoRefresh,\n clearRefreshFailed,\n logout,\n initialize\n }\n})\n","import { useAuthStore } from './store'\nimport { getProxyUrl, getClientId, getRedirectUri } from '../config'\nimport { success, failure } from '../types'\nimport type { Result } from '../types'\nimport { debug } from '../utils/debug'\n\nconst EEN_AUTH_URL = 'https://auth.eagleeyenetworks.com/oauth2/authorize'\n\n/**\n * Token response from the OAuth proxy.\n *\n * @remarks\n * This is the response returned by the proxy's `/proxy/getAccessToken` endpoint\n * after successfully exchanging an authorization code for an access token.\n *\n * @category Authentication\n */\nexport interface TokenResponse {\n accessToken: string\n expiresIn: number\n httpsBaseUrl: string | { hostname: string; port?: number }\n userEmail: string\n sessionId: string\n}\n\n/**\n * Generate the OAuth authorization URL\n */\nexport function getAuthUrl(): string {\n const clientId = getClientId()\n if (!clientId) {\n throw new Error('Client ID not configured. Call initEenToolkit() or set VITE_EEN_CLIENT_ID')\n }\n\n // Generate and store state for CSRF protection\n const state = crypto.randomUUID()\n try {\n sessionStorage.setItem('een_oauth_state', state)\n } catch {\n // sessionStorage might not be available\n }\n\n const params = new URLSearchParams({\n client_id: clientId,\n response_type: 'code',\n scope: 'vms.all',\n redirect_uri: getRedirectUri(),\n state\n })\n\n debug('Generated auth URL with state:', state)\n return `${EEN_AUTH_URL}?${params.toString()}`\n}\n\n/**\n * Exchange authorization code for access token\n */\nexport async function getAccessToken(code: string): Promise<Result<TokenResponse>> {\n const proxyUrl = getProxyUrl()\n if (!proxyUrl) {\n return failure('AUTH_FAILED', 'Proxy URL not configured. Call initEenToolkit() or set VITE_PROXY_URL')\n }\n\n const params = new URLSearchParams({\n code,\n redirect_uri: getRedirectUri()\n })\n\n try {\n const response = await fetch(`${proxyUrl}/proxy/getAccessToken?${params.toString()}`, {\n method: 'POST',\n credentials: 'include',\n headers: {\n 'Accept': 'application/json'\n }\n })\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error')\n return failure('AUTH_FAILED', `Token exchange failed: ${errorText}`, response.status)\n }\n\n const data = await response.json() as TokenResponse\n debug('Token received, expires in:', data.expiresIn)\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to exchange code: ${String(err)}`)\n }\n}\n\n/**\n * Refresh the access token using stored refresh token\n */\nexport async function refreshToken(): Promise<Result<{ accessToken: string; expiresIn: number }>> {\n const proxyUrl = getProxyUrl()\n if (!proxyUrl) {\n return failure('AUTH_FAILED', 'Proxy URL not configured')\n }\n\n const authStore = useAuthStore()\n\n try {\n const headers: HeadersInit = {\n 'Accept': 'application/json'\n }\n\n // Add session ID header as fallback for environments where cookies don't work\n if (authStore.sessionId) {\n headers['Authorization'] = `Bearer ${authStore.sessionId}`\n }\n\n const response = await fetch(`${proxyUrl}/proxy/refreshAccessToken`, {\n method: 'POST',\n credentials: 'include',\n headers\n })\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error')\n return failure('AUTH_FAILED', `Token refresh failed: ${errorText}`, response.status)\n }\n\n const data = await response.json() as { accessToken: string; expiresIn: number }\n\n // Update store with new token\n authStore.setToken(data.accessToken, data.expiresIn)\n\n debug('Token refreshed, expires in:', data.expiresIn)\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to refresh token: ${String(err)}`)\n }\n}\n\n/**\n * Revoke the current token and logout\n */\nexport async function revokeToken(): Promise<Result<void>> {\n const proxyUrl = getProxyUrl()\n if (!proxyUrl) {\n return failure('AUTH_FAILED', 'Proxy URL not configured')\n }\n\n const authStore = useAuthStore()\n\n try {\n const headers: HeadersInit = {\n 'Accept': 'application/json'\n }\n\n if (authStore.sessionId) {\n headers['Authorization'] = `Bearer ${authStore.sessionId}`\n }\n\n const response = await fetch(`${proxyUrl}/proxy/revoke`, {\n method: 'POST',\n credentials: 'include',\n headers\n })\n\n // Logout regardless of response\n authStore.logout()\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error')\n return failure('AUTH_FAILED', `Token revocation failed: ${errorText}`, response.status)\n }\n\n debug('Token revoked')\n return success(undefined)\n } catch (err) {\n // Still logout on error\n authStore.logout()\n return failure('NETWORK_ERROR', `Failed to revoke token: ${String(err)}`)\n }\n}\n\n/**\n * Handle OAuth callback - validates state and exchanges code for token\n */\nexport async function handleAuthCallback(code: string, state: string): Promise<Result<TokenResponse>> {\n // Validate state for CSRF protection\n let storedState: string | null = null\n try {\n storedState = sessionStorage.getItem('een_oauth_state')\n sessionStorage.removeItem('een_oauth_state')\n } catch {\n // sessionStorage might not be available\n }\n\n if (!storedState) {\n return failure('AUTH_FAILED', 'No OAuth state found. Please restart the login process.')\n }\n\n // Constant-time comparison to prevent timing attacks\n if (!constantTimeEquals(state, storedState)) {\n return failure('AUTH_FAILED', 'Invalid OAuth state. Possible CSRF attack.')\n }\n\n debug('State validated, exchanging code for token')\n\n // Exchange code for token\n const result = await getAccessToken(code)\n\n if (result.error) {\n return result\n }\n\n // Update auth store with received data\n const authStore = useAuthStore()\n const data = result.data\n\n authStore.setToken(data.accessToken, data.expiresIn)\n authStore.setRefreshTokenMarker('present')\n authStore.setSessionId(data.sessionId)\n authStore.setBaseUrl(data.httpsBaseUrl)\n\n debug('Auth callback complete, user:', data.userEmail)\n\n return success(data)\n}\n\n/**\n * Constant-time string comparison to prevent timing attacks\n */\nfunction constantTimeEquals(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false\n }\n\n let result = 0\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i)\n }\n\n return result === 0\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type { Result, PaginatedResult, User, UserProfile, ListUsersParams, GetUserParams } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * Get the current authenticated user's profile.\n *\n * @remarks\n * Fetches the profile of the currently authenticated user from `/api/v3.0/users/self`.\n * The result is also stored in the auth store for easy access via `useAuthStore().userProfile`.\n *\n * @returns A Result containing the user profile or an error\n *\n * @example\n * ```typescript\n * import { getCurrentUser } from 'een-api-toolkit'\n *\n * const { data, error } = await getCurrentUser()\n *\n * if (error) {\n * if (error.code === 'AUTH_REQUIRED') {\n * router.push('/login')\n * }\n * return\n * }\n *\n * console.log(`Welcome, ${data.firstName} ${data.lastName}`)\n * ```\n *\n * @category Users\n */\nexport async function getCurrentUser(): Promise<Result<UserProfile>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/users/self`\n debug('Fetching current user:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as UserProfile\n debug('Current user fetched:', data.email)\n\n // Update profile in store\n authStore.setUserProfile(data)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch current user: ${String(err)}`)\n }\n}\n\n/**\n * List users with optional pagination and filtering.\n *\n * @remarks\n * Fetches a paginated list of users from `/api/v3.0/users`. Use the `pageSize`\n * parameter to control how many results are returned per page, and `pageToken`\n * to navigate to subsequent pages.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listusers).\n *\n * @param params - Optional pagination and filtering parameters\n * @returns A Result containing a paginated list of users or an error\n *\n * @example\n * ```typescript\n * import { getUsers } from 'een-api-toolkit'\n *\n * // Basic usage\n * const { data, error } = await getUsers()\n * if (data) {\n * console.log(`Found ${data.results.length} users`)\n * }\n *\n * // With pagination\n * const { data } = await getUsers({ pageSize: 50 })\n * if (data?.nextPageToken) {\n * const { data: page2 } = await getUsers({\n * pageSize: 50,\n * pageToken: data.nextPageToken\n * })\n * }\n *\n * // Fetch all users\n * let allUsers: User[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await getUsers({ pageSize: 100, pageToken })\n * if (error) break\n * allUsers.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Users\n */\nexport async function getUsers(params?: ListUsersParams): Promise<Result<PaginatedResult<User>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/users${queryString ? `?${queryString}` : ''}`\n debug('Fetching users:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<User>\n debug('Users fetched:', data.results?.length ?? 0, 'users')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch users: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific user by ID.\n *\n * @remarks\n * Fetches a single user from `/api/v3.0/users/{userId}`. Use the `include`\n * parameter to request additional fields like permissions.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getuser).\n *\n * @param userId - The unique identifier of the user to fetch\n * @param params - Optional parameters (e.g., include additional fields)\n * @returns A Result containing the user or an error\n *\n * @example\n * ```typescript\n * import { getUser } from 'een-api-toolkit'\n *\n * const { data, error } = await getUser('user-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('User not found')\n * }\n * return\n * }\n *\n * console.log(`User: ${data.firstName} ${data.lastName}`)\n *\n * // With permissions\n * const { data: userWithPerms } = await getUser('user-123', {\n * include: ['permissions']\n * })\n * console.log('Permissions:', userWithPerms?.permissions)\n * ```\n *\n * @category Users\n */\nexport async function getUser(userId: string, params?: GetUserParams): Promise<Result<User>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!userId) {\n return failure('VALIDATION_ERROR', 'User ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/users/${encodeURIComponent(userId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching user:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as User\n debug('User fetched:', data.email)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch user: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch {\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { ref, computed, onMounted } from 'vue'\nimport { getCurrentUser, getUsers, getUser } from './service'\nimport type { User, UserProfile, EenError, ListUsersParams, GetUserParams } from '../types'\n\n/**\n * Options for the useCurrentUser composable.\n *\n * @category Users\n */\nexport interface UseCurrentUserOptions {\n /**\n * Whether to fetch the user immediately on mount.\n * @defaultValue true\n */\n immediate?: boolean\n}\n\n/**\n * Vue 3 composable for getting the current authenticated user.\n *\n * @remarks\n * Provides reactive access to the current user's profile with automatic\n * fetching on component mount (configurable via options).\n *\n * @param options - Configuration options\n * @returns Reactive user state and control functions\n *\n * @example\n * ```vue\n * <script setup>\n * import { useCurrentUser } from 'een-api-toolkit'\n *\n * const { user, loading, error, refresh } = useCurrentUser()\n * </script>\n *\n * <template>\n * <div v-if=\"loading\">Loading...</div>\n * <div v-else-if=\"error\">Error: {{ error.message }}</div>\n * <div v-else-if=\"user\">\n * <h1>Welcome, {{ user.firstName }}!</h1>\n * <p>Email: {{ user.email }}</p>\n * <button @click=\"refresh\">Refresh</button>\n * </div>\n * </template>\n * ```\n *\n * @example\n * ```typescript\n * // Manual fetch (don't fetch on mount)\n * const { user, fetch } = useCurrentUser({ immediate: false })\n *\n * onMounted(async () => {\n * if (someCondition) {\n * await fetch()\n * }\n * })\n * ```\n *\n * @category Users\n */\nexport function useCurrentUser(options?: UseCurrentUserOptions) {\n /** The current user profile, or null if not loaded */\n const user = ref<UserProfile | null>(null)\n /** Whether a fetch is in progress */\n const loading = ref(false)\n /** The last error that occurred, or null if successful */\n const error = ref<EenError | null>(null)\n\n const fetch = async () => {\n loading.value = true\n error.value = null\n\n const result = await getCurrentUser()\n\n if (result.error) {\n error.value = result.error\n user.value = null\n } else {\n user.value = result.data\n }\n\n loading.value = false\n return result\n }\n\n /** Alias for fetch - refresh the current user data */\n const refresh = fetch\n\n // Fetch immediately by default\n if (options?.immediate !== false) {\n onMounted(fetch)\n }\n\n return {\n user,\n loading,\n error,\n fetch,\n refresh\n }\n}\n\n/**\n * Options for the useUsers composable.\n *\n * @category Users\n */\nexport interface UseUsersOptions {\n /**\n * Whether to fetch users immediately on mount.\n * @defaultValue true\n */\n immediate?: boolean\n}\n\n/**\n * Vue 3 composable for listing users with pagination.\n *\n * @remarks\n * Provides reactive access to a paginated list of users with built-in\n * pagination controls. Automatically fetches on mount unless disabled.\n *\n * @param initialParams - Initial pagination/filter parameters\n * @param options - Configuration options\n * @returns Reactive users state and pagination controls\n *\n * @example\n * ```vue\n * <script setup>\n * import { useUsers } from 'een-api-toolkit'\n *\n * const {\n * users,\n * loading,\n * error,\n * hasNextPage,\n * fetchNextPage,\n * refresh\n * } = useUsers({ pageSize: 20 })\n * </script>\n *\n * <template>\n * <div v-if=\"loading\">Loading...</div>\n * <div v-else-if=\"error\">Error: {{ error.message }}</div>\n * <div v-else>\n * <ul>\n * <li v-for=\"user in users\" :key=\"user.id\">\n * {{ user.firstName }} {{ user.lastName }} ({{ user.email }})\n * </li>\n * </ul>\n * <button v-if=\"hasNextPage\" @click=\"fetchNextPage\">\n * Load More\n * </button>\n * <button @click=\"refresh\">Refresh</button>\n * </div>\n * </template>\n * ```\n *\n * @example\n * ```typescript\n * // Change parameters dynamically\n * const { users, setParams, fetch } = useUsers()\n *\n * async function searchUsers(query: string) {\n * setParams({ pageSize: 50 })\n * await fetch()\n * }\n * ```\n *\n * @category Users\n */\nexport function useUsers(initialParams?: ListUsersParams, options?: UseUsersOptions) {\n /** Array of users for the current page */\n const users = ref<User[]>([])\n /** Whether a fetch is in progress */\n const loading = ref(false)\n /** The last error that occurred, or null if successful */\n const error = ref<EenError | null>(null)\n /** Token for fetching the next page */\n const nextPageToken = ref<string | undefined>(undefined)\n /** Token for fetching the previous page */\n const prevPageToken = ref<string | undefined>(undefined)\n /** Total number of users (if provided by API) */\n const totalSize = ref<number | undefined>(undefined)\n\n /** Whether there is a next page available */\n const hasNextPage = computed(() => !!nextPageToken.value)\n /** Whether there is a previous page available */\n const hasPrevPage = computed(() => !!prevPageToken.value)\n\n /** Current pagination/filter parameters */\n const params = ref<ListUsersParams>(initialParams ?? {})\n\n const fetch = async (fetchParams?: ListUsersParams) => {\n loading.value = true\n error.value = null\n\n const mergedParams = { ...params.value, ...fetchParams }\n const result = await getUsers(mergedParams)\n\n if (result.error) {\n error.value = result.error\n users.value = []\n nextPageToken.value = undefined\n prevPageToken.value = undefined\n totalSize.value = undefined\n } else {\n users.value = result.data.results\n nextPageToken.value = result.data.nextPageToken\n prevPageToken.value = result.data.prevPageToken\n totalSize.value = result.data.totalSize\n }\n\n loading.value = false\n return result\n }\n\n /** Refresh the current page */\n const refresh = () => fetch()\n\n /** Fetch the next page of results */\n const fetchNextPage = async () => {\n if (!nextPageToken.value) return\n return fetch({ ...params.value, pageToken: nextPageToken.value })\n }\n\n /** Fetch the previous page of results */\n const fetchPrevPage = async () => {\n if (!prevPageToken.value) return\n return fetch({ ...params.value, pageToken: prevPageToken.value })\n }\n\n /** Update the pagination/filter parameters */\n const setParams = (newParams: ListUsersParams) => {\n params.value = newParams\n }\n\n // Fetch immediately by default\n if (options?.immediate !== false) {\n onMounted(fetch)\n }\n\n return {\n users,\n loading,\n error,\n nextPageToken,\n prevPageToken,\n totalSize,\n hasNextPage,\n hasPrevPage,\n params,\n fetch,\n refresh,\n fetchNextPage,\n fetchPrevPage,\n setParams\n }\n}\n\n/**\n * Options for the useUser composable.\n *\n * @category Users\n */\nexport interface UseUserOptions {\n /**\n * Whether to fetch the user immediately on mount.\n * @defaultValue true\n */\n immediate?: boolean\n /**\n * Additional fields to include in the response.\n */\n include?: string[]\n}\n\n/**\n * Vue 3 composable for getting a single user by ID.\n *\n * @remarks\n * Provides reactive access to a specific user. The user ID can be provided\n * as a string or a getter function (useful for reactive route params).\n *\n * @param userId - The user ID (string or getter function)\n * @param options - Configuration options\n * @returns Reactive user state and control functions\n *\n * @example\n * ```vue\n * <script setup>\n * import { useUser } from 'een-api-toolkit'\n * import { useRoute } from 'vue-router'\n *\n * const route = useRoute()\n *\n * // Static ID\n * const { user, loading, error } = useUser('user-123')\n *\n * // Or reactive ID from route\n * const { user: routeUser } = useUser(() => route.params.id as string)\n * </script>\n *\n * <template>\n * <div v-if=\"loading\">Loading...</div>\n * <div v-else-if=\"error\">Error: {{ error.message }}</div>\n * <div v-else-if=\"user\">\n * <h1>{{ user.firstName }} {{ user.lastName }}</h1>\n * <p>Email: {{ user.email }}</p>\n * </div>\n * </template>\n * ```\n *\n * @example\n * ```typescript\n * // With additional fields\n * const { user } = useUser('user-123', {\n * include: ['permissions']\n * })\n *\n * // Access permissions when loaded\n * watchEffect(() => {\n * if (user.value?.permissions) {\n * console.log('User permissions:', user.value.permissions)\n * }\n * })\n * ```\n *\n * @category Users\n */\nexport function useUser(userId: string | (() => string), options?: UseUserOptions) {\n /** The user, or null if not loaded */\n const user = ref<User | null>(null)\n /** Whether a fetch is in progress */\n const loading = ref(false)\n /** The last error that occurred, or null if successful */\n const error = ref<EenError | null>(null)\n\n const resolveUserId = () => {\n return typeof userId === 'function' ? userId() : userId\n }\n\n const fetch = async (params?: GetUserParams) => {\n const id = resolveUserId()\n if (!id) {\n error.value = { code: 'VALIDATION_ERROR', message: 'User ID is required' }\n return { data: null, error: error.value }\n }\n\n loading.value = true\n error.value = null\n\n const mergedParams: GetUserParams = {\n include: options?.include,\n ...params\n }\n\n const result = await getUser(id, mergedParams)\n\n if (result.error) {\n error.value = result.error\n user.value = null\n } else {\n user.value = result.data\n }\n\n loading.value = false\n return result\n }\n\n /** Refresh the user data */\n const refresh = () => fetch()\n\n // Fetch immediately by default if userId is provided\n if (options?.immediate !== false && resolveUserId()) {\n onMounted(fetch)\n }\n\n return {\n user,\n loading,\n error,\n fetch,\n refresh\n }\n}\n"],"names":["config","initEenToolkit","options","__vite_import_meta_env__","getConfig","getProxyUrl","getClientId","getRedirectUri","success","data","failure","code","message","status","details","isDebugEnabled","debug","args","useAuthStore","defineStore","token","ref","tokenExpiration","refreshTokenMarker","sessionId","hostname","port","userProfile","refreshTimerId","isRefreshing","refreshPromise","refreshFailed","refreshFailedMessage","isAuthenticated","computed","baseUrl","isTokenExpired","tokenExpiresIn","setToken","newToken","expiresIn","saveToStorage","setupAutoRefresh","setRefreshTokenMarker","marker","setSessionId","newSessionId","setBaseUrl","url","err","setUserProfile","profile","now","timeUntilExpiry","fiveMinutes","halfTtl","refreshBuffer","refreshTime","timeout","performAutoRefresh","refreshToken","service","result","clearRefreshFailed","logout","clearStorage","initialize","loadFromStorage","expStr","portStr","profileStr","EEN_AUTH_URL","getAuthUrl","clientId","state","params","getAccessToken","proxyUrl","response","errorText","authStore","headers","revokeToken","handleAuthCallback","storedState","constantTimeEquals","a","b","i","getCurrentUser","handleErrorResponse","getUsers","queryParams","queryString","_a","getUser","userId","errorData","useCurrentUser","user","loading","error","fetch","refresh","onMounted","useUsers","initialParams","users","nextPageToken","prevPageToken","totalSize","hasNextPage","hasPrevPage","fetchParams","mergedParams","fetchNextPage","fetchPrevPage","setParams","newParams","useUser","resolveUserId","id"],"mappings":"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"}