@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/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,254 +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
25
+ ## Entrypoints
26
+
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
33
+
34
+ ## Auth flows matrix
35
+
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 |
41
+
42
+ ## Example apps
43
+
44
+ - `examples/react`
45
+ - `examples/vue`
46
+ - `examples/nuxt`
47
+ - `examples/next`
48
+ - `examples/angular`
49
+
50
+ ## Core quick start
24
51
 
25
52
  ```ts
26
53
  import { createAuthClient } from '@nuria-tech/auth-sdk';
27
54
 
28
55
  const auth = createAuthClient({
29
56
  clientId: 'your-client-id',
30
- authorizationEndpoint: 'https://your-auth-server.example.com/authorize',
31
- tokenEndpoint: 'https://your-auth-server.example.com/token',
32
- redirectUri: 'https://your-app.example.com/callback',
33
- scope: 'openid profile email',
57
+ redirectUri: `${window.location.origin}/callback`,
34
58
  });
35
59
 
36
- // Redirect to login
37
60
  await auth.startLogin();
38
-
39
- // In your callback page
40
- const session = await auth.handleRedirectCallback(window.location.href);
41
- console.log(session.tokens.accessToken);
61
+ // callback route
62
+ await auth.handleRedirectCallback(window.location.href);
63
+ const token = await auth.getAccessToken();
64
+ console.log(token);
42
65
  ```
43
66
 
44
- ## Configuration
67
+ ## Default login flow (login code sent)
45
68
 
46
69
  ```ts
47
- interface AuthConfig {
48
- // Required
49
- clientId: string;
50
- authorizationEndpoint: string;
51
- tokenEndpoint: string;
52
- redirectUri: string;
53
-
54
- // Optional
55
- scope?: string; // default scope sent with every login
56
- logoutEndpoint?: string; // if set, logout() redirects here
57
- userinfoEndpoint?: string; // required for getUserinfo()
58
- storage?: StorageAdapter; // default: MemoryStorageAdapter
59
- transport?: AuthTransport; // default: FetchAuthTransport
60
- onRedirect?: (url: string) => void | Promise<void>; // override browser redirect
61
- enableRefreshToken?: boolean; // enable automatic token refresh
62
- now?: () => number; // override Date.now() for testing
63
- }
64
- ```
65
-
66
- > **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.
67
-
68
- ## Public API
69
-
70
- ```ts
71
- interface AuthClient {
72
- startLogin(options?: StartLoginOptions): Promise<void>;
73
- handleRedirectCallback(callbackUrl?: string): Promise<Session>;
74
- getSession(): Session | null;
75
- getAccessToken(): Promise<string | null>;
76
- logout(options?: { returnTo?: string }): Promise<void>;
77
- isAuthenticated(): boolean;
78
- onAuthStateChanged(handler: (session: Session | null) => void): () => void;
79
- getUserinfo(): Promise<Record<string, unknown>>;
80
- }
81
- ```
82
-
83
- ### `startLogin(options?)`
84
-
85
- 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
+ });
86
75
 
87
- ```ts
88
- await auth.startLogin({
89
- scopes: ['openid', 'profile'], // overrides config.scope
90
- loginHint: 'user@example.com',
91
- extraParams: { prompt: 'login' },
76
+ const session = await auth.verifyLoginCode({
77
+ challengeId: challenge.challengeId,
78
+ code: '123456',
92
79
  });
93
80
  ```
94
81
 
95
- ### `handleRedirectCallback(callbackUrl?)`
96
-
97
- 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.
98
- Token endpoint calls are sent with `credentials: 'include'` to support `HttpOnly` refresh-token cookies.
82
+ Aliases with clearer naming:
99
83
 
100
84
  ```ts
101
- // In your /callback route
102
- const session = await auth.handleRedirectCallback(window.location.href);
85
+ await auth.loginWithCodeSent({ email: 'user@company.com' });
86
+ await auth.completeLoginWithCode({ challengeId: '...', code: '123456' });
103
87
  ```
