velocious 1.0.600 → 1.0.601

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 CHANGED
@@ -775,22 +775,20 @@ Use `await FrontendModelBase.waitForIdle()` when a test harness or app lifecycle
775
775
 
776
776
  Frontend-model HTTP requests always use `credentials: "include"` so shared custom commands can set session cookies without app-level transport overrides.
777
777
 
778
- Unexpected frontend-model endpoint failures return their original message by default with `errorType: "internal_error"` and a server-generated `correlationId` shared with the matching framework-error report. Set `secureFrontendModelErrors: true` to return only explicitly safe messages and otherwise `errorMessage: "Request failed."`. Expected application failures can use `VelociousError.safe(message, {errorType, details, code})`; generated frontend-model callers preserve the server's safe error fields. See [docs/frontend-models.md](docs/frontend-models.md#error-payloads).
778
+ Unexpected frontend-model endpoint failures return their original message and full stack trace by default in every environment, including production. Responses use `errorType: "internal_error"`, a server-generated `correlationId` shared with the matching framework-error report, and the established `debugErrorClass`, `debugErrorMessage`, and `debugBacktrace` fields. Expected application failures can use `VelociousError.safe(message, {errorType, details, code})`; generated frontend-model callers preserve the server's safe error fields without adding irrelevant debug fields. See [docs/frontend-models.md](docs/frontend-models.md#error-payloads).
779
779
  Invalid client query descriptors, such as unknown `select`, `where`, `search`, `joins`, `preload`, `group`, `sort`, `pluck`, or Ransack attributes, return the specific frontend-model query error message with `velocious.code: "frontend-model-query-error"` and are not emitted as framework errors.
780
780
  Invalid frontend-model write attributes and attachment names, including attributes rejected by `permittedParams()`, return the specific safe error message with `velocious.code: "frontend-model-attribute-error"` and are not emitted as framework errors.
781
- In `development` and `test`, Velocious also includes `debugErrorClass`, `debugErrorMessage`, and `debugBacktrace` fields so browser/system-test failures are easier to diagnose without exposing those details in production.
782
- Other non-production environments, such as `staging`, keep the same client-safe default unless you explicitly opt in with `exposeInternalErrorsToClients: true`:
781
+ To mask unexpected internal details, explicitly opt out for the application configuration:
783
782
 
784
783
  ```js
785
784
  const configuration = new Configuration({
786
- environment: "staging",
787
- exposeInternalErrorsToClients: true
785
+ exposeInternalErrorsToClients: false
788
786
  })
789
787
  ```
790
788
 
791
- This opt-in is ignored in `production`; production frontend-model responses never include internal exception details.
789
+ With this opt-out, built-in commands, custom commands, and sync replay failures return `errorMessage: "Request failed."` and omit the debug message and stack fields in every environment. `secureFrontendModelErrors: true` remains a deprecated compatibility alias when `exposeInternalErrorsToClients` is omitted; an explicit `exposeInternalErrorsToClients` value always wins.
792
790
 
793
- Backends can append client-safe metadata to frontend-model error responses with `configuration.addClientErrorPayloadReporter(...)`. Reporters receive the caught `error`, the current `request`, a safe `requestDetails` snapshot, and a small `context` object, and should only return fields that are safe for clients to see. Frontend-model endpoint failures include `context.frontendModelEndpoint`, `action`, `commandType`, `model`, `requestId`, and `expectedError`. This is useful for attaching an error-reporting URL while keeping the normal production error message generic:
791
+ Backends can append client-safe metadata to frontend-model error responses with `configuration.addClientErrorPayloadReporter(...)`. Reporters receive the caught `error`, the current `request`, a safe `requestDetails` snapshot, and a small `context` object, and should only return fields that are safe for clients to see. Frontend-model endpoint failures include `context.frontendModelEndpoint`, `action`, `commandType`, `model`, `requestId`, and `expectedError`. When exposure is disabled, Velocious strips the established debug fields even if a reporter supplies them. This is useful for attaching an error-reporting URL while keeping an opted-out error message generic:
794
792
 
