@simtlix/simfinity-js 2.3.4 → 2.4.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 +394 -0
- package/package.json +2 -1
- package/src/auth/errors.js +44 -0
- package/src/auth/expressions.js +273 -0
- package/src/auth/index.js +391 -0
- package/src/auth/rules.js +274 -0
- package/src/index.js +1 -0
- package/src/plugins.js +10 -7
package/README.md
CHANGED
|
@@ -20,6 +20,13 @@ A powerful Node.js framework that automatically generates GraphQL schemas from y
|
|
|
20
20
|
- [Adding Middlewares](#adding-middlewares)
|
|
21
21
|
- [Middleware Parameters](#middleware-parameters)
|
|
22
22
|
- [Common Use Cases](#common-use-cases)
|
|
23
|
+
- [Authorization](#-authorization)
|
|
24
|
+
- [Quick Start](#quick-start-1)
|
|
25
|
+
- [Permission Schema](#permission-schema)
|
|
26
|
+
- [Rule Helpers](#rule-helpers)
|
|
27
|
+
- [Policy Expressions (JSON AST)](#policy-expressions-json-ast)
|
|
28
|
+
- [Integration with GraphQL Yoga / Envelop](#integration-with-graphql-yoga--envelop)
|
|
29
|
+
- [Legacy: Integration with graphql-middleware](#legacy-integration-with-graphql-middleware)
|
|
23
30
|
- [Relationships](#-relationships)
|
|
24
31
|
- [Defining Relationships](#defining-relationships)
|
|
25
32
|
- [Auto-Generated Resolve Methods](#auto-generated-resolve-methods)
|
|
@@ -69,6 +76,7 @@ A powerful Node.js framework that automatically generates GraphQL schemas from y
|
|
|
69
76
|
- **Lifecycle Hooks**: Controller methods for granular control over operations
|
|
70
77
|
- **Custom Validation**: Field-level and type-level custom validations
|
|
71
78
|
- **Relationship Management**: Support for embedded and referenced relationships
|
|
79
|
+
- **Authorization**: Production-grade GraphQL authorization with RBAC/ABAC, function-based rules, declarative policy expressions, and native Envelop/Yoga plugin support
|
|
72
80
|
|
|
73
81
|
## 📦 Installation
|
|
74
82
|
|
|
@@ -622,6 +630,392 @@ simfinity.use((params, next) => {
|
|
|
622
630
|
5. **Performance consideration**: Middlewares run on every operation, keep them lightweight
|
|
623
631
|
6. **Use context wisely**: Store request-specific data in the GraphQL context object
|
|
624
632
|
|
|
633
|
+
## 🔐 Authorization
|
|
634
|
+
|
|
635
|
+
Simfinity.js provides production-grade centralized GraphQL authorization supporting RBAC/ABAC, function-based rules, declarative policy expressions (JSON AST), wildcard permissions, and configurable default policies. It ships as a native Envelop plugin for GraphQL Yoga (recommended) and also supports the legacy graphql-middleware approach.
|
|
636
|
+
|
|
637
|
+
### Quick Start
|
|
638
|
+
|
|
639
|
+
```javascript
|
|
640
|
+
const { auth } = require('@simtlix/simfinity-js');
|
|
641
|
+
const { createYoga } = require('graphql-yoga');
|
|
642
|
+
|
|
643
|
+
const { createAuthPlugin, requireAuth, requireRole } = auth;
|
|
644
|
+
|
|
645
|
+
// Define your permission schema
|
|
646
|
+
const permissions = {
|
|
647
|
+
Query: {
|
|
648
|
+
users: requireAuth(),
|
|
649
|
+
adminDashboard: requireRole('ADMIN'),
|
|
650
|
+
},
|
|
651
|
+
Mutation: {
|
|
652
|
+
publishPost: requireRole('EDITOR'),
|
|
653
|
+
},
|
|
654
|
+
User: {
|
|
655
|
+
'*': requireAuth(), // Wildcard: all fields require auth
|
|
656
|
+
email: requireRole('ADMIN'), // Override: email requires ADMIN role
|
|
657
|
+
},
|
|
658
|
+
Post: {
|
|
659
|
+
'*': requireAuth(),
|
|
660
|
+
content: async (post, _args, ctx) => {
|
|
661
|
+
// Custom logic: allow if published OR if author
|
|
662
|
+
if (post.published) return true;
|
|
663
|
+
if (post.authorId === ctx.user?.id) return true;
|
|
664
|
+
return false;
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
// Create the Envelop auth plugin and pass it to your server
|
|
670
|
+
const authPlugin = createAuthPlugin(permissions, { defaultPolicy: 'DENY' });
|
|
671
|
+
const yoga = createYoga({ schema, plugins: [authPlugin] });
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### Permission Schema
|
|
675
|
+
|
|
676
|
+
The permission schema defines authorization rules per type and field:
|
|
677
|
+
|
|
678
|
+
```javascript
|
|
679
|
+
const permissions = {
|
|
680
|
+
// Operation types (Query, Mutation, Subscription)
|
|
681
|
+
Query: {
|
|
682
|
+
fieldName: ruleOrRules,
|
|
683
|
+
},
|
|
684
|
+
|
|
685
|
+
// Object types
|
|
686
|
+
TypeName: {
|
|
687
|
+
'*': wildcardRule, // Applies to all fields unless overridden
|
|
688
|
+
fieldName: specificRule, // Overrides wildcard for this field
|
|
689
|
+
},
|
|
690
|
+
};
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
**Resolution Order:**
|
|
694
|
+
1. Check exact field rule: `permissions[TypeName][fieldName]`
|
|
695
|
+
2. Fallback to wildcard: `permissions[TypeName]['*']`
|
|
696
|
+
3. Apply default policy (ALLOW or DENY)
|
|
697
|
+
|
|
698
|
+
**Rule Types:**
|
|
699
|
+
- **Function**: `(parent, args, ctx, info) => boolean | void | Promise<boolean | void>`
|
|
700
|
+
- **Array of functions**: All rules must pass (AND logic)
|
|
701
|
+
- **Policy expression**: JSON AST object (see below)
|
|
702
|
+
|
|
703
|
+
**Rule Semantics:**
|
|
704
|
+
- `return true` or `return void` → allow
|
|
705
|
+
- `return false` → deny
|
|
706
|
+
- `throw Error` → deny with error
|
|
707
|
+
|
|
708
|
+
### Rule Helpers
|
|
709
|
+
|
|
710
|
+
Simfinity.js provides reusable rule builders:
|
|
711
|
+
|
|
712
|
+
```javascript
|
|
713
|
+
const { auth } = require('@simtlix/simfinity-js');
|
|
714
|
+
|
|
715
|
+
const {
|
|
716
|
+
resolvePath, // Utility to resolve dotted paths in objects
|
|
717
|
+
requireAuth, // Requires ctx.user to exist
|
|
718
|
+
requireRole, // Requires specific role(s)
|
|
719
|
+
requirePermission, // Requires specific permission(s)
|
|
720
|
+
composeRules, // Combine rules (AND logic)
|
|
721
|
+
anyRule, // Combine rules (OR logic)
|
|
722
|
+
isOwner, // Check resource ownership
|
|
723
|
+
allow, // Always allow
|
|
724
|
+
deny, // Always deny
|
|
725
|
+
createRule, // Create custom rule
|
|
726
|
+
} = auth;
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
#### requireAuth(userPath?)
|
|
730
|
+
|
|
731
|
+
Requires the user to be authenticated. Supports custom user paths in context:
|
|
732
|
+
|
|
733
|
+
```javascript
|
|
734
|
+
const permissions = {
|
|
735
|
+
Query: {
|
|
736
|
+
// Default: checks ctx.user
|
|
737
|
+
me: requireAuth(),
|
|
738
|
+
|
|
739
|
+
// Custom path: checks ctx.auth.currentUser
|
|
740
|
+
profile: requireAuth('auth.currentUser'),
|
|
741
|
+
|
|
742
|
+
// Deep path: checks ctx.session.data.user
|
|
743
|
+
settings: requireAuth('session.data.user'),
|
|
744
|
+
},
|
|
745
|
+
};
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
#### requireRole(role, options?)
|
|
749
|
+
|
|
750
|
+
Requires the user to have a specific role. Supports custom paths:
|
|
751
|
+
|
|
752
|
+
```javascript
|
|
753
|
+
const permissions = {
|
|
754
|
+
Query: {
|
|
755
|
+
// Default: checks ctx.user.role
|
|
756
|
+
adminDashboard: requireRole('ADMIN'),
|
|
757
|
+
modTools: requireRole(['ADMIN', 'MODERATOR']), // Any of these roles
|
|
758
|
+
|
|
759
|
+
// Custom paths: checks ctx.auth.user.profile.role
|
|
760
|
+
superAdmin: requireRole('SUPER_ADMIN', {
|
|
761
|
+
userPath: 'auth.user',
|
|
762
|
+
rolePath: 'profile.role',
|
|
763
|
+
}),
|
|
764
|
+
},
|
|
765
|
+
};
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
#### requirePermission(permission, options?)
|
|
769
|
+
|
|
770
|
+
Requires the user to have specific permission(s). Supports custom paths:
|
|
771
|
+
|
|
772
|
+
```javascript
|
|
773
|
+
const permissions = {
|
|
774
|
+
Mutation: {
|
|
775
|
+
// Default: checks ctx.user.permissions
|
|
776
|
+
deletePost: requirePermission('posts:delete'),
|
|
777
|
+
manageUsers: requirePermission(['users:read', 'users:write']), // All required
|
|
778
|
+
|
|
779
|
+
// Custom paths: checks ctx.session.user.access.grants
|
|
780
|
+
admin: requirePermission('admin:all', {
|
|
781
|
+
userPath: 'session.user',
|
|
782
|
+
permissionsPath: 'access.grants',
|
|
783
|
+
}),
|
|
784
|
+
},
|
|
785
|
+
};
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
#### composeRules(...rules)
|
|
789
|
+
|
|
790
|
+
Combines multiple rules with AND logic (all must pass):
|
|
791
|
+
|
|
792
|
+
```javascript
|
|
793
|
+
const permissions = {
|
|
794
|
+
Mutation: {
|
|
795
|
+
updatePost: composeRules(
|
|
796
|
+
requireAuth(),
|
|
797
|
+
requireRole('EDITOR'),
|
|
798
|
+
async (post, args, ctx) => post.authorId === ctx.user.id,
|
|
799
|
+
),
|
|
800
|
+
},
|
|
801
|
+
};
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
#### anyRule(...rules)
|
|
805
|
+
|
|
806
|
+
Combines multiple rules with OR logic (any must pass):
|
|
807
|
+
|
|
808
|
+
```javascript
|
|
809
|
+
const permissions = {
|
|
810
|
+
Post: {
|
|
811
|
+
content: anyRule(
|
|
812
|
+
requireRole('ADMIN'),
|
|
813
|
+
async (post, args, ctx) => post.authorId === ctx.user.id,
|
|
814
|
+
),
|
|
815
|
+
},
|
|
816
|
+
};
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
#### isOwner(ownerField, userIdField)
|
|
820
|
+
|
|
821
|
+
Checks if the authenticated user owns the resource:
|
|
822
|
+
|
|
823
|
+
```javascript
|
|
824
|
+
const permissions = {
|
|
825
|
+
Post: {
|
|
826
|
+
'*': composeRules(
|
|
827
|
+
requireAuth(),
|
|
828
|
+
isOwner('authorId', 'id'), // Compares post.authorId with ctx.user.id
|
|
829
|
+
),
|
|
830
|
+
},
|
|
831
|
+
};
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
### Policy Expressions (JSON AST)
|
|
835
|
+
|
|
836
|
+
For declarative rules, use JSON AST policy expressions:
|
|
837
|
+
|
|
838
|
+
```javascript
|
|
839
|
+
const permissions = {
|
|
840
|
+
Post: {
|
|
841
|
+
content: {
|
|
842
|
+
anyOf: [
|
|
843
|
+
{ eq: [{ ref: 'parent.published' }, true] },
|
|
844
|
+
{ eq: [{ ref: 'parent.authorId' }, { ref: 'ctx.user.id' }] },
|
|
845
|
+
],
|
|
846
|
+
},
|
|
847
|
+
},
|
|
848
|
+
};
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
**Supported Operators:**
|
|
852
|
+
|
|
853
|
+
| Operator | Description | Example |
|
|
854
|
+
|----------|-------------|---------|
|
|
855
|
+
| `eq` | Equals | `{ eq: [{ ref: 'parent.status' }, 'active'] }` |
|
|
856
|
+
| `in` | Value in array | `{ in: [{ ref: 'ctx.user.role' }, ['ADMIN', 'MOD']] }` |
|
|
857
|
+
| `allOf` | All must be true (AND) | `{ allOf: [expr1, expr2] }` |
|
|
858
|
+
| `anyOf` | Any must be true (OR) | `{ anyOf: [expr1, expr2] }` |
|
|
859
|
+
| `not` | Negation | `{ not: { eq: [{ ref: 'parent.deleted' }, true] } }` |
|
|
860
|
+
|
|
861
|
+
**References:**
|
|
862
|
+
|
|
863
|
+
Use `{ ref: 'path' }` to reference values:
|
|
864
|
+
- `parent.*` - Parent resolver result (the object being resolved)
|
|
865
|
+
- `args.*` - GraphQL arguments
|
|
866
|
+
- `ctx.*` - GraphQL context
|
|
867
|
+
|
|
868
|
+
**Security:**
|
|
869
|
+
- Only `parent`, `args`, and `ctx` roots are allowed
|
|
870
|
+
- Unknown operators fail closed (deny)
|
|
871
|
+
- No `eval()` or `Function()` - pure object traversal
|
|
872
|
+
|
|
873
|
+
### Integration with GraphQL Yoga / Envelop
|
|
874
|
+
|
|
875
|
+
The recommended way to use the auth system is via the Envelop plugin, which works natively with GraphQL Yoga and any Envelop-based server. The plugin wraps resolvers in-place without rebuilding the schema, avoiding compatibility issues.
|
|
876
|
+
|
|
877
|
+
```javascript
|
|
878
|
+
const { createYoga } = require('graphql-yoga');
|
|
879
|
+
const { createServer } = require('http');
|
|
880
|
+
const simfinity = require('@simtlix/simfinity-js');
|
|
881
|
+
|
|
882
|
+
const { auth } = simfinity;
|
|
883
|
+
const { createAuthPlugin, requireAuth, requireRole, requirePermission } = auth;
|
|
884
|
+
|
|
885
|
+
// Define your types and connect them
|
|
886
|
+
simfinity.connect(null, UserType, 'user', 'users');
|
|
887
|
+
simfinity.connect(null, PostType, 'post', 'posts');
|
|
888
|
+
|
|
889
|
+
// Create base schema
|
|
890
|
+
const schema = simfinity.createSchema();
|
|
891
|
+
|
|
892
|
+
// Define permissions
|
|
893
|
+
const permissions = {
|
|
894
|
+
Query: {
|
|
895
|
+
users: requireAuth(),
|
|
896
|
+
user: requireAuth(),
|
|
897
|
+
posts: requireAuth(),
|
|
898
|
+
post: requireAuth(),
|
|
899
|
+
},
|
|
900
|
+
Mutation: {
|
|
901
|
+
adduser: requireRole('ADMIN'),
|
|
902
|
+
updateuser: requireRole('ADMIN'),
|
|
903
|
+
deleteuser: requireRole('ADMIN'),
|
|
904
|
+
addpost: requireAuth(),
|
|
905
|
+
updatepost: composeRules(requireAuth(), isOwner('authorId')),
|
|
906
|
+
deletepost: requireRole('ADMIN'),
|
|
907
|
+
},
|
|
908
|
+
User: {
|
|
909
|
+
'*': requireAuth(),
|
|
910
|
+
email: requireRole('ADMIN'),
|
|
911
|
+
password: deny('Password field is not accessible'),
|
|
912
|
+
},
|
|
913
|
+
Post: {
|
|
914
|
+
'*': requireAuth(),
|
|
915
|
+
content: {
|
|
916
|
+
anyOf: [
|
|
917
|
+
{ eq: [{ ref: 'parent.published' }, true] },
|
|
918
|
+
{ eq: [{ ref: 'parent.authorId' }, { ref: 'ctx.user.id' }] },
|
|
919
|
+
],
|
|
920
|
+
},
|
|
921
|
+
},
|
|
922
|
+
};
|
|
923
|
+
|
|
924
|
+
// Create auth plugin
|
|
925
|
+
const authPlugin = createAuthPlugin(permissions, {
|
|
926
|
+
defaultPolicy: 'DENY',
|
|
927
|
+
debug: false,
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
// Setup Yoga with the auth plugin
|
|
931
|
+
const yoga = createYoga({
|
|
932
|
+
schema,
|
|
933
|
+
plugins: [authPlugin],
|
|
934
|
+
context: (req) => ({
|
|
935
|
+
user: req.user, // Set by your authentication layer
|
|
936
|
+
}),
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
const server = createServer(yoga);
|
|
940
|
+
server.listen(4000);
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
### Legacy: Integration with graphql-middleware
|
|
944
|
+
|
|
945
|
+
> **Deprecated:** `applyMiddleware` from `graphql-middleware` rebuilds the schema via `mapSchema`,
|
|
946
|
+
> which can cause `"Schema must contain uniquely named types"` errors with Simfinity schemas.
|
|
947
|
+
> Use `createAuthPlugin` with GraphQL Yoga / Envelop instead.
|
|
948
|
+
|
|
949
|
+
```javascript
|
|
950
|
+
const { applyMiddleware } = require('graphql-middleware');
|
|
951
|
+
const simfinity = require('@simtlix/simfinity-js');
|
|
952
|
+
|
|
953
|
+
const { auth } = simfinity;
|
|
954
|
+
const { createAuthMiddleware, requireAuth, requireRole } = auth;
|
|
955
|
+
|
|
956
|
+
const baseSchema = simfinity.createSchema();
|
|
957
|
+
|
|
958
|
+
const authMiddleware = createAuthMiddleware(permissions, {
|
|
959
|
+
defaultPolicy: 'DENY',
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
const schema = applyMiddleware(baseSchema, authMiddleware);
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
### Plugin / Middleware Options
|
|
966
|
+
|
|
967
|
+
```javascript
|
|
968
|
+
const plugin = createAuthPlugin(permissions, {
|
|
969
|
+
defaultPolicy: 'DENY', // 'ALLOW' or 'DENY' (default: 'DENY')
|
|
970
|
+
debug: false, // Enable debug logging
|
|
971
|
+
});
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
| Option | Type | Default | Description |
|
|
975
|
+
|--------|------|---------|-------------|
|
|
976
|
+
| `defaultPolicy` | `'ALLOW' \| 'DENY'` | `'DENY'` | Policy when no rule matches |
|
|
977
|
+
| `debug` | `boolean` | `false` | Log authorization decisions |
|
|
978
|
+
|
|
979
|
+
### Error Handling
|
|
980
|
+
|
|
981
|
+
The auth middleware uses Simfinity error classes:
|
|
982
|
+
|
|
983
|
+
```javascript
|
|
984
|
+
const { auth } = require('@simtlix/simfinity-js');
|
|
985
|
+
|
|
986
|
+
const { UnauthenticatedError, ForbiddenError } = auth;
|
|
987
|
+
|
|
988
|
+
// UnauthenticatedError: code 'UNAUTHENTICATED', status 401
|
|
989
|
+
// ForbiddenError: code 'FORBIDDEN', status 403
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
Custom error handling in rules:
|
|
993
|
+
|
|
994
|
+
```javascript
|
|
995
|
+
const permissions = {
|
|
996
|
+
Mutation: {
|
|
997
|
+
deleteAccount: async (parent, args, ctx) => {
|
|
998
|
+
if (!ctx.user) {
|
|
999
|
+
throw new auth.UnauthenticatedError('Please log in');
|
|
1000
|
+
}
|
|
1001
|
+
if (ctx.user.role !== 'ADMIN' && ctx.user.id !== args.id) {
|
|
1002
|
+
throw new auth.ForbiddenError('Cannot delete other users');
|
|
1003
|
+
}
|
|
1004
|
+
return true;
|
|
1005
|
+
},
|
|
1006
|
+
},
|
|
1007
|
+
};
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
### Best Practices
|
|
1011
|
+
|
|
1012
|
+
1. **Default to DENY**: Use `defaultPolicy: 'DENY'` for security
|
|
1013
|
+
2. **Use wildcards wisely**: `'*'` rules provide baseline security per type
|
|
1014
|
+
3. **Prefer helper rules**: Use `requireAuth()`, `requireRole()` over custom functions
|
|
1015
|
+
4. **Fail closed**: Custom rules should deny on unexpected conditions
|
|
1016
|
+
5. **Keep rules simple**: Complex logic belongs in controllers, not auth rules
|
|
1017
|
+
6. **Test thoroughly**: Auth rules are critical - test all scenarios
|
|
1018
|
+
|
|
625
1019
|
## 🔗 Relationships
|
|
626
1020
|
|
|
627
1021
|
### Defining Relationships
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simtlix/simfinity-js",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
37
|
"graphql": "^16.11.0",
|
|
38
|
+
"graphql-middleware": "^6.1.35",
|
|
38
39
|
"mongoose": "^8.16.2"
|
|
39
40
|
}
|
|
40
41
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import SimfinityError from '../errors/simfinity.error.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Authentication error - thrown when user is not authenticated
|
|
5
|
+
* Uses code: UNAUTHENTICATED, status: 401
|
|
6
|
+
*/
|
|
7
|
+
export class UnauthenticatedError extends SimfinityError {
|
|
8
|
+
constructor(message = 'Authentication required') {
|
|
9
|
+
super(message, 'UNAUTHENTICATED', 401);
|
|
10
|
+
this.name = 'UnauthenticatedError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Authorization error - thrown when user lacks permission
|
|
16
|
+
* Uses code: FORBIDDEN, status: 403
|
|
17
|
+
*/
|
|
18
|
+
export class ForbiddenError extends SimfinityError {
|
|
19
|
+
constructor(message = 'Access denied') {
|
|
20
|
+
super(message, 'FORBIDDEN', 403);
|
|
21
|
+
this.name = 'ForbiddenError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generic auth error factory for custom auth failures
|
|
27
|
+
* @param {string} message - Error message
|
|
28
|
+
* @param {string} code - Error code (UNAUTHENTICATED or FORBIDDEN)
|
|
29
|
+
* @returns {SimfinityError}
|
|
30
|
+
*/
|
|
31
|
+
export const createAuthError = (message, code = 'FORBIDDEN') => {
|
|
32
|
+
const status = code === 'UNAUTHENTICATED' ? 401 : 403;
|
|
33
|
+
return new SimfinityError(message, code, status);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Export all errors as an object for convenience
|
|
37
|
+
const errors = {
|
|
38
|
+
UnauthenticatedError,
|
|
39
|
+
ForbiddenError,
|
|
40
|
+
createAuthError,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default errors;
|
|
44
|
+
|