velocious 1.0.562 → 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 (245) hide show
  1. package/README.md +5 -1
  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/configuration-types.js +1 -0
  9. package/build/configuration.js +44 -3
  10. package/build/database/drivers/sqlite/web-persistence.js +2 -5
  11. package/build/database/pool/async-tracked-multi-connection.js +65 -15
  12. package/build/database/pool/base.js +23 -7
  13. package/build/database/query/index.js +21 -22
  14. package/build/database/query/model-class-query.js +5 -6
  15. package/build/database/record/attachments/normalize-input.js +9 -10
  16. package/build/database/record/attachments/store.js +2 -2
  17. package/build/database/record/auditing.js +7 -8
  18. package/build/database/record/index.js +4 -5
  19. package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +1 -2
  20. package/build/frontend-model-controller.js +49 -56
  21. package/build/frontend-models/base.js +17 -19
  22. package/build/frontend-models/outgoing-event-buffer.js +3 -4
  23. package/build/frontend-models/query.js +40 -44
  24. package/build/frontend-models/resource-definition.js +7 -8
  25. package/build/frontend-models/transport-serialization.js +10 -12
  26. package/build/frontend-models/websocket-channel.js +12 -13
  27. package/build/http-server/client/websocket-session.js +7 -8
  28. package/build/http-server/client-delivery-queue.js +167 -0
  29. package/build/http-server/server-client.js +9 -0
  30. package/build/http-server/websocket-event-log-store.js +4 -6
  31. package/build/http-server/websocket-events-host.js +42 -12
  32. package/build/http-server/worker-handler/in-process.js +53 -14
  33. package/build/http-server/worker-handler/index.js +88 -18
  34. package/build/http-server/worker-handler/worker-thread.js +2 -2
  35. package/build/plugins/sqljs-wasm-route.js +3 -5
  36. package/build/src/background-jobs/cron-expression.d.ts +0 -12
  37. package/build/src/background-jobs/cron-expression.d.ts.map +1 -1
  38. package/build/src/background-jobs/cron-expression.js +13 -13
  39. package/build/src/background-jobs/main.d.ts.map +1 -1
  40. package/build/src/background-jobs/main.js +7 -7
  41. package/build/src/background-jobs/runner-graceful-shutdown.d.ts +0 -6
  42. package/build/src/background-jobs/runner-graceful-shutdown.d.ts.map +1 -1
  43. package/build/src/background-jobs/runner-graceful-shutdown.js +3 -3
  44. package/build/src/background-jobs/scheduler.d.ts +0 -3
  45. package/build/src/background-jobs/scheduler.d.ts.map +1 -1
  46. package/build/src/background-jobs/scheduler.js +4 -4
  47. package/build/src/background-jobs/worker.d.ts +0 -8
  48. package/build/src/background-jobs/worker.d.ts.map +1 -1
  49. package/build/src/background-jobs/worker.js +9 -9
  50. package/build/src/beacon/client.d.ts +0 -4
  51. package/build/src/beacon/client.d.ts.map +1 -1
  52. package/build/src/beacon/client.js +4 -4
  53. package/build/src/configuration-types.d.ts +8 -0
  54. package/build/src/configuration-types.d.ts.map +1 -1
  55. package/build/src/configuration-types.js +2 -1
  56. package/build/src/configuration.d.ts +34 -1
  57. package/build/src/configuration.d.ts.map +1 -1
  58. package/build/src/configuration.js +40 -4
  59. package/build/src/database/drivers/sqlite/web-persistence.d.ts +0 -14
  60. package/build/src/database/drivers/sqlite/web-persistence.d.ts.map +1 -1
  61. package/build/src/database/drivers/sqlite/web-persistence.js +3 -3
  62. package/build/src/database/pool/async-tracked-multi-connection.d.ts +29 -1
  63. package/build/src/database/pool/async-tracked-multi-connection.d.ts.map +1 -1
  64. package/build/src/database/pool/async-tracked-multi-connection.js +57 -15
  65. package/build/src/database/pool/base.d.ts +53 -4
  66. package/build/src/database/pool/base.d.ts.map +1 -1
  67. package/build/src/database/pool/base.js +23 -6
  68. package/build/src/database/query/index.d.ts +18 -39
  69. package/build/src/database/query/index.d.ts.map +1 -1
  70. package/build/src/database/query/index.js +22 -22
  71. package/build/src/database/query/model-class-query.d.ts +0 -5
  72. package/build/src/database/query/model-class-query.d.ts.map +1 -1
  73. package/build/src/database/query/model-class-query.js +6 -6
  74. package/build/src/database/record/attachments/normalize-input.d.ts +0 -9
  75. package/build/src/database/record/attachments/normalize-input.d.ts.map +1 -1
  76. package/build/src/database/record/attachments/normalize-input.js +10 -10
  77. package/build/src/database/record/attachments/store.d.ts.map +1 -1
  78. package/build/src/database/record/attachments/store.js +2 -2
  79. package/build/src/database/record/auditing.d.ts +17 -24
  80. package/build/src/database/record/auditing.d.ts.map +1 -1
  81. package/build/src/database/record/auditing.js +8 -8
  82. package/build/src/database/record/index.d.ts +4 -4
  83. package/build/src/database/record/index.d.ts.map +1 -1
  84. package/build/src/database/record/index.js +5 -5
  85. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +0 -39
  86. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
  87. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +2 -2
  88. package/build/src/frontend-model-controller.d.ts +1 -1
  89. package/build/src/frontend-model-controller.d.ts.map +1 -1
  90. package/build/src/frontend-model-controller.js +50 -50
  91. package/build/src/frontend-models/base.d.ts.map +1 -1
  92. package/build/src/frontend-models/base.js +18 -18
  93. package/build/src/frontend-models/outgoing-event-buffer.d.ts.map +1 -1
  94. package/build/src/frontend-models/outgoing-event-buffer.js +3 -3
  95. package/build/src/frontend-models/query.d.ts +56 -37
  96. package/build/src/frontend-models/query.d.ts.map +1 -1
  97. package/build/src/frontend-models/query.js +39 -39
  98. package/build/src/frontend-models/resource-definition.d.ts +0 -7
  99. package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
  100. package/build/src/frontend-models/resource-definition.js +8 -8
  101. package/build/src/frontend-models/transport-serialization.d.ts +0 -10
  102. package/build/src/frontend-models/transport-serialization.d.ts.map +1 -1
  103. package/build/src/frontend-models/transport-serialization.js +11 -11
  104. package/build/src/frontend-models/websocket-channel.d.ts +0 -12
  105. package/build/src/frontend-models/websocket-channel.d.ts.map +1 -1
  106. package/build/src/frontend-models/websocket-channel.js +13 -13
  107. package/build/src/http-server/client/websocket-session.d.ts.map +1 -1
  108. package/build/src/http-server/client/websocket-session.js +8 -8
  109. package/build/src/http-server/client-delivery-queue.d.ts +121 -0
  110. package/build/src/http-server/client-delivery-queue.d.ts.map +1 -0
  111. package/build/src/http-server/client-delivery-queue.js +152 -0
  112. package/build/src/http-server/server-client.d.ts +6 -0
  113. package/build/src/http-server/server-client.d.ts.map +1 -1
  114. package/build/src/http-server/server-client.js +10 -1
  115. package/build/src/http-server/websocket-event-log-store.d.ts +0 -14
  116. package/build/src/http-server/websocket-event-log-store.d.ts.map +1 -1
  117. package/build/src/http-server/websocket-event-log-store.js +5 -5
  118. package/build/src/http-server/websocket-events-host.d.ts +15 -4
  119. package/build/src/http-server/websocket-events-host.d.ts.map +1 -1
  120. package/build/src/http-server/websocket-events-host.js +39 -13
  121. package/build/src/http-server/worker-handler/in-process.d.ts +19 -1
  122. package/build/src/http-server/worker-handler/in-process.d.ts.map +1 -1
  123. package/build/src/http-server/worker-handler/in-process.js +50 -14
  124. package/build/src/http-server/worker-handler/index.d.ts +36 -4
  125. package/build/src/http-server/worker-handler/index.d.ts.map +1 -1
  126. package/build/src/http-server/worker-handler/index.js +82 -18
  127. package/build/src/http-server/worker-handler/worker-thread.js +3 -3
  128. package/build/src/plugins/sqljs-wasm-route.d.ts.map +1 -1
  129. package/build/src/plugins/sqljs-wasm-route.js +4 -4
  130. package/build/src/sync/conflict-strategy.d.ts +0 -15
  131. package/build/src/sync/conflict-strategy.d.ts.map +1 -1
  132. package/build/src/sync/conflict-strategy.js +3 -3
  133. package/build/src/sync/device-identity.d.ts +0 -45
  134. package/build/src/sync/device-identity.d.ts.map +1 -1
  135. package/build/src/sync/device-identity.js +4 -4
  136. package/build/src/sync/local-mutation-log.d.ts +0 -41
  137. package/build/src/sync/local-mutation-log.d.ts.map +1 -1
  138. package/build/src/sync/local-mutation-log.js +9 -9
  139. package/build/src/sync/offline-grant.d.ts +0 -26
  140. package/build/src/sync/offline-grant.d.ts.map +1 -1
  141. package/build/src/sync/offline-grant.js +4 -4
  142. package/build/src/sync/peer-mutation-bundle.d.ts +0 -14
  143. package/build/src/sync/peer-mutation-bundle.d.ts.map +1 -1
  144. package/build/src/sync/peer-mutation-bundle.js +3 -3
  145. package/build/src/sync/server-change-feed.d.ts.map +1 -1
  146. package/build/src/sync/server-change-feed.js +33 -33
  147. package/build/src/sync/sync-api-client.d.ts +0 -9
  148. package/build/src/sync/sync-api-client.d.ts.map +1 -1
  149. package/build/src/sync/sync-api-client.js +2 -2
  150. package/build/src/sync/sync-envelope-replay-service.d.ts +38 -21
  151. package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
  152. package/build/src/sync/sync-envelope-replay-service.js +18 -18
  153. package/build/src/sync/sync-resource-base.d.ts +0 -7
  154. package/build/src/sync/sync-resource-base.d.ts.map +1 -1
  155. package/build/src/sync/sync-resource-base.js +2 -2
  156. package/build/src/sync/sync-scope-store.d.ts +0 -9
  157. package/build/src/sync/sync-scope-store.d.ts.map +1 -1
  158. package/build/src/sync/sync-scope-store.js +10 -10
  159. package/build/src/testing/test-filter-parser.d.ts +0 -10
  160. package/build/src/testing/test-filter-parser.d.ts.map +1 -1
  161. package/build/src/testing/test-filter-parser.js +11 -11
  162. package/build/src/testing/test-runner.d.ts +25 -91
  163. package/build/src/testing/test-runner.d.ts.map +1 -1
  164. package/build/src/testing/test-runner.js +113 -98
  165. package/build/src/testing/test.d.ts +8 -0
  166. package/build/src/testing/test.d.ts.map +1 -1
  167. package/build/src/testing/test.js +9 -9
  168. package/build/src/utils/backtrace-cleaner.d.ts.map +1 -1
  169. package/build/src/utils/backtrace-cleaner.js +9 -9
  170. package/build/src/utils/model-scope.d.ts +0 -8
  171. package/build/src/utils/model-scope.d.ts.map +1 -1
  172. package/build/src/utils/model-scope.js +3 -3
  173. package/build/src/utils/ransack.d.ts +52 -19
  174. package/build/src/utils/ransack.d.ts.map +1 -1
  175. package/build/src/utils/ransack.js +26 -26
  176. package/build/sync/conflict-strategy.js +3 -6
  177. package/build/sync/device-identity.js +4 -9
  178. package/build/sync/local-mutation-log.js +9 -14
  179. package/build/sync/offline-grant.js +4 -7
  180. package/build/sync/peer-mutation-bundle.js +2 -4
  181. package/build/sync/server-change-feed.js +32 -34
  182. package/build/sync/sync-api-client.js +1 -2
  183. package/build/sync/sync-envelope-replay-service.js +17 -19
  184. package/build/sync/sync-resource-base.js +1 -2
  185. package/build/sync/sync-scope-store.js +9 -10
  186. package/build/testing/test-filter-parser.js +10 -11
  187. package/build/testing/test-runner.js +116 -108
  188. package/build/testing/test.js +8 -9
  189. package/build/tsconfig.tsbuildinfo +1 -1
  190. package/build/utils/backtrace-cleaner.js +8 -9
  191. package/build/utils/model-scope.js +3 -4
  192. package/build/utils/ransack.js +27 -34
  193. package/package.json +3 -1
  194. package/scripts/eslint-rules/typedefs-first.js +67 -0
  195. package/scripts/prewarm-chromedriver.js +26 -0
  196. package/src/background-jobs/cron-expression.js +12 -13
  197. package/src/background-jobs/main.js +6 -6
  198. package/src/background-jobs/runner-graceful-shutdown.js +2 -3
  199. package/src/background-jobs/scheduler.js +3 -3
  200. package/src/background-jobs/worker.js +8 -9
  201. package/src/beacon/client.js +3 -4
  202. package/src/configuration-types.js +1 -0
  203. package/src/configuration.js +44 -3
  204. package/src/database/drivers/sqlite/web-persistence.js +2 -5
  205. package/src/database/pool/async-tracked-multi-connection.js +65 -15
  206. package/src/database/pool/base.js +23 -7
  207. package/src/database/query/index.js +21 -22
  208. package/src/database/query/model-class-query.js +5 -6
  209. package/src/database/record/attachments/normalize-input.js +9 -10
  210. package/src/database/record/attachments/store.js +2 -2
  211. package/src/database/record/auditing.js +7 -8
  212. package/src/database/record/index.js +4 -5
  213. package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +1 -2
  214. package/src/frontend-model-controller.js +49 -56
  215. package/src/frontend-models/base.js +17 -19
  216. package/src/frontend-models/outgoing-event-buffer.js +3 -4
  217. package/src/frontend-models/query.js +40 -44
  218. package/src/frontend-models/resource-definition.js +7 -8
  219. package/src/frontend-models/transport-serialization.js +10 -12
  220. package/src/frontend-models/websocket-channel.js +12 -13
  221. package/src/http-server/client/websocket-session.js +7 -8
  222. package/src/http-server/client-delivery-queue.js +167 -0
  223. package/src/http-server/server-client.js +9 -0
  224. package/src/http-server/websocket-event-log-store.js +4 -6
  225. package/src/http-server/websocket-events-host.js +42 -12
  226. package/src/http-server/worker-handler/in-process.js +53 -14
  227. package/src/http-server/worker-handler/index.js +88 -18
  228. package/src/http-server/worker-handler/worker-thread.js +2 -2
  229. package/src/plugins/sqljs-wasm-route.js +3 -5
  230. package/src/sync/conflict-strategy.js +3 -6
  231. package/src/sync/device-identity.js +4 -9
  232. package/src/sync/local-mutation-log.js +9 -14
  233. package/src/sync/offline-grant.js +4 -7
  234. package/src/sync/peer-mutation-bundle.js +2 -4
  235. package/src/sync/server-change-feed.js +32 -34
  236. package/src/sync/sync-api-client.js +1 -2
  237. package/src/sync/sync-envelope-replay-service.js +17 -19
  238. package/src/sync/sync-resource-base.js +1 -2
  239. package/src/sync/sync-scope-store.js +9 -10
  240. package/src/testing/test-filter-parser.js +10 -11
  241. package/src/testing/test-runner.js +116 -108
  242. package/src/testing/test.js +8 -9
  243. package/src/utils/backtrace-cleaner.js +8 -9
  244. package/src/utils/model-scope.js +3 -4
  245. package/src/utils/ransack.js +27 -34
