@schmock/core 2.3.0 → 2.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/LICENSE +21 -0
- package/README.md +35 -0
- package/dist/abort.d.ts +3 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +30 -0
- package/dist/builder.d.ts +31 -10
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +760 -190
- package/dist/constants.d.ts +38 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +123 -2
- package/dist/errors.d.ts +14 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +41 -6
- package/dist/helpers.d.ts +9 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +18 -2
- package/dist/http-helpers.d.ts +39 -4
- package/dist/http-helpers.d.ts.map +1 -1
- package/dist/http-helpers.js +147 -49
- package/dist/index.d.ts +292 -34
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/interceptor.d.ts +11 -1
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/interceptor.js +316 -169
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +12 -3
- package/dist/plugin-pipeline.d.ts +3 -3
- package/dist/plugin-pipeline.d.ts.map +1 -1
- package/dist/plugin-pipeline.js +29 -14
- package/dist/response-normalizer.d.ts +16 -0
- package/dist/response-normalizer.d.ts.map +1 -0
- package/dist/response-normalizer.js +316 -0
- package/dist/response-parser.d.ts.map +1 -1
- package/dist/response-parser.js +39 -2
- package/dist/route-matcher.d.ts +3 -0
- package/dist/route-matcher.d.ts.map +1 -1
- package/dist/route-matcher.js +12 -6
- package/dist/types.d.ts +7 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +18 -6
- package/src/audit-core-builder.test.ts +0 -218
- package/src/audit-response-guard.test.ts +0 -38
- package/src/binary.test.ts +0 -126
- package/src/binary.ts +0 -11
- package/src/builder.test.ts +0 -289
- package/src/builder.ts +0 -748
- package/src/constants.test.ts +0 -99
- package/src/constants.ts +0 -73
- package/src/debug.test.ts +0 -241
- package/src/delay.test.ts +0 -319
- package/src/dist-shape.test.ts +0 -35
- package/src/errors.test.ts +0 -223
- package/src/errors.ts +0 -130
- package/src/factory.test.ts +0 -133
- package/src/helpers.test.ts +0 -147
- package/src/helpers.ts +0 -58
- package/src/http-helpers.test.ts +0 -39
- package/src/http-helpers.ts +0 -149
- package/src/index.ts +0 -152
- package/src/interceptor.test.ts +0 -488
- package/src/interceptor.ts +0 -407
- package/src/namespace.test.ts +0 -274
- package/src/parser.property.test.ts +0 -630
- package/src/parser.test.ts +0 -148
- package/src/parser.ts +0 -64
- package/src/plugin-pipeline.ts +0 -208
- package/src/plugin-system.test.ts +0 -697
- package/src/response-parser.ts +0 -114
- package/src/response-parsing.test.ts +0 -333
- package/src/route-matcher.ts +0 -69
- package/src/route-matching.test.ts +0 -394
- package/src/server.test.ts +0 -234
- package/src/smart-defaults.test.ts +0 -361
- package/src/steps/async-support.steps.ts +0 -421
- package/src/steps/audit-core-builder.steps.ts +0 -188
- package/src/steps/audit-onerror-tuple.steps.ts +0 -83
- package/src/steps/basic-usage.steps.ts +0 -245
- package/src/steps/developer-experience.steps.ts +0 -204
- package/src/steps/error-handling.steps.ts +0 -555
- package/src/steps/fetch-interceptor.steps.ts +0 -457
- package/src/steps/fluent-api.steps.ts +0 -255
- package/src/steps/http-methods.steps.ts +0 -342
- package/src/steps/lifecycle-events.steps.ts +0 -149
- package/src/steps/performance-reliability.steps.ts +0 -90
- package/src/steps/plugin-integration.steps.ts +0 -334
- package/src/steps/request-history.steps.ts +0 -458
- package/src/steps/response-delay.steps.ts +0 -88
- package/src/steps/route-key-format.steps.ts +0 -99
- package/src/steps/standalone-server.steps.ts +0 -227
- package/src/steps/state-concurrency.steps.ts +0 -167
- package/src/types.ts +0 -36
package/src/parser.test.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { parseRouteKey } from "./parser";
|
|
3
|
-
|
|
4
|
-
describe("parseRouteKey", () => {
|
|
5
|
-
describe("valid route keys", () => {
|
|
6
|
-
it("parses simple GET route", () => {
|
|
7
|
-
const result = parseRouteKey("GET /users");
|
|
8
|
-
expect(result).toEqual({
|
|
9
|
-
method: "GET",
|
|
10
|
-
path: "/users",
|
|
11
|
-
pattern: expect.any(RegExp),
|
|
12
|
-
params: [],
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it("parses route with single parameter", () => {
|
|
17
|
-
const result = parseRouteKey("GET /users/:id");
|
|
18
|
-
expect(result).toEqual({
|
|
19
|
-
method: "GET",
|
|
20
|
-
path: "/users/:id",
|
|
21
|
-
pattern: expect.any(RegExp),
|
|
22
|
-
params: ["id"],
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("parses route with multiple parameters", () => {
|
|
27
|
-
const result = parseRouteKey(
|
|
28
|
-
"DELETE /api/posts/:postId/comments/:commentId",
|
|
29
|
-
);
|
|
30
|
-
expect(result).toEqual({
|
|
31
|
-
method: "DELETE",
|
|
32
|
-
path: "/api/posts/:postId/comments/:commentId",
|
|
33
|
-
pattern: expect.any(RegExp),
|
|
34
|
-
params: ["postId", "commentId"],
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("supports all HTTP methods", () => {
|
|
39
|
-
const methods = [
|
|
40
|
-
"GET",
|
|
41
|
-
"POST",
|
|
42
|
-
"PUT",
|
|
43
|
-
"DELETE",
|
|
44
|
-
"PATCH",
|
|
45
|
-
"HEAD",
|
|
46
|
-
"OPTIONS",
|
|
47
|
-
] as const;
|
|
48
|
-
|
|
49
|
-
for (const method of methods) {
|
|
50
|
-
const result = parseRouteKey(`${method} /test`);
|
|
51
|
-
expect(result.method).toBe(method);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("handles paths with namespace", () => {
|
|
56
|
-
const result = parseRouteKey("POST /api/v2/users");
|
|
57
|
-
expect(result).toEqual({
|
|
58
|
-
method: "POST",
|
|
59
|
-
path: "/api/v2/users",
|
|
60
|
-
pattern: expect.any(RegExp),
|
|
61
|
-
params: [],
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("creates correct regex pattern for simple path", () => {
|
|
66
|
-
const result = parseRouteKey("GET /users");
|
|
67
|
-
expect("/users").toMatch(result.pattern);
|
|
68
|
-
expect("/users/123").not.toMatch(result.pattern);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it("creates correct regex pattern with parameters", () => {
|
|
72
|
-
const result = parseRouteKey("GET /users/:id");
|
|
73
|
-
expect("/users/123").toMatch(result.pattern);
|
|
74
|
-
expect("/users/abc-def").toMatch(result.pattern);
|
|
75
|
-
expect("/users").not.toMatch(result.pattern);
|
|
76
|
-
expect("/users/").not.toMatch(result.pattern);
|
|
77
|
-
expect("/users/123/posts").not.toMatch(result.pattern);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
describe("invalid route keys", () => {
|
|
82
|
-
it("throws on missing method", () => {
|
|
83
|
-
expect(() => parseRouteKey("/users")).toThrow("Invalid route key format");
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("throws on missing path", () => {
|
|
87
|
-
expect(() => parseRouteKey("GET")).toThrow("Invalid route key format");
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("throws on invalid method", () => {
|
|
91
|
-
expect(() => parseRouteKey("INVALID /users")).toThrow(
|
|
92
|
-
"Invalid route key format",
|
|
93
|
-
);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("throws on lowercase method", () => {
|
|
97
|
-
expect(() => parseRouteKey("get /users")).toThrow(
|
|
98
|
-
"Invalid route key format",
|
|
99
|
-
);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it("throws on missing space", () => {
|
|
103
|
-
expect(() => parseRouteKey("GET/users")).toThrow(
|
|
104
|
-
"Invalid route key format",
|
|
105
|
-
);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("throws on empty string", () => {
|
|
109
|
-
expect(() => parseRouteKey("")).toThrow("Invalid route key format");
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
describe("parameter extraction", () => {
|
|
114
|
-
it("extracts matched parameters", () => {
|
|
115
|
-
const route = parseRouteKey("GET /users/:userId/posts/:postId");
|
|
116
|
-
const match = "/users/123/posts/456".match(route.pattern);
|
|
117
|
-
|
|
118
|
-
expect(match).toBeTruthy();
|
|
119
|
-
expect(match?.[1]).toBe("123");
|
|
120
|
-
expect(match?.[2]).toBe("456");
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("handles special characters in parameters", () => {
|
|
124
|
-
const route = parseRouteKey("GET /files/:filename");
|
|
125
|
-
const match = "/files/report-2023.pdf".match(route.pattern);
|
|
126
|
-
|
|
127
|
-
expect(match).toBeTruthy();
|
|
128
|
-
expect(match?.[1]).toBe("report-2023.pdf");
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("stops the param name at a literal '.' suffix and escapes the dot", () => {
|
|
132
|
-
const route = parseRouteKey("GET /files/:name.json");
|
|
133
|
-
|
|
134
|
-
expect(route.params).toEqual(["name"]);
|
|
135
|
-
expect("/files/report.json".match(route.pattern)?.[1]).toBe("report");
|
|
136
|
-
expect("/files/report.json2".match(route.pattern)).toBeNull();
|
|
137
|
-
expect("/files/reportXjson".match(route.pattern)).toBeNull();
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it("treats parens around params as literal characters", () => {
|
|
141
|
-
const route = parseRouteKey("GET /items/(:id)");
|
|
142
|
-
|
|
143
|
-
expect(route.params).toEqual(["id"]);
|
|
144
|
-
expect("/items/(42)".match(route.pattern)?.[1]).toBe("42");
|
|
145
|
-
expect("/items/42".match(route.pattern)).toBeNull();
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
});
|
package/src/parser.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { toHttpMethod } from "./constants.js";
|
|
2
|
-
import { RouteParseError } from "./errors.js";
|
|
3
|
-
import type { HttpMethod } from "./types.js";
|
|
4
|
-
|
|
5
|
-
export interface ParsedRoute {
|
|
6
|
-
method: HttpMethod;
|
|
7
|
-
path: string;
|
|
8
|
-
pattern: RegExp;
|
|
9
|
-
params: string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Parse 'METHOD /path' route key format
|
|
14
|
-
*
|
|
15
|
-
* Design note: We validate the format strictly to catch typos early.
|
|
16
|
-
* The 'METHOD /path' format was chosen for its readability and
|
|
17
|
-
* similarity to API documentation formats.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* parseRouteKey('GET /users/:id')
|
|
21
|
-
* // => { method: 'GET', path: '/users/:id', pattern: /^\/users\/([^/]+)$/, params: ['id'] }
|
|
22
|
-
*/
|
|
23
|
-
export function parseRouteKey(routeKey: string): ParsedRoute {
|
|
24
|
-
const match = routeKey.match(
|
|
25
|
-
/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS) (.+)$/,
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
if (!match) {
|
|
29
|
-
throw new RouteParseError(
|
|
30
|
-
routeKey,
|
|
31
|
-
'Expected format: "METHOD /path" (e.g., "GET /users")',
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const [, method, path] = match;
|
|
36
|
-
|
|
37
|
-
// Parameter names are restricted to [A-Za-z0-9_-] so that surrounding
|
|
38
|
-
// literals (".json", brackets, parens, etc.) terminate the name and can
|
|
39
|
-
// be escaped without bleeding into the parameter regex. Build the
|
|
40
|
-
// pattern by splitting the path on the param marker, escaping each
|
|
41
|
-
// literal segment, then substituting the capture group for each :name.
|
|
42
|
-
const params: string[] = [];
|
|
43
|
-
|
|
44
|
-
const regexPath = path
|
|
45
|
-
.split(/(:[a-zA-Z0-9_-]+)/g)
|
|
46
|
-
.map((segment) => {
|
|
47
|
-
const paramMatch = segment.match(/^:([a-zA-Z0-9_-]+)$/);
|
|
48
|
-
if (paramMatch) {
|
|
49
|
-
params.push(paramMatch[1]);
|
|
50
|
-
return "([^/]+)";
|
|
51
|
-
}
|
|
52
|
-
return segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
53
|
-
})
|
|
54
|
-
.join("");
|
|
55
|
-
|
|
56
|
-
const pattern = new RegExp(`^${regexPath}$`);
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
method: toHttpMethod(method),
|
|
60
|
-
path,
|
|
61
|
-
pattern,
|
|
62
|
-
params,
|
|
63
|
-
};
|
|
64
|
-
}
|
package/src/plugin-pipeline.ts
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { errorMessage, PluginError } from "./errors.js";
|
|
2
|
-
|
|
3
|
-
/** Structural typing — DebugLogger satisfies this without an import */
|
|
4
|
-
interface PipelineLogger {
|
|
5
|
-
log(category: string, message: string, data?: unknown): void;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
interface PipelineResult {
|
|
9
|
-
context: Schmock.PluginContext;
|
|
10
|
-
response?: unknown;
|
|
11
|
-
recoveredFromError?: boolean;
|
|
12
|
-
requestShortCircuited?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function isPluginResult(value: unknown): value is Schmock.PluginResult {
|
|
16
|
-
return (
|
|
17
|
-
typeof value === "object" &&
|
|
18
|
-
value !== null &&
|
|
19
|
-
"context" in value &&
|
|
20
|
-
typeof value.context === "object" &&
|
|
21
|
-
value.context !== null
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function recoverPluginError(
|
|
26
|
-
plugins: Schmock.Plugin[],
|
|
27
|
-
startIndex: number,
|
|
28
|
-
error: unknown,
|
|
29
|
-
context: Schmock.PluginContext,
|
|
30
|
-
logger: PipelineLogger,
|
|
31
|
-
): Promise<
|
|
32
|
-
{ handled: true; response: unknown } | { handled: false; error: Error }
|
|
33
|
-
> {
|
|
34
|
-
let currentError =
|
|
35
|
-
error instanceof Error ? error : new Error(errorMessage(error));
|
|
36
|
-
|
|
37
|
-
for (let index = startIndex; index < plugins.length; index += 1) {
|
|
38
|
-
const plugin = plugins[index];
|
|
39
|
-
if (!plugin.onError) continue;
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
const errorResult = await plugin.onError(currentError, context);
|
|
43
|
-
if (errorResult instanceof Error) {
|
|
44
|
-
currentError = errorResult;
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (errorResult !== undefined) {
|
|
48
|
-
logger.log("pipeline", `Plugin ${plugin.name} handled error`);
|
|
49
|
-
return { handled: true, response: errorResult };
|
|
50
|
-
}
|
|
51
|
-
} catch (hookError) {
|
|
52
|
-
currentError =
|
|
53
|
-
hookError instanceof Error
|
|
54
|
-
? hookError
|
|
55
|
-
: new Error(errorMessage(hookError));
|
|
56
|
-
logger.log(
|
|
57
|
-
"pipeline",
|
|
58
|
-
`Plugin ${plugin.name} error handler failed: ${errorMessage(hookError)}`,
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return { handled: false, error: currentError };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Run request guards before route code is allowed to execute. */
|
|
67
|
-
export async function runPluginBeforeRequest(
|
|
68
|
-
plugins: Schmock.Plugin[],
|
|
69
|
-
context: Schmock.PluginContext,
|
|
70
|
-
logger: PipelineLogger,
|
|
71
|
-
): Promise<PipelineResult> {
|
|
72
|
-
let currentContext = context;
|
|
73
|
-
|
|
74
|
-
for (let index = 0; index < plugins.length; index += 1) {
|
|
75
|
-
const plugin = plugins[index];
|
|
76
|
-
if (!plugin.beforeRequest) continue;
|
|
77
|
-
|
|
78
|
-
logger.log("pipeline", `Running beforeRequest: ${plugin.name}`);
|
|
79
|
-
try {
|
|
80
|
-
const result = await plugin.beforeRequest(currentContext);
|
|
81
|
-
if (result === undefined) continue;
|
|
82
|
-
if (!isPluginResult(result)) {
|
|
83
|
-
throw new Error(`Plugin ${plugin.name} didn't return valid result`);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
currentContext = result.context;
|
|
87
|
-
if (result.response !== undefined) {
|
|
88
|
-
logger.log("pipeline", `Plugin ${plugin.name} rejected request`);
|
|
89
|
-
return {
|
|
90
|
-
context: currentContext,
|
|
91
|
-
response: result.response,
|
|
92
|
-
requestShortCircuited: true,
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
} catch (error) {
|
|
96
|
-
logger.log(
|
|
97
|
-
"pipeline",
|
|
98
|
-
`Plugin ${plugin.name} beforeRequest failed: ${errorMessage(error)}`,
|
|
99
|
-
);
|
|
100
|
-
const recovery = await recoverPluginError(
|
|
101
|
-
plugins,
|
|
102
|
-
index,
|
|
103
|
-
error,
|
|
104
|
-
currentContext,
|
|
105
|
-
logger,
|
|
106
|
-
);
|
|
107
|
-
if (recovery.handled) {
|
|
108
|
-
return {
|
|
109
|
-
context: currentContext,
|
|
110
|
-
response: recovery.response,
|
|
111
|
-
recoveredFromError: true,
|
|
112
|
-
requestShortCircuited: true,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
throw new PluginError(plugin.name, recovery.error);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return { context: currentContext };
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** Give pipeline error handlers a chance to recover a route-generator error. */
|
|
123
|
-
export async function recoverGeneratorError(
|
|
124
|
-
plugins: Schmock.Plugin[],
|
|
125
|
-
context: Schmock.PluginContext,
|
|
126
|
-
error: unknown,
|
|
127
|
-
logger: PipelineLogger,
|
|
128
|
-
): Promise<PipelineResult> {
|
|
129
|
-
const recovery = await recoverPluginError(plugins, 0, error, context, logger);
|
|
130
|
-
if (recovery.handled) {
|
|
131
|
-
return {
|
|
132
|
-
context,
|
|
133
|
-
response: recovery.response,
|
|
134
|
-
recoveredFromError: true,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
throw recovery.error;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Run all registered plugins in sequence
|
|
142
|
-
* First plugin to set response becomes generator, subsequent plugins transform
|
|
143
|
-
* Handles plugin errors via onError hooks
|
|
144
|
-
*/
|
|
145
|
-
export async function runPluginPipeline(
|
|
146
|
-
plugins: Schmock.Plugin[],
|
|
147
|
-
context: Schmock.PluginContext,
|
|
148
|
-
initialResponse: unknown,
|
|
149
|
-
logger: PipelineLogger,
|
|
150
|
-
): Promise<PipelineResult> {
|
|
151
|
-
let currentContext = context;
|
|
152
|
-
let response: unknown = initialResponse;
|
|
153
|
-
|
|
154
|
-
logger.log(
|
|
155
|
-
"pipeline",
|
|
156
|
-
`Running plugin pipeline for ${plugins.length} plugins`,
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
for (let index = 0; index < plugins.length; index += 1) {
|
|
160
|
-
const plugin = plugins[index];
|
|
161
|
-
logger.log("pipeline", `Processing plugin: ${plugin.name}`);
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
const result = await plugin.process(currentContext, response);
|
|
165
|
-
|
|
166
|
-
if (!isPluginResult(result)) {
|
|
167
|
-
throw new Error(`Plugin ${plugin.name} didn't return valid result`);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
currentContext = result.context;
|
|
171
|
-
|
|
172
|
-
// First plugin to set response becomes the generator
|
|
173
|
-
if (
|
|
174
|
-
result.response !== undefined &&
|
|
175
|
-
(response === undefined || response === null)
|
|
176
|
-
) {
|
|
177
|
-
logger.log("pipeline", `Plugin ${plugin.name} generated response`);
|
|
178
|
-
response = result.response;
|
|
179
|
-
} else if (result.response !== undefined && response !== undefined) {
|
|
180
|
-
logger.log("pipeline", `Plugin ${plugin.name} transformed response`);
|
|
181
|
-
response = result.response;
|
|
182
|
-
}
|
|
183
|
-
} catch (error) {
|
|
184
|
-
logger.log(
|
|
185
|
-
"pipeline",
|
|
186
|
-
`Plugin ${plugin.name} failed: ${errorMessage(error)}`,
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
const recovery = await recoverPluginError(
|
|
190
|
-
plugins,
|
|
191
|
-
index,
|
|
192
|
-
error,
|
|
193
|
-
currentContext,
|
|
194
|
-
logger,
|
|
195
|
-
);
|
|
196
|
-
if (recovery.handled) {
|
|
197
|
-
return {
|
|
198
|
-
context: currentContext,
|
|
199
|
-
response: recovery.response,
|
|
200
|
-
recoveredFromError: true,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
throw new PluginError(plugin.name, recovery.error);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return { context: currentContext, response };
|
|
208
|
-
}
|