@salesforce/lds-adapters-apex 0.1.0-dev1
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 +82 -0
- package/dist/es/es2018/apex-service.js +642 -0
- package/dist/es/es2018/types/src/generated/adapters/adapter-utils.d.ts +62 -0
- package/dist/es/es2018/types/src/generated/resources/getByApexMethodAndApexClass.d.ts +16 -0
- package/dist/es/es2018/types/src/generated/resources/postByApexMethodAndApexClass.d.ts +14 -0
- package/dist/es/es2018/types/src/generated/types/ApexMethodExecuteErrorResponse.d.ts +29 -0
- package/dist/es/es2018/types/src/generated/types/ApexMethodExecuteRequest.d.ts +25 -0
- package/dist/es/es2018/types/src/generated/types/type-utils.d.ts +32 -0
- package/dist/es/es2018/types/src/lds-apex-static-utils.d.ts +8 -0
- package/dist/es/es2018/types/src/main.d.ts +5 -0
- package/dist/es/es2018/types/src/predictive-loading/index.d.ts +1 -0
- package/dist/es/es2018/types/src/predictive-loading/registry.d.ts +8 -0
- package/dist/es/es2018/types/src/sfdc.d.ts +23 -0
- package/dist/es/es2018/types/src/types.d.ts +10 -0
- package/dist/es/es2018/types/src/util/language.d.ts +19 -0
- package/dist/es/es2018/types/src/util/shared.d.ts +39 -0
- package/dist/es/es2018/types/src/util/utils.d.ts +26 -0
- package/dist/es/es2018/types/src/wire/getApex/index.d.ts +14 -0
- package/dist/es/es2018/types/src/wire/postApex/index.d.ts +14 -0
- package/package.json +63 -0
- package/sfdc/index.d.ts +1 -0
- package/sfdc/index.js +689 -0
- package/sfdc/lds-apex-static-utils.js +63 -0
- package/src/raml/api.raml +139 -0
- package/src/raml/luvio.raml +7 -0
package/sfdc/index.js
ADDED
|
@@ -0,0 +1,689 @@
|
|
|
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 { serializeStructuredKey, deepFreeze, StoreKeyMap, StoreKeySet } from 'force/luvioEngine';
|
|
16
|
+
export { getSObjectValue } from './lds-apex-static-utils';
|
|
17
|
+
import { bindWireRefresh, refresh, createInstrumentedAdapter, createLDSAdapter, createImperativeAdapter, createWireAdapterConstructor } from 'force/ldsBindings';
|
|
18
|
+
import { withDefaultLuvio } from 'force/ldsEngine';
|
|
19
|
+
|
|
20
|
+
const { keys: ObjectKeys, create: ObjectCreate } = Object;
|
|
21
|
+
const { stringify: JSONStringify } = JSON;
|
|
22
|
+
const { isArray: ArrayIsArray } = Array;
|
|
23
|
+
function untrustedIsObject(untrusted) {
|
|
24
|
+
return typeof untrusted === 'object' && untrusted !== null && ArrayIsArray(untrusted) === false;
|
|
25
|
+
}
|
|
26
|
+
const snapshotRefreshOptions = {
|
|
27
|
+
overrides: {
|
|
28
|
+
headers: {
|
|
29
|
+
'Cache-Control': 'no-cache',
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
|
|
35
|
+
* This is needed because insertion order for JSON.stringify(object) affects output:
|
|
36
|
+
* JSON.stringify({a: 1, b: 2})
|
|
37
|
+
* "{"a":1,"b":2}"
|
|
38
|
+
* JSON.stringify({b: 2, a: 1})
|
|
39
|
+
* "{"b":2,"a":1}"
|
|
40
|
+
* @param data Data to be JSON-stringified.
|
|
41
|
+
* @returns JSON.stringified value with consistent ordering of keys.
|
|
42
|
+
*/
|
|
43
|
+
function stableJSONStringify$1(node) {
|
|
44
|
+
// This is for Date values.
|
|
45
|
+
if (node && node.toJSON && typeof node.toJSON === 'function') {
|
|
46
|
+
// eslint-disable-next-line no-param-reassign
|
|
47
|
+
node = node.toJSON();
|
|
48
|
+
}
|
|
49
|
+
if (node === undefined) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (typeof node === 'number') {
|
|
53
|
+
return isFinite(node) ? '' + node : 'null';
|
|
54
|
+
}
|
|
55
|
+
if (typeof node !== 'object') {
|
|
56
|
+
return JSONStringify(node);
|
|
57
|
+
}
|
|
58
|
+
let i;
|
|
59
|
+
let out;
|
|
60
|
+
if (ArrayIsArray(node)) {
|
|
61
|
+
out = '[';
|
|
62
|
+
for (i = 0; i < node.length; i++) {
|
|
63
|
+
if (i) {
|
|
64
|
+
out += ',';
|
|
65
|
+
}
|
|
66
|
+
out += stableJSONStringify$1(node[i]) || 'null';
|
|
67
|
+
}
|
|
68
|
+
return out + ']';
|
|
69
|
+
}
|
|
70
|
+
if (node === null) {
|
|
71
|
+
return 'null';
|
|
72
|
+
}
|
|
73
|
+
const keys = ObjectKeys(node).sort();
|
|
74
|
+
out = '';
|
|
75
|
+
for (i = 0; i < keys.length; i++) {
|
|
76
|
+
const key = keys[i];
|
|
77
|
+
const value = stableJSONStringify$1(node[key]);
|
|
78
|
+
if (!value) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (out) {
|
|
82
|
+
out += ',';
|
|
83
|
+
}
|
|
84
|
+
out += JSONStringify(key) + ':' + value;
|
|
85
|
+
}
|
|
86
|
+
return '{' + out + '}';
|
|
87
|
+
}
|
|
88
|
+
const keyPrefix = 'Apex';
|
|
89
|
+
|
|
90
|
+
function createResourceRequest$1(config) {
|
|
91
|
+
const headers = {};
|
|
92
|
+
const header_xSFDCAllowContinuation = config.headers.xSFDCAllowContinuation;
|
|
93
|
+
if (header_xSFDCAllowContinuation !== undefined) {
|
|
94
|
+
headers['X-SFDC-Allow-Continuation'] = header_xSFDCAllowContinuation;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
baseUri: '/lwr/apex/v66.0',
|
|
98
|
+
basePath: '/' + config.urlParams.apexClass + '/' + config.urlParams.apexMethod + '',
|
|
99
|
+
method: 'get',
|
|
100
|
+
body: null,
|
|
101
|
+
urlParams: config.urlParams,
|
|
102
|
+
queryParams: config.queryParams,
|
|
103
|
+
headers,
|
|
104
|
+
priority: 'normal',
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const { create, keys, values } = Object;
|
|
109
|
+
const { isArray } = Array;
|
|
110
|
+
const { stringify } = JSON;
|
|
111
|
+
|
|
112
|
+
function createLink(ref) {
|
|
113
|
+
return {
|
|
114
|
+
__ref: serializeStructuredKey(ref),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const CACHE_CONTROL = 'cache-control';
|
|
119
|
+
// eslint-disable-next-line @salesforce/lds/no-invalid-todo
|
|
120
|
+
// TODO: APEX_TTL, apexResponseEquals, apexResponseIngest, and validateAdapterConfig should have been code generated
|
|
121
|
+
// however compiler does not support response body type any so hand roll for now
|
|
122
|
+
/**
|
|
123
|
+
* Time to live for the Apex cache value. 5 minutes.
|
|
124
|
+
*/
|
|
125
|
+
const APEX_TTL = 5 * 60 * 1000;
|
|
126
|
+
// apex is essentially versionless, we can never know the shape of apex data
|
|
127
|
+
// so we will rely on components to code defensively. All apex data will be ingested
|
|
128
|
+
// and looked up with this version
|
|
129
|
+
const APEX_VERSION = 'APEX_V_1';
|
|
130
|
+
const APEX_STORE_METADATA_PARAMS = {
|
|
131
|
+
ttl: APEX_TTL,
|
|
132
|
+
namespace: keyPrefix,
|
|
133
|
+
representationName: '',
|
|
134
|
+
version: APEX_VERSION,
|
|
135
|
+
};
|
|
136
|
+
function apexResponseEquals(existing, incoming) {
|
|
137
|
+
return stringify(incoming) === stringify(existing);
|
|
138
|
+
}
|
|
139
|
+
const apexResponseIngest = (input, path, luvio, store, timestamp) => {
|
|
140
|
+
// skip validation and normalization, since input type is any
|
|
141
|
+
const key = path.fullPath;
|
|
142
|
+
const incomingRecord = input;
|
|
143
|
+
const existingRecord = store.readEntry(key);
|
|
144
|
+
// freeze on ingest (luvio.opaque)
|
|
145
|
+
deepFreeze(incomingRecord);
|
|
146
|
+
if (existingRecord === undefined ||
|
|
147
|
+
apexResponseEquals(existingRecord, incomingRecord) === false) {
|
|
148
|
+
luvio.storePublish(key, incomingRecord);
|
|
149
|
+
}
|
|
150
|
+
luvio.publishStoreMetadata(key, {
|
|
151
|
+
...APEX_STORE_METADATA_PARAMS,
|
|
152
|
+
ingestionTimestamp: timestamp,
|
|
153
|
+
});
|
|
154
|
+
return createLink(key);
|
|
155
|
+
};
|
|
156
|
+
function validateAdapterConfig(untrustedConfig) {
|
|
157
|
+
if (untrustedIsObject(untrustedConfig)) {
|
|
158
|
+
const values$1 = values(untrustedConfig);
|
|
159
|
+
return values$1.indexOf(undefined) === -1 ? untrustedConfig : null;
|
|
160
|
+
}
|
|
161
|
+
return untrustedConfig;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* A standard delimiter when producing cache keys.
|
|
165
|
+
*/
|
|
166
|
+
const KEY_DELIM = ':';
|
|
167
|
+
function isEmptyParam(param) {
|
|
168
|
+
return (param === undefined ||
|
|
169
|
+
param === null ||
|
|
170
|
+
(typeof param === 'object' && keys(param).length === 0));
|
|
171
|
+
}
|
|
172
|
+
function keyBuilder(classname, method, isContinuation, params) {
|
|
173
|
+
return [
|
|
174
|
+
classname.replace('__', KEY_DELIM),
|
|
175
|
+
method,
|
|
176
|
+
isContinuation,
|
|
177
|
+
isEmptyParam(params) ? '' : stableJSONStringify$1(params),
|
|
178
|
+
].join(KEY_DELIM);
|
|
179
|
+
}
|
|
180
|
+
function configBuilder(config, classname, method, isContinuation) {
|
|
181
|
+
return {
|
|
182
|
+
apexMethod: method,
|
|
183
|
+
apexClass: classname,
|
|
184
|
+
methodParams: config,
|
|
185
|
+
xSFDCAllowContinuation: isContinuation + '',
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function apexClassnameBuilder(namespace, classname) {
|
|
189
|
+
return namespace !== '' ? `${namespace}__${classname}` : classname;
|
|
190
|
+
}
|
|
191
|
+
function isCacheControlValueCacheable(value) {
|
|
192
|
+
if (value === undefined || value === null || typeof value !== 'string') {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
return value.indexOf('no-cache') < 0 && value.indexOf('no-store') < 0;
|
|
196
|
+
}
|
|
197
|
+
function getCacheControlHeaderValue(headers) {
|
|
198
|
+
if (headers === undefined) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
// header fields are case-insensitive according to
|
|
202
|
+
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
|
|
203
|
+
const headerKeys = keys(headers);
|
|
204
|
+
for (let i = 0, len = headerKeys.length; i < len; i += 1) {
|
|
205
|
+
const key = headerKeys[i];
|
|
206
|
+
if (key.toLowerCase() === CACHE_CONTROL) {
|
|
207
|
+
return headers[key];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
function shouldCache(response) {
|
|
213
|
+
const { headers } = response;
|
|
214
|
+
const headerValue = getCacheControlHeaderValue(headers);
|
|
215
|
+
return isCacheControlValueCacheable(headerValue);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function createResourceParams$1(config) {
|
|
219
|
+
const queryParams = create(null);
|
|
220
|
+
if (!isEmptyParam(config.methodParams)) {
|
|
221
|
+
queryParams.methodParams = config.methodParams;
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
queryParams,
|
|
225
|
+
urlParams: {
|
|
226
|
+
apexMethod: config.apexMethod,
|
|
227
|
+
apexClass: config.apexClass,
|
|
228
|
+
},
|
|
229
|
+
headers: {
|
|
230
|
+
xSFDCAllowContinuation: config.xSFDCAllowContinuation,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function keyBuilderFromResourceParams$1(params) {
|
|
235
|
+
let classname = params.urlParams.apexClass.replace('__', KEY_DELIM);
|
|
236
|
+
return [
|
|
237
|
+
classname,
|
|
238
|
+
params.urlParams.apexMethod,
|
|
239
|
+
params.headers.xSFDCAllowContinuation,
|
|
240
|
+
isEmptyParam(params.queryParams.methodParams)
|
|
241
|
+
? ''
|
|
242
|
+
: stableJSONStringify$1(params.queryParams.methodParams),
|
|
243
|
+
].join(KEY_DELIM);
|
|
244
|
+
}
|
|
245
|
+
function ingestSuccess$1(luvio, resourceParams, response, snapshotRefresh) {
|
|
246
|
+
const { body } = response;
|
|
247
|
+
const recordId = keyBuilderFromResourceParams$1(resourceParams);
|
|
248
|
+
const select = {
|
|
249
|
+
recordId,
|
|
250
|
+
node: { kind: 'Fragment', opaque: true, private: [], version: APEX_VERSION },
|
|
251
|
+
variables: {},
|
|
252
|
+
};
|
|
253
|
+
luvio.storeIngest(recordId, apexResponseIngest, body);
|
|
254
|
+
const snapshot = luvio.storeLookup(select, snapshotRefresh);
|
|
255
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
256
|
+
if (response.headers !== undefined && snapshot.state !== 'Fulfilled') {
|
|
257
|
+
throw new Error('Invalid network response. Expected resource response to result in Fulfilled snapshot');
|
|
258
|
+
}
|
|
259
|
+
if (!(snapshot.state === 'Fulfilled' || snapshot.state === 'Stale')) {
|
|
260
|
+
throw new Error('Invalid resource response. Expected resource response to result in Fulfilled or Stale snapshot');
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return snapshot;
|
|
264
|
+
}
|
|
265
|
+
function buildCachedSnapshotCachePolicy$1(buildSnapshotContext, storeLookup) {
|
|
266
|
+
const { luvio, config } = buildSnapshotContext;
|
|
267
|
+
const { apexClass, apexMethod, xSFDCAllowContinuation, methodParams } = config;
|
|
268
|
+
const recordId = keyBuilder(apexClass, apexMethod, xSFDCAllowContinuation, methodParams);
|
|
269
|
+
return storeLookup({
|
|
270
|
+
recordId: recordId,
|
|
271
|
+
node: {
|
|
272
|
+
kind: 'Fragment',
|
|
273
|
+
opaque: true,
|
|
274
|
+
private: [],
|
|
275
|
+
version: APEX_VERSION,
|
|
276
|
+
},
|
|
277
|
+
variables: {},
|
|
278
|
+
}, {
|
|
279
|
+
config,
|
|
280
|
+
resolve: () => buildNetworkSnapshot$1(luvio, config, snapshotRefreshOptions),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
function onFetchResponseSuccess$1(luvio, config, resourceParams, response) {
|
|
284
|
+
const recordId = keyBuilderFromResourceParams$1(resourceParams);
|
|
285
|
+
const select = {
|
|
286
|
+
recordId,
|
|
287
|
+
node: { kind: 'Fragment', opaque: true, private: [], version: APEX_VERSION },
|
|
288
|
+
variables: {},
|
|
289
|
+
};
|
|
290
|
+
if (shouldCache(response)) {
|
|
291
|
+
const snapshot = ingestSuccess$1(luvio, resourceParams, response, {
|
|
292
|
+
config,
|
|
293
|
+
resolve: () => buildNetworkSnapshot$1(luvio, config, snapshotRefreshOptions),
|
|
294
|
+
});
|
|
295
|
+
return luvio.storeBroadcast().then(() => snapshot);
|
|
296
|
+
}
|
|
297
|
+
// if Cache-Control is not set or set to 'no-cache', return a synthetic snapshot
|
|
298
|
+
return Promise.resolve({
|
|
299
|
+
recordId,
|
|
300
|
+
variables: {},
|
|
301
|
+
seenRecords: new StoreKeySet(),
|
|
302
|
+
select,
|
|
303
|
+
state: 'Fulfilled',
|
|
304
|
+
data: response.body,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
function onFetchResponseError$1(luvio, config, _resourceParams, response) {
|
|
308
|
+
return Promise.resolve(luvio.errorSnapshot(response, {
|
|
309
|
+
config,
|
|
310
|
+
resolve: () => buildNetworkSnapshot$1(luvio, config, snapshotRefreshOptions),
|
|
311
|
+
}));
|
|
312
|
+
}
|
|
313
|
+
function buildNetworkSnapshot$1(luvio, config, options) {
|
|
314
|
+
const resourceParams = createResourceParams$1(config);
|
|
315
|
+
const request = createResourceRequest$1(resourceParams);
|
|
316
|
+
return luvio.dispatchResourceRequest(request, options).then((response) => {
|
|
317
|
+
return luvio.handleSuccessResponse(() => onFetchResponseSuccess$1(luvio, config, resourceParams, response),
|
|
318
|
+
// TODO [W-10490362]: Properly generate the response cache keys
|
|
319
|
+
() => {
|
|
320
|
+
return new StoreKeyMap();
|
|
321
|
+
});
|
|
322
|
+
}, (response) => {
|
|
323
|
+
return luvio.handleErrorResponse(() => onFetchResponseError$1(luvio, config, resourceParams, response));
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
function buildNetworkSnapshotCachePolicy$1(context, coercedAdapterRequestContext) {
|
|
327
|
+
const { luvio, config } = context;
|
|
328
|
+
const { networkPriority, requestCorrelator, eventObservers, sourceContext } = coercedAdapterRequestContext;
|
|
329
|
+
const dispatchOptions = {
|
|
330
|
+
resourceRequestContext: {
|
|
331
|
+
requestCorrelator,
|
|
332
|
+
sourceContext,
|
|
333
|
+
},
|
|
334
|
+
eventObservers,
|
|
335
|
+
};
|
|
336
|
+
if (networkPriority !== 'normal') {
|
|
337
|
+
dispatchOptions.overrides = {
|
|
338
|
+
priority: networkPriority,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
return buildNetworkSnapshot$1(luvio, config, dispatchOptions);
|
|
342
|
+
}
|
|
343
|
+
const factory = (luvio, invokerParams) => {
|
|
344
|
+
const { namespace, classname, method, isContinuation } = invokerParams;
|
|
345
|
+
return getApexAdapterFactory(luvio, namespace, classname, method, isContinuation);
|
|
346
|
+
};
|
|
347
|
+
function getApexAdapterFactory(luvio, namespace, classname, method, isContinuation) {
|
|
348
|
+
return (untrustedConfig, requestContext) => {
|
|
349
|
+
// Even though the config is of type `any`,
|
|
350
|
+
// validation is required here because `undefined`
|
|
351
|
+
// values on a wire mean that properties on the component
|
|
352
|
+
// used in the config have not been loaded yet.
|
|
353
|
+
const config = validateAdapterConfig(untrustedConfig);
|
|
354
|
+
// Invalid or incomplete config
|
|
355
|
+
if (config === null) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const configPlus = configBuilder(config, apexClassnameBuilder(namespace, classname), method, isContinuation);
|
|
359
|
+
return luvio.applyCachePolicy(requestContext || {}, { config: configPlus, luvio }, buildCachedSnapshotCachePolicy$1, buildNetworkSnapshotCachePolicy$1);
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
|
|
365
|
+
* This is needed because insertion order for JSON.stringify(object) affects output:
|
|
366
|
+
* JSON.stringify({a: 1, b: 2})
|
|
367
|
+
* "{"a":1,"b":2}"
|
|
368
|
+
* JSON.stringify({b: 2, a: 1})
|
|
369
|
+
* "{"b":2,"a":1}"
|
|
370
|
+
* @param data Data to be JSON-stringified.
|
|
371
|
+
* @returns JSON.stringified value with consistent ordering of keys.
|
|
372
|
+
*/
|
|
373
|
+
function stableJSONStringify(node) {
|
|
374
|
+
// This is for Date values.
|
|
375
|
+
if (node && node.toJSON && typeof node.toJSON === 'function') {
|
|
376
|
+
// eslint-disable-next-line no-param-reassign
|
|
377
|
+
node = node.toJSON();
|
|
378
|
+
}
|
|
379
|
+
if (node === undefined) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (typeof node === 'number') {
|
|
383
|
+
return isFinite(node) ? '' + node : 'null';
|
|
384
|
+
}
|
|
385
|
+
if (typeof node !== 'object') {
|
|
386
|
+
return stringify(node);
|
|
387
|
+
}
|
|
388
|
+
let i;
|
|
389
|
+
let out;
|
|
390
|
+
if (isArray(node)) {
|
|
391
|
+
out = '[';
|
|
392
|
+
for (i = 0; i < node.length; i++) {
|
|
393
|
+
if (i) {
|
|
394
|
+
out += ',';
|
|
395
|
+
}
|
|
396
|
+
out += stableJSONStringify(node[i]) || 'null';
|
|
397
|
+
}
|
|
398
|
+
return out + ']';
|
|
399
|
+
}
|
|
400
|
+
if (node === null) {
|
|
401
|
+
return 'null';
|
|
402
|
+
}
|
|
403
|
+
const keys$1 = keys(node).sort();
|
|
404
|
+
out = '';
|
|
405
|
+
for (i = 0; i < keys$1.length; i++) {
|
|
406
|
+
const key = keys$1[i];
|
|
407
|
+
const value = stableJSONStringify(node[key]);
|
|
408
|
+
if (!value) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (out) {
|
|
412
|
+
out += ',';
|
|
413
|
+
}
|
|
414
|
+
out += stringify(key) + ':' + value;
|
|
415
|
+
}
|
|
416
|
+
return '{' + out + '}';
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function createResourceRequest(config) {
|
|
420
|
+
const headers = {};
|
|
421
|
+
const header_xSFDCAllowContinuation = config.headers.xSFDCAllowContinuation;
|
|
422
|
+
if (header_xSFDCAllowContinuation !== undefined) {
|
|
423
|
+
headers['X-SFDC-Allow-Continuation'] = header_xSFDCAllowContinuation;
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
baseUri: '/lwr/apex/v66.0',
|
|
427
|
+
basePath: '/' + config.urlParams.apexClass + '/' + config.urlParams.apexMethod + '',
|
|
428
|
+
method: 'post',
|
|
429
|
+
body: config.body,
|
|
430
|
+
urlParams: config.urlParams,
|
|
431
|
+
queryParams: {},
|
|
432
|
+
headers,
|
|
433
|
+
priority: 'normal',
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function createResourceParams(config) {
|
|
438
|
+
return {
|
|
439
|
+
urlParams: {
|
|
440
|
+
apexMethod: config.apexMethod,
|
|
441
|
+
apexClass: config.apexClass,
|
|
442
|
+
},
|
|
443
|
+
body: config.methodParams,
|
|
444
|
+
headers: {
|
|
445
|
+
xSFDCAllowContinuation: config.xSFDCAllowContinuation,
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
function keyBuilderFromResourceParams(params) {
|
|
450
|
+
let classname = params.urlParams.apexClass.replace('__', KEY_DELIM);
|
|
451
|
+
return [
|
|
452
|
+
classname,
|
|
453
|
+
params.urlParams.apexMethod,
|
|
454
|
+
params.headers.xSFDCAllowContinuation,
|
|
455
|
+
isEmptyParam(params.body) ? '' : stableJSONStringify(params.body),
|
|
456
|
+
].join(KEY_DELIM);
|
|
457
|
+
}
|
|
458
|
+
function ingestSuccess(luvio, resourceParams, response, snapshotRefresh) {
|
|
459
|
+
const { body } = response;
|
|
460
|
+
const recordId = keyBuilderFromResourceParams(resourceParams);
|
|
461
|
+
const select = {
|
|
462
|
+
recordId,
|
|
463
|
+
node: { kind: 'Fragment', opaque: true, private: [], version: APEX_VERSION },
|
|
464
|
+
variables: {},
|
|
465
|
+
};
|
|
466
|
+
luvio.storeIngest(recordId, apexResponseIngest, body);
|
|
467
|
+
const snapshot = luvio.storeLookup(select, snapshotRefresh);
|
|
468
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
469
|
+
if (response.headers !== undefined && snapshot.state !== 'Fulfilled') {
|
|
470
|
+
throw new Error('Invalid network response. Expected resource response to result in Fulfilled snapshot');
|
|
471
|
+
}
|
|
472
|
+
if (!(snapshot.state === 'Fulfilled' || snapshot.state === 'Stale')) {
|
|
473
|
+
throw new Error('Invalid resource response. Expected resource response to result in Fulfilled or Stale snapshot');
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return snapshot;
|
|
477
|
+
}
|
|
478
|
+
function buildCachedSnapshotCachePolicy(buildSnapshotContext, storeLookup) {
|
|
479
|
+
const { config } = buildSnapshotContext;
|
|
480
|
+
const { apexClass, apexMethod, xSFDCAllowContinuation, methodParams } = config;
|
|
481
|
+
const recordId = keyBuilder(apexClass, apexMethod, xSFDCAllowContinuation, methodParams);
|
|
482
|
+
return storeLookup({
|
|
483
|
+
recordId: recordId,
|
|
484
|
+
node: {
|
|
485
|
+
kind: 'Fragment',
|
|
486
|
+
opaque: true,
|
|
487
|
+
private: [],
|
|
488
|
+
version: APEX_VERSION,
|
|
489
|
+
},
|
|
490
|
+
variables: {},
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
function onFetchResponseSuccess(luvio, _config, resourceParams, response) {
|
|
494
|
+
const recordId = keyBuilderFromResourceParams(resourceParams);
|
|
495
|
+
const select = {
|
|
496
|
+
recordId,
|
|
497
|
+
node: { kind: 'Fragment', opaque: true, private: [], version: APEX_VERSION },
|
|
498
|
+
variables: {},
|
|
499
|
+
};
|
|
500
|
+
if (shouldCache(response)) {
|
|
501
|
+
const snapshot = ingestSuccess(luvio, resourceParams, response);
|
|
502
|
+
return luvio.storeBroadcast().then(() => snapshot);
|
|
503
|
+
}
|
|
504
|
+
// if Cache-Control is not set or set to 'no-cache', return a synthetic snapshot
|
|
505
|
+
return Promise.resolve({
|
|
506
|
+
recordId,
|
|
507
|
+
variables: {},
|
|
508
|
+
seenRecords: new StoreKeySet(),
|
|
509
|
+
select,
|
|
510
|
+
state: 'Fulfilled',
|
|
511
|
+
data: response.body,
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
function onFetchResponseError(luvio, _config, _resourceParams, response) {
|
|
515
|
+
return Promise.resolve(luvio.errorSnapshot(response));
|
|
516
|
+
}
|
|
517
|
+
function buildNetworkSnapshot(luvio, config, options) {
|
|
518
|
+
const resourceParams = createResourceParams(config);
|
|
519
|
+
const request = createResourceRequest(resourceParams);
|
|
520
|
+
return luvio.dispatchResourceRequest(request, options).then((response) => {
|
|
521
|
+
return luvio.handleSuccessResponse(() => onFetchResponseSuccess(luvio, config, resourceParams, response),
|
|
522
|
+
// TODO [W-10490362]: Properly generate response cache keys
|
|
523
|
+
() => {
|
|
524
|
+
return new StoreKeyMap();
|
|
525
|
+
});
|
|
526
|
+
}, (response) => {
|
|
527
|
+
return luvio.handleErrorResponse(() => onFetchResponseError(luvio, config, resourceParams, response));
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
function buildNetworkSnapshotCachePolicy(context, coercedAdapterRequestContext) {
|
|
531
|
+
const { luvio, config } = context;
|
|
532
|
+
const { networkPriority, requestCorrelator, eventObservers, sourceContext } = coercedAdapterRequestContext;
|
|
533
|
+
const dispatchOptions = {
|
|
534
|
+
resourceRequestContext: {
|
|
535
|
+
requestCorrelator,
|
|
536
|
+
sourceContext,
|
|
537
|
+
},
|
|
538
|
+
eventObservers,
|
|
539
|
+
};
|
|
540
|
+
if (networkPriority !== 'normal') {
|
|
541
|
+
dispatchOptions.overrides = {
|
|
542
|
+
priority: networkPriority,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
return buildNetworkSnapshot(luvio, config, dispatchOptions);
|
|
546
|
+
}
|
|
547
|
+
function handleSnapshot(snapshot) {
|
|
548
|
+
if (snapshot.state === 'Error') {
|
|
549
|
+
throw snapshot.error;
|
|
550
|
+
}
|
|
551
|
+
return snapshot.data;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Returns a function that executes the supplied ldsAdapter,
|
|
555
|
+
* and handles unwrapping the snapshot to return to caller
|
|
556
|
+
*
|
|
557
|
+
* @param ldsAdapter adapter to be invoked
|
|
558
|
+
* @returns an ApexInvoker
|
|
559
|
+
*/
|
|
560
|
+
function invoker(ldsAdapter) {
|
|
561
|
+
return (config, requestContext) => {
|
|
562
|
+
const snapshotOrPromise = ldsAdapter(config, requestContext);
|
|
563
|
+
return Promise.resolve(snapshotOrPromise).then(handleSnapshot);
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
const invokerFactory = (luvio, invokerParams, adapterFactory) => {
|
|
567
|
+
const { namespace, classname, method, isContinuation } = invokerParams;
|
|
568
|
+
const ldsAdapter = adapterFactory(luvio, namespace, classname, method, isContinuation);
|
|
569
|
+
return invoker(ldsAdapter);
|
|
570
|
+
};
|
|
571
|
+
const postInvoker = (luvio, invokerParams) => {
|
|
572
|
+
return invokerFactory(luvio, invokerParams, postApexAdapterFactory);
|
|
573
|
+
};
|
|
574
|
+
const getInvoker = (luvio, invokerParams) => {
|
|
575
|
+
return invokerFactory(luvio, invokerParams, getApexAdapterFactory);
|
|
576
|
+
};
|
|
577
|
+
function postApexAdapterFactory(luvio, namespace, classname, method, isContinuation) {
|
|
578
|
+
return (config, requestContext) => {
|
|
579
|
+
// config validation is unnecessary for this imperative adapter
|
|
580
|
+
// due to the config being of type `any`.
|
|
581
|
+
// however, we have special config validation for the wire adapter,
|
|
582
|
+
// explanation in getApex
|
|
583
|
+
const configPlus = configBuilder(config, apexClassnameBuilder(namespace, classname), method, isContinuation);
|
|
584
|
+
return luvio.applyCachePolicy(requestContext || {}, { config: configPlus, luvio }, buildCachedSnapshotCachePolicy, buildNetworkSnapshotCachePolicy);
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const engineForPrefetcherMap = new Map();
|
|
589
|
+
function registerPrefetcher(luvio, prefetcher) {
|
|
590
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
591
|
+
if (engineForPrefetcherMap.has(luvio)) {
|
|
592
|
+
throw new Error('Environment error: Only one prefetcher per engine is allowed.');
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
engineForPrefetcherMap.set(luvio, prefetcher);
|
|
596
|
+
}
|
|
597
|
+
function getPrefetcherFor(luvio) {
|
|
598
|
+
return engineForPrefetcherMap.get(luvio);
|
|
599
|
+
}
|
|
600
|
+
function createGetApexAdapterWithPrediction(adapter, luvio, invokerParams, name) {
|
|
601
|
+
return (config, requestContext) => {
|
|
602
|
+
const prefetcher = getPrefetcherFor(luvio);
|
|
603
|
+
const result = adapter(config, requestContext);
|
|
604
|
+
// only save requests with a valid config.
|
|
605
|
+
if (result !== null &&
|
|
606
|
+
prefetcher !== undefined &&
|
|
607
|
+
!(requestContext && requestContext.excludeFromPredictions)) {
|
|
608
|
+
prefetcher.saveRequest({
|
|
609
|
+
adapterName: 'getApex',
|
|
610
|
+
config: {
|
|
611
|
+
name,
|
|
612
|
+
invokerParams,
|
|
613
|
+
config,
|
|
614
|
+
},
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
return result;
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const REFRESH_APEX_KEY = 'refreshApex';
|
|
622
|
+
// export for @salesforce/apex
|
|
623
|
+
const refreshApex = function (data) {
|
|
624
|
+
return refresh(data, REFRESH_APEX_KEY);
|
|
625
|
+
};
|
|
626
|
+
let luvio;
|
|
627
|
+
withDefaultLuvio((_luvio) => {
|
|
628
|
+
luvio = _luvio;
|
|
629
|
+
bindWireRefresh(luvio);
|
|
630
|
+
});
|
|
631
|
+
/**
|
|
632
|
+
* Imperative GET Apex Adapter.
|
|
633
|
+
*
|
|
634
|
+
* @param namespace a one- to 15-character alphanumeric identifier that distinguishes a package and its contents from other packages
|
|
635
|
+
* @param classname name of class where method is defined
|
|
636
|
+
* @param method name of method defining the Apex code
|
|
637
|
+
* @param isContinuation used to specify if the Apex method is a Continuation
|
|
638
|
+
* @returns an ImperativeAdapter that uses the GET endpoint
|
|
639
|
+
*/
|
|
640
|
+
const getApexInvoker_imperative = function (namespace, classname, method, isContinuation) {
|
|
641
|
+
if (luvio === undefined) {
|
|
642
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
643
|
+
throw new Error('cannot create Apex adapter before default luvio is set');
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
const adapterName = `getApex_${namespace}_${classname}_${method}_${isContinuation}`;
|
|
647
|
+
const adapterMetadata = {
|
|
648
|
+
apiFamily: 'Apex',
|
|
649
|
+
name: adapterName,
|
|
650
|
+
};
|
|
651
|
+
const getApexInstrumentedLdsAdapter = createInstrumentedAdapter(createLDSAdapter(luvio, adapterName, (luvio) => factory(luvio, { namespace, classname, method, isContinuation })), adapterMetadata);
|
|
652
|
+
return createImperativeAdapter(luvio, getApexInstrumentedLdsAdapter, adapterMetadata);
|
|
653
|
+
};
|
|
654
|
+
/**
|
|
655
|
+
* Apex
|
|
656
|
+
*
|
|
657
|
+
* The Apex invoker is dual purpose; it can be invoked imperatively or be provided to an @wire
|
|
658
|
+
* In order for this to work, LWC will look for the property "adapter" on the object, and check that
|
|
659
|
+
* it conforms to the WireAdapter interface.
|
|
660
|
+
*/
|
|
661
|
+
const getApexInvoker = function (namespace, classname, method, isContinuation, isCacheable) {
|
|
662
|
+
if (luvio === undefined) {
|
|
663
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
664
|
+
throw new Error('cannot create Apex adapter before default luvio is set');
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
const adapterName = `getApex_${namespace}_${classname}_${method}_${isContinuation}`;
|
|
668
|
+
const adapterMetadata = {
|
|
669
|
+
apiFamily: 'Apex',
|
|
670
|
+
name: adapterName,
|
|
671
|
+
};
|
|
672
|
+
const apexInvoker = isCacheable ? getInvoker : postInvoker;
|
|
673
|
+
const invokeApexImperative = createLDSAdapter(luvio, adapterName, (luvio) => apexInvoker(luvio, {
|
|
674
|
+
namespace,
|
|
675
|
+
classname,
|
|
676
|
+
method,
|
|
677
|
+
isContinuation,
|
|
678
|
+
}));
|
|
679
|
+
invokeApexImperative.adapter = createWireAdapterConstructor(luvio, createInstrumentedAdapter(createGetApexAdapterWithPrediction(createLDSAdapter(luvio, adapterName, (luvio) => factory(luvio, {
|
|
680
|
+
namespace,
|
|
681
|
+
classname,
|
|
682
|
+
method,
|
|
683
|
+
isContinuation,
|
|
684
|
+
})), luvio, { namespace, classname, method, isContinuation }, adapterName), adapterMetadata), adapterMetadata);
|
|
685
|
+
return invokeApexImperative;
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
export { factory as GetApexWireAdapterFactory, getApexInvoker, getApexInvoker_imperative, refreshApex, registerPrefetcher };
|
|
689
|
+
// version: 0.1.0-dev1-c978a7b010
|