@lenne.tech/nuxt-extensions 1.19.0 → 1.19.1

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 CHANGED
@@ -583,6 +583,20 @@ absolute URL is used as it is. If your project routes uploads through its own sa
583
583
  instead, set `ltExtensions.tus.resolveAgainstApi: false` and the relative endpoint stays on the app
584
584
  origin.
585
585
 
586
+ **Changing it per stage.** The `tus` options are part of the public runtime config, so a deployed
587
+ stage can override them through the environment, without a rebuild:
588
+
589
+ ```bash
590
+ # Send this stage's uploads to another host (absolute URLs are used as they are)
591
+ NUXT_PUBLIC_LT_EXTENSIONS_TUS_DEFAULT_ENDPOINT=https://uploads.example.com/tus
592
+ # Keep a relative endpoint on the app origin (own same-origin proxy)
593
+ NUXT_PUBLIC_LT_EXTENSIONS_TUS_RESOLVE_AGAINST_API=false
594
+ ```
595
+
596
+ Keep the relative default where you can: `NUXT_PUBLIC_API_URL` already differs per stage, so `'/tus'`
597
+ follows it. Uploads are sent with credentials, so a host other than the API has to receive the
598
+ session cookie, or every upload answers 401.
599
+
586
600
  **Which id to keep.** After a successful upload, `item.fileId` is the id of the stored file, read
587
601
  from the `X-File-Id` response header (nest-server 11.42.13+). Use it for file links and references.
588
602
  `item.url` is the TUS upload resource; its last segment is the upload id, not the file id. `fileId`
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.19.0";
6
+ declare const version = "1.19.1";
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.19.0",
4
+ "version": "1.19.1",
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.19.0";
5
+ const version = "1.19.1";
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";
@@ -3,6 +3,7 @@ import { ltArrayBufferToBase64Url, ltBase64UrlToUint8Array } from "../../utils/c
3
3
  import { clearLtAuthCookies, getLtApiBase, getLtAuthCookieNames, resolveLtAuthState } from "../../lib/auth-state.js";
4
4
  import { useLtAuthClient } from "../use-lt-auth-client.js";
5
5
  const VALIDATE_SESSION_TIMEOUT_MS = 1e4;
6
+ let staleJwtRefresh = null;
6
7
  function useTranslation() {
7
8
  const nuxtApp = useNuxtApp();
8
9
  const i18n = nuxtApp.$i18n;
@@ -139,8 +140,35 @@ export function useLtAuth() {
139
140
  });
140
141
  }
141
142
  }
143
+ if (response.status === 401 && isJwtMode.value && isAuthenticated.value && !needsCookies) {
144
+ const freshToken = await refreshStaleJwt();
145
+ if (freshToken) {
146
+ headers.set("Authorization", `Bearer ${freshToken}`);
147
+ return fetch(url, {
148
+ ...options,
149
+ headers,
150
+ credentials: "omit"
151
+ });
152
+ }
153
+ }
142
154
  return response;
143
155
  }
156
+ async function refreshStaleJwt() {
157
+ const mint = async () => await switchToJwtMode() ? jwtToken.value : null;
158
+ if (!import.meta.client) {
159
+ return mint();
160
+ }
161
+ if (!staleJwtRefresh) {
162
+ staleJwtRefresh = mint().finally(() => {
163
+ staleJwtRefresh = null;
164
+ });
165
+ }
166
+ const token = await staleJwtRefresh;
167
+ if (token && jwtToken.value !== token) {
168
+ jwtToken.value = token;
169
+ }
170
+ return token;
171
+ }
144
172
  const AUTHZ_KEYS = ["banExpires", "banReason", "banned", "emailVerified", "role", "roles", "twoFactorEnabled"];
145
173
  function mergeSessionUser(sessionUser) {
146
174
  const cached = resolvedAuthState.value?.user;
@@ -1,10 +1,21 @@
1
1
  import { computed, useState } from "#imports";
2
2
  import { ltSha256 } from "../../utils/crypto.js";
3
- import { buildLtApiUrl } from "../../lib/auth-state.js";
3
+ import { buildLtApiUrl, resolveLtApiBaseUrl, warnMissingLtApiUrl } from "../../lib/auth-state.js";
4
+ function isApiUrlMissing() {
5
+ try {
6
+ return resolveLtApiBaseUrl().missing;
7
+ } catch {
8
+ return true;
9
+ }
10
+ }
4
11
  export function useSystemSetup() {
5
12
  const needsSetupState = useState("lt-needs-setup", () => null);
6
13
  const needsSetup = computed(() => needsSetupState.value);
7
14
  async function checkSetupStatus() {
15
+ if (import.meta.server && isApiUrlMissing()) {
16
+ warnMissingLtApiUrl("server");
17
+ return false;
18
+ }
8
19
  try {
9
20
  const url = buildLtApiUrl("/system-setup/status");
10
21
  const data = await $fetch(url);
@@ -78,7 +78,7 @@ export function isLocalDevApiProxy() {
78
78
  }
79
79
  const MISSING_API_URL_WARNING = {
80
80
  client: "[LtExtensions] No API URL configured. Set NUXT_PUBLIC_API_URL. API paths stay relative and resolve against the app origin, so auth and setup calls 404 unless the app is served behind a same-origin reverse proxy.",
81
- server: "[LtExtensions] No API URL configured for SSR. Set NUXT_API_URL or NUXT_PUBLIC_API_URL. API paths stay relative, so server-side requests never reach the backend: $fetch resolves them against Nitro (404) and global fetch rejects them as an invalid URL."
81
+ server: "[LtExtensions] No API URL configured for SSR. Set NUXT_API_URL or NUXT_PUBLIC_API_URL. API paths stay relative, so server-side requests never reach the backend: $fetch sends them to this Nitro server itself and global fetch rejects them as an invalid URL."
82
82
  };
83
83
  function stripTrailingSlashes(url) {
84
84
  return url.replace(/\/+$/, "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nuxt-extensions",
3
- "version": "1.19.0",
3
+ "version": "1.19.1",
4
4
  "description": "Reusable Nuxt 4 composables, components, and Better-Auth integration for lenne.tech projects",
5
5
  "repository": {
6
6
  "type": "git",