@@ -7,6 +7,23 @@ import SyncReplayUpsertApplier from "./sync-replay-upsert-applier.js"
7
7
  import {ValidationError} from "../database/record/index.js"
8
8
  import VelociousError from "../velocious-error.js"
9
9
 
10
+ /**
11
+ * Resolved routed-resource registration for one replay resource type.
12
+ * @typedef {object} SyncReplayResourceRegistration
13
+ * @property {string} modelName - Effective frontend model name.
14
+ * @property {import("../configuration-types.js").FrontendModelResourceClassType} resourceClass - Routed resource class.
15
+ * @property {import("../configuration-types.js").NormalizedFrontendModelResourceConfiguration | null} resourceConfiguration - Normalized resource configuration when registry-resolved.
16
+ */
17
+ /**
18
+ * @typedef {object} SyncReplayMutation
19
+ * @property {Date} clientUpdatedAt - Client-side mutation timestamp.
20
+ * @property {Record<string, ?>} data - Parsed mutation payload.
21
+ * @property {?} id - Client sync row id for per-sync responses.
22
+ * @property {string} resourceId - Resource id as a string.
23
+ * @property {string} resourceType - Resource/model name.
24
+ * @property {string} serializedData - JSON serialized mutation payload.
25
+ * @property {string} syncType - Sync operation type.
26
+ */
10
27
  /**
11
28
  * One declarative broadcast fanned out after a mutation applies.
12
29
  * @typedef {object} SyncReplayBroadcast
@@ -778,22 +795,3 @@ export default class SyncEnvelopeReplayService {
778
795
  await deliverDeclaredBroadcasts({args, broadcaster: this.broadcaster, broadcasts: this.broadcasts})
779
796
  }
780
797
  }
781
-
782
- /**
783
- * Resolved routed-resource registration for one replay resource type.
784
- * @typedef {object} SyncReplayResourceRegistration
785
- * @property {string} modelName - Effective frontend model name.
786
- * @property {import("../configuration-types.js").FrontendModelResourceClassType} resourceClass - Routed resource class.
787
- * @property {import("../configuration-types.js").NormalizedFrontendModelResourceConfiguration | null} resourceConfiguration - Normalized resource configuration when registry-resolved.
788
- */
789
-
790
- /**
791
- * @typedef {object} SyncReplayMutation
792
- * @property {Date} clientUpdatedAt - Client-side mutation timestamp.
793
- * @property {Record<string, ?>} data - Parsed mutation payload.
794
- * @property {?} id - Client sync row id for per-sync responses.
795
- * @property {string} resourceId - Resource id as a string.
796
- * @property {string} resourceType - Resource/model name.
797
- * @property {string} serializedData - JSON serialized mutation payload.
798
- * @property {string} syncType - Sync operation type.
799
- */
@@ -7,8 +7,6 @@ import SyncEnvelopeReplayService from "./sync-envelope-replay-service.js"
7
7
  import SyncModelChangeFeedService from "./sync-model-change-feed-service.js"
