webspresso 0.0.61 → 0.0.62

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/README.md CHANGED
@@ -336,7 +336,7 @@ Creates and configures the Express app.
336
336
  - `pagesDir` (required): Path to pages directory
337
337
  - `viewsDir` (optional): Path to views/layouts directory
338
338
  - `publicDir` (optional): Path to public/static directory
339
- - `db` (optional): Database instance — exposed as `ctx.db` in plugin hooks (`register`, `onRoutesReady`) and in page `load`/`meta` functions
339
+ - `db` (optional): Database instance — exposed as `ctx.db` in plugin hooks (`register`, `onRoutesReady`) and in page `load`/`meta` functions; also registered for [`getDb()` / `getAppContext()`](#app-context-getdb-hasdb-getappcontext) below
340
340
  - `logging` (optional): Enable request logging (default: true in development)
341
341
  - `helmet` (optional): Helmet security configuration
342
342
  - `true` or `undefined`: Use default secure configuration
@@ -386,6 +386,54 @@ module.exports = {
386
386
  };
387
387
  ```
388
388
 
389
+ ### App context (`req.db`, `getDb`, `attachDbMiddleware`)
390
+
391
+ With **`createApp({ db })`**, file-based **API** routes (`pages/api/*.js`) get the same ORM instance on **`req.db`** before your **`middleware`** array and the handler run — no extra `require` in the handler:
392
+
393
+ ```javascript
394
+ module.exports = async function handler(req, res) {
395
+ if (!req.db) {
396
+ return res.status(503).json({ error: 'Database not configured' });
397
+ }
398
+ const posts = await req.db.getRepository('Post').query().limit(10).list();
399
+ res.json(posts);
400
+ };
401
+
402
+ module.exports.middleware = ['auth']; // can use req.db too
403
+ ```
404
+
405
+ The framework also registers that instance for **non-request** code (scripts, jobs) and for tests:
406
+
407
+ ```javascript
408
+ const { getDb, hasDb } = require('webspresso');
409
+ // hasDb() / getDb() — getDb() throws if createApp had no db
410
+ ```
411
+
412
+ For routes you add manually in **`setupRoutes`**, run **`attachDbMiddleware`** early so those handlers get `req.db`:
413
+
414
+ ```javascript
415
+ const { createApp, attachDbMiddleware } = require('webspresso');
416
+
417
+ createApp({
418
+ pagesDir: './pages',
419
+ db,
420
+ setupRoutes(app) {
421
+ app.use(attachDbMiddleware);
422
+ app.get('/custom/api', (req, res) => res.json({ ok: !!req.db }));
423
+ },
424
+ });
425
+ ```
426
+
427
+ | Export | Role |
428
+ |--------|------|
429
+ | `req.db` | Set on each API request when `createApp({ db })` was used (file-based API routes + after `attachDbMiddleware`) |
430
+ | `getDb()` | Same instance as `req.db`; **throws** if no `db` was passed to `createApp` |
431
+ | `hasDb()` | `true` if `createApp` was given `db` |
432
+ | `getAppContext()` | `{ db }` — `db` may be `null` |
433
+ | `attachDbMiddleware` | Express middleware to populate `req.db` for non–file-router routes |
434
+ | `resetAppContext()` | Clears context (mainly for tests) |
435
+ | `setAppContext(partial)` | Low-level merge; normally only `createApp` uses this |
436
+
389
437
  **Custom Error Pages:**
390
438
 
391
439
  ```javascript
package/index.js CHANGED
@@ -3,6 +3,14 @@
3
3
  */
4
4
 
5
5
  const { createApp } = require('./src/server');
6
+ const {
7
+ attachDbMiddleware,
8
+ getAppContext,
9
+ getDb,
10
+ hasDb,
11
+ resetAppContext,
12
+ setAppContext,
13
+ } = require('./src/app-context');
6
14
  const {
7
15
  mountPages,
8
16
  filePathToRoute,
@@ -35,6 +43,13 @@ const { schemaExplorerPlugin, adminPanelPlugin, siteAnalyticsPlugin, auditLogPlu
35
43
  module.exports = {
36
44
  // Main API
37
45
  createApp,
46
+
47
+ attachDbMiddleware,
48
+ getAppContext,
49
+ getDb,
50
+ hasDb,
51
+ resetAppContext,
52
+ setAppContext,
38
53
 
39
54
  // Router utilities (for advanced use)
40
55
  mountPages,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webspresso",
3
- "version": "0.0.61",
3
+ "version": "0.0.62",
4
4
  "description": "Minimal, production-ready SSR framework for Node.js with file-based routing, Nunjucks templating, built-in i18n, and CLI tooling",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Process-wide app context set by createApp() — use from API handlers, jobs, etc.
3
+ * @module src/app-context
4
+ */
5
+
6
+ /** @type {{ db: object|null }} */
7
+ let context = {
8
+ db: null,
9
+ };
10
+
11
+ /**
12
+ * Merge into the current context (typically called once from createApp).
13
+ * @param {{ db?: object|null }} partial
14
+ */
15
+ function setAppContext(partial) {
16
+ context = { ...context, ...partial };
17
+ }
18
+
19
+ /**
20
+ * @returns {{ db: object|null }}
21
+ */
22
+ function getAppContext() {
23
+ return context;
24
+ }
25
+
26
+ /**
27
+ * Database instance passed to createApp({ db }) (Knex + ORM helpers).
28
+ * @returns {object}
29
+ * @throws {Error} If createApp was not given a db instance
30
+ */
31
+ function getDb() {
32
+ if (!context.db) {
33
+ throw new Error(
34
+ 'No database registered. Create a DB with createDatabase(), then pass it to createApp({ db }). ' +
35
+ 'Or use hasDb() before calling getDb().'
36
+ );
37
+ }
38
+ return context.db;
39
+ }
40
+
41
+ /**
42
+ * @returns {boolean}
43
+ */
44
+ function hasDb() {
45
+ return context.db != null;
46
+ }
47
+
48
+ /**
49
+ * Clear context (e.g. between tests).
50
+ */
51
+ function resetAppContext() {
52
+ context = { db: null };
53
+ }
54
+
55
+ /**
56
+ * Express middleware: sets `req.db` from registered app context.
57
+ * File-based `pages/api/*` routes attach this automatically; use in `setupRoutes`
58
+ * for manually registered handlers that need `req.db`.
59
+ * @type {import('express').RequestHandler}
60
+ */
61
+ function attachDbMiddleware(req, res, next) {
62
+ if (context.db != null) {
63
+ req.db = context.db;
64
+ }
65
+ next();
66
+ }
67
+
68
+ module.exports = {
69
+ setAppContext,
70
+ getAppContext,
71
+ getDb,
72
+ hasDb,
73
+ resetAppContext,
74
+ attachDbMiddleware,
75
+ };
@@ -397,6 +397,11 @@ function mountPages(app, options) {
397
397
 
398
398
  app[route.method](route.routePath, async (req, res, next) => {
399
399
  try {
400
+ // Same instance as createApp({ db }) / getAppContext().db — available to handler & route middleware
401
+ if (db != null) {
402
+ req.db = db;
403
+ }
404
+
400
405
  // Reload handler in dev mode
401
406
  if (isDev && require.cache[require.resolve(route.fullPath)]) {
402
407
  delete require.cache[require.resolve(route.fullPath)];
package/src/server.js CHANGED
@@ -8,6 +8,7 @@ const helmet = require('helmet');
8
8
  const nunjucks = require('nunjucks');
9
9
  const timeout = require('connect-timeout');
10
10
 
11
+ const { setAppContext } = require('./app-context');
11
12
  const { mountPages } = require('./file-router');
12
13
  const { configureAssets, createHelpers, getScriptInjector } = require('./helpers');
13
14
  const { createPluginManager } = require('./plugin-manager');
@@ -200,6 +201,8 @@ function createApp(options = {}) {
200
201
  if (!pagesDir) {
201
202
  throw new Error('pagesDir is required');
202
203
  }
204
+
205
+ setAppContext({ db: options.db ?? null });
203
206
 
204
207
  const app = express();
205
208
 
@@ -162,7 +162,7 @@ Analytics plugin adds `fsy.analyticsHead`, `fsy.verificationTags`, etc., when co
162
162
 
163
163
  **Transactions:** `db.transaction(async (trx) => { trx.getRepository('User') })`.
164
164
 
165
- Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and plugins.
165
+ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and plugins. **`pages/api/`** handlers receive **`req.db`** (and route **`middleware`** runs after it). Outside requests, use **`getDb()`** / **`hasDb()`**; for **`setupRoutes`**-only routes, use **`attachDbMiddleware`**.
166
166
 
167
167
  ---
168
168