velocious 1.0.496 → 1.0.497
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/build/configuration-types.js +21 -0
- package/build/configuration.js +48 -0
- package/build/database/column-types.js +19 -0
- package/build/database/record/index.js +9 -0
- package/build/src/configuration-types.d.ts +68 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +20 -1
- package/build/src/configuration.d.ts +6 -0
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +45 -1
- package/build/src/database/column-types.d.ts +8 -0
- package/build/src/database/column-types.d.ts.map +1 -0
- package/build/src/database/column-types.js +18 -0
- package/build/src/database/record/index.d.ts +8 -0
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +9 -1
- package/build/src/sync/sync-api-client.d.ts +4 -1
- package/build/src/sync/sync-api-client.d.ts.map +1 -1
- package/build/src/sync/sync-api-client.js +9 -2
- package/build/src/sync/sync-client-types.d.ts +88 -10
- package/build/src/sync/sync-client-types.d.ts.map +1 -1
- package/build/src/sync/sync-client-types.js +1 -1
- package/build/src/sync/sync-client.d.ts +38 -11
- package/build/src/sync/sync-client.d.ts.map +1 -1
- package/build/src/sync/sync-client.js +193 -29
- package/build/sync/sync-api-client.js +7 -1
- package/build/sync/sync-client-types.js +34 -5
- package/build/sync/sync-client.js +223 -27
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/configuration-types.js +21 -0
- package/src/configuration.js +48 -0
- package/src/database/column-types.js +19 -0
- package/src/database/record/index.js +9 -0
- package/src/sync/sync-api-client.js +7 -1
- package/src/sync/sync-client-types.js +34 -5
- package/src/sync/sync-client.js +223 -27
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
-
import {forcedFunction} from "typanic"
|
|
4
|
-
|
|
5
3
|
import Configuration from "../configuration.js"
|
|
4
|
+
import {isBooleanColumnType} from "../database/column-types.js"
|
|
5
|
+
import restArgsError from "../utils/rest-args-error.js"
|
|
6
6
|
|
|
7
7
|
import {serializedScopeFromQuery} from "./query-scope.js"
|
|
8
8
|
import SyncApiClient from "./sync-api-client.js"
|
|
@@ -14,44 +14,85 @@ let clientCounter = 0
|
|
|
14
14
|
/** @type {{create: "afterCreate", update: "afterUpdate", destroy: "afterDestroy"}} */
|
|
15
15
|
const TRACKED_CALLBACK_NAMES = {create: "afterCreate", destroy: "afterDestroy", update: "afterUpdate"}
|
|
16
16
|
|
|
17
|
+
/** Attribute names treated as client-local sync bookkeeping when deriving localOnlyAttributes. */
|
|
18
|
+
const LOCAL_BOOKKEEPING_ATTRIBUTE_NAMES = ["createdAt", "updatedAt", "lastSyncChangeAt"]
|
|
19
|
+
|
|
20
|
+
/** @type {WeakMap<Configuration, SyncClient>} */
|
|
21
|
+
const syncClientsByConfiguration = new WeakMap()
|
|
22
|
+
|
|
17
23
|
/**
|
|
18
24
|
* Declarative client-side sync driver.
|
|
19
25
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* and
|
|
26
|
+
* Everything is derived from the app's Velocious configuration: models declare
|
|
27
|
+
* `static sync`, transport/auth/connectivity come from the `sync.client`
|
|
28
|
+
* configuration block, and Velocious owns scope persistence, per-scope cursors,
|
|
29
|
+
* pull paging/apply, local queueing, and online-gated replay. Declare sync
|
|
30
|
+
* interest from queries:
|
|
23
31
|
*
|
|
24
|
-
*
|
|
25
|
-
* syncClient.
|
|
26
|
-
* await syncClient.sync(Event.where({partnerId}))
|
|
32
|
+
* await syncClient().start()
|
|
33
|
+
* await syncClient().sync(Event.where({partnerId}))
|
|
27
34
|
*/
|
|
28
35
|
export default class SyncClient {
|
|
29
36
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
37
|
+
* Builds the sync client by deriving everything from the app's Velocious
|
|
38
|
+
* configuration: every registered model declaring `static sync` becomes a
|
|
39
|
+
* resource with booleanAttributes derived from column types and
|
|
40
|
+
* localOnlyAttributes derived from the primary key, createdAt/updatedAt, and
|
|
41
|
+
* sync bookkeeping columns; the pending-sync model is the registered "Sync"
|
|
42
|
+
* model; transport, auth, connectivity, and error reporting come from the
|
|
43
|
+
* `sync.client` configuration block, with the framework owning the
|
|
44
|
+
* `${mountPath}/changes` and `${mountPath}/replay` POSTers.
|
|
45
|
+
* @param {import("./sync-client-types.js").SyncClientOptions} [options] - Optional overrides.
|
|
32
46
|
*/
|
|
33
|
-
constructor(
|
|
34
|
-
|
|
47
|
+
constructor(options = {}) {
|
|
48
|
+
const {configuration = Configuration.current(), legacyCursor, scopeStore, syncModel, ...restOptions} = options
|
|
35
49
|
|
|
36
|
-
|
|
37
|
-
forcedFunction(config.postReplay, "SyncClient config.postReplay")
|
|
38
|
-
forcedFunction(config.authenticationToken, "SyncClient config.authenticationToken")
|
|
50
|
+
restArgsError(restOptions)
|
|
39
51
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
const clientConfiguration = configuration.getSyncConfiguration().client
|
|
53
|
+
|
|
54
|
+
if (!clientConfiguration) {
|
|
55
|
+
throw new Error("SyncClient requires a sync.client configuration block: new Configuration({sync: {client: {authenticationToken, transport}}})")
|
|
43
56
|
}
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
const modelClasses = configuration.getModelClasses()
|
|
59
|
+
/** @type {Record<string, import("./sync-client-types.js").SyncClientResourceConfig>} */
|
|
60
|
+
const resources = {}
|
|
61
|
+
|
|
62
|
+
for (const modelClass of Object.values(modelClasses)) {
|
|
63
|
+
if (!modelClass.sync) continue
|
|
64
|
+
|
|
65
|
+
const resourceType = modelClass.getModelName()
|
|
66
|
+
|
|
67
|
+
resources[resourceType] = resourceConfigFromSyncDeclaration({declaration: modelClass.sync, modelClass, resourceType})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (Object.keys(resources).length === 0) {
|
|
71
|
+
throw new Error("SyncClient found no registered models declaring static sync - declare `static sync = true` (or a sync declaration object) on the models that should sync")
|
|
49
72
|
}
|
|
50
73
|
|
|
51
|
-
|
|
74
|
+
const resolvedSyncModel = syncModel || modelClasses.Sync
|
|
75
|
+
|
|
76
|
+
if (!resolvedSyncModel) {
|
|
77
|
+
throw new Error("SyncClient requires a registered \"Sync\" model for pending local sync rows (or pass options.syncModel)")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @type {import("./sync-client-types.js").SyncClientConfig} */
|
|
81
|
+
this.config = {
|
|
82
|
+
authenticationToken: clientConfiguration.authenticationToken,
|
|
83
|
+
batchSize: clientConfiguration.batchSize,
|
|
84
|
+
configuration,
|
|
85
|
+
isOnline: clientConfiguration.isOnline,
|
|
86
|
+
legacyCursor,
|
|
87
|
+
onError: clientConfiguration.onError,
|
|
88
|
+
postChanges: transportPoster({path: `${clientConfiguration.mountPath}/changes`, transport: clientConfiguration.transport}),
|
|
89
|
+
postReplay: transportPoster({path: `${clientConfiguration.mountPath}/replay`, transport: clientConfiguration.transport}),
|
|
90
|
+
resources,
|
|
91
|
+
syncModel: resolvedSyncModel
|
|
92
|
+
}
|
|
52
93
|
this._clientNumber = ++clientCounter
|
|
53
94
|
/** @type {import("./sync-scope-store.js").default | null} */
|
|
54
|
-
this._scopeStore =
|
|
95
|
+
this._scopeStore = scopeStore || null
|
|
55
96
|
/** @type {Promise<void> | null} */
|
|
56
97
|
this._scheduledReplay = null
|
|
57
98
|
/** @type {Record<string, import("./sync-api-client-types.js").SyncResourceConfig> | null} */
|
|
@@ -171,6 +212,17 @@ export default class SyncClient {
|
|
|
171
212
|
return /** @type {SyncClient} */ (currentSyncClient())
|
|
172
213
|
}
|
|
173
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Builds a sync client derived from the given configuration. Alias for
|
|
217
|
+
* `new SyncClient({configuration, ...options})`.
|
|
218
|
+
* @param {Configuration} [configuration] - Configuration owning the registered models and the sync.client block. Defaults to the current configuration.
|
|
219
|
+
* @param {Omit<import("./sync-client-types.js").SyncClientOptions, "configuration">} [options] - Optional overrides.
|
|
220
|
+
* @returns {SyncClient} Sync client derived from the configuration.
|
|
221
|
+
*/
|
|
222
|
+
static fromConfiguration(configuration = Configuration.current(), options = {}) {
|
|
223
|
+
return new SyncClient({...options, configuration})
|
|
224
|
+
}
|
|
225
|
+
|
|
174
226
|
/**
|
|
175
227
|
* Declares (or re-activates) a sync scope from a model query and pulls it when online.
|
|
176
228
|
* @param {import("../database/query/model-class-query.js").default<?>} query - Query declaring the sync scope.
|
|
@@ -364,7 +416,7 @@ export default class SyncClient {
|
|
|
364
416
|
* @returns {import("./sync-scope-store.js").default} Scope store.
|
|
365
417
|
*/
|
|
366
418
|
scopeStore() {
|
|
367
|
-
this._scopeStore ||= new SyncScopeStore({configuration: this.config.configuration
|
|
419
|
+
this._scopeStore ||= new SyncScopeStore({configuration: this.config.configuration})
|
|
368
420
|
|
|
369
421
|
return this._scopeStore
|
|
370
422
|
}
|
|
@@ -390,13 +442,16 @@ export default class SyncClient {
|
|
|
390
442
|
}
|
|
391
443
|
|
|
392
444
|
/**
|
|
393
|
-
* Resolves the sync type for a mutation through the resource config.
|
|
445
|
+
* Resolves the sync type for a mutation through the resource config. The
|
|
446
|
+
* "upsert" flag queues creates and updates as "update" rows (the server
|
|
447
|
+
* upserts by resource id) and destroys as "delete" rows.
|
|
394
448
|
* @param {{operation: "create" | "update" | "destroy", record: ?, resourceConfig: import("./sync-client-types.js").SyncClientResourceConfig}} args - Mutation args.
|
|
395
449
|
* @returns {string} Sync type.
|
|
396
450
|
*/
|
|
397
451
|
defaultSyncType({operation, record, resourceConfig}) {
|
|
398
|
-
if (resourceConfig.syncType) return resourceConfig.syncType({operation, record})
|
|
452
|
+
if (typeof resourceConfig.syncType === "function") return resourceConfig.syncType({operation, record})
|
|
399
453
|
if (operation === "destroy") return "delete"
|
|
454
|
+
if (resourceConfig.syncType === "upsert") return "update"
|
|
400
455
|
|
|
401
456
|
return operation
|
|
402
457
|
}
|
|
@@ -423,6 +478,147 @@ export default class SyncClient {
|
|
|
423
478
|
}
|
|
424
479
|
}
|
|
425
480
|
|
|
481
|
+
/**
|
|
482
|
+
* Builds one resource config from a model's `static sync` declaration plus its
|
|
483
|
+
* derived column metadata.
|
|
484
|
+
* @param {{declaration: import("./sync-client-types.js").ModelSyncDeclaration, modelClass: ?, resourceType: string}} args - Declaration args.
|
|
485
|
+
* @returns {import("./sync-client-types.js").SyncClientResourceConfig} Derived resource config.
|
|
486
|
+
*/
|
|
487
|
+
function resourceConfigFromSyncDeclaration({declaration, modelClass, resourceType}) {
|
|
488
|
+
const normalizedDeclaration = declaration === true ? {} : declaration
|
|
489
|
+
|
|
490
|
+
if (!normalizedDeclaration || typeof normalizedDeclaration !== "object" || Array.isArray(normalizedDeclaration)) {
|
|
491
|
+
throw new Error(`${resourceType} static sync must be true or a sync declaration object, got: ${String(declaration)}`)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const {afterApply, attributes, booleanAttributes, findRecord, findRecordForDelete, localOnlyAttributes, syncType, track, trackedData, ...restDeclaration} = normalizedDeclaration
|
|
495
|
+
const unknownKeys = Object.keys(restDeclaration)
|
|
496
|
+
|
|
497
|
+
if (unknownKeys.length > 0) {
|
|
498
|
+
throw new Error(`${resourceType} static sync received unknown keys: ${unknownKeys.join(", ")} (supported: afterApply, attributes, booleanAttributes, findRecord, findRecordForDelete, localOnlyAttributes, syncType, track, trackedData)`)
|
|
499
|
+
}
|
|
500
|
+
if (syncType !== undefined && typeof syncType !== "function" && syncType !== "upsert") {
|
|
501
|
+
throw new Error(`${resourceType} static sync syncType must be a function or the string "upsert", got: ${String(syncType)}`)
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const derived = derivedSyncAttributes({modelClass, resourceType})
|
|
505
|
+
|
|
506
|
+
return {
|
|
507
|
+
afterApply,
|
|
508
|
+
attributes,
|
|
509
|
+
booleanAttributes: mergedAttributeNames(derived.booleanAttributes, booleanAttributes),
|
|
510
|
+
findRecord,
|
|
511
|
+
findRecordForDelete,
|
|
512
|
+
localOnlyAttributes: mergedAttributeNames(derived.localOnlyAttributes, localOnlyAttributes),
|
|
513
|
+
modelClass,
|
|
514
|
+
syncType,
|
|
515
|
+
track: normalizedTrack(track),
|
|
516
|
+
trackedData
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Derives boolean and local-only attribute names from a model's column metadata:
|
|
522
|
+
* booleans from boolean column types; local-only from the primary key,
|
|
523
|
+
* createdAt/updatedAt, and sync bookkeeping columns.
|
|
524
|
+
* @param {{modelClass: ?, resourceType: string}} args - Derivation args.
|
|
525
|
+
* @returns {{booleanAttributes: string[], localOnlyAttributes: string[]}} Derived attribute names.
|
|
526
|
+
*/
|
|
527
|
+
function derivedSyncAttributes({modelClass, resourceType}) {
|
|
528
|
+
if (
|
|
529
|
+
typeof modelClass.getColumnNames !== "function" ||
|
|
530
|
+
typeof modelClass.getColumnNameToAttributeNameMap !== "function" ||
|
|
531
|
+
typeof modelClass.getColumnTypeByName !== "function" ||
|
|
532
|
+
typeof modelClass.primaryKey !== "function" ||
|
|
533
|
+
typeof modelClass.hasPrimaryKey !== "function"
|
|
534
|
+
) {
|
|
535
|
+
throw new Error(`${resourceType} static sync requires a Velocious model class with column metadata (getColumnNames, getColumnNameToAttributeNameMap, getColumnTypeByName, primaryKey, hasPrimaryKey)`)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const columnNameToAttributeName = modelClass.getColumnNameToAttributeNameMap()
|
|
539
|
+
/** @type {string[]} */
|
|
540
|
+
const booleanAttributes = []
|
|
541
|
+
/** @type {string[]} */
|
|
542
|
+
const localOnlyAttributes = []
|
|
543
|
+
|
|
544
|
+
if (modelClass.hasPrimaryKey()) {
|
|
545
|
+
const primaryKeyColumn = modelClass.primaryKey()
|
|
546
|
+
|
|
547
|
+
localOnlyAttributes.push(columnNameToAttributeName[primaryKeyColumn] || primaryKeyColumn)
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
for (const columnName of modelClass.getColumnNames()) {
|
|
551
|
+
const attributeName = columnNameToAttributeName[columnName] || columnName
|
|
552
|
+
const columnType = modelClass.getColumnTypeByName(columnName)
|
|
553
|
+
|
|
554
|
+
if (LOCAL_BOOKKEEPING_ATTRIBUTE_NAMES.includes(attributeName) && !localOnlyAttributes.includes(attributeName)) {
|
|
555
|
+
localOnlyAttributes.push(attributeName)
|
|
556
|
+
}
|
|
557
|
+
if (columnType && isBooleanColumnType(columnType)) {
|
|
558
|
+
booleanAttributes.push(attributeName)
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return {booleanAttributes, localOnlyAttributes}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Merges derived attribute names with declared extras into a sorted, duplicate-free list.
|
|
567
|
+
* @param {string[]} derived - Derived attribute names.
|
|
568
|
+
* @param {string[] | undefined} declared - Declared extra attribute names.
|
|
569
|
+
* @returns {string[]} Merged attribute names.
|
|
570
|
+
*/
|
|
571
|
+
function mergedAttributeNames(derived, declared) {
|
|
572
|
+
return [...new Set([...derived, ...(declared || [])])].sort()
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Normalizes a declaration's track value: an operations array is shorthand for
|
|
577
|
+
* the {operations} form.
|
|
578
|
+
* @param {import("./sync-client-types.js").ModelSyncDeclarationConfig["track"]} track - Declared track value.
|
|
579
|
+
* @returns {import("./sync-client-types.js").SyncClientResourceConfig["track"]} Normalized track value.
|
|
580
|
+
*/
|
|
581
|
+
function normalizedTrack(track) {
|
|
582
|
+
if (Array.isArray(track)) return {operations: track}
|
|
583
|
+
|
|
584
|
+
return track
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Builds a framework-owned sync endpoint POSTer over the configured transport.
|
|
589
|
+
* @param {{path: string, transport: import("../configuration-types.js").VelociousSyncClientTransport}} args - Poster args.
|
|
590
|
+
* @returns {(payload: Record<string, ?>) => Promise<?>} Sync endpoint POSTer.
|
|
591
|
+
*/
|
|
592
|
+
function transportPoster({path, transport}) {
|
|
593
|
+
return async (payload) => {
|
|
594
|
+
const response = await transport.post(path, payload)
|
|
595
|
+
|
|
596
|
+
if (!response || typeof response.json !== "function") {
|
|
597
|
+
throw new Error(`sync.client transport.post must resolve to a response with a json() method for ${path} (like the frontend-model websocket client)`)
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return await response.json()
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Lazily builds (and memoizes per configuration) the sync client derived from the
|
|
606
|
+
* app's Velocious configuration and registers it as the current sync client.
|
|
607
|
+
* @param {Configuration} [configuration] - Configuration owning the registered models and the sync.client block. Defaults to the current configuration.
|
|
608
|
+
* @returns {SyncClient} Memoized sync client for the configuration.
|
|
609
|
+
*/
|
|
610
|
+
export function syncClient(configuration = Configuration.current()) {
|
|
611
|
+
let client = syncClientsByConfiguration.get(configuration)
|
|
612
|
+
|
|
613
|
+
if (!client) {
|
|
614
|
+
client = SyncClient.fromConfiguration(configuration)
|
|
615
|
+
syncClientsByConfiguration.set(configuration, client)
|
|
616
|
+
client.setCurrent()
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return client
|
|
620
|
+
}
|
|
621
|
+
|
|
426
622
|
/**
|
|
427
623
|
* Declares a sync scope on the current sync client.
|
|
428
624
|
* @param {import("../database/query/model-class-query.js").default<?>} query - Query declaring the sync scope.
|
|
@@ -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/validation-messages.js","../src/database/record/attachments/attachment-record.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/length.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/database/tenants/data-copier.js","../src/database/tenants/schema-cloner.js","../src/database/tenants/tenant-table-plan.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/packages/velocious-package.js","../src/plugins/sqljs-wasm-route-controller.js","../src/plugins/sqljs-wasm-route.js","../src/routes/app-routes.js","../src/routes/base-route.js","../src/routes/basic-route.js","../src/routes/get-route.js","../src/routes/index.js","../src/routes/namespace-route.js","../src/routes/plugin-routes.js","../src/routes/post-route.js","../src/routes/resolver.js","../src/routes/resource-route.js","../src/routes/root-route.js","../src/routes/built-in/debug/controller.js","../src/routes/built-in/errors/controller.js","../src/routes/hooks/frontend-model-command-route-hook.js","../src/sync/conflict-strategy.js","../src/sync/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.js","../src/sync/peer-mutation-bundle.js","../src/sync/query-scope.js","../src/sync/server-change-feed.js","../src/sync/server-sequence-allocator.js","../src/sync/stable-json.js","../src/sync/sync-api-client-types.js","../src/sync/sync-api-client.js","../src/sync/sync-api-controller.js","../src/sync/sync-client-registry.js","../src/sync/sync-client-types.js","../src/sync/sync-client.js","../src/sync/sync-envelope-replay-service.js","../src/sync/sync-model-change-feed-service.js","../src/sync/sync-replay-upsert-applier.js","../src/sync/sync-resource-base.js","../src/sync/sync-scope-store.js","../src/tenants/default-tenant-database-provisioning.js","../src/tenants/tenant-iterator.js","../src/tenants/tenant.js","../src/testing/base-expect.js","../src/testing/browser-frontend-model-event-hook-scenarios.js","../src/testing/browser-test-app.js","../src/testing/expect-to-change.js","../src/testing/expect-utils.js","../src/testing/expect.js","../src/testing/request-client.js","../src/testing/test-files-finder.js","../src/testing/test-filter-parser.js","../src/testing/test-runner.js","../src/testing/test-suite-splitter.js","../src/testing/test.js","../src/types/external-modules.d.ts","../src/utils/backtrace-cleaner-node.js","../src/utils/backtrace-cleaner.js","../src/utils/deburr-column-name.js","../src/utils/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/is-date.js","../src/utils/model-scope.js","../src/utils/nest-callbacks.js","../src/utils/plain-object.js","../src/utils/ransack.js","../src/utils/rest-args-error.js","../src/utils/singularize-model-name.js","../src/utils/split-sql-statements.js","../src/utils/to-import-specifier.js","../src/utils/with-tracked-stack-async-hooks.js","../src/utils/with-tracked-stack.js"],"version":"6.0.3"}
|
|
1
|
+
{"root":["../index.js","../bin/velocious.js","../src/application.js","../src/configuration-resolver.js","../src/configuration-types.js","../src/configuration.js","../src/controller.js","../src/current-configuration.js","../src/current.js","../src/error-logger.js","../src/frontend-model-controller.js","../src/initializer.js","../src/logger.js","../src/mailer.js","../src/record-payload-values.js","../src/time-zone.js","../src/velocious-error.js","../src/authorization/ability.js","../src/authorization/base-resource.js","../src/background-jobs/client.js","../src/background-jobs/cron-expression.js","../src/background-jobs/forked-runner-child.js","../src/background-jobs/job-record.js","../src/background-jobs/job-registry.js","../src/background-jobs/job-runner.js","../src/background-jobs/job.js","../src/background-jobs/json-socket.js","../src/background-jobs/main.js","../src/background-jobs/normalize-error.js","../src/background-jobs/scheduler.js","../src/background-jobs/socket-request.js","../src/background-jobs/status-reporter.js","../src/background-jobs/store.js","../src/background-jobs/types.js","../src/background-jobs/worker.js","../src/background-jobs/web/authorization.js","../src/background-jobs/web/controller.js","../src/background-jobs/web/index.js","../src/background-jobs/web/path-matcher.js","../src/background-jobs/web/registry.js","../src/beacon/client.js","../src/beacon/in-process-broker.js","../src/beacon/in-process-client.js","../src/beacon/server.js","../src/beacon/types.js","../src/cli/base-command.js","../src/cli/browser-cli.js","../src/cli/index.js","../src/cli/tenant-database-command-helper.js","../src/cli/use-browser-cli.js","../src/cli/commands/background-jobs-main.js","../src/cli/commands/background-jobs-runner.js","../src/cli/commands/background-jobs-worker.js","../src/cli/commands/beacon.js","../src/cli/commands/console.js","../src/cli/commands/init.js","../src/cli/commands/routes.js","../src/cli/commands/run-script.js","../src/cli/commands/runner.js","../src/cli/commands/server.js","../src/cli/commands/test.js","../src/cli/commands/db/base-command.js","../src/cli/commands/db/create.js","../src/cli/commands/db/drop.js","../src/cli/commands/db/migrate.js","../src/cli/commands/db/reset.js","../src/cli/commands/db/rollback.js","../src/cli/commands/db/seed.js","../src/cli/commands/db/schema/dump.js","../src/cli/commands/db/schema/load.js","../src/cli/commands/db/tenants/check.js","../src/cli/commands/db/tenants/create.js","../src/cli/commands/db/tenants/drop.js","../src/cli/commands/db/tenants/migrate.js","../src/cli/commands/destroy/migration.js","../src/cli/commands/generate/base-models.js","../src/cli/commands/generate/frontend-models.js","../src/cli/commands/generate/migration.js","../src/cli/commands/generate/model.js","../src/cli/commands/lint/relationships.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/column-types.js","../src/database/datetime-storage.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/migrations-ledger.js","../src/database/migrator.js","../src/database/use-database.js","../src/database/drivers/base-column.js","../src/database/drivers/base-columns-index.js","../src/database/drivers/base-foreign-key.js","../src/database/drivers/base-table.js","../src/database/drivers/base.js","../src/database/drivers/mssql/column.js","../src/database/drivers/mssql/columns-index.js","../src/database/drivers/mssql/connect-connection.js","../src/database/drivers/mssql/foreign-key.js","../src/database/drivers/mssql/index.js","../src/database/drivers/mssql/options.js","../src/database/drivers/mssql/query-parser.js","../src/database/drivers/mssql/structure-sql.js","../src/database/drivers/mssql/table.js","../src/database/drivers/mssql/sql/alter-table.js","../src/database/drivers/mssql/sql/create-database.js","../src/database/drivers/mssql/sql/create-index.js","../src/database/drivers/mssql/sql/create-table.js","../src/database/drivers/mssql/sql/delete.js","../src/database/drivers/mssql/sql/drop-database.js","../src/database/drivers/mssql/sql/drop-table.js","../src/database/drivers/mssql/sql/insert.js","../src/database/drivers/mssql/sql/remove-index.js","../src/database/drivers/mssql/sql/update.js","../src/database/drivers/mssql/sql/upsert.js","../src/database/drivers/mysql/column.js","../src/database/drivers/mysql/columns-index.js","../src/database/drivers/mysql/foreign-key.js","../src/database/drivers/mysql/index.js","../src/database/drivers/mysql/options.js","../src/database/drivers/mysql/query-parser.js","../src/database/drivers/mysql/query.js","../src/database/drivers/mysql/structure-sql.js","../src/database/drivers/mysql/table.js","../src/database/drivers/mysql/sql/alter-table.js","../src/database/drivers/mysql/sql/create-database.js","../src/database/drivers/mysql/sql/create-index.js","../src/database/drivers/mysql/sql/create-table.js","../src/database/drivers/mysql/sql/delete.js","../src/database/drivers/mysql/sql/drop-database.js","../src/database/drivers/mysql/sql/drop-table.js","../src/database/drivers/mysql/sql/insert.js","../src/database/drivers/mysql/sql/remove-index.js","../src/database/drivers/mysql/sql/update.js","../src/database/drivers/mysql/sql/upsert.js","../src/database/drivers/pgsql/column.js","../src/database/drivers/pgsql/columns-index.js","../src/database/drivers/pgsql/foreign-key.js","../src/database/drivers/pgsql/index.js","../src/database/drivers/pgsql/options.js","../src/database/drivers/pgsql/query-parser.js","../src/database/drivers/pgsql/structure-sql.js","../src/database/drivers/pgsql/table.js","../src/database/drivers/pgsql/sql/alter-table.js","../src/database/drivers/pgsql/sql/create-database.js","../src/database/drivers/pgsql/sql/create-index.js","../src/database/drivers/pgsql/sql/create-table.js","../src/database/drivers/pgsql/sql/delete.js","../src/database/drivers/pgsql/sql/drop-database.js","../src/database/drivers/pgsql/sql/drop-table.js","../src/database/drivers/pgsql/sql/insert.js","../src/database/drivers/pgsql/sql/remove-index.js","../src/database/drivers/pgsql/sql/update.js","../src/database/drivers/pgsql/sql/upsert.js","../src/database/drivers/sqlite/base.js","../src/database/drivers/sqlite/column.js","../src/database/drivers/sqlite/columns-index.js","../src/database/drivers/sqlite/connection-sql-js.js","../src/database/drivers/sqlite/foreign-key.js","../src/database/drivers/sqlite/index.js","../src/database/drivers/sqlite/index.native.js","../src/database/drivers/sqlite/index.web.js","../src/database/drivers/sqlite/options.js","../src/database/drivers/sqlite/query-parser.js","../src/database/drivers/sqlite/query.js","../src/database/drivers/sqlite/query.native.js","../src/database/drivers/sqlite/query.web.js","../src/database/drivers/sqlite/structure-sql.js","../src/database/drivers/sqlite/table-rebuilder.js","../src/database/drivers/sqlite/table.js","../src/database/drivers/sqlite/web-persistence.js","../src/database/drivers/sqlite/sql/alter-table.js","../src/database/drivers/sqlite/sql/create-index.js","../src/database/drivers/sqlite/sql/create-table.js","../src/database/drivers/sqlite/sql/delete.js","../src/database/drivers/sqlite/sql/drop-table.js","../src/database/drivers/sqlite/sql/insert.js","../src/database/drivers/sqlite/sql/remove-index.js","../src/database/drivers/sqlite/sql/update.js","../src/database/drivers/sqlite/sql/upsert.js","../src/database/drivers/structure-sql/utils.js","../src/database/migration/index.js","../src/database/migrator/files-finder.js","../src/database/migrator/types.js","../src/database/pool/async-tracked-multi-connection.js","../src/database/pool/base-methods-forward.js","../src/database/pool/base.js","../src/database/pool/single-multi-use.js","../src/database/query/alter-table-base.js","../src/database/query/base.js","../src/database/query/create-database-base.js","../src/database/query/create-index-base.js","../src/database/query/create-table-base.js","../src/database/query/delete-base.js","../src/database/query/drop-database-base.js","../src/database/query/drop-table-base.js","../src/database/query/from-base.js","../src/database/query/from-plain.js","../src/database/query/from-table.js","../src/database/query/index.js","../src/database/query/insert-base.js","../src/database/query/join-base.js","../src/database/query/join-object.js","../src/database/query/join-plain.js","../src/database/query/join-tracker.js","../src/database/query/model-class-query.js","../src/database/query/order-base.js","../src/database/query/order-column.js","../src/database/query/order-plain.js","../src/database/query/preloader.js","../src/database/query/query-data.js","../src/database/query/remove-index-base.js","../src/database/query/select-base.js","../src/database/query/select-plain.js","../src/database/query/select-table-and-column.js","../src/database/query/update-base.js","../src/database/query/upsert-base.js","../src/database/query/where-base.js","../src/database/query/where-combinator.js","../src/database/query/where-hash.js","../src/database/query/where-model-class-hash.js","../src/database/query/where-not.js","../src/database/query/where-plain.js","../src/database/query/with-count.js","../src/database/query/preloader/belongs-to.js","../src/database/query/preloader/ensure-model-class-initialized.js","../src/database/query/preloader/has-many.js","../src/database/query/preloader/has-one.js","../src/database/query/preloader/selection.js","../src/database/query-parser/base-query-parser.js","../src/database/query-parser/from-parser.js","../src/database/query-parser/group-parser.js","../src/database/query-parser/joins-parser.js","../src/database/query-parser/limit-parser.js","../src/database/query-parser/options.js","../src/database/query-parser/order-parser.js","../src/database/query-parser/select-parser.js","../src/database/query-parser/where-parser.js","../src/database/record/acts-as-list.js","../src/database/record/auditing.js","../src/database/record/index.js","../src/database/record/record-not-found-error.js","../src/database/record/state-machine.js","../src/database/record/user-module.js","../src/database/record/validation-messages.js","../src/database/record/attachments/attachment-record.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/length.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/database/tenants/data-copier.js","../src/database/tenants/schema-cloner.js","../src/database/tenants/tenant-table-plan.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/packages/velocious-package.js","../src/plugins/sqljs-wasm-route-controller.js","../src/plugins/sqljs-wasm-route.js","../src/routes/app-routes.js","../src/routes/base-route.js","../src/routes/basic-route.js","../src/routes/get-route.js","../src/routes/index.js","../src/routes/namespace-route.js","../src/routes/plugin-routes.js","../src/routes/post-route.js","../src/routes/resolver.js","../src/routes/resource-route.js","../src/routes/root-route.js","../src/routes/built-in/debug/controller.js","../src/routes/built-in/errors/controller.js","../src/routes/hooks/frontend-model-command-route-hook.js","../src/sync/conflict-strategy.js","../src/sync/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.js","../src/sync/peer-mutation-bundle.js","../src/sync/query-scope.js","../src/sync/server-change-feed.js","../src/sync/server-sequence-allocator.js","../src/sync/stable-json.js","../src/sync/sync-api-client-types.js","../src/sync/sync-api-client.js","../src/sync/sync-api-controller.js","../src/sync/sync-client-registry.js","../src/sync/sync-client-types.js","../src/sync/sync-client.js","../src/sync/sync-envelope-replay-service.js","../src/sync/sync-model-change-feed-service.js","../src/sync/sync-replay-upsert-applier.js","../src/sync/sync-resource-base.js","../src/sync/sync-scope-store.js","../src/tenants/default-tenant-database-provisioning.js","../src/tenants/tenant-iterator.js","../src/tenants/tenant.js","../src/testing/base-expect.js","../src/testing/browser-frontend-model-event-hook-scenarios.js","../src/testing/browser-test-app.js","../src/testing/expect-to-change.js","../src/testing/expect-utils.js","../src/testing/expect.js","../src/testing/request-client.js","../src/testing/test-files-finder.js","../src/testing/test-filter-parser.js","../src/testing/test-runner.js","../src/testing/test-suite-splitter.js","../src/testing/test.js","../src/types/external-modules.d.ts","../src/utils/backtrace-cleaner-node.js","../src/utils/backtrace-cleaner.js","../src/utils/deburr-column-name.js","../src/utils/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/is-date.js","../src/utils/model-scope.js","../src/utils/nest-callbacks.js","../src/utils/plain-object.js","../src/utils/ransack.js","../src/utils/rest-args-error.js","../src/utils/singularize-model-name.js","../src/utils/split-sql-statements.js","../src/utils/to-import-specifier.js","../src/utils/with-tracked-stack-async-hooks.js","../src/utils/with-tracked-stack.js"],"version":"6.0.3"}
|
package/package.json
CHANGED
|
@@ -362,10 +362,31 @@
|
|
|
362
362
|
* @property {FrontendModelResourceClassType} resourceClass - App sync resource class served by the auto-mounted sync endpoints.
|
|
363
363
|
*/
|
|
364
364
|
|
|
365
|
+
/**
|
|
366
|
+
* Client-side sync transport owning HTTP POSTs to the framework sync endpoints,
|
|
367
|
+
* matching the frontend-model websocket client post contract.
|
|
368
|
+
* @typedef {object} VelociousSyncClientTransport
|
|
369
|
+
* @property {(path: string, body?: ?, options?: {headers?: Record<string, string>}) => Promise<{json: () => ?}>} post - Posts one request and resolves a response with a json accessor.
|
|
370
|
+
*/
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Client-side sync configuration consumed by `SyncClient.fromConfiguration(...)`.
|
|
374
|
+
* The framework owns the `${mountPath}/changes` and `${mountPath}/replay`
|
|
375
|
+
* POSTers over the given transport.
|
|
376
|
+
* @typedef {object} VelociousSyncClientConfiguration
|
|
377
|
+
* @property {() => string | Promise<string>} authenticationToken - Resolves the auth token sent with sync requests.
|
|
378
|
+
* @property {number} [batchSize] - Max syncs per request.
|
|
379
|
+
* @property {() => boolean | Promise<boolean>} [isOnline] - Connectivity gate for pulls and replays. Defaults to always online.
|
|
380
|
+
* @property {string} [mountPath] - Mount path the server serves the sync endpoints under (match the server's `sync.api.mountPath`). Defaults to "/velocious/sync"; normalization strips trailing slashes and always fills in the default.
|
|
381
|
+
* @property {(error: Error) => void} [onError] - Reports background replay/pull failures. Defaults to rethrowing.
|
|
382
|
+
* @property {VelociousSyncClientTransport} transport - Transport posting to the framework sync endpoints (e.g. the frontend-model websocket client).
|
|
383
|
+
*/
|
|
384
|
+
|
|
365
385
|
/**
|
|
366
386
|
* Velocious sync configuration.
|
|
367
387
|
* @typedef {object} VelociousSyncConfiguration
|
|
368
388
|
* @property {VelociousSyncApiConfiguration} [api] - Auto-mounts the Velocious sync changes/replay endpoints for this resource class.
|
|
389
|
+
* @property {VelociousSyncClientConfiguration} [client] - Client-side sync configuration consumed by `SyncClient.fromConfiguration(...)`.
|
|
369
390
|
* @property {import("./sync/device-identity.js").SyncJsonWebKey | null} [deviceCertificateBackendPublicKey] - Public backend key used to verify offline device certificates for sync replay.
|
|
370
391
|
* @property {number} [changeFeedRetentionSize] - Number of accepted server changes retained before clients must refresh from snapshot.
|
|
371
392
|
* @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.
|
package/src/configuration.js
CHANGED
|
@@ -444,12 +444,60 @@ export default class VelociousConfiguration {
|
|
|
444
444
|
return {
|
|
445
445
|
api: this._normalizeSyncApiConfiguration(api),
|
|
446
446
|
changeFeedRetentionSize: changeFeedRetentionSize || 10000,
|
|
447
|
+
client: this._normalizeSyncClientConfiguration(sync?.client),
|
|
447
448
|
deviceCertificateBackendPublicKey,
|
|
448
449
|
offlineGrantSigningKeys: offlineGrantSigningKeys.map((key) => normalizeOfflineGrantSigningKey(key)),
|
|
449
450
|
offlineGrantTtlMs: offlineGrantTtlMs || 24 * 60 * 60 * 1000
|
|
450
451
|
}
|
|
451
452
|
}
|
|
452
453
|
|
|
454
|
+
/**
|
|
455
|
+
* Normalizes client-side sync configuration consumed by `SyncClient.fromConfiguration(...)`.
|
|
456
|
+
* @param {import("./configuration-types.js").VelociousSyncClientConfiguration | undefined} client - Client-side sync configuration.
|
|
457
|
+
* @returns {import("./configuration-types.js").VelociousSyncClientConfiguration | undefined} - Normalized client-side sync configuration.
|
|
458
|
+
*/
|
|
459
|
+
_normalizeSyncClientConfiguration(client) {
|
|
460
|
+
if (client === undefined || client === null) return undefined
|
|
461
|
+
|
|
462
|
+
if (typeof client !== "object" || Array.isArray(client)) {
|
|
463
|
+
throw new Error("sync.client must be an object with transport and authenticationToken")
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const {authenticationToken, batchSize, isOnline, mountPath, onError, transport, ...restClient} = client
|
|
467
|
+
const restClientKeys = Object.keys(restClient)
|
|
468
|
+
|
|
469
|
+
if (restClientKeys.length > 0) {
|
|
470
|
+
throw new Error(`sync.client received unknown keys: ${restClientKeys.join(", ")} (supported: authenticationToken, batchSize, isOnline, mountPath, onError, transport)`)
|
|
471
|
+
}
|
|
472
|
+
if (!transport || typeof transport !== "object" || typeof transport.post !== "function") {
|
|
473
|
+
throw new Error("sync.client.transport must be an object with a post(path, body) method (like the frontend-model websocket client)")
|
|
474
|
+
}
|
|
475
|
+
if (typeof authenticationToken !== "function") {
|
|
476
|
+
throw new Error("sync.client.authenticationToken must be a function resolving the auth token sent with sync requests")
|
|
477
|
+
}
|
|
478
|
+
if (isOnline !== undefined && typeof isOnline !== "function") {
|
|
479
|
+
throw new Error("sync.client.isOnline must be a function resolving connectivity")
|
|
480
|
+
}
|
|
481
|
+
if (onError !== undefined && typeof onError !== "function") {
|
|
482
|
+
throw new Error("sync.client.onError must be a function reporting background sync failures")
|
|
483
|
+
}
|
|
484
|
+
if (batchSize !== undefined && (!Number.isInteger(batchSize) || batchSize <= 0)) {
|
|
485
|
+
throw new Error("sync.client.batchSize must be a positive integer")
|
|
486
|
+
}
|
|
487
|
+
if (mountPath !== undefined && (typeof mountPath !== "string" || !mountPath.startsWith("/"))) {
|
|
488
|
+
throw new Error(`sync.client.mountPath must start with '/', got: ${String(mountPath)}`)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return {
|
|
492
|
+
authenticationToken,
|
|
493
|
+
batchSize,
|
|
494
|
+
isOnline,
|
|
495
|
+
mountPath: (mountPath || "/velocious/sync").replace(/\/+$/u, "") || "/",
|
|
496
|
+
onError,
|
|
497
|
+
transport
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
453
501
|
/**
|
|
454
502
|
* Normalizes sync API endpoint configuration.
|
|
455
503
|
* @param {import("./configuration-types.js").VelociousSyncApiConfiguration | undefined} api - Sync API configuration.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Driver column types that store boolean values. Drivers report storage types,
|
|
5
|
+
* which diverge for booleans (Postgres/SQLite `boolean`, some drivers `bool`,
|
|
6
|
+
* MSSQL `bit`), so cross-driver consumers must match them uniformly.
|
|
7
|
+
* @type {Set<string>}
|
|
8
|
+
*/
|
|
9
|
+
const BOOLEAN_COLUMN_TYPES = new Set(["bit", "bool", "boolean"])
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Whether a driver-reported (or cast) column type stores boolean values,
|
|
13
|
+
* uniformly across database drivers.
|
|
14
|
+
* @param {string} columnType - Driver-reported (or cast) column type.
|
|
15
|
+
* @returns {boolean} Whether the column type is boolean-backed.
|
|
16
|
+
*/
|
|
17
|
+
export function isBooleanColumnType(columnType) {
|
|
18
|
+
return BOOLEAN_COLUMN_TYPES.has(columnType.toLowerCase())
|
|
19
|
+
}
|
|
@@ -239,6 +239,15 @@ class VelociousDatabaseRecord {
|
|
|
239
239
|
* @type {string | undefined} */
|
|
240
240
|
static modelName
|
|
241
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Opt-in client sync declaration consumed by `SyncClient.fromConfiguration(...)`.
|
|
244
|
+
* Declare `static sync = true` (all defaults) or a declaration object like
|
|
245
|
+
* `static sync = {track: ["create", "update"], syncType: "upsert"}` to have the
|
|
246
|
+
* sync client auto-discover this model and derive its resource config from
|
|
247
|
+
* column metadata.
|
|
248
|
+
* @type {import("../../sync/sync-client-types.js").ModelSyncDeclaration | undefined} */
|
|
249
|
+
static sync
|
|
250
|
+
|
|
242
251
|
/**
|
|
243
252
|
* Narrows the runtime value to the documented type.
|
|
244
253
|
* @type {Promise<void> | null | undefined} */
|
|
@@ -485,7 +485,10 @@ export default class SyncApiClient {
|
|
|
485
485
|
}
|
|
486
486
|
|
|
487
487
|
/**
|
|
488
|
-
* Builds backend-safe queued sync data without mutating caller data.
|
|
488
|
+
* Builds backend-safe queued sync data without mutating caller data. The default
|
|
489
|
+
* (no explicit `data`) is the resource's attributes minus local-only attributes,
|
|
490
|
+
* with booleans coerced and Date values serialized to ISO strings, so apps don't
|
|
491
|
+
* need per-model tracked-payload builders.
|
|
489
492
|
* @param {{resource: ?, data?: Record<string, unknown>, localOnlyAttributes?: string[], booleanAttributes?: string[], normalizeData?: (data: Record<string, unknown>) => Record<string, unknown>}} args - Data args.
|
|
490
493
|
* @returns {Record<string, unknown>} Queued data.
|
|
491
494
|
*/
|
|
@@ -498,6 +501,9 @@ export default class SyncApiClient {
|
|
|
498
501
|
for (const attributeName of args.booleanAttributes || []) {
|
|
499
502
|
if (Object.hasOwn(syncData, attributeName)) syncData[attributeName] = this.optionalBooleanSyncValue(syncData[attributeName], attributeName)
|
|
500
503
|
}
|
|
504
|
+
for (const [attributeName, value] of Object.entries(syncData)) {
|
|
505
|
+
if (value instanceof Date) syncData[attributeName] = value.toISOString()
|
|
506
|
+
}
|
|
501
507
|
|
|
502
508
|
return syncData
|
|
503
509
|
}
|