8
8
  import VelociousError from "../velocious-error.js"
9
9
 
10
- const QUICK_SEARCH_COLUMN = "quickSearch"
11
-
12
10
  /**
13
11
  * Optional client-declared sync scope carried on a changes request.
14
12
  * @typedef {object} SerializedChangesScope
@@ -16,6 +14,7 @@ const QUICK_SEARCH_COLUMN = "quickSearch"
16
14
  * @property {string | null} resourceType - Client resource/model name the scope was declared for, or null for the all-types (user) scope: one scope covering every resource type this resource authorizes for the caller, so a sync authorizes once however many types it serves.
17
15
  * @property {string[] | null} resourceTypes - For the all-types scope, the resource types the client can apply. A cheap delivery/type filter only - it narrows, never widens, what the app's authorization already allows. Null for a type-declared scope.
18
16
  */
17
+ const QUICK_SEARCH_COLUMN = "quickSearch"
19
18
 
20
19
  /**
21
20
  * Base resource for Velocious sync endpoints.
@@ -6,6 +6,15 @@ import UUID from "pure-uuid"
6
6
  import {scopeKey} from "./query-scope.js"
7
7
  import stableJsonStringify from "./stable-json.js"
8
8
 
9
+ /**
10
+ * @typedef {object} SyncScopeRow
11
+ * @property {Record<string, ?>} conditions - Scope attribute conditions.
12
+ * @property {string | null} cursorPayload - Persisted cursor JSON payload.
13
+ * @property {string} id - Scope row id.
14
+ * @property {string | null} resourceType - Scope resource/model name, or null for the all-types (user) scope.
15
+ * @property {string} scopeDigest - Fixed-size deterministic digest of the canonical scope key.
16
+ * @property {string} state - Scope state ("active" or "removed").
17
+ */
9
18
  const TABLE_NAME = "velocious_sync_scopes"
