@api-client/core 0.3.3 → 0.3.4
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 +1 -1
- package/src/data/DataReader.ts +11 -0
- package/src/data/DataUtils.ts +108 -0
- package/src/data/JmesparthReader.ts +26 -0
- package/src/data/Json2Xml.ts +190 -0
- package/src/data/JsonReader.ts +41 -0
- package/src/data/PayloadPointer.ts +48 -0
- package/src/data/RequestDataExtractor.ts +133 -0
- package/src/data/UrlEncodedReader.ts +20 -0
- package/src/data/XmlReader.ts +103 -0
- package/src/events/BaseEvents.ts +259 -0
- package/src/events/CustomEvent.ts +27 -0
- package/src/events/EventTypes.ts +19 -0
- package/src/events/Events.ts +19 -0
- package/src/events/authorization/AuthorizationEventTypes.ts +22 -0
- package/src/events/authorization/AuthorizationEvents.ts +61 -0
- package/src/events/cookies/CookieEventTypes.ts +13 -0
- package/src/events/cookies/CookieEvents.ts +157 -0
- package/src/events/encryption/EncryptionEventTypes.ts +4 -0
- package/src/events/encryption/EncryptionEvents.ts +51 -0
- package/src/events/environment/EnvironmentEventTypes.ts +3 -0
- package/src/events/environment/EnvironmentEvents.ts +24 -0
- package/src/events/models/ClientCertificateEvents.ts +87 -0
- package/src/events/models/ModelEventTypes.ts +47 -0
- package/src/events/models/ModelEvents.ts +7 -0
- package/src/events/models/ProjectEvents.ts +331 -0
- package/src/events/process/ProcessEventTypes.ts +5 -0
- package/src/events/process/ProcessEvents.ts +76 -0
- package/src/events/readme.md +22 -0
- package/src/events/reporting/ReportingEventTypes.ts +3 -0
- package/src/events/reporting/ReportingEvents.ts +28 -0
- package/src/events/telemetry/TelemetryEventTypes.ts +10 -0
- package/src/events/telemetry/TelemetryEvents.ts +156 -0
- package/src/lib/cookies/Cookie.ts +312 -0
- package/src/lib/cookies/Cookies.ts +326 -0
- package/src/lib/cookies/Utils.ts +168 -0
- package/src/lib/headers/Headers.ts +219 -0
- package/src/lib/logging/DefaultLogger.ts +19 -0
- package/src/lib/logging/DummyLogger.ts +21 -0
- package/src/lib/logging/Logger.ts +16 -0
- package/src/lib/transformers/PayloadSerializer.ts +332 -0
- package/src/lib/transformers/Utils.ts +18 -0
- package/src/lib/uuid.ts +40 -0
- package/src/mocking/LegacyInterfaces.ts +52 -0
- package/src/mocking/LegacyMock.ts +37 -0
- package/src/mocking/legacy/Authorization.ts +39 -0
- package/src/mocking/legacy/Certificates.ts +145 -0
- package/src/mocking/legacy/Cookies.ts +51 -0
- package/src/mocking/legacy/HostRules.ts +43 -0
- package/src/mocking/legacy/Http.ts +236 -0
- package/src/mocking/legacy/HttpResponse.ts +106 -0
- package/src/mocking/legacy/RestApi.ts +68 -0
- package/src/mocking/legacy/Urls.ts +44 -0
- package/src/mocking/legacy/Variables.ts +53 -0
- package/src/models/ArcResponse.ts +166 -0
- package/src/models/Authorization.ts +481 -0
- package/src/models/AuthorizationData.ts +60 -0
- package/src/models/Backend.ts +107 -0
- package/src/models/ClientCertificate.ts +68 -0
- package/src/models/Environment.ts +279 -0
- package/src/models/ErrorResponse.ts +101 -0
- package/src/models/HistoryIndex.ts +76 -0
- package/src/models/HistoryRequest.ts +28 -0
- package/src/models/HostRule.ts +163 -0
- package/src/models/HttpCookie.ts +285 -0
- package/src/models/HttpProject.ts +1294 -0
- package/src/models/HttpProjectListItem.ts +23 -0
- package/src/models/HttpRequest.ts +124 -0
- package/src/models/HttpResponse.ts +143 -0
- package/src/models/License.ts +113 -0
- package/src/models/ProjectDefinitionProperty.ts +40 -0
- package/src/models/ProjectFolder.ts +439 -0
- package/src/models/ProjectItem.ts +135 -0
- package/src/models/ProjectParent.ts +113 -0
- package/src/models/ProjectRequest.ts +277 -0
- package/src/models/ProjectSchema.ts +202 -0
- package/src/models/Property.ts +423 -0
- package/src/models/Provider.ts +98 -0
- package/src/models/README.md +20 -0
- package/src/models/Request.ts +452 -0
- package/src/models/RequestActions.ts +163 -0
- package/src/models/RequestAuthorization.ts +115 -0
- package/src/models/RequestConfig.ts +317 -0
- package/src/models/RequestLog.ts +159 -0
- package/src/models/RequestTime.ts +108 -0
- package/src/models/RequestUiMeta.ts +258 -0
- package/src/models/RequestsSize.ts +65 -0
- package/src/models/ResponseAuthorization.ts +104 -0
- package/src/models/ResponseRedirect.ts +158 -0
- package/src/models/RevisionInfo.ts +37 -0
- package/src/models/SentRequest.ts +125 -0
- package/src/models/SerializablePayload.ts +68 -0
- package/src/models/Server.ts +153 -0
- package/src/models/Thing.ts +110 -0
- package/src/models/Url.ts +90 -0
- package/src/models/User.ts +120 -0
- package/src/models/WebApi.ts +234 -0
- package/src/models/WebApiIndex.ts +122 -0
- package/src/models/Workspace.ts +182 -0
- package/src/models/actions/Action.ts +213 -0
- package/src/models/actions/ActionView.ts +40 -0
- package/src/models/actions/Condition.ts +207 -0
- package/src/models/actions/ConditionView.ts +42 -0
- package/src/models/actions/Enums.ts +29 -0
- package/src/models/actions/RunnableAction.ts +144 -0
- package/src/models/actions/runnable/DeleteCookieAction.ts +113 -0
- package/src/models/actions/runnable/Runnable.ts +9 -0
- package/src/models/actions/runnable/SetCookieAction.ts +216 -0
- package/src/models/actions/runnable/SetVariableAction.ts +81 -0
- package/src/models/legacy/DataExport.ts +172 -0
- package/src/models/legacy/Normalizer.ts +110 -0
- package/src/models/legacy/actions/Actions.ts +269 -0
- package/src/models/legacy/authorization/Authorization.ts +572 -0
- package/src/models/legacy/models/ApiTypes.ts +202 -0
- package/src/models/legacy/models/ArcLegacyProject.ts +39 -0
- package/src/models/legacy/models/AuthData.ts +17 -0
- package/src/models/legacy/models/ClientCertificate.ts +95 -0
- package/src/models/legacy/models/Cookies.ts +52 -0
- package/src/models/legacy/models/HostRule.ts +35 -0
- package/src/models/legacy/models/RestApi.ts +49 -0
- package/src/models/legacy/models/UrlHistory.ts +37 -0
- package/src/models/legacy/models/Variable.ts +43 -0
- package/src/models/legacy/models/base.d.ts +95 -0
- package/src/models/legacy/request/ArcRequest.ts +405 -0
- package/src/models/legacy/request/ArcResponse.ts +177 -0
- package/src/models/legacy/request/HistoryData.ts +47 -0
- package/src/models/legacy/request/Legacy.ts +45 -0
- package/src/models/legacy/request/RequestBody.ts +87 -0
- package/src/models/transformers/ArcDexieTransformer.ts +323 -0
- package/src/models/transformers/ArcLegacyNormalizer.ts +85 -0
- package/src/models/transformers/ArcLegacyTransformer.ts +200 -0
- package/src/models/transformers/ArcPouchTransformer.ts +184 -0
- package/src/models/transformers/BaseTransformer.ts +116 -0
- package/src/models/transformers/ImportUtils.ts +141 -0
- package/src/models/transformers/LegacyDataExportToApiProject.ts +76 -0
- package/src/models/transformers/LegacyExportProcessor.ts +252 -0
- package/src/models/transformers/PostmanBackupTransformer.ts +306 -0
- package/src/models/transformers/PostmanDataTransformer.ts +50 -0
- package/src/models/transformers/PostmanTransformer.ts +106 -0
- package/src/models/transformers/PostmanV21Transformer.ts +311 -0
- package/src/models/transformers/PostmanV2Transformer.ts +308 -0
- package/src/models/transformers/har.ts +865 -0
- package/src/runtime/actions/ActionRunner.ts +83 -0
- package/src/runtime/actions/ConditionRunner.ts +194 -0
- package/src/runtime/actions/RunnableCondition.ts +57 -0
- package/src/runtime/actions/runnable/ActionRunnable.ts +19 -0
- package/src/runtime/actions/runnable/DeleteCookieRunnable.ts +39 -0
- package/src/runtime/actions/runnable/SetCookieRunnable.ts +92 -0
- package/src/runtime/actions/runnable/SetVariableRunnable.ts +53 -0
- package/src/runtime/http-engine/ArcEngine.ts +1064 -0
- package/src/runtime/http-engine/Errors.ts +13 -0
- package/src/runtime/http-engine/FormData.ts +85 -0
- package/src/runtime/http-engine/HttpEngine.ts +874 -0
- package/src/runtime/http-engine/HttpErrorCodes.ts +270 -0
- package/src/runtime/http-engine/NodeEngine.ts +787 -0
- package/src/runtime/http-engine/NodeEngineDirect.ts +476 -0
- package/src/runtime/http-engine/PayloadSupport.ts +84 -0
- package/src/runtime/http-engine/RequestUtils.ts +164 -0
- package/src/runtime/http-engine/ntlm/Des.ts +345 -0
- package/src/runtime/http-engine/ntlm/MD4.ts +135 -0
- package/src/runtime/http-engine/ntlm/NtlmAuth.ts +186 -0
- package/src/runtime/http-engine/ntlm/NtlmMessage.ts +57 -0
- package/src/runtime/modules/BasicAuthCache.ts +133 -0
- package/src/runtime/modules/ExecutionResponse.ts +4 -0
- package/src/runtime/modules/ModulesRegistry.ts +136 -0
- package/src/runtime/modules/RequestAuthorization.ts +110 -0
- package/src/runtime/modules/RequestCookies.ts +145 -0
- package/src/runtime/node/ProjectRunner.ts +275 -0
- package/src/runtime/node/RequestFactory.ts +422 -0
- package/src/runtime/node/VariablesStore.ts +25 -0
- package/src/runtime/store/StoreSdk.ts +838 -0
- package/src/runtime/variables/Cache.ts +53 -0
- package/src/runtime/variables/EvalFunctions.ts +132 -0
- package/src/runtime/variables/ProjectVariables.ts +6 -0
- package/src/runtime/variables/VariablesProcessor.ts +543 -0
- package/src/runtime/variables/VariablesTokenizer.ts +55 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Environment } from '../../models/Environment.js';
|
|
3
|
+
import { Logger } from '../../lib/logging/Logger.js';
|
|
4
|
+
import { IRequestLog } from '../../models/RequestLog.js';
|
|
5
|
+
import { Property } from '../../models/Property.js';
|
|
6
|
+
import { ProjectFolder, Kind as ProjectFolderKind } from '../../models/ProjectFolder.js';
|
|
7
|
+
import { ProjectRequest } from '../../models/ProjectRequest.js';
|
|
8
|
+
import { IHttpRequest } from '../../models/HttpRequest.js';
|
|
9
|
+
import { HttpProject, IProjectRequestIterator } from '../../models/HttpProject.js';
|
|
10
|
+
import { VariablesStore } from './VariablesStore.js';
|
|
11
|
+
import { VariablesProcessor } from '../variables/VariablesProcessor.js';
|
|
12
|
+
import { RequestFactory } from './RequestFactory.js';
|
|
13
|
+
import { EventTypes } from '../../events/EventTypes.js';
|
|
14
|
+
|
|
15
|
+
export interface ProjectRunnerOptions {
|
|
16
|
+
/**
|
|
17
|
+
* When provided it overrides any project / folder defined environment.
|
|
18
|
+
*/
|
|
19
|
+
environment?: Environment;
|
|
20
|
+
/**
|
|
21
|
+
* Additional variables to pass to the selected environment.
|
|
22
|
+
* This can be use to pass system variables, when needed.
|
|
23
|
+
*
|
|
24
|
+
* To use system variables tou can use `init.variables = process.env`;
|
|
25
|
+
*/
|
|
26
|
+
variables?: Record<string, string>;
|
|
27
|
+
/**
|
|
28
|
+
* Overrides the default logger (console).
|
|
29
|
+
*/
|
|
30
|
+
logger?: Logger;
|
|
31
|
+
/**
|
|
32
|
+
* The event target to use.
|
|
33
|
+
* By default it creates its own target.
|
|
34
|
+
*/
|
|
35
|
+
eventTarget?: EventTarget;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ProjectRunnerRunOptions extends IProjectRequestIterator {
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface RunResult {
|
|
42
|
+
/**
|
|
43
|
+
* The key of the request from the HttpProject that was executed.
|
|
44
|
+
*/
|
|
45
|
+
key: string;
|
|
46
|
+
/**
|
|
47
|
+
* The key of parent folder of the executed request.
|
|
48
|
+
*/
|
|
49
|
+
parent?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Set when a fatal error occurred so the request couldn't be executed.
|
|
52
|
+
* This is not the same as error reported during a request. The log's response can still be IResponseError.
|
|
53
|
+
*/
|
|
54
|
+
error?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* The error message. Always set when the `error` is `true`.
|
|
57
|
+
*/
|
|
58
|
+
errorMessage?: string;
|
|
59
|
+
/**
|
|
60
|
+
* The request log.
|
|
61
|
+
* Always set when the `error` is `false`.
|
|
62
|
+
*/
|
|
63
|
+
log?: IRequestLog;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ProjectRunner {
|
|
67
|
+
/**
|
|
68
|
+
* The request object is prepared and about to be sent to the HTTP engine
|
|
69
|
+
*/
|
|
70
|
+
on(event: 'request', listener: (key: string, request: IHttpRequest) => void): this;
|
|
71
|
+
/**
|
|
72
|
+
* The response is ready.
|
|
73
|
+
*/
|
|
74
|
+
on(event: 'response', listener: (key: string, log: IRequestLog) => void): this;
|
|
75
|
+
/**
|
|
76
|
+
* There was a general error during the request
|
|
77
|
+
*/
|
|
78
|
+
on(event: 'error', listener: (key: string, request: IHttpRequest, message: string) => void): this;
|
|
79
|
+
/**
|
|
80
|
+
* The request object is prepared and about to be sent to the HTTP engine
|
|
81
|
+
*/
|
|
82
|
+
once(event: 'request', listener: (key: string, request: IHttpRequest) => void): this;
|
|
83
|
+
/**
|
|
84
|
+
* The response is ready.
|
|
85
|
+
*/
|
|
86
|
+
once(event: 'response', listener: (key: string, log: IRequestLog) => void): this;
|
|
87
|
+
/**
|
|
88
|
+
* There was a general error during the request
|
|
89
|
+
*/
|
|
90
|
+
once(event: 'error', listener: (key: string, request: IHttpRequest, message: string) => void): this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Runs requests in a project.
|
|
95
|
+
* Developers can run the entire project with the `recursive` flag set. They can also
|
|
96
|
+
* set the starting point with the `parent` options.
|
|
97
|
+
*
|
|
98
|
+
* Requests are executed in order defined in the folder.
|
|
99
|
+
*/
|
|
100
|
+
export class ProjectRunner extends EventEmitter {
|
|
101
|
+
eventTarget: EventTarget;
|
|
102
|
+
logger?: Logger;
|
|
103
|
+
project: HttpProject;
|
|
104
|
+
|
|
105
|
+
protected masterEnvironment?: Environment;
|
|
106
|
+
protected extraVariables?: Record<string, string>;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The variables processor instance.
|
|
110
|
+
*/
|
|
111
|
+
protected variablesProcessor = new VariablesProcessor();
|
|
112
|
+
|
|
113
|
+
constructor(project: HttpProject, opts: ProjectRunnerOptions = {}) {
|
|
114
|
+
super();
|
|
115
|
+
this.project = project;
|
|
116
|
+
this.logger = opts.logger;
|
|
117
|
+
this.eventTarget = opts.eventTarget || new EventTarget();
|
|
118
|
+
this.masterEnvironment = opts.environment;
|
|
119
|
+
this.extraVariables = opts.variables;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Runs the request from the project root or a specified folder.
|
|
124
|
+
* @param options Run options.
|
|
125
|
+
* @returns A promise with the run result.
|
|
126
|
+
*/
|
|
127
|
+
async run(options?: ProjectRunnerRunOptions): Promise<RunResult[]> {
|
|
128
|
+
const { project } = this;
|
|
129
|
+
const executed: RunResult[] = [];
|
|
130
|
+
for (const request of project.requestIterator(options)) {
|
|
131
|
+
const parent = request.getParent() || project;
|
|
132
|
+
let variables: Record<string, string>;
|
|
133
|
+
if (VariablesStore.has(parent)) {
|
|
134
|
+
variables = VariablesStore.get(parent);
|
|
135
|
+
} else {
|
|
136
|
+
variables = await this.getVariables(parent);
|
|
137
|
+
VariablesStore.set(parent, variables);
|
|
138
|
+
}
|
|
139
|
+
const info = await this.execute(request, variables);
|
|
140
|
+
executed.push(info);
|
|
141
|
+
}
|
|
142
|
+
return executed;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
protected async execute(request: ProjectRequest, variables: Record<string, string>): Promise<RunResult> {
|
|
146
|
+
const config = request.getConfig();
|
|
147
|
+
const factory = new RequestFactory(this.eventTarget);
|
|
148
|
+
|
|
149
|
+
factory.variables = variables;
|
|
150
|
+
if (request.authorization) {
|
|
151
|
+
factory.authorization = request.authorization.map(i => i.toJSON());
|
|
152
|
+
}
|
|
153
|
+
if (request.actions) {
|
|
154
|
+
factory.actions = request.actions.toJSON();
|
|
155
|
+
}
|
|
156
|
+
if (request.clientCertificate) {
|
|
157
|
+
factory.certificates = [request.clientCertificate];
|
|
158
|
+
}
|
|
159
|
+
if (config.enabled !== false) {
|
|
160
|
+
factory.config = config.toJSON();
|
|
161
|
+
}
|
|
162
|
+
if (this.logger) {
|
|
163
|
+
factory.logger = this.logger;
|
|
164
|
+
}
|
|
165
|
+
const info: RunResult = {
|
|
166
|
+
key: request.key,
|
|
167
|
+
};
|
|
168
|
+
const requestData = request.expects.toJSON();
|
|
169
|
+
requestData.url = this.prepareRequestUrl(requestData.url, variables);
|
|
170
|
+
|
|
171
|
+
function variableHandler(e: CustomEvent): void {
|
|
172
|
+
if (e.defaultPrevented) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const { name, value } = e.detail;
|
|
176
|
+
variables[name] = value;
|
|
177
|
+
e.preventDefault();
|
|
178
|
+
e.detail.result = Promise.resolve();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
this.eventTarget.addEventListener(EventTypes.Environment.set, variableHandler as any);
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
// Below replaces the single call to the `run()` function of the factory to
|
|
185
|
+
// report via the events a request object that has evaluated with the Jexl library.
|
|
186
|
+
const requestCopy = await factory.processRequestVariables(requestData);
|
|
187
|
+
this.emit('request', request.key, { ...requestCopy });
|
|
188
|
+
await factory.processRequestLogic(requestCopy);
|
|
189
|
+
const result = await factory.executeRequest(requestCopy);
|
|
190
|
+
await factory.processResponse(result);
|
|
191
|
+
request.setLog(result);
|
|
192
|
+
info.log = result;
|
|
193
|
+
this.emit('response', request.key, { ...result });
|
|
194
|
+
} catch (e) {
|
|
195
|
+
info.error = true;
|
|
196
|
+
info.errorMessage = (e as Error).message;
|
|
197
|
+
this.emit('error', request.key, { ...requestData }, info.errorMessage);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
this.eventTarget.removeEventListener(EventTypes.Environment.set, variableHandler as any);
|
|
201
|
+
return info;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
protected async getVariables(parent: HttpProject | ProjectFolder): Promise<Record<string, string>> {
|
|
205
|
+
if (this.masterEnvironment) {
|
|
206
|
+
return this.applyVariables([this.masterEnvironment]);
|
|
207
|
+
}
|
|
208
|
+
return this.createEnvironment(parent);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
protected async createEnvironment(parent: HttpProject | ProjectFolder): Promise<Record<string, string>> {
|
|
212
|
+
const envs = await this.readEnvironments(parent);
|
|
213
|
+
return this.applyVariables(envs);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Reads the list of the environments to apply to this runtime.
|
|
218
|
+
*/
|
|
219
|
+
protected async readEnvironments(parent: HttpProject | ProjectFolder): Promise<Environment[]> {
|
|
220
|
+
const folderKey = parent.kind === ProjectFolderKind ? (parent as ProjectFolder).key : undefined;
|
|
221
|
+
return this.project.readEnvironments({ folderKey });
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Reads the variables and the base URI from the passed environments.
|
|
226
|
+
*/
|
|
227
|
+
protected async applyVariables(environments: Environment[]): Promise<Record<string, string>> {
|
|
228
|
+
let baseUri = '';
|
|
229
|
+
const variables: Property[] = [];
|
|
230
|
+
environments.forEach((environment) => {
|
|
231
|
+
const { server, variables: envVariables } = environment;
|
|
232
|
+
if (server) {
|
|
233
|
+
baseUri = server.readUri();
|
|
234
|
+
}
|
|
235
|
+
if (envVariables.length) {
|
|
236
|
+
envVariables.forEach((item) => {
|
|
237
|
+
const defined = variables.findIndex(i => i.name === item.name);
|
|
238
|
+
if (defined >= 0) {
|
|
239
|
+
variables[defined] = item;
|
|
240
|
+
} else {
|
|
241
|
+
variables.push(item);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
const { extraVariables } = this;
|
|
247
|
+
const ctx = VariablesProcessor.createContextFromProperties(variables);
|
|
248
|
+
if (extraVariables) {
|
|
249
|
+
Object.keys(extraVariables).forEach((key) => {
|
|
250
|
+
ctx[key] = extraVariables[key];
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
// the `baseUri` is reserved and always set to the environment's `baseUri`.
|
|
254
|
+
ctx.baseUri = baseUri || '';
|
|
255
|
+
return this.variablesProcessor.buildContext(ctx);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* When defined it applies the serve's base URI to relative URLs.
|
|
260
|
+
* @param currentUrl The URL to process.
|
|
261
|
+
*/
|
|
262
|
+
protected prepareRequestUrl(currentUrl: string, variables: Record<string, string>): string {
|
|
263
|
+
const { baseUri } = variables;
|
|
264
|
+
if (!baseUri) {
|
|
265
|
+
return currentUrl;
|
|
266
|
+
}
|
|
267
|
+
if (currentUrl.startsWith('http:') || currentUrl.startsWith('https:')) {
|
|
268
|
+
return currentUrl;
|
|
269
|
+
}
|
|
270
|
+
if (currentUrl.startsWith('/')) {
|
|
271
|
+
return `${baseUri}${currentUrl}`;
|
|
272
|
+
}
|
|
273
|
+
return `${baseUri}/${currentUrl}`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import { IRequest } from '../../models/Request.js';
|
|
2
|
+
import { IHttpRequest } from '../../models/HttpRequest.js';
|
|
3
|
+
import { IRequestConfig, IRequestBaseConfig } from '../../models/RequestConfig.js';
|
|
4
|
+
import { IRequestAuthorization } from '../../models/RequestAuthorization.js';
|
|
5
|
+
import { IRequestActions } from '../../models/RequestActions.js';
|
|
6
|
+
import { IRequestCertificate } from '../../models/ClientCertificate.js';
|
|
7
|
+
import { IRequestLog } from '../../models/RequestLog.js';
|
|
8
|
+
import { VariablesProcessor } from '../variables/VariablesProcessor.js';
|
|
9
|
+
import { IRunnableAction } from '../../models/actions/RunnableAction.js';
|
|
10
|
+
import { Action } from '../../models/actions/Action.js';
|
|
11
|
+
import { RunnableCondition } from '../actions/RunnableCondition.js';
|
|
12
|
+
import { ActionRunner } from '../actions/ActionRunner.js';
|
|
13
|
+
import { HttpEngineOptions } from '../http-engine/HttpEngine.js';
|
|
14
|
+
import { ArcEngine } from '../http-engine/ArcEngine.js';
|
|
15
|
+
import { ModulesRegistry, RegisteredRequestModule, RegisteredResponseModule, ExecutionContext, RegistryPermission } from '../modules/ModulesRegistry.js';
|
|
16
|
+
import { ExecutionResponse } from '../modules/ExecutionResponse.js';
|
|
17
|
+
import { Events } from '../../events/Events.js';
|
|
18
|
+
import { Logger } from '../../lib/logging/Logger.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The main class to make HTTP requests in the API Client / ARC.
|
|
22
|
+
* This factory includes all logic components to perform the entire HTTP request lifecycle. This includes:
|
|
23
|
+
*
|
|
24
|
+
* - variables evaluation on the request object
|
|
25
|
+
* - running request actions
|
|
26
|
+
* - running request modules
|
|
27
|
+
* - choosing the execution engine
|
|
28
|
+
* - performing the request
|
|
29
|
+
* - running response actions
|
|
30
|
+
* - running response modules
|
|
31
|
+
* - reporting the response
|
|
32
|
+
*
|
|
33
|
+
* This class may not be used when not necessary but the logic should take care of the items listed above.
|
|
34
|
+
*
|
|
35
|
+
* This class splits the `IRequest` object into it's components and use them when defined.
|
|
36
|
+
* This way it is possible to use the factory only with the `IHttpRequest` interface.
|
|
37
|
+
*/
|
|
38
|
+
export class RequestFactory {
|
|
39
|
+
/**
|
|
40
|
+
* The main events bus.
|
|
41
|
+
* This target is used to dispatch the events on.
|
|
42
|
+
* The runtime should handle the events and proxy them to the corresponding context store.
|
|
43
|
+
*/
|
|
44
|
+
eventTarget: EventTarget;
|
|
45
|
+
/**
|
|
46
|
+
* Request processing configuration.
|
|
47
|
+
*/
|
|
48
|
+
config?: IRequestConfig;
|
|
49
|
+
/**
|
|
50
|
+
* Request authorization configuration
|
|
51
|
+
*/
|
|
52
|
+
authorization?: IRequestAuthorization[];
|
|
53
|
+
/**
|
|
54
|
+
* Actions to be performed when the request is executed.
|
|
55
|
+
*/
|
|
56
|
+
actions?: IRequestActions;
|
|
57
|
+
/**
|
|
58
|
+
* The list of certificates to use with the request.
|
|
59
|
+
*/
|
|
60
|
+
certificates?: IRequestCertificate[];
|
|
61
|
+
/**
|
|
62
|
+
* The cumulative list of all variables to be applied to the request and other properties.
|
|
63
|
+
* The variables must be already processed for variables in values (evaluated).
|
|
64
|
+
*
|
|
65
|
+
* These variables are passed by reference. Changes made anywhere to the variables will result
|
|
66
|
+
* with updating this list.
|
|
67
|
+
*/
|
|
68
|
+
variables?: Record<string, string>;
|
|
69
|
+
/**
|
|
70
|
+
* The variables processor instance.
|
|
71
|
+
*/
|
|
72
|
+
variablesProcessor = new VariablesProcessor();
|
|
73
|
+
|
|
74
|
+
logger?: Logger;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Creates an instance from the IRequest object with setting the corresponding variables.
|
|
78
|
+
* @param eventTarget The main events bus.
|
|
79
|
+
* This target is used to dispatch the events on.
|
|
80
|
+
* The runtime should handle the events and proxy them to the corresponding context store.
|
|
81
|
+
* @param request The request object to use.
|
|
82
|
+
*/
|
|
83
|
+
static fromRequest(eventTarget: EventTarget, request: IRequest): RequestFactory {
|
|
84
|
+
const instance = new RequestFactory(eventTarget);
|
|
85
|
+
instance.actions = request.actions;
|
|
86
|
+
instance.authorization = request.authorization;
|
|
87
|
+
if (request.clientCertificate) {
|
|
88
|
+
instance.certificates = [request.clientCertificate];
|
|
89
|
+
}
|
|
90
|
+
instance.config = request.config;
|
|
91
|
+
return instance;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param eventTarget The main events bus.
|
|
96
|
+
* This target is used to dispatch the events on.
|
|
97
|
+
* The runtime should handle the events and proxy them to the corresponding context store.
|
|
98
|
+
*/
|
|
99
|
+
constructor(eventTarget: EventTarget) {
|
|
100
|
+
this.eventTarget = eventTarget;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Runs the request and all tasks around the HTTp request execution like gathering
|
|
105
|
+
* environment information, running actions, and HTTP modules.
|
|
106
|
+
*
|
|
107
|
+
* @param request The request object to execute.
|
|
108
|
+
* @returns The execution log.
|
|
109
|
+
*/
|
|
110
|
+
async run(request: IHttpRequest): Promise<IRequestLog> {
|
|
111
|
+
const requestCopy = await this.processRequest(request);
|
|
112
|
+
const result = await this.executeRequest(requestCopy);
|
|
113
|
+
await this.processResponse(result);
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @returns the configuration processed by the variables processor.
|
|
119
|
+
*/
|
|
120
|
+
async readConfig(): Promise<IRequestConfig | undefined> {
|
|
121
|
+
const { config, variables, variablesProcessor } = this;
|
|
122
|
+
if (!config) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
if (!variables) {
|
|
126
|
+
return config;
|
|
127
|
+
}
|
|
128
|
+
return variablesProcessor.evaluateVariablesWithContext(config, variables);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @returns the authorization data processed by the variables processor.
|
|
133
|
+
*/
|
|
134
|
+
async readAuthorization(): Promise<IRequestAuthorization[] | undefined> {
|
|
135
|
+
const { variables, authorization, variablesProcessor } = this;
|
|
136
|
+
if (!Array.isArray(authorization) || !authorization.length) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
if (!variables) {
|
|
140
|
+
return authorization;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const ps = authorization.filter(i => i.enabled !== false).map(async (item) => {
|
|
144
|
+
const copy = await variablesProcessor.evaluateVariablesWithContext(item, variables);
|
|
145
|
+
if (copy.config) {
|
|
146
|
+
copy.config = await variablesProcessor.evaluateVariablesWithContext(copy.config, variables);
|
|
147
|
+
}
|
|
148
|
+
return copy;
|
|
149
|
+
});
|
|
150
|
+
const result = await Promise.all(ps);
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @returns the actions for the passed type processed by the variables processor.
|
|
156
|
+
*/
|
|
157
|
+
async readActions(type: keyof IRequestActions): Promise<IRunnableAction[] | undefined> {
|
|
158
|
+
const { variables, actions, variablesProcessor } = this;
|
|
159
|
+
if (!actions) {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
const list = actions[type];
|
|
163
|
+
if (!Array.isArray(list) || !list.length) {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
if (!variables) {
|
|
167
|
+
return list;
|
|
168
|
+
}
|
|
169
|
+
const ps = list.filter(i => i.enabled !== false).map(async (item) => {
|
|
170
|
+
const copy = await variablesProcessor.evaluateVariablesWithContext(item, variables);
|
|
171
|
+
if (copy.condition) {
|
|
172
|
+
copy.condition = await variablesProcessor.evaluateVariablesWithContext(copy.condition, variables);
|
|
173
|
+
}
|
|
174
|
+
if (Array.isArray(copy.actions) && copy.actions.length) {
|
|
175
|
+
const actionsPs = copy.actions.map(async (action) => {
|
|
176
|
+
const actionCopy = await variablesProcessor.evaluateVariablesWithContext(action, variables);
|
|
177
|
+
if (actionCopy.config) {
|
|
178
|
+
actionCopy.config = await variablesProcessor.evaluateVariablesWithContext(actionCopy.config, variables);
|
|
179
|
+
}
|
|
180
|
+
return actionCopy;
|
|
181
|
+
});
|
|
182
|
+
copy.actions = await Promise.all(actionsPs);
|
|
183
|
+
}
|
|
184
|
+
return copy;
|
|
185
|
+
});
|
|
186
|
+
const result: IRunnableAction[] = await Promise.all(ps);
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Prepares the request object before making the HTTP request
|
|
192
|
+
* and runs actions and modules.
|
|
193
|
+
*
|
|
194
|
+
* @param request The request to execute.
|
|
195
|
+
* @returns the copy of the request object.
|
|
196
|
+
*/
|
|
197
|
+
async processRequest(request: IHttpRequest): Promise<IHttpRequest> {
|
|
198
|
+
const copy = await this.processRequestVariables(request);
|
|
199
|
+
await this.processRequestLogic(copy);
|
|
200
|
+
return copy;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Runs the request through the variables processor.
|
|
205
|
+
* @returns A copy of the passed request with possibly changed values.
|
|
206
|
+
*/
|
|
207
|
+
async processRequestVariables(request: IHttpRequest): Promise<IHttpRequest> {
|
|
208
|
+
const { variables, variablesProcessor } = this;
|
|
209
|
+
let copy: IHttpRequest = { ...request };
|
|
210
|
+
if (variables) {
|
|
211
|
+
copy = await variablesProcessor.evaluateVariablesWithContext(copy, variables);
|
|
212
|
+
}
|
|
213
|
+
return copy;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Executes the request actions and modules.
|
|
218
|
+
*/
|
|
219
|
+
async processRequestLogic(request: IHttpRequest): Promise<void> {
|
|
220
|
+
const actions = await this.readActions('request');
|
|
221
|
+
if (Array.isArray(actions) && actions.length) {
|
|
222
|
+
await this.processRequestActions(request, actions);
|
|
223
|
+
}
|
|
224
|
+
await this.processRequestModules(request);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Runs each action one by one.
|
|
229
|
+
* @param request The request object associated with actions
|
|
230
|
+
* @param actions The list of actions to execute.
|
|
231
|
+
*/
|
|
232
|
+
async processRequestActions(request: IHttpRequest, actions: IRunnableAction[]): Promise<void> {
|
|
233
|
+
const runnables = actions.filter((item) => item.enabled !== false && !!item.actions && !!item.actions.length);
|
|
234
|
+
if (!runnables.length) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
for (let i = 0, len = runnables.length; i < len; i++) {
|
|
238
|
+
const runnable = new RunnableCondition(runnables[i]);
|
|
239
|
+
const passed = await runnable.satisfied(request);
|
|
240
|
+
if (!passed) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
const execs = runnable.actions.filter(i => i.enabled !== false);
|
|
244
|
+
execs.sort(Action.sortActions);
|
|
245
|
+
for (let j = 0, eLen = execs.length; j < eLen; j++) {
|
|
246
|
+
const action = execs[j];
|
|
247
|
+
const runner = new ActionRunner(action, this.eventTarget);
|
|
248
|
+
try {
|
|
249
|
+
await runner.request(request);
|
|
250
|
+
} catch (e) {
|
|
251
|
+
if (action.failOnError) {
|
|
252
|
+
throw e;
|
|
253
|
+
} else {
|
|
254
|
+
const err = e as Error;
|
|
255
|
+
console.error(`Unable to run a request action: ${action.name || 'unknown name'}: ${err.message}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async processRequestModules(request: IHttpRequest): Promise<void> {
|
|
263
|
+
const modules = ModulesRegistry.get(ModulesRegistry.request);
|
|
264
|
+
for (const [id, main] of modules) {
|
|
265
|
+
const mod = main as RegisteredRequestModule;
|
|
266
|
+
const context = await this.buildExecutionContext(mod.permissions);
|
|
267
|
+
|
|
268
|
+
let result: number|undefined;
|
|
269
|
+
try {
|
|
270
|
+
result = await mod.fn(request, context);
|
|
271
|
+
} catch (e) {
|
|
272
|
+
// eslint-disable-next-line no-console
|
|
273
|
+
const err = e as Error;
|
|
274
|
+
console.warn(e);
|
|
275
|
+
const message = `Request module ${id} reported error: ${err.message}`;
|
|
276
|
+
throw new Error(message);
|
|
277
|
+
}
|
|
278
|
+
if (result === ExecutionResponse.ABORT) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (Array.isArray(context.certificates)) {
|
|
282
|
+
if (!Array.isArray(this.certificates)) {
|
|
283
|
+
this.certificates = [];
|
|
284
|
+
}
|
|
285
|
+
this.certificates.concat(context.certificates);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Prepares the HTTP engine configuration and executes the request,
|
|
292
|
+
* @param request The request to execute.
|
|
293
|
+
* @returns The execution log.
|
|
294
|
+
*/
|
|
295
|
+
async executeRequest(request: IHttpRequest): Promise<IRequestLog> {
|
|
296
|
+
const opts = await this.prepareEngineConfig();
|
|
297
|
+
const engine = new ArcEngine(request, opts);
|
|
298
|
+
return engine.send();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Creates a configuration options for the HTTP engine.
|
|
303
|
+
*/
|
|
304
|
+
async prepareEngineConfig(): Promise<HttpEngineOptions> {
|
|
305
|
+
const { certificates, logger } = this;
|
|
306
|
+
const auth = await this.readAuthorization();
|
|
307
|
+
const config = await this.readConfig();
|
|
308
|
+
const opts: HttpEngineOptions = {};
|
|
309
|
+
if (Array.isArray(certificates) && certificates.length) {
|
|
310
|
+
opts.certificates = certificates;
|
|
311
|
+
}
|
|
312
|
+
if (Array.isArray(auth)) {
|
|
313
|
+
opts.authorization = auth;
|
|
314
|
+
}
|
|
315
|
+
if (logger) {
|
|
316
|
+
opts.logger = logger;
|
|
317
|
+
}
|
|
318
|
+
if (!config || config.enabled === false) {
|
|
319
|
+
return opts;
|
|
320
|
+
}
|
|
321
|
+
const exclude = ['kind', 'enabled', 'ignoreSessionCookies', 'variables'];
|
|
322
|
+
(Object.keys(config) as (keyof IRequestBaseConfig)[]).forEach(key => {
|
|
323
|
+
if (exclude.includes(key)) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const value: any = config[key];
|
|
327
|
+
opts[key] = value;
|
|
328
|
+
});
|
|
329
|
+
return opts;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async processResponse(log: IRequestLog): Promise<void> {
|
|
333
|
+
const { request, response } = log;
|
|
334
|
+
if (!request || !response) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
await this.processResponseActions(log);
|
|
338
|
+
await this.processResponseModules(log);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async processResponseActions(log: IRequestLog): Promise<void> {
|
|
342
|
+
const actions = await this.readActions('response');
|
|
343
|
+
if (!Array.isArray(actions) || !actions.length) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (!log.request || !log.response) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const runnables = actions.filter((item) => item.enabled !== false && !!item.actions && !!item.actions.length);
|
|
350
|
+
if (!runnables.length) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
for (let i = 0, len = runnables.length; i < len; i++) {
|
|
354
|
+
const runnable = new RunnableCondition(runnables[i]);
|
|
355
|
+
const passed = await runnable.satisfied(log.request, log.response);
|
|
356
|
+
if (!passed) {
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
const execs = runnable.actions.filter(i => i.enabled !== false);
|
|
360
|
+
execs.sort(Action.sortActions);
|
|
361
|
+
for (let j = 0, eLen = execs.length; j < eLen; j++) {
|
|
362
|
+
const action = execs[j];
|
|
363
|
+
const runner = new ActionRunner(action, this.eventTarget);
|
|
364
|
+
try {
|
|
365
|
+
await runner.response(log);
|
|
366
|
+
} catch (e) {
|
|
367
|
+
if (action.failOnError) {
|
|
368
|
+
throw e;
|
|
369
|
+
} else {
|
|
370
|
+
const err = e as Error;
|
|
371
|
+
console.error(`Unable to run a request action: ${action.name || 'unknown name'}: ${err.message}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async processResponseModules(log: IRequestLog): Promise<void> {
|
|
379
|
+
const modules = ModulesRegistry.get(ModulesRegistry.response);
|
|
380
|
+
for (const [id, main] of modules) {
|
|
381
|
+
const mod = main as RegisteredResponseModule;
|
|
382
|
+
const context = await this.buildExecutionContext(mod.permissions);
|
|
383
|
+
|
|
384
|
+
let result: number|undefined;
|
|
385
|
+
try {
|
|
386
|
+
result = await mod.fn(log, context);
|
|
387
|
+
} catch (e) {
|
|
388
|
+
// eslint-disable-next-line no-console
|
|
389
|
+
const err = e as Error;
|
|
390
|
+
console.warn(e);
|
|
391
|
+
const message = `Response module ${id} reported error: ${err.message}`;
|
|
392
|
+
throw new Error(message);
|
|
393
|
+
}
|
|
394
|
+
if (result === ExecutionResponse.ABORT) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async buildExecutionContext(permissions: RegistryPermission[]): Promise<ExecutionContext> {
|
|
401
|
+
const result: ExecutionContext = {
|
|
402
|
+
eventsTarget: this.eventTarget,
|
|
403
|
+
};
|
|
404
|
+
const hasEnvironment = permissions.includes(RegistryPermission.environment);
|
|
405
|
+
if (hasEnvironment) {
|
|
406
|
+
result.variables = this.variables;
|
|
407
|
+
}
|
|
408
|
+
if (permissions.includes(RegistryPermission.events)) {
|
|
409
|
+
result.Events = {
|
|
410
|
+
Authorization: Events.Authorization,
|
|
411
|
+
ClientCertificate: Events.Model.ClientCertificate,
|
|
412
|
+
Cookie: Events.Cookie,
|
|
413
|
+
Encryption: Events.Encryption,
|
|
414
|
+
Process: Events.Process,
|
|
415
|
+
Environment: Events.Environment,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
result.authorization = this.authorization;
|
|
419
|
+
result.config = await this.readConfig();
|
|
420
|
+
return result;
|
|
421
|
+
}
|
|
422
|
+
}
|