@nuria-tech/auth-sdk 1.0.3 → 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/README.md CHANGED
@@ -1,16 +1,18 @@
1
1
  # @nuria-tech/auth-sdk
2
2
 
3
- A minimal, browser-native TypeScript SDK for OAuth 2.0 Authorization Code flow with PKCE. Redirect-only — no embedded UI, no password flows.
3
+ [![npm version](https://img.shields.io/npm/v/@nuria-tech/auth-sdk.svg)](https://www.npmjs.com/package/@nuria-tech/auth-sdk)
4
+ [![CI](https://github.com/nuria-tech/nuria-auth-sdk/actions/workflows/ci-publish.yml/badge.svg)](https://github.com/nuria-tech/nuria-auth-sdk/actions/workflows/ci-publish.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
4
6
 
5
- ## Features
7
+ TypeScript SDK for OAuth 2.0 Authorization Code + PKCE, focused on browser apps and framework integrations (React, Vue, Nuxt, Next, Angular).
6
8
 
7
- - Authorization Code flow + PKCE (S256, mandatory)
8
- - State parameter generation and validation
9
- - Token exchange via standard form-encoded request
10
- - Automatic token refresh (optional)
11
- - Pluggable storage adapters (memory, sessionStorage, cookies)
12
- - Configurable HTTP transport with retry and interceptors
13
- - Zero production dependencies uses Web Crypto API and fetch
9
+ ## Why this SDK
10
+
11
+ - PKCE S256 + state validation by default
12
+ - Redirect-only flow (no embedded credential UI)
13
+ - Optional automatic refresh with concurrency dedupe
14
+ - Storage adapters for browser/SSR scenarios
15
+ - Framework helpers in dedicated entrypoints
14
16
 
15
17
  ## Installation
16
18
 
@@ -20,291 +22,271 @@ npm install @nuria-tech/auth-sdk
20
22
 
21
23
  Published on [npm](https://www.npmjs.com/package/@nuria-tech/auth-sdk).
22
24
 
23
- ## Quick start
24
-
25
- ```ts
26
- import { createAuthClient } from '@nuria-tech/auth-sdk';
27
-
28
- const auth = createAuthClient({
29
- clientId: 'your-client-id',
30
- baseUrl: 'https://ms-auth-v2.nuria.com.br',
31
- redirectUri: 'https://your-app.example.com/callback',
32
- });
25
+ ## Entrypoints
33
26
 
34
- // Redirect to login
35
- await auth.startLogin();
27
+ - `@nuria-tech/auth-sdk`: core client + adapters
28
+ - `@nuria-tech/auth-sdk/react`: `useAuthSession`, `AuthProvider`, `useAuth`
29
+ - `@nuria-tech/auth-sdk/vue`: `useAuthSession` composable
30
+ - `@nuria-tech/auth-sdk/nuxt`: Nuxt cookie adapter helpers
31
+ - `@nuria-tech/auth-sdk/next`: Next cookie adapter helpers
32
+ - `@nuria-tech/auth-sdk/angular`: RxJS auth facade for Angular services/components
36
33
 
37
- // In your callback page
38
- const session = await auth.handleRedirectCallback(window.location.href);
39
- console.log(session.tokens.accessToken);
40
- ```
34
+ ## Auth flows matrix
41
35
 
42
- ## Default behavior
36
+ | Flow | Backend endpoint(s) | SDK method(s) | Result |
37
+ |---|---|---|---|
38
+ | Google | `POST /v2/google` | `loginWithGoogle(...)` | `Session` tokens |
39
+ | Login + password | `POST /v2/login` | `loginWithPassword(...)` | `Session` tokens |
40
+ | Code sent (default) | `POST /v2/login-code/challenge` + `POST /v2/2fa/verify-login` | `loginWithCodeSent(...)` + `completeLoginWithCode(...)` | `Session` tokens after code verify |
43
41
 
44
- When omitted, the SDK uses:
42
+ ## Example apps
45
43
 
46
- - `baseUrl`: `https://ms-auth-v2.nuria.com.br`
47
- - `authorizationEndpoint`: `${baseUrl}/v2/oauth/authorize`
48
- - `tokenEndpoint`: `${baseUrl}/v2/oauth/token`
49
- - `scope`: `openid profile email`
50
- - `enableRefreshToken`: `true`
44
+ - `examples/react`
45
+ - `examples/vue`
46
+ - `examples/nuxt`
47
+ - `examples/next`
48
+ - `examples/angular`
51
49
 
52
- Override example:
50
+ ## Core quick start
53
51
 
54
52
  ```ts
53
+ import { createAuthClient } from '@nuria-tech/auth-sdk';
54
+
55
55
  const auth = createAuthClient({
56
56
  clientId: 'your-client-id',
57
- baseUrl: 'https://auth.hml.nuria.com.br',
58
- authorizationEndpoint: 'https://auth.hml.nuria.com.br/custom/authorize',
59
- tokenEndpoint: 'https://auth.hml.nuria.com.br/custom/token',
60
- redirectUri: 'https://your-app.example.com/callback',
61
- scope: 'openid profile',
62
- enableRefreshToken: false,
57
+ redirectUri: `${window.location.origin}/callback`,
63
58
  });
64
- ```
65
-
66
- ## Configuration
67
59
 
68
- ```ts
69
- interface AuthConfig {
70
- // Required
71
- clientId: string;
72
- redirectUri: string;
73
-
74
- // Optional
75
- baseUrl?: string; // default: https://ms-auth-v2.nuria.com.br
76
- authorizationEndpoint?: string; // default: {baseUrl}/v2/oauth/authorize
77
- tokenEndpoint?: string; // default: {baseUrl}/v2/oauth/token
78
- scope?: string; // default: "openid profile email"
79
- logoutEndpoint?: string; // if set, logout() redirects here
80
- userinfoEndpoint?: string; // required for getUserinfo()
81
- storage?: StorageAdapter; // default: MemoryStorageAdapter
82
- transport?: AuthTransport; // default: FetchAuthTransport
83
- onRedirect?: (url: string) => void | Promise<void>; // override browser redirect
84
- enableRefreshToken?: boolean; // default: true
85
- now?: () => number; // override Date.now() for testing
86
- }
60
+ await auth.startLogin();
61
+ // callback route
62
+ await auth.handleRedirectCallback(window.location.href);
63
+ const token = await auth.getAccessToken();
64
+ console.log(token);
87
65
  ```
88
66
 
89
- > **Security note:** Do not include `clientSecret` in browser apps. This SDK is designed for public clients (SPAs, mobile). PKCE provides the proof of possession without a client secret.
90
-
91
- ## Public API
67
+ ## Default login flow (login code sent)
92
68
 
93
69
  ```ts
94
- interface AuthClient {
95
- startLogin(options?: StartLoginOptions): Promise<void>;
96
- handleRedirectCallback(callbackUrl?: string): Promise<Session>;
97
- getSession(): Session | null;
98
- getAccessToken(): Promise<string | null>;
99
- logout(options?: { returnTo?: string }): Promise<void>;
100
- isAuthenticated(): boolean;
101
- onAuthStateChanged(handler: (session: Session | null) => void): () => void;
102
- getUserinfo(): Promise<Record<string, unknown>>;
103
- }
104
- ```
105
-
106
- ### `startLogin(options?)`
107
-
108
- Generates PKCE `code_verifier` + `code_challenge` (S256), stores them in the configured storage, and redirects to `authorizationEndpoint`. The `state` parameter is always included and validated on callback.
70
+ const challenge = await auth.startLoginCodeChallenge({
71
+ email: 'user@company.com',
72
+ // optional: channel defaults to 'email'
73
+ // channel: 'sms',
74
+ });
109
75
 
110
- ```ts
111
- await auth.startLogin({
112
- scopes: ['openid', 'profile'], // overrides config.scope
113
- loginHint: 'user@example.com',
114
- extraParams: { prompt: 'login' },
76
+ const session = await auth.verifyLoginCode({
77
+ challengeId: challenge.challengeId,
78
+ code: '123456',
115
79
  });
116
80
  ```
117
81
 
118
- ### `handleRedirectCallback(callbackUrl?)`
119
-
120
- Parses the callback URL, validates `state`, exchanges `code` for tokens using a form-encoded POST to `tokenEndpoint`, and clears transient PKCE storage. Throws typed `AuthError` on any failure.
121
- Token endpoint calls are sent with `credentials: 'include'` to support `HttpOnly` refresh-token cookies.
82
+ Aliases with clearer naming:
122
83
 
123
84
  ```ts
124
- // In your /callback route
125
- const session = await auth.handleRedirectCallback(window.location.href);
85
+ await auth.loginWithCodeSent({ email: 'user@company.com' });
86
+ await auth.completeLoginWithCode({ challengeId: '...', code: '123456' });
126
87
  ```
127
88
 
128
- ### `getAccessToken()`
89
+ ## React quick start
129
90
 
130
- Returns the current access token. If the token is expired and `enableRefreshToken: true`, automatically refreshes it (concurrent calls are deduplicated).
131
- Refresh calls to `tokenEndpoint` are sent with `credentials: 'include'`.
132
- If no `refresh_token` is available in JS memory/storage, SDK still attempts refresh using cookie-based session (HttpOnly) when the server supports it.
133
-
134
- ### `logout(options?)`
135
-
136
- Clears the local session. If `logoutEndpoint` is configured, redirects to it. Validates `returnTo` to prevent open redirect attacks.
91
+ ```tsx
92
+ import { createAuthClient } from '@nuria-tech/auth-sdk';
93
+ import { AuthProvider, useAuth } from '@nuria-tech/auth-sdk/react';
137
94
 
138
- ```ts
139
- await auth.logout({ returnTo: 'https://your-app.example.com' });
140
- ```
95
+ const auth = createAuthClient({
96
+ clientId: 'your-client-id',
97
+ redirectUri: `${window.location.origin}/callback`,
98
+ });
141
99
 
142
- ### `onAuthStateChanged(handler)`
100
+ function AppContent() {
101
+ const { session, isLoading, login, logout } = useAuth();
143
102
 
144
- Subscribes to session changes. Returns an unsubscribe function.
103
+ if (isLoading) return <div>Loading...</div>;
104
+ if (!session) return <button onClick={() => login()}>Login</button>;
105
+ return <button onClick={() => logout()}>Logout</button>;
106
+ }
145
107
 
146
- ```ts
147
- const unsubscribe = auth.onAuthStateChanged((session) => {
148
- console.log(session ? 'logged in' : 'logged out');
149
- });
108
+ export function App() {
109
+ return (
110
+ <AuthProvider auth={auth}>
111
+ <AppContent />
112
+ </AuthProvider>
113
+ );
114
+ }
150
115
  ```
151
116
 
152
- ## Storage adapters
153
-
154
- Default is `MemoryStorageAdapter` (most secure for XSS resistance, clears on reload).
117
+ ## Vue quick start
155
118
 
156
119
  ```ts
157
- import { WebStorageAdapter } from '@nuria-tech/auth-sdk';
120
+ import { createAuthClient } from '@nuria-tech/auth-sdk';
121
+ import { useAuthSession } from '@nuria-tech/auth-sdk/vue';
158
122
 
159
- // sessionStorage: persists per tab, JS-readable
160
123
  const auth = createAuthClient({
161
- ...config,
162
- storage: new WebStorageAdapter(window.sessionStorage),
124
+ clientId: 'your-client-id',
125
+ redirectUri: `${window.location.origin}/callback`,
163
126
  });
127
+
128
+ export function usePageAuth() {
129
+ const { session, isLoading, refresh } = useAuthSession(auth);
130
+ return { session, isLoading, refresh };
131
+ }
164
132
  ```
165
133
 
166
- Cookie adapter for SSR:
134
+ ## Nuxt quick start
167
135
 
168
136
  ```ts
169
- import { CookieStorageAdapter } from '@nuria-tech/auth-sdk';
170
-
171
- const auth = createAuthClient({
172
- ...config,
173
- storage: new CookieStorageAdapter({
174
- getCookie: async (name) => getCookieFromRequest(name),
175
- setCookie: async (name, value) => setResponseCookie(name, value),
176
- removeCookie: async (name) => clearResponseCookie(name),
177
- }),
178
- });
137
+ import { createNuxtAuthClient } from '@nuria-tech/auth-sdk/nuxt';
138
+ import { useCookie } from '#app';
139
+
140
+ const auth = createNuxtAuthClient(
141
+ {
142
+ clientId: process.env.NUXT_PUBLIC_AUTH_CLIENT_ID!,
143
+ redirectUri: process.env.NUXT_PUBLIC_AUTH_CALLBACK_URL!,
144
+ },
145
+ {
146
+ get: (name) => useCookie<string | null>(name).value,
147
+ set: (name, value) => {
148
+ useCookie<string | null>(name).value = value;
149
+ },
150
+ remove: (name) => {
151
+ useCookie<string | null>(name).value = null;
152
+ },
153
+ },
154
+ );
179
155
  ```
180
156
 
181
- ## Transport customization
157
+ ## Next quick start
182
158
 
183
159
  ```ts
184
- import { FetchAuthTransport } from '@nuria-tech/auth-sdk';
185
-
186
- const auth = createAuthClient({
187
- ...config,
188
- transport: new FetchAuthTransport({
189
- timeoutMs: 10_000,
190
- retries: 1,
191
- interceptors: [
192
- {
193
- onRequest: async (_url, req) => ({
194
- ...req,
195
- headers: { ...(req.headers ?? {}), 'X-App-Version': '1.0.0' },
196
- }),
197
- },
198
- ],
199
- }),
200
- });
160
+ import { createNextAuthClient } from '@nuria-tech/auth-sdk/next';
161
+ import { cookies } from 'next/headers';
162
+
163
+ export function createServerAuth() {
164
+ const cookieStore = cookies();
165
+ return createNextAuthClient(
166
+ {
167
+ clientId: process.env.NEXT_PUBLIC_AUTH_CLIENT_ID!,
168
+ redirectUri: process.env.NEXT_PUBLIC_AUTH_CALLBACK_URL!,
169
+ },
170
+ {
171
+ get: (name) => cookieStore.get(name)?.value,
172
+ set: (name, value) => cookieStore.set(name, value),
173
+ remove: (name) => cookieStore.delete(name),
174
+ },
175
+ );
176
+ }
201
177
  ```
202
178
 
203
- ## React example
179
+ ## Angular quick start
204
180
 
205
- ```tsx
206
- import { useMemo, useState, useEffect } from 'react';
181
+ ```ts
182
+ import { Injectable } from '@angular/core';
207
183
  import { createAuthClient } from '@nuria-tech/auth-sdk';
184
+ import { createAngularAuthFacade } from '@nuria-tech/auth-sdk/angular';
208
185
 
209
- const auth = createAuthClient({
210
- clientId: 'your-client-id',
211
- baseUrl: 'https://ms-auth-v2.nuria.com.br',
212
- redirectUri: `${window.location.origin}/callback`,
213
- });
186
+ @Injectable({ providedIn: 'root' })
187
+ export class AuthService {
188
+ private auth = createAuthClient({
189
+ clientId: 'your-client-id',
190
+ redirectUri: `${window.location.origin}/callback`,
191
+ });
214
192
 
215
- export function App() {
216
- const [session, setSession] = useState(auth.getSession());
193
+ private facade = createAngularAuthFacade(this.auth);
194
+ state$ = this.facade.state$;
217
195
 
218
- useEffect(() => auth.onAuthStateChanged(setSession), []);
196
+ login() {
197
+ return this.facade.login();
198
+ }
219
199
 
220
- if (!session) {
221
- return <button onClick={() => auth.startLogin()}>Login</button>;
200
+ logout() {
201
+ return this.facade.logout();
222
202
  }
223
- return <button onClick={() => auth.logout()}>Logout</button>;
224
203
  }
225
204
  ```
226
205
 
227
- ## Next.js SSR example
206
+ Full Angular example (service + guard + callback route + status component):
207
+ `examples/angular`
208
+
209
+ ## Defaults
210
+
211
+ - `baseUrl`: `https://ms-auth-v2.nuria.com.br`
212
+ - `authorizationEndpoint`: `${baseUrl}/v2/oauth/authorize`
213
+ - `tokenEndpoint`: `${baseUrl}/v2/oauth/token`
214
+ - `scope`: `openid profile email`
215
+ - `enableRefreshToken`: `true`
216
+
217
+ ## Configuration
228
218
 
229
219
  ```ts
230
- // lib/auth.ts
231
- import { createAuthClient, CookieStorageAdapter } from '@nuria-tech/auth-sdk';
232
-
233
- export function createServerAuth(cookieApi: {
234
- get: (name: string) => string | undefined;
235
- set: (name: string, value: string) => void;
236
- delete: (name: string) => void;
237
- }) {
238
- return createAuthClient({
239
- clientId: process.env.NEXT_PUBLIC_AUTH_CLIENT_ID!,
240
- baseUrl: process.env.NEXT_PUBLIC_AUTH_BASE_URL!,
241
- redirectUri: process.env.NEXT_PUBLIC_AUTH_CALLBACK_URL!,
242
- storage: new CookieStorageAdapter({
243
- getCookie: async (name) => cookieApi.get(name) ?? null,
244
- setCookie: async (name, value) => cookieApi.set(name, value),
245
- removeCookie: async (name) => cookieApi.delete(name),
246
- }),
247
- onRedirect: (url) => { redirect(url); },
248
- });
220
+ interface AuthConfig {
221
+ clientId: string;
222
+ redirectUri: string;
223
+ baseUrl?: string;
224
+ authorizationEndpoint?: string;
225
+ tokenEndpoint?: string;
226
+ scope?: string;
227
+ logoutEndpoint?: string;
228
+ userinfoEndpoint?: string;
229
+ storage?: StorageAdapter;
230
+ transport?: AuthTransport;
231
+ onRedirect?: (url: string) => void | Promise<void>;
232
+ enableRefreshToken?: boolean;
233
+ now?: () => number;
249
234
  }
250
235
  ```
251
236
 
252
- ## Security notes
237
+ ## Storage strategy
253
238
 
254
- - **No secrets:** Never include a `clientSecret` in browser/mobile apps. This SDK supports public clients only.
255
- - **PKCE is mandatory:** S256 code challenge is always used. Plain PKCE is not supported.
256
- - **State validation:** State is always generated and validated on callback.
257
- - **Memory storage default:** Tokens are stored in memory by default to minimize XSS exposure.
258
- - **Use sessionStorage cautiously:** Survives page reload but is still JS-readable.
259
- - **Avoid localStorage** for sensitive tokens.
260
- - **Validate `returnTo`:** The `logout()` method rejects non-`https://` or `http://` `returnTo` values.
239
+ | Adapter | Persists reload | JS-readable | SSR |
240
+ |---|---|---|---|
241
+ | `MemoryStorageAdapter` | No | Yes | No |
242
+ | `WebStorageAdapter(sessionStorage)` | Per tab | Yes | No |
243
+ | `WebStorageAdapter(localStorage)` | Yes | Yes | No |
244
+ | `CookieStorageAdapter` | Configurable | Depends on cookie flags | Yes |
261
245
 
262
- ## Storage trade-offs
246
+ ## Security notes
263
247
 
264
- | Adapter | Persists reload | XSS risk | SSR compatible |
265
- |---------|----------------|----------|----------------|
266
- | `MemoryStorageAdapter` | No | Lowest | No |
267
- | `WebStorageAdapter(sessionStorage)` | Per tab | Medium | No |
268
- | `WebStorageAdapter(localStorage)` | Yes | High | No |
269
- | `CookieStorageAdapter` | Configurable | Low (httpOnly) | Yes |
248
+ - Do not use `clientSecret` in browser/mobile apps.
249
+ - Prefer memory storage when possible.
250
+ - Keep refresh on cookies (`HttpOnly`) server-side when available.
251
+ - `logout({ returnTo })` accepts `https://` URLs, plus `http://localhost|127.0.0.1|[::1]` for local dev only.
252
+ - `logout({ returnTo })` rejects URLs with embedded credentials (`user:pass@host`).
253
+ - `isAuthenticated()` also checks token expiration (`expiresAt`) when available.
254
+ - Browser cookie storage encodes/decodes values safely (`encodeURIComponent`/`decodeURIComponent`).
270
255
 
271
- ## Troubleshooting
256
+ Full policy and reporting process: [SECURITY.md](./SECURITY.md).
272
257
 
273
- - **State mismatch:** Ensure the same storage instance/tab is used between `startLogin()` and `handleRedirectCallback()`. Clear `nuria:oauth:state` and retry.
274
- - **Missing code_verifier:** The `nuria:oauth:code_verifier` key was not found in storage. Ensure `startLogin()` was called before `handleRedirectCallback()`.
275
- - **Token refresh fails:** Ensure `enableRefreshToken: true` is set and the auth server supports the `refresh_token` grant for your client.
258
+ ## Public API
276
259
 
277
- ## CI/CD
260
+ ```ts
261
+ interface AuthClient {
262
+ startLogin(options?: StartLoginOptions): Promise<void>;
263
+ handleRedirectCallback(callbackUrl?: string): Promise<Session>;
264
+ getSession(): Session | null;
265
+ getAccessToken(): Promise<string | null>;
266
+ logout(options?: { returnTo?: string }): Promise<void>;
267
+ isAuthenticated(): boolean;
268
+ onAuthStateChanged(handler: (session: Session | null) => void): () => void;
269
+ getUserinfo(): Promise<Record<string, unknown>>;
270
+ startLoginCodeChallenge(options: LoginCodeChallengeOptions): Promise<TwoFactorChallenge>;
271
+ verifyLoginCode(options: VerifyLoginCodeOptions): Promise<Session>;
272
+ loginWithCodeSent(options: LoginCodeChallengeOptions): Promise<TwoFactorChallenge>;
273
+ completeLoginWithCode(options: VerifyLoginCodeOptions): Promise<Session>;
274
+ loginWithGoogle(options: GoogleLoginOptions): Promise<Session>;
275
+ loginWithPassword(options: PasswordLoginOptions): Promise<Session>;
276
+ }
277
+ ```
278
278
 
279
- This repository uses GitHub Actions (`.github/workflows/ci-publish.yml`):
279
+ ## CI and publish
280
280
 
281
- - **PR and `main` push:** typecheck, lint, test (coverage), build — runs on Node 20, 22
282
- - **Tag `v*` push:** validates tag matches `package.json` version, then publishes to npm via Trusted Publishing (OIDC — no stored tokens)
281
+ - PR/main runs: typecheck, lint, test, build
282
+ - Tag `v*` runs publish workflow with Trusted Publishing
283
283
 
284
- ### Publishing
284
+ Publish flow:
285
285
 
286
286
  1. Update `version` in `package.json`
287
- 2. Push a tag: `git tag v1.0.0 && git push --tags`
288
- 3. The workflow validates the version and publishes to npm
289
-
290
- > **One-time setup:** after the first manual publish, configure Trusted Publishing at **npmjs.com → package → Settings → Automated Publishing** with repository `nuria-tech/nuria-auth-sdk` and workflow `ci-publish.yml`.
291
-
292
- ## Endpoint defaults
293
-
294
- By default, the SDK assumes `ms-auth` OAuth endpoints:
295
-
296
- - `baseUrl`: `https://ms-auth-v2.nuria.com.br`
297
- - `authorizationEndpoint`: `${baseUrl}/v2/oauth/authorize`
298
- - `tokenEndpoint`: `${baseUrl}/v2/oauth/token`
299
-
300
- You can still override `authorizationEndpoint` and `tokenEndpoint` explicitly when needed.
301
-
302
- ## SSO strategy for multiple portals/apps
303
-
304
- - Storage adapter (memory/session/local) is **per origin** and does not share tokens across different domains.
305
- - For real SSO between different portals/apps, rely on auth-server session + `HttpOnly` refresh cookie (`__Host-nuria_rt`) and keep token calls with `credentials: 'include'`.
306
- - Keep `MemoryStorageAdapter` as default to reduce token exposure in JS.
287
+ 2. Tag and push (`git tag vX.Y.Z && git push --tags`)
288
+ 3. Workflow validates and publishes
307
289
 
308
290
  ## License
309
291
 
310
- MIT see [LICENSE](./LICENSE).
292
+ MIT - see [LICENSE](./LICENSE).
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ var rxjs = require('rxjs');
4
+
5
+ // src/angular/index.ts
6
+ function toState(session, isLoading, error) {
7
+ return {
8
+ session,
9
+ isAuthenticated: session !== null,
10
+ isLoading,
11
+ error
12
+ };
13
+ }
14
+ function createAngularAuthFacade(auth) {
15
+ const subject = new rxjs.BehaviorSubject(
16
+ toState(auth.getSession(), auth.getSession() === null, null)
17
+ );
18
+ const unsubscribe = auth.onAuthStateChanged((nextSession) => {
19
+ subject.next(toState(nextSession, false, null));
20
+ });
21
+ const refresh = async () => {
22
+ subject.next(toState(subject.value.session, true, null));
23
+ try {
24
+ await auth.getAccessToken();
25
+ const session = auth.getSession();
26
+ subject.next(toState(session, false, null));
27
+ return session;
28
+ } catch (error) {
29
+ subject.next(toState(auth.getSession(), false, error));
30
+ return null;
31
+ }
32
+ };
33
+ void refresh();
34
+ return {
35
+ state$: subject.asObservable(),
36
+ snapshot: () => subject.value,
37
+ refresh,
38
+ login: () => auth.startLogin(),
39
+ logout: (options) => auth.logout(options),
40
+ destroy: () => {
41
+ unsubscribe();
42
+ subject.complete();
43
+ }
44
+ };
45
+ }
46
+
47
+ exports.createAngularAuthFacade = createAngularAuthFacade;
48
+ //# sourceMappingURL=angular.cjs.map
49
+ //# sourceMappingURL=angular.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/angular/index.ts"],"names":["BehaviorSubject"],"mappings":";;;;;AAmBA,SAAS,OAAA,CACP,OAAA,EACA,SAAA,EACA,KAAA,EACkB;AAClB,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,iBAAiB,OAAA,KAAY,IAAA;AAAA,IAC7B,SAAA;AAAA,IACA;AAAA,GACF;AACF;AAEO,SAAS,wBAAwB,IAAA,EAAqC;AAC3E,EAAA,MAAM,UAAU,IAAIA,oBAAA;AAAA,IAClB,OAAA,CAAQ,KAAK,UAAA,EAAW,EAAG,KAAK,UAAA,EAAW,KAAM,MAAM,IAAI;AAAA,GAC7D;AAEA,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,kBAAA,CAAmB,CAAC,WAAA,KAAgB;AAC3D,IAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,WAAA,EAAa,KAAA,EAAO,IAAI,CAAC,CAAA;AAAA,EAChD,CAAC,CAAA;AAED,EAAA,MAAM,UAAU,YAAqC;AACnD,IAAA,OAAA,CAAQ,KAAK,OAAA,CAAQ,OAAA,CAAQ,MAAM,OAAA,EAAS,IAAA,EAAM,IAAI,CAAC,CAAA;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,KAAK,cAAA,EAAe;AAC1B,MAAA,MAAM,OAAA,GAAU,KAAK,UAAA,EAAW;AAChC,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS,KAAA,EAAO,IAAI,CAAC,CAAA;AAC1C,MAAA,OAAO,OAAA;AAAA,IACT,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAK,OAAA,CAAQ,IAAA,CAAK,YAAW,EAAG,KAAA,EAAO,KAAK,CAAC,CAAA;AACrD,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA;AAEA,EAAA,KAAK,OAAA,EAAQ;AAEb,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,QAAQ,YAAA,EAAa;AAAA,IAC7B,QAAA,EAAU,MAAM,OAAA,CAAQ,KAAA;AAAA,IACxB,OAAA;AAAA,IACA,KAAA,EAAO,MAAM,IAAA,CAAK,UAAA,EAAW;AAAA,IAC7B,MAAA,EAAQ,CAAC,OAAA,KAAY,IAAA,CAAK,OAAO,OAAO,CAAA;AAAA,IACxC,SAAS,MAAM;AACb,MAAA,WAAA,EAAY;AACZ,MAAA,OAAA,CAAQ,QAAA,EAAS;AAAA,IACnB;AAAA,GACF;AACF","file":"angular.cjs","sourcesContent":["import { BehaviorSubject, type Observable } from 'rxjs';\nimport type { AuthClient, Session } from '../core/types';\n\nexport interface AngularAuthState {\n session: Session | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n error: unknown;\n}\n\nexport interface AngularAuthFacade {\n state$: Observable<AngularAuthState>;\n snapshot: () => AngularAuthState;\n refresh: () => Promise<Session | null>;\n login: () => Promise<void>;\n logout: (options?: { returnTo?: string }) => Promise<void>;\n destroy: () => void;\n}\n\nfunction toState(\n session: Session | null,\n isLoading: boolean,\n error: unknown,\n): AngularAuthState {\n return {\n session,\n isAuthenticated: session !== null,\n isLoading,\n error,\n };\n}\n\nexport function createAngularAuthFacade(auth: AuthClient): AngularAuthFacade {\n const subject = new BehaviorSubject<AngularAuthState>(\n toState(auth.getSession(), auth.getSession() === null, null),\n );\n\n const unsubscribe = auth.onAuthStateChanged((nextSession) => {\n subject.next(toState(nextSession, false, null));\n });\n\n const refresh = async (): Promise<Session | null> => {\n subject.next(toState(subject.value.session, true, null));\n try {\n await auth.getAccessToken();\n const session = auth.getSession();\n subject.next(toState(session, false, null));\n return session;\n } catch (error) {\n subject.next(toState(auth.getSession(), false, error));\n return null;\n }\n };\n\n void refresh();\n\n return {\n state$: subject.asObservable(),\n snapshot: () => subject.value,\n refresh,\n login: () => auth.startLogin(),\n logout: (options) => auth.logout(options),\n destroy: () => {\n unsubscribe();\n subject.complete();\n },\n };\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { Observable } from 'rxjs';
2
+ import { e as Session, a as AuthClient } from './types-2k4ZYpF4.cjs';
3
+
4
+ interface AngularAuthState {
5
+ session: Session | null;
6
+ isAuthenticated: boolean;
7
+ isLoading: boolean;
8
+ error: unknown;
9
+ }
10
+ interface AngularAuthFacade {
11
+ state$: Observable<AngularAuthState>;
12
+ snapshot: () => AngularAuthState;
13
+ refresh: () => Promise<Session | null>;
14
+ login: () => Promise<void>;
15
+ logout: (options?: {
16
+ returnTo?: string;
17
+ }) => Promise<void>;
18
+ destroy: () => void;
19
+ }
20
+ declare function createAngularAuthFacade(auth: AuthClient): AngularAuthFacade;
21
+
22
+ export { type AngularAuthFacade, type AngularAuthState, createAngularAuthFacade };
@@ -0,0 +1,22 @@
1
+ import { Observable } from 'rxjs';
2
+ import { e as Session, a as AuthClient } from './types-2k4ZYpF4.js';
3
+
4
+ interface AngularAuthState {
5
+ session: Session | null;
6
+ isAuthenticated: boolean;
7
+ isLoading: boolean;
8
+ error: unknown;
9
+ }
10
+ interface AngularAuthFacade {
11
+ state$: Observable<AngularAuthState>;
12
+ snapshot: () => AngularAuthState;
13
+ refresh: () => Promise<Session | null>;
14
+ login: () => Promise<void>;
15
+ logout: (options?: {
16
+ returnTo?: string;
17
+ }) => Promise<void>;
18
+ destroy: () => void;
19
+ }
20
+ declare function createAngularAuthFacade(auth: AuthClient): AngularAuthFacade;
21
+
22
+ export { type AngularAuthFacade, type AngularAuthState, createAngularAuthFacade };