10
19
  const SCOPE_DIGEST_PREFIX = "velocious-sync-scope:"
11
20
 
@@ -19,16 +28,6 @@ function scopeDigestForScope(scope) {
19
28
  return new UUID(5, "ns:URL", `${SCOPE_DIGEST_PREFIX}${scopeKey(scope)}`).format()
20
29
  }
21
30
 
22
- /**
23
- * @typedef {object} SyncScopeRow
24
- * @property {Record<string, ?>} conditions - Scope attribute conditions.
25
- * @property {string | null} cursorPayload - Persisted cursor JSON payload.
26
- * @property {string} id - Scope row id.
27
- * @property {string | null} resourceType - Scope resource/model name, or null for the all-types (user) scope.
28
- * @property {string} scopeDigest - Fixed-size deterministic digest of the canonical scope key.
29
- * @property {string} state - Scope state ("active" or "removed").
30
- */
31
-
32
31
  /**
33
32
  * Framework-owned local persistence for declared sync scopes and their cursors.
34
33
  *
@@ -1,3 +1,13 @@
1
+ /**
2
+ * ParseFiltersResult type.
3
+ * @typedef {object} ParseFiltersResult
4
+ * @property {string[]} includeTags - Tags to include.
5
+ * @property {string[]} excludeTags - Tags to exclude.
6
+ * @property {string[]} examplePatterns - Example name patterns.
7
+ * @property {string[]} filteredProcessArgs - Remaining process args with filter flags removed.
8
+ * @property {number | undefined} groups - Total number of groups for test splitting.
9
+ * @property {number | undefined} groupNumber - Which group to run (1-indexed).
10
+ */
1
11
  // @ts-check
2
12
 
3
13
  const INCLUDE_TAG_FLAGS = new Set(["--tag", "--include-tag", "-t"])
@@ -50,17 +60,6 @@ export function normalizeExamplePatterns(patterns) {
50
60
  return normalized
51
61
  }
52
62
 