104
88
 
105
- ### `getAccessToken()`
89
+ ## React quick start
106
90
 
107
- Returns the current access token. If the token is expired and `enableRefreshToken: true`, automatically refreshes it (concurrent calls are deduplicated).
108
- Refresh calls to `tokenEndpoint` are sent with `credentials: 'include'`.
109
- If no `refresh_token` is available in JS memory/storage, SDK still attempts refresh using cookie-based session (HttpOnly) when the server supports it.
110
-
111
- ### `logout(options?)`
112
-
113
- 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';
114
94
 
115
- ```ts
116
- await auth.logout({ returnTo: 'https://your-app.example.com' });
117
- ```
95
+ const auth = createAuthClient({
96
+ clientId: 'your-client-id',
97
+ redirectUri: `${window.location.origin}/callback`,
98
+ });
118
99
 
119
- ### `onAuthStateChanged(handler)`
100
+ function AppContent() {
101
+ const { session, isLoading, login, logout } = useAuth();
120
102
 
121
- 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
+ }
122
107
 
123
- ```ts
124
- const unsubscribe = auth.onAuthStateChanged((session) => {
125
- console.log(session ? 'logged in' : 'logged out');
126
- });
108
+ export function App() {
109
+ return (
110
+ <AuthProvider auth={auth}>
111
+ <AppContent />
112
+ </AuthProvider>
113
+ );
114
+ }
127
115
  ```
128
116
 
129
- ## Storage adapters
130
-
131
- Default is `MemoryStorageAdapter` (most secure for XSS resistance, clears on reload).
117
+ ## Vue quick start
132
118
 
133
119
  ```ts
134
- import { WebStorageAdapter } from '@nuria-tech/auth-sdk';
120
+ import { createAuthClient } from '@nuria-tech/auth-sdk';
121
+ import { useAuthSession } from '@nuria-tech/auth-sdk/vue';
135
122
 
136
- // sessionStorage: persists per tab, JS-readable
137
123
  const auth = createAuthClient({
138
- ...config,
139
- storage: new WebStorageAdapter(window.sessionStorage),
124
+ clientId: 'your-client-id',
125
+ redirectUri: `${window.location.origin}/callback`,
140
126
  });
127
+
128
+ export function usePageAuth() {
129
+ const { session, isLoading, refresh } = useAuthSession(auth);
130
+ return { session, isLoading, refresh };
131
+ }
141
132
  ```
142
133
 
143
- Cookie adapter for SSR:
134
+ ## Nuxt quick start
144
135
 
145
136
  ```ts
146
- import { CookieStorageAdapter } from '@nuria-tech/auth-sdk';
147
-
148
- const auth = createAuthClient({
149
- ...config,
150
- storage: new CookieStorageAdapter({
151
- getCookie: async (name) => getCookieFromRequest(name),
152
- setCookie: async (name, value) => setResponseCookie(name, value),
153
- removeCookie: async (name) => clearResponseCookie(name),
154
- }),
155
- });
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
+ );
156
155
  ```
157
156
 
158
- ## Transport customization
157
+ ## Next quick start
159
158
 
160
159
  ```ts
161
- import { FetchAuthTransport } from '@nuria-tech/auth-sdk';
162
-
163
- const auth = createAuthClient({
164
- ...config,
165
- transport: new FetchAuthTransport({
166
- timeoutMs: 10_000,
167
- retries: 1,
168
- interceptors: [
169
- {
170
- onRequest: async (_url, req) => ({
171
- ...req,
172
- headers: { ...(req.headers ?? {}), 'X-App-Version': '1.0.0' },
173
- }),
174
- },
175
- ],
176
- }),
177
- });
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
+ }
178
177
  ```
179
178
 
180
- ## React example
179
+ ## Angular quick start
181
180
 
