@nuria-tech/auth-sdk 1.0.2 → 1.0.4

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/nuxt.js ADDED
@@ -0,0 +1,716 @@
1
+ // src/errors/auth-error.ts
2
+ var AuthError = class extends Error {
3
+ constructor(code, message, cause) {
4
+ super(message);
5
+ this.code = code;
6
+ this.cause = cause;
7
+ this.name = "AuthError";
8
+ }
9
+ };
10
+
11
+ // src/core/pkce.ts
12
+ var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
13
+ function getCryptoImpl() {
14
+ if (typeof globalThis !== "undefined" && globalThis.crypto) {
15
+ return globalThis.crypto;
16
+ }
17
+ throw new Error("Web Crypto API unavailable");
18
+ }
19
+ function randomString(length = 64) {
20
+ const crypto = getCryptoImpl();
21
+ const THRESHOLD = 256 - 256 % ALPHABET.length;
22
+ const result = [];
23
+ while (result.length < length) {
24
+ const bytes = new Uint8Array(Math.ceil((length - result.length) * 1.4));
25
+ crypto.getRandomValues(bytes);
26
+ for (const b of bytes) {
27
+ if (result.length >= length) break;
28
+ if (b < THRESHOLD) result.push(ALPHABET[b % ALPHABET.length]);
29
+ }
30
+ }
31
+ return result.join("");
32
+ }
33
+ function toBase64Url(bytes) {
34
+ const binary = Array.from(bytes, (b) => String.fromCharCode(b)).join("");
35
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
36
+ }
37
+ function verifierToBytes(verifier) {
38
+ const bytes = new Uint8Array(verifier.length);
39
+ for (let i = 0; i < verifier.length; i++) {
40
+ bytes[i] = verifier.charCodeAt(i);
41
+ }
42
+ return bytes;
43
+ }
44
+ async function createCodeChallenge(verifier) {
45
+ const crypto = getCryptoImpl();
46
+ const buffer = verifierToBytes(verifier);
47
+ const digest = await crypto.subtle.digest("SHA-256", buffer);
48
+ return toBase64Url(new Uint8Array(digest));
49
+ }
50
+
51
+ // src/core/utils.ts
52
+ var STORAGE_KEYS = {
53
+ session: "nuria:session",
54
+ state: "nuria:oauth:state",
55
+ codeVerifier: "nuria:oauth:code_verifier"
56
+ };
57
+ function normalizeTokenSet(raw, now) {
58
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
59
+ const accessToken = (_b = (_a = raw.access_token) != null ? _a : raw.accessToken) != null ? _b : raw.Token;
60
+ if (!accessToken || typeof accessToken !== "string") {
61
+ throw new AuthError(
62
+ "TOKEN_EXCHANGE_FAILED" /* TOKEN_EXCHANGE_FAILED */,
63
+ "Missing access token in token response"
64
+ );
65
+ }
66
+ const expiresIn = Number((_d = (_c = raw.expires_in) != null ? _c : raw.expiresIn) != null ? _d : 0) || void 0;
67
+ const expiresAtFromResponse = Number((_e = raw.ExpiresAt) != null ? _e : 0) || void 0;
68
+ const computedExpiresAt = expiresIn != null ? now() + expiresIn * 1e3 : expiresAtFromResponse ? expiresAtFromResponse : void 0;
69
+ return {
70
+ accessToken,
71
+ tokenType: (_g = (_f = raw.token_type) != null ? _f : raw.tokenType) != null ? _g : raw.TokenType,
72
+ expiresIn,
73
+ refreshToken: (_i = (_h = raw.refresh_token) != null ? _h : raw.refreshToken) != null ? _i : raw.RefreshToken,
74
+ idToken: (_j = raw.id_token) != null ? _j : raw.idToken,
75
+ scope: raw.scope,
76
+ expiresAt: computedExpiresAt
77
+ };
78
+ }
79
+ async function safeGet(storage, key) {
80
+ try {
81
+ return await storage.get(key);
82
+ } catch (cause) {
83
+ throw new AuthError(
84
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
85
+ `Failed reading key: ${key}`,
86
+ cause
87
+ );
88
+ }
89
+ }
90
+ async function safeSet(storage, key, value) {
91
+ try {
92
+ await storage.set(key, value);
93
+ } catch (cause) {
94
+ throw new AuthError(
95
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
96
+ `Failed writing key: ${key}`,
97
+ cause
98
+ );
99
+ }
100
+ }
101
+ async function safeRemove(storage, key) {
102
+ try {
103
+ await storage.remove(key);
104
+ } catch (cause) {
105
+ throw new AuthError(
106
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
107
+ `Failed removing key: ${key}`,
108
+ cause
109
+ );
110
+ }
111
+ }
112
+ function timingSafeEqual(a, b) {
113
+ if (a.length !== b.length) return false;
114
+ let diff = 0;
115
+ for (let i = 0; i < a.length; i++) {
116
+ diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
117
+ }
118
+ return diff === 0;
119
+ }
120
+ function parseUrl(url) {
121
+ try {
122
+ return new URL(url);
123
+ } catch (e) {
124
+ throw new AuthError("CALLBACK_ERROR" /* CALLBACK_ERROR */, "Invalid callback URL");
125
+ }
126
+ }
127
+
128
+ // src/storage/memory-storage-adapter.ts
129
+ var MemoryStorageAdapter = class {
130
+ constructor() {
131
+ this.store = /* @__PURE__ */ new Map();
132
+ }
133
+ get(key) {
134
+ var _a;
135
+ return (_a = this.store.get(key)) != null ? _a : null;
136
+ }
137
+ set(key, value) {
138
+ this.store.set(key, value);
139
+ }
140
+ remove(key) {
141
+ this.store.delete(key);
142
+ }
143
+ };
144
+
145
+ // src/transport/fetch-transport.ts
146
+ var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
147
+ var FetchAuthTransport = class {
148
+ constructor(options = {}) {
149
+ var _a, _b, _c;
150
+ this.fetchFn = (_a = options.fetchFn) != null ? _a : fetch;
151
+ this.timeoutMs = options.timeoutMs;
152
+ this.retries = (_b = options.retries) != null ? _b : 0;
153
+ this.interceptors = (_c = options.interceptors) != null ? _c : [];
154
+ }
155
+ async request(url, req = {}) {
156
+ var _a, _b, _c, _d;
157
+ let request = req;
158
+ for (const i of this.interceptors) {
159
+ if (i.onRequest) request = await i.onRequest(url, request);
160
+ }
161
+ const retries = (_a = request.retries) != null ? _a : this.retries;
162
+ let attempt = 0;
163
+ while (true) {
164
+ const controller = new AbortController();
165
+ const timeout = (_b = request.timeoutMs) != null ? _b : this.timeoutMs;
166
+ const timer = timeout ? setTimeout(() => controller.abort(), timeout) : void 0;
167
+ try {
168
+ const defaultContentType = typeof request.body === "string" ? "application/x-www-form-urlencoded" : "application/json";
169
+ const res = await this.fetchFn(this.withQuery(url, request.query), {
170
+ method: (_c = request.method) != null ? _c : "GET",
171
+ credentials: request.credentials,
172
+ headers: {
173
+ "Content-Type": defaultContentType,
174
+ ...(_d = request.headers) != null ? _d : {}
175
+ },
176
+ body: request.body !== void 0 ? typeof request.body === "string" ? request.body : JSON.stringify(request.body) : void 0,
177
+ signal: controller.signal
178
+ });
179
+ const data = await this.parseBody(res);
180
+ if (!res.ok) {
181
+ if (attempt < retries && RETRYABLE_STATUS.has(res.status)) {
182
+ attempt += 1;
183
+ continue;
184
+ }
185
+ throw new AuthError("HTTP_ERROR" /* HTTP_ERROR */, `HTTP ${res.status}`);
186
+ }
187
+ let out = {
188
+ status: res.status,
189
+ data,
190
+ headers: res.headers
191
+ };
192
+ for (const i of this.interceptors) {
193
+ if (i.onResponse) out = await i.onResponse(out);
194
+ }
195
+ return out;
196
+ } catch (cause) {
197
+ if (cause instanceof AuthError) throw cause;
198
+ if (attempt < retries) {
199
+ attempt += 1;
200
+ continue;
201
+ }
202
+ throw new AuthError(
203
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
204
+ "Network request failed",
205
+ cause
206
+ );
207
+ } finally {
208
+ if (timer) clearTimeout(timer);
209
+ }
210
+ }
211
+ }
212
+ withQuery(url, query) {
213
+ if (!query) return url;
214
+ const parsed = new URL(url);
215
+ Object.entries(query).forEach(([k, v]) => {
216
+ if (v !== void 0) parsed.searchParams.set(k, v);
217
+ });
218
+ return parsed.toString();
219
+ }
220
+ async parseBody(res) {
221
+ var _a;
222
+ const contentType = (_a = res.headers.get("content-type")) != null ? _a : "";
223
+ if (contentType.includes("application/json")) {
224
+ return await res.json();
225
+ }
226
+ return await res.text();
227
+ }
228
+ };
229
+
230
+ // src/client/nuria-auth-client.ts
231
+ var DefaultAuthClient = class {
232
+ constructor(config) {
233
+ this.config = config;
234
+ this.session = null;
235
+ this.refreshPromise = null;
236
+ this.listeners = /* @__PURE__ */ new Set();
237
+ var _a, _b, _c;
238
+ this.storage = (_a = config.storage) != null ? _a : new MemoryStorageAdapter();
239
+ this.transport = (_b = config.transport) != null ? _b : new FetchAuthTransport();
240
+ this.now = (_c = config.now) != null ? _c : (() => Date.now());
241
+ }
242
+ async startLogin(options = {}) {
243
+ var _a, _b;
244
+ const state = randomString(32);
245
+ const codeVerifier = randomString(96);
246
+ const codeChallenge = await createCodeChallenge(codeVerifier);
247
+ await safeSet(this.storage, STORAGE_KEYS.state, state);
248
+ await safeSet(this.storage, STORAGE_KEYS.codeVerifier, codeVerifier);
249
+ const params = {
250
+ response_type: "code",
251
+ client_id: this.config.clientId,
252
+ redirect_uri: this.config.redirectUri,
253
+ state,
254
+ code_challenge: codeChallenge,
255
+ code_challenge_method: "S256"
256
+ };
257
+ const scope = (_b = (_a = options.scopes) == null ? void 0 : _a.join(" ")) != null ? _b : this.config.scope;
258
+ if (scope) params.scope = scope;
259
+ if (options.loginHint) params.login_hint = options.loginHint;
260
+ if (options.extraParams) {
261
+ const RESERVED = /* @__PURE__ */ new Set([
262
+ "response_type",
263
+ "client_id",
264
+ "redirect_uri",
265
+ "state",
266
+ "code_challenge",
267
+ "code_challenge_method"
268
+ ]);
269
+ for (const [k, v] of Object.entries(options.extraParams)) {
270
+ if (!RESERVED.has(k)) params[k] = v;
271
+ }
272
+ }
273
+ const url = new URL(this.config.authorizationEndpoint);
274
+ Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
275
+ const redirectUrl = url.toString();
276
+ if (this.config.onRedirect) {
277
+ await this.config.onRedirect(redirectUrl);
278
+ return;
279
+ }
280
+ if (typeof window !== "undefined") {
281
+ window.location.assign(redirectUrl);
282
+ return;
283
+ }
284
+ throw new AuthError(
285
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
286
+ "Missing onRedirect callback for non-browser runtime"
287
+ );
288
+ }
289
+ async handleRedirectCallback(callbackUrl) {
290
+ const input = callbackUrl != null ? callbackUrl : typeof window !== "undefined" ? window.location.href : "";
291
+ if (!input) {
292
+ throw new AuthError(
293
+ "CALLBACK_ERROR" /* CALLBACK_ERROR */,
294
+ "callbackUrl required in non-browser runtime"
295
+ );
296
+ }
297
+ const url = parseUrl(input);
298
+ const error = url.searchParams.get("error");
299
+ if (error) {
300
+ const desc = url.searchParams.get("error_description");
301
+ throw new AuthError(
302
+ "CALLBACK_ERROR" /* CALLBACK_ERROR */,
303
+ desc ? `Authorization error: ${error} \u2014 ${desc}` : `Authorization error: ${error}`
304
+ );
305
+ }
306
+ const code = url.searchParams.get("code");
307
+ if (!code) {
308
+ throw new AuthError(
309
+ "MISSING_CODE" /* MISSING_CODE */,
310
+ "Missing code in callback"
311
+ );
312
+ }
313
+ const state = url.searchParams.get("state");
314
+ if (!state) {
315
+ throw new AuthError(
316
+ "MISSING_STATE" /* MISSING_STATE */,
317
+ "Missing state in callback"
318
+ );
319
+ }
320
+ const storedState = await safeGet(this.storage, STORAGE_KEYS.state);
321
+ if (!storedState || !timingSafeEqual(storedState, state)) {
322
+ throw new AuthError(
323
+ "STATE_MISMATCH" /* STATE_MISMATCH */,
324
+ "State validation failed"
325
+ );
326
+ }
327
+ return this.exchangeCode(code);
328
+ }
329
+ getSession() {
330
+ return this.session;
331
+ }
332
+ async getAccessToken() {
333
+ var _a, _b;
334
+ if (!this.session) {
335
+ await this.hydrateSession();
336
+ }
337
+ if (!this.session) return null;
338
+ const exp = this.session.tokens.expiresAt;
339
+ if (exp && exp <= this.now() && this.config.enableRefreshToken) {
340
+ if (!this.refreshPromise) {
341
+ this.refreshPromise = this.doRefresh().finally(() => {
342
+ this.refreshPromise = null;
343
+ });
344
+ }
345
+ await this.refreshPromise;
346
+ }
347
+ return (_b = (_a = this.session) == null ? void 0 : _a.tokens.accessToken) != null ? _b : null;
348
+ }
349
+ async logout(options) {
350
+ if (options == null ? void 0 : options.returnTo) {
351
+ let returnToUrl;
352
+ try {
353
+ returnToUrl = new URL(options.returnTo);
354
+ } catch (e) {
355
+ throw new AuthError(
356
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
357
+ "returnTo must be a valid absolute URL"
358
+ );
359
+ }
360
+ const isHttps = returnToUrl.protocol === "https:";
361
+ const isLocalHttp = returnToUrl.protocol === "http:" && (returnToUrl.hostname === "localhost" || returnToUrl.hostname === "127.0.0.1" || returnToUrl.hostname === "[::1]");
362
+ if (!isHttps && !isLocalHttp) {
363
+ throw new AuthError(
364
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
365
+ "returnTo must use https:// (or http:// only for localhost)"
366
+ );
367
+ }
368
+ if (returnToUrl.username || returnToUrl.password) {
369
+ throw new AuthError(
370
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
371
+ "returnTo must not include URL credentials"
372
+ );
373
+ }
374
+ }
375
+ this.session = null;
376
+ await safeRemove(this.storage, STORAGE_KEYS.session);
377
+ await safeRemove(this.storage, STORAGE_KEYS.state);
378
+ await safeRemove(this.storage, STORAGE_KEYS.codeVerifier);
379
+ this.notify();
380
+ if (this.config.logoutEndpoint) {
381
+ const url = new URL(this.config.logoutEndpoint);
382
+ if (options == null ? void 0 : options.returnTo) {
383
+ url.searchParams.set("returnTo", options.returnTo);
384
+ }
385
+ const logoutUrl = url.toString();
386
+ if (this.config.onRedirect) {
387
+ await this.config.onRedirect(logoutUrl);
388
+ } else if (typeof window !== "undefined") {
389
+ window.location.assign(logoutUrl);
390
+ }
391
+ }
392
+ }
393
+ isAuthenticated() {
394
+ var _a, _b;
395
+ const accessToken = (_a = this.session) == null ? void 0 : _a.tokens.accessToken;
396
+ if (!accessToken) return false;
397
+ const exp = (_b = this.session) == null ? void 0 : _b.tokens.expiresAt;
398
+ if (exp && exp <= this.now()) return false;
399
+ return true;
400
+ }
401
+ onAuthStateChanged(handler) {
402
+ this.listeners.add(handler);
403
+ return () => this.listeners.delete(handler);
404
+ }
405
+ async getUserinfo() {
406
+ const accessToken = await this.getAccessToken();
407
+ if (!accessToken) {
408
+ throw new AuthError(
409
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
410
+ "Not authenticated \u2014 call handleRedirectCallback first"
411
+ );
412
+ }
413
+ if (!this.config.userinfoEndpoint) {
414
+ throw new AuthError(
415
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
416
+ "config.userinfoEndpoint is required for getUserinfo"
417
+ );
418
+ }
419
+ const response = await this.transport.request(
420
+ this.config.userinfoEndpoint,
421
+ { headers: { Authorization: `Bearer ${accessToken}` } }
422
+ );
423
+ return response.data;
424
+ }
425
+ async startLoginCodeChallenge(options) {
426
+ var _a, _b, _c, _d, _e, _f, _g;
427
+ if (!(options == null ? void 0 : options.email)) {
428
+ throw new AuthError(
429
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
430
+ "email is required for startLoginCodeChallenge"
431
+ );
432
+ }
433
+ const response = await this.transport.request(
434
+ `${this.config.baseUrl}/v2/login-code/challenge`,
435
+ {
436
+ method: "POST",
437
+ credentials: "include",
438
+ body: {
439
+ email: options.email,
440
+ channel: (_a = options.channel) != null ? _a : "email",
441
+ destination: options.destination,
442
+ purpose: (_b = options.purpose) != null ? _b : "login"
443
+ }
444
+ }
445
+ );
446
+ return {
447
+ challengeId: String((_c = response.data.challengeId) != null ? _c : ""),
448
+ channel: String((_d = response.data.channel) != null ? _d : ""),
449
+ destinationMasked: String((_e = response.data.destinationMasked) != null ? _e : ""),
450
+ expiresAt: Number((_f = response.data.expiresAt) != null ? _f : 0),
451
+ purpose: String((_g = response.data.purpose) != null ? _g : "login")
452
+ };
453
+ }
454
+ async verifyLoginCode(options) {
455
+ if (!(options == null ? void 0 : options.challengeId) || !(options == null ? void 0 : options.code)) {
456
+ throw new AuthError(
457
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
458
+ "challengeId and code are required for verifyLoginCode"
459
+ );
460
+ }
461
+ const response = await this.transport.request(
462
+ `${this.config.baseUrl}/v2/2fa/verify-login`,
463
+ {
464
+ method: "POST",
465
+ credentials: "include",
466
+ body: {
467
+ challengeId: options.challengeId,
468
+ code: options.code
469
+ }
470
+ }
471
+ );
472
+ const tokens = normalizeTokenSet(response.data, this.now);
473
+ return this.createSession(tokens);
474
+ }
475
+ async loginWithCodeSent(options) {
476
+ return this.startLoginCodeChallenge(options);
477
+ }
478
+ async completeLoginWithCode(options) {
479
+ return this.verifyLoginCode(options);
480
+ }
481
+ async loginWithGoogle(options) {
482
+ if (!(options == null ? void 0 : options.idToken)) {
483
+ throw new AuthError(
484
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
485
+ "idToken is required for loginWithGoogle"
486
+ );
487
+ }
488
+ const response = await this.transport.request(
489
+ `${this.config.baseUrl}/v2/google`,
490
+ {
491
+ method: "POST",
492
+ credentials: "include",
493
+ body: {
494
+ idToken: options.idToken
495
+ }
496
+ }
497
+ );
498
+ const tokens = normalizeTokenSet(response.data, this.now);
499
+ return this.createSession(tokens);
500
+ }
501
+ async loginWithPassword(options) {
502
+ if (!(options == null ? void 0 : options.email) || !(options == null ? void 0 : options.password)) {
503
+ throw new AuthError(
504
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
505
+ "email and password are required for loginWithPassword"
506
+ );
507
+ }
508
+ const response = await this.transport.request(
509
+ `${this.config.baseUrl}/v2/login`,
510
+ {
511
+ method: "POST",
512
+ credentials: "include",
513
+ body: {
514
+ email: options.email,
515
+ password: options.password
516
+ }
517
+ }
518
+ );
519
+ const tokens = normalizeTokenSet(response.data, this.now);
520
+ return this.createSession(tokens);
521
+ }
522
+ async exchangeCode(code) {
523
+ const verifier = await safeGet(this.storage, STORAGE_KEYS.codeVerifier);
524
+ if (!verifier) {
525
+ throw new AuthError(
526
+ "TOKEN_EXCHANGE_FAILED" /* TOKEN_EXCHANGE_FAILED */,
527
+ "Missing PKCE code_verifier in storage"
528
+ );
529
+ }
530
+ const body = new URLSearchParams({
531
+ grant_type: "authorization_code",
532
+ code,
533
+ code_verifier: verifier,
534
+ redirect_uri: this.config.redirectUri,
535
+ client_id: this.config.clientId
536
+ });
537
+ const response = await this.transport.request(
538
+ this.config.tokenEndpoint,
539
+ {
540
+ method: "POST",
541
+ credentials: "include",
542
+ body: body.toString()
543
+ }
544
+ );
545
+ const tokens = normalizeTokenSet(response.data, this.now);
546
+ await safeRemove(this.storage, STORAGE_KEYS.state);
547
+ await safeRemove(this.storage, STORAGE_KEYS.codeVerifier);
548
+ return this.createSession(tokens);
549
+ }
550
+ async doRefresh() {
551
+ var _a;
552
+ const refreshToken = (_a = this.session) == null ? void 0 : _a.tokens.refreshToken;
553
+ const body = new URLSearchParams({
554
+ grant_type: "refresh_token",
555
+ client_id: this.config.clientId
556
+ });
557
+ if (refreshToken) body.set("refresh_token", refreshToken);
558
+ const response = await this.transport.request(
559
+ this.config.tokenEndpoint,
560
+ {
561
+ method: "POST",
562
+ credentials: "include",
563
+ body: body.toString()
564
+ }
565
+ );
566
+ const tokens = normalizeTokenSet(response.data, this.now);
567
+ return this.createSession(tokens);
568
+ }
569
+ async createSession(tokens) {
570
+ var _a, _b;
571
+ const previousRefreshToken = (_a = this.session) == null ? void 0 : _a.tokens.refreshToken;
572
+ const mergedTokens = {
573
+ ...tokens,
574
+ refreshToken: (_b = tokens.refreshToken) != null ? _b : previousRefreshToken
575
+ };
576
+ this.session = {
577
+ tokens: mergedTokens,
578
+ createdAt: this.now()
579
+ };
580
+ await safeSet(
581
+ this.storage,
582
+ STORAGE_KEYS.session,
583
+ JSON.stringify(this.session)
584
+ );
585
+ this.notify();
586
+ return this.session;
587
+ }
588
+ notify() {
589
+ this.listeners.forEach((handler) => handler(this.session));
590
+ }
591
+ async hydrateSession() {
592
+ var _a;
593
+ const raw = await safeGet(this.storage, STORAGE_KEYS.session);
594
+ if (!raw) return;
595
+ try {
596
+ const parsed = JSON.parse(raw);
597
+ if (typeof ((_a = parsed == null ? void 0 : parsed.tokens) == null ? void 0 : _a.accessToken) !== "string") {
598
+ await safeRemove(this.storage, STORAGE_KEYS.session);
599
+ return;
600
+ }
601
+ this.session = parsed;
602
+ } catch (e) {
603
+ await safeRemove(this.storage, STORAGE_KEYS.session);
604
+ this.session = null;
605
+ }
606
+ }
607
+ };
608
+
609
+ // src/client/create-client.ts
610
+ var DEFAULT_AUTH_BASE_URL = "https://ms-auth-v2.nuria.com.br";
611
+ var DEFAULT_AUTHORIZATION_PATH = "/v2/oauth/authorize";
612
+ var DEFAULT_TOKEN_PATH = "/v2/oauth/token";
613
+ var DEFAULT_SCOPE = "openid profile email";
614
+ function normalizeBaseUrl(value) {
615
+ const raw = String(value != null ? value : DEFAULT_AUTH_BASE_URL).trim();
616
+ if (!raw) {
617
+ throw new AuthError(
618
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
619
+ "config.baseUrl must be a valid absolute URL"
620
+ );
621
+ }
622
+ let parsed;
623
+ try {
624
+ parsed = new URL(raw);
625
+ } catch (e) {
626
+ throw new AuthError(
627
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
628
+ "config.baseUrl must be a valid absolute URL"
629
+ );
630
+ }
631
+ return parsed.toString().replace(/\/+$/, "");
632
+ }
633
+ function resolveEndpoint(baseUrl, explicit, fallbackPath) {
634
+ if (explicit) {
635
+ try {
636
+ return new URL(explicit).toString();
637
+ } catch (e) {
638
+ throw new AuthError(
639
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
640
+ "OAuth endpoints must be valid absolute URLs"
641
+ );
642
+ }
643
+ }
644
+ return new URL(fallbackPath, `${baseUrl}/`).toString();
645
+ }
646
+ function createAuthClient(config) {
647
+ var _a, _b;
648
+ if (!(config == null ? void 0 : config.clientId)) {
649
+ throw new AuthError(
650
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
651
+ "config.clientId is required"
652
+ );
653
+ }
654
+ if (!config.redirectUri) {
655
+ throw new AuthError(
656
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
657
+ "config.redirectUri is required"
658
+ );
659
+ }
660
+ const baseUrl = normalizeBaseUrl(config.baseUrl);
661
+ const resolvedConfig = {
662
+ ...config,
663
+ baseUrl,
664
+ scope: String((_a = config.scope) != null ? _a : "").trim() || DEFAULT_SCOPE,
665
+ enableRefreshToken: (_b = config.enableRefreshToken) != null ? _b : true,
666
+ authorizationEndpoint: resolveEndpoint(
667
+ baseUrl,
668
+ config.authorizationEndpoint,
669
+ DEFAULT_AUTHORIZATION_PATH
670
+ ),
671
+ tokenEndpoint: resolveEndpoint(
672
+ baseUrl,
673
+ config.tokenEndpoint,
674
+ DEFAULT_TOKEN_PATH
675
+ )
676
+ };
677
+ return new DefaultAuthClient(resolvedConfig);
678
+ }
679
+
680
+ // src/storage/cookie-storage-adapter.ts
681
+ var CookieStorageAdapter = class {
682
+ constructor(callbacks) {
683
+ this.callbacks = callbacks;
684
+ }
685
+ async get(key) {
686
+ return this.callbacks.getCookie(key);
687
+ }
688
+ async set(key, value) {
689
+ await this.callbacks.setCookie(key, value);
690
+ }
691
+ async remove(key) {
692
+ await this.callbacks.removeCookie(key);
693
+ }
694
+ };
695
+
696
+ // src/nuxt/index.ts
697
+ function createNuxtCookieStorageAdapter(cookies) {
698
+ return new CookieStorageAdapter({
699
+ getCookie: async (name) => {
700
+ var _a;
701
+ return (_a = await cookies.get(name)) != null ? _a : null;
702
+ },
703
+ setCookie: (name, value) => cookies.set(name, value),
704
+ removeCookie: (name) => cookies.remove(name)
705
+ });
706
+ }
707
+ function createNuxtAuthClient(config, cookies) {
708
+ return createAuthClient({
709
+ ...config,
710
+ storage: createNuxtCookieStorageAdapter(cookies)
711
+ });
712
+ }
713
+
714
+ export { createNuxtAuthClient, createNuxtCookieStorageAdapter };
715
+ //# sourceMappingURL=nuxt.js.map
716
+ //# sourceMappingURL=nuxt.js.map