@appxdigital/appx-core 0.1.121-beta.13 → 0.1.121-beta.15

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/PRERELEASES.md CHANGED
@@ -31,6 +31,33 @@ Prereleases are excluded from normal semver range resolution, so a project on
31
31
 
32
32
  ---
33
33
 
34
+ ## [0.1.121-beta.15] — unreleased
35
+
36
+ **Library / docs. Additive — no behaviour change.** Auth is now extensible from
37
+ the package root instead of deep `dist/` imports.
38
+
39
+ - **Exported the auth building blocks** from `@appxdigital/appx-core`:
40
+ `AuthController`, `AuthService`, `RegisterDto`, `UserDto`, `AuthField`,
41
+ `LocalStrategy`, `JwtStrategy`, `RefreshTokenStrategy`, `LocalAuthGuard`,
42
+ `RefreshTokenGuard`, `SessionSerializer`, `SessionAuthGuard`. Stop importing
43
+ these from `@appxdigital/appx-core/dist/...` — deep paths are internal.
44
+ - **`AuthModule.forRoot({ controller?: boolean })`** — importing
45
+ `AuthModule.forRoot({ controller: false })` registers every auth provider
46
+ globally but **not** the built-in `AuthController`, so you can register your own
47
+ controller (e.g. `extends AuthController`) at the same `/auth` prefix with no
48
+ duplicate route. Importing the plain `AuthModule` is unchanged (still registers
49
+ the controller).
50
+ - **New doc `docs/authentication.md`** — the built-in `/auth` surface and how to
51
+ override framework internals (widen `RegisterDto` to accept e.g. `name`, extend
52
+ `AuthService`, swap a Passport strategy), wired at the same prefix in `AppModule`.
53
+
54
+ ## [0.1.121-beta.14] — unreleased
55
+
56
+ **Library / types.** `RolePermissions.relations` is now usable in a properly
57
+ typed `PermissionsConfigType` (no `as any`) — the catch-all index signature no
58
+ longer collides with the `relations` key. Guarded by a type-contract test. The
59
+ boot validator now takes `PermissionsConfigType` directly. No runtime change.
60
+
34
61
  ## [0.1.121-beta.13] — unreleased
35
62
 
36
63
  **Library.** **Relation-scoped `connect` rules.** A `connect` rule can now be