182
- ```tsx
183
- import { useMemo, useState, useEffect } from 'react';
181
+ ```ts
182
+ import { Injectable } from '@angular/core';
184
183
  import { createAuthClient } from '@nuria-tech/auth-sdk';
184
+ import { createAngularAuthFacade } from '@nuria-tech/auth-sdk/angular';
185
185
 
186
- const auth = createAuthClient({
187
- clientId: 'your-client-id',
188
- authorizationEndpoint: 'https://auth.example.com/authorize',
189
- tokenEndpoint: 'https://auth.example.com/token',
190
- redirectUri: `${window.location.origin}/callback`,
191
- });
186
+ @Injectable({ providedIn: 'root' })
187
+ export class AuthService {
188
+ private auth = createAuthClient({
189
+ clientId: 'your-client-id',
190
+ redirectUri: `${window.location.origin}/callback`,
191
+ });
192
192
 
193
- export function App() {
194
- const [session, setSession] = useState(auth.getSession());
193
+ private facade = createAngularAuthFacade(this.auth);
194
+ state$ = this.facade.state$;
195
195
 
196
- useEffect(() => auth.onAuthStateChanged(setSession), []);
196
+ login() {
197
+ return this.facade.login();
198
+ }
197
199
 
198
- if (!session) {
199
- return <button onClick={() => auth.startLogin()}>Login</button>;
200
+ logout() {
201
+ return this.facade.logout();
200
202
  }
201
- return <button onClick={() => auth.logout()}>Logout</button>;
202
203
  }
203
204
  ```
204
205
 
205
- ## 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
206
218
 
207
219
  ```ts
208
- // lib/auth.ts
209
- import { createAuthClient, CookieStorageAdapter } from '@nuria-tech/auth-sdk';
210
-
211
- export function createServerAuth(cookieApi: {
212
- get: (name: string) => string | undefined;
213
- set: (name: string, value: string) => void;
214
- delete: (name: string) => void;
215
- }) {
216
- return createAuthClient({
217
- clientId: process.env.NEXT_PUBLIC_AUTH_CLIENT_ID!,
218
- authorizationEndpoint: `${process.env.NEXT_PUBLIC_AUTH_BASE_URL}/authorize`,
219
- tokenEndpoint: `${process.env.NEXT_PUBLIC_AUTH_BASE_URL}/token`,
220
- redirectUri: process.env.NEXT_PUBLIC_AUTH_CALLBACK_URL!,
221
- storage: new CookieStorageAdapter({
222
- getCookie: async (name) => cookieApi.get(name) ?? null,
223
- setCookie: async (name, value) => cookieApi.set(name, value),
224
- removeCookie: async (name) => cookieApi.delete(name),
225
- }),
226
- onRedirect: (url) => { redirect(url); },
227
- });
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;
228
234
  }
229
235
  ```
230
236
 
231
- ## Security notes
237
+ ## Storage strategy
232
238
 
233
- - **No secrets:** Never include a `clientSecret` in browser/mobile apps. This SDK supports public clients only.
234
- - **PKCE is mandatory:** S256 code challenge is always used. Plain PKCE is not supported.
235
- - **State validation:** State is always generated and validated on callback.
236
- - **Memory storage default:** Tokens are stored in memory by default to minimize XSS exposure.
237
- - **Use sessionStorage cautiously:** Survives page reload but is still JS-readable.
238
- - **Avoid localStorage** for sensitive tokens.
239
- - **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 |
240
245
 
241
- ## Storage trade-offs
246
+ ## Security notes
242
247
 
243
- | Adapter | Persists reload | XSS risk | SSR compatible |
244
- |---------|----------------|----------|----------------|
245
- | `MemoryStorageAdapter` | No | Lowest | No |
246
- | `WebStorageAdapter(sessionStorage)` | Per tab | Medium | No |
247
- | `WebStorageAdapter(localStorage)` | Yes | High | No |
248
- | `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`).
249
255
 
250
- ## Troubleshooting
256
+ Full policy and reporting process: [SECURITY.md](./SECURITY.md).
251
257
 
252
- - **State mismatch:** Ensure the same storage instance/tab is used between `startLogin()` and `handleRedirectCallback()`. Clear `nuria:oauth:state` and retry.
253
- - **Missing code_verifier:** The `nuria:oauth:code_verifier` key was not found in storage. Ensure `startLogin()` was called before `handleRedirectCallback()`.
254
- - **Token refresh fails:** Ensure `enableRefreshToken: true` is set and the auth server supports the `refresh_token` grant for your client.
258
+ ## Public API
255
259
 
256
- ## 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
+ ```
257
278
 
258
- This repository uses GitHub Actions (`.github/workflows/ci-publish.yml`):
279
+ ## CI and publish
259
280
 
260
- - **PR and `main` push:** typecheck, lint, test (coverage), build — runs on Node 20, 22
261
- - **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
262
283
 
263
- ### Publishing
284
+ Publish flow:
264
285
 
265
286
  1. Update `version` in `package.json`
266
- 2. Push a tag: `git tag v1.0.0 && git push --tags`
267
- 3. The workflow validates the version and publishes to npm
268
-
269
- > **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`.
287
+ 2. Tag and push (`git tag vX.Y.Z && git push --tags`)
288
+ 3. Workflow validates and publishes
270
289
 
271
290
  ## License
272
291
 
273
- 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 };
@@ -0,0 +1,47 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+
3
+ // src/angular/index.ts
4
+ function toState(session, isLoading, error) {
5
+ return {
6
+ session,
7
+ isAuthenticated: session !== null,
8
+ isLoading,
9
+ error
10
+ };
11
+ }
12
+ function createAngularAuthFacade(auth) {
13
+ const subject = new BehaviorSubject(
14
+ toState(auth.getSession(), auth.getSession() === null, null)
15
+ );
16
+ const unsubscribe = auth.onAuthStateChanged((nextSession) => {
17
+ subject.next(toState(nextSession, false, null));
18
+ });
19
+ const refresh = async () => {
20
+ subject.next(toState(subject.value.session, true, null));
21
+ try {
22
+ await auth.getAccessToken();
23
+ const session = auth.getSession();
24
+ subject.next(toState(session, false, null));
25
+ return session;
26
+ } catch (error) {
27
+ subject.next(toState(auth.getSession(), false, error));
28
+ return null;
29
+ }
30
+ };
31
+ void refresh();
32
+ return {
33
+ state$: subject.asObservable(),
34
+ snapshot: () => subject.value,
35
+ refresh,
36
+ login: () => auth.startLogin(),
37
+ logout: (options) => auth.logout(options),
38
+ destroy: () => {
39
+ unsubscribe();
40
+ subject.complete();
41
+ }
42
+ };
43
+ }
44
+
45
+ export { createAngularAuthFacade };
46
+ //# sourceMappingURL=angular.js.map
47
+ //# sourceMappingURL=angular.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/angular/index.ts"],"names":[],"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,IAAI,eAAA;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.js","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,16 @@
1
+ import { S as StorageAdapter } from './types-2k4ZYpF4.js';
2
+
3
+ interface CookieStorageCallbacks {
4
+ getCookie(name: string): string | null | Promise<string | null>;
5
+ setCookie(name: string, value: string): void | Promise<void>;
6
+ removeCookie(name: string): void | Promise<void>;
7
+ }
8
+ declare class CookieStorageAdapter implements StorageAdapter {
9
+ private readonly callbacks;
10
+ constructor(callbacks: CookieStorageCallbacks);
11
+ get(key: string): Promise<string | null>;
12
+ set(key: string, value: string): Promise<void>;
13
+ remove(key: string): Promise<void>;
14
+ }
15
+
16
+ export { CookieStorageAdapter as C };