@memberjunction/core 6.2.0-edge.5 → 6.2.0-edge.6
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/dist/generic/BaseEntitySaveQueue.d.ts +15 -0
- package/dist/generic/BaseEntitySaveQueue.d.ts.map +1 -1
- package/dist/generic/BaseEntitySaveQueue.js +21 -0
- package/dist/generic/BaseEntitySaveQueue.js.map +1 -1
- package/dist/generic/alternateBaseViews.d.ts +119 -0
- package/dist/generic/alternateBaseViews.d.ts.map +1 -0
- package/dist/generic/alternateBaseViews.js +223 -0
- package/dist/generic/alternateBaseViews.js.map +1 -0
- package/dist/generic/baseEngine.d.ts +53 -9
- package/dist/generic/baseEngine.d.ts.map +1 -1
- package/dist/generic/baseEngine.js +194 -35
- package/dist/generic/baseEngine.js.map +1 -1
- package/dist/generic/baseEngineRegistry.d.ts.map +1 -1
- package/dist/generic/baseEngineRegistry.js +2 -1
- package/dist/generic/baseEngineRegistry.js.map +1 -1
- package/dist/generic/baseEntity.d.ts +153 -17
- package/dist/generic/baseEntity.d.ts.map +1 -1
- package/dist/generic/baseEntity.js +345 -46
- package/dist/generic/baseEntity.js.map +1 -1
- package/dist/generic/contextTokens.d.ts +136 -0
- package/dist/generic/contextTokens.d.ts.map +1 -0
- package/dist/generic/contextTokens.js +319 -0
- package/dist/generic/contextTokens.js.map +1 -0
- package/dist/generic/databaseProviderBase.d.ts +66 -5
- package/dist/generic/databaseProviderBase.d.ts.map +1 -1
- package/dist/generic/databaseProviderBase.js +159 -12
- package/dist/generic/databaseProviderBase.js.map +1 -1
- package/dist/generic/embeddedRecord.d.ts +6 -0
- package/dist/generic/embeddedRecord.d.ts.map +1 -1
- package/dist/generic/embeddedRecord.js +15 -1
- package/dist/generic/embeddedRecord.js.map +1 -1
- package/dist/generic/entityCompanion.d.ts +7 -0
- package/dist/generic/entityCompanion.d.ts.map +1 -1
- package/dist/generic/entityCompanion.js +8 -0
- package/dist/generic/entityCompanion.js.map +1 -1
- package/dist/generic/entityInfo.d.ts +228 -9
- package/dist/generic/entityInfo.d.ts.map +1 -1
- package/dist/generic/entityInfo.js +574 -65
- package/dist/generic/entityInfo.js.map +1 -1
- package/dist/generic/entityValueFieldSecurity.d.ts +139 -0
- package/dist/generic/entityValueFieldSecurity.d.ts.map +1 -0
- package/dist/generic/entityValueFieldSecurity.js +250 -0
- package/dist/generic/entityValueFieldSecurity.js.map +1 -0
- package/dist/generic/fieldSecuritySQLGate.d.ts +350 -0
- package/dist/generic/fieldSecuritySQLGate.d.ts.map +1 -0
- package/dist/generic/fieldSecuritySQLGate.js +898 -0
- package/dist/generic/fieldSecuritySQLGate.js.map +1 -0
- package/dist/generic/indexRestrictedFields.d.ts +47 -0
- package/dist/generic/indexRestrictedFields.d.ts.map +1 -0
- package/dist/generic/indexRestrictedFields.js +129 -0
- package/dist/generic/indexRestrictedFields.js.map +1 -0
- package/dist/generic/interfaces.d.ts +14 -1
- package/dist/generic/interfaces.d.ts.map +1 -1
- package/dist/generic/interfaces.js.map +1 -1
- package/dist/generic/localCacheManager.d.ts +80 -11
- package/dist/generic/localCacheManager.d.ts.map +1 -1
- package/dist/generic/localCacheManager.js +209 -38
- package/dist/generic/localCacheManager.js.map +1 -1
- package/dist/generic/logging.d.ts.map +1 -1
- package/dist/generic/logging.js +7 -1
- package/dist/generic/logging.js.map +1 -1
- package/dist/generic/metadata.d.ts +3 -2
- package/dist/generic/metadata.d.ts.map +1 -1
- package/dist/generic/metadata.js +5 -2
- package/dist/generic/metadata.js.map +1 -1
- package/dist/generic/platformSQL.d.ts +54 -0
- package/dist/generic/platformSQL.d.ts.map +1 -1
- package/dist/generic/platformSQL.js +55 -0
- package/dist/generic/platformSQL.js.map +1 -1
- package/dist/generic/providerBase.d.ts +254 -56
- package/dist/generic/providerBase.d.ts.map +1 -1
- package/dist/generic/providerBase.js +698 -195
- package/dist/generic/providerBase.js.map +1 -1
- package/dist/generic/queryInfo.d.ts +13 -0
- package/dist/generic/queryInfo.d.ts.map +1 -1
- package/dist/generic/queryInfo.js +13 -0
- package/dist/generic/queryInfo.js.map +1 -1
- package/dist/generic/queryInfoInterfaces.d.ts +8 -0
- package/dist/generic/queryInfoInterfaces.d.ts.map +1 -1
- package/dist/generic/queryTemplateContext.d.ts +49 -0
- package/dist/generic/queryTemplateContext.d.ts.map +1 -0
- package/dist/generic/queryTemplateContext.js +113 -0
- package/dist/generic/queryTemplateContext.js.map +1 -0
- package/dist/generic/recordChangeFieldSecurity.d.ts.map +1 -1
- package/dist/generic/recordChangeFieldSecurity.js +13 -2
- package/dist/generic/recordChangeFieldSecurity.js.map +1 -1
- package/dist/generic/relatedRecordCollection.d.ts +13 -0
- package/dist/generic/relatedRecordCollection.d.ts.map +1 -1
- package/dist/generic/relatedRecordCollection.js +44 -5
- package/dist/generic/relatedRecordCollection.js.map +1 -1
- package/dist/generic/runQuery.d.ts +42 -0
- package/dist/generic/runQuery.d.ts.map +1 -1
- package/dist/generic/runQuery.js +14 -0
- package/dist/generic/runQuery.js.map +1 -1
- package/dist/generic/runQuerySQLFilterImplementations.d.ts.map +1 -1
- package/dist/generic/runQuerySQLFilterImplementations.js +38 -2
- package/dist/generic/runQuerySQLFilterImplementations.js.map +1 -1
- package/dist/generic/saveEntityGraphOperation.d.ts.map +1 -1
- package/dist/generic/saveEntityGraphOperation.js +3 -0
- package/dist/generic/saveEntityGraphOperation.js.map +1 -1
- package/dist/generic/securityInfo.d.ts +11 -0
- package/dist/generic/securityInfo.d.ts.map +1 -1
- package/dist/generic/securityInfo.js +15 -0
- package/dist/generic/securityInfo.js.map +1 -1
- package/dist/generic/telemetryManager.d.ts +9 -0
- package/dist/generic/telemetryManager.d.ts.map +1 -1
- package/dist/generic/telemetryManager.js +5 -1
- package/dist/generic/telemetryManager.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/views/runView.d.ts +89 -0
- package/dist/views/runView.d.ts.map +1 -1
- package/dist/views/runView.js +36 -0
- package/dist/views/runView.js.map +1 -1
- package/dist/views/viewProperties.d.ts +55 -0
- package/dist/views/viewProperties.d.ts.map +1 -0
- package/dist/views/viewProperties.js +258 -0
- package/dist/views/viewProperties.js.map +1 -0
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BaseEntity, BaseEntityEvent } from "./baseEntity.js";
|
|
2
2
|
import { EntityDependency, EntityDocumentTypeInfo, EntityInfo, RecordDependency, RecordMergeRequest, RecordMergeResult } from "./entityInfo.js";
|
|
3
|
-
import { IMetadataProvider, MetadataSweepResult, ProviderConfigDataBase, MetadataInfo, ILocalStorageProvider, IFileSystemProvider, DatasetResultType, DatasetStatusResultType, DatasetItemFilterType, EntityRecordNameInput, EntityRecordNameResult, ProviderType, PotentialDuplicateRequest, PotentialDuplicateResponse, EntityMergeOptions, AllMetadata, IRunViewProvider, RunViewResult, IRunQueryProvider, RunQueryResult, RunViewWithCacheCheckParams, FullTextSearchParams, FullTextSearchResult, SearchEntityParams, EntitySearchResult, IRemoteOperationProvider, RemoteOpInvokeOptions, RemoteOpResult } from "./interfaces.js";
|
|
3
|
+
import { IMetadataProvider, MetadataSweepResult, ProviderConfigDataBase, MetadataInfo, ILocalStorageProvider, IFileSystemProvider, DatasetResultType, DatasetStatusResultType, DatasetItemFilterType, EntityRecordNameInput, EntityRecordNameResult, ProviderType, PotentialDuplicateRequest, PotentialDuplicateResponse, EntityMergeOptions, GetRecordDependenciesOptions, AllMetadata, IRunViewProvider, RunViewResult, IRunQueryProvider, RunQueryResult, RunViewWithCacheCheckParams, FullTextSearchParams, FullTextSearchResult, SearchEntityParams, EntitySearchResult, IRemoteOperationProvider, RemoteOpInvokeOptions, RemoteOpResult } from "./interfaces.js";
|
|
4
4
|
import { ScoredCandidate } from "./scoring/ReciprocalRankFusion.js";
|
|
5
5
|
import { RunQueryParams } from "./runQuery.js";
|
|
6
6
|
import { CachedRunViewResult } from "./localCacheManager.js";
|
|
@@ -15,6 +15,7 @@ import { CompositeKey } from "./compositeKey.js";
|
|
|
15
15
|
import { ExplorerNavigationItem } from "./explorerNavigationItem.js";
|
|
16
16
|
import { RunViewParams } from "../views/runView.js";
|
|
17
17
|
import { DatabasePlatform, PlatformSQL } from "./platformSQL.js";
|
|
18
|
+
import { ContextToken } from "./contextTokens.js";
|
|
18
19
|
/**
|
|
19
20
|
* Creates a new instance of AllMetadata from a simple object.
|
|
20
21
|
* Handles deserialization and proper instantiation of all metadata classes.
|
|
@@ -51,6 +52,12 @@ export interface QueryCacheAuthorization {
|
|
|
51
52
|
categoryPath?: string;
|
|
52
53
|
/** Resolved query name — for log messages when the request was by ID only. */
|
|
53
54
|
queryName?: string;
|
|
55
|
+
/**
|
|
56
|
+
* The context tokens the resolved query's template reads, with every query it composes
|
|
57
|
+
* (`FindQueryContextTokens`). Their values join the fingerprint, so a result that depends on
|
|
58
|
+
* the user or the date is never served to another user or on another day.
|
|
59
|
+
*/
|
|
60
|
+
contextTokens?: ContextToken[];
|
|
54
61
|
/**
|
|
55
62
|
* Resolved query ID. With `queryName`, the identity the RunQuery fingerprint is built from, so
|
|
56
63
|
* a request by ID, by name, or by both reaches the same slot.
|
|
@@ -123,6 +130,7 @@ export type EntityMetadataRow = BaseMetadataRow & {
|
|
|
123
130
|
EntityRelationships?: unknown[];
|
|
124
131
|
EntitySettings?: unknown[];
|
|
125
132
|
EntityOrganicKeys?: unknown[];
|
|
133
|
+
EntityAlternateBaseViews?: unknown[];
|
|
126
134
|
};
|
|
127
135
|
export type EntityFieldMetadataRow = BaseMetadataRow & {
|
|
128
136
|
ID: string;
|
|
@@ -401,10 +409,11 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
401
409
|
*/
|
|
402
410
|
private _metadataReadsJoinTransaction;
|
|
403
411
|
/**
|
|
404
|
-
* The MJ_Metadata dataset items (code + entity name) as of the last
|
|
412
|
+
* The MJ_Metadata dataset items (code + entity name + row count) as of the last load. The remote
|
|
405
413
|
* timestamps ({@link GetLatestMetadataUpdates}) are keyed by entity name while a dataset
|
|
406
414
|
* read is scoped by item code, so this is the bridge that lets a staleness check be turned
|
|
407
|
-
* into a scoped reload (see {@link PartialRefreshItemCodes})
|
|
415
|
+
* into a scoped reload (see {@link PartialRefreshItemCodes}) and lets {@link adoptServerMetadata}
|
|
416
|
+
* verify that the received dataset items' row counts match `_latestRemoteMetadataTimestamps`.
|
|
408
417
|
*/
|
|
409
418
|
private _metadataDatasetItems;
|
|
410
419
|
/**
|
|
@@ -817,6 +826,17 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
817
826
|
* internal execution, post-processing).
|
|
818
827
|
*/
|
|
819
828
|
private executeRunViewsPipeline;
|
|
829
|
+
/**
|
|
830
|
+
* Puts each refused view's result back at its own index of the caller's batch, with the
|
|
831
|
+
* admitted views' results filling the remaining indexes in order.
|
|
832
|
+
*/
|
|
833
|
+
private static interleaveRefusedResults;
|
|
834
|
+
/**
|
|
835
|
+
* The cache, database and post-processing stages of a RunViews batch, for the views the
|
|
836
|
+
* field-security predicate gate admitted. `params` and every index map in `preResult`
|
|
837
|
+
* describe the same admitted views.
|
|
838
|
+
*/
|
|
839
|
+
private runAdmittedViews;
|
|
820
840
|
/**
|
|
821
841
|
* Enqueues a RunViews call for coalescing. Multiple calls arriving within
|
|
822
842
|
* CoalesceWindowMs are merged into a single mega-batch, executed once, and
|
|
@@ -890,6 +910,17 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
890
910
|
* - entities where server caching is disallowed
|
|
891
911
|
*/
|
|
892
912
|
protected runViewCacheEligible(param: RunViewParams): boolean;
|
|
913
|
+
/**
|
|
914
|
+
* True when the request targets an `AlternateBaseView` (explicitly on `param.AlternateBaseView`
|
|
915
|
+
* or pinned on `param.ViewEntity`) whose `CachePolicy` (or an ancestor's `CachePolicy` in its
|
|
916
|
+
* `ParentID` chain) is `'Bypass'` (`IsBypassCache === true`), when the requested alternate
|
|
917
|
+
* base view does not resolve to a usable view on the entity, or when a saved User View is
|
|
918
|
+
* referenced only by `ViewID`/`ViewName` without a loaded `ViewEntity` (fail-closed: we cannot
|
|
919
|
+
* synchronously inspect `DisplayState.alternateBaseView` until the view is loaded).
|
|
920
|
+
*/
|
|
921
|
+
protected isAlternateBaseViewCacheBypassed(param: RunViewParams): boolean;
|
|
922
|
+
/** True when a run carries view properties (even an empty map): the browser sends it to the server as it is. */
|
|
923
|
+
private static carriesViewProperties;
|
|
893
924
|
/** True when the entity is a CodeGen materialized-query wrapper (materialized_vw*) whose snapshot is
|
|
894
925
|
* refreshed out-of-band — the same one IsServerCacheAllowedForEntity excludes from the server cache. */
|
|
895
926
|
protected isMaterializedWrapperEntity(param: RunViewParams): boolean;
|
|
@@ -1120,6 +1151,13 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1120
1151
|
* the miss path also checked entity read permissions).
|
|
1121
1152
|
*/
|
|
1122
1153
|
protected ResolveQueryCacheAuthorization(params: RunQueryParams, user?: UserInfo): QueryCacheAuthorization;
|
|
1154
|
+
/**
|
|
1155
|
+
* The fingerprint segment for what the server sets on a run: `ServerParameters`, and the
|
|
1156
|
+
* `Context.*` values the query reads, worked out for this user, zone and day. Empty when the
|
|
1157
|
+
* run has neither, so the fingerprint is exactly what it was before either existed.
|
|
1158
|
+
* @returns null when the query reads `Context.Now`: such a result is never reused
|
|
1159
|
+
*/
|
|
1160
|
+
private queryCacheServerSegment;
|
|
1123
1161
|
RunQuery(params: RunQueryParams, contextUser?: UserInfo): Promise<RunQueryResult>;
|
|
1124
1162
|
/**
|
|
1125
1163
|
* Executes a query from a `QueryExecutionSpec` — the lower-layer interface-based entry point.
|
|
@@ -1151,6 +1189,12 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1151
1189
|
* @param callerName
|
|
1152
1190
|
*/
|
|
1153
1191
|
protected EntityStatusCheck(params: RunViewParams, callerName: string, contextUser?: UserInfo): Promise<void>;
|
|
1192
|
+
/**
|
|
1193
|
+
* Emits a `[Deprecated]` warning when a cache-hit RunView served rows for a deprecated
|
|
1194
|
+
* `AlternateBaseView` (or an alternate view whose ancestor in `ParentID` is deprecated).
|
|
1195
|
+
* Cache misses log deprecation once inside `ResolveAlternateBaseView` during execution.
|
|
1196
|
+
*/
|
|
1197
|
+
protected logDeprecatedAlternateBaseViewIfAny(params: RunViewParams, callerName: string): void;
|
|
1154
1198
|
/**
|
|
1155
1199
|
* Result from PreRunView hook containing cache status and optional cached result
|
|
1156
1200
|
*/
|
|
@@ -1202,6 +1246,14 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1202
1246
|
* already-parsed results for 'current' items without a second IndexedDB read.
|
|
1203
1247
|
*/
|
|
1204
1248
|
preResolvedCache?: Map<string, CachedRunViewResult | null>;
|
|
1249
|
+
/**
|
|
1250
|
+
* Views the field-security predicate gate refused, keyed by their index in the caller's
|
|
1251
|
+
* batch, each with its `Success: false` result. Present only when at least one view was
|
|
1252
|
+
* refused. Every other field of this result — the index maps, `cachedResults`,
|
|
1253
|
+
* `uncachedParams`, `smartCacheCheckParams` — then describes the ADMITTED views only,
|
|
1254
|
+
* indexed by their position among them.
|
|
1255
|
+
*/
|
|
1256
|
+
refusedResults?: Map<number, RunViewResult>;
|
|
1205
1257
|
};
|
|
1206
1258
|
/**
|
|
1207
1259
|
* Result from PreRunQuery hook containing cache status and optional cached result
|
|
@@ -1263,7 +1315,7 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1263
1315
|
*/
|
|
1264
1316
|
protected ComputeRunViewRLSWhereClause(params: RunViewParams, contextUser?: UserInfo): string;
|
|
1265
1317
|
/**
|
|
1266
|
-
* The
|
|
1318
|
+
* The field-security cache key for one entity: a canonical list of the fields the user MAY read.
|
|
1267
1319
|
*
|
|
1268
1320
|
* Keyed on the ALLOWED set rather than the denied set for two reasons. Once metadata ships
|
|
1269
1321
|
* to browsers filtered to what a user may see ([#3485](https://github.com/MemberJunction/MJ/issues/3485)),
|
|
@@ -1275,36 +1327,90 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1275
1327
|
* Returns '' when the entity has field security off or the user is denied nothing, so
|
|
1276
1328
|
* unrestricted users keep byte-identical fingerprints and shared slots.
|
|
1277
1329
|
*
|
|
1278
|
-
*
|
|
1279
|
-
*
|
|
1280
|
-
*
|
|
1330
|
+
* Reads the denied set through {@link ResolveRequestDeniedReadFields}, so the key and the
|
|
1331
|
+
* SELECT list a database provider builds for the same request describe the same columns.
|
|
1332
|
+
*
|
|
1333
|
+
* @param params - The request; also the memo the denied set is shared through
|
|
1334
|
+
* @param contextUser - The request's user; defaults to {@link CurrentUser}
|
|
1335
|
+
*/
|
|
1336
|
+
protected ComputeClientFLSAllowedKey(params: RunViewParams, contextUser?: UserInfo): string;
|
|
1337
|
+
/**
|
|
1338
|
+
* The field-security segment for a {@link LocalCacheManager} RunView fingerprint, on both
|
|
1339
|
+
* tiers: the slot a request reads and fills belongs to the user's permission class.
|
|
1340
|
+
*
|
|
1341
|
+
* - **The entity's allowed columns** ({@link ComputeClientFLSAllowedKey}). A database
|
|
1342
|
+
* provider selects only the columns the reader may see, so a restricted reader's fill is
|
|
1343
|
+
* narrower than an unrestricted one's, and the two must never share a slot. A browser
|
|
1344
|
+
* stores rows exactly as the server returned them and never projects on read, so its
|
|
1345
|
+
* slots need the same identity. It also keeps user searches apart: which rows match a
|
|
1346
|
+
* search depends on which columns the reader may search.
|
|
1347
|
+
* - **For a saved view, the user's denials on every entity.** A view's stored clause can
|
|
1348
|
+
* reach other entities (nested view filters), and those clauses are only screened when the
|
|
1349
|
+
* database runs them, on a miss. Keying the slot on the whole denial profile means a hit
|
|
1350
|
+
* is only ever served from a fill by a user whose clauses screen identically.
|
|
1351
|
+
*
|
|
1352
|
+
* Empty for a user denied nothing, so unrestricted users keep byte-identical fingerprints
|
|
1353
|
+
* and share slots. Read-time projection ({@link ApplyFieldSecurityProjection}) still runs on
|
|
1354
|
+
* every hit and miss, as a backstop.
|
|
1355
|
+
*
|
|
1356
|
+
* @param params - The request
|
|
1357
|
+
* @param contextUser - The request's user; defaults to {@link CurrentUser}. On a server
|
|
1358
|
+
* this must be the request's user, never the process user.
|
|
1359
|
+
*/
|
|
1360
|
+
protected ComputeRunViewFLSFingerprintKey(params: RunViewParams, contextUser?: UserInfo): string;
|
|
1361
|
+
/**
|
|
1362
|
+
* Every field `user` may not read, across all entities: one `entityID:field,field` entry per
|
|
1363
|
+
* entity on which the user is denied something, sorted. '' for a user denied nothing.
|
|
1364
|
+
*
|
|
1365
|
+
* @param user - The user whose denials to describe
|
|
1366
|
+
*/
|
|
1367
|
+
protected ComputeFieldSecurityProfileKey(user: UserInfo): string;
|
|
1368
|
+
/**
|
|
1369
|
+
* The fingerprint of the server-cache slot a RunView reads and fills for `contextUser`:
|
|
1370
|
+
* the request, this provider's connection, the user's row-level-security clause and the
|
|
1371
|
+
* user's field-security key. Every server path that reads or writes a RunView slot builds
|
|
1372
|
+
* its fingerprint here, so none of them can leave a segment out — a path that omitted the
|
|
1373
|
+
* user's segments would read or fill another permission class's slot.
|
|
1374
|
+
*
|
|
1375
|
+
* @param params - The request
|
|
1376
|
+
* @param contextUser - The request's user; defaults to {@link CurrentUser}
|
|
1281
1377
|
*/
|
|
1282
|
-
|
|
1378
|
+
ComputeRunViewCacheFingerprint(params: RunViewParams, contextUser?: UserInfo): string;
|
|
1283
1379
|
/**
|
|
1284
|
-
* The field-security
|
|
1285
|
-
*
|
|
1380
|
+
* The field-security key a browser sends with a cached slot's status, and the one a server
|
|
1381
|
+
* compares it with: a hash of {@link ComputeRunViewFLSFingerprintKey}, or '' for a user
|
|
1382
|
+
* denied nothing.
|
|
1286
1383
|
*
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1384
|
+
* The currency check otherwise compares only `maxUpdatedAt` and `rowCount`, and neither
|
|
1385
|
+
* changes when a user loses a column. A browser whose metadata has not refreshed yet keeps
|
|
1386
|
+
* its old slot (same fingerprint) and would be told "current" while still showing the
|
|
1387
|
+
* column; with this key the server sees the mismatch and answers "stale" with fresh rows.
|
|
1291
1388
|
*
|
|
1292
|
-
*
|
|
1293
|
-
*
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
*
|
|
1389
|
+
* @param params - The request
|
|
1390
|
+
* @param contextUser - The request's user; defaults to {@link CurrentUser}
|
|
1391
|
+
*/
|
|
1392
|
+
protected ComputeFieldSecurityCacheStatusKey(params: RunViewParams, contextUser?: UserInfo): string;
|
|
1393
|
+
/**
|
|
1394
|
+
* The fields `user` may not read on `entity` for this one request, resolved once and reused by
|
|
1395
|
+
* everything that asks again for the same request (`params` object), user object and entity.
|
|
1298
1396
|
*
|
|
1299
|
-
*
|
|
1300
|
-
*
|
|
1397
|
+
* The cache key and the SELECT list are built at different moments of a request. Read
|
|
1398
|
+
* independently, a metadata refresh landing between the two would key a slot for one
|
|
1399
|
+
* permission class and fill it with another's columns. Sharing one answer per request rules
|
|
1400
|
+
* that out. Empty when field security does not apply.
|
|
1401
|
+
*
|
|
1402
|
+
* @param params - The request; the memo is keyed on this object
|
|
1403
|
+
* @param entity - The entity being read
|
|
1404
|
+
* @param user - The request's user
|
|
1301
1405
|
*/
|
|
1302
|
-
protected
|
|
1406
|
+
protected ResolveRequestDeniedReadFields(params: RunViewParams, entity: EntityInfo, user: UserInfo | undefined): Set<string>;
|
|
1407
|
+
private _requestDeniedReadFields;
|
|
1303
1408
|
/**
|
|
1304
1409
|
* The fetch-widening field list for a cache-eligible request: always every entity field.
|
|
1305
|
-
* One slot per (entity, filter, order) serves every caller regardless of
|
|
1306
|
-
* they asked for
|
|
1307
|
-
*
|
|
1410
|
+
* One slot per (entity, filter, order, permission class) serves every caller regardless of
|
|
1411
|
+
* the field subset they asked for. Field security is not applied here: a database provider
|
|
1412
|
+
* leaves the user's denied columns out of the SELECT it builds from this list, and the slot
|
|
1413
|
+
* key carries the user's class ({@link ComputeRunViewFLSFingerprintKey}).
|
|
1308
1414
|
*/
|
|
1309
1415
|
protected ComputeRunViewFetchFields(entity: EntityInfo, params?: RunViewParams): string[];
|
|
1310
1416
|
/**
|
|
@@ -1338,28 +1444,44 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1338
1444
|
* @returns Pre-processing result with cache status and optional cached result
|
|
1339
1445
|
*/
|
|
1340
1446
|
/**
|
|
1341
|
-
* Rejects a RunView whose
|
|
1342
|
-
*
|
|
1447
|
+
* Rejects a RunView whose caller-authored SQL reads a field the user cannot read: `ExtraFilter`,
|
|
1448
|
+
* `OrderBy`, `OverrideExcludeFilter`, every `Aggregates[].expression`, and — when the request
|
|
1449
|
+
* carries a loaded `ViewEntity` — that view's stored `WhereClause` and `OrderByClause`.
|
|
1343
1450
|
*
|
|
1344
1451
|
* Output projection alone is security theater. A user denied `Salary` can send
|
|
1345
1452
|
* `ExtraFilter: "Salary > 200000"` or `OrderBy: "Salary DESC"` and reconstruct the values
|
|
1346
1453
|
* from which rows come back and in what order — the column never appears in a result, so
|
|
1347
1454
|
* every output-stripping point reports "secure." Aggregates are the same channel in a purer
|
|
1348
1455
|
* form: `Aggregates: [{expression: 'MIN(Salary)'}]` under a narrow filter returns a denied
|
|
1349
|
-
* field's exact values directly.
|
|
1350
|
-
*
|
|
1351
|
-
* surface (`UserSearchString` is handled by excluding denied fields from the searched set,
|
|
1352
|
-
* not by rejection — see below).
|
|
1456
|
+
* field's exact values directly. `UserSearchString` is handled by excluding denied fields from
|
|
1457
|
+
* the searched set, not by rejection.
|
|
1353
1458
|
*
|
|
1354
|
-
* Lives at the provider layer
|
|
1355
|
-
*
|
|
1356
|
-
*
|
|
1357
|
-
*
|
|
1459
|
+
* Lives at the provider layer because every RunView funnels through here — the batch path,
|
|
1460
|
+
* server-internal agents and actions running under a restricted `contextUser`, and the
|
|
1461
|
+
* resolver alike. A database provider checks the clauses it actually runs a second time, once
|
|
1462
|
+
* a saved view is resolved, so a request that names only a `ViewID` is covered too.
|
|
1358
1463
|
*
|
|
1359
|
-
* The
|
|
1360
|
-
* see {@link ProviderBase.FieldSecurityDenialMessage}.
|
|
1464
|
+
* The reading of each clause, and the error it raises, is {@link FieldSecuritySQLGate}'s.
|
|
1361
1465
|
*/
|
|
1362
1466
|
protected AssertPredicatesRespectFieldSecurity(params: RunViewParams, contextUser?: UserInfo): void;
|
|
1467
|
+
/**
|
|
1468
|
+
* Throws a {@link FieldSecurityError} when any of `clauses` — SQL fragments that run against
|
|
1469
|
+
* `entity`'s view — reads a field `user` cannot read, reads whole rows of an entity the user is
|
|
1470
|
+
* denied fields on, or cannot be read well enough to tell. Non-string and blank entries are
|
|
1471
|
+
* skipped. A no-op, with nothing scanned, for a user denied nothing on any entity.
|
|
1472
|
+
*
|
|
1473
|
+
* The shared entry point for every clause slot a provider runs: RunView parameters, a saved
|
|
1474
|
+
* view's stored clauses, dataset item filters, user-search text spliced as SQL.
|
|
1475
|
+
*/
|
|
1476
|
+
protected AssertClausesRespectFieldSecurityForEntity(entity: EntityInfo, clauses: Iterable<unknown>, user: UserInfo): void;
|
|
1477
|
+
/**
|
|
1478
|
+
* {@link AssertClausesRespectFieldSecurityForEntity} for ORDER BY fragments, which also refuses
|
|
1479
|
+
* a sort by column position for a user denied a field on `entity`
|
|
1480
|
+
* ({@link FieldSecuritySQLGate.FindSortViolation}).
|
|
1481
|
+
*/
|
|
1482
|
+
protected AssertSortRespectsFieldSecurityForEntity(entity: EntityInfo, orderBys: Iterable<unknown>, user: UserInfo): void;
|
|
1483
|
+
/** Throws the field-security error for the first of `fragments` that `find` refuses. */
|
|
1484
|
+
private assertFragmentsAllowed;
|
|
1363
1485
|
/**
|
|
1364
1486
|
* The single wording for "you cannot use this field," modeled on SQL Server's posture of
|
|
1365
1487
|
* never disclosing whether an object is missing or merely inaccessible.
|
|
@@ -1376,15 +1498,13 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1376
1498
|
/**
|
|
1377
1499
|
* Strips fields the user cannot read from plain-object result rows.
|
|
1378
1500
|
*
|
|
1379
|
-
*
|
|
1380
|
-
*
|
|
1381
|
-
*
|
|
1382
|
-
*
|
|
1383
|
-
*
|
|
1384
|
-
*
|
|
1385
|
-
*
|
|
1386
|
-
* restricted service account has no business holding: the `simple`-path SELECT-list
|
|
1387
|
-
* intersection, and `Load()`'s allowed-column SELECT.
|
|
1501
|
+
* The backstop behind slot segmentation: cache slots are keyed by the reader's permission
|
|
1502
|
+
* class ({@link ComputeRunViewFLSFingerprintKey}) and filled with only that class's columns,
|
|
1503
|
+
* and this still runs on BOTH cache hits and cache misses, checking every row. A slot can hold
|
|
1504
|
+
* more than its class may read (an `entity_object` fill selects every column, and a slot keyed
|
|
1505
|
+
* just before a permission change keeps its old width), and this is what keeps such a slot
|
|
1506
|
+
* from reaching a reader. It reads live metadata, so a tightened permission applies here from
|
|
1507
|
+
* the next metadata refresh.
|
|
1388
1508
|
*
|
|
1389
1509
|
* NEVER applied to `entity_object` results. Those become `BaseEntity` instances whose
|
|
1390
1510
|
* fields round-trip through `GenerateSaveSQL`, which iterates ALL `IsSPParameter` fields
|
|
@@ -1396,13 +1516,30 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1396
1516
|
protected ApplyFieldSecurityProjection<T>(rows: T[], params: RunViewParams, contextUser?: UserInfo): T[];
|
|
1397
1517
|
/**
|
|
1398
1518
|
* Row-loop half of {@link ApplyFieldSecurityProjection}, split out so the policy above reads
|
|
1399
|
-
* as policy. Mirrors {@link ProjectRowsToFields}' matching semantics (trim + lowercase)
|
|
1400
|
-
*
|
|
1401
|
-
*
|
|
1519
|
+
* as policy. Mirrors {@link ProjectRowsToFields}' matching semantics (trim + lowercase).
|
|
1520
|
+
*
|
|
1521
|
+
* Every row is checked on its own: rows in one result need not share a shape (a slot can mix
|
|
1522
|
+
* rows written by different paths), so no row stands in for the others. A row carrying no
|
|
1523
|
+
* denied key is kept as is, and when none do the input array itself is returned.
|
|
1524
|
+
*
|
|
1525
|
+
* The per-key work (trim, lowercase, set lookup) is done once per key SHAPE rather than once
|
|
1526
|
+
* per row: rows with the same keys in the same order share one {@link RowProjectionPlan}. A
|
|
1527
|
+
* result is almost always a single shape, so a restricted user's 10k-row result pays for one
|
|
1528
|
+
* row's worth of key matching plus a copy per row.
|
|
1402
1529
|
*
|
|
1403
1530
|
* @param deniedLowercase field names to omit, already lowercased
|
|
1404
1531
|
*/
|
|
1405
1532
|
private static omitFieldsFromRows;
|
|
1533
|
+
/** One row of {@link omitFieldsFromRows}: the row itself when it carries no denied key, else a copy without them. */
|
|
1534
|
+
private static omitFieldsFromRow;
|
|
1535
|
+
/**
|
|
1536
|
+
* The plan for a row with exactly these keys, built on first sight of the shape. The last plan
|
|
1537
|
+
* used is tried first; otherwise plans are found by the joined key list. Either way the plan's
|
|
1538
|
+
* own key list is compared with the row's before it is used, so two different shapes can
|
|
1539
|
+
* never share a plan.
|
|
1540
|
+
*/
|
|
1541
|
+
private static rowProjectionPlanFor;
|
|
1542
|
+
private static sameKeys;
|
|
1406
1543
|
/**
|
|
1407
1544
|
* Strips or narrows the `MJ: Record Changes` payload columns a user may not read, using the
|
|
1408
1545
|
* denied set of the entity each row is ABOUT rather than of Record Changes itself.
|
|
@@ -1413,6 +1550,9 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1413
1550
|
* Everything about the per-row denied set, the payload treatment, and the fail-closed decision
|
|
1414
1551
|
* lives in {@link RecordChangeFieldSecurityProjector}; this is only the RunView wiring.
|
|
1415
1552
|
*
|
|
1553
|
+
* A request whose entity cannot be resolved without I/O (only a `ViewID` or `ViewName`) is
|
|
1554
|
+
* projected too, so a saved view over Record Changes is not a way around it.
|
|
1555
|
+
*
|
|
1416
1556
|
* Runs at all four RunView projection points, matching the main projection: both cache-hit
|
|
1417
1557
|
* paths and both cache-miss paths. The cache-hit path is not optional — it is the exact path
|
|
1418
1558
|
* the original cross-user leak runs through, an unrestricted user warming a full-width slot
|
|
@@ -1448,11 +1588,34 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1448
1588
|
/**
|
|
1449
1589
|
* Pre-processing hook for RunViews (batch).
|
|
1450
1590
|
* Handles telemetry, validation, and cache lookup for multiple views.
|
|
1591
|
+
* A view the field-security predicate gate refuses is left out of every later stage and
|
|
1592
|
+
* reported in `refusedResults`; the cache status describes the admitted views only.
|
|
1451
1593
|
* @param params - Array of view parameters
|
|
1452
1594
|
* @param contextUser - Optional user context
|
|
1453
|
-
* @returns Pre-processing result with cache status for each view
|
|
1595
|
+
* @returns Pre-processing result with cache status for each admitted view
|
|
1454
1596
|
*/
|
|
1455
1597
|
protected PreRunViews(params: RunViewParams[], contextUser?: UserInfo): Promise<typeof this._preRunViewsResultType>;
|
|
1598
|
+
/**
|
|
1599
|
+
* Runs each view's PreRunView hooks, replacing `params[i]` with the hooked params, then the
|
|
1600
|
+
* field-security predicate gate — the same contract as the single-view path, except that a
|
|
1601
|
+
* refusal fails only its own view: it becomes that view's `Success: false` result, carrying
|
|
1602
|
+
* the refusal's ambiguous message, so the views batched with it still run. A batch is often
|
|
1603
|
+
* several independent reads (a dashboard's panels), and one unreadable column in one of them
|
|
1604
|
+
* must not blank the rest; the refusal is still reported, at the refused view's index. Any
|
|
1605
|
+
* other error from the gate is thrown and fails the batch.
|
|
1606
|
+
* @returns The refused views' results keyed by batch index, or `undefined` when none was refused.
|
|
1607
|
+
*/
|
|
1608
|
+
private runBatchHooksAndPredicateGate;
|
|
1609
|
+
/** `error` as a failed view result when it is a field-security refusal; otherwise rethrows it. */
|
|
1610
|
+
protected static fieldSecurityRefusalAsResult<T = unknown>(error: unknown): RunViewResult<T>;
|
|
1611
|
+
/**
|
|
1612
|
+
* The cache stage of PreRunViews for the views the predicate gate admitted. An empty batch
|
|
1613
|
+
* (every view refused) is reported as fully cached, so the pipeline returns without a
|
|
1614
|
+
* database call and still ends the batch's telemetry event.
|
|
1615
|
+
*/
|
|
1616
|
+
private lookUpAdmittedViews;
|
|
1617
|
+
/** The server's trusted-cache lookup for a batch: serves hits, and lists the misses to run. */
|
|
1618
|
+
private lookUpBatchCache;
|
|
1456
1619
|
/**
|
|
1457
1620
|
* Prepares smart cache check parameters for RunViews when CacheLocal is enabled.
|
|
1458
1621
|
* Instead of returning cached data immediately, this builds params to send to the server
|
|
@@ -1512,6 +1675,16 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1512
1675
|
* @param contextUser - Optional user context
|
|
1513
1676
|
*/
|
|
1514
1677
|
protected PostRunViews(results: RunViewResult[], params: RunViewParams[], preResult: typeof this._preRunViewsResultType, contextUser?: UserInfo): Promise<void>;
|
|
1678
|
+
/**
|
|
1679
|
+
* Works out a stored view's property values ({@link RunViewParams.Properties},
|
|
1680
|
+
* {@link RunViewParams.ServerProperties}, and each property's default) before the run's cache
|
|
1681
|
+
* lookup, so the result-cache fingerprint keys on the values the run will actually use. Called
|
|
1682
|
+
* on the run's own params copy, after the PreRunView hooks. Must never throw: a run whose
|
|
1683
|
+
* properties would be refused is left for the provider's run path to refuse with its message.
|
|
1684
|
+
*
|
|
1685
|
+
* Does nothing here. A database provider, which resolves token defaults on the server, overrides it.
|
|
1686
|
+
*/
|
|
1687
|
+
protected PrepareRunViewProperties(_params: RunViewParams, _contextUser?: UserInfo): Promise<void>;
|
|
1515
1688
|
/**
|
|
1516
1689
|
* Runs all registered PreRunView hooks against a single RunViewParams,
|
|
1517
1690
|
* returning the (possibly mutated) params.
|
|
@@ -1753,13 +1926,23 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1753
1926
|
protected ReloadMetadata(hardRefresh: boolean, providerToUse?: IMetadataProvider, scopedFirst?: boolean): Promise<boolean>;
|
|
1754
1927
|
/**
|
|
1755
1928
|
* Adopts a metadata snapshot just loaded from the server: swaps it in, records that the
|
|
1756
|
-
* local copy now matches the server's timestamps
|
|
1929
|
+
* local copy now matches the server's timestamps (verified per item against the received
|
|
1930
|
+
* dataset row counts), and persists it to local storage.
|
|
1757
1931
|
*
|
|
1758
1932
|
* The swap goes through UpdateLocalMetadata — a single property assignment, atomic in
|
|
1759
1933
|
* JavaScript, so readers see the old snapshot until the new one is complete — which keeps
|
|
1760
1934
|
* it consistent with LoadLocalMetadataFromStorage() and lets subclasses override it.
|
|
1761
1935
|
*/
|
|
1762
1936
|
private adoptServerMetadata;
|
|
1937
|
+
/**
|
|
1938
|
+
* Verifies that each item in `_latestRemoteMetadataTimestamps` matches the row count actually
|
|
1939
|
+
* received in the loaded `MJ_Metadata` dataset (or `AllMetadata` collections) before advancing
|
|
1940
|
+
* `_latestLocalMetadataTimestamps`. If any item has a mismatched row count (e.g., because a
|
|
1941
|
+
* server cache slot returned stale rows while the SQL status probe reported newer counts),
|
|
1942
|
+
* logs a warning and preserves the unadvanced local timestamp for that item so the next
|
|
1943
|
+
* staleness check (`LocalMetadataObsolete`) detects the discrepancy and self-heals.
|
|
1944
|
+
*/
|
|
1945
|
+
private reconcileAdoptedMetadataTimestamps;
|
|
1763
1946
|
/**
|
|
1764
1947
|
* Decides whether the current staleness can be served by a scoped reload of the saved-query
|
|
1765
1948
|
* family. Compares local and remote timestamps item by item (the same test as
|
|
@@ -1865,11 +2048,22 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1865
2048
|
* customized adoption through CloneAllMetadata. Remove the CloneAllMetadata
|
|
1866
2049
|
* override to activate a CreateSharedMetadataShell override.
|
|
1867
2050
|
*/
|
|
2051
|
+
/**
|
|
2052
|
+
* Builds this instance's AllMetadata as a zero-copy prototype-delegated shell over
|
|
2053
|
+
* another provider's already-loaded metadata (`Object.create(shared)`), keeping
|
|
2054
|
+
* `CurrentUser` as an own property on the shell instance.
|
|
2055
|
+
*
|
|
2056
|
+
* Why zero-copy prototype delegation is safe: the metadata graph (`AllMetadata` and its
|
|
2057
|
+
* arrays) is treated as immutable after `Config`. Refreshes swap the entire `AllMetadata`
|
|
2058
|
+
* reference via `UpdateLocalMetadata` rather than mutating the previous `AllMetadata`
|
|
2059
|
+
* instance in place, so in-flight shells continue reading a consistent snapshot while
|
|
2060
|
+
* avoiding 19 array shallow-copies on every per-request provider creation.
|
|
2061
|
+
*/
|
|
1868
2062
|
protected CreateSharedMetadataShell(shared: AllMetadata): AllMetadata;
|
|
1869
2063
|
/**
|
|
1870
2064
|
* Adopts the global provider's metadata for this instance without reloading it
|
|
1871
2065
|
* from the server: shares the (immutable post-Config) metadata arrays by
|
|
1872
|
-
* reference via {@link CreateSharedMetadataShell} and builds this instance's
|
|
2066
|
+
* reference via {@link CreateSharedMetadataShell} and shares or builds this instance's
|
|
1873
2067
|
* entity lookup maps.
|
|
1874
2068
|
*/
|
|
1875
2069
|
protected CopyMetadataFromGlobalProvider(): boolean;
|
|
@@ -1917,7 +2111,7 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1917
2111
|
* metadata post-processing, replacing repeated O(N*M) filter scans.
|
|
1918
2112
|
*/
|
|
1919
2113
|
private groupByNormalizedUUID;
|
|
1920
|
-
protected PostProcessEntityMetadata(entities: EntityMetadataRow[], fields: EntityFieldMetadataRow[], fieldValues: EntityFieldValueMetadataRow[], permissions: EntityChildMetadataRow[], relationships: EntityChildMetadataRow[], settings: EntityChildMetadataRow[], organicKeys?: OrganicKeyMetadataRow[], organicKeyRelatedEntities?: OrganicKeyRelatedEntityMetadataRow[], fieldPermissions?: EntityFieldPermissionMetadataRow[]): EntityInfo[];
|
|
2114
|
+
protected PostProcessEntityMetadata(entities: EntityMetadataRow[], fields: EntityFieldMetadataRow[], fieldValues: EntityFieldValueMetadataRow[], permissions: EntityChildMetadataRow[], relationships: EntityChildMetadataRow[], settings: EntityChildMetadataRow[], organicKeys?: OrganicKeyMetadataRow[], organicKeyRelatedEntities?: OrganicKeyRelatedEntityMetadataRow[], fieldPermissions?: EntityFieldPermissionMetadataRow[], alternateBaseViews?: EntityChildMetadataRow[]): EntityInfo[];
|
|
1921
2115
|
/**
|
|
1922
2116
|
* Gets the configuration data that was provided to the provider.
|
|
1923
2117
|
* @returns The provider configuration including schema filters
|
|
@@ -2097,9 +2291,11 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
2097
2291
|
* is within the EntityField table and specifically the RelatedEntity and RelatedEntityField columns. In turn, this method uses that metadata and queries the database to determine the dependencies. To get the list of entity dependencies
|
|
2098
2292
|
* you can use the utility method GetEntityDependencies(), which doesn't check for dependencies on a specific record, but rather gets the metadata in one shot that can be used for dependency checking.
|
|
2099
2293
|
* @param entityName the name of the entity to check
|
|
2100
|
-
* @param
|
|
2294
|
+
* @param CompositeKey the values of the primary key of the record to check
|
|
2295
|
+
* @param contextUser optional user context (or options when called with 3 arguments)
|
|
2296
|
+
* @param options optional filtering options for dependency discovery
|
|
2101
2297
|
*/
|
|
2102
|
-
abstract GetRecordDependencies(entityName: string, CompositeKey: CompositeKey, contextUser?: UserInfo): Promise<RecordDependency[]>;
|
|
2298
|
+
abstract GetRecordDependencies(entityName: string, CompositeKey: CompositeKey, contextUser?: UserInfo | GetRecordDependenciesOptions, options?: GetRecordDependenciesOptions): Promise<RecordDependency[]>;
|
|
2103
2299
|
/**
|
|
2104
2300
|
* Returns a list of record IDs that are possible duplicates of the specified record.
|
|
2105
2301
|
*
|
|
@@ -2311,6 +2507,8 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
2311
2507
|
protected UpdateLocalMetadata(res: AllMetadata): void;
|
|
2312
2508
|
/**
|
|
2313
2509
|
* Rebuilds the O(1) entity lookup Maps from the current AllEntities array.
|
|
2510
|
+
* Allocates fresh Map instances so any per-request provider sharing a previous
|
|
2511
|
+
* snapshot's maps is unaffected by a subsequent refresh.
|
|
2314
2512
|
* Called automatically from UpdateLocalMetadata().
|
|
2315
2513
|
*/
|
|
2316
2514
|
protected RebuildEntityMaps(): void;
|