better-auth-studio 1.0.79-beta.35 → 1.0.79-beta.37
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/dist/public/assets/{main-R1O9iElM.css → main-BgI41EAt.css} +1 -1
- package/dist/public/assets/main-DEnyGsn2.js +1155 -0
- package/dist/public/index.html +2 -2
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +429 -22
- package/dist/routes.js.map +1 -1
- package/package.json +1 -4
- package/public/assets/{main-R1O9iElM.css → main-BgI41EAt.css} +1 -1
- package/public/assets/main-DEnyGsn2.js +1155 -0
- package/public/index.html +2 -2
- package/scripts/postinstall.js +0 -2
- package/dist/public/assets/main-DAv-RHMo.js +0 -1155
- package/public/assets/main-DAv-RHMo.js +0 -1155
package/dist/public/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/png" href="/logo.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Better Auth Studio</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/main-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/main-
|
|
8
|
+
<script type="module" crossorigin src="/assets/main-DEnyGsn2.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/main-BgI41EAt.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/dist/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAeA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAU9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AA0GnE,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAqLhG;AAeD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE,GAAG,EACtB,oBAAoB,CAAC,EAAE,GAAG,EAC1B,YAAY,CAAC,EAAE,kBAAkB,EACjC,YAAY,CAAC,EAAE,GAAG,GACjB,MAAM,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAeA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAU9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AA0GnE,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAqLhG;AAeD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE,GAAG,EACtB,oBAAoB,CAAC,EAAE,GAAG,EAC1B,YAAY,CAAC,EAAE,kBAAkB,EACjC,YAAY,CAAC,EAAE,GAAG,GACjB,MAAM,CAy2MR;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,EAAE,GAAG,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC,CA+FD"}
|
package/dist/routes.js
CHANGED
|
@@ -320,6 +320,10 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
|
|
|
320
320
|
// For self-hosted studio, wrap the preloaded adapter to match expected interface
|
|
321
321
|
return {
|
|
322
322
|
...preloadedAdapter,
|
|
323
|
+
findUnique: preloadedAdapter.findUnique?.bind(preloadedAdapter),
|
|
324
|
+
findOne: preloadedAdapter.findOne?.bind(preloadedAdapter) ||
|
|
325
|
+
preloadedAdapter.findUnique?.bind(preloadedAdapter),
|
|
326
|
+
findFirst: preloadedAdapter.findFirst?.bind(preloadedAdapter),
|
|
323
327
|
findMany: preloadedAdapter.findMany?.bind(preloadedAdapter),
|
|
324
328
|
create: preloadedAdapter.create?.bind(preloadedAdapter),
|
|
325
329
|
update: preloadedAdapter.update?.bind(preloadedAdapter),
|
|
@@ -2717,6 +2721,26 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
|
|
|
2717
2721
|
if (!adapter.update) {
|
|
2718
2722
|
return res.status(500).json({ error: 'Adapter update method not available' });
|
|
2719
2723
|
}
|
|
2724
|
+
let invitation = null;
|
|
2725
|
+
try {
|
|
2726
|
+
invitation = await adapter.findOne({
|
|
2727
|
+
model: 'invitation',
|
|
2728
|
+
where: [{ field: 'id', value: id }],
|
|
2729
|
+
});
|
|
2730
|
+
}
|
|
2731
|
+
catch (_findError) {
|
|
2732
|
+
if (typeof adapter.findMany === 'function') {
|
|
2733
|
+
const invitations = await adapter.findMany({
|
|
2734
|
+
model: 'invitation',
|
|
2735
|
+
where: [{ field: 'id', value: id }],
|
|
2736
|
+
limit: 1,
|
|
2737
|
+
});
|
|
2738
|
+
invitation = invitations && invitations.length > 0 ? invitations[0] : null;
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
if (!invitation) {
|
|
2742
|
+
return res.status(404).json({ error: 'Invitation not found' });
|
|
2743
|
+
}
|
|
2720
2744
|
await adapter.update({
|
|
2721
2745
|
model: 'invitation',
|
|
2722
2746
|
where: [{ field: 'id', value: id }],
|
|
@@ -2727,8 +2751,245 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
|
|
|
2727
2751
|
});
|
|
2728
2752
|
res.json({ success: true });
|
|
2729
2753
|
}
|
|
2754
|
+
catch (error) {
|
|
2755
|
+
console.error('Error resending invitation:', error);
|
|
2756
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to resend invitation';
|
|
2757
|
+
res.status(500).json({
|
|
2758
|
+
error: 'Failed to resend invitation',
|
|
2759
|
+
details: isSelfHosted ? errorMessage : undefined,
|
|
2760
|
+
});
|
|
2761
|
+
}
|
|
2762
|
+
});
|
|
2763
|
+
router.get('/api/users/:userId/invitations', async (req, res) => {
|
|
2764
|
+
try {
|
|
2765
|
+
const { userId } = req.params;
|
|
2766
|
+
const adapter = await getAuthAdapterWithConfig();
|
|
2767
|
+
if (!adapter) {
|
|
2768
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
2769
|
+
}
|
|
2770
|
+
let user;
|
|
2771
|
+
try {
|
|
2772
|
+
user = await adapter.findOne({
|
|
2773
|
+
model: 'user',
|
|
2774
|
+
where: [{ field: 'id', value: userId }],
|
|
2775
|
+
});
|
|
2776
|
+
}
|
|
2777
|
+
catch (error) {
|
|
2778
|
+
console.error('Error fetching user:', error);
|
|
2779
|
+
return res.status(500).json({
|
|
2780
|
+
error: 'Failed to fetch user',
|
|
2781
|
+
details: error?.message || String(error),
|
|
2782
|
+
});
|
|
2783
|
+
}
|
|
2784
|
+
if (!user || !user.email) {
|
|
2785
|
+
return res.json({ success: true, invitations: [] });
|
|
2786
|
+
}
|
|
2787
|
+
if (typeof adapter.findMany !== 'function') {
|
|
2788
|
+
return res.json({ success: true, invitations: [] });
|
|
2789
|
+
}
|
|
2790
|
+
let invitations;
|
|
2791
|
+
try {
|
|
2792
|
+
invitations = await adapter.findMany({
|
|
2793
|
+
model: 'invitation',
|
|
2794
|
+
where: [{ field: 'email', value: user.email }],
|
|
2795
|
+
});
|
|
2796
|
+
}
|
|
2797
|
+
catch (error) {
|
|
2798
|
+
console.error('Error fetching invitations:', error);
|
|
2799
|
+
return res.json({ success: true, invitations: [] });
|
|
2800
|
+
}
|
|
2801
|
+
if (!invitations || invitations.length === 0) {
|
|
2802
|
+
return res.json({ success: true, invitations: [] });
|
|
2803
|
+
}
|
|
2804
|
+
const transformedInvitations = await Promise.all(invitations.map(async (invitation) => {
|
|
2805
|
+
let organizationName = 'Unknown';
|
|
2806
|
+
let teamName;
|
|
2807
|
+
try {
|
|
2808
|
+
if (invitation.organizationId &&
|
|
2809
|
+
(typeof adapter.findOne === 'function' || typeof adapter.findUnique === 'function')) {
|
|
2810
|
+
try {
|
|
2811
|
+
const findMethod = adapter.findOne || adapter.findUnique;
|
|
2812
|
+
const org = await findMethod({
|
|
2813
|
+
model: 'organization',
|
|
2814
|
+
where: [{ field: 'id', value: invitation.organizationId }],
|
|
2815
|
+
});
|
|
2816
|
+
organizationName = org?.name || 'Unknown';
|
|
2817
|
+
}
|
|
2818
|
+
catch (_orgError) {
|
|
2819
|
+
// Ignore org fetch errors
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
if (invitation.teamId &&
|
|
2823
|
+
(typeof adapter.findOne === 'function' || typeof adapter.findUnique === 'function')) {
|
|
2824
|
+
try {
|
|
2825
|
+
const findMethod = adapter.findOne || adapter.findUnique;
|
|
2826
|
+
const team = await findMethod({
|
|
2827
|
+
model: 'team',
|
|
2828
|
+
where: [{ field: 'id', value: invitation.teamId }],
|
|
2829
|
+
});
|
|
2830
|
+
teamName = team?.name;
|
|
2831
|
+
}
|
|
2832
|
+
catch (_teamError) { }
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
catch (_error) { }
|
|
2836
|
+
return {
|
|
2837
|
+
id: invitation.id,
|
|
2838
|
+
email: invitation.email,
|
|
2839
|
+
role: invitation.role || 'member',
|
|
2840
|
+
status: invitation.status || 'pending',
|
|
2841
|
+
organizationId: invitation.organizationId,
|
|
2842
|
+
organizationName,
|
|
2843
|
+
teamId: invitation.teamId,
|
|
2844
|
+
teamName,
|
|
2845
|
+
inviterId: invitation.inviterId,
|
|
2846
|
+
expiresAt: invitation.expiresAt,
|
|
2847
|
+
createdAt: invitation.createdAt,
|
|
2848
|
+
};
|
|
2849
|
+
}));
|
|
2850
|
+
res.json({ success: true, invitations: transformedInvitations });
|
|
2851
|
+
}
|
|
2852
|
+
catch (error) {
|
|
2853
|
+
console.error('Error in /api/users/:userId/invitations:', error);
|
|
2854
|
+
res.status(500).json({
|
|
2855
|
+
error: 'Failed to fetch invitations',
|
|
2856
|
+
details: error?.message || String(error),
|
|
2857
|
+
});
|
|
2858
|
+
}
|
|
2859
|
+
});
|
|
2860
|
+
router.post('/api/invitations/:id/accept', async (req, res) => {
|
|
2861
|
+
try {
|
|
2862
|
+
const { id } = req.params;
|
|
2863
|
+
const { userId } = req.body;
|
|
2864
|
+
const adapter = await getAuthAdapterWithConfig();
|
|
2865
|
+
if (!adapter) {
|
|
2866
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
2867
|
+
}
|
|
2868
|
+
if (!userId) {
|
|
2869
|
+
return res.status(400).json({ error: 'User ID is required' });
|
|
2870
|
+
}
|
|
2871
|
+
const invitation = await adapter.findOne({
|
|
2872
|
+
model: 'invitation',
|
|
2873
|
+
where: [{ field: 'id', value: id }],
|
|
2874
|
+
});
|
|
2875
|
+
if (!invitation) {
|
|
2876
|
+
return res.status(404).json({ error: 'Invitation not found' });
|
|
2877
|
+
}
|
|
2878
|
+
if (invitation.status !== 'pending') {
|
|
2879
|
+
return res.status(400).json({ error: 'Invitation is not pending' });
|
|
2880
|
+
}
|
|
2881
|
+
await adapter.update({
|
|
2882
|
+
model: 'invitation',
|
|
2883
|
+
where: [{ field: 'id', value: id }],
|
|
2884
|
+
update: {
|
|
2885
|
+
status: 'accepted',
|
|
2886
|
+
updatedAt: new Date().toISOString(),
|
|
2887
|
+
},
|
|
2888
|
+
});
|
|
2889
|
+
if (invitation.organizationId) {
|
|
2890
|
+
try {
|
|
2891
|
+
// Check if member already exists
|
|
2892
|
+
let existingMember = null;
|
|
2893
|
+
if (typeof adapter.findFirst === 'function') {
|
|
2894
|
+
existingMember = await adapter.findFirst({
|
|
2895
|
+
model: 'member',
|
|
2896
|
+
where: [
|
|
2897
|
+
{ field: 'organizationId', value: invitation.organizationId },
|
|
2898
|
+
{ field: 'userId', value: userId },
|
|
2899
|
+
],
|
|
2900
|
+
});
|
|
2901
|
+
}
|
|
2902
|
+
else if (typeof adapter.findMany === 'function') {
|
|
2903
|
+
const members = await adapter.findMany({
|
|
2904
|
+
model: 'member',
|
|
2905
|
+
where: [
|
|
2906
|
+
{ field: 'organizationId', value: invitation.organizationId },
|
|
2907
|
+
{ field: 'userId', value: userId },
|
|
2908
|
+
],
|
|
2909
|
+
});
|
|
2910
|
+
existingMember = members && members.length > 0 ? members[0] : null;
|
|
2911
|
+
}
|
|
2912
|
+
if (!existingMember) {
|
|
2913
|
+
await adapter.create({
|
|
2914
|
+
model: 'member',
|
|
2915
|
+
data: {
|
|
2916
|
+
organizationId: invitation.organizationId,
|
|
2917
|
+
userId: userId,
|
|
2918
|
+
role: invitation.role || 'member',
|
|
2919
|
+
createdAt: new Date().toISOString(),
|
|
2920
|
+
},
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
catch (error) {
|
|
2925
|
+
console.error('Error creating member:', error);
|
|
2926
|
+
// Ignore errors creating membership
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
if (invitation.teamId) {
|
|
2930
|
+
try {
|
|
2931
|
+
let existingMember = null;
|
|
2932
|
+
if (typeof adapter.findFirst === 'function') {
|
|
2933
|
+
existingMember = await adapter.findFirst({
|
|
2934
|
+
model: 'teamMember',
|
|
2935
|
+
where: [
|
|
2936
|
+
{ field: 'teamId', value: invitation.teamId },
|
|
2937
|
+
{ field: 'userId', value: userId },
|
|
2938
|
+
],
|
|
2939
|
+
});
|
|
2940
|
+
}
|
|
2941
|
+
else if (typeof adapter.findMany === 'function') {
|
|
2942
|
+
const members = await adapter.findMany({
|
|
2943
|
+
model: 'teamMember',
|
|
2944
|
+
where: [
|
|
2945
|
+
{ field: 'teamId', value: invitation.teamId },
|
|
2946
|
+
{ field: 'userId', value: userId },
|
|
2947
|
+
],
|
|
2948
|
+
});
|
|
2949
|
+
existingMember = members && members.length > 0 ? members[0] : null;
|
|
2950
|
+
}
|
|
2951
|
+
if (!existingMember) {
|
|
2952
|
+
await adapter.create({
|
|
2953
|
+
model: 'teamMember',
|
|
2954
|
+
data: {
|
|
2955
|
+
teamId: invitation.teamId,
|
|
2956
|
+
userId: userId,
|
|
2957
|
+
createdAt: new Date().toISOString(),
|
|
2958
|
+
},
|
|
2959
|
+
});
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
catch (error) {
|
|
2963
|
+
console.error('Error creating team member:', error);
|
|
2964
|
+
// Ignore errors creating team membership
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
res.json({ success: true });
|
|
2968
|
+
}
|
|
2969
|
+
catch (error) {
|
|
2970
|
+
console.error('Failed to accept invitation:', error);
|
|
2971
|
+
res.status(500).json({ error: 'Failed to accept invitation' });
|
|
2972
|
+
}
|
|
2973
|
+
});
|
|
2974
|
+
router.post('/api/invitations/:id/reject', async (req, res) => {
|
|
2975
|
+
try {
|
|
2976
|
+
const { id } = req.params;
|
|
2977
|
+
const adapter = await getAuthAdapterWithConfig();
|
|
2978
|
+
if (!adapter) {
|
|
2979
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
2980
|
+
}
|
|
2981
|
+
await adapter.update({
|
|
2982
|
+
model: 'invitation',
|
|
2983
|
+
where: [{ field: 'id', value: id }],
|
|
2984
|
+
update: {
|
|
2985
|
+
status: 'rejected',
|
|
2986
|
+
updatedAt: new Date().toISOString(),
|
|
2987
|
+
},
|
|
2988
|
+
});
|
|
2989
|
+
res.json({ success: true });
|
|
2990
|
+
}
|
|
2730
2991
|
catch (_error) {
|
|
2731
|
-
res.status(500).json({ error: 'Failed to
|
|
2992
|
+
res.status(500).json({ error: 'Failed to reject invitation' });
|
|
2732
2993
|
}
|
|
2733
2994
|
});
|
|
2734
2995
|
router.delete('/api/invitations/:id', async (req, res) => {
|
|
@@ -2758,7 +3019,13 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
|
|
|
2758
3019
|
router.post('/api/organizations/:orgId/invitations', async (req, res) => {
|
|
2759
3020
|
try {
|
|
2760
3021
|
const { orgId } = req.params;
|
|
2761
|
-
const { email, role = 'member', inviterId } = req.body;
|
|
3022
|
+
const { email, role = 'member', inviterId, teamId } = req.body;
|
|
3023
|
+
if (!email || typeof email !== 'string') {
|
|
3024
|
+
return res.status(400).json({ error: 'Email is required' });
|
|
3025
|
+
}
|
|
3026
|
+
if (!orgId) {
|
|
3027
|
+
return res.status(400).json({ error: 'Organization ID is required' });
|
|
3028
|
+
}
|
|
2762
3029
|
if (!inviterId) {
|
|
2763
3030
|
return res.status(400).json({ error: 'Inviter ID is required' });
|
|
2764
3031
|
}
|
|
@@ -2766,8 +3033,66 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
|
|
|
2766
3033
|
if (!adapter) {
|
|
2767
3034
|
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
2768
3035
|
}
|
|
3036
|
+
if (!adapter.create) {
|
|
3037
|
+
return res.status(500).json({ error: 'Adapter create method not available' });
|
|
3038
|
+
}
|
|
3039
|
+
try {
|
|
3040
|
+
const organization = await adapter.findOne({
|
|
3041
|
+
model: 'organization',
|
|
3042
|
+
where: [{ field: 'id', value: orgId }],
|
|
3043
|
+
});
|
|
3044
|
+
if (!organization) {
|
|
3045
|
+
return res.status(404).json({ error: 'Organization not found' });
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
catch (orgError) {
|
|
3049
|
+
try {
|
|
3050
|
+
if (typeof adapter.findMany === 'function') {
|
|
3051
|
+
const orgs = await adapter.findMany({
|
|
3052
|
+
model: 'organization',
|
|
3053
|
+
where: [{ field: 'id', value: orgId }],
|
|
3054
|
+
limit: 1,
|
|
3055
|
+
});
|
|
3056
|
+
if (!orgs || orgs.length === 0) {
|
|
3057
|
+
return res.status(404).json({ error: 'Organization not found' });
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
catch (_fallbackError) { }
|
|
3062
|
+
}
|
|
3063
|
+
try {
|
|
3064
|
+
let existingInvitation = null;
|
|
3065
|
+
if (typeof adapter.findFirst === 'function') {
|
|
3066
|
+
existingInvitation = await adapter.findFirst({
|
|
3067
|
+
model: 'invitation',
|
|
3068
|
+
where: [
|
|
3069
|
+
{ field: 'email', value: email.toLowerCase() },
|
|
3070
|
+
{ field: 'organizationId', value: orgId },
|
|
3071
|
+
{ field: 'status', value: 'pending' },
|
|
3072
|
+
],
|
|
3073
|
+
});
|
|
3074
|
+
}
|
|
3075
|
+
else if (typeof adapter.findMany === 'function') {
|
|
3076
|
+
const invitations = await adapter.findMany({
|
|
3077
|
+
model: 'invitation',
|
|
3078
|
+
where: [
|
|
3079
|
+
{ field: 'email', value: email.toLowerCase() },
|
|
3080
|
+
{ field: 'organizationId', value: orgId },
|
|
3081
|
+
{ field: 'status', value: 'pending' },
|
|
3082
|
+
],
|
|
3083
|
+
limit: 1,
|
|
3084
|
+
});
|
|
3085
|
+
existingInvitation = invitations && invitations.length > 0 ? invitations[0] : null;
|
|
3086
|
+
}
|
|
3087
|
+
if (existingInvitation) {
|
|
3088
|
+
return res
|
|
3089
|
+
.status(400)
|
|
3090
|
+
.json({ error: 'A pending invitation already exists for this email' });
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
catch (_duplicateCheckError) { }
|
|
2769
3094
|
const invitationData = {
|
|
2770
|
-
email,
|
|
3095
|
+
email: email.toLowerCase(),
|
|
2771
3096
|
role,
|
|
2772
3097
|
organizationId: orgId,
|
|
2773
3098
|
status: 'pending',
|
|
@@ -2775,29 +3100,25 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
|
|
|
2775
3100
|
createdAt: new Date(),
|
|
2776
3101
|
inviterId: inviterId,
|
|
2777
3102
|
};
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
...invitationData,
|
|
2781
|
-
};
|
|
2782
|
-
if (!adapter.create) {
|
|
2783
|
-
return res.status(500).json({ error: 'Adapter create method not available' });
|
|
3103
|
+
if (teamId) {
|
|
3104
|
+
invitationData.teamId = teamId;
|
|
2784
3105
|
}
|
|
2785
|
-
await adapter.create({
|
|
3106
|
+
const createdInvitation = await adapter.create({
|
|
2786
3107
|
model: 'invitation',
|
|
2787
|
-
data:
|
|
2788
|
-
organizationId: invitationData.organizationId,
|
|
2789
|
-
email: invitationData.email,
|
|
2790
|
-
role: invitationData.role,
|
|
2791
|
-
status: invitationData.status,
|
|
2792
|
-
inviterId: invitationData.inviterId,
|
|
2793
|
-
expiresAt: invitationData.expiresAt,
|
|
2794
|
-
createdAt: invitationData.createdAt,
|
|
2795
|
-
},
|
|
3108
|
+
data: invitationData,
|
|
2796
3109
|
});
|
|
2797
|
-
|
|
3110
|
+
if (!createdInvitation) {
|
|
3111
|
+
return res.status(500).json({ error: 'Failed to create invitation' });
|
|
3112
|
+
}
|
|
3113
|
+
res.json({ success: true, invitation: createdInvitation });
|
|
2798
3114
|
}
|
|
2799
|
-
catch (
|
|
2800
|
-
|
|
3115
|
+
catch (error) {
|
|
3116
|
+
console.error('Error creating invitation:', error);
|
|
3117
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to create invitation';
|
|
3118
|
+
res.status(500).json({
|
|
3119
|
+
error: 'Failed to create invitation',
|
|
3120
|
+
details: isSelfHosted ? errorMessage : undefined,
|
|
3121
|
+
});
|
|
2801
3122
|
}
|
|
2802
3123
|
});
|
|
2803
3124
|
router.get('/api/organizations/:orgId/teams', async (req, res) => {
|
|
@@ -3661,6 +3982,92 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
|
|
|
3661
3982
|
res.status(500).json({ success: false, error: 'Failed to fetch OAuth providers' });
|
|
3662
3983
|
}
|
|
3663
3984
|
});
|
|
3985
|
+
router.get('/api/tools/oauth/credentials', async (req, res) => {
|
|
3986
|
+
try {
|
|
3987
|
+
const { provider, origin } = req.query;
|
|
3988
|
+
if (!provider || typeof provider !== 'string') {
|
|
3989
|
+
return res.status(400).json({
|
|
3990
|
+
success: false,
|
|
3991
|
+
error: 'Provider is required',
|
|
3992
|
+
});
|
|
3993
|
+
}
|
|
3994
|
+
if (!origin || typeof origin !== 'string') {
|
|
3995
|
+
return res.status(400).json({
|
|
3996
|
+
success: false,
|
|
3997
|
+
error: 'Origin is required',
|
|
3998
|
+
});
|
|
3999
|
+
}
|
|
4000
|
+
// TODO: Import getOAuthCredentials at the top of this file:
|
|
4001
|
+
// import { getOAuthCredentials } from './path/to/your/oauth-config';
|
|
4002
|
+
// For now, we'll access it from a function that should be provided
|
|
4003
|
+
// This assumes getOAuthCredentials is available in the scope
|
|
4004
|
+
// You need to import it: import { getOAuthCredentials } from './your-oauth-config-file';
|
|
4005
|
+
// Placeholder - replace this with actual import at top of file
|
|
4006
|
+
const getOAuthCredentials = global.getOAuthCredentials;
|
|
4007
|
+
if (typeof getOAuthCredentials !== 'function') {
|
|
4008
|
+
return res.status(500).json({
|
|
4009
|
+
success: false,
|
|
4010
|
+
error: 'OAuth credentials function not configured. Please import getOAuthCredentials function.',
|
|
4011
|
+
});
|
|
4012
|
+
}
|
|
4013
|
+
const credentialsResult = getOAuthCredentials(provider, origin);
|
|
4014
|
+
// Handle null return (provider not found)
|
|
4015
|
+
if (credentialsResult === null) {
|
|
4016
|
+
return res.status(404).json({
|
|
4017
|
+
success: false,
|
|
4018
|
+
error: 'No credential found',
|
|
4019
|
+
});
|
|
4020
|
+
}
|
|
4021
|
+
// Handle error cases with proper messages as requested
|
|
4022
|
+
if (credentialsResult.error) {
|
|
4023
|
+
if (credentialsResult.error === 'NO_CREDENTIALS_FOUND') {
|
|
4024
|
+
return res.status(404).json({
|
|
4025
|
+
success: false,
|
|
4026
|
+
error: 'No credential found',
|
|
4027
|
+
});
|
|
4028
|
+
}
|
|
4029
|
+
else if (credentialsResult.error === 'INVALID_ORIGIN') {
|
|
4030
|
+
return res.status(400).json({
|
|
4031
|
+
success: false,
|
|
4032
|
+
error: 'Invalid origin. OAuth credentials are only available for localhost origins.',
|
|
4033
|
+
});
|
|
4034
|
+
}
|
|
4035
|
+
else {
|
|
4036
|
+
return res.status(400).json({
|
|
4037
|
+
success: false,
|
|
4038
|
+
error: credentialsResult.error || 'Failed to get OAuth credentials',
|
|
4039
|
+
});
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
// Check if result exists and has required fields
|
|
4043
|
+
if (!credentialsResult.result) {
|
|
4044
|
+
return res.status(404).json({
|
|
4045
|
+
success: false,
|
|
4046
|
+
error: 'No credential found',
|
|
4047
|
+
});
|
|
4048
|
+
}
|
|
4049
|
+
const { clientId, clientSecret } = credentialsResult.result;
|
|
4050
|
+
if (!clientId || !clientSecret) {
|
|
4051
|
+
return res.status(404).json({
|
|
4052
|
+
success: false,
|
|
4053
|
+
error: 'No credential found',
|
|
4054
|
+
});
|
|
4055
|
+
}
|
|
4056
|
+
res.json({
|
|
4057
|
+
success: true,
|
|
4058
|
+
clientId,
|
|
4059
|
+
clientSecret,
|
|
4060
|
+
});
|
|
4061
|
+
}
|
|
4062
|
+
catch (error) {
|
|
4063
|
+
console.error('Failed to fetch OAuth credentials:', error);
|
|
4064
|
+
res.status(500).json({
|
|
4065
|
+
success: false,
|
|
4066
|
+
error: 'Failed to fetch OAuth credentials',
|
|
4067
|
+
details: error instanceof Error ? error.message : String(error),
|
|
4068
|
+
});
|
|
4069
|
+
}
|
|
4070
|
+
});
|
|
3664
4071
|
router.post('/api/tools/oauth/test', async (req, res) => {
|
|
3665
4072
|
try {
|
|
3666
4073
|
const { provider } = req.body;
|