@bluelibs/runner 4.8.1 → 4.8.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.
package/AI.md CHANGED
@@ -50,7 +50,7 @@ const createUser = r
50
50
  .dependencies({ logger: globals.resources.logger })
51
51
  .inputSchema<{ name: string }>({ parse: (value) => value })
52
52
  .resultSchema<{ id: string; name: string }>({ parse: (value) => value })
53
- .run(async ({ input }, { logger }) => {
53
+ .run(async (input, { logger }) => {
54
54
  await logger.info(`Creating user ${input.name}`);
55
55
  return { id: "user-1", name: input.name };
56
56
  })
@@ -104,7 +104,7 @@ const sendEmail = r
104
104
  loggingMiddleware.with({ label: "email" }),
105
105
  tracingMiddleware,
106
106
  ])
107
- .run(async ({ input }, { emailer }) => {
107
+ .run(async (input, { emailer }) => {
108
108
  await emailer.send(input);
109
109
  return { delivered: true };
110
110
  })
@@ -131,9 +131,9 @@ const userRegistered = r
131
131
  const registerUser = r
132
132
  .task("app.tasks.registerUser")
133
133
  .dependencies({ userRegistered, userService })
134
- .run(async ({ input }, deps) => {
134
+ .run(async (input, deps) => {
135
135
  const user = await deps.userService.create(input);
136
- await deps.userRegistered.emit({ userId: user.id, email: user.email });
136
+ await deps.userRegistered({ userId: user.id, email: user.email });
137
137
  return user;
138
138
  })
139
139
  .build();
@@ -309,7 +309,46 @@ const root = r
309
309
  .build();
310
310
  ```
311
311
 
312
- Use the unified HTTP client anywhere:
312
+ ### HTTP Client Factory (Recommended)
313
+
314
+ The `globals.resources.httpClientFactory` automatically injects serializer, error registry, and async contexts from the store:
315
+
316
+ ```ts
317
+ import { r, globals } from "@bluelibs/runner";
318
+
319
+ const myTask = r
320
+ .task("app.tasks.callRemote")
321
+ .dependencies({ clientFactory: globals.resources.httpClientFactory })
322
+ .run(async (input, { clientFactory }) => {
323
+ // Client automatically has serializer, errors, and contexts injected
324
+ const client = clientFactory({
325
+ baseUrl: process.env.API_URL,
326
+ auth: { token: process.env.API_TOKEN },
327
+ });
328
+
329
+ return await client.task("remote.task", input);
330
+ })
331
+ .build();
332
+
333
+ // Node streaming clients via Node DI factories
334
+ import { globals as nodeGlobals } from "@bluelibs/runner/node";
335
+
336
+ const nodeTask = r
337
+ .task("app.tasks.streamingCall")
338
+ .dependencies({ smartFactory: nodeGlobals.resources.httpSmartClientFactory })
339
+ .run(async (input, { smartFactory }) => {
340
+ const client = smartFactory({
341
+ baseUrl: process.env.API_URL,
342
+ });
343
+ // Supports duplex streams and multipart uploads
344
+ return await client.task("remote.streaming.task", input);
345
+ })
346
+ .build();
347
+ ```
348
+
349
+ ### Direct Client Creation (Legacy)
350
+
351
+ You can also create clients directly without DI (manual serializer/error/context passing):
313
352
 
314
353
  ```ts
315
354
  import { createHttpClient } from "@bluelibs/runner";
package/README.md CHANGED
@@ -76,7 +76,7 @@ const createUser = r
76
76
  .task("app.tasks.createUser")
77
77
  .dependencies({ server, logger: globals.resources.logger })
78
78
  .inputSchema<{ name: string }>({ parse: (value) => value })
79
- .run(async ({ input }, { server, logger }) => {
79
+ .run(async (input, { server, logger }) => {
80
80
  await logger.info(`Creating ${input.name}`);
81
81
  return { id: "user-123", name: input.name };
82
82
  })
@@ -144,7 +144,7 @@ import { r } from "@bluelibs/runner";
144
144
  const sendEmail = r
145
145
  .task("app.tasks.sendEmail")
146
146
  .dependencies({ emailService, logger })
147
- .run(async ({ input }, { emailService, logger }) => {
147
+ .run(async (input, { emailService, logger }) => {
148
148
  await logger.info(`Sending email to ${input.to}`);
149
149
  return emailService.send(input);
150
150
  })
@@ -280,9 +280,9 @@ const userRegistered = r
280
280
  const registerUser = r
281
281
  .task("app.tasks.registerUser")
282
282
  .dependencies({ userService, userRegistered })
283
- .run(async ({ input }, { userService, userRegistered }) => {
283
+ .run(async (input, { userService, userRegistered }) => {
284
284
  const user = await userService.createUser(input);
285
- await userRegistered.emit({ userId: user.id, email: user.email });
285
+ await userRegistered({ userId: user.id, email: user.email });
286
286
  return user;
287
287
  })
288
288
  .build();
@@ -491,7 +491,7 @@ const authMiddleware = r.middleware
491
491
  const adminTask = r
492
492
  .task("app.tasks.adminOnly")
493
493
  .middleware([authMiddleware.with({ requiredRole: "admin" })])
494
- .run(async ({ input }: { input: { user: User } }) => "Secret admin data")
494
+ .run(async (input) => "Secret admin data")
495
495
  .build();
496
496
  ```
497
497
 
@@ -531,7 +531,7 @@ const resourceAuthMiddleware = r.middleware
531
531
  const adminTask = r
532
532
  .task("app.tasks.adminOnly")
533
533
  .middleware([authMiddleware.with({ requiredRole: "admin" })])
534
- .run(async ({ input }: { input: { user: { role: string } } }) => ({
534
+ .run(async (input: { user: { role: string } }) => ({
535
535
  user: { role: input.user.role, verified: true },
536
536
  }))
537
537
  .build();
@@ -599,7 +599,7 @@ const loggingMiddleware = r.middleware
599
599
  const loggedTask = r
600
600
  .task("app.tasks.logged")
601
601
  .middleware([loggingMiddleware.with({ includeTimestamp: true })])
602
- .run(async ({ input }: { input: { data: string } }) => ({
602
+ .run(async (input: { data: string }) => ({
603
603
  data: input.data.toUpperCase(),
604
604
  }))
605
605
  .build();
@@ -620,7 +620,7 @@ import { r } from "@bluelibs/runner";
620
620
  const apiTask = r
621
621
  .task("app.tasks.getUserData")
622
622
  .tags(["api", "public", "cacheable"])
623
- .run(async ({ input }) => getUserFromDatabase(input as any))
623
+ .run(async (input) => getUserFromDatabase(input as any))
624
624
  .build();
625
625
 
626
626
  // Structured tags with configuration
@@ -629,7 +629,7 @@ const httpTag = r.tag<{ method: string; path: string }>("http.route").build();
629
629
  const getUserTask = r
630
630
  .task("app.tasks.getUser")
631
631
  .tags(["api", httpTag.with({ method: "GET", path: "/users/:id" })])
632
- .run(async ({ input }) => getUserFromDatabase((input as any).id))
632
+ .run(async (input) => getUserFromDatabase((input as any).id))
633
633
  .build();
634
634
  ```
635
635
 
@@ -760,7 +760,7 @@ const userNotFoundError = r
760
760
  const getUser = r
761
761
  .task("app.tasks.getUser")
762
762
  .dependencies({ userNotFoundError })
763
- .run(async ({ input }, { userNotFoundError }) => {
763
+ .run(async (input, { userNotFoundError }) => {
764
764
  userNotFoundError.throw({ code: 404, message: `User ${input} not found` });
765
765
  })
766
766
  .build();
@@ -884,7 +884,7 @@ import { r, run } from "@bluelibs/runner";
884
884
 
885
885
  const calculatorTask = r
886
886
  .task("app.tasks.calculator")
887
- .run(async ({ input }: { input: { value: number } }) => {
887
+ .run(async (input: { value: number }) => {
888
888
  console.log("3. Task is running...");
889
889
  return { result: input.value + 1 };
890
890
  })
@@ -949,7 +949,7 @@ const userRegistration = r
949
949
  emailService: emailService.optional(), // Optional - won't fail if missing
950
950
  analytics: analyticsService.optional(), // Optional - graceful degradation
951
951
  })
952
- .run(async ({ input }, { database, emailService, analytics }) => {
952
+ .run(async (input, { database, emailService, analytics }) => {
953
953
  // Create user (required)
954
954
  const user = await database.users.create(userData);
955
955
 
@@ -1051,12 +1051,13 @@ app = app.build();
1051
1051
  const remoteTasksTunnel = r
1052
1052
  .resource("app.tunnels.http")
1053
1053
  .tags([globals.tags.tunnel])
1054
- .init(async () => ({
1054
+ .dependencies({ createClient: globals.resource.httpClientFactory })
1055
+ .init(async (_, { createClient }) => ({
1055
1056
  mode: "client", // or "server", or "none", or "both" for emulating network infrastructure
1056
1057
  transport: "http", // the only one supported for now
1057
1058
  // Selectively forward tasks starting with "remote.tasks."
1058
1059
  tasks: (t) => t.id.startsWith("remote.tasks."),
1059
- client: globals.tunnels.http.createClient({
1060
+ client: createClient({
1060
1061
  url: "http://remote-runner:8080/__runner",
1061
1062
  }),
1062
1063
  }))
@@ -1184,9 +1185,7 @@ import type {
1184
1185
  // Task example
1185
1186
  const add = r
1186
1187
  .task("calc.add")
1187
- .run(
1188
- async ({ input }: { input: { a: number; b: number } }) => input.a + input.b,
1189
- )
1188
+ .run(async (input: { a: number; b: number }) => input.a + input.b)
1190
1189
  .build();
1191
1190
 
1192
1191
  type AddInput = ExtractTaskInput<typeof add>; // { a: number; b: number }
@@ -1245,7 +1244,7 @@ const requestMiddleware = r.middleware
1245
1244
  const handleRequest = r
1246
1245
  .task("app.handleRequest")
1247
1246
  .middleware([requestMiddleware])
1248
- .run(async ({ input }: { input: { path: string } }) => {
1247
+ .run(async (input: { path: string }) => {
1249
1248
  const request = requestContext.use();
1250
1249
  console.log(`Processing ${input.path} (Request ID: ${request.requestId})`);
1251
1250
  return { success: true, requestId: request.requestId };
@@ -1395,7 +1394,7 @@ const expensiveTask = r
1395
1394
  keyBuilder: (taskId, input) => `${taskId}-${(input as any).userId}`, // optional key builder
1396
1395
  }),
1397
1396
  ])
1398
- .run(async ({ input }: { input: { userId: string } }) => {
1397
+ .run(async (input: { userId: string }) => {
1399
1398
  // This expensive operation will be cached
1400
1399
  return await doExpensiveCalculation(input.userId);
1401
1400
  })
@@ -1423,7 +1422,7 @@ import { r } from "@bluelibs/runner";
1423
1422
 
1424
1423
  const redisCacheFactory = r
1425
1424
  .task("globals.tasks.cacheFactory") // Same ID as the default task
1426
- .run(async ({ input }: { input: any }) => new RedisCache(input))
1425
+ .run(async (input: { input: any }) => new RedisCache(input))
1427
1426
  .build();
1428
1427
 
1429
1428
  const app = r
@@ -1468,7 +1467,7 @@ Here are real performance metrics from our comprehensive benchmark suite on an M
1468
1467
  const userTask = r
1469
1468
  .task("user.create")
1470
1469
  .middleware([auth, logging, metrics])
1471
- .run(async ({ input }) => database.users.create(input as any))
1470
+ .run(async (input) => database.users.create(input as any))
1472
1471
  .build();
1473
1472
 
1474
1473
  // 1000 executions = ~5ms total time
@@ -1528,7 +1527,7 @@ const database = r
1528
1527
  const expensiveTask = r
1529
1528
  .task("app.performance.expensive")
1530
1529
  .middleware([globals.middleware.cache.with({ ttl: 60000 })])
1531
- .run(async ({ input }) => {
1530
+ .run(async (input) => {
1532
1531
  // This expensive computation is cached
1533
1532
  return performExpensiveCalculation(input);
1534
1533
  })
@@ -1751,7 +1750,7 @@ The logger accepts rich, structured data that makes debugging actually useful:
1751
1750
  const userTask = r
1752
1751
  .task("app.tasks.user.create")
1753
1752
  .dependencies({ logger: globals.resources.logger })
1754
- .run(async ({ input }, { logger }) => {
1753
+ .run(async (input, { logger }) => {
1755
1754
  // Basic message
1756
1755
  logger.info("Creating new user");
1757
1756
 
@@ -2028,7 +2027,7 @@ const criticalTask = r
2028
2027
  logTaskOnError: true,
2029
2028
  }),
2030
2029
  ])
2031
- .run(async ({ input }) => {
2030
+ .run(async (input) => {
2032
2031
  // This task will have verbose debug logging
2033
2032
  return await processPayment(input as any);
2034
2033
  })
@@ -2719,7 +2718,7 @@ type UserData = z.infer<typeof userSchema>;
2719
2718
  const createUser = r
2720
2719
  .task("app.tasks.createUser.zod")
2721
2720
  .inputSchema(userSchema)
2722
- .run(async ({ input }: { input: UserData }) => {
2721
+ .run(async (input: { input: UserData }) => {
2723
2722
  // Both runtime validation AND compile-time typing
2724
2723
  return { id: "user-123", ...input };
2725
2724
  })