greend-server 1.0.0 → 1.0.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +24 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "greend-server",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "GreenD ESG backend — self-hosted Express.js API server",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -103,7 +103,9 @@ async function readEsgData() {
103
103
  // yearlyValues and lastModifiedBy are accumulated across all year files.
104
104
  const byId = new Map();
105
105
  for (const yearRecords of allYearData) {
106
+ if (!Array.isArray(yearRecords)) continue;
106
107
  for (const record of yearRecords) {
108
+ if (!record || typeof record.id !== 'string') continue;
107
109
  if (!byId.has(record.id)) {
108
110
  byId.set(record.id, { ...record, yearlyValues: {}, lastModifiedBy: [] });
109
111
  }
@@ -116,8 +118,12 @@ async function readEsgData() {
116
118
  m.unit = record.unit;
117
119
  m.department = record.department;
118
120
  // Year-specific data
119
- Object.assign(m.yearlyValues, record.yearlyValues);
120
- m.lastModifiedBy.push(...record.lastModifiedBy);
121
+ if (record.yearlyValues && typeof record.yearlyValues === 'object') {
122
+ Object.assign(m.yearlyValues, record.yearlyValues);
123
+ }
124
+ if (Array.isArray(record.lastModifiedBy)) {
125
+ m.lastModifiedBy.push(...record.lastModifiedBy);
126
+ }
121
127
  }
122
128
  }
123
129
 
@@ -129,22 +135,30 @@ async function readEsgData() {
129
135
  // can corrupt data. This storage layer is designed for single-user or low-concurrency
130
136
  // deployments. For multi-user environments with simultaneous edits, migrate to SQLite.
131
137
  async function writeEsgData(records) {
138
+ if (!Array.isArray(records)) return;
132
139
  await mkdir(join(DATA_DIR, 'esg'), { recursive: true });
133
140
 
134
141
  // Collect every year referenced in values or change history
135
142
  const years = new Set();
136
143
  for (const r of records) {
137
- for (const y of Object.keys(r.yearlyValues)) years.add(Number(y));
138
- for (const c of r.lastModifiedBy) years.add(c.year);
144
+ if (!r) continue;
145
+ const yv = r.yearlyValues && typeof r.yearlyValues === 'object' ? r.yearlyValues : {};
146
+ const lm = Array.isArray(r.lastModifiedBy) ? r.lastModifiedBy : [];
147
+ for (const y of Object.keys(yv)) years.add(Number(y));
148
+ for (const c of lm) if (c?.year != null) years.add(c.year);
139
149
  }
140
150
 
141
151
  for (const year of [...years].sort()) {
142
152
  const yearRecords = records
143
- .filter(r => year in r.yearlyValues || r.lastModifiedBy.some(c => c.year === year))
153
+ .filter(r => {
154
+ const yv = r?.yearlyValues ?? {};
155
+ const lm = Array.isArray(r?.lastModifiedBy) ? r.lastModifiedBy : [];
156
+ return year in yv || lm.some(c => c.year === year);
157
+ })
144
158
  .map(r => ({
145
159
  ...r,
146
- yearlyValues: year in r.yearlyValues ? { [year]: r.yearlyValues[year] } : {},
147
- lastModifiedBy: r.lastModifiedBy.filter(c => c.year === year),
160
+ yearlyValues: year in (r.yearlyValues ?? {}) ? { [year]: r.yearlyValues[year] } : {},
161
+ lastModifiedBy: (Array.isArray(r.lastModifiedBy) ? r.lastModifiedBy : []).filter(c => c.year === year),
148
162
  }));
149
163
  await writeFile(
150
164
  join(DATA_DIR, 'esg', `${year}.json`),
@@ -154,13 +168,8 @@ async function writeEsgData(records) {
154
168
  }
155
169
 
156
170
  const DEFAULT_PREFS = {
157
- dashboardLayout: [
158
- { i: 'emissions', x: 0, y: 0, w: 6, h: 4 },
159
- { i: 'energy', x: 6, y: 0, w: 6, h: 4 },
160
- { i: 'diversity', x: 0, y: 4, w: 6, h: 4 },
161
- { i: 'summary', x: 6, y: 4, w: 6, h: 4 },
162
- ],
163
- dashboardPanels: ['emissions', 'energy', 'diversity', 'summary'],
171
+ dashboardLayout: [],
172
+ dashboardPanels: [],
164
173
  customPanelConfigs: {},
165
174
  };
166
175
 
@@ -301,6 +310,7 @@ app.get('/api/data', requireAuth, async (req, res) => {
301
310
  res.json(await readEsgData());
302
311
  });
303
312
  app.put('/api/data', requireAuth, async (req, res) => {
313
+ if (!Array.isArray(req.body)) return res.status(400).json({ error: 'Body must be an array' });
304
314
  await writeEsgData(req.body);
305
315
  res.sendStatus(204);
306
316
  });