@memberjunction/core 6.2.0-edge.4 → 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 +22 -0
- package/dist/generic/BaseEntitySaveQueue.d.ts.map +1 -1
- package/dist/generic/BaseEntitySaveQueue.js +43 -4
- package/dist/generic/BaseEntitySaveQueue.js.map +1 -1
- package/dist/generic/JSONType-interfaces/IEntityConfiguration.d.ts +18 -0
- package/dist/generic/JSONType-interfaces/IEntityConfiguration.d.ts.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 +82 -14
- package/dist/generic/baseEngine.d.ts.map +1 -1
- package/dist/generic/baseEngine.js +311 -46
- 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 +194 -14
- package/dist/generic/baseEntity.d.ts.map +1 -1
- package/dist/generic/baseEntity.js +638 -218
- package/dist/generic/baseEntity.js.map +1 -1
- package/dist/generic/baseInfo.d.ts +31 -3
- package/dist/generic/baseInfo.d.ts.map +1 -1
- package/dist/generic/baseInfo.js +138 -40
- package/dist/generic/baseInfo.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 +103 -13
- package/dist/generic/databaseProviderBase.d.ts.map +1 -1
- package/dist/generic/databaseProviderBase.js +321 -77
- 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/entityConfiguration.d.ts +8 -2
- package/dist/generic/entityConfiguration.d.ts.map +1 -1
- package/dist/generic/entityConfiguration.js +9 -0
- package/dist/generic/entityConfiguration.js.map +1 -1
- package/dist/generic/entityInfo.d.ts +306 -12
- package/dist/generic/entityInfo.d.ts.map +1 -1
- package/dist/generic/entityInfo.js +894 -92
- 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/infoProviderResolution.d.ts +16 -0
- package/dist/generic/infoProviderResolution.d.ts.map +1 -0
- package/dist/generic/infoProviderResolution.js +17 -0
- package/dist/generic/infoProviderResolution.js.map +1 -0
- package/dist/generic/interfaces.d.ts +39 -2
- package/dist/generic/interfaces.d.ts.map +1 -1
- package/dist/generic/interfaces.js.map +1 -1
- package/dist/generic/localCacheManager.d.ts +318 -51
- package/dist/generic/localCacheManager.d.ts.map +1 -1
- package/dist/generic/localCacheManager.js +675 -109
- 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/mjapiUrl.d.ts +21 -0
- package/dist/generic/mjapiUrl.d.ts.map +1 -0
- package/dist/generic/mjapiUrl.js +25 -0
- package/dist/generic/mjapiUrl.js.map +1 -0
- 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 +370 -57
- package/dist/generic/providerBase.d.ts.map +1 -1
- package/dist/generic/providerBase.js +1085 -284
- package/dist/generic/providerBase.js.map +1 -1
- package/dist/generic/queryInfo.d.ts +23 -9
- package/dist/generic/queryInfo.d.ts.map +1 -1
- package/dist/generic/queryInfo.js +73 -33
- 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/scoring/ReciprocalRankFusion.d.ts.map +1 -1
- package/dist/generic/scoring/ReciprocalRankFusion.js +10 -3
- package/dist/generic/scoring/ReciprocalRankFusion.js.map +1 -1
- package/dist/generic/securityInfo.d.ts +17 -6
- package/dist/generic/securityInfo.d.ts.map +1 -1
- package/dist/generic/securityInfo.js +25 -10
- 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/generic/util.d.ts.map +1 -1
- package/dist/generic/util.js +3 -0
- package/dist/generic/util.js.map +1 -1
- package/dist/generic/wellKnownUserSource.d.ts +3 -2
- package/dist/generic/wellKnownUserSource.d.ts.map +1 -1
- package/dist/generic/wellKnownUserSource.js +18 -9
- package/dist/generic/wellKnownUserSource.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -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
- package/readme.md +29 -4
|
@@ -1,9 +1,10 @@
|
|
|
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
|
-
import
|
|
6
|
+
import { CachedRunViewResult } from "./localCacheManager.js";
|
|
7
|
+
import type { CacheChangedEvent, QueryDefinitionSignature } from "./localCacheManager.js";
|
|
7
8
|
import { ApplicationInfo } from "../generic/applicationInfo.js";
|
|
8
9
|
import { AuditLogTypeInfo, AuthorizationInfo, AuthorizationRoleInfo, RoleInfo, RowLevelSecurityFilterInfo, UserInfo } from "./securityInfo.js";
|
|
9
10
|
import { TransactionGroupBase } from "./transactionGroup.js";
|
|
@@ -14,6 +15,7 @@ import { CompositeKey } from "./compositeKey.js";
|
|
|
14
15
|
import { ExplorerNavigationItem } from "./explorerNavigationItem.js";
|
|
15
16
|
import { RunViewParams } from "../views/runView.js";
|
|
16
17
|
import { DatabasePlatform, PlatformSQL } from "./platformSQL.js";
|
|
18
|
+
import { ContextToken } from "./contextTokens.js";
|
|
17
19
|
/**
|
|
18
20
|
* Creates a new instance of AllMetadata from a simple object.
|
|
19
21
|
* Handles deserialization and proper instantiation of all metadata classes.
|
|
@@ -50,8 +52,28 @@ export interface QueryCacheAuthorization {
|
|
|
50
52
|
categoryPath?: string;
|
|
51
53
|
/** Resolved query name — for log messages when the request was by ID only. */
|
|
52
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[];
|
|
61
|
+
/**
|
|
62
|
+
* Resolved query ID. With `queryName`, the identity the RunQuery fingerprint is built from, so
|
|
63
|
+
* a request by ID, by name, or by both reaches the same slot.
|
|
64
|
+
*/
|
|
65
|
+
queryId?: string;
|
|
66
|
+
/**
|
|
67
|
+
* The definition the provider would execute on a miss. Set by providers that execute queries
|
|
68
|
+
* themselves; a slot written under another definition is then a miss. Undefined where the
|
|
69
|
+
* provider cannot compute one (a client, whose slots the server validates instead).
|
|
70
|
+
*/
|
|
71
|
+
definition?: QueryDefinitionSignature;
|
|
53
72
|
}
|
|
54
73
|
export declare const AllMetadataArrays: ({
|
|
74
|
+
key: string;
|
|
75
|
+
class: typeof EntityInfo;
|
|
76
|
+
} | {
|
|
55
77
|
key: string;
|
|
56
78
|
class: typeof ApplicationInfo;
|
|
57
79
|
} | {
|
|
@@ -60,6 +82,12 @@ export declare const AllMetadataArrays: ({
|
|
|
60
82
|
} | {
|
|
61
83
|
key: string;
|
|
62
84
|
class: typeof AuthorizationRoleInfo;
|
|
85
|
+
} | {
|
|
86
|
+
key: string;
|
|
87
|
+
class: typeof QueryCategoryInfo;
|
|
88
|
+
} | {
|
|
89
|
+
key: string;
|
|
90
|
+
class: typeof QueryInfo;
|
|
63
91
|
} | {
|
|
64
92
|
key: string;
|
|
65
93
|
class: typeof QueryFieldInfo;
|
|
@@ -75,6 +103,9 @@ export declare const AllMetadataArrays: ({
|
|
|
75
103
|
} | {
|
|
76
104
|
key: string;
|
|
77
105
|
class: typeof QueryDependencyInfo;
|
|
106
|
+
} | {
|
|
107
|
+
key: string;
|
|
108
|
+
class: typeof SQLDialectInfo;
|
|
78
109
|
} | {
|
|
79
110
|
key: string;
|
|
80
111
|
class: typeof QuerySQLInfo;
|
|
@@ -99,6 +130,7 @@ export type EntityMetadataRow = BaseMetadataRow & {
|
|
|
99
130
|
EntityRelationships?: unknown[];
|
|
100
131
|
EntitySettings?: unknown[];
|
|
101
132
|
EntityOrganicKeys?: unknown[];
|
|
133
|
+
EntityAlternateBaseViews?: unknown[];
|
|
102
134
|
};
|
|
103
135
|
export type EntityFieldMetadataRow = BaseMetadataRow & {
|
|
104
136
|
ID: string;
|
|
@@ -322,6 +354,25 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
322
354
|
* step no-ops safely.
|
|
323
355
|
*/
|
|
324
356
|
private ensureInflightViewInvalidation;
|
|
357
|
+
/**
|
|
358
|
+
* Drops this provider's in-flight/lingered RunView dedup entries so the next identical
|
|
359
|
+
* RunView goes to the server instead of replaying a result from the last
|
|
360
|
+
* {@link DedupLingerMs}.
|
|
361
|
+
*
|
|
362
|
+
* Saves and deletes made through a `BaseEntity` in this process already invalidate the entries
|
|
363
|
+
* for their entity automatically. Call this after anything that can write on the SERVER
|
|
364
|
+
* without such an event reaching this process — a Remote Operation, an Action, an agent run,
|
|
365
|
+
* any other mutation. {@link RouteOperation} and the GraphQL client's mutation transport call
|
|
366
|
+
* it for you.
|
|
367
|
+
*
|
|
368
|
+
* Dropping an in-flight entry never affects the callers already waiting on it; it only stops
|
|
369
|
+
* later callers from joining (and stops the result from lingering), since that query may have
|
|
370
|
+
* read pre-write data.
|
|
371
|
+
*
|
|
372
|
+
* @param entityNames - entities known to have been written. Only entries touching them are
|
|
373
|
+
* dropped. Omit (or pass an empty list) when the writes are unknown: every entry is dropped.
|
|
374
|
+
*/
|
|
375
|
+
InvalidateRunViewDedupCache(entityNames?: readonly string[]): void;
|
|
325
376
|
/**
|
|
326
377
|
* Drops every in-flight/lingered RunView entry whose params touch the given
|
|
327
378
|
* entity (lowercased name). Called on BaseEntity save/delete/remote-invalidate.
|
|
@@ -357,6 +408,34 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
357
408
|
* so a push can see the metadata rows it has not committed yet (MJ#4836).
|
|
358
409
|
*/
|
|
359
410
|
private _metadataReadsJoinTransaction;
|
|
411
|
+
/**
|
|
412
|
+
* The MJ_Metadata dataset items (code + entity name + row count) as of the last load. The remote
|
|
413
|
+
* timestamps ({@link GetLatestMetadataUpdates}) are keyed by entity name while a dataset
|
|
414
|
+
* read is scoped by item code, so this is the bridge that lets a staleness check be turned
|
|
415
|
+
* into a scoped reload (see {@link PartialRefreshItemCodes}) and lets {@link adoptServerMetadata}
|
|
416
|
+
* verify that the received dataset items' row counts match `_latestRemoteMetadataTimestamps`.
|
|
417
|
+
*/
|
|
418
|
+
private _metadataDatasetItems;
|
|
419
|
+
/**
|
|
420
|
+
* MJ_Metadata item codes that may be reloaded on their own, without rebuilding the rest of
|
|
421
|
+
* the metadata graph: the saved-query family. Those rows are written continuously by agents
|
|
422
|
+
* (a query is persisted per analysis step), and every write moves the timestamps of these
|
|
423
|
+
* items. Before this list existed, each such write cost a FULL reload — every EntityInfo and
|
|
424
|
+
* EntityFieldInfo rebuilt (hundreds of MB on a large schema) to pick up a few QueryInfo rows;
|
|
425
|
+
* on a busy server that was a fresh half-gigabyte graph per refresh window until the process
|
|
426
|
+
* hit its memory guard.
|
|
427
|
+
*
|
|
428
|
+
* Membership rule: an item qualifies only when no OTHER metadata class embeds or memoizes its
|
|
429
|
+
* rows at construction. The query classes reference each other lazily through the provider
|
|
430
|
+
* (`QueryInfo.Fields` filters `QueryFields` on first use), so they can be swapped as a set;
|
|
431
|
+
* entity metadata cannot (EntityInfo owns its fields, permissions and relationships).
|
|
432
|
+
* The family is always reloaded together — see {@link PartialRefreshItemCodes}.
|
|
433
|
+
* Intersected with {@link AllMetadataArrays} so the list is valid for whatever this build knows.
|
|
434
|
+
*/
|
|
435
|
+
static get PartialRefreshMetadataItemCodes(): ReadonlyArray<string>;
|
|
436
|
+
private static readonly _queryFamilyItemCodes;
|
|
437
|
+
/** The synthetic roll-up row {@link GetLatestMetadataUpdates} appends to the per-entity timestamps. */
|
|
438
|
+
private static readonly _allMetadataTypeName;
|
|
360
439
|
/** Debounce timer for {@link scheduleMetadataMemberRefresh}. */
|
|
361
440
|
private _metadataMemberRefreshTimer;
|
|
362
441
|
/**
|
|
@@ -747,6 +826,17 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
747
826
|
* internal execution, post-processing).
|
|
748
827
|
*/
|
|
749
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;
|
|
750
840
|
/**
|
|
751
841
|
* Enqueues a RunViews call for coalescing. Multiple calls arriving within
|
|
752
842
|
* CoalesceWindowMs are merged into a single mega-batch, executed once, and
|
|
@@ -820,6 +910,17 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
820
910
|
* - entities where server caching is disallowed
|
|
821
911
|
*/
|
|
822
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;
|
|
823
924
|
/** True when the entity is a CodeGen materialized-query wrapper (materialized_vw*) whose snapshot is
|
|
824
925
|
* refreshed out-of-band — the same one IsServerCacheAllowedForEntity excludes from the server cache. */
|
|
825
926
|
protected isMaterializedWrapperEntity(param: RunViewParams): boolean;
|
|
@@ -906,8 +1007,9 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
906
1007
|
private clientCacheFingerprint;
|
|
907
1008
|
private _clientFingerprintMemo;
|
|
908
1009
|
/**
|
|
909
|
-
* True when `param.Fields` names EVERY field of the entity — i.e. an explicit list
|
|
910
|
-
* semantically "full width"
|
|
1010
|
+
* True when `param.Fields` names EVERY fetchable field of the entity — i.e. an explicit list
|
|
1011
|
+
* that is semantically "full width" (accounting for binary fields excluded when
|
|
1012
|
+
* `IncludeBinaryFields !== true`). Case-insensitive; order-independent. Returns false on any
|
|
911
1013
|
* uncertainty (unknown entity, missing fields) so the fingerprint falls back to the explicit
|
|
912
1014
|
* list — the safe direction, since misclassifying narrow-as-full would cross-serve shapes.
|
|
913
1015
|
*/
|
|
@@ -1049,6 +1151,13 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1049
1151
|
* the miss path also checked entity read permissions).
|
|
1050
1152
|
*/
|
|
1051
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;
|
|
1052
1161
|
RunQuery(params: RunQueryParams, contextUser?: UserInfo): Promise<RunQueryResult>;
|
|
1053
1162
|
/**
|
|
1054
1163
|
* Executes a query from a `QueryExecutionSpec` — the lower-layer interface-based entry point.
|
|
@@ -1080,6 +1189,12 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1080
1189
|
* @param callerName
|
|
1081
1190
|
*/
|
|
1082
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;
|
|
1083
1198
|
/**
|
|
1084
1199
|
* Result from PreRunView hook containing cache status and optional cached result
|
|
1085
1200
|
*/
|
|
@@ -1125,6 +1240,20 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1125
1240
|
* fingerprint string for every batch item.
|
|
1126
1241
|
*/
|
|
1127
1242
|
fingerprintMap?: Map<number, string>;
|
|
1243
|
+
/**
|
|
1244
|
+
* Pre-resolved local cache entries keyed by client cache fingerprint, populated
|
|
1245
|
+
* during prepareSmartCacheCheckParams so executeSmartCacheCheck can reuse the
|
|
1246
|
+
* already-parsed results for 'current' items without a second IndexedDB read.
|
|
1247
|
+
*/
|
|
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>;
|
|
1128
1257
|
};
|
|
1129
1258
|
/**
|
|
1130
1259
|
* Result from PreRunQuery hook containing cache status and optional cached result
|
|
@@ -1186,7 +1315,7 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1186
1315
|
*/
|
|
1187
1316
|
protected ComputeRunViewRLSWhereClause(params: RunViewParams, contextUser?: UserInfo): string;
|
|
1188
1317
|
/**
|
|
1189
|
-
* The
|
|
1318
|
+
* The field-security cache key for one entity: a canonical list of the fields the user MAY read.
|
|
1190
1319
|
*
|
|
1191
1320
|
* Keyed on the ALLOWED set rather than the denied set for two reasons. Once metadata ships
|
|
1192
1321
|
* to browsers filtered to what a user may see ([#3485](https://github.com/MemberJunction/MJ/issues/3485)),
|
|
@@ -1198,36 +1327,90 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1198
1327
|
* Returns '' when the entity has field security off or the user is denied nothing, so
|
|
1199
1328
|
* unrestricted users keep byte-identical fingerprints and shared slots.
|
|
1200
1329
|
*
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
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}
|
|
1204
1335
|
*/
|
|
1205
|
-
protected ComputeClientFLSAllowedKey(params: RunViewParams): string;
|
|
1336
|
+
protected ComputeClientFLSAllowedKey(params: RunViewParams, contextUser?: UserInfo): string;
|
|
1206
1337
|
/**
|
|
1207
|
-
* The field-security segment for a {@link LocalCacheManager} RunView fingerprint
|
|
1208
|
-
*
|
|
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.
|
|
1209
1340
|
*
|
|
1210
|
-
* **
|
|
1211
|
-
*
|
|
1212
|
-
*
|
|
1213
|
-
*
|
|
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.
|
|
1214
1351
|
*
|
|
1215
|
-
*
|
|
1216
|
-
*
|
|
1217
|
-
*
|
|
1218
|
-
* persisted IndexedDB slot: the currency check compares `maxUpdatedAt` and `rowCount` only,
|
|
1219
|
-
* neither of which notices a column, so the server answers "current" and the browser keeps
|
|
1220
|
-
* showing a column that was just taken away.
|
|
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.
|
|
1221
1355
|
*
|
|
1222
|
-
*
|
|
1223
|
-
*
|
|
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.
|
|
1224
1359
|
*/
|
|
1225
|
-
protected ComputeRunViewFLSFingerprintKey(params: RunViewParams): string
|
|
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}
|
|
1377
|
+
*/
|
|
1378
|
+
ComputeRunViewCacheFingerprint(params: RunViewParams, contextUser?: UserInfo): string;
|
|
1379
|
+
/**
|
|
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.
|
|
1383
|
+
*
|
|
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.
|
|
1388
|
+
*
|
|
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.
|
|
1396
|
+
*
|
|
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
|
|
1405
|
+
*/
|
|
1406
|
+
protected ResolveRequestDeniedReadFields(params: RunViewParams, entity: EntityInfo, user: UserInfo | undefined): Set<string>;
|
|
1407
|
+
private _requestDeniedReadFields;
|
|
1226
1408
|
/**
|
|
1227
1409
|
* The fetch-widening field list for a cache-eligible request: always every entity field.
|
|
1228
|
-
* One slot per (entity, filter, order) serves every caller regardless of
|
|
1229
|
-
* they asked for
|
|
1230
|
-
*
|
|
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}).
|
|
1231
1414
|
*/
|
|
1232
1415
|
protected ComputeRunViewFetchFields(entity: EntityInfo, params?: RunViewParams): string[];
|
|
1233
1416
|
/**
|
|
@@ -1261,28 +1444,44 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1261
1444
|
* @returns Pre-processing result with cache status and optional cached result
|
|
1262
1445
|
*/
|
|
1263
1446
|
/**
|
|
1264
|
-
* Rejects a RunView whose
|
|
1265
|
-
*
|
|
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`.
|
|
1266
1450
|
*
|
|
1267
1451
|
* Output projection alone is security theater. A user denied `Salary` can send
|
|
1268
1452
|
* `ExtraFilter: "Salary > 200000"` or `OrderBy: "Salary DESC"` and reconstruct the values
|
|
1269
1453
|
* from which rows come back and in what order — the column never appears in a result, so
|
|
1270
1454
|
* every output-stripping point reports "secure." Aggregates are the same channel in a purer
|
|
1271
1455
|
* form: `Aggregates: [{expression: 'MIN(Salary)'}]` under a narrow filter returns a denied
|
|
1272
|
-
* field's exact values directly.
|
|
1273
|
-
*
|
|
1274
|
-
* surface (`UserSearchString` is handled by excluding denied fields from the searched set,
|
|
1275
|
-
* 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.
|
|
1276
1458
|
*
|
|
1277
|
-
* Lives at the provider layer
|
|
1278
|
-
*
|
|
1279
|
-
*
|
|
1280
|
-
*
|
|
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.
|
|
1281
1463
|
*
|
|
1282
|
-
* The
|
|
1283
|
-
* see {@link ProviderBase.FieldSecurityDenialMessage}.
|
|
1464
|
+
* The reading of each clause, and the error it raises, is {@link FieldSecuritySQLGate}'s.
|
|
1284
1465
|
*/
|
|
1285
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;
|
|
1286
1485
|
/**
|
|
1287
1486
|
* The single wording for "you cannot use this field," modeled on SQL Server's posture of
|
|
1288
1487
|
* never disclosing whether an object is missing or merely inaccessible.
|
|
@@ -1299,15 +1498,13 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1299
1498
|
/**
|
|
1300
1499
|
* Strips fields the user cannot read from plain-object result rows.
|
|
1301
1500
|
*
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1304
|
-
*
|
|
1305
|
-
*
|
|
1306
|
-
*
|
|
1307
|
-
*
|
|
1308
|
-
*
|
|
1309
|
-
* restricted service account has no business holding: the `simple`-path SELECT-list
|
|
1310
|
-
* 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.
|
|
1311
1508
|
*
|
|
1312
1509
|
* NEVER applied to `entity_object` results. Those become `BaseEntity` instances whose
|
|
1313
1510
|
* fields round-trip through `GenerateSaveSQL`, which iterates ALL `IsSPParameter` fields
|
|
@@ -1319,13 +1516,30 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1319
1516
|
protected ApplyFieldSecurityProjection<T>(rows: T[], params: RunViewParams, contextUser?: UserInfo): T[];
|
|
1320
1517
|
/**
|
|
1321
1518
|
* Row-loop half of {@link ApplyFieldSecurityProjection}, split out so the policy above reads
|
|
1322
|
-
* as policy. Mirrors {@link ProjectRowsToFields}' matching semantics (trim + lowercase)
|
|
1323
|
-
*
|
|
1324
|
-
*
|
|
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.
|
|
1325
1529
|
*
|
|
1326
1530
|
* @param deniedLowercase field names to omit, already lowercased
|
|
1327
1531
|
*/
|
|
1328
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;
|
|
1329
1543
|
/**
|
|
1330
1544
|
* Strips or narrows the `MJ: Record Changes` payload columns a user may not read, using the
|
|
1331
1545
|
* denied set of the entity each row is ABOUT rather than of Record Changes itself.
|
|
@@ -1336,6 +1550,9 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1336
1550
|
* Everything about the per-row denied set, the payload treatment, and the fail-closed decision
|
|
1337
1551
|
* lives in {@link RecordChangeFieldSecurityProjector}; this is only the RunView wiring.
|
|
1338
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
|
+
*
|
|
1339
1556
|
* Runs at all four RunView projection points, matching the main projection: both cache-hit
|
|
1340
1557
|
* paths and both cache-miss paths. The cache-hit path is not optional — it is the exact path
|
|
1341
1558
|
* the original cross-user leak runs through, an unrestricted user warming a full-width slot
|
|
@@ -1371,11 +1588,34 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1371
1588
|
/**
|
|
1372
1589
|
* Pre-processing hook for RunViews (batch).
|
|
1373
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.
|
|
1374
1593
|
* @param params - Array of view parameters
|
|
1375
1594
|
* @param contextUser - Optional user context
|
|
1376
|
-
* @returns Pre-processing result with cache status for each view
|
|
1595
|
+
* @returns Pre-processing result with cache status for each admitted view
|
|
1377
1596
|
*/
|
|
1378
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;
|
|
1379
1619
|
/**
|
|
1380
1620
|
* Prepares smart cache check parameters for RunViews when CacheLocal is enabled.
|
|
1381
1621
|
* Instead of returning cached data immediately, this builds params to send to the server
|
|
@@ -1435,6 +1675,16 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1435
1675
|
* @param contextUser - Optional user context
|
|
1436
1676
|
*/
|
|
1437
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>;
|
|
1438
1688
|
/**
|
|
1439
1689
|
* Runs all registered PreRunView hooks against a single RunViewParams,
|
|
1440
1690
|
* returning the (possibly mutated) params.
|
|
@@ -1665,15 +1915,54 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1665
1915
|
* @returns True if configuration was successful
|
|
1666
1916
|
*/
|
|
1667
1917
|
Config(data: ProviderConfigDataBase, providerToUse?: IMetadataProvider): Promise<boolean>;
|
|
1918
|
+
/**
|
|
1919
|
+
* Reloads this provider's metadata. Single-flight: at most one reload runs at a time, and a
|
|
1920
|
+
* request arriving mid-reload queues exactly one follow-up pass.
|
|
1921
|
+
* @param hardRefresh - re-read the remote timestamps first and bypass every cache layer
|
|
1922
|
+
* @param scopedFirst - try the scoped reload of the saved-query family (see
|
|
1923
|
+
* {@link PartialRefreshMetadataItemCodes}) before the full one. Defaults to true unless
|
|
1924
|
+
* hardRefresh: an explicit Refresh() is always a full reload.
|
|
1925
|
+
*/
|
|
1926
|
+
protected ReloadMetadata(hardRefresh: boolean, providerToUse?: IMetadataProvider, scopedFirst?: boolean): Promise<boolean>;
|
|
1668
1927
|
/**
|
|
1669
1928
|
* Adopts a metadata snapshot just loaded from the server: swaps it in, records that the
|
|
1670
|
-
* 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.
|
|
1671
1931
|
*
|
|
1672
1932
|
* The swap goes through UpdateLocalMetadata — a single property assignment, atomic in
|
|
1673
1933
|
* JavaScript, so readers see the old snapshot until the new one is complete — which keeps
|
|
1674
1934
|
* it consistent with LoadLocalMetadataFromStorage() and lets subclasses override it.
|
|
1675
1935
|
*/
|
|
1676
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;
|
|
1946
|
+
/**
|
|
1947
|
+
* Decides whether the current staleness can be served by a scoped reload of the saved-query
|
|
1948
|
+
* family. Compares local and remote timestamps item by item (the same test as
|
|
1949
|
+
* {@link LocalMetadataObsolete}) and maps each stale entity back to its MJ_Metadata item code.
|
|
1950
|
+
* @returns the family's item codes (the whole family — the query classes are swapped as a set)
|
|
1951
|
+
* when every stale item belongs to it; null when anything else is stale, nothing is, or the
|
|
1952
|
+
* inputs needed to attribute the change are missing — the full reload is then the answer.
|
|
1953
|
+
*/
|
|
1954
|
+
protected PartialRefreshItemCodes(): string[] | null;
|
|
1955
|
+
private static metadataStampChanged;
|
|
1956
|
+
/**
|
|
1957
|
+
* Reloads only the saved-query family of MJ_Metadata and swaps it into the current metadata,
|
|
1958
|
+
* keeping every other array — and every object in them — as is. The dataset definition is
|
|
1959
|
+
* reused verbatim (same columns, where clauses and post-processing): every other item is
|
|
1960
|
+
* requested with a `1=0` filter, so it reads nothing. Always bypasses cache layers — the read
|
|
1961
|
+
* is small, and a cached answer is exactly what a staleness check cannot trust.
|
|
1962
|
+
* @returns true when the scoped reload was applied; false when it does not apply or any part
|
|
1963
|
+
* of it failed — the caller then runs the full reload, so a failure never leaves stale queries.
|
|
1964
|
+
*/
|
|
1965
|
+
protected TryPartialMetadataReload(providerToUse?: IMetadataProvider): Promise<boolean>;
|
|
1677
1966
|
/**
|
|
1678
1967
|
* Background validation for the stale-while-revalidate fast-start pattern.
|
|
1679
1968
|
* Checks if local metadata is still current; if stale, fetches fresh metadata
|
|
@@ -1743,6 +2032,15 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1743
2032
|
* were on the client's global provider): treat Info objects and everything
|
|
1744
2033
|
* they own as read-only; copy before sorting.
|
|
1745
2034
|
*
|
|
2035
|
+
* Owning provider: the shared Info objects deliberately keep the
|
|
2036
|
+
* {@link BaseInfo.OwningProvider} of the provider that built them (the source
|
|
2037
|
+
* global provider); the shell does NOT re-stamp them. Re-stamping a shared
|
|
2038
|
+
* instance would re-point it for every other provider holding it. The sibling
|
|
2039
|
+
* lookups it drives (IS-A children, RLS filters, query fields, ...) therefore
|
|
2040
|
+
* read the source provider's graph — the same immutable graph this shell
|
|
2041
|
+
* points into, so the answers are identical. A provider that needs its own
|
|
2042
|
+
* graph (a different database) must load its own metadata, not adopt a shell.
|
|
2043
|
+
*
|
|
1746
2044
|
* Override precedence: if a subclass overrides BOTH this method and the
|
|
1747
2045
|
* deprecated {@link CloneAllMetadata}, the CloneAllMetadata override wins on
|
|
1748
2046
|
* the fast path (see {@link CopyMetadataFromGlobalProvider}) — the
|
|
@@ -1750,11 +2048,22 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1750
2048
|
* customized adoption through CloneAllMetadata. Remove the CloneAllMetadata
|
|
1751
2049
|
* override to activate a CreateSharedMetadataShell override.
|
|
1752
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
|
+
*/
|
|
1753
2062
|
protected CreateSharedMetadataShell(shared: AllMetadata): AllMetadata;
|
|
1754
2063
|
/**
|
|
1755
2064
|
* Adopts the global provider's metadata for this instance without reloading it
|
|
1756
2065
|
* from the server: shares the (immutable post-Config) metadata arrays by
|
|
1757
|
-
* reference via {@link CreateSharedMetadataShell} and builds this instance's
|
|
2066
|
+
* reference via {@link CreateSharedMetadataShell} and shares or builds this instance's
|
|
1758
2067
|
* entity lookup maps.
|
|
1759
2068
|
*/
|
|
1760
2069
|
protected CopyMetadataFromGlobalProvider(): boolean;
|
|
@@ -1802,7 +2111,7 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1802
2111
|
* metadata post-processing, replacing repeated O(N*M) filter scans.
|
|
1803
2112
|
*/
|
|
1804
2113
|
private groupByNormalizedUUID;
|
|
1805
|
-
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[];
|
|
1806
2115
|
/**
|
|
1807
2116
|
* Gets the configuration data that was provided to the provider.
|
|
1808
2117
|
* @returns The provider configuration including schema filters
|
|
@@ -1982,9 +2291,11 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
1982
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
|
|
1983
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.
|
|
1984
2293
|
* @param entityName the name of the entity to check
|
|
1985
|
-
* @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
|
|
1986
2297
|
*/
|
|
1987
|
-
abstract GetRecordDependencies(entityName: string, CompositeKey: CompositeKey, contextUser?: UserInfo): Promise<RecordDependency[]>;
|
|
2298
|
+
abstract GetRecordDependencies(entityName: string, CompositeKey: CompositeKey, contextUser?: UserInfo | GetRecordDependenciesOptions, options?: GetRecordDependenciesOptions): Promise<RecordDependency[]>;
|
|
1988
2299
|
/**
|
|
1989
2300
|
* Returns a list of record IDs that are possible duplicates of the specified record.
|
|
1990
2301
|
*
|
|
@@ -2196,6 +2507,8 @@ export declare abstract class ProviderBase implements IMetadataProvider, IRunVie
|
|
|
2196
2507
|
protected UpdateLocalMetadata(res: AllMetadata): void;
|
|
2197
2508
|
/**
|
|
2198
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.
|
|
2199
2512
|
* Called automatically from UpdateLocalMetadata().
|
|
2200
2513
|
*/
|
|
2201
2514
|
protected RebuildEntityMaps(): void;
|