53
- /**
54
- * ParseFiltersResult type.
55
- * @typedef {object} ParseFiltersResult
56
- * @property {string[]} includeTags - Tags to include.
57
- * @property {string[]} excludeTags - Tags to exclude.
58
- * @property {string[]} examplePatterns - Example name patterns.
59
- * @property {string[]} filteredProcessArgs - Remaining process args with filter flags removed.
60
- * @property {number | undefined} groups - Total number of groups for test splitting.
61
- * @property {number | undefined} groupNumber - Which group to run (1-indexed).
62
- */
63
-
64
63
  /**
65
64
  * Runs the parseFilters helper.
66
65
  * @param {string[]} processArgs - Process args.
@@ -13,6 +13,87 @@ import {testConfig, testEvents, tests} from "./test.js"
13
13
  import {pathToFileURL} from "url"
14
14
  import {clearDeliveries} from "../mailer.js"
15
15
 
16
+ /**
17
+ * ConsoleMethodName type.
18
+ * @typedef {"log" | "info" | "warn" | "error" | "debug"} ConsoleMethodName */
19
+ /**
20
+ * AttemptConsoleOutput type.
21
+ * @typedef {object} AttemptConsoleOutput
22
+ * @property {number} attemptNumber - Attempt number.
23
+ * @property {string} output - Captured console output.
24
+ */
25
+ /**
26
+ * TestArgs type.
27
+ * @typedef {object} TestArgs
28
+ * @property {Application} [application] - Application instance for integration tests.
29
+ * @property {RequestClient} [client] - HTTP client for request tests.
30
+ * @property {object} [databaseCleaning] - Database cleanup options for tests.
31
+ * @property {boolean} [databaseCleaning.transaction] - Use transactions to rollback between tests.
32
+ * @property {boolean} [databaseCleaning.truncate] - Truncate tables between tests.
33
+ * @property {boolean} [databaseCleaning.truncateBefore] - Truncate tables before each test, in addition to the default cleanup.
34
+ * @property {boolean} [focus] - Whether this test is focused.
35
+ * @property {() => (void|Promise<void>)} [function] - Test callback function.
36
+ * @property {number} [retry] - Number of retries when a test fails.
37
+ * @property {string[] | string} [tags] - Tags for filtering.
38
+ * @property {number} [timeoutSeconds] - Timeout in seconds for the test.
39
+ * @property {string} [type] - Test type identifier.
40
+ */
41
+ /**
42
+ * TestData type.
43
+ * @typedef {object} TestData
44
+ * @property {TestArgs} args - Arguments passed to the test.
45
+ * @property {string} [filePath] - Source file path.
46
+ * @property {number} [line] - Source line number.
47
+ * @property {function(TestArgs) : (void|Promise<void>)} function - Test callback to execute.
48
+ */
49
+ /**
50
+ * FailedTestDetail type.
51
+ * @typedef {object} FailedTestDetail
52
+ * @property {string} fullDescription - Full test description.
53
+ * @property {string} [filePath] - Source file path.
54
+ * @property {number} [line] - Source line number.
55
+ * @property {?} error - Failure error.
56
+ * @property {string} [consoleOutput] - Captured console output while test ran.
57
+ * @property {string} [consoleLogPath] - Saved console log path.
58
+ */
59
+ /**
60
+ * ActiveAfterAllScopeEntry type.
61
+ * @typedef {object} ActiveAfterAllScopeEntry
62
+ * @property {TestsArgument} tests - Scope test tree.
63
+ * @property {boolean} afterAllsRun - Whether cleanup hooks have run.
64
+ */
65
+ /**
66
+ * Defines this typedef.
67
+ * @typedef {function({configuration: import("../configuration.js").default, testArgs: TestArgs, testData: TestData}) : (void|Promise<void>)} AfterBeforeEachCallbackType
68
+ */
69
+ /**
70
+ * AfterBeforeEachCallbackObjectType type.
71
+ * @typedef {object} AfterBeforeEachCallbackObjectType
72
+ * @property {AfterBeforeEachCallbackType} callback - Hook callback to execute.
73
+ */
74
+ /**
75
+ * Defines this typedef.
76
+ * @typedef {function({configuration: import("../configuration.js").default}) : (void|Promise<void>)} BeforeAfterAllCallbackType
77
+ */
78
+ /**
79
+ * BeforeAfterAllCallbackObjectType type.
80
+ * @typedef {object} BeforeAfterAllCallbackObjectType
81
+ * @property {BeforeAfterAllCallbackType} callback - Hook callback to execute.
82
+ */
83
+ /**
84
+ * TestsArgument type.
85
+ * @typedef {object} TestsArgument
86
+ * @property {Record<string, TestData>} args - Arguments keyed by test description.
87
+ * @property {boolean} [anyTestsFocussed] - Whether any tests in the tree are focused.
88
+ * @property {AfterBeforeEachCallbackObjectType[]} afterEaches - After-each hooks for this scope.
89
+ * @property {BeforeAfterAllCallbackObjectType[]} afterAlls - After-all hooks for this scope.
90
+ * @property {BeforeAfterAllCallbackObjectType[]} beforeAlls - Before-all hooks for this scope.
91
+ * @property {AfterBeforeEachCallbackObjectType[]} beforeEaches - Before-each hooks for this scope.
92
+ * @property {string} [filePath] - Source file path.
93
+ * @property {number} [line] - Source line number.
94
+ * @property {Record<string, TestData>} tests - A unique identifier for the node.
95
+ * @property {Record<string, TestsArgument>} subs - Optional child nodes. Each item is another `Node`, allowing recursion.
96
+ */
16
97
  /**
17
98
  * Marks the error thrown by {@link runWithTimeout} so the caller can tell a
18
99
  * lifecycle timeout (the promise is still running detached) apart from an
@@ -85,22 +166,11 @@ function awaitSettledOrGrace(lifecycle, graceMs) {
85
166
  })
86
167
  }
87
168
 
88
- /**
89
- * ConsoleMethodName type.
90
- * @typedef {"log" | "info" | "warn" | "error" | "debug"} ConsoleMethodName */
91
-
92
169
  /**
93
170
  * Captured console methods.
94
171
  * @type {ConsoleMethodName[]} */
95
172
  const CAPTURED_CONSOLE_METHODS = ["log", "info", "warn", "error", "debug"]
96
173
 
