@authon/angular 0.1.0
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 +115 -0
- package/dist/index.cjs +132 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +114 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @authon/angular
|
|
2
|
+
|
|
3
|
+
Angular SDK for [Authon](https://authon.dev) — service, guard, and interceptor.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @authon/angular
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @authon/angular
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires `@angular/core >= 16.0.0`.
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### 1. Import Module
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// app.config.ts
|
|
21
|
+
import { provideAuthon } from '@authon/angular';
|
|
22
|
+
|
|
23
|
+
export const appConfig = {
|
|
24
|
+
providers: [
|
|
25
|
+
provideAuthon({
|
|
26
|
+
publishableKey: 'pk_live_...',
|
|
27
|
+
}),
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Use the Service
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { Component } from '@angular/core';
|
|
36
|
+
import { AuthonService } from '@authon/angular';
|
|
37
|
+
|
|
38
|
+
@Component({
|
|
39
|
+
selector: 'app-header',
|
|
40
|
+
template: `
|
|
41
|
+
@if (auth.isSignedIn()) {
|
|
42
|
+
<button (click)="auth.signOut()">Sign Out</button>
|
|
43
|
+
<p>{{ auth.user()?.displayName }}</p>
|
|
44
|
+
} @else {
|
|
45
|
+
<button (click)="auth.openSignIn()">Sign In</button>
|
|
46
|
+
}
|
|
47
|
+
`,
|
|
48
|
+
})
|
|
49
|
+
export class HeaderComponent {
|
|
50
|
+
constructor(public auth: AuthonService) {}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 3. Route Guard
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// app.routes.ts
|
|
58
|
+
import { authGuard } from '@authon/angular';
|
|
59
|
+
|
|
60
|
+
export const routes = [
|
|
61
|
+
{ path: 'dashboard', component: DashboardComponent, canActivate: [authGuard] },
|
|
62
|
+
{ path: 'login', component: LoginComponent },
|
|
63
|
+
];
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 4. HTTP Interceptor
|
|
67
|
+
|
|
68
|
+
Automatically attach the access token to outgoing requests:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
// app.config.ts
|
|
72
|
+
import { provideAuthon, authInterceptor } from '@authon/angular';
|
|
73
|
+
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
74
|
+
|
|
75
|
+
export const appConfig = {
|
|
76
|
+
providers: [
|
|
77
|
+
provideAuthon({ publishableKey: 'pk_live_...' }),
|
|
78
|
+
provideHttpClient(withInterceptors([authInterceptor])),
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## API Reference
|
|
84
|
+
|
|
85
|
+
### `AuthonService`
|
|
86
|
+
|
|
87
|
+
| Property / Method | Type | Description |
|
|
88
|
+
|-------------------|------|-------------|
|
|
89
|
+
| `user()` | `Signal<AuthonUser \| null>` | Current user signal |
|
|
90
|
+
| `isSignedIn()` | `Signal<boolean>` | Whether signed in |
|
|
91
|
+
| `isLoading()` | `Signal<boolean>` | Loading state |
|
|
92
|
+
| `openSignIn()` | `Promise<void>` | Open sign-in modal |
|
|
93
|
+
| `openSignUp()` | `Promise<void>` | Open sign-up modal |
|
|
94
|
+
| `signOut()` | `Promise<void>` | Sign out |
|
|
95
|
+
| `getToken()` | `string \| null` | Get current access token |
|
|
96
|
+
|
|
97
|
+
### Guard
|
|
98
|
+
|
|
99
|
+
| Export | Description |
|
|
100
|
+
|--------|-------------|
|
|
101
|
+
| `authGuard` | `CanActivateFn` that redirects unauthenticated users |
|
|
102
|
+
|
|
103
|
+
### Interceptor
|
|
104
|
+
|
|
105
|
+
| Export | Description |
|
|
106
|
+
|--------|-------------|
|
|
107
|
+
| `authInterceptor` | `HttpInterceptorFn` that adds Bearer token to requests |
|
|
108
|
+
|
|
109
|
+
## Documentation
|
|
110
|
+
|
|
111
|
+
[authon.dev/docs](https://authon.dev/docs)
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
[MIT](../../LICENSE)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AUTHON_CONFIG: () => AUTHON_CONFIG,
|
|
24
|
+
AuthonService: () => AuthonService,
|
|
25
|
+
authGuard: () => authGuard,
|
|
26
|
+
provideAuthon: () => provideAuthon
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/service.ts
|
|
31
|
+
var import_js = require("@authon/js");
|
|
32
|
+
var AUTHON_CONFIG = "AUTHON_CONFIG";
|
|
33
|
+
var AuthonService = class {
|
|
34
|
+
client;
|
|
35
|
+
_user = null;
|
|
36
|
+
_isSignedIn = false;
|
|
37
|
+
_isLoading = true;
|
|
38
|
+
_listeners = [];
|
|
39
|
+
constructor(config) {
|
|
40
|
+
this.client = new import_js.Authon(config.publishableKey, config.config);
|
|
41
|
+
this.client.on("signedIn", (user) => {
|
|
42
|
+
this._user = user;
|
|
43
|
+
this._isSignedIn = true;
|
|
44
|
+
this._isLoading = false;
|
|
45
|
+
this.notifyListeners();
|
|
46
|
+
});
|
|
47
|
+
this.client.on("signedOut", () => {
|
|
48
|
+
this._user = null;
|
|
49
|
+
this._isSignedIn = false;
|
|
50
|
+
this.notifyListeners();
|
|
51
|
+
});
|
|
52
|
+
this.client.on("error", () => {
|
|
53
|
+
this._isLoading = false;
|
|
54
|
+
this.notifyListeners();
|
|
55
|
+
});
|
|
56
|
+
this._isLoading = false;
|
|
57
|
+
}
|
|
58
|
+
get user() {
|
|
59
|
+
return this._user;
|
|
60
|
+
}
|
|
61
|
+
get isSignedIn() {
|
|
62
|
+
return this._isSignedIn;
|
|
63
|
+
}
|
|
64
|
+
get isLoading() {
|
|
65
|
+
return this._isLoading;
|
|
66
|
+
}
|
|
67
|
+
async openSignIn() {
|
|
68
|
+
await this.client.openSignIn();
|
|
69
|
+
}
|
|
70
|
+
async openSignUp() {
|
|
71
|
+
await this.client.openSignUp();
|
|
72
|
+
}
|
|
73
|
+
async signOut() {
|
|
74
|
+
await this.client.signOut();
|
|
75
|
+
this._user = null;
|
|
76
|
+
this._isSignedIn = false;
|
|
77
|
+
this.notifyListeners();
|
|
78
|
+
}
|
|
79
|
+
getToken() {
|
|
80
|
+
return this.client.getToken();
|
|
81
|
+
}
|
|
82
|
+
getClient() {
|
|
83
|
+
return this.client;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Subscribe to auth state changes.
|
|
87
|
+
* Returns an unsubscribe function.
|
|
88
|
+
*/
|
|
89
|
+
onStateChange(callback) {
|
|
90
|
+
this._listeners.push(callback);
|
|
91
|
+
return () => {
|
|
92
|
+
this._listeners = this._listeners.filter((l) => l !== callback);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
destroy() {
|
|
96
|
+
this.client.destroy();
|
|
97
|
+
this._listeners = [];
|
|
98
|
+
}
|
|
99
|
+
notifyListeners() {
|
|
100
|
+
for (const listener of this._listeners) {
|
|
101
|
+
listener();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// src/guard.ts
|
|
107
|
+
function authGuard(authonService, redirectTo = "/sign-in") {
|
|
108
|
+
if (authonService.isLoading) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
if (!authonService.isSignedIn) {
|
|
112
|
+
return { path: redirectTo };
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/helpers.ts
|
|
118
|
+
function provideAuthon(config) {
|
|
119
|
+
const service = new AuthonService(config);
|
|
120
|
+
return [
|
|
121
|
+
{ provide: AUTHON_CONFIG, useValue: config },
|
|
122
|
+
{ provide: "AuthonService", useValue: service }
|
|
123
|
+
];
|
|
124
|
+
}
|
|
125
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
126
|
+
0 && (module.exports = {
|
|
127
|
+
AUTHON_CONFIG,
|
|
128
|
+
AuthonService,
|
|
129
|
+
authGuard,
|
|
130
|
+
provideAuthon
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/service.ts","../src/guard.ts","../src/helpers.ts"],"sourcesContent":["export { AuthonService, AUTHON_CONFIG, type AuthonServiceConfig } from './service';\nexport { authGuard } from './guard';\nexport { provideAuthon } from './helpers';\n","import { Authon } from '@authon/js';\nimport type { AuthonConfig } from '@authon/js';\nimport type { AuthonUser } from '@authon/shared';\n\n/**\n * Injection token key for Authon configuration.\n * Used with Angular's InjectionToken.\n */\nexport const AUTHON_CONFIG = 'AUTHON_CONFIG';\n\nexport interface AuthonServiceConfig {\n publishableKey: string;\n config?: Omit<AuthonConfig, 'mode'>;\n}\n\n/**\n * Plain class wrapping @authon/js for Angular dependency injection.\n *\n * Since tsup cannot compile Angular decorators, this is a plain class.\n * Users should wrap it in their own injectable service:\n *\n * ```ts\n * import { Injectable } from '@angular/core';\n * import { AuthonService as BaseAuthonService } from '@authon/angular';\n *\n * @Injectable({ providedIn: 'root' })\n * export class AuthonService extends BaseAuthonService {\n * constructor() {\n * super({ publishableKey: 'pk_live_...' });\n * }\n * }\n * ```\n *\n * Or use the `provideAuthon()` helper for standalone components.\n */\nexport class AuthonService {\n private client: Authon;\n private _user: AuthonUser | null = null;\n private _isSignedIn = false;\n private _isLoading = true;\n private _listeners: Array<() => void> = [];\n\n constructor(config: AuthonServiceConfig) {\n this.client = new Authon(config.publishableKey, config.config);\n\n this.client.on('signedIn', (user) => {\n this._user = user as AuthonUser;\n this._isSignedIn = true;\n this._isLoading = false;\n this.notifyListeners();\n });\n\n this.client.on('signedOut', () => {\n this._user = null;\n this._isSignedIn = false;\n this.notifyListeners();\n });\n\n this.client.on('error', () => {\n this._isLoading = false;\n this.notifyListeners();\n });\n\n this._isLoading = false;\n }\n\n get user(): AuthonUser | null {\n return this._user;\n }\n\n get isSignedIn(): boolean {\n return this._isSignedIn;\n }\n\n get isLoading(): boolean {\n return this._isLoading;\n }\n\n async openSignIn(): Promise<void> {\n await this.client.openSignIn();\n }\n\n async openSignUp(): Promise<void> {\n await this.client.openSignUp();\n }\n\n async signOut(): Promise<void> {\n await this.client.signOut();\n this._user = null;\n this._isSignedIn = false;\n this.notifyListeners();\n }\n\n getToken(): string | null {\n return this.client.getToken();\n }\n\n getClient(): Authon {\n return this.client;\n }\n\n /**\n * Subscribe to auth state changes.\n * Returns an unsubscribe function.\n */\n onStateChange(callback: () => void): () => void {\n this._listeners.push(callback);\n return () => {\n this._listeners = this._listeners.filter((l) => l !== callback);\n };\n }\n\n destroy(): void {\n this.client.destroy();\n this._listeners = [];\n }\n\n private notifyListeners(): void {\n for (const listener of this._listeners) {\n listener();\n }\n }\n}\n","import type { AuthonService } from './service';\n\n/**\n * Route guard factory for Angular Router (CanActivateFn style).\n *\n * Since tsup can't compile Angular decorators, this returns a plain function.\n * Users wire it up in their route config:\n *\n * ```ts\n * import { inject } from '@angular/core';\n * import { authGuard } from '@authon/angular';\n * import { AuthonService } from './authon.service'; // your injectable wrapper\n *\n * const routes = [\n * {\n * path: 'dashboard',\n * component: DashboardComponent,\n * canActivate: [() => {\n * const authon = inject(AuthonService);\n * return authGuard(authon, '/login');\n * }],\n * },\n * ];\n * ```\n */\nexport function authGuard(\n authonService: AuthonService,\n redirectTo = '/sign-in',\n): boolean | { path: string } {\n if (authonService.isLoading) {\n return false;\n }\n\n if (!authonService.isSignedIn) {\n return { path: redirectTo };\n }\n\n return true;\n}\n","import { AuthonService, AUTHON_CONFIG, type AuthonServiceConfig } from './service';\n\n/**\n * Provider factory for Angular standalone components.\n *\n * Usage in app.config.ts:\n * ```ts\n * import { provideAuthon } from '@authon/angular';\n *\n * export const appConfig = {\n * providers: [\n * ...provideAuthon({ publishableKey: 'pk_live_...' }),\n * ],\n * };\n * ```\n *\n * Then inject in your components:\n * ```ts\n * import { Inject } from '@angular/core';\n * import { AUTHON_CONFIG, AuthonService } from '@authon/angular';\n *\n * constructor(@Inject('AuthonService') private authon: AuthonService) {}\n * ```\n */\nexport function provideAuthon(config: AuthonServiceConfig) {\n const service = new AuthonService(config);\n\n return [\n { provide: AUTHON_CONFIG, useValue: config },\n { provide: 'AuthonService', useValue: service },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,gBAAuB;AAQhB,IAAM,gBAAgB;AA2BtB,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EACA,QAA2B;AAAA,EAC3B,cAAc;AAAA,EACd,aAAa;AAAA,EACb,aAAgC,CAAC;AAAA,EAEzC,YAAY,QAA6B;AACvC,SAAK,SAAS,IAAI,iBAAO,OAAO,gBAAgB,OAAO,MAAM;AAE7D,SAAK,OAAO,GAAG,YAAY,CAAC,SAAS;AACnC,WAAK,QAAQ;AACb,WAAK,cAAc;AACnB,WAAK,aAAa;AAClB,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,SAAK,OAAO,GAAG,aAAa,MAAM;AAChC,WAAK,QAAQ;AACb,WAAK,cAAc;AACnB,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,SAAK,OAAO,GAAG,SAAS,MAAM;AAC5B,WAAK,aAAa;AAClB,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,IAAI,OAA0B;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,aAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,aAA4B;AAChC,UAAM,KAAK,OAAO,WAAW;AAAA,EAC/B;AAAA,EAEA,MAAM,aAA4B;AAChC,UAAM,KAAK,OAAO,WAAW;AAAA,EAC/B;AAAA,EAEA,MAAM,UAAyB;AAC7B,UAAM,KAAK,OAAO,QAAQ;AAC1B,SAAK,QAAQ;AACb,SAAK,cAAc;AACnB,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,WAA0B;AACxB,WAAO,KAAK,OAAO,SAAS;AAAA,EAC9B;AAAA,EAEA,YAAoB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,UAAkC;AAC9C,SAAK,WAAW,KAAK,QAAQ;AAC7B,WAAO,MAAM;AACX,WAAK,aAAa,KAAK,WAAW,OAAO,CAAC,MAAM,MAAM,QAAQ;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAQ;AACpB,SAAK,aAAa,CAAC;AAAA,EACrB;AAAA,EAEQ,kBAAwB;AAC9B,eAAW,YAAY,KAAK,YAAY;AACtC,eAAS;AAAA,IACX;AAAA,EACF;AACF;;;ACjGO,SAAS,UACd,eACA,aAAa,YACe;AAC5B,MAAI,cAAc,WAAW;AAC3B,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,cAAc,YAAY;AAC7B,WAAO,EAAE,MAAM,WAAW;AAAA,EAC5B;AAEA,SAAO;AACT;;;ACdO,SAAS,cAAc,QAA6B;AACzD,QAAM,UAAU,IAAI,cAAc,MAAM;AAExC,SAAO;AAAA,IACL,EAAE,SAAS,eAAe,UAAU,OAAO;AAAA,IAC3C,EAAE,SAAS,iBAAiB,UAAU,QAAQ;AAAA,EAChD;AACF;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { AuthonConfig, Authon } from '@authon/js';
|
|
2
|
+
import { AuthonUser } from '@authon/shared';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Injection token key for Authon configuration.
|
|
6
|
+
* Used with Angular's InjectionToken.
|
|
7
|
+
*/
|
|
8
|
+
declare const AUTHON_CONFIG = "AUTHON_CONFIG";
|
|
9
|
+
interface AuthonServiceConfig {
|
|
10
|
+
publishableKey: string;
|
|
11
|
+
config?: Omit<AuthonConfig, 'mode'>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Plain class wrapping @authon/js for Angular dependency injection.
|
|
15
|
+
*
|
|
16
|
+
* Since tsup cannot compile Angular decorators, this is a plain class.
|
|
17
|
+
* Users should wrap it in their own injectable service:
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { Injectable } from '@angular/core';
|
|
21
|
+
* import { AuthonService as BaseAuthonService } from '@authon/angular';
|
|
22
|
+
*
|
|
23
|
+
* @Injectable({ providedIn: 'root' })
|
|
24
|
+
* export class AuthonService extends BaseAuthonService {
|
|
25
|
+
* constructor() {
|
|
26
|
+
* super({ publishableKey: 'pk_live_...' });
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* Or use the `provideAuthon()` helper for standalone components.
|
|
32
|
+
*/
|
|
33
|
+
declare class AuthonService {
|
|
34
|
+
private client;
|
|
35
|
+
private _user;
|
|
36
|
+
private _isSignedIn;
|
|
37
|
+
private _isLoading;
|
|
38
|
+
private _listeners;
|
|
39
|
+
constructor(config: AuthonServiceConfig);
|
|
40
|
+
get user(): AuthonUser | null;
|
|
41
|
+
get isSignedIn(): boolean;
|
|
42
|
+
get isLoading(): boolean;
|
|
43
|
+
openSignIn(): Promise<void>;
|
|
44
|
+
openSignUp(): Promise<void>;
|
|
45
|
+
signOut(): Promise<void>;
|
|
46
|
+
getToken(): string | null;
|
|
47
|
+
getClient(): Authon;
|
|
48
|
+
/**
|
|
49
|
+
* Subscribe to auth state changes.
|
|
50
|
+
* Returns an unsubscribe function.
|
|
51
|
+
*/
|
|
52
|
+
onStateChange(callback: () => void): () => void;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
private notifyListeners;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Route guard factory for Angular Router (CanActivateFn style).
|
|
59
|
+
*
|
|
60
|
+
* Since tsup can't compile Angular decorators, this returns a plain function.
|
|
61
|
+
* Users wire it up in their route config:
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { inject } from '@angular/core';
|
|
65
|
+
* import { authGuard } from '@authon/angular';
|
|
66
|
+
* import { AuthonService } from './authon.service'; // your injectable wrapper
|
|
67
|
+
*
|
|
68
|
+
* const routes = [
|
|
69
|
+
* {
|
|
70
|
+
* path: 'dashboard',
|
|
71
|
+
* component: DashboardComponent,
|
|
72
|
+
* canActivate: [() => {
|
|
73
|
+
* const authon = inject(AuthonService);
|
|
74
|
+
* return authGuard(authon, '/login');
|
|
75
|
+
* }],
|
|
76
|
+
* },
|
|
77
|
+
* ];
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function authGuard(authonService: AuthonService, redirectTo?: string): boolean | {
|
|
81
|
+
path: string;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Provider factory for Angular standalone components.
|
|
86
|
+
*
|
|
87
|
+
* Usage in app.config.ts:
|
|
88
|
+
* ```ts
|
|
89
|
+
* import { provideAuthon } from '@authon/angular';
|
|
90
|
+
*
|
|
91
|
+
* export const appConfig = {
|
|
92
|
+
* providers: [
|
|
93
|
+
* ...provideAuthon({ publishableKey: 'pk_live_...' }),
|
|
94
|
+
* ],
|
|
95
|
+
* };
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* Then inject in your components:
|
|
99
|
+
* ```ts
|
|
100
|
+
* import { Inject } from '@angular/core';
|
|
101
|
+
* import { AUTHON_CONFIG, AuthonService } from '@authon/angular';
|
|
102
|
+
*
|
|
103
|
+
* constructor(@Inject('AuthonService') private authon: AuthonService) {}
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
declare function provideAuthon(config: AuthonServiceConfig): ({
|
|
107
|
+
provide: string;
|
|
108
|
+
useValue: AuthonServiceConfig;
|
|
109
|
+
} | {
|
|
110
|
+
provide: string;
|
|
111
|
+
useValue: AuthonService;
|
|
112
|
+
})[];
|
|
113
|
+
|
|
114
|
+
export { AUTHON_CONFIG, AuthonService, type AuthonServiceConfig, authGuard, provideAuthon };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { AuthonConfig, Authon } from '@authon/js';
|
|
2
|
+
import { AuthonUser } from '@authon/shared';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Injection token key for Authon configuration.
|
|
6
|
+
* Used with Angular's InjectionToken.
|
|
7
|
+
*/
|
|
8
|
+
declare const AUTHON_CONFIG = "AUTHON_CONFIG";
|
|
9
|
+
interface AuthonServiceConfig {
|
|
10
|
+
publishableKey: string;
|
|
11
|
+
config?: Omit<AuthonConfig, 'mode'>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Plain class wrapping @authon/js for Angular dependency injection.
|
|
15
|
+
*
|
|
16
|
+
* Since tsup cannot compile Angular decorators, this is a plain class.
|
|
17
|
+
* Users should wrap it in their own injectable service:
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { Injectable } from '@angular/core';
|
|
21
|
+
* import { AuthonService as BaseAuthonService } from '@authon/angular';
|
|
22
|
+
*
|
|
23
|
+
* @Injectable({ providedIn: 'root' })
|
|
24
|
+
* export class AuthonService extends BaseAuthonService {
|
|
25
|
+
* constructor() {
|
|
26
|
+
* super({ publishableKey: 'pk_live_...' });
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* Or use the `provideAuthon()` helper for standalone components.
|
|
32
|
+
*/
|
|
33
|
+
declare class AuthonService {
|
|
34
|
+
private client;
|
|
35
|
+
private _user;
|
|
36
|
+
private _isSignedIn;
|
|
37
|
+
private _isLoading;
|
|
38
|
+
private _listeners;
|
|
39
|
+
constructor(config: AuthonServiceConfig);
|
|
40
|
+
get user(): AuthonUser | null;
|
|
41
|
+
get isSignedIn(): boolean;
|
|
42
|
+
get isLoading(): boolean;
|
|
43
|
+
openSignIn(): Promise<void>;
|
|
44
|
+
openSignUp(): Promise<void>;
|
|
45
|
+
signOut(): Promise<void>;
|
|
46
|
+
getToken(): string | null;
|
|
47
|
+
getClient(): Authon;
|
|
48
|
+
/**
|
|
49
|
+
* Subscribe to auth state changes.
|
|
50
|
+
* Returns an unsubscribe function.
|
|
51
|
+
*/
|
|
52
|
+
onStateChange(callback: () => void): () => void;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
private notifyListeners;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Route guard factory for Angular Router (CanActivateFn style).
|
|
59
|
+
*
|
|
60
|
+
* Since tsup can't compile Angular decorators, this returns a plain function.
|
|
61
|
+
* Users wire it up in their route config:
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { inject } from '@angular/core';
|
|
65
|
+
* import { authGuard } from '@authon/angular';
|
|
66
|
+
* import { AuthonService } from './authon.service'; // your injectable wrapper
|
|
67
|
+
*
|
|
68
|
+
* const routes = [
|
|
69
|
+
* {
|
|
70
|
+
* path: 'dashboard',
|
|
71
|
+
* component: DashboardComponent,
|
|
72
|
+
* canActivate: [() => {
|
|
73
|
+
* const authon = inject(AuthonService);
|
|
74
|
+
* return authGuard(authon, '/login');
|
|
75
|
+
* }],
|
|
76
|
+
* },
|
|
77
|
+
* ];
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function authGuard(authonService: AuthonService, redirectTo?: string): boolean | {
|
|
81
|
+
path: string;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Provider factory for Angular standalone components.
|
|
86
|
+
*
|
|
87
|
+
* Usage in app.config.ts:
|
|
88
|
+
* ```ts
|
|
89
|
+
* import { provideAuthon } from '@authon/angular';
|
|
90
|
+
*
|
|
91
|
+
* export const appConfig = {
|
|
92
|
+
* providers: [
|
|
93
|
+
* ...provideAuthon({ publishableKey: 'pk_live_...' }),
|
|
94
|
+
* ],
|
|
95
|
+
* };
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* Then inject in your components:
|
|
99
|
+
* ```ts
|
|
100
|
+
* import { Inject } from '@angular/core';
|
|
101
|
+
* import { AUTHON_CONFIG, AuthonService } from '@authon/angular';
|
|
102
|
+
*
|
|
103
|
+
* constructor(@Inject('AuthonService') private authon: AuthonService) {}
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
declare function provideAuthon(config: AuthonServiceConfig): ({
|
|
107
|
+
provide: string;
|
|
108
|
+
useValue: AuthonServiceConfig;
|
|
109
|
+
} | {
|
|
110
|
+
provide: string;
|
|
111
|
+
useValue: AuthonService;
|
|
112
|
+
})[];
|
|
113
|
+
|
|
114
|
+
export { AUTHON_CONFIG, AuthonService, type AuthonServiceConfig, authGuard, provideAuthon };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// src/service.ts
|
|
2
|
+
import { Authon } from "@authon/js";
|
|
3
|
+
var AUTHON_CONFIG = "AUTHON_CONFIG";
|
|
4
|
+
var AuthonService = class {
|
|
5
|
+
client;
|
|
6
|
+
_user = null;
|
|
7
|
+
_isSignedIn = false;
|
|
8
|
+
_isLoading = true;
|
|
9
|
+
_listeners = [];
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.client = new Authon(config.publishableKey, config.config);
|
|
12
|
+
this.client.on("signedIn", (user) => {
|
|
13
|
+
this._user = user;
|
|
14
|
+
this._isSignedIn = true;
|
|
15
|
+
this._isLoading = false;
|
|
16
|
+
this.notifyListeners();
|
|
17
|
+
});
|
|
18
|
+
this.client.on("signedOut", () => {
|
|
19
|
+
this._user = null;
|
|
20
|
+
this._isSignedIn = false;
|
|
21
|
+
this.notifyListeners();
|
|
22
|
+
});
|
|
23
|
+
this.client.on("error", () => {
|
|
24
|
+
this._isLoading = false;
|
|
25
|
+
this.notifyListeners();
|
|
26
|
+
});
|
|
27
|
+
this._isLoading = false;
|
|
28
|
+
}
|
|
29
|
+
get user() {
|
|
30
|
+
return this._user;
|
|
31
|
+
}
|
|
32
|
+
get isSignedIn() {
|
|
33
|
+
return this._isSignedIn;
|
|
34
|
+
}
|
|
35
|
+
get isLoading() {
|
|
36
|
+
return this._isLoading;
|
|
37
|
+
}
|
|
38
|
+
async openSignIn() {
|
|
39
|
+
await this.client.openSignIn();
|
|
40
|
+
}
|
|
41
|
+
async openSignUp() {
|
|
42
|
+
await this.client.openSignUp();
|
|
43
|
+
}
|
|
44
|
+
async signOut() {
|
|
45
|
+
await this.client.signOut();
|
|
46
|
+
this._user = null;
|
|
47
|
+
this._isSignedIn = false;
|
|
48
|
+
this.notifyListeners();
|
|
49
|
+
}
|
|
50
|
+
getToken() {
|
|
51
|
+
return this.client.getToken();
|
|
52
|
+
}
|
|
53
|
+
getClient() {
|
|
54
|
+
return this.client;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Subscribe to auth state changes.
|
|
58
|
+
* Returns an unsubscribe function.
|
|
59
|
+
*/
|
|
60
|
+
onStateChange(callback) {
|
|
61
|
+
this._listeners.push(callback);
|
|
62
|
+
return () => {
|
|
63
|
+
this._listeners = this._listeners.filter((l) => l !== callback);
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
destroy() {
|
|
67
|
+
this.client.destroy();
|
|
68
|
+
this._listeners = [];
|
|
69
|
+
}
|
|
70
|
+
notifyListeners() {
|
|
71
|
+
for (const listener of this._listeners) {
|
|
72
|
+
listener();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/guard.ts
|
|
78
|
+
function authGuard(authonService, redirectTo = "/sign-in") {
|
|
79
|
+
if (authonService.isLoading) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (!authonService.isSignedIn) {
|
|
83
|
+
return { path: redirectTo };
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/helpers.ts
|
|
89
|
+
function provideAuthon(config) {
|
|
90
|
+
const service = new AuthonService(config);
|
|
91
|
+
return [
|
|
92
|
+
{ provide: AUTHON_CONFIG, useValue: config },
|
|
93
|
+
{ provide: "AuthonService", useValue: service }
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
AUTHON_CONFIG,
|
|
98
|
+
AuthonService,
|
|
99
|
+
authGuard,
|
|
100
|
+
provideAuthon
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/service.ts","../src/guard.ts","../src/helpers.ts"],"sourcesContent":["import { Authon } from '@authon/js';\nimport type { AuthonConfig } from '@authon/js';\nimport type { AuthonUser } from '@authon/shared';\n\n/**\n * Injection token key for Authon configuration.\n * Used with Angular's InjectionToken.\n */\nexport const AUTHON_CONFIG = 'AUTHON_CONFIG';\n\nexport interface AuthonServiceConfig {\n publishableKey: string;\n config?: Omit<AuthonConfig, 'mode'>;\n}\n\n/**\n * Plain class wrapping @authon/js for Angular dependency injection.\n *\n * Since tsup cannot compile Angular decorators, this is a plain class.\n * Users should wrap it in their own injectable service:\n *\n * ```ts\n * import { Injectable } from '@angular/core';\n * import { AuthonService as BaseAuthonService } from '@authon/angular';\n *\n * @Injectable({ providedIn: 'root' })\n * export class AuthonService extends BaseAuthonService {\n * constructor() {\n * super({ publishableKey: 'pk_live_...' });\n * }\n * }\n * ```\n *\n * Or use the `provideAuthon()` helper for standalone components.\n */\nexport class AuthonService {\n private client: Authon;\n private _user: AuthonUser | null = null;\n private _isSignedIn = false;\n private _isLoading = true;\n private _listeners: Array<() => void> = [];\n\n constructor(config: AuthonServiceConfig) {\n this.client = new Authon(config.publishableKey, config.config);\n\n this.client.on('signedIn', (user) => {\n this._user = user as AuthonUser;\n this._isSignedIn = true;\n this._isLoading = false;\n this.notifyListeners();\n });\n\n this.client.on('signedOut', () => {\n this._user = null;\n this._isSignedIn = false;\n this.notifyListeners();\n });\n\n this.client.on('error', () => {\n this._isLoading = false;\n this.notifyListeners();\n });\n\n this._isLoading = false;\n }\n\n get user(): AuthonUser | null {\n return this._user;\n }\n\n get isSignedIn(): boolean {\n return this._isSignedIn;\n }\n\n get isLoading(): boolean {\n return this._isLoading;\n }\n\n async openSignIn(): Promise<void> {\n await this.client.openSignIn();\n }\n\n async openSignUp(): Promise<void> {\n await this.client.openSignUp();\n }\n\n async signOut(): Promise<void> {\n await this.client.signOut();\n this._user = null;\n this._isSignedIn = false;\n this.notifyListeners();\n }\n\n getToken(): string | null {\n return this.client.getToken();\n }\n\n getClient(): Authon {\n return this.client;\n }\n\n /**\n * Subscribe to auth state changes.\n * Returns an unsubscribe function.\n */\n onStateChange(callback: () => void): () => void {\n this._listeners.push(callback);\n return () => {\n this._listeners = this._listeners.filter((l) => l !== callback);\n };\n }\n\n destroy(): void {\n this.client.destroy();\n this._listeners = [];\n }\n\n private notifyListeners(): void {\n for (const listener of this._listeners) {\n listener();\n }\n }\n}\n","import type { AuthonService } from './service';\n\n/**\n * Route guard factory for Angular Router (CanActivateFn style).\n *\n * Since tsup can't compile Angular decorators, this returns a plain function.\n * Users wire it up in their route config:\n *\n * ```ts\n * import { inject } from '@angular/core';\n * import { authGuard } from '@authon/angular';\n * import { AuthonService } from './authon.service'; // your injectable wrapper\n *\n * const routes = [\n * {\n * path: 'dashboard',\n * component: DashboardComponent,\n * canActivate: [() => {\n * const authon = inject(AuthonService);\n * return authGuard(authon, '/login');\n * }],\n * },\n * ];\n * ```\n */\nexport function authGuard(\n authonService: AuthonService,\n redirectTo = '/sign-in',\n): boolean | { path: string } {\n if (authonService.isLoading) {\n return false;\n }\n\n if (!authonService.isSignedIn) {\n return { path: redirectTo };\n }\n\n return true;\n}\n","import { AuthonService, AUTHON_CONFIG, type AuthonServiceConfig } from './service';\n\n/**\n * Provider factory for Angular standalone components.\n *\n * Usage in app.config.ts:\n * ```ts\n * import { provideAuthon } from '@authon/angular';\n *\n * export const appConfig = {\n * providers: [\n * ...provideAuthon({ publishableKey: 'pk_live_...' }),\n * ],\n * };\n * ```\n *\n * Then inject in your components:\n * ```ts\n * import { Inject } from '@angular/core';\n * import { AUTHON_CONFIG, AuthonService } from '@authon/angular';\n *\n * constructor(@Inject('AuthonService') private authon: AuthonService) {}\n * ```\n */\nexport function provideAuthon(config: AuthonServiceConfig) {\n const service = new AuthonService(config);\n\n return [\n { provide: AUTHON_CONFIG, useValue: config },\n { provide: 'AuthonService', useValue: service },\n ];\n}\n"],"mappings":";AAAA,SAAS,cAAc;AAQhB,IAAM,gBAAgB;AA2BtB,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EACA,QAA2B;AAAA,EAC3B,cAAc;AAAA,EACd,aAAa;AAAA,EACb,aAAgC,CAAC;AAAA,EAEzC,YAAY,QAA6B;AACvC,SAAK,SAAS,IAAI,OAAO,OAAO,gBAAgB,OAAO,MAAM;AAE7D,SAAK,OAAO,GAAG,YAAY,CAAC,SAAS;AACnC,WAAK,QAAQ;AACb,WAAK,cAAc;AACnB,WAAK,aAAa;AAClB,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,SAAK,OAAO,GAAG,aAAa,MAAM;AAChC,WAAK,QAAQ;AACb,WAAK,cAAc;AACnB,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,SAAK,OAAO,GAAG,SAAS,MAAM;AAC5B,WAAK,aAAa;AAClB,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,IAAI,OAA0B;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,aAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,aAA4B;AAChC,UAAM,KAAK,OAAO,WAAW;AAAA,EAC/B;AAAA,EAEA,MAAM,aAA4B;AAChC,UAAM,KAAK,OAAO,WAAW;AAAA,EAC/B;AAAA,EAEA,MAAM,UAAyB;AAC7B,UAAM,KAAK,OAAO,QAAQ;AAC1B,SAAK,QAAQ;AACb,SAAK,cAAc;AACnB,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,WAA0B;AACxB,WAAO,KAAK,OAAO,SAAS;AAAA,EAC9B;AAAA,EAEA,YAAoB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,UAAkC;AAC9C,SAAK,WAAW,KAAK,QAAQ;AAC7B,WAAO,MAAM;AACX,WAAK,aAAa,KAAK,WAAW,OAAO,CAAC,MAAM,MAAM,QAAQ;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAQ;AACpB,SAAK,aAAa,CAAC;AAAA,EACrB;AAAA,EAEQ,kBAAwB;AAC9B,eAAW,YAAY,KAAK,YAAY;AACtC,eAAS;AAAA,IACX;AAAA,EACF;AACF;;;ACjGO,SAAS,UACd,eACA,aAAa,YACe;AAC5B,MAAI,cAAc,WAAW;AAC3B,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,cAAc,YAAY;AAC7B,WAAO,EAAE,MAAM,WAAW;AAAA,EAC5B;AAEA,SAAO;AACT;;;ACdO,SAAS,cAAc,QAA6B;AACzD,QAAM,UAAU,IAAI,cAAc,MAAM;AAExC,SAAO;AAAA,IACL,EAAE,SAAS,eAAe,UAAU,OAAO;AAAA,IAC3C,EAAE,SAAS,iBAAiB,UAAU,QAAQ;AAAA,EAChD;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@authon/angular",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Authon Angular SDK — service, guard, and components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist"],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"dev": "tsup --watch"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/mikusnuz/authon-sdk.git",
|
|
25
|
+
"directory": "packages/angular"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/mikusnuz/authon-sdk/tree/main/packages/angular",
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"keywords": ["authon", "angular", "auth", "guard"],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@authon/js": "workspace:*",
|
|
34
|
+
"@authon/shared": "workspace:*"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"@angular/core": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"tsup": "^8.0.0",
|
|
41
|
+
"typescript": "^5.9.3"
|
|
42
|
+
}
|
|
43
|
+
}
|