@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.
Files changed (79) hide show
  1. package/README.md +6 -0
  2. package/dist/comm/http/FormHtmlParser.d.ts +34 -0
  3. package/dist/comm/http/FormHtmlParser.js +227 -0
  4. package/dist/comm/http/FormHtmlParser.js.map +1 -0
  5. package/dist/comm/http/FormRecordModels.d.ts +120 -0
  6. package/dist/comm/http/FormRecordModels.js +6 -0
  7. package/dist/comm/http/FormRecordModels.js.map +1 -0
  8. package/dist/comm/http/FormRecordWriter.d.ts +99 -0
  9. package/dist/comm/http/FormRecordWriter.js +385 -0
  10. package/dist/comm/http/FormRecordWriter.js.map +1 -0
  11. package/dist/comm/http/HTTPRequest.d.ts +4 -0
  12. package/dist/comm/http/RequestHandler.d.ts +1 -0
  13. package/dist/comm/http/RequestHandler.js +34 -22
  14. package/dist/comm/http/RequestHandler.js.map +1 -1
  15. package/dist/comm/http/internal/FormTransportModels.d.ts +26 -0
  16. package/dist/comm/http/internal/FormTransportModels.js +2 -0
  17. package/dist/comm/http/internal/FormTransportModels.js.map +1 -0
  18. package/dist/exception/FormSubmitError.d.ts +13 -0
  19. package/dist/exception/FormSubmitError.js +19 -0
  20. package/dist/exception/FormSubmitError.js.map +1 -0
  21. package/dist/exception/WorkflowValidationError.d.ts +24 -0
  22. package/dist/exception/WorkflowValidationError.js +24 -0
  23. package/dist/exception/WorkflowValidationError.js.map +1 -0
  24. package/dist/index.d.ts +19 -0
  25. package/dist/index.js +19 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/sn/metadata/MetadataFormWriter.d.ts +13 -0
  28. package/dist/sn/metadata/MetadataFormWriter.js +264 -0
  29. package/dist/sn/metadata/MetadataFormWriter.js.map +1 -0
  30. package/dist/sn/metadata/MetadataModels.d.ts +44 -0
  31. package/dist/sn/metadata/MetadataModels.js +2 -0
  32. package/dist/sn/metadata/MetadataModels.js.map +1 -0
  33. package/dist/sn/metadata/MetadataScopeError.d.ts +5 -0
  34. package/dist/sn/metadata/MetadataScopeError.js +10 -0
  35. package/dist/sn/metadata/MetadataScopeError.js.map +1 -0
  36. package/dist/sn/metadata/MetadataVerificationError.d.ts +11 -0
  37. package/dist/sn/metadata/MetadataVerificationError.js +20 -0
  38. package/dist/sn/metadata/MetadataVerificationError.js.map +1 -0
  39. package/dist/sn/metadata/internal/MetadataPreferences.d.ts +12 -0
  40. package/dist/sn/metadata/internal/MetadataPreferences.js +27 -0
  41. package/dist/sn/metadata/internal/MetadataPreferences.js.map +1 -0
  42. package/dist/sn/metadata/internal/MetadataReader.d.ts +9 -0
  43. package/dist/sn/metadata/internal/MetadataReader.js +55 -0
  44. package/dist/sn/metadata/internal/MetadataReader.js.map +1 -0
  45. package/dist/sn/variables/VariableDefinitions.d.ts +23 -0
  46. package/dist/sn/variables/VariableDefinitions.js +106 -0
  47. package/dist/sn/variables/VariableDefinitions.js.map +1 -0
  48. package/dist/sn/variables/VariableModels.d.ts +49 -0
  49. package/dist/sn/variables/VariableModels.js +6 -0
  50. package/dist/sn/variables/VariableModels.js.map +1 -0
  51. package/dist/sn/workflow/WorkflowConversionModels.d.ts +209 -0
  52. package/dist/sn/workflow/WorkflowConversionModels.js +2 -0
  53. package/dist/sn/workflow/WorkflowConversionModels.js.map +1 -0
  54. package/dist/sn/workflow/WorkflowDiagramClient.d.ts +70 -0
  55. package/dist/sn/workflow/WorkflowDiagramClient.js +151 -0
  56. package/dist/sn/workflow/WorkflowDiagramClient.js.map +1 -0
  57. package/dist/sn/workflow/WorkflowFlowConversion.d.ts +19 -0
  58. package/dist/sn/workflow/WorkflowFlowConversion.js +1013 -0
  59. package/dist/sn/workflow/WorkflowFlowConversion.js.map +1 -0
  60. package/dist/sn/workflow/WorkflowFlowHints.d.ts +3 -0
  61. package/dist/sn/workflow/WorkflowFlowHints.js +36 -0
  62. package/dist/sn/workflow/WorkflowFlowHints.js.map +1 -0
  63. package/dist/sn/workflow/WorkflowFluentGenerator.d.ts +17 -0
  64. package/dist/sn/workflow/WorkflowFluentGenerator.js +348 -0
  65. package/dist/sn/workflow/WorkflowFluentGenerator.js.map +1 -0
  66. package/dist/sn/workflow/WorkflowGraphML.d.ts +39 -0
  67. package/dist/sn/workflow/WorkflowGraphML.js +162 -0
  68. package/dist/sn/workflow/WorkflowGraphML.js.map +1 -0
  69. package/dist/sn/workflow/WorkflowManager.d.ts +236 -6
  70. package/dist/sn/workflow/WorkflowManager.js +1443 -15
  71. package/dist/sn/workflow/WorkflowManager.js.map +1 -1
  72. package/dist/sn/workflow/WorkflowModels.d.ts +738 -0
  73. package/dist/sn/workflow/WorkflowStructure.d.ts +137 -0
  74. package/dist/sn/workflow/WorkflowStructure.js +368 -0
  75. package/dist/sn/workflow/WorkflowStructure.js.map +1 -0
  76. package/dist/sn/workflow/WorkflowViews.d.ts +104 -0
  77. package/dist/sn/workflow/WorkflowViews.js +408 -0
  78. package/dist/sn/workflow/WorkflowViews.js.map +1 -0
  79. 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":"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"}
@@ -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) {