@bluelibs/runner 3.3.2 → 3.4.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.
- package/README.md +437 -33
- package/dist/define.d.ts +5 -5
- package/dist/define.js +22 -2
- package/dist/define.js.map +1 -1
- package/dist/defs.d.ts +55 -21
- package/dist/defs.js.map +1 -1
- package/dist/defs.returnTag.d.ts +36 -0
- package/dist/defs.returnTag.js +4 -0
- package/dist/defs.returnTag.js.map +1 -0
- package/dist/errors.d.ts +60 -10
- package/dist/errors.js +103 -12
- package/dist/errors.js.map +1 -1
- package/dist/globals/globalMiddleware.d.ts +4 -4
- package/dist/globals/globalResources.d.ts +28 -10
- package/dist/globals/middleware/cache.middleware.d.ts +9 -9
- package/dist/globals/resources/queue.resource.d.ts +5 -2
- package/dist/index.d.ts +33 -14
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/models/DependencyProcessor.js +4 -4
- package/dist/models/DependencyProcessor.js.map +1 -1
- package/dist/models/EventManager.js +10 -1
- package/dist/models/EventManager.js.map +1 -1
- package/dist/models/Logger.d.ts +8 -0
- package/dist/models/Logger.js +24 -0
- package/dist/models/Logger.js.map +1 -1
- package/dist/models/OverrideManager.js +1 -1
- package/dist/models/OverrideManager.js.map +1 -1
- package/dist/models/ResourceInitializer.d.ts +2 -2
- package/dist/models/ResourceInitializer.js.map +1 -1
- package/dist/models/Store.d.ts +2 -2
- package/dist/models/Store.js +1 -1
- package/dist/models/Store.js.map +1 -1
- package/dist/models/StoreConstants.d.ts +6 -3
- package/dist/models/StoreRegistry.d.ts +2 -2
- package/dist/models/StoreRegistry.js +1 -1
- package/dist/models/StoreRegistry.js.map +1 -1
- package/dist/models/StoreTypes.d.ts +1 -1
- package/dist/models/StoreValidator.js +5 -5
- package/dist/models/StoreValidator.js.map +1 -1
- package/dist/models/TaskRunner.js +10 -0
- package/dist/models/TaskRunner.js.map +1 -1
- package/dist/run.d.ts +3 -3
- package/dist/run.js +1 -1
- package/dist/run.js.map +1 -1
- package/dist/t1.d.ts +1 -0
- package/dist/t1.js +13 -0
- package/dist/t1.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/package.json +2 -2
- package/src/__tests__/errors.test.ts +92 -11
- package/src/__tests__/models/EventManager.test.ts +0 -1
- package/src/__tests__/models/Logger.test.ts +82 -5
- package/src/__tests__/recursion/c.resource.ts +1 -1
- package/src/__tests__/run.overrides.test.ts +3 -3
- package/src/__tests__/typesafety.test.ts +112 -9
- package/src/__tests__/validation-edge-cases.test.ts +111 -0
- package/src/__tests__/validation-interface.test.ts +428 -0
- package/src/define.ts +47 -15
- package/src/defs.returnTag.ts +91 -0
- package/src/defs.ts +84 -27
- package/src/errors.ts +95 -23
- package/src/index.ts +1 -0
- package/src/models/DependencyProcessor.ts +9 -5
- package/src/models/EventManager.ts +12 -3
- package/src/models/Logger.ts +28 -0
- package/src/models/OverrideManager.ts +2 -7
- package/src/models/ResourceInitializer.ts +8 -3
- package/src/models/Store.ts +3 -3
- package/src/models/StoreRegistry.ts +2 -2
- package/src/models/StoreTypes.ts +1 -1
- package/src/models/StoreValidator.ts +6 -6
- package/src/models/TaskRunner.ts +10 -1
- package/src/run.ts +8 -5
- package/src/testing.ts +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ _Or: How I Learned to Stop Worrying and Love Dependency Injection_
|
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<a href="https://github.com/bluelibs/runner/actions/workflows/ci.yml"><img src="https://github.com/bluelibs/runner/actions/workflows/ci.yml/badge.svg?branch=main" alt="Build Status" /></a>
|
|
7
|
-
<a href="https://
|
|
7
|
+
<a href="https://github.com/bluelibs/runner"><img src="https://img.shields.io/badge/coverage-100%25-brightgreen" alt="Coverage 100% is enforced. Code does not build without 100% on all branches, lines, etc." /></a>
|
|
8
8
|
<a href="https://bluelibs.github.io/runner/" target="_blank"><img src="https://img.shields.io/badge/read-typedocs-blue" alt="Docs" /></a>
|
|
9
9
|
<a href="https://github.com/bluelibs/runner" target="_blank"><img src="https://img.shields.io/badge/github-blue" alt="GitHub" /></a>
|
|
10
10
|
</p>
|
|
@@ -616,18 +616,32 @@ const businessTask = task({
|
|
|
616
616
|
id: "app.tasks.business",
|
|
617
617
|
dependencies: { logger: globals.resources.logger },
|
|
618
618
|
run: async (_, { logger }) => {
|
|
619
|
-
logger.info("Starting business process");
|
|
620
|
-
logger.warn("This might take a while");
|
|
619
|
+
logger.info("Starting business process"); // ✅ Visible by default
|
|
620
|
+
logger.warn("This might take a while"); // ✅ Visible by default
|
|
621
621
|
logger.error("Oops, something went wrong", {
|
|
622
|
+
// ✅ Visible by default
|
|
622
623
|
error: new Error("Database connection failed"),
|
|
623
624
|
});
|
|
624
625
|
logger.critical("System is on fire", {
|
|
626
|
+
// ✅ Visible by default
|
|
625
627
|
data: { temperature: "9000°C" },
|
|
626
628
|
});
|
|
629
|
+
logger.debug("Debug information"); // ❌ Hidden by default
|
|
630
|
+
logger.trace("Very detailed trace"); // ❌ Hidden by default
|
|
627
631
|
},
|
|
628
632
|
});
|
|
629
633
|
```
|
|
630
634
|
|
|
635
|
+
**Good news!** Logs at `info` level and above are visible by default, so you'll see your application logs immediately without any configuration. For development and debugging, you can easily show more detailed logs:
|
|
636
|
+
|
|
637
|
+
```bash
|
|
638
|
+
# Show debug logs and framework internals
|
|
639
|
+
RUNNER_LOG_LEVEL=debug node your-app.js
|
|
640
|
+
|
|
641
|
+
# Hide all logs for production
|
|
642
|
+
RUNNER_DISABLE_LOGS=true node your-app.js
|
|
643
|
+
```
|
|
644
|
+
|
|
631
645
|
### Log Levels: From Whispers to Screams
|
|
632
646
|
|
|
633
647
|
The logger supports six log levels with increasing severity:
|
|
@@ -733,18 +747,31 @@ const requestHandler = task({
|
|
|
733
747
|
|
|
734
748
|
### Print Threshold: Control What Shows Up
|
|
735
749
|
|
|
736
|
-
By default, logs
|
|
750
|
+
By default, logs at `info` level and above are automatically printed to console for better developer experience. You can easily control this behavior through environment variables or by setting a print threshold programmatically:
|
|
751
|
+
|
|
752
|
+
#### Environment Variable Controls
|
|
753
|
+
|
|
754
|
+
```bash
|
|
755
|
+
# Disable all logging output
|
|
756
|
+
RUNNER_DISABLE_LOGS=true node your-app.js
|
|
757
|
+
|
|
758
|
+
# Set specific log level (trace, debug, info, warn, error, critical)
|
|
759
|
+
RUNNER_LOG_LEVEL=debug node your-app.js
|
|
760
|
+
RUNNER_LOG_LEVEL=error node your-app.js
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
#### Programmatic Control
|
|
737
764
|
|
|
738
765
|
```typescript
|
|
739
|
-
//
|
|
766
|
+
// Override the default print threshold programmatically
|
|
740
767
|
const setupLogging = task({
|
|
741
768
|
id: "app.logging.setup",
|
|
742
769
|
on: globals.resources.logger.events.afterInit,
|
|
743
770
|
run: async (event) => {
|
|
744
771
|
const logger = event.data.value;
|
|
745
772
|
|
|
746
|
-
// Print
|
|
747
|
-
logger.setPrintThreshold("
|
|
773
|
+
// Print debug level and above (debug, info, warn, error, critical)
|
|
774
|
+
logger.setPrintThreshold("debug");
|
|
748
775
|
|
|
749
776
|
// Print only errors and critical issues
|
|
750
777
|
logger.setPrintThreshold("error");
|
|
@@ -1171,16 +1198,16 @@ const performanceMiddleware = middleware({
|
|
|
1171
1198
|
id: "app.middleware.performance",
|
|
1172
1199
|
run: async ({ task, next }) => {
|
|
1173
1200
|
const tags = task.definition.meta?.tags || [];
|
|
1174
|
-
const
|
|
1201
|
+
const perfConfigTag = performanceTag.extract(tags); // or easier: .extract(task.definition)
|
|
1175
1202
|
|
|
1176
|
-
if (
|
|
1203
|
+
if (perfConfigTag) {
|
|
1177
1204
|
const startTime = Date.now();
|
|
1178
1205
|
|
|
1179
1206
|
try {
|
|
1180
1207
|
const result = await next(task.input);
|
|
1181
1208
|
const duration = Date.now() - startTime;
|
|
1182
1209
|
|
|
1183
|
-
if (duration >
|
|
1210
|
+
if (duration > perfConfigTag.config.criticalAboveMs) {
|
|
1184
1211
|
await alerting.critical(
|
|
1185
1212
|
`Task ${task.definition.id} took ${duration}ms`
|
|
1186
1213
|
);
|
|
@@ -1202,36 +1229,70 @@ const performanceMiddleware = middleware({
|
|
|
1202
1229
|
return next(task.input);
|
|
1203
1230
|
},
|
|
1204
1231
|
});
|
|
1232
|
+
```
|
|
1205
1233
|
|
|
1206
|
-
|
|
1207
|
-
id: "app.middleware.rateLimit",
|
|
1208
|
-
dependencies: { redis },
|
|
1209
|
-
run: async ({ task, next }, { redis }) => {
|
|
1210
|
-
// Extraction can be done at task.definition level or at task.definition.meta.tags
|
|
1211
|
-
const rateLimitCurrentTag = rateLimitTag.extract(task.definition);
|
|
1234
|
+
#### Contract Tags: Enforcing Return Types
|
|
1212
1235
|
|
|
1213
|
-
|
|
1214
|
-
const tags = task.definition.meta?.tags;
|
|
1215
|
-
const rateLimitCurrentTag = rateLimitTag.extract(tags);
|
|
1236
|
+
You can attach contracts to tags to enforce the shape of a task's returned value and a resource's `init()` value at compile time. Contracts are specified via the second generic of `defineTag<TConfig, TContract>`.
|
|
1216
1237
|
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1238
|
+
```typescript
|
|
1239
|
+
// A tag that enforces the returned value to include { name: string }
|
|
1240
|
+
const userContract = tag<void, { name: string }>({ id: "contract.user" });
|
|
1220
1241
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
}
|
|
1242
|
+
// Another tag that enforces { age: number }
|
|
1243
|
+
const ageContract = tag<void, { age: number }>({ id: "contract.age" });
|
|
1224
1244
|
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1245
|
+
// Works with configured tags too
|
|
1246
|
+
const preferenceContract = tag<{ locale: string }, { preferredLocale: string }>(
|
|
1247
|
+
{ id: "contract.preferences" }
|
|
1248
|
+
);
|
|
1249
|
+
```
|
|
1229
1250
|
|
|
1230
|
-
|
|
1251
|
+
When these tags are present in `meta.tags`, the returned value must satisfy the intersection of all contract types:
|
|
1252
|
+
|
|
1253
|
+
```typescript
|
|
1254
|
+
// Task: the awaited return value must satisfy { name: string } & { age: number }
|
|
1255
|
+
const getProfile = task({
|
|
1256
|
+
id: "app.tasks.getProfile",
|
|
1257
|
+
meta: {
|
|
1258
|
+
tags: [
|
|
1259
|
+
userContract,
|
|
1260
|
+
ageContract,
|
|
1261
|
+
preferenceContract.with({ locale: "en" }),
|
|
1262
|
+
],
|
|
1263
|
+
},
|
|
1264
|
+
run: async () => {
|
|
1265
|
+
return { name: "Ada", age: 37, preferredLocale: "en" }; // OK
|
|
1266
|
+
},
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1269
|
+
// Resource: init() return must satisfy the same intersection
|
|
1270
|
+
const profileService = resource({
|
|
1271
|
+
id: "app.resources.profileService",
|
|
1272
|
+
meta: { tags: [userContract, ageContract] },
|
|
1273
|
+
init: async () => {
|
|
1274
|
+
return { name: "Ada", age: 37 }; // OK
|
|
1231
1275
|
},
|
|
1232
1276
|
});
|
|
1233
1277
|
```
|
|
1234
1278
|
|
|
1279
|
+
If the returned value does not satisfy the intersection, TypeScript surfaces a readable, verbose type error that includes what was expected and what was received.
|
|
1280
|
+
|
|
1281
|
+
```typescript
|
|
1282
|
+
const badTask = task({
|
|
1283
|
+
id: "app.tasks.bad",
|
|
1284
|
+
meta: { tags: [userContract, ageContract] },
|
|
1285
|
+
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
|
1286
|
+
run: async () => ({ name: "Ada" }), // Missing { age: number }
|
|
1287
|
+
// Type error includes a helpful shape similar to:
|
|
1288
|
+
// ContractViolationError<
|
|
1289
|
+
// { message: "Value does not satisfy all tag contracts";
|
|
1290
|
+
// expected: { name: string } & { age: number };
|
|
1291
|
+
// received: { name: string } }
|
|
1292
|
+
// >
|
|
1293
|
+
});
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1235
1296
|
### When to Use Metadata
|
|
1236
1297
|
|
|
1237
1298
|
#### ✅ Great Use Cases
|
|
@@ -1375,9 +1436,8 @@ function getApiTasks(store: Store) {
|
|
|
1375
1436
|
|
|
1376
1437
|
// Find all tasks with specific performance requirements
|
|
1377
1438
|
function getPerformanceCriticalTasks(store: Store) {
|
|
1378
|
-
return store.
|
|
1379
|
-
|
|
1380
|
-
return performanceTag.extract(tags) !== null;
|
|
1439
|
+
return store.tasks.values().filter(({ task }) => {
|
|
1440
|
+
return performanceTag.extract(task) !== null;
|
|
1381
1441
|
});
|
|
1382
1442
|
}
|
|
1383
1443
|
```
|
|
@@ -1512,6 +1572,350 @@ const app = resource({
|
|
|
1512
1572
|
});
|
|
1513
1573
|
```
|
|
1514
1574
|
|
|
1575
|
+
### Runtime Input and Config Validation
|
|
1576
|
+
|
|
1577
|
+
BlueLibs Runner includes a generic validation interface that works with any validation library, including [Zod](https://zod.dev/), [Yup](https://github.com/jquense/yup), [Joi](https://joi.dev/), and others. The framework provides runtime validation with excellent TypeScript inference while remaining library-agnostic.
|
|
1578
|
+
|
|
1579
|
+
#### The Validation Interface
|
|
1580
|
+
|
|
1581
|
+
The framework defines a simple `IValidationSchema<T>` interface that any validation library can implement:
|
|
1582
|
+
|
|
1583
|
+
```typescript
|
|
1584
|
+
interface IValidationSchema<T> {
|
|
1585
|
+
parse(input: unknown): T;
|
|
1586
|
+
}
|
|
1587
|
+
```
|
|
1588
|
+
|
|
1589
|
+
Popular validation libraries already implement this interface:
|
|
1590
|
+
|
|
1591
|
+
- **Zod**: `.parse()` method works directly
|
|
1592
|
+
- **Yup**: Use `.validateSync()` or create a wrapper
|
|
1593
|
+
- **Joi**: Use `.assert()` or create a wrapper
|
|
1594
|
+
- **Custom validators**: Implement the interface yourself
|
|
1595
|
+
|
|
1596
|
+
#### Task Input Validation
|
|
1597
|
+
|
|
1598
|
+
Add an `inputSchema` to any task to validate inputs before execution:
|
|
1599
|
+
|
|
1600
|
+
```typescript
|
|
1601
|
+
import { z } from "zod";
|
|
1602
|
+
import { task, resource, run } from "@bluelibs/runner";
|
|
1603
|
+
|
|
1604
|
+
const userSchema = z.object({
|
|
1605
|
+
name: z.string().min(2),
|
|
1606
|
+
email: z.string().email(),
|
|
1607
|
+
age: z.number().min(0).max(150),
|
|
1608
|
+
});
|
|
1609
|
+
|
|
1610
|
+
const createUserTask = task({
|
|
1611
|
+
id: "app.tasks.createUser",
|
|
1612
|
+
inputSchema: userSchema, // Works directly with Zod!
|
|
1613
|
+
run: async (userData) => {
|
|
1614
|
+
// userData is validated and properly typed
|
|
1615
|
+
return { id: "user-123", ...userData };
|
|
1616
|
+
},
|
|
1617
|
+
});
|
|
1618
|
+
|
|
1619
|
+
const app = resource({
|
|
1620
|
+
id: "app",
|
|
1621
|
+
register: [createUserTask],
|
|
1622
|
+
dependencies: { createUserTask },
|
|
1623
|
+
init: async (_, { createUserTask }) => {
|
|
1624
|
+
// This works - valid input
|
|
1625
|
+
const user = await createUserTask({
|
|
1626
|
+
name: "John Doe",
|
|
1627
|
+
email: "john@example.com",
|
|
1628
|
+
age: 30,
|
|
1629
|
+
});
|
|
1630
|
+
|
|
1631
|
+
// This throws a validation error at runtime
|
|
1632
|
+
try {
|
|
1633
|
+
await createUserTask({
|
|
1634
|
+
name: "J", // Too short
|
|
1635
|
+
email: "invalid-email", // Invalid format
|
|
1636
|
+
age: -5, // Negative age
|
|
1637
|
+
});
|
|
1638
|
+
} catch (error) {
|
|
1639
|
+
console.log(error.message);
|
|
1640
|
+
// "Task input validation failed for app.tasks.createUser: ..."
|
|
1641
|
+
}
|
|
1642
|
+
},
|
|
1643
|
+
});
|
|
1644
|
+
```
|
|
1645
|
+
|
|
1646
|
+
#### Resource Config Validation (Fail Fast)
|
|
1647
|
+
|
|
1648
|
+
Add a `configSchema` to resources to validate configurations. **Validation happens immediately when `.with()` is called**, ensuring configuration errors are caught early:
|
|
1649
|
+
|
|
1650
|
+
```typescript
|
|
1651
|
+
const databaseConfigSchema = z.object({
|
|
1652
|
+
host: z.string(),
|
|
1653
|
+
port: z.number().min(1).max(65535),
|
|
1654
|
+
database: z.string(),
|
|
1655
|
+
ssl: z.boolean().default(false), // Optional with default
|
|
1656
|
+
});
|
|
1657
|
+
|
|
1658
|
+
const databaseResource = resource({
|
|
1659
|
+
id: "app.resources.database",
|
|
1660
|
+
configSchema: databaseConfigSchema, // Validation on .with()
|
|
1661
|
+
init: async (config) => {
|
|
1662
|
+
// config is already validated and has proper types
|
|
1663
|
+
return createConnection({
|
|
1664
|
+
host: config.host,
|
|
1665
|
+
port: config.port,
|
|
1666
|
+
database: config.database,
|
|
1667
|
+
ssl: config.ssl,
|
|
1668
|
+
});
|
|
1669
|
+
},
|
|
1670
|
+
});
|
|
1671
|
+
|
|
1672
|
+
// Validation happens here, not during init!
|
|
1673
|
+
try {
|
|
1674
|
+
const configuredResource = databaseResource.with({
|
|
1675
|
+
host: "localhost",
|
|
1676
|
+
port: 99999, // Invalid: port too high
|
|
1677
|
+
database: "myapp",
|
|
1678
|
+
});
|
|
1679
|
+
} catch (error) {
|
|
1680
|
+
// "Resource config validation failed for app.resources.database: ..."
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
const app = resource({
|
|
1684
|
+
id: "app",
|
|
1685
|
+
register: [
|
|
1686
|
+
databaseResource.with({
|
|
1687
|
+
host: "localhost",
|
|
1688
|
+
port: 5432,
|
|
1689
|
+
database: "myapp",
|
|
1690
|
+
// ssl defaults to false
|
|
1691
|
+
}),
|
|
1692
|
+
],
|
|
1693
|
+
});
|
|
1694
|
+
```
|
|
1695
|
+
|
|
1696
|
+
#### Event Payload Validation
|
|
1697
|
+
|
|
1698
|
+
Add a `payloadSchema` to events to validate payloads every time they're emitted:
|
|
1699
|
+
|
|
1700
|
+
```typescript
|
|
1701
|
+
const userActionSchema = z.object({
|
|
1702
|
+
userId: z.string().uuid(),
|
|
1703
|
+
action: z.enum(["created", "updated", "deleted"]),
|
|
1704
|
+
timestamp: z.date().default(() => new Date()),
|
|
1705
|
+
});
|
|
1706
|
+
|
|
1707
|
+
const userActionEvent = event({
|
|
1708
|
+
id: "app.events.userAction",
|
|
1709
|
+
payloadSchema: userActionSchema, // Validates on emit
|
|
1710
|
+
});
|
|
1711
|
+
|
|
1712
|
+
const notificationTask = task({
|
|
1713
|
+
id: "app.tasks.sendNotification",
|
|
1714
|
+
on: userActionEvent,
|
|
1715
|
+
run: async (eventData) => {
|
|
1716
|
+
// eventData.data is validated and properly typed
|
|
1717
|
+
console.log(`User ${eventData.data.userId} was ${eventData.data.action}`);
|
|
1718
|
+
},
|
|
1719
|
+
});
|
|
1720
|
+
|
|
1721
|
+
const app = resource({
|
|
1722
|
+
id: "app",
|
|
1723
|
+
register: [userActionEvent, notificationTask],
|
|
1724
|
+
dependencies: { userActionEvent },
|
|
1725
|
+
init: async (_, { userActionEvent }) => {
|
|
1726
|
+
// This works - valid payload
|
|
1727
|
+
await userActionEvent({
|
|
1728
|
+
userId: "123e4567-e89b-12d3-a456-426614174000",
|
|
1729
|
+
action: "created",
|
|
1730
|
+
});
|
|
1731
|
+
|
|
1732
|
+
// This throws validation error when emitted
|
|
1733
|
+
try {
|
|
1734
|
+
await userActionEvent({
|
|
1735
|
+
userId: "invalid-uuid",
|
|
1736
|
+
action: "unknown",
|
|
1737
|
+
});
|
|
1738
|
+
} catch (error) {
|
|
1739
|
+
// "Event payload validation failed for app.events.userAction: ..."
|
|
1740
|
+
}
|
|
1741
|
+
},
|
|
1742
|
+
});
|
|
1743
|
+
```
|
|
1744
|
+
|
|
1745
|
+
#### Middleware Config Validation (Fail Fast)
|
|
1746
|
+
|
|
1747
|
+
Add a `configSchema` to middleware to validate configurations. Like resources, **validation happens immediately when `.with()` is called**:
|
|
1748
|
+
|
|
1749
|
+
```typescript
|
|
1750
|
+
const timingConfigSchema = z.object({
|
|
1751
|
+
timeout: z.number().positive(),
|
|
1752
|
+
logLevel: z.enum(["debug", "info", "warn", "error"]).default("info"),
|
|
1753
|
+
logSuccessful: z.boolean().default(true),
|
|
1754
|
+
});
|
|
1755
|
+
|
|
1756
|
+
const timingMiddleware = middleware({
|
|
1757
|
+
id: "app.middleware.timing",
|
|
1758
|
+
configSchema: timingConfigSchema, // Validation on .with()
|
|
1759
|
+
run: async ({ next }, _, config) => {
|
|
1760
|
+
const start = Date.now();
|
|
1761
|
+
try {
|
|
1762
|
+
const result = await next();
|
|
1763
|
+
const duration = Date.now() - start;
|
|
1764
|
+
if (config.logSuccessful && config.logLevel === "debug") {
|
|
1765
|
+
console.log(`Operation completed in ${duration}ms`);
|
|
1766
|
+
}
|
|
1767
|
+
return result;
|
|
1768
|
+
} catch (error) {
|
|
1769
|
+
const duration = Date.now() - start;
|
|
1770
|
+
console.log(`Operation failed after ${duration}ms`);
|
|
1771
|
+
throw error;
|
|
1772
|
+
}
|
|
1773
|
+
},
|
|
1774
|
+
});
|
|
1775
|
+
|
|
1776
|
+
// Validation happens here, not during execution!
|
|
1777
|
+
try {
|
|
1778
|
+
const configuredMiddleware = timingMiddleware.with({
|
|
1779
|
+
timeout: -5, // Invalid: negative timeout
|
|
1780
|
+
logLevel: "invalid", // Invalid: not in enum
|
|
1781
|
+
});
|
|
1782
|
+
} catch (error) {
|
|
1783
|
+
// "Middleware config validation failed for app.middleware.timing: ..."
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
const myTask = task({
|
|
1787
|
+
id: "app.tasks.example",
|
|
1788
|
+
middleware: [
|
|
1789
|
+
timingMiddleware.with({
|
|
1790
|
+
timeout: 5000,
|
|
1791
|
+
logLevel: "debug",
|
|
1792
|
+
logSuccessful: true,
|
|
1793
|
+
}),
|
|
1794
|
+
],
|
|
1795
|
+
run: async () => "success",
|
|
1796
|
+
});
|
|
1797
|
+
```
|
|
1798
|
+
|
|
1799
|
+
#### Advanced Validation Features
|
|
1800
|
+
|
|
1801
|
+
Any validation library features work with the generic interface. Here's an example with transformations and refinements:
|
|
1802
|
+
|
|
1803
|
+
```typescript
|
|
1804
|
+
const advancedSchema = z
|
|
1805
|
+
.object({
|
|
1806
|
+
userId: z.string().uuid(),
|
|
1807
|
+
amount: z.string().transform((val) => parseFloat(val)), // Transform string to number
|
|
1808
|
+
currency: z.enum(["USD", "EUR", "GBP"]),
|
|
1809
|
+
metadata: z.record(z.string()).optional(),
|
|
1810
|
+
})
|
|
1811
|
+
.refine((data) => data.amount > 0, {
|
|
1812
|
+
message: "Amount must be positive",
|
|
1813
|
+
path: ["amount"],
|
|
1814
|
+
});
|
|
1815
|
+
|
|
1816
|
+
const paymentTask = task({
|
|
1817
|
+
id: "app.tasks.payment",
|
|
1818
|
+
inputSchema: advancedSchema,
|
|
1819
|
+
run: async (payment) => {
|
|
1820
|
+
// payment.amount is now a number (transformed from string)
|
|
1821
|
+
// All validations have passed
|
|
1822
|
+
return processPayment(payment);
|
|
1823
|
+
},
|
|
1824
|
+
});
|
|
1825
|
+
```
|
|
1826
|
+
|
|
1827
|
+
#### Error Handling
|
|
1828
|
+
|
|
1829
|
+
Validation errors are thrown with clear, descriptive messages that include the component ID:
|
|
1830
|
+
|
|
1831
|
+
```typescript
|
|
1832
|
+
// Task validation error format:
|
|
1833
|
+
// "Task input validation failed for {taskId}: {validationErrorMessage}"
|
|
1834
|
+
|
|
1835
|
+
// Resource validation error format (thrown on .with() call):
|
|
1836
|
+
// "Resource config validation failed for {resourceId}: {validationErrorMessage}"
|
|
1837
|
+
|
|
1838
|
+
// Event validation error format (thrown on emit):
|
|
1839
|
+
// "Event payload validation failed for {eventId}: {validationErrorMessage}"
|
|
1840
|
+
|
|
1841
|
+
// Middleware validation error format (thrown on .with() call):
|
|
1842
|
+
// "Middleware config validation failed for {middlewareId}: {validationErrorMessage}"
|
|
1843
|
+
```
|
|
1844
|
+
|
|
1845
|
+
#### Using Different Validation Libraries
|
|
1846
|
+
|
|
1847
|
+
The framework works with any validation library that implements the `IValidationSchema<T>` interface:
|
|
1848
|
+
|
|
1849
|
+
```typescript
|
|
1850
|
+
// Zod (works directly)
|
|
1851
|
+
import { z } from "zod";
|
|
1852
|
+
const zodSchema = z.string().email();
|
|
1853
|
+
|
|
1854
|
+
// Yup (with wrapper)
|
|
1855
|
+
import * as yup from "yup";
|
|
1856
|
+
const yupSchema = {
|
|
1857
|
+
parse: (input: unknown) => yup.string().email().validateSync(input),
|
|
1858
|
+
};
|
|
1859
|
+
|
|
1860
|
+
// Joi (with wrapper)
|
|
1861
|
+
import Joi from "joi";
|
|
1862
|
+
const joiSchema = {
|
|
1863
|
+
parse: (input: unknown) => {
|
|
1864
|
+
const { error, value } = Joi.string().email().validate(input);
|
|
1865
|
+
if (error) throw error;
|
|
1866
|
+
return value;
|
|
1867
|
+
},
|
|
1868
|
+
};
|
|
1869
|
+
|
|
1870
|
+
// Custom validation
|
|
1871
|
+
const customSchema = {
|
|
1872
|
+
parse: (input: unknown) => {
|
|
1873
|
+
if (typeof input !== "string" || !input.includes("@")) {
|
|
1874
|
+
throw new Error("Must be a valid email");
|
|
1875
|
+
}
|
|
1876
|
+
return input;
|
|
1877
|
+
},
|
|
1878
|
+
};
|
|
1879
|
+
```
|
|
1880
|
+
|
|
1881
|
+
#### When to Use Validation
|
|
1882
|
+
|
|
1883
|
+
- **API boundaries**: Validating user inputs from HTTP requests
|
|
1884
|
+
- **External data**: Processing data from files, databases, or APIs
|
|
1885
|
+
- **Configuration**: Ensuring environment variables and configs are correct (fail fast)
|
|
1886
|
+
- **Event payloads**: Validating data in event-driven architectures
|
|
1887
|
+
- **Middleware configs**: Validating middleware settings at registration time (fail fast)
|
|
1888
|
+
|
|
1889
|
+
#### Performance Notes
|
|
1890
|
+
|
|
1891
|
+
- Validation only runs when schemas are provided (zero overhead when not used)
|
|
1892
|
+
- Resource and middleware validation happens once at registration time (`.with()`)
|
|
1893
|
+
- Task and event validation happens at runtime
|
|
1894
|
+
- Consider the validation library's performance characteristics for your use case
|
|
1895
|
+
- All major validation libraries are optimized for runtime validation
|
|
1896
|
+
|
|
1897
|
+
#### TypeScript Integration
|
|
1898
|
+
|
|
1899
|
+
While runtime validation happens with your chosen library, TypeScript still enforces compile-time types. For the best experience:
|
|
1900
|
+
|
|
1901
|
+
```typescript
|
|
1902
|
+
// With Zod, define your type and schema together
|
|
1903
|
+
type UserData = z.infer<typeof userSchema>;
|
|
1904
|
+
|
|
1905
|
+
const userSchema = z.object({
|
|
1906
|
+
name: z.string(),
|
|
1907
|
+
email: z.string().email(),
|
|
1908
|
+
});
|
|
1909
|
+
|
|
1910
|
+
const createUser = task({
|
|
1911
|
+
inputSchema: userSchema,
|
|
1912
|
+
run: async (input: UserData) => {
|
|
1913
|
+
// Both runtime validation AND compile-time typing
|
|
1914
|
+
return { id: "user-123", ...input };
|
|
1915
|
+
},
|
|
1916
|
+
});
|
|
1917
|
+
```
|
|
1918
|
+
|
|
1515
1919
|
### Internal Services: For When You Need Direct Access
|
|
1516
1920
|
|
|
1517
1921
|
We expose the internal services for advanced use cases (but try not to use them unless you really need to):
|
package/dist/define.d.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* metadata: anonymous IDs, file path tags (for better debugging), lifecycle
|
|
6
6
|
* events, and global middleware flags. See README for high-level concepts.
|
|
7
7
|
*/
|
|
8
|
-
import { ITask, ITaskDefinition, IResource, IResourceWithConfig, IResourceDefinition, IEventDefinition, IMiddlewareDefinition, DependencyMapType, DependencyValuesType, IMiddleware, IEvent, RegisterableItems, ITag, ITagDefinition } from "./defs";
|
|
9
|
-
export declare function defineTask<Input = undefined, Output extends Promise<any> = any, Deps extends DependencyMapType = any, TOn extends "*" | IEventDefinition | undefined = undefined>(taskConfig: ITaskDefinition<Input, Output, Deps, TOn>): ITask<Input, Output, Deps, TOn>;
|
|
10
|
-
export declare function defineResource<TConfig = void, TValue = any
|
|
8
|
+
import { ITask, ITaskDefinition, IResource, IResourceWithConfig, IResourceDefinition, IEventDefinition, IMiddlewareDefinition, DependencyMapType, DependencyValuesType, IMiddleware, IEvent, RegisterableItems, ITag, ITagDefinition, ITaskMeta, IResourceMeta } from "./defs";
|
|
9
|
+
export declare function defineTask<Input = undefined, Output extends Promise<any> = any, Deps extends DependencyMapType = any, TOn extends "*" | IEventDefinition | undefined = undefined, TMeta extends ITaskMeta = any>(taskConfig: ITaskDefinition<Input, Output, Deps, TOn, TMeta>): ITask<Input, Output, Deps, TOn, TMeta>;
|
|
10
|
+
export declare function defineResource<TConfig = void, TValue extends Promise<any> = Promise<any>, TDeps extends DependencyMapType = {}, TPrivate = any, TMeta extends IResourceMeta = any>(constConfig: IResourceDefinition<TConfig, TValue, TDeps, TPrivate, any, any, TMeta>): IResource<TConfig, TValue, TDeps, TPrivate, TMeta>;
|
|
11
11
|
/**
|
|
12
12
|
* Creates an "index" resource which groups multiple registerable items under
|
|
13
13
|
* a single dependency. The resulting resource registers every item, depends
|
|
@@ -16,7 +16,7 @@ export declare function defineResource<TConfig = void, TValue = any, TDeps exten
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function defineIndex<T extends Record<string, RegisterableItems>, D extends {
|
|
18
18
|
[K in keyof T]: T[K] extends IResourceWithConfig<any, any, any> ? T[K]["resource"] : T[K];
|
|
19
|
-
} & DependencyMapType>(items: T): IResource<void, DependencyValuesType<D
|
|
19
|
+
} & DependencyMapType>(items: T): IResource<void, Promise<DependencyValuesType<D>>, D>;
|
|
20
20
|
export declare function defineEvent<TPayload = void>(config?: IEventDefinition<TPayload>): IEvent<TPayload>;
|
|
21
21
|
export type MiddlewareEverywhereOptions = {
|
|
22
22
|
/**
|
|
@@ -46,4 +46,4 @@ export declare function defineOverride<T extends IMiddleware<any, any>>(base: T,
|
|
|
46
46
|
* - `.with(config)` to create configured instances
|
|
47
47
|
* - `.extract(tags)` to extract this tag from a list of tags
|
|
48
48
|
*/
|
|
49
|
-
export declare function defineTag<TConfig = void>(definition: ITagDefinition<TConfig>): ITag<TConfig>;
|
|
49
|
+
export declare function defineTag<TConfig = void, TEnforceContract = void>(definition: ITagDefinition<TConfig, TEnforceContract>): ITag<TConfig, TEnforceContract>;
|
package/dist/define.js
CHANGED
|
@@ -42,6 +42,7 @@ function defineTask(taskConfig) {
|
|
|
42
42
|
run: taskConfig.run,
|
|
43
43
|
on: taskConfig.on,
|
|
44
44
|
listenerOrder: taskConfig.listenerOrder,
|
|
45
|
+
inputSchema: taskConfig.inputSchema,
|
|
45
46
|
events: {
|
|
46
47
|
beforeRun: {
|
|
47
48
|
...defineEvent({
|
|
@@ -96,7 +97,17 @@ function defineResource(constConfig) {
|
|
|
96
97
|
overrides: constConfig.overrides || [],
|
|
97
98
|
init: constConfig.init,
|
|
98
99
|
context: constConfig.context,
|
|
100
|
+
configSchema: constConfig.configSchema,
|
|
99
101
|
with: function (config) {
|
|
102
|
+
// Validate config with schema if provided (fail fast)
|
|
103
|
+
if (this.configSchema) {
|
|
104
|
+
try {
|
|
105
|
+
config = this.configSchema.parse(config);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new errors_1.ValidationError("Resource config", this.id, error instanceof Error ? error : new Error(String(error)));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
100
111
|
return {
|
|
101
112
|
[defs_1.symbolResourceWithConfig]: true,
|
|
102
113
|
id: this.id,
|
|
@@ -130,7 +141,7 @@ function defineResource(constConfig) {
|
|
|
130
141
|
[defs_1.symbolFilePath]: filePath,
|
|
131
142
|
},
|
|
132
143
|
},
|
|
133
|
-
meta: constConfig.meta || {},
|
|
144
|
+
meta: (constConfig.meta || {}),
|
|
134
145
|
middleware: constConfig.middleware || [],
|
|
135
146
|
};
|
|
136
147
|
}
|
|
@@ -198,6 +209,15 @@ function defineMiddleware(middlewareDef) {
|
|
|
198
209
|
return {
|
|
199
210
|
...object,
|
|
200
211
|
with: (config) => {
|
|
212
|
+
// Validate config with schema if provided (fail fast)
|
|
213
|
+
if (object.configSchema) {
|
|
214
|
+
try {
|
|
215
|
+
config = object.configSchema.parse(config);
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
throw new errors_1.ValidationError("Middleware config", object.id, error instanceof Error ? error : new Error(String(error)));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
201
221
|
return {
|
|
202
222
|
...object,
|
|
203
223
|
[defs_1.symbolMiddlewareConfigured]: true,
|
|
@@ -214,7 +234,7 @@ function defineMiddleware(middlewareDef) {
|
|
|
214
234
|
[defs_1.symbolMiddlewareEverywhereTasks]: tasks,
|
|
215
235
|
[defs_1.symbolMiddlewareEverywhereResources]: resources,
|
|
216
236
|
everywhere() {
|
|
217
|
-
throw errors_1.
|
|
237
|
+
throw new errors_1.MiddlewareAlreadyGlobalError(object.id);
|
|
218
238
|
},
|
|
219
239
|
};
|
|
220
240
|
},
|
package/dist/define.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"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"}
|