@bakapiano/ccsm 0.15.4 → 0.17.0

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/server.js CHANGED
@@ -506,6 +506,24 @@ app.delete('/api/sessions/:id', asyncH(async (req, res) => {
506
506
  res.json({ removed });
507
507
  }));
508
508
 
509
+ // Reorder sessions within a folder. Body: { folderId, ids } where ids
510
+ // is the new sequence of session ids in their final display order
511
+ // inside that folder. Each session gets `folderId` + `order: 0..N-1`
512
+ // assigned. Setting folderId here (rather than requiring a separate
513
+ // PUT) lets the drag-and-drop UI move a session across folders AND
514
+ // drop it at a specific position in one shot — without the call, the
515
+ // move would either land at the end of the destination folder (just
516
+ // PUT folderId) or leave it in place (just reorder).
517
+ app.post('/api/sessions/reorder', asyncH(async (req, res) => {
518
+ const ids = Array.isArray(req.body?.ids) ? req.body.ids : null;
519
+ if (!ids) return res.status(400).json({ error: 'ids array required' });
520
+ const folderId = req.body?.folderId ?? null;
521
+ for (let i = 0; i < ids.length; i++) {
522
+ try { await persistedSessions.update(ids[i], { folderId, order: i }); } catch {}
523
+ }
524
+ res.json({ ok: true, count: ids.length });
525
+ }));
526
+
509
527
  // ---- workspaces ----
510
528
 
511
529
  // ---- directory browser ----
@@ -1027,6 +1045,11 @@ function cmpSemver(a, b) {
1027
1045
  app.get('/api/version', asyncH(async (req, res) => {
1028
1046
  const force = String(req.query.refresh || '') === '1';
1029
1047
  const now = Date.now();
1048
+ // devMode: set when the server was launched from scripts/dev.js
1049
+ // (CCSM_DEV=1). Lets the About page render a "test upgrade flow"
1050
+ // button that re-installs to a sandbox prefix without affecting the
1051
+ // user's global ccsm install.
1052
+ const devMode = process.env.CCSM_DEV === '1';
1030
1053
  if (!force && versionCache && (now - versionCache.fetchedAt) < VERSION_CACHE_MS) {
1031
1054
  return res.json({
1032
1055
  current: pkg.version,
@@ -1034,6 +1057,7 @@ app.get('/api/version', asyncH(async (req, res) => {
1034
1057
  updateAvailable: cmpSemver(versionCache.latest, pkg.version) > 0,
1035
1058
  fetchedAt: versionCache.fetchedAt,
1036
1059
  cached: true,
1060
+ devMode,
1037
1061
  });
1038
1062
  }
1039
1063
  try {
@@ -1045,16 +1069,16 @@ app.get('/api/version', asyncH(async (req, res) => {
1045
1069
  updateAvailable: cmpSemver(latest, pkg.version) > 0,
1046
1070
  fetchedAt: now,
1047
1071
  cached: false,
1072
+ devMode,
1048
1073
  });
1049
1074
  } catch (e) {
1050
- // Swallow: surface "unknown" so the UI doesn't keep showing a stale
1051
- // "update available" badge based on a 6-hour-old cached value.
1052
1075
  res.json({
1053
1076
  current: pkg.version,
1054
1077
  latest: null,
1055
1078
  updateAvailable: false,
1056
1079
  fetchedAt: now,
1057
1080
  error: String(e.message || e),
1081
+ devMode,
1058
1082
  });
1059
1083
  }
1060
1084
  }));
@@ -1094,9 +1118,24 @@ app.post('/api/upgrade', asyncH(async (req, res) => {
1094
1118
  upgradeInFlight = false;
1095
1119
  return res.status(500).json({ error: `helper copy failed: ${e.message}` });
1096
1120
  }
1097
- const args = [helperTmp, target, String(currentPort), String(process.pid), installPrefix, respawn];
1121
+ // Where to send the user back when the upgrade succeeds. In prod
1122
+ // that's the GH Pages router (it'll re-probe localhost:7777 and
1123
+ // redirect to the matching per-version frontend); in dev (CCSM_DEV=1)
1124
+ // that's our local server on whatever port we're listening on, so
1125
+ // the test sandbox flow returns to the dev instance instead of
1126
+ // hitting GH Pages (which doesn't know about port 7788).
1127
+ const redirectTo = frontendUrl || `http://localhost:${currentPort}/`;
1098
1128
 
1099
- res.json({ ok: true, started: true, target, helper: helperTmp, closeFrontend: true });
1129
+ const args = [helperTmp, target, String(currentPort), String(process.pid), installPrefix, respawn, redirectTo];
1130
+
1131
+ res.json({
1132
+ ok: true,
1133
+ started: true,
1134
+ target,
1135
+ helper: helperTmp,
1136
+ helperUrl: 'http://localhost:7779/',
1137
+ closeFrontend: false,
1138
+ });
1100
1139
 
1101
1140
  // Flush response, then spawn helper detached and gracefulShutdown so
1102
1141
  // the helper's npm install isn't fighting our open file handles.