Files
wekan/server/lib/restArrayParam.js
T
Lauri OjansivuandClaude Opus 4.8 1f344879fb fix: client bundle crash — move server-only card helpers out of the client bundle
models/lib/cardBoardConsistency.js and models/lib/restArrayParam.js are
CommonJS (module.exports), but being under models/ they were eagerly bundled
into the client by rspack, which classifies a no-import/require .js as an ES
module and threw at load time:

  Uncaught Error: ES Modules may not assign module.exports or exports.*
  ... ./models/lib/cardBoardConsistency.js -> ./models/cards.js

This aborted the client bundle on every page. (filenameSanitizer.js uses the
same module.exports pattern without issue only because it is never imported
into the client bundle.)

Both helpers are server-only logic (a REST handler and a Cards.before.update
hook), so they are moved to server/lib/ (excluded from the client rspack
bundle, CommonJS is fine on the Node server) and enforceCardBoardConsistency
is relocated from the isomorphic models/cards.js into server/models/cards.js.
The isomorphic models/cards.js no longer imports either helper.

Verified in a real headless Chromium against a running dev server: the page
now loads with window.Meteor present and zero console/page errors (previously
one PAGEERROR from cardBoardConsistency.js). Node unit tests updated to the new
paths and pass (npm run test:unit:node, 11 passing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 08:50:29 +03:00

37 lines
1.6 KiB
JavaScript

// Pure, dependency-free helper (no Meteor imports) so it can be unit tested
// directly with plain Node. Used by the REST API card update handler in
// server/models/cards.js.
//
// #3697: editing a card's `members` via the REST API and then trying to clear
// them left the field in a state the UI could not edit. Two problems:
// 1. The handler guarded with `if (req.body.members)`, which is falsy for the
// two natural "clear" payloads (`null` and `""`), so removing the last
// member via REST was a silent no-op.
// 2. Its string branch wrote `null` (not `[]`) for an empty value, and a card
// with `members: null` breaks UI code that treats it as an array
// (`members.indexOf(...)`, the members popup, etc.) — the schema declares
// `members` as an Array with defaultValue `[]`, never null.
//
// coerceRestArrayParam normalizes whatever the REST client sent into a clean
// String[] so the stored value is always an array: a single id becomes a
// one-element array, an empty string / null / any non-array becomes `[]` (an
// explicit clear), and an array is kept but filtered to strings (so a stray
// `[null]` / `[123]` cannot reach the document).
/**
* @param {*} value the raw REST body value for members / assignees
* @return {string[]} a normalized array of id strings (possibly empty)
*/
function coerceRestArrayParam(value) {
if (Array.isArray(value)) {
return value.filter(v => typeof v === 'string' && v !== '');
}
if (typeof value === 'string') {
return value === '' ? [] : [value];
}
// null / undefined / number / object → treat as an explicit clear.
return [];
}
module.exports = { coerceRestArrayParam };