@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
|
-
|
|
420
|
+
const pageOpts = {
|
|
425
421
|
...opts,
|
|
426
422
|
limit: limit === undefined ? undefined : Number(limit),
|
|
427
423
|
offset: offset === undefined ? undefined : Number(offset),
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
|
|
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,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.
|
|
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.
|
|
28
|
-
"@coffer-org/sdk": "^2.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",
|