velocious 1.0.502 → 1.0.504

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 (81) hide show
  1. package/build/application.js +4 -0
  2. package/build/configuration-types.js +8 -8
  3. package/build/configuration.js +2 -2
  4. package/build/src/application.d.ts.map +1 -1
  5. package/build/src/application.js +5 -1
  6. package/build/src/configuration-types.d.ts +17 -17
  7. package/build/src/configuration-types.d.ts.map +1 -1
  8. package/build/src/configuration-types.js +9 -9
  9. package/build/src/configuration.d.ts +4 -4
  10. package/build/src/configuration.d.ts.map +1 -1
  11. package/build/src/configuration.js +3 -3
  12. package/build/src/sync/sync-change-fanout.d.ts +71 -0
  13. package/build/src/sync/sync-change-fanout.d.ts.map +1 -0
  14. package/build/src/sync/sync-change-fanout.js +54 -0
  15. package/build/src/sync/sync-channel-name.d.ts +9 -0
  16. package/build/src/sync/sync-channel-name.d.ts.map +1 -0
  17. package/build/src/sync/sync-channel-name.js +10 -0
  18. package/build/src/sync/sync-client-types.d.ts +13 -6
  19. package/build/src/sync/sync-client-types.d.ts.map +1 -1
  20. package/build/src/sync/sync-client-types.js +1 -1
  21. package/build/src/sync/sync-client.d.ts +1 -1
  22. package/build/src/sync/sync-client.d.ts.map +1 -1
  23. package/build/src/sync/sync-client.js +8 -4
  24. package/build/src/sync/sync-envelope-replay-service.d.ts +15 -4
  25. package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
  26. package/build/src/sync/sync-envelope-replay-service.js +60 -42
  27. package/build/src/sync/sync-model-change-feed-service.d.ts +6 -1
  28. package/build/src/sync/sync-model-change-feed-service.d.ts.map +1 -1
  29. package/build/src/sync/sync-model-change-feed-service.js +15 -4
  30. package/build/src/sync/sync-publish-suppression.d.ts +31 -0
  31. package/build/src/sync/sync-publish-suppression.d.ts.map +1 -0
  32. package/build/src/sync/sync-publish-suppression.js +54 -0
  33. package/build/src/sync/sync-publisher-types.d.ts +178 -0
  34. package/build/src/sync/sync-publisher-types.d.ts.map +1 -0
  35. package/build/src/sync/sync-publisher-types.js +3 -0
  36. package/build/src/sync/sync-publisher.d.ts +160 -0
  37. package/build/src/sync/sync-publisher.d.ts.map +1 -0
  38. package/build/src/sync/sync-publisher.js +438 -0
  39. package/build/src/sync/sync-realtime-bridge.d.ts +33 -10
  40. package/build/src/sync/sync-realtime-bridge.d.ts.map +1 -1
  41. package/build/src/sync/sync-realtime-bridge.js +51 -12
  42. package/build/src/sync/sync-scope-attributes.d.ts +15 -0
  43. package/build/src/sync/sync-scope-attributes.d.ts.map +1 -0
  44. package/build/src/sync/sync-scope-attributes.js +24 -0
  45. package/build/src/sync/sync-websocket-channel.d.ts +58 -0
  46. package/build/src/sync/sync-websocket-channel.d.ts.map +1 -0
  47. package/build/src/sync/sync-websocket-channel.js +131 -0
  48. package/build/src/testing/test-runner.d.ts +8 -0
  49. package/build/src/testing/test-runner.d.ts.map +1 -1
  50. package/build/src/testing/test-runner.js +64 -2
  51. package/build/sync/sync-change-fanout.js +58 -0
  52. package/build/sync/sync-channel-name.js +10 -0
  53. package/build/sync/sync-client-types.js +12 -5
  54. package/build/sync/sync-client.js +8 -3
  55. package/build/sync/sync-envelope-replay-service.js +60 -41
  56. package/build/sync/sync-model-change-feed-service.js +17 -3
  57. package/build/sync/sync-publish-suppression.js +59 -0
  58. package/build/sync/sync-publisher-types.js +84 -0
  59. package/build/sync/sync-publisher.js +502 -0
  60. package/build/sync/sync-realtime-bridge.js +56 -11
  61. package/build/sync/sync-scope-attributes.js +26 -0
  62. package/build/sync/sync-websocket-channel.js +146 -0
  63. package/build/testing/test-runner.js +69 -1
  64. package/build/tsconfig.tsbuildinfo +1 -1
  65. package/package.json +1 -1
  66. package/src/application.js +4 -0
  67. package/src/configuration-types.js +8 -8
  68. package/src/configuration.js +2 -2
  69. package/src/sync/sync-change-fanout.js +58 -0
  70. package/src/sync/sync-channel-name.js +10 -0
  71. package/src/sync/sync-client-types.js +12 -5
  72. package/src/sync/sync-client.js +8 -3
  73. package/src/sync/sync-envelope-replay-service.js +60 -41
  74. package/src/sync/sync-model-change-feed-service.js +17 -3
  75. package/src/sync/sync-publish-suppression.js +59 -0
  76. package/src/sync/sync-publisher-types.js +84 -0
  77. package/src/sync/sync-publisher.js +502 -0
  78. package/src/sync/sync-realtime-bridge.js +56 -11
  79. package/src/sync/sync-scope-attributes.js +26 -0
  80. package/src/sync/sync-websocket-channel.js +146 -0
  81. package/src/testing/test-runner.js +69 -1
