velocious 1.0.438 → 1.0.439

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.
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Transliterates German umlauts (and ß) in a database column name to ASCII so generated and runtime
3
+ * attribute names stay ASCII regardless of whether the column uses the umlaut ("Plätze") or already
4
+ * transliterated ("Plaetze") spelling. Both then map to the same attribute (e.g. "plaetzeVerkauft"),
5
+ * which keeps generated model bases consistent with code that references the ASCII attribute names.
6
+ * The raw column name is still used for the actual SQL, so the underlying column is untouched.
7
+ * @param {string} columnName - Raw database column name.
8
+ * @returns {string} - ASCII-transliterated column name.
9
+ */
10
+ export default function deburrColumnName(columnName: string): string;
11
+ //# sourceMappingURL=deburr-column-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deburr-column-name.d.ts","sourceRoot":"","sources":["../../../src/utils/deburr-column-name.js"],"names":[],"mappings":"AAaA;;;;;;;;GAQG;AACH,qDAHW,MAAM,GACJ,MAAM,CAgBlB"}
@@ -0,0 +1,33 @@
1
+ // @ts-check
2
+ /** @type {Array<[RegExp, string]>} */
3
+ const UMLAUT_REPLACEMENTS = [
4
+ [/Ä/g, "Ae"],
5
+ [/Ö/g, "Oe"],
6
+ [/Ü/g, "Ue"],
7
+ [/ä/g, "ae"],
8
+ [/ö/g, "oe"],
9
+ [/ü/g, "ue"],
10
+ [/ß/g, "ss"]
11
+ ];
12
+ /**
13
+ * Transliterates German umlauts (and ß) in a database column name to ASCII so generated and runtime
14
+ * attribute names stay ASCII regardless of whether the column uses the umlaut ("Plätze") or already
15
+ * transliterated ("Plaetze") spelling. Both then map to the same attribute (e.g. "plaetzeVerkauft"),
16
+ * which keeps generated model bases consistent with code that references the ASCII attribute names.
17
+ * The raw column name is still used for the actual SQL, so the underlying column is untouched.
18
+ * @param {string} columnName - Raw database column name.
19
+ * @returns {string} - ASCII-transliterated column name.
20
+ */
21
+ export default function deburrColumnName(columnName) {
22
+ let result = columnName;
23
+ for (const [pattern, replacement] of UMLAUT_REPLACEMENTS) {
24
+ result = result.replace(pattern, replacement);
25
+ }
26
+ // An all-caps acronym column (e.g. "IP", "EA") would camelize to "iP"/"eA" because only the first
27
+ // letter is lowercased. Down-case columns that contain no lowercase letters so "IP" becomes "ip".
28
+ if (!/[a-z]/.test(result)) {
29
+ result = result.toLowerCase();
30
+ }
31
+ return result;
32
+ }
33
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVidXJyLWNvbHVtbi1uYW1lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3V0aWxzL2RlYnVyci1jb2x1bW4tbmFtZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosc0NBQXNDO0FBQ3RDLE1BQU0sbUJBQW1CLEdBQUc7SUFDMUIsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDO0lBQ1osQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDO0lBQ1osQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDO0lBQ1osQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDO0lBQ1osQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDO0lBQ1osQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDO0lBQ1osQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDO0NBQ2IsQ0FBQTtBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxDQUFDLE9BQU8sVUFBVSxnQkFBZ0IsQ0FBQyxVQUFVO0lBQ2pELElBQUksTUFBTSxHQUFHLFVBQVUsQ0FBQTtJQUV2QixLQUFLLE1BQU0sQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLElBQUksbUJBQW1CLEVBQUUsQ0FBQztRQUN6RCxNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUE7SUFDL0MsQ0FBQztJQUVELGtHQUFrRztJQUNsRyxrR0FBa0c7SUFDbEcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztRQUMxQixNQUFNLEdBQUcsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFBO0lBQy9CLENBQUM7SUFFRCxPQUFPLE1BQU0sQ0FBQTtBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuLyoqIEB0eXBlIHtBcnJheTxbUmVnRXhwLCBzdHJpbmddPn0gKi9cbmNvbnN0IFVNTEFVVF9SRVBMQUNFTUVOVFMgPSBbXG4gIFsvw4QvZywgXCJBZVwiXSxcbiAgWy/Dli9nLCBcIk9lXCJdLFxuICBbL8OcL2csIFwiVWVcIl0sXG4gIFsvw6QvZywgXCJhZVwiXSxcbiAgWy/Dti9nLCBcIm9lXCJdLFxuICBbL8O8L2csIFwidWVcIl0sXG4gIFsvw58vZywgXCJzc1wiXVxuXVxuXG4vKipcbiAqIFRyYW5zbGl0ZXJhdGVzIEdlcm1hbiB1bWxhdXRzIChhbmQgw58pIGluIGEgZGF0YWJhc2UgY29sdW1uIG5hbWUgdG8gQVNDSUkgc28gZ2VuZXJhdGVkIGFuZCBydW50aW1lXG4gKiBhdHRyaWJ1dGUgbmFtZXMgc3RheSBBU0NJSSByZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhlIGNvbHVtbiB1c2VzIHRoZSB1bWxhdXQgKFwiUGzDpHR6ZVwiKSBvciBhbHJlYWR5XG4gKiB0cmFuc2xpdGVyYXRlZCAoXCJQbGFldHplXCIpIHNwZWxsaW5nLiBCb3RoIHRoZW4gbWFwIHRvIHRoZSBzYW1lIGF0dHJpYnV0ZSAoZS5nLiBcInBsYWV0emVWZXJrYXVmdFwiKSxcbiAqIHdoaWNoIGtlZXBzIGdlbmVyYXRlZCBtb2RlbCBiYXNlcyBjb25zaXN0ZW50IHdpdGggY29kZSB0aGF0IHJlZmVyZW5jZXMgdGhlIEFTQ0lJIGF0dHJpYnV0ZSBuYW1lcy5cbiAqIFRoZSByYXcgY29sdW1uIG5hbWUgaXMgc3RpbGwgdXNlZCBmb3IgdGhlIGFjdHVhbCBTUUwsIHNvIHRoZSB1bmRlcmx5aW5nIGNvbHVtbiBpcyB1bnRvdWNoZWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gY29sdW1uTmFtZSAtIFJhdyBkYXRhYmFzZSBjb2x1bW4gbmFtZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gQVNDSUktdHJhbnNsaXRlcmF0ZWQgY29sdW1uIG5hbWUuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGRlYnVyckNvbHVtbk5hbWUoY29sdW1uTmFtZSkge1xuICBsZXQgcmVzdWx0ID0gY29sdW1uTmFtZVxuXG4gIGZvciAoY29uc3QgW3BhdHRlcm4sIHJlcGxhY2VtZW50XSBvZiBVTUxBVVRfUkVQTEFDRU1FTlRTKSB7XG4gICAgcmVzdWx0ID0gcmVzdWx0LnJlcGxhY2UocGF0dGVybiwgcmVwbGFjZW1lbnQpXG4gIH1cblxuICAvLyBBbiBhbGwtY2FwcyBhY3JvbnltIGNvbHVtbiAoZS5nLiBcIklQXCIsIFwiRUFcIikgd291bGQgY2FtZWxpemUgdG8gXCJpUFwiL1wiZUFcIiBiZWNhdXNlIG9ubHkgdGhlIGZpcnN0XG4gIC8vIGxldHRlciBpcyBsb3dlcmNhc2VkLiBEb3duLWNhc2UgY29sdW1ucyB0aGF0IGNvbnRhaW4gbm8gbG93ZXJjYXNlIGxldHRlcnMgc28gXCJJUFwiIGJlY29tZXMgXCJpcFwiLlxuICBpZiAoIS9bYS16XS8udGVzdChyZXN1bHQpKSB7XG4gICAgcmVzdWx0ID0gcmVzdWx0LnRvTG93ZXJDYXNlKClcbiAgfVxuXG4gIHJldHVybiByZXN1bHRcbn1cbiJdfQ==
@@ -1 +1 @@
1
- {"root":["../index.js","../bin/velocious.js","../src/application.js","../src/configuration-resolver.js","../src/configuration-types.js","../src/configuration.js","../src/controller.js","../src/current-configuration.js","../src/current.js","../src/error-logger.js","../src/frontend-model-controller.js","../src/initializer.js","../src/logger.js","../src/mailer.js","../src/record-payload-values.js","../src/velocious-error.js","../src/authorization/ability.js","../src/authorization/base-resource.js","../src/background-jobs/client.js","../src/background-jobs/cron-expression.js","../src/background-jobs/forked-runner-child.js","../src/background-jobs/job-record.js","../src/background-jobs/job-registry.js","../src/background-jobs/job-runner.js","../src/background-jobs/job.js","../src/background-jobs/json-socket.js","../src/background-jobs/main.js","../src/background-jobs/normalize-error.js","../src/background-jobs/scheduler.js","../src/background-jobs/socket-request.js","../src/background-jobs/status-reporter.js","../src/background-jobs/store.js","../src/background-jobs/types.js","../src/background-jobs/worker.js","../src/background-jobs/web/authorization.js","../src/background-jobs/web/controller.js","../src/background-jobs/web/index.js","../src/background-jobs/web/path-matcher.js","../src/background-jobs/web/registry.js","../src/beacon/client.js","../src/beacon/in-process-broker.js","../src/beacon/in-process-client.js","../src/beacon/server.js","../src/beacon/types.js","../src/cli/base-command.js","../src/cli/browser-cli.js","../src/cli/index.js","../src/cli/tenant-database-command-helper.js","../src/cli/use-browser-cli.js","../src/cli/commands/background-jobs-main.js","../src/cli/commands/background-jobs-runner.js","../src/cli/commands/background-jobs-worker.js","../src/cli/commands/beacon.js","../src/cli/commands/console.js","../src/cli/commands/init.js","../src/cli/commands/routes.js","../src/cli/commands/run-script.js","../src/cli/commands/runner.js","../src/cli/commands/server.js","../src/cli/commands/test.js","../src/cli/commands/db/base-command.js","../src/cli/commands/db/create.js","../src/cli/commands/db/drop.js","../src/cli/commands/db/migrate.js","../src/cli/commands/db/reset.js","../src/cli/commands/db/rollback.js","../src/cli/commands/db/seed.js","../src/cli/commands/db/schema/dump.js","../src/cli/commands/db/schema/load.js","../src/cli/commands/db/tenants/check.js","../src/cli/commands/db/tenants/create.js","../src/cli/commands/db/tenants/migrate.js","../src/cli/commands/destroy/migration.js","../src/cli/commands/generate/base-models.js","../src/cli/commands/generate/frontend-models.js","../src/cli/commands/generate/migration.js","../src/cli/commands/generate/model.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/migrator.js","../src/database/use-database.js","../src/database/drivers/base-column.js","../src/database/drivers/base-columns-index.js","../src/database/drivers/base-foreign-key.js","../src/database/drivers/base-table.js","../src/database/drivers/base.js","../src/database/drivers/mssql/column.js","../src/database/drivers/mssql/columns-index.js","../src/database/drivers/mssql/connect-connection.js","../src/database/drivers/mssql/foreign-key.js","../src/database/drivers/mssql/index.js","../src/database/drivers/mssql/options.js","../src/database/drivers/mssql/query-parser.js","../src/database/drivers/mssql/structure-sql.js","../src/database/drivers/mssql/table.js","../src/database/drivers/mssql/sql/alter-table.js","../src/database/drivers/mssql/sql/create-database.js","../src/database/drivers/mssql/sql/create-index.js","../src/database/drivers/mssql/sql/create-table.js","../src/database/drivers/mssql/sql/delete.js","../src/database/drivers/mssql/sql/drop-database.js","../src/database/drivers/mssql/sql/drop-table.js","../src/database/drivers/mssql/sql/insert.js","../src/database/drivers/mssql/sql/update.js","../src/database/drivers/mssql/sql/upsert.js","../src/database/drivers/mysql/column.js","../src/database/drivers/mysql/columns-index.js","../src/database/drivers/mysql/foreign-key.js","../src/database/drivers/mysql/index.js","../src/database/drivers/mysql/options.js","../src/database/drivers/mysql/query-parser.js","../src/database/drivers/mysql/query.js","../src/database/drivers/mysql/structure-sql.js","../src/database/drivers/mysql/table.js","../src/database/drivers/mysql/sql/alter-table.js","../src/database/drivers/mysql/sql/create-database.js","../src/database/drivers/mysql/sql/create-index.js","../src/database/drivers/mysql/sql/create-table.js","../src/database/drivers/mysql/sql/delete.js","../src/database/drivers/mysql/sql/drop-database.js","../src/database/drivers/mysql/sql/drop-table.js","../src/database/drivers/mysql/sql/insert.js","../src/database/drivers/mysql/sql/update.js","../src/database/drivers/mysql/sql/upsert.js","../src/database/drivers/pgsql/column.js","../src/database/drivers/pgsql/columns-index.js","../src/database/drivers/pgsql/foreign-key.js","../src/database/drivers/pgsql/index.js","../src/database/drivers/pgsql/options.js","../src/database/drivers/pgsql/query-parser.js","../src/database/drivers/pgsql/structure-sql.js","../src/database/drivers/pgsql/table.js","../src/database/drivers/pgsql/sql/alter-table.js","../src/database/drivers/pgsql/sql/create-database.js","../src/database/drivers/pgsql/sql/create-index.js","../src/database/drivers/pgsql/sql/create-table.js","../src/database/drivers/pgsql/sql/delete.js","../src/database/drivers/pgsql/sql/drop-database.js","../src/database/drivers/pgsql/sql/drop-table.js","../src/database/drivers/pgsql/sql/insert.js","../src/database/drivers/pgsql/sql/update.js","../src/database/drivers/pgsql/sql/upsert.js","../src/database/drivers/sqlite/base.js","../src/database/drivers/sqlite/column.js","../src/database/drivers/sqlite/columns-index.js","../src/database/drivers/sqlite/connection-sql-js.js","../src/database/drivers/sqlite/foreign-key.js","../src/database/drivers/sqlite/index.js","../src/database/drivers/sqlite/index.native.js","../src/database/drivers/sqlite/index.web.js","../src/database/drivers/sqlite/options.js","../src/database/drivers/sqlite/query-parser.js","../src/database/drivers/sqlite/query.js","../src/database/drivers/sqlite/query.native.js","../src/database/drivers/sqlite/query.web.js","../src/database/drivers/sqlite/structure-sql.js","../src/database/drivers/sqlite/table-rebuilder.js","../src/database/drivers/sqlite/table.js","../src/database/drivers/sqlite/sql/alter-table.js","../src/database/drivers/sqlite/sql/create-index.js","../src/database/drivers/sqlite/sql/create-table.js","../src/database/drivers/sqlite/sql/delete.js","../src/database/drivers/sqlite/sql/drop-table.js","../src/database/drivers/sqlite/sql/insert.js","../src/database/drivers/sqlite/sql/update.js","../src/database/drivers/sqlite/sql/upsert.js","../src/database/drivers/structure-sql/utils.js","../src/database/migration/index.js","../src/database/migrator/files-finder.js","../src/database/migrator/types.js","../src/database/pool/async-tracked-multi-connection.js","../src/database/pool/base-methods-forward.js","../src/database/pool/base.js","../src/database/pool/single-multi-use.js","../src/database/query/alter-table-base.js","../src/database/query/base.js","../src/database/query/create-database-base.js","../src/database/query/create-index-base.js","../src/database/query/create-table-base.js","../src/database/query/delete-base.js","../src/database/query/drop-database-base.js","../src/database/query/drop-table-base.js","../src/database/query/from-base.js","../src/database/query/from-plain.js","../src/database/query/from-table.js","../src/database/query/index.js","../src/database/query/insert-base.js","../src/database/query/join-base.js","../src/database/query/join-object.js","../src/database/query/join-plain.js","../src/database/query/join-tracker.js","../src/database/query/model-class-query.js","../src/database/query/order-base.js","../src/database/query/order-column.js","../src/database/query/order-plain.js","../src/database/query/preloader.js","../src/database/query/query-data.js","../src/database/query/select-base.js","../src/database/query/select-plain.js","../src/database/query/select-table-and-column.js","../src/database/query/update-base.js","../src/database/query/upsert-base.js","../src/database/query/where-base.js","../src/database/query/where-combinator.js","../src/database/query/where-hash.js","../src/database/query/where-model-class-hash.js","../src/database/query/where-not.js","../src/database/query/where-plain.js","../src/database/query/with-count.js","../src/database/query/preloader/belongs-to.js","../src/database/query/preloader/ensure-model-class-initialized.js","../src/database/query/preloader/has-many.js","../src/database/query/preloader/has-one.js","../src/database/query/preloader/selection.js","../src/database/query-parser/base-query-parser.js","../src/database/query-parser/from-parser.js","../src/database/query-parser/group-parser.js","../src/database/query-parser/joins-parser.js","../src/database/query-parser/limit-parser.js","../src/database/query-parser/options.js","../src/database/query-parser/order-parser.js","../src/database/query-parser/select-parser.js","../src/database/query-parser/where-parser.js","../src/database/record/acts-as-list.js","../src/database/record/index.js","../src/database/record/record-not-found-error.js","../src/database/record/state-machine.js","../src/database/record/user-module.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/frontend-model-resource/base-resource.js","../src/frontend-models/base.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/plugins/sqljs-wasm-route-controller.js","../src/plugins/sqljs-wasm-route.js","../src/routes/app-routes.js","../src/routes/base-route.js","../src/routes/basic-route.js","../src/routes/get-route.js","../src/routes/index.js","../src/routes/namespace-route.js","../src/routes/plugin-routes.js","../src/routes/post-route.js","../src/routes/resolver.js","../src/routes/resource-route.js","../src/routes/root-route.js","../src/routes/built-in/debug/controller.js","../src/routes/built-in/errors/controller.js","../src/routes/hooks/frontend-model-command-route-hook.js","../src/testing/base-expect.js","../src/testing/browser-frontend-model-event-hook-scenarios.js","../src/testing/browser-test-app.js","../src/testing/expect-to-change.js","../src/testing/expect-utils.js","../src/testing/expect.js","../src/testing/request-client.js","../src/testing/test-files-finder.js","../src/testing/test-filter-parser.js","../src/testing/test-runner.js","../src/testing/test-suite-splitter.js","../src/testing/test.js","../src/types/external-modules.d.ts","../src/utils/backtrace-cleaner-node.js","../src/utils/backtrace-cleaner.js","../src/utils/ensure-error.js","../src/utils/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/model-scope.js","../src/utils/nest-callbacks.js","../src/utils/plain-object.js","../src/utils/ransack.js","../src/utils/rest-args-error.js","../src/utils/singularize-model-name.js","../src/utils/split-sql-statements.js","../src/utils/to-import-specifier.js","../src/utils/with-tracked-stack-async-hooks.js","../src/utils/with-tracked-stack.js"],"version":"6.0.3"}
1
+ {"root":["../index.js","../bin/velocious.js","../src/application.js","../src/configuration-resolver.js","../src/configuration-types.js","../src/configuration.js","../src/controller.js","../src/current-configuration.js","../src/current.js","../src/error-logger.js","../src/frontend-model-controller.js","../src/initializer.js","../src/logger.js","../src/mailer.js","../src/record-payload-values.js","../src/velocious-error.js","../src/authorization/ability.js","../src/authorization/base-resource.js","../src/background-jobs/client.js","../src/background-jobs/cron-expression.js","../src/background-jobs/forked-runner-child.js","../src/background-jobs/job-record.js","../src/background-jobs/job-registry.js","../src/background-jobs/job-runner.js","../src/background-jobs/job.js","../src/background-jobs/json-socket.js","../src/background-jobs/main.js","../src/background-jobs/normalize-error.js","../src/background-jobs/scheduler.js","../src/background-jobs/socket-request.js","../src/background-jobs/status-reporter.js","../src/background-jobs/store.js","../src/background-jobs/types.js","../src/background-jobs/worker.js","../src/background-jobs/web/authorization.js","../src/background-jobs/web/controller.js","../src/background-jobs/web/index.js","../src/background-jobs/web/path-matcher.js","../src/background-jobs/web/registry.js","../src/beacon/client.js","../src/beacon/in-process-broker.js","../src/beacon/in-process-client.js","../src/beacon/server.js","../src/beacon/types.js","../src/cli/base-command.js","../src/cli/browser-cli.js","../src/cli/index.js","../src/cli/tenant-database-command-helper.js","../src/cli/use-browser-cli.js","../src/cli/commands/background-jobs-main.js","../src/cli/commands/background-jobs-runner.js","../src/cli/commands/background-jobs-worker.js","../src/cli/commands/beacon.js","../src/cli/commands/console.js","../src/cli/commands/init.js","../src/cli/commands/routes.js","../src/cli/commands/run-script.js","../src/cli/commands/runner.js","../src/cli/commands/server.js","../src/cli/commands/test.js","../src/cli/commands/db/base-command.js","../src/cli/commands/db/create.js","../src/cli/commands/db/drop.js","../src/cli/commands/db/migrate.js","../src/cli/commands/db/reset.js","../src/cli/commands/db/rollback.js","../src/cli/commands/db/seed.js","../src/cli/commands/db/schema/dump.js","../src/cli/commands/db/schema/load.js","../src/cli/commands/db/tenants/check.js","../src/cli/commands/db/tenants/create.js","../src/cli/commands/db/tenants/migrate.js","../src/cli/commands/destroy/migration.js","../src/cli/commands/generate/base-models.js","../src/cli/commands/generate/frontend-models.js","../src/cli/commands/generate/migration.js","../src/cli/commands/generate/model.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/migrator.js","../src/database/use-database.js","../src/database/drivers/base-column.js","../src/database/drivers/base-columns-index.js","../src/database/drivers/base-foreign-key.js","../src/database/drivers/base-table.js","../src/database/drivers/base.js","../src/database/drivers/mssql/column.js","../src/database/drivers/mssql/columns-index.js","../src/database/drivers/mssql/connect-connection.js","../src/database/drivers/mssql/foreign-key.js","../src/database/drivers/mssql/index.js","../src/database/drivers/mssql/options.js","../src/database/drivers/mssql/query-parser.js","../src/database/drivers/mssql/structure-sql.js","../src/database/drivers/mssql/table.js","../src/database/drivers/mssql/sql/alter-table.js","../src/database/drivers/mssql/sql/create-database.js","../src/database/drivers/mssql/sql/create-index.js","../src/database/drivers/mssql/sql/create-table.js","../src/database/drivers/mssql/sql/delete.js","../src/database/drivers/mssql/sql/drop-database.js","../src/database/drivers/mssql/sql/drop-table.js","../src/database/drivers/mssql/sql/insert.js","../src/database/drivers/mssql/sql/update.js","../src/database/drivers/mssql/sql/upsert.js","../src/database/drivers/mysql/column.js","../src/database/drivers/mysql/columns-index.js","../src/database/drivers/mysql/foreign-key.js","../src/database/drivers/mysql/index.js","../src/database/drivers/mysql/options.js","../src/database/drivers/mysql/query-parser.js","../src/database/drivers/mysql/query.js","../src/database/drivers/mysql/structure-sql.js","../src/database/drivers/mysql/table.js","../src/database/drivers/mysql/sql/alter-table.js","../src/database/drivers/mysql/sql/create-database.js","../src/database/drivers/mysql/sql/create-index.js","../src/database/drivers/mysql/sql/create-table.js","../src/database/drivers/mysql/sql/delete.js","../src/database/drivers/mysql/sql/drop-database.js","../src/database/drivers/mysql/sql/drop-table.js","../src/database/drivers/mysql/sql/insert.js","../src/database/drivers/mysql/sql/update.js","../src/database/drivers/mysql/sql/upsert.js","../src/database/drivers/pgsql/column.js","../src/database/drivers/pgsql/columns-index.js","../src/database/drivers/pgsql/foreign-key.js","../src/database/drivers/pgsql/index.js","../src/database/drivers/pgsql/options.js","../src/database/drivers/pgsql/query-parser.js","../src/database/drivers/pgsql/structure-sql.js","../src/database/drivers/pgsql/table.js","../src/database/drivers/pgsql/sql/alter-table.js","../src/database/drivers/pgsql/sql/create-database.js","../src/database/drivers/pgsql/sql/create-index.js","../src/database/drivers/pgsql/sql/create-table.js","../src/database/drivers/pgsql/sql/delete.js","../src/database/drivers/pgsql/sql/drop-database.js","../src/database/drivers/pgsql/sql/drop-table.js","../src/database/drivers/pgsql/sql/insert.js","../src/database/drivers/pgsql/sql/update.js","../src/database/drivers/pgsql/sql/upsert.js","../src/database/drivers/sqlite/base.js","../src/database/drivers/sqlite/column.js","../src/database/drivers/sqlite/columns-index.js","../src/database/drivers/sqlite/connection-sql-js.js","../src/database/drivers/sqlite/foreign-key.js","../src/database/drivers/sqlite/index.js","../src/database/drivers/sqlite/index.native.js","../src/database/drivers/sqlite/index.web.js","../src/database/drivers/sqlite/options.js","../src/database/drivers/sqlite/query-parser.js","../src/database/drivers/sqlite/query.js","../src/database/drivers/sqlite/query.native.js","../src/database/drivers/sqlite/query.web.js","../src/database/drivers/sqlite/structure-sql.js","../src/database/drivers/sqlite/table-rebuilder.js","../src/database/drivers/sqlite/table.js","../src/database/drivers/sqlite/sql/alter-table.js","../src/database/drivers/sqlite/sql/create-index.js","../src/database/drivers/sqlite/sql/create-table.js","../src/database/drivers/sqlite/sql/delete.js","../src/database/drivers/sqlite/sql/drop-table.js","../src/database/drivers/sqlite/sql/insert.js","../src/database/drivers/sqlite/sql/update.js","../src/database/drivers/sqlite/sql/upsert.js","../src/database/drivers/structure-sql/utils.js","../src/database/migration/index.js","../src/database/migrator/files-finder.js","../src/database/migrator/types.js","../src/database/pool/async-tracked-multi-connection.js","../src/database/pool/base-methods-forward.js","../src/database/pool/base.js","../src/database/pool/single-multi-use.js","../src/database/query/alter-table-base.js","../src/database/query/base.js","../src/database/query/create-database-base.js","../src/database/query/create-index-base.js","../src/database/query/create-table-base.js","../src/database/query/delete-base.js","../src/database/query/drop-database-base.js","../src/database/query/drop-table-base.js","../src/database/query/from-base.js","../src/database/query/from-plain.js","../src/database/query/from-table.js","../src/database/query/index.js","../src/database/query/insert-base.js","../src/database/query/join-base.js","../src/database/query/join-object.js","../src/database/query/join-plain.js","../src/database/query/join-tracker.js","../src/database/query/model-class-query.js","../src/database/query/order-base.js","../src/database/query/order-column.js","../src/database/query/order-plain.js","../src/database/query/preloader.js","../src/database/query/query-data.js","../src/database/query/select-base.js","../src/database/query/select-plain.js","../src/database/query/select-table-and-column.js","../src/database/query/update-base.js","../src/database/query/upsert-base.js","../src/database/query/where-base.js","../src/database/query/where-combinator.js","../src/database/query/where-hash.js","../src/database/query/where-model-class-hash.js","../src/database/query/where-not.js","../src/database/query/where-plain.js","../src/database/query/with-count.js","../src/database/query/preloader/belongs-to.js","../src/database/query/preloader/ensure-model-class-initialized.js","../src/database/query/preloader/has-many.js","../src/database/query/preloader/has-one.js","../src/database/query/preloader/selection.js","../src/database/query-parser/base-query-parser.js","../src/database/query-parser/from-parser.js","../src/database/query-parser/group-parser.js","../src/database/query-parser/joins-parser.js","../src/database/query-parser/limit-parser.js","../src/database/query-parser/options.js","../src/database/query-parser/order-parser.js","../src/database/query-parser/select-parser.js","../src/database/query-parser/where-parser.js","../src/database/record/acts-as-list.js","../src/database/record/index.js","../src/database/record/record-not-found-error.js","../src/database/record/state-machine.js","../src/database/record/user-module.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/frontend-model-resource/base-resource.js","../src/frontend-models/base.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/plugins/sqljs-wasm-route-controller.js","../src/plugins/sqljs-wasm-route.js","../src/routes/app-routes.js","../src/routes/base-route.js","../src/routes/basic-route.js","../src/routes/get-route.js","../src/routes/index.js","../src/routes/namespace-route.js","../src/routes/plugin-routes.js","../src/routes/post-route.js","../src/routes/resolver.js","../src/routes/resource-route.js","../src/routes/root-route.js","../src/routes/built-in/debug/controller.js","../src/routes/built-in/errors/controller.js","../src/routes/hooks/frontend-model-command-route-hook.js","../src/testing/base-expect.js","../src/testing/browser-frontend-model-event-hook-scenarios.js","../src/testing/browser-test-app.js","../src/testing/expect-to-change.js","../src/testing/expect-utils.js","../src/testing/expect.js","../src/testing/request-client.js","../src/testing/test-files-finder.js","../src/testing/test-filter-parser.js","../src/testing/test-runner.js","../src/testing/test-suite-splitter.js","../src/testing/test.js","../src/types/external-modules.d.ts","../src/utils/backtrace-cleaner-node.js","../src/utils/backtrace-cleaner.js","../src/utils/deburr-column-name.js","../src/utils/ensure-error.js","../src/utils/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/model-scope.js","../src/utils/nest-callbacks.js","../src/utils/plain-object.js","../src/utils/ransack.js","../src/utils/rest-args-error.js","../src/utils/singularize-model-name.js","../src/utils/split-sql-statements.js","../src/utils/to-import-specifier.js","../src/utils/with-tracked-stack-async-hooks.js","../src/utils/with-tracked-stack.js"],"version":"6.0.3"}
@@ -0,0 +1,37 @@
1
+ // @ts-check
2
+
3
+ /** @type {Array<[RegExp, string]>} */
4
+ const UMLAUT_REPLACEMENTS = [
5
+ [/Ä/g, "Ae"],
6
+ [/Ö/g, "Oe"],
7
+ [/Ü/g, "Ue"],
8
+ [/ä/g, "ae"],
9
+ [/ö/g, "oe"],
10
+ [/ü/g, "ue"],
11
+ [/ß/g, "ss"]
12
+ ]
13
+
14
+ /**
15
+ * Transliterates German umlauts (and ß) in a database column name to ASCII so generated and runtime
16
+ * attribute names stay ASCII regardless of whether the column uses the umlaut ("Plätze") or already
17
+ * transliterated ("Plaetze") spelling. Both then map to the same attribute (e.g. "plaetzeVerkauft"),
18
+ * which keeps generated model bases consistent with code that references the ASCII attribute names.
19
+ * The raw column name is still used for the actual SQL, so the underlying column is untouched.
20
+ * @param {string} columnName - Raw database column name.
21
+ * @returns {string} - ASCII-transliterated column name.
22
+ */
23
+ export default function deburrColumnName(columnName) {
24
+ let result = columnName
25
+
26
+ for (const [pattern, replacement] of UMLAUT_REPLACEMENTS) {
27
+ result = result.replace(pattern, replacement)
28
+ }
29
+
30
+ // An all-caps acronym column (e.g. "IP", "EA") would camelize to "iP"/"eA" because only the first
31
+ // letter is lowercased. Down-case columns that contain no lowercase letters so "IP" becomes "ip".
32
+ if (!/[a-z]/.test(result)) {
33
+ result = result.toLowerCase()
34
+ }
35
+
36
+ return result
37
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "build/bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.438",
6
+ "version": "1.0.439",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -143,6 +143,8 @@ export default class VelociousConfiguration {
143
143
  this._scheduledBackgroundJobs = scheduledBackgroundJobs
144
144
  this._attachments = attachments || {}
145
145
  this._backendProjects = backendProjects || []
146
+ /** @type {Array<(args: {context: ?, error: Error, request: ?}) => Promise<Record<string, ?> | void> | Record<string, ?> | void>} */
147
+ this._clientErrorPayloadReporters = []
146
148
  this.cors = cors
147
149
  this._cookieSecret = cookieSecret
148
150
  this.database = database
@@ -2382,6 +2384,35 @@ export default class VelociousConfiguration {
2382
2384
  return this._errorEvents
2383
2385
  }
2384
2386
 
2387
+ /**
2388
+ * Registers a reporter that can add client-safe metadata to frontend-model error payloads.
2389
+ * @param {(args: {context: ?, error: Error, request: ?}) => Promise<Record<string, ?> | void> | Record<string, ?> | void} reporter - Reporter callback.
2390
+ * @returns {void}
2391
+ */
2392
+ addClientErrorPayloadReporter(reporter) {
2393
+ this._clientErrorPayloadReporters.push(reporter)
2394
+ }
2395
+
2396
+ /**
2397
+ * Runs registered client error payload reporters.
2398
+ * @param {{context: ?, error: Error, request: ?}} args - Reporter args.
2399
+ * @returns {Promise<Record<string, ?>>} - Merged client-safe reporter payload.
2400
+ */
2401
+ async clientErrorPayloadForError(args) {
2402
+ /** @type {Record<string, ?>} */
2403
+ const payload = {}
2404
+
2405
+ for (const reporter of this._clientErrorPayloadReporters) {
2406
+ const reporterPayload = await reporter(args)
2407
+
2408
+ if (reporterPayload && typeof reporterPayload === "object") {
2409
+ Object.assign(payload, reporterPayload)
2410
+ }
2411
+ }
2412
+
2413
+ return payload
2414
+ }
2415
+
2385
2416
  /**
2386
2417
  * Runs with connections.
2387
2418
  * @template T
@@ -30,6 +30,7 @@ import HasOneInstanceRelationship from "./instance-relationships/has-one.js"
30
30
  import HasOneRelationship from "./relationships/has-one.js"
31
31
  import RecordAttachmentHandle from "./attachments/handle.js"
32
32
  import * as inflection from "inflection"
33
+ import deburrColumnName from "../../utils/deburr-column-name.js"
33
34
  import ModelClassQuery from "../query/model-class-query.js"
34
35
  import Preloader from "../query/preloader.js"
35
36
  import {readPayloadAssociationCount, readPayloadComputedAbility, readPayloadQueryData, setPayloadAssociationCount, setPayloadComputedAbility, setPayloadQueryData} from "../../record-payload-values.js"
@@ -1350,8 +1351,9 @@ class VelociousDatabaseRecord {
1350
1351
  for (const column of this._columns) {
1351
1352
  this._columnsAsHash[column.getName()] = column
1352
1353
 
1353
- const camelizedColumnName = inflection.camelize(column.getName(), true)
1354
- const camelizedColumnNameBigFirst = inflection.camelize(column.getName())
1354
+ const deburredColumnName = deburrColumnName(column.getName())
1355
+ const camelizedColumnName = inflection.camelize(deburredColumnName, true)
1356
+ const camelizedColumnNameBigFirst = inflection.camelize(deburredColumnName)
1355
1357
 
1356
1358
  attributeNameToColumnName[camelizedColumnName] = column.getName()
1357
1359
  columnNameToAttributeName[column.getName()] = camelizedColumnName
@@ -1,4 +1,5 @@
1
1
  import BaseCommand from "../../../../../cli/base-command.js"
2
+ import deburrColumnName from "../../../../../utils/deburr-column-name.js"
2
3
  import fileExists from "../../../../../utils/file-exists.js"
3
4
  import fs from "fs/promises"
4
5
  import * as inflection from "inflection"
@@ -141,8 +142,9 @@ export default class DbGenerateModel extends BaseCommand {
141
142
  let methodsCount = 0
142
143
 
143
144
  for (const column of columns) {
144
- const camelizedColumnName = inflection.camelize(column.getName(), true)
145
- const camelizedColumnNameBigFirst = inflection.camelize(column.getName())
145
+ const deburredColumnName = deburrColumnName(column.getName())
146
+ const camelizedColumnName = inflection.camelize(deburredColumnName, true)
147
+ const camelizedColumnNameBigFirst = inflection.camelize(deburredColumnName)
146
148
  const jsdocType = this.jsDocTypeFromColumn(column, modelClass)
147
149
 
148
150
  if (methodsCount > 0) {
@@ -2741,10 +2741,11 @@ export default class FrontendModelController extends Controller {
2741
2741
  /**
2742
2742
  * Runs frontend model client error payload for error.
2743
2743
  * @param {?} error - Caught error.
2744
- * @returns {Record<string, ?>} - Client payload for the current environment.
2744
+ * @returns {Promise<Record<string, ?>>} - Client payload for the current environment.
2745
2745
  */
2746
- frontendModelClientErrorPayloadForError(error) {
2746
+ async frontendModelClientErrorPayloadForError(error) {
2747
2747
  const velociousMetadata = frontendModelVelociousMetadataForError(error)
2748
+ const normalizedError = error instanceof Error ? error : new Error(String(error))
2748
2749
 
2749
2750
  let validationErrorsPayload = {}
2750
2751
 
@@ -2778,7 +2779,14 @@ export default class FrontendModelController extends Controller {
2778
2779
  error
2779
2780
  }),
2780
2781
  ...(velociousMetadata ? {velocious: velociousMetadata} : {}),
2781
- ...validationErrorsPayload
2782
+ ...validationErrorsPayload,
2783
+ ...(await this.getConfiguration().clientErrorPayloadForError({
2784
+ context: {
2785
+ controller: this.constructor.name
2786
+ },
2787
+ error: normalizedError,
2788
+ request: this.getRequest()
2789
+ }))
2782
2790
  }
2783
2791
  }
2784
2792
 
@@ -2845,7 +2853,7 @@ export default class FrontendModelController extends Controller {
2845
2853
  await this.render({
2846
2854
  json: /**
2847
2855
  * Types the following value.
2848
- @type {Record<string, ?>} */ (serializeFrontendModelTransportValue(this.frontendModelClientErrorPayloadForError(error)))
2856
+ @type {Record<string, ?>} */ (serializeFrontendModelTransportValue(await this.frontendModelClientErrorPayloadForError(error)))
2849
2857
  })
2850
2858
  }
2851
2859
  }
