ctx-router 0.1.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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +320 -0
  3. package/dist/adapter/express.v5.d.ts +11 -0
  4. package/dist/adapter/express.v5.d.ts.map +1 -0
  5. package/dist/adapter/express.v5.js +119 -0
  6. package/dist/adapter/express.v5.js.map +1 -0
  7. package/dist/adapter/index.d.ts +2 -0
  8. package/dist/adapter/index.d.ts.map +1 -0
  9. package/dist/adapter/index.js +6 -0
  10. package/dist/adapter/index.js.map +1 -0
  11. package/dist/common/const.d.ts +6 -0
  12. package/dist/common/const.d.ts.map +1 -0
  13. package/dist/common/const.js +9 -0
  14. package/dist/common/const.js.map +1 -0
  15. package/dist/common/helper.d.ts +7 -0
  16. package/dist/common/helper.d.ts.map +1 -0
  17. package/dist/common/helper.js +34 -0
  18. package/dist/common/helper.js.map +1 -0
  19. package/dist/core/index.d.ts +25 -0
  20. package/dist/core/index.d.ts.map +1 -0
  21. package/dist/core/index.js +10 -0
  22. package/dist/core/index.js.map +1 -0
  23. package/dist/core/meta.d.ts +55 -0
  24. package/dist/core/meta.d.ts.map +1 -0
  25. package/dist/core/meta.js +3 -0
  26. package/dist/core/meta.js.map +1 -0
  27. package/dist/core/req.d.ts +131 -0
  28. package/dist/core/req.d.ts.map +1 -0
  29. package/dist/core/req.js +3 -0
  30. package/dist/core/req.js.map +1 -0
  31. package/dist/core/res.d.ts +26 -0
  32. package/dist/core/res.d.ts.map +1 -0
  33. package/dist/core/res.js +3 -0
  34. package/dist/core/res.js.map +1 -0
  35. package/dist/core/user.d.ts +24 -0
  36. package/dist/core/user.d.ts.map +1 -0
  37. package/dist/core/user.js +3 -0
  38. package/dist/core/user.js.map +1 -0
  39. package/dist/defaultHook/hook.onExecBefore.d.ts +4 -0
  40. package/dist/defaultHook/hook.onExecBefore.d.ts.map +1 -0
  41. package/dist/defaultHook/hook.onExecBefore.js +30 -0
  42. package/dist/defaultHook/hook.onExecBefore.js.map +1 -0
  43. package/dist/defaultHook/hook.onExecError.d.ts +4 -0
  44. package/dist/defaultHook/hook.onExecError.d.ts.map +1 -0
  45. package/dist/defaultHook/hook.onExecError.js +39 -0
  46. package/dist/defaultHook/hook.onExecError.js.map +1 -0
  47. package/dist/index.d.ts +16 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +21 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/router/error.d.ts +290 -0
  52. package/dist/router/error.d.ts.map +1 -0
  53. package/dist/router/error.js +283 -0
  54. package/dist/router/error.js.map +1 -0
  55. package/dist/router/index.d.ts +4 -0
  56. package/dist/router/index.d.ts.map +1 -0
  57. package/dist/router/index.js +9 -0
  58. package/dist/router/index.js.map +1 -0
  59. package/dist/router/instance.d.ts +15 -0
  60. package/dist/router/instance.d.ts.map +1 -0
  61. package/dist/router/instance.js +32 -0
  62. package/dist/router/instance.js.map +1 -0
  63. package/dist/router/lifecycle.exec.d.ts +17 -0
  64. package/dist/router/lifecycle.exec.d.ts.map +1 -0
  65. package/dist/router/lifecycle.exec.js +132 -0
  66. package/dist/router/lifecycle.exec.js.map +1 -0
  67. package/dist/router/router.d.ts +74 -0
  68. package/dist/router/router.d.ts.map +1 -0
  69. package/dist/router/router.js +326 -0
  70. package/dist/router/router.js.map +1 -0
  71. package/dist/router/types.d.ts +44 -0
  72. package/dist/router/types.d.ts.map +1 -0
  73. package/dist/router/types.js +3 -0
  74. package/dist/router/types.js.map +1 -0
  75. package/package.json +94 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Hyugorix
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,320 @@
1
+ # ctx-router
2
+
3
+ A transport-agnostic router built around a single execution context.
4
+
5
+ Write your business logic once. Run it over HTTP, events, jobs, queues, or anything else — without rewriting handlers.
6
+
7
+ ## Why ctx-router exists
8
+
9
+ Most applications start simple:
10
+
11
+ - HTTP with Express / Fastify
12
+ - A few REST endpoints
13
+ - Some middleware
14
+
15
+ Then reality hits:
16
+
17
+ - You add background jobs (SQS, Kafka, cron)
18
+ - You need async workers
19
+ - You want to reuse business logic
20
+ - You deploy to Lambda or another runtime
21
+ - You end up duplicating logic across transports
22
+
23
+ The problem is not routing.
24
+ The problem is transport leakage into business logic.
25
+
26
+ ## What ctx-router is
27
+
28
+ ctx-router is a routing + execution layer that:
29
+
30
+ - Normalizes all ingress types into a single context
31
+ - Routes based on patterns, not frameworks
32
+ - Executes logic as a linear pipeline
33
+ - Keeps transport concerns outside your business code
34
+
35
+ It is not:
36
+
37
+ - A web framework
38
+ - An HTTP abstraction
39
+ - A DI container
40
+
41
+ It is a context router.
42
+
43
+ ## Core idea (one sentence)
44
+
45
+ Everything becomes a ctx. Routes select a pipeline. Pipelines mutate the ctx.
46
+
47
+ ## High-level flow
48
+
49
+ ```mermaid
50
+ flowchart LR
51
+ A["Ingress<br/>HTTP / Queue / Job"] --> B["Create ctx"]
52
+ B --> C["Adapter enrich"]
53
+ C --> D["router.exec(ctx)"]
54
+ D --> E["Route match"]
55
+ E --> F["Pipeline execution"]
56
+ F --> G["ctx.res set"]
57
+ G --> H["Adapter sends response / ack"]
58
+ ```
59
+
60
+ ## Key concepts (read in order)
61
+
62
+ ### 1. Context (ctx)
63
+
64
+ The single object that flows through your entire system.
65
+
66
+ - Created once per request / event
67
+ - Mutated by middleware and handlers
68
+ - Returned at the end
69
+
70
+ Business logic never touches raw framework objects.
71
+
72
+ ### 2. Routes are patterns
73
+
74
+ Routes are identified by patterns, not concrete values.
75
+
76
+ Examples:
77
+
78
+ - `user.:id.detail`
79
+ - `job.:resource.clean`
80
+ - `GET /user/:id`
81
+
82
+ Patterns:
83
+
84
+ - are low-cardinality
85
+ - are safe to log & index
86
+ - are the identity of a route
87
+
88
+ Raw values are kept separately.
89
+
90
+ ### 3. Pipelines are linear
91
+
92
+ Every route resolves to a prebuilt pipeline:
93
+
94
+ ```
95
+ [ middleware1 → middleware2 → handler ]
96
+ ```
97
+
98
+ - Always sequential
99
+ - Always awaited
100
+ - No fan-out
101
+ - No magic
102
+
103
+ ### 4. Build-time vs runtime
104
+
105
+ | Phase | What happens |
106
+ | ---------- | ------------------------------------------ |
107
+ | Build time | `route()`, `via()`, `to()` build pipelines |
108
+ | Runtime | `exec(ctx)` selects & runs a pipeline |
109
+
110
+ The runtime never sees the DSL.
111
+
112
+ ## Installation
113
+
114
+ ```bash
115
+ npm install ctx-router
116
+ ```
117
+
118
+ ## Minimal example
119
+
120
+ ### `router.ts`
121
+
122
+ ```typescript
123
+ import { CtxRouter, TDefaultCtx } from "ctx-router";
124
+ import * as api from "./api";
125
+
126
+ export type TCtx = TDefaultCtx & {
127
+ user: { role: string[] };
128
+ };
129
+
130
+ export const router = new CtxRouter<TCtx>();
131
+
132
+ router.route("GET /health/ping").to(api.health.ping);
133
+
134
+ const userRouter = router.route("user").via(rateLimit, auth);
135
+
136
+ userRouter.route("POST /update").to(api.user.update);
137
+ userRouter.route("GET /:userId").to(api.user.detail);
138
+ userRouter.route("detail").to(api.user.detail);
139
+ ```
140
+
141
+ ### `server.ts` (Express example)
142
+
143
+ ```typescript
144
+ import express from "express";
145
+ import { adapter } from "ctx-router";
146
+ import { router, TCtx } from "./router";
147
+
148
+ const app = express();
149
+ app.use(express.json());
150
+
151
+ app.use(async (req, res) => {
152
+ const ctx: TCtx = router.newCtx();
153
+ adapter.enrichFromExpress(ctx, req, res);
154
+
155
+ await router.exec(ctx);
156
+
157
+ res.status(ctx.res.code === "OK" ? 200 : 400).json(ctx.res);
158
+ });
159
+
160
+ app.listen(3000);
161
+ ```
162
+
163
+ The same router works for Lambda, SQS, Kafka, cron jobs, etc.
164
+
165
+ ## Routing DSL
166
+
167
+ ### `route(segment)`
168
+
169
+ Adds a prefix segment.
170
+
171
+ ```typescript
172
+ router.route("user").route(":id").route("detail");
173
+ ```
174
+
175
+ Builds the pattern:
176
+
177
+ ```
178
+ user.:id.detail
179
+ ```
180
+
181
+ ### `via(...middleware)`
182
+
183
+ Adds middleware to the pipeline.
184
+
185
+ ```typescript
186
+ route("x").via(auth, validate).to(handler);
187
+ ```
188
+
189
+ - Sequential
190
+ - Awaited
191
+ - Mutates ctx
192
+
193
+ ### `to(handler)`
194
+
195
+ Registers the terminal handler.
196
+
197
+ - Exactly one handler
198
+ - Ends the pipeline
199
+ - Build-time only
200
+ - Returns void
201
+
202
+ ## Execution lifecycle (authoritative)
203
+
204
+ ```mermaid
205
+ sequenceDiagram
206
+ participant Ingress
207
+ participant Router
208
+ participant Hooks
209
+ participant Handler
210
+
211
+ Ingress->>Router: newCtx()
212
+ Ingress->>Router: enrich(ctx)
213
+ Ingress->>Router: exec(ctx)
214
+
215
+ Router->>Router: init metrics & trace
216
+ Router->>Hooks: onExecBefore(ctx)
217
+
218
+ Router->>Router: match route
219
+ Router->>Handler: run pipeline
220
+
221
+ Handler-->>Router: ctx
222
+ Router->>Hooks: onExecAfter(ctx)
223
+
224
+ Router->>Hooks: onExecFinally(ctx)
225
+ Router-->>Ingress: ctx
226
+ ```
227
+
228
+ ## Hooks (system lifecycle)
229
+
230
+ Hooks wrap execution, not routing DSL.
231
+
232
+ ```typescript
233
+ router.hook.onExec.before(async (ctx) => {
234
+ console.log("request in", ctx.id);
235
+ });
236
+
237
+ router.hook.onExec.error(async (ctx, err) => {
238
+ ctx.res.code = "ERROR";
239
+ });
240
+ ```
241
+
242
+ Available hooks:
243
+
244
+ - `onExec.before`
245
+ - `onExec.after`
246
+ - `onExec.error`
247
+ - `onExec.finally`
248
+
249
+ Hooks are side-effect only and mutate ctx directly.
250
+
251
+ ## Error handling
252
+
253
+ ctx-router provides a structured error system.
254
+
255
+ ### Define your error class
256
+
257
+ ```typescript
258
+ class AppError extends CtxBaseError {
259
+ constructor(e) {
260
+ super(e);
261
+ }
262
+ }
263
+ ```
264
+
265
+ ### Create error map
266
+
267
+ ```typescript
268
+ export const appErr = ctxErrMap(AppError, {
269
+ auth: {
270
+ UNAUTHORIZED: "Unauthorized",
271
+ },
272
+ general: {
273
+ UNKNOWN_ERROR: "Something went wrong",
274
+ },
275
+ });
276
+ ```
277
+
278
+ ### Throw anywhere
279
+
280
+ ```typescript
281
+ throw appErr.auth.UNAUTHORIZED({
282
+ data: { reason: "missing_token" },
283
+ });
284
+ ```
285
+
286
+ Router errors and app errors are cleanly separated.
287
+
288
+ ## Design guarantees
289
+
290
+ - Transport-agnostic
291
+ - Pattern-first routing
292
+ - Low cardinality by design
293
+ - Linear, deterministic execution
294
+ - No hidden parallelism
295
+ - No framework lock-in
296
+
297
+ ## When should you use ctx-router?
298
+
299
+ Use it if you:
300
+
301
+ - Share logic between HTTP + jobs
302
+ - Want clean boundaries between transport and business logic
303
+ - Care about observability and routing identity
304
+ - Prefer explicit, boring execution models
305
+
306
+ Do not use it if you want:
307
+
308
+ - Automatic DI
309
+ - Controllers / decorators
310
+ - Magic middleware behavior
311
+
312
+ ## Status
313
+
314
+ - First public release
315
+ - API intentionally small
316
+ - Focused on correctness over features
317
+
318
+ ## License
319
+
320
+ MIT © Kaushik R Bangera
@@ -0,0 +1,11 @@
1
+ import { Request, Response } from "express";
2
+ import { TDefaultCtx } from "../core";
3
+ /**
4
+ * Enriches an existing context with Express request data.
5
+ * Modifies ctx in-place.
6
+ *
7
+ * @param ctx - Context created by router.getNewCtx()
8
+ * @param req - Express request object
9
+ */
10
+ export declare function enrichFromExpress(ctx: TDefaultCtx, req: Request, res: Response): void;
11
+ //# sourceMappingURL=express.v5.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.v5.d.ts","sourceRoot":"","sources":["../../src/adapter/express.v5.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA4BtC;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACZ,IAAI,CAiFN"}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enrichFromExpress = enrichFromExpress;
4
+ function getPath(url) {
5
+ const queryParamPos = url.indexOf("?");
6
+ if (queryParamPos === -1)
7
+ return url;
8
+ return url.substring(0, queryParamPos);
9
+ }
10
+ function extractBearerToken(authHeader) {
11
+ if (!authHeader)
12
+ return undefined;
13
+ const auth = Array.isArray(authHeader) ? authHeader[0] : authHeader;
14
+ if (auth?.startsWith("Bearer ")) {
15
+ return auth.substring(7);
16
+ }
17
+ return undefined;
18
+ }
19
+ function getHeader(headers, key) {
20
+ const value = headers[key];
21
+ if (!value)
22
+ return undefined;
23
+ return Array.isArray(value) ? value[0] : value;
24
+ }
25
+ /**
26
+ * Enriches an existing context with Express request data.
27
+ * Modifies ctx in-place.
28
+ *
29
+ * @param ctx - Context created by router.getNewCtx()
30
+ * @param req - Express request object
31
+ */
32
+ function enrichFromExpress(ctx, req, res) {
33
+ const method = req.method;
34
+ const path = getPath(req.url);
35
+ // Build auth (only include fields that exist)
36
+ const bearerToken = extractBearerToken(req.headers.authorization);
37
+ const apiKey = getHeader(req.headers, "x-api-key");
38
+ const refreshToken = getHeader(req.headers, "x-ctx-refresh-token");
39
+ const auth = {};
40
+ if (bearerToken)
41
+ auth.bearerToken = bearerToken;
42
+ if (apiKey)
43
+ auth.apiKey = apiKey;
44
+ if (refreshToken)
45
+ auth.refreshToken = refreshToken;
46
+ // Build client (only include fields that exist)
47
+ const deviceName = getHeader(req.headers, "x-ctx-device-name");
48
+ const deviceId = getHeader(req.headers, "x-ctx-device-id");
49
+ const os = getHeader(req.headers, "x-ctx-os");
50
+ const appVersion = getHeader(req.headers, "x-ctx-app-version");
51
+ const apiVersion = getHeader(req.headers, "x-ctx-api-version");
52
+ const sessionId = getHeader(req.headers, "x-ctx-session-id");
53
+ const client = {};
54
+ if (deviceName)
55
+ client.deviceName = deviceName;
56
+ if (deviceId)
57
+ client.deviceId = deviceId;
58
+ if (os)
59
+ client.os = os;
60
+ if (appVersion)
61
+ client.appVersion = appVersion;
62
+ if (apiVersion)
63
+ client.apiVersion = apiVersion;
64
+ if (sessionId)
65
+ client.sessionId = sessionId;
66
+ // Build clientInvocation (only include fields that exist)
67
+ const invocationTraceId = getHeader(req.headers, "x-ctx-trace-id");
68
+ const invocationSeq = parseInt(getHeader(req.headers, "x-ctx-seq") || "0", 10);
69
+ const clientTsStr = getHeader(req.headers, "x-ctx-ts");
70
+ const clientTs = clientTsStr ? new Date(clientTsStr).getTime() : undefined;
71
+ const clientInvocation = {};
72
+ if (invocationTraceId)
73
+ clientInvocation.traceId = invocationTraceId;
74
+ if (invocationSeq)
75
+ clientInvocation.seq = invocationSeq;
76
+ if (clientTs && !isNaN(clientTs))
77
+ clientInvocation.ts = clientTs;
78
+ // Build transport meta (only include fields that exist)
79
+ const userAgent = getHeader(req.headers, "user-agent");
80
+ const contentType = getHeader(req.headers, "content-type");
81
+ const transportMeta = {};
82
+ if (userAgent)
83
+ transportMeta["user-agent"] = userAgent;
84
+ if (contentType)
85
+ transportMeta["content-type"] = contentType;
86
+ // Enrich ctx.req
87
+ ctx.req.data = { ...req.body, ...req.query, ...req.params };
88
+ ctx.req.route = {
89
+ op: method, // HTTP method (GET, POST, etc.)
90
+ raw: path, // Concrete path with "/" separator
91
+ pattern: "PENDING", // Router will set after matching
92
+ };
93
+ if (Object.keys(auth).length > 0)
94
+ ctx.req.auth = auth;
95
+ if (Object.keys(client).length > 0)
96
+ ctx.req.client = client;
97
+ if (Object.keys(clientInvocation).length > 0)
98
+ ctx.req.clientInvocation = clientInvocation;
99
+ ctx.req.transport = {
100
+ protocol: "http",
101
+ framework: "express",
102
+ request: {
103
+ method,
104
+ path,
105
+ },
106
+ ...(req.ip && {
107
+ network: {
108
+ originIp: req.ip,
109
+ hops: req.ips,
110
+ },
111
+ }),
112
+ ...(Object.keys(transportMeta).length > 0 && { meta: transportMeta }),
113
+ raw: {
114
+ req,
115
+ res,
116
+ },
117
+ };
118
+ }
119
+ //# sourceMappingURL=express.v5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.v5.js","sourceRoot":"","sources":["../../src/adapter/express.v5.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // This file previously contained INSTANCE and utility functions
4
+ // These have been moved to CtxRouter as instance properties and methods
5
+ // Keeping this file for potential future adapter utilities
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":";;AAAA,gEAAgE;AAChE,wEAAwE;AACxE,2DAA2D"}
@@ -0,0 +1,6 @@
1
+ export declare const STATS_INTERVAL_MS = 5000;
2
+ export declare const STATS: {
3
+ cpu: number;
4
+ mem: number;
5
+ };
6
+ //# sourceMappingURL=const.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/common/const.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC,eAAO,MAAM,KAAK;;;CAGjB,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STATS = exports.STATS_INTERVAL_MS = void 0;
4
+ exports.STATS_INTERVAL_MS = 5000; // Stats refresh interval in milliseconds
5
+ exports.STATS = {
6
+ cpu: -1, // percentage (0-100), -1 if unavailable
7
+ mem: -1, // MB used by process, -1 if unavailable
8
+ };
9
+ //# sourceMappingURL=const.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"const.js","sourceRoot":"","sources":["../../src/common/const.ts"],"names":[],"mappings":";;;AAAa,QAAA,iBAAiB,GAAG,IAAI,CAAC,CAAC,yCAAyC;AAEnE,QAAA,KAAK,GAAG;IACnB,GAAG,EAAE,CAAC,CAAC,EAAE,wCAAwC;IACjD,GAAG,EAAE,CAAC,CAAC,EAAE,wCAAwC;CAClD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Updates stats only if the interval has elapsed.
3
+ * Lazy update pattern - stats only refresh during traffic, not on background timer.
4
+ * This prevents setInterval from keeping serverless runtimes alive.
5
+ */
6
+ export declare function updateStatsIfStale(): void;
7
+ //# sourceMappingURL=helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../src/common/helper.ts"],"names":[],"mappings":"AAyBA;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateStatsIfStale = updateStatsIfStale;
4
+ const const_1 = require("./const");
5
+ let prevCpuUsage = process.cpuUsage();
6
+ let prevTime = Date.now();
7
+ let nextStatsAt = 0; // Force immediate update on first call
8
+ function updateStats() {
9
+ // Memory: process RSS in MB
10
+ const memUsage = process.memoryUsage();
11
+ const_1.STATS.mem = Math.round(memUsage.rss / 1024 / 1024);
12
+ // CPU: percentage since last check
13
+ const currentCpuUsage = process.cpuUsage(prevCpuUsage);
14
+ const currentTime = Date.now();
15
+ const elapsedMs = currentTime - prevTime;
16
+ // CPU time is in microseconds, convert to percentage
17
+ const cpuPercent = ((currentCpuUsage.user + currentCpuUsage.system) / 1000 / elapsedMs) * 100;
18
+ const_1.STATS.cpu = Math.round(cpuPercent * 100) / 100;
19
+ prevCpuUsage = process.cpuUsage();
20
+ prevTime = currentTime;
21
+ }
22
+ /**
23
+ * Updates stats only if the interval has elapsed.
24
+ * Lazy update pattern - stats only refresh during traffic, not on background timer.
25
+ * This prevents setInterval from keeping serverless runtimes alive.
26
+ */
27
+ function updateStatsIfStale() {
28
+ const now = Date.now();
29
+ if (now >= nextStatsAt) {
30
+ updateStats();
31
+ nextStatsAt = now + const_1.STATS_INTERVAL_MS;
32
+ }
33
+ }
34
+ //# sourceMappingURL=helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.js","sourceRoot":"","sources":["../../src/common/helper.ts"],"names":[],"mappings":";;AA8BA,gDAMC;AApCD,mCAAmD;AAEnD,IAAI,YAAY,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;AACtC,IAAI,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC1B,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC,uCAAuC;AAE5D,SAAS,WAAW;IAClB,4BAA4B;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACvC,aAAK,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IAEnD,mCAAmC;IACnC,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACvD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IAEzC,qDAAqD;IACrD,MAAM,UAAU,GACd,CAAC,CAAC,eAAe,CAAC,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC;IAC7E,aAAK,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IAE/C,YAAY,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAClC,QAAQ,GAAG,WAAW,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,SAAgB,kBAAkB;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;QACvB,WAAW,EAAE,CAAC;QACd,WAAW,GAAG,GAAG,GAAG,yBAAiB,CAAC;IACxC,CAAC;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { CtxMeta } from "./meta";
2
+ import { CtxReq } from "./req";
3
+ import { CtxRes } from "./res";
4
+ import { CtxUser } from "./user";
5
+ import { CtxBaseError } from "../router/error";
6
+ export type { CtxMeta } from "./meta";
7
+ export type { CtxReq } from "./req";
8
+ export type { CtxRes } from "./res";
9
+ export type { CtxUser } from "./user";
10
+ export declare const DEFAULT_USER_ROLE: {
11
+ readonly none: "none";
12
+ readonly user: "user";
13
+ readonly admin: "admin";
14
+ readonly service: "service";
15
+ };
16
+ export type TDefaultCtx = {
17
+ id: string;
18
+ req: CtxReq;
19
+ res: CtxRes;
20
+ user: CtxUser;
21
+ meta: CtxMeta;
22
+ locals: Record<string, unknown>;
23
+ err: CtxBaseError | null;
24
+ };
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,YAAY,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,YAAY,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpC,YAAY,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpC,YAAY,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,eAAO,MAAM,iBAAiB;;;;;CAKpB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,GAAG,EAAE,YAAY,GAAG,IAAI,CAAC;CAC1B,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_USER_ROLE = void 0;
4
+ exports.DEFAULT_USER_ROLE = {
5
+ none: "none",
6
+ user: "user",
7
+ admin: "admin",
8
+ service: "service",
9
+ };
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";;;AAYa,QAAA,iBAAiB,GAAG;IAC/B,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;CACV,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * System-owned metadata describing runtime, timing, tracing, and logs
3
+ * for the current execution context.
4
+ */
5
+ export type CtxMeta = {
6
+ /** Name of the running service (payment, payout, identity, etc.) */
7
+ readonly serviceName: string;
8
+ /** Runtime instance information */
9
+ readonly instance: {
10
+ /** Unique identifier of the instance */
11
+ readonly id: string;
12
+ /** Instance creation time (epoch ms) */
13
+ readonly createdAt: number;
14
+ /** Monotonic sequence number for this instance */
15
+ readonly seq: number;
16
+ /** In-flight executions when this request arrived */
17
+ readonly inflight: number;
18
+ /** CPU usage percentage, or -1 if unavailable */
19
+ readonly cpu: number;
20
+ /** Memory usage in MB, or -1 if unavailable */
21
+ readonly mem: number;
22
+ };
23
+ /** Execution timestamps (epoch ms, -1 if unavailable) */
24
+ ts: {
25
+ /** When execution entered the system */
26
+ readonly in: number;
27
+ /** When the client sent the request */
28
+ readonly clientIn: number;
29
+ /** When execution completed */
30
+ out: number;
31
+ /** Total execution time in ms */
32
+ execTime: number;
33
+ /** One-way network delay in ms */
34
+ readonly owd: number;
35
+ };
36
+ /** Distributed tracing identifiers */
37
+ readonly monitor: {
38
+ /** Trace identifier (origin-assigned, always present) */
39
+ readonly traceId: string;
40
+ /** Span identifier for this execution */
41
+ readonly spanId: string;
42
+ };
43
+ /** Logs collected during execution */
44
+ readonly log?: {
45
+ /** Standard output logs */
46
+ readonly stdout: readonly string[];
47
+ /** Database query logs */
48
+ readonly db?: readonly {
49
+ readonly q: string;
50
+ readonly p: readonly unknown[];
51
+ readonly ms: number;
52
+ }[];
53
+ };
54
+ };
55
+ //# sourceMappingURL=meta.d.ts.map