velocious 1.0.467 → 1.0.469
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 +5 -3
- package/build/configuration-types.js +9 -1
- package/build/configuration.js +6 -1
- package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +168 -36
- package/build/error-reporting/request-details.js +308 -0
- package/build/frontend-model-controller.js +50 -2
- package/build/src/configuration-types.d.ts +23 -1
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +9 -2
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +7 -2
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +91 -9
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +149 -36
- package/build/src/error-reporting/request-details.d.ts +7 -0
- package/build/src/error-reporting/request-details.d.ts.map +1 -0
- package/build/src/error-reporting/request-details.js +278 -0
- package/build/src/frontend-model-controller.d.ts +16 -0
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +39 -3
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/configuration-types.js +9 -1
- package/src/configuration.js +6 -1
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +168 -36
- package/src/error-reporting/request-details.js +308 -0
- package/src/frontend-model-controller.js +50 -2
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import UploadedFile from "../http-server/client/uploaded-file/uploaded-file.js"
|
|
4
|
+
|
|
5
|
+
const REQUEST_DETAILS_BODY_MAX_SERIALIZED_LENGTH = 12000
|
|
6
|
+
const REQUEST_DETAILS_STRING_MAX_LENGTH = 1000
|
|
7
|
+
const REQUEST_DETAILS_ARRAY_MAX_ITEMS = 50
|
|
8
|
+
const REDACTED_REQUEST_DETAILS_VALUE = "[redacted]"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extracts request metadata without retaining the request object.
|
|
12
|
+
* @param {import("../http-server/client/request.js").default | import("../http-server/client/websocket-request.js").default | undefined} request - Request object, when present.
|
|
13
|
+
* @returns {import("../configuration-types.js").ErrorRequestDetails | null} - Request metadata.
|
|
14
|
+
*/
|
|
15
|
+
export function requestDetails(request) {
|
|
16
|
+
if (!request) return null
|
|
17
|
+
|
|
18
|
+
let details
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
details = {
|
|
22
|
+
httpMethod: request.httpMethod(),
|
|
23
|
+
path: request.path()
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const body = requestBodySnapshot(request)
|
|
30
|
+
|
|
31
|
+
if (body !== undefined) {
|
|
32
|
+
return {...details, body}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return details
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Snapshots parsed request params for error reports.
|
|
40
|
+
* @param {import("../http-server/client/request.js").default | import("../http-server/client/websocket-request.js").default} request - Request object.
|
|
41
|
+
* @returns {? | undefined} - Sanitized body snapshot.
|
|
42
|
+
*/
|
|
43
|
+
function requestBodySnapshot(request) {
|
|
44
|
+
if (typeof request.params !== "function") return undefined
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
return requestDetailsBodySnapshot(request.params())
|
|
48
|
+
} catch (error) {
|
|
49
|
+
return {
|
|
50
|
+
__unavailable: true,
|
|
51
|
+
error: error instanceof Error ? error.message : String(error)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Builds a bounded, redacted body snapshot for error reports.
|
|
58
|
+
* @param {?} body - Parsed request body.
|
|
59
|
+
* @returns {?} - Sanitized body snapshot.
|
|
60
|
+
*/
|
|
61
|
+
function requestDetailsBodySnapshot(body) {
|
|
62
|
+
const originalLength = serializedLength(body)
|
|
63
|
+
const sanitized = sanitizeRequestDetailsValue(body)
|
|
64
|
+
const sanitizedLength = serializedLength(sanitized)
|
|
65
|
+
|
|
66
|
+
if (originalLength <= REQUEST_DETAILS_BODY_MAX_SERIALIZED_LENGTH && sanitizedLength <= REQUEST_DETAILS_BODY_MAX_SERIALIZED_LENGTH) {
|
|
67
|
+
return sanitized
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const compactFrontendModelBody = compactFrontendModelRequestBody(sanitized, originalLength)
|
|
71
|
+
|
|
72
|
+
if (serializedLength(compactFrontendModelBody) <= REQUEST_DETAILS_BODY_MAX_SERIALIZED_LENGTH) {
|
|
73
|
+
return compactFrontendModelBody
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return compactRequestDetailsBody(sanitized, originalLength)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Sanitizes a value recursively for request details.
|
|
81
|
+
* @param {?} value - Value to sanitize.
|
|
82
|
+
* @param {string} [key] - Current object key.
|
|
83
|
+
* @param {WeakSet<object>} [seen] - Seen object references.
|
|
84
|
+
* @returns {?} - Sanitized value.
|
|
85
|
+
*/
|
|
86
|
+
function sanitizeRequestDetailsValue(value, key = "", seen = new WeakSet()) {
|
|
87
|
+
if (sensitiveRequestDetailsKey(key)) return REDACTED_REQUEST_DETAILS_VALUE
|
|
88
|
+
if (primitiveRequestDetailsValue(value)) return value
|
|
89
|
+
if (bufferValue(value)) return bufferRequestDetailsSummary(value)
|
|
90
|
+
if (value instanceof UploadedFile) return uploadedFileRequestDetailsSummary(value)
|
|
91
|
+
if (typeof value === "string") return sanitizeRequestDetailsString(value)
|
|
92
|
+
if (Array.isArray(value)) return sanitizeRequestDetailsArray(value, seen)
|
|
93
|
+
if (typeof value === "object") return sanitizeRequestDetailsObject(value, seen)
|
|
94
|
+
|
|
95
|
+
return String(value)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Checks whether a value can be kept as-is.
|
|
100
|
+
* @param {?} value - Value.
|
|
101
|
+
* @returns {boolean} - Whether the value is primitive and safe.
|
|
102
|
+
*/
|
|
103
|
+
function primitiveRequestDetailsValue(value) {
|
|
104
|
+
return value == null || typeof value === "boolean" || typeof value === "number"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Sanitizes a string value.
|
|
109
|
+
* @param {string} value - String value.
|
|
110
|
+
* @returns {string} - Sanitized string.
|
|
111
|
+
*/
|
|
112
|
+
function sanitizeRequestDetailsString(value) {
|
|
113
|
+
if (value.length <= REQUEST_DETAILS_STRING_MAX_LENGTH) return value
|
|
114
|
+
|
|
115
|
+
return `${value.slice(0, REQUEST_DETAILS_STRING_MAX_LENGTH)}... [truncated ${value.length - REQUEST_DETAILS_STRING_MAX_LENGTH} chars]`
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Sanitizes an array value.
|
|
120
|
+
* @param {Array<?>} value - Array value.
|
|
121
|
+
* @param {WeakSet<object>} seen - Seen object references.
|
|
122
|
+
* @returns {Array<?>} - Sanitized array.
|
|
123
|
+
*/
|
|
124
|
+
function sanitizeRequestDetailsArray(value, seen) {
|
|
125
|
+
const entries = value
|
|
126
|
+
.slice(0, REQUEST_DETAILS_ARRAY_MAX_ITEMS)
|
|
127
|
+
.map((entry) => sanitizeRequestDetailsValue(entry, "", seen))
|
|
128
|
+
|
|
129
|
+
if (value.length > REQUEST_DETAILS_ARRAY_MAX_ITEMS) {
|
|
130
|
+
entries.push({__omittedItems: value.length - REQUEST_DETAILS_ARRAY_MAX_ITEMS})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return entries
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Sanitizes a plain object-like value.
|
|
138
|
+
* @param {object} value - Object value.
|
|
139
|
+
* @param {WeakSet<object>} seen - Seen object references.
|
|
140
|
+
* @returns {Record<string, ?> | string} - Sanitized object or circular marker.
|
|
141
|
+
*/
|
|
142
|
+
function sanitizeRequestDetailsObject(value, seen) {
|
|
143
|
+
if (seen.has(value)) return "[circular]"
|
|
144
|
+
|
|
145
|
+
seen.add(value)
|
|
146
|
+
|
|
147
|
+
/** @type {Record<string, ?>} */
|
|
148
|
+
const sanitized = {}
|
|
149
|
+
|
|
150
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
151
|
+
sanitized[entryKey] = sanitizeRequestDetailsValue(entryValue, entryKey, seen)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
seen.delete(value)
|
|
155
|
+
|
|
156
|
+
return sanitized
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Checks whether a value is a Node.js Buffer.
|
|
161
|
+
* @param {?} value - Value.
|
|
162
|
+
* @returns {value is Buffer} - Whether value is a Buffer.
|
|
163
|
+
*/
|
|
164
|
+
function bufferValue(value) {
|
|
165
|
+
return typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(value)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Summarizes raw binary data without serializing bytes.
|
|
170
|
+
* @param {Buffer} buffer - Uploaded or request buffer.
|
|
171
|
+
* @returns {Record<string, ?>} - Request-safe buffer summary.
|
|
172
|
+
*/
|
|
173
|
+
function bufferRequestDetailsSummary(buffer) {
|
|
174
|
+
return {
|
|
175
|
+
__redacted: true,
|
|
176
|
+
__type: "Buffer",
|
|
177
|
+
byteLength: buffer.byteLength
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Summarizes uploaded files without serializing file bytes or temp paths.
|
|
183
|
+
* @param {UploadedFile} uploadedFile - Uploaded file object.
|
|
184
|
+
* @returns {Record<string, ?>} - Request-safe upload summary.
|
|
185
|
+
*/
|
|
186
|
+
function uploadedFileRequestDetailsSummary(uploadedFile) {
|
|
187
|
+
return {
|
|
188
|
+
__redacted: true,
|
|
189
|
+
__type: "UploadedFile",
|
|
190
|
+
contentType: uploadedFile.contentType() ?? null,
|
|
191
|
+
fieldName: uploadedFile.fieldName(),
|
|
192
|
+
filename: uploadedFile.filename(),
|
|
193
|
+
size: uploadedFile.size()
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Checks whether a key should be redacted from request details.
|
|
199
|
+
* @param {string} key - Object key.
|
|
200
|
+
* @returns {boolean} - Whether the value is sensitive.
|
|
201
|
+
*/
|
|
202
|
+
function sensitiveRequestDetailsKey(key) {
|
|
203
|
+
return /authorization|contentBase64|password|secret|sessionToken|token/i.test(key)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Compacts a frontend-model request envelope while preserving debugging shape.
|
|
208
|
+
* @param {?} value - Sanitized body value.
|
|
209
|
+
* @param {number} originalSerializedLength - Byte count before redaction or compaction.
|
|
210
|
+
* @returns {?} - Compacted body value.
|
|
211
|
+
*/
|
|
212
|
+
function compactFrontendModelRequestBody(value, originalSerializedLength) {
|
|
213
|
+
if (!value || typeof value !== "object" || !Array.isArray(/** @type {Record<string, ?>} */ (value).requests)) {
|
|
214
|
+
return compactRequestDetailsBody(value, originalSerializedLength)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
__truncated: true,
|
|
219
|
+
originalSerializedLength,
|
|
220
|
+
requests: /** @type {Array<?>} */ (/** @type {Record<string, ?>} */ (value).requests).map((request) => {
|
|
221
|
+
return compactFrontendModelRequest(request)
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Compacts one frontend-model request entry.
|
|
228
|
+
* @param {?} value - Candidate request entry from the transport envelope.
|
|
229
|
+
* @returns {?} - Compacted request.
|
|
230
|
+
*/
|
|
231
|
+
function compactFrontendModelRequest(value) {
|
|
232
|
+
if (!value || typeof value !== "object") return value
|
|
233
|
+
|
|
234
|
+
const request = /** @type {Record<string, ?>} */ (value)
|
|
235
|
+
/** @type {Record<string, ?>} */
|
|
236
|
+
const compact = {}
|
|
237
|
+
|
|
238
|
+
for (const key of ["requestId", "model", "commandType", "customPath"]) {
|
|
239
|
+
if (request[key] !== undefined) compact[key] = request[key]
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (request.payload !== undefined) {
|
|
243
|
+
compact.payload = compactFrontendModelPayload(request.payload)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return compact
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Compacts a frontend-model payload.
|
|
251
|
+
* @param {?} value - Candidate payload from a request entry.
|
|
252
|
+
* @returns {?} - Compacted payload.
|
|
253
|
+
*/
|
|
254
|
+
function compactFrontendModelPayload(value) {
|
|
255
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value
|
|
256
|
+
|
|
257
|
+
const payload = /** @type {Record<string, ?>} */ (value)
|
|
258
|
+
/** @type {Record<string, ?>} */
|
|
259
|
+
const compact = {}
|
|
260
|
+
|
|
261
|
+
for (const [key, entryValue] of Object.entries(payload)) {
|
|
262
|
+
compact[key] = compactFrontendModelPayloadEntry({key, value: entryValue})
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return compact
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Compacts one frontend-model payload entry.
|
|
270
|
+
* @param {{key: string, value: ?}} args - Payload entry.
|
|
271
|
+
* @returns {?} - Compacted value.
|
|
272
|
+
*/
|
|
273
|
+
function compactFrontendModelPayloadEntry({key, value}) {
|
|
274
|
+
if (key !== "attributes" || !value || typeof value !== "object" || Array.isArray(value)) {
|
|
275
|
+
return value
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return {__keys: Object.keys(/** @type {Record<string, ?>} */ (value))}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Builds a last-resort compact body summary.
|
|
283
|
+
* @param {?} value - Sanitized body.
|
|
284
|
+
* @param {number} originalSerializedLength - Byte count before redaction or compaction.
|
|
285
|
+
* @returns {Record<string, ?>} - Compact summary.
|
|
286
|
+
*/
|
|
287
|
+
function compactRequestDetailsBody(value, originalSerializedLength) {
|
|
288
|
+
return {
|
|
289
|
+
__truncated: true,
|
|
290
|
+
originalSerializedLength,
|
|
291
|
+
topLevelKeys: value && typeof value === "object" && !Array.isArray(value)
|
|
292
|
+
? Object.keys(/** @type {Record<string, ?>} */ (value))
|
|
293
|
+
: []
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Measures JSON serialized length.
|
|
299
|
+
* @param {?} value - Value to measure.
|
|
300
|
+
* @returns {number} - Serialized length, or Infinity when not serializable.
|
|
301
|
+
*/
|
|
302
|
+
function serializedLength(value) {
|
|
303
|
+
try {
|
|
304
|
+
return JSON.stringify(value).length
|
|
305
|
+
} catch {
|
|
306
|
+
return Infinity
|
|
307
|
+
}
|
|
308
|
+
}
|
|
@@ -8,6 +8,7 @@ import {frontendModelResourcesWithBuiltInsForBackendProject} from "./frontend-mo
|
|
|
8
8
|
import {frontendModelResourceClassFromDefinition, frontendModelResourceConfigurationFromDefinition, frontendModelResourcePath, frontendModelResourcesForBackendProject} from "./frontend-models/resource-definition.js"
|
|
9
9
|
import {FrontendModelQueryError, normalizeGroup as normalizeQueryGroup, normalizeJoins as normalizeQueryJoins, normalizePluck as normalizeQueryPluck, normalizePreload as normalizeQueryPreload, normalizeSearchOperator as normalizeQuerySearchOperator, normalizeSort as normalizeQuerySort} from "./frontend-models/query.js"
|
|
10
10
|
import {assignSafeProperty, deserializeFrontendModelTransportValue, isBackendModelInstance, serializeFrontendModelTransportValue} from "./frontend-models/transport-serialization.js"
|
|
11
|
+
import {requestDetails} from "./error-reporting/request-details.js"
|
|
11
12
|
import RoutesResolver from "./routes/resolver.js"
|
|
12
13
|
import {ValidationError} from "./database/record/index.js"
|
|
13
14
|
import { normalizeDateStringForWrite } from "./database/datetime-storage.js"
|
|
@@ -584,6 +585,12 @@ export default class FrontendModelController extends Controller {
|
|
|
584
585
|
* Frontend model ability override.
|
|
585
586
|
* @type {import("./authorization/ability.js").default | undefined} */
|
|
586
587
|
_frontendModelAbilityOverride = undefined
|
|
588
|
+
/**
|
|
589
|
+
* Original deserialized custom-command client payload, captured before route
|
|
590
|
+
* framework params are merged in, so a typed command method receives the client's
|
|
591
|
+
* own arguments rather than the route metadata. Only set on the shared-endpoint path.
|
|
592
|
+
* @type {Record<string, ?> | undefined} */
|
|
593
|
+
_frontendModelCustomCommandClientArguments = undefined
|
|
587
594
|
|
|
588
595
|
/**
|
|
589
596
|
* Runs frontend model params.
|
|
@@ -3177,7 +3184,8 @@ export default class FrontendModelController extends Controller {
|
|
|
3177
3184
|
const errorPayload = {
|
|
3178
3185
|
context: errorContext,
|
|
3179
3186
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
3180
|
-
request: this.getRequest()
|
|
3187
|
+
request: this.getRequest(),
|
|
3188
|
+
requestDetails: requestDetails(this.getRequest())
|
|
3181
3189
|
}
|
|
3182
3190
|
|
|
3183
3191
|
this.getConfiguration().getErrorEvents().emit("framework-error", errorPayload)
|
|
@@ -3578,6 +3586,14 @@ export default class FrontendModelController extends Controller {
|
|
|
3578
3586
|
viewPath
|
|
3579
3587
|
})
|
|
3580
3588
|
|
|
3589
|
+
// Preserve the client's own command arguments before route framework params won
|
|
3590
|
+
// the `controllerParams` merge above, so a typed command method (`async name(args)`)
|
|
3591
|
+
// receives the client payload — not the route's member id / model / controller keys.
|
|
3592
|
+
const customCommandController = /** @type {FrontendModelController} */ (/** @type {unknown} */ (controllerInstance))
|
|
3593
|
+
|
|
3594
|
+
customCommandController._frontendModelCustomCommandClientArguments =
|
|
3595
|
+
(payload && typeof payload === "object" && !Array.isArray(payload)) ? /** @type {Record<string, ?>} */ (payload) : {}
|
|
3596
|
+
|
|
3581
3597
|
await this.withFrontendModelRequestContext(controllerParams, response, async () => {
|
|
3582
3598
|
await controllerInstance._runBeforeCallbacks()
|
|
3583
3599
|
const controllerMethods = /** @type {Record<string, () => Promise<void> | void>} */ (/** @type {?} */ (controllerInstance))
|
|
@@ -3757,7 +3773,13 @@ export default class FrontendModelController extends Controller {
|
|
|
3757
3773
|
return this.frontendModelErrorPayload(`Missing frontend-model custom command '${methodName}'.`)
|
|
3758
3774
|
}
|
|
3759
3775
|
|
|
3760
|
-
|
|
3776
|
+
// Pass the client command arguments as the method's first argument so a command
|
|
3777
|
+
// method can take a typed args object (`async name(args)`) and the generated
|
|
3778
|
+
// frontend method can forward the backend method's `@param`. `this.params()` is
|
|
3779
|
+
// unchanged, so existing parameterless methods keep working. The args are untrusted
|
|
3780
|
+
// client input typed only by the declared contract, so methods must still validate.
|
|
3781
|
+
const commandArguments = this.frontendModelCustomCommandArguments(params)
|
|
3782
|
+
const responsePayload = await commandMethod.call(resource, commandArguments)
|
|
3761
3783
|
|
|
3762
3784
|
if (!responsePayload || typeof responsePayload !== "object") {
|
|
3763
3785
|
return {status: "success"}
|
|
@@ -3772,6 +3794,32 @@ export default class FrontendModelController extends Controller {
|
|
|
3772
3794
|
)
|
|
3773
3795
|
}
|
|
3774
3796
|
|
|
3797
|
+
/**
|
|
3798
|
+
* Resolves the typed argument object passed to a custom command method. On the
|
|
3799
|
+
* shared-endpoint path the original client payload was captured before route
|
|
3800
|
+
* framework params were merged, so it is returned verbatim (a client `id` survives
|
|
3801
|
+
* a member route). On the direct path it falls back to the request params with the
|
|
3802
|
+
* framework keys the command route hook injected stripped out.
|
|
3803
|
+
* @param {Record<string, ?>} params - Deserialized frontend-model params.
|
|
3804
|
+
* @returns {Record<string, ?>} - Client command arguments.
|
|
3805
|
+
*/
|
|
3806
|
+
frontendModelCustomCommandArguments(params) {
|
|
3807
|
+
if (this._frontendModelCustomCommandClientArguments) {
|
|
3808
|
+
return this._frontendModelCustomCommandClientArguments
|
|
3809
|
+
}
|
|
3810
|
+
|
|
3811
|
+
const {
|
|
3812
|
+
action: _action,
|
|
3813
|
+
controller: _controller,
|
|
3814
|
+
frontendModelCustomCommandMethodName: _methodName,
|
|
3815
|
+
frontendModelCustomCommandScope: _scope,
|
|
3816
|
+
model: _model,
|
|
3817
|
+
...commandArguments
|
|
3818
|
+
} = params
|
|
3819
|
+
|
|
3820
|
+
return commandArguments
|
|
3821
|
+
}
|
|
3822
|
+
|
|
3775
3823
|
/**
|
|
3776
3824
|
* Walks a custom-command response payload and replaces any backend `Record`
|
|
3777
3825
|
* instance with the resource's per-action serialized form so handlers can
|