795
793
  ```js
796
794
  configuration.addClientErrorPayloadReporter(async ({error, requestDetails, context}) => {
@@ -1919,7 +1917,7 @@ configuration.getErrorEvents().on("all-error", ({error, errorType}) => {
1919
1917
  })
1920
1918
  ```
1921
1919
 
1922
- Genuinely unexpected frontend-model command failures reach this bus too. The frontend-model controller catches them to return an `internal_error` response with the original message by default (or `Request failed.` when `secureFrontendModelErrors` is enabled) and a correlation ID, then emits them as `framework-error`/`all-error` with the same correlation ID and `context.frontendModelEndpoint === true`. Expected user-flow errors are excluded: validation failures are forwarded with their real message (for example `Name can't be blank`), invalid client query descriptors are returned as frontend-model query errors, and `error.velocious`-annotated / `safeToExpose` errors keep their expected-error status. A raw `errorType` property alone is not considered safe and does not suppress reporting.
1920
+ Genuinely unexpected frontend-model command failures reach this bus too. The frontend-model controller catches them to return an `internal_error` response with the original message and stack trace by default (or `Request failed.` without debug fields when `exposeInternalErrorsToClients: false`) and a correlation ID, then emits them as `framework-error`/`all-error` with the same correlation ID and `context.frontendModelEndpoint === true`. Expected user-flow errors are excluded: validation failures are forwarded with their real message (for example `Name can't be blank`), invalid client query descriptors are returned as frontend-model query errors, and `error.velocious`-annotated / `safeToExpose` errors keep their expected-error status without irrelevant debug fields. A raw `errorType` property alone is not considered safe and does not suppress reporting.
1923
1921
 
1924
1922
  Unexpected inbound decoded WebSocket dispatch failures emit one `framework-error` and one matching `all-error`. Established expected client-flow errors remain excluded from both events.
1925
1923
 
@@ -697,9 +697,9 @@
697
697
  * @property {boolean} [enforceTenantDatabaseScopes] - Require tenant-switched model queries to resolve a tenant database identifier. Defaults to true.
698
698
  * @property {string} [environment] - Current environment name.
699
699
  * @property {import("./environment-handlers/base.js").default} environmentHandler - Environment handler instance.
700
- * @property {boolean} [exposeInternalErrorsToClients] - Return unexpected internal error details in client API payloads outside production. Defaults to false.
700
+ * @property {boolean} [exposeInternalErrorsToClients] - Return unexpected internal error messages and stack traces in frontend-model client payloads in every environment. Defaults to true.
701
701
  * @property {{maxOpenHandles?: number}} [frontendTenantSqlite] - Bounded frontend tenant SQLite lifecycle configuration.
702
- * @property {boolean} [secureFrontendModelErrors] - Return only explicitly safe frontend-model error messages to clients. Defaults to false.
702
+ * @property {boolean} [secureFrontendModelErrors] - Deprecated compatibility alias for `exposeInternalErrorsToClients: false` when the authoritative option is omitted.
703
703
  * @property {HttpServerConfiguration} [httpServer] - Default HTTP server configuration for applications started from this configuration.
704
704
  * @property {LoggingConfiguration} [logging] - Logging configuration.
705
705
  * @property {BackgroundJobsConfiguration} [backgroundJobs] - Background jobs configuration.
