@coffer-org/server 2.5.0 → 2.5.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.
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import { baseUrl } from "./public-url.js";
24
24
  import { discoverPluginAssets, discoverRuntime } from "./plugin-discovery.js";
25
25
  import { checkLatestVersion, resolveUpdateTarget, resolveAllUpdateTargets, resolveBaseTargets, resolveRuntimeTarget, runNpmInstall, } from "./plugin-updates.js";
26
26
  import { buildClientSchema } from "./schema-api.js";
27
- import { recordList, recordListPage, isPagedRequest, recordGet, recordCreate, recordUpdate, recordDelete, recordRestore, recordPurge, recordTrashList, UnknownShelfError, } from "./records-api.js";
27
+ import { recordList, recordListPage, isPagedRequest, recordGet, recordCreate, recordUpdate, recordDelete, recordRestore, recordPurge, recordTrashList, MAX_PAGE, UnknownShelfError, } from "./records-api.js";
28
28
  import { maskTree, preserveTree } from "./field-masking.js";
29
29
  import { writePluginSettings } from "./settings-write.js";
30
30
  import { rootLogger, getLogger } from "./log.js";
@@ -35,6 +35,7 @@ import { setPluginState } from "./plugin-state.js";
35
35
  import { SEARCH_STATE_PLUGIN, SEARCH_CURSOR_KEY } from "./search-indexer.js";
36
36
  import { globalSearch } from "./global-search.js";
37
37
  import { applySmartRanking, getRecordActivity, markRecordViewed, setRecordFavorite } from "./record-activity.js";
38
+ import { tracksRecordActivity } from "./record-activity-policy.js";
38
39
  const ENV_FILE = join(process.cwd(), '.env');
39
40
  if (existsSync(ENV_FILE))
40
41
  process.loadEnvFile(ENV_FILE);
@@ -364,11 +365,6 @@ function maskRecordRow(library, shelf, row) {
364
365
  }
365
366
  return out;
366
367
  }
367
- function tracksRecordActivity(req) {
368
- const marker = req.headers['x-coffer-automated'];
369
- const value = Array.isArray(marker) ? marker[0] : marker;
370
- return value?.toLowerCase().trim() !== 'true';
371
- }
372
368
  app.get('/api/trash', async (_req, reply) => {
373
369
  const rows = await recordTrashList();
374
370
  return rows.map((entry) => ({ ...entry, record: maskRecordRow(entry.library, entry.shelf, entry.record) }));
@@ -417,17 +413,23 @@ app.get('/api/:library/:shelf', async (req, reply) => {
417
413
  try {
418
414
  if (!paged) {
419
415
  let rows = await recordList(library, shelf, query, opts);
420
- if (req.user && tracksRecordActivity(req))
416
+ if (req.user && tracksRecordActivity(req.headers))
421
417
  rows = await applySmartRanking(req.user.id, library, shelf, rows);
422
418
  return rows.map((r) => maskRecordRow(library, shelf, r));
423
419
  }
424
- let page = await recordListPage(library, shelf, query, {
420
+ const pageOpts = {
425
421
  ...opts,
426
422
  limit: limit === undefined ? undefined : Number(limit),
427
423
  offset: offset === undefined ? undefined : Number(offset),
428
- });
429
- if (req.user && tracksRecordActivity(req)) {
430
- page = { ...page, rows: await applySmartRanking(req.user.id, library, shelf, page.rows) };
424
+ };
425
+ let page = await recordListPage(library, shelf, query, pageOpts);
426
+ if (req.user && tracksRecordActivity(req.headers)) {
427
+ const allRows = await recordList(library, shelf, query, { ...opts, limit: undefined, offset: undefined });
428
+ const ranked = await applySmartRanking(req.user.id, library, shelf, allRows);
429
+ const rawLimit = Number.isFinite(pageOpts.limit) ? Math.trunc(pageOpts.limit) : MAX_PAGE;
430
+ const pageLimit = Math.min(Math.max(1, rawLimit), MAX_PAGE);
431
+ const pageOffset = Math.max(0, Number.isFinite(pageOpts.offset) ? Math.trunc(pageOpts.offset) : 0);
432
+ page = { rows: ranked.slice(pageOffset, pageOffset + pageLimit), total: ranked.length };
431
433
  }
432
434
  return { rows: page.rows.map((r) => maskRecordRow(library, shelf, r)), total: page.total };
433
435
  }
@@ -484,7 +486,7 @@ app.get('/api/:library/:shelf/:id', async (req, reply) => {
484
486
  if (!row)
485
487
  return reply.code(404).send({ error: 'not_found' });
486
488
  const masked = maskRecordRow(library, shelf, row);
487
- if (req.user && tracksRecordActivity(req)) {
489
+ if (req.user && tracksRecordActivity(req.headers)) {
488
490
  return { ...masked, _activity: await markRecordViewed(req.user.id, library, shelf, rid) };
489
491
  }
490
492
  return masked;
@@ -0,0 +1,3 @@
1
+ export declare const AUTOMATED_ACTIVITY_HEADER = "x-coffer-automated";
2
+ export type RequestHeaders = Record<string, string | string[] | undefined>;
3
+ export declare function tracksRecordActivity(headers: RequestHeaders): boolean;
@@ -0,0 +1,7 @@
1
+ export const AUTOMATED_ACTIVITY_HEADER = 'x-coffer-automated';
2
+ export function tracksRecordActivity(headers) {
3
+ const entry = Object.entries(headers).find(([key]) => key.toLowerCase() === AUTOMATED_ACTIVITY_HEADER);
4
+ const marker = entry?.[1];
5
+ const value = Array.isArray(marker) ? marker[0] : marker;
6
+ return value?.toLowerCase().trim() !== 'true';
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffer-org/server",
3
- "version": "2.5.0",
3
+ "version": "2.5.2",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=24"
@@ -24,8 +24,8 @@
24
24
  "postpack": "node ../../scripts/swap-exports.mjs src"
25
25
  },
26
26
  "dependencies": {
27
- "@coffer-org/core": "^2.1.2",
28
- "@coffer-org/sdk": "^2.1.1",
27
+ "@coffer-org/core": "^2.1.4",
28
+ "@coffer-org/sdk": "^2.1.3",
29
29
  "@extractus/oembed-extractor": "^4.1.0",
30
30
  "@fastify/cors": "^11.2.0",
31
31
  "@fastify/multipart": "^10.0.0",