@coffer-org/server 1.3.0 → 1.4.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/dist/auth-api.js CHANGED
@@ -127,7 +127,11 @@ export async function registerAuthApi(app) {
127
127
  return;
128
128
  const id = Number(req.params.id);
129
129
  const body = (req.body ?? {});
130
- const wantsDisabled = body.disabled === undefined ? undefined : Boolean(body.disabled);
130
+ const wantsDisabled = body.disabled === undefined
131
+ ? undefined
132
+ : body.disabled === 'false' || body.disabled === '0'
133
+ ? false
134
+ : Boolean(body.disabled);
131
135
  const demotingOrDisabling = (body.role === 'member' || wantsDisabled === true) && (await isLastAdmin(id));
132
136
  if (demotingOrDisabling)
133
137
  return reply.code(409).send({ error: 'last_admin' });
@@ -125,8 +125,7 @@ export async function resolveApiToken(raw) {
125
125
  const user = await findUserById(token.user_id);
126
126
  if (!user || user.disabled)
127
127
  return null;
128
- em.assign(token, { last_used_at: new Date().toISOString() });
129
- await em.flush();
128
+ await em.nativeUpdate('_ApiToken', { id: token.id }, { last_used_at: new Date().toISOString() });
130
129
  return user;
131
130
  }
132
131
  export async function listApiTokens(userId) {
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ import { checkLatestVersion, resolveUpdateTarget, runNpmInstall } from "./plugin
32
32
  import { buildClientSchema } from "./schema-api.js";
33
33
  import { recordList, recordGet, recordCreate, recordUpdate, recordDelete, rowMatch, UnknownTypeError } from "./records-api.js";
34
34
  import { maskTree, preserveTree } from "./secrets.js";
35
+ import { rootLogger, getLogger } from "./log.js";
35
36
  import { uploadsDir } from "./uploads.js";
36
37
  const ENV_FILE = join(process.cwd(), '.env');
37
38
  if (existsSync(ENV_FILE))
@@ -46,7 +47,20 @@ for (const m of modules) {
46
47
  moduleDefs.set(`${m.vault}/${m.module}`, m);
47
48
  }
48
49
  const UPLOADS = uploadsDir();
49
- const app = Fastify({ logger: true });
50
+ const app = Fastify({
51
+ loggerInstance: rootLogger,
52
+ disableRequestLogging: true,
53
+ });
54
+ const httpLog = getLogger('http');
55
+ app.addHook('onResponse', async (req, reply) => {
56
+ const level = reply.statusCode >= 500 ? 'error' : reply.statusCode >= 400 ? 'warn' : 'debug';
57
+ httpLog[level]('request', {
58
+ method: req.method,
59
+ url: req.url,
60
+ status: reply.statusCode,
61
+ ms: Number(reply.elapsedTime.toFixed(1)),
62
+ });
63
+ });
50
64
  await app.register(cors, { origin: true });
51
65
  await app.register(multipart, { limits: { fileSize: 25 * 1024 * 1024 } });
52
66
  await app.register(fastifyStatic, { root: UPLOADS, prefix: '/uploads/' });
package/dist/log.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { getLogger } from '@coffer-org/sdk/logger';
2
+ export declare const rootLogger: import("pino").Logger<never, boolean>;
3
+ export { getLogger };
package/dist/log.js ADDED
@@ -0,0 +1,5 @@
1
+ import { pino } from 'pino';
2
+ import { setRootLogger, LOG_LEVEL, getLogger } from '@coffer-org/sdk/logger';
3
+ export const rootLogger = pino({ level: LOG_LEVEL });
4
+ setRootLogger(rootLogger);
5
+ export { getLogger };
@@ -1,5 +1,7 @@
1
1
  import { DatabaseSchema } from '@mikro-orm/sql';
2
2
  import { dialectOf } from "./dialect.js";
3
+ import { getLogger } from '@coffer-org/sdk/logger';
4
+ const log = getLogger('migrations');
3
5
  function sqlType(col) {
4
6
  if (col === 'integer' || col === 'boolean')
5
7
  return 'integer';
@@ -161,7 +163,7 @@ export async function runMigrations({ em, plugins, hooks }) {
161
163
  if (p.tables?.length && !(await anyTableExists(em, p.tables))) {
162
164
  await conn.execute(`INSERT INTO _migrations (plugin_id, version) VALUES (?, ?)
163
165
  ON CONFLICT(plugin_id) DO UPDATE SET version = excluded.version`, [p.id, maxV]);
164
- console.log(`[migrations] ${p.id}: fresh DB → stamp v${maxV} (no run)`);
166
+ log.info(`${p.id}: fresh DB → stamp v${maxV} (no run)`);
165
167
  continue;
166
168
  }
167
169
  const pending = [...list].filter((m) => m.version > stored).sort((a, b) => a.version - b.version);
@@ -172,7 +174,7 @@ export async function runMigrations({ em, plugins, hooks }) {
172
174
  ON CONFLICT(plugin_id) DO UPDATE SET version = excluded.version`, [p.id, m.version]);
173
175
  }
174
176
  if (pending.length)
175
- console.log(`[migrations] ${p.id}: applied ${pending.length} (→ v${pending[pending.length - 1].version})`);
177
+ log.info(`${p.id}: applied ${pending.length} (→ v${pending[pending.length - 1].version})`);
176
178
  }
177
179
  }
178
180
  export async function assertSafeRequired(em, entities) {
@@ -9,6 +9,8 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
9
9
  import { readdir, readFile } from 'node:fs/promises';
10
10
  import { join } from 'node:path';
11
11
  import { pathToFileURL } from 'node:url';
12
+ import { getLogger } from '@coffer-org/sdk/logger';
13
+ const log = getLogger('discovery');
12
14
  async function pkgNames(nm) {
13
15
  const names = [];
14
16
  try {
@@ -63,7 +65,7 @@ export async function discoverPluginAssets() {
63
65
  });
64
66
  }
65
67
  catch (e) {
66
- console.error(`[discovery] ${name}: asset scan skip — ${e.message}`);
68
+ log.error(`${name}: asset scan skip — ${e.message}`);
67
69
  }
68
70
  }
69
71
  return out;
@@ -77,11 +79,11 @@ async function loadManifest(nm, name) {
77
79
  const manifest = mod.default;
78
80
  if (manifest && typeof manifest.id === 'string')
79
81
  return manifest;
80
- console.warn(`[discovery] ${name}: no valid default manifest, skipping`);
82
+ log.warn(`${name}: no valid default manifest, skipping`);
81
83
  return null;
82
84
  }
83
85
  catch (e) {
84
- console.error(`[discovery] ${name}: import failed, skipping — ${e.message}`);
86
+ log.error(`${name}: import failed, skipping — ${e.message}`);
85
87
  return null;
86
88
  }
87
89
  }
@@ -117,7 +119,7 @@ export async function loadServerHooks() {
117
119
  hooks[id] = mod.serverHooks;
118
120
  }
119
121
  catch (e) {
120
- console.error(`[discovery] ${name}: server hooks not loaded — ${e.message}`);
122
+ log.error(`${name}: server hooks not loaded — ${e.message}`);
121
123
  }
122
124
  }
123
125
  return hooks;
@@ -1,5 +1,6 @@
1
1
  import { serialize } from '@mikro-orm/core';
2
2
  import { composeRegistry } from '@coffer-org/core/compose';
3
+ import { getLogger } from '@coffer-org/sdk/logger';
3
4
  import { initDb, getOrm, getEm } from "./db.js";
4
5
  import { syncSchema } from "./schema-sync.js";
5
6
  import { systemEntities, buildPluginEntities, moduleTableName } from "./entity-schema.js";
@@ -9,6 +10,7 @@ import { runMigrations, assertSafeRequired } from "./migrations.js";
9
10
  import { runSeeds } from "./seeds.js";
10
11
  import { setActiveRegistry } from "./registry-context.js";
11
12
  import { migrateEmbeddingVectorsToBlob } from "./embeddings.js";
13
+ const log = getLogger('plugins');
12
14
  let _plugins = null;
13
15
  export async function getPlugins() {
14
16
  return (_plugins ??= await discoverPlugins());
@@ -77,15 +79,15 @@ export async function initPlugins() {
77
79
  try {
78
80
  if (h?.init) {
79
81
  await h.init({ em: getEm().fork() });
80
- console.log(`[plugin] ${p.id}: init ✓`);
82
+ log.debug(`${p.id}: init ✓`);
81
83
  }
82
84
  }
83
85
  catch (err) {
84
- console.error(`[plugin] ${p.id}: initialization failure`, err);
86
+ log.error(`${p.id}: initialization failure`, err);
85
87
  throw err;
86
88
  }
87
89
  }
88
- console.log(`[plugin] active: ${reg.order.map((p) => p.id).join(' ')}` +
90
+ log.info(`active: ${reg.order.map((p) => p.id).join(' ')}` +
89
91
  (disabled.size ? ` | disabled: ${[...disabled].join(' ')}` : ''));
90
92
  return reg;
91
93
  }
@@ -99,10 +101,10 @@ export async function teardownPlugins() {
99
101
  continue;
100
102
  try {
101
103
  await h.teardown({ em: getEm().fork() });
102
- console.log(`[plugin] ${p.id}: teardown ✓`);
104
+ log.debug(`${p.id}: teardown ✓`);
103
105
  }
104
106
  catch (e) {
105
- console.warn(`[plugin] ${p.id}: teardown ✗ ${e.message}`);
107
+ log.warn(`${p.id}: teardown ✗ ${e.message}`);
106
108
  }
107
109
  }
108
110
  }
@@ -110,7 +112,7 @@ export async function teardownPlugin(id) {
110
112
  const h = pluginHooks[id];
111
113
  if (h?.teardown) {
112
114
  await h.teardown({ em: getEm().fork() });
113
- console.log(`[plugin] ${id}: teardown ✓`);
115
+ log.debug(`${id}: teardown ✓`);
114
116
  }
115
117
  }
116
118
  function pluginModules(p) {
@@ -154,7 +156,7 @@ export async function purgePluginData(p, actor) {
154
156
  after: null,
155
157
  });
156
158
  });
157
- console.log(`[plugin] ${p.id}: purge ✓ (${tables.length} tables)`);
159
+ log.info(`${p.id}: purge ✓ (${tables.length} tables)`);
158
160
  }
159
161
  export function filterEnabled(all, disabled) {
160
162
  return all.filter((p) => !disabled.has(p.id));
package/dist/seeds.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { getLogger } from '@coffer-org/sdk/logger';
2
+ const log = getLogger('seeds');
1
3
  export function validateSeeds(pluginId, list) {
2
4
  const names = list.map((s) => s.name);
3
5
  if (new Set(names).size !== names.length) {
@@ -18,6 +20,6 @@ export async function runSeeds({ em, plugins, hooks }) {
18
20
  await conn.execute(`INSERT INTO _seeds (plugin_id, name) VALUES (?, ?)`, [p.id, s.name]);
19
21
  }
20
22
  if (pending.length)
21
- console.log(`[seeds] ${p.id}: applied ${pending.length} (${pending.map((s) => s.name).join(', ')})`);
23
+ log.info(`${p.id}: applied ${pending.length} (${pending.map((s) => s.name).join(', ')})`);
22
24
  }
23
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffer-org/server",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=24"
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@coffer-org/core": "^1.3.0",
28
- "@coffer-org/sdk": "^1.3.0",
28
+ "@coffer-org/sdk": "^1.4.0",
29
29
  "@extractus/oembed-extractor": "^4.1.0",
30
30
  "@fastify/cors": "^11.2.0",
31
31
  "@fastify/multipart": "^10.0.0",
@@ -34,6 +34,7 @@
34
34
  "@mikro-orm/sqlite": "^7.1.4",
35
35
  "fastify": "^5.2.1",
36
36
  "open-graph-scraper": "^6.11.0",
37
+ "pino": "^9.14.0",
37
38
  "zod": "^4.4.3"
38
39
  },
39
40
  "optionalDependencies": {