Skip to content

Comments

Staging to Production#11

Open
github-actions[bot] wants to merge 41 commits intoproductionfrom
staging
Open

Staging to Production#11
github-actions[bot] wants to merge 41 commits intoproductionfrom
staging

Conversation

@github-actions
Copy link

@github-actions github-actions bot commented Feb 23, 2026

This PR was auto-generated via a workflow action.

Included Pull Requests

Diff

- ESLint 6→9: migrate to flat config format (eslint.config.js), replace
  babel-eslint with @babel/eslint-parser, add @eslint/eslintrc FlatCompat
- Jest 24→29: add jest-environment-jsdom, update transform pattern for ts/tsx
- Stylelint 12→16: drop abandoned styled-components processor, new config file
- Add TypeScript: typescript, @types/node, @types/react, @types/react-dom,
  tsconfig.json with allowJs:true for incremental migration, next-env.d.ts
- Remove babel-plugin-transform-class-properties from .babelrc (in next/babel)
- Remove sw-precache-webpack-plugin: strip webpack plugin from next.config.js
  and the entry point manipulation for offline/polyfills; service worker support
  can be re-added later with next-pwa
- Remove react-lazy: replace styled(Lazy) with styled.div in QueryRelease.styles.js
  since IntersectionObserver is now native in all modern browsers
- Remove object-dig: replace dig() calls with optional chaining (?.) in
  config/passport.js and app/discogs.js
- Remove intersection-observer polyfill from lib/polyfills.js (native now)
- Remove redux-devtools-extension: replace with @redux-devtools/extension
  (drop-in replacement); update import in client/reduxStore.js

Updated safe packages (no API changes):
- dotenv 8→16, compression latest, cookie-parser latest, disconnect 1.2.2,
  lodash latest, morgan latest, prop-types latest, react-icons 3→4,
  react-timeago 4→8, styled-icons 9→10
Redis v4+ rewrote the API to be promise-based; v5 follows the same interface:
- createClient() no longer auto-connects; must call client.connect() explicitly
- All methods return Promises natively (no more util.promisify needed)
- client.set() now accepts an options object ({EX: ttl}) instead of
  positional 'EX', ttl arguments

Changes:
- app/cache.js: rewrite to use promise-based API directly
- config/express.js: update RedisStore initialization for connect-redis v9
  (named export, new RedisStore({ client }) instead of factory function)
- app/__mocks__/redis.js: update manual mock to match v5 promise-based API
- app/spec/cache.spec.js: update assertions for new set() options format
Mongoose 6 removed deprecated connection options; Mongoose 7 removed callbacks;
Mongoose 8 finalizes async-first API.

- server.js: remove deprecated useNewUrlParser/useUnifiedTopology options and
  mongoose.set('useCreateIndex', true) — all are now defaults
- config/passport.js: convert deserializeUser and strategy callback from
  callback-based to async/await (callbacks removed in Mongoose 7)
- app/routes/api/scrobble.js: convert Release.findOne callback to async/await
- app/routes/api/user/history.js: convert Release.find callback to async/await
- app/routes/api/user/autoscrobbles.js: convert Release.find callback to
  async/await; replace deprecated Model.update() with Model.updateOne()
Express 5 (released 2024) adds native async error propagation and stricter
route path parsing (wildcards require explicit patterns).

- express 4→5, express-session 1.17→1.19, helmet 3→8
- Remove body-parser package: use built-in express.json() instead
- config/express.js: replace bodyParser.json() with express.json(),
  update Helmet to disable CSP for now (to be configured at Next.js layer),
  Helmet v8 has stricter defaults and a new API for some options
- server.js: replace '*' wildcard (invalid in Express 5) with /(.*)/ regex
- react/react-dom 16→18, react-test-renderer 16→18
- react-redux 7→9
- next-redux-wrapper 4→8: convert _app.js from class component HOC to
  function component using useWrappedStore hook; export wrapper from
  client/reduxStore.js via createWrapper()
- styled-components 5→6: add babel-plugin-styled-components as explicit
  devDependency (no longer bundled in v6)
- redux 4→5, redux-thunk 2→3: named export (thunk vs default export);
  update import in reduxStore.js and all test files
- Remove enzyme + enzyme-adapter-react-16 (not compatible with React 18);
  replace with @testing-library/react; clean up setupTests.js