@@ -0,0 +1,146 @@
1
+ // @ts-check
2
+
3
+ import VelociousWebsocketChannel from "../http-server/websocket-channel.js"
4
+ import {VELOCIOUS_SYNC_CHANNEL} from "./sync-channel-name.js"
5
+
6
+ /** Configurations whose framework sync channel has already been registered. */
7
+ const registeredConfigurations = new WeakSet()
8
+
9
+ /**
10
+ * Framework-owned websocket channel for synced resources
11
+ * ({@link VELOCIOUS_SYNC_CHANNEL}).
12
+ *
13
+ * Subscribe params mirror a declared pull scope — `{resourceType, conditions}`
14
+ * plus the client-injected `authenticationToken` — and subscribe-time
15
+ * authorization delegates to the app sync resource's existing
16
+ * `authorizeChanges({params, scope})` (the `sync.api.resourceClass`), so apps
17
+ * hook in through the authorization they already declared instead of writing
18
+ * their own channel classes. Broadcast routing matches the publisher's
19
+ * scoping params against the subscription's scope conditions.
20
+ */
21
+ export default class SyncWebsocketChannel extends VelociousWebsocketChannel {
22
+ /**
23
+ * Scope the subscription was authorized for, set by {@link SyncWebsocketChannel#canSubscribe}.
24
+ * @type {import("./sync-resource-base.js").SerializedChangesScope | null}
25
+ */
26
+ _scope = null
27
+
28
+ /**
29
+ * Registers the framework sync channel on a configuration declaring a
30
+ * `sync.api` block (guarded so repeated server boots with the same
31
+ * configuration register it only once). No-op without `sync.api` — the
32
+ * channel authorizes through the app's sync resource class.
33
+ * @param {import("../configuration.js").default} configuration - Configuration instance.
34
+ * @returns {void}
35
+ */
36
+ static registerFromConfiguration(configuration) {
37
+ if (!configuration.getSyncConfiguration().api || registeredConfigurations.has(configuration)) return
38
+
39
+ registeredConfigurations.add(configuration)
40
+ configuration.registerWebsocketChannel(VELOCIOUS_SYNC_CHANNEL, this)
41
+ }
42
+
43
+ /**
44
+ * Authorizes the subscription through the app sync resource: the subscribe
45
+ * params are parsed into the same serialized scope the changes endpoint
46
+ * consumes and passed to the resource's `authorizeChanges({params, scope})`.
47
+ * Denials and malformed scopes throw, rejecting the subscription.
48
+ * @returns {Promise<boolean>} Whether the subscription is allowed.
49
+ */
50
+ async canSubscribe() {
51
+ const resource = await this.buildSyncResource()
52
+ const scope = resource.changesScope({scope: {conditions: this.params.conditions, resourceType: this.params.resourceType}})
53
+
54
+ await resource.authorizeChanges({params: this.params, scope})
55
+
56
+ this._scope = scope
57
+
58
+ return true
59
+ }
60
+
61
+ /**
62
+ * Builds the app sync resource authorizing this subscription, mirroring the
63
+ * sync transport controller's resource construction with the ability
64
+ * resolved from the subscribe params (which carry the client-injected
65
+ * authenticationToken).
66
+ * @returns {Promise<import("./sync-resource-base.js").default>} App sync resource instance.
67
+ */
68
+ async buildSyncResource() {
69
+ const configuration = this.session.configuration
70
+ const api = configuration.getSyncConfiguration().api
71
+
72
+ if (!api) {
73
+ throw new Error(`The ${VELOCIOUS_SYNC_CHANNEL} channel requires a sync.api configuration block with the app's sync resource class`)
74
+ }
75
+
76
+ // Narrows the configured resource class to the sync resource contract
77
+ // (changesScope/authorizeChanges) the sync.api validation requires.
78
+ const ResourceClass = /** @type {typeof import("./sync-resource-base.js").default} */ (api.resourceClass)
79
+ // Narrows the websocket subscribe params to the resource params contract.
80
+ const params = /** @type {import("../configuration-types.js").VelociousParams} */ (/** @type {unknown} */ (this.params))
81
+ const request = this.session.upgradeRequest
82
+ const ability = await configuration.resolveAbility({params, request})
83
+
84
+ return new ResourceClass({
85
+ ability,
86
+ context: {
87
+ ...(ability?.getContext() || {}),
88
+ params,
89
+ request
90
+ },
91
+ locals: ability?.getLocals() || {},
92
+ modelClass: ResourceClass.ModelClass,
93
+ modelName: ResourceClass.ModelClass?.name,
94
+ params,
95
+ resourceConfiguration: /** @type {import("../configuration-types.js").FrontendModelResourceConfiguration} */ ({
96
+ attributes: ResourceClass.attributes || {},
97
+ sync: {enabled: true}
98
+ })
99
+ })
100
+ }
101
+
102
+ /**
103
+ * Routes a publisher broadcast to this subscription when the published
104
+ * resource type equals the type the subscription was authorized for and the
105
+ * scoping params satisfy every scope condition: each condition key must be
106
+ * present in the broadcast params and match by string comparison (array
107
+ * conditions match by membership). Broadcasts without a resource type and
108
+ * conditions the publisher's scoping params do not carry never match, so a
109
+ * subscription cannot receive changes outside its authorized scope.
110
+ * @param {import("../http-server/websocket-channel.js").WebsocketJsonValue} broadcastParams - Publisher scoping params (the published resourceType plus the change's scope-partition values).
111
+ * @returns {boolean} Whether the broadcast belongs to this subscription's scope.
112
+ */
113
+ matches(broadcastParams) {
114
+ const scope = this._scope
115
+
116
+ if (!scope) return false
117
+
118
+ const scopingParams = broadcastParams && typeof broadcastParams === "object" && !Array.isArray(broadcastParams)
119
+ ? /** @type {Record<string, ?>} */ (broadcastParams)
120
+ : {}
121
+
122
+ if (!Object.hasOwn(scopingParams, "resourceType") || String(scopingParams.resourceType) !== String(scope.resourceType)) return false
123
+
124
+ for (const [conditionName, conditionValue] of Object.entries(scope.conditions)) {
125
+ if (!Object.hasOwn(scopingParams, conditionName)) return false
126
+
127
+ const scopingValue = scopingParams[conditionName]
128
+
129
+ if (Array.isArray(conditionValue)) {
130
+ if (!conditionValue.some((value) => String(value) === String(scopingValue))) return false
131
+ } else if (String(conditionValue) !== String(scopingValue)) {
132
+ return false
133
+ }
134
+ }
135
+
136
+ return true
137
+ }
138
+
139
+ /**
140
+ * Returns the authorized scope for debug snapshots.
141
+ * @returns {Record<string, ?>} Debug-safe subscription details.
142
+ */
143
+ debugSnapshot() {
144
+ return {scope: this._scope}
145
+ }
146
+ }
@@ -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-channel-name.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-attributes.js","../src/sync/sync-scope-store.js","../src/sync/sync-websocket-channel.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.502",
6
+ "version": "1.0.504",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -5,6 +5,8 @@ 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"
9
+ import SyncWebsocketChannel from "./sync/sync-websocket-channel.js"
8
10
  import websocketEventsHost from "./http-server/websocket-events-host.js"
