@jperezmart/nest-casl-testing 0.2.0 → 0.3.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 +4 -2
- package/dist/index.cjs +8 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -61,8 +61,10 @@ application would:
|
|
|
61
61
|
| `detectSubjectType` | `(subject: object) => string` | Custom subject-type detection, for subjects CASL cannot name on its own. |
|
|
62
62
|
|
|
63
63
|
A role whose definition is `true` rather than a function also grants
|
|
64
|
-
`manage all`.
|
|
65
|
-
|
|
64
|
+
`manage all`. The `everyone` entry applies to every user before their Roles,
|
|
65
|
+
and a role named `everyone` on the user is ignored. A user whose `roles` is
|
|
66
|
+
missing or not an array is treated as having no roles (the Everyone
|
|
67
|
+
permissions still apply), which is what `AbilityFactory` does.
|
|
66
68
|
|
|
67
69
|
## License
|
|
68
70
|
|
package/dist/index.cjs
CHANGED
|
@@ -4,9 +4,9 @@ let _casl_ability = require("@casl/ability");
|
|
|
4
4
|
/**
|
|
5
5
|
* Build a CASL ability directly from Role permissions and a user, without
|
|
6
6
|
* booting a Nest application. Intended for unit-testing permission definitions
|
|
7
|
-
* in projects that consume `@jperezmart/nest-casl`. The
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* in projects that consume `@jperezmart/nest-casl`. The user and ability types
|
|
8
|
+
* are inferred from `permissions`; the user may carry roles the map does not
|
|
9
|
+
* declare. Everyone permissions apply first, then the user's Roles.
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```ts
|
|
@@ -22,10 +22,14 @@ function buildAbilityForTest(permissions, user, options = {}) {
|
|
|
22
22
|
builder.can("manage", "all");
|
|
23
23
|
return builder.build(buildOptions);
|
|
24
24
|
}
|
|
25
|
+
const abilityBuilder = builder;
|
|
26
|
+
const everyone = permissions["everyone"];
|
|
27
|
+
if (typeof everyone === "function") everyone(user, abilityBuilder);
|
|
25
28
|
for (const role of roles) {
|
|
29
|
+
if (role === "everyone") continue;
|
|
26
30
|
const definition = permissions[role];
|
|
27
31
|
if (definition === true) builder.can("manage", "all");
|
|
28
|
-
else if (typeof definition === "function") definition(user,
|
|
32
|
+
else if (typeof definition === "function") definition(user, abilityBuilder);
|
|
29
33
|
}
|
|
30
34
|
return builder.build(buildOptions);
|
|
31
35
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["AbilityBuilder","createMongoAbility"],"sources":["../src/index.ts"],"sourcesContent":["import type { AnyAbility, MongoAbility } from '@casl/ability';\nimport { AbilityBuilder, createMongoAbility } from '@casl/ability';\nimport type {\n AuthorizableUser,\n DefineRolePermissions,\n RolePermissions,\n} from '@jperezmart/nest-casl';\n\n/** Extra options accepted by {@link buildAbilityForTest}. */\nexport interface BuildAbilityForTestOptions {\n /**\n * Role that bypasses all checks (mirrors `CaslModule.forRoot`). Any string:\n * the superuser role usually has no entry in the Role permissions.\n */\n superuserRole?: string;\n\n /** Custom subject-type detection (mirrors `CaslModule.forRoot`). */\n detectSubjectType?: (subject: object) => string;\n}\n\n/**\n * Build a CASL ability directly from Role permissions and a user, without\n * booting a Nest application. Intended for unit-testing permission definitions\n * in projects that consume `@jperezmart/nest-casl`. The
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["AbilityBuilder","createMongoAbility"],"sources":["../src/index.ts"],"sourcesContent":["import type { AnyAbility, MongoAbility } from '@casl/ability';\nimport { AbilityBuilder, createMongoAbility } from '@casl/ability';\nimport type {\n AuthorizableUser,\n DefineRolePermissions,\n RolePermissions,\n} from '@jperezmart/nest-casl';\n\n/** Extra options accepted by {@link buildAbilityForTest}. */\nexport interface BuildAbilityForTestOptions {\n /**\n * Role that bypasses all checks (mirrors `CaslModule.forRoot`). Any string:\n * the superuser role usually has no entry in the Role permissions.\n */\n superuserRole?: string;\n\n /** Custom subject-type detection (mirrors `CaslModule.forRoot`). */\n detectSubjectType?: (subject: object) => string;\n}\n\n/**\n * Build a CASL ability directly from Role permissions and a user, without\n * booting a Nest application. Intended for unit-testing permission definitions\n * in projects that consume `@jperezmart/nest-casl`. The user and ability types\n * are inferred from `permissions`; the user may carry roles the map does not\n * declare. Everyone permissions apply first, then the user's Roles.\n *\n * @example\n * ```ts\n * const ability = buildAbilityForTest(permissions, { id: \"1\", roles: [\"author\"] });\n * expect(ability.can(\"update\", subject(\"Article\", { authorId: \"1\" }))).toBe(true);\n * ```\n */\nexport function buildAbilityForTest<\n TUser extends AuthorizableUser = AuthorizableUser,\n TAbility extends AnyAbility = AnyAbility,\n>(\n permissions: RolePermissions<string, TUser, TAbility>,\n user: TUser,\n options: BuildAbilityForTestOptions = {},\n): TAbility {\n const builder = new AbilityBuilder<MongoAbility>(createMongoAbility);\n const buildOptions = options.detectSubjectType\n ? { detectSubjectType: options.detectSubjectType }\n : undefined;\n\n // Mirror AbilityFactory: a missing / non-array `roles` means \"no roles\"\n // (Everyone permissions still apply).\n const roles: readonly string[] = Array.isArray(user.roles) ? user.roles : [];\n\n if (\n options.superuserRole !== undefined &&\n roles.includes(options.superuserRole)\n ) {\n builder.can('manage', 'all');\n return builder.build(buildOptions) as unknown as TAbility;\n }\n\n const abilityBuilder = builder as unknown as AbilityBuilder<AnyAbility>;\n const everyone = (permissions as Record<string, unknown>)['everyone'];\n if (typeof everyone === 'function') {\n (everyone as DefineRolePermissions<TUser, AnyAbility>)(\n user,\n abilityBuilder,\n );\n }\n\n for (const role of roles) {\n // A foreign Role named `everyone` is not a Role: its rules are already in.\n if (role === 'everyone') continue;\n const definition = (permissions as Record<string, unknown>)[role];\n if (definition === true) {\n builder.can('manage', 'all');\n } else if (typeof definition === 'function') {\n (definition as DefineRolePermissions<TUser, AnyAbility>)(\n user,\n abilityBuilder,\n );\n }\n }\n\n return builder.build(buildOptions) as unknown as TAbility;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiCA,SAAgB,oBAId,aACA,MACA,UAAsC,CAAC,GAC7B;CACV,MAAM,UAAU,IAAIA,cAAAA,eAA6BC,cAAAA,kBAAkB;CACnE,MAAM,eAAe,QAAQ,oBACzB,EAAE,mBAAmB,QAAQ,kBAAkB,IAC/C,KAAA;CAIJ,MAAM,QAA2B,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,QAAQ,CAAC;CAE3E,IACE,QAAQ,kBAAkB,KAAA,KAC1B,MAAM,SAAS,QAAQ,aAAa,GACpC;EACA,QAAQ,IAAI,UAAU,KAAK;EAC3B,OAAO,QAAQ,MAAM,YAAY;CACnC;CAEA,MAAM,iBAAiB;CACvB,MAAM,WAAY,YAAwC;CAC1D,IAAI,OAAO,aAAa,YACtB,SACE,MACA,cACF;CAGF,KAAK,MAAM,QAAQ,OAAO;EAExB,IAAI,SAAS,YAAY;EACzB,MAAM,aAAc,YAAwC;EAC5D,IAAI,eAAe,MACjB,QAAQ,IAAI,UAAU,KAAK;OACtB,IAAI,OAAO,eAAe,YAC/B,WACE,MACA,cACF;CAEJ;CAEA,OAAO,QAAQ,MAAM,YAAY;AACnC"}
|
package/dist/index.d.cts
CHANGED
|
@@ -15,9 +15,9 @@ interface BuildAbilityForTestOptions {
|
|
|
15
15
|
/**
|
|
16
16
|
* Build a CASL ability directly from Role permissions and a user, without
|
|
17
17
|
* booting a Nest application. Intended for unit-testing permission definitions
|
|
18
|
-
* in projects that consume `@jperezmart/nest-casl`. The
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* in projects that consume `@jperezmart/nest-casl`. The user and ability types
|
|
19
|
+
* are inferred from `permissions`; the user may carry roles the map does not
|
|
20
|
+
* declare. Everyone permissions apply first, then the user's Roles.
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
23
23
|
* ```ts
|
|
@@ -25,7 +25,7 @@ interface BuildAbilityForTestOptions {
|
|
|
25
25
|
* expect(ability.can("update", subject("Article", { authorId: "1" }))).toBe(true);
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
declare function buildAbilityForTest<
|
|
28
|
+
declare function buildAbilityForTest<TUser extends AuthorizableUser = AuthorizableUser, TAbility extends AnyAbility = AnyAbility>(permissions: RolePermissions<string, TUser, TAbility>, user: TUser, options?: BuildAbilityForTestOptions): TAbility;
|
|
29
29
|
//#endregion
|
|
30
30
|
export { BuildAbilityForTestOptions, buildAbilityForTest };
|
|
31
31
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;UASiB,0BAAA;EAAA;;;;EAKf,aAAA;EAGA;EAAA,iBAAA,IAAqB,OAAA;AAAA;AAAe;AAgBtC;;;;;;;;;;;;AAhBsC,iBAgBtB,mBAAA,
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;UASiB,0BAAA;EAAA;;;;EAKf,aAAA;EAGA;EAAA,iBAAA,IAAqB,OAAA;AAAA;AAAe;AAgBtC;;;;;;;;;;;;AAhBsC,iBAgBtB,mBAAA,eACA,gBAAA,GAAmB,gBAAA,mBAChB,UAAA,GAAa,UAAA,EAE9B,WAAA,EAAa,eAAA,SAAwB,KAAA,EAAO,QAAA,GAC5C,IAAA,EAAM,KAAA,EACN,OAAA,GAAS,0BAAA,GACR,QAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,9 +15,9 @@ interface BuildAbilityForTestOptions {
|
|
|
15
15
|
/**
|
|
16
16
|
* Build a CASL ability directly from Role permissions and a user, without
|
|
17
17
|
* booting a Nest application. Intended for unit-testing permission definitions
|
|
18
|
-
* in projects that consume `@jperezmart/nest-casl`. The
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* in projects that consume `@jperezmart/nest-casl`. The user and ability types
|
|
19
|
+
* are inferred from `permissions`; the user may carry roles the map does not
|
|
20
|
+
* declare. Everyone permissions apply first, then the user's Roles.
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
23
23
|
* ```ts
|
|
@@ -25,7 +25,7 @@ interface BuildAbilityForTestOptions {
|
|
|
25
25
|
* expect(ability.can("update", subject("Article", { authorId: "1" }))).toBe(true);
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
declare function buildAbilityForTest<
|
|
28
|
+
declare function buildAbilityForTest<TUser extends AuthorizableUser = AuthorizableUser, TAbility extends AnyAbility = AnyAbility>(permissions: RolePermissions<string, TUser, TAbility>, user: TUser, options?: BuildAbilityForTestOptions): TAbility;
|
|
29
29
|
//#endregion
|
|
30
30
|
export { BuildAbilityForTestOptions, buildAbilityForTest };
|
|
31
31
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;UASiB,0BAAA;EAAA;;;;EAKf,aAAA;EAGA;EAAA,iBAAA,IAAqB,OAAA;AAAA;AAAe;AAgBtC;;;;;;;;;;;;AAhBsC,iBAgBtB,mBAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;UASiB,0BAAA;EAAA;;;;EAKf,aAAA;EAGA;EAAA,iBAAA,IAAqB,OAAA;AAAA;AAAe;AAgBtC;;;;;;;;;;;;AAhBsC,iBAgBtB,mBAAA,eACA,gBAAA,GAAmB,gBAAA,mBAChB,UAAA,GAAa,UAAA,EAE9B,WAAA,EAAa,eAAA,SAAwB,KAAA,EAAO,QAAA,GAC5C,IAAA,EAAM,KAAA,EACN,OAAA,GAAS,0BAAA,GACR,QAAA"}
|
package/dist/index.js
CHANGED
|
@@ -3,9 +3,9 @@ import { AbilityBuilder, createMongoAbility } from "@casl/ability";
|
|
|
3
3
|
/**
|
|
4
4
|
* Build a CASL ability directly from Role permissions and a user, without
|
|
5
5
|
* booting a Nest application. Intended for unit-testing permission definitions
|
|
6
|
-
* in projects that consume `@jperezmart/nest-casl`. The
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* in projects that consume `@jperezmart/nest-casl`. The user and ability types
|
|
7
|
+
* are inferred from `permissions`; the user may carry roles the map does not
|
|
8
|
+
* declare. Everyone permissions apply first, then the user's Roles.
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```ts
|
|
@@ -21,10 +21,14 @@ function buildAbilityForTest(permissions, user, options = {}) {
|
|
|
21
21
|
builder.can("manage", "all");
|
|
22
22
|
return builder.build(buildOptions);
|
|
23
23
|
}
|
|
24
|
+
const abilityBuilder = builder;
|
|
25
|
+
const everyone = permissions["everyone"];
|
|
26
|
+
if (typeof everyone === "function") everyone(user, abilityBuilder);
|
|
24
27
|
for (const role of roles) {
|
|
28
|
+
if (role === "everyone") continue;
|
|
25
29
|
const definition = permissions[role];
|
|
26
30
|
if (definition === true) builder.can("manage", "all");
|
|
27
|
-
else if (typeof definition === "function") definition(user,
|
|
31
|
+
else if (typeof definition === "function") definition(user, abilityBuilder);
|
|
28
32
|
}
|
|
29
33
|
return builder.build(buildOptions);
|
|
30
34
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { AnyAbility, MongoAbility } from '@casl/ability';\nimport { AbilityBuilder, createMongoAbility } from '@casl/ability';\nimport type {\n AuthorizableUser,\n DefineRolePermissions,\n RolePermissions,\n} from '@jperezmart/nest-casl';\n\n/** Extra options accepted by {@link buildAbilityForTest}. */\nexport interface BuildAbilityForTestOptions {\n /**\n * Role that bypasses all checks (mirrors `CaslModule.forRoot`). Any string:\n * the superuser role usually has no entry in the Role permissions.\n */\n superuserRole?: string;\n\n /** Custom subject-type detection (mirrors `CaslModule.forRoot`). */\n detectSubjectType?: (subject: object) => string;\n}\n\n/**\n * Build a CASL ability directly from Role permissions and a user, without\n * booting a Nest application. Intended for unit-testing permission definitions\n * in projects that consume `@jperezmart/nest-casl`. The
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { AnyAbility, MongoAbility } from '@casl/ability';\nimport { AbilityBuilder, createMongoAbility } from '@casl/ability';\nimport type {\n AuthorizableUser,\n DefineRolePermissions,\n RolePermissions,\n} from '@jperezmart/nest-casl';\n\n/** Extra options accepted by {@link buildAbilityForTest}. */\nexport interface BuildAbilityForTestOptions {\n /**\n * Role that bypasses all checks (mirrors `CaslModule.forRoot`). Any string:\n * the superuser role usually has no entry in the Role permissions.\n */\n superuserRole?: string;\n\n /** Custom subject-type detection (mirrors `CaslModule.forRoot`). */\n detectSubjectType?: (subject: object) => string;\n}\n\n/**\n * Build a CASL ability directly from Role permissions and a user, without\n * booting a Nest application. Intended for unit-testing permission definitions\n * in projects that consume `@jperezmart/nest-casl`. The user and ability types\n * are inferred from `permissions`; the user may carry roles the map does not\n * declare. Everyone permissions apply first, then the user's Roles.\n *\n * @example\n * ```ts\n * const ability = buildAbilityForTest(permissions, { id: \"1\", roles: [\"author\"] });\n * expect(ability.can(\"update\", subject(\"Article\", { authorId: \"1\" }))).toBe(true);\n * ```\n */\nexport function buildAbilityForTest<\n TUser extends AuthorizableUser = AuthorizableUser,\n TAbility extends AnyAbility = AnyAbility,\n>(\n permissions: RolePermissions<string, TUser, TAbility>,\n user: TUser,\n options: BuildAbilityForTestOptions = {},\n): TAbility {\n const builder = new AbilityBuilder<MongoAbility>(createMongoAbility);\n const buildOptions = options.detectSubjectType\n ? { detectSubjectType: options.detectSubjectType }\n : undefined;\n\n // Mirror AbilityFactory: a missing / non-array `roles` means \"no roles\"\n // (Everyone permissions still apply).\n const roles: readonly string[] = Array.isArray(user.roles) ? user.roles : [];\n\n if (\n options.superuserRole !== undefined &&\n roles.includes(options.superuserRole)\n ) {\n builder.can('manage', 'all');\n return builder.build(buildOptions) as unknown as TAbility;\n }\n\n const abilityBuilder = builder as unknown as AbilityBuilder<AnyAbility>;\n const everyone = (permissions as Record<string, unknown>)['everyone'];\n if (typeof everyone === 'function') {\n (everyone as DefineRolePermissions<TUser, AnyAbility>)(\n user,\n abilityBuilder,\n );\n }\n\n for (const role of roles) {\n // A foreign Role named `everyone` is not a Role: its rules are already in.\n if (role === 'everyone') continue;\n const definition = (permissions as Record<string, unknown>)[role];\n if (definition === true) {\n builder.can('manage', 'all');\n } else if (typeof definition === 'function') {\n (definition as DefineRolePermissions<TUser, AnyAbility>)(\n user,\n abilityBuilder,\n );\n }\n }\n\n return builder.build(buildOptions) as unknown as TAbility;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiCA,SAAgB,oBAId,aACA,MACA,UAAsC,CAAC,GAC7B;CACV,MAAM,UAAU,IAAI,eAA6B,kBAAkB;CACnE,MAAM,eAAe,QAAQ,oBACzB,EAAE,mBAAmB,QAAQ,kBAAkB,IAC/C,KAAA;CAIJ,MAAM,QAA2B,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,QAAQ,CAAC;CAE3E,IACE,QAAQ,kBAAkB,KAAA,KAC1B,MAAM,SAAS,QAAQ,aAAa,GACpC;EACA,QAAQ,IAAI,UAAU,KAAK;EAC3B,OAAO,QAAQ,MAAM,YAAY;CACnC;CAEA,MAAM,iBAAiB;CACvB,MAAM,WAAY,YAAwC;CAC1D,IAAI,OAAO,aAAa,YACtB,SACE,MACA,cACF;CAGF,KAAK,MAAM,QAAQ,OAAO;EAExB,IAAI,SAAS,YAAY;EACzB,MAAM,aAAc,YAAwC;EAC5D,IAAI,eAAe,MACjB,QAAQ,IAAI,UAAU,KAAK;OACtB,IAAI,OAAO,eAAe,YAC/B,WACE,MACA,cACF;CAEJ;CAEA,OAAO,QAAQ,MAAM,YAAY;AACnC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jperezmart/nest-casl-testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Testing utilities for @jperezmart/nest-casl — build and assert abilities without booting Nest.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@casl/ability": "^7.0.0",
|
|
37
37
|
"@jperezmart/eslint-config": "^1.0.0",
|
|
38
|
-
"@jperezmart/nest-casl": "0.
|
|
38
|
+
"@jperezmart/nest-casl": "0.3.0",
|
|
39
39
|
"@jperezmart/typescript-config": "^1.0.0",
|
|
40
40
|
"eslint": "^10.3.0",
|
|
41
41
|
"tsdown": "^0.22.2",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@casl/ability": "^7.0.0",
|
|
47
|
-
"@jperezmart/nest-casl": "^0.
|
|
47
|
+
"@jperezmart/nest-casl": "^0.3.0"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|