@lenne.tech/nuxt-extensions 1.18.4 → 1.18.6

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.d.mts CHANGED
@@ -3,7 +3,7 @@ import { LtExtensionsModuleOptions } from '../dist/runtime/types/index.js';
3
3
  export * from '../dist/runtime/types/index.js';
4
4
 
5
5
  declare const name = "@lenne.tech/nuxt-extensions";
6
- declare const version = "1.18.4";
6
+ declare const version = "1.18.6";
7
7
  declare const configKey = "ltExtensions";
8
8
  declare const DEFAULT_LT_AUTH_STATE_COOKIE = "lt-auth-state";
9
9
  declare const DEFAULT_LT_JWT_TOKEN_COOKIE = "lt-jwt-token";
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "configKey": "ltExtensions",
3
3
  "name": "@lenne.tech/nuxt-extensions",
4
- "version": "1.18.4",
4
+ "version": "1.18.6",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.3",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -2,7 +2,7 @@ import { defineNuxtModule, createResolver, tryResolveModule, addImports, addComp
2
2
  import { pathToFileURL } from 'node:url';
3
3
 
4
4
  const name = "@lenne.tech/nuxt-extensions";
5
- const version = "1.18.4";
5
+ const version = "1.18.6";
6
6
  const configKey = "ltExtensions";
7
7
  const DEFAULT_LT_AUTH_STATE_COOKIE = "lt-auth-state";
8
8
  const DEFAULT_LT_JWT_TOKEN_COOKIE = "lt-jwt-token";