@@ -236,7 +236,7 @@ export default class VelociousConfiguration {
236
236
  * Runs constructor.
237
237
  * @param {import("./configuration-types.js").ConfigurationArgsType} args - Configuration arguments.
238
238
  */
239
- constructor({abilityResolver, abilityResources, attachments, autoload = true, backgroundJobs, backendProjects, beacon, cookieSecret, cors, database, debug = false, debugEndpoint = false, apiManifest = false, directory, enforceTenantDatabaseScopes = true, environment, environmentHandler, exposeInternalErrorsToClients = false, frontendTenantSqlite, httpServer, initializeModels, initializers, locale, localeFallbacks, locales, logging, mailerBackend, packages, requestTimeoutMs, routeResolverHooks, scheduledBackgroundJobs, secureFrontendModelErrors = false, structureSql, sync, tenantDatabaseProviders, tenantDatabaseResolver, tenantResolver, testing, timeZone, timezoneOffsetMinutes, trustedProxies, websocketChannelResolver, websocketMessageHandlerResolver, ...restArgs}) {
239
+ constructor({abilityResolver, abilityResources, attachments, autoload = true, backgroundJobs, backendProjects, beacon, cookieSecret, cors, database, debug = false, debugEndpoint = false, apiManifest = false, directory, enforceTenantDatabaseScopes = true, environment, environmentHandler, exposeInternalErrorsToClients, frontendTenantSqlite, httpServer, initializeModels, initializers, locale, localeFallbacks, locales, logging, mailerBackend, packages, requestTimeoutMs, routeResolverHooks, scheduledBackgroundJobs, secureFrontendModelErrors, structureSql, sync, tenantDatabaseProviders, tenantDatabaseResolver, tenantResolver, testing, timeZone, timezoneOffsetMinutes, trustedProxies, websocketChannelResolver, websocketMessageHandlerResolver, ...restArgs}) {
240
240
  restArgsError(restArgs)
241
241
 
242
242
  this._abilityResolver = abilityResolver
@@ -283,8 +283,9 @@ export default class VelociousConfiguration {
283
283
  this._environment = environment || globalThis.process?.env.VELOCIOUS_ENV || globalThis.process?.env.NODE_ENV || "development"
284
284
  this._environmentHandler = environmentHandler
285
285
  this._enforceTenantDatabaseScopes = enforceTenantDatabaseScopes
286
- this._exposeInternalErrorsToClients = exposeInternalErrorsToClients
287
- this._secureFrontendModelErrors = secureFrontendModelErrors
286
+ this._exposeInternalErrorsToClients = exposeInternalErrorsToClients === undefined
287
+ ? secureFrontendModelErrors !== true
288
+ : exposeInternalErrorsToClients
288
289
  this._directory = directory
289
290
  this._initializeModels = initializeModels
290
291
  /** @type {VelociousPackage[]} */
@@ -461,9 +462,10 @@ export default class VelociousConfiguration {
461
462
 
462
463
  /**
463
464
  * Returns whether frontend-model errors expose only explicitly safe messages.
464
- * @returns {boolean} Whether frontend-model errors expose only explicitly safe messages.
465
+ * @deprecated Use `getExposeInternalErrorsToClients()`.
466
+ * @returns {boolean} Whether frontend-model internal error exposure is disabled.
465
467
  */
466
- getSecureFrontendModelErrors() { return this._secureFrontendModelErrors === true }
468
+ getSecureFrontendModelErrors() { return !this.getExposeInternalErrorsToClients() }
467
469
 
468
470
  /**
469
471
  * Runs get debug endpoint.
@@ -175,7 +175,6 @@ const frontendModelJoinedPathsSymbol = Symbol("frontendModelJoinedPaths")
175
175
  const frontendModelGroupedColumnsSymbol = Symbol("frontendModelGroupedColumns")
176
176
  const frontendModelWhereNoMatchSymbol = Symbol("frontendModelWhereNoMatch")
177
177
  const frontendModelClientSafeErrorMessage = "Request failed."
178
- const frontendModelDebugErrorEnvironments = new Set(["development", "test"])
179
178
 
180
179
  /**
181
180
  * Builds a client-safe sync replay validation error.
@@ -277,10 +276,10 @@ function frontendModelVelociousMetadataForError(error) {
277
276
  /**
278
277
  * Runs frontend model client message for error.
279
278
  * @param {unknown} error - Caught error.
280
- * @param {boolean} forwardUnexpectedErrorMessage - Whether unexpected error messages may be exposed.
279
+ * @param {boolean} exposeInternalErrorsToClients - Whether unexpected error messages may be exposed.
281
280
  * @returns {string} - Message safe to return to API clients.
282
281
  */
283
- function frontendModelClientMessageForError(error, forwardUnexpectedErrorMessage) {
282
+ function frontendModelClientMessageForError(error, exposeInternalErrorsToClients) {
284
283
  if (error instanceof RecordNotFoundError) {
285
284
  return "Record not found."
286
285
  }
@@ -301,7 +300,7 @@ function frontendModelClientMessageForError(error, forwardUnexpectedErrorMessage
301
300
  return error.message
302
301
  }
303
302
 
304
- if (forwardUnexpectedErrorMessage && error instanceof Error) return error.message
303
+ if (exposeInternalErrorsToClients && error instanceof Error) return error.message
305
304
 
306
305
  return frontendModelClientSafeErrorMessage
307
306
  }
@@ -310,14 +309,11 @@ function frontendModelClientMessageForError(error, forwardUnexpectedErrorMessage
310
309
  * Runs frontend model debug payload for error.
311
310
  * @param {object} args - Arguments.
312
311
  * @param {import("./configuration.js").default} args.configuration - Current configuration.
313
- * @param {string} args.environment - Current environment.
314
312
  * @param {unknown} args.error - Caught error.
315
- * @returns {import("./configuration-types.js").ClientErrorPayloadReporterPayload} - Optional debug payload for non-production environments.
313
+ * @returns {import("./configuration-types.js").ClientErrorPayloadReporterPayload} - Optional internal error details when client exposure is enabled.
316
314
  */
317
- function frontendModelDebugPayloadForError({configuration, environment, error}) {
318
- const debugAllowed = frontendModelDebugErrorEnvironments.has(environment) || environment !== "production" && configuration.getExposeInternalErrorsToClients()
319
-
320
- if (!debugAllowed) {
315
+ function frontendModelDebugPayloadForError({configuration, error}) {
316
+ if (!configuration.getExposeInternalErrorsToClients()) {
321
317
  return {}
322
318
  }
323
319
 
@@ -3259,10 +3255,9 @@ export default class FrontendModelController extends Controller {
3259
3255
  * Runs frontend model client error payload for error.
3260
3256
  * @param {unknown} error - Caught error.
3261
3257
  * @param {FrontendModelEndpointErrorContext | undefined} [endpointErrorContext] - Frontend-model endpoint error context.
3262
- * @param {{forwardUnexpectedErrorMessage?: boolean}} [options] - Client error rendering options.
3263
3258
  * @returns {Promise<import("./configuration-types.js").ClientErrorPayloadReporterPayload>} - Client payload for the current environment.
3264
3259
  */
3265
- async frontendModelClientErrorPayloadForError(error, endpointErrorContext, {forwardUnexpectedErrorMessage = false} = {}) {
3260
+ async frontendModelClientErrorPayloadForError(error, endpointErrorContext) {
3266
3261
  const velociousMetadata = frontendModelVelociousMetadataForError(error)
3267
3262
  const normalizedError = error instanceof Error ? error : new Error(String(error))
3268
3263
  /** @type {import("./configuration-types.js").ClientErrorPayloadReporterPayload} */
@@ -3312,15 +3307,20 @@ export default class FrontendModelController extends Controller {
3312
3307
  request: this.getRequest()
3313
3308
  })
3314
3309
 
3310
+ if (!this.getConfiguration().getExposeInternalErrorsToClients()) {
3311
+ delete reporterPayload.debugBacktrace
3312
+ delete reporterPayload.debugErrorClass
3313
+ delete reporterPayload.debugErrorMessage
3314
+ }
3315
+
3315
3316
  return {
3316
3317
  ...reporterPayload,
3317
3318
  ...this.frontendModelErrorPayload(frontendModelClientMessageForError(
3318
3319
  error,
3319
- forwardUnexpectedErrorMessage && !this.getConfiguration().getSecureFrontendModelErrors()
3320
+ this.getConfiguration().getExposeInternalErrorsToClients()
3320
3321
  )),
3321
3322
  ...frontendModelDebugPayloadForError({
3322
3323
  configuration: this.getConfiguration(),
3323
- environment: this.getConfiguration().getEnvironment(),
3324
3324
  error
3325
3325
  }),
3326
3326
  ...(velociousMetadata ? {velocious: velociousMetadata} : {}),
@@ -4397,9 +4397,7 @@ export default class FrontendModelController extends Controller {
4397
4397
 
4398
4398
  responses.push({
4399
4399
  requestId,
4400
- response: await this.frontendModelClientErrorPayloadForError(error, errorContext, {
4401
- forwardUnexpectedErrorMessage: !isBuiltInCommand
4402
- })
4400
+ response: await this.frontendModelClientErrorPayloadForError(error, errorContext)
4403
4401
  })
4404
4402
  }
4405
4403
  }
@@ -4623,9 +4621,7 @@ export default class FrontendModelController extends Controller {
4623
4621
  await this.frontendModelLogEndpointError({error, errorContext})
4624
4622
 
4625
4623
  await this.render({
4626
- json: /** @type {Record<string, ReturnType<typeof JSON.parse>>} */ (serializeFrontendModelTransportValue(await this.frontendModelClientErrorPayloadForError(error, errorContext, {
4627
- forwardUnexpectedErrorMessage: true
4628
- }), this.transportSerializationOptions()))
4624
+ json: /** @type {Record<string, ReturnType<typeof JSON.parse>>} */ (serializeFrontendModelTransportValue(await this.frontendModelClientErrorPayloadForError(error, errorContext), this.transportSerializationOptions()))
4629
4625
  })
4630
4626
  }
4631
4627
  }
@@ -1512,7 +1512,7 @@ export type ConfigurationArgsType = {
1512
1512
  */
1513
1513
  environmentHandler: import("./environment-handlers/base.js").default;
1514
1514
  /**
1515
- * - Return unexpected internal error details in client API payloads outside production. Defaults to false.
1515
+ * - Return unexpected internal error messages and stack traces in frontend-model client payloads in every environment. Defaults to true.
1516
1516
  */
1517
1517
  exposeInternalErrorsToClients?: boolean;
1518
1518
  /**
@@ -1522,7 +1522,7 @@ export type ConfigurationArgsType = {
1522
1522
  maxOpenHandles?: number;
1523
1523
  };
1524
1524
  /**
1525
- * - Return only explicitly safe frontend-model error messages to clients. Defaults to false.
1525
+ * - Deprecated compatibility alias for `exposeInternalErrorsToClients: false` when the authoritative option is omitted.
1526
1526
  */
1527
1527
  secureFrontendModelErrors?: boolean;
1528
1528
  /**
@@ -2247,9 +2247,9 @@ export type ConfigurationArgsType = {
2247
2247
  * @property {boolean} [enforceTenantDatabaseScopes] - Require tenant-switched model queries to resolve a tenant database identifier. Defaults to true.
2248
2248
  * @property {string} [environment] - Current environment name.
2249
2249
  * @property {import("./environment-handlers/base.js").default} environmentHandler - Environment handler instance.
2250
- * @property {boolean} [exposeInternalErrorsToClients] - Return unexpected internal error details in client API payloads outside production. Defaults to false.
2250
+ * @property {boolean} [exposeInternalErrorsToClients] - Return unexpected internal error messages and stack traces in frontend-model client payloads in every environment. Defaults to true.
2251
2251
  * @property {{maxOpenHandles?: number}} [frontendTenantSqlite] - Bounded frontend tenant SQLite lifecycle configuration.
2252
- * @property {boolean} [secureFrontendModelErrors] - Return only explicitly safe frontend-model error messages to clients. Defaults to false.
2252
+ * @property {boolean} [secureFrontendModelErrors] - Deprecated compatibility alias for `exposeInternalErrorsToClients: false` when the authoritative option is omitted.
2253
2253
  * @property {HttpServerConfiguration} [httpServer] - Default HTTP server configuration for applications started from this configuration.
2254
2254
  * @property {LoggingConfiguration} [logging] - Logging configuration.
2255
2255
  * @property {BackgroundJobsConfiguration} [backgroundJobs] - Background jobs configuration.