9
11
  import restArgsError from "./utils/rest-args-error.js"
10
12
 
@@ -56,6 +58,8 @@ export default class VelociousApplication {
56
58
  await this.configuration.initialize({type: this.getType()})
57
59
 
58
60
  SyncApiController.mountFromConfiguration(this.configuration)
61
+ SyncWebsocketChannel.registerFromConfiguration(this.configuration)
62
+ await SyncPublisher.startFromConfiguration(this.configuration)
59
63
 
60
64
  this.configuration.setRoutes(routes)
61
65
 
@@ -390,19 +390,19 @@
390
390
  * One realtime channel subscription descriptor.
391
391
  * @typedef {object} VelociousSyncRealtimeChannelDescriptor
392
392
  * @property {string} channel - Server channel name to subscribe.
393
- * @property {Record<string, ?>} [params] - Subscribe params (runtime values like eventId). The framework injects `authenticationToken` automatically.
393
+ * @property {Record<string, ?>} [params] - Subscribe params (runtime scope values). The framework injects `authenticationToken` automatically.
394
394
  * @property {string} [resourceType] - Default resource/model name for pushed changes that do not carry their own resourceType.
395
395
  */
396
396
 
397
397
  /**
398
- * Realtime push configuration for the sync client. Only the genuinely app-owned
399
- * callbacks live here: how to build the websocket client and which channels
400
- * (with runtime params) to subscribe. Everything else - subscribing, applying
401
- * pushes through the derived resource applier, echo suppression, and
402
- * pull-on-reconnect - is derived.
398
+ * Realtime push configuration for the sync client. Only the genuinely
399
+ * app-owned callback lives here: how to build the websocket client.
400
+ * Everything else - deriving the framework sync channel subscriptions from
401
+ * the declared pull scopes, subscribing, applying pushes through the derived
402
+ * resource applier, echo suppression, and pull-on-reconnect - is derived.
403
403
  * @typedef {object} VelociousSyncClientRealtimeConfiguration
404
404
  * @property {() => VelociousSyncRealtimeWebsocketClient | Promise<VelociousSyncRealtimeWebsocketClient>} createClient - Builds the (unconnected) websocket client; the framework owns connect/disconnect.
405
- * @property {(context: ?) => Array<VelociousSyncRealtimeChannelDescriptor> | Promise<Array<VelociousSyncRealtimeChannelDescriptor>>} [channels] - Resolves channel descriptors from the `subscribeRealtime(context)` context (runtime params like eventId). Optional when models declare `static sync = {realtime: {channel}}`.
405
+ * @property {(context: ?) => Array<VelociousSyncRealtimeChannelDescriptor> | Promise<Array<VelociousSyncRealtimeChannelDescriptor>>} [channels] - Deprecated legacy escape hatch: resolves extra app-channel descriptors from the `subscribeRealtime(context)` context. Declared pull scopes subscribe the framework sync channel automatically.
406
406
  * @property {() => string | Promise<string>} [localOrigin] - Resolves this device's echo origin; pushed messages with a matching `echoOrigin` are dropped.
407
407
  * @property {boolean} [pullOnReconnect] - Fire a coalesced `pull()` when subscriptions become ready or resume after a drop, closing offline gaps. Defaults to true.
408
408
  */
@@ -541,7 +541,7 @@
541
541
  */
542
542
 
543
543
  /**
544
- * @typedef {function({configuration: import("./configuration.js").default, params: Record<string, ?>, request: import("./http-server/client/request.js").default | import("./http-server/client/websocket-request.js").default, response: import("./http-server/client/response.js").default}) : import("./authorization/ability.js").default | void | Promise<import("./authorization/ability.js").default | void>} AbilityResolverType
544
+ * @typedef {function({configuration: import("./configuration.js").default, params: Record<string, ?>, request: import("./http-server/client/request.js").default | import("./http-server/client/websocket-request.js").default | undefined, response: import("./http-server/client/response.js").default | undefined}) : import("./authorization/ability.js").default | void | Promise<import("./authorization/ability.js").default | void>} AbilityResolverType
545
545
  */
546
546
 
547
547
  /**
@@ -2502,8 +2502,8 @@ export default class VelociousConfiguration {
2502
2502
  * Runs resolve ability.
2503
2503
  * @param {object} args - Ability resolver args.
2504
2504
  * @param {Record<string, ?>} args.params - Request params.
2505
- * @param {import("./http-server/client/request.js").default | import("./http-server/client/websocket-request.js").default} args.request - Request object.
2506
- * @param {import("./http-server/client/response.js").default} args.response - Response object.
2505
+ * @param {import("./http-server/client/request.js").default | import("./http-server/client/websocket-request.js").default} [args.request] - Request object. Absent for websocket channel subscriptions resolved from subscribe params.
2506
+ * @param {import("./http-server/client/response.js").default} [args.response] - Response object. Absent outside HTTP request handling.
2507
2507
  * @returns {Promise<import("./authorization/ability.js").default | undefined>} - Resolved ability.
2508
2508
  */
2509
2509
  async resolveAbility({params, request, response}) {
@@ -0,0 +1,58 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * One declarative broadcast delivered through an injected broadcaster. The
5
+ * replay service resolves it with replay args ({actor, applyResult, mutation,
6
+ * ...}) and the sync publisher with publish args
7
+ * ({@link import("./sync-publisher-types.js").SyncPublishBroadcastArgs}).
8
+ * @template [Args=Record<string, ?>]
9
+ * @typedef {object} DeclaredBroadcast
10
+ * @property {string | ((args: Args) => string)} channel - Channel name or resolver.
11
+ * @property {(args: Args) => Record<string, ?>} broadcastParams - Channel routing params.
12
+ * @property {(args: Args) => ?} body - Broadcast body.
13
+ * @property {(args: Args) => boolean} [when] - Optional gate; skipped when it returns false.
14
+ */
15
+
16
+ /**
17
+ * Upserts one sync/change row through the shared sync-model contract: an
18
+ * existing row for the resource identity is reassigned and re-sequenced
19
+ * through `advanceServerSequence()` (the change-feed sequence contract) so
20
+ * feed cursors pick the change up again; otherwise a new row is created
21
+ * (creates allocate their sequence through the model's own hooks). Shared by
22
+ * the replay service's model-backed persistence and the server sync
23
+ * publisher.
24
+ * @param {{attributes: Record<string, ?>, existingSync: ?, syncModel: ?}} args - Row attributes, existing row for the resource identity, and the sync model.
25
+ * @returns {Promise<?>} Upserted sync row.
26
+ */
27
+ export async function upsertSyncRow({attributes, existingSync, syncModel}) {
28
+ if (existingSync) {
29
+ existingSync.assign(attributes)
30
+ await existingSync.advanceServerSequence()
31
+ await existingSync.save()
32
+
33
+ return existingSync
34
+ }
35
+
36
+ return await syncModel.create(attributes)
37
+ }
38
+
39
+ /**
40
+ * Delivers declarative broadcasts through an injected broadcaster: each
41
+ * broadcast's `when` gate is checked, then channel/params/body are resolved
42
+ * from the caller's args. Shared by the replay service's default
43
+ * afterReplayMutation and the server sync publisher.
44
+ * @template Args
45
+ * @param {{args: Args, broadcaster: (broadcast: {channel: string, params: Record<string, ?>, body: ?}) => Promise<void>, broadcasts: Array<DeclaredBroadcast<Args>>}} deliveryArgs - Broadcast resolver args, broadcaster, and declared broadcasts.
46
+ * @returns {Promise<void>}
47
+ */
48
+ export async function deliverDeclaredBroadcasts({args, broadcaster, broadcasts}) {
49
+ for (const broadcast of broadcasts) {
50
+ if (broadcast.when && !broadcast.when(args)) continue
51
+
52
+ await broadcaster({
53
+ body: broadcast.body(args),
54
+ channel: typeof broadcast.channel === "function" ? broadcast.channel(args) : broadcast.channel,
55
+ params: broadcast.broadcastParams(args)
56
+ })
57
+ }
58
+ }
@@ -0,0 +1,10 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * Canonical framework-owned websocket channel for synced resources. The server
5
+ * registers it automatically when `sync.api` is configured (subscribe
6
+ * authorization delegates to the app sync resource's `authorizeChanges`), the
7
+ * sync publisher broadcasts standard sync envelopes on it, and the derived
8
+ * sync client subscribes its declared pull scopes to it automatically.
9
+ */
10
+ export const VELOCIOUS_SYNC_CHANNEL = "velocious-sync"
@@ -9,8 +9,8 @@
9
9
 
10
10
  /**
11
11
  * Static realtime channel declaration on a model's `static sync`, for channels
12
- * whose name and params are static. Channels needing runtime params (like
13
- * eventId) belong in the `sync.client.realtime.channels` callback instead.
12
+ * whose name and params are static.
13
+ * @deprecated Declared pull scopes subscribe the framework sync channel automatically; keep this only for legacy app channels.
14
14
  * @typedef {object} ModelSyncRealtimeDeclaration
15
15
  * @property {string} channel - Server channel name to subscribe.
16
16
  * @property {Record<string, ?>} [params] - Static subscribe params. The framework injects `authenticationToken` automatically.
@@ -29,13 +29,14 @@
29
29
  * @property {"upsert" | ((args: {operation: "create" | "update" | "destroy", record: ?}) => string)} [syncType] - Maps a mutation operation to a sync type. The "upsert" flag queues creates and updates as "update" rows (the server upserts by resource id) and destroys as "delete". Defaults to the operation name with destroy mapped to "delete".
30
30
  * @property {(args: {operation: "create" | "update" | "destroy", record: ?}) => Record<string, ?>} [trackedData] - Custom queued-payload builder for tracked mutations.
31
31
  * @property {boolean | {operations: Array<"create" | "update" | "destroy">}} [track] - Automatic mutation tracking policy. On by default (creates and updates queue automatically); `false` opts the resource out, `true` adds destroys, `{operations}` narrows the tracked operations.
32
- * @property {ModelSyncRealtimeDeclaration} [realtime] - Static realtime channel this resource subscribes through `subscribeRealtime(...)`.
32
+ * @property {ModelSyncRealtimeDeclaration} [realtime] - Deprecated: static legacy realtime channel this resource subscribes through `subscribeRealtime(...)`. Declared pull scopes subscribe the framework sync channel automatically.
33
33
  */
34
34
 
35
35
  /**
36
36
  * Model-level client sync declaration read from `static sync` by
37
37
  * `SyncClient.fromConfiguration(...)`. `true` opts the model in with all
38
38
  * defaults; an object customizes the derived resource config.
39
+ * @template [TModel=any]
39
40
  * @typedef {object} ModelSyncDeclarationConfig
40
41
  * @property {import("./sync-api-client-types.js").SyncResourceConfig["afterApply"]} [afterApply] - Post-apply hook.
41
42
  * @property {import("./sync-api-client-types.js").SyncResourceConfig["attributes"]} [attributes] - Pull-apply attribute mapper. Required for resources that receive pulled changes.
@@ -43,13 +44,19 @@
43
44
  * @property {import("./sync-api-client-types.js").SyncResourceConfig["findRecord"]} [findRecord] - Custom pull-apply record resolver.
44
45
  * @property {import("./sync-api-client-types.js").SyncResourceConfig["findRecordForDelete"]} [findRecordForDelete] - Custom pull-apply delete resolver.
45
46
  * @property {string[]} [localOnlyAttributes] - Extra local-only attributes merged with the derived primary key, createdAt/updatedAt, and sync bookkeeping attributes.
47
+ * @property {import("./sync-publisher-types.js").SyncPublishDeclaration<TModel>} [publish] - Server-side publish declaration consumed by `SyncPublisher.fromConfiguration(...)` on the backend; ignored by the client.
46
48
  * @property {"upsert" | ((args: {operation: "create" | "update" | "destroy", record: ?}) => string)} [syncType] - Sync type flag or mapper (see SyncClientResourceConfig).
47
49
  * @property {boolean | Array<"create" | "update" | "destroy"> | {operations: Array<"create" | "update" | "destroy">}} [track] - Automatic mutation tracking policy; an array is shorthand for {operations}. On by default (creates and updates queue automatically); `false` opts the model out (for models written by non-user flows), `true` adds destroys.
48
50
  * @property {(args: {operation: "create" | "update" | "destroy", record: ?}) => Record<string, ?>} [trackedData] - Custom queued-payload builder for tracked mutations.
49
- * @property {ModelSyncRealtimeDeclaration} [realtime] - Static realtime channel this resource subscribes through `subscribeRealtime(...)`; use the `sync.client.realtime.channels` callback for channels needing runtime params.
51
+ * @property {ModelSyncRealtimeDeclaration} [realtime] - Deprecated: static legacy realtime channel this resource subscribes through `subscribeRealtime(...)`. Declared pull scopes subscribe the framework sync channel automatically.
50
52
  */
51
53
 
52
- /** @typedef {boolean | ModelSyncDeclarationConfig} ModelSyncDeclaration */
54
+ /**
55
+ * Model-level sync declaration value: `true` opts in with all defaults, an
56
+ * object customizes the derived resource config.
57
+ * @template [TModel=any]
58
+ * @typedef {boolean | ModelSyncDeclarationConfig<TModel>} ModelSyncDeclaration
59
+ */
53
60
 
54
61
  /**
55
62
  * Options for building a sync client. Everything else — resources, transport