- Add @testing-library/dom peer dependency
Next.js 14 uses webpack 5 natively (supports OpenSSL 3), React 18, and
the Pages Router (stable). Key changes:

- Remove NODE_OPTIONS=--openssl-legacy-provider from Dockerfile and
  docker-compose.yml (no longer needed with webpack 5 + OpenSSL 3)
- next.config.js: add reactStrictMode:true, remove legacy options, add
  JSDoc type annotation for IntelliSense
- next/link API changes (Next.js 13+): <Link> now renders as <a> directly;
  add legacyBehavior prop where child is a styled.a or styled.button to
  prevent nested <a> elements; remove redundant inner <a> in CircleLayout
- _document.js: add null check for ctx.req (may be absent in static pages)
- @next/bundle-analyzer updated to v14 to match Next.js version
- Add @babel/runtime-corejs2 devDep (jest-fetch-mock compiled with it;
  previously provided transitively by next@9)
Rename all .js/.jsx files to .ts/.tsx across pages, components, lib,
styles, config, and client. Add TypeScript type annotations to resolve
compiler errors: generic props for styled-components, React.Component<any,any>
for class components, (Class as any).propTypes for external static
assignments, and module augmentation for styled-components css prop.

- Add types/styled-components.d.ts for css prop support
- Update tsconfig.json to exclude spec files (handled by babel-jest)
- Add @types/jest for test infrastructure types
- Fix styled-icons import paths (named exports from package root)
- Make Spinner size prop optional to support styled extension without size
Replace the custom Express server routing layer with Next.js API routes.
Add iron-session for encrypted-cookie session management (replaces
Redis-backed express-session + Passport). Redis is retained for
Discogs/Last.fm API response caching.

New API routes mirror the old Express routes:
- pages/api/session.ts
- pages/api/barcode/[id].ts
- pages/api/search/[query].ts
- pages/api/scrobble.ts
- pages/api/user/history.ts
- pages/api/user/autoscrobbles.ts
- pages/api/auth/lastfm.ts (redirect to Last.fm OAuth)
- pages/api/auth/callback/lastfm.ts (exchange token, create session)
- pages/api/auth/logout.ts (destroy session)

Infrastructure helpers: lib/session.ts, lib/mongodb.ts, lib/withAuth.ts

Update /auth/lastfm and /logout links to /api/auth/lastfm and
/api/auth/logout. Update profile page SSR to read session via iron-session.
Delete server.js, config/express.js, config/passport.js, all Express
route handlers (app/routes/), and Express middleware (app/middlewares/).

Remove dependencies: express, express-session, compression, morgan,
cookie-parser, passport, passport-lastfm, helmet, connect-redis.

Update package.json scripts to use next dev / next start.
Update Dockerfile CMD to node_modules/.bin/next start.

The app now runs entirely on Next.js: API routes handle all server-side
logic, iron-session handles auth, Redis handles Discogs/LastFM caching,
and mongoose models remain in app/models/.
- Remove defaultProps from Logo and LogoSmall (use JS default params)
- Use transient prop $visible in Camera styled component to prevent DOM forwarding
- Move viewport meta tag from _document.tsx to _app.tsx (Next.js 14 requirement)
Use mongoose.models.User/Release guard so models aren't re-registered
on hot module replacement, which was causing 500 errors on /api/session.
- fetchSession now checks response.ok and dispatches setErrorState on
  non-2xx responses instead of dispatching the error JSON as session data
- Session component redirects to /login when error state is set
- Add Next.js middleware to redirect cookie-less requests to /login
  before the page renders, matching the old Express auth guard behavior
The old Express server rewrote /detected/:barcode and /scrobbled/:barcode
to ?barcode= query params. Without it, direct navigation 404s. Convert to
proper Next.js dynamic routes pages/detected/[barcode].tsx and
pages/scrobbled/[barcode].tsx and update Router.push calls accordingly.
next-redux-wrapper v8's useWrappedStore expects the full _app props
({ pageProps, router, ... }) so it can reconstruct props.pageProps.
Passing only pageProps caused props.pageProps to be undefined, silently
dropping all getInitialProps results (e.g. barcode in detected/[barcode]).
Remove all prop-types usage across 21 components and pages. Replace
with named TypeScript interfaces (ComponentNameProps pattern) and
default values in parameter destructuring. Remove prop-types package.
…rops

