@sonisoft/now-sdk-ext-core 6.6.3 → 6.8.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 +6 -0
- package/dist/comm/http/FormHtmlParser.d.ts +34 -0
- package/dist/comm/http/FormHtmlParser.js +227 -0
- package/dist/comm/http/FormHtmlParser.js.map +1 -0
- package/dist/comm/http/FormRecordModels.d.ts +120 -0
- package/dist/comm/http/FormRecordModels.js +6 -0
- package/dist/comm/http/FormRecordModels.js.map +1 -0
- package/dist/comm/http/FormRecordWriter.d.ts +99 -0
- package/dist/comm/http/FormRecordWriter.js +385 -0
- package/dist/comm/http/FormRecordWriter.js.map +1 -0
- package/dist/comm/http/HTTPRequest.d.ts +4 -0
- package/dist/comm/http/RequestHandler.d.ts +1 -0
- package/dist/comm/http/RequestHandler.js +34 -22
- package/dist/comm/http/RequestHandler.js.map +1 -1
- package/dist/comm/http/internal/FormTransportModels.d.ts +26 -0
- package/dist/comm/http/internal/FormTransportModels.js +2 -0
- package/dist/comm/http/internal/FormTransportModels.js.map +1 -0
- package/dist/exception/FormSubmitError.d.ts +13 -0
- package/dist/exception/FormSubmitError.js +19 -0
- package/dist/exception/FormSubmitError.js.map +1 -0
- package/dist/exception/WorkflowValidationError.d.ts +24 -0
- package/dist/exception/WorkflowValidationError.js +24 -0
- package/dist/exception/WorkflowValidationError.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/dist/sn/metadata/MetadataFormWriter.d.ts +13 -0
- package/dist/sn/metadata/MetadataFormWriter.js +264 -0
- package/dist/sn/metadata/MetadataFormWriter.js.map +1 -0
- package/dist/sn/metadata/MetadataModels.d.ts +44 -0
- package/dist/sn/metadata/MetadataModels.js +2 -0
- package/dist/sn/metadata/MetadataModels.js.map +1 -0
- package/dist/sn/metadata/MetadataScopeError.d.ts +5 -0
- package/dist/sn/metadata/MetadataScopeError.js +10 -0
- package/dist/sn/metadata/MetadataScopeError.js.map +1 -0
- package/dist/sn/metadata/MetadataVerificationError.d.ts +11 -0
- package/dist/sn/metadata/MetadataVerificationError.js +20 -0
- package/dist/sn/metadata/MetadataVerificationError.js.map +1 -0
- package/dist/sn/metadata/internal/MetadataPreferences.d.ts +12 -0
- package/dist/sn/metadata/internal/MetadataPreferences.js +27 -0
- package/dist/sn/metadata/internal/MetadataPreferences.js.map +1 -0
- package/dist/sn/metadata/internal/MetadataReader.d.ts +9 -0
- package/dist/sn/metadata/internal/MetadataReader.js +55 -0
- package/dist/sn/metadata/internal/MetadataReader.js.map +1 -0
- package/dist/sn/variables/VariableDefinitions.d.ts +23 -0
- package/dist/sn/variables/VariableDefinitions.js +106 -0
- package/dist/sn/variables/VariableDefinitions.js.map +1 -0
- package/dist/sn/variables/VariableModels.d.ts +49 -0
- package/dist/sn/variables/VariableModels.js +6 -0
- package/dist/sn/variables/VariableModels.js.map +1 -0
- package/dist/sn/workflow/WorkflowConversionModels.d.ts +209 -0
- package/dist/sn/workflow/WorkflowConversionModels.js +2 -0
- package/dist/sn/workflow/WorkflowConversionModels.js.map +1 -0
- package/dist/sn/workflow/WorkflowDiagramClient.d.ts +70 -0
- package/dist/sn/workflow/WorkflowDiagramClient.js +151 -0
- package/dist/sn/workflow/WorkflowDiagramClient.js.map +1 -0
- package/dist/sn/workflow/WorkflowFlowConversion.d.ts +19 -0
- package/dist/sn/workflow/WorkflowFlowConversion.js +1013 -0
- package/dist/sn/workflow/WorkflowFlowConversion.js.map +1 -0
- package/dist/sn/workflow/WorkflowFlowHints.d.ts +3 -0
- package/dist/sn/workflow/WorkflowFlowHints.js +36 -0
- package/dist/sn/workflow/WorkflowFlowHints.js.map +1 -0
- package/dist/sn/workflow/WorkflowFluentGenerator.d.ts +17 -0
- package/dist/sn/workflow/WorkflowFluentGenerator.js +348 -0
- package/dist/sn/workflow/WorkflowFluentGenerator.js.map +1 -0
- package/dist/sn/workflow/WorkflowGraphML.d.ts +39 -0
- package/dist/sn/workflow/WorkflowGraphML.js +162 -0
- package/dist/sn/workflow/WorkflowGraphML.js.map +1 -0
- package/dist/sn/workflow/WorkflowManager.d.ts +236 -6
- package/dist/sn/workflow/WorkflowManager.js +1443 -15
- package/dist/sn/workflow/WorkflowManager.js.map +1 -1
- package/dist/sn/workflow/WorkflowModels.d.ts +738 -0
- package/dist/sn/workflow/WorkflowStructure.d.ts +137 -0
- package/dist/sn/workflow/WorkflowStructure.js +368 -0
- package/dist/sn/workflow/WorkflowStructure.js.map +1 -0
- package/dist/sn/workflow/WorkflowViews.d.ts +104 -0
- package/dist/sn/workflow/WorkflowViews.js +408 -0
- package/dist/sn/workflow/WorkflowViews.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { isPolicyRefusal } from "../../policy/PolicyRefusal.js";
|
|
2
|
+
import { InvalidParameterException } from "../../exception/InvalidParameterException.js";
|
|
3
|
+
import { FormSubmitError } from "../../exception/FormSubmitError.js";
|
|
4
|
+
import { READ_ONLY } from "../../policy/PolicyTypes.js";
|
|
5
|
+
import { Logger } from "../../util/Logger.js";
|
|
6
|
+
import { redactMessage, stripSecretsFromError } from "../../util/redact.js";
|
|
7
|
+
import { parseFormHtml, parseFormMessages, parseFormResponse } from "./FormHtmlParser.js";
|
|
8
|
+
import { SessionManager } from "./SessionManager.js";
|
|
9
|
+
const NAME = /^[a-z0-9_]+$/i;
|
|
10
|
+
const SYS_ID = /^[0-9a-f]{32}$/i;
|
|
11
|
+
/** Where a successful submit lands. Small, and it echoes back the action and sys_id. */
|
|
12
|
+
const GOTO_URL = "modal_dialog_form_response.do?sysparm_returned_action=$action&sysparm_returned_sysid=$sys_id";
|
|
13
|
+
/**
|
|
14
|
+
* Writes a record through its classic UI form (`/<table>.do`), exactly as a browser does:
|
|
15
|
+
* load the form, then submit it with the form's tokens.
|
|
16
|
+
*
|
|
17
|
+
* This is a low-level tool for writing directly to an instance when the record is NOT
|
|
18
|
+
* authored in a now-sdk application. Its reason to exist is variable-backed records
|
|
19
|
+
* (any table with a glide_var column, e.g. `wf_activity.vars`): the form submit is the
|
|
20
|
+
* path that writes their `sys_variable_value` rows, where REST writes to that table run
|
|
21
|
+
* into ACLs. Records that belong in a now-sdk app (ATF tests, flows, …) should be
|
|
22
|
+
* authored there instead.
|
|
23
|
+
*
|
|
24
|
+
* Why two requests: a new record's form carries values that are not form inputs —
|
|
25
|
+
* anything set through `sysparm_query` at load time, such as the record's variable
|
|
26
|
+
* model — inside the signed `sysparm_encoded_record`. A submit without it inserts the
|
|
27
|
+
* record but silently drops every variable.
|
|
28
|
+
*
|
|
29
|
+
* Only the values you pass are posted. The instance fills in everything else the same
|
|
30
|
+
* way the form would: variable defaults on insert, current values on update.
|
|
31
|
+
*/
|
|
32
|
+
class FormTransport {
|
|
33
|
+
_logger = new Logger("FormRecordWriter");
|
|
34
|
+
_instance;
|
|
35
|
+
constructor(instance) {
|
|
36
|
+
this._instance = instance;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Load a record's form.
|
|
40
|
+
*
|
|
41
|
+
* @param table Table name
|
|
42
|
+
* @param sysId Record sys_id, or `-1` for a new record
|
|
43
|
+
* @param options View and, for new records, the initial query
|
|
44
|
+
* @throws Error when the page is not the expected form, or the record does not exist
|
|
45
|
+
*/
|
|
46
|
+
async loadForm(table, sysId = "-1", options = {}) {
|
|
47
|
+
this.requireTable(table);
|
|
48
|
+
if (sysId !== "-1" && !SYS_ID.test(sysId)) {
|
|
49
|
+
throw new InvalidParameterException("sysId must be -1 or a 32-character sys_id");
|
|
50
|
+
}
|
|
51
|
+
const query = { ...options.query, sys_id: sysId };
|
|
52
|
+
if (options.view)
|
|
53
|
+
query.sysparm_view = options.view;
|
|
54
|
+
if (options.initialQuery)
|
|
55
|
+
query.sysparm_query = options.initialQuery;
|
|
56
|
+
try {
|
|
57
|
+
const response = await this.request().get({
|
|
58
|
+
method: "GET", path: `/${table}.do`, headers: null, body: null, query,
|
|
59
|
+
requires: READ_ONLY, responseFormat: "text", sensitive: options.sensitive,
|
|
60
|
+
...(options.sensitive ? { redirect: "manual" } : {}),
|
|
61
|
+
});
|
|
62
|
+
const snapshot = parseFormHtml(this.text(response.data), table, options);
|
|
63
|
+
if (sysId !== "-1" && (snapshot.isNewRecord || snapshot.sysId !== sysId)) {
|
|
64
|
+
throw new Error(`Record ${table}/${sysId} was not found or is not readable`);
|
|
65
|
+
}
|
|
66
|
+
return snapshot;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (options.sensitive && !isPolicyRefusal(error) && !(error instanceof FormSubmitError)) {
|
|
70
|
+
const code = error instanceof Error && ["csrf_token_unavailable", "csrf_rejected"].includes(error.message) ? error.message : "Form request failed";
|
|
71
|
+
throw new Error(code);
|
|
72
|
+
}
|
|
73
|
+
throw this.sanitizeError(error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Submit a form you already loaded. Use this to inspect the form's variables (names,
|
|
78
|
+
* types, choices) before deciding what to write.
|
|
79
|
+
*/
|
|
80
|
+
async submit(snapshot, action, options = {}) {
|
|
81
|
+
const table = snapshot.table;
|
|
82
|
+
let posted;
|
|
83
|
+
try {
|
|
84
|
+
posted = this.buildFields(snapshot, options);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (options.sensitive)
|
|
88
|
+
throw new InvalidParameterException("Invalid form field or variable value");
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const session = (await this.request().getUserSession());
|
|
93
|
+
if (options.tokenSource === "page" ? !snapshot.pageToken : !session?.userToken) {
|
|
94
|
+
throw new Error("An authenticated ServiceNow session token is required to submit a form");
|
|
95
|
+
}
|
|
96
|
+
const fields = {
|
|
97
|
+
...(options.postAllRenderedInputs ? snapshot.renderedInputs : {}),
|
|
98
|
+
sys_target: table,
|
|
99
|
+
sys_uniqueName: "sys_id",
|
|
100
|
+
sys_uniqueValue: snapshot.sysId,
|
|
101
|
+
sys_row: snapshot.isNewRecord ? "-1" : "0",
|
|
102
|
+
sys_modCount: snapshot.modCount,
|
|
103
|
+
onLoad_sys_updated_on: snapshot.updatedOn,
|
|
104
|
+
sys_action: options.actionValue ?? snapshot.actions[action] ?? action,
|
|
105
|
+
sysparm_ck: options.tokenSource === "page" ? snapshot.pageToken : session.userToken,
|
|
106
|
+
sysparm_encoded_record: snapshot.encodedRecord,
|
|
107
|
+
sysparm_goto_url: GOTO_URL,
|
|
108
|
+
isFormPage: "true",
|
|
109
|
+
...(options.view ? { sysparm_view: options.view } : {}),
|
|
110
|
+
...posted,
|
|
111
|
+
...options.extraFields,
|
|
112
|
+
};
|
|
113
|
+
this._logger.info(`Submitting ${action} for ${table}/${snapshot.sysId}`);
|
|
114
|
+
const response = await this.request().post({
|
|
115
|
+
method: "POST", path: `/${table}.do`, headers: null, query: null, body: null,
|
|
116
|
+
fields, responseFormat: "text", redirect: options.redirect, sensitive: options.sensitive,
|
|
117
|
+
});
|
|
118
|
+
if (options.landing === "guarded") {
|
|
119
|
+
return await this.guardedLanding(snapshot, action, response.status, response.headers, this.text(response.data), fields);
|
|
120
|
+
}
|
|
121
|
+
const html = this.text(response.data);
|
|
122
|
+
const accepted = parseFormResponse(html);
|
|
123
|
+
const messages = parseFormMessages(html);
|
|
124
|
+
if (!accepted || accepted.action !== action) {
|
|
125
|
+
throw new FormSubmitError(table, `The ${table} form submit was not accepted`, messages.errors);
|
|
126
|
+
}
|
|
127
|
+
return { sysId: accepted.sysId, action, messages: messages.info };
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (options.sensitive && !isPolicyRefusal(error) && !(error instanceof FormSubmitError)) {
|
|
131
|
+
const code = error instanceof Error && ["csrf_token_unavailable", "csrf_rejected"].includes(error.message) ? error.message : "Form request failed";
|
|
132
|
+
throw new Error(code);
|
|
133
|
+
}
|
|
134
|
+
throw this.sanitizeError(error);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Validate caller values without submitting the form. */
|
|
138
|
+
validate(snapshot, options) {
|
|
139
|
+
try {
|
|
140
|
+
this.buildFields(snapshot, options);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
throw new InvalidParameterException("Invalid form field or variable value");
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Turn caller values into posted form parameters, validating variables against the
|
|
148
|
+
* form so a misspelt element fails loudly instead of being silently ignored.
|
|
149
|
+
*/
|
|
150
|
+
buildFields(snapshot, options) {
|
|
151
|
+
const table = snapshot.table;
|
|
152
|
+
const out = {};
|
|
153
|
+
for (const [field, value] of Object.entries(options.fields ?? {})) {
|
|
154
|
+
if (!NAME.test(field))
|
|
155
|
+
throw new InvalidParameterException(`Invalid field name '${field}'`);
|
|
156
|
+
const name = `${table}.${field}`;
|
|
157
|
+
out[name] = encodeFormValue(value, snapshot.fields[name]);
|
|
158
|
+
}
|
|
159
|
+
const values = Object.entries(options.variables ?? {});
|
|
160
|
+
if (values.length) {
|
|
161
|
+
const available = this.variablesFor(snapshot, options.variableField);
|
|
162
|
+
for (const [element, value] of values) {
|
|
163
|
+
const control = available[element];
|
|
164
|
+
if (!control) {
|
|
165
|
+
const known = Object.keys(available).sort().join(", ") || "(none)";
|
|
166
|
+
throw new InvalidParameterException(`Unknown variable '${element}' on the ${table} form. Available: ${known}`);
|
|
167
|
+
}
|
|
168
|
+
out[control.name] = encodeFormValue(value, control);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
173
|
+
variablesFor(snapshot, field) {
|
|
174
|
+
const all = Object.values(snapshot.variables);
|
|
175
|
+
const columns = [...new Set(all.map(v => v.field))];
|
|
176
|
+
if (!columns.length) {
|
|
177
|
+
throw new InvalidParameterException(`The ${snapshot.table} form has no variables`);
|
|
178
|
+
}
|
|
179
|
+
const column = field ?? (columns.length === 1 ? columns[0] : undefined);
|
|
180
|
+
if (!column || !columns.includes(column)) {
|
|
181
|
+
throw new InvalidParameterException(`Specify variableField for the ${snapshot.table} form; it has variables on: ${columns.join(", ")}`);
|
|
182
|
+
}
|
|
183
|
+
return Object.fromEntries(all.filter(v => v.field === column).map(v => [v.element, v]));
|
|
184
|
+
}
|
|
185
|
+
async requireExists(table, sysId) {
|
|
186
|
+
const read = () => this.request().get({
|
|
187
|
+
method: "GET", path: `/api/now/table/${table}`, headers: { Accept: "application/json" }, body: null,
|
|
188
|
+
query: { sysparm_query: `sys_id=${sysId}`, sysparm_fields: "sys_id", sysparm_limit: "1" },
|
|
189
|
+
});
|
|
190
|
+
let response = await read();
|
|
191
|
+
// 202: the instance queued the request behind others in this session; ask again.
|
|
192
|
+
for (let attempt = 1; response?.status === 202 && attempt <= 3; attempt++) {
|
|
193
|
+
await new Promise(resolve => setTimeout(resolve, 500 * attempt));
|
|
194
|
+
response = await read();
|
|
195
|
+
}
|
|
196
|
+
if (response?.status !== 200) {
|
|
197
|
+
// The insert was reported; only the check failed. Say so, so nobody inserts again.
|
|
198
|
+
throw new FormSubmitError(table, `The ${table} form reported inserting record ${sysId}, `
|
|
199
|
+
+ `but checking that it exists failed (status ${response?.status ?? "unknown"})`);
|
|
200
|
+
}
|
|
201
|
+
if (!response.bodyObject?.result?.length) {
|
|
202
|
+
throw new FormSubmitError(table, `The ${table} form reported an insert, but record ${sysId} does not exist`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async guardedLanding(snapshot, action, status, headers, html, fields) {
|
|
206
|
+
const session = await this.request().getUserSession();
|
|
207
|
+
const withheld = new Set([...Object.values(fields), session.userToken ?? "",
|
|
208
|
+
...(session.cookie?.getCookiesSync(String(session.instanceUrl)) ?? []).map(cookie => cookie.value)]);
|
|
209
|
+
for (const value of [...withheld])
|
|
210
|
+
for (const line of value.split(/[\r\n]+/))
|
|
211
|
+
if (line)
|
|
212
|
+
withheld.add(line);
|
|
213
|
+
const clean = (text) => {
|
|
214
|
+
text = text.replace(/\s+/g, " ").trim();
|
|
215
|
+
for (const value of [...withheld].filter(Boolean).sort((a, b) => b.length - a.length)) {
|
|
216
|
+
text = text.split(value.replace(/\s+/g, " ").trim()).join("[redacted]");
|
|
217
|
+
text = text.split(encodeURIComponent(value)).join("[redacted]");
|
|
218
|
+
}
|
|
219
|
+
text = redactMessage(text).replace(/https?:\/\/\S+/g, "[url]").replace(/[A-Za-z0-9_+/=.-]{24,}/g, "[redacted]");
|
|
220
|
+
return /(?:Class\.create|\.prototype|function\s*\(|[{};]|<script)/i.test(text)
|
|
221
|
+
? "[message withheld: script content]" : text.slice(0, 200);
|
|
222
|
+
};
|
|
223
|
+
const messages = parseFormMessages(html);
|
|
224
|
+
const location = headers.location ?? headers.Location;
|
|
225
|
+
if (status >= 300 && status < 400 && location) {
|
|
226
|
+
const origin = new URL(String(session.instanceUrl));
|
|
227
|
+
const url = new URL(location, origin);
|
|
228
|
+
if (url.pathname === "/security_interceptor.do")
|
|
229
|
+
throw new Error("csrf_rejected");
|
|
230
|
+
const allowed = new Set(["sys_id", "sysparm_transaction_scope", "sysparm_isdevstudio", "sysparm_nameofstack", "sysparm_view", "sysparm_referring_url"]);
|
|
231
|
+
const unexpectedDestination = url.origin !== origin.origin || url.username || url.password || url.hash ||
|
|
232
|
+
url.pathname !== `/${snapshot.table}.do`;
|
|
233
|
+
const parameters = [...url.searchParams.keys()];
|
|
234
|
+
const unexpectedParameters = parameters.some(key => !allowed.has(key) || url.searchParams.getAll(key).length !== 1);
|
|
235
|
+
const unexpectedScope = url.searchParams.has("sysparm_transaction_scope") &&
|
|
236
|
+
url.searchParams.get("sysparm_transaction_scope") !== fields.sysparm_transaction_scope;
|
|
237
|
+
const unexpectedRecord = !url.searchParams.has("sys_id") ||
|
|
238
|
+
![snapshot.sysId, "-1"].includes(url.searchParams.get("sys_id"));
|
|
239
|
+
if (unexpectedDestination || unexpectedParameters || unexpectedScope || unexpectedRecord) {
|
|
240
|
+
throw new FormSubmitError(snapshot.table, "Unexpected form redirect");
|
|
241
|
+
}
|
|
242
|
+
const landing = await this.request().get({ path: url.pathname,
|
|
243
|
+
query: Object.fromEntries(url.searchParams), headers: null, body: null,
|
|
244
|
+
requires: READ_ONLY, responseFormat: "text", sensitive: true, redirect: "manual" });
|
|
245
|
+
if (landing.status >= 300)
|
|
246
|
+
throw new FormSubmitError(snapshot.table, "Unexpected landing redirect");
|
|
247
|
+
const parsed = parseFormMessages(this.text(landing.data));
|
|
248
|
+
messages.errors.push(...parsed.errors);
|
|
249
|
+
messages.info.push(...parsed.info);
|
|
250
|
+
}
|
|
251
|
+
return { sysId: snapshot.sysId, action, messages: messages.info.map(clean), errors: messages.errors.map(clean) };
|
|
252
|
+
}
|
|
253
|
+
request() {
|
|
254
|
+
// One session for the form load, the submit and the follow-up read: the submit's
|
|
255
|
+
// token must belong to the session that loaded the form.
|
|
256
|
+
return SessionManager.getInstance().getRequest(this._instance);
|
|
257
|
+
}
|
|
258
|
+
requireTable(table) {
|
|
259
|
+
if (!table || !NAME.test(table))
|
|
260
|
+
throw new InvalidParameterException("A valid table name is required");
|
|
261
|
+
}
|
|
262
|
+
text(data) {
|
|
263
|
+
return typeof data === "string" ? data : "";
|
|
264
|
+
}
|
|
265
|
+
sanitizeError(error) {
|
|
266
|
+
if (error instanceof Error)
|
|
267
|
+
error.message = redactMessage(error.message);
|
|
268
|
+
return stripSecretsFromError(error);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/** Shared internal transport. Excluded from the package barrel. */
|
|
272
|
+
export function createFormTransport(instance) {
|
|
273
|
+
return new FormTransport(instance);
|
|
274
|
+
}
|
|
275
|
+
/** Write ordinary records through classic forms with the established defaults. */
|
|
276
|
+
export class FormRecordWriter {
|
|
277
|
+
_transport;
|
|
278
|
+
constructor(instance) { this._transport = createFormTransport(instance); }
|
|
279
|
+
loadForm(table, sysId = "-1", options = {}) {
|
|
280
|
+
return this._transport.loadForm(table, sysId, options);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Insert a record through its form.
|
|
284
|
+
*
|
|
285
|
+
* @param table Table name
|
|
286
|
+
* @param options Field values, variable values, view and initial query
|
|
287
|
+
* @returns The new record's sys_id and any info messages
|
|
288
|
+
* @throws InvalidParameterException for unknown variables or invalid choice values
|
|
289
|
+
* @throws FormSubmitError when the instance does not accept the submit
|
|
290
|
+
*/
|
|
291
|
+
async insert(table, options = {}) {
|
|
292
|
+
const snapshot = await this.loadForm(table, "-1", options);
|
|
293
|
+
const result = await this.submit(snapshot, "sysverb_insert", options);
|
|
294
|
+
await this._transport.requireExists(table, result.sysId);
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Update a record through its form. Fields and variables you do not pass keep their
|
|
299
|
+
* current values.
|
|
300
|
+
*
|
|
301
|
+
* @param table Table name
|
|
302
|
+
* @param sysId Record sys_id
|
|
303
|
+
* @param options Field values, variable values and view
|
|
304
|
+
* @throws InvalidParameterException for unknown variables or invalid choice values
|
|
305
|
+
* @throws FormSubmitError when the instance does not accept the submit
|
|
306
|
+
*/
|
|
307
|
+
async update(table, sysId, options = {}) {
|
|
308
|
+
if (!SYS_ID.test(sysId ?? ""))
|
|
309
|
+
throw new InvalidParameterException("sysId must be a 32-character sys_id");
|
|
310
|
+
const snapshot = await this.loadForm(table, sysId, { view: options.view });
|
|
311
|
+
return await this.submit(snapshot, "sysverb_update", options);
|
|
312
|
+
}
|
|
313
|
+
async submit(snapshot, action, options = {}) {
|
|
314
|
+
return await this._transport.submit(snapshot, action, options);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Encode a caller value the way the form posts it.
|
|
319
|
+
*
|
|
320
|
+
* @param value The caller's value
|
|
321
|
+
* @param control The form control it is going to, when known (drives duration and choice handling)
|
|
322
|
+
*/
|
|
323
|
+
export function encodeFormValue(value, control) {
|
|
324
|
+
if (value === null || value === undefined)
|
|
325
|
+
return "";
|
|
326
|
+
if (Array.isArray(value))
|
|
327
|
+
return value.join(",");
|
|
328
|
+
if (typeof value === "boolean")
|
|
329
|
+
return value ? "true" : "false";
|
|
330
|
+
if (control?.type === "glide_duration")
|
|
331
|
+
return encodeDuration(value);
|
|
332
|
+
if (typeof value === "object") {
|
|
333
|
+
throw new InvalidParameterException(`An object value is only valid for a duration field (${control?.name ?? "unknown field"})`);
|
|
334
|
+
}
|
|
335
|
+
const text = String(value);
|
|
336
|
+
if (control?.choices?.length)
|
|
337
|
+
return resolveChoice(text, control);
|
|
338
|
+
return text;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Durations post in the form's display format, `D HH:MM:SS`. The stored format
|
|
342
|
+
* (`1970-01-03 01:02:03`) and plain seconds are not understood by the form, so both are
|
|
343
|
+
* converted here.
|
|
344
|
+
*/
|
|
345
|
+
export function encodeDuration(value) {
|
|
346
|
+
let total;
|
|
347
|
+
if (typeof value === "number") {
|
|
348
|
+
total = value;
|
|
349
|
+
}
|
|
350
|
+
else if (typeof value === "object") {
|
|
351
|
+
total = ((value.days ?? 0) * 86400) + ((value.hours ?? 0) * 3600) + ((value.minutes ?? 0) * 60) + (value.seconds ?? 0);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
const text = value.trim();
|
|
355
|
+
if (text === "")
|
|
356
|
+
return "";
|
|
357
|
+
const stored = /^1970-01-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/.exec(text);
|
|
358
|
+
if (stored) {
|
|
359
|
+
total = ((Number(stored[1]) - 1) * 86400) + (Number(stored[2]) * 3600) + (Number(stored[3]) * 60) + Number(stored[4]);
|
|
360
|
+
}
|
|
361
|
+
else if (/^\d+$/.test(text)) {
|
|
362
|
+
total = Number(text);
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
return text;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (!Number.isFinite(total) || total < 0)
|
|
369
|
+
throw new InvalidParameterException(`Invalid duration: ${JSON.stringify(value)}`);
|
|
370
|
+
total = Math.floor(total);
|
|
371
|
+
const days = Math.floor(total / 86400);
|
|
372
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
373
|
+
return `${days} ${pad(Math.floor((total % 86400) / 3600))}:${pad(Math.floor((total % 3600) / 60))}:${pad(total % 60)}`;
|
|
374
|
+
}
|
|
375
|
+
function resolveChoice(text, control) {
|
|
376
|
+
const choices = control.choices;
|
|
377
|
+
if (choices.some(c => c.value === text))
|
|
378
|
+
return text;
|
|
379
|
+
const byLabel = choices.find(c => c.label.toLowerCase() === text.toLowerCase());
|
|
380
|
+
if (byLabel)
|
|
381
|
+
return byLabel.value;
|
|
382
|
+
const allowed = choices.map(c => (c.value === "" ? `'' (${c.label})` : c.value)).join(", ");
|
|
383
|
+
throw new InvalidParameterException(`'${text}' is not a choice for ${control.name}. Allowed: ${allowed}`);
|
|
384
|
+
}
|
|
385
|
+
//# sourceMappingURL=FormRecordWriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormRecordWriter.js","sourceRoot":"","sources":["../../../src/comm/http/FormRecordWriter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAYvF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,IAAI,GAAG,eAAe,CAAC;AAC7B,MAAM,MAAM,GAAG,iBAAiB,CAAC;AAEjC,wFAAwF;AACxF,MAAM,QAAQ,GAAG,8FAA8F,CAAC;AAEhH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,aAAa;IACP,OAAO,GAAW,IAAI,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACjD,SAAS,CAAqB;IAEtC,YAAmB,QAA4B;QAC3C,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC9B,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,QAAgB,IAAI,EAAE,UAAoC,EAAE;QAC7F,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,yBAAyB,CAAC,2CAA2C,CAAC,CAAC;QACrF,CAAC;QAED,MAAM,KAAK,GAA2B,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAC1E,IAAI,OAAO,CAAC,IAAI;YAAE,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;QACpD,IAAI,OAAO,CAAC,YAAY;YAAE,KAAK,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;QAErE,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAS;gBAC9C,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,KAAK,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK;gBACrE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS;gBACzE,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChE,CAAC,CAAC;YACH,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YACzE,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,QAAQ,CAAC,KAAK,KAAK,KAAK,CAAC,EAAE,CAAC;gBACvE,MAAM,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,KAAK,mCAAmC,CAAC,CAAC;YACjF,CAAC;YACD,OAAO,QAAQ,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,YAAY,eAAe,CAAC,EAAE,CAAC;gBACtF,MAAM,IAAI,GAAG,KAAK,YAAY,KAAK,IAAI,CAAC,wBAAwB,EAAE,eAAe,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;gBACnJ,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YACD,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,MAAM,CACf,QAA+B,EAC/B,MAAc,EACd,UAAsC,EAAE;QAExC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QAC7B,IAAI,MAA8B,CAAC;QACnC,IAAI,CAAC;YAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACjE,IAAI,OAAO,CAAC,SAAS;gBAAE,MAAM,IAAI,yBAAyB,CAAC,sCAAsC,CAAC,CAAC;YACnG,MAAM,KAAK,CAAC;QAChB,CAAC;QAED,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,cAAc,EAAE,CAAuC,CAAC;YAC9F,IAAI,OAAO,CAAC,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;gBAC7E,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;YAC9F,CAAC;YACD,MAAM,MAAM,GAA2B;gBACnC,GAAG,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjE,UAAU,EAAE,KAAK;gBACjB,cAAc,EAAE,QAAQ;gBACxB,eAAe,EAAE,QAAQ,CAAC,KAAK;gBAC/B,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG;gBAC1C,YAAY,EAAE,QAAQ,CAAC,QAAQ;gBAC/B,qBAAqB,EAAE,QAAQ,CAAC,SAAS;gBACzC,UAAU,EAAE,OAAO,CAAC,WAAW,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM;gBACrE,UAAU,EAAE,OAAO,CAAC,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS;gBACnF,sBAAsB,EAAE,QAAQ,CAAC,aAAa;gBAC9C,gBAAgB,EAAE,QAAQ;gBAC1B,UAAU,EAAE,MAAM;gBAClB,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,GAAG,MAAM;gBACT,GAAG,OAAO,CAAC,WAAW;aACzB,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;YACzE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAS;gBAC/C,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;gBAC5E,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS;aAC3F,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAChC,OAAO,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAC9D,QAAQ,CAAC,OAAiC,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;YACtF,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC1C,MAAM,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,KAAK,+BAA+B,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YACnG,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,YAAY,eAAe,CAAC,EAAE,CAAC;gBACtF,MAAM,IAAI,GAAG,KAAK,YAAY,KAAK,IAAI,CAAC,wBAAwB,EAAE,eAAe,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;gBACnJ,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YACD,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;IAED,0DAA0D;IACnD,QAAQ,CAAC,QAAsB,EAAE,OAAyB;QAC7D,IAAI,CAAC;YAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAAC,CAAC;QAC5C,MAAM,CAAC;YAAC,MAAM,IAAI,yBAAyB,CAAC,sCAAsC,CAAC,CAAC;QAAC,CAAC;IAC1F,CAAC;IAED;;;OAGG;IACK,WAAW,CAAC,QAAsB,EAAE,OAAyB;QACjE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QAC7B,MAAM,GAAG,GAA2B,EAAE,CAAC;QAEvC,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;YAChE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,MAAM,IAAI,yBAAyB,CAAC,uBAAuB,KAAK,GAAG,CAAC,CAAC;YAC5F,MAAM,IAAI,GAAG,GAAG,KAAK,IAAI,KAAK,EAAE,CAAC;YACjC,GAAG,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QACvD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;YACrE,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;gBACpC,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;gBACnC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACX,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;oBACnE,MAAM,IAAI,yBAAyB,CAAC,qBAAqB,OAAO,YAAY,KAAK,qBAAqB,KAAK,EAAE,CAAC,CAAC;gBACnH,CAAC;gBACD,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACxD,CAAC;QACL,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAEO,YAAY,CAAC,QAAsB,EAAE,KAAc;QACvD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,IAAI,yBAAyB,CAAC,OAAO,QAAQ,CAAC,KAAK,wBAAwB,CAAC,CAAC;QACvF,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACxE,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,yBAAyB,CAC/B,iCAAiC,QAAQ,CAAC,KAAK,+BAA+B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5G,CAAC;QACD,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5F,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,KAAa;QACnD,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAyC;YAC1E,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI;YACnG,KAAK,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,EAAE;SAC5F,CAAC,CAAC;QACH,IAAI,QAAQ,GAAG,MAAM,IAAI,EAAE,CAAC;QAC5B,iFAAiF;QACjF,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,GAAG,IAAI,OAAO,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;YACxE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;YACjE,QAAQ,GAAG,MAAM,IAAI,EAAE,CAAC;QAC5B,CAAC;QACD,IAAI,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;YAC3B,mFAAmF;YACnF,MAAM,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,KAAK,mCAAmC,KAAK,IAAI;kBACnF,8CAA8C,QAAQ,EAAE,MAAM,IAAI,SAAS,GAAG,CAAC,CAAC;QAC1F,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YACvC,MAAM,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,KAAK,wCAAwC,KAAK,iBAAiB,CAAC,CAAC;QACjH,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,QAAsB,EAAE,MAAc,EAAE,MAAc,EAC/E,OAA+B,EAAE,IAAY,EAAE,MAA8B;QAC7E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,cAAc,EACqB,CAAC;QACzE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;YACvE,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzG,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC;YAAE,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;gBAAE,IAAI,IAAI;oBAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3G,MAAM,KAAK,GAAG,CAAC,IAAY,EAAU,EAAE;YACnC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YACxC,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;gBACpF,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBACxE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACpE,CAAC;YACD,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,yBAAyB,EAAE,YAAY,CAAC,CAAC;YAChH,OAAO,4DAA4D,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC1E,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACpE,CAAC,CAAC;QACF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;QACtD,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;YACpD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACtC,IAAI,GAAG,CAAC,QAAQ,KAAK,0BAA0B;gBAAE,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;YAClF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,cAAc,EAAE,uBAAuB,CAAC,CAAC,CAAC;YACxJ,MAAM,qBAAqB,GAAG,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,IAAI;gBAClG,GAAG,CAAC,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC;YAC7C,MAAM,UAAU,GAAG,CAAC,GAAG,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;YAChD,MAAM,oBAAoB,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;YACpH,MAAM,eAAe,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC;gBACrE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,KAAK,MAAM,CAAC,yBAAyB,CAAC;YAC3F,MAAM,gBAAgB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC;gBACpD,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;YACrE,IAAI,qBAAqB,IAAI,oBAAoB,IAAI,eAAe,IAAI,gBAAgB,EAAE,CAAC;gBACvF,MAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;YAC1E,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAS,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ;gBACjE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;gBACtE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;YACxF,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG;gBAAE,MAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;YACpG,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1D,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;IACrH,CAAC;IAEO,OAAO;QACX,iFAAiF;QACjF,yDAAyD;QACzD,OAAO,cAAc,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACnE,CAAC;IAEO,YAAY,CAAC,KAAa;QAC9B,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,yBAAyB,CAAC,gCAAgC,CAAC,CAAC;IAC3G,CAAC;IAEO,IAAI,CAAC,IAAa;QACtB,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAChD,CAAC;IAEO,aAAa,CAAI,KAAQ;QAC7B,IAAI,KAAK,YAAY,KAAK;YAAE,KAAK,CAAC,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzE,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC;CACJ;AAED,mEAAmE;AACnE,MAAM,UAAU,mBAAmB,CAAC,QAA4B;IAC5D,OAAO,IAAI,aAAa,CAAC,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED,kFAAkF;AAClF,MAAM,OAAO,gBAAgB;IACjB,UAAU,CAAgB;IAClC,YAAmB,QAA4B,IAAI,IAAI,CAAC,UAAU,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9F,QAAQ,CAAC,KAAa,EAAE,KAAK,GAAG,IAAI,EAAE,UAA2B,EAAE;QACtE,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC;IACD;;;;;;;;OAQG;IACI,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,UAA4B,EAAE;QAC7D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;QACtE,MAAM,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QACzD,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;;;;;;;OASG;IACI,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,KAAa,EAAE,UAA4B,EAAE;QAC5E,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YAAE,MAAM,IAAI,yBAAyB,CAAC,qCAAqC,CAAC,CAAC;QAC1G,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3E,OAAO,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAClE,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,QAAsB,EAAE,MAA2C,EACnF,UAA4B,EAAE;QAC9B,OAAO,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAoB,CAAC;IACtF,CAAC;CACJ;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAqB,EAAE,OAAqB;IACxE,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjD,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAEhE,IAAI,OAAO,EAAE,IAAI,KAAK,gBAAgB;QAAE,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC;IACrE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,yBAAyB,CAAC,uDAAuD,OAAO,EAAE,IAAI,IAAI,eAAe,GAAG,CAAC,CAAC;IACpI,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,OAAO,EAAE,OAAO,EAAE,MAAM;QAAE,OAAO,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAClE,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0C;IACrE,IAAI,KAAa,CAAC;IAClB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC5B,KAAK,GAAG,KAAK,CAAC;IAClB,CAAC;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACnC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IAC3H,CAAC;SAAM,CAAC;QACJ,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC1B,IAAI,IAAI,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,2CAA2C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtE,IAAI,MAAM,EAAE,CAAC;YACT,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1H,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACJ,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,MAAM,IAAI,yBAAyB,CAAC,qBAAqB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC5H,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9D,OAAO,GAAG,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC;AAC3H,CAAC;AAED,SAAS,aAAa,CAAC,IAAY,EAAE,OAAoB;IACrD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACrD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAChF,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC;IAClC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5F,MAAM,IAAI,yBAAyB,CAAC,IAAI,IAAI,yBAAyB,OAAO,CAAC,IAAI,cAAc,OAAO,EAAE,CAAC,CAAC;AAC9G,CAAC"}
|
|
@@ -9,6 +9,10 @@ export interface HTTPRequest {
|
|
|
9
9
|
json?: object | null;
|
|
10
10
|
/** Keep successful HTML/XML responses as text without attempting JSON parsing. */
|
|
11
11
|
responseFormat?: "json" | "text";
|
|
12
|
+
/** Opt in to returning redirects to the caller. Defaults to fetch's follow behavior. */
|
|
13
|
+
redirect?: "follow" | "manual";
|
|
14
|
+
/** Exclude payloads, query values and raw errors from request diagnostics. */
|
|
15
|
+
sensitive?: boolean;
|
|
12
16
|
/**
|
|
13
17
|
* What permission this request needs, when the HTTP verb would get it wrong.
|
|
14
18
|
*
|
|
@@ -67,5 +67,6 @@ export declare class RequestHandler implements IRequestHandler {
|
|
|
67
67
|
get<T>(request: HTTPRequest): Promise<IHttpResponse<T>>;
|
|
68
68
|
delete<T>(request: HTTPRequest): Promise<IHttpResponse<T>>;
|
|
69
69
|
private getRequestConfig;
|
|
70
|
+
private diagnostic;
|
|
70
71
|
private getQueryString;
|
|
71
72
|
}
|
|
@@ -5,7 +5,7 @@ import { DOMParser } from '@xmldom/xmldom';
|
|
|
5
5
|
import { StaleInstanceError } from '../../exception/StaleInstanceError.js';
|
|
6
6
|
import { stripSecretsFromError, redactValue } from '../../util/redact.js';
|
|
7
7
|
import { checkRequirement } from '../../policy/Policy.js';
|
|
8
|
-
import { policyRefusal } from '../../policy/PolicyRefusal.js';
|
|
8
|
+
import { isPolicyRefusal, policyRefusal } from '../../policy/PolicyRefusal.js';
|
|
9
9
|
import { classify } from '../../policy/internal/Classify.js';
|
|
10
10
|
import { SessionAuthError } from '../../auth/SessionAuthError.js';
|
|
11
11
|
//axios.defaults.withCredentials = true;
|
|
@@ -76,7 +76,10 @@ export class RequestHandler {
|
|
|
76
76
|
* are stripped first, because the consumer's logger has no redaction format of its
|
|
77
77
|
* own.
|
|
78
78
|
*/
|
|
79
|
-
toThrowable(ex) {
|
|
79
|
+
toThrowable(ex, request) {
|
|
80
|
+
if (request?.sensitive && !isPolicyRefusal(ex) && !(ex instanceof SessionAuthError) && !(ex instanceof StaleInstanceError)) {
|
|
81
|
+
return new Error("Sensitive request failed; no payload diagnostics retained");
|
|
82
|
+
}
|
|
80
83
|
if (ex instanceof Error) {
|
|
81
84
|
return stripSecretsFromError(ex);
|
|
82
85
|
}
|
|
@@ -183,7 +186,7 @@ export class RequestHandler {
|
|
|
183
186
|
async doRequest(request, retried = false) {
|
|
184
187
|
let response = null;
|
|
185
188
|
const { config } = await this.getRequestConfig(request);
|
|
186
|
-
this._logger.debug("Retrieved Configuration", { config: config });
|
|
189
|
+
this._logger.debug("Retrieved Configuration", this.diagnostic(request, { config: config }));
|
|
187
190
|
//const { auth, path, params, fields, json, headers: baseHeaders, ...rest } = opts;
|
|
188
191
|
// let opts = {
|
|
189
192
|
// auth: this._session,
|
|
@@ -205,17 +208,19 @@ export class RequestHandler {
|
|
|
205
208
|
this._authHandler.pinSession?.();
|
|
206
209
|
}
|
|
207
210
|
let responseBodyString = null;
|
|
208
|
-
if (!resp.ok) {
|
|
211
|
+
if (!resp.ok && !(request.redirect === "manual" && resp.status >= 300 && resp.status < 400)) {
|
|
209
212
|
try {
|
|
210
213
|
responseBodyString = await resp.text();
|
|
211
214
|
}
|
|
212
215
|
catch (e) {
|
|
213
216
|
responseBodyString = null;
|
|
214
217
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
215
|
-
this._logger.error("Error parsing response body.", { error: e });
|
|
218
|
+
this._logger.error("Error parsing response body.", this.diagnostic(request, { error: e }, resp.status));
|
|
216
219
|
}
|
|
217
|
-
this._logger.error("Error during request.", { error: resp, request: request });
|
|
218
|
-
this._logger.error("Response Details:", { body: responseBodyString, status: resp.status });
|
|
220
|
+
this._logger.error("Error during request.", this.diagnostic(request, { error: resp, request: request }, resp.status));
|
|
221
|
+
this._logger.error("Response Details:", this.diagnostic(request, { body: responseBodyString, status: resp.status }, resp.status));
|
|
222
|
+
if (request.sensitive)
|
|
223
|
+
throw new Error(`Request failed with status ${resp.status}`);
|
|
219
224
|
throw new Error("Error during request. Status: " + resp.status + " Body: " + (responseBodyString !== null ? responseBodyString : "[no response body]"));
|
|
220
225
|
}
|
|
221
226
|
else {
|
|
@@ -225,7 +230,7 @@ export class RequestHandler {
|
|
|
225
230
|
catch (e) {
|
|
226
231
|
responseBodyString = null;
|
|
227
232
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
228
|
-
this._logger.error("Error parsing response body.", { error: e });
|
|
233
|
+
this._logger.error("Error parsing response body.", this.diagnostic(request, { error: e }, resp.status));
|
|
229
234
|
}
|
|
230
235
|
}
|
|
231
236
|
// let responseBodyReader = resp.body.getReader();
|
|
@@ -276,7 +281,7 @@ export class RequestHandler {
|
|
|
276
281
|
const response = null;
|
|
277
282
|
try {
|
|
278
283
|
const response = await this.doRequest(request);
|
|
279
|
-
this._logger.debug("Http SN POST Response Received", response);
|
|
284
|
+
this._logger.debug("Http SN POST Response Received", this.diagnostic(request, response, response.status));
|
|
280
285
|
try {
|
|
281
286
|
if (!((response.data) instanceof String)) {
|
|
282
287
|
const rpObj = response.data;
|
|
@@ -284,13 +289,13 @@ export class RequestHandler {
|
|
|
284
289
|
}
|
|
285
290
|
}
|
|
286
291
|
catch (ex) {
|
|
287
|
-
this._logger.error("Error setting response.bodyObject.", { error: ex, response: response, request: request });
|
|
292
|
+
this._logger.error("Error setting response.bodyObject.", this.diagnostic(request, { error: ex, response: response, request: request }));
|
|
288
293
|
}
|
|
289
294
|
return response;
|
|
290
295
|
}
|
|
291
296
|
catch (ex) {
|
|
292
|
-
this._logger.error("Error during POST request.", { error: ex, response: response, request: request });
|
|
293
|
-
throw this.toThrowable(ex);
|
|
297
|
+
this._logger.error("Error during POST request.", this.diagnostic(request, { error: ex, response: response, request: request }));
|
|
298
|
+
throw this.toThrowable(ex, request);
|
|
294
299
|
}
|
|
295
300
|
}
|
|
296
301
|
async put(request) {
|
|
@@ -298,7 +303,7 @@ export class RequestHandler {
|
|
|
298
303
|
const response = null;
|
|
299
304
|
try {
|
|
300
305
|
const response = await this.doRequest(request);
|
|
301
|
-
this._logger.debug("Http PUT Response Received", response);
|
|
306
|
+
this._logger.debug("Http PUT Response Received", this.diagnostic(request, response, response.status));
|
|
302
307
|
try {
|
|
303
308
|
if (!((response.data) instanceof String)) {
|
|
304
309
|
const rpObj = response.data;
|
|
@@ -311,8 +316,8 @@ export class RequestHandler {
|
|
|
311
316
|
return response;
|
|
312
317
|
}
|
|
313
318
|
catch (ex) {
|
|
314
|
-
this._logger.error("Error during PUT request.", { error: ex, response: response, request: request });
|
|
315
|
-
throw this.toThrowable(ex);
|
|
319
|
+
this._logger.error("Error during PUT request.", this.diagnostic(request, { error: ex, response: response, request: request }));
|
|
320
|
+
throw this.toThrowable(ex, request);
|
|
316
321
|
}
|
|
317
322
|
}
|
|
318
323
|
async get(request) {
|
|
@@ -320,7 +325,7 @@ export class RequestHandler {
|
|
|
320
325
|
const response = null;
|
|
321
326
|
try {
|
|
322
327
|
const response = await this.doRequest(request);
|
|
323
|
-
this._logger.debug("Http SN GET Response Received", response);
|
|
328
|
+
this._logger.debug("Http SN GET Response Received", this.diagnostic(request, response, response.status));
|
|
324
329
|
try {
|
|
325
330
|
if (!((response.data) instanceof String)) {
|
|
326
331
|
const rpObj = response.data;
|
|
@@ -328,13 +333,13 @@ export class RequestHandler {
|
|
|
328
333
|
}
|
|
329
334
|
}
|
|
330
335
|
catch (ex) {
|
|
331
|
-
this._logger.error("Error setting response.bodyObject.", { error: ex, response: response, request: request });
|
|
336
|
+
this._logger.error("Error setting response.bodyObject.", this.diagnostic(request, { error: ex, response: response, request: request }));
|
|
332
337
|
}
|
|
333
338
|
return response;
|
|
334
339
|
}
|
|
335
340
|
catch (ex) {
|
|
336
|
-
this._logger.error("Error during GET request.", { error: ex, response: response, request: request });
|
|
337
|
-
throw this.toThrowable(ex);
|
|
341
|
+
this._logger.error("Error during GET request.", this.diagnostic(request, { error: ex, response: response, request: request }));
|
|
342
|
+
throw this.toThrowable(ex, request);
|
|
338
343
|
}
|
|
339
344
|
}
|
|
340
345
|
async delete(request) {
|
|
@@ -349,13 +354,13 @@ export class RequestHandler {
|
|
|
349
354
|
}
|
|
350
355
|
}
|
|
351
356
|
catch (ex) {
|
|
352
|
-
this._logger.error("Error setting response.bodyObject.", { error: ex, response: response, request: request });
|
|
357
|
+
this._logger.error("Error setting response.bodyObject.", this.diagnostic(request, { error: ex, response: response, request: request }));
|
|
353
358
|
}
|
|
354
359
|
return response;
|
|
355
360
|
}
|
|
356
361
|
catch (ex) {
|
|
357
|
-
this._logger.error("Error during DELETE request.", { error: ex, response: response, request: request });
|
|
358
|
-
throw this.toThrowable(ex);
|
|
362
|
+
this._logger.error("Error during DELETE request.", this.diagnostic(request, { error: ex, response: response, request: request }));
|
|
363
|
+
throw this.toThrowable(ex, request);
|
|
359
364
|
}
|
|
360
365
|
}
|
|
361
366
|
async getRequestConfig(request) {
|
|
@@ -386,8 +391,15 @@ export class RequestHandler {
|
|
|
386
391
|
config.headers = request.headers;
|
|
387
392
|
config.path = request.path;
|
|
388
393
|
config.method = request.method;
|
|
394
|
+
if (request.redirect)
|
|
395
|
+
config.redirect = request.redirect;
|
|
389
396
|
return { config: config };
|
|
390
397
|
}
|
|
398
|
+
diagnostic(request, legacy, status) {
|
|
399
|
+
return request.sensitive
|
|
400
|
+
? { method: request.method, path: request.path.split("?")[0], status }
|
|
401
|
+
: legacy;
|
|
402
|
+
}
|
|
391
403
|
getQueryString(queryObj) {
|
|
392
404
|
const params = new URLSearchParams();
|
|
393
405
|
for (const prop in queryObj) {
|