@salesforce/lds-runtime-aura 1.100.2

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/LICENSE.txt ADDED
@@ -0,0 +1,82 @@
1
+ Terms of Use
2
+
3
+ Copyright 2022 Salesforce, Inc. All rights reserved.
4
+
5
+ These Terms of Use govern the download, installation, and/or use of this
6
+ software provided by Salesforce, Inc. ("Salesforce") (the "Software"), were
7
+ last updated on April 15, 2022, and constitute a legally binding
8
+ agreement between you and Salesforce. If you do not agree to these Terms of
9
+ Use, do not install or use the Software.
10
+
11
+ Salesforce grants you a worldwide, non-exclusive, no-charge, royalty-free
12
+ copyright license to reproduce, prepare derivative works of, publicly
13
+ display, publicly perform, sublicense, and distribute the Software and
14
+ derivative works subject to these Terms. These Terms shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ Subject to the limited rights expressly granted hereunder, Salesforce
18
+ reserves all rights, title, and interest in and to all intellectual
19
+ property subsisting in the Software. No rights are granted to you hereunder
20
+ other than as expressly set forth herein. Users residing in countries on
21
+ the United States Office of Foreign Assets Control sanction list, or which
22
+ are otherwise subject to a US export embargo, may not use the Software.
23
+
24
+ Implementation of the Software may require development work, for which you
25
+ are responsible. The Software may contain bugs, errors and
26
+ incompatibilities and is made available on an AS IS basis without support,
27
+ updates, or service level commitments.
28
+
29
+ Salesforce reserves the right at any time to modify, suspend, or
30
+ discontinue, the Software (or any part thereof) with or without notice. You
31
+ agree that Salesforce shall not be liable to you or to any third party for
32
+ any modification, suspension, or discontinuance.
33
+
34
+ You agree to defend Salesforce against any claim, demand, suit or
35
+ proceeding made or brought against Salesforce by a third party arising out
36
+ of or accruing from (a) your use of the Software, and (b) any application
37
+ you develop with the Software that infringes any copyright, trademark,
38
+ trade secret, trade dress, patent, or other intellectual property right of
39
+ any person or defames any person or violates their rights of publicity or
40
+ privacy (each a "Claim Against Salesforce"), and will indemnify Salesforce
41
+ from any damages, attorney fees, and costs finally awarded against
42
+ Salesforce as a result of, or for any amounts paid by Salesforce under a
43
+ settlement approved by you in writing of, a Claim Against Salesforce,
44
+ provided Salesforce (x) promptly gives you written notice of the Claim
45
+ Against Salesforce, (y) gives you sole control of the defense and
46
+ settlement of the Claim Against Salesforce (except that you may not settle
47
+ any Claim Against Salesforce unless it unconditionally releases Salesforce
48
+ of all liability), and (z) gives you all reasonable assistance, at your
49
+ expense.
50
+
51
+ WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE SOFTWARE IS NOT
52
+ SUPPORTED AND IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
53
+ IMPLIED. IN NO EVENT SHALL SALESFORCE HAVE ANY LIABILITY FOR ANY DAMAGES,
54
+ INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
55
+ PUNITIVE, OR CONSEQUENTIAL DAMAGES, OR DAMAGES BASED ON LOST PROFITS, DATA,
56
+ OR USE, IN CONNECTION WITH THE SOFTWARE, HOWEVER CAUSED AND WHETHER IN
57
+ CONTRACT, TORT, OR UNDER ANY OTHER THEORY OF LIABILITY, WHETHER OR NOT YOU
58
+ HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
59
+
60
+ These Terms of Use shall be governed exclusively by the internal laws of
61
+ the State of California, without regard to its conflicts of laws
62
+ rules. Each party hereby consents to the exclusive jurisdiction of the
63
+ state and federal courts located in San Francisco County, California to
64
+ adjudicate any dispute arising out of or relating to these Terms of Use and
65
+ the download, installation, and/or use of the Software. Except as expressly
66
+ stated herein, these Terms of Use constitute the entire agreement between
67
+ the parties, and supersede all prior and contemporaneous agreements,
68
+ proposals, or representations, written or oral, concerning their subject
69
+ matter. No modification, amendment, or waiver of any provision of these
70
+ Terms of Use shall be effective unless it is by an update to these Terms of
71
+ Use that Salesforce makes available, or is in writing and signed by the
72
+ party against whom the modification, amendment, or waiver is to be
73
+ asserted.
74
+
75
+ Data Privacy: Salesforce may collect, process, and store device,
76
+ system, and other information related to your use of the Software. This
77
+ information includes, but is not limited to, IP address, user metrics, and
78
+ other data ("Usage Data"). Salesforce may use Usage Data for analytics,
79
+ product development, and marketing purposes. You acknowledge that files
80
+ generated in conjunction with the Software may contain sensitive or
81
+ confidential data, and you are solely responsible for anonymizing and
82
+ protecting such data.
@@ -0,0 +1,4 @@
1
+ declare const _default: {
2
+ isOpen: () => boolean;
3
+ };
4
+ export default _default;
@@ -0,0 +1,2 @@
1
+ export default function (): void;
2
+ export declare function instrument(): void;
@@ -0,0 +1 @@
1
+ export declare function clearStorages(): Promise<void>;
@@ -0,0 +1,9 @@
1
+ export declare function setupInstrumentation(): void;
2
+ export declare function LRUCache(): Map<any, any>;
3
+ export declare function incrementCounterMetric(): void;
4
+ export declare function updatePercentileHistogramMetric(): void;
5
+ export declare function instrumentAdapter<_C, _D>(adapter: any, _metadata: any): any;
6
+ export declare function instrumentLuvio(): void;
7
+ export declare function instrumentStoreMethods(): void;
8
+ export declare function setLdsAdaptersUiapiInstrumentation(): void;
9
+ export declare function setLdsNetworkAdapterInstrumentation(): void;
@@ -0,0 +1,2 @@
1
+ export default function (): void;
2
+ export declare function instrument(): void;
@@ -0,0 +1,3 @@
1
+ /// <reference types="jest" />
2
+ declare const astResolver: jest.Mock<any, any>;
3
+ export { astResolver };
@@ -0,0 +1,33 @@
1
+ export declare function counter(): {
2
+ increment(): void;
3
+ decrement(): void;
4
+ getValue(): void;
5
+ reset(): void;
6
+ };
7
+ export declare function gauge(): {
8
+ setValue(): void;
9
+ getValue(): void;
10
+ reset(): void;
11
+ };
12
+ export declare function mark(): void;
13
+ export declare function markStart(): void;
14
+ export declare function markEnd(): void;
15
+ export declare function perfStart(): void;
16
+ export declare function perfEnd(): void;
17
+ export declare function percentileHistogram(): {
18
+ update(): void;
19
+ getValue(): void;
20
+ reset(): void;
21
+ };
22
+ export declare function time(): void;
23
+ export declare function timer(): {
24
+ addDuration(): void;
25
+ getValue(): void;
26
+ time(): void;
27
+ };
28
+ export declare function registerCacheStats(): {
29
+ logHits(): void;
30
+ logMisses(): void;
31
+ };
32
+ export declare function registerPlugin(): void;
33
+ export declare function registerPeriodicLogger(): void;
@@ -0,0 +1,178 @@
1
+ import type { FetchResponse, Luvio, InMemoryStore, Adapter, UnfulfilledSnapshot } from '@luvio/engine';
2
+ import type { AdapterMetadata } from '@salesforce/lds-bindings';
3
+ import { ADAPTER_UNFULFILLED_ERROR } from '@salesforce/lds-bindings';
4
+ import type { CacheStatsLogger, Timer } from 'instrumentation/service';
5
+ export interface AdapterUnfulfilledError {
6
+ [ADAPTER_UNFULFILLED_ERROR]: boolean;
7
+ adapterName: string;
8
+ missingPaths: UnfulfilledSnapshot<any, any>['missingPaths'];
9
+ missingLinks: UnfulfilledSnapshot<any, any>['missingLinks'];
10
+ }
11
+ export declare const APEX_ADAPTER_NAME = "getApex";
12
+ export declare const NORMALIZED_APEX_ADAPTER_NAME: string;
13
+ export declare const REFRESH_APEX_KEY = "refreshApex";
14
+ export declare const REFRESH_UIAPI_KEY = "refreshUiApi";
15
+ export declare const SUPPORTED_KEY = "refreshSupported";
16
+ export declare const UNSUPPORTED_KEY = "refreshUnsupported";
17
+ type refreshApiNames = {
18
+ refreshApex: string;
19
+ refreshUiApi: string;
20
+ };
21
+ export interface LightningInteractionSchema {
22
+ target: string;
23
+ scope: string;
24
+ context: unknown;
25
+ eventSource: string;
26
+ eventType: string;
27
+ attributes: unknown;
28
+ }
29
+ export declare class Instrumentation {
30
+ private adapterUnfulfilledErrorCounters;
31
+ private recordApiNameChangeCounters;
32
+ private refreshAdapterEvents;
33
+ private refreshApiCallEventStats;
34
+ private lastRefreshApiCall;
35
+ private weakEtagZeroEvents;
36
+ private adapterCacheMisses;
37
+ constructor();
38
+ /**
39
+ * Instruments an existing adapter to log argus metrics and cache stats.
40
+ * @param adapter The adapter function.
41
+ * @param metadata The adapter metadata.
42
+ * @param wireConfigKeyFn Optional function to transform wire configs to a unique key.
43
+ * @returns The wrapped adapter.
44
+ */
45
+ instrumentAdapter<C, D>(adapter: Adapter<C, D>, metadata: AdapterMetadata): Adapter<C, D>;
46
+ /**
47
+ * Logs when adapter requests come in. If we have subsequent cache misses on a given config, beyond its TTL then log the duration to metrics.
48
+ * Backed by an LRU Cache implementation to prevent too many record entries from being stored in-memory.
49
+ * @param name The wire adapter name.
50
+ * @param config The config passed into wire adapter.
51
+ * @param ttlMissStats CacheStatsLogger to log misses out of TTL.
52
+ * @param currentCacheMissTimestamp Timestamp for when the request was made.
53
+ * @param ttl TTL for the wire adapter.
54
+ */
55
+ private logAdapterCacheMissOutOfTtlDuration;
56
+ /**
57
+ * Injected to LDS for Luvio specific instrumentation.
58
+ *
59
+ * @param context The transaction context.
60
+ */
61
+ instrumentLuvio(context: unknown): void;
62
+ /**
63
+ * Returns whether or not this is a RefreshAdapterEvent.
64
+ * @param context The transaction context.
65
+ * @returns Whether or not this is a RefreshAdapterEvent.
66
+ */
67
+ private isRefreshAdapterEvent;
68
+ /**
69
+ * Returns whether or not this is an AdapterUnfulfilledError.
70
+ * @param context The transaction context.
71
+ * @returns Whether or not this is an AdapterUnfulfilledError.
72
+ */
73
+ private isAdapterUnfulfilledError;
74
+ /**
75
+ * Specific instrumentation for getRecordNotifyChange.
76
+ * temporary implementation to match existing aura call for now
77
+ *
78
+ * @param uniqueWeakEtags whether weakEtags match or not
79
+ * @param error if dispatchResourceRequest fails for any reason
80
+ */
81
+ notifyChangeNetwork(uniqueWeakEtags: boolean | null, error?: boolean): void;
82
+ /**
83
+ * Parses and aggregates weakETagZero events to be sent in summarized log line.
84
+ * @param context The transaction context.
85
+ */
86
+ aggregateWeakETagEvents(incomingWeakEtagZero: boolean, existingWeakEtagZero: boolean, apiName: string): void;
87
+ /**
88
+ * Aggregates refresh adapter events to be sent in summarized log line.
89
+ * - how many times refreshApex is called
90
+ * - how many times refresh from lightning/uiRecordApi is called
91
+ * - number of supported calls: refreshApex called on apex adapter
92
+ * - number of unsupported calls: refreshApex on non-apex adapter
93
+ * + any use of refresh from uiRecordApi module
94
+ * - count of refresh calls per adapter
95
+ * @param context The refresh adapter event.
96
+ */
97
+ private aggregateRefreshAdapterEvents;
98
+ /**
99
+ * Increments call stat for incoming refresh api call, and sets the name
100
+ * to be used in {@link aggregateRefreshCalls}
101
+ * @param from The name of the refresh function called.
102
+ */
103
+ handleRefreshApiCall(apiName: keyof refreshApiNames): void;
104
+ /**
105
+ * W-7302241
106
+ * Logs refresh call summary stats as a LightningInteraction.
107
+ */
108
+ logRefreshStats(): void;
109
+ /**
110
+ * Resets the stat trackers for refresh call events.
111
+ */
112
+ private resetRefreshStats;
113
+ /**
114
+ * W-7801618
115
+ * Counter for occurrences where the incoming record to be merged has a different apiName.
116
+ * Dynamically generated metric, stored in an {@link RecordApiNameChangeCounters} object.
117
+ *
118
+ * @param context The transaction context.
119
+ *
120
+ * Note: Short-lived metric candidate, remove at the end of 230
121
+ */
122
+ incrementRecordApiNameChangeCount(_incomingApiName: string, existingApiName: string): void;
123
+ /**
124
+ * W-8620679
125
+ * Increment the counter for an UnfulfilledSnapshotError coming from luvio
126
+ *
127
+ * @param context The transaction context.
128
+ */
129
+ private incrementAdapterRequestErrorCount;
130
+ }
131
+ /**
132
+ * Calls instrumentation/service interaction API. Function name and parameters mapped to `o11y`
133
+ * implementation for Log Lines.
134
+ * @param schema Expected shape of the payload (Currently unused)
135
+ * @param payload Content to be logged, shape matches schema
136
+ */
137
+ export declare function log(_schema: any, payload: LightningInteractionSchema): void;
138
+ /**
139
+ * Calls instrumentation/service telemetry timer
140
+ * @param name Name of the metric
141
+ * @param duration number to update backing percentile histogram, negative numbers ignored
142
+ */
143
+ export declare function updateTimerMetric(name: string, duration: number): void;
144
+ export declare function timerMetricAddDuration(timer: Timer, duration: number): void;
145
+ export declare function incrementRequestResponseCount(cb: () => FetchResponse<unknown>): void;
146
+ /**
147
+ * Add a mark to the metrics service.
148
+ *
149
+ * @param name The mark name.
150
+ * @param content The mark content.
151
+ */
152
+ export declare function mark(name: string, content?: any): void;
153
+ /**
154
+ * Create a new instrumentation cache stats and return it.
155
+ *
156
+ * @param name The cache logger name.
157
+ */
158
+ export declare function registerLdsCacheStats(name: string): CacheStatsLogger;
159
+ /**
160
+ * Add or overwrite hooks that require aura implementations
161
+ */
162
+ export declare function setAuraInstrumentationHooks(): void;
163
+ /**
164
+ * Initialize the instrumentation and instrument the LDS instance and the InMemoryStore.
165
+ *
166
+ * @param luvio The Luvio instance to instrument.
167
+ * @param store The InMemoryStore to instrument.
168
+ */
169
+ export declare function setupInstrumentation(luvio: Luvio, store: InMemoryStore): void;
170
+ /**
171
+ * Note: locator.scope is set to 'force_record' in order for the instrumentation gate to work, which will
172
+ * disable all crud operations if it is on.
173
+ * @param eventSource - Source of the logging event.
174
+ * @param attributes - Free form object of attributes to log.
175
+ */
176
+ export declare function logCRUDLightningInteraction(eventSource: string, attributes: object): void;
177
+ export declare const instrumentation: Instrumentation;
178
+ export {};
@@ -0,0 +1,13 @@
1
+ declare const create: {
2
+ (o: object | null): any;
3
+ (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any;
4
+ }, keys: {
5
+ (o: object): string[];
6
+ (o: {}): string[];
7
+ };
8
+ declare const isArray: (arg: any) => arg is any[];
9
+ declare const stringify: {
10
+ (value: any, replacer?: ((this: any, key: string, value: any) => any) | undefined, space?: string | number | undefined): string;
11
+ (value: any, replacer?: (string | number)[] | null | undefined, space?: string | number | undefined): string;
12
+ };
13
+ export { create as ObjectCreate, keys as ObjectKeys, isArray as ArrayIsArray, stringify as JSONStringify, };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Observability / Critical Availability Program (230+)
3
+ *
4
+ * This file is intended to be used as a consolidated place for all definitions, functions,
5
+ * and helpers related to "M1"[1].
6
+ *
7
+ * Below are the R.E.A.D.S. metrics for the Lightning Data Service, defined here[2].
8
+ *
9
+ * [1] https://salesforce.quip.com/NfW9AsbGEaTY
10
+ * [2] https://salesforce.quip.com/1dFvAba1b0eq
11
+ */
12
+ import type { MetricsKey } from 'instrumentation/service';
13
+ export declare const OBSERVABILITY_NAMESPACE = "LIGHTNING.lds.service";
14
+ export declare const ADAPTER_INVOCATION_COUNT_METRIC_NAME = "request";
15
+ export declare const ADAPTER_ERROR_COUNT_METRIC_NAME = "error";
16
+ export declare const NETWORK_ADAPTER_RESPONSE_METRIC_NAME = "network-response";
17
+ /**
18
+ * W-8379680
19
+ * Counter for number of getApex requests.
20
+ */
21
+ export declare const GET_APEX_REQUEST_COUNT: MetricsKey;
22
+ /**
23
+ * W-8379680
24
+ * Counter for number of getApex errors.
25
+ */
26
+ export declare const GET_APEX_ERROR_COUNT: MetricsKey;
27
+ /**
28
+ * W-8828410
29
+ * Counter for the number of UnfulfilledSnapshotErrors the luvio engine has.
30
+ */
31
+ export declare const TOTAL_ADAPTER_ERROR_COUNT: MetricsKey;
32
+ /**
33
+ * W-8828410
34
+ * Counter for the number of invocations made into LDS by a wire adapter.
35
+ */
36
+ export declare const TOTAL_ADAPTER_REQUEST_SUCCESS_COUNT: MetricsKey;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
3
+ * This is needed because insertion order for JSON.stringify(object) affects output:
4
+ * JSON.stringify({a: 1, b: 2})
5
+ * "{"a":1,"b":2}"
6
+ * JSON.stringify({b: 2, a: 1})
7
+ * "{"b":2,"a":1}"
8
+ * Modified from the apex implementation to sort arrays non-destructively.
9
+ * @param data Data to be JSON-stringified.
10
+ * @returns JSON.stringified value with consistent ordering of keys.
11
+ */
12
+ export declare function stableJSONStringify(node: any): string | undefined;
13
+ export declare function isPromise<D>(value: D | Promise<D> | null): value is Promise<D>;
@@ -0,0 +1,682 @@
1
+ /**
2
+ * Copyright (c) 2022, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+
7
+ /* *******************************************************************************************
8
+ * ATTENTION!
9
+ * THIS IS A GENERATED FILE FROM https://github.com/salesforce-experience-platform-emu/lds-lightning-platform
10
+ * If you would like to contribute to LDS, please follow the steps outlined in the git repo.
11
+ * Any changes made to this file in p4 will be automatically overwritten.
12
+ * *******************************************************************************************
13
+ */
14
+ /* proxy-compat-disable */
15
+ import { InMemoryStore, Environment, Luvio, InMemoryStoreQueryEvaluator } from 'force/luvioEngine';
16
+ import ldsTrackedFieldsBehaviorGate from '@salesforce/gate/lds.useNewTrackedFieldBehavior';
17
+ import { instrument, configuration, InMemoryRecordRepresentationQueryEvaluator, UiApiNamespace, RecordRepresentationRepresentationType } from 'force/ldsAdaptersUiapi';
18
+ import { withRegistration, register, setDefaultLuvio } from 'force/ldsEngine';
19
+ import { REFRESH_ADAPTER_EVENT, ADAPTER_UNFULFILLED_ERROR, instrument as instrument$2 } from 'force/ldsBindings';
20
+ import { counter, registerCacheStats, perfStart, perfEnd, registerPeriodicLogger, interaction, mark as mark$1, timer } from 'instrumentation/service';
21
+ import { LRUCache, instrumentAdapter, instrumentLuvio, setupInstrumentation as setupInstrumentation$1, updatePercentileHistogramMetric, incrementCounterMetric, incrementGetRecordNotifyChangeAllowCount, incrementGetRecordNotifyChangeDropCount, incrementNotifyRecordUpdateAvailableAllowCount, incrementNotifyRecordUpdateAvailableDropCount, setLdsAdaptersUiapiInstrumentation, setLdsNetworkAdapterInstrumentation } from 'force/ldsInstrumentation';
22
+ import networkAdapter, { instrument as instrument$1, forceRecordTransactionsDisabled, ldsNetworkAdapterInstrument } from 'force/ldsNetwork';
23
+ import { instrument as instrument$3 } from 'force/adsBridge';
24
+ import { clearStorages } from 'force/ldsStorage';
25
+
26
+ /**
27
+ * Observability / Critical Availability Program (230+)
28
+ *
29
+ * This file is intended to be used as a consolidated place for all definitions, functions,
30
+ * and helpers related to "M1"[1].
31
+ *
32
+ * Below are the R.E.A.D.S. metrics for the Lightning Data Service, defined here[2].
33
+ *
34
+ * [1] https://salesforce.quip.com/NfW9AsbGEaTY
35
+ * [2] https://salesforce.quip.com/1dFvAba1b0eq
36
+ */
37
+ const OBSERVABILITY_NAMESPACE = 'LIGHTNING.lds.service';
38
+ const ADAPTER_INVOCATION_COUNT_METRIC_NAME = 'request';
39
+ const ADAPTER_ERROR_COUNT_METRIC_NAME = 'error';
40
+ const NETWORK_ADAPTER_RESPONSE_METRIC_NAME = 'network-response';
41
+ /**
42
+ * W-8379680
43
+ * Counter for number of getApex requests.
44
+ */
45
+ const GET_APEX_REQUEST_COUNT = {
46
+ get() {
47
+ return {
48
+ owner: OBSERVABILITY_NAMESPACE,
49
+ name: ADAPTER_INVOCATION_COUNT_METRIC_NAME + '.' + NORMALIZED_APEX_ADAPTER_NAME,
50
+ };
51
+ },
52
+ };
53
+ /**
54
+ * W-8828410
55
+ * Counter for the number of UnfulfilledSnapshotErrors the luvio engine has.
56
+ */
57
+ const TOTAL_ADAPTER_ERROR_COUNT = {
58
+ get() {
59
+ return { owner: OBSERVABILITY_NAMESPACE, name: ADAPTER_ERROR_COUNT_METRIC_NAME };
60
+ },
61
+ };
62
+ /**
63
+ * W-8828410
64
+ * Counter for the number of invocations made into LDS by a wire adapter.
65
+ */
66
+ const TOTAL_ADAPTER_REQUEST_SUCCESS_COUNT = {
67
+ get() {
68
+ return { owner: OBSERVABILITY_NAMESPACE, name: ADAPTER_INVOCATION_COUNT_METRIC_NAME };
69
+ },
70
+ };
71
+
72
+ const { create, keys } = Object;
73
+ const { isArray } = Array;
74
+ const { stringify } = JSON;
75
+
76
+ /**
77
+ * A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
78
+ * This is needed because insertion order for JSON.stringify(object) affects output:
79
+ * JSON.stringify({a: 1, b: 2})
80
+ * "{"a":1,"b":2}"
81
+ * JSON.stringify({b: 2, a: 1})
82
+ * "{"b":2,"a":1}"
83
+ * Modified from the apex implementation to sort arrays non-destructively.
84
+ * @param data Data to be JSON-stringified.
85
+ * @returns JSON.stringified value with consistent ordering of keys.
86
+ */
87
+ function stableJSONStringify(node) {
88
+ // This is for Date values.
89
+ if (node && node.toJSON && typeof node.toJSON === 'function') {
90
+ // eslint-disable-next-line no-param-reassign
91
+ node = node.toJSON();
92
+ }
93
+ if (node === undefined) {
94
+ return;
95
+ }
96
+ if (typeof node === 'number') {
97
+ return isFinite(node) ? '' + node : 'null';
98
+ }
99
+ if (typeof node !== 'object') {
100
+ return stringify(node);
101
+ }
102
+ let i;
103
+ let out;
104
+ if (isArray(node)) {
105
+ // copy any array before sorting so we don't mutate the object.
106
+ // eslint-disable-next-line no-param-reassign
107
+ node = node.slice(0).sort();
108
+ out = '[';
109
+ for (i = 0; i < node.length; i++) {
110
+ if (i) {
111
+ out += ',';
112
+ }
113
+ out += stableJSONStringify(node[i]) || 'null';
114
+ }
115
+ return out + ']';
116
+ }
117
+ if (node === null) {
118
+ return 'null';
119
+ }
120
+ const keys$1 = keys(node).sort();
121
+ out = '';
122
+ for (i = 0; i < keys$1.length; i++) {
123
+ const key = keys$1[i];
124
+ const value = stableJSONStringify(node[key]);
125
+ if (!value) {
126
+ continue;
127
+ }
128
+ if (out) {
129
+ out += ',';
130
+ }
131
+ out += stringify(key) + ':' + value;
132
+ }
133
+ return '{' + out + '}';
134
+ }
135
+ function isPromise(value) {
136
+ // check for Thenable due to test frameworks using custom Promise impls
137
+ return value !== null && value.then !== undefined;
138
+ }
139
+
140
+ const APEX_ADAPTER_NAME = 'getApex';
141
+ const NORMALIZED_APEX_ADAPTER_NAME = `Apex.${APEX_ADAPTER_NAME}`;
142
+ const REFRESH_APEX_KEY = 'refreshApex';
143
+ const REFRESH_UIAPI_KEY = 'refreshUiApi';
144
+ const SUPPORTED_KEY = 'refreshSupported';
145
+ const UNSUPPORTED_KEY = 'refreshUnsupported';
146
+ const REFRESH_EVENTSOURCE = 'lds-refresh-summary';
147
+ const REFRESH_EVENTTYPE = 'system';
148
+ const REFRESH_PAYLOAD_TARGET = 'adapters';
149
+ const REFRESH_PAYLOAD_SCOPE = 'lds';
150
+ const INCOMING_WEAKETAG_0_KEY = 'incoming-weaketag-0';
151
+ const EXISTING_WEAKETAG_0_KEY = 'existing-weaketag-0';
152
+ const RECORD_API_NAME_CHANGE_COUNT_METRIC_NAME = 'record-api-name-change-count';
153
+ const NAMESPACE = 'lds';
154
+ const NETWORK_TRANSACTION_NAME = 'lds-network';
155
+ const CACHE_STATS_OUT_OF_TTL_MISS_POSTFIX = 'out-of-ttl-miss';
156
+ // Aggregate Cache Stats and Metrics for all getApex invocations
157
+ const getApexCacheStats = registerLdsCacheStats(NORMALIZED_APEX_ADAPTER_NAME);
158
+ const getApexTtlCacheStats = registerLdsCacheStats(NORMALIZED_APEX_ADAPTER_NAME + ':' + CACHE_STATS_OUT_OF_TTL_MISS_POSTFIX);
159
+ // Observability (READS)
160
+ const getApexRequestCountMetric = counter(GET_APEX_REQUEST_COUNT);
161
+ const totalAdapterRequestSuccessMetric = counter(TOTAL_ADAPTER_REQUEST_SUCCESS_COUNT);
162
+ const totalAdapterErrorMetric = counter(TOTAL_ADAPTER_ERROR_COUNT);
163
+ class Instrumentation {
164
+ constructor() {
165
+ this.adapterUnfulfilledErrorCounters = {};
166
+ this.recordApiNameChangeCounters = {};
167
+ this.refreshAdapterEvents = {};
168
+ this.refreshApiCallEventStats = {
169
+ [REFRESH_APEX_KEY]: 0,
170
+ [REFRESH_UIAPI_KEY]: 0,
171
+ [SUPPORTED_KEY]: 0,
172
+ [UNSUPPORTED_KEY]: 0,
173
+ };
174
+ this.lastRefreshApiCall = null;
175
+ this.weakEtagZeroEvents = {};
176
+ this.adapterCacheMisses = new LRUCache(250);
177
+ if (typeof window !== 'undefined' && window.addEventListener) {
178
+ window.addEventListener('beforeunload', () => {
179
+ if (keys(this.weakEtagZeroEvents).length > 0) {
180
+ perfStart(NETWORK_TRANSACTION_NAME);
181
+ perfEnd(NETWORK_TRANSACTION_NAME, this.weakEtagZeroEvents);
182
+ }
183
+ });
184
+ }
185
+ registerPeriodicLogger(NAMESPACE, this.logRefreshStats.bind(this));
186
+ }
187
+ /**
188
+ * Instruments an existing adapter to log argus metrics and cache stats.
189
+ * @param adapter The adapter function.
190
+ * @param metadata The adapter metadata.
191
+ * @param wireConfigKeyFn Optional function to transform wire configs to a unique key.
192
+ * @returns The wrapped adapter.
193
+ */
194
+ instrumentAdapter(adapter, metadata) {
195
+ // We are consolidating all apex adapter instrumentation calls under a single key
196
+ const { apiFamily, name, ttl } = metadata;
197
+ const adapterName = normalizeAdapterName(name, apiFamily);
198
+ const isGetApexAdapter = isApexAdapter(name);
199
+ const stats = isGetApexAdapter ? getApexCacheStats : registerLdsCacheStats(adapterName);
200
+ const ttlMissStats = isGetApexAdapter
201
+ ? getApexTtlCacheStats
202
+ : registerLdsCacheStats(adapterName + ':' + CACHE_STATS_OUT_OF_TTL_MISS_POSTFIX);
203
+ /**
204
+ * W-8076905
205
+ * Dynamically generated metric. Simple counter for all requests made by this adapter.
206
+ */
207
+ const wireAdapterRequestMetric = isGetApexAdapter
208
+ ? getApexRequestCountMetric
209
+ : counter(createMetricsKey(OBSERVABILITY_NAMESPACE, ADAPTER_INVOCATION_COUNT_METRIC_NAME, adapterName));
210
+ const instrumentedAdapter = (config, requestContext) => {
211
+ // increment overall and adapter request metrics
212
+ wireAdapterRequestMetric.increment(1);
213
+ totalAdapterRequestSuccessMetric.increment(1);
214
+ // execute adapter logic
215
+ const result = adapter(config, requestContext);
216
+ // In the case where the adapter returns a non-Pending Snapshot it is constructed out of the store
217
+ // (cache hit) whereas a Promise<Snapshot> or Pending Snapshot indicates a network request (cache miss).
218
+ //
219
+ // Note: we can't do a plain instanceof check for a promise here since the Promise may
220
+ // originate from another javascript realm (for example: in jest test). Instead we use a
221
+ // duck-typing approach by checking if the result has a then property.
222
+ //
223
+ // For adapters without persistent store:
224
+ // - total cache hit ratio:
225
+ // [in-memory cache hit count] / ([in-memory cache hit count] + [in-memory cache miss count])
226
+ // For adapters with persistent store:
227
+ // - in-memory cache hit ratio:
228
+ // [in-memory cache hit count] / ([in-memory cache hit count] + [in-memory cache miss count])
229
+ // - total cache hit ratio:
230
+ // ([in-memory cache hit count] + [store cache hit count]) / ([in-memory cache hit count] + [in-memory cache miss count])
231
+ // if result === null then config is insufficient/invalid so do not log
232
+ if (isPromise(result)) {
233
+ stats.logMisses();
234
+ if (ttl !== undefined) {
235
+ this.logAdapterCacheMissOutOfTtlDuration(adapterName, config, ttlMissStats, Date.now(), ttl);
236
+ }
237
+ }
238
+ else if (result !== null) {
239
+ stats.logHits();
240
+ }
241
+ return result;
242
+ };
243
+ // Set the name property on the function for debugging purposes.
244
+ Object.defineProperty(instrumentedAdapter, 'name', {
245
+ value: name + '__instrumented',
246
+ });
247
+ return instrumentAdapter(instrumentedAdapter, metadata);
248
+ }
249
+ /**
250
+ * Logs when adapter requests come in. If we have subsequent cache misses on a given config, beyond its TTL then log the duration to metrics.
251
+ * Backed by an LRU Cache implementation to prevent too many record entries from being stored in-memory.
252
+ * @param name The wire adapter name.
253
+ * @param config The config passed into wire adapter.
254
+ * @param ttlMissStats CacheStatsLogger to log misses out of TTL.
255
+ * @param currentCacheMissTimestamp Timestamp for when the request was made.
256
+ * @param ttl TTL for the wire adapter.
257
+ */
258
+ logAdapterCacheMissOutOfTtlDuration(name, config, ttlMissStats, currentCacheMissTimestamp, ttl) {
259
+ const configKey = `${name}:${stableJSONStringify(config)}`;
260
+ const existingCacheMissTimestamp = this.adapterCacheMisses.get(configKey);
261
+ this.adapterCacheMisses.set(configKey, currentCacheMissTimestamp);
262
+ if (existingCacheMissTimestamp !== undefined) {
263
+ const duration = currentCacheMissTimestamp - existingCacheMissTimestamp;
264
+ if (duration > ttl) {
265
+ ttlMissStats.logMisses();
266
+ }
267
+ }
268
+ }
269
+ /**
270
+ * Injected to LDS for Luvio specific instrumentation.
271
+ *
272
+ * @param context The transaction context.
273
+ */
274
+ instrumentLuvio(context) {
275
+ instrumentLuvio(context);
276
+ if (this.isRefreshAdapterEvent(context)) {
277
+ this.aggregateRefreshAdapterEvents(context);
278
+ }
279
+ else if (this.isAdapterUnfulfilledError(context)) {
280
+ this.incrementAdapterRequestErrorCount(context);
281
+ }
282
+ else ;
283
+ }
284
+ /**
285
+ * Returns whether or not this is a RefreshAdapterEvent.
286
+ * @param context The transaction context.
287
+ * @returns Whether or not this is a RefreshAdapterEvent.
288
+ */
289
+ isRefreshAdapterEvent(context) {
290
+ return context[REFRESH_ADAPTER_EVENT] === true;
291
+ }
292
+ /**
293
+ * Returns whether or not this is an AdapterUnfulfilledError.
294
+ * @param context The transaction context.
295
+ * @returns Whether or not this is an AdapterUnfulfilledError.
296
+ */
297
+ isAdapterUnfulfilledError(context) {
298
+ return context[ADAPTER_UNFULFILLED_ERROR] === true;
299
+ }
300
+ /**
301
+ * Specific instrumentation for getRecordNotifyChange.
302
+ * temporary implementation to match existing aura call for now
303
+ *
304
+ * @param uniqueWeakEtags whether weakEtags match or not
305
+ * @param error if dispatchResourceRequest fails for any reason
306
+ */
307
+ notifyChangeNetwork(uniqueWeakEtags, error) {
308
+ perfStart(NETWORK_TRANSACTION_NAME);
309
+ if (error === true) {
310
+ perfEnd(NETWORK_TRANSACTION_NAME, { 'notify-change-network': 'error' });
311
+ }
312
+ else {
313
+ perfEnd(NETWORK_TRANSACTION_NAME, { 'notify-change-network': uniqueWeakEtags });
314
+ }
315
+ }
316
+ /**
317
+ * Parses and aggregates weakETagZero events to be sent in summarized log line.
318
+ * @param context The transaction context.
319
+ */
320
+ aggregateWeakETagEvents(incomingWeakEtagZero, existingWeakEtagZero, apiName) {
321
+ const key = 'weaketag-0-' + apiName;
322
+ if (this.weakEtagZeroEvents[key] === undefined) {
323
+ this.weakEtagZeroEvents[key] = {
324
+ [EXISTING_WEAKETAG_0_KEY]: 0,
325
+ [INCOMING_WEAKETAG_0_KEY]: 0,
326
+ };
327
+ }
328
+ if (existingWeakEtagZero) {
329
+ this.weakEtagZeroEvents[key][EXISTING_WEAKETAG_0_KEY] += 1;
330
+ }
331
+ if (incomingWeakEtagZero) {
332
+ this.weakEtagZeroEvents[key][INCOMING_WEAKETAG_0_KEY] += 1;
333
+ }
334
+ }
335
+ /**
336
+ * Aggregates refresh adapter events to be sent in summarized log line.
337
+ * - how many times refreshApex is called
338
+ * - how many times refresh from lightning/uiRecordApi is called
339
+ * - number of supported calls: refreshApex called on apex adapter
340
+ * - number of unsupported calls: refreshApex on non-apex adapter
341
+ * + any use of refresh from uiRecordApi module
342
+ * - count of refresh calls per adapter
343
+ * @param context The refresh adapter event.
344
+ */
345
+ aggregateRefreshAdapterEvents(context) {
346
+ // We are consolidating all apex adapter instrumentation calls under a single key
347
+ // Adding additional logging that getApex adapters can invoke? Read normalizeAdapterName ts-doc.
348
+ const adapterName = normalizeAdapterName(context.adapterName);
349
+ if (this.lastRefreshApiCall === REFRESH_APEX_KEY) {
350
+ if (isApexAdapter(adapterName)) {
351
+ this.refreshApiCallEventStats[SUPPORTED_KEY] += 1;
352
+ }
353
+ else {
354
+ this.refreshApiCallEventStats[UNSUPPORTED_KEY] += 1;
355
+ }
356
+ }
357
+ else if (this.lastRefreshApiCall === REFRESH_UIAPI_KEY) {
358
+ this.refreshApiCallEventStats[UNSUPPORTED_KEY] += 1;
359
+ }
360
+ if (this.refreshAdapterEvents[adapterName] === undefined) {
361
+ this.refreshAdapterEvents[adapterName] = 0;
362
+ }
363
+ this.refreshAdapterEvents[adapterName] += 1;
364
+ this.lastRefreshApiCall = null;
365
+ }
366
+ /**
367
+ * Increments call stat for incoming refresh api call, and sets the name
368
+ * to be used in {@link aggregateRefreshCalls}
369
+ * @param from The name of the refresh function called.
370
+ */
371
+ handleRefreshApiCall(apiName) {
372
+ this.refreshApiCallEventStats[apiName] += 1;
373
+ // set function call to be used with aggregateRefreshCalls
374
+ this.lastRefreshApiCall = apiName;
375
+ }
376
+ /**
377
+ * W-7302241
378
+ * Logs refresh call summary stats as a LightningInteraction.
379
+ */
380
+ logRefreshStats() {
381
+ if (keys(this.refreshAdapterEvents).length > 0) {
382
+ interaction(REFRESH_PAYLOAD_TARGET, REFRESH_PAYLOAD_SCOPE, this.refreshAdapterEvents, REFRESH_EVENTSOURCE, REFRESH_EVENTTYPE, this.refreshApiCallEventStats);
383
+ this.resetRefreshStats();
384
+ }
385
+ }
386
+ /**
387
+ * Resets the stat trackers for refresh call events.
388
+ */
389
+ resetRefreshStats() {
390
+ this.refreshAdapterEvents = {};
391
+ this.refreshApiCallEventStats = {
392
+ [REFRESH_APEX_KEY]: 0,
393
+ [REFRESH_UIAPI_KEY]: 0,
394
+ [SUPPORTED_KEY]: 0,
395
+ [UNSUPPORTED_KEY]: 0,
396
+ };
397
+ this.lastRefreshApiCall = null;
398
+ }
399
+ /**
400
+ * W-7801618
401
+ * Counter for occurrences where the incoming record to be merged has a different apiName.
402
+ * Dynamically generated metric, stored in an {@link RecordApiNameChangeCounters} object.
403
+ *
404
+ * @param context The transaction context.
405
+ *
406
+ * Note: Short-lived metric candidate, remove at the end of 230
407
+ */
408
+ incrementRecordApiNameChangeCount(_incomingApiName, existingApiName) {
409
+ let apiNameChangeCounter = this.recordApiNameChangeCounters[existingApiName];
410
+ if (apiNameChangeCounter === undefined) {
411
+ apiNameChangeCounter = counter(createMetricsKey(NAMESPACE, RECORD_API_NAME_CHANGE_COUNT_METRIC_NAME, existingApiName));
412
+ this.recordApiNameChangeCounters[existingApiName] = apiNameChangeCounter;
413
+ }
414
+ apiNameChangeCounter.increment(1);
415
+ }
416
+ /**
417
+ * W-8620679
418
+ * Increment the counter for an UnfulfilledSnapshotError coming from luvio
419
+ *
420
+ * @param context The transaction context.
421
+ */
422
+ incrementAdapterRequestErrorCount(context) {
423
+ // We are consolidating all apex adapter instrumentation calls under a single key
424
+ const adapterName = normalizeAdapterName(context.adapterName);
425
+ let adapterRequestErrorCounter = this.adapterUnfulfilledErrorCounters[adapterName];
426
+ if (adapterRequestErrorCounter === undefined) {
427
+ adapterRequestErrorCounter = counter(createMetricsKey(OBSERVABILITY_NAMESPACE, ADAPTER_ERROR_COUNT_METRIC_NAME, adapterName));
428
+ this.adapterUnfulfilledErrorCounters[adapterName] = adapterRequestErrorCounter;
429
+ }
430
+ adapterRequestErrorCounter.increment(1);
431
+ totalAdapterErrorMetric.increment(1);
432
+ }
433
+ }
434
+ function createMetricsKey(owner, name, unit) {
435
+ let metricName = name;
436
+ if (unit) {
437
+ metricName = metricName + '.' + unit;
438
+ }
439
+ return {
440
+ get() {
441
+ return { owner: owner, name: metricName };
442
+ },
443
+ };
444
+ }
445
+ /**
446
+ * Returns whether adapter is an Apex one or not.
447
+ * @param adapterName The name of the adapter.
448
+ */
449
+ function isApexAdapter(adapterName) {
450
+ return adapterName.indexOf(APEX_ADAPTER_NAME) > -1;
451
+ }
452
+ /**
453
+ * Normalizes getApex adapter names to `Apex.getApex`. Non-Apex adapters will be prefixed with
454
+ * API family, if supplied. Example: `UiApi.getRecord`.
455
+ *
456
+ * Note: If you are adding additional logging that can come from getApex adapter contexts that provide
457
+ * the full getApex adapter name (i.e. getApex_[namespace]_[class]_[function]_[continuation]),
458
+ * ensure to call this method to normalize all logging to 'getApex'. This
459
+ * is because Argus has a 50k key cardinality limit. More context: W-8379680.
460
+ *
461
+ * @param adapterName The name of the adapter.
462
+ * @param apiFamily The API family of the adapter.
463
+ */
464
+ function normalizeAdapterName(adapterName, apiFamily) {
465
+ if (isApexAdapter(adapterName)) {
466
+ return NORMALIZED_APEX_ADAPTER_NAME;
467
+ }
468
+ return apiFamily ? `${apiFamily}.${adapterName}` : adapterName;
469
+ }
470
+ const timerMetricTracker = create(null);
471
+ /**
472
+ * Calls instrumentation/service telemetry timer
473
+ * @param name Name of the metric
474
+ * @param duration number to update backing percentile histogram, negative numbers ignored
475
+ */
476
+ function updateTimerMetric(name, duration) {
477
+ let metric = timerMetricTracker[name];
478
+ if (metric === undefined) {
479
+ metric = timer(createMetricsKey(NAMESPACE, name));
480
+ timerMetricTracker[name] = metric;
481
+ }
482
+ timerMetricAddDuration(metric, duration);
483
+ }
484
+ function timerMetricAddDuration(timer, duration) {
485
+ // Guard against negative values since it causes error to be thrown by MetricsService
486
+ if (duration >= 0) {
487
+ timer.addDuration(duration);
488
+ }
489
+ }
490
+ /**
491
+ * W-10315098
492
+ * Increments the counter associated with the request response. Counts are bucketed by status.
493
+ */
494
+ const requestResponseMetricTracker = create(null);
495
+ function incrementRequestResponseCount(cb) {
496
+ const status = cb().status;
497
+ let metric = requestResponseMetricTracker[status];
498
+ if (metric === undefined) {
499
+ metric = counter(createMetricsKey(OBSERVABILITY_NAMESPACE, NETWORK_ADAPTER_RESPONSE_METRIC_NAME, `${status.valueOf()}`));
500
+ requestResponseMetricTracker[status] = metric;
501
+ }
502
+ metric.increment();
503
+ }
504
+ /**
505
+ * Add a mark to the metrics service.
506
+ *
507
+ * @param name The mark name.
508
+ * @param content The mark content.
509
+ */
510
+ function mark(name, content) {
511
+ mark$1(NAMESPACE, name, content);
512
+ }
513
+ /**
514
+ * Create a new instrumentation cache stats and return it.
515
+ *
516
+ * @param name The cache logger name.
517
+ */
518
+ function registerLdsCacheStats(name) {
519
+ return registerCacheStats(`${NAMESPACE}:${name}`);
520
+ }
521
+ /**
522
+ * Add or overwrite hooks that require aura implementations
523
+ */
524
+ function setAuraInstrumentationHooks() {
525
+ instrument({
526
+ recordConflictsResolved: (serverRequestCount) => {
527
+ // Ignore 0 values which can originate from ADS bridge
528
+ if (serverRequestCount > 0) {
529
+ updatePercentileHistogramMetric('record-conflicts-resolved', serverRequestCount);
530
+ }
531
+ },
532
+ nullDisplayValueConflict: ({ fieldType, areValuesEqual }) => {
533
+ const metricName = `merge-null-dv-count.${fieldType}`;
534
+ if (fieldType === 'scalar') {
535
+ incrementCounterMetric(`${metricName}.${areValuesEqual}`);
536
+ }
537
+ else {
538
+ incrementCounterMetric(metricName);
539
+ }
540
+ },
541
+ getRecordNotifyChangeAllowed: incrementGetRecordNotifyChangeAllowCount,
542
+ getRecordNotifyChangeDropped: incrementGetRecordNotifyChangeDropCount,
543
+ notifyRecordUpdateAvailableAllowed: incrementNotifyRecordUpdateAvailableAllowCount,
544
+ notifyRecordUpdateAvailableDropped: incrementNotifyRecordUpdateAvailableDropCount,
545
+ recordApiNameChanged: instrumentation.incrementRecordApiNameChangeCount.bind(instrumentation),
546
+ weakEtagZero: instrumentation.aggregateWeakETagEvents.bind(instrumentation),
547
+ getRecordNotifyChangeNetworkResult: instrumentation.notifyChangeNetwork.bind(instrumentation),
548
+ });
549
+ withRegistration('@salesforce/lds-adapters-uiapi', (reg) => setLdsAdaptersUiapiInstrumentation(reg));
550
+ instrument$1({
551
+ logCrud: logCRUDLightningInteraction,
552
+ networkResponse: incrementRequestResponseCount,
553
+ });
554
+ instrument$2({
555
+ refreshCalled: instrumentation.handleRefreshApiCall.bind(instrumentation),
556
+ instrumentAdapter: instrumentation.instrumentAdapter.bind(instrumentation),
557
+ });
558
+ instrument$3({
559
+ timerMetricAddDuration: updateTimerMetric,
560
+ });
561
+ // Our getRecord through aggregate-ui CRUD logging has moved
562
+ // to lds-network-adapter. We still need to respect the
563
+ // orgs environment setting
564
+ if (forceRecordTransactionsDisabled === false) {
565
+ ldsNetworkAdapterInstrument({
566
+ getRecordAggregateResolve: (cb) => {
567
+ const { recordId, apiName } = cb();
568
+ logCRUDLightningInteraction('read', {
569
+ recordId,
570
+ recordType: apiName,
571
+ state: 'SUCCESS',
572
+ });
573
+ },
574
+ getRecordAggregateReject: (cb) => {
575
+ const recordId = cb();
576
+ logCRUDLightningInteraction('read', {
577
+ recordId,
578
+ state: 'ERROR',
579
+ });
580
+ },
581
+ });
582
+ }
583
+ withRegistration('@salesforce/lds-network-adapter', (reg) => setLdsNetworkAdapterInstrumentation(reg));
584
+ }
585
+ /**
586
+ * Initialize the instrumentation and instrument the LDS instance and the InMemoryStore.
587
+ *
588
+ * @param luvio The Luvio instance to instrument.
589
+ * @param store The InMemoryStore to instrument.
590
+ */
591
+ function setupInstrumentation(luvio, store) {
592
+ setupInstrumentation$1(luvio, store);
593
+ setAuraInstrumentationHooks();
594
+ }
595
+ /**
596
+ * Note: locator.scope is set to 'force_record' in order for the instrumentation gate to work, which will
597
+ * disable all crud operations if it is on.
598
+ * @param eventSource - Source of the logging event.
599
+ * @param attributes - Free form object of attributes to log.
600
+ */
601
+ function logCRUDLightningInteraction(eventSource, attributes) {
602
+ interaction(eventSource, 'force_record', null, eventSource, 'crud', attributes);
603
+ }
604
+ const instrumentation = new Instrumentation();
605
+
606
+ const OBJECT_INFO_PREFIX = 'UiApi::ObjectInfoRepresentation:';
607
+ const STORAGE_DROP_MARK_NAME = 'storage-drop';
608
+ const STORAGE_DROP_MARK_CONTEXT = {
609
+ reason: 'Object info changed',
610
+ };
611
+ /**
612
+ * Watch a Luvio instance for metadata changes.
613
+ */
614
+ function setupMetadataWatcher(luvio) {
615
+ // Watch for object info changes. Since we don't have enough information to understand to which
616
+ // extent an object info change may impact the application the only thing we do is to clear all
617
+ // the persistent storages.
618
+ luvio.storeWatch(OBJECT_INFO_PREFIX, (entries) => {
619
+ for (let i = 0, len = entries.length; i < len; i++) {
620
+ const entry = entries[i];
621
+ const isObjectInfoUpdated = entry.inserted === false;
622
+ if (isObjectInfoUpdated) {
623
+ mark(STORAGE_DROP_MARK_NAME, STORAGE_DROP_MARK_CONTEXT);
624
+ clearStorages().catch(() => {
625
+ /* noop */
626
+ });
627
+ break;
628
+ }
629
+ }
630
+ });
631
+ }
632
+
633
+ // This code *should* be in lds-network-adapter, but when combined with the Aura
634
+ // component test workaround in lds-default-luvio it creates a circular dependecy
635
+ // between lds-default-luvio and lds-network-adapter. We do the register on behalf
636
+ // of lds-network-adapter here to avoid the cycle.
637
+ register({
638
+ id: '@salesforce/lds-network-adapter',
639
+ instrument: ldsNetworkAdapterInstrument,
640
+ });
641
+ function setTrackedFieldsConfig(includeLeafNodeIdAndNameOnly) {
642
+ const depth = includeLeafNodeIdAndNameOnly ? 1 : 5;
643
+ configuration.setTrackedFieldLeafNodeIdAndNameOnly(includeLeafNodeIdAndNameOnly);
644
+ configuration.setTrackedFieldDepthOnCacheMiss(depth);
645
+ configuration.setTrackedFieldDepthOnCacheMergeConflict(depth);
646
+ configuration.setTrackedFieldDepthOnNotifyChange(depth);
647
+ }
648
+ function setupQueryEvaluators(luvio, store) {
649
+ const baseQueryEvaluator = new InMemoryStoreQueryEvaluator(store);
650
+ const recordRepresentationQueryEvaluator = new InMemoryRecordRepresentationQueryEvaluator(baseQueryEvaluator);
651
+ store.addStoreEventObserver({
652
+ onStorePublish: (event) => {
653
+ baseQueryEvaluator.registerKey(store, event.key, event.keySchema);
654
+ },
655
+ });
656
+ luvio.registerStoreQueryEvaluator(baseQueryEvaluator);
657
+ luvio.registerTypeQueryEvaluator(UiApiNamespace, RecordRepresentationRepresentationType, recordRepresentationQueryEvaluator);
658
+ }
659
+ // LDS initialization logic, invoked directly by Aura component tests
660
+ function initializeLDS() {
661
+ const storeOptions = {
662
+ scheduler: () => { },
663
+ };
664
+ const store = new InMemoryStore(storeOptions);
665
+ const environment = new Environment(store, networkAdapter);
666
+ const luvio = new Luvio(environment, {
667
+ instrument: instrumentation.instrumentLuvio.bind(instrumentation),
668
+ });
669
+ setupInstrumentation(luvio, store);
670
+ setupMetadataWatcher(luvio);
671
+ setupQueryEvaluators(luvio, store);
672
+ setDefaultLuvio({ luvio });
673
+ setTrackedFieldsConfig(ldsTrackedFieldsBehaviorGate.isOpen({ fallback: false }));
674
+ }
675
+ // service function to be invoked by Aura
676
+ function ldsEngineCreator() {
677
+ initializeLDS();
678
+ return { name: 'ldsEngineCreator' };
679
+ }
680
+
681
+ export { ldsEngineCreator as default, initializeLDS };
682
+ // version: 1.100.2-ca56bb821
package/dist/main.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export declare function initializeLDS(): void;
2
+ declare function ldsEngineCreator(): {
3
+ name: string;
4
+ };
5
+ export default ldsEngineCreator;
@@ -0,0 +1,5 @@
1
+ import type { Luvio } from '@luvio/engine';
2
+ /**
3
+ * Watch a Luvio instance for metadata changes.
4
+ */
5
+ export declare function setupMetadataWatcher(luvio: Luvio): void;
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@salesforce/lds-runtime-aura",
3
+ "version": "1.100.2",
4
+ "license": "SEE LICENSE IN LICENSE.txt",
5
+ "description": "LDS engine for Aura runtime",
6
+ "main": "dist/ldsEngineCreator.js",
7
+ "module": "dist/ldsEngineCreator.js",
8
+ "types": "dist/main.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/ldsEngineCreator.js",
15
+ "types": "./dist/main.d.ts",
16
+ "default": "./dist/ldsEngineCreator.js"
17
+ }
18
+ },
19
+ "sfdc": {
20
+ "path": "forcelds/ldsEngineCreator/",
21
+ "publishedFileName": "ldsEngineCreator.js",
22
+ "overrides": {
23
+ "artifactDirectory": "dist",
24
+ "outputModuleName": "ldsEngineCreator"
25
+ }
26
+ },
27
+ "scripts": {
28
+ "prepare": "yarn build",
29
+ "build": "rollup --config rollup.config.js",
30
+ "clean": "rm -rf dist",
31
+ "test:unit": "jest",
32
+ "test:debug": "node --inspect-brk ../../node_modules/.bin/jest --runInBand",
33
+ "test:size": "bundlesize",
34
+ "release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-runtime-aura"
35
+ },
36
+ "devDependencies": {
37
+ "@salesforce/lds-adapters-uiapi": "^1.100.2",
38
+ "@salesforce/lds-ads-bridge": "^1.100.2",
39
+ "@salesforce/lds-aura-storage": "^1.100.2",
40
+ "@salesforce/lds-bindings": "^1.100.2",
41
+ "@salesforce/lds-instrumentation": "^1.100.2",
42
+ "@salesforce/lds-network-aura": "^1.100.2",
43
+ "@salesforce/lds-runtime-web": "^1.100.2"
44
+ },
45
+ "bundlesize": [
46
+ {
47
+ "path": "./dist/ldsEngineCreator.js",
48
+ "maxSize": "10 kB",
49
+ "compression": "brotli"
50
+ }
51
+ ]
52
+ }