@@ -70,7 +70,7 @@ export type RolePermissions<M extends ModelKey<RuntimeClient> = ModelKey<Runtime
70
70
  } & {
71
71
  relations?: RelationConnectMap;
72
72
  } & {
73
- [custom: string]: 'ALL' | {
73
+ [custom: string]: 'ALL' | RelationConnectMap | {
74
74
  conditions?: unknown | unknown[];
75
75
  setUserIdField?: string;
76
76
  };
@@ -1 +1 @@
1
- {"version":3,"file":"permissionsConfigTypes.d.ts","sourceRoot":"","sources":["../../../src/common/config/permissionsConfigTypes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,MAAM,EAAE,YAAY,IAAI,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAC,SAAS,EAAC,MAAM,gCAAgC,CAAC;AAEzD,eAAO,MAAM,qBAAqB,EAAE;IAChC,OAAO,EAAE,GAAG,CAAC;CAGhB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIlD,CAAC;AAEF,gEAAgE;AAChE,KAAK,aAAa,CAAC,CAAC,IAAI;KACnB,CAAC,IAAI,MAAM,CAAC,GACb,CAAC,CAAC,CAAC,CAAC,SAAS;QAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;KAAC,GAAG,CAAC,GAAG,KAAK;CAC/D,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC;AAEpB,mDAAmD;AACnD,KAAK,iBAAiB,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC;AAE7C,8DAA8D;AAC9D,KAAK,QAAQ,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa,IACjD,iBAAiB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;AAE5D,4EAA4E;AAC5E,KAAK,cAAc,CACf,CAAC,SAAS,aAAa,EACvB,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,IAErB,CAAC,SAAS,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,GAC5B,CAAC,SAAS,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAC/E,KAAK,CAAC;AAEpB,oDAAoD;AACpD,KAAK,WAAW,CACZ,CAAC,SAAS,aAAa,EACvB,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,IACrB,CAAC,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAE5B,0CAA0C;AAC1C,KAAK,UAAU,CACX,CAAC,SAAS,aAAa,EACvB,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,IACrB;KACC,CAAC,IAAI,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK;CACnE,CAAC,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;AAEpC,iEAAiE;AACjE,KAAK,aAAa,CACd,CAAC,SAAS,aAAa,EACvB,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,IACrB,OAAO,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAEzC,oFAAoF;AACpF,KAAK,MAAM,CACP,CAAC,SAAS,aAAa,EACvB,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,EACrB,CAAC,SAAS,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,IAC7B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEtC,4DAA4D;AAC5D,KAAK,OAAO,CACR,CAAC,SAAS,aAAa,EACvB,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,EACrB,CAAC,SAAS,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,IAE7B,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,SAAS;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAA;CAAC,GAAG,CAAC,GACzC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,SAAS;IAAC,KAAK,EAAE,MAAM,CAAC,CAAA;CAAC,GAAG,CAAC,GACxC,KAAK,CAAC;AAElB,0DAA0D;AAC1D,KAAK,gBAAgB,CACjB,CAAC,SAAS,aAAa,EACvB,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,IACrB;KACC,CAAC,IAAI,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,GAAG,CAAC;CAC7C,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;AAEhC,6DAA6D;AAE7D,MAAM,MAAM,eAAe,CACvB,CAAC,SAAS,QAAQ,CAAC,aAAa,CAAC,EACjC,CAAC,SAAS,gBAAgB,CAAC,aAAa,EAAE,CAAC,CAAC,IAC5C,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAEjC,MAAM,WAAW,gBAAgB,CAC7B,CAAC,SAAS,QAAQ,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,EAC3D,CAAC,SAAS,gBAAgB,CAAC,aAAa,EAAE,CAAC,CAAC,GAAG,gBAAgB,CAAC,aAAa,EAAE,CAAC,CAAC;IAEjF,UAAU,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,KAAK,GAAG;QAAE,UAAU,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAA;KAAE,CAAC;CACzD;AACD,MAAM,MAAM,kBAAkB,GAAG;IAAE,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB,CAAA;CAAE,CAAC;AAElF,MAAM,MAAM,eAAe,CACvB,CAAC,SAAS,QAAQ,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,IAE3D;KACK,CAAC,IAAI,gBAAgB,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC;CAC7E,GAAG;IACA,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAClC,GAAG;IACJ,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG;QACtB,UAAU,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;QACjC,cAAc,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACL,CAAC;AAEF,MAAM,MAAM,gBAAgB,CACxB,CAAC,SAAS,QAAQ,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,IAC3D;IACA,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAC7B,CAAC,SAAS,QAAQ,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,IAC3D;KACC,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC;CACzC,CAAC"}
1
+ {"version":3,"file":"permissionsConfigTypes.d.ts","sourceRoot":"","sources":["../../../src/common/config/permissionsConfigTypes.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -6,6 +6,18 @@ export * from './graphql/graphql.module';
6
6
  export * from './graphql/generic.resolver';
7
7
  export * from './tasks/session-cleanup.service';
8
8
  export * from './modules/auth/auth.module';
9
+ export * from './modules/auth/auth.controller';
10
+ export * from './modules/auth/auth.service';
11
+ export * from './modules/auth/dto/register.dto';
12
+ export * from './modules/auth/dto/user.dto';
13
+ export * from './modules/auth/auth-field.decorator';
14
+ export * from './modules/auth/local.strategy';
15
+ export * from './modules/auth/local-auth.guard';
16
+ export * from './modules/auth/jwt.strategy';
17
+ export * from './modules/auth/refresh-token.strategy';
18
+ export * from './modules/auth/refresh-token.guard';
19
+ export * from './modules/auth/session/session-serializer';
20
+ export * from './modules/auth/session/session-auth.guard';
9
21
  export * from './modules/auth/session/session-store';
10
22
  export * from './common/guards/rbac.guard';
11
23
  export * from './common/guards/user-population.guard';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sCAAsC,CAAC;AACrD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uCAAuC,CAAC;AACtD,cAAc,yBAAyB,CAAC;AACxC,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,iCAAiC,CAAC;AAChD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,oBAAoB,CAAC;AACnC,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,wCAAwC,CAAC;AACvD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAI3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AACnD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,sCAAsC,CAAC;AACrD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uCAAuC,CAAC;AACtD,cAAc,yBAAyB,CAAC;AACxC,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,iCAAiC,CAAC;AAChD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,oBAAoB,CAAC;AACnC,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,wCAAwC,CAAC;AACvD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC"}
package/dist/index.js CHANGED
@@ -22,6 +22,21 @@ __exportStar(require("./graphql/graphql.module"), exports);
22
22
  __exportStar(require("./graphql/generic.resolver"), exports);
23
23
  __exportStar(require("./tasks/session-cleanup.service"), exports);
24
24
  __exportStar(require("./modules/auth/auth.module"), exports);
25
+ // Auth building blocks — exported so consumers can extend/override them
26
+ // (custom AuthController, widened RegisterDto, custom Passport strategy) without
27
+ // deep-importing from `dist/`. See docs/authentication.md.
28
+ __exportStar(require("./modules/auth/auth.controller"), exports);
29
+ __exportStar(require("./modules/auth/auth.service"), exports);
30
+ __exportStar(require("./modules/auth/dto/register.dto"), exports);
31
+ __exportStar(require("./modules/auth/dto/user.dto"), exports);
32
+ __exportStar(require("./modules/auth/auth-field.decorator"), exports);
33
+ __exportStar(require("./modules/auth/local.strategy"), exports);
34
+ __exportStar(require("./modules/auth/local-auth.guard"), exports);
35
+ __exportStar(require("./modules/auth/jwt.strategy"), exports);
36
+ __exportStar(require("./modules/auth/refresh-token.strategy"), exports);
37
+ __exportStar(require("./modules/auth/refresh-token.guard"), exports);
38
+ __exportStar(require("./modules/auth/session/session-serializer"), exports);
39
+ __exportStar(require("./modules/auth/session/session-auth.guard"), exports);
25
40
  __exportStar(require("./modules/auth/session/session-store"), exports);
26
41
  __exportStar(require("./common/guards/rbac.guard"), exports);
27
42
  __exportStar(require("./common/guards/user-population.guard"), exports);
@@ -1,3 +1,14 @@
1
+ import { DynamicModule } from '@nestjs/common';
1
2
  export declare class AuthModule {
3
+ /**
4
+ * For overriding the auth endpoints. `AuthModule.forRoot({ controller: false })`
5
+ * imports every auth provider globally (AuthService, Jwt, Passport, strategies,
6
+ * guards) but does NOT register the built-in `AuthController` — so you can
7
+ * register your OWN controller (e.g. one that `extends AuthController`) at the
8
+ * same `/auth` prefix with no duplicate route. See docs/authentication.md.
9
+ */
10
+ static forRoot(options?: {
11
+ controller?: boolean;
12
+ }): DynamicModule;
2
13
  }
3
14
  //# sourceMappingURL=auth.module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.module.ts"],"names":[],"mappings":"AAcA,qBAea,UAAU;CACtB"}
1
+ {"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAiB,MAAM,gBAAgB,CAAC;AAgC7D,qBAOa,UAAU;IACnB;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAC,GAAG,aAAa;CAUlE"}
@@ -5,6 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
6
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
7
  };
8
+ var AuthModule_1;
8
9
  Object.defineProperty(exports, "__esModule", { value: true });
9
10
  exports.AuthModule = void 0;
10
11
  const common_1 = require("@nestjs/common");
@@ -20,22 +21,48 @@ const jwt_auth_guard_1 = require("./jwt-auth.guard");
20
21
  const authenticated_guard_1 = require("./authenticated.guard");
21
22
  const jwt_strategy_1 = require("./jwt.strategy");
22
23
  const refresh_token_strategy_1 = require("./refresh-token.strategy");
23
- let AuthModule = exports.AuthModule = class AuthModule {
24
+ // Shared so the static @Module (default: registers AuthController) and the
25
+ // forRoot() hook (optionally skips it) provide identical wiring.
26
+ const authImports = [
27
+ config_1.ConfigModule,
28
+ user_module_1.UserModule,
29
+ passport_1.PassportModule.register({ session: true }),
30
+ jwt_1.JwtModule.registerAsync({
31
+ imports: [config_1.ConfigModule],
32
+ useFactory: async (config) => ({
33
+ secret: config.get('JWT_SECRET'),
34
+ signOptions: { expiresIn: config.get('JWT_EXPIRES_IN', '60m') },
35
+ }),
36
+ inject: [config_1.ConfigService],
37
+ }),
38
+ ];
39
+ const authProviders = [auth_service_1.AuthService, local_strategy_1.LocalStrategy, session_serializer_1.SessionSerializer, jwt_strategy_1.JwtStrategy, jwt_auth_guard_1.JwtAuthGuard, authenticated_guard_1.AuthenticatedGuard, refresh_token_strategy_1.RefreshTokenStrategy];
40
+ const authExports = [auth_service_1.AuthService, jwt_auth_guard_1.JwtAuthGuard, authenticated_guard_1.AuthenticatedGuard, jwt_1.JwtModule];
41
+ let AuthModule = exports.AuthModule = AuthModule_1 = class AuthModule {
42
+ /**
43
+ * For overriding the auth endpoints. `AuthModule.forRoot({ controller: false })`
44
+ * imports every auth provider globally (AuthService, Jwt, Passport, strategies,
45
+ * guards) but does NOT register the built-in `AuthController` — so you can
46
+ * register your OWN controller (e.g. one that `extends AuthController`) at the
47
+ * same `/auth` prefix with no duplicate route. See docs/authentication.md.
48
+ */
49
+ static forRoot(options) {
50
+ return {
51
+ module: AuthModule_1,
52
+ global: true,
53
+ imports: authImports,
54
+ providers: authProviders,
55
+ controllers: options?.controller === false ? [] : [auth_controller_1.AuthController],
56
+ exports: authExports,
57
+ };
58
+ }
24
59
  };
25
- exports.AuthModule = AuthModule = __decorate([
60
+ exports.AuthModule = AuthModule = AuthModule_1 = __decorate([
26
61
  (0, common_1.Global)(),
27
62
  (0, common_1.Module)({
28
- imports: [config_1.ConfigModule, user_module_1.UserModule, passport_1.PassportModule.register({ session: true }),
29
- jwt_1.JwtModule.registerAsync({
30
- imports: [config_1.ConfigModule],
31
- useFactory: async (config) => ({
32
- secret: config.get('JWT_SECRET'),
33
- signOptions: { expiresIn: config.get('JWT_EXPIRES_IN', '60m') },
34
- }),
35
- inject: [config_1.ConfigService],
36
- }),],
37
- providers: [auth_service_1.AuthService, local_strategy_1.LocalStrategy, session_serializer_1.SessionSerializer, jwt_strategy_1.JwtStrategy, jwt_auth_guard_1.JwtAuthGuard, authenticated_guard_1.AuthenticatedGuard, refresh_token_strategy_1.RefreshTokenStrategy],
63
+ imports: authImports,
64
+ providers: authProviders,
38
65
  controllers: [auth_controller_1.AuthController],
39
- exports: [auth_service_1.AuthService, jwt_auth_guard_1.JwtAuthGuard, authenticated_guard_1.AuthenticatedGuard, jwt_1.JwtModule],
66
+ exports: authExports,
40
67
  })
41
68
  ], AuthModule);
@@ -9,6 +9,7 @@
9
9
  *
10
10
  * Pure and schema-only (no database), so it is independently unit-testable.
11
11
  */
12
+ import type { PermissionsConfigType } from '../common/config/permissionsConfigTypes';
12
13
  export type RelationKind = 'belongsTo' | 'hasMany';
13
14
  export interface RelationMeta {
14
15
  /** The relation navigation field name on the owning model. */
@@ -46,5 +47,5 @@ export interface ValidationIssue {
46
47
  * - **warning** `missing-connect-optional` — an *optional* belongsTo FK's target
47
48
  * has no `connect` rule for the role. Only denied when the payload sets it.
48
49
  */
49
- export declare function validatePermissionsConfig(config: Record<string, Record<string, any>>, relations: SchemaRelations): ValidationIssue[];
50
+ export declare function validatePermissionsConfig(config: PermissionsConfigType, relations: SchemaRelations): ValidationIssue[];
50
51
  //# sourceMappingURL=permissions-validator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"permissions-validator.d.ts","sourceRoot":"","sources":["../../src/prisma/permissions-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;AAEnD,MAAM,WAAW,YAAY;IACzB,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,wGAAwG;IACxG,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;AAE7D,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAE7C,MAAM,MAAM,SAAS,GACf,8BAA8B,GAC9B,0BAA0B,GAC1B,iBAAiB,GACjB,uBAAuB,GACvB,kBAAkB,CAAC;AAEzB,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAmBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EAC3C,SAAS,EAAE,eAAe,GAC3B,eAAe,EAAE,CAgHnB"}
1
+ {"version":3,"file":"permissions-validator.d.ts","sourceRoot":"","sources":["../../src/prisma/permissions-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAErF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;AAEnD,MAAM,WAAW,YAAY;IACzB,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,wGAAwG;IACxG,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;AAE7D,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAE7C,MAAM,MAAM,SAAS,GACf,8BAA8B,GAC9B,0BAA0B,GAC1B,iBAAiB,GACjB,uBAAuB,GACvB,kBAAkB,CAAC;AAEzB,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAmBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACrC,MAAM,EAAE,qBAAqB,EAC7B,SAAS,EAAE,eAAe,GAC3B,eAAe,EAAE,CAmHnB"}
@@ -1,15 +1,4 @@
1
1
  "use strict";
2
- /**
3
- * Static validation of a `PermissionsConfig` against the Prisma schema.
4
- *
5
- * Runs at boot (in the PrismaService constructor). It encodes the Option A
6
- * authorization model: a create condition judges a model's own scalar fields
7
- * only, and every foreign-key reference a create establishes is authorized by
8
- * the target model's `connect` rule. Misconfigurations that would break at
9
- * runtime are surfaced here — errors reject boot, warnings are advisory.
10
- *
11
- * Pure and schema-only (no database), so it is independently unit-testable.
12
- */
13
2
  Object.defineProperty(exports, "__esModule", { value: true });
14
3
  exports.validatePermissionsConfig = void 0;
15
4
  /** Collects condition keys that name a relation (skips AND/OR/NOT, which recurse). */
@@ -46,9 +35,12 @@ function findRelationKeys(cond, relationFields, found = new Set()) {
46
35
  */
47
36
  function validatePermissionsConfig(config, relations) {
48
37
  const issues = [];
38
+ // Iterate the typed config structurally — model/role keys are dynamic, and
39
+ // condition/rule shapes are inspected at runtime.
40
+ const cfg = (config || {});
49
41
  const byModel = {};
50
- for (const m of Object.keys(config || {}))
51
- byModel[m.toLowerCase()] = config[m];
42
+ for (const m of Object.keys(cfg))
43
+ byModel[m.toLowerCase()] = cfg[m];
52
44
  const hasConnectRule = (targetModel, role) => {
53
45
  const rules = byModel[targetModel.toLowerCase()]?.[role];
54
46
  return !!rules && rules.connect !== undefined && rules.connect !== null;
@@ -58,8 +50,8 @@ function validatePermissionsConfig(config, relations) {
58
50
  const hasRelationConnect = (sourceRules, field) => !!sourceRules?.relations?.[field]?.connect;
59
51
  const canCreate = (rules) => !!rules && (rules.create !== undefined || rules.createMany !== undefined);
60
52
  const canUpdate = (rules) => !!rules && (rules.update !== undefined || rules.updateMany !== undefined);
61
- for (const modelKey of Object.keys(config || {})) {
62
- const roles = config[modelKey] || {};
53
+ for (const modelKey of Object.keys(cfg)) {
54
+ const roles = cfg[modelKey] || {};
63
55
  const rels = relations[modelKey.toLowerCase()] || [];
64
56
  const belongsTo = rels.filter((r) => r.kind === 'belongsTo' && r.referencingColumn);
65
57
  const relationFieldNames = new Set(rels.map((r) => r.field));
package/docs/README.md CHANGED
@@ -7,6 +7,7 @@ Authoritative usage documentation for `@appxdigital/appx-core`. **This folder is
7
7
  - **[permissions.md](./permissions.md)** — the authorization model: the `@Permission` and `@ExposeModels` decorators, the `permissions.config.ts` shape, roles/actions, row-level `conditions`, field-level control, action fallbacks, and the `GUEST` (unauthenticated) flow.
8
8
  - **[dtos.md](./dtos.md)** — the generated CRUD validation DTOs: their two-file structure, **how to remove a field** (`OmitType` / `@NoWrite`), how to add validation, and why nested relation writes don't belong on generic CRUD.
9
9
  - **[data-access.md](./data-access.md)** — how you talk to the database: the Prisma proxy (`prisma.model.*`), how ABAC filtering and field omission are enforced on every call, the redirected single-record methods, relation behaviour, bypass hatches, and transactions.
10
+ - **[authentication.md](./authentication.md)** — the built-in `/auth` surface, and **how to override framework internals** (extend the exported `AuthController`/`AuthService`/`RegisterDto`/Passport strategies and register your own at the same prefix via `AuthModule.forRoot({ controller: false })`) — e.g. adding `name` to registration.
10
11
  - **[graphql.md](./graphql.md)** — the **read-only** GraphQL API generated from your schema: queries, nested selections, and how ABAC filters them.
11
12
  - **[limitations.md](./limitations.md)** — **known limitations and features that are NOT ready for use** (e.g. `aggregate`, GraphQL writes). Read this before relying on any method not covered in the guides above.
12
13
 
@@ -0,0 +1,215 @@
1
+ # Authentication & overriding framework internals
2
+
3
+ The framework ships a working auth surface. When you need to change part of it —
4
+ add a field to registration, add endpoints, swap a Passport strategy — you don't
5
+ fork it: you **extend the exported classes and register your own versions**. This
6
+ page shows the pattern (auth is the main example, but it applies to any exported
7
+ framework class).
8
+
9
+ ---
10
+
11
+ ## What `AuthModule` provides
12
+
13
+ Importing `AuthModule` registers, under the `/auth` prefix:
14
+
15
+ | Route | Guard | Body |
16
+ |---|---|---|
17
+ | `POST /auth/register` | — | `RegisterDto` (`email`, `password`) |
18
+ | `POST /auth/login` | `LocalAuthGuard` | credentials |
19
+ | `POST /auth/login/jwt` | `LocalAuthGuard` | credentials → tokens |
20
+ | `POST /auth/refresh` | `RefreshTokenGuard` | refresh token |
21
+ | `POST /auth/logout` · `logout/jwt` | `AuthenticatedGuard` | — |
22
+ | `GET /auth/me`, `GET/POST /auth/sessions…` | `AuthenticatedGuard` | — |
23
+
24
+ plus the providers (all **global**): `AuthService`, the Passport strategies
25
+ (`LocalStrategy`, `JwtStrategy`, `RefreshTokenStrategy`), the guards
26
+ (`LocalAuthGuard`, `JwtAuthGuard`, `AuthenticatedGuard`, `RefreshTokenGuard`,
27
+ `SessionAuthGuard`), and `SessionSerializer`.
28
+
29
+ **Registration is intentionally narrow.** `RegisterDto` accepts only `email` +
30
+ `password`, and `AuthService.register` creates the user with `BYPASS_FILTERING`
31
+ (it's an unauthenticated flow, so ABAC create-enforcement can't gate it). The
32
+ `RegisterDto` whitelist is therefore the *only* thing controlling which fields a
33
+ sign-up may set — which is exactly why widening it is a deliberate override, not
34
+ a config toggle.
35
+
36
+ All of these are exported from the package root — **import from
37
+ `@appxdigital/appx-core`, never from `@appxdigital/appx-core/dist/...`** (deep
38
+ paths are internal and can move between versions):
39
+
40
+ ```ts
41
+ import {
42
+ AuthModule, AuthController, AuthService,
43
+ RegisterDto, UserDto, AuthField,
44
+ LocalStrategy, JwtStrategy, RefreshTokenStrategy,
45
+ } from '@appxdigital/appx-core';
46
+ ```
47
+
48
+ ---
49
+
50
+ ## The override pattern
51
+
52
+ To replace or extend an auth endpoint **at the same `/auth` prefix**:
53
+
54
+ 1. **Extend** the framework class (controller / service / strategy).
55
+ 2. Put your version in **your own module**.
56
+ 3. Import **`AuthModule.forRoot({ controller: false })`** — this keeps every auth
57
+ provider global but drops the built-in `AuthController`, so *your* controller
58
+ owns `/auth` with no duplicate route.
59
+ 4. Register your module in `AppModule` (in place of a bare `AuthModule`).
60
+
61
+ ```ts
62
+ // app.module.ts
63
+ @Module({
64
+ imports: [
65
+ AppxCoreModule.forRoot(PermissionsConfig),
66
+ AuthModule.forRoot({ controller: false }), // providers only, no built-in controller
67
+ MyAuthModule, // your controller/service live here
68
+ // …
69
+ ],
70
+ })
71
+ export class AppModule {}
72
+ ```
73
+
74
+ ```ts
75
+ // my-auth.module.ts
76
+ @Module({
77
+ controllers: [MyAuthController],
78
+ providers: [/* MyAuthService, MyLocalStrategy, … as needed */],
79
+ })
80
+ export class MyAuthModule {}
81
+ ```
82
+
83
+ > **Why `forRoot({ controller: false })`?** If you import the plain `AuthModule`
84
+ > *and* register your own `/auth` controller, you get two handlers for the same
85
+ > routes. Skipping the built-in controller — while keeping its providers — is what
86
+ > lets your controller take over cleanly. (Importing the plain `AuthModule` is
87
+ > still correct when you're *not* overriding the controller.)
88
+
89
+ ---
90
+
91
+ ## Recipe 1 — add a field to registration (e.g. `name`)
92
+
93
+ Extend `RegisterDto`, then override the inherited `register` handler:
94
+
95
+ ```ts
96
+ // register-local.dto.ts
97
+ import { RegisterDto } from '@appxdigital/appx-core';
98
+ import { IsOptional, IsString } from 'class-validator';
99
+
100
+ export class RegisterLocalDto extends RegisterDto {
101
+ @IsOptional()
102
+ @IsString()
103
+ name?: string;
104
+ }
105
+ ```
106
+
107
+ ```ts
108
+ // my-auth.controller.ts
109
+ import { Body, Controller, Post } from '@nestjs/common';
110
+ import { AuthController } from '@appxdigital/appx-core';
111
+ import { RegisterLocalDto } from './register-local.dto';
112
+
113
+ @Controller('auth')
114
+ export class MyAuthController extends AuthController {
115
+ @Post('register')
116
+ async register(@Body() dto: RegisterLocalDto) {
117
+ return this.authService.register(dto); // authService is `protected` on AuthController
118
+ }
119
+ }
120
+ ```
121
+
122
+ `AuthService.register` spreads the DTO straight into the user create, so `name`
123
+ persists (your `User` model must have the column). Everything else on
124
+ `AuthController` — login, refresh, sessions — is inherited unchanged. The global
125
+ validation pipe now validates the body against `RegisterLocalDto`, so `name` is
126
+ accepted and any *other* unknown field still `400`s.
127
+
128
+ > Keep registration a **narrow allowlist** — only add fields a self-service
129
+ > sign-up should legitimately set. Never widen it to privileged columns (`role`,
130
+ > tenant, ownership ids); mark those `/// @NoWrite` and set them server-side.
131
+
132
+ ---
133
+
134
+ ## Recipe 2 — extend the service (add methods / change behaviour)
135
+
136
+ Extend `AuthService` and forward its constructor. Its signature is
137
+ `(userService, prisma, jwtService, configService)`:
138
+
139
+ ```ts
140
+ import { Injectable } from '@nestjs/common';
141
+ import { AuthService, PrismaService } from '@appxdigital/appx-core';
142
+ import { UserService } from '../user/user.service';
143
+ import { ConfigService } from '@nestjs/config';
144
+ import { JwtService } from '@nestjs/jwt';
145
+
146
+ @Injectable()
147
+ export class MyAuthService extends AuthService {
148
+ constructor(
149
+ userService: UserService,
150
+ prisma: PrismaService,
151
+ jwtService: JwtService,
152
+ configService: ConfigService,
153
+ ) {
154
+ super(userService, prisma, jwtService, configService);
155
+ }
156
+
157
+ async handleForgotPassword(email: string) { /* … */ }
158
+ }
159
+ ```
160
+
161
+ Provide `MyAuthService` in your module and inject it in your controller
162
+ (`super(myAuthService)` if the controller extends `AuthController`). Because you
163
+ imported `AuthModule.forRoot({ controller: false })`, `UserService`, `JwtService`,
164
+ `PrismaService`, and `ConfigService` are all already available to inject.
165
+
166
+ ---
167
+
168
+ ## Recipe 3 — override a Passport strategy
169
+
170
+ The built-in `LocalStrategy` reads the username/password field names from
171
+ `@AuthField(...)` metadata on `UserDto` and delegates to
172
+ `AuthService.validateUser`. To change credential validation, extend it (or
173
+ `JwtStrategy` / `RefreshTokenStrategy`) and provide your version:
174
+
175
+ ```ts
176
+ import { Injectable } from '@nestjs/common';
177
+ import { LocalStrategy } from '@appxdigital/appx-core';
178
+
179
+ @Injectable()
180
+ export class MyLocalStrategy extends LocalStrategy {
181
+ async validate(username: string, password: string) {
182
+ // custom checks, then fall back to the framework behaviour:
183
+ return super.validate(username, password);
184
+ }
185
+ }
186
+ ```
187
+
188
+ ```ts
189
+ @Module({
190
+ controllers: [MyAuthController],
191
+ providers: [MyLocalStrategy], // Passport picks up the last-registered strategy of this name
192
+ })
193
+ export class MyAuthModule {}
194
+ ```
195
+
196
+ > Passport registers strategies by name. Providing your own `LocalStrategy`
197
+ > subclass in your module (with `AuthModule.forRoot({ controller: false })` for
198
+ > the rest) makes yours the active `local` strategy.
199
+
200
+ ---
201
+
202
+ ## The general principle
203
+
204
+ This isn't auth-specific. Every framework class you might need to specialise is
205
+ exported from `@appxdigital/appx-core`. To override inner functionality:
206
+
207
+ 1. **Extend** the exported class.
208
+ 2. **Provide** your subclass in your own module (a subclass provider shadows the
209
+ base where you inject it).
210
+ 3. When the framework module would *also* register the thing you're replacing
211
+ (a controller, a route), import it in a mode that omits that piece — e.g.
212
+ `AuthModule.forRoot({ controller: false })` — so there's no duplicate.
213
+
214
+ If a class you need to extend isn't exported, that's a framework gap — open it
215
+ rather than deep-importing from `dist/`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appxdigital/appx-core",
3
- "version": "0.1.121-beta.13",
3
+ "version": "0.1.121-beta.15",
4
4
  "description": "Appx Core is a library that provides a set of tools to help you build your application faster.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",