velocious 1.0.486 → 1.0.488

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 (48) hide show
  1. package/README.md +1 -0
  2. package/build/configuration-types.js +19 -1
  3. package/build/configuration.js +25 -2
  4. package/build/environment-handlers/base.js +9 -0
  5. package/build/environment-handlers/node.js +105 -19
  6. package/build/packages/velocious-package.js +115 -0
  7. package/build/src/configuration-types.d.ts +57 -2
  8. package/build/src/configuration-types.d.ts.map +1 -1
  9. package/build/src/configuration-types.js +18 -2
  10. package/build/src/configuration.d.ts +9 -1
  11. package/build/src/configuration.d.ts.map +1 -1
  12. package/build/src/configuration.js +21 -3
  13. package/build/src/environment-handlers/base.d.ts +6 -0
  14. package/build/src/environment-handlers/base.d.ts.map +1 -1
  15. package/build/src/environment-handlers/base.js +9 -1
  16. package/build/src/environment-handlers/node.d.ts +18 -0
  17. package/build/src/environment-handlers/node.d.ts.map +1 -1
  18. package/build/src/environment-handlers/node.js +94 -19
  19. package/build/src/packages/velocious-package.d.ts +69 -0
  20. package/build/src/packages/velocious-package.d.ts.map +1 -0
  21. package/build/src/packages/velocious-package.js +101 -0
  22. package/build/src/sync/sync-api-client-types.d.ts +182 -0
  23. package/build/src/sync/sync-api-client-types.d.ts.map +1 -0
  24. package/build/src/sync/sync-api-client-types.js +3 -0
  25. package/build/src/sync/sync-api-client.d.ts +188 -0
  26. package/build/src/sync/sync-api-client.d.ts.map +1 -0
  27. package/build/src/sync/sync-api-client.js +307 -0
  28. package/build/src/sync/sync-api-controller.d.ts +78 -0
  29. package/build/src/sync/sync-api-controller.d.ts.map +1 -0
  30. package/build/src/sync/sync-api-controller.js +142 -0
  31. package/build/src/sync/sync-model-change-feed-service.d.ts +131 -0
  32. package/build/src/sync/sync-model-change-feed-service.d.ts.map +1 -0
  33. package/build/src/sync/sync-model-change-feed-service.js +212 -0
  34. package/build/sync/sync-api-client-types.js +77 -0
  35. package/build/sync/sync-api-client.js +342 -0
  36. package/build/sync/sync-api-controller.js +161 -0
  37. package/build/sync/sync-model-change-feed-service.js +244 -0
  38. package/build/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +4 -4
  40. package/src/configuration-types.js +19 -1
  41. package/src/configuration.js +25 -2
  42. package/src/environment-handlers/base.js +9 -0
  43. package/src/environment-handlers/node.js +105 -19
  44. package/src/packages/velocious-package.js +115 -0
  45. package/src/sync/sync-api-client-types.js +77 -0
  46. package/src/sync/sync-api-client.js +342 -0
  47. package/src/sync/sync-api-controller.js +161 -0
  48. package/src/sync/sync-model-change-feed-service.js +244 -0
