@stonecrop/casl-middleware 0.13.3 → 0.13.5

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.
@@ -75,7 +75,7 @@ export const createCaslMiddleware = (options = {}) => {
75
75
  const subjectType = info.parentType.name;
76
76
  const subjectName = subjectMap[subjectType] || subjectType;
77
77
  if (debug) {
78
- console.log(`Checking permission: ${action} on ${subjectName} at ${fieldPath}`);
78
+ console.debug(`Checking permission: ${action} on ${subjectName} at ${fieldPath}`);
79
79
  }
80
80
  // Check field-level permissions if defined
81
81
  if (fieldPermissions[fieldPath]) {
@@ -57,7 +57,7 @@ export declare const createJWTMiddleware: (config?: JWTConfig) => (context: Cont
57
57
  */
58
58
  export declare const createJWT: (user: User, config: {
59
59
  secret: string;
60
- expiresIn?: string | number;
60
+ expiresIn?: jwt.SignOptions["expiresIn"];
61
61
  issuer?: string;
62
62
  audience?: string;
63
63
  additionalClaims?: Record<string, any>;
@@ -92,8 +92,8 @@ export declare const refreshTokenUtils: {
92
92
  createTokenPair: (user: User, config: {
93
93
  accessSecret: string;
94
94
  refreshSecret: string;
95
- accessExpiresIn?: string;
96
- refreshExpiresIn?: string;
95
+ accessExpiresIn?: jwt.SignOptions["expiresIn"];
96
+ refreshExpiresIn?: jwt.SignOptions["expiresIn"];
97
97
  }) => {
98
98
  accessToken: string;
99
99
  refreshToken: string;
@@ -105,7 +105,7 @@ export declare const refreshTokenUtils: {
105
105
  accessSecret: string;
106
106
  refreshSecret: string;
107
107
  getUserById: (id: string) => Promise<User | null>;
108
- accessExpiresIn?: string;
108
+ accessExpiresIn?: jwt.SignOptions["expiresIn"];
109
109
  }) => Promise<{
110
110
  accessToken: string;
111
111
  user: User;
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../src/middleware/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAA;AAE9B,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAG7C,MAAM,WAAW,SAAS;IACzB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,SAAS,CAAA;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,UAAW,SAAQ,GAAG,CAAC,UAAU;IACjD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,CAAC,EAAE,KAAK,CAAC;QACnB,MAAM,EAAE,MAAM,CAAA;QACd,OAAO,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,GAAG,CAAA;KAChB,CAAC,CAAA;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAClB;AAeD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAQ,SAAc,MAoB3C,SAAS,OAAO,EAAE,MAAM,MAAM,OAAO,CAAC,GAAG,CAAC,iBAoExD,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,GACrB,MAAM,IAAI,EACV,QAAQ;IACP,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACtC,KACC,MAiBF,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,UAAS,SAAc,MAChD,OAAO,IAAI,4CAsBzB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,2BAA2B,GAAI,QAAQ,SAAS;;;;;yBAQtC,GAAG,UAAU,GAAG;;;CAwBtC,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,SAAS,MAI1C,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,kBA4B3C,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB;IAC7B;;OAEG;4BAEI,IAAI,UACF;QACP,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;QACrB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;KACzB;;;;IAkCF;;OAEG;uCAEY,MAAM,UACZ;QACP,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;QACrB,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAA;QACjD,eAAe,CAAC,EAAE,MAAM,CAAA;KACxB;;;;CAyCF,CAAA"}
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../src/middleware/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAA;AAE9B,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAG7C,MAAM,WAAW,SAAS;IACzB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,SAAS,CAAA;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,UAAW,SAAQ,GAAG,CAAC,UAAU;IACjD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,CAAC,EAAE,KAAK,CAAC;QACnB,MAAM,EAAE,MAAM,CAAA;QACd,OAAO,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,GAAG,CAAA;KAChB,CAAC,CAAA;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAClB;AAeD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAQ,SAAc,MAoB3C,SAAS,OAAO,EAAE,MAAM,MAAM,OAAO,CAAC,GAAG,CAAC,iBAwExD,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,GACrB,MAAM,IAAI,EACV,QAAQ;IACP,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;IACxC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACtC,KACC,MAiBF,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,UAAS,SAAc,MAChD,OAAO,IAAI,4CAsBzB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,2BAA2B,GAAI,QAAQ,SAAS;;;;;yBAQtC,GAAG,UAAU,GAAG;;;CAwBtC,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,SAAS,MAI1C,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,kBA4B3C,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB;IAC7B;;OAEG;4BAEI,IAAI,UACF;QACP,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;QACrB,eAAe,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;QAC9C,gBAAgB,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;KAC/C;;;;IAkCF;;OAEG;uCAEY,MAAM,UACZ;QACP,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;QACrB,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAA;QACjD,eAAe,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;KAC9C;;;;CAgDF,CAAA"}
@@ -74,7 +74,11 @@ export const createJWTMiddleware = (config = {}) => {
74
74
  };
75
75
  // Verify and decode token
76
76
  const secretOrPublicKey = publicKey || secret;
77
- const payload = jwt.verify(token, secretOrPublicKey, verifyOptions);
77
+ const decoded = jwt.verify(token, secretOrPublicKey, verifyOptions);
78
+ if (typeof decoded === 'string' || decoded == null) {
79
+ throw new Error('Invalid JWT payload: expected object');
80
+ }
81
+ const payload = decoded;
78
82
  // Extract user from payload
79
83
  const user = extractUser(payload);
80
84
  if (user) {
@@ -125,7 +129,7 @@ export const createJWT = (user, config) => {
125
129
  if (audience !== undefined)
126
130
  signOptions.audience = audience;
127
131
  if (expiresIn !== undefined)
128
- signOptions.expiresIn = expiresIn; // Type cast to avoid TS issues
132
+ signOptions.expiresIn = expiresIn;
129
133
  return jwt.sign(payload, secret, signOptions);
130
134
  };
131
135
  /**
@@ -240,13 +244,13 @@ export const refreshTokenUtils = {
240
244
  // Create access token with proper options
241
245
  const accessOptions = {};
242
246
  if (accessExpiresIn) {
243
- accessOptions.expiresIn = accessExpiresIn; // Type cast to avoid TS issues
247
+ accessOptions.expiresIn = accessExpiresIn;
244
248
  }
245
249
  const accessToken = jwt.sign(accessPayload, accessSecret, accessOptions);
246
250
  // Create refresh token with proper options
247
251
  const refreshOptions = {};
248
252
  if (refreshExpiresIn) {
249
- refreshOptions.expiresIn = refreshExpiresIn; // Type cast to avoid TS issues
253
+ refreshOptions.expiresIn = refreshExpiresIn;
250
254
  }
251
255
  const refreshToken = jwt.sign(refreshPayload, refreshSecret, refreshOptions);
252
256
  return { accessToken, refreshToken };
@@ -258,11 +262,18 @@ export const refreshTokenUtils = {
258
262
  const { accessSecret, refreshSecret, getUserById, accessExpiresIn = '15m' } = config;
259
263
  try {
260
264
  // Verify refresh token
261
- const payload = jwt.verify(refreshToken, refreshSecret);
265
+ const decoded = jwt.verify(refreshToken, refreshSecret);
266
+ if (typeof decoded === 'string' || decoded == null) {
267
+ throw new Error('Invalid refresh token payload: expected object');
268
+ }
269
+ const payload = decoded;
262
270
  if (payload.type !== 'refresh') {
263
271
  throw new Error('Invalid token type');
264
272
  }
265
273
  // Get fresh user data
274
+ if (!payload.sub) {
275
+ throw new Error('Invalid refresh token payload: missing subject');
276
+ }
266
277
  const user = await getUserById(payload.sub);
267
278
  if (!user) {
268
279
  throw new Error('User not found');
@@ -276,7 +287,7 @@ export const refreshTokenUtils = {
276
287
  // Create access token with proper options
277
288
  const accessOptions = {};
278
289
  if (accessExpiresIn) {
279
- accessOptions.expiresIn = accessExpiresIn; // Type cast to avoid TS issues
290
+ accessOptions.expiresIn = accessExpiresIn;
280
291
  }
281
292
  const accessToken = jwt.sign(accessPayload, accessSecret, accessOptions);
282
293
  return { accessToken, user };
@@ -1 +1 @@
1
- {"version":3,"file":"postgraphile.d.ts","sourceRoot":"","sources":["../../../src/middleware/postgraphile.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAI5D;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,cAAc,CAAC,MAkFzC,CAAA"}
1
+ {"version":3,"file":"postgraphile.d.ts","sourceRoot":"","sources":["../../../src/middleware/postgraphile.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAI5D;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,cAAc,CAAC,MA8EzC,CAAA"}
@@ -51,9 +51,8 @@ export const pglCaslPlugin = extendSchema(build => {
51
51
  Mutation: {
52
52
  plans: {
53
53
  async createAbility(_plan, fieldArgs) {
54
- const $input = fieldArgs.getRaw().input;
55
- const $userId = $input.userId;
56
- const $roles = $input.roles;
54
+ const $userId = fieldArgs.getRaw().input.userId;
55
+ const $roles = fieldArgs.getRaw().input.roles;
57
56
  return sideEffect([$userId, $roles], async ([userId, roles]) => {
58
57
  // Make this async
59
58
  try {
@@ -9,7 +9,7 @@ export declare const yogaCaslPlugin: Plugin<Context>;
9
9
  * @returns Yoga plugin
10
10
  * @public
11
11
  */
12
- export declare const createYogaPlugin: (options?: MiddlewareOptions) => {
12
+ export declare const createYogaPlugin: (_options?: MiddlewareOptions) => {
13
13
  onExecute: (_: any) => Promise<void>;
14
14
  };
15
15
  //# sourceMappingURL=yoga.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"yoga.d.ts","sourceRoot":"","sources":["../../../src/middleware/yoga.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAI1C,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAO1D,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,OAAO,CAO1C,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,UAAS,iBAAsB;mBAIzC,GAAG;CAMzB,CAAA"}
1
+ {"version":3,"file":"yoga.d.ts","sourceRoot":"","sources":["../../../src/middleware/yoga.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAG1C,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAO1D,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,OAAO,CAO1C,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAU,iBAAsB;mBAE1C,GAAG;CAMzB,CAAA"}
@@ -1,5 +1,4 @@
1
1
  import { createAbility } from './ability';
2
- import { createCaslMiddleware } from './graphql';
3
2
  const getLoggedInUser = () => {
4
3
  // Mock user for demonstration purposes
5
4
  return { id: '1', roles: ['editor'] };
@@ -20,13 +19,12 @@ export const yogaCaslPlugin = {
20
19
  * @returns Yoga plugin
21
20
  * @public
22
21
  */
23
- export const createYogaPlugin = (options = {}) => {
24
- const _middleware = createCaslMiddleware(options);
22
+ export const createYogaPlugin = (_options = {}) => {
25
23
  return {
26
24
  onExecute: async (_) => {
27
- // TODO: Implement Yoga plugin
28
- // This would integrate with GraphQL Yoga's plugin system
29
- console.log('Yoga plugin not yet implemented');
25
+ // TODO: Implement Yoga plugin via createCaslMiddleware(_options).
26
+ // This would integrate with GraphQL Yoga's plugin system.
27
+ console.warn('Yoga plugin not yet implemented');
30
28
  },
31
29
  };
32
30
  };
@@ -58,12 +58,12 @@ export interface FieldPermission {
58
58
  * GraphQL resolver function type
59
59
  * @public
60
60
  */
61
- export type ResolverFn = (root: any, args: any, context: Context, info: GraphQLResolveInfo) => Promise<any> | any;
61
+ export type ResolverFn = (root: any, args: any, context: Context, info: GraphQLResolveInfo) => any;
62
62
  /**
63
63
  * Middleware function that wraps a GraphQL resolver with authorization logic
64
64
  * @public
65
65
  */
66
- export type MiddlewareFn = (resolve: ResolverFn, root: any, args: any, context: Context, info: GraphQLResolveInfo) => Promise<any> | any;
66
+ export type MiddlewareFn = (resolve: ResolverFn, root: any, args: any, context: Context, info: GraphQLResolveInfo) => any;
67
67
  /**
68
68
  * Plugin configuration options for framework integrations
69
69
  * @public
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stonecrop/casl-middleware",
3
- "version": "0.13.3",
3
+ "version": "0.13.5",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "author": {
@@ -42,14 +42,11 @@
42
42
  "@rushstack/heft": "^1.2.17",
43
43
  "@types/node": "^24.12.4",
44
44
  "@vitest/coverage-istanbul": "^4.1.5",
45
- "@eslint/js": "^10.0.1",
46
- "eslint": "^10.3.0",
47
- "eslint-config-prettier": "^10.1.8",
48
- "globals": "^17.6.0",
49
- "typescript-eslint": "^8.59.1",
50
45
  "graphql-middleware": "^6.1.35",
51
46
  "graphql-yoga": "^5.18.0",
52
47
  "jsdom": "^29.1.1",
48
+ "oxlint": "1.67.0",
49
+ "oxlint-tsgolint": "0.23.0",
53
50
  "postgraphile": "^5.0.3",
54
51
  "typescript": "^6.0.3",
55
52
  "vite": "^7.3.2",
@@ -80,7 +77,8 @@
80
77
  "build": "heft build && vite build && rushx docs",
81
78
  "dev": "vite",
82
79
  "docs": "bash ../common/scripts/run-docs.sh casl_middleware",
83
- "lint": "eslint .",
80
+ "lint": "oxlint",
81
+ "lint:fix": "oxlint --fix",
84
82
  "preview": "vite preview",
85
83
  "test": "vitest run --coverage.enabled false",
86
84
  "test:watch": "vitest watch",
@@ -98,7 +98,7 @@ export const createCaslMiddleware = (options: MiddlewareOptions = {}) => {
98
98
  const subjectName = subjectMap[subjectType] || subjectType
99
99
 
100
100
  if (debug) {
101
- console.log(`Checking permission: ${action} on ${subjectName} at ${fieldPath}`)
101
+ console.debug(`Checking permission: ${action} on ${subjectName} at ${fieldPath}`)
102
102
  }
103
103
 
104
104
  // Check field-level permissions if defined
@@ -122,7 +122,11 @@ export const createJWTMiddleware = (config: JWTConfig = {}) => {
122
122
 
123
123
  // Verify and decode token
124
124
  const secretOrPublicKey = publicKey || secret!
125
- const payload = jwt.verify(token, secretOrPublicKey, verifyOptions) as JWTPayload
125
+ const decoded = jwt.verify(token, secretOrPublicKey, verifyOptions)
126
+ if (typeof decoded === 'string' || decoded == null) {
127
+ throw new Error('Invalid JWT payload: expected object')
128
+ }
129
+ const payload: JWTPayload = decoded
126
130
 
127
131
  // Extract user from payload
128
132
  const user = extractUser(payload)
@@ -166,7 +170,7 @@ export const createJWT = (
166
170
  user: User,
167
171
  config: {
168
172
  secret: string
169
- expiresIn?: string | number
173
+ expiresIn?: jwt.SignOptions['expiresIn']
170
174
  issuer?: string
171
175
  audience?: string
172
176
  additionalClaims?: Record<string, any>
@@ -185,7 +189,7 @@ export const createJWT = (
185
189
  // Add optional fields only if they exist
186
190
  if (issuer !== undefined) signOptions.issuer = issuer
187
191
  if (audience !== undefined) signOptions.audience = audience
188
- if (expiresIn !== undefined) signOptions.expiresIn = expiresIn as any // Type cast to avoid TS issues
192
+ if (expiresIn !== undefined) signOptions.expiresIn = expiresIn
189
193
 
190
194
  return jwt.sign(payload, secret, signOptions)
191
195
  }
@@ -196,11 +200,11 @@ export const createJWT = (
196
200
  export const createJWTAbilityBuilder = (_config: JWTConfig = {}) => {
197
201
  return async (user?: User) => {
198
202
  // If user has direct permissions in JWT, use those
199
- const jwtPermissions = (user as any)?.permissions
203
+ const jwtPermissions: unknown = user?.permissions
200
204
 
201
205
  if (jwtPermissions && Array.isArray(jwtPermissions)) {
202
206
  // Build ability from JWT permissions
203
- const { can, cannot, build } = new AbilityBuilder<PureAbility>(PureAbility as any)
207
+ const { can, cannot, build } = new AbilityBuilder<PureAbility>(PureAbility)
204
208
 
205
209
  jwtPermissions.forEach((permission: any) => {
206
210
  if (permission.inverted) {
@@ -304,8 +308,8 @@ export const refreshTokenUtils = {
304
308
  config: {
305
309
  accessSecret: string
306
310
  refreshSecret: string
307
- accessExpiresIn?: string
308
- refreshExpiresIn?: string
311
+ accessExpiresIn?: jwt.SignOptions['expiresIn']
312
+ refreshExpiresIn?: jwt.SignOptions['expiresIn']
309
313
  }
310
314
  ) => {
311
315
  const { accessSecret, refreshSecret, accessExpiresIn = '15m', refreshExpiresIn = '7d' } = config
@@ -324,7 +328,7 @@ export const refreshTokenUtils = {
324
328
  // Create access token with proper options
325
329
  const accessOptions: jwt.SignOptions = {}
326
330
  if (accessExpiresIn) {
327
- accessOptions.expiresIn = accessExpiresIn as any // Type cast to avoid TS issues
331
+ accessOptions.expiresIn = accessExpiresIn
328
332
  }
329
333
 
330
334
  const accessToken = jwt.sign(accessPayload, accessSecret, accessOptions)
@@ -332,7 +336,7 @@ export const refreshTokenUtils = {
332
336
  // Create refresh token with proper options
333
337
  const refreshOptions: jwt.SignOptions = {}
334
338
  if (refreshExpiresIn) {
335
- refreshOptions.expiresIn = refreshExpiresIn as any // Type cast to avoid TS issues
339
+ refreshOptions.expiresIn = refreshExpiresIn
336
340
  }
337
341
 
338
342
  const refreshToken = jwt.sign(refreshPayload, refreshSecret, refreshOptions)
@@ -349,20 +353,27 @@ export const refreshTokenUtils = {
349
353
  accessSecret: string
350
354
  refreshSecret: string
351
355
  getUserById: (id: string) => Promise<User | null>
352
- accessExpiresIn?: string
356
+ accessExpiresIn?: jwt.SignOptions['expiresIn']
353
357
  }
354
358
  ) => {
355
359
  const { accessSecret, refreshSecret, getUserById, accessExpiresIn = '15m' } = config
356
360
 
357
361
  try {
358
362
  // Verify refresh token
359
- const payload = jwt.verify(refreshToken, refreshSecret) as any
363
+ const decoded = jwt.verify(refreshToken, refreshSecret)
364
+ if (typeof decoded === 'string' || decoded == null) {
365
+ throw new Error('Invalid refresh token payload: expected object')
366
+ }
367
+ const payload = decoded as jwt.JwtPayload & { type?: string; sub?: string }
360
368
 
361
369
  if (payload.type !== 'refresh') {
362
370
  throw new Error('Invalid token type')
363
371
  }
364
372
 
365
373
  // Get fresh user data
374
+ if (!payload.sub) {
375
+ throw new Error('Invalid refresh token payload: missing subject')
376
+ }
366
377
  const user = await getUserById(payload.sub)
367
378
  if (!user) {
368
379
  throw new Error('User not found')
@@ -378,7 +389,7 @@ export const refreshTokenUtils = {
378
389
  // Create access token with proper options
379
390
  const accessOptions: jwt.SignOptions = {}
380
391
  if (accessExpiresIn) {
381
- accessOptions.expiresIn = accessExpiresIn as any // Type cast to avoid TS issues
392
+ accessOptions.expiresIn = accessExpiresIn
382
393
  }
383
394
 
384
395
  const accessToken = jwt.sign(accessPayload, accessSecret, accessOptions)
@@ -61,30 +61,26 @@ export const pglCaslPlugin: GraphileConfig.Plugin = extendSchema(build => {
61
61
  Mutation: {
62
62
  plans: {
63
63
  async createAbility(_plan: any, fieldArgs: any) {
64
- const $input = fieldArgs.getRaw().input
65
- const $userId = $input.userId
66
- const $roles = $input.roles
64
+ const $userId: ExecutableStep = fieldArgs.getRaw().input.userId
65
+ const $roles: ExecutableStep = fieldArgs.getRaw().input.roles
67
66
 
68
- return sideEffect(
69
- [$userId as ExecutableStep, $roles as ExecutableStep],
70
- async ([userId, roles]: readonly [string, string[]]) => {
71
- // Make this async
72
- try {
73
- const ability = await createAbility({ id: userId, roles }) // Await here
74
- return {
75
- success: true,
76
- ability: ability.rules,
77
- message: 'Ability created successfully',
78
- }
79
- } catch (error) {
80
- return {
81
- success: false,
82
- ability: null,
83
- message: error instanceof Error ? error.message : 'Unknown error occurred',
84
- }
67
+ return sideEffect([$userId, $roles], async ([userId, roles]: readonly [string, string[]]) => {
68
+ // Make this async
69
+ try {
70
+ const ability = await createAbility({ id: userId, roles }) // Await here
71
+ return {
72
+ success: true,
73
+ ability: ability.rules,
74
+ message: 'Ability created successfully',
75
+ }
76
+ } catch (error) {
77
+ return {
78
+ success: false,
79
+ ability: null,
80
+ message: error instanceof Error ? error.message : 'Unknown error occurred',
85
81
  }
86
82
  }
87
- )
83
+ })
88
84
  },
89
85
  },
90
86
  },
@@ -1,7 +1,6 @@
1
1
  import type { Plugin } from 'graphql-yoga'
2
2
 
3
3
  import { createAbility } from './ability'
4
- import { createCaslMiddleware } from './graphql'
5
4
  import type { Context, MiddlewareOptions } from '../types'
6
5
 
7
6
  const getLoggedInUser = () => {
@@ -26,14 +25,12 @@ export const yogaCaslPlugin: Plugin<Context> = {
26
25
  * @returns Yoga plugin
27
26
  * @public
28
27
  */
29
- export const createYogaPlugin = (options: MiddlewareOptions = {}) => {
30
- const _middleware = createCaslMiddleware(options)
31
-
28
+ export const createYogaPlugin = (_options: MiddlewareOptions = {}) => {
32
29
  return {
33
30
  onExecute: async (_: any) => {
34
- // TODO: Implement Yoga plugin
35
- // This would integrate with GraphQL Yoga's plugin system
36
- console.log('Yoga plugin not yet implemented')
31
+ // TODO: Implement Yoga plugin via createCaslMiddleware(_options).
32
+ // This would integrate with GraphQL Yoga's plugin system.
33
+ console.warn('Yoga plugin not yet implemented')
37
34
  },
38
35
  }
39
36
  }
@@ -66,7 +66,7 @@ export interface FieldPermission {
66
66
  * GraphQL resolver function type
67
67
  * @public
68
68
  */
69
- export type ResolverFn = (root: any, args: any, context: Context, info: GraphQLResolveInfo) => Promise<any> | any
69
+ export type ResolverFn = (root: any, args: any, context: Context, info: GraphQLResolveInfo) => any
70
70
 
71
71
  /**
72
72
  * Middleware function that wraps a GraphQL resolver with authorization logic
@@ -78,7 +78,7 @@ export type MiddlewareFn = (
78
78
  args: any,
79
79
  context: Context,
80
80
  info: GraphQLResolveInfo
81
- ) => Promise<any> | any
81
+ ) => any
82
82
 
83
83
  /**
84
84
  * Plugin configuration options for framework integrations