@anarchitects/auth-angular 0.4.0 → 0.5.1
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 +88 -10
- package/data-access/README.md +10 -0
- package/feature/README.md +32 -3
- package/fesm2022/anarchitects-auth-angular-data-access.mjs +84 -65
- package/fesm2022/anarchitects-auth-angular-data-access.mjs.map +1 -1
- package/fesm2022/anarchitects-auth-angular-feature.mjs +61 -6
- package/fesm2022/anarchitects-auth-angular-feature.mjs.map +1 -1
- package/fesm2022/anarchitects-auth-angular-state.mjs +194 -47
- package/fesm2022/anarchitects-auth-angular-state.mjs.map +1 -1
- package/fesm2022/anarchitects-auth-angular-ui.mjs +338 -262
- package/fesm2022/anarchitects-auth-angular-ui.mjs.map +1 -1
- package/fesm2022/anarchitects-auth-angular-util.mjs +36 -3
- package/fesm2022/anarchitects-auth-angular-util.mjs.map +1 -1
- package/package.json +7 -7
- package/state/README.md +36 -1
- package/types/anarchitects-auth-angular-data-access.d.ts +19 -3
- package/types/anarchitects-auth-angular-feature.d.ts +4 -2
- package/types/anarchitects-auth-angular-state.d.ts +25 -8
- package/types/anarchitects-auth-angular-ui.d.ts +11 -11
- package/types/anarchitects-auth-angular-util.d.ts +11 -13
- package/util/README.md +28 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import * as _anarchitects_forms_ts_models from '@anarchitects/forms-ts/models';
|
|
1
2
|
import * as _angular_core from '@angular/core';
|
|
2
3
|
import { SubmissionRequestDTO } from '@anarchitects/forms-ts/dtos';
|
|
3
|
-
import { FormConfig } from '@anarchitects/forms-ts/models';
|
|
4
4
|
|
|
5
5
|
declare class AnarchitectsAuthUiLoginForm {
|
|
6
6
|
readonly layout: _angular_core.InputSignal<`form:${string}` | `list:${string}` | `detail:${string}` | `app-${string}:${string}` | null>;
|
|
@@ -9,7 +9,7 @@ declare class AnarchitectsAuthUiLoginForm {
|
|
|
9
9
|
credential: string;
|
|
10
10
|
password: string;
|
|
11
11
|
}>;
|
|
12
|
-
readonly formConfig: _angular_core.
|
|
12
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
13
13
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
14
14
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiLoginForm, never>;
|
|
15
15
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiLoginForm, "anarchitects-auth-ui-login-form", never, { "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -24,7 +24,7 @@ declare class AnarchitectsAuthUiRegisterForm {
|
|
|
24
24
|
email: string;
|
|
25
25
|
confirmPassword: string;
|
|
26
26
|
}>;
|
|
27
|
-
readonly formConfig: _angular_core.
|
|
27
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
28
28
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
29
29
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiRegisterForm, never>;
|
|
30
30
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiRegisterForm, "anarchitects-auth-ui-register-form", never, { "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -37,7 +37,7 @@ declare class AnarchitectsAuthUiActivateUserForm {
|
|
|
37
37
|
readonly submitted: _angular_core.OutputEmitterRef<{
|
|
38
38
|
token: string;
|
|
39
39
|
}>;
|
|
40
|
-
readonly formConfig: _angular_core.Signal<FormConfig>;
|
|
40
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
41
41
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
42
42
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiActivateUserForm, never>;
|
|
43
43
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiActivateUserForm, "anarchitects-auth-ui-activate-user-form", never, { "token": { "alias": "token"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -49,7 +49,7 @@ declare class AnarchitectsAuthUiForgotPasswordForm {
|
|
|
49
49
|
readonly submitted: _angular_core.OutputEmitterRef<{
|
|
50
50
|
email: string;
|
|
51
51
|
}>;
|
|
52
|
-
readonly formConfig: _angular_core.
|
|
52
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
53
53
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
54
54
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiForgotPasswordForm, never>;
|
|
55
55
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiForgotPasswordForm, "anarchitects-auth-ui-forgot-password-form", never, { "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -64,7 +64,7 @@ declare class AnarchitectsAuthUiResetPasswordForm {
|
|
|
64
64
|
confirmPassword: string;
|
|
65
65
|
token: string;
|
|
66
66
|
}>;
|
|
67
|
-
readonly formConfig: _angular_core.Signal<FormConfig>;
|
|
67
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
68
68
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
69
69
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiResetPasswordForm, never>;
|
|
70
70
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiResetPasswordForm, "anarchitects-auth-ui-reset-password-form", never, { "token": { "alias": "token"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -77,7 +77,7 @@ declare class AnarchitectsAuthUiVerifyEmailForm {
|
|
|
77
77
|
readonly submitted: _angular_core.OutputEmitterRef<{
|
|
78
78
|
token: string;
|
|
79
79
|
}>;
|
|
80
|
-
readonly formConfig: _angular_core.Signal<FormConfig>;
|
|
80
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
81
81
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
82
82
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiVerifyEmailForm, never>;
|
|
83
83
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiVerifyEmailForm, "anarchitects-auth-ui-verify-email-form", never, { "token": { "alias": "token"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -91,7 +91,7 @@ declare class AnarchitectsAuthUiChangePasswordForm {
|
|
|
91
91
|
currentPassword: string;
|
|
92
92
|
newPassword: string;
|
|
93
93
|
}>;
|
|
94
|
-
readonly formConfig: _angular_core.
|
|
94
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
95
95
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
96
96
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiChangePasswordForm, never>;
|
|
97
97
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiChangePasswordForm, "anarchitects-auth-ui-change-password-form", never, { "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -104,7 +104,7 @@ declare class AnarchitectsAuthUiUpdateEmailForm {
|
|
|
104
104
|
password?: string | undefined;
|
|
105
105
|
newEmail: string;
|
|
106
106
|
}>;
|
|
107
|
-
readonly formConfig: _angular_core.
|
|
107
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
108
108
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
109
109
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiUpdateEmailForm, never>;
|
|
110
110
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiUpdateEmailForm, "anarchitects-auth-ui-update-email-form", never, { "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -117,7 +117,7 @@ declare class AnarchitectsAuthUiLogoutForm {
|
|
|
117
117
|
accessToken?: string | undefined;
|
|
118
118
|
refreshToken: string;
|
|
119
119
|
}>;
|
|
120
|
-
readonly formConfig: _angular_core.
|
|
120
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
121
121
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
122
122
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiLogoutForm, never>;
|
|
123
123
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiLogoutForm, "anarchitects-auth-ui-logout-form", never, { "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -129,7 +129,7 @@ declare class AnarchitectsAuthUiRefreshTokensForm {
|
|
|
129
129
|
readonly submitted: _angular_core.OutputEmitterRef<{
|
|
130
130
|
refreshToken: string;
|
|
131
131
|
}>;
|
|
132
|
-
readonly formConfig: _angular_core.
|
|
132
|
+
readonly formConfig: _angular_core.Signal<_anarchitects_forms_ts_models.FormConfig>;
|
|
133
133
|
onSubmitted(input: SubmissionRequestDTO): void;
|
|
134
134
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AnarchitectsAuthUiRefreshTokensForm, never>;
|
|
135
135
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AnarchitectsAuthUiRefreshTokensForm, "anarchitects-auth-ui-refresh-tokens-form", never, { "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "layoutOptions": { "alias": "layoutOptions"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["ng-template[anxTemplate]", "[anxSlot]"], true, never>;
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import * as _casl_ability from '@casl/ability';
|
|
2
|
-
import { MongoAbility } from '@casl/ability';
|
|
3
1
|
import { Action, Subject, PolicyRule } from '@anarchitects/auth-ts/models';
|
|
2
|
+
import { MongoAbility } from '@casl/ability';
|
|
4
3
|
|
|
5
|
-
type AbilitySubject = Subject |
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
declare const createAppAbility: (rules: PolicyRule[]) => MongoAbility<_casl_ability.AbilityTuple, Record<string, unknown>>;
|
|
4
|
+
type AbilitySubject = Subject | object;
|
|
5
|
+
type AbilityResource = Record<string, unknown>;
|
|
6
|
+
type AppAbility = MongoAbility<[Action, AbilitySubject]>;
|
|
7
|
+
declare const createAppAbility: (rules: PolicyRule[]) => AppAbility;
|
|
8
|
+
declare const asAppAbilitySubject: <TResource extends AbilityResource>(subjectName: Subject, resource: TResource) => TResource & {
|
|
9
|
+
__caslSubjectType__: Subject;
|
|
10
|
+
};
|
|
11
|
+
declare const canAccessResource: <TResource extends AbilityResource>(ability: AppAbility | undefined, action: Action, subjectName: Subject, resource: TResource) => boolean;
|
|
12
|
+
declare const canAccessResourceField: <TResource extends AbilityResource>(ability: AppAbility | undefined, action: Action, subjectName: Subject, field: string, resource: TResource) => boolean;
|
|
15
13
|
|
|
16
|
-
export { createAppAbility };
|
|
14
|
+
export { asAppAbilitySubject, canAccessResource, canAccessResourceField, createAppAbility };
|
|
17
15
|
export type { AppAbility };
|
package/util/README.md
CHANGED
|
@@ -5,12 +5,28 @@ Utility layer for Angular auth. Re-exported via `@anarchitects/auth-angular/util
|
|
|
5
5
|
## Exports
|
|
6
6
|
|
|
7
7
|
- `createAppAbility(rules: PolicyRule[])`: wraps `createMongoAbility` and returns the typed `AppAbility` used throughout the auth domain.
|
|
8
|
+
- `canAccessResource(...)`: checks a concrete resource instance against the current ability.
|
|
9
|
+
- `canAccessResourceField(...)`: checks whether a specific field-level action is allowed for a concrete resource.
|
|
8
10
|
- `AppAbility`: CASL ability type configured for `Action`/`Subject` pairs defined in `@anarchitects/auth-ts/models`.
|
|
9
11
|
|
|
12
|
+
## When To Use These Helpers
|
|
13
|
+
|
|
14
|
+
Use this layer for concrete resource decisions, not coarse route metadata:
|
|
15
|
+
|
|
16
|
+
- `createAppAbility(rules)` builds the frontend CASL ability from validated RBAC rules
|
|
17
|
+
- `canAccessResource(...)` answers instance-level questions such as "may this user edit this post?"
|
|
18
|
+
- `canAccessResourceField(...)` answers field-sensitive UI questions such as inline title editing
|
|
19
|
+
|
|
20
|
+
If you only need coarse route-attempt semantics, use `policyGuard` and `RoutePolicy` instead of calling CASL directly here.
|
|
21
|
+
|
|
10
22
|
## Usage
|
|
11
23
|
|
|
12
24
|
```ts
|
|
13
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
canAccessResource,
|
|
27
|
+
canAccessResourceField,
|
|
28
|
+
createAppAbility,
|
|
29
|
+
} from '@anarchitects/auth-angular/util';
|
|
14
30
|
import type { PolicyRule } from '@anarchitects/auth-ts/models';
|
|
15
31
|
|
|
16
32
|
const rules: PolicyRule[] = [
|
|
@@ -23,6 +39,16 @@ const ability = createAppAbility(rules);
|
|
|
23
39
|
if (ability.can('manage', 'Project')) {
|
|
24
40
|
// guarded feature logic
|
|
25
41
|
}
|
|
42
|
+
|
|
43
|
+
const post = { id: 'post-1', authorId: 'user-1', title: 'Draft' };
|
|
44
|
+
|
|
45
|
+
if (canAccessResource(ability, 'update', 'Post', post)) {
|
|
46
|
+
// show edit button
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (canAccessResourceField(ability, 'update', 'Post', 'title', post)) {
|
|
50
|
+
// allow inline title editing
|
|
51
|
+
}
|
|
26
52
|
```
|
|
27
53
|
|
|
28
|
-
|
|
54
|
+
Use these helpers for frontend instance-level decisions such as edit buttons, row actions, and resolved edit routes. Coarse route gating still belongs to `policyGuard`, and the backend must still enforce the final instance-level decision.
|