@thunderid/nuxt 0.2.0 → 0.2.2
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/module.json +1 -1
- package/dist/module.mjs +0 -46
- package/dist/runtime/components/ThunderIDRoot.d.ts +3 -7
- package/dist/runtime/components/ThunderIDRoot.js +22 -92
- package/dist/runtime/components/auth/SignUp.js +1 -4
- package/dist/runtime/composables/useThunderID.js +1 -12
- package/dist/runtime/errors/error-codes.d.ts +0 -2
- package/dist/runtime/errors/error-codes.js +0 -2
- package/dist/runtime/plugins/thunderid.d.ts +2 -3
- package/dist/runtime/plugins/thunderid.js +1 -13
- package/dist/runtime/server/ThunderIDNuxtClient.d.ts +2 -10
- package/dist/runtime/server/ThunderIDNuxtClient.js +3 -116
- package/dist/runtime/server/plugins/thunderid-ssr.d.ts +1 -3
- package/dist/runtime/server/plugins/thunderid-ssr.js +2 -22
- package/dist/runtime/server/routes/auth/session/signin.post.d.ts +1 -1
- package/dist/runtime/server/routes/auth/session/signin.post.js +1 -1
- package/dist/runtime/server/routes/auth/session/signup.post.js +2 -2
- package/dist/runtime/types.d.ts +1 -20
- package/package.json +9 -9
- package/dist/runtime/components/organization/CreateOrganization.d.ts +0 -32
- package/dist/runtime/components/organization/CreateOrganization.js +0 -29
- package/dist/runtime/components/organization/Organization.d.ts +0 -39
- package/dist/runtime/components/organization/Organization.js +0 -17
- package/dist/runtime/components/organization/OrganizationList.d.ts +0 -34
- package/dist/runtime/components/organization/OrganizationList.js +0 -30
- package/dist/runtime/components/organization/OrganizationProfile.d.ts +0 -32
- package/dist/runtime/components/organization/OrganizationProfile.js +0 -32
- package/dist/runtime/components/organization/OrganizationSwitcher.d.ts +0 -36
- package/dist/runtime/components/organization/OrganizationSwitcher.js +0 -26
- package/dist/runtime/server/routes/auth/branding/branding.get.d.ts +0 -31
- package/dist/runtime/server/routes/auth/branding/branding.get.js +0 -40
- package/dist/runtime/server/routes/auth/organizations/current.get.d.ts +0 -29
- package/dist/runtime/server/routes/auth/organizations/current.get.js +0 -24
- package/dist/runtime/server/routes/auth/organizations/id.get.d.ts +0 -28
- package/dist/runtime/server/routes/auth/organizations/id.get.js +0 -28
- package/dist/runtime/server/routes/auth/organizations/index.get.d.ts +0 -28
- package/dist/runtime/server/routes/auth/organizations/index.get.js +0 -24
- package/dist/runtime/server/routes/auth/organizations/index.post.d.ts +0 -30
- package/dist/runtime/server/routes/auth/organizations/index.post.js +0 -30
- package/dist/runtime/server/routes/auth/organizations/me.get.d.ts +0 -28
- package/dist/runtime/server/routes/auth/organizations/me.get.js +0 -24
- package/dist/runtime/server/routes/auth/organizations/switch.post.d.ts +0 -32
- package/dist/runtime/server/routes/auth/organizations/switch.post.js +0 -49
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -103,33 +103,6 @@ const module$1 = defineNuxtModule({
|
|
|
103
103
|
method: "patch",
|
|
104
104
|
route: "/api/auth/user/profile"
|
|
105
105
|
},
|
|
106
|
-
// ── Organisations ─────────────────────────────────────────────────
|
|
107
|
-
{
|
|
108
|
-
handler: resolve("./runtime/server/routes/auth/organizations/index.get"),
|
|
109
|
-
route: "/api/auth/organizations"
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
handler: resolve("./runtime/server/routes/auth/organizations/index.post"),
|
|
113
|
-
method: "post",
|
|
114
|
-
route: "/api/auth/organizations"
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
handler: resolve("./runtime/server/routes/auth/organizations/me.get"),
|
|
118
|
-
route: "/api/auth/organizations/me"
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
handler: resolve("./runtime/server/routes/auth/organizations/current.get"),
|
|
122
|
-
route: "/api/auth/organizations/current"
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
handler: resolve("./runtime/server/routes/auth/organizations/id.get"),
|
|
126
|
-
route: "/api/auth/organizations/:id"
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
handler: resolve("./runtime/server/routes/auth/organizations/switch.post"),
|
|
130
|
-
method: "post",
|
|
131
|
-
route: "/api/auth/organizations/switch"
|
|
132
|
-
},
|
|
133
106
|
// ── Branding ──────────────────────────────────────────────────────
|
|
134
107
|
{ handler: resolve("./runtime/server/routes/auth/branding/branding.get"), route: "/api/auth/branding" }
|
|
135
108
|
];
|
|
@@ -147,11 +120,9 @@ const module$1 = defineNuxtModule({
|
|
|
147
120
|
{ from: resolve("./runtime/composables/useThunderID"), name: "useThunderID" },
|
|
148
121
|
// Composables from @thunderid/vue — auto-imported directly, no local wrappers
|
|
149
122
|
{ from: "@thunderid/vue", name: "useUser" },
|
|
150
|
-
{ from: "@thunderid/vue", name: "useOrganization" },
|
|
151
123
|
{ from: "@thunderid/vue", name: "useFlow" },
|
|
152
124
|
{ from: "@thunderid/vue", name: "useFlowMeta" },
|
|
153
125
|
{ from: "@thunderid/vue", name: "useTheme" },
|
|
154
|
-
{ from: "@thunderid/vue", name: "useBranding" },
|
|
155
126
|
// useI18n aliased to `useThunderIDI18n` to avoid collision with @nuxtjs/i18n
|
|
156
127
|
{ as: "useThunderIDI18n", from: "@thunderid/vue", name: "useI18n" },
|
|
157
128
|
// Middleware factory
|
|
@@ -172,23 +143,6 @@ const module$1 = defineNuxtModule({
|
|
|
172
143
|
addComponent({ filePath: resolve("./runtime/components/user/User"), name: "ThunderIDUser" });
|
|
173
144
|
addComponent({ filePath: resolve("./runtime/components/user/UserProfile"), name: "ThunderIDUserProfile" });
|
|
174
145
|
addComponent({ filePath: resolve("./runtime/components/user/UserDropdown"), name: "ThunderIDUserDropdown" });
|
|
175
|
-
addComponent({ filePath: resolve("./runtime/components/organization/Organization"), name: "ThunderIDOrganization" });
|
|
176
|
-
addComponent({
|
|
177
|
-
filePath: resolve("./runtime/components/organization/OrganizationProfile"),
|
|
178
|
-
name: "ThunderIDOrganizationProfile"
|
|
179
|
-
});
|
|
180
|
-
addComponent({
|
|
181
|
-
filePath: resolve("./runtime/components/organization/OrganizationSwitcher"),
|
|
182
|
-
name: "ThunderIDOrganizationSwitcher"
|
|
183
|
-
});
|
|
184
|
-
addComponent({
|
|
185
|
-
filePath: resolve("./runtime/components/organization/OrganizationList"),
|
|
186
|
-
name: "ThunderIDOrganizationList"
|
|
187
|
-
});
|
|
188
|
-
addComponent({
|
|
189
|
-
filePath: resolve("./runtime/components/organization/CreateOrganization"),
|
|
190
|
-
name: "ThunderIDCreateOrganization"
|
|
191
|
-
});
|
|
192
146
|
addComponent({ filePath: resolve("./runtime/components/auth/Callback"), name: "ThunderIDCallback" });
|
|
193
147
|
extendViteConfig(
|
|
194
148
|
(viteConfig) => {
|
|
@@ -24,19 +24,15 @@ import { type Component } from 'vue';
|
|
|
24
24
|
* data as props to each Vue provider:
|
|
25
25
|
*
|
|
26
26
|
* - {@link I18nProvider} ← `preferences.i18n`
|
|
27
|
-
* - {@link
|
|
28
|
-
* - {@link ThemeProvider} ← `inheritFromBranding`, `mode`
|
|
27
|
+
* - {@link ThemeProvider} ← `mode`
|
|
29
28
|
* - {@link FlowProvider}
|
|
30
29
|
* - {@link UserProvider} ← `profile`, `flattenedProfile`, `schemas`,
|
|
31
30
|
* `updateProfile`, `revalidateProfile`, `onUpdateProfile`
|
|
32
|
-
* - {@link OrganizationProvider} ← `currentOrganization`, `myOrganizations`,
|
|
33
|
-
* `onOrganizationSwitch`, `getAllOrganizations`,
|
|
34
|
-
* `revalidateMyOrganizations`
|
|
35
31
|
*
|
|
36
32
|
* The `THUNDERID_KEY` (config + auth state + actions) is still provided at the
|
|
37
33
|
* app level by the Nuxt plugin; this component only supplies the auxiliary
|
|
38
|
-
* provider contexts so downstream composables (`useUser`, `
|
|
39
|
-
* `
|
|
34
|
+
* provider contexts so downstream composables (`useUser`, `useTheme`,
|
|
35
|
+
* `useThunderIDI18n`) receive real data.
|
|
40
36
|
*
|
|
41
37
|
* @example
|
|
42
38
|
* ```vue
|
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
import { generateFlattenedUserProfile } from "@thunderid/browser";
|
|
2
|
-
import {
|
|
3
|
-
BrandingProvider,
|
|
4
|
-
FlowMetaProvider,
|
|
5
|
-
FlowProvider,
|
|
6
|
-
I18nProvider,
|
|
7
|
-
OrganizationProvider,
|
|
8
|
-
ThemeProvider,
|
|
9
|
-
UserProvider
|
|
10
|
-
} from "@thunderid/vue";
|
|
2
|
+
import { FlowMetaProvider, FlowProvider, I18nProvider, ThemeProvider, UserProvider } from "@thunderid/vue";
|
|
11
3
|
import { defineComponent, h } from "vue";
|
|
12
4
|
import { useState, useRuntimeConfig } from "#imports";
|
|
13
5
|
const ThunderIDRoot = defineComponent({
|
|
14
6
|
name: "ThunderIDRoot",
|
|
15
7
|
setup(_props, { slots }) {
|
|
16
8
|
const userProfileState = useState("thunderid:user-profile");
|
|
17
|
-
const currentOrgState = useState("thunderid:current-org");
|
|
18
|
-
const myOrgsState = useState("thunderid:my-orgs");
|
|
19
|
-
const brandingState = useState("thunderid:branding");
|
|
20
9
|
const authState = useState("thunderid:auth");
|
|
21
10
|
const prefs = useRuntimeConfig().public.thunderid?.preferences;
|
|
22
11
|
const shouldFetchProfile = prefs?.user?.fetchUserProfile !== false;
|
|
23
|
-
const shouldFetchOrgs = prefs?.user?.fetchOrganizations !== false;
|
|
24
|
-
const shouldFetchBranding = prefs?.theme?.inheritFromBranding !== false;
|
|
25
12
|
const themeMode = prefs?.theme?.mode ?? "light";
|
|
26
13
|
const onUpdateProfile = (payload) => {
|
|
27
14
|
const prev = userProfileState.value;
|
|
@@ -59,34 +46,6 @@ const ThunderIDRoot = defineComponent({
|
|
|
59
46
|
} catch {
|
|
60
47
|
}
|
|
61
48
|
};
|
|
62
|
-
const onOrganizationSwitch = async (organization) => $fetch("/api/auth/organizations/switch", { body: { organization }, method: "POST" });
|
|
63
|
-
const getAllOrganizations = async () => $fetch("/api/auth/organizations");
|
|
64
|
-
const revalidateMyOrganizations = async () => {
|
|
65
|
-
try {
|
|
66
|
-
const res = await $fetch("/api/auth/organizations/me");
|
|
67
|
-
myOrgsState.value = res ?? [];
|
|
68
|
-
return myOrgsState.value;
|
|
69
|
-
} catch {
|
|
70
|
-
return myOrgsState.value;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
const createOrganization = async (payload) => $fetch("/api/auth/organizations", { body: payload, method: "POST" });
|
|
74
|
-
const revalidateCurrentOrganization = async () => {
|
|
75
|
-
try {
|
|
76
|
-
const res = await $fetch("/api/auth/organizations/current");
|
|
77
|
-
currentOrgState.value = res ?? null;
|
|
78
|
-
return currentOrgState.value;
|
|
79
|
-
} catch {
|
|
80
|
-
return currentOrgState.value;
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
const revalidateBranding = async () => {
|
|
84
|
-
try {
|
|
85
|
-
const res = await $fetch("/api/auth/branding");
|
|
86
|
-
if (res) brandingState.value = res;
|
|
87
|
-
} catch {
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
49
|
return () => h(
|
|
91
50
|
I18nProvider,
|
|
92
51
|
{ preferences: prefs?.i18n },
|
|
@@ -96,59 +55,30 @@ const ThunderIDRoot = defineComponent({
|
|
|
96
55
|
{ enabled: false },
|
|
97
56
|
{
|
|
98
57
|
default: () => h(
|
|
99
|
-
|
|
58
|
+
ThemeProvider,
|
|
100
59
|
{
|
|
101
|
-
|
|
102
|
-
// falls back to its own default theme without using SSR-fetched data.
|
|
103
|
-
brandingPreference: shouldFetchBranding ? brandingState.value : null,
|
|
104
|
-
revalidateBranding: shouldFetchBranding ? revalidateBranding : void 0
|
|
60
|
+
mode: themeMode
|
|
105
61
|
},
|
|
106
62
|
{
|
|
107
|
-
default: () => h(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
schemas: shouldFetchProfile ? userProfileState.value?.schemas ?? null : null,
|
|
127
|
-
updateProfile: shouldFetchProfile ? updateProfile : void 0
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
default: () => h(
|
|
131
|
-
OrganizationProvider,
|
|
132
|
-
{
|
|
133
|
-
// When fetchOrganizations is false pass empty
|
|
134
|
-
// values so the provider renders without org data.
|
|
135
|
-
createOrganization: shouldFetchOrgs ? createOrganization : void 0,
|
|
136
|
-
currentOrganization: shouldFetchOrgs ? currentOrgState.value : null,
|
|
137
|
-
getAllOrganizations: shouldFetchOrgs ? getAllOrganizations : void 0,
|
|
138
|
-
myOrganizations: shouldFetchOrgs ? myOrgsState.value : [],
|
|
139
|
-
onOrganizationSwitch: shouldFetchOrgs ? onOrganizationSwitch : void 0,
|
|
140
|
-
revalidateCurrentOrganization: shouldFetchOrgs ? revalidateCurrentOrganization : void 0,
|
|
141
|
-
revalidateMyOrganizations: shouldFetchOrgs ? revalidateMyOrganizations : void 0
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
default: () => slots.default?.()
|
|
145
|
-
}
|
|
146
|
-
)
|
|
147
|
-
}
|
|
148
|
-
)
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
)
|
|
63
|
+
default: () => h(FlowProvider, null, {
|
|
64
|
+
default: () => h(
|
|
65
|
+
UserProvider,
|
|
66
|
+
{
|
|
67
|
+
// When fetchUserProfile is false the Nitro plugin
|
|
68
|
+
// skips SCIM calls, so we must also pass empty values
|
|
69
|
+
// here to keep SSR and client in sync.
|
|
70
|
+
flattenedProfile: shouldFetchProfile ? userProfileState.value?.flattenedProfile ?? null : null,
|
|
71
|
+
onUpdateProfile: shouldFetchProfile ? onUpdateProfile : void 0,
|
|
72
|
+
profile: shouldFetchProfile ? userProfileState.value : null,
|
|
73
|
+
revalidateProfile: shouldFetchProfile ? revalidateProfile : void 0,
|
|
74
|
+
schemas: shouldFetchProfile ? userProfileState.value?.schemas ?? null : null,
|
|
75
|
+
updateProfile: shouldFetchProfile ? updateProfile : void 0
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
default: () => slots.default?.()
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
})
|
|
152
82
|
}
|
|
153
83
|
)
|
|
154
84
|
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { navigateTo } from "#app";
|
|
2
|
-
import {
|
|
3
|
-
EmbeddedFlowResponseType,
|
|
4
|
-
EmbeddedFlowType
|
|
5
|
-
} from "@thunderid/browser";
|
|
2
|
+
import { EmbeddedFlowResponseType, EmbeddedFlowType } from "@thunderid/browser";
|
|
6
3
|
import { BaseSignUp } from "@thunderid/vue";
|
|
7
4
|
import { defineComponent, h } from "vue";
|
|
8
5
|
import { useThunderID } from "#imports";
|
|
@@ -24,7 +24,7 @@ export function useThunderID() {
|
|
|
24
24
|
}
|
|
25
25
|
return {
|
|
26
26
|
authData: {},
|
|
27
|
-
flowStatus: EmbeddedSignInFlowStatus.
|
|
27
|
+
flowStatus: EmbeddedSignInFlowStatus.Complete
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
return res.data;
|
|
@@ -41,17 +41,6 @@ export function useThunderID() {
|
|
|
41
41
|
};
|
|
42
42
|
const signUp = async (...args) => {
|
|
43
43
|
const payload = args[0];
|
|
44
|
-
if (payload && typeof payload === "object" && "flowType" in payload) {
|
|
45
|
-
const res = await $fetch("/api/auth/signup", {
|
|
46
|
-
body: { payload },
|
|
47
|
-
method: "POST"
|
|
48
|
-
});
|
|
49
|
-
if (res.data?.afterSignUpUrl) {
|
|
50
|
-
await navigateTo(res.data.afterSignUpUrl, { external: false });
|
|
51
|
-
return void 0;
|
|
52
|
-
}
|
|
53
|
-
return res.data;
|
|
54
|
-
}
|
|
55
44
|
const cfg = useRuntimeConfig().public.thunderid ?? {};
|
|
56
45
|
if (cfg.signUpUrl) {
|
|
57
46
|
await navigateTo(cfg.signUpUrl, { external: true });
|
|
@@ -27,8 +27,6 @@ export declare enum ErrorCode {
|
|
|
27
27
|
OAuthCallbackError = "oauth/callback-error",
|
|
28
28
|
OAuthStateInvalid = "oauth/state-invalid",
|
|
29
29
|
OpenRedirectBlocked = "security/open-redirect-blocked",
|
|
30
|
-
OrganizationCreateFailed = "organization/create-failed",
|
|
31
|
-
OrganizationSwitchFailed = "organization/switch-failed",
|
|
32
30
|
SessionExpired = "session/expired",
|
|
33
31
|
SessionInvalid = "session/invalid",
|
|
34
32
|
SessionMissing = "session/missing",
|
|
@@ -5,8 +5,6 @@ export var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
|
5
5
|
ErrorCode2["OAuthCallbackError"] = "oauth/callback-error";
|
|
6
6
|
ErrorCode2["OAuthStateInvalid"] = "oauth/state-invalid";
|
|
7
7
|
ErrorCode2["OpenRedirectBlocked"] = "security/open-redirect-blocked";
|
|
8
|
-
ErrorCode2["OrganizationCreateFailed"] = "organization/create-failed";
|
|
9
|
-
ErrorCode2["OrganizationSwitchFailed"] = "organization/switch-failed";
|
|
10
8
|
ErrorCode2["SessionExpired"] = "session/expired";
|
|
11
9
|
ErrorCode2["SessionInvalid"] = "session/invalid";
|
|
12
10
|
ErrorCode2["SessionMissing"] = "session/missing";
|
|
@@ -29,9 +29,8 @@
|
|
|
29
29
|
* Action helpers (`signIn` / `signOut` / `signUp`) use Nuxt's
|
|
30
30
|
* `navigateTo` so redirects work on both server and client.
|
|
31
31
|
* 3. **ThunderIDRoot** — register the wrapper component that mounts the rest
|
|
32
|
-
* of the provider tree (`I18nProvider`, `
|
|
33
|
-
* `
|
|
34
|
-
* so downstream composables receive real context values.
|
|
32
|
+
* of the provider tree (`I18nProvider`, `ThemeProvider`, `FlowProvider`,
|
|
33
|
+
* `UserProvider`) so downstream composables receive real context values.
|
|
35
34
|
* 4. **ThunderIDPlugin (delegated)** — install the Vue SDK plugin in
|
|
36
35
|
* delegated mode so it skips browser-only initialisation (SSR-safe).
|
|
37
36
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { defineNuxtPlugin, useState, useRequestEvent, useRuntimeConfig, navigateTo } from "#app";
|
|
2
1
|
import { getRedirectBasedSignUpUrl } from "@thunderid/browser";
|
|
3
2
|
import { ThunderIDPlugin, THUNDERID_KEY } from "@thunderid/vue";
|
|
4
3
|
import { computed } from "vue";
|
|
5
4
|
import ThunderIDRoot from "../components/ThunderIDRoot.js";
|
|
5
|
+
import { defineNuxtPlugin, useState, useRequestEvent, useRuntimeConfig, navigateTo } from "#app";
|
|
6
6
|
export default defineNuxtPlugin((nuxtApp) => {
|
|
7
7
|
const publicConfig = useRuntimeConfig().public.thunderid;
|
|
8
8
|
if (import.meta.client && import.meta.dev) {
|
|
@@ -18,12 +18,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
18
18
|
user: null
|
|
19
19
|
}));
|
|
20
20
|
const userProfileState = useState("thunderid:user-profile", () => null);
|
|
21
|
-
const currentOrgState = useState("thunderid:current-org", () => null);
|
|
22
|
-
const myOrgsState = useState("thunderid:my-orgs", () => []);
|
|
23
|
-
const brandingState = useState(
|
|
24
|
-
"thunderid:branding",
|
|
25
|
-
() => null
|
|
26
|
-
);
|
|
27
21
|
if (import.meta.server) {
|
|
28
22
|
const event = useRequestEvent();
|
|
29
23
|
const ssr = event?.context?.thunderid?.ssr;
|
|
@@ -34,9 +28,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
34
28
|
user: ssr.user
|
|
35
29
|
};
|
|
36
30
|
userProfileState.value = ssr.userProfile;
|
|
37
|
-
currentOrgState.value = ssr.currentOrganization;
|
|
38
|
-
myOrgsState.value = ssr.myOrganizations;
|
|
39
|
-
brandingState.value = ssr.brandingPreference;
|
|
40
31
|
} else {
|
|
41
32
|
const ssrContext = event?.context?.thunderid;
|
|
42
33
|
if (ssrContext) {
|
|
@@ -58,7 +49,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
58
49
|
const isLoading = computed(() => authState.value.isLoading);
|
|
59
50
|
const isInitialized = computed(() => !authState.value.isLoading);
|
|
60
51
|
const user = computed(() => authState.value.user ?? null);
|
|
61
|
-
const organizationRef = computed(() => currentOrgState.value);
|
|
62
52
|
const signIn = async (options) => {
|
|
63
53
|
const returnTo = typeof options?.returnTo === "string" ? options.returnTo : void 0;
|
|
64
54
|
const url = returnTo ? `/api/auth/signin?returnTo=${encodeURIComponent(returnTo)}` : "/api/auth/signin";
|
|
@@ -108,7 +98,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
108
98
|
isInitialized,
|
|
109
99
|
isLoading,
|
|
110
100
|
isSignedIn,
|
|
111
|
-
organization: organizationRef,
|
|
112
101
|
organizationHandle: publicConfig.organizationHandle,
|
|
113
102
|
platform: void 0,
|
|
114
103
|
reInitialize: async () => false,
|
|
@@ -121,7 +110,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
121
110
|
signUp,
|
|
122
111
|
signUpUrl: publicConfig.signUpUrl,
|
|
123
112
|
storage: void 0,
|
|
124
|
-
switchOrganization: noop,
|
|
125
113
|
user
|
|
126
114
|
});
|
|
127
115
|
nuxtApp.vueApp.component("ThunderIDRoot", ThunderIDRoot);
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* specific language governing permissions and limitations
|
|
16
16
|
* under the License.
|
|
17
17
|
*/
|
|
18
|
-
import { ThunderIDNodeClient, type IdToken, type
|
|
18
|
+
import { ThunderIDNodeClient, type IdToken, type Storage, type TokenExchangeRequestConfig, type TokenResponse, type User, type UserProfile, type UpdateMeProfileConfig, type ExtendedAuthorizeRequestUrlParams, type SignUpOptions } from '@thunderid/node';
|
|
19
19
|
import type { ThunderIDNuxtConfig, ThunderIDSessionPayload } from '../types.js';
|
|
20
20
|
declare class ThunderIDNuxtClient extends ThunderIDNodeClient<ThunderIDNuxtConfig> {
|
|
21
21
|
private static instance;
|
|
@@ -26,8 +26,7 @@ declare class ThunderIDNuxtClient extends ThunderIDNodeClient<ThunderIDNuxtConfi
|
|
|
26
26
|
reInitialize(config: Partial<ThunderIDNuxtConfig>): Promise<boolean>;
|
|
27
27
|
rehydrateSessionFromPayload(session: ThunderIDSessionPayload): Promise<void>;
|
|
28
28
|
signIn(...args: any[]): Promise<any>;
|
|
29
|
-
signUp(
|
|
30
|
-
signUp(payload: EmbeddedFlowExecuteRequestPayload): Promise<EmbeddedFlowExecuteResponse>;
|
|
29
|
+
signUp(_options?: SignUpOptions): Promise<void>;
|
|
31
30
|
getAuthorizeRequestUrl(customParams: ExtendedAuthorizeRequestUrlParams, userId?: string): Promise<string>;
|
|
32
31
|
signOut(...args: any[]): Promise<string>;
|
|
33
32
|
getUser(sessionId?: string): Promise<User>;
|
|
@@ -36,14 +35,7 @@ declare class ThunderIDNuxtClient extends ThunderIDNodeClient<ThunderIDNuxtConfi
|
|
|
36
35
|
isSignedIn(sessionId?: string): Promise<boolean>;
|
|
37
36
|
exchangeToken(config: TokenExchangeRequestConfig, sessionId?: string): Promise<TokenResponse | Response>;
|
|
38
37
|
getUserProfile(sessionId: string): Promise<UserProfile>;
|
|
39
|
-
getCurrentOrganization(sessionId: string): Promise<Organization | null>;
|
|
40
|
-
getMyOrganizations(sessionId: string): Promise<Organization[]>;
|
|
41
|
-
getBrandingPreference(config: GetBrandingPreferenceConfig): Promise<BrandingPreference>;
|
|
42
38
|
updateUserProfile(config: UpdateMeProfileConfig, sessionId: string): Promise<User>;
|
|
43
|
-
getAllOrganizations(options?: any, sessionId?: string): Promise<AllOrganizationsApiResponse>;
|
|
44
|
-
createOrganization(payload: CreateOrganizationPayload, sessionId: string): Promise<Organization>;
|
|
45
|
-
getOrganization(organizationId: string, sessionId: string): Promise<OrganizationDetails>;
|
|
46
|
-
switchOrganization(organization: Organization, sessionId: string): Promise<TokenResponse | Response>;
|
|
47
39
|
getStorageManager(): any;
|
|
48
40
|
}
|
|
49
41
|
export default ThunderIDNuxtClient;
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ThunderIDNodeClient
|
|
3
|
-
getBrandingPreference,
|
|
4
|
-
getMeOrganizations,
|
|
5
|
-
getAllOrganizations,
|
|
6
|
-
createOrganization,
|
|
7
|
-
getOrganization,
|
|
8
|
-
initializeEmbeddedSignInFlow,
|
|
9
|
-
executeEmbeddedSignInFlow,
|
|
10
|
-
executeEmbeddedSignUpFlow
|
|
2
|
+
ThunderIDNodeClient
|
|
11
3
|
} from "@thunderid/node";
|
|
12
4
|
class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
13
5
|
static instance;
|
|
@@ -66,25 +58,6 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
66
58
|
}
|
|
67
59
|
signIn(...args) {
|
|
68
60
|
const arg0 = args[0];
|
|
69
|
-
if (typeof arg0 === "object" && arg0 !== null && "flowId" in arg0) {
|
|
70
|
-
const sessionId = args[2];
|
|
71
|
-
if (arg0.flowId === "") {
|
|
72
|
-
return this.getSignInUrl({ client_secret: "{{clientSecret}}", response_mode: "direct" }, sessionId).then(
|
|
73
|
-
(authorizeUrl) => {
|
|
74
|
-
const url = new URL(authorizeUrl);
|
|
75
|
-
return initializeEmbeddedSignInFlow({
|
|
76
|
-
payload: Object.fromEntries(url.searchParams.entries()),
|
|
77
|
-
url: `${url.origin}${url.pathname}`
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
const request = args[1] ?? {};
|
|
83
|
-
return executeEmbeddedSignInFlow({
|
|
84
|
-
payload: arg0,
|
|
85
|
-
url: request.url
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
61
|
if (typeof arg0 === "object" && arg0 !== null && ("code" in arg0 || "state" in arg0)) {
|
|
89
62
|
const payload = arg0;
|
|
90
63
|
const code = typeof payload.code === "string" ? payload.code : void 0;
|
|
@@ -98,17 +71,8 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
98
71
|
}
|
|
99
72
|
return super.signIn(args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
100
73
|
}
|
|
101
|
-
async signUp(
|
|
102
|
-
|
|
103
|
-
return void 0;
|
|
104
|
-
}
|
|
105
|
-
const configData = this.getStorageManager().getConfigData();
|
|
106
|
-
const baseUrl = configData?.baseUrl;
|
|
107
|
-
const response = await executeEmbeddedSignUpFlow({
|
|
108
|
-
baseUrl,
|
|
109
|
-
payload: payloadOrOptions
|
|
110
|
-
});
|
|
111
|
-
return response;
|
|
74
|
+
async signUp(_options) {
|
|
75
|
+
return void 0;
|
|
112
76
|
}
|
|
113
77
|
async getAuthorizeRequestUrl(customParams, userId) {
|
|
114
78
|
return this.getSignInUrl(customParams, userId);
|
|
@@ -136,86 +100,9 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
136
100
|
const user = await this.getUser(sessionId);
|
|
137
101
|
return { flattenedProfile: user, profile: user, schemas: [] };
|
|
138
102
|
}
|
|
139
|
-
async getCurrentOrganization(sessionId) {
|
|
140
|
-
try {
|
|
141
|
-
const idToken = await this.getDecodedIdToken(sessionId);
|
|
142
|
-
if (!idToken?.org_id) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
id: idToken.org_id,
|
|
147
|
-
name: idToken.org_name ?? "",
|
|
148
|
-
orgHandle: idToken.org_handle ?? ""
|
|
149
|
-
};
|
|
150
|
-
} catch {
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
async getMyOrganizations(sessionId) {
|
|
155
|
-
const accessToken = await this.getAccessToken(sessionId);
|
|
156
|
-
const configData = this.getStorageManager().getConfigData();
|
|
157
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
158
|
-
return getMeOrganizations({
|
|
159
|
-
baseUrl,
|
|
160
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
async getBrandingPreference(config) {
|
|
164
|
-
return getBrandingPreference(config);
|
|
165
|
-
}
|
|
166
103
|
async updateUserProfile(config, sessionId) {
|
|
167
104
|
throw new Error("Profile updates are not supported for the ThunderID platform.");
|
|
168
105
|
}
|
|
169
|
-
async getAllOrganizations(options, sessionId) {
|
|
170
|
-
const resolvedSessionId = sessionId ?? "";
|
|
171
|
-
const accessToken = await this.getAccessToken(resolvedSessionId);
|
|
172
|
-
const configData = this.getStorageManager().getConfigData();
|
|
173
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
174
|
-
return getAllOrganizations({
|
|
175
|
-
baseUrl,
|
|
176
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
async createOrganization(payload, sessionId) {
|
|
180
|
-
const accessToken = await this.getAccessToken(sessionId);
|
|
181
|
-
const configData = this.getStorageManager().getConfigData();
|
|
182
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
183
|
-
return createOrganization({
|
|
184
|
-
baseUrl,
|
|
185
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
186
|
-
payload
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
async getOrganization(organizationId, sessionId) {
|
|
190
|
-
const accessToken = await this.getAccessToken(sessionId);
|
|
191
|
-
const configData = this.getStorageManager().getConfigData();
|
|
192
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
193
|
-
return getOrganization({
|
|
194
|
-
baseUrl,
|
|
195
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
196
|
-
organizationId
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
async switchOrganization(organization, sessionId) {
|
|
200
|
-
if (!organization.id) {
|
|
201
|
-
throw new Error("Organization ID is required for switching organizations.");
|
|
202
|
-
}
|
|
203
|
-
const exchangeConfig = {
|
|
204
|
-
attachToken: false,
|
|
205
|
-
data: {
|
|
206
|
-
client_id: "{{clientId}}",
|
|
207
|
-
client_secret: "{{clientSecret}}",
|
|
208
|
-
grant_type: "organization_switch",
|
|
209
|
-
scope: "{{scopes}}",
|
|
210
|
-
switching_organization: organization.id,
|
|
211
|
-
token: "{{accessToken}}"
|
|
212
|
-
},
|
|
213
|
-
id: "organization-switch",
|
|
214
|
-
returnsSession: true,
|
|
215
|
-
signInRequired: true
|
|
216
|
-
};
|
|
217
|
-
return this.exchangeToken(exchangeConfig, sessionId);
|
|
218
|
-
}
|
|
219
106
|
getStorageManager() {
|
|
220
107
|
return super.getStorageManager();
|
|
221
108
|
}
|
|
@@ -27,12 +27,10 @@
|
|
|
27
27
|
* within an organisation.
|
|
28
28
|
* 4. In parallel (gated by `preferences`):
|
|
29
29
|
* - Fetches user + SCIM2 user profile (`preferences.user.fetchUserProfile !== false`)
|
|
30
|
-
* - Fetches current org + my orgs (`preferences.user.fetchOrganizations !== false`)
|
|
31
|
-
* - Fetches branding preference (`preferences.theme.inheritFromBranding !== false`)
|
|
32
30
|
* 5. Writes the full {@link ThunderIDSSRData} to `event.context.thunderid.ssr`
|
|
33
31
|
* so the Nuxt plugin can seed `useState` keys for zero-cost hydration.
|
|
34
32
|
*
|
|
35
|
-
* Each fetch is individually wrapped in try/catch so a broken SCIM
|
|
33
|
+
* Each fetch is individually wrapped in try/catch so a broken SCIM
|
|
36
34
|
* call never crashes SSR — the client layer can recover via the existing
|
|
37
35
|
* `/api/auth/*` routes.
|
|
38
36
|
*/
|
|
@@ -84,19 +84,11 @@ export default defineNitroPlugin((nitro) => {
|
|
|
84
84
|
} catch {
|
|
85
85
|
}
|
|
86
86
|
const shouldFetchProfile = prefs?.user?.fetchUserProfile !== false;
|
|
87
|
-
const
|
|
88
|
-
const shouldFetchBranding = prefs?.theme?.inheritFromBranding !== false;
|
|
89
|
-
const [userResult, userProfileResult, orgsResult, currentOrgResult, brandingResult] = await Promise.allSettled([
|
|
87
|
+
const [userResult, userProfileResult] = await Promise.allSettled([
|
|
90
88
|
// Always fetch the basic user object (needed for ThunderIDAuthState.user)
|
|
91
89
|
client.getUser(session.sessionId),
|
|
92
90
|
// SCIM2 user profile (flattened + schemas)
|
|
93
|
-
shouldFetchProfile ? client.getUserProfile(session.sessionId) : Promise.resolve(null)
|
|
94
|
-
// User's organisations
|
|
95
|
-
shouldFetchOrgs ? client.getMyOrganizations(session.sessionId) : Promise.resolve([]),
|
|
96
|
-
// Current organisation (derived from the ID token)
|
|
97
|
-
shouldFetchOrgs ? client.getCurrentOrganization(session.sessionId) : Promise.resolve(null),
|
|
98
|
-
// Branding preference (does not require a session)
|
|
99
|
-
shouldFetchBranding ? client.getBrandingPreference({ baseUrl: resolvedBaseUrl }) : Promise.resolve(null)
|
|
91
|
+
shouldFetchProfile ? client.getUserProfile(session.sessionId) : Promise.resolve(null)
|
|
100
92
|
]);
|
|
101
93
|
if (userResult.status === "rejected") {
|
|
102
94
|
log.debug("Failed to fetch user:", userResult.reason);
|
|
@@ -104,20 +96,8 @@ export default defineNitroPlugin((nitro) => {
|
|
|
104
96
|
if (userProfileResult.status === "rejected") {
|
|
105
97
|
log.warn("Failed to fetch user profile (SCIM2):", userProfileResult.reason);
|
|
106
98
|
}
|
|
107
|
-
if (orgsResult.status === "rejected") {
|
|
108
|
-
log.warn("Failed to fetch my organisations:", orgsResult.reason);
|
|
109
|
-
}
|
|
110
|
-
if (currentOrgResult.status === "rejected") {
|
|
111
|
-
log.warn("Failed to resolve current organisation:", currentOrgResult.reason);
|
|
112
|
-
}
|
|
113
|
-
if (brandingResult.status === "rejected") {
|
|
114
|
-
log.warn("Failed to fetch branding preference:", brandingResult.reason);
|
|
115
|
-
}
|
|
116
99
|
const ssrData = {
|
|
117
|
-
brandingPreference: brandingResult.status === "fulfilled" ? brandingResult.value : null,
|
|
118
|
-
currentOrganization: currentOrgResult.status === "fulfilled" ? currentOrgResult.value : null,
|
|
119
100
|
isSignedIn: true,
|
|
120
|
-
myOrganizations: orgsResult.status === "fulfilled" && Array.isArray(orgsResult.value) ? orgsResult.value : [],
|
|
121
101
|
resolvedBaseUrl,
|
|
122
102
|
session,
|
|
123
103
|
user: userResult.status === "fulfilled" ? userResult.value : null,
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* Handles embedded (app-native) sign-in flow steps.
|
|
22
22
|
*
|
|
23
23
|
* Request body:
|
|
24
|
-
* - `payload` — the embedded flow step payload
|
|
24
|
+
* - `payload` — the embedded flow step payload.
|
|
25
25
|
* When omitted or `{}`, the flow is initialised and the authorize URL is returned.
|
|
26
26
|
* - `request` — optional per-step config (e.g. `{ url }` override).
|
|
27
27
|
*
|
|
@@ -66,7 +66,7 @@ export default defineEventHandler(async (event) => {
|
|
|
66
66
|
statusMessage: `Embedded sign-in step failed: ${err?.message ?? String(err)}`
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
|
-
if (response?.flowStatus === EmbeddedSignInFlowStatus.
|
|
69
|
+
if (response?.flowStatus === EmbeddedSignInFlowStatus.Complete) {
|
|
70
70
|
const authData = response?.authData ?? {};
|
|
71
71
|
const { code, state, session_state: sessionState } = authData;
|
|
72
72
|
if (!code) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EmbeddedSignUpFlowStatus } from "@thunderid/node";
|
|
2
2
|
import { defineEventHandler, readBody, createError } from "h3";
|
|
3
3
|
import ThunderIDNuxtClient from "../../../ThunderIDNuxtClient.js";
|
|
4
4
|
import { useRuntimeConfig } from "#imports";
|
|
@@ -23,7 +23,7 @@ export default defineEventHandler(async (event) => {
|
|
|
23
23
|
statusMessage: `Embedded sign-up step failed: ${err?.message ?? String(err)}`
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
|
-
if (hasFlowStatus(response) && response.flowStatus ===
|
|
26
|
+
if (hasFlowStatus(response) && response.flowStatus === EmbeddedSignUpFlowStatus.Complete) {
|
|
27
27
|
return { data: { afterSignUpUrl }, success: true };
|
|
28
28
|
}
|
|
29
29
|
return { data: response, success: true };
|