velocious 1.0.501 → 1.0.503

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 (46) hide show
  1. package/build/application.js +2 -0
  2. package/build/src/application.d.ts.map +1 -1
  3. package/build/src/application.js +3 -1
  4. package/build/src/sync/sync-change-fanout.d.ts +71 -0
  5. package/build/src/sync/sync-change-fanout.d.ts.map +1 -0
  6. package/build/src/sync/sync-change-fanout.js +54 -0
  7. package/build/src/sync/sync-client-types.d.ts +6 -2
  8. package/build/src/sync/sync-client-types.d.ts.map +1 -1
  9. package/build/src/sync/sync-client-types.js +1 -1
  10. package/build/src/sync/sync-client.d.ts +71 -4
  11. package/build/src/sync/sync-client.d.ts.map +1 -1
  12. package/build/src/sync/sync-client.js +126 -18
  13. package/build/src/sync/sync-envelope-replay-service.d.ts +15 -4
  14. package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
  15. package/build/src/sync/sync-envelope-replay-service.js +60 -42
  16. package/build/src/sync/sync-publish-suppression.d.ts +31 -0
  17. package/build/src/sync/sync-publish-suppression.d.ts.map +1 -0
  18. package/build/src/sync/sync-publish-suppression.js +54 -0
  19. package/build/src/sync/sync-publisher-types.d.ts +146 -0
  20. package/build/src/sync/sync-publisher-types.d.ts.map +1 -0
  21. package/build/src/sync/sync-publisher-types.js +3 -0
  22. package/build/src/sync/sync-publisher.d.ts +137 -0
  23. package/build/src/sync/sync-publisher.d.ts.map +1 -0
  24. package/build/src/sync/sync-publisher.js +305 -0
  25. package/build/src/testing/test-runner.d.ts +8 -0
  26. package/build/src/testing/test-runner.d.ts.map +1 -1
  27. package/build/src/testing/test-runner.js +64 -2
  28. package/build/sync/sync-change-fanout.js +58 -0
  29. package/build/sync/sync-client-types.js +3 -2
  30. package/build/sync/sync-client.js +136 -18
  31. package/build/sync/sync-envelope-replay-service.js +60 -41
  32. package/build/sync/sync-publish-suppression.js +59 -0
  33. package/build/sync/sync-publisher-types.js +64 -0
  34. package/build/sync/sync-publisher.js +351 -0
  35. package/build/testing/test-runner.js +69 -1
  36. package/build/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +1 -1
  38. package/src/application.js +2 -0
  39. package/src/sync/sync-change-fanout.js +58 -0
  40. package/src/sync/sync-client-types.js +3 -2
  41. package/src/sync/sync-client.js +136 -18
  42. package/src/sync/sync-envelope-replay-service.js +60 -41
  43. package/src/sync/sync-publish-suppression.js +59 -0
  44. package/src/sync/sync-publisher-types.js +64 -0
  45. package/src/sync/sync-publisher.js +351 -0
  46. package/src/testing/test-runner.js +69 -1
