velocious 1.0.494 → 1.0.496
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/build/database/record/index.js +2 -0
- package/build/database/record/validation-messages.js +50 -0
- package/build/database/record/validators/length.js +52 -0
- package/build/database/record/validators/presence.js +4 -1
- package/build/database/record/validators/uniqueness.js +4 -1
- package/build/frontend-model-resource/base-resource.js +175 -5
- package/build/frontend-models/resource-definition.js +49 -1
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +3 -1
- package/build/src/database/record/validation-messages.d.ts +38 -0
- package/build/src/database/record/validation-messages.d.ts.map +1 -0
- package/build/src/database/record/validation-messages.js +45 -0
- package/build/src/database/record/validators/length.d.ts +12 -0
- package/build/src/database/record/validators/length.d.ts.map +1 -0
- package/build/src/database/record/validators/length.js +45 -0
- package/build/src/database/record/validators/presence.d.ts.map +1 -1
- package/build/src/database/record/validators/presence.js +4 -2
- package/build/src/database/record/validators/uniqueness.d.ts.map +1 -1
- package/build/src/database/record/validators/uniqueness.js +4 -2
- package/build/src/frontend-model-resource/base-resource.d.ts +184 -5
- package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/base-resource.js +155 -6
- package/build/src/frontend-models/resource-definition.d.ts +41 -0
- package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
- package/build/src/frontend-models/resource-definition.js +45 -2
- package/build/src/sync/sync-envelope-replay-service.d.ts +166 -3
- package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
- package/build/src/sync/sync-envelope-replay-service.js +304 -12
- package/build/src/sync/sync-replay-upsert-applier.d.ts +1 -0
- package/build/src/sync/sync-replay-upsert-applier.d.ts.map +1 -1
- package/build/src/sync/sync-replay-upsert-applier.js +2 -1
- package/build/src/sync/sync-resource-base.d.ts +16 -32
- package/build/src/sync/sync-resource-base.d.ts.map +1 -1
- package/build/src/sync/sync-resource-base.js +31 -43
- package/build/src/testing/test-runner.d.ts +24 -0
- package/build/src/testing/test-runner.d.ts.map +1 -1
- package/build/src/testing/test-runner.js +99 -9
- package/build/sync/sync-envelope-replay-service.js +350 -10
- package/build/sync/sync-replay-upsert-applier.js +1 -0
- package/build/sync/sync-resource-base.js +32 -45
- package/build/testing/test-runner.js +104 -8
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/scripts/run-tests.js +6 -0
- package/src/database/record/index.js +2 -0
- package/src/database/record/validation-messages.js +50 -0
- package/src/database/record/validators/length.js +52 -0
- package/src/database/record/validators/presence.js +4 -1
- package/src/database/record/validators/uniqueness.js +4 -1
- package/src/frontend-model-resource/base-resource.js +175 -5
- package/src/frontend-models/resource-definition.js +49 -1
- package/src/sync/sync-envelope-replay-service.js +350 -10
- package/src/sync/sync-replay-upsert-applier.js +1 -0
- package/src/sync/sync-resource-base.js +32 -45
- package/src/testing/test-runner.js +104 -8
- package/build/src/sync/sync-attribute-normalizer.d.ts +0 -105
- package/build/src/sync/sync-attribute-normalizer.d.ts.map +0 -1
- package/build/src/sync/sync-attribute-normalizer.js +0 -172
- package/build/sync/sync-attribute-normalizer.js +0 -186
- package/src/sync/sync-attribute-normalizer.js +0 -186
|
@@ -187,6 +187,8 @@ export default class TestRunner {
|
|
|
187
187
|
this._testsCount = 0
|
|
188
188
|
this._activeAfterAllScopes = []
|
|
189
189
|
this._failedTestDetails = []
|
|
190
|
+
/** @type {{fullDescription: string, filePath: string, line: number} | null} */
|
|
191
|
+
this._lastTestContext = null
|
|
190
192
|
}
|
|
191
193
|
|
|
192
194
|
/**
|
|
@@ -638,16 +640,102 @@ export default class TestRunner {
|
|
|
638
640
|
* Runs run.
|
|
639
641
|
* @returns {Promise<void>} - Resolves when complete.
|
|
640
642
|
*/
|
|
643
|
+
/**
|
|
644
|
+
* Records an asynchronous crash (an unhandled promise rejection detached from
|
|
645
|
+
* any await, e.g. a `void connection.afterCommit(async () => broadcast(...))`
|
|
646
|
+
* frontend-model publish — or a synchronous throw inside a detached callback
|
|
647
|
+
* such as a driver socket or timer callback) as a real, visible, attributed
|
|
648
|
+
* test failure.
|
|
649
|
+
*
|
|
650
|
+
* Without this, such a rejection/exception has no handler, so on modern Node
|
|
651
|
+
* the process is TERMINATED — the run ends with no reported failures and CI
|
|
652
|
+
* just sees a crashed/retried shard with an empty result (the recurring
|
|
653
|
+
* "silent test-runner death": invisible and impossible to diagnose). Turning
|
|
654
|
+
* it into a failure makes the run go red with something debuggable instead of
|
|
655
|
+
* vanishing.
|
|
656
|
+
* @param {"uncaughtException" | "unhandledRejection"} kind - Async-crash kind.
|
|
657
|
+
* @param {unknown} reason - Rejection reason or thrown error.
|
|
658
|
+
* @returns {void}
|
|
659
|
+
*/
|
|
660
|
+
recordAsyncCrash(kind, reason) {
|
|
661
|
+
const error = reason instanceof Error ? reason : new Error(`${kind}: ${String(reason)}`)
|
|
662
|
+
const near = this._lastTestContext
|
|
663
|
+
const attribution = near ? `, near test: ${near.fullDescription} (${near.filePath}:${near.line})` : ""
|
|
664
|
+
|
|
665
|
+
this._failedTests = (this._failedTests || 0) + 1
|
|
666
|
+
this._failedTestDetails.push({
|
|
667
|
+
fullDescription: `<${kind} during test run${attribution}>`,
|
|
668
|
+
filePath: near ? near.filePath : "<test runner>",
|
|
669
|
+
line: near ? near.line : 0,
|
|
670
|
+
error,
|
|
671
|
+
consoleOutput: undefined
|
|
672
|
+
})
|
|
673
|
+
|
|
674
|
+
console.error(picocolors.red(`\n[test-runner] ${kind} during the test run — this would otherwise terminate the process silently and surface only as a crashed/retried shard with zero reported failures.${attribution}`))
|
|
675
|
+
console.error(error)
|
|
676
|
+
}
|
|
677
|
+
|
|
641
678
|
async run() {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
679
|
+
/**
|
|
680
|
+
* Handles a process-level unhandled rejection during the run.
|
|
681
|
+
* @param {unknown} reason - Rejection reason.
|
|
682
|
+
* @returns {void}
|
|
683
|
+
*/
|
|
684
|
+
const onUnhandledRejection = (reason) => {
|
|
685
|
+
// If a test attached its OWN unhandledRejection listener, it is
|
|
686
|
+
// intentionally observing/triggering the rejection (e.g. beacon
|
|
687
|
+
// error-reporting-spec.js) — Node dispatches to EVERY listener, so also
|
|
688
|
+
// failing the suite here would break those tests. Defer to the test's
|
|
689
|
+
// handler; only treat a rejection as a silent-death crash when ours is the
|
|
690
|
+
// sole listener (no persistent framework listener exists to mask this).
|
|
691
|
+
if (process.listenerCount("unhandledRejection") > 1) return
|
|
692
|
+
|
|
693
|
+
this.recordAsyncCrash("unhandledRejection", reason)
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Handles a process-level uncaught exception during the run — a
|
|
698
|
+
* synchronous throw inside a detached callback (driver socket, timer,
|
|
699
|
+
* event emitter) that no test await observes. Same silent-death mode as
|
|
700
|
+
* unhandled rejections: without a handler the process dies mid-run and CI
|
|
701
|
+
* sees a crashed shard with zero reported failures.
|
|
702
|
+
* @param {unknown} error - Thrown error.
|
|
703
|
+
* @returns {void}
|
|
704
|
+
*/
|
|
705
|
+
const onUncaughtException = (error) => {
|
|
706
|
+
// Mirror the unhandledRejection deferral: a test observing/triggering
|
|
707
|
+
// uncaught exceptions with its own listener owns them.
|
|
708
|
+
if (process.listenerCount("uncaughtException") > 1) return
|
|
709
|
+
|
|
710
|
+
this.recordAsyncCrash("uncaughtException", error)
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
process.on("unhandledRejection", onUnhandledRejection)
|
|
714
|
+
process.on("uncaughtException", onUncaughtException)
|
|
715
|
+
|
|
716
|
+
try {
|
|
717
|
+
await this.getConfiguration().ensureConnections({name: "Test runner suite"}, async () => {
|
|
718
|
+
await this.runTests({
|
|
719
|
+
afterEaches: [],
|
|
720
|
+
beforeEaches: [],
|
|
721
|
+
tests,
|
|
722
|
+
descriptions: [],
|
|
723
|
+
indentLevel: 0
|
|
724
|
+
})
|
|
725
|
+
|
|
726
|
+
// A rejection scheduled by the final test (a detached rejected promise,
|
|
727
|
+
// or an afterCommit callback rejecting as the suite drains) is reported
|
|
728
|
+
// by Node on a LATER turn. Drain a few turns while the handler is still
|
|
729
|
+
// attached — and connections still open — so those late rejections are
|
|
730
|
+
// recorded instead of escaping to the default crash path after cleanup.
|
|
731
|
+
for (let drainTurn = 0; drainTurn < 3; drainTurn++) {
|
|
732
|
+
await new Promise((resolve) => setImmediate(resolve))
|
|
733
|
+
}
|
|
649
734
|
})
|
|
650
|
-
}
|
|
735
|
+
} finally {
|
|
736
|
+
process.off("unhandledRejection", onUnhandledRejection)
|
|
737
|
+
process.off("uncaughtException", onUncaughtException)
|
|
738
|
+
}
|
|
651
739
|
}
|
|
652
740
|
|
|
653
741
|
/**
|
|
@@ -798,6 +886,14 @@ export default class TestRunner {
|
|
|
798
886
|
await beforeEachData.callback({configuration: this.getConfiguration(), testArgs, testData})
|
|
799
887
|
}
|
|
800
888
|
|
|
889
|
+
// Record which test is running so an async crash (an unhandled
|
|
890
|
+
// rejection detached from any await) that fires during or shortly
|
|
891
|
+
// after this test can be attributed to it in run()'s handler.
|
|
892
|
+
this._lastTestContext = {
|
|
893
|
+
fullDescription: this.buildFullDescription(descriptions, testDescription),
|
|
894
|
+
filePath: testData.filePath ?? "<unknown>",
|
|
895
|
+
line: testData.line ?? 0
|
|
896
|
+
}
|
|
801
897
|
await testData.function(testArgs)
|
|
802
898
|
this._successfulTests++
|
|
803
899
|
} finally {
|
|
@@ -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/time-zone.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/drop.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/cli/commands/lint/relationships.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/datetime-storage.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/migrations-ledger.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/remove-index.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/remove-index.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/remove-index.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/web-persistence.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/remove-index.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/remove-index-base.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/auditing.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/attachment-record.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/database/tenants/data-copier.js","../src/database/tenants/schema-cloner.js","../src/database/tenants/tenant-table-plan.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/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.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/packages/velocious-package.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/sync/conflict-strategy.js","../src/sync/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.js","../src/sync/peer-mutation-bundle.js","../src/sync/query-scope.js","../src/sync/server-change-feed.js","../src/sync/server-sequence-allocator.js","../src/sync/stable-json.js","../src/sync/sync-api-client-types.js","../src/sync/sync-api-client.js","../src/sync/sync-api-controller.js","../src/sync/sync-attribute-normalizer.js","../src/sync/sync-client-registry.js","../src/sync/sync-client-types.js","../src/sync/sync-client.js","../src/sync/sync-envelope-replay-service.js","../src/sync/sync-model-change-feed-service.js","../src/sync/sync-replay-upsert-applier.js","../src/sync/sync-resource-base.js","../src/sync/sync-scope-store.js","../src/tenants/default-tenant-database-provisioning.js","../src/tenants/tenant-iterator.js","../src/tenants/tenant.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/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/is-date.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/time-zone.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/drop.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/cli/commands/lint/relationships.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/datetime-storage.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/migrations-ledger.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/remove-index.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/remove-index.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/remove-index.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/web-persistence.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/remove-index.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/remove-index-base.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/auditing.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/validation-messages.js","../src/database/record/attachments/attachment-record.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/length.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/database/tenants/data-copier.js","../src/database/tenants/schema-cloner.js","../src/database/tenants/tenant-table-plan.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/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.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/packages/velocious-package.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/sync/conflict-strategy.js","../src/sync/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.js","../src/sync/peer-mutation-bundle.js","../src/sync/query-scope.js","../src/sync/server-change-feed.js","../src/sync/server-sequence-allocator.js","../src/sync/stable-json.js","../src/sync/sync-api-client-types.js","../src/sync/sync-api-client.js","../src/sync/sync-api-controller.js","../src/sync/sync-client-registry.js","../src/sync/sync-client-types.js","../src/sync/sync-client.js","../src/sync/sync-envelope-replay-service.js","../src/sync/sync-model-change-feed-service.js","../src/sync/sync-replay-upsert-applier.js","../src/sync/sync-resource-base.js","../src/sync/sync-scope-store.js","../src/tenants/default-tenant-database-provisioning.js","../src/tenants/tenant-iterator.js","../src/tenants/tenant.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/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/is-date.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"}
|
package/package.json
CHANGED
package/scripts/run-tests.js
CHANGED
|
@@ -27,6 +27,12 @@ async function main() {
|
|
|
27
27
|
return
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
// A non-zero exit without the runner's own failure summary is the
|
|
31
|
+
// "silent test-runner death" mode (e.g. a hard process.exit or native
|
|
32
|
+
// crash). Always print the exit code so CI logs show that the child
|
|
33
|
+
// died rather than ending the log mid-run with no explanation.
|
|
34
|
+
if (code !== 0) console.error(`Test process exited with code: ${code ?? "unknown"}`)
|
|
35
|
+
|
|
30
36
|
resolve(code ?? 1)
|
|
31
37
|
})
|
|
32
38
|
}).then((code) => {
|
|
@@ -48,6 +48,7 @@ import { normalizeDateStringForWrite, normalizeDateValueForRead, normalizeDateVa
|
|
|
48
48
|
import {formatValue} from "../../utils/format-value.js"
|
|
49
49
|
import {captureCreateAuditChanges, captureUpdateAuditChanges, createAudit, createCreateAudit, createDestroyAudit, createUpdateAudit, registerAuditCallback, registerAuditing, withoutAudit} from "./auditing.js"
|
|
50
50
|
import ValidatorsFormat from "./validators/format.js"
|
|
51
|
+
import ValidatorsLength from "./validators/length.js"
|
|
51
52
|
import ValidatorsPresence from "./validators/presence.js"
|
|
52
53
|
import ValidatorsUniqueness from "./validators/uniqueness.js"
|
|
53
54
|
import registerActsAsListCallbacks from "./acts-as-list.js"
|
|
@@ -4403,6 +4404,7 @@ class VelociousDatabaseRecord {
|
|
|
4403
4404
|
*/
|
|
4404
4405
|
|
|
4405
4406
|
VelociousDatabaseRecord.registerValidatorType("format", ValidatorsFormat)
|
|
4407
|
+
VelociousDatabaseRecord.registerValidatorType("length", ValidatorsLength)
|
|
4406
4408
|
VelociousDatabaseRecord.registerValidatorType("presence", ValidatorsPresence)
|
|
4407
4409
|
VelociousDatabaseRecord.registerValidatorType("uniqueness", ValidatorsUniqueness)
|
|
4408
4410
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Translates a validation message ID into a localized message.
|
|
5
|
+
* @callback ValidationMessageTranslator
|
|
6
|
+
* @param {string} msgID - Stable message ID (e.g. "velocious.errors.messages.blank").
|
|
7
|
+
* @param {Record<string, string | number> & {defaultValue?: string}} [args] - Interpolation variables plus the English default message.
|
|
8
|
+
* @returns {string} Localized message.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* English default validation message predicates keyed by message type,
|
|
13
|
+
* matching Rails' `errors.messages.*` where an equivalent exists. Values may
|
|
14
|
+
* contain `%{variable}` placeholders.
|
|
15
|
+
* @type {Record<string, string>}
|
|
16
|
+
*/
|
|
17
|
+
export const VALIDATION_MESSAGE_DEFAULTS = {
|
|
18
|
+
blank: "can't be blank",
|
|
19
|
+
taken: "has already been taken",
|
|
20
|
+
too_long: "is too long (maximum is %{count} characters)",
|
|
21
|
+
too_short: "is too short (minimum is %{count} characters)"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Builds a validation message predicate through the framework's translation
|
|
26
|
+
* layer. The message is looked up under `velocious.errors.messages.<type>`
|
|
27
|
+
* with the English default as fallback; `%{variable}` placeholders are
|
|
28
|
+
* interpolated from the given variables. Without a translator the English
|
|
29
|
+
* default is interpolated directly.
|
|
30
|
+
* @param {object} args - Options.
|
|
31
|
+
* @param {ValidationMessageTranslator | null} [args.translator] - Translator resolving message IDs (usually `configuration.getTranslator()`).
|
|
32
|
+
* @param {string} args.type - Message type key in {@link VALIDATION_MESSAGE_DEFAULTS}.
|
|
33
|
+
* @param {Record<string, string | number>} [args.variables] - Interpolation variables.
|
|
34
|
+
* @returns {string} Localized message predicate.
|
|
35
|
+
*/
|
|
36
|
+
export default function validationMessage({translator, type, variables}) {
|
|
37
|
+
const defaultMessage = VALIDATION_MESSAGE_DEFAULTS[type]
|
|
38
|
+
|
|
39
|
+
if (!defaultMessage) throw new Error(`Unknown validation message type: ${String(type)}`)
|
|
40
|
+
|
|
41
|
+
if (translator) return translator(`velocious.errors.messages.${type}`, {...variables, defaultValue: defaultMessage})
|
|
42
|
+
|
|
43
|
+
let message = defaultMessage
|
|
44
|
+
|
|
45
|
+
for (const [variableName, variableValue] of Object.entries(variables ?? {})) {
|
|
46
|
+
message = message.replaceAll(`%{${variableName}}`, String(variableValue))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return message
|
|
50
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import Base from "./base.js"
|
|
4
|
+
import validationMessage from "../validation-messages.js"
|
|
5
|
+
|
|
6
|
+
export default class VelociousDatabaseRecordValidatorsLength extends Base {
|
|
7
|
+
/**
|
|
8
|
+
* Runs validate: bounds the value's string length by the `maximum` and/or
|
|
9
|
+
* `minimum` options. Absent values (null/undefined/"") are skipped — they
|
|
10
|
+
* are the presence validator's concern.
|
|
11
|
+
* @param {object} args - Options object.
|
|
12
|
+
* @param {import("../index.js").default} args.model - Model instance.
|
|
13
|
+
* @param {string} args.attributeName - Attribute name.
|
|
14
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
15
|
+
*/
|
|
16
|
+
async validate({model, attributeName}) {
|
|
17
|
+
const maximum = this.args?.maximum
|
|
18
|
+
const minimum = this.args?.minimum
|
|
19
|
+
|
|
20
|
+
if (typeof maximum != "number" && typeof minimum != "number") {
|
|
21
|
+
throw new Error("length validator requires a maximum and/or minimum option")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const rawValue = model.readAttribute(attributeName)
|
|
25
|
+
|
|
26
|
+
if (rawValue === null || rawValue === undefined || rawValue === "") return
|
|
27
|
+
|
|
28
|
+
const valueLength = String(rawValue).length
|
|
29
|
+
const translator = model.getModelClass()._getConfiguration().getTranslator()
|
|
30
|
+
|
|
31
|
+
if (typeof maximum == "number" && valueLength > maximum) {
|
|
32
|
+
this._addError(model, attributeName, validationMessage({translator, type: "too_long", variables: {count: maximum}}))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (typeof minimum == "number" && valueLength < minimum) {
|
|
36
|
+
this._addError(model, attributeName, validationMessage({translator, type: "too_short", variables: {count: minimum}}))
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Adds a length validation error to the model.
|
|
42
|
+
* @param {import("../index.js").default} model - Model instance.
|
|
43
|
+
* @param {string} attributeName - Attribute name.
|
|
44
|
+
* @param {string} message - Translated message predicate.
|
|
45
|
+
* @returns {void}
|
|
46
|
+
*/
|
|
47
|
+
_addError(model, attributeName, message) {
|
|
48
|
+
if (!(attributeName in model._validationErrors)) model._validationErrors[attributeName] = []
|
|
49
|
+
|
|
50
|
+
model._validationErrors[attributeName].push({type: "length", message})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import Base from "./base.js"
|
|
4
|
+
import validationMessage from "../validation-messages.js"
|
|
4
5
|
|
|
5
6
|
export default class VelociousDatabaseRecordValidatorsPresence extends Base {
|
|
6
7
|
/**
|
|
@@ -16,7 +17,9 @@ export default class VelociousDatabaseRecordValidatorsPresence extends Base {
|
|
|
16
17
|
if (!attributeValue) {
|
|
17
18
|
if (!(attributeName in model._validationErrors)) model._validationErrors[attributeName] = []
|
|
18
19
|
|
|
19
|
-
model.
|
|
20
|
+
const translator = model.getModelClass()._getConfiguration().getTranslator()
|
|
21
|
+
|
|
22
|
+
model._validationErrors[attributeName].push({type: "presence", message: validationMessage({translator, type: "blank"})})
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import Base from "./base.js"
|
|
4
4
|
import * as inflection from "inflection"
|
|
5
|
+
import validationMessage from "../validation-messages.js"
|
|
5
6
|
|
|
6
7
|
export default class VelociousDatabaseRecordValidatorsUniqueness extends Base {
|
|
7
8
|
/**
|
|
@@ -61,7 +62,9 @@ export default class VelociousDatabaseRecordValidatorsUniqueness extends Base {
|
|
|
61
62
|
if (existingRecord) {
|
|
62
63
|
if (!(attributeName in model._validationErrors)) model._validationErrors[attributeName] = []
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
const translator = modelClass._getConfiguration().getTranslator()
|
|
66
|
+
|
|
67
|
+
model._validationErrors[attributeName].push({type: "uniqueness", message: validationMessage({translator, type: "taken"})})
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
|