velocious 1.0.563 → 1.0.564

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/README.md +2 -0
  2. package/build/background-jobs/cron-expression.js +12 -13
  3. package/build/background-jobs/main.js +6 -6
  4. package/build/background-jobs/runner-graceful-shutdown.js +2 -3
  5. package/build/background-jobs/scheduler.js +3 -3
  6. package/build/background-jobs/worker.js +8 -9
  7. package/build/beacon/client.js +3 -4
  8. package/build/database/drivers/sqlite/web-persistence.js +2 -5
  9. package/build/database/pool/async-tracked-multi-connection.js +65 -15
  10. package/build/database/pool/base.js +23 -7
  11. package/build/database/query/index.js +21 -22
  12. package/build/database/query/model-class-query.js +5 -6
  13. package/build/database/record/attachments/normalize-input.js +9 -10
  14. package/build/database/record/attachments/store.js +2 -2
  15. package/build/database/record/auditing.js +7 -8
  16. package/build/database/record/index.js +4 -5
  17. package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +1 -2
  18. package/build/frontend-model-controller.js +49 -56
  19. package/build/frontend-models/base.js +17 -19
  20. package/build/frontend-models/outgoing-event-buffer.js +3 -4
  21. package/build/frontend-models/query.js +40 -44
  22. package/build/frontend-models/resource-definition.js +7 -8
  23. package/build/frontend-models/transport-serialization.js +10 -12
  24. package/build/frontend-models/websocket-channel.js +12 -13
  25. package/build/http-server/client/websocket-session.js +4 -5
  26. package/build/http-server/client-delivery-queue.js +7 -8
  27. package/build/http-server/websocket-event-log-store.js +4 -6
  28. package/build/plugins/sqljs-wasm-route.js +3 -5
  29. package/build/src/background-jobs/cron-expression.d.ts +0 -12
  30. package/build/src/background-jobs/cron-expression.d.ts.map +1 -1
  31. package/build/src/background-jobs/cron-expression.js +13 -13
  32. package/build/src/background-jobs/main.d.ts.map +1 -1
  33. package/build/src/background-jobs/main.js +7 -7
  34. package/build/src/background-jobs/runner-graceful-shutdown.d.ts +0 -6
  35. package/build/src/background-jobs/runner-graceful-shutdown.d.ts.map +1 -1
  36. package/build/src/background-jobs/runner-graceful-shutdown.js +3 -3
  37. package/build/src/background-jobs/scheduler.d.ts +0 -3
  38. package/build/src/background-jobs/scheduler.d.ts.map +1 -1
  39. package/build/src/background-jobs/scheduler.js +4 -4
  40. package/build/src/background-jobs/worker.d.ts +0 -8
  41. package/build/src/background-jobs/worker.d.ts.map +1 -1
  42. package/build/src/background-jobs/worker.js +9 -9
  43. package/build/src/beacon/client.d.ts +0 -4
  44. package/build/src/beacon/client.d.ts.map +1 -1
  45. package/build/src/beacon/client.js +4 -4
  46. package/build/src/database/drivers/sqlite/web-persistence.d.ts +0 -14
  47. package/build/src/database/drivers/sqlite/web-persistence.d.ts.map +1 -1
  48. package/build/src/database/drivers/sqlite/web-persistence.js +3 -3
  49. package/build/src/database/pool/async-tracked-multi-connection.d.ts +29 -1
  50. package/build/src/database/pool/async-tracked-multi-connection.d.ts.map +1 -1
  51. package/build/src/database/pool/async-tracked-multi-connection.js +57 -15
  52. package/build/src/database/pool/base.d.ts +53 -4
  53. package/build/src/database/pool/base.d.ts.map +1 -1
  54. package/build/src/database/pool/base.js +23 -6
  55. package/build/src/database/query/index.d.ts +18 -39
  56. package/build/src/database/query/index.d.ts.map +1 -1
  57. package/build/src/database/query/index.js +22 -22
  58. package/build/src/database/query/model-class-query.d.ts +0 -5
  59. package/build/src/database/query/model-class-query.d.ts.map +1 -1
  60. package/build/src/database/query/model-class-query.js +6 -6
  61. package/build/src/database/record/attachments/normalize-input.d.ts +0 -9
  62. package/build/src/database/record/attachments/normalize-input.d.ts.map +1 -1
  63. package/build/src/database/record/attachments/normalize-input.js +10 -10
  64. package/build/src/database/record/attachments/store.d.ts.map +1 -1
  65. package/build/src/database/record/attachments/store.js +2 -2
  66. package/build/src/database/record/auditing.d.ts +17 -24
  67. package/build/src/database/record/auditing.d.ts.map +1 -1
  68. package/build/src/database/record/auditing.js +8 -8
  69. package/build/src/database/record/index.d.ts +4 -4
  70. package/build/src/database/record/index.d.ts.map +1 -1
  71. package/build/src/database/record/index.js +5 -5
  72. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +0 -39
  73. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
  74. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +2 -2
  75. package/build/src/frontend-model-controller.d.ts +1 -1
  76. package/build/src/frontend-model-controller.d.ts.map +1 -1
  77. package/build/src/frontend-model-controller.js +50 -50
  78. package/build/src/frontend-models/base.d.ts.map +1 -1
  79. package/build/src/frontend-models/base.js +18 -18
  80. package/build/src/frontend-models/outgoing-event-buffer.d.ts.map +1 -1
  81. package/build/src/frontend-models/outgoing-event-buffer.js +3 -3
  82. package/build/src/frontend-models/query.d.ts +56 -37
  83. package/build/src/frontend-models/query.d.ts.map +1 -1
  84. package/build/src/frontend-models/query.js +39 -39
  85. package/build/src/frontend-models/resource-definition.d.ts +0 -7
  86. package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
  87. package/build/src/frontend-models/resource-definition.js +8 -8
  88. package/build/src/frontend-models/transport-serialization.d.ts +0 -10
  89. package/build/src/frontend-models/transport-serialization.d.ts.map +1 -1
  90. package/build/src/frontend-models/transport-serialization.js +11 -11
  91. package/build/src/frontend-models/websocket-channel.d.ts +0 -12
  92. package/build/src/frontend-models/websocket-channel.d.ts.map +1 -1
  93. package/build/src/frontend-models/websocket-channel.js +13 -13
  94. package/build/src/http-server/client/websocket-session.d.ts.map +1 -1
  95. package/build/src/http-server/client/websocket-session.js +5 -5
  96. package/build/src/http-server/client-delivery-queue.d.ts +7 -7
  97. package/build/src/http-server/client-delivery-queue.d.ts.map +1 -1
  98. package/build/src/http-server/client-delivery-queue.js +8 -8
  99. package/build/src/http-server/websocket-event-log-store.d.ts +0 -14
  100. package/build/src/http-server/websocket-event-log-store.d.ts.map +1 -1
  101. package/build/src/http-server/websocket-event-log-store.js +5 -5
  102. package/build/src/plugins/sqljs-wasm-route.d.ts.map +1 -1
  103. package/build/src/plugins/sqljs-wasm-route.js +4 -4
  104. package/build/src/sync/conflict-strategy.d.ts +0 -15
  105. package/build/src/sync/conflict-strategy.d.ts.map +1 -1
  106. package/build/src/sync/conflict-strategy.js +3 -3
  107. package/build/src/sync/device-identity.d.ts +0 -45
  108. package/build/src/sync/device-identity.d.ts.map +1 -1
  109. package/build/src/sync/device-identity.js +4 -4
  110. package/build/src/sync/local-mutation-log.d.ts +0 -41
  111. package/build/src/sync/local-mutation-log.d.ts.map +1 -1
  112. package/build/src/sync/local-mutation-log.js +9 -9
  113. package/build/src/sync/offline-grant.d.ts +0 -26
  114. package/build/src/sync/offline-grant.d.ts.map +1 -1
  115. package/build/src/sync/offline-grant.js +4 -4
  116. package/build/src/sync/peer-mutation-bundle.d.ts +0 -14
  117. package/build/src/sync/peer-mutation-bundle.d.ts.map +1 -1
  118. package/build/src/sync/peer-mutation-bundle.js +3 -3
  119. package/build/src/sync/server-change-feed.d.ts.map +1 -1
  120. package/build/src/sync/server-change-feed.js +33 -33
  121. package/build/src/sync/sync-api-client.d.ts +0 -9
  122. package/build/src/sync/sync-api-client.d.ts.map +1 -1
  123. package/build/src/sync/sync-api-client.js +2 -2
  124. package/build/src/sync/sync-envelope-replay-service.d.ts +38 -21
  125. package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
  126. package/build/src/sync/sync-envelope-replay-service.js +18 -18
  127. package/build/src/sync/sync-resource-base.d.ts +0 -7
  128. package/build/src/sync/sync-resource-base.d.ts.map +1 -1
  129. package/build/src/sync/sync-resource-base.js +2 -2
  130. package/build/src/sync/sync-scope-store.d.ts +0 -9
  131. package/build/src/sync/sync-scope-store.d.ts.map +1 -1
  132. package/build/src/sync/sync-scope-store.js +10 -10
  133. package/build/src/testing/test-filter-parser.d.ts +0 -10
  134. package/build/src/testing/test-filter-parser.d.ts.map +1 -1
  135. package/build/src/testing/test-filter-parser.js +11 -11
  136. package/build/src/testing/test-runner.d.ts +25 -91
  137. package/build/src/testing/test-runner.d.ts.map +1 -1
  138. package/build/src/testing/test-runner.js +113 -98
  139. package/build/src/testing/test.d.ts +8 -0
  140. package/build/src/testing/test.d.ts.map +1 -1
  141. package/build/src/testing/test.js +9 -9
  142. package/build/src/utils/backtrace-cleaner.d.ts.map +1 -1
  143. package/build/src/utils/backtrace-cleaner.js +9 -9
  144. package/build/src/utils/model-scope.d.ts +0 -8
  145. package/build/src/utils/model-scope.d.ts.map +1 -1
  146. package/build/src/utils/model-scope.js +3 -3
  147. package/build/src/utils/ransack.d.ts +52 -19
  148. package/build/src/utils/ransack.d.ts.map +1 -1
  149. package/build/src/utils/ransack.js +26 -26
  150. package/build/sync/conflict-strategy.js +3 -6
  151. package/build/sync/device-identity.js +4 -9
  152. package/build/sync/local-mutation-log.js +9 -14
  153. package/build/sync/offline-grant.js +4 -7
  154. package/build/sync/peer-mutation-bundle.js +2 -4
  155. package/build/sync/server-change-feed.js +32 -34
  156. package/build/sync/sync-api-client.js +1 -2
  157. package/build/sync/sync-envelope-replay-service.js +17 -19
  158. package/build/sync/sync-resource-base.js +1 -2
  159. package/build/sync/sync-scope-store.js +9 -10
  160. package/build/testing/test-filter-parser.js +10 -11
  161. package/build/testing/test-runner.js +116 -108
  162. package/build/testing/test.js +8 -9
  163. package/build/utils/backtrace-cleaner.js +8 -9
  164. package/build/utils/model-scope.js +3 -4
  165. package/build/utils/ransack.js +27 -34
  166. package/package.json +2 -1
  167. package/scripts/eslint-rules/typedefs-first.js +67 -0
  168. package/scripts/prewarm-chromedriver.js +26 -0
  169. package/src/background-jobs/cron-expression.js +12 -13
  170. package/src/background-jobs/main.js +6 -6
  171. package/src/background-jobs/runner-graceful-shutdown.js +2 -3
  172. package/src/background-jobs/scheduler.js +3 -3
  173. package/src/background-jobs/worker.js +8 -9
  174. package/src/beacon/client.js +3 -4
  175. package/src/database/drivers/sqlite/web-persistence.js +2 -5
  176. package/src/database/pool/async-tracked-multi-connection.js +65 -15
  177. package/src/database/pool/base.js +23 -7
  178. package/src/database/query/index.js +21 -22
  179. package/src/database/query/model-class-query.js +5 -6
  180. package/src/database/record/attachments/normalize-input.js +9 -10
  181. package/src/database/record/attachments/store.js +2 -2
  182. package/src/database/record/auditing.js +7 -8
  183. package/src/database/record/index.js +4 -5
  184. package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +1 -2
  185. package/src/frontend-model-controller.js +49 -56
  186. package/src/frontend-models/base.js +17 -19
  187. package/src/frontend-models/outgoing-event-buffer.js +3 -4
  188. package/src/frontend-models/query.js +40 -44
  189. package/src/frontend-models/resource-definition.js +7 -8
  190. package/src/frontend-models/transport-serialization.js +10 -12
  191. package/src/frontend-models/websocket-channel.js +12 -13
  192. package/src/http-server/client/websocket-session.js +4 -5
  193. package/src/http-server/client-delivery-queue.js +7 -8
  194. package/src/http-server/websocket-event-log-store.js +4 -6
  195. package/src/plugins/sqljs-wasm-route.js +3 -5
  196. package/src/sync/conflict-strategy.js +3 -6
  197. package/src/sync/device-identity.js +4 -9
  198. package/src/sync/local-mutation-log.js +9 -14
  199. package/src/sync/offline-grant.js +4 -7
  200. package/src/sync/peer-mutation-bundle.js +2 -4
  201. package/src/sync/server-change-feed.js +32 -34
  202. package/src/sync/sync-api-client.js +1 -2
  203. package/src/sync/sync-envelope-replay-service.js +17 -19
  204. package/src/sync/sync-resource-base.js +1 -2
  205. package/src/sync/sync-scope-store.js +9 -10
  206. package/src/testing/test-filter-parser.js +10 -11
  207. package/src/testing/test-runner.js +116 -108
  208. package/src/testing/test.js +8 -9
  209. package/src/utils/backtrace-cleaner.js +8 -9
  210. package/src/utils/model-scope.js +3 -4
  211. package/src/utils/ransack.js +27 -34