@@ -0,0 +1,351 @@
1
+ // @ts-check
2
+
3
+ import Configuration from "../configuration.js"
4
+ import Logger from "../logger.js"
5
+ import restArgsError from "../utils/rest-args-error.js"
6
+
7
+ import {deliverDeclaredBroadcasts, upsertSyncRow} from "./sync-change-fanout.js"
8
+ import {isPublishingSuppressed} from "./sync-publish-suppression.js"
9
+
10
+ /** @type {{create: "afterCreate", update: "afterUpdate", destroy: "afterDestroy"}} */
11
+ const PUBLISHED_CALLBACK_NAMES = {create: "afterCreate", destroy: "afterDestroy", update: "afterUpdate"}
12
+
13
+ /**
14
+ * Operations published by default for models declaring `static sync` publish
15
+ * without an `operations` key: server-side creates and updates publish
16
+ * automatically. Destroys are not published by default because a server
17
+ * destroy is often cleanup rather than a synced delete; opt in with an
18
+ * operations list.
19
+ * @type {Array<"create" | "update" | "destroy">} */
20
+ const DEFAULT_PUBLISHED_OPERATIONS = ["create", "update"]
21
+
22
+ /** @type {WeakMap<Configuration, SyncPublisher>} */
23
+ const startedPublishersByConfiguration = new WeakMap()
24
+
25
+ /**
26
+ * Declarative server-side sync publisher — the server mirror of the client's
27
+ * track-by-default mutation tracking.
28
+ *
29
+ * Server models declare what to publish through `static sync`'s `publish`
30
+ * key, and Velocious writes every committed server-side change to the sync
31
+ * change feed (model-backed Sync-row upsert with server re-sequencing) and
32
+ * fans out the declared broadcasts, so devices receive server-origin changes
33
+ * without app code calling manual upsert/broadcast helpers:
34
+ *
35
+ * static sync = {
36
+ * publish: {
37
+ * serialize: (event) => ({id: event.id(), eventPin: event.eventPin()}),
38
+ * eventId: (event) => event.id(),
39
+ * broadcasts: [{channel: "ticket-scans", broadcastParams: ..., body: ...}]
40
+ * }
41
+ * }
42
+ *
43
+ * Replayed device mutations never double-publish: the framework's routed
44
+ * replay apply marks its written records through `markServerApply(record)`
45
+ * (see sync-publish-suppression.js), and app code applying already-synced
46
+ * data can use `markServerApply`/`withoutPublishing` the same way.
47
+ */
48
+ export default class SyncPublisher {
49
+ /**
50
+ * Builds the sync publisher by deriving published resources from the
51
+ * configuration's registered models: every model declaring `static sync`
52
+ * with a `publish` declaration becomes a published resource
53
+ * (`publish: false` opts out). The sync/change model is the registered
54
+ * "Sync" model and broadcasts default to the configuration's channel
55
+ * broadcast.
56
+ * @param {import("./sync-publisher-types.js").SyncPublisherOptions} [options] - Optional overrides.
57
+ */
58
+ constructor(options = {}) {
59
+ const {actorForeignKeyColumn = "authentication_token_id", broadcaster, configuration = Configuration.current(), onError, syncModel, ...restOptions} = options
60
+
61
+ restArgsError(restOptions)
62
+
63
+ const modelClasses = configuration.getModelClasses()
64
+ /** @type {Record<string, import("./sync-publisher-types.js").SyncPublisherResourceConfig>} */
65
+ const resources = {}
66
+
67
+ for (const modelClass of Object.values(modelClasses)) {
68
+ const publish = publishDeclarationFor(modelClass)
69
+
70
+ if (!publish) continue
71
+
72
+ const resourceConfig = resourceConfigFromPublishDeclaration({modelClass, publish})
73
+
74
+ resources[resourceConfig.resourceType] = resourceConfig
75
+ }
76
+
77
+ if (Object.keys(resources).length === 0) {
78
+ throw new Error("SyncPublisher found no registered models declaring static sync publish - declare `static sync = {publish: {serialize}}` on the models whose server-side changes should publish to the sync feed")
79
+ }
80
+
81
+ const resolvedSyncModel = syncModel || modelClasses.Sync
82
+
83
+ if (!resolvedSyncModel) {
84
+ throw new Error("SyncPublisher requires a registered \"Sync\" model for published sync change rows (or pass options.syncModel)")
85
+ }
86
+
87
+ /** @type {{actorForeignKeyColumn: string, broadcaster: import("./sync-publisher-types.js").SyncPublisherOptions["broadcaster"], configuration: Configuration, onError: import("./sync-publisher-types.js").SyncPublisherOptions["onError"], resources: Record<string, import("./sync-publisher-types.js").SyncPublisherResourceConfig>, syncModel: ?}} */
88
+ this.config = {actorForeignKeyColumn, broadcaster, configuration, onError, resources, syncModel: resolvedSyncModel}
89
+ /** @type {Array<{callback: (record: ?) => Promise<void>, callbackName: "afterCreate" | "afterUpdate" | "afterDestroy", modelClass: ?}>} */
90
+ this._publishedCallbacks = []
91
+ /** @type {Logger | null} */
92
+ this._logger = null
93
+ this._started = false
94
+ }
95
+
96
+ /**
97
+ * Builds a sync publisher derived from the given configuration. Alias for
98
+ * `new SyncPublisher({configuration, ...options})`.
99
+ * @param {Configuration} [configuration] - Configuration owning the registered models. Defaults to the current configuration.
100
+ * @param {Omit<import("./sync-publisher-types.js").SyncPublisherOptions, "configuration">} [options] - Optional overrides.
101
+ * @returns {SyncPublisher} Sync publisher derived from the configuration.
102
+ */
103
+ static fromConfiguration(configuration = Configuration.current(), options = {}) {
104
+ return new SyncPublisher({...options, configuration})
105
+ }
106
+
107
+ /**
108
+ * Starts (and memoizes per configuration) the sync publisher for a server
109
+ * boot: no-op when no registered model declares a publish config, guarded so
110
+ * repeated boots with the same configuration register the publish callbacks
111
+ * only once.
112
+ * @param {Configuration} configuration - Configuration owning the registered models.
113
+ * @returns {Promise<SyncPublisher | null>} Started publisher, or null when no models declare publish.
114
+ */
115
+ static async startFromConfiguration(configuration) {
116
+ const startedPublisher = startedPublishersByConfiguration.get(configuration)
117
+
118
+ if (startedPublisher) return startedPublisher
119
+
120
+ if (!Object.values(configuration.getModelClasses()).some((modelClass) => publishDeclarationFor(modelClass))) return null
121
+
122
+ const publisher = new SyncPublisher({configuration})
123
+
124
+ startedPublishersByConfiguration.set(configuration, publisher)
125
+ await publisher.start()
126
+
127
+ return publisher
128
+ }
129
+
130
+ /**
131
+ * Registers the publish callbacks for every published resource: server-side
132
+ * creates and updates (destroys when opted in) upsert a sync change row and
133
+ * fan out the declared broadcasts once their transaction commits.
134
+ * @returns {Promise<void>}
135
+ */
136
+ async start() {
137
+ if (this._started) return
138
+
139
+ this._started = true
140
+
141
+ for (const resourceConfig of Object.values(this.config.resources)) {
142
+ for (const operation of resourceConfig.operations) {
143
+ const callbackName = PUBLISHED_CALLBACK_NAMES[operation]
144
+ const callback = this.publishedMutationCallback({operation, resourceConfig})
145
+
146
+ resourceConfig.modelClass[callbackName](callback)
147
+ this._publishedCallbacks.push({callback, callbackName, modelClass: resourceConfig.modelClass})
148
+ }
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Unregisters all publish callbacks (tests, shutdown).
154
+ * @returns {void}
155
+ */
156
+ stop() {
157
+ for (const {callback, callbackName, modelClass} of this._publishedCallbacks) {
158
+ modelClass.unregisterLifecycleCallback(callbackName, callback)
159
+ }
160
+
161
+ this._publishedCallbacks = []
162
+ this._started = false
163
+ }
164
+
165
+ /**
166
+ * Builds the lifecycle callback publishing one server-side mutation. The
167
+ * published payload (declaration `serialize`), event scope, and sync type
168
+ * are snapshotted at mutation-callback time, so afterSave hooks assigning
169
+ * unsaved attributes (or any later drift on the record) cannot change what
170
+ * gets published vs what was committed. Persisting and broadcasting are
171
+ * deferred through the model connection's afterCommit hook so they only run
172
+ * once the mutation's transaction has committed (immediately when no
173
+ * transaction is open) - rolled-back mutations never publish. Post-commit
174
+ * publish failures are reported without rethrowing into the driver's
175
+ * afterCommit chain (see reportAfterCommitError).
176
+ * @param {{operation: "create" | "update" | "destroy", resourceConfig: import("./sync-publisher-types.js").SyncPublisherResourceConfig}} args - Operation and resource config.
177
+ * @returns {(record: ?) => Promise<void>} Lifecycle callback.
178
+ */
179
+ publishedMutationCallback({operation, resourceConfig}) {
180
+ return async (record) => {
181
+ if (isPublishingSuppressed(record)) return
182
+
183
+ const data = await resourceConfig.serialize(record)
184
+ const resourceId = String(record.id())
185
+ const syncType = operation === "destroy" ? "delete" : "update"
186
+ /** @type {Record<string, ?>} */
187
+ const attributes = {
188
+ [this.config.actorForeignKeyColumn]: null,
189
+ client_updated_at: new Date(),
190
+ data: JSON.stringify(data),
191
+ resource_id: resourceId,
192
+ resource_type: resourceConfig.resourceType,
193
+ sync_type: syncType
194
+ }
195
+
196
+ if (resourceConfig.eventId) {
197
+ const eventId = await resourceConfig.eventId(record)
198
+
199
+ attributes.event_id = eventId === undefined || eventId === null ? null : String(eventId)
200
+ }
201
+
202
+ await resourceConfig.modelClass.connection().afterCommit(async () => {
203
+ try {
204
+ const syncRow = await this.upsertPublishedSyncRow(attributes)
205
+
206
+ if (resourceConfig.broadcasts) {
207
+ await deliverDeclaredBroadcasts({
208
+ args: {data, operation, record, resourceId, resourceType: resourceConfig.resourceType, syncRow, syncType},
209
+ broadcaster: this.broadcaster(),
210
+ broadcasts: resourceConfig.broadcasts
211
+ })
212
+ }
213
+ } catch (error) {
214
+ await this.reportAfterCommitError(/** @type {Error} */ (error))
215
+ }
216
+ })
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Upserts the published server-origin sync row for a resource identity:
222
+ * server-origin rows carry a null actor column (no device to echo the
223
+ * change back to), so repeated server changes to one resource reuse and
224
+ * re-sequence one feed row.
225
+ * @param {Record<string, ?>} attributes - Snapshotted sync row attributes.
226
+ * @returns {Promise<?>} Upserted sync row.
227
+ */
228
+ async upsertPublishedSyncRow(attributes) {
229
+ const existingSync = await this.config.syncModel
230
+ .where({
231
+ [this.config.actorForeignKeyColumn]: null,
232
+ resource_id: attributes.resource_id,
233
+ resource_type: attributes.resource_type
234
+ })
235
+ .first()
236
+
237
+ return await upsertSyncRow({attributes, existingSync, syncModel: this.config.syncModel})
238
+ }
239
+
240
+ /**
241
+ * Returns the broadcaster delivering declared broadcasts: the injected one,
242
+ * or the configuration's channel broadcast awaited through the pending
243
+ * broadcast queue.
244
+ * @returns {NonNullable<import("./sync-publisher-types.js").SyncPublisherOptions["broadcaster"]>} Broadcast deliverer.
245
+ */
246
+ broadcaster() {
247
+ if (this.config.broadcaster) return this.config.broadcaster
248
+
249
+ return async ({body, channel, params}) => {
250
+ this.config.configuration.broadcastToChannel(channel, params, body)
251
+ await this.config.configuration.awaitPendingBroadcasts()
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Reports a post-commit publish failure. The transaction has already
257
+ * committed when afterCommit callbacks run, so rethrowing here would poison
258
+ * the driver's awaited afterCommit chain (breaking unrelated callbacks) -
259
+ * instead the failure goes to the configured onError hook, or is emitted on
260
+ * the configuration's framework-error/all-error channels (so production bug
261
+ * reporting via `configuration.getErrorEvents()` sees a broken publish
262
+ * path) and logged loudly through the publisher's logger when none is
263
+ * configured.
264
+ * @param {Error} error - Post-commit publish failure.
265
+ * @returns {Promise<void>}
266
+ */
267
+ async reportAfterCommitError(error) {
268
+ if (this.config.onError) {
269
+ this.config.onError(error)
270
+
271
+ return
272
+ }
273
+
274
+ const errorEvents = this.config.configuration.getErrorEvents()
275
+ const payload = {context: {stage: "sync-publish-after-commit"}, error}
276
+
277
+ errorEvents.emit("framework-error", payload)
278
+ errorEvents.emit("all-error", {...payload, errorType: "framework-error"})
279
+
280
+ await this.logger().error("SyncPublisher failed to publish a server-side sync change after commit", error)
281
+ }
282
+
283
+ /**
284
+ * Returns the lazily built publisher logger.
285
+ * @returns {Logger} Publisher logger.
286
+ */
287
+ logger() {
288
+ this._logger ||= new Logger("SyncPublisher", {configuration: this.config.configuration})
289
+
290
+ return this._logger
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Resolves a model class's active publish declaration from `static sync`.
296
+ * Opted-out (`publish: false`) and undeclared models resolve to null; every
297
+ * other declared value flows into loud declaration validation.
298
+ * @param {?} modelClass - Registered model class.
299
+ * @returns {import("./sync-publisher-types.js").SyncPublishDeclarationConfig | null} Active publish declaration, or null.
300
+ */
301
+ function publishDeclarationFor(modelClass) {
302
+ const declaration = modelClass.sync
303
+
304
+ if (!declaration || typeof declaration !== "object" || declaration.publish === undefined || declaration.publish === false) return null
305
+
306
+ return declaration.publish
307
+ }
308
+
309
+ /**
310
+ * Builds one published resource config from a model's `static sync` publish
311
+ * declaration.
312
+ * @param {{modelClass: ?, publish: import("./sync-publisher-types.js").SyncPublishDeclarationConfig}} args - Declaration args.
313
+ * @returns {import("./sync-publisher-types.js").SyncPublisherResourceConfig} Derived resource config.
314
+ */
315
+ function resourceConfigFromPublishDeclaration({modelClass, publish}) {
316
+ const modelName = modelClass.getModelName()
317
+
318
+ if (!publish || typeof publish !== "object" || Array.isArray(publish)) {
319
+ throw new Error(`${modelName} static sync publish must be false or a publish declaration object, got: ${String(publish)}`)
320
+ }
321
+
322
+ const {broadcasts, eventId, operations, resourceType, serialize, ...restDeclaration} = publish
323
+ const unknownKeys = Object.keys(restDeclaration)
324
+
325
+ if (unknownKeys.length > 0) {
326
+ throw new Error(`${modelName} static sync publish received unknown keys: ${unknownKeys.join(", ")} (supported: broadcasts, eventId, operations, resourceType, serialize)`)
327
+ }
328
+ if (typeof serialize !== "function") {
329
+ throw new Error(`${modelName} static sync publish requires a serialize(record) function building the published payload`)
330
+ }
331
+ if (operations !== undefined) {
332
+ if (!Array.isArray(operations) || operations.length === 0) {
333
+ throw new Error(`${modelName} static sync publish operations must be a non-empty array of create/update/destroy`)
334
+ }
335
+
336
+ for (const operation of operations) {
337
+ if (!(operation in PUBLISHED_CALLBACK_NAMES)) {
338
+ throw new Error(`${modelName} static sync publish operations must be create/update/destroy, got: ${String(operation)}`)
339
+ }
340
+ }
341
+ }
342
+
343
+ return {
344
+ broadcasts,
345
+ eventId,
346
+ modelClass,
347
+ operations: operations === undefined ? DEFAULT_PUBLISHED_OPERATIONS : operations,
348
+ resourceType: resourceType === undefined ? modelName : resourceType,
349
+ serialize
350
+ }
351
+ }
@@ -13,8 +13,20 @@ import {testConfig, testEvents, tests} from "./test.js"
13
13
  import {pathToFileURL} from "url"
14
14
  import {clearDeliveries} from "../mailer.js"
15
15
 
16
+ /**
17
+ * Marks the error thrown by {@link runWithTimeout} so the caller can tell a
18
+ * lifecycle timeout (the promise is still running detached) apart from an
19
+ * ordinary test failure (the promise already settled).
20
+ * @typedef {Error & {velociousTestTimeout?: true}} TestTimeoutError
21
+ */
22
+
16
23
  /**
17
24
  * Runs run with timeout.
25
+ *
26
+ * On timeout the wrapped `promise` is NOT cancelled — it keeps running detached.
27
+ * The rejected error is tagged with `velociousTestTimeout` so the runner knows
28
+ * the lifecycle (and its afterEach database cleanup) is still in flight and can
29
+ * wait for it to settle before the next test reuses the shared connection.
18
30
  * @param {Promise<?> | ?} promise - Promise or value.
19
31
  * @param {number} timeoutMs - Timeout in milliseconds.
20
32
  * @param {string} testDescription - Test description.
@@ -22,7 +34,9 @@ import {clearDeliveries} from "../mailer.js"
22
34
  */
23
35
  function runWithTimeout(promise, timeoutMs, testDescription) {
24
36
  const timeoutSeconds = (timeoutMs / 1000).toFixed(3).replace(/\.?0+$/, "")
37
+ /** @type {TestTimeoutError} */
25
38
  const timeoutError = new Error(`Timed out after ${timeoutSeconds}s: ${testDescription}`)
39
+ timeoutError.velociousTestTimeout = true
26
40
 
27
41
  return new Promise((resolve, reject) => {
28
42
  const timeout = setTimeout(() => reject(timeoutError), timeoutMs)
@@ -37,6 +51,38 @@ function runWithTimeout(promise, timeoutMs, testDescription) {
37
51
  })
38
52
  }
39
53
 
54
+ /**
55
+ * Waits for an abandoned (timed-out) test lifecycle to settle, bounded by a
56
+ * grace period, so its afterEach database cleanup runs on the shared connection
57
+ * before the next test reuses it. Resolves early the moment the lifecycle
58
+ * settles; otherwise resolves once the grace elapses (never rejects, and never
59
+ * keeps the process alive on its own).
60
+ * @param {Promise<?>} lifecycle - The abandoned per-test lifecycle promise.
61
+ * @param {number} graceMs - Maximum time to wait for the lifecycle to settle.
62
+ * @returns {Promise<boolean>} - Whether the lifecycle settled within the grace period.
63
+ */
64
+ function awaitSettledOrGrace(lifecycle, graceMs) {
65
+ return new Promise((resolve) => {
66
+ let settled = false
67
+ const graceTimer = setTimeout(() => {
68
+ if (settled) return
69
+
70
+ settled = true
71
+ resolve(false)
72
+ }, graceMs)
73
+
74
+ if (typeof graceTimer.unref === "function") graceTimer.unref()
75
+
76
+ Promise.resolve(lifecycle).then(() => {}, () => {}).then(() => {
77
+ if (settled) return
78
+
79
+ settled = true
80
+ clearTimeout(graceTimer)
81
+ resolve(true)
82
+ })
83
+ })
84
+ }
85
+
40
86
  /**
41
87
  * ConsoleMethodName type.
42
88
  * @typedef {"log" | "info" | "warn" | "error" | "debug"} ConsoleMethodName */
@@ -862,6 +908,11 @@ export default class TestRunner {
862
908
  * @type {?} */
863
909
  let lastError
864
910
  let willRetry = false
911
+ /**
912
+ * The per-test lifecycle promise, hoisted so the timeout branch can
913
+ * still wait for it to settle after runWithTimeout has abandoned it.
914
+ * @type {Promise<?> | undefined} */
915
+ let testLifecycle
865
916
  const stopConsoleCapture = this.startConsoleCapture({
866
917
  passthrough: testConfig.consoleOutput === "live"
867
918
  })
@@ -870,7 +921,7 @@ export default class TestRunner {
870
921
  // Run the whole per-test lifecycle (dummy/server startup, connection
871
922
  // acquisition, beforeEach hooks, the test body and afterEach hooks) as
872
923
  // one promise so the timeout below can cover all of it.
873
- const testLifecycle = this.runWithDummyIfNeeded(testArgs, async () => {
924
+ testLifecycle = this.runWithDummyIfNeeded(testArgs, async () => {
874
925
  // Pin one connection per test so beforeEach, the test body and afterEach
875
926
  // all run on the SAME connection. This is required for transaction-based
876
927
  // database cleaning (beforeEach starts a transaction, afterEach rolls it
@@ -917,6 +968,23 @@ export default class TestRunner {
917
968
  } catch (error) {
918
969
  caughtError = error
919
970
  lastError = error
971
+
972
+ // A timeout REJECTS while the lifecycle keeps running detached on the
973
+ // shared per-suite connection — including its afterEach database
974
+ // cleanup (e.g. transaction rollback). If the next test starts before
975
+ // that rollback runs, its own startTransaction() implicitly COMMITS
976
+ // the timed-out test's rows on the shared connection, poisoning every
977
+ // later test in the shard (duplicate-key / foreign-key cascades from
978
+ // leaked fixtures). Wait — bounded — for the abandoned lifecycle to
979
+ // settle so its cleanup lands first. Bounded so a genuinely hung test
980
+ // still can't stall the whole run: if it will not settle within the
981
+ // grace, we proceed exactly as before (no worse than today).
982
+ const timedOut = Boolean(/** @type {TestTimeoutError} */ (error)?.velociousTestTimeout)
983
+
984
+ if (timedOut && testLifecycle) {
985
+ await awaitSettledOrGrace(testLifecycle, timeoutMs ?? 60000)
986
+ }
987
+
920
988
  willRetry = retriesUsed < retryCount
921
989
 
922
990
  if (willRetry) {
@@ -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/column-types.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/counter-cache-magnitude.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-realtime-bridge.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/column-types.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/counter-cache-magnitude.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-change-fanout.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-publish-suppression.js","../src/sync/sync-publisher-types.js","../src/sync/sync-publisher.js","../src/sync/sync-realtime-bridge.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
@@ -3,7 +3,7 @@
3
3
  "velocious": "build/bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.501",
6
+ "version": "1.0.503",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -5,6 +5,7 @@ import Logger from "./logger.js"
5
5
  import HttpServer from "./http-server/index.js"
6
6
  import HttpServerLock from "./http-server/server-lock.js"
7
7
  import SyncApiController from "./sync/sync-api-controller.js"
8
+ import SyncPublisher from "./sync/sync-publisher.js"
8
9
  import websocketEventsHost from "./http-server/websocket-events-host.js"
9
10
  import restArgsError from "./utils/rest-args-error.js"
10
11
 
@@ -56,6 +57,7 @@ export default class VelociousApplication {
56
57
  await this.configuration.initialize({type: this.getType()})
57
58
 
58
59
  SyncApiController.mountFromConfiguration(this.configuration)
60
+ await SyncPublisher.startFromConfiguration(this.configuration)
59
61
 
60
62
  this.configuration.setRoutes(routes)
61
63