@bluelibs/runner 4.5.8 → 4.5.10
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/AI.md +48 -102
- package/README.md +43 -4
- package/dist/index.cjs +1 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -12
- package/dist/index.mjs +1 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/AI.md
CHANGED
|
@@ -184,9 +184,7 @@ import { globals, task } from "@bluelibs/runner";
|
|
|
184
184
|
|
|
185
185
|
const critical = task({
|
|
186
186
|
id: "app.tasks.critical",
|
|
187
|
-
tags: [
|
|
188
|
-
globals.tags.debug.with({ logTaskInput: true, logTaskOutput: true }),
|
|
189
|
-
],
|
|
187
|
+
tags: [globals.tags.debug.with({ logTaskInput: true, logTaskOutput: true })],
|
|
190
188
|
run: async () => "ok",
|
|
191
189
|
});
|
|
192
190
|
```
|
|
@@ -203,7 +201,7 @@ const logsExtension = resource({
|
|
|
203
201
|
logger.info("test", { example: 123 }); // "trace", "debug", "info", "warn", "error", "critical"
|
|
204
202
|
const sublogger = logger.with({
|
|
205
203
|
source: "app.logs",
|
|
206
|
-
|
|
204
|
+
additionalContext: {},
|
|
207
205
|
});
|
|
208
206
|
logger.onLog((log) => {
|
|
209
207
|
// ship or transform
|
|
@@ -238,7 +236,8 @@ export async function getRunner() {
|
|
|
238
236
|
// handler.ts
|
|
239
237
|
export const handler = async (event: any, context: any) => {
|
|
240
238
|
const rr: any = await getRunner();
|
|
241
|
-
const method =
|
|
239
|
+
const method =
|
|
240
|
+
event?.requestContext?.http?.method ?? event?.httpMethod ?? "GET";
|
|
242
241
|
const path = event?.rawPath || event?.path || "/";
|
|
243
242
|
const rawBody = event?.body
|
|
244
243
|
? event.isBase64Encoded
|
|
@@ -247,9 +246,12 @@ export const handler = async (event: any, context: any) => {
|
|
|
247
246
|
: undefined;
|
|
248
247
|
const body = rawBody ? JSON.parse(rawBody) : undefined;
|
|
249
248
|
|
|
250
|
-
return RequestCtx.provide(
|
|
251
|
-
|
|
252
|
-
|
|
249
|
+
return RequestCtx.provide(
|
|
250
|
+
{ requestId: context?.awsRequestId ?? "local", method, path },
|
|
251
|
+
async () => {
|
|
252
|
+
// route and call rr.runTask(...)
|
|
253
|
+
},
|
|
254
|
+
);
|
|
253
255
|
};
|
|
254
256
|
```
|
|
255
257
|
|
|
@@ -396,6 +398,21 @@ const { dispose } = await run(app, {
|
|
|
396
398
|
});
|
|
397
399
|
```
|
|
398
400
|
|
|
401
|
+
## Type Helpers
|
|
402
|
+
|
|
403
|
+
Extract generics from tasks, resources, and events without re-declaring their shapes and avoid use of 'any'.
|
|
404
|
+
|
|
405
|
+
```ts
|
|
406
|
+
import { task, resource, event } from "@bluelibs/runner";
|
|
407
|
+
import type {
|
|
408
|
+
ExtractTaskInput, // ExtractTaskInput(typeof myTask)
|
|
409
|
+
ExtractTaskOutput,
|
|
410
|
+
ExtractResourceConfig,
|
|
411
|
+
ExtractResourceValue,
|
|
412
|
+
ExtractEventPayload,
|
|
413
|
+
} from "@bluelibs/runner";
|
|
414
|
+
```
|
|
415
|
+
|
|
399
416
|
## Run Options (high‑level)
|
|
400
417
|
|
|
401
418
|
- debug: "normal" | "verbose" | DebugConfig
|
|
@@ -521,115 +538,40 @@ Coverage tip: the script name is `npm run coverage`.
|
|
|
521
538
|
|
|
522
539
|
## Metadata & Tags
|
|
523
540
|
|
|
541
|
+
Tags and meta can be applied to all elements.
|
|
542
|
+
|
|
524
543
|
```ts
|
|
525
544
|
import { tag, globals, task, resource } from "@bluelibs/runner";
|
|
526
545
|
|
|
527
|
-
// Simple tags and debug/system globals
|
|
528
|
-
const perf = tag<{ warnAboveMs: number }>({ id: "perf" });
|
|
529
546
|
const contractTag = tag<void, void, { result: string }>({ id: "contract" });
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
id: "app.tasks.pay",
|
|
533
|
-
tags: [perf.with({ warnAboveMs: 1000 })],
|
|
534
|
-
meta: {
|
|
535
|
-
title: "Process Payment",
|
|
536
|
-
description: "Detailed",
|
|
537
|
-
},
|
|
538
|
-
run: async () => {
|
|
539
|
-
/* ... */
|
|
540
|
-
},
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
const internalSvc = resource({
|
|
544
|
-
id: "app.resources.internal",
|
|
545
|
-
register: [perf],
|
|
546
|
-
tags: [globals.tags.system],
|
|
547
|
-
init: async () => ({}),
|
|
548
|
-
});
|
|
549
|
-
```
|
|
550
|
-
|
|
551
|
-
### Tag Contracts (type‑enforced returns)
|
|
552
|
-
|
|
553
|
-
```ts
|
|
554
|
-
// Contract enforces the awaited return type (Config, Input, Output)
|
|
555
|
-
const userContract = tag<void, void, { name: string }>({ id: "contract.user" });
|
|
556
|
-
|
|
557
|
-
const getProfile = task({
|
|
558
|
-
id: "app.tasks.getProfile",
|
|
559
|
-
tags: [userContract],
|
|
560
|
-
run: async () => ({ name: "Ada" }), // must contain { name: string }
|
|
547
|
+
const httpRouteTag = tag<{ method: "GET" | "POST"; path: string }>({
|
|
548
|
+
id: "httpRoute",
|
|
561
549
|
});
|
|
562
550
|
|
|
563
|
-
const
|
|
564
|
-
id: "app.
|
|
565
|
-
tags: [
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
### Tag Extraction (behavior flags)
|
|
571
|
-
|
|
572
|
-
```ts
|
|
573
|
-
const perf = tag<{ warnAboveMs: number }>({ id: "perf" });
|
|
574
|
-
|
|
575
|
-
const perfMiddleware = taskMiddleware({
|
|
576
|
-
id: "app.middleware.perf",
|
|
577
|
-
run: async ({ task, next }) => {
|
|
578
|
-
const cfg = perf.extract(task.definition);
|
|
579
|
-
// use perf.exists(task.definition) to check for existence
|
|
580
|
-
if (!cfg) return next(task.input);
|
|
581
|
-
// performance hooks here ...
|
|
551
|
+
const task = task({
|
|
552
|
+
id: "app.tasks.myTask",
|
|
553
|
+
tags: [contractTag, httpRouteTag.with({ method: "POST", path: "/do" })],
|
|
554
|
+
run: async () => ({ result: "ok" }), // must return { result: string }
|
|
555
|
+
meta: {
|
|
556
|
+
title: "My Task",
|
|
557
|
+
description: "Does something important", // multi-line description, markdown
|
|
582
558
|
},
|
|
583
559
|
});
|
|
584
560
|
```
|
|
585
561
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
Use a hook on `globals.events.ready` to discover and intercept tasks by tag:
|
|
562
|
+
Usage:
|
|
589
563
|
|
|
590
564
|
```ts
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
const apiTag = tag<void>({ id: "api" });
|
|
594
|
-
|
|
595
|
-
const addTracingToApiTasks = hook({
|
|
596
|
-
id: "app.hooks.traceApis",
|
|
565
|
+
const onReady = hook({
|
|
566
|
+
id: "app.hooks.onReady",
|
|
597
567
|
on: globals.events.ready,
|
|
598
568
|
dependencies: { store: globals.resources.store },
|
|
599
569
|
run: async (_, { store }) => {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
taskDef.intercept(async (next, input) => {
|
|
603
|
-
// ...
|
|
604
|
-
});
|
|
605
|
-
});
|
|
606
|
-
// Apply same concept to routing like fastify, express routes based on tag config to your fastify instance.
|
|
607
|
-
},
|
|
608
|
-
});
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
### Route registration via tags (ready hook)
|
|
612
|
-
|
|
613
|
-
```ts
|
|
614
|
-
import { hook, globals } from "@bluelibs/runner";
|
|
615
|
-
import { httpTag } from "./http.tag"; // your structured tag (method, path, schemas, etc.)
|
|
616
|
-
import { expressServer } from "./expressServer"; // resource that returns { app, port }
|
|
617
|
-
|
|
618
|
-
const registerRoutes = hook({
|
|
619
|
-
id: "app.hooks.registerRoutes",
|
|
620
|
-
on: globals.events.ready,
|
|
621
|
-
dependencies: { store: globals.resources.store, server: expressServer },
|
|
622
|
-
run: async (_, { store, server }) => {
|
|
623
|
-
const tasks = store.getTasksWithTag(httpTag);
|
|
570
|
+
// Same concept for resources
|
|
571
|
+
const tasks = store.getTasksWithTag(httpRouteTag); // uses httpRouteTag.exists(component);
|
|
624
572
|
tasks.forEach((t) => {
|
|
625
|
-
const cfg =
|
|
626
|
-
|
|
627
|
-
const { method, path } = cfg.config;
|
|
628
|
-
if (!method || !path) return;
|
|
629
|
-
(server.app as any)[method.toLowerCase()](path, async (req, res) => {
|
|
630
|
-
const result = await t({ ...req.body, ...req.query, ...req.params });
|
|
631
|
-
res.json(result);
|
|
632
|
-
});
|
|
573
|
+
const cfg = httpRouteTag.extract(tasks); // { method, path }
|
|
574
|
+
// you can even do t
|
|
633
575
|
});
|
|
634
576
|
},
|
|
635
577
|
});
|
|
@@ -704,7 +646,7 @@ interface IValidationSchema<T> {
|
|
|
704
646
|
}
|
|
705
647
|
```
|
|
706
648
|
|
|
707
|
-
Works out of the box with Zod (`z.object(...).parse`), and can be adapted for Yup/Joi with small wrappers.
|
|
649
|
+
Works out of the box with Zod (`z.object(...).parse`), and can be adapted for Yup/Joi with small wrappers. As it only needs a parse() method.
|
|
708
650
|
|
|
709
651
|
```ts
|
|
710
652
|
import { z } from "zod";
|
|
@@ -728,6 +670,10 @@ event({
|
|
|
728
670
|
payloadSchema, // Runs on event emission
|
|
729
671
|
});
|
|
730
672
|
|
|
673
|
+
tag({
|
|
674
|
+
configSchema, // Tag config validation (runs on .with())
|
|
675
|
+
});
|
|
676
|
+
|
|
731
677
|
// Middleware config validation (runs on .with())
|
|
732
678
|
middleware({
|
|
733
679
|
// ...
|
package/README.md
CHANGED
|
@@ -958,6 +958,43 @@ const handleRequest = resource({
|
|
|
958
958
|
});
|
|
959
959
|
```
|
|
960
960
|
|
|
961
|
+
## Type Helpers
|
|
962
|
+
|
|
963
|
+
These utility types help you extract the generics from tasks, resources, and events without re-declaring them. Import them from `@bluelibs/runner`.
|
|
964
|
+
|
|
965
|
+
```ts
|
|
966
|
+
import { task, resource, event } from "@bluelibs/runner";
|
|
967
|
+
import type {
|
|
968
|
+
ExtractTaskInput,
|
|
969
|
+
ExtractTaskOutput,
|
|
970
|
+
ExtractResourceConfig,
|
|
971
|
+
ExtractResourceValue,
|
|
972
|
+
ExtractEventPayload,
|
|
973
|
+
} from "@bluelibs/runner";
|
|
974
|
+
|
|
975
|
+
// Task example
|
|
976
|
+
const add = task({
|
|
977
|
+
id: "calc.add",
|
|
978
|
+
run: async (input: { a: number; b: number }) => input.a + input.b,
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
type AddInput = ExtractTaskInput<typeof add>; // { a: number; b: number }
|
|
982
|
+
type AddOutput = ExtractTaskOutput<typeof add>; // number
|
|
983
|
+
|
|
984
|
+
// Resource example
|
|
985
|
+
const config = resource({
|
|
986
|
+
id: "app.config",
|
|
987
|
+
init: async (cfg: { baseUrl: string }) => ({ baseUrl: cfg.baseUrl }),
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
type ConfigInput = ExtractResourceConfig<typeof config>; // { baseUrl: string }
|
|
991
|
+
type ConfigValue = ExtractResourceValue<typeof config>; // { baseUrl: string }
|
|
992
|
+
|
|
993
|
+
// Event example
|
|
994
|
+
const userRegistered = event<{ userId: string; email: string }>({ id: "app.events.userRegistered" });
|
|
995
|
+
type UserRegisteredPayload = ExtractEventPayload<typeof userRegistered>; // { userId: string; email: string }
|
|
996
|
+
```
|
|
997
|
+
|
|
961
998
|
### Context with Middleware
|
|
962
999
|
|
|
963
1000
|
Context shines when combined with middleware for request-scoped data:
|
|
@@ -1328,7 +1365,7 @@ BlueLibs Runner achieves high performance while providing enterprise features:
|
|
|
1328
1365
|
| Event System | ~0.013ms | Loose coupling, observability |
|
|
1329
1366
|
| Middleware Chain | ~0.0003ms/middleware | Cross-cutting concerns |
|
|
1330
1367
|
| Resource Management | One-time init | Singleton pattern, lifecycle |
|
|
1331
|
-
| Built-in Caching |
|
|
1368
|
+
| Built-in Caching | Variable speedup | Automatic optimization |
|
|
1332
1369
|
|
|
1333
1370
|
**Bottom line**: The framework adds minimal overhead (~0.005ms per task) while providing significant architectural benefits.
|
|
1334
1371
|
|
|
@@ -1552,10 +1589,12 @@ const requestHandler = task({
|
|
|
1552
1589
|
const request = RequestContext.use();
|
|
1553
1590
|
|
|
1554
1591
|
// Create a contextual logger with bound metadata with source and context
|
|
1555
|
-
const requestLogger = logger.with(
|
|
1592
|
+
const requestLogger = logger.with({
|
|
1556
1593
|
source: requestHandler.id,
|
|
1557
|
-
|
|
1558
|
-
|
|
1594
|
+
additionalContext: {
|
|
1595
|
+
requestId: request.requestId,
|
|
1596
|
+
userId: request.userId,
|
|
1597
|
+
},
|
|
1559
1598
|
});
|
|
1560
1599
|
|
|
1561
1600
|
// All logs from this logger will include the bound context
|
package/dist/index.cjs
CHANGED
|
@@ -4105,13 +4105,7 @@ async function run(resourceOrResourceWithConfig, options) {
|
|
|
4105
4105
|
store2.lock();
|
|
4106
4106
|
eventManager.lock();
|
|
4107
4107
|
await logger.lock();
|
|
4108
|
-
await eventManager.emit(
|
|
4109
|
-
globalEvents.ready,
|
|
4110
|
-
{
|
|
4111
|
-
root: store2.root.resource
|
|
4112
|
-
},
|
|
4113
|
-
"system"
|
|
4114
|
-
);
|
|
4108
|
+
await eventManager.emit(globalEvents.ready, void 0, "run");
|
|
4115
4109
|
await boundedLogger.info("Runner online. Awaiting tasks and events.");
|
|
4116
4110
|
if (shutdownHooks) {
|
|
4117
4111
|
unhookShutdown = registerShutdownHook(() => store2.dispose());
|