@@ -82,6 +82,13 @@ const module$1 = defineNuxtModule({
82
82
  nuxt.options.nitro ??= {};
83
83
  nuxt.options.nitro.alias = { ...nuxt.options.nitro.alias, "@better-auth/passkey/client": passkeyStub };
84
84
  }
85
+ const uiToastAvailable = !!await tryResolveModule("@nuxt/ui/composables/useToast", [new URL(import.meta.url), pathToFileURL(`${nuxt.options.rootDir}/`)]);
86
+ if (!uiToastAvailable) {
87
+ const uiToastStub = resolve("./runtime/lib/ui-toast-stub");
88
+ nuxt.options.alias["@nuxt/ui/composables/useToast"] = uiToastStub;
89
+ nuxt.options.nitro ??= {};
90
+ nuxt.options.nitro.alias = { ...nuxt.options.nitro.alias, "@nuxt/ui/composables/useToast": uiToastStub };
91
+ }
85
92
  const enablePasskey = (resolvedOptions.auth?.enablePasskey ?? true) && passkeyAvailable;
86
93
  if ((resolvedOptions.auth?.enablePasskey ?? true) && !passkeyAvailable) {
87
94
  console.warn(
@@ -1,5 +1,6 @@
1
1
  import { computed, ref, useState, useNuxtApp, useRuntimeConfig } from "#imports";
2
2
  import { buildLtApiUrl } from "../lib/auth-state.js";
3
+ import { ltAddToast } from "../lib/toast.js";
3
4
  const ERROR_CODE_REGEX = /^#([A-Z_]+_\d+):\s*(.+)$/;
4
5
  export function useLtErrorTranslation() {
5
6
  const nuxtApp = useNuxtApp();
@@ -101,21 +102,14 @@ export function useLtErrorTranslation() {
101
102
  return;
102
103
  }
103
104
  const parsed = parseError(errorOrMessage);
104
- try {
105
- nuxtApp.runWithContext(() => {
106
- const toastComposable = nuxtApp.useToast || globalThis.useToast;
107
- if (typeof toastComposable === "function") {
108
- const toast = toastComposable();
109
- toast.add({
110
- color: "error",
111
- title: title || t("lt.error.title", "Fehler"),
112
- description: parsed.translatedMessage
113
- });
114
- } else {
115
- console.error("[LtErrorTranslation]", parsed.translatedMessage);
116
- }
117
- });
118
- } catch {
105
+ const shown = nuxtApp.runWithContext(
106
+ () => ltAddToast({
107
+ color: "error",
108
+ description: parsed.translatedMessage,
109
+ title: title || t("lt.error.title", "Fehler")
110
+ })
111
+ );
112
+ if (!shown) {
119
113
  console.error("[LtErrorTranslation]", parsed.translatedMessage);
120
114
  }
121
115
  }
@@ -1,4 +1,5 @@
1
1
  import { useNuxtApp, useRoute } from "#imports";
2
+ import { ltAddToast } from "../lib/toast.js";
2
3
  export function useLtShare() {
3
4
  const route = useRoute();
4
5
  const nuxtApp = useNuxtApp();
@@ -26,19 +27,14 @@ export function useLtShare() {
26
27
  } else {
27
28
  try {
28
29
  await navigator.clipboard.writeText(url ?? window.location.origin);
29
- const useToast = nuxtApp.$useToast || globalThis.useToast;
30
- if (typeof useToast === "function") {
31
- try {
32
- const toast = useToast();
33
- toast.add({
34
- color: "success",
35
- description: t("lt.share.copiedDescription", "Der Link wurde in die Zwischenablage kopiert."),
36
- title: t("lt.share.copied", "Link kopiert")
37
- });
38
- } catch {
39
- console.debug("Link copied to clipboard");
40
- }
41
- } else {
30
+ const shown = nuxtApp.runWithContext(
31
+ () => ltAddToast({
32
+ color: "success",
33
+ description: t("lt.share.copiedDescription", "Der Link wurde in die Zwischenablage kopiert."),
34
+ title: t("lt.share.copied", "Link kopiert")
35
+ })
36
+ );
37
+ if (!shown) {
42
38
  console.debug("Link copied to clipboard");
43
39
  }
44
40
  } catch (error) {
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Toast helper
3
+ *
4
+ * Single place where the module talks to Nuxt UI's toaster.
5
+ *
6
+ * Composables used to look the composable up on `nuxtApp` / `globalThis`
7
+ * (`(nuxtApp as any).useToast || (globalThis as any).useToast`). Nuxt UI exposes
8
+ * `useToast` as an auto-import and puts it on neither, so that lookup was always
9
+ * `undefined` and every toast silently degraded to a `console.*` line — users
10
+ * got no visible feedback at all.
11
+ *
12
+ * Importing Nuxt UI's `useToast` directly is what actually works. The specifier
13
+ * resolves to the very same file the auto-import points at, so the toast lands
14
+ * in the `useState('toasts')` array that `<UApp>` / `<UToaster>` renders.
15
+ * `module.ts` aliases it onto {@link ui-toast-stub} when `@nuxt/ui` is not
16
+ * installed, which keeps it an optional peer.
17
+ */
18
+ /** Semantic toast colors — mirrors Nuxt UI's color tokens. */
19
+ export type LtToastColor = 'error' | 'info' | 'neutral' | 'primary' | 'secondary' | 'success' | 'warning';
20
+ export interface LtToastOptions {
21
+ color?: LtToastColor;
22
+ description?: string;
23
+ title?: string;
24
+ }
25
+ /**
26
+ * Show a toast, if the app has a toaster.
27
+ *
28
+ * Call it inside `nuxtApp.runWithContext()` when you are past an `await` or
29
+ * outside a component: `useToast()` needs the Nuxt instance for `useState`.
30
+ *
31
+ * @param options - Toast color, title and description
32
+ * @returns `true` when the toast was handed to Nuxt UI, `false` when no toaster
33
+ * is available (or it threw) — callers use this to fall back to the console
34
+ * instead of swallowing the message.
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * if (!ltAddToast({ color: 'error', description: message, title: 'Fehler' })) {
39
+ * console.error('[MyComposable]', message);
40
+ * }
41
+ * ```
42
+ */
43
+ export declare function ltAddToast(options: LtToastOptions): boolean;
@@ -0,0 +1,13 @@
1
+ import { useToast } from "@nuxt/ui/composables/useToast";
2
+ export function ltAddToast(options) {
3
+ try {
4
+ const toast = useToast();
5
+ if (typeof toast?.add !== "function") {
6
+ return false;
7
+ }
8
+ toast.add(options);
9
+ return true;
10
+ } catch {
11
+ return false;
12
+ }
13
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Build-time stand-in for Nuxt UI's `@nuxt/ui/composables/useToast`.
3
+ *
4
+ * `@nuxt/ui` is an OPTIONAL peer of this module, but `runtime/lib/toast.ts`
5
+ * imports `useToast` at the top level — so the bundler must resolve the
6
+ * specifier even in a project that ships a different UI layer. `module.ts`
7
+ * aliases `@nuxt/ui/composables/useToast` onto this file when the package is
8
+ * absent; without it the build would fail on an unresolved optional peer
9
+ * instead of honouring the optionality (same pattern as `passkey-stub.ts`).
10
+ *
11
+ * The alias rewrites the specifier for the WHOLE consumer app, so this file
12
+ * mirrors every name the real module exports. `test/lt-toast.test.ts` pins that
13
+ * surface against the real package.
14
+ */
15
+ /** Mirror of Nuxt UI's injection key for the toaster's `max` prop. */
16
+ export declare const toastMaxInjectionKey: unique symbol;
17
+ /**
18
+ * No-op replacement for Nuxt UI's `useToast()`.
19
+ *
20
+ * Returning `undefined` — rather than an object whose `add()` silently swallows
21
+ * the toast — is what lets {@link ltAddToast} report "no toast was shown", so
22
+ * callers keep their console fallback.
23
+ */
24
+ export declare function useToast(): undefined;
@@ -0,0 +1,4 @@
1
+ export const toastMaxInjectionKey = Symbol("nuxt-ui.toast-max");
2
+ export function useToast() {
3
+ return void 0;
4
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nuxt-extensions",
3
- "version": "1.18.4",
3
+ "version": "1.18.6",
4
4
  "description": "Reusable Nuxt 4 composables, components, and Better-Auth integration for lenne.tech projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -102,18 +102,18 @@
102
102
  "devDependencies": {
103
103
  "@better-auth/passkey": "1.7.7",
104
104
  "@nuxt/module-builder": "1.0.3",
105
- "@nuxt/schema": "4.5.2",
105
+ "@nuxt/schema": "4.6.0",
106
106
  "@nuxt/ui": "4.11.3",
107
- "@playwright/test": "1.63.0",
107
+ "@playwright/test": "1.64.0",
108
108
  "@types/node": "26.6.4",
109
109
  "@vitest/coverage-v8": "5.0.3",
110
110
  "@vue/server-renderer": "3.5.43",
111
111
  "better-auth": "1.7.7",
112
112
  "cross-spawn": "7.0.6",
113
113
  "happy-dom": "20.14.5",
114
- "nuxt": "4.5.2",
115
- "oxfmt": "0.71.0",
116
- "oxlint": "1.86.0",
114
+ "nuxt": "4.6.0",
115
+ "oxfmt": "0.72.0",
116
+ "oxlint": "1.87.0",
117
117
  "reka-ui": "2.10.5",
118
118
  "tus-js-client": "4.3.1",
119
119
  "typescript": "5.9.3",
@@ -137,5 +137,5 @@
137
137
  "node": ">= 22",
138
138
  "pnpm": "^11.0.0"
139
139
  },
140
- "packageManager": "pnpm@11.14.0+sha512.66c1ac4c7d4762d6d7dde44c7f3e5a73591ed0a0806e751d4ed32d4f004f25b2285a906b1fd8a9e3e621df3b4e2858bf88e50e0cf626bedbe977fe434a5caf85"
140
+ "packageManager": "pnpm@11.28.5+sha512.484563d30b4c2ad27cb48aa94ff2b302dbcebc8ff6bf28816c2589886e146ce7f76f354f3bc1a438e6f5e9768c302aa0a6f7add8232903cd4cf81426cbc14d9e"
141
141
  }