@webpieces/rules-config 0.4.762 → 0.4.763
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/rules-config",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.763",
|
|
4
4
|
"description": "Shared webpieces.config.json loader. Single source of truth for validation rule configuration consumed by @webpieces/ai-hook-rules, @webpieces/code-rules, and @webpieces/nx-webpieces-rules.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -112,7 +112,7 @@ TraceId (also called correlation ID, request ID) ties these together.
|
|
|
112
112
|
- Is it catching for cleanup? → Usually wrong pattern
|
|
113
113
|
- **Is this a global entry point?** → **ASK USER**: "I think this code is the entry point where we need a global try-catch block. Is this correct?" (95% of the time it is NOT!)
|
|
114
114
|
- **Is this edge code calling external services?** → **ASK USER**: "This looks like edge code calling an external service. Should I add request/response logging with try-catch?"
|
|
115
|
-
- **Is this form error handling?** → Valid IF: catches only `
|
|
115
|
+
- **Is this form error handling?** → Valid IF: catches only `ApiEndUserError` for display AND rethrows other errors (see Form Error Handling Pattern)
|
|
116
116
|
- Is it adding context to the error before rethrowing? → May be valid (see Problem 3)
|
|
117
117
|
|
|
118
118
|
3. **IF REMOVING** the try-catch block:
|
|
@@ -232,7 +232,7 @@ export class DebugController implements DebugApi {
|
|
|
232
232
|
async getErrorById(@PathParam('id') id: string): Promise<DebugErrorResponse> {
|
|
233
233
|
const error = ErrorStore.get(id);
|
|
234
234
|
if (!error) {
|
|
235
|
-
throw new
|
|
235
|
+
throw new ApiNotFoundError(`Error ${id} not found`);
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
return {
|
|
@@ -377,9 +377,10 @@ async function callVendorApiWithRetry(request: VendorRequest): Promise<VendorRes
|
|
|
377
377
|
|
|
378
378
|
// After retries exhausted, throw with traceId
|
|
379
379
|
const traceId = RequestContext.get<string>('TRACE_ID');
|
|
380
|
-
throw new
|
|
380
|
+
throw new ApiDependencyBackoffError(
|
|
381
381
|
`Vendor API failed after ${maxRetries} retries. TraceId: ${traceId}`,
|
|
382
|
-
|
|
382
|
+
30,
|
|
383
|
+
lastError,
|
|
383
384
|
);
|
|
384
385
|
}
|
|
385
386
|
```
|
|
@@ -479,7 +480,7 @@ You may use `// eslint-disable-next-line @webpieces/no-unmanaged-exceptions` ONL
|
|
|
479
480
|
3. **Resource cleanup** with explicit approval
|
|
480
481
|
4. **Global error handler entry points** (see below)
|
|
481
482
|
5. **Edge code patterns** for vendor/external service calls (see below)
|
|
482
|
-
6. **Form error handling** - catching `
|
|
483
|
+
6. **Form error handling** - catching `ApiEndUserError` for display, rethrowing others (see below)
|
|
483
484
|
|
|
484
485
|
All require:
|
|
485
486
|
- Comment explaining WHY try-catch is needed
|
|
@@ -615,9 +616,9 @@ async function sendMail(request: MailRequest): Promise<MailResponse> {
|
|
|
615
616
|
Frontend forms often need to catch user-facing errors (like validation errors) to display in the UI, while rethrowing unexpected errors to the global handler.
|
|
616
617
|
|
|
617
618
|
**This pattern is ACCEPTABLE because**:
|
|
618
|
-
- It catches ONLY user-facing errors (`
|
|
619
|
+
- It catches ONLY user-facing errors (`ApiEndUserError`) for display
|
|
619
620
|
- Unexpected errors are RETHROWN (not swallowed)
|
|
620
|
-
- Server throws `
|
|
621
|
+
- Server throws `ApiEndUserError` → protocol translates to error payload → client translates back to exception
|
|
621
622
|
|
|
622
623
|
### Example: Form Submission Error Handling
|
|
623
624
|
```typescript
|
|
@@ -629,7 +630,7 @@ async submitForm(): Promise<void> {
|
|
|
629
630
|
} catch (err: unknown) {
|
|
630
631
|
const error = toError(err);
|
|
631
632
|
|
|
632
|
-
if (error instanceof
|
|
633
|
+
if (error instanceof ApiEndUserError) {
|
|
633
634
|
// User-facing error - display in form
|
|
634
635
|
this.formError = error.message;
|
|
635
636
|
this.cdr.detectChanges();
|
|
@@ -645,31 +646,31 @@ async submitForm(): Promise<void> {
|
|
|
645
646
|
|
|
646
647
|
1. **Selective catching**: Only catches errors meant for user display
|
|
647
648
|
2. **No swallowing**: Unexpected errors bubble to global handler with traceId
|
|
648
|
-
3. **Protocol design**: Server intentionally throws `
|
|
649
|
+
3. **Protocol design**: Server intentionally throws `ApiEndUserError` for user-facing messages
|
|
649
650
|
4. **UX requirement**: Forms must show validation errors inline, not via global error page
|
|
650
651
|
|
|
651
652
|
### Key Requirements
|
|
652
653
|
|
|
653
|
-
- **ONLY catch specific error types** (e.g., `
|
|
654
|
+
- **ONLY catch specific error types** (e.g., `ApiEndUserError`, `ValidationError`)
|
|
654
655
|
- **ALWAYS rethrow** errors that aren't user-facing
|
|
655
|
-
- Server-side code MUST throw `
|
|
656
|
+
- Server-side code MUST throw `ApiEndUserError` for user-displayable messages
|
|
656
657
|
|
|
657
|
-
### `
|
|
658
|
+
### `ApiEndUserError` is not a convention — it is the only message that survives the wire
|
|
658
659
|
|
|
659
|
-
This is a HARD RULE, enforced by `
|
|
660
|
+
This is a HARD RULE, enforced by `ApiErrorHttpMapper` on the server (`http-server`):
|
|
660
661
|
|
|
661
|
-
> **Only `
|
|
662
|
-
>
|
|
662
|
+
> **Only `ApiEndUserError`'s `message` is sent to the caller.** Every other `ApiError` subclass sends
|
|
663
|
+
> its generic semantic message — `'Not Found'`, `'Internal Error'`, … — and
|
|
663
664
|
> its real message goes to the server's LOG only.
|
|
664
665
|
|
|
665
666
|
`Error.message` is an operator-facing field. It routinely quotes a downstream service url, an HTTP
|
|
666
667
|
method and content-type, a body snippet, a table name or an internal id, and none of that may reach an
|
|
667
668
|
external consumer. So:
|
|
668
669
|
|
|
669
|
-
- Throwing `new
|
|
670
|
-
text to the user — the caller receives `'Bad Request'`. Throw `
|
|
671
|
-
text as `
|
|
672
|
-
- A client must branch on the error TYPE, on `subType`, on `errorCode` or on `
|
|
670
|
+
- Throwing `new ApiBadRequestError('the email you entered is already taken')` does **not** show that
|
|
671
|
+
text to the user — the caller receives `'Bad Request'`. Throw `ApiEndUserError` instead, or pass the
|
|
672
|
+
text as `ApiBadRequestError`'s `callerMessage`, which IS sent (as `callerMessage`).
|
|
673
|
+
- A client must branch on the error TYPE, on `subType`, on `errorCode` or on `callerMessage` — never
|
|
673
674
|
on the prose of `message`. Against a current webpieces server that prose is a constant per status.
|
|
674
675
|
- An app that deliberately wants to publish richer text installs an `ErrorTranslators` on
|
|
675
676
|
`ClientRegistry` (`setErrorTranslators`); its `toWire()` response — status, reason phrase, headers
|
|
@@ -754,7 +755,6 @@ and in `/debugLocal/{traceId}` responses.
|
|
|
754
755
|
2. **Edge code**: External API calls, database operations, email services - use logRequest/logSuccess/logFailure pattern
|
|
755
756
|
3. **Retry loops**: Vendor APIs with exponential backoff
|
|
756
757
|
4. **Batching**: Partial failure handling where processing must continue
|
|
757
|
-
5. **Form error handling**: Catch `
|
|
758
|
+
5. **Form error handling**: Catch `ApiEndUserError` for UI display, rethrow all other errors
|
|
758
759
|
|
|
759
760
|
**Remember**: If you can't handle the error meaningfully, don't catch it. Let it bubble to the global handler where it will be logged with full context and traceId.
|
|
760
|
-
|