velocious 1.0.445 → 1.0.447
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 -1
- package/build/configuration-types.js +2 -2
- package/build/database/pool/async-tracked-multi-connection.js +3 -1
- package/build/database/record/index.js +38 -38
- package/build/environment-handlers/node/cli/commands/generate/base-models.js +67 -1
- package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +169 -0
- package/build/frontend-model-controller.js +44 -12
- package/build/frontend-model-resource/base-resource.js +519 -129
- package/build/frontend-models/base.js +417 -203
- package/build/frontend-models/preloader.js +7 -7
- package/build/frontend-models/query.js +18 -18
- package/build/frontend-models/use-created-event.js +1 -1
- package/build/frontend-models/use-destroyed-event.js +1 -1
- package/build/frontend-models/use-model-class-event.js +1 -1
- package/build/frontend-models/use-updated-event.js +1 -1
- package/build/frontend-models/websocket-channel.js +39 -3
- package/build/routes/resolver.js +17 -14
- package/build/src/configuration-types.d.ts +6 -6
- package/build/src/configuration-types.js +3 -3
- package/build/src/database/pool/async-tracked-multi-connection.d.ts.map +1 -1
- package/build/src/database/pool/async-tracked-multi-connection.js +5 -2
- package/build/src/database/record/index.d.ts +38 -38
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +39 -39
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts +13 -0
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +59 -2
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +74 -0
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +155 -1
- package/build/src/frontend-model-controller.d.ts +2 -1
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +38 -14
- package/build/src/frontend-model-resource/base-resource.d.ts +196 -21
- package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/base-resource.js +467 -112
- package/build/src/frontend-models/base.d.ts +232 -149
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +371 -201
- package/build/src/frontend-models/preloader.d.ts +10 -10
- package/build/src/frontend-models/preloader.d.ts.map +1 -1
- package/build/src/frontend-models/preloader.js +8 -8
- package/build/src/frontend-models/query.d.ts +8 -8
- package/build/src/frontend-models/query.d.ts.map +1 -1
- package/build/src/frontend-models/query.js +19 -19
- package/build/src/frontend-models/use-created-event.d.ts +2 -2
- package/build/src/frontend-models/use-created-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-created-event.js +2 -2
- package/build/src/frontend-models/use-destroyed-event.d.ts +1 -1
- package/build/src/frontend-models/use-destroyed-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-destroyed-event.js +2 -2
- package/build/src/frontend-models/use-model-class-event.d.ts +1 -1
- package/build/src/frontend-models/use-model-class-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-model-class-event.js +2 -2
- package/build/src/frontend-models/use-updated-event.d.ts +1 -1
- package/build/src/frontend-models/use-updated-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-updated-event.js +2 -2
- package/build/src/frontend-models/websocket-channel.d.ts +8 -0
- package/build/src/frontend-models/websocket-channel.d.ts.map +1 -1
- package/build/src/frontend-models/websocket-channel.js +35 -4
- package/build/src/routes/resolver.d.ts.map +1 -1
- package/build/src/routes/resolver.js +7 -4
- package/build/src/utils/model-scope.d.ts +4 -4
- package/build/src/utils/model-scope.d.ts.map +1 -1
- package/build/src/utils/model-scope.js +3 -3
- package/build/src/utils/ransack.d.ts +1 -1
- package/build/src/utils/ransack.d.ts.map +1 -1
- package/build/src/utils/ransack.js +2 -2
- package/build/utils/model-scope.js +2 -2
- package/build/utils/ransack.js +1 -1
- package/package.json +1 -1
- package/src/configuration-types.js +2 -2
- package/src/database/pool/async-tracked-multi-connection.js +3 -1
- package/src/database/record/index.js +38 -38
- package/src/environment-handlers/node/cli/commands/generate/base-models.js +67 -1
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +169 -0
- package/src/frontend-model-controller.js +44 -12
- package/src/frontend-model-resource/base-resource.js +519 -129
- package/src/frontend-models/base.js +417 -203
- package/src/frontend-models/preloader.js +7 -7
- package/src/frontend-models/query.js +18 -18
- package/src/frontend-models/use-created-event.js +1 -1
- package/src/frontend-models/use-destroyed-event.js +1 -1
- package/src/frontend-models/use-model-class-event.js +1 -1
- package/src/frontend-models/use-updated-event.js +1 -1
- package/src/frontend-models/websocket-channel.js +39 -3
- package/src/routes/resolver.js +17 -14
- package/src/utils/model-scope.js +2 -2
- package/src/utils/ransack.js +1 -1
|
@@ -15,7 +15,7 @@ export default class FrontendModelPreloader {
|
|
|
15
15
|
/**
|
|
16
16
|
* Runs preload.
|
|
17
17
|
* @param {Array<import("./base.js").default>} models - Frontend model instances to preload onto.
|
|
18
|
-
* @param {import("./query.js").default<
|
|
18
|
+
* @param {import("./query.js").default<import("./base.js").FrontendModelClass> | import("../database/query/index.js").NestedPreloadRecord | string | Array<string | import("../database/query/index.js").NestedPreloadRecord>} queryOrSpec - A query built via `Model.preload(...).select(...)`, or a raw preload spec.
|
|
19
19
|
* @param {{force?: boolean}} [options] - Options.
|
|
20
20
|
* @returns {Promise<void>} - Resolves when preloading completes.
|
|
21
21
|
*/
|
|
@@ -24,12 +24,12 @@ export default class FrontendModelPreloader {
|
|
|
24
24
|
|
|
25
25
|
const modelClass = /**
|
|
26
26
|
* Narrows the runtime value to the documented type.
|
|
27
|
-
@type {
|
|
27
|
+
@type {import("./base.js").FrontendModelClass} */ (models[0].constructor)
|
|
28
28
|
const isQuery = Boolean(queryOrSpec) && typeof queryOrSpec === "object" && "_preload" in queryOrSpec
|
|
29
29
|
const query = isQuery
|
|
30
30
|
? /**
|
|
31
31
|
* Narrows the runtime value to the documented type.
|
|
32
|
-
@type {import("./query.js").default<
|
|
32
|
+
@type {import("./query.js").default<import("./base.js").FrontendModelClass>} */ (queryOrSpec)
|
|
33
33
|
: modelClass.preload(/**
|
|
34
34
|
* Narrows the runtime value to the documented type.
|
|
35
35
|
@type {?} */ (queryOrSpec))
|
|
@@ -85,10 +85,10 @@ export default class FrontendModelPreloader {
|
|
|
85
85
|
/**
|
|
86
86
|
* Runs model needs reload.
|
|
87
87
|
* @param {object} args - Options object.
|
|
88
|
-
* @param {
|
|
88
|
+
* @param {import("./base.js").FrontendModelClass} args.modelClass - Model class the preload graph is rooted at.
|
|
89
89
|
* @param {import("./base.js").default} args.model - Model instance.
|
|
90
90
|
* @param {import("../database/query/index.js").NestedPreloadRecord} args.preload - Preload sub-graph to satisfy.
|
|
91
|
-
* @param {import("./query.js").default<
|
|
91
|
+
* @param {import("./query.js").default<import("./base.js").FrontendModelClass>} args.query - Source query carrying select/selectsExtra.
|
|
92
92
|
* @param {boolean} args.force - Whether to reload regardless of cached state.
|
|
93
93
|
* @returns {boolean} - Whether the model needs a reload request.
|
|
94
94
|
*/
|
|
@@ -110,11 +110,11 @@ export default class FrontendModelPreloader {
|
|
|
110
110
|
* client-unknown default attributes plus the extras), so it always reloads.
|
|
111
111
|
* With no select and no nested preload, being preloaded is enough.
|
|
112
112
|
* @param {object} args - Options object.
|
|
113
|
-
* @param {
|
|
113
|
+
* @param {import("./base.js").FrontendModelClass} args.modelClass - Model class owning the relationship.
|
|
114
114
|
* @param {import("./base.js").default} args.model - Model instance.
|
|
115
115
|
* @param {string} args.relationshipName - Relationship name.
|
|
116
116
|
* @param {import("../database/query/index.js").NestedPreloadRecord[string]} args.subPreload - Preload value for this relationship (`true` or a nested record).
|
|
117
|
-
* @param {import("./query.js").default<
|
|
117
|
+
* @param {import("./query.js").default<import("./base.js").FrontendModelClass>} args.query - Source query carrying select/selectsExtra.
|
|
118
118
|
* @returns {boolean} - Whether the relationship is already satisfied.
|
|
119
119
|
*/
|
|
120
120
|
static _relationshipSatisfied({modelClass, model, relationshipName, subPreload, query}) {
|
|
@@ -37,11 +37,11 @@ import isPlainObject from "../utils/plain-object.js"
|
|
|
37
37
|
*/
|
|
38
38
|
/**
|
|
39
39
|
* Defines this typedef.
|
|
40
|
-
* @typedef {FrontendModelProjectionOptions & {query?: FrontendModelQuery<
|
|
40
|
+
* @typedef {FrontendModelProjectionOptions & {query?: FrontendModelQuery<import("./base.js").FrontendModelClass>}} FrontendModelEventOptionsObject
|
|
41
41
|
*/
|
|
42
42
|
/**
|
|
43
43
|
* FrontendModelEventOptions type.
|
|
44
|
-
* @typedef {FrontendModelEventOptionsObject | FrontendModelQuery<
|
|
44
|
+
* @typedef {FrontendModelEventOptionsObject | FrontendModelQuery<import("./base.js").FrontendModelClass>} FrontendModelEventOptions
|
|
45
45
|
*/
|
|
46
46
|
/**
|
|
47
47
|
* FrontendModelProjectionPayload type.
|
|
@@ -955,7 +955,7 @@ export function normalizePluck(pluck) {
|
|
|
955
955
|
|
|
956
956
|
/**
|
|
957
957
|
* Runs frontend model resource attributes.
|
|
958
|
-
* @param {
|
|
958
|
+
* @param {import("./base.js").FrontendModelClass} modelClass - Model class.
|
|
959
959
|
* @returns {Set<string>} - Resource attribute names.
|
|
960
960
|
*/
|
|
961
961
|
function frontendModelResourceAttributes(modelClass) {
|
|
@@ -977,9 +977,9 @@ function frontendModelResourceAttributes(modelClass) {
|
|
|
977
977
|
|
|
978
978
|
/**
|
|
979
979
|
* Runs frontend model pluck target model class.
|
|
980
|
-
* @param {
|
|
980
|
+
* @param {import("./base.js").FrontendModelClass} modelClass - Root model class.
|
|
981
981
|
* @param {string[]} path - Relationship path.
|
|
982
|
-
* @returns {
|
|
982
|
+
* @returns {import("./base.js").FrontendModelClass} - Target model class for path.
|
|
983
983
|
*/
|
|
984
984
|
function frontendModelPluckTargetModelClass(modelClass, path) {
|
|
985
985
|
let targetModelClass = modelClass
|
|
@@ -1011,7 +1011,7 @@ function frontendModelPluckTargetModelClass(modelClass, path) {
|
|
|
1011
1011
|
/**
|
|
1012
1012
|
* Runs validate pluck definitions.
|
|
1013
1013
|
* @param {object} args - Pluck validation args.
|
|
1014
|
-
* @param {
|
|
1014
|
+
* @param {import("./base.js").FrontendModelClass} args.modelClass - Root model class.
|
|
1015
1015
|
* @param {FrontendModelPluck[]} args.pluck - Pluck descriptors.
|
|
1016
1016
|
* @returns {FrontendModelPluck[]} - Validated pluck descriptors.
|
|
1017
1017
|
*/
|
|
@@ -1075,7 +1075,7 @@ function reverseSortDirection(direction) {
|
|
|
1075
1075
|
|
|
1076
1076
|
/**
|
|
1077
1077
|
* Query wrapper for frontend model commands.
|
|
1078
|
-
* @template {
|
|
1078
|
+
* @template {import("./base.js").FrontendModelClass} T
|
|
1079
1079
|
*/
|
|
1080
1080
|
export default class FrontendModelQuery {
|
|
1081
1081
|
/**
|
|
@@ -2145,7 +2145,7 @@ function frontendModelEventFilterKey(payload) {
|
|
|
2145
2145
|
|
|
2146
2146
|
/**
|
|
2147
2147
|
* Runs apply frontend model projection options.
|
|
2148
|
-
* @param {FrontendModelQuery<
|
|
2148
|
+
* @param {FrontendModelQuery<import("./base.js").FrontendModelClass>} query - Query receiving projection options.
|
|
2149
2149
|
* @param {FrontendModelProjectionOptions} options - Projection options.
|
|
2150
2150
|
* @returns {void}
|
|
2151
2151
|
*/
|
|
@@ -2160,8 +2160,8 @@ function applyFrontendModelProjectionOptions(query, options) {
|
|
|
2160
2160
|
|
|
2161
2161
|
/**
|
|
2162
2162
|
* Runs assert frontend model event query class.
|
|
2163
|
-
* @param {
|
|
2164
|
-
* @param {FrontendModelQuery<
|
|
2163
|
+
* @param {import("./base.js").FrontendModelClass} modelClass - Expected frontend model class.
|
|
2164
|
+
* @param {FrontendModelQuery<import("./base.js").FrontendModelClass>} query - Event query.
|
|
2165
2165
|
* @returns {void}
|
|
2166
2166
|
*/
|
|
2167
2167
|
function assertFrontendModelEventQueryClass(modelClass, query) {
|
|
@@ -2183,9 +2183,9 @@ function assertFrontendModelEventOptionsObject(options) {
|
|
|
2183
2183
|
|
|
2184
2184
|
/**
|
|
2185
2185
|
* Runs cloned frontend model event query.
|
|
2186
|
-
* @param {
|
|
2187
|
-
* @param {FrontendModelQuery<
|
|
2188
|
-
* @returns {FrontendModelQuery<
|
|
2186
|
+
* @param {import("./base.js").FrontendModelClass} modelClass - Frontend model class.
|
|
2187
|
+
* @param {FrontendModelQuery<import("./base.js").FrontendModelClass>} query - Event query.
|
|
2188
|
+
* @returns {FrontendModelQuery<import("./base.js").FrontendModelClass>} - Cloned query used by event subscriptions.
|
|
2189
2189
|
*/
|
|
2190
2190
|
function clonedFrontendModelEventQuery(modelClass, query) {
|
|
2191
2191
|
assertFrontendModelEventQueryClass(modelClass, query)
|
|
@@ -2195,9 +2195,9 @@ function clonedFrontendModelEventQuery(modelClass, query) {
|
|
|
2195
2195
|
|
|
2196
2196
|
/**
|
|
2197
2197
|
* Runs frontend model event query from options object.
|
|
2198
|
-
* @param {
|
|
2198
|
+
* @param {import("./base.js").FrontendModelClass} modelClass - Frontend model class.
|
|
2199
2199
|
* @param {FrontendModelEventOptionsObject} options - Event options object.
|
|
2200
|
-
* @returns {FrontendModelQuery<
|
|
2200
|
+
* @returns {FrontendModelQuery<import("./base.js").FrontendModelClass>} - Query used by event subscriptions.
|
|
2201
2201
|
*/
|
|
2202
2202
|
function frontendModelEventQueryFromOptionsObject(modelClass, options) {
|
|
2203
2203
|
if (options.query !== undefined && !(options.query instanceof FrontendModelQuery)) {
|
|
@@ -2215,9 +2215,9 @@ function frontendModelEventQueryFromOptionsObject(modelClass, options) {
|
|
|
2215
2215
|
|
|
2216
2216
|
/**
|
|
2217
2217
|
* Runs frontend model event query.
|
|
2218
|
-
* @param {
|
|
2218
|
+
* @param {import("./base.js").FrontendModelClass} modelClass - Frontend model class.
|
|
2219
2219
|
* @param {FrontendModelEventOptions} [options] - Event query or projection options.
|
|
2220
|
-
* @returns {FrontendModelQuery<
|
|
2220
|
+
* @returns {FrontendModelQuery<import("./base.js").FrontendModelClass>} - Normalized query used by event subscriptions.
|
|
2221
2221
|
*/
|
|
2222
2222
|
function frontendModelEventQuery(modelClass, options = {}) {
|
|
2223
2223
|
if (options instanceof FrontendModelQuery) return clonedFrontendModelEventQuery(modelClass, options)
|
|
@@ -2236,7 +2236,7 @@ function frontendModelEventQuery(modelClass, options = {}) {
|
|
|
2236
2236
|
|
|
2237
2237
|
/**
|
|
2238
2238
|
* Runs the frontendModelEventOptionsPayload helper.
|
|
2239
|
-
* @param {
|
|
2239
|
+
* @param {import("./base.js").FrontendModelClass} modelClass - Frontend model class.
|
|
2240
2240
|
* @param {FrontendModelEventOptions} [options] - Event query or projection options.
|
|
2241
2241
|
* @returns {FrontendModelEventOptionsPayload} - Normalized event subscription payload.
|
|
2242
2242
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import useModelClassEvent from "./use-model-class-event.js"
|
|
4
4
|
|
|
5
|
-
/** @typedef {
|
|
5
|
+
/** @typedef {import("./base.js").FrontendModelClass} FrontendModelClass */
|
|
6
6
|
/** @typedef {import("./use-model-class-event.js").FrontendModelCreateUpdateEventPayload} FrontendModelCreateEventPayload */
|
|
7
7
|
/** @typedef {import("./use-model-class-event.js").UseModelClassEventOptions} UseCreatedEventOptions */
|
|
8
8
|
/** @typedef {(payload: FrontendModelCreateEventPayload) => void} FrontendModelCreateEventCallback */
|
|
@@ -9,7 +9,7 @@ import useModelClassEvent from "./use-model-class-event.js"
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* FrontendModelClass type.
|
|
12
|
-
@typedef {
|
|
12
|
+
@typedef {import("./base.js").FrontendModelClass} FrontendModelClass */
|
|
13
13
|
/**
|
|
14
14
|
* FrontendModelInstance type.
|
|
15
15
|
@typedef {import("./base.js").default} FrontendModelInstance */
|
|
@@ -7,7 +7,7 @@ import clearPendingDebouncedCallback from "./clear-pending-debounced-callback.js
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* FrontendModelClass type.
|
|
10
|
-
@typedef {
|
|
10
|
+
@typedef {import("./base.js").FrontendModelClass} FrontendModelClass */
|
|
11
11
|
/**
|
|
12
12
|
* FrontendModelInstance type.
|
|
13
13
|
@typedef {InstanceType<FrontendModelClass>} FrontendModelInstance */
|
|
@@ -9,7 +9,7 @@ import useModelClassEvent from "./use-model-class-event.js"
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* FrontendModelClass type.
|
|
12
|
-
@typedef {
|
|
12
|
+
@typedef {import("./base.js").FrontendModelClass} FrontendModelClass */
|
|
13
13
|
/**
|
|
14
14
|
* FrontendModelInstance type.
|
|
15
15
|
@typedef {import("./base.js").default} FrontendModelInstance */
|
|
@@ -61,7 +61,11 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
|
|
|
61
61
|
if (!ModelClass) return false
|
|
62
62
|
|
|
63
63
|
const ability = await configuration.resolveAbility?.({
|
|
64
|
-
params
|
|
64
|
+
// Forward the subscriber's params (e.g. authenticationToken) so token-authenticated clients
|
|
65
|
+
// resolve the same ability they would over HTTP. Without this only session/cookie auth on the
|
|
66
|
+
// upgrade request works, and param-based auth (like a scanner passing an authenticationToken)
|
|
67
|
+
// is dropped — leaving such subscribers with a guest ability and no read rule.
|
|
68
|
+
params: {...this.params, model: modelName},
|
|
65
69
|
request: /**
|
|
66
70
|
* Narrows the runtime value to the documented type.
|
|
67
71
|
@type {import("../http-server/client/request.js").default} */ (this._syntheticRequest()),
|
|
@@ -116,6 +120,15 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
|
|
|
116
120
|
const hasEventFilters = this._hasEventFilterParams()
|
|
117
121
|
|
|
118
122
|
if (!this._hasProjectionParams() && !hasEventFilters) {
|
|
123
|
+
// Even unfiltered subscriptions must respect the subscriber's ability. A create/update carries
|
|
124
|
+
// the record, so only deliver it when the record is within the authenticated ability's scope.
|
|
125
|
+
// Destroys (and bodies without a usable id) carry no record, so pass them through unchanged.
|
|
126
|
+
if (body && typeof body === "object" && (body.action === "create" || body.action === "update") && body.id !== undefined && body.id !== null) {
|
|
127
|
+
const FrontendModelController = await this._frontendModelControllerClass()
|
|
128
|
+
|
|
129
|
+
if (!await this._eventIsAccessible(body.id, FrontendModelController)) return
|
|
130
|
+
}
|
|
131
|
+
|
|
119
132
|
this.sendMessage(body, meta)
|
|
120
133
|
return
|
|
121
134
|
}
|
|
@@ -343,6 +356,25 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
|
|
|
343
356
|
return controller
|
|
344
357
|
}
|
|
345
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Whether the broadcast record is within the subscriber's authenticated ability scope. Used to gate
|
|
361
|
+
* unfiltered/unprojected create/update delivery so a scoped token never receives a record it cannot read.
|
|
362
|
+
* @param {string | number} id - Event record id.
|
|
363
|
+
* @param {typeof import("../frontend-model-controller.js").default} FrontendModelController - Server-side frontend-model controller class.
|
|
364
|
+
* @returns {Promise<boolean>} True when the record is readable by this subscription.
|
|
365
|
+
*/
|
|
366
|
+
async _eventIsAccessible(id, FrontendModelController) {
|
|
367
|
+
const controller = this._frontendModelController(FrontendModelController)
|
|
368
|
+
|
|
369
|
+
await controller.ensureFrontendModelClassInitialized()
|
|
370
|
+
|
|
371
|
+
const ModelClass = controller.frontendModelClass()
|
|
372
|
+
const primaryKey = ModelClass.primaryKey()
|
|
373
|
+
const query = controller.frontendModelAuthorizedQuery("find").where({[ModelClass.tableName()]: {[primaryKey]: id}})
|
|
374
|
+
|
|
375
|
+
return Boolean(await query.first())
|
|
376
|
+
}
|
|
377
|
+
|
|
346
378
|
/**
|
|
347
379
|
* Runs matched event filter keys for event id.
|
|
348
380
|
* @param {string | number} id - Event record id.
|
|
@@ -389,7 +421,9 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
|
|
|
389
421
|
const primaryKey = ModelClass.primaryKey()
|
|
390
422
|
const where = controller.frontendModelWhere()
|
|
391
423
|
const joins = controller.frontendModelJoins()
|
|
392
|
-
|
|
424
|
+
// Start from the subscriber's authorized scope so a filter can only ever match records the
|
|
425
|
+
// subscription's ability permits to read.
|
|
426
|
+
let query = controller.frontendModelAuthorizedQuery("find").where({[ModelClass.tableName()]: {[primaryKey]: id}})
|
|
393
427
|
|
|
394
428
|
if (where) controller.applyFrontendModelWhere({query, where})
|
|
395
429
|
if (joins) controller.applyFrontendModelJoins({joins, query})
|
|
@@ -414,7 +448,9 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
|
|
|
414
448
|
|
|
415
449
|
const ModelClass = controller.frontendModelClass()
|
|
416
450
|
const primaryKey = ModelClass.primaryKey()
|
|
417
|
-
|
|
451
|
+
// Reload through the subscriber's authorized scope so projected records are only ever sent for
|
|
452
|
+
// rows the subscription's ability permits to read.
|
|
453
|
+
let query = controller.frontendModelAuthorizedQuery("find").where({[ModelClass.tableName()]: {[primaryKey]: id}})
|
|
418
454
|
const preload = controller.frontendModelPreload()
|
|
419
455
|
|
|
420
456
|
if (preload) query = query.preload(preload)
|
package/src/routes/resolver.js
CHANGED
|
@@ -120,9 +120,9 @@ export default class VelociousRoutesResolver {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
const routeResolverHookMatch = await this.resolveRouteResolverHooks(currentPath, {hasMatchingCustomRoute})
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
let skipControllerConnections = routeResolverHookMatch?.skipControllerConnections === true
|
|
124
|
+
let skipAbilityResolution = routeResolverHookMatch?.skipAbilityResolution === true
|
|
125
|
+
let skipTenantResolution = routeResolverHookMatch?.skipTenantResolution === true
|
|
126
126
|
const matchResult = routeResolverHookMatch || !currentRoute ? undefined : this.matchPathWithRoutes(currentRoute, currentPath)
|
|
127
127
|
const actionParam = this.params.action
|
|
128
128
|
const controllerParam = this.params.controller
|
|
@@ -151,21 +151,24 @@ export default class VelociousRoutesResolver {
|
|
|
151
151
|
viewPath = routeHookViewPath || `${this.configuration.getDirectory()}/src/routes/${controller}`
|
|
152
152
|
this.routeHookControllerClass = routeHookControllerClass
|
|
153
153
|
} else if (!matchResult) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
155
|
+
const __dirname = dirname(__filename)
|
|
156
|
+
const requestedPath = currentPath.replace(/^\//, "") || "_root"
|
|
157
|
+
const attemptedControllerPath = `${this.configuration.getDirectory()}/src/routes/${requestedPath}/controller.js`
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
const logger = this.logger
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
if (!logger) throw new Error("Logger not initialized")
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
await logger.warn(`No route matched for ${rawPath}. Tried controller at ${attemptedControllerPath}`)
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
controller = "errors"
|
|
166
|
+
controllerPath = "./built-in/errors/controller.js"
|
|
167
|
+
action = "notFound"
|
|
168
|
+
skipAbilityResolution = true
|
|
169
|
+
skipControllerConnections = true
|
|
170
|
+
skipTenantResolution = true
|
|
171
|
+
viewPath = await fs.realpath(`${__dirname}/built-in/errors`)
|
|
169
172
|
} else if (action) {
|
|
170
173
|
if (!controller) controller = "_root"
|
|
171
174
|
|
package/src/utils/model-scope.js
CHANGED
|
@@ -7,7 +7,7 @@ const MODEL_SCOPE_DESCRIPTOR_MARKER = "velociousModelScopeDescriptor"
|
|
|
7
7
|
* @typedef {object} ModelScopeDescriptor
|
|
8
8
|
* @property {true} [velociousModelScopeDescriptor] - Internal marker.
|
|
9
9
|
* @property {(...args: Array<?>) => ?} callback - Scope callback.
|
|
10
|
-
* @property {typeof import("../database/record/index.js").default |
|
|
10
|
+
* @property {typeof import("../database/record/index.js").default | import("../frontend-models/base.js").FrontendModelClass} modelClass - Owning model class.
|
|
11
11
|
* @property {Array<?>} scopeArgs - Scope arguments.
|
|
12
12
|
*/
|
|
13
13
|
|
|
@@ -15,7 +15,7 @@ const MODEL_SCOPE_DESCRIPTOR_MARKER = "velociousModelScopeDescriptor"
|
|
|
15
15
|
* Runs the defineModelScope helper.
|
|
16
16
|
* @param {object} args - Definition arguments.
|
|
17
17
|
* @param {(...args: Array<?>) => ?} args.callback - Scope callback.
|
|
18
|
-
* @param {typeof import("../database/record/index.js").default |
|
|
18
|
+
* @param {typeof import("../database/record/index.js").default | import("../frontend-models/base.js").FrontendModelClass} args.modelClass - Owning model class.
|
|
19
19
|
* @param {() => ?} args.startQuery - Factory that returns a fresh query for the owning model class.
|
|
20
20
|
* @returns {((...args: Array<?>) => ?) & {scope: (...args: Array<?>) => ModelScopeDescriptor}} - Scope helper.
|
|
21
21
|
*/
|
package/src/utils/ransack.js
CHANGED
|
@@ -16,7 +16,7 @@ import {resolveFrontendModelClass} from "../frontend-models/model-registry.js"
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* RansackModelClass type.
|
|
19
|
-
* @typedef {typeof import("../database/record/index.js").default |
|
|
19
|
+
* @typedef {typeof import("../database/record/index.js").default | import("../frontend-models/base.js").FrontendModelClass} RansackModelClass
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
/**
|