@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.
@@ -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.WritableSignal<FormConfig>;
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.WritableSignal<FormConfig>;
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.WritableSignal<FormConfig>;
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.WritableSignal<FormConfig>;
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.WritableSignal<FormConfig>;
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.WritableSignal<FormConfig>;
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.WritableSignal<FormConfig>;
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 | (Record<string, unknown> & {
6
- __caslSubjectType__?: Subject;
7
- });
8
- type AppAbility = MongoAbility<[
9
- Action,
10
- AbilitySubject
11
- ], {
12
- conditions: Record<string, unknown>;
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 { createAppAbility } from '@anarchitects/auth-angular/util';
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
- For stateful orchestration examples, see `auth.store` in the state layer where the ability factory is integrated with the auth API responses.
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.