Replace deprecated getInitialProps with getServerSideProps using
next-redux-wrapper for proper server-side Redux store hydration.
The detected page was converted from query-param routing (pages/detected.tsx)
to a dynamic route (pages/detected/[barcode].tsx). Update the Link href to
match the new route structure so history item clicks don't 404.
Initial state has data: null. REMOVE_AUTO_SCROBBLE could be dispatched
before RECEIVED_AUTO_SCROBBLES arrives, causing null.filter() to throw.
…e actions

4xx/5xx responses resolve successfully with error bodies, which were being
dispatched as valid data. This caused .map() to be called on an error object,
crashing the app. Now throws on non-ok responses so the error handler runs.
Error objects have non-enumerable properties; JSON.stringify({err}) produces {}.
Use err.message string instead, consistent with other routes using { error: '...' }.
Typo caused misleading names in React DevTools and stack traces.
Same issue as ProfileHistoryItem — the detected page was converted to a
dynamic route but the old query-param href was left in QueryRelease.
- Pass actual Discogs error to reject() instead of calling reject() with no
  argument, so the error propagates correctly through the promise chain
- Fix error serialization in barcode API handler (same issue as history.ts)
- Add response.ok check in releaseActions before parsing JSON
React 18 StrictMode double-invokes componentDidMount, causing two concurrent
requests for the same barcode. Both findOne calls return null before either
saves, leading to two createFromDiscogs calls and an E11000 duplicate key error.

Catch the duplicate key error (code 11000) and retry the findOne to return
the record that was created by the winning request.
Accessing release.data.id when data is absent (e.g. during loading state)
caused a TypeError on page refresh. Optional chaining prevents the crash.
Convert all five source files in app/ to TypeScript with proper types
and ES module syntax, replacing CommonJS require/module.exports:

- app/cache.ts: named exports with generic Cache.get<T>()
- app/discogs.ts: interfaces for Discogs API shapes (ReleaseData,
  SearchResult, DiscogsData); typed disconnect client
- app/lastfm.ts: exports LastFMUserData interface for consumers
- app/models/release.ts: Mongoose v8 pattern with IRelease,
  IReleaseMethods, IReleaseModel; default export
- app/models/user.ts: same Mongoose pattern with UserJSON interface
  exported for session typing

Update all consumers (pages/api/*, lib/withAuth.ts, app/spec/) to use
ES import statements instead of require().

Also includes bug fixes incorporated during the conversion:
- Fix barcode cache storing full results array instead of release ID
- Fix firstOrCreate 11000 error recovery querying by id instead of
  barcode param, resolving {} response caused by barcode format
  mismatch between scanned value and Discogs-formatted stored value
- Fix updateFromDiscogs unconditionally overwriting existing barcode
- Guard convertTimecode against null/undefined track duration
- Add getMaster fallback in getRelease for master release IDs (404)
- Add legal/privacy routes to middleware public paths
feat: modernize full stack — Next.js 14, React 18, TypeScript, remove Express
@github-actions github-actions bot requested a review from dpuscher February 23, 2026 20:58
Replace manual QueryReleaseProps interface with ConnectedProps<typeof connector>
so TypeScript correctly infers that Redux-injected props are not required from
the parent, fixing the Docker build failure.
- Remove unused catch bindings (e, error) using optional catch syntax
- Split ConnectedProps into `import type` to fix import/named rule
- Add eslint-disable block for intentional autoFocus in QueryRelease
- Move media-has-caption disable comment inside Camera to target video element
- Rename Image styled component to Avatar to avoid jsx-a11y/alt-text collision with Next.js Image
Add ESLint, Prettier, and pre-commit checks
- add PR CI workflow (lint, stylelint, tests, build) on pull requests
- modernize staging auto-PR flow to native gh CLI and include generated list of included PRs
- update staging/production deploy workflows to current action versions
Install postcss-styled-syntax and set it as the custom syntax in stylelint config.
Update lint:css script to target *.styles.ts files instead of all JS/TS files.
Add PR CI and modernize deployment workflows
…kflow

Switches from gh api GET/POST/PATCH to gh pr list/create/edit to avoid
a 422 error caused by gh api exiting non-zero when jq produces empty
output via `// empty`, which killed the script before reaching the
if/else branch.
chore(test): migrate jest to vitest with happy-dom
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant