@thunderid/nuxt 0.2.1 → 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/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 +1 -8
- package/dist/runtime/server/ThunderIDNuxtClient.js +1 -83
- package/dist/runtime/server/plugins/thunderid-ssr.d.ts +1 -3
- package/dist/runtime/server/plugins/thunderid-ssr.js +2 -22
- package/dist/runtime/types.d.ts +1 -14
- package/package.json +4 -4
- 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
|
}
|
|
@@ -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;
|
|
@@ -35,14 +35,7 @@ declare class ThunderIDNuxtClient extends ThunderIDNodeClient<ThunderIDNuxtConfi
|
|
|
35
35
|
isSignedIn(sessionId?: string): Promise<boolean>;
|
|
36
36
|
exchangeToken(config: TokenExchangeRequestConfig, sessionId?: string): Promise<TokenResponse | Response>;
|
|
37
37
|
getUserProfile(sessionId: string): Promise<UserProfile>;
|
|
38
|
-
getCurrentOrganization(sessionId: string): Promise<Organization | null>;
|
|
39
|
-
getMyOrganizations(sessionId: string): Promise<Organization[]>;
|
|
40
|
-
getBrandingPreference(config: GetBrandingPreferenceConfig): Promise<BrandingPreference>;
|
|
41
38
|
updateUserProfile(config: UpdateMeProfileConfig, sessionId: string): Promise<User>;
|
|
42
|
-
getAllOrganizations(options?: any, sessionId?: string): Promise<AllOrganizationsApiResponse>;
|
|
43
|
-
createOrganization(payload: CreateOrganizationPayload, sessionId: string): Promise<Organization>;
|
|
44
|
-
getOrganization(organizationId: string, sessionId: string): Promise<OrganizationDetails>;
|
|
45
|
-
switchOrganization(organization: Organization, sessionId: string): Promise<TokenResponse | Response>;
|
|
46
39
|
getStorageManager(): any;
|
|
47
40
|
}
|
|
48
41
|
export default ThunderIDNuxtClient;
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ThunderIDNodeClient
|
|
3
|
-
getBrandingPreference,
|
|
4
|
-
getMeOrganizations,
|
|
5
|
-
getAllOrganizations,
|
|
6
|
-
createOrganization,
|
|
7
|
-
getOrganization
|
|
2
|
+
ThunderIDNodeClient
|
|
8
3
|
} from "@thunderid/node";
|
|
9
4
|
class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
10
5
|
static instance;
|
|
@@ -105,86 +100,9 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
105
100
|
const user = await this.getUser(sessionId);
|
|
106
101
|
return { flattenedProfile: user, profile: user, schemas: [] };
|
|
107
102
|
}
|
|
108
|
-
async getCurrentOrganization(sessionId) {
|
|
109
|
-
try {
|
|
110
|
-
const idToken = await this.getDecodedIdToken(sessionId);
|
|
111
|
-
if (!idToken?.org_id) {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
return {
|
|
115
|
-
id: idToken.org_id,
|
|
116
|
-
name: idToken.org_name ?? "",
|
|
117
|
-
orgHandle: idToken.org_handle ?? ""
|
|
118
|
-
};
|
|
119
|
-
} catch {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
async getMyOrganizations(sessionId) {
|
|
124
|
-
const accessToken = await this.getAccessToken(sessionId);
|
|
125
|
-
const configData = this.getStorageManager().getConfigData();
|
|
126
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
127
|
-
return getMeOrganizations({
|
|
128
|
-
baseUrl,
|
|
129
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
async getBrandingPreference(config) {
|
|
133
|
-
return getBrandingPreference(config);
|
|
134
|
-
}
|
|
135
103
|
async updateUserProfile(config, sessionId) {
|
|
136
104
|
throw new Error("Profile updates are not supported for the ThunderID platform.");
|
|
137
105
|
}
|
|
138
|
-
async getAllOrganizations(options, sessionId) {
|
|
139
|
-
const resolvedSessionId = sessionId ?? "";
|
|
140
|
-
const accessToken = await this.getAccessToken(resolvedSessionId);
|
|
141
|
-
const configData = this.getStorageManager().getConfigData();
|
|
142
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
143
|
-
return getAllOrganizations({
|
|
144
|
-
baseUrl,
|
|
145
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
async createOrganization(payload, sessionId) {
|
|
149
|
-
const accessToken = await this.getAccessToken(sessionId);
|
|
150
|
-
const configData = this.getStorageManager().getConfigData();
|
|
151
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
152
|
-
return createOrganization({
|
|
153
|
-
baseUrl,
|
|
154
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
155
|
-
payload
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
async getOrganization(organizationId, sessionId) {
|
|
159
|
-
const accessToken = await this.getAccessToken(sessionId);
|
|
160
|
-
const configData = this.getStorageManager().getConfigData();
|
|
161
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
162
|
-
return getOrganization({
|
|
163
|
-
baseUrl,
|
|
164
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
165
|
-
organizationId
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
async switchOrganization(organization, sessionId) {
|
|
169
|
-
if (!organization.id) {
|
|
170
|
-
throw new Error("Organization ID is required for switching organizations.");
|
|
171
|
-
}
|
|
172
|
-
const exchangeConfig = {
|
|
173
|
-
attachToken: false,
|
|
174
|
-
data: {
|
|
175
|
-
client_id: "{{clientId}}",
|
|
176
|
-
client_secret: "{{clientSecret}}",
|
|
177
|
-
grant_type: "organization_switch",
|
|
178
|
-
scope: "{{scopes}}",
|
|
179
|
-
switching_organization: organization.id,
|
|
180
|
-
token: "{{accessToken}}"
|
|
181
|
-
},
|
|
182
|
-
id: "organization-switch",
|
|
183
|
-
returnsSession: true,
|
|
184
|
-
signInRequired: true
|
|
185
|
-
};
|
|
186
|
-
return this.exchangeToken(exchangeConfig, sessionId);
|
|
187
|
-
}
|
|
188
106
|
getStorageManager() {
|
|
189
107
|
return super.getStorageManager();
|
|
190
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,
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* specific language governing permissions and limitations
|
|
16
16
|
* under the License.
|
|
17
17
|
*/
|
|
18
|
-
import type {
|
|
18
|
+
import type { I18nPreferences, TokenEndpointAuthMethod, User, UserProfile } from '@thunderid/node';
|
|
19
19
|
import type { JWTPayload } from 'jose';
|
|
20
20
|
/**
|
|
21
21
|
* Configuration for the ThunderID Nuxt module.
|
|
@@ -44,11 +44,6 @@ export interface ThunderIDNuxtConfig {
|
|
|
44
44
|
/** i18n configuration forwarded to `I18nProvider`. */
|
|
45
45
|
i18n?: I18nPreferences;
|
|
46
46
|
theme?: {
|
|
47
|
-
/**
|
|
48
|
-
* When true (default), the Nitro plugin fetches the branding preference
|
|
49
|
-
* from ThunderID and passes it to `BrandingProvider` / `ThemeProvider`.
|
|
50
|
-
*/
|
|
51
|
-
inheritFromBranding?: boolean;
|
|
52
47
|
/**
|
|
53
48
|
* Theme mode forwarded to the Vue SDK's `ThemeProvider`.
|
|
54
49
|
* - `'light'` (default) | `'dark'`: Fixed color scheme. Toggle at runtime with `useTheme().toggleTheme()`.
|
|
@@ -59,8 +54,6 @@ export interface ThunderIDNuxtConfig {
|
|
|
59
54
|
mode?: 'light' | 'dark' | 'system' | 'class' | 'branding';
|
|
60
55
|
};
|
|
61
56
|
user?: {
|
|
62
|
-
/** Whether to fetch the user's organisations during SSR (default: true). */
|
|
63
|
-
fetchOrganizations?: boolean;
|
|
64
57
|
/** Whether to fetch the SCIM2 user profile during SSR (default: true). */
|
|
65
58
|
fetchUserProfile?: boolean;
|
|
66
59
|
};
|
|
@@ -126,13 +119,7 @@ export interface ThunderIDTempSessionPayload extends JWTPayload {
|
|
|
126
119
|
* hydrated `useState` keys so the client never re-fetches on first render.
|
|
127
120
|
*/
|
|
128
121
|
export interface ThunderIDSSRData {
|
|
129
|
-
/** Branding preference fetched from ThunderID (null when `preferences.theme.inheritFromBranding` is false). */
|
|
130
|
-
brandingPreference: BrandingPreference | null;
|
|
131
|
-
/** The organisation the user is currently acting within (null when not in an org). */
|
|
132
|
-
currentOrganization: Organization | null;
|
|
133
122
|
isSignedIn: boolean;
|
|
134
|
-
/** All organisations the user is a member of (empty array when `preferences.user.fetchOrganizations` is false). */
|
|
135
|
-
myOrganizations: Organization[];
|
|
136
123
|
/**
|
|
137
124
|
* The base URL actually used for this request.
|
|
138
125
|
* Equals `${baseUrl}/o` when the user is acting within an organisation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thunderid/nuxt",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Nuxt SDK for ThunderID",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"thunderid",
|
|
@@ -64,9 +64,9 @@
|
|
|
64
64
|
"@nuxt/kit": "3.21.7",
|
|
65
65
|
"defu": "6.1.5",
|
|
66
66
|
"jose": "5.2.0",
|
|
67
|
-
"@thunderid/
|
|
68
|
-
"@thunderid/
|
|
69
|
-
"@thunderid/
|
|
67
|
+
"@thunderid/node": "^0.2.2",
|
|
68
|
+
"@thunderid/vue": "^0.3.4",
|
|
69
|
+
"@thunderid/browser": "^0.3.2"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@nuxt/devtools": "2.6.4",
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
-
*
|
|
4
|
-
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
-
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
-
* in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing,
|
|
12
|
-
* software distributed under the License is distributed on an
|
|
13
|
-
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
-
* KIND, either express or implied. See the License for the
|
|
15
|
-
* specific language governing permissions and limitations
|
|
16
|
-
* under the License.
|
|
17
|
-
*/
|
|
18
|
-
import { type Component } from 'vue';
|
|
19
|
-
/**
|
|
20
|
-
* Nuxt-specific CreateOrganization container.
|
|
21
|
-
*
|
|
22
|
-
* Reads `createOrganization` from `useOrganization()` (Nuxt auto-import,
|
|
23
|
-
* re-exported from `@thunderid/vue`) and delegates rendering to
|
|
24
|
-
* {@link BaseCreateOrganization} from `@thunderid/vue`.
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```vue
|
|
28
|
-
* <ThunderIDCreateOrganization title="New Team" />
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
declare const CreateOrganization: Component;
|
|
32
|
-
export default CreateOrganization;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { withVendorCSSClassPrefix } from "@thunderid/browser";
|
|
2
|
-
import { BaseCreateOrganization } from "@thunderid/vue";
|
|
3
|
-
import { defineComponent, h } from "vue";
|
|
4
|
-
import { useOrganization } from "#imports";
|
|
5
|
-
const CreateOrganization = defineComponent({
|
|
6
|
-
name: "CreateOrganization",
|
|
7
|
-
props: {
|
|
8
|
-
className: { default: "", type: String },
|
|
9
|
-
description: { default: "Create a new sub-organization.", type: String },
|
|
10
|
-
title: { default: "Create Organization", type: String }
|
|
11
|
-
},
|
|
12
|
-
setup(props, { slots }) {
|
|
13
|
-
const { createOrganization } = useOrganization();
|
|
14
|
-
return () => h(
|
|
15
|
-
BaseCreateOrganization,
|
|
16
|
-
{
|
|
17
|
-
class: withVendorCSSClassPrefix("create-organization--styled"),
|
|
18
|
-
className: props.className,
|
|
19
|
-
description: props.description,
|
|
20
|
-
onCreate: createOrganization ? async (name) => {
|
|
21
|
-
await createOrganization({ description: "", name, parentId: "", type: "TENANT" }, "");
|
|
22
|
-
} : void 0,
|
|
23
|
-
title: props.title
|
|
24
|
-
},
|
|
25
|
-
slots
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
export default CreateOrganization;
|