velocious 1.0.487 → 1.0.489
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.
- package/README.md +2 -0
- package/build/configuration-types.js +1 -0
- package/build/configuration.js +29 -0
- package/build/environment-handlers/node.js +22 -6
- package/build/src/configuration-types.d.ts +5 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +2 -1
- package/build/src/configuration.d.ts +11 -0
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +27 -1
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +20 -8
- package/build/src/sync/sync-api-client-types.d.ts +182 -0
- package/build/src/sync/sync-api-client-types.d.ts.map +1 -0
- package/build/src/sync/sync-api-client-types.js +3 -0
- package/build/src/sync/sync-api-client.d.ts +188 -0
- package/build/src/sync/sync-api-client.d.ts.map +1 -0
- package/build/src/sync/sync-api-client.js +307 -0
- package/build/src/sync/sync-api-controller.d.ts +78 -0
- package/build/src/sync/sync-api-controller.d.ts.map +1 -0
- package/build/src/sync/sync-api-controller.js +142 -0
- package/build/src/sync/sync-model-change-feed-service.d.ts +131 -0
- package/build/src/sync/sync-model-change-feed-service.d.ts.map +1 -0
- package/build/src/sync/sync-model-change-feed-service.js +212 -0
- package/build/sync/sync-api-client-types.js +77 -0
- package/build/sync/sync-api-client.js +342 -0
- package/build/sync/sync-api-controller.js +161 -0
- package/build/sync/sync-model-change-feed-service.js +244 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/configuration-types.js +1 -0
- package/src/configuration.js +29 -0
- package/src/environment-handlers/node.js +22 -6
- package/src/sync/sync-api-client-types.js +77 -0
- package/src/sync/sync-api-client.js +342 -0
- package/src/sync/sync-api-controller.js +161 -0
- 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/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-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.
|
|
6
|
+
"version": "1.0.489",
|
|
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.
|
|
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.
|
|
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": "^
|
|
118
|
+
"tedious": "^20.0.0",
|
|
119
119
|
"typescript": "^6.0.2",
|
|
120
120
|
"uniqunize": "^1.0.3"
|
|
121
121
|
}
|
|
@@ -421,6 +421,7 @@
|
|
|
421
421
|
* @property {string} [frontendModelsOutputPath] - Optional output project path where `src/frontend-models` should be generated.
|
|
422
422
|
* @property {string} [resourcesPath] - Optional override for the resources directory to auto-discover; defaults to `<path>/src/resources`. Set internally for package entries.
|
|
423
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.
|
|
424
|
+
* @property {AbilityResourceClassType[]} [abilityResources] - Auto-discovered ability resource classes (frontend-model and authorization) from this project's resources directory. Set internally by the environment handler — do not set manually.
|
|
424
425
|
*/
|
|
425
426
|
|
|
426
427
|
/**
|
package/src/configuration.js
CHANGED
|
@@ -875,6 +875,34 @@ export default class VelociousConfiguration {
|
|
|
875
875
|
*/
|
|
876
876
|
setAbilityResources(resources) { this._abilityResources = resources }
|
|
877
877
|
|
|
878
|
+
/**
|
|
879
|
+
* Merges resource classes discovered from the app and every registered package
|
|
880
|
+
* into the ability-resources list. `autoDiscoverResources` populates each backend
|
|
881
|
+
* project's `frontendModels` (including package projects), so this makes a
|
|
882
|
+
* package-contributed model's abilities reach subscription and per-record
|
|
883
|
+
* authorization automatically — consuming apps do not have to hand-register
|
|
884
|
+
* package resources. Already-present classes (e.g. an app's explicitly-set
|
|
885
|
+
* resources) are left untouched.
|
|
886
|
+
* @returns {void} - No return value.
|
|
887
|
+
*/
|
|
888
|
+
_mergeDiscoveredAbilityResources() {
|
|
889
|
+
const merged = [...this._abilityResources]
|
|
890
|
+
const seen = new Set(merged)
|
|
891
|
+
|
|
892
|
+
for (const backendProject of this._backendProjects) {
|
|
893
|
+
if (!backendProject.abilityResources) continue
|
|
894
|
+
|
|
895
|
+
for (const ResourceClass of backendProject.abilityResources) {
|
|
896
|
+
if (seen.has(ResourceClass)) continue
|
|
897
|
+
|
|
898
|
+
seen.add(ResourceClass)
|
|
899
|
+
merged.push(ResourceClass)
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
this._abilityResources = merged
|
|
904
|
+
}
|
|
905
|
+
|
|
878
906
|
/**
|
|
879
907
|
* Runs get ability resolver.
|
|
880
908
|
* @returns {import("./configuration-types.js").AbilityResolverType | undefined} - Ability resolver.
|
|
@@ -1723,6 +1751,7 @@ export default class VelociousConfiguration {
|
|
|
1723
1751
|
|
|
1724
1752
|
await this.initializeModels({type})
|
|
1725
1753
|
await this.getEnvironmentHandler().autoDiscoverResources(this)
|
|
1754
|
+
this._mergeDiscoveredAbilityResources()
|
|
1726
1755
|
this._validateResourceRelationshipsOnModels()
|
|
1727
1756
|
|
|
1728
1757
|
if (this._initializers) {
|
|
@@ -100,10 +100,11 @@ export default class VelociousEnvironmentHandlerNode extends Base{
|
|
|
100
100
|
*/
|
|
101
101
|
async autoDiscoverResources(configuration) {
|
|
102
102
|
const {frontendModelResourceDefinitionIsClass} = await import("../frontend-models/resource-definition.js")
|
|
103
|
+
const {default: AuthorizationBaseResource} = await import("../authorization/base-resource.js")
|
|
103
104
|
const backendProjects = configuration.getBackendProjects()
|
|
104
105
|
|
|
105
106
|
for (const backendProject of backendProjects) {
|
|
106
|
-
if (backendProject.
|
|
107
|
+
if (backendProject.abilityResources) continue
|
|
107
108
|
|
|
108
109
|
const resourcesDir = backendProject.resourcesPath || path.join(backendProject.path, "src", "resources")
|
|
109
110
|
let files
|
|
@@ -115,9 +116,13 @@ export default class VelociousEnvironmentHandlerNode extends Base{
|
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
/**
|
|
118
|
-
* Discovered.
|
|
119
|
+
* Discovered frontend-model resources keyed by model name.
|
|
119
120
|
* @type {Record<string, ?>} */
|
|
120
121
|
const discovered = {}
|
|
122
|
+
/**
|
|
123
|
+
* Every discovered ability resource class (frontend-model and authorization).
|
|
124
|
+
* @type {Array<?>} */
|
|
125
|
+
const abilityResourceClasses = []
|
|
121
126
|
|
|
122
127
|
for (const file of files) {
|
|
123
128
|
if (!file.endsWith(".js") && !file.endsWith(".mjs")) continue
|
|
@@ -127,10 +132,17 @@ export default class VelociousEnvironmentHandlerNode extends Base{
|
|
|
127
132
|
const imported = await import(filePath)
|
|
128
133
|
const ResourceClass = imported.default
|
|
129
134
|
|
|
135
|
+
// Any authorization resource (frontend-model resources also extend it) that
|
|
136
|
+
// declares a `ModelClass`; skip abstract/common base resources without one.
|
|
137
|
+
const isAbilityResource = typeof ResourceClass === "function"
|
|
138
|
+
&& (ResourceClass === AuthorizationBaseResource || ResourceClass.prototype instanceof AuthorizationBaseResource)
|
|
139
|
+
|
|
140
|
+
if (!isAbilityResource || !ResourceClass.ModelClass) continue
|
|
141
|
+
|
|
142
|
+
abilityResourceClasses.push(ResourceClass)
|
|
143
|
+
|
|
144
|
+
// Only frontend-model resources drive routing/generation/publisher discovery.
|
|
130
145
|
if (!frontendModelResourceDefinitionIsClass(ResourceClass)) continue
|
|
131
|
-
// Skip abstract/common base resources that declare no `ModelClass` — they are
|
|
132
|
-
// not models, so they must not be recorded as discovered frontend models.
|
|
133
|
-
if (!ResourceClass.ModelClass) continue
|
|
134
146
|
|
|
135
147
|
const baseName = file.replace(/\.(js|mjs)$/, "")
|
|
136
148
|
const modelName = baseName.replace(/-resource$/, "")
|
|
@@ -141,9 +153,13 @@ export default class VelociousEnvironmentHandlerNode extends Base{
|
|
|
141
153
|
discovered[modelName] = ResourceClass
|
|
142
154
|
}
|
|
143
155
|
|
|
144
|
-
if (Object.keys(discovered).length > 0) {
|
|
156
|
+
if (!backendProject.frontendModels && Object.keys(discovered).length > 0) {
|
|
145
157
|
backendProject.frontendModels = discovered
|
|
146
158
|
}
|
|
159
|
+
|
|
160
|
+
if (abilityResourceClasses.length > 0) {
|
|
161
|
+
backendProject.abilityResources = abilityResourceClasses
|
|
162
|
+
}
|
|
147
163
|
}
|
|
148
164
|
}
|
|
149
165
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module sync-api-client-types
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** @typedef {{id: string | null, serverSequence: number | null, updatedAt: string} | null} SyncCursor */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {object} SyncChangeEnvelope
|
|
11
|
+
* @property {() => unknown} data - Sync data payload.
|
|
12
|
+
* @property {() => unknown} id - Sync row identifier.
|
|
13
|
+
* @property {() => unknown} resourceId - Resource identifier.
|
|
14
|
+
* @property {() => string | null} resourceType - Resource type name.
|
|
15
|
+
* @property {() => string} syncType - Sync operation type.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {object} SyncChangeApplyResult
|
|
20
|
+
* @property {boolean} changed - Whether the local store changed.
|
|
21
|
+
* @property {string | null} [resourceType] - Applied resource type override.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {object} SyncResourceConfig
|
|
26
|
+
* @property {(args: {attributes: Record<string, unknown>, data: Record<string, unknown>, record: ?, sync: SyncChangeEnvelope}) => Promise<boolean | void> | boolean | void} [afterApply] - Optional post-save hook.
|
|
27
|
+
* @property {(args: {data: Record<string, unknown>, record: ?, sync: SyncChangeEnvelope}) => Promise<Record<string, unknown>> | Record<string, unknown>} attributes - Allowed attributes builder.
|
|
28
|
+
* @property {boolean} enabled - Whether this resource is sync-enabled.
|
|
29
|
+
* @property {(args: {data: Record<string, unknown>, resourceId: unknown, sync: SyncChangeEnvelope}) => Promise<?> | ?} [findRecord] - Optional upsert finder.
|
|
30
|
+
* @property {(args: {resourceId: unknown, sync: SyncChangeEnvelope}) => Promise<?> | ?} [findRecordForDelete] - Optional destroy finder.
|
|
31
|
+
* @property {?} modelClass - Velocious model class.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @typedef {object} SyncChangesRequest
|
|
36
|
+
* @property {string} authenticationToken - Auth token.
|
|
37
|
+
* @property {string | null} [afterId] - Last seen row id.
|
|
38
|
+
* @property {number} [afterServerSequence] - Last seen server sequence.
|
|
39
|
+
* @property {string} [afterUpdatedAt] - Last seen timestamp.
|
|
40
|
+
* @property {number} limit - Page size.
|
|
41
|
+
* @property {string | null} [upToId] - Snapshot upper-bound row id.
|
|
42
|
+
* @property {number} [upToServerSequence] - Snapshot upper-bound server sequence.
|
|
43
|
+
* @property {string} [upToUpdatedAt] - Snapshot upper-bound timestamp.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {object} SyncChangesResponse
|
|
48
|
+
* @property {string} [errorMessage] - Error message.
|
|
49
|
+
* @property {SyncCursor | Record<string, ?>} [nextCursor] - Next cursor.
|
|
50
|
+
* @property {string} [status] - Response status.
|
|
51
|
+
* @property {Array<unknown>} [syncs] - Sync rows.
|
|
52
|
+
* @property {SyncCursor | Record<string, ?>} [upToCursor] - Snapshot upper-bound cursor.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @typedef {object} SyncChangesResult
|
|
57
|
+
* @property {boolean} changed - Whether any local record changed.
|
|
58
|
+
* @property {number} pages - Applied page count.
|
|
59
|
+
* @property {Record<string, boolean>} resourceChanged - Changed flags by resource type.
|
|
60
|
+
* @property {Record<string, number>} resourceCounts - Applied counts by resource type.
|
|
61
|
+
* @property {number} syncedCount - Applied row count.
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @typedef {object} SyncReplayItem
|
|
66
|
+
* @property {string | number} id - Sync id.
|
|
67
|
+
* @property {string} syncState - Replay state.
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @typedef {object} SyncReplayResponse
|
|
72
|
+
* @property {string} [errorMessage] - Error message.
|
|
73
|
+
* @property {string} [status] - Response status.
|
|
74
|
+
* @property {Array<SyncReplayItem>} [syncs] - Replay results.
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
export {}
|