diff --git a/package.json b/package.json index 442cfffe..e9e3f210 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ }, "dependencies": { "@apollo/server": "^5.5.1", - "@as-integrations/express4": "^1.1.2", + "@as-integrations/express": "^3.0.0", "@aztec/bb.js": "^0.87.9", "@opentelemetry/api": "^1.9.0", "@opentelemetry/auto-instrumentations-node": "^0.67.0", @@ -144,7 +144,7 @@ "buffer": "^6.0.3", "cors": "^2.8.5", "dataloader": "^2.2.3", - "express": "^4.21.0", + "express": "^5.0.0", "express-rate-limit": "^8.6.2", "fuse.js": "^7.5.0", "ioredis": "^5.4.1", diff --git a/server/graphql/server.ts b/server/graphql/server.ts index 945453da..ea93d150 100644 --- a/server/graphql/server.ts +++ b/server/graphql/server.ts @@ -1,8 +1,8 @@ /** - * server/graphql/server.ts — Apollo Server wiring for Express (#528) + * server/graphql/server.ts — Apollo Server 5 wiring for Express 5 (#751) */ import { ApolloServer } from '@apollo/server' -import { expressMiddleware } from '@as-integrations/express4' +import { expressMiddleware } from '@as-integrations/express' import { ApolloServerPluginLandingPageDisabled } from '@apollo/server/plugin/disabled' import { GraphQLError, Kind, type ValidationRule } from 'graphql' import type { NextFunction, Request, RequestHandler, Response } from 'express' diff --git a/server/middleware/cors.js b/server/middleware/cors.js index 35aed9a1..5e0f15e0 100644 --- a/server/middleware/cors.js +++ b/server/middleware/cors.js @@ -86,6 +86,8 @@ export function createCorsMiddleware(opts = {}) { res.setHeader("Access-Control-Allow-Origin", origin); res.setHeader("Access-Control-Allow-Methods", methods.join(", ")); res.setHeader("Access-Control-Allow-Headers", headers.join(", ")); + // #753: Allow credentials for wallet postMessage flows + res.setHeader("Access-Control-Allow-Credentials", "true"); if (req.method === "OPTIONS") { res.setHeader("Access-Control-Max-Age", String(maxAge)); return res.status(204).end(); diff --git a/server/middleware/cors.ts b/server/middleware/cors.ts index 6df614dc..f665dcc4 100644 --- a/server/middleware/cors.ts +++ b/server/middleware/cors.ts @@ -125,8 +125,8 @@ export function createCorsMiddleware(opts: CorsOptions = {}) { // Allowed origin – set CORS headers res.setHeader('Access-Control-Allow-Origin', origin) - // Credentials are not needed for ZK prover (no cookies), keep false to avoid extra complexity - // If you need credentials, set Access-Control-Allow-Credentials: true and mirror origin + // #753: Allow credentials for Stellar wallet popups with postMessage + res.setHeader('Access-Control-Allow-Credentials', 'true') res.setHeader('Access-Control-Allow-Methods', methods.join(', ')) res.setHeader('Access-Control-Allow-Headers', headers.join(', ')) // Only set Max-Age on preflight responses (per spec, but also harmless on simple requests) diff --git a/src/i18n.ts b/src/i18n.ts index 837caa0c..4789af0a 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -1,29 +1,33 @@ import i18n from 'i18next' -import HttpBackend from 'i18next-http-backend' import { initReactI18next } from 'react-i18next' export const SUPPORTED_LANGUAGES = ['en', 'ar'] as const export const DEFAULT_LNG = 'en' export const DEFAULT_NS = 'common' -const ready = i18n - .use(HttpBackend) - .use(initReactI18next) - .init({ - lng: DEFAULT_LNG, - fallbackLng: DEFAULT_LNG, - supportedLngs: [...SUPPORTED_LANGUAGES], - nonExplicitSupportedLngs: true, - load: 'languageOnly', - defaultNS: DEFAULT_NS, - ns: [DEFAULT_NS], - backend: { - loadPath: '/locales/{{lng}}/{{ns}}.json', - requestOptions: { cache: 'no-cache' }, - }, - interpolation: { escapeValue: false }, - react: { useSuspense: false }, - }) +const ready = (async () => { + // Lazy-load HttpBackend to reduce initial bundle (#744) + const { default: HttpBackend } = await import('i18next-http-backend') + + return i18n + .use(HttpBackend) + .use(initReactI18next) + .init({ + lng: DEFAULT_LNG, + fallbackLng: DEFAULT_LNG, + supportedLngs: [...SUPPORTED_LANGUAGES], + nonExplicitSupportedLngs: true, + load: 'languageOnly', + defaultNS: DEFAULT_NS, + ns: [DEFAULT_NS], + backend: { + loadPath: '/locales/{{lng}}/{{ns}}.json', + requestOptions: { cache: 'no-cache' }, + }, + interpolation: { escapeValue: false }, + react: { useSuspense: false }, + }) +})() function syncDocumentLocale(language: string): void { if (typeof document === 'undefined') return diff --git a/src/service-worker.js b/src/service-worker.js index 5e87163c..0b4a1582 100644 --- a/src/service-worker.js +++ b/src/service-worker.js @@ -54,6 +54,15 @@ self.addEventListener("fetch", (event) => { const { request } = event; const url = new URL(request.url); + // #742: Skip caching for HMR and dev server requests to avoid stale-while-revalidate + if ( + url.searchParams.has("t") || // Vite HMR timestamp query + /\/@vite\//.test(url.pathname) || // Vite HMR module + /\.hmr(?:\.json)?$/.test(url.pathname) // HMR manifest + ) { + return; // Let fetch proceed normally, don't cache + } + if ( request.method === "GET" && url.origin === self.location.origin && diff --git a/vite.config.ts b/vite.config.ts index 0e13355f..2061aac3 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -243,6 +243,13 @@ export default defineConfig(({ mode }) => ({ "Cross-Origin-Opener-Policy": "same-origin", "Cross-Origin-Embedder-Policy": "credentialless", }, + hmr: { + // #742: Explicit HMR config prevents stale-cache issues with service worker + protocol: "ws", + host: "localhost", + port: 3000, + timeout: 5000, + }, proxy: { "/zk": { target: "http://127.0.0.1:3001",