velocious 1.0.476 → 1.0.478
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 +1 -0
- package/build/configuration-types.js +3 -0
- package/build/configuration.js +24 -0
- package/build/frontend-model-controller.js +368 -11
- package/build/frontend-models/base.js +5 -1
- package/build/frontend-models/resource-definition.js +20 -3
- package/build/http-server/client/websocket-session.js +93 -0
- package/build/routes/hooks/frontend-model-command-route-hook.js +16 -0
- package/build/src/configuration-types.d.ts +15 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +4 -1
- package/build/src/configuration.d.ts +13 -0
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +23 -1
- package/build/src/frontend-model-controller.d.ts +96 -2
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +319 -12
- package/build/src/frontend-models/base.d.ts +5 -0
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +6 -2
- package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
- package/build/src/frontend-models/resource-definition.js +20 -4
- package/build/src/http-server/client/websocket-session.d.ts +39 -0
- package/build/src/http-server/client/websocket-session.d.ts.map +1 -1
- package/build/src/http-server/client/websocket-session.js +85 -1
- package/build/src/routes/hooks/frontend-model-command-route-hook.d.ts.map +1 -1
- package/build/src/routes/hooks/frontend-model-command-route-hook.js +15 -1
- package/build/src/sync/conflict-strategy.d.ts +83 -0
- package/build/src/sync/conflict-strategy.d.ts.map +1 -0
- package/build/src/sync/conflict-strategy.js +215 -0
- package/build/src/sync/peer-mutation-bundle.d.ts +97 -0
- package/build/src/sync/peer-mutation-bundle.d.ts.map +1 -0
- package/build/src/sync/peer-mutation-bundle.js +215 -0
- package/build/src/sync/server-change-feed.d.ts +265 -0
- package/build/src/sync/server-change-feed.d.ts.map +1 -0
- package/build/src/sync/server-change-feed.js +475 -0
- package/build/src/sync/sync-envelope-replay-service.d.ts +213 -0
- package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -0
- package/build/src/sync/sync-envelope-replay-service.js +229 -0
- package/build/sync/conflict-strategy.js +225 -0
- package/build/sync/peer-mutation-bundle.js +232 -0
- package/build/sync/server-change-feed.js +524 -0
- package/build/sync/sync-envelope-replay-service.js +263 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/configuration-types.js +3 -0
- package/src/configuration.js +24 -0
- package/src/frontend-model-controller.js +368 -11
- package/src/frontend-models/base.js +5 -1
- package/src/frontend-models/resource-definition.js +20 -3
- package/src/http-server/client/websocket-session.js +93 -0
- package/src/routes/hooks/frontend-model-command-route-hook.js +16 -0
- package/src/sync/conflict-strategy.js +225 -0
- package/src/sync/peer-mutation-bundle.js +232 -0
- package/src/sync/server-change-feed.js +524 -0
- package/src/sync/sync-envelope-replay-service.js +263 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Replays client sync envelopes through project supplied authentication,
|
|
5
|
+
* authorization, application, and persistence hooks.
|
|
6
|
+
*
|
|
7
|
+
* This is intentionally transport/model agnostic: Velocious owns the generic
|
|
8
|
+
* replay loop, normalization, stale-client comparison, and per-sync result
|
|
9
|
+
* shape while each app owns its token lookup, model handlers, and
|
|
10
|
+
* domain authorization rules.
|
|
11
|
+
*/
|
|
12
|
+
export default class SyncEnvelopeReplayService {
|
|
13
|
+
/**
|
|
14
|
+
* Creates a sync envelope replay service.
|
|
15
|
+
* @param {object} [args] - Constructor arguments.
|
|
16
|
+
* @param {{debug?: (...args: Array<unknown>) => void, warn?: (...args: Array<unknown>) => void}} [args.logger] - Logger used for normalization warnings.
|
|
17
|
+
*/
|
|
18
|
+
constructor(args = {}) {
|
|
19
|
+
this.logger = args.logger || console
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Replays a sync batch.
|
|
24
|
+
* @param {Record<string, ?>} params - Request params carrying authentication and syncs.
|
|
25
|
+
* @returns {Promise<{syncs: Array<Record<string, ?>>, status?: string, errorCode?: string, errorMessage?: string}>} Replay response.
|
|
26
|
+
*/
|
|
27
|
+
async replay(params) {
|
|
28
|
+
const actorResult = await this.authenticateReplay(params)
|
|
29
|
+
|
|
30
|
+
if (!actorResult.authenticated) {
|
|
31
|
+
return {
|
|
32
|
+
syncs: [],
|
|
33
|
+
status: "error",
|
|
34
|
+
errorCode: actorResult.errorCode,
|
|
35
|
+
errorMessage: actorResult.errorMessage
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const syncResponses = []
|
|
40
|
+
const context = await this.buildReplayContext({actor: actorResult.actor, params})
|
|
41
|
+
|
|
42
|
+
for (const rawSync of this.replaySyncs(params)) {
|
|
43
|
+
const normalizedResult = this.normalizeReplaySync(rawSync)
|
|
44
|
+
|
|
45
|
+
if (!normalizedResult.ok) {
|
|
46
|
+
syncResponses.push(normalizedResult.response)
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const mutation = normalizedResult.mutation
|
|
51
|
+
const accessResult = await this.authorizeReplayMutation({actor: actorResult.actor, context, mutation})
|
|
52
|
+
|
|
53
|
+
if (!accessResult.allowed) {
|
|
54
|
+
syncResponses.push({
|
|
55
|
+
id: mutation.id,
|
|
56
|
+
syncState: "failed",
|
|
57
|
+
reason: accessResult.reason || "access-denied"
|
|
58
|
+
})
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const existingSync = await this.findExistingReplaySync({actor: actorResult.actor, context, mutation})
|
|
63
|
+
const shouldApply = await this.shouldApplyReplayMutation({actor: actorResult.actor, context, existingSync, mutation})
|
|
64
|
+
const applyResult = shouldApply
|
|
65
|
+
? await this.applyReplayMutation({actor: actorResult.actor, context, existingSync, mutation})
|
|
66
|
+
: await this.skippedReplayMutation({actor: actorResult.actor, context, existingSync, mutation})
|
|
67
|
+
|
|
68
|
+
await this.persistReplayMutation({actor: actorResult.actor, context, existingSync, applyResult, mutation, shouldApply})
|
|
69
|
+
await this.afterReplayMutation({actor: actorResult.actor, context, existingSync, applyResult, mutation, shouldApply})
|
|
70
|
+
|
|
71
|
+
syncResponses.push({id: mutation.id, syncState: "successful"})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {syncs: syncResponses}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Authenticates the sync batch actor.
|
|
79
|
+
* @param {Record<string, ?>} _params - Request params.
|
|
80
|
+
* @returns {Promise<{authenticated: true, actor: ?} | {authenticated: false, errorCode: string, errorMessage: string}>} Auth result.
|
|
81
|
+
*/
|
|
82
|
+
async authenticateReplay(_params) {
|
|
83
|
+
throw new Error("SyncEnvelopeReplayService.authenticateReplay must be implemented")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Builds per-batch mutable context for caches shared across sync items.
|
|
88
|
+
* @param {{actor: ?, params: Record<string, ?>}} _args - Actor and request params.
|
|
89
|
+
* @returns {Promise<Record<string, ?>>} Replay context.
|
|
90
|
+
*/
|
|
91
|
+
async buildReplayContext(_args) {
|
|
92
|
+
return {}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Returns raw sync entries from request params.
|
|
97
|
+
* @param {Record<string, ?>} params - Request params.
|
|
98
|
+
* @returns {Array<?>} Raw sync entries.
|
|
99
|
+
*/
|
|
100
|
+
replaySyncs(params) {
|
|
101
|
+
return Array.isArray(params.syncs) ? params.syncs : []
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Normalizes one sync entry.
|
|
106
|
+
* @param {?} rawSync - Raw sync entry.
|
|
107
|
+
* @returns {{ok: true, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation} | {ok: false, response: Record<string, ?>}} Normalized mutation or failed response.
|
|
108
|
+
*/
|
|
109
|
+
normalizeReplaySync(rawSync) {
|
|
110
|
+
if (!rawSync || typeof rawSync !== "object" || Array.isArray(rawSync)) {
|
|
111
|
+
return {ok: false, response: {id: undefined, syncState: "failed", reason: "invalid-sync"}}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const sync = /** @type {Record<string, ?>} */ (rawSync)
|
|
115
|
+
const {clientUpdatedAt, data, id, resourceId, resourceType, syncType} = sync
|
|
116
|
+
|
|
117
|
+
if (typeof resourceType !== "string" || resourceType.length < 1 || resourceId === undefined || resourceId === null || typeof syncType !== "string" || syncType.length < 1) {
|
|
118
|
+
return {ok: false, response: {id, syncState: "failed", reason: "invalid-resource-id"}}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const resourceIdString = String(resourceId)
|
|
122
|
+
let clientUpdatedAtDate = typeof clientUpdatedAt === "string" || clientUpdatedAt instanceof Date ? new Date(clientUpdatedAt) : new Date()
|
|
123
|
+
|
|
124
|
+
if (Number.isNaN(clientUpdatedAtDate.getTime())) clientUpdatedAtDate = new Date()
|
|
125
|
+
|
|
126
|
+
const normalizedDataResult = this.normalizeReplaySyncData({data, id, resourceId: resourceIdString, resourceType})
|
|
127
|
+
|
|
128
|
+
if (!normalizedDataResult.ok) return normalizedDataResult
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
ok: true,
|
|
132
|
+
mutation: {
|
|
133
|
+
clientUpdatedAt: clientUpdatedAtDate,
|
|
134
|
+
data: normalizedDataResult.data,
|
|
135
|
+
id,
|
|
136
|
+
resourceId: resourceIdString,
|
|
137
|
+
resourceType,
|
|
138
|
+
serializedData: JSON.stringify(normalizedDataResult.data),
|
|
139
|
+
syncType
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Normalizes one sync data payload.
|
|
146
|
+
* @param {{data: ?, id: ?, resourceId: string, resourceType: string}} args - Sync payload normalization arguments.
|
|
147
|
+
* @returns {{ok: true, data: Record<string, ?>} | {ok: false, response: Record<string, ?>}} Normalized payload or failed response.
|
|
148
|
+
*/
|
|
149
|
+
normalizeReplaySyncData({data, id, resourceId, resourceType}) {
|
|
150
|
+
if (data === undefined || data === null) return {ok: true, data: {}}
|
|
151
|
+
|
|
152
|
+
if (typeof data === "string") {
|
|
153
|
+
try {
|
|
154
|
+
const parsedData = JSON.parse(data)
|
|
155
|
+
|
|
156
|
+
if (!parsedData || typeof parsedData !== "object" || Array.isArray(parsedData)) return {ok: true, data: {}}
|
|
157
|
+
|
|
158
|
+
return {ok: true, data: /** @type {Record<string, ?>} */ (parsedData)}
|
|
159
|
+
} catch (error) {
|
|
160
|
+
this.logger.warn?.("Invalid sync data JSON", {error, id, resourceId, resourceType})
|
|
161
|
+
return {ok: false, response: {id, syncState: "failed", reason: "invalid-data"}}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (typeof data !== "object" || Array.isArray(data)) return {ok: true, data: {}}
|
|
166
|
+
|
|
167
|
+
return {ok: true, data: JSON.parse(JSON.stringify(data))}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Authorizes one normalized mutation.
|
|
172
|
+
* @param {{actor: ?, context: Record<string, ?>, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation}} _args - Actor, batch context, and mutation.
|
|
173
|
+
* @returns {Promise<{allowed: boolean, reason?: string}>} Access result.
|
|
174
|
+
*/
|
|
175
|
+
async authorizeReplayMutation(_args) {
|
|
176
|
+
return {allowed: true}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Loads the previously stored sync/change row for stale-client comparison.
|
|
181
|
+
* @param {{actor: ?, context: Record<string, ?>, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation}} _args - Actor, batch context, and mutation.
|
|
182
|
+
* @returns {Promise<?>} Existing sync row.
|
|
183
|
+
*/
|
|
184
|
+
async findExistingReplaySync(_args) {
|
|
185
|
+
return null
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Returns whether a normalized mutation should be applied to domain models.
|
|
190
|
+
* @param {{actor: ?, context: Record<string, ?>, existingSync: ?, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation}} args - Actor, batch context, existing sync row, and mutation.
|
|
191
|
+
* @returns {Promise<boolean>} Whether to apply the mutation.
|
|
192
|
+
*/
|
|
193
|
+
async shouldApplyReplayMutation({existingSync, mutation}) {
|
|
194
|
+
const existingClientUpdatedAt = this.existingReplaySyncClientUpdatedAt(existingSync)
|
|
195
|
+
|
|
196
|
+
return !existingClientUpdatedAt || mutation.clientUpdatedAt > existingClientUpdatedAt
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Resolves the client timestamp from an existing sync row.
|
|
201
|
+
* @param {?} existingSync - Existing sync row.
|
|
202
|
+
* @returns {Date | null} Existing client timestamp.
|
|
203
|
+
*/
|
|
204
|
+
existingReplaySyncClientUpdatedAt(existingSync) {
|
|
205
|
+
if (!existingSync || typeof existingSync !== "object") return null
|
|
206
|
+
|
|
207
|
+
const syncRecord = /** @type {Record<string, ?>} */ (existingSync)
|
|
208
|
+
const value = typeof syncRecord.clientUpdatedAt === "function"
|
|
209
|
+
? syncRecord.clientUpdatedAt()
|
|
210
|
+
: syncRecord.clientUpdatedAt
|
|
211
|
+
|
|
212
|
+
if (value instanceof Date) return value
|
|
213
|
+
|
|
214
|
+
if (typeof value !== "string") return null
|
|
215
|
+
|
|
216
|
+
const parsedValue = new Date(value)
|
|
217
|
+
|
|
218
|
+
return Number.isNaN(parsedValue.getTime()) ? null : parsedValue
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Applies one normalized mutation to domain models.
|
|
223
|
+
* @param {{actor: ?, context: Record<string, ?>, existingSync: ?, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation}} _args - Actor, batch context, existing sync row, and mutation.
|
|
224
|
+
* @returns {Promise<?>} Project-specific apply result.
|
|
225
|
+
*/
|
|
226
|
+
async applyReplayMutation(_args) {
|
|
227
|
+
return null
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Resolves an apply result for stale mutations that should not touch domain models.
|
|
232
|
+
* @param {{actor: ?, context: Record<string, ?>, existingSync: ?, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation}} _args - Actor, batch context, existing sync row, and mutation.
|
|
233
|
+
* @returns {Promise<?>} Project-specific apply result.
|
|
234
|
+
*/
|
|
235
|
+
async skippedReplayMutation(_args) {
|
|
236
|
+
return null
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Persists one normalized mutation into the app sync/change store.
|
|
241
|
+
* @param {{actor: ?, context: Record<string, ?>, existingSync: ?, applyResult: ?, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation, shouldApply: boolean}} _args - Replay persistence arguments.
|
|
242
|
+
* @returns {Promise<void>}
|
|
243
|
+
*/
|
|
244
|
+
async persistReplayMutation(_args) {}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Runs side effects after a successful mutation replay and persistence.
|
|
248
|
+
* @param {{actor: ?, context: Record<string, ?>, existingSync: ?, applyResult: ?, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation, shouldApply: boolean}} _args - Replay side-effect arguments.
|
|
249
|
+
* @returns {Promise<void>}
|
|
250
|
+
*/
|
|
251
|
+
async afterReplayMutation(_args) {}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @typedef {object} SyncReplayMutation
|
|
256
|
+
* @property {Date} clientUpdatedAt - Client-side mutation timestamp.
|
|
257
|
+
* @property {Record<string, ?>} data - Parsed mutation payload.
|
|
258
|
+
* @property {?} id - Client sync row id for per-sync responses.
|
|
259
|
+
* @property {string} resourceId - Resource id as a string.
|
|
260
|
+
* @property {string} resourceType - Resource/model name.
|
|
261
|
+
* @property {string} serializedData - JSON serialized mutation payload.
|
|
262
|
+
* @property {string} syncType - Sync operation type.
|
|
263
|
+
*/
|
|
@@ -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/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/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/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/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/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.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/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/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/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/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/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
|
@@ -348,6 +348,7 @@
|
|
|
348
348
|
* frontends and peers; `policy` is hashed but intentionally omitted from
|
|
349
349
|
* frontend-safe manifests.
|
|
350
350
|
* @typedef {object} FrontendModelResourceSyncConfiguration
|
|
351
|
+
* @property {"optimisticVersion" | "serverWins" | "lastWriterWins" | "fieldThreeWay" | "appendOnly"} [conflictStrategy] - Strategy used when replay detects server/client divergence. Defaults to `optimisticVersion`.
|
|
351
352
|
* @property {boolean} [enabled] - Whether the resource is sync-enabled. Defaults to true when `sync` is configured.
|
|
352
353
|
* @property {string[]} [operations] - Sync operation names such as `index`, `find`, `create`, `update`, custom domain commands, etc.
|
|
353
354
|
* @property {string | number} [policyVersion] - App-controlled policy version used as a stable change signal.
|
|
@@ -359,6 +360,7 @@
|
|
|
359
360
|
* Velocious sync configuration.
|
|
360
361
|
* @typedef {object} VelociousSyncConfiguration
|
|
361
362
|
* @property {import("./sync/device-identity.js").SyncJsonWebKey | null} [deviceCertificateBackendPublicKey] - Public backend key used to verify offline device certificates for sync replay.
|
|
363
|
+
* @property {number} [changeFeedRetentionSize] - Number of accepted server changes retained before clients must refresh from snapshot.
|
|
362
364
|
* @property {Array<import("./sync/offline-grant.js").OfflineGrantSigningKey>} offlineGrantSigningKeys - Signing keys used to issue and verify offline grants. Secrets must never be exposed to clients.
|
|
363
365
|
* @property {number} [offlineGrantTtlMs] - Default offline grant TTL in milliseconds. Defaults to 24 hours.
|
|
364
366
|
*/
|
|
@@ -366,6 +368,7 @@
|
|
|
366
368
|
/**
|
|
367
369
|
* Frontend-safe normalized sync metadata.
|
|
368
370
|
* @typedef {object} NormalizedFrontendModelResourceSyncConfiguration
|
|
371
|
+
* @property {"optimisticVersion" | "serverWins" | "lastWriterWins" | "fieldThreeWay" | "appendOnly"} conflictStrategy - Normalized replay conflict strategy.
|
|
369
372
|
* @property {boolean} enabled - Whether the resource is sync-enabled.
|
|
370
373
|
* @property {string[]} operations - Sorted, duplicate-free sync operation names.
|
|
371
374
|
* @property {string | null} policyVersion - App-controlled policy version, or null.
|
package/src/configuration.js
CHANGED
|
@@ -232,6 +232,9 @@ export default class VelociousConfiguration {
|
|
|
232
232
|
/** Grace period for paused WebSocket sessions before permanent teardown. */
|
|
233
233
|
this._websocketSessionGraceSeconds = 300
|
|
234
234
|
|
|
235
|
+
/** Interval (seconds) between server→client heartbeat pings; 0 disables reaping of silent sockets. */
|
|
236
|
+
this._websocketSessionHeartbeatSeconds = 30
|
|
237
|
+
|
|
235
238
|
/**
|
|
236
239
|
* Optional wrapper called around every WebSocket-borne request /
|
|
237
240
|
* connection message / channel dispatch. Apps register it here
|
|
@@ -407,18 +410,23 @@ export default class VelociousConfiguration {
|
|
|
407
410
|
*/
|
|
408
411
|
_normalizeSyncConfiguration(sync) {
|
|
409
412
|
const deviceCertificateBackendPublicKey = sync?.deviceCertificateBackendPublicKey || null
|
|
413
|
+
const changeFeedRetentionSize = sync?.changeFeedRetentionSize
|
|
410
414
|
const offlineGrantSigningKeys = sync?.offlineGrantSigningKeys || []
|
|
411
415
|
const offlineGrantTtlMs = sync?.offlineGrantTtlMs
|
|
412
416
|
|
|
413
417
|
if (deviceCertificateBackendPublicKey !== null && (typeof deviceCertificateBackendPublicKey !== "object" || Array.isArray(deviceCertificateBackendPublicKey))) {
|
|
414
418
|
throw new Error("sync.deviceCertificateBackendPublicKey must be a public JSON Web Key object")
|
|
415
419
|
}
|
|
420
|
+
if (changeFeedRetentionSize !== undefined && (!Number.isInteger(changeFeedRetentionSize) || changeFeedRetentionSize <= 0)) {
|
|
421
|
+
throw new Error("sync.changeFeedRetentionSize must be a positive integer")
|
|
422
|
+
}
|
|
416
423
|
if (!Array.isArray(offlineGrantSigningKeys)) throw new Error("sync.offlineGrantSigningKeys must be an array")
|
|
417
424
|
if (offlineGrantTtlMs !== undefined && (!Number.isInteger(offlineGrantTtlMs) || offlineGrantTtlMs <= 0)) {
|
|
418
425
|
throw new Error("sync.offlineGrantTtlMs must be a positive integer number of milliseconds")
|
|
419
426
|
}
|
|
420
427
|
|
|
421
428
|
return {
|
|
429
|
+
changeFeedRetentionSize: changeFeedRetentionSize || 10000,
|
|
422
430
|
deviceCertificateBackendPublicKey,
|
|
423
431
|
offlineGrantSigningKeys: offlineGrantSigningKeys.map((key) => normalizeOfflineGrantSigningKey(key)),
|
|
424
432
|
offlineGrantTtlMs: offlineGrantTtlMs || 24 * 60 * 60 * 1000
|
|
@@ -2047,6 +2055,12 @@ export default class VelociousConfiguration {
|
|
|
2047
2055
|
*/
|
|
2048
2056
|
getWebsocketSessionGraceSeconds() { return this._websocketSessionGraceSeconds }
|
|
2049
2057
|
|
|
2058
|
+
/**
|
|
2059
|
+
* Runs get websocket session heartbeat seconds.
|
|
2060
|
+
* @returns {number} - Interval (seconds) between server→client heartbeat pings; 0 disables reaping.
|
|
2061
|
+
*/
|
|
2062
|
+
getWebsocketSessionHeartbeatSeconds() { return this._websocketSessionHeartbeatSeconds }
|
|
2063
|
+
|
|
2050
2064
|
/**
|
|
2051
2065
|
* Registers a wrapper invoked around every WS-borne request /
|
|
2052
2066
|
* connection message / channel dispatch. The wrapper receives the
|
|
@@ -2124,6 +2138,16 @@ export default class VelociousConfiguration {
|
|
|
2124
2138
|
this._websocketSessionGraceSeconds = seconds
|
|
2125
2139
|
}
|
|
2126
2140
|
|
|
2141
|
+
/**
|
|
2142
|
+
* Runs set websocket session heartbeat seconds.
|
|
2143
|
+
* @param {number} seconds
|
|
2144
|
+
* @returns {void}
|
|
2145
|
+
*/
|
|
2146
|
+
setWebsocketSessionHeartbeatSeconds(seconds) {
|
|
2147
|
+
if (!Number.isFinite(seconds) || seconds < 0) throw new Error(`Invalid heartbeat seconds: ${seconds}`)
|
|
2148
|
+
this._websocketSessionHeartbeatSeconds = seconds
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2127
2151
|
/**
|
|
2128
2152
|
* Moves a session into the paused registry and starts the grace
|
|
2129
2153
|
* timer. When the timer fires, the session's permanent teardown
|