@common-stack/server-stack 9.0.2-alpha.1 → 9.0.2-alpha.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.
@@ -1,12 +1,47 @@
1
- 'use strict';require('isomorphic-fetch');const contextServicesMiddleware = (createContext, serviceContext) => (req, res, next) => {
2
- Promise.all([
3
- createContext(req, res),
4
- serviceContext(req, res),
5
- ])
6
- .then(([context, services]) => {
7
- req.context = context;
8
- req.services = services;
1
+ 'use strict';require('isomorphic-fetch');/**
2
+ * Phase-aware context middleware. Runs only the `createContextFunc` factories
3
+ * whose `phase` property matches the current phase (untagged factories default
4
+ * to `pre-beforeware`).
5
+ *
6
+ * - `pre-beforeware` (default): seeds `req.services` with the container-built
7
+ * service map and merges any safe context factories. Lenient: a thrown
8
+ * factory is logged and skipped so the request can still reach auth.
9
+ * - `pre-middleware`: runs after the consumer's beforewares (e.g. auth chain),
10
+ * so factories that depend on `req.user` belong here. Strict: errors are
11
+ * propagated via `next(err)`.
12
+ * - `post-middleware`: runs after the consumer's middlewares. Strict.
13
+ */
14
+ const phasedContextMiddleware = (feature, phase) => async (req, res, next) => {
15
+ const isPreBeforeware = phase === 'pre-beforeware';
16
+ try {
17
+ const { context, matched } = await feature.runContextFactoriesForPhase(req, res, phase);
18
+ if (isPreBeforeware) {
19
+ const services = feature.services || {};
20
+ req.context = { ...(req.context || {}), ...context };
21
+ req.services = { ...(req.services || {}), ...services, ...context };
22
+ }
23
+ else if (matched) {
24
+ req.context = { ...(req.context || {}), ...context };
25
+ req.services = { ...(req.services || {}), ...context };
26
+ }
9
27
  next();
10
- })
11
- .catch((err) => next());
12
- };exports.contextServicesMiddleware=contextServicesMiddleware;//# sourceMappingURL=services.cjs.map
28
+ }
29
+ catch (err) {
30
+ if (isPreBeforeware) {
31
+ // Lenient: some factories require auth (which has not run yet).
32
+ // Seed req.services with the static service map so downstream
33
+ // beforewares still have a usable services object.
34
+ // eslint-disable-next-line no-console
35
+ console.warn(`[phased-context] pre-beforeware factory failed (continuing):`, err?.message);
36
+ const services = feature.services || {};
37
+ if (!req.services)
38
+ req.services = { ...services };
39
+ else
40
+ req.services = { ...req.services, ...services };
41
+ next();
42
+ }
43
+ else {
44
+ next(err);
45
+ }
46
+ }
47
+ };exports.phasedContextMiddleware=phasedContextMiddleware;//# sourceMappingURL=services.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.cjs","sources":["../../src/middleware/services.ts"],"sourcesContent":[null],"names":[],"mappings":"yCAEa,MAAA,yBAAyB,GAAG,CAAC,aAAa,EAAE,cAAc,KAAM,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,KAAI;IAC5F,OAAO,CAAC,GAAG,CAAC;AACR,QAAA,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC;AACvB,QAAA,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC;KAC3B,CAAC;SACG,IAAI,CAAC,CAAC,CAAE,OAAO,EAAE,QAAQ,CAAE,KAAI;AAC5B,QAAA,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;AACtB,QAAA,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAExB,QAAA,IAAI,EAAE,CAAC;AACX,KAAC,CAAC;SACD,KAAK,CAAC,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC;AAChC"}
1
+ {"version":3,"file":"services.cjs","sources":["../../src/middleware/services.ts"],"sourcesContent":[null],"names":[],"mappings":"yCAsBA;;;;;;;;;;;;AAYG;AACU,MAAA,uBAAuB,GAAG,CAAC,OAAgB,EAAE,KAAmB,KAAK,OAAO,GAAG,EAAE,GAAG,EAAE,IAAI,KAAI;AACvG,IAAA,MAAM,eAAe,GAAG,KAAK,KAAK,gBAAgB,CAAC;AACnD,IAAA,IAAI;AACA,QAAA,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,CAAC,2BAA2B,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACxF,IAAI,eAAe,EAAE;AACjB,YAAA,MAAM,QAAQ,GAAI,OAAe,CAAC,QAAQ,IAAI,EAAE,CAAC;AACjD,YAAA,GAAG,CAAC,OAAO,GAAG,EAAE,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;AACrD,YAAA,GAAG,CAAC,QAAQ,GAAG,EAAE,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;SACvE;aAAM,IAAI,OAAO,EAAE;AAChB,YAAA,GAAG,CAAC,OAAO,GAAG,EAAE,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;AACrD,YAAA,GAAG,CAAC,QAAQ,GAAG,EAAE,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;SAC1D;AACD,QAAA,IAAI,EAAE,CAAC;KACV;IAAC,OAAO,GAAG,EAAE;QACV,IAAI,eAAe,EAAE;;;;;YAKjB,OAAO,CAAC,IAAI,CAAC,CAAA,4DAAA,CAA8D,EAAG,GAAa,EAAE,OAAO,CAAC,CAAC;AACtG,YAAA,MAAM,QAAQ,GAAI,OAAe,CAAC,QAAQ,IAAI,EAAE,CAAC;YACjD,IAAI,CAAC,GAAG,CAAC,QAAQ;AAAE,gBAAA,GAAG,CAAC,QAAQ,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;;AAC7C,gBAAA,GAAG,CAAC,QAAQ,GAAG,EAAE,GAAG,GAAG,CAAC,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAC;AACrD,YAAA,IAAI,EAAE,CAAC;SACV;aAAM;YACH,IAAI,CAAC,GAAG,CAAC,CAAC;SACb;KACJ;AACL"}
@@ -1,12 +1,47 @@
1
- import'isomorphic-fetch';const contextServicesMiddleware = (createContext, serviceContext) => (req, res, next) => {
2
- Promise.all([
3
- createContext(req, res),
4
- serviceContext(req, res),
5
- ])
6
- .then(([context, services]) => {
7
- req.context = context;
8
- req.services = services;
1
+ import'isomorphic-fetch';/**
2
+ * Phase-aware context middleware. Runs only the `createContextFunc` factories
3
+ * whose `phase` property matches the current phase (untagged factories default
4
+ * to `pre-beforeware`).
5
+ *
6
+ * - `pre-beforeware` (default): seeds `req.services` with the container-built
7
+ * service map and merges any safe context factories. Lenient: a thrown
8
+ * factory is logged and skipped so the request can still reach auth.
9
+ * - `pre-middleware`: runs after the consumer's beforewares (e.g. auth chain),
10
+ * so factories that depend on `req.user` belong here. Strict: errors are
11
+ * propagated via `next(err)`.
12
+ * - `post-middleware`: runs after the consumer's middlewares. Strict.
13
+ */
14
+ const phasedContextMiddleware = (feature, phase) => async (req, res, next) => {
15
+ const isPreBeforeware = phase === 'pre-beforeware';
16
+ try {
17
+ const { context, matched } = await feature.runContextFactoriesForPhase(req, res, phase);
18
+ if (isPreBeforeware) {
19
+ const services = feature.services || {};
20
+ req.context = { ...(req.context || {}), ...context };
21
+ req.services = { ...(req.services || {}), ...services, ...context };
22
+ }
23
+ else if (matched) {
24
+ req.context = { ...(req.context || {}), ...context };
25
+ req.services = { ...(req.services || {}), ...context };
26
+ }
9
27
  next();
10
- })
11
- .catch((err) => next());
12
- };export{contextServicesMiddleware};//# sourceMappingURL=services.mjs.map
28
+ }
29
+ catch (err) {
30
+ if (isPreBeforeware) {
31
+ // Lenient: some factories require auth (which has not run yet).
32
+ // Seed req.services with the static service map so downstream
33
+ // beforewares still have a usable services object.
34
+ // eslint-disable-next-line no-console
35
+ console.warn(`[phased-context] pre-beforeware factory failed (continuing):`, err?.message);
36
+ const services = feature.services || {};
37
+ if (!req.services)
38
+ req.services = { ...services };
39
+ else
40
+ req.services = { ...req.services, ...services };
41
+ next();
42
+ }
43
+ else {
44
+ next(err);
45
+ }
46
+ }
47
+ };export{phasedContextMiddleware};//# sourceMappingURL=services.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.mjs","sources":["../../src/middleware/services.ts"],"sourcesContent":[null],"names":[],"mappings":"yBAEa,MAAA,yBAAyB,GAAG,CAAC,aAAa,EAAE,cAAc,KAAM,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,KAAI;IAC5F,OAAO,CAAC,GAAG,CAAC;AACR,QAAA,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC;AACvB,QAAA,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC;KAC3B,CAAC;SACG,IAAI,CAAC,CAAC,CAAE,OAAO,EAAE,QAAQ,CAAE,KAAI;AAC5B,QAAA,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;AACtB,QAAA,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAExB,QAAA,IAAI,EAAE,CAAC;AACX,KAAC,CAAC;SACD,KAAK,CAAC,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC;AAChC"}
1
+ {"version":3,"file":"services.mjs","sources":["../../src/middleware/services.ts"],"sourcesContent":[null],"names":[],"mappings":"yBAsBA;;;;;;;;;;;;AAYG;AACU,MAAA,uBAAuB,GAAG,CAAC,OAAgB,EAAE,KAAmB,KAAK,OAAO,GAAG,EAAE,GAAG,EAAE,IAAI,KAAI;AACvG,IAAA,MAAM,eAAe,GAAG,KAAK,KAAK,gBAAgB,CAAC;AACnD,IAAA,IAAI;AACA,QAAA,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,CAAC,2BAA2B,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACxF,IAAI,eAAe,EAAE;AACjB,YAAA,MAAM,QAAQ,GAAI,OAAe,CAAC,QAAQ,IAAI,EAAE,CAAC;AACjD,YAAA,GAAG,CAAC,OAAO,GAAG,EAAE,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;AACrD,YAAA,GAAG,CAAC,QAAQ,GAAG,EAAE,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;SACvE;aAAM,IAAI,OAAO,EAAE;AAChB,YAAA,GAAG,CAAC,OAAO,GAAG,EAAE,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;AACrD,YAAA,GAAG,CAAC,QAAQ,GAAG,EAAE,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;SAC1D;AACD,QAAA,IAAI,EAAE,CAAC;KACV;IAAC,OAAO,GAAG,EAAE;QACV,IAAI,eAAe,EAAE;;;;;YAKjB,OAAO,CAAC,IAAI,CAAC,CAAA,4DAAA,CAA8D,EAAG,GAAa,EAAE,OAAO,CAAC,CAAC;AACtG,YAAA,MAAM,QAAQ,GAAI,OAAe,CAAC,QAAQ,IAAI,EAAE,CAAC;YACjD,IAAI,CAAC,GAAG,CAAC,QAAQ;AAAE,gBAAA,GAAG,CAAC,QAAQ,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;;AAC7C,gBAAA,GAAG,CAAC,QAAQ,GAAG,EAAE,GAAG,GAAG,CAAC,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAC;AACrD,YAAA,IAAI,EAAE,CAAC;SACV;aAAM;YACH,IAAI,CAAC,GAAG,CAAC,CAAC;SACb;KACJ;AACL"}
@@ -6,10 +6,17 @@ function expressApp(modules, options, middlewares, http, redisClient$1) {
6
6
  if (redisClient$1) {
7
7
  app.use(redisClient.redisClientMiddleware(redisClient$1));
8
8
  }
9
- app.use(services.contextServicesMiddleware(options.createContext, options.serviceContext));
9
+ // Phase 1: pre-beforeware — runs default-tagged context factories and
10
+ // seeds req.services from the static service map. Lenient: a factory
11
+ // that throws (e.g. one that requires auth) is logged and skipped.
12
+ app.use(services.phasedContextMiddleware(modules, 'pre-beforeware'));
13
+ // Consumer beforewares (e.g. auth chains for /graphql, /api/workflow).
10
14
  for (const applyBeforeware of modules.beforewares) {
11
15
  applyBeforeware(app);
12
16
  }
17
+ // Phase 2: pre-middleware — runs context factories tagged
18
+ // `phase = 'pre-middleware'` (e.g. ones that read req.user). Strict.
19
+ app.use(services.phasedContextMiddleware(modules, 'pre-middleware'));
13
20
  // Don't rate limit heroku
14
21
  app.enable('trust proxy');
15
22
  if (middlewares !== null) {
@@ -33,6 +40,10 @@ function expressApp(modules, options, middlewares, http, redisClient$1) {
33
40
  for (const applyMiddleware of modules.middlewares) {
34
41
  applyMiddleware(app);
35
42
  }
43
+ // Phase 3: post-middleware — runs context factories tagged
44
+ // `phase = 'post-middleware'`. Strict. Skipped at zero cost when none
45
+ // are tagged.
46
+ app.use(services.phasedContextMiddleware(modules, 'post-middleware'));
36
47
  // Sentry error handler must be after all middleware/routes but before generic error handlers
37
48
  Sentry__namespace.setupExpressErrorHandler(app);
38
49
  if (__DEV__) {
@@ -1 +1 @@
1
- {"version":3,"file":"ExpressApp.cjs","sources":["../../src/servers/ExpressApp.ts"],"sourcesContent":[null],"names":["redisClient","redisClientMiddleware","contextServicesMiddleware","corsMiddleware","Sentry","errorMiddleware"],"mappings":"4qBAAA;AAWM,SAAU,UAAU,CAAC,OAAgB,EAAE,OAAuB,EAAE,WAAW,EAAE,IAAK,EAAEA,aAAY,EAAA;AAClG,IAAA,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;;;IAItB,IAAIA,aAAW,EAAE;QACb,GAAG,CAAC,GAAG,CAACC,iCAAqB,CAACD,aAAW,CAAC,CAAC,CAAC;KAC/C;AAED,IAAA,GAAG,CAAC,GAAG,CAACE,kCAAyB,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;AAClF,IAAA,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE;QAC/C,eAAe,CAAC,GAAG,CAAC,CAAC;KACxB;;AAGD,IAAA,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AAE1B,IAAA,IAAI,WAAW,KAAK,IAAI,EAAE;AACtB,QAAA,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;KACxB;AAED,IAAA,GAAG,CAAC,GAAG,CAACC,mBAAc,CAAC,CAAC;IACxB,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,KAAI;AACvB,QAAA,GAAG,CAAC,MAAM,CAAC,kCAAkC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACrE,QAAA,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,qBAAqB,CAAC,CAAC;AAClE,QAAA,GAAG,CAAC,MAAM,CACN,8BAA8B,EAC9B,6EAA6E,CAChF,CAAC;AACF,QAAA,IAAI,EAAE,CAAC;AACX,KAAC,CAAC,CAAC;AAEH,IAAA,GAAG,CAAC,GAAG,CACH,UAAU,CAAC,IAAI,CAAC;AACZ,QAAA,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,KAAI;;AAErB,YAAA,GAAW,CAAC,OAAO,GAAG,GAAG,CAAC;SAC9B;AACJ,KAAA,CAAC,CACL,CAAC;IACF,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAEzF,IAAA,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE;QAC/C,eAAe,CAAC,GAAG,CAAC,CAAC;KACxB;;AAGD,IAAAC,iBAAM,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;IAErC,IAAI,OAAO,EAAE;AACT,QAAA,GAAG,CAAC,GAAG,CAACC,qBAAe,CAAC,CAAC;KAC5B;AAED,IAAA,OAAO,GAAG,CAAC;AACf"}
1
+ {"version":3,"file":"ExpressApp.cjs","sources":["../../src/servers/ExpressApp.ts"],"sourcesContent":[null],"names":["redisClient","redisClientMiddleware","phasedContextMiddleware","corsMiddleware","Sentry","errorMiddleware"],"mappings":"4qBAAA;AAWM,SAAU,UAAU,CAAC,OAAgB,EAAE,OAAuB,EAAE,WAAW,EAAE,IAAK,EAAEA,aAAY,EAAA;AAClG,IAAA,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;;;IAItB,IAAIA,aAAW,EAAE;QACb,GAAG,CAAC,GAAG,CAACC,iCAAqB,CAACD,aAAW,CAAC,CAAC,CAAC;KAC/C;;;;IAKD,GAAG,CAAC,GAAG,CAACE,gCAAuB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;;AAG5D,IAAA,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE;QAC/C,eAAe,CAAC,GAAG,CAAC,CAAC;KACxB;;;IAID,GAAG,CAAC,GAAG,CAACA,gCAAuB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;;AAG5D,IAAA,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AAE1B,IAAA,IAAI,WAAW,KAAK,IAAI,EAAE;AACtB,QAAA,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;KACxB;AAED,IAAA,GAAG,CAAC,GAAG,CAACC,mBAAc,CAAC,CAAC;IACxB,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,KAAI;AACvB,QAAA,GAAG,CAAC,MAAM,CAAC,kCAAkC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACrE,QAAA,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,qBAAqB,CAAC,CAAC;AAClE,QAAA,GAAG,CAAC,MAAM,CACN,8BAA8B,EAC9B,6EAA6E,CAChF,CAAC;AACF,QAAA,IAAI,EAAE,CAAC;AACX,KAAC,CAAC,CAAC;AAEH,IAAA,GAAG,CAAC,GAAG,CACH,UAAU,CAAC,IAAI,CAAC;AACZ,QAAA,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,KAAI;;AAErB,YAAA,GAAW,CAAC,OAAO,GAAG,GAAG,CAAC;SAC9B;AACJ,KAAA,CAAC,CACL,CAAC;IACF,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAEzF,IAAA,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE;QAC/C,eAAe,CAAC,GAAG,CAAC,CAAC;KACxB;;;;IAKD,GAAG,CAAC,GAAG,CAACD,gCAAuB,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC;;AAG7D,IAAAE,iBAAM,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;IAErC,IAAI,OAAO,EAAE;AACT,QAAA,GAAG,CAAC,GAAG,CAACC,qBAAe,CAAC,CAAC;KAC5B;AAED,IAAA,OAAO,GAAG,CAAC;AACf"}
@@ -1,4 +1,4 @@
1
- import express from'express';import bodyParser from'body-parser';import {errorMiddleware}from'../middleware/error.mjs';import {contextServicesMiddleware}from'../middleware/services.mjs';import'../middleware/sentry.mjs';import {redisClientMiddleware}from'../middleware/redis-client.mjs';import {corsMiddleware}from'../middleware/cors.mjs';import*as Sentry from'@sentry/node';/* eslint-disable @typescript-eslint/no-var-requires */
1
+ import express from'express';import bodyParser from'body-parser';import {errorMiddleware}from'../middleware/error.mjs';import {phasedContextMiddleware}from'../middleware/services.mjs';import'../middleware/sentry.mjs';import {redisClientMiddleware}from'../middleware/redis-client.mjs';import {corsMiddleware}from'../middleware/cors.mjs';import*as Sentry from'@sentry/node';/* eslint-disable @typescript-eslint/no-var-requires */
2
2
  function expressApp(modules, options, middlewares, http, redisClient) {
3
3
  const app = express();
4
4
  // FIRST PRIORITY: Add Redis client middleware at the very top
@@ -6,10 +6,17 @@ function expressApp(modules, options, middlewares, http, redisClient) {
6
6
  if (redisClient) {
7
7
  app.use(redisClientMiddleware(redisClient));
8
8
  }
9
- app.use(contextServicesMiddleware(options.createContext, options.serviceContext));
9
+ // Phase 1: pre-beforeware — runs default-tagged context factories and
10
+ // seeds req.services from the static service map. Lenient: a factory
11
+ // that throws (e.g. one that requires auth) is logged and skipped.
12
+ app.use(phasedContextMiddleware(modules, 'pre-beforeware'));
13
+ // Consumer beforewares (e.g. auth chains for /graphql, /api/workflow).
10
14
  for (const applyBeforeware of modules.beforewares) {
11
15
  applyBeforeware(app);
12
16
  }
17
+ // Phase 2: pre-middleware — runs context factories tagged
18
+ // `phase = 'pre-middleware'` (e.g. ones that read req.user). Strict.
19
+ app.use(phasedContextMiddleware(modules, 'pre-middleware'));
13
20
  // Don't rate limit heroku
14
21
  app.enable('trust proxy');
15
22
  if (middlewares !== null) {
@@ -33,6 +40,10 @@ function expressApp(modules, options, middlewares, http, redisClient) {
33
40
  for (const applyMiddleware of modules.middlewares) {
34
41
  applyMiddleware(app);
35
42
  }
43
+ // Phase 3: post-middleware — runs context factories tagged
44
+ // `phase = 'post-middleware'`. Strict. Skipped at zero cost when none
45
+ // are tagged.
46
+ app.use(phasedContextMiddleware(modules, 'post-middleware'));
36
47
  // Sentry error handler must be after all middleware/routes but before generic error handlers
37
48
  Sentry.setupExpressErrorHandler(app);
38
49
  if (__DEV__) {
@@ -1 +1 @@
1
- {"version":3,"file":"ExpressApp.mjs","sources":["../../src/servers/ExpressApp.ts"],"sourcesContent":[null],"names":[],"mappings":"sXAAA;AAWM,SAAU,UAAU,CAAC,OAAgB,EAAE,OAAuB,EAAE,WAAW,EAAE,IAAK,EAAE,WAAY,EAAA;AAClG,IAAA,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;;;IAItB,IAAI,WAAW,EAAE;QACb,GAAG,CAAC,GAAG,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAC;KAC/C;AAED,IAAA,GAAG,CAAC,GAAG,CAAC,yBAAyB,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;AAClF,IAAA,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE;QAC/C,eAAe,CAAC,GAAG,CAAC,CAAC;KACxB;;AAGD,IAAA,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AAE1B,IAAA,IAAI,WAAW,KAAK,IAAI,EAAE;AACtB,QAAA,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;KACxB;AAED,IAAA,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACxB,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,KAAI;AACvB,QAAA,GAAG,CAAC,MAAM,CAAC,kCAAkC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACrE,QAAA,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,qBAAqB,CAAC,CAAC;AAClE,QAAA,GAAG,CAAC,MAAM,CACN,8BAA8B,EAC9B,6EAA6E,CAChF,CAAC;AACF,QAAA,IAAI,EAAE,CAAC;AACX,KAAC,CAAC,CAAC;AAEH,IAAA,GAAG,CAAC,GAAG,CACH,UAAU,CAAC,IAAI,CAAC;AACZ,QAAA,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,KAAI;;AAErB,YAAA,GAAW,CAAC,OAAO,GAAG,GAAG,CAAC;SAC9B;AACJ,KAAA,CAAC,CACL,CAAC;IACF,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAEzF,IAAA,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE;QAC/C,eAAe,CAAC,GAAG,CAAC,CAAC;KACxB;;AAGD,IAAA,MAAM,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;IAErC,IAAI,OAAO,EAAE;AACT,QAAA,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;KAC5B;AAED,IAAA,OAAO,GAAG,CAAC;AACf"}
1
+ {"version":3,"file":"ExpressApp.mjs","sources":["../../src/servers/ExpressApp.ts"],"sourcesContent":[null],"names":[],"mappings":"oXAAA;AAWM,SAAU,UAAU,CAAC,OAAgB,EAAE,OAAuB,EAAE,WAAW,EAAE,IAAK,EAAE,WAAY,EAAA;AAClG,IAAA,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;;;IAItB,IAAI,WAAW,EAAE;QACb,GAAG,CAAC,GAAG,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAC;KAC/C;;;;IAKD,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;;AAG5D,IAAA,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE;QAC/C,eAAe,CAAC,GAAG,CAAC,CAAC;KACxB;;;IAID,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;;AAG5D,IAAA,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AAE1B,IAAA,IAAI,WAAW,KAAK,IAAI,EAAE;AACtB,QAAA,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;KACxB;AAED,IAAA,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACxB,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,KAAI;AACvB,QAAA,GAAG,CAAC,MAAM,CAAC,kCAAkC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACrE,QAAA,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,qBAAqB,CAAC,CAAC;AAClE,QAAA,GAAG,CAAC,MAAM,CACN,8BAA8B,EAC9B,6EAA6E,CAChF,CAAC;AACF,QAAA,IAAI,EAAE,CAAC;AACX,KAAC,CAAC,CAAC;AAEH,IAAA,GAAG,CAAC,GAAG,CACH,UAAU,CAAC,IAAI,CAAC;AACZ,QAAA,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,KAAI;;AAErB,YAAA,GAAW,CAAC,OAAO,GAAG,GAAG,CAAC;SAC9B;AACJ,KAAA,CAAC,CACL,CAAC;IACF,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAEzF,IAAA,KAAK,MAAM,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE;QAC/C,eAAe,CAAC,GAAG,CAAC,CAAC;KACxB;;;;IAKD,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC;;AAG7D,IAAA,MAAM,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;IAErC,IAAI,OAAO,EAAE;AACT,QAAA,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;KAC5B;AAED,IAAA,OAAO,GAAG,CAAC;AACf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@common-stack/server-stack",
3
- "version": "9.0.2-alpha.1",
3
+ "version": "9.0.2-alpha.2",
4
4
  "description": "common core for higher packages to depend on",
5
5
  "license": "UNLICENSED",
6
6
  "author": "CDMBase LLC",
@@ -33,7 +33,7 @@
33
33
  "@cdm-logger/server": "^9.0.17",
34
34
  "@cdmbase/graphql-type-uri": "^4.0.0",
35
35
  "@common-stack/codegen-zod": "9.0.2-alpha.1",
36
- "@common-stack/graphql-api": "9.0.2-alpha.1",
36
+ "@common-stack/graphql-api": "9.0.2-alpha.2",
37
37
  "@common-stack/store-redis": "9.0.2-alpha.1",
38
38
  "@graphql-tools/links": "^9.0.1",
39
39
  "@graphql-tools/schema": "^10.0.6",
@@ -84,7 +84,7 @@
84
84
  "zod": "^4.0.0"
85
85
  },
86
86
  "devDependencies": {
87
- "@common-stack/server-core": "9.0.2-alpha.1",
87
+ "@common-stack/server-core": "9.0.2-alpha.2",
88
88
  "common": "9.0.2-alpha.1"
89
89
  },
90
90
  "peerDependencies": {
@@ -98,7 +98,7 @@
98
98
  "publishConfig": {
99
99
  "access": "public"
100
100
  },
101
- "gitHead": "4a8d494c6c85340528c69d6729cf8518a3f0277c",
101
+ "gitHead": "a9302f283cd6804ea171774a4f476dc911855b42",
102
102
  "typescript": {
103
103
  "definition": "lib/index.d.ts"
104
104
  }