@merkaly/nuxt 0.12.4 → 0.12.5
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 +14 -0
- package/dist/module.json +1 -1
- package/dist/runtime/components/auth.d.vue.ts +6 -2
- package/dist/runtime/components/auth.vue +5 -1
- package/dist/runtime/components/auth.vue.d.ts +6 -2
- package/dist/runtime/composables/useAuth.d.ts +3 -0
- package/dist/runtime/composables/useAuth.js +5 -0
- package/dist/runtime/plugins/auth0.client.js +3 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -35,6 +35,20 @@ On boot the module restores an existing session (user and token) and then runs t
|
|
|
35
35
|
| store | optional | required | `merkaly:tenant` resolves the store from the host (public); a signed-in buyer is restored too; protected pages (account, checkout) ask for login. |
|
|
36
36
|
| www | optional | not used | No hooks; anonymous or signed-in. |
|
|
37
37
|
|
|
38
|
+
### Login entry points (`MKAuth`)
|
|
39
|
+
|
|
40
|
+
The callback page renders `MKAuth`, which reads its query string:
|
|
41
|
+
|
|
42
|
+
| Query | Behavior |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `?code=...` (Auth0 callback) | Completes the login, navigates to the `appState.target` set when it started (or `/`) and emits `success` with that `appState`. |
|
|
45
|
+
| `?error=...&error_description=...` | Emits `error` and shows a 400 error page. |
|
|
46
|
+
| `?invitation=<ticket>&organization=<org_id>` | Accepts an organization invitation (Auth0 Organizations). |
|
|
47
|
+
| `?organization=<org_id>[&redirect=/path]` | Logs in straight into that organization (a silent login when the Auth0 session exists) and lands on `redirect`, e.g. `https://admin.merkaly.io/auth?organization=org_123&redirect=/onboarding` right after creating a store in www. |
|
|
48
|
+
| `?redirect=/path` | Plain login, lands on `redirect` (the auth middleware sends protected pages here). |
|
|
49
|
+
|
|
50
|
+
To open the Auth0 signup screen instead of the login one, use `useAuth().signup({ redirectTo })`: it calls `loginWithRedirect` with `screen_hint: 'signup'` and `appState: { target: redirectTo }`, so after the callback the app lands on `redirectTo` (default `/`).
|
|
51
|
+
|
|
38
52
|
### Session lifetime
|
|
39
53
|
|
|
40
54
|
The SPA keeps the session with **refresh tokens**: the client uses `useRefreshTokens` with `localStorage` cache and logs in with `audience` and `scope: openid profile email offline_access`. Before each API call the module asks Auth0 for the current access token, which is cached and renewed with the refresh token once it expires (2 hours for `https://api.merkaly.io`). When the refresh token is gone or expired, protected surfaces (`requiresAuth: true`) go back to login instead of calling the API without a token. Account linking (`linkWithConnection(connection)`) uses a separate Auth0 client, the `auth.merkaly.io` SPA client in Auth0, with an in-memory cache, created only on the first call (no extra `checkSession` on page load). It opens a login popup for that connection and sends the popup's raw ID token to `POST /auth/identities` as `{ idToken }`; the api verifies the token (signature, issuer, audience = the account linking client, expiry) and links the identity from its `sub` into the logged-in user. Requires an api with that contract (older clients that sent `{ provider, userId }` get `400`).
|
package/dist/module.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
2
2
|
error: (reason: string) => any;
|
|
3
|
-
success: (
|
|
3
|
+
success: (appState?: {
|
|
4
|
+
target?: string;
|
|
5
|
+
} | undefined) => any;
|
|
4
6
|
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
5
7
|
onError?: ((reason: string) => any) | undefined;
|
|
6
|
-
onSuccess?: ((
|
|
8
|
+
onSuccess?: ((appState?: {
|
|
9
|
+
target?: string;
|
|
10
|
+
} | undefined) => any) | undefined;
|
|
7
11
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
8
12
|
declare const _default: typeof __VLS_export;
|
|
9
13
|
export default _default;
|
|
@@ -12,6 +12,9 @@ const redirect = params.get("redirect");
|
|
|
12
12
|
function handleInvite() {
|
|
13
13
|
return $auth0.loginWithRedirect({ authorizationParams: { organization, invitation } });
|
|
14
14
|
}
|
|
15
|
+
function handleOrganization() {
|
|
16
|
+
return $auth0.loginWithRedirect({ appState: { target: redirect || "/" }, authorizationParams: { organization } });
|
|
17
|
+
}
|
|
15
18
|
function handleError() {
|
|
16
19
|
const errorDescription = params.get("error_description") ?? "Auth error";
|
|
17
20
|
emit("error", errorDescription);
|
|
@@ -21,12 +24,13 @@ function handleError() {
|
|
|
21
24
|
});
|
|
22
25
|
}
|
|
23
26
|
function handleCode() {
|
|
24
|
-
return void $auth0.handleRedirectCallback().then(() => emit("success"));
|
|
27
|
+
return void $auth0.handleRedirectCallback().then((result) => emit("success", result?.appState));
|
|
25
28
|
}
|
|
26
29
|
callOnce(async () => {
|
|
27
30
|
if (error) return handleError();
|
|
28
31
|
if (code) return handleCode();
|
|
29
32
|
if (invitation && organization) return handleInvite();
|
|
33
|
+
if (organization) return handleOrganization();
|
|
30
34
|
return $auth0.loginWithRedirect({ appState: { target: redirect || "/" } });
|
|
31
35
|
});
|
|
32
36
|
</script>
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
2
2
|
error: (reason: string) => any;
|
|
3
|
-
success: (
|
|
3
|
+
success: (appState?: {
|
|
4
|
+
target?: string;
|
|
5
|
+
} | undefined) => any;
|
|
4
6
|
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
5
7
|
onError?: ((reason: string) => any) | undefined;
|
|
6
|
-
onSuccess?: ((
|
|
8
|
+
onSuccess?: ((appState?: {
|
|
9
|
+
target?: string;
|
|
10
|
+
} | undefined) => any) | undefined;
|
|
7
11
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
8
12
|
declare const _default: typeof __VLS_export;
|
|
9
13
|
export default _default;
|
|
@@ -20,6 +20,9 @@ export declare const useAuth: () => {
|
|
|
20
20
|
isLoading: import("vue").Ref<boolean, boolean>;
|
|
21
21
|
logout: () => any;
|
|
22
22
|
retry: () => Promise<void>;
|
|
23
|
+
signup: ({ redirectTo }?: {
|
|
24
|
+
redirectTo?: string;
|
|
25
|
+
}) => any;
|
|
23
26
|
token: import("vue").Ref<string | null, string | null>;
|
|
24
27
|
user: import("vue").Ref<User | undefined, User | undefined>;
|
|
25
28
|
};
|
|
@@ -9,6 +9,10 @@ export const useAuth = () => {
|
|
|
9
9
|
const isAuthenticated = computed(() => Boolean(user.value?.sub));
|
|
10
10
|
const clear = () => error.value = void 0;
|
|
11
11
|
const logout = () => nuxtApp.$auth0.logout();
|
|
12
|
+
const signup = ({ redirectTo = "/" } = {}) => nuxtApp.$auth0.loginWithRedirect({
|
|
13
|
+
appState: { target: redirectTo },
|
|
14
|
+
authorizationParams: { screen_hint: "signup" }
|
|
15
|
+
});
|
|
12
16
|
const retry = async () => {
|
|
13
17
|
isLoading.value = true;
|
|
14
18
|
clear();
|
|
@@ -31,6 +35,7 @@ export const useAuth = () => {
|
|
|
31
35
|
isLoading,
|
|
32
36
|
logout,
|
|
33
37
|
retry,
|
|
38
|
+
signup,
|
|
34
39
|
token,
|
|
35
40
|
user
|
|
36
41
|
};
|
|
@@ -53,10 +53,12 @@ export default defineNuxtPlugin(async ({ callHook, hook }) => {
|
|
|
53
53
|
return initTenantContext();
|
|
54
54
|
};
|
|
55
55
|
hook("merkaly:auth:retry", () => resolveIdentity().then(startSession));
|
|
56
|
-
auth0.handleRedirectCallback = () => self0.handleRedirectCallback().then(async (
|
|
56
|
+
auth0.handleRedirectCallback = () => self0.handleRedirectCallback().then(async (result) => {
|
|
57
|
+
const { appState } = result;
|
|
57
58
|
await resolveIdentity();
|
|
58
59
|
await startSession();
|
|
59
60
|
void navigateTo(appState?.target || "/");
|
|
61
|
+
return result;
|
|
60
62
|
}, (reason) => fail({ message: reason.error_description || reason.message, stage: "callback" }));
|
|
61
63
|
auth0.loginWithRedirect = (options = {}) => self0.loginWithRedirect(defu(options, {
|
|
62
64
|
authorizationParams: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@merkaly/nuxt",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.5",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/merkaly-io/nuxt.git"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@auth0/auth0-spa-js": "^2.30.0",
|
|
32
32
|
"@bootstrap-vue-next/nuxt": "^1.0.0",
|
|
33
|
-
"@nuxt/devtools": "^4.
|
|
33
|
+
"@nuxt/devtools": "^4.1.0",
|
|
34
34
|
"@nuxt/eslint": "1.17.0",
|
|
35
35
|
"@nuxt/eslint-config": "^1.17.0",
|
|
36
36
|
"@nuxt/fonts": "1.2.0",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@nuxtjs/plausible": "^4.0.0",
|
|
41
41
|
"@nuxtjs/robots": "^7.0.2",
|
|
42
42
|
"@nuxtjs/sitemap": "^9.1.0",
|
|
43
|
-
"@sentry/nuxt": "^11.
|
|
43
|
+
"@sentry/nuxt": "^11.11.0",
|
|
44
44
|
"@types/node": "latest",
|
|
45
45
|
"@types/vue-select": "^3.16.8",
|
|
46
46
|
"@vueuse/components": "^15.0.0",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"gsap": "^3.15.0",
|
|
58
58
|
"notivue": "^2.4.5",
|
|
59
59
|
"nuxt": "^4.6.3",
|
|
60
|
-
"posthog-js": "^1.
|
|
60
|
+
"posthog-js": "^1.447.1",
|
|
61
61
|
"reflect-metadata": "^0.2.2",
|
|
62
|
-
"sass": "^1.
|
|
62
|
+
"sass": "^1.108.0",
|
|
63
63
|
"typescript": "~5.9.3",
|
|
64
64
|
"v-money3": "^3.26.1",
|
|
65
65
|
"vite-svg-loader": "^5.1.1",
|