@asgardeo/nuxt 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +482 -6
- package/dist/module.d.mts +17 -24
- package/dist/module.json +2 -2
- package/dist/module.mjs +174 -48
- package/dist/runtime/components/AsgardeoRoot.d.ts +52 -0
- package/dist/runtime/components/AsgardeoRoot.js +160 -0
- package/dist/runtime/components/actions/SignInButton.d.ts +37 -0
- package/dist/runtime/components/actions/SignInButton.js +51 -0
- package/dist/runtime/components/actions/SignOutButton.d.ts +34 -0
- package/dist/runtime/components/actions/SignOutButton.js +43 -0
- package/dist/runtime/components/actions/SignUpButton.d.ts +33 -0
- package/dist/runtime/components/actions/SignUpButton.js +48 -0
- package/dist/runtime/components/auth/Callback.d.ts +43 -0
- package/dist/runtime/components/auth/Callback.js +93 -0
- package/dist/runtime/components/auth/SignIn.d.ts +38 -0
- package/dist/runtime/components/auth/SignIn.js +60 -0
- package/dist/runtime/components/auth/SignUp.d.ts +40 -0
- package/dist/runtime/components/auth/SignUp.js +79 -0
- package/dist/runtime/components/control/Loading.d.ts +36 -0
- package/dist/runtime/components/control/Loading.js +17 -0
- package/dist/runtime/components/control/SignedIn.d.ts +38 -0
- package/dist/runtime/components/control/SignedIn.js +17 -0
- package/dist/runtime/components/control/SignedOut.d.ts +37 -0
- package/dist/runtime/components/control/SignedOut.js +17 -0
- package/dist/runtime/components/organization/CreateOrganization.d.ts +32 -0
- package/dist/runtime/components/organization/CreateOrganization.js +29 -0
- package/dist/runtime/components/organization/Organization.d.ts +39 -0
- package/dist/runtime/components/organization/Organization.js +17 -0
- package/dist/runtime/components/organization/OrganizationList.d.ts +34 -0
- package/dist/runtime/components/organization/OrganizationList.js +30 -0
- package/dist/runtime/components/organization/OrganizationProfile.d.ts +32 -0
- package/dist/runtime/components/organization/OrganizationProfile.js +32 -0
- package/dist/runtime/components/organization/OrganizationSwitcher.d.ts +36 -0
- package/dist/runtime/components/organization/OrganizationSwitcher.js +26 -0
- package/dist/runtime/components/user/User.d.ts +38 -0
- package/dist/runtime/components/user/User.js +17 -0
- package/dist/runtime/components/user/UserDropdown.d.ts +38 -0
- package/dist/runtime/components/user/UserDropdown.js +45 -0
- package/dist/runtime/components/user/UserProfile.d.ts +35 -0
- package/dist/runtime/components/user/UserProfile.js +35 -0
- package/dist/runtime/composables/useAsgardeo.d.ts +38 -0
- package/dist/runtime/composables/useAsgardeo.js +73 -0
- package/dist/runtime/errors/asgardeo-error.d.ts +47 -0
- package/dist/runtime/errors/asgardeo-error.js +15 -0
- package/dist/runtime/errors/error-codes.d.ts +40 -0
- package/dist/runtime/errors/error-codes.js +19 -0
- package/dist/runtime/{composables/asgardeo/useAuth.d.ts → errors/index.d.ts} +2 -2
- package/dist/runtime/errors/index.js +2 -0
- package/dist/runtime/middleware/auth.d.ts +35 -0
- package/dist/runtime/middleware/auth.js +2 -0
- package/dist/runtime/middleware/defineAsgardeoMiddleware.d.ts +53 -0
- package/dist/runtime/middleware/defineAsgardeoMiddleware.js +24 -0
- package/dist/runtime/plugins/asgardeo.d.ts +40 -0
- package/dist/runtime/plugins/asgardeo.js +129 -0
- package/dist/runtime/server/AsgardeoNuxtClient.d.ts +182 -0
- package/dist/runtime/server/AsgardeoNuxtClient.js +366 -0
- package/dist/runtime/server/index.d.ts +33 -0
- package/dist/runtime/server/index.js +3 -0
- package/dist/runtime/server/plugins/asgardeo-ssr.d.ts +41 -0
- package/dist/runtime/server/plugins/asgardeo-ssr.js +134 -0
- package/dist/runtime/server/routes/auth/branding/branding.get.d.ts +31 -0
- package/dist/runtime/server/routes/auth/branding/branding.get.js +40 -0
- package/dist/runtime/server/routes/auth/organizations/current.get.d.ts +29 -0
- package/dist/runtime/server/routes/auth/organizations/current.get.js +24 -0
- package/dist/runtime/server/routes/auth/organizations/id.get.d.ts +28 -0
- package/dist/runtime/server/routes/auth/organizations/id.get.js +28 -0
- package/dist/runtime/server/routes/auth/organizations/index.get.d.ts +28 -0
- package/dist/runtime/server/routes/auth/organizations/index.get.js +24 -0
- package/dist/runtime/server/routes/auth/organizations/index.post.d.ts +30 -0
- package/dist/runtime/server/routes/auth/organizations/index.post.js +30 -0
- package/dist/runtime/server/routes/auth/organizations/me.get.d.ts +28 -0
- package/dist/runtime/server/routes/auth/organizations/me.get.js +24 -0
- package/dist/runtime/server/routes/auth/organizations/switch.post.d.ts +32 -0
- package/dist/runtime/server/routes/auth/organizations/switch.post.js +49 -0
- package/dist/runtime/server/routes/auth/session/callback.get.d.ts +27 -0
- package/dist/runtime/server/routes/auth/session/callback.get.js +91 -0
- package/dist/runtime/server/routes/auth/session/callback.post.d.ts +48 -0
- package/dist/runtime/server/routes/auth/session/callback.post.js +53 -0
- package/dist/runtime/server/routes/auth/session/session.get.d.ts +26 -0
- package/dist/runtime/server/routes/auth/session/session.get.js +22 -0
- package/dist/runtime/server/routes/auth/session/signin.get.d.ts +29 -0
- package/dist/runtime/server/routes/auth/session/signin.get.js +37 -0
- package/dist/runtime/server/routes/auth/session/signin.post.d.ts +37 -0
- package/dist/runtime/server/routes/auth/session/signin.post.js +102 -0
- package/dist/runtime/server/routes/auth/session/signout.post.d.ts +31 -0
- package/dist/runtime/server/routes/auth/session/signout.post.js +38 -0
- package/dist/runtime/server/routes/auth/session/signup.post.d.ts +36 -0
- package/dist/runtime/server/routes/auth/session/signup.post.js +30 -0
- package/dist/runtime/server/routes/auth/session/token.get.d.ts +29 -0
- package/dist/runtime/server/routes/auth/session/token.get.js +6 -0
- package/dist/runtime/server/routes/auth/user/profile.get.d.ts +29 -0
- package/dist/runtime/server/routes/auth/user/profile.get.js +24 -0
- package/dist/runtime/server/{handler.d.ts → routes/auth/user/profile.patch.d.ts} +17 -13
- package/dist/runtime/server/routes/auth/user/profile.patch.js +33 -0
- package/dist/runtime/server/{services/asgardeo/index.d.ts → routes/auth/user/user.get.d.ts} +6 -4
- package/dist/runtime/server/routes/auth/user/user.get.js +21 -0
- package/dist/runtime/server/utils/event-context.d.ts +49 -0
- package/dist/runtime/server/utils/event-context.js +3 -0
- package/dist/runtime/server/utils/serverSession.d.ts +65 -0
- package/dist/runtime/server/utils/serverSession.js +44 -0
- package/dist/runtime/server/utils/session.d.ts +85 -0
- package/dist/runtime/server/utils/session.js +106 -0
- package/dist/runtime/server/utils/token-refresh.d.ts +42 -0
- package/dist/runtime/server/utils/token-refresh.js +65 -0
- package/dist/runtime/types/augments.d.ts +61 -0
- package/dist/runtime/types.d.ts +115 -38
- package/dist/runtime/utils/createRouteMatcher.d.ts +40 -0
- package/dist/runtime/utils/createRouteMatcher.js +7 -0
- package/dist/runtime/utils/index.d.ts +30 -0
- package/dist/runtime/utils/index.js +1 -0
- package/dist/runtime/utils/log.d.ts +44 -0
- package/dist/runtime/utils/log.js +25 -0
- package/dist/runtime/utils/url-validation.d.ts +49 -0
- package/dist/runtime/utils/url-validation.js +38 -0
- package/dist/types.d.mts +0 -2
- package/package.json +48 -23
- package/dist/runtime/composables/asgardeo/useAuth.js +0 -129
- package/dist/runtime/server/handler.js +0 -231
- package/dist/runtime/server/services/asgardeo/index.js +0 -18
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AsgardeoNodeClient,
|
|
3
|
+
LegacyAsgardeoNodeClient,
|
|
4
|
+
getBrandingPreference,
|
|
5
|
+
getMeOrganizations,
|
|
6
|
+
getAllOrganizations,
|
|
7
|
+
createOrganization,
|
|
8
|
+
getOrganization,
|
|
9
|
+
getScim2Me,
|
|
10
|
+
getSchemas,
|
|
11
|
+
flattenUserSchema,
|
|
12
|
+
generateFlattenedUserProfile,
|
|
13
|
+
updateMeProfile,
|
|
14
|
+
initializeEmbeddedSignInFlow,
|
|
15
|
+
executeEmbeddedSignInFlow,
|
|
16
|
+
executeEmbeddedSignUpFlow
|
|
17
|
+
} from "@asgardeo/node";
|
|
18
|
+
class AsgardeoNuxtClient extends AsgardeoNodeClient {
|
|
19
|
+
static instance;
|
|
20
|
+
legacy;
|
|
21
|
+
isInitialized = false;
|
|
22
|
+
constructor() {
|
|
23
|
+
super();
|
|
24
|
+
this.legacy = new LegacyAsgardeoNodeClient();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get the singleton instance of AsgardeoNuxtClient.
|
|
28
|
+
*/
|
|
29
|
+
static getInstance() {
|
|
30
|
+
if (!AsgardeoNuxtClient.instance) {
|
|
31
|
+
AsgardeoNuxtClient.instance = new AsgardeoNuxtClient();
|
|
32
|
+
}
|
|
33
|
+
return AsgardeoNuxtClient.instance;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Initializes the underlying legacy client with OAuth/OIDC settings derived
|
|
37
|
+
* from the Nuxt module config. Idempotent — repeated calls are no-ops after
|
|
38
|
+
* the first successful initialization.
|
|
39
|
+
*/
|
|
40
|
+
async initialize(config, storage) {
|
|
41
|
+
if (this.isInitialized) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
const authConfig = {
|
|
45
|
+
afterSignInUrl: config.afterSignInUrl,
|
|
46
|
+
afterSignOutUrl: config.afterSignOutUrl || "/",
|
|
47
|
+
baseUrl: config.baseUrl,
|
|
48
|
+
clientId: config.clientId,
|
|
49
|
+
clientSecret: config.clientSecret || void 0,
|
|
50
|
+
enablePKCE: true,
|
|
51
|
+
scopes: config.scopes || ["openid", "profile"]
|
|
52
|
+
};
|
|
53
|
+
const result = await this.legacy.initialize(authConfig, storage);
|
|
54
|
+
this.isInitialized = true;
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
async reInitialize(config) {
|
|
58
|
+
await this.legacy.reInitialize(config);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Seeds the legacy in-memory token store from a verified session JWT payload.
|
|
63
|
+
*
|
|
64
|
+
* The signed session cookie is the source of truth for tokens in this SDK — it
|
|
65
|
+
* survives server restarts and new worker processes. The underlying
|
|
66
|
+
* {@link LegacyAsgardeoNodeClient}, however, keeps tokens in a
|
|
67
|
+
* {@link MemoryCacheStore} keyed by `sessionId`, and its
|
|
68
|
+
* `getAccessToken` / `getUser` / `getDecodedIdToken` / `signOut` paths all
|
|
69
|
+
* read from that store. Without rehydration, those calls fail whenever the
|
|
70
|
+
* in-memory store and the cookie diverge (the classic case: `nuxi dev`
|
|
71
|
+
* restart while the browser still holds a valid session cookie).
|
|
72
|
+
*
|
|
73
|
+
* Writes the snake_case token shape the legacy helper expects
|
|
74
|
+
* (see `AuthenticationHelper.processTokenResponse`). Safe to call on every
|
|
75
|
+
* request — it's an in-memory write and the cookie always reflects the
|
|
76
|
+
* freshest tokens (the refresh path re-issues the cookie too).
|
|
77
|
+
*/
|
|
78
|
+
async rehydrateSessionFromPayload(session) {
|
|
79
|
+
if (!this.isInitialized || !session?.sessionId || !session?.accessToken) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const storageManager = await this.legacy.getStorageManager();
|
|
83
|
+
const iatSeconds = typeof session.iat === "number" ? session.iat : Math.floor(Date.now() / 1e3);
|
|
84
|
+
const expiresInSeconds = typeof session.accessTokenExpiresAt === "number" ? Math.max(0, session.accessTokenExpiresAt - iatSeconds) : 3600;
|
|
85
|
+
await storageManager.setSessionData(
|
|
86
|
+
{
|
|
87
|
+
access_token: session.accessToken,
|
|
88
|
+
created_at: iatSeconds * 1e3,
|
|
89
|
+
expires_in: String(expiresInSeconds || 3600),
|
|
90
|
+
id_token: session.idToken ?? "",
|
|
91
|
+
refresh_token: session.refreshToken ?? "",
|
|
92
|
+
scope: session.scopes ?? "",
|
|
93
|
+
session_state: "",
|
|
94
|
+
token_type: "Bearer"
|
|
95
|
+
},
|
|
96
|
+
session.sessionId
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Initiates the authorization code flow, handles an embedded sign-in step,
|
|
101
|
+
* or exchanges a code for tokens.
|
|
102
|
+
*
|
|
103
|
+
* Overload 1 — **redirect-flow** (existing callers like `signin.get.ts`):
|
|
104
|
+
* ```
|
|
105
|
+
* signIn(authURLCallback, sessionId, code?, sessionState?, state?, config?)
|
|
106
|
+
* ```
|
|
107
|
+
* Overload 2 — **embedded flow initiate** (flowId === ''):
|
|
108
|
+
* ```
|
|
109
|
+
* signIn({flowId: ''}, request, sessionId)
|
|
110
|
+
* ```
|
|
111
|
+
* Dispatches to `initializeEmbeddedSignInFlow`.
|
|
112
|
+
*
|
|
113
|
+
* Overload 3 — **embedded flow execute** (flowId set):
|
|
114
|
+
* ```
|
|
115
|
+
* signIn(payload, request, sessionId)
|
|
116
|
+
* ```
|
|
117
|
+
* Dispatches to `executeEmbeddedSignInFlow`.
|
|
118
|
+
*
|
|
119
|
+
* Overload 4 — **code exchange** (completion after embedded flow):
|
|
120
|
+
* ```
|
|
121
|
+
* signIn({code, state, session_state}, {}, sessionId)
|
|
122
|
+
* ```
|
|
123
|
+
* Falls through to the legacy redirect-flow code-exchange path.
|
|
124
|
+
*/
|
|
125
|
+
signIn(...args) {
|
|
126
|
+
const arg0 = args[0];
|
|
127
|
+
if (typeof arg0 === "object" && arg0 !== null && "flowId" in arg0) {
|
|
128
|
+
const sessionId = args[2];
|
|
129
|
+
if (arg0.flowId === "") {
|
|
130
|
+
return this.getAuthorizeRequestUrl(
|
|
131
|
+
{ client_secret: "{{clientSecret}}", response_mode: "direct" },
|
|
132
|
+
sessionId
|
|
133
|
+
).then((authorizeUrl) => {
|
|
134
|
+
const url = new URL(authorizeUrl);
|
|
135
|
+
return initializeEmbeddedSignInFlow({
|
|
136
|
+
payload: Object.fromEntries(url.searchParams.entries()),
|
|
137
|
+
url: `${url.origin}${url.pathname}`
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const request = args[1] ?? {};
|
|
142
|
+
return executeEmbeddedSignInFlow({
|
|
143
|
+
payload: arg0,
|
|
144
|
+
url: request.url
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (typeof arg0 === "object" && arg0 !== null && ("code" in arg0 || "state" in arg0)) {
|
|
148
|
+
const payload = arg0;
|
|
149
|
+
const code = typeof payload.code === "string" ? payload.code : void 0;
|
|
150
|
+
const sessionState = typeof payload.session_state === "string" ? payload.session_state : void 0;
|
|
151
|
+
const state = typeof payload.state === "string" ? payload.state : void 0;
|
|
152
|
+
const extraParams = {};
|
|
153
|
+
if (code) {
|
|
154
|
+
extraParams.code = code;
|
|
155
|
+
}
|
|
156
|
+
if (sessionState) {
|
|
157
|
+
extraParams.session_state = sessionState;
|
|
158
|
+
}
|
|
159
|
+
if (state) {
|
|
160
|
+
extraParams.state = state;
|
|
161
|
+
}
|
|
162
|
+
return this.legacy.signIn(args[3], args[2], code, sessionState, state, extraParams);
|
|
163
|
+
}
|
|
164
|
+
return this.legacy.signIn(args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
165
|
+
}
|
|
166
|
+
async signUp(payloadOrOptions) {
|
|
167
|
+
if (!payloadOrOptions || !("flowType" in payloadOrOptions)) {
|
|
168
|
+
return void 0;
|
|
169
|
+
}
|
|
170
|
+
const configData = await this.legacy.getConfigData?.();
|
|
171
|
+
const baseUrl = configData?.baseUrl;
|
|
172
|
+
const response = await executeEmbeddedSignUpFlow({
|
|
173
|
+
baseUrl,
|
|
174
|
+
payload: payloadOrOptions
|
|
175
|
+
});
|
|
176
|
+
return response;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Returns the OAuth2 authorization URL.
|
|
180
|
+
* Used by the redirect-flow GET handler and the embedded-flow initiation path.
|
|
181
|
+
*
|
|
182
|
+
* Mirrors `AsgardeoNextClient.getAuthorizeRequestUrl`.
|
|
183
|
+
*/
|
|
184
|
+
async getAuthorizeRequestUrl(customParams, userId) {
|
|
185
|
+
return this.legacy.getSignInUrl(customParams, userId);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Clears the session and returns the RP-Initiated Logout URL.
|
|
189
|
+
* Accepts either `(sessionId: string)` or `(options?, sessionId?, callback?)`.
|
|
190
|
+
*/
|
|
191
|
+
async signOut(...args) {
|
|
192
|
+
const sessionId = typeof args[0] === "string" ? args[0] : args[1];
|
|
193
|
+
return this.legacy.signOut(sessionId);
|
|
194
|
+
}
|
|
195
|
+
getUser(sessionId) {
|
|
196
|
+
return this.legacy.getUser(sessionId);
|
|
197
|
+
}
|
|
198
|
+
getAccessToken(sessionId) {
|
|
199
|
+
return this.legacy.getAccessToken(sessionId);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Decodes and returns the ID token claims for the given session.
|
|
203
|
+
* Exposed here (as on {@link AsgardeoNextClient}) so route handlers can
|
|
204
|
+
* access ID token claims without falling back to the legacy client.
|
|
205
|
+
*/
|
|
206
|
+
getDecodedIdToken(sessionId, idToken) {
|
|
207
|
+
return this.legacy.getDecodedIdToken(sessionId, idToken);
|
|
208
|
+
}
|
|
209
|
+
isSignedIn(sessionId) {
|
|
210
|
+
return this.legacy.isSignedIn(sessionId);
|
|
211
|
+
}
|
|
212
|
+
exchangeToken(config, sessionId) {
|
|
213
|
+
return this.legacy.exchangeToken(config, sessionId);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Fetches the flattened SCIM2 user profile for the given session.
|
|
217
|
+
* Mirrors `AsgardeoNextClient.getUserProfile` — calls `getScim2Me` +
|
|
218
|
+
* `getSchemas` + `generateFlattenedUserProfile` and falls back to
|
|
219
|
+
* `getUser` claims if SCIM2 is unavailable.
|
|
220
|
+
*/
|
|
221
|
+
async getUserProfile(sessionId) {
|
|
222
|
+
const accessToken = await this.getAccessToken(sessionId);
|
|
223
|
+
const configData = await this.legacy.getConfigData?.();
|
|
224
|
+
const baseUrl = configData?.baseUrl ?? "";
|
|
225
|
+
try {
|
|
226
|
+
const authHeaders = { Authorization: `Bearer ${accessToken}` };
|
|
227
|
+
const [profile, schemas] = await Promise.all([
|
|
228
|
+
getScim2Me({ baseUrl, headers: authHeaders }),
|
|
229
|
+
getSchemas({ baseUrl, headers: authHeaders })
|
|
230
|
+
]);
|
|
231
|
+
const processedSchemas = flattenUserSchema(schemas);
|
|
232
|
+
return {
|
|
233
|
+
flattenedProfile: generateFlattenedUserProfile(profile, processedSchemas),
|
|
234
|
+
profile,
|
|
235
|
+
schemas: processedSchemas
|
|
236
|
+
};
|
|
237
|
+
} catch {
|
|
238
|
+
const user = await this.getUser(sessionId);
|
|
239
|
+
return { flattenedProfile: user, profile: user, schemas: [] };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Extracts the current organisation from the decoded ID token.
|
|
244
|
+
* Returns null when the user is not acting within an organisation.
|
|
245
|
+
*/
|
|
246
|
+
async getCurrentOrganization(sessionId) {
|
|
247
|
+
try {
|
|
248
|
+
const idToken = await this.getDecodedIdToken(sessionId);
|
|
249
|
+
if (!idToken?.org_id) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
id: idToken.org_id,
|
|
254
|
+
name: idToken.org_name ?? "",
|
|
255
|
+
orgHandle: idToken.org_handle ?? ""
|
|
256
|
+
};
|
|
257
|
+
} catch {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Returns the list of organisations the authenticated user is a member of.
|
|
263
|
+
*/
|
|
264
|
+
async getMyOrganizations(sessionId) {
|
|
265
|
+
const accessToken = await this.getAccessToken(sessionId);
|
|
266
|
+
const configData = await this.legacy.getConfigData?.();
|
|
267
|
+
const baseUrl = configData?.baseUrl ?? "";
|
|
268
|
+
return getMeOrganizations({
|
|
269
|
+
baseUrl,
|
|
270
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Fetches the branding preference for the tenant / application.
|
|
275
|
+
* Delegates to the standalone `getBrandingPreference` API helper from
|
|
276
|
+
* `@asgardeo/node`, which does not require an authenticated session.
|
|
277
|
+
*/
|
|
278
|
+
// eslint-disable-next-line class-methods-use-this
|
|
279
|
+
async getBrandingPreference(config) {
|
|
280
|
+
return getBrandingPreference(config);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Updates the SCIM2 /Me profile for the authenticated user.
|
|
284
|
+
* Mirrors `AsgardeoNextClient.updateUserProfile`.
|
|
285
|
+
*/
|
|
286
|
+
async updateUserProfile(config, sessionId) {
|
|
287
|
+
const accessToken = await this.getAccessToken(sessionId);
|
|
288
|
+
const configData = await this.legacy.getConfigData?.();
|
|
289
|
+
const baseUrl = configData?.baseUrl ?? "";
|
|
290
|
+
return updateMeProfile({
|
|
291
|
+
...config,
|
|
292
|
+
// pass-through, includes payload
|
|
293
|
+
baseUrl,
|
|
294
|
+
headers: { ...config.headers, Authorization: `Bearer ${accessToken}` }
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Retrieves all organisations accessible to the authenticated user
|
|
299
|
+
* (paginated). Mirrors `AsgardeoNextClient.getAllOrganizations`.
|
|
300
|
+
*/
|
|
301
|
+
async getAllOrganizations(options, sessionId) {
|
|
302
|
+
const resolvedSessionId = sessionId ?? "";
|
|
303
|
+
const accessToken = await this.getAccessToken(resolvedSessionId);
|
|
304
|
+
const configData = await this.legacy.getConfigData?.();
|
|
305
|
+
const baseUrl = configData?.baseUrl ?? "";
|
|
306
|
+
return getAllOrganizations({
|
|
307
|
+
baseUrl,
|
|
308
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Creates a new sub-organisation. Mirrors `AsgardeoNextClient.createOrganization`.
|
|
313
|
+
*/
|
|
314
|
+
async createOrganization(payload, sessionId) {
|
|
315
|
+
const accessToken = await this.getAccessToken(sessionId);
|
|
316
|
+
const configData = await this.legacy.getConfigData?.();
|
|
317
|
+
const baseUrl = configData?.baseUrl ?? "";
|
|
318
|
+
return createOrganization({
|
|
319
|
+
baseUrl,
|
|
320
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
321
|
+
payload
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Fetches the details of a single organisation by ID.
|
|
326
|
+
* Mirrors `AsgardeoNextClient.getOrganization`.
|
|
327
|
+
*/
|
|
328
|
+
async getOrganization(organizationId, sessionId) {
|
|
329
|
+
const accessToken = await this.getAccessToken(sessionId);
|
|
330
|
+
const configData = await this.legacy.getConfigData?.();
|
|
331
|
+
const baseUrl = configData?.baseUrl ?? "";
|
|
332
|
+
return getOrganization({
|
|
333
|
+
baseUrl,
|
|
334
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
335
|
+
organizationId
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Performs an organisation-switch token exchange and returns the new
|
|
340
|
+
* `TokenResponse`. The caller (the Nitro route) is responsible for
|
|
341
|
+
* persisting the new session cookie.
|
|
342
|
+
*
|
|
343
|
+
* Mirrors `AsgardeoNextClient.switchOrganization`.
|
|
344
|
+
*/
|
|
345
|
+
async switchOrganization(organization, sessionId) {
|
|
346
|
+
if (!organization.id) {
|
|
347
|
+
throw new Error("Organization ID is required for switching organizations.");
|
|
348
|
+
}
|
|
349
|
+
const exchangeConfig = {
|
|
350
|
+
attachToken: false,
|
|
351
|
+
data: {
|
|
352
|
+
client_id: "{{clientId}}",
|
|
353
|
+
client_secret: "{{clientSecret}}",
|
|
354
|
+
grant_type: "organization_switch",
|
|
355
|
+
scope: "{{scopes}}",
|
|
356
|
+
switching_organization: organization.id,
|
|
357
|
+
token: "{{accessToken}}"
|
|
358
|
+
},
|
|
359
|
+
id: "organization-switch",
|
|
360
|
+
returnsSession: true,
|
|
361
|
+
signInRequired: true
|
|
362
|
+
};
|
|
363
|
+
return this.legacy.exchangeToken(exchangeConfig, sessionId);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
export default AsgardeoNuxtClient;
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
/**
|
|
19
|
+
* @asgardeo/nuxt/server
|
|
20
|
+
*
|
|
21
|
+
* Public server-only barrel. Import from this subpath to access
|
|
22
|
+
* server utilities without bundling them into the client.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { useServerSession, requireServerSession } from '@asgardeo/nuxt/server';
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export { useServerSession, requireServerSession } from './utils/serverSession.js';
|
|
30
|
+
export { getValidAccessToken } from './utils/token-refresh.js';
|
|
31
|
+
export { getAsgardeoContext } from './utils/event-context.js';
|
|
32
|
+
export type { AsgardeoEventContext } from './utils/event-context.js';
|
|
33
|
+
export type { AsgardeoSessionPayload, AsgardeoNuxtConfig } from '../types.js';
|
|
@@ -0,0 +1,41 @@
|
|
|
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 '../../types/augments.d.js';
|
|
19
|
+
/**
|
|
20
|
+
* Nitro server plugin — the Nuxt equivalent of `AsgardeoServerProvider` in the
|
|
21
|
+
* Next.js SDK.
|
|
22
|
+
*
|
|
23
|
+
* On every page request it:
|
|
24
|
+
* 1. Initialises the singleton {@link AsgardeoNuxtClient} once (idempotent).
|
|
25
|
+
* 2. Verifies the JWT session cookie → resolves `isSignedIn`.
|
|
26
|
+
* 3. When signed in, detects org context from the ID token (`user_org`) and
|
|
27
|
+
* switches `resolvedBaseUrl` to `${baseUrl}/o` when the user is acting
|
|
28
|
+
* within an organisation.
|
|
29
|
+
* 4. In parallel (gated by `preferences`):
|
|
30
|
+
* - Fetches user + SCIM2 user profile (`preferences.user.fetchUserProfile !== false`)
|
|
31
|
+
* - Fetches current org + my orgs (`preferences.user.fetchOrganizations !== false`)
|
|
32
|
+
* - Fetches branding preference (`preferences.theme.inheritFromBranding !== false`)
|
|
33
|
+
* 5. Writes the full {@link AsgardeoSSRData} to `event.context.asgardeo.ssr`
|
|
34
|
+
* so the Nuxt plugin can seed `useState` keys for zero-cost hydration.
|
|
35
|
+
*
|
|
36
|
+
* Each fetch is individually wrapped in try/catch so a broken SCIM or branding
|
|
37
|
+
* call never crashes SSR — the client layer can recover via the existing
|
|
38
|
+
* `/api/auth/*` routes.
|
|
39
|
+
*/
|
|
40
|
+
declare const _default: import("nitropack/types").NitroAppPlugin;
|
|
41
|
+
export default _default;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { getRequestURL } from "h3";
|
|
2
|
+
import { defineNitroPlugin } from "nitropack/runtime";
|
|
3
|
+
import { createLogger } from "../../utils/log.js";
|
|
4
|
+
import AsgardeoNuxtClient from "../AsgardeoNuxtClient.js";
|
|
5
|
+
import { verifyAndRehydrateSession } from "../utils/serverSession.js";
|
|
6
|
+
import { useRuntimeConfig } from "#imports";
|
|
7
|
+
import "../../types/augments.d";
|
|
8
|
+
const log = createLogger("asgardeo-ssr");
|
|
9
|
+
const CALLBACK_PATH = "/api/auth/callback";
|
|
10
|
+
function resolveCallbackUrl(event) {
|
|
11
|
+
const url = getRequestURL(event, { xForwardedHost: true, xForwardedProto: true });
|
|
12
|
+
return `${url.origin}${CALLBACK_PATH}`;
|
|
13
|
+
}
|
|
14
|
+
export default defineNitroPlugin((nitro) => {
|
|
15
|
+
nitro.hooks.hook("request", async (event) => {
|
|
16
|
+
const client = AsgardeoNuxtClient.getInstance();
|
|
17
|
+
if (!client.isInitialized) {
|
|
18
|
+
const config2 = useRuntimeConfig(event);
|
|
19
|
+
const publicConfig2 = config2.public.asgardeo;
|
|
20
|
+
const privateConfig = config2.asgardeo;
|
|
21
|
+
if (!publicConfig2?.baseUrl || !publicConfig2?.clientId) {
|
|
22
|
+
log.error(
|
|
23
|
+
"Missing required config: baseUrl and clientId. Set NUXT_PUBLIC_ASGARDEO_BASE_URL and NUXT_PUBLIC_ASGARDEO_CLIENT_ID."
|
|
24
|
+
);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const sessionSecret2 = process.env["ASGARDEO_SESSION_SECRET"] || privateConfig?.sessionSecret;
|
|
28
|
+
if (!sessionSecret2) {
|
|
29
|
+
if (process.env["NODE_ENV"] === "production") {
|
|
30
|
+
log.error(
|
|
31
|
+
"ASGARDEO_SESSION_SECRET is required in production. Set it to a secure random string of at least 32 characters. Refusing to initialize Asgardeo client."
|
|
32
|
+
);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
log.warn(
|
|
36
|
+
"ASGARDEO_SESSION_SECRET is not set. Using an insecure default for development only. Set ASGARDEO_SESSION_SECRET before deploying."
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
await client.initialize({
|
|
41
|
+
afterSignInUrl: resolveCallbackUrl(event),
|
|
42
|
+
afterSignOutUrl: publicConfig2.afterSignOutUrl || "/",
|
|
43
|
+
baseUrl: publicConfig2.baseUrl,
|
|
44
|
+
clientId: publicConfig2.clientId,
|
|
45
|
+
clientSecret: privateConfig?.clientSecret || void 0,
|
|
46
|
+
scopes: publicConfig2.scopes || ["openid", "profile"]
|
|
47
|
+
});
|
|
48
|
+
} catch (err) {
|
|
49
|
+
log.error("Failed to initialize Asgardeo client:", err);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const url = event.path || "";
|
|
54
|
+
if (url.startsWith("/api/") || url.startsWith("/_nuxt/") || url.startsWith("/__nuxt_")) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const config = useRuntimeConfig(event);
|
|
58
|
+
const publicConfig = config.public.asgardeo;
|
|
59
|
+
const prefs = publicConfig?.preferences;
|
|
60
|
+
const sessionSecret = process.env["ASGARDEO_SESSION_SECRET"] || config.asgardeo?.sessionSecret;
|
|
61
|
+
const session = await verifyAndRehydrateSession(
|
|
62
|
+
event,
|
|
63
|
+
sessionSecret
|
|
64
|
+
);
|
|
65
|
+
if (!session) {
|
|
66
|
+
const eventContext2 = event.context;
|
|
67
|
+
eventContext2.asgardeo = { isSignedIn: false, session: null };
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const baseUrl = publicConfig?.baseUrl ?? "";
|
|
71
|
+
let resolvedBaseUrl = baseUrl;
|
|
72
|
+
try {
|
|
73
|
+
if (session.organizationId) {
|
|
74
|
+
resolvedBaseUrl = `${baseUrl}/o`;
|
|
75
|
+
} else {
|
|
76
|
+
const idToken = await client.getDecodedIdToken(
|
|
77
|
+
session.sessionId
|
|
78
|
+
);
|
|
79
|
+
if (idToken?.["user_org"]) {
|
|
80
|
+
resolvedBaseUrl = `${baseUrl}/o`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
const shouldFetchProfile = prefs?.user?.fetchUserProfile !== false;
|
|
86
|
+
const shouldFetchOrgs = prefs?.user?.fetchOrganizations !== false;
|
|
87
|
+
const shouldFetchBranding = prefs?.theme?.inheritFromBranding !== false;
|
|
88
|
+
const [userResult, userProfileResult, orgsResult, currentOrgResult, brandingResult] = await Promise.allSettled([
|
|
89
|
+
// Always fetch the basic user object (needed for AsgardeoAuthState.user)
|
|
90
|
+
client.getUser(session.sessionId),
|
|
91
|
+
// SCIM2 user profile (flattened + schemas)
|
|
92
|
+
shouldFetchProfile ? client.getUserProfile(session.sessionId) : Promise.resolve(null),
|
|
93
|
+
// User's organisations
|
|
94
|
+
shouldFetchOrgs ? client.getMyOrganizations(session.sessionId) : Promise.resolve([]),
|
|
95
|
+
// Current organisation (derived from the ID token)
|
|
96
|
+
shouldFetchOrgs ? client.getCurrentOrganization(session.sessionId) : Promise.resolve(null),
|
|
97
|
+
// Branding preference (does not require a session)
|
|
98
|
+
shouldFetchBranding ? client.getBrandingPreference({ baseUrl: resolvedBaseUrl }) : Promise.resolve(null)
|
|
99
|
+
]);
|
|
100
|
+
if (userResult.status === "rejected") {
|
|
101
|
+
log.debug("Failed to fetch user:", userResult.reason);
|
|
102
|
+
}
|
|
103
|
+
if (userProfileResult.status === "rejected") {
|
|
104
|
+
log.warn("Failed to fetch user profile (SCIM2):", userProfileResult.reason);
|
|
105
|
+
}
|
|
106
|
+
if (orgsResult.status === "rejected") {
|
|
107
|
+
log.warn("Failed to fetch my organisations:", orgsResult.reason);
|
|
108
|
+
}
|
|
109
|
+
if (currentOrgResult.status === "rejected") {
|
|
110
|
+
log.warn("Failed to resolve current organisation:", currentOrgResult.reason);
|
|
111
|
+
}
|
|
112
|
+
if (brandingResult.status === "rejected") {
|
|
113
|
+
log.warn("Failed to fetch branding preference:", brandingResult.reason);
|
|
114
|
+
}
|
|
115
|
+
const ssrData = {
|
|
116
|
+
brandingPreference: brandingResult.status === "fulfilled" ? brandingResult.value : null,
|
|
117
|
+
currentOrganization: currentOrgResult.status === "fulfilled" ? currentOrgResult.value : null,
|
|
118
|
+
isSignedIn: true,
|
|
119
|
+
myOrganizations: orgsResult.status === "fulfilled" && Array.isArray(orgsResult.value) ? orgsResult.value : [],
|
|
120
|
+
resolvedBaseUrl,
|
|
121
|
+
session,
|
|
122
|
+
user: userResult.status === "fulfilled" ? userResult.value : null,
|
|
123
|
+
userProfile: userProfileResult.status === "fulfilled" ? userProfileResult.value : null
|
|
124
|
+
};
|
|
125
|
+
const eventContext = event.context;
|
|
126
|
+
eventContext.asgardeo = { isSignedIn: true, session, ssr: ssrData };
|
|
127
|
+
const authState = {
|
|
128
|
+
isLoading: false,
|
|
129
|
+
isSignedIn: true,
|
|
130
|
+
user: ssrData.user
|
|
131
|
+
};
|
|
132
|
+
eventContext["__asgardeoAuth"] = authState;
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
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 { BrandingPreference } from '@asgardeo/node';
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/auth/branding
|
|
21
|
+
*
|
|
22
|
+
* Returns the branding preference for the current tenant / organisation context.
|
|
23
|
+
* Resolves the correct `baseUrl` (org-scoped if the session is inside an org).
|
|
24
|
+
* Does not require an authenticated session — unauthenticated callers receive
|
|
25
|
+
* the root-tenant branding.
|
|
26
|
+
*
|
|
27
|
+
* Used by `AsgardeoRoot.revalidateBranding` to refresh client-side branding
|
|
28
|
+
* state without a full page reload.
|
|
29
|
+
*/
|
|
30
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<BrandingPreference | null>>;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { defineEventHandler, createError } from "h3";
|
|
2
|
+
import AsgardeoNuxtClient from "../../../AsgardeoNuxtClient.js";
|
|
3
|
+
import { verifyAndRehydrateSession } from "../../../utils/serverSession.js";
|
|
4
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const config = useRuntimeConfig(event);
|
|
7
|
+
const publicConfig = config.public.asgardeo;
|
|
8
|
+
const sessionSecret = config.asgardeo?.sessionSecret;
|
|
9
|
+
const baseUrl = publicConfig?.baseUrl ?? "";
|
|
10
|
+
let resolvedBaseUrl = baseUrl;
|
|
11
|
+
try {
|
|
12
|
+
const session = await verifyAndRehydrateSession(
|
|
13
|
+
event,
|
|
14
|
+
sessionSecret
|
|
15
|
+
);
|
|
16
|
+
if (session) {
|
|
17
|
+
if (session.organizationId) {
|
|
18
|
+
resolvedBaseUrl = `${baseUrl}/o`;
|
|
19
|
+
} else {
|
|
20
|
+
const client = AsgardeoNuxtClient.getInstance();
|
|
21
|
+
const idToken = await client.getDecodedIdToken(
|
|
22
|
+
session.sessionId
|
|
23
|
+
);
|
|
24
|
+
if (idToken?.["user_org"]) {
|
|
25
|
+
resolvedBaseUrl = `${baseUrl}/o`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const client = AsgardeoNuxtClient.getInstance();
|
|
33
|
+
return await client.getBrandingPreference({ baseUrl: resolvedBaseUrl });
|
|
34
|
+
} catch (err) {
|
|
35
|
+
throw createError({
|
|
36
|
+
statusCode: 500,
|
|
37
|
+
statusMessage: `Failed to retrieve branding preference: ${err instanceof Error ? err.message : String(err)}`
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
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 { Organization } from '@asgardeo/node';
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/auth/organizations/current
|
|
21
|
+
*
|
|
22
|
+
* Returns the organisation the authenticated user is currently acting within,
|
|
23
|
+
* derived from the session's ID token (`org_id` / `org_name` claims).
|
|
24
|
+
* Returns `null` when the user is not inside an organisation context.
|
|
25
|
+
*
|
|
26
|
+
* Used by `AsgardeoRoot.revalidateCurrentOrganization` callback.
|
|
27
|
+
*/
|
|
28
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Organization | null>>;
|
|
29
|
+
export default _default;
|