package/README.md CHANGED
@@ -1873,6 +1873,8 @@ If you are developing on Velocious, you can run the tests with:
1873
1873
 
1874
1874
  Tests default to a 60-second timeout. Override per test with `{timeoutSeconds: 5}` or set a suite-wide default via `configureTests({defaultTimeoutSeconds: 30})`.
1875
1875
 
1876
+ Request tests share transaction-active, non-tenant database connections with their in-process HTTP handlers. Eligibility is evaluated when each request is dispatched, so a hook can start a transaction and issue a request in the same callback. This makes uncommitted setup visible to handlers while preserving rollback isolation. Without an active transaction, handlers use independent pooled connections, so concurrency and locking tests can opt out of transaction cleanup and exercise production-style connections. Shared connection state is scoped to the test lifecycle and cleared around each test. See [docs/testing-guidelines.md](docs/testing-guidelines.md#request-test-database-connections).
1877
+
1876
1878
  # Writing a request test
1877
1879
 
1878
1880
  First create a test file under something like the following path 'src/routes/accounts/create-test.js' with something like the following content:
@@ -1,3 +1,15 @@
1
+ /**
2
+ * ParsedCron type.
3
+ * @typedef {object} ParsedCron
4
+ * @property {Set<number>} minute - Allowed minute values (0-59).
5
+ * @property {Set<number>} hour - Allowed hour values (0-23).
6
+ * @property {Set<number>} dayOfMonth - Allowed day-of-month values (1-31).
7
+ * @property {Set<number>} month - Allowed month values (1-12).
8
+ * @property {Set<number>} dayOfWeek - Allowed day-of-week values (0-6, 0=Sun).
9
+ * @property {boolean} dayOfMonthRestricted - True when the dayOfMonth field is not `?`.
10
+ * @property {boolean} dayOfWeekRestricted - True when the dayOfWeek field is not `?`.
11
+ * @property {string} expression - Original expression for diagnostics.
12
+ */
1
13
  // @ts-check
2
14
 
3
15
  /**
@@ -36,19 +48,6 @@ const FIELDS = [
36
48
  {name: "dayOfWeek", min: 0, max: 7, names: DAY_NAMES}
37
49
  ]
38
50
 
39
- /**
40
- * ParsedCron type.
41
- * @typedef {object} ParsedCron
42
- * @property {Set<number>} minute - Allowed minute values (0-59).
43
- * @property {Set<number>} hour - Allowed hour values (0-23).
44
- * @property {Set<number>} dayOfMonth - Allowed day-of-month values (1-31).
45
- * @property {Set<number>} month - Allowed month values (1-12).
46
- * @property {Set<number>} dayOfWeek - Allowed day-of-week values (0-6, 0=Sun).
47
- * @property {boolean} dayOfMonthRestricted - True when the dayOfMonth field is not `?`.
48
- * @property {boolean} dayOfWeekRestricted - True when the dayOfWeek field is not `?`.
49
- * @property {string} expression - Original expression for diagnostics.
50
- */
51
-
52
51
  /**
53
52
  * Runs the parseCronExpression helper.
54
53
  * @param {string} expression - Cron expression or shortcut.
@@ -9,6 +9,12 @@ import PruneTerminalBackgroundJobsJob from "../jobs/prune-terminal-background-jo
9
9
  import VelociousError from "../velocious-error.js"
10
10
  import shutdownLifecycle from "../utils/shutdown-lifecycle.js"
11
11
 
12
+ /**
13
+ * WorkerExecutionModeCapability type.
14
+ * @typedef {object} WorkerExecutionModeCapability
15
+ * @property {import("./types.js").BackgroundJobExecutionMode} executionMode - Execution mode.
16
+ * @property {(worker: JsonSocket) => boolean} accepts - Whether the worker accepts this mode.
17
+ */
12
18
  /**
13
19
  * Channel used by `background-jobs-main` to coordinate dispatch wake-ups
14
20
  * across processes via Beacon. Workers do NOT subscribe to this channel
@@ -28,12 +34,6 @@ const MAX_TIMER_MS = 2_147_483_647 // ~24.8 days
28
34
  const WORKER_STALE_TIMEOUT_MS = 60000
29
35
  /** How often the main scans workers for staleness. */
30
36
  const WORKER_LIVENESS_SWEEP_MS = 15000
31
- /**
32
- * WorkerExecutionModeCapability type.
33
- * @typedef {object} WorkerExecutionModeCapability
34
- * @property {import("./types.js").BackgroundJobExecutionMode} executionMode - Execution mode.
35
- * @property {(worker: JsonSocket) => boolean} accepts - Whether the worker accepts this mode.
36
- */
37
37
  /**
38
38
  * Worker execution mode capabilities.
39
39
  * @type {WorkerExecutionModeCapability[]} */
@@ -4,15 +4,14 @@ import timeout from "awaitery/build/timeout.js"
4
4
 
5
5
  import Configuration, {CurrentConfigurationNotSetError} from "../configuration.js"
6
6
 
7
- /** Bounded grace for closing framework connections on shutdown before forcing exit. */
8
- const SHUTDOWN_CLOSE_TIMEOUT_MS = 5000
9
-
10
7
  /**
11
8
  * The subset of a configuration a runner closes on shutdown. Typed structurally so
12
9
  * the shutdown path stays typechecked without a broad cast, and a future signature
13
10
  * drift surfaces at the call sites (and in tests) instead of hiding behind `any`.
14
11
  * @typedef {{disconnectBeacon: () => Promise<void>, closeDatabaseConnections: () => Promise<void>}} RunnerCloseableConfiguration
15
12
  */
13
+ /** Bounded grace for closing framework connections on shutdown before forcing exit. */
14
+ const SHUTDOWN_CLOSE_TIMEOUT_MS = 5000
16
15
 
17
16
  /**
18
17
  * Gracefully closes a background-job runner's framework connections (beacon +
@@ -3,6 +3,9 @@
3
3
  import Logger from "../logger.js"
4
4
  import {nextCronFireDate, parseCronExpression} from "./cron-expression.js"
5
5
 
6
+ /**
7
+ * DurationUnit type.
8
+ * @typedef {keyof typeof DURATION_MULTIPLIERS} DurationUnit */
6
9
  const DURATION_MULTIPLIERS = {
7
10
  d: 24 * 60 * 60 * 1000,
8
11
  day: 24 * 60 * 60 * 1000,
@@ -21,9 +24,6 @@ const DURATION_MULTIPLIERS = {
21
24
  week: 7 * 24 * 60 * 60 * 1000,
22
25
  weeks: 7 * 24 * 60 * 60 * 1000
23
26
  }
24
- /**
25
- * DurationUnit type.
26
- * @typedef {keyof typeof DURATION_MULTIPLIERS} DurationUnit */
27
27
 
28
28
  /**
29
29
  * Runs the parseScheduledDuration helper.
@@ -10,6 +10,14 @@ import {randomUUID} from "crypto"
10
10
  import {fileURLToPath} from "node:url"
11
11
  import shutdownLifecycle from "../utils/shutdown-lifecycle.js"
12
12
 
13
+ /**
14
+ * Per-forked-child timeout bookkeeping.
15
+ * @typedef {object} ForkedJobTimeoutState
16
+ * @property {boolean} timedOut - Whether the timeout fired and the child was terminated.
17
+ * @property {number | null} timeoutMs - The armed timeout in ms, or null when disabled.
18
+ * @property {ReturnType<typeof setTimeout> | null} timer - The pending timeout timer, cleared on exit.
19
+ * @property {ReturnType<typeof setTimeout> | null} sigkillTimer - The pending SIGKILL grace timer, cleared on exit.
20
+ */
13
21
  /** Grace period after SIGTERM before a lingering process runner is SIGKILLed. */
14
22
  const FORKED_CHILD_SIGKILL_GRACE_MS = 5000
15
23
  /**
@@ -48,15 +56,6 @@ function positiveNumber(value) {
48
56
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined
49
57
  }
50
58
 
51
- /**
52
- * Per-forked-child timeout bookkeeping.
53
- * @typedef {object} ForkedJobTimeoutState
54
- * @property {boolean} timedOut - Whether the timeout fired and the child was terminated.
55
- * @property {number | null} timeoutMs - The armed timeout in ms, or null when disabled.
56
- * @property {ReturnType<typeof setTimeout> | null} timer - The pending timeout timer, cleared on exit.
57
- * @property {ReturnType<typeof setTimeout> | null} sigkillTimer - The pending SIGKILL grace timer, cleared on exit.
58
- */
59
-
60
59
  export default class BackgroundJobsWorker {
61
60
  /**
62
61
  * Runs constructor.
@@ -7,14 +7,13 @@ import timeout from "awaitery/build/timeout.js"
7
7
  import JsonSocket from "../background-jobs/json-socket.js"
8
8
  import EventEmitter from "../utils/event-emitter.js"
9
9
 
10
- const DEFAULT_RECONNECT_DELAY_MS = 1000
11
- const MAX_RECONNECT_DELAY_MS = 30_000
12
- const DEFAULT_CLOSE_TIMEOUT_MS = 1000
13
-
14
10
  /**
15
11
  * BeaconBroadcastHandler type.
16
12
  * @typedef {function(import("./types.js").BeaconBroadcastMessage): void} BeaconBroadcastHandler
17
13
  */
14
+ const DEFAULT_RECONNECT_DELAY_MS = 1000
15
+ const MAX_RECONNECT_DELAY_MS = 30_000
16
+ const DEFAULT_CLOSE_TIMEOUT_MS = 1000
18
17
 
19
18
  /**
20
19
  * BeaconClient connects to a `velocious beacon` daemon and exchanges
@@ -2,9 +2,6 @@
2
2
 
3
3
  import BetterLocalStorage from "better-localstorage"
4
4
 
5
- const SUPPORT_CHECK_FILE = ".velocious-opfs-support-check"
6
- const SUPPORT_CHECK_BYTES = new Uint8Array([118, 101, 108, 111, 99, 105, 111, 117, 115])
7
-
8
5
  /**
9
6
  * SQLite web persistence adapter.
10
7
  * @typedef {object} SqliteWebPersistence
@@ -13,13 +10,14 @@ const SUPPORT_CHECK_BYTES = new Uint8Array([118, 101, 108, 111, 99, 105, 111, 11
13
10
  * @property {() => Promise<Uint8Array | undefined>} load - Loads persisted database bytes.
14
11
  * @property {(content: Uint8Array) => Promise<void>} save - Saves persisted database bytes.
15
12
  */
16
-
17
13
  /**
18
14
  * Browser-like environment used for web persistence detection.
19
15
  * @typedef {object} SqliteWebPersistenceEnvironment
20
16
  * @property {unknown} [indexedDB] - IndexedDB global.
21
17
  * @property {unknown} [navigator] - Navigator global.
22
18
  */
19
+ const SUPPORT_CHECK_FILE = ".velocious-opfs-support-check"
20
+ const SUPPORT_CHECK_BYTES = new Uint8Array([118, 101, 108, 111, 99, 105, 111, 117, 115])
23
21
 
24
22
  /**
25
23
  * Creates the best SQLite web persistence adapter supported by the current browser.
@@ -297,7 +295,6 @@ class LocalStoragePersistence {
297
295
  }
298
296
  }
299
297
 
300
-
301
298
  /**
302
299
  * Selects the preferred available SQLite web persistence backend.
303
300
  * @param {object} args - Arguments.
@@ -3,14 +3,6 @@
3
3
  import {AsyncLocalStorage} from "async_hooks"
4
4
  import BasePool, {POOL_CONFIGURATION_KEY} from "./base.js"
5
5
 
6
- export const CLOSED_CONNECTION = Symbol("velociousClosedConnection")
7
- const IDLE_CONNECTION_CHECKED_IN_AT = Symbol("velociousIdleConnectionCheckedInAt")
8
- const CONNECTION_CHECKED_OUT_AT = Symbol("velociousConnectionCheckedOutAt")
9
- const SUPPRESSED_CONNECTION_CONTEXT = Symbol("velociousSuppressedConnectionContext")
10
- const DEFAULT_MAX_CONNECTIONS = 10
11
- const DEFAULT_IDLE_TIMEOUT_MILLIS = 5000
12
- const DEFAULT_CHECKOUT_TIMEOUT_MILLIS = 10000
13
-
14
6
  /**
15
7
  * PendingCheckout type.
16
8
  * @typedef {object} PendingCheckout
@@ -24,6 +16,13 @@ const DEFAULT_CHECKOUT_TIMEOUT_MILLIS = 10000
24
16
  * @property {number | null} timeoutMillis - Milliseconds to wait before rejecting, or null when disabled.
25
17
  * @property {ReturnType<typeof setTimeout> | undefined} timeoutTimer - Timer that rejects the pending checkout.
26
18
  */
19
+ export const CLOSED_CONNECTION = Symbol("velociousClosedConnection")
20
+ const IDLE_CONNECTION_CHECKED_IN_AT = Symbol("velociousIdleConnectionCheckedInAt")
21
+ const CONNECTION_CHECKED_OUT_AT = Symbol("velociousConnectionCheckedOutAt")
22
+ const SUPPRESSED_CONNECTION_CONTEXT = Symbol("velociousSuppressedConnectionContext")
23
+ const DEFAULT_MAX_CONNECTIONS = 10
24
+ const DEFAULT_IDLE_TIMEOUT_MILLIS = 5000
25
+ const DEFAULT_CHECKOUT_TIMEOUT_MILLIS = 10000
27
26
 
28
27
  export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends BasePool {
29
28
  /**
@@ -42,6 +41,18 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
42
41
  */
43
42
  _testSharedConnection = undefined
44
43
 
44
+ /**
45
+ * Dynamically resolves the connection eligible for in-process test request sharing.
46
+ * @type {(() => import("../drivers/base.js").default | undefined) | undefined}
47
+ */
48
+ _testSharedConnectionProvider = undefined
49
+
50
+ /**
51
+ * Identifies the lifecycle that installed the current shared connection or provider.
52
+ * @type {import("./base.js").TestSharedConnectionRegistration | undefined}
53
+ */
54
+ _testSharedConnectionRegistration = undefined
55
+
45
56
  /**
46
57
  * Connections.
47
58
  * @type {import("../drivers/base.js").default[]} */
@@ -797,17 +808,44 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
797
808
  * Set a shared connection for test mode so that HTTP handlers running
798
809
  * in the same process can reuse the test runner's database connection.
799
810
  * @param {import("../drivers/base.js").default} connection - Shared connection.
800
- * @returns {void}
811
+ * @returns {import("./base.js").TestSharedConnectionRegistration} - Opaque registration handle.
801
812
  */
802
813
  setTestSharedConnection(connection) {
814
+ const registration = {owner: Symbol("test-shared-connection")}
815
+
803
816
  this._testSharedConnection = connection
817
+ this._testSharedConnectionProvider = undefined
818
+ this._testSharedConnectionRegistration = registration
819
+
820
+ return registration
804
821
  }
805
822
 
806
823
  /**
807
- * Runs clear test shared connection.
824
+ * Sets a provider that is evaluated when an in-process test request is dispatched.
825
+ * @param {() => import("../drivers/base.js").default | undefined} provider - Shared connection provider.
826
+ * @returns {import("./base.js").TestSharedConnectionRegistration} - Opaque registration handle.
827
+ */
828
+ setTestSharedConnectionProvider(provider) {
829
+ const registration = {owner: Symbol("test-shared-connection-provider")}
830
+
831
+ this._testSharedConnection = undefined
832
+ this._testSharedConnectionProvider = provider
833
+ this._testSharedConnectionRegistration = registration
834
+
835
+ return registration
836
+ }
837
+
838
+ /**
839
+ * Clears the current shared connection registration. A supplied stale registration
840
+ * cannot clear a provider installed by a newer lifecycle.
841
+ * @param {import("./base.js").TestSharedConnectionRegistration} [registration] - Opaque registration handle to clear conditionally.
808
842
  * @returns {void} */
809
- clearTestSharedConnection() {
843
+ clearTestSharedConnection(registration) {
844
+ if (registration && registration !== this._testSharedConnectionRegistration) return
845
+
810
846
  this._testSharedConnection = undefined
847
+ this._testSharedConnectionProvider = undefined
848
+ this._testSharedConnectionRegistration = undefined
811
849
  }
812
850
 
813
851
  /**
@@ -821,9 +859,21 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
821
859
  * @returns {T} - Callback result.
822
860
  */
823
861
  runWithTestSharedConnection(callback) {
824
- if (!this._testSharedConnection) return callback()
862
+ const connection = this.testSharedConnection()
825
863
 
826
- return this.asyncLocalStorage.run(this._testSharedConnection.getIdSeq(), callback)
864
+ if (!connection) return callback()
865
+
866
+ return this.asyncLocalStorage.run(connection.getIdSeq(), callback)
867
+ }
868
+
869
+ /**
870
+ * Resolves the connection currently eligible for in-process test request sharing.
871
+ * @returns {import("../drivers/base.js").default | undefined} - Shared connection.
872
+ */
873
+ testSharedConnection() {
874
+ return this._testSharedConnectionProvider
875
+ ? this._testSharedConnectionProvider()
876
+ : this._testSharedConnection
827
877
  }
828
878
 
829
879
  /**
@@ -835,7 +885,7 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
835
885
  const id = this.asyncLocalStorage.getStore()
836
886
 
837
887
  if (id === SUPPRESSED_CONNECTION_CONTEXT) return undefined
838
- if (id === undefined) return this._testSharedConnection
888
+ if (id === undefined) return this.testSharedConnection()
839
889
 
840
890
  return this.getCurrentConnection()
841
891
  }
@@ -1285,7 +1335,7 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
1285
1335
 
1286
1336
  this.connections = []
1287
1337
  this.connectionsInUse = {}
1288
- this._testSharedConnection = undefined
1338
+ this.clearTestSharedConnection()
1289
1339
  this.clearGlobalConnectionForIdentifier()
1290
1340
 
1291
1341
  for (const connection of connections) {
@@ -4,14 +4,16 @@ import Configuration from "../../configuration.js"
4
4
  import Logger from "../../logger.js"
5
5
  import baseMethodsForward from "./base-methods-forward.js"
6
6
 
7
- export const POOL_CONFIGURATION_KEY = Symbol("velociousPoolConfigurationKey")
7
+ /**
8
+ * Opaque ownership handle for an in-process test shared connection registration.
9
+ * @typedef {{owner: symbol}} TestSharedConnectionRegistration
10
+ */
8
11
 
9
12
  /**
10
13
  * ConnectionCheckoutOptions type.
11
14
  * @typedef {object} ConnectionCheckoutOptions
12
15
  * @property {string} [name] - Human-readable name for the checked-out connection.
13
16
  */
14
-
15
17
  /**
16
18
  * DatabasePoolPendingCheckoutDebugSnapshot type.
17
19
  * @typedef {object} DatabasePoolPendingCheckoutDebugSnapshot
@@ -24,7 +26,6 @@ export const POOL_CONFIGURATION_KEY = Symbol("velociousPoolConfigurationKey")
24
26
  * @property {number | null} timeoutMillis - Timeout configured for the checkout, or null when disabled.
25
27
  * @property {number} waitingForMs - Milliseconds already spent waiting.
26
28
  */
27
-
28
29
  /**
29
30
  * DatabasePoolDebugSnapshot type.
30
31
  * @typedef {object} DatabasePoolDebugSnapshot
@@ -38,6 +39,7 @@ export const POOL_CONFIGURATION_KEY = Symbol("velociousPoolConfigurationKey")
38
39
  * @property {number} pendingCheckoutCount - Number of queued checkout requests.
39
40
  * @property {string} poolClass - Pool class name.
40
41
  */
42
+ export const POOL_CONFIGURATION_KEY = Symbol("velociousPoolConfigurationKey")
41
43
 
42
44
  /**
43
45
  * Shared.
@@ -149,15 +151,29 @@ class VelociousDatabasePoolBase {
149
151
  * pin (used by the test runner to share one connection with in-process HTTP handlers).
150
152
  * Base pools that do not track async context ignore it; async-context pools override.
151
153
  * @param {import("../drivers/base.js").default} _connection - Shared connection.
152
- * @returns {void}
154
+ * @returns {TestSharedConnectionRegistration | undefined} - Opaque registration handle when supported.
153
155
  */
154
- setTestSharedConnection(_connection) {}
156
+ setTestSharedConnection(_connection) {
157
+ return undefined
158
+ }
159
+
160
+ /**
161
+ * Sets a provider that resolves the connection eligible for in-process test request sharing.
162
+ * Base pools that do not track async context ignore it; async-context pools override.
163
+ * @param {() => import("../drivers/base.js").default | undefined} _provider - Shared connection provider.
164
+ * @returns {TestSharedConnectionRegistration | undefined} - Opaque registration handle when supported.
165
+ */
166
+ setTestSharedConnectionProvider(_provider) {
167
+ return undefined
168
+ }
155
169
 
156
170
  /**
157
- * Clears the shared connection set by {@link setTestSharedConnection}. No-op by default.
171
+ * Clears the shared connection or provider set for in-process test requests. No-op by default.
172
+ * When a registration is provided, clears only if it is still the active registration.
173
+ * @param {TestSharedConnectionRegistration} [_registration] - Opaque handle returned when the shared value was set.
158
174
  * @returns {void}
159
175
  */
160
- clearTestSharedConnection() {}
176
+ clearTestSharedConnection(_registration) {}
161
177
 
162
178
  /**
163
179
  * Runs a callback inside the test shared connection's context. Base pools that do not
@@ -14,6 +14,27 @@ import WhereHash from "./where-hash.js"
14
14
  import WhereNot from "./where-not.js"
15
15
  import WherePlain from "./where-plain.js"
16
16
 
17
+ /**
18
+ * QueryArgsType type.
19
+ * @typedef {object} QueryArgsType
20
+ * @property {import("../drivers/base.js").default | (() => import("../drivers/base.js").default)} driver - Driver instance or factory for query execution.
21
+ * @property {Array<import("./from-base.js").default>} [froms] - FROM clauses for the query.
22
+ * @property {string[]} [groups] - GROUP BY columns.
23
+ * @property {Array<import("./join-base.js").default>} [joins] - JOIN clauses for the query.
24
+ * @property {import("../handler.js").default} handler - Handler used for executing and transforming results.
25
+ * @property {number | null} [limit] - LIMIT clause value.
26
+ * @property {number | null} [offset] - OFFSET clause value.
27
+ * @property {Array<import("./order-base.js").default>} [orders] - ORDER BY clauses.
28
+ * @property {number | null} [page] - Page number for pagination.
29
+ * @property {number} [perPage] - Records per page for pagination.
30
+ * @property {NestedPreloadRecord} [preload] - Preload graph for related records.
31
+ * @property {Record<string, string[]>} [preloadSelects] - Attribute names to load for preloaded relationships, keyed by target model name.
32
+ * @property {Record<string, string[]>} [preloadSelectsExtra] - Extra selects to load in addition to the defaults for preloaded relationships, keyed by target model name.
33
+ * @property {Array<import("./select-base.js").default>} [selects] - SELECT clauses for the query.
34
+ * @property {AbortSignal} [signal] - Signal passed to database query execution.
35
+ * @property {boolean} [distinct] - Whether the query should use DISTINCT.
36
+ * @property {Array<import("./where-base.js").default>} [wheres] - WHERE conditions for the query.
37
+ */
17
38
  /**
18
39
  * OrderArgumentType type.
19
40
  * @typedef {{[key: string]: boolean | string | string[] | NestedPreloadRecord }} NestedPreloadRecord
@@ -108,28 +129,6 @@ function mergeJoinValue(existing, incoming) {
108
129
  return incoming
109
130
  }
110
131
 
111
- /**
112
- * QueryArgsType type.
113
- * @typedef {object} QueryArgsType
114
- * @property {import("../drivers/base.js").default | (() => import("../drivers/base.js").default)} driver - Driver instance or factory for query execution.
115
- * @property {Array<import("./from-base.js").default>} [froms] - FROM clauses for the query.
116
- * @property {string[]} [groups] - GROUP BY columns.
117
- * @property {Array<import("./join-base.js").default>} [joins] - JOIN clauses for the query.
118
- * @property {import("../handler.js").default} handler - Handler used for executing and transforming results.
119
- * @property {number | null} [limit] - LIMIT clause value.
120
- * @property {number | null} [offset] - OFFSET clause value.
121
- * @property {Array<import("./order-base.js").default>} [orders] - ORDER BY clauses.
122
- * @property {number | null} [page] - Page number for pagination.
123
- * @property {number} [perPage] - Records per page for pagination.
124
- * @property {NestedPreloadRecord} [preload] - Preload graph for related records.
125
- * @property {Record<string, string[]>} [preloadSelects] - Attribute names to load for preloaded relationships, keyed by target model name.
126
- * @property {Record<string, string[]>} [preloadSelectsExtra] - Extra selects to load in addition to the defaults for preloaded relationships, keyed by target model name.
127
- * @property {Array<import("./select-base.js").default>} [selects] - SELECT clauses for the query.
128
- * @property {AbortSignal} [signal] - Signal passed to database query execution.
129
- * @property {boolean} [distinct] - Whether the query should use DISTINCT.
130
- * @property {Array<import("./where-base.js").default>} [wheres] - WHERE conditions for the query.
131
- */
132
-
133
132
  export default class VelociousDatabaseQuery {
134
133
  /**
135
134
  * Runs constructor.
@@ -21,6 +21,11 @@ import WhereNot from "./where-not.js"
21
21
  import JoinsParser from "../query-parser/joins-parser.js"
22
22
  import WhereParser from "../query-parser/where-parser.js"
23
23
 
24
+ /**
25
+ * Defines this typedef.
26
+ * @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
27
+ * @typedef {import("./index.js").QueryArgsType & {modelClass: MC, joinBasePath?: string[], joinTracker?: import("./join-tracker.js").default, forceQualifyBaseTable?: boolean, withCount?: import("./with-count.js").WithCountEntry[], queryData?: import("./query-data.js").QueryDataEntry[]}} ModelClassQueryArgsType
28
+ */
24
29
  /**
25
30
  * Runs unquote sql identifier.
26
31
  * @param {string} value - Potentially quoted SQL identifier.
@@ -166,11 +171,6 @@ function normalizePreloadRecord(preload) {
166
171
  * Defines this typedef.
167
172
  * @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
168
173
  */
169
- /**
170
- * Defines this typedef.
171
- * @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
172
- * @typedef {import("./index.js").QueryArgsType & {modelClass: MC, joinBasePath?: string[], joinTracker?: import("./join-tracker.js").default, forceQualifyBaseTable?: boolean, withCount?: import("./with-count.js").WithCountEntry[], queryData?: import("./query-data.js").QueryDataEntry[]}} ModelClassQueryArgsType
173
- */
174
174
 
175
175
  /**
176
176
  * A generic query over some model type.
@@ -330,7 +330,6 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
330
330
 
331
331
  sql += " AS count"
332
332
 
333
-
334
333
  // Clone query and execute count
335
334
  const countQuery = this.clone()
336
335
 
@@ -2,6 +2,15 @@
2
2
 
3
3
  import UploadedFile from "../../../http-server/client/uploaded-file/uploaded-file.js"
4
4
 
5
+ /**
6
+ * NormalizedAttachmentInput type.
7
+ * @typedef {object} NormalizedAttachmentInput
8
+ * @property {number} byteSize - File size in bytes.
9
+ * @property {Buffer} contentBuffer - Raw content bytes.
10
+ * @property {string} contentBase64 - Base64 encoded content.
11
+ * @property {string | null} contentType - Content type.
12
+ * @property {string} filename - Filename.
13
+ */
5
14
  /**
6
15
  * Runs base name.
7
16
  * @param {string} value - Path-like value.
@@ -96,16 +105,6 @@ async function uploadedFileBuffer(uploadedFile, environmentHandler) {
96
105
  throw new Error("Unsupported uploaded file type")
97
106
  }
98
107
 
99
- /**
100
- * NormalizedAttachmentInput type.
101
- * @typedef {object} NormalizedAttachmentInput
102
- * @property {number} byteSize - File size in bytes.
103
- * @property {Buffer} contentBuffer - Raw content bytes.
104
- * @property {string} contentBase64 - Base64 encoded content.
105
- * @property {string | null} contentType - Content type.
106
- * @property {string} filename - Filename.
107
- */
108
-
109
108
  /**
110
109
  * Runs normalize record attachment input.
111
110
  * @param {?} input - Attachment input.
@@ -4,11 +4,11 @@ import UUID from "pure-uuid"
4
4
  import TableData from "../../table-data/index.js"
5
5
  import normalizeRecordAttachmentInput from "./normalize-input.js"
6
6
 
7
- const ATTACHMENTS_TABLE = "velocious_attachments"
8
-
9
7
  /**
10
8
  * AttachmentDriverConstructor type.
11
9
  * @typedef {import("../../../configuration-types.js").AttachmentDriverConstructor} AttachmentDriverConstructor */
10
+ const ATTACHMENTS_TABLE = "velocious_attachments"
11
+
12
12
  /**
13
13
  * Stores by configuration.
14
14
  * @type {WeakMap<import("../../../configuration.js").default, Map<string, RecordAttachmentsStore>>} */
@@ -2,6 +2,13 @@
2
2
 
3
3
  import UUID from "pure-uuid"
4
4
 
5
+ /**
6
+ * Global audit event bus matching ActiveRecordAuditable::Events.
7
+ * @typedef {object} AuditEventsType
8
+ * @property {(type: string, action: string, args: AuditEventPayload) => void} call - Fire all callbacks for a model type + action.
9
+ * @property {(type: string, action: string, callback: (args: AuditEventPayload) => void) => () => void} connect - Register a callback for a model type + action. Returns an unsubscribe function.
10
+ * @property {() => void} reset - Clear all registered callbacks.
11
+ */
5
12
  /**
6
13
  * AuditChanges type.
7
14
  * @typedef {Record<string, ?>} AuditChanges
@@ -64,14 +71,6 @@ const generatedAuditRelationships = new WeakSet()
64
71
  /** @type {Record<string, Record<string, Array<(args: AuditEventPayload) => void>>>} */
65
72
  let globalEventConnections = {}
66
73
 
67
- /**
68
- * Global audit event bus matching ActiveRecordAuditable::Events.
69
- * @typedef {object} AuditEventsType
70
- * @property {(type: string, action: string, args: AuditEventPayload) => void} call - Fire all callbacks for a model type + action.
71
- * @property {(type: string, action: string, callback: (args: AuditEventPayload) => void) => () => void} connect - Register a callback for a model type + action. Returns an unsubscribe function.
72
- * @property {() => void} reset - Clear all registered callbacks.
73
- */
74
-
75
74
  /** @type {AuditEventsType} */
76
75
  const AuditEvents = {
77
76
  /**
@@ -57,6 +57,10 @@ import ValidatorsUniqueness from "./validators/uniqueness.js"
57
57
  import registerActsAsListCallbacks from "./acts-as-list.js"
58
58
  import UUID from "pure-uuid"
59
59
 
60
+ /**
61
+ * Translation record shape used by translated attributes.
62
+ * @typedef {VelociousDatabaseRecord & {locale: function(): string}} TranslationBase
63
+ */
60
64
  /**
61
65
  * AttachmentDriverConstructor type.
62
66
  * @typedef {import("../../configuration-types.js").AttachmentDriverConstructor} AttachmentDriverConstructor
@@ -4452,11 +4456,6 @@ class VelociousDatabaseRecord {
4452
4456
  }
4453
4457
  }
4454
4458
 
4455
- /**
4456
- * Translation record shape used by translated attributes.
4457
- * @typedef {VelociousDatabaseRecord & {locale: function(): string}} TranslationBase
4458
- */
4459
-
4460
4459
  VelociousDatabaseRecord.registerValidatorType("format", ValidatorsFormat)
4461
4460
  VelociousDatabaseRecord.registerValidatorType("length", ValidatorsLength)
4462
4461
  VelociousDatabaseRecord.registerValidatorType("presence", ValidatorsPresence)
@@ -6,8 +6,6 @@ import * as inflection from "inflection"
6
6
  import {frontendModelResourceIsBuiltIn, frontendModelResourcesWithBuiltInsForBackendProject} from "../../../../../frontend-models/built-in-resources.js"
7
7
  import {frontendModelResourceClassFromDefinition, frontendModelResourceConfigurationFromDefinition} from "../../../../../frontend-models/resource-definition.js"
8
8
 
9
- const FRONTEND_MODELS_REGENERATE_COMMAND = "velocious generate:frontend-models"
10
-
11
9
  /**
12
10
  * Attribute metadata used for generated frontend-model JSDoc.
13
11
  * @typedef {object} FrontendAttributeConfig
@@ -47,6 +45,7 @@ const FRONTEND_MODELS_REGENERATE_COMMAND = "velocious generate:frontend-models"
47
45
  * @property {string | null} sourceFile - Source file that declared the method.
48
46
  * @property {string} type - JSDoc parameter type.
49
47
  */
48
+ const FRONTEND_MODELS_REGENERATE_COMMAND = "velocious generate:frontend-models"
50
49
 
51
50
  /** Node CLI command that generates frontend model classes from backend project resource config. */
52
51
  export default class DbGenerateFrontendModels extends BaseCommand {