@@ -3122,7 +3130,7 @@ export default class FrontendModelController extends Controller {
3122
3130
 
3123
3131
  responses.push({
3124
3132
  requestId,
3125
- response: this.frontendModelClientErrorPayloadForError(error)
3133
+ response: await this.frontendModelClientErrorPayloadForError(error)
3126
3134
  })
3127
3135
  }
3128
3136
  }
@@ -3348,7 +3356,7 @@ export default class FrontendModelController extends Controller {
3348
3356
  await this.render({
3349
3357
  json: /**
3350
3358
  * Types the following value.
3351
- @type {Record<string, ?>} */ (serializeFrontendModelTransportValue(this.frontendModelClientErrorPayloadForError(error)))
3359
+ @type {Record<string, ?>} */ (serializeFrontendModelTransportValue(await this.frontendModelClientErrorPayloadForError(error)))
3352
3360
  })
3353
3361
  }
3354
3362
  }
@@ -0,0 +1,37 @@
1
+ // @ts-check
2
+
3
+ /** @type {Array<[RegExp, string]>} */
4
+ const UMLAUT_REPLACEMENTS = [
5
+ [/Ä/g, "Ae"],
6
+ [/Ö/g, "Oe"],
7
+ [/Ü/g, "Ue"],
8
+ [/ä/g, "ae"],
9
+ [/ö/g, "oe"],
10
+ [/ü/g, "ue"],
11
+ [/ß/g, "ss"]
12
+ ]
13
+
14
+ /**
15
+ * Transliterates German umlauts (and ß) in a database column name to ASCII so generated and runtime
16
+ * attribute names stay ASCII regardless of whether the column uses the umlaut ("Plätze") or already
17
+ * transliterated ("Plaetze") spelling. Both then map to the same attribute (e.g. "plaetzeVerkauft"),
18
+ * which keeps generated model bases consistent with code that references the ASCII attribute names.
19
+ * The raw column name is still used for the actual SQL, so the underlying column is untouched.
20
+ * @param {string} columnName - Raw database column name.
21
+ * @returns {string} - ASCII-transliterated column name.
22
+ */
23
+ export default function deburrColumnName(columnName) {
24
+ let result = columnName
25
+
26
+ for (const [pattern, replacement] of UMLAUT_REPLACEMENTS) {
27
+ result = result.replace(pattern, replacement)
28
+ }
29
+
30
+ // An all-caps acronym column (e.g. "IP", "EA") would camelize to "iP"/"eA" because only the first
31
+ // letter is lowercased. Down-case columns that contain no lowercase letters so "IP" becomes "ip".
32
+ if (!/[a-z]/.test(result)) {
33
+ result = result.toLowerCase()
34
+ }
35
+
36
+ return result
37
+ }