@@ -0,0 +1,244 @@
1
+ // @ts-check
2
+
3
+ import VelociousError from "../velocious-error.js"
4
+
5
+ /**
6
+ * Generic cursor-paginated change feed over an app-owned sync/change model.
7
+ *
8
+ * Apps provide the model and optional scoping/serialization hooks. Velocious owns
9
+ * cursor parsing, snapshot high-water resolution, stable ordering, page limits,
10
+ * and response shape for `/velocious/sync/changes` style endpoints.
11
+ */
12
+ export default class SyncModelChangeFeedService {
13
+ /**
14
+ * Creates a generic sync-model change-feed service.
15
+ * @param {object} args - Service arguments.
16
+ * @param {typeof import("../database/record/index.js").default} args.modelClass - Sync/change model class.
17
+ * @param {Record<string, unknown>} args.params - Request params.
18
+ * @param {number} [args.defaultLimit] - Default page size.
19
+ * @param {number} [args.maxLimit] - Maximum page size.
20
+ * @param {(record: ?) => Record<string, unknown>} [args.serializeRecord] - Record serializer.
21
+ * @param {function({query: import("../database/query/model-class-query.js").default}): void} [args.scopeQuery] - Applies app-owned visibility scope.
22
+ */
23
+ constructor({defaultLimit = 1000, maxLimit = 1000, modelClass, params, scopeQuery, serializeRecord}) {
24
+ this.defaultLimit = defaultLimit
25
+ this.maxLimit = maxLimit
26
+ this.modelClass = modelClass
27
+ this.params = params
28
+ this.scopeQuery = scopeQuery || null
29
+ this.serializeRecord = serializeRecord || ((record) => this.defaultSerializeRecord(record))
30
+ }
31
+
32
+ /**
33
+ * Builds a stable change-feed page.
34
+ * @returns {Promise<{status: string, nextCursor: {id: string, serverSequence: number, updatedAt: string} | null, syncs: Array<Record<string, unknown>>, upToCursor: {id: string, serverSequence: number, updatedAt: string} | null}>} Change-feed page result.
35
+ */
36
+ async changes() {
37
+ const limit = this.normalizedLimit(this.params.limit)
38
+ const upToCursor = await this.resolveUpToCursor()
39
+
40
+ if (!upToCursor) return {status: "success", nextCursor: null, syncs: [], upToCursor: null}
41
+
42
+ const query = this.pageQuery({limit, upToCursor})
43
+ const records = await query.toArray()
44
+ const nextCursor = records.length > 0 ? this.cursorForRecord(records[records.length - 1]) : upToCursor
45
+
46
+ return {
47
+ status: "success",
48
+ nextCursor,
49
+ syncs: records.map((record) => this.serializeRecord(record)),
50
+ upToCursor
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Normalizes the requested page limit.
56
+ * @param {unknown} value - Raw limit param.
57
+ * @returns {number} Normalized page limit.
58
+ */
59
+ normalizedLimit(value) {
60
+ if (value === undefined || value === null || value === "") return this.defaultLimit
61
+
62
+ const limit = Number(value)
63
+
64
+ if (!Number.isSafeInteger(limit) || limit <= 0) {
65
+ throw VelociousError.safe("Sync changes limit must be a positive integer.", {code: "sync-invalid-changes-limit"})
66
+ }
67
+
68
+ return Math.min(limit, this.maxLimit)
69
+ }
70
+
71
+ /**
72
+ * Parses an optional positive integer cursor field.
73
+ * @param {unknown} value - Raw integer param.
74
+ * @param {string} name - Param name for error messages.
75
+ * @returns {number | null} Positive integer value, or null when omitted.
76
+ */
77
+ optionalPositiveIntegerParam(value, name) {
78
+ if (value === undefined || value === null || value === "") return null
79
+
80
+ const integer = Number(value)
81
+
82
+ if (!Number.isSafeInteger(integer) || integer <= 0) {
83
+ throw VelociousError.safe(`${name} must be a positive integer.`, {code: "sync-invalid-changes-cursor"})
84
+ }
85
+
86
+ return integer
87
+ }
88
+
89
+ /**
90
+ * Resolves the high-water cursor that bounds the current feed page.
91
+ * @returns {Promise<{id: string, serverSequence: number, updatedAt: string} | null>} Snapshot upper-bound cursor.
92
+ */
93
+ async resolveUpToCursor() {
94
+ const upToServerSequence = this.optionalPositiveIntegerParam(this.params.upToServerSequence, "upToServerSequence")
95
+
96
+ if (upToServerSequence !== null && typeof this.params.upToUpdatedAt === "string" && typeof this.params.upToId === "string") {
97
+ return {id: this.params.upToId, serverSequence: upToServerSequence, updatedAt: this.params.upToUpdatedAt}
98
+ }
99
+
100
+ if (typeof this.params.upToUpdatedAt === "string" && typeof this.params.upToId === "string") {
101
+ const upToRecord = await this.modelClass.findBy({id: this.params.upToId})
102
+
103
+ if (upToRecord) return this.cursorForRecord(upToRecord)
104
+ }
105
+
106
+ const query = this.scopedQuery()
107
+ const table = query.driver.quoteTable(this.modelClass.tableName())
108
+ const serverSequenceColumn = query.driver.quoteColumn("server_sequence")
109
+ const latestRecords = await query
110
+ .order(`${table}.${serverSequenceColumn} DESC`)
111
+ .limit(1)
112
+ .toArray()
113
+
114
+ if (latestRecords.length === 0) return null
115
+
116
+ return this.cursorForRecord(latestRecords[0])
117
+ }
118
+
119
+ /**
120
+ * Builds the ordered and cursor-filtered page query.
121
+ * @param {{limit: number, upToCursor: {id: string, serverSequence: number, updatedAt: string}}} args - Page query args.
122
+ * @returns {import("../database/query/model-class-query.js").default} Page query.
123
+ */
124
+ pageQuery({limit, upToCursor}) {
125
+ const query = this.scopedQuery()
126
+ const driver = query.driver
127
+ const table = driver.quoteTable(this.modelClass.tableName())
128
+ const serverSequenceColumn = `${table}.${driver.quoteColumn("server_sequence")}`
129
+ const updatedAtColumn = `${table}.${driver.quoteColumn("updated_at")}`
130
+ const idColumn = `${table}.${driver.quoteColumn("id")}`
131
+
132
+ query
133
+ .where(`${serverSequenceColumn} <= ${driver.quote(upToCursor.serverSequence)}`)
134
+ .order(`${serverSequenceColumn} ASC`)
135
+ .limit(limit)
136
+
137
+ const afterServerSequence = this.optionalPositiveIntegerParam(this.params.afterServerSequence, "afterServerSequence")
138
+
139
+ if (afterServerSequence !== null) {
140
+ query.where(`${serverSequenceColumn} > ${driver.quote(afterServerSequence)}`)
141
+ } else if (typeof this.params.afterUpdatedAt === "string" && this.params.afterUpdatedAt !== "") {
142
+ const isPagingExistingSnapshot = typeof this.params.upToUpdatedAt === "string" && this.params.upToUpdatedAt !== "" && typeof this.params.upToId === "string" && this.params.upToId !== ""
143
+
144
+ if (isPagingExistingSnapshot && typeof this.params.afterId === "string" && this.params.afterId !== "") {
145
+ query.where(`(${updatedAtColumn} > ${driver.quote(this.params.afterUpdatedAt)} OR (${updatedAtColumn} = ${driver.quote(this.params.afterUpdatedAt)} AND ${idColumn} > ${driver.quote(this.params.afterId)}))`)
146
+ } else {
147
+ query.where(`${updatedAtColumn} >= ${driver.quote(this.params.afterUpdatedAt)}`)
148
+ }
149
+ }
150
+
151
+ return query
152
+ }
153
+
154
+ /**
155
+ * Builds a base query with app-owned scope applied.
156
+ * @returns {import("../database/query/model-class-query.js").default} Scoped base query.
157
+ */
158
+ scopedQuery() {
159
+ const query = this.modelClass.where({})
160
+
161
+ if (this.scopeQuery) this.scopeQuery({query})
162
+
163
+ return query
164
+ }
165
+
166
+ /**
167
+ * Serializes a record into a transport cursor.
168
+ * @param {?} record - Sync/change record.
169
+ * @returns {{id: string, serverSequence: number, updatedAt: string}} Cursor for row.
170
+ */
171
+ cursorForRecord(record) {
172
+ return {id: String(this.recordValue(record, "id")), serverSequence: Number(this.recordValue(record, "serverSequence")), updatedAt: this.isoDate(this.recordValue(record, "updatedAt"))}
173
+ }
174
+
175
+ /**
176
+ * Serializes a record using the standard sync envelope shape.
177
+ * @param {?} record - Sync/change record.
178
+ * @returns {Record<string, unknown>} Default serialized row.
179
+ */
180
+ defaultSerializeRecord(record) {
181
+ return {
182
+ data: this.recordData(record),
183
+ eventId: this.recordValue(record, "eventId"),
184
+ id: this.recordValue(record, "id"),
185
+ resourceId: this.recordValue(record, "resourceId"),
186
+ resourceType: this.recordValue(record, "resourceType"),
187
+ serverSequence: this.recordValue(record, "serverSequence"),
188
+ syncType: this.recordValue(record, "syncType"),
189
+ updatedAt: this.isoDate(this.recordValue(record, "updatedAt"))
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Reads and parses the record data payload.
195
+ * @param {?} record - Sync/change record.
196
+ * @returns {unknown} Parsed data value.
197
+ */
198
+ recordData(record) {
199
+ const data = this.recordValue(record, "data")
200
+
201
+ if (data === "" || data === null || data === undefined) return null
202
+ if (typeof data !== "string") return data
203
+
204
+ return JSON.parse(data)
205
+ }
206
+
207
+ /**
208
+ * Reads a value from either a record accessor method or plain property.
209
+ * @param {?} record - Sync/change record.
210
+ * @param {string} name - Camel-cased value/method name.
211
+ * @returns {unknown} Record value.
212
+ */
213
+ recordValue(record, name) {
214
+ if (!record || typeof record !== "object") {
215
+ throw new Error("Sync changes row must be an object.")
216
+ }
217
+
218
+ const recordObject = /** @type {Record<string, ?>} */ (record)
219
+ const method = recordObject[name]
220
+ const value = typeof method === "function" ? method.call(record) : method
221
+
222
+ if (value === undefined) {
223
+ throw new Error(`Sync changes row is missing ${name}.`)
224
+ }
225
+
226
+ return value
227
+ }
228
+
229
+ /**
230
+ * Converts a date-like value to an ISO string.
231
+ * @param {Date | string | null | undefined | unknown} value - Date value.
232
+ * @returns {string} ISO date.
233
+ */
234
+ isoDate(value) {
235
+ const date = value instanceof Date ? value : new Date(typeof value === "string" || typeof value === "number" ? value : 0)
236
+
237
+ if (Number.isNaN(date.getTime())) {
238
+ throw VelociousError.safe("Sync changes row has an invalid updated_at value.", {code: "sync-invalid-changes-row"})
239
+ }
240
+
241
+ return date.toISOString()
242
+ }
243
+ }
244
+
@@ -1 +1 @@
1
- {"root":["../index.js","../bin/velocious.js","../src/application.js","../src/configuration-resolver.js","../src/configuration-types.js","../src/configuration.js","../src/controller.js","../src/current-configuration.js","../src/current.js","../src/error-logger.js","../src/frontend-model-controller.js","../src/initializer.js","../src/logger.js","../src/mailer.js","../src/record-payload-values.js","../src/time-zone.js","../src/velocious-error.js","../src/authorization/ability.js","../src/authorization/base-resource.js","../src/background-jobs/client.js","../src/background-jobs/cron-expression.js","../src/background-jobs/forked-runner-child.js","../src/background-jobs/job-record.js","../src/background-jobs/job-registry.js","../src/background-jobs/job-runner.js","../src/background-jobs/job.js","../src/background-jobs/json-socket.js","../src/background-jobs/main.js","../src/background-jobs/normalize-error.js","../src/background-jobs/scheduler.js","../src/background-jobs/socket-request.js","../src/background-jobs/status-reporter.js","../src/background-jobs/store.js","../src/background-jobs/types.js","../src/background-jobs/worker.js","../src/background-jobs/web/authorization.js","../src/background-jobs/web/controller.js","../src/background-jobs/web/index.js","../src/background-jobs/web/path-matcher.js","../src/background-jobs/web/registry.js","../src/beacon/client.js","../src/beacon/in-process-broker.js","../src/beacon/in-process-client.js","../src/beacon/server.js","../src/beacon/types.js","../src/cli/base-command.js","../src/cli/browser-cli.js","../src/cli/index.js","../src/cli/tenant-database-command-helper.js","../src/cli/use-browser-cli.js","../src/cli/commands/background-jobs-main.js","../src/cli/commands/background-jobs-runner.js","../src/cli/commands/background-jobs-worker.js","../src/cli/commands/beacon.js","../src/cli/commands/console.js","../src/cli/commands/init.js","../src/cli/commands/routes.js","../src/cli/commands/run-script.js","../src/cli/commands/runner.js","../src/cli/commands/server.js","../src/cli/commands/test.js","../src/cli/commands/db/base-command.js","../src/cli/commands/db/create.js","../src/cli/commands/db/drop.js","../src/cli/commands/db/migrate.js","../src/cli/commands/db/reset.js","../src/cli/commands/db/rollback.js","../src/cli/commands/db/seed.js","../src/cli/commands/db/schema/dump.js","../src/cli/commands/db/schema/load.js","../src/cli/commands/db/tenants/check.js","../src/cli/commands/db/tenants/create.js","../src/cli/commands/db/tenants/drop.js","../src/cli/commands/db/tenants/migrate.js","../src/cli/commands/destroy/migration.js","../src/cli/commands/generate/base-models.js","../src/cli/commands/generate/frontend-models.js","../src/cli/commands/generate/migration.js","../src/cli/commands/generate/model.js","../src/cli/commands/lint/relationships.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/datetime-storage.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/migrations-ledger.js","../src/database/migrator.js","../src/database/use-database.js","../src/database/drivers/base-column.js","../src/database/drivers/base-columns-index.js","../src/database/drivers/base-foreign-key.js","../src/database/drivers/base-table.js","../src/database/drivers/base.js","../src/database/drivers/mssql/column.js","../src/database/drivers/mssql/columns-index.js","../src/database/drivers/mssql/connect-connection.js","../src/database/drivers/mssql/foreign-key.js","../src/database/drivers/mssql/index.js","../src/database/drivers/mssql/options.js","../src/database/drivers/mssql/query-parser.js","../src/database/drivers/mssql/structure-sql.js","../src/database/drivers/mssql/table.js","../src/database/drivers/mssql/sql/alter-table.js","../src/database/drivers/mssql/sql/create-database.js","../src/database/drivers/mssql/sql/create-index.js","../src/database/drivers/mssql/sql/create-table.js","../src/database/drivers/mssql/sql/delete.js","../src/database/drivers/mssql/sql/drop-database.js","../src/database/drivers/mssql/sql/drop-table.js","../src/database/drivers/mssql/sql/insert.js","../src/database/drivers/mssql/sql/remove-index.js","../src/database/drivers/mssql/sql/update.js","../src/database/drivers/mssql/sql/upsert.js","../src/database/drivers/mysql/column.js","../src/database/drivers/mysql/columns-index.js","../src/database/drivers/mysql/foreign-key.js","../src/database/drivers/mysql/index.js","../src/database/drivers/mysql/options.js","../src/database/drivers/mysql/query-parser.js","../src/database/drivers/mysql/query.js","../src/database/drivers/mysql/structure-sql.js","../src/database/drivers/mysql/table.js","../src/database/drivers/mysql/sql/alter-table.js","../src/database/drivers/mysql/sql/create-database.js","../src/database/drivers/mysql/sql/create-index.js","../src/database/drivers/mysql/sql/create-table.js","../src/database/drivers/mysql/sql/delete.js","../src/database/drivers/mysql/sql/drop-database.js","../src/database/drivers/mysql/sql/drop-table.js","../src/database/drivers/mysql/sql/insert.js","../src/database/drivers/mysql/sql/remove-index.js","../src/database/drivers/mysql/sql/update.js","../src/database/drivers/mysql/sql/upsert.js","../src/database/drivers/pgsql/column.js","../src/database/drivers/pgsql/columns-index.js","../src/database/drivers/pgsql/foreign-key.js","../src/database/drivers/pgsql/index.js","../src/database/drivers/pgsql/options.js","../src/database/drivers/pgsql/query-parser.js","../src/database/drivers/pgsql/structure-sql.js","../src/database/drivers/pgsql/table.js","../src/database/drivers/pgsql/sql/alter-table.js","../src/database/drivers/pgsql/sql/create-database.js","../src/database/drivers/pgsql/sql/create-index.js","../src/database/drivers/pgsql/sql/create-table.js","../src/database/drivers/pgsql/sql/delete.js","../src/database/drivers/pgsql/sql/drop-database.js","../src/database/drivers/pgsql/sql/drop-table.js","../src/database/drivers/pgsql/sql/insert.js","../src/database/drivers/pgsql/sql/remove-index.js","../src/database/drivers/pgsql/sql/update.js","../src/database/drivers/pgsql/sql/upsert.js","../src/database/drivers/sqlite/base.js","../src/database/drivers/sqlite/column.js","../src/database/drivers/sqlite/columns-index.js","../src/database/drivers/sqlite/connection-sql-js.js","../src/database/drivers/sqlite/foreign-key.js","../src/database/drivers/sqlite/index.js","../src/database/drivers/sqlite/index.native.js","../src/database/drivers/sqlite/index.web.js","../src/database/drivers/sqlite/options.js","../src/database/drivers/sqlite/query-parser.js","../src/database/drivers/sqlite/query.js","../src/database/drivers/sqlite/query.native.js","../src/database/drivers/sqlite/query.web.js","../src/database/drivers/sqlite/structure-sql.js","../src/database/drivers/sqlite/table-rebuilder.js","../src/database/drivers/sqlite/table.js","../src/database/drivers/sqlite/web-persistence.js","../src/database/drivers/sqlite/sql/alter-table.js","../src/database/drivers/sqlite/sql/create-index.js","../src/database/drivers/sqlite/sql/create-table.js","../src/database/drivers/sqlite/sql/delete.js","../src/database/drivers/sqlite/sql/drop-table.js","../src/database/drivers/sqlite/sql/insert.js","../src/database/drivers/sqlite/sql/remove-index.js","../src/database/drivers/sqlite/sql/update.js","../src/database/drivers/sqlite/sql/upsert.js","../src/database/drivers/structure-sql/utils.js","../src/database/migration/index.js","../src/database/migrator/files-finder.js","../src/database/migrator/types.js","../src/database/pool/async-tracked-multi-connection.js","../src/database/pool/base-methods-forward.js","../src/database/pool/base.js","../src/database/pool/single-multi-use.js","../src/database/query/alter-table-base.js","../src/database/query/base.js","../src/database/query/create-database-base.js","../src/database/query/create-index-base.js","../src/database/query/create-table-base.js","../src/database/query/delete-base.js","../src/database/query/drop-database-base.js","../src/database/query/drop-table-base.js","../src/database/query/from-base.js","../src/database/query/from-plain.js","../src/database/query/from-table.js","../src/database/query/index.js","../src/database/query/insert-base.js","../src/database/query/join-base.js","../src/database/query/join-object.js","../src/database/query/join-plain.js","../src/database/query/join-tracker.js","../src/database/query/model-class-query.js","../src/database/query/order-base.js","../src/database/query/order-column.js","../src/database/query/order-plain.js","../src/database/query/preloader.js","../src/database/query/query-data.js","../src/database/query/remove-index-base.js","../src/database/query/select-base.js","../src/database/query/select-plain.js","../src/database/query/select-table-and-column.js","../src/database/query/update-base.js","../src/database/query/upsert-base.js","../src/database/query/where-base.js","../src/database/query/where-combinator.js","../src/database/query/where-hash.js","../src/database/query/where-model-class-hash.js","../src/database/query/where-not.js","../src/database/query/where-plain.js","../src/database/query/with-count.js","../src/database/query/preloader/belongs-to.js","../src/database/query/preloader/ensure-model-class-initialized.js","../src/database/query/preloader/has-many.js","../src/database/query/preloader/has-one.js","../src/database/query/preloader/selection.js","../src/database/query-parser/base-query-parser.js","../src/database/query-parser/from-parser.js","../src/database/query-parser/group-parser.js","../src/database/query-parser/joins-parser.js","../src/database/query-parser/limit-parser.js","../src/database/query-parser/options.js","../src/database/query-parser/order-parser.js","../src/database/query-parser/select-parser.js","../src/database/query-parser/where-parser.js","../src/database/record/acts-as-list.js","../src/database/record/auditing.js","../src/database/record/index.js","../src/database/record/record-not-found-error.js","../src/database/record/state-machine.js","../src/database/record/user-module.js","../src/database/record/attachments/attachment-record.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/database/tenants/data-copier.js","../src/database/tenants/schema-cloner.js","../src/database/tenants/tenant-table-plan.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/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/server-change-feed.js","../src/sync/sync-envelope-replay-service.js","../src/tenants/tenant-iterator.js","../src/tenants/tenant.js","../src/testing/base-expect.js","../src/testing/browser-frontend-model-event-hook-scenarios.js","../src/testing/browser-test-app.js","../src/testing/expect-to-change.js","../src/testing/expect-utils.js","../src/testing/expect.js","../src/testing/request-client.js","../src/testing/test-files-finder.js","../src/testing/test-filter-parser.js","../src/testing/test-runner.js","../src/testing/test-suite-splitter.js","../src/testing/test.js","../src/types/external-modules.d.ts","../src/utils/backtrace-cleaner-node.js","../src/utils/backtrace-cleaner.js","../src/utils/deburr-column-name.js","../src/utils/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/is-date.js","../src/utils/model-scope.js","../src/utils/nest-callbacks.js","../src/utils/plain-object.js","../src/utils/ransack.js","../src/utils/rest-args-error.js","../src/utils/singularize-model-name.js","../src/utils/split-sql-statements.js","../src/utils/to-import-specifier.js","../src/utils/with-tracked-stack-async-hooks.js","../src/utils/with-tracked-stack.js"],"version":"6.0.3"}
1
+ {"root":["../index.js","../bin/velocious.js","../src/application.js","../src/configuration-resolver.js","../src/configuration-types.js","../src/configuration.js","../src/controller.js","../src/current-configuration.js","../src/current.js","../src/error-logger.js","../src/frontend-model-controller.js","../src/initializer.js","../src/logger.js","../src/mailer.js","../src/record-payload-values.js","../src/time-zone.js","../src/velocious-error.js","../src/authorization/ability.js","../src/authorization/base-resource.js","../src/background-jobs/client.js","../src/background-jobs/cron-expression.js","../src/background-jobs/forked-runner-child.js","../src/background-jobs/job-record.js","../src/background-jobs/job-registry.js","../src/background-jobs/job-runner.js","../src/background-jobs/job.js","../src/background-jobs/json-socket.js","../src/background-jobs/main.js","../src/background-jobs/normalize-error.js","../src/background-jobs/scheduler.js","../src/background-jobs/socket-request.js","../src/background-jobs/status-reporter.js","../src/background-jobs/store.js","../src/background-jobs/types.js","../src/background-jobs/worker.js","../src/background-jobs/web/authorization.js","../src/background-jobs/web/controller.js","../src/background-jobs/web/index.js","../src/background-jobs/web/path-matcher.js","../src/background-jobs/web/registry.js","../src/beacon/client.js","../src/beacon/in-process-broker.js","../src/beacon/in-process-client.js","../src/beacon/server.js","../src/beacon/types.js","../src/cli/base-command.js","../src/cli/browser-cli.js","../src/cli/index.js","../src/cli/tenant-database-command-helper.js","../src/cli/use-browser-cli.js","../src/cli/commands/background-jobs-main.js","../src/cli/commands/background-jobs-runner.js","../src/cli/commands/background-jobs-worker.js","../src/cli/commands/beacon.js","../src/cli/commands/console.js","../src/cli/commands/init.js","../src/cli/commands/routes.js","../src/cli/commands/run-script.js","../src/cli/commands/runner.js","../src/cli/commands/server.js","../src/cli/commands/test.js","../src/cli/commands/db/base-command.js","../src/cli/commands/db/create.js","../src/cli/commands/db/drop.js","../src/cli/commands/db/migrate.js","../src/cli/commands/db/reset.js","../src/cli/commands/db/rollback.js","../src/cli/commands/db/seed.js","../src/cli/commands/db/schema/dump.js","../src/cli/commands/db/schema/load.js","../src/cli/commands/db/tenants/check.js","../src/cli/commands/db/tenants/create.js","../src/cli/commands/db/tenants/drop.js","../src/cli/commands/db/tenants/migrate.js","../src/cli/commands/destroy/migration.js","../src/cli/commands/generate/base-models.js","../src/cli/commands/generate/frontend-models.js","../src/cli/commands/generate/migration.js","../src/cli/commands/generate/model.js","../src/cli/commands/lint/relationships.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/datetime-storage.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/migrations-ledger.js","../src/database/migrator.js","../src/database/use-database.js","../src/database/drivers/base-column.js","../src/database/drivers/base-columns-index.js","../src/database/drivers/base-foreign-key.js","../src/database/drivers/base-table.js","../src/database/drivers/base.js","../src/database/drivers/mssql/column.js","../src/database/drivers/mssql/columns-index.js","../src/database/drivers/mssql/connect-connection.js","../src/database/drivers/mssql/foreign-key.js","../src/database/drivers/mssql/index.js","../src/database/drivers/mssql/options.js","../src/database/drivers/mssql/query-parser.js","../src/database/drivers/mssql/structure-sql.js","../src/database/drivers/mssql/table.js","../src/database/drivers/mssql/sql/alter-table.js","../src/database/drivers/mssql/sql/create-database.js","../src/database/drivers/mssql/sql/create-index.js","../src/database/drivers/mssql/sql/create-table.js","../src/database/drivers/mssql/sql/delete.js","../src/database/drivers/mssql/sql/drop-database.js","../src/database/drivers/mssql/sql/drop-table.js","../src/database/drivers/mssql/sql/insert.js","../src/database/drivers/mssql/sql/remove-index.js","../src/database/drivers/mssql/sql/update.js","../src/database/drivers/mssql/sql/upsert.js","../src/database/drivers/mysql/column.js","../src/database/drivers/mysql/columns-index.js","../src/database/drivers/mysql/foreign-key.js","../src/database/drivers/mysql/index.js","../src/database/drivers/mysql/options.js","../src/database/drivers/mysql/query-parser.js","../src/database/drivers/mysql/query.js","../src/database/drivers/mysql/structure-sql.js","../src/database/drivers/mysql/table.js","../src/database/drivers/mysql/sql/alter-table.js","../src/database/drivers/mysql/sql/create-database.js","../src/database/drivers/mysql/sql/create-index.js","../src/database/drivers/mysql/sql/create-table.js","../src/database/drivers/mysql/sql/delete.js","../src/database/drivers/mysql/sql/drop-database.js","../src/database/drivers/mysql/sql/drop-table.js","../src/database/drivers/mysql/sql/insert.js","../src/database/drivers/mysql/sql/remove-index.js","../src/database/drivers/mysql/sql/update.js","../src/database/drivers/mysql/sql/upsert.js","../src/database/drivers/pgsql/column.js","../src/database/drivers/pgsql/columns-index.js","../src/database/drivers/pgsql/foreign-key.js","../src/database/drivers/pgsql/index.js","../src/database/drivers/pgsql/options.js","../src/database/drivers/pgsql/query-parser.js","../src/database/drivers/pgsql/structure-sql.js","../src/database/drivers/pgsql/table.js","../src/database/drivers/pgsql/sql/alter-table.js","../src/database/drivers/pgsql/sql/create-database.js","../src/database/drivers/pgsql/sql/create-index.js","../src/database/drivers/pgsql/sql/create-table.js","../src/database/drivers/pgsql/sql/delete.js","../src/database/drivers/pgsql/sql/drop-database.js","../src/database/drivers/pgsql/sql/drop-table.js","../src/database/drivers/pgsql/sql/insert.js","../src/database/drivers/pgsql/sql/remove-index.js","../src/database/drivers/pgsql/sql/update.js","../src/database/drivers/pgsql/sql/upsert.js","../src/database/drivers/sqlite/base.js","../src/database/drivers/sqlite/column.js","../src/database/drivers/sqlite/columns-index.js","../src/database/drivers/sqlite/connection-sql-js.js","../src/database/drivers/sqlite/foreign-key.js","../src/database/drivers/sqlite/index.js","../src/database/drivers/sqlite/index.native.js","../src/database/drivers/sqlite/index.web.js","../src/database/drivers/sqlite/options.js","../src/database/drivers/sqlite/query-parser.js","../src/database/drivers/sqlite/query.js","../src/database/drivers/sqlite/query.native.js","../src/database/drivers/sqlite/query.web.js","../src/database/drivers/sqlite/structure-sql.js","../src/database/drivers/sqlite/table-rebuilder.js","../src/database/drivers/sqlite/table.js","../src/database/drivers/sqlite/web-persistence.js","../src/database/drivers/sqlite/sql/alter-table.js","../src/database/drivers/sqlite/sql/create-index.js","../src/database/drivers/sqlite/sql/create-table.js","../src/database/drivers/sqlite/sql/delete.js","../src/database/drivers/sqlite/sql/drop-table.js","../src/database/drivers/sqlite/sql/insert.js","../src/database/drivers/sqlite/sql/remove-index.js","../src/database/drivers/sqlite/sql/update.js","../src/database/drivers/sqlite/sql/upsert.js","../src/database/drivers/structure-sql/utils.js","../src/database/migration/index.js","../src/database/migrator/files-finder.js","../src/database/migrator/types.js","../src/database/pool/async-tracked-multi-connection.js","../src/database/pool/base-methods-forward.js","../src/database/pool/base.js","../src/database/pool/single-multi-use.js","../src/database/query/alter-table-base.js","../src/database/query/base.js","../src/database/query/create-database-base.js","../src/database/query/create-index-base.js","../src/database/query/create-table-base.js","../src/database/query/delete-base.js","../src/database/query/drop-database-base.js","../src/database/query/drop-table-base.js","../src/database/query/from-base.js","../src/database/query/from-plain.js","../src/database/query/from-table.js","../src/database/query/index.js","../src/database/query/insert-base.js","../src/database/query/join-base.js","../src/database/query/join-object.js","../src/database/query/join-plain.js","../src/database/query/join-tracker.js","../src/database/query/model-class-query.js","../src/database/query/order-base.js","../src/database/query/order-column.js","../src/database/query/order-plain.js","../src/database/query/preloader.js","../src/database/query/query-data.js","../src/database/query/remove-index-base.js","../src/database/query/select-base.js","../src/database/query/select-plain.js","../src/database/query/select-table-and-column.js","../src/database/query/update-base.js","../src/database/query/upsert-base.js","../src/database/query/where-base.js","../src/database/query/where-combinator.js","../src/database/query/where-hash.js","../src/database/query/where-model-class-hash.js","../src/database/query/where-not.js","../src/database/query/where-plain.js","../src/database/query/with-count.js","../src/database/query/preloader/belongs-to.js","../src/database/query/preloader/ensure-model-class-initialized.js","../src/database/query/preloader/has-many.js","../src/database/query/preloader/has-one.js","../src/database/query/preloader/selection.js","../src/database/query-parser/base-query-parser.js","../src/database/query-parser/from-parser.js","../src/database/query-parser/group-parser.js","../src/database/query-parser/joins-parser.js","../src/database/query-parser/limit-parser.js","../src/database/query-parser/options.js","../src/database/query-parser/order-parser.js","../src/database/query-parser/select-parser.js","../src/database/query-parser/where-parser.js","../src/database/record/acts-as-list.js","../src/database/record/auditing.js","../src/database/record/index.js","../src/database/record/record-not-found-error.js","../src/database/record/state-machine.js","../src/database/record/user-module.js","../src/database/record/attachments/attachment-record.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/database/tenants/data-copier.js","../src/database/tenants/schema-cloner.js","../src/database/tenants/tenant-table-plan.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/packages/velocious-package.js","../src/plugins/sqljs-wasm-route-controller.js","../src/plugins/sqljs-wasm-route.js","../src/routes/app-routes.js","../src/routes/base-route.js","../src/routes/basic-route.js","../src/routes/get-route.js","../src/routes/index.js","../src/routes/namespace-route.js","../src/routes/plugin-routes.js","../src/routes/post-route.js","../src/routes/resolver.js","../src/routes/resource-route.js","../src/routes/root-route.js","../src/routes/built-in/debug/controller.js","../src/routes/built-in/errors/controller.js","../src/routes/hooks/frontend-model-command-route-hook.js","../src/sync/conflict-strategy.js","../src/sync/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.js","../src/sync/peer-mutation-bundle.js","../src/sync/server-change-feed.js","../src/sync/sync-api-client-types.js","../src/sync/sync-api-client.js","../src/sync/sync-api-controller.js","../src/sync/sync-envelope-replay-service.js","../src/sync/sync-model-change-feed-service.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.486",
6
+ "version": "1.0.488",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -69,7 +69,7 @@
69
69
  "pure-uuid": "^2.0.0",
70
70
  "require-context": "^1.1.0",
71
71
  "set-state-compare": "^1.0.61",
72
- "snapreq": "^0.0.8",
72
+ "snapreq": "^0.0.9",
73
73
  "sql-escape-string": "^1.1.0",
74
74
  "sql.js": "^1.12.0",
75
75
  "strftime": "^0.10.2",
@@ -103,7 +103,7 @@
103
103
  "eslint-plugin-jsdoc": "^63.0.0",
104
104
  "eslint-plugin-jsdoc-inline-type-casts": "https://github.com/kaspernj/eslint-plugin-jsdoc-inline-type-casts/archive/refs/heads/master.tar.gz",
105
105
  "eslint-plugin-jsdoc-tag-lines": "^1.0.1",
106
- "fallow": "2.102.0",
106
+ "fallow": "2.104.0",
107
107
  "globals": "^17.0.0",
108
108
  "mssql": "^12.0.0",
109
109
  "mysql": "^2.18.1",
@@ -115,7 +115,7 @@
115
115
  "sqlite": "^5.1.1",
116
116
  "sqlite3": "^6.0.1",
117
117
  "system-testing": "^1.0.108",
118
- "tedious": "^19.1.3",
118
+ "tedious": "^20.0.0",
119
119
  "typescript": "^6.0.2",
120
120
  "uniqunize": "^1.0.3"
121
121
  }
@@ -417,11 +417,28 @@
417
417
 
418
418
  /**
419
419
  * @typedef {object} BackendProjectConfiguration
420
- * @property {string} path - Path to the backend project.
420
+ * @property {string} path - Path to the backend project. May be an app root or a contributing package root (package entries are appended internally from `packages`).
421
421
  * @property {string} [frontendModelsOutputPath] - Optional output project path where `src/frontend-models` should be generated.
422
+ * @property {string} [resourcesPath] - Optional override for the resources directory to auto-discover; defaults to `<path>/src/resources`. Set internally for package entries.
422
423
  * @property {Record<string, FrontendModelResourceDefinition>} [frontendModels] - Auto-discovered frontend model definitions keyed by model class name. Set internally by the environment handler — do not set manually.
423
424
  */
424
425
 
426
+ /**
427
+ * A descriptor for an external Velocious package (engine) that contributes models,
428
+ * resources and migrations. A package usually exports `new VelociousPackage({name, url: import.meta.url})`.
429
+ * @typedef {object} VelociousPackageDescriptor
430
+ * @property {string} name - The package name.
431
+ * @property {string} [url] - The descriptor module's `import.meta.url`; the package root is derived from it when `path` is omitted.
432
+ * @property {string} [path] - The package root directory (the one containing `src`). Derived from `url` when omitted.
433
+ * @property {string} [modelsPath] - Override for the package's models directory (default `<path>/src/models`).
434
+ * @property {string} [resourcesPath] - Override for the package's frontend-model resources directory (default `<path>/src/resources`).
435
+ * @property {string} [migrationsPath] - Override for the package's migrations directory (default `<path>/src/database/migrations`).
436
+ */
437
+
438
+ /**
439
+ * @typedef {import("./packages/velocious-package.js").default | VelociousPackageDescriptor} VelociousPackageConfiguration
440
+ */
441
+
425
442
  /**
426
443
  * @typedef {object} RouteResolverHookArgs
427
444
  * @property {import("./configuration.js").default} configuration - Configuration instance.
@@ -491,6 +508,7 @@
491
508
  * @property {AbilityResolverType} [abilityResolver] - Resolver for creating request-scoped ability instances.
492
509
  * @property {AttachmentsConfiguration} [attachments] - Attachment storage configuration.
493
510
  * @property {BackendProjectConfiguration[]} [backendProjects] - Backend project definitions used for frontend model generation.
511
+ * @property {VelociousPackageConfiguration[]} [packages] - External Velocious packages that contribute models, frontend-model resources and migrations.
494
512
  * @property {{[key: string]: {[key: string]: DatabaseConfigurationType}}} database - Database configurations keyed by environment and identifier.
495
513
  * @property {boolean} [debug] - Enable debug logging.
496
514
  * @property {boolean | DebugEndpointConfiguration} [debugEndpoint] - Enable the built-in debug endpoint. Defaults to false.
@@ -25,6 +25,7 @@ import PluginRoutes from "./routes/plugin-routes.js"
25
25
  import restArgsError from "./utils/rest-args-error.js"
26
26
  import {validateTimeZone} from "./time-zone.js"
27
27
  import {withTrackedStack} from "./utils/with-tracked-stack.js"
28
+ import VelociousPackage from "./packages/velocious-package.js"
28
29
 
29
30
  export {CurrentConfigurationNotSetError}
30
31
 
@@ -127,7 +128,7 @@ export default class VelociousConfiguration {
127
128
  * Runs constructor.
128
129
  * @param {import("./configuration-types.js").ConfigurationArgsType} args - Configuration arguments.
129
130
  */
130
- constructor({abilityResolver, abilityResources, attachments, autoload = true, backgroundJobs, backendProjects, beacon, cookieSecret, cors, database, debug = false, debugEndpoint = false, directory, enforceTenantDatabaseScopes = true, environment, environmentHandler, exposeInternalErrorsToClients = false, httpServer, initializeModels, initializers, locale, localeFallbacks, locales, logging, mailerBackend, requestTimeoutMs, routeResolverHooks, scheduledBackgroundJobs, structureSql, sync, tenantDatabaseProviders, tenantDatabaseResolver, tenantResolver, testing, timeZone, timezoneOffsetMinutes, trustedProxies, websocketChannelResolver, websocketMessageHandlerResolver, ...restArgs}) {
131
+ constructor({abilityResolver, abilityResources, attachments, autoload = true, backgroundJobs, backendProjects, beacon, cookieSecret, cors, database, debug = false, debugEndpoint = false, directory, enforceTenantDatabaseScopes = true, environment, environmentHandler, exposeInternalErrorsToClients = false, httpServer, initializeModels, initializers, locale, localeFallbacks, locales, logging, mailerBackend, packages, requestTimeoutMs, routeResolverHooks, scheduledBackgroundJobs, structureSql, sync, tenantDatabaseProviders, tenantDatabaseResolver, tenantResolver, testing, timeZone, timezoneOffsetMinutes, trustedProxies, websocketChannelResolver, websocketMessageHandlerResolver, ...restArgs}) {
131
132
  restArgsError(restArgs)
132
133
 
133
134
  this._abilityResolver = abilityResolver
@@ -160,7 +161,9 @@ export default class VelociousConfiguration {
160
161
  this._beaconLastDownError = undefined
161
162
  this._scheduledBackgroundJobs = scheduledBackgroundJobs
162
163
  this._attachments = attachments || {}
163
- this._backendProjects = backendProjects || []
164
+ // Copy so appending package-derived entries below never mutates a caller's
165
+ // shared array (config modules commonly export a reused backendProjects array).
166
+ this._backendProjects = backendProjects ? [...backendProjects] : []
164
167
  /** @type {import("./configuration-types.js").ClientErrorPayloadReporterType[]} */
165
168
  this._clientErrorPayloadReporters = []
166
169
  this.cors = cors
@@ -174,6 +177,18 @@ export default class VelociousConfiguration {
174
177
  this._exposeInternalErrorsToClients = exposeInternalErrorsToClients
175
178
  this._directory = directory
176
179
  this._initializeModels = initializeModels
180
+ /** @type {VelociousPackage[]} */
181
+ this._packages = (packages || []).map((entry) => VelociousPackage.from(entry))
182
+
183
+ // Append a derived backend-project per package so the existing resource
184
+ // discovery + frontend-model generation machinery includes it. Package
185
+ // frontend models are generated into the app's frontend-models output.
186
+ const appFrontendModelsOutputPath = this._backendProjects[0]?.frontendModelsOutputPath
187
+
188
+ for (const velociousPackage of this._packages) {
189
+ this._backendProjects.push(velociousPackage.toBackendProjectConfiguration({frontendModelsOutputPath: appFrontendModelsOutputPath}))
190
+ }
191
+
177
192
  this._isInitialized = false
178
193
  this.httpServer = httpServer || {}
179
194
  /**
@@ -841,6 +856,12 @@ export default class VelociousConfiguration {
841
856
  */
842
857
  getBackendProjects() { return this._backendProjects }
843
858
 
859
+ /**
860
+ * Runs get packages.
861
+ * @returns {VelociousPackage[]} - Registered Velocious packages.
862
+ */
863
+ getPackages() { return this._packages }
864
+
844
865
  /**
845
866
  * Runs get ability resources.
846
867
  * @returns {import("./configuration-types.js").AbilityResourceClassType[]} - Ability resource classes.
@@ -1671,6 +1692,8 @@ export default class VelociousConfiguration {
1671
1692
  await this._initializeModels({configuration: this, type: args.type})
1672
1693
  }
1673
1694
 
1695
+ await this.getEnvironmentHandler().initializePackageModels(this)
1696
+
1674
1697
  await this.getEnvironmentHandler().initializeFrontendModelWebsocketPublishers(this)
1675
1698
  }
1676
1699
  }
@@ -614,4 +614,13 @@ export default class VelociousEnvironmentHandlerBase {
614
614
  async initializeFrontendModelWebsocketPublishers(_configuration) {
615
615
  // No-op in base handler; Node handler does the real registration.
616
616
  }
617
+
618
+ /**
619
+ * Loads models contributed by registered packages.
620
+ * @param {import("../configuration.js").default} _configuration - Configuration instance.
621
+ * @returns {Promise<void>} - Resolves when complete.
622
+ */
623
+ async initializePackageModels(_configuration) {
624
+ // No-op in base handler; Node handler loads package models from the filesystem.
625
+ }
617
626
  }