97
- /**
98
- * AttemptConsoleOutput type.
99
- * @typedef {object} AttemptConsoleOutput
100
- * @property {number} attemptNumber - Attempt number.
101
- * @property {string} output - Captured console output.
102
- */
103
-
104
174
  /**
105
175
  * Runs to file slug.
106
176
  * @param {string} value - Value to sanitize.
@@ -114,87 +184,6 @@ function toFileSlug(value) {
114
184
  .slice(0, 80) || "failed-test"
115
185
  }
116
186
 
117
- /**
118
- * TestArgs type.
119
- * @typedef {object} TestArgs
120
- * @property {Application} [application] - Application instance for integration tests.
121
- * @property {RequestClient} [client] - HTTP client for request tests.
122
- * @property {object} [databaseCleaning] - Database cleanup options for tests.
123
- * @property {boolean} [databaseCleaning.transaction] - Use transactions to rollback between tests.
124
- * @property {boolean} [databaseCleaning.truncate] - Truncate tables between tests.
125
- * @property {boolean} [databaseCleaning.truncateBefore] - Truncate tables before each test, in addition to the default cleanup.
126
- * @property {boolean} [focus] - Whether this test is focused.
127
- * @property {() => (void|Promise<void>)} [function] - Test callback function.
128
- * @property {number} [retry] - Number of retries when a test fails.
129
- * @property {string[] | string} [tags] - Tags for filtering.
130
- * @property {number} [timeoutSeconds] - Timeout in seconds for the test.
131
- * @property {string} [type] - Test type identifier.
132
- */
133
-
134
- /**
135
- * TestData type.
136
- * @typedef {object} TestData
137
- * @property {TestArgs} args - Arguments passed to the test.
138
- * @property {string} [filePath] - Source file path.
139
- * @property {number} [line] - Source line number.
140
- * @property {function(TestArgs) : (void|Promise<void>)} function - Test callback to execute.
141
- */
142
-
143
- /**
144
- * FailedTestDetail type.
145
- * @typedef {object} FailedTestDetail
146
- * @property {string} fullDescription - Full test description.
147
- * @property {string} [filePath] - Source file path.
148
- * @property {number} [line] - Source line number.
149
- * @property {?} error - Failure error.
150
- * @property {string} [consoleOutput] - Captured console output while test ran.
151
- * @property {string} [consoleLogPath] - Saved console log path.
152
- */
153
-
154
- /**
155
- * ActiveAfterAllScopeEntry type.
156
- * @typedef {object} ActiveAfterAllScopeEntry
157
- * @property {TestsArgument} tests - Scope test tree.
158
- * @property {boolean} afterAllsRun - Whether cleanup hooks have run.
159
- */
160
-
161
- /**
162
- * Defines this typedef.
163
- * @typedef {function({configuration: import("../configuration.js").default, testArgs: TestArgs, testData: TestData}) : (void|Promise<void>)} AfterBeforeEachCallbackType
164
- */
165
-
166
- /**
167
- * AfterBeforeEachCallbackObjectType type.
168
- * @typedef {object} AfterBeforeEachCallbackObjectType
169
- * @property {AfterBeforeEachCallbackType} callback - Hook callback to execute.
170
- */
171
-
172
- /**
173
- * Defines this typedef.
174
- * @typedef {function({configuration: import("../configuration.js").default}) : (void|Promise<void>)} BeforeAfterAllCallbackType
175
- */
176
-
177
- /**
178
- * BeforeAfterAllCallbackObjectType type.
179
- * @typedef {object} BeforeAfterAllCallbackObjectType
180
- * @property {BeforeAfterAllCallbackType} callback - Hook callback to execute.
181
- */
182
-
183
- /**
184
- * TestsArgument type.
185
- * @typedef {object} TestsArgument
186
- * @property {Record<string, TestData>} args - Arguments keyed by test description.
187
- * @property {boolean} [anyTestsFocussed] - Whether any tests in the tree are focused.
188
- * @property {AfterBeforeEachCallbackObjectType[]} afterEaches - After-each hooks for this scope.
189
- * @property {BeforeAfterAllCallbackObjectType[]} afterAlls - After-all hooks for this scope.
190
- * @property {BeforeAfterAllCallbackObjectType[]} beforeAlls - Before-all hooks for this scope.
191
- * @property {AfterBeforeEachCallbackObjectType[]} beforeEaches - Before-each hooks for this scope.
192
- * @property {string} [filePath] - Source file path.
193
- * @property {number} [line] - Source line number.
194
- * @property {Record<string, TestData>} tests - A unique identifier for the node.
195
- * @property {Record<string, TestsArgument>} subs - Optional child nodes. Each item is another `Node`, allowing recursion.
196
- */
197
-
198
187
  export default class TestRunner {
199
188
  /**
200
189
  * Narrows the runtime value to the documented type.
@@ -539,17 +528,18 @@ export default class TestRunner {
539
528
  }
540
529
 
541
530
  /**
542
- * Pins each per-test connection as its pool's in-process test shared connection so
543
- * HTTP request handlers dispatched during the test (which run in the main thread but
544
- * in a fresh async context without the connection pin) resolve to the SAME connection
545
- * and therefore the same open transaction — as the test body. Pools that predate the
546
- * shared-connection hook are skipped. Pair with {@link clearTestSharedConnections} in a
547
- * finally.
548
- * @returns {void}
531
+ * Registers each non-tenant per-test connection as a dynamic candidate for in-process
532
+ * request sharing. The pool evaluates transaction state when each request is dispatched,
533
+ * so a transaction started or ended during a hook callback takes effect immediately.
534
+ * Inactive and tenant-only connections remain independently pooled. Pair with
535
+ * {@link clearTestSharedConnections} in a finally.
536
+ * @returns {{pool: import("../database/pool/base.js").default, registration: import("../database/pool/base.js").TestSharedConnectionRegistration}[]} - Lifecycle-owned registrations.
549
537
  */
550
538
  activateTestSharedConnections() {
551
539
  const configuration = this.getConfiguration()
552
540
  const currentConnections = configuration.getCurrentConnections()
541
+ /** @type {{pool: import("../database/pool/base.js").default, registration: import("../database/pool/base.js").TestSharedConnectionRegistration}[]} */
542
+ const registrations = []
553
543
 
554
544
  for (const identifier of Object.keys(currentConnections)) {
555
545
  const pool = configuration.getDatabasePool(identifier)
@@ -561,16 +551,33 @@ export default class TestRunner {
561
551
  if (pool.getConfiguration().tenantOnly) {
562
552
  continue
563
553
  }
564
- pool.setTestSharedConnection(currentConnections[identifier])
554
+
555
+ const connection = currentConnections[identifier]
556
+
557
+ const registration = pool.setTestSharedConnectionProvider(() => {
558
+ return connection.insideTransaction() ? connection : undefined
559
+ })
560
+
561
+ if (registration) registrations.push({pool, registration})
565
562
  }
563
+
564
+ return registrations
566
565
  }
567
566
 
568
567
  /**
569
568
  * Clears the in-process test shared connection on every configured pool. Idempotent and
570
569
  * safe to call when none was set.
570
+ * @param {{pool: import("../database/pool/base.js").default, registration: import("../database/pool/base.js").TestSharedConnectionRegistration}[]} [registrations] - Lifecycle-owned registrations to clear conditionally.
571
571
  * @returns {void}
572
572
  */
573
- clearTestSharedConnections() {
573
+ clearTestSharedConnections(registrations) {
574
+ if (registrations) {
575
+ for (const {pool, registration} of registrations) {
576
+ pool.clearTestSharedConnection(registration)
577
+ }
578
+ return
579
+ }
580
+
574
581
  const configuration = this.getConfiguration()
575
582
 
576
583
  for (const identifier of configuration.getDatabaseIdentifiers()) {
@@ -976,6 +983,8 @@ export default class TestRunner {
976
983
  * still wait for it to settle after runWithTimeout has abandoned it.
977
984
  * @type {Promise<?> | undefined} */
978
985
  let testLifecycle
986
+ /** @type {{pool: import("../database/pool/base.js").default, registration: import("../database/pool/base.js").TestSharedConnectionRegistration}[]} */
987
+ let testSharedConnectionRegistrations = []
979
988
  /**
980
989
  * Shared mutable flag so the catch block can suppress the
981
990
  * `_successfulTests` increment inside the still-detached lifecycle:
@@ -1002,12 +1011,11 @@ export default class TestRunner {
1002
1011
  // stale async-context pin and force every later test onto a fresh checkout,
1003
1012
  // breaking isolation).
1004
1013
  await this.getConfiguration().ensureConnections({name: `Test: ${testDescription}`}, async () => {
1005
- // Only request-type tests dispatch through the in-process HTTP handler,
1006
- // so only they need the pinned connection shared with it. Sharing it for
1007
- // every test would let unrelated specs observe a test shared connection on
1008
- // pools they inspect directly. Cleared after afterEach either way.
1014
+ // Register dynamic candidates before application hooks so transaction
1015
+ // state changes made during a hook are visible to a request dispatched
1016
+ // by that same callback.
1009
1017
  if (testArgs.type == "request") {
1010
- this.activateTestSharedConnections()
1018
+ testSharedConnectionRegistrations = this.activateTestSharedConnections()
1011
1019
  }
1012
1020
 
1013
1021
  try {
@@ -1035,7 +1043,7 @@ export default class TestRunner {
1035
1043
  }
1036
1044
  }
1037
1045
  } finally {
1038
- this.clearTestSharedConnections()
1046
+ this.clearTestSharedConnections(testSharedConnectionRegistrations)
1039
1047
  }
1040
1048
  })
1041
1049
  })
@@ -1077,7 +1085,7 @@ export default class TestRunner {
1077
1085
  // ensureConnections before activateTestSharedConnections() replaces
1078
1086
  // it. Clear it here so the next test checks out a fresh connection.
1079
1087
  // Idempotent when the lifecycle did settle and already cleared.
1080
- this.clearTestSharedConnections()
1088
+ this.clearTestSharedConnections(testSharedConnectionRegistrations)
1081
1089
  }
1082
1090
 
1083
1091
  willRetry = retriesUsed < retryCount
@@ -7,6 +7,14 @@ import Expect from "./expect.js"
7
7
  import waitForEvent from "./wait-for-event.js"
8
8
  import {arrayContaining, objectContaining} from "./expect-utils.js"
9
9
 
10
+ /**
11
+ * VelociousTestConfig type.
12
+ * @typedef {object} VelociousTestConfig
13
+ * @property {"failure" | "live"} consoleOutput - Console output mode.
14
+ * @property {string[]} excludeTags - Tags excluded by default.
15
+ * @property {number} defaultTimeoutSeconds - Default timeout in seconds.
16
+ * @property {number} failedConsoleOutputMaxLines - Maximum failed console lines to print inline.
17
+ */
10
18
  /**
11
19
  * Tests.
12
20
  * @type {import("./test-runner.js").TestsArgument} */
@@ -202,7 +210,6 @@ function afterAll(callback) {
202
210
  currentTest.afterAlls.push({callback})
203
211
  }
204
212
 
205
-
206
213
  /**
207
214
  * Runs describe.
208
215
  * @param {string} description - Description.
@@ -353,11 +360,3 @@ globalThis.testEvents = testEvents
353
360
  globalThis.configureTests = configureTests
354
361
 
355
362
  export {afterAll, afterEach, beforeAll, beforeEach, configureTests, describe, expect, fit, it, arrayContaining, objectContaining, testConfig, testEvents, tests, waitForEvent}
356
- /**
357
- * VelociousTestConfig type.
358
- * @typedef {object} VelociousTestConfig
359
- * @property {"failure" | "live"} consoleOutput - Console output mode.
360
- * @property {string[]} excludeTags - Tags excluded by default.
361
- * @property {number} defaultTimeoutSeconds - Default timeout in seconds.
362
- * @property {number} failedConsoleOutputMaxLines - Maximum failed console lines to print inline.
363
- */
@@ -1,3 +1,11 @@
1
+ /**
2
+ * ParsedStackFrame type.
3
+ * @typedef {object} ParsedStackFrame
4
+ * @property {string | undefined} methodName - Method/function name from the stack frame.
5
+ * @property {string} sourcePath - File or URL path from the stack frame.
6
+ * @property {number} lineNumber - Source line number.
7
+ * @property {number | undefined} columnNumber - Source column number.
8
+ */
1
9
  // @ts-check
2
10
 
3
11
  /**
@@ -9,15 +17,6 @@ function escapeRegExp(value) {
9
17
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
10
18
  }
11
19
 
12
- /**
13
- * ParsedStackFrame type.
14
- * @typedef {object} ParsedStackFrame
15
- * @property {string | undefined} methodName - Method/function name from the stack frame.
16
- * @property {string} sourcePath - File or URL path from the stack frame.
17
- * @property {number} lineNumber - Source line number.
18
- * @property {number | undefined} columnNumber - Source column number.
19
- */
20
-
21
20
  /**
22
21
  * Runs normalize path.
23
22
  * @param {string | undefined} value - Path or file URL.
@@ -1,7 +1,3 @@
1
- // @ts-check
2
-
3
- const MODEL_SCOPE_DESCRIPTOR_MARKER = "velociousModelScopeDescriptor"
4
-
5
1
  /**
6
2
  * ModelScopeDescriptor type.
7
3
  * @typedef {object} ModelScopeDescriptor
@@ -10,6 +6,9 @@ const MODEL_SCOPE_DESCRIPTOR_MARKER = "velociousModelScopeDescriptor"
10
6
  * @property {typeof import("../database/record/index.js").default | import("../frontend-models/base.js").FrontendModelClass} modelClass - Owning model class.
11
7
  * @property {Array<?>} scopeArgs - Scope arguments.
12
8
  */
9
+ // @ts-check
10
+
11
+ const MODEL_SCOPE_DESCRIPTOR_MARKER = "velociousModelScopeDescriptor"
13
12
 
14
13
  /**
15
14
  * Runs the defineModelScope helper.
@@ -4,50 +4,24 @@ import * as inflection from "inflection"
4
4
  import {isPlainObject} from "is-plain-object"
5
5
  import {resolveFrontendModelClass} from "../frontend-models/model-registry.js"
6
6
 
7
- /** Error raised when a Ransack descriptor is malformed. */
8
- export class RansackQueryError extends Error {
9
- /**
10
- * Creates a Ransack query error.
11
- * @param {string} message - Error message.
12
- */
13
- constructor(message) {
14
- super(message)
15
-
16
- this.name = "RansackQueryError"
17
- }
18
- }
19
-
20
- /**
21
- * Builds a Ransack query error.
22
- * @param {string} message - Error message.
23
- * @returns {RansackQueryError} - Ransack query error.
24
- */
25
- function ransackQueryError(message) {
26
- return new RansackQueryError(message)
27
- }
28
-
29
7
  /**
30
8
  * RansackPredicate type.
31
9
  * @typedef {"cont" | "end" | "eq" | "gt" | "gteq" | "in" | "lt" | "lteq" | "not_eq" | "not_in" | "null" | "start"} RansackPredicate
32
10
  */
33
-
34
11
  /**
35
12
  * RansackCombinator type.
36
13
  * @typedef {"and" | "or"} RansackCombinator
37
14
  */
38
-
39
15
  /**
40
16
  * RansackModelClass type.
41
17
  * @typedef {typeof import("../database/record/index.js").default | import("../frontend-models/base.js").FrontendModelClass} RansackModelClass
42
18
  */
43
-
44
19
  /**
45
20
  * RansackAttribute type.
46
21
  * @typedef {object} RansackAttribute
47
22
  * @property {string} attributeName - Resolved attribute name.
48
23
  * @property {string[]} path - Resolved relationship path.
49
24
  */
50
-
51
25
  /**
52
26
  * RansackCondition type.
53
27
  * @typedef {object} RansackCondition
@@ -56,7 +30,6 @@ function ransackQueryError(message) {
56
30
  * @property {RansackPredicate} predicate - Parsed Ransack predicate.
57
31
  * @property {?} value - Normalized value.
58
32
  */
59
-
60
33
  /**
61
34
  * RansackGroup type.
62
35
  * @typedef {object} RansackGroup
@@ -64,6 +37,33 @@ function ransackQueryError(message) {
64
37
  * @property {RansackCondition[]} conditions - Conditions in this group.
65
38
  * @property {RansackGroup[]} groupings - Nested groups.
66
39
  */
40
+ /**
41
+ * RansackSort type.
42
+ * @typedef {object} RansackSort
43
+ * @property {string} attribute - Resolved attribute name.
44
+ * @property {"asc" | "desc"} direction - Sort direction.
45
+ */
46
+ /** Error raised when a Ransack descriptor is malformed. */
47
+ export class RansackQueryError extends Error {
48
+ /**
49
+ * Creates a Ransack query error.
50
+ * @param {string} message - Error message.
51
+ */
52
+ constructor(message) {
53
+ super(message)
54
+
55
+ this.name = "RansackQueryError"
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Builds a Ransack query error.
61
+ * @param {string} message - Error message.
62
+ * @returns {RansackQueryError} - Ransack query error.
63
+ */
64
+ function ransackQueryError(message) {
65
+ return new RansackQueryError(message)
66
+ }
67
67
 
68
68
  const supportedPredicates = [
69
69
  "not_in",
@@ -803,13 +803,6 @@ function normalizeRansackArray(value) {
803
803
  return [value]
804
804
  }
805
805
 
806
- /**
807
- * RansackSort type.
808
- * @typedef {object} RansackSort
809
- * @property {string} attribute - Resolved attribute name.
810
- * @property {"asc" | "desc"} direction - Sort direction.
811
- */
812
-
813
806
  /**
814
807
  * Parses a ransack `s` sort string against model attributes.
815
808
  * @param {RansackModelClass} modelClass - Model class for attribute lookup.