@salesforce/lds-runtime-mobile 1.110.1 → 1.111.0
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/main.js +173 -71
- package/dist/priming/NimbusPrimingNetworkAdapter.d.ts +6 -0
- package/dist/priming/primingSessionFactory.d.ts +1 -2
- package/package.json +18 -18
- package/sfdc/main.js +173 -71
- package/sfdc/priming/NimbusPrimingNetworkAdapter.d.ts +6 -0
- package/sfdc/priming/primingSessionFactory.d.ts +1 -2
package/dist/main.js
CHANGED
|
@@ -1055,10 +1055,10 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1055
1055
|
};
|
|
1056
1056
|
const storeBroadcast = function (_rebuildSnapshot, _snapshotDataAvailable) {
|
|
1057
1057
|
validateNotDisposed();
|
|
1058
|
-
//
|
|
1059
|
-
//
|
|
1060
|
-
//
|
|
1061
|
-
return
|
|
1058
|
+
// publishing to L2 is essentially "broadcasting" because the onChanged
|
|
1059
|
+
// handler will fire which will revive records to the main L1 store and
|
|
1060
|
+
// call the base storeBroadcast
|
|
1061
|
+
return publishChangesToDurableStore();
|
|
1062
1062
|
};
|
|
1063
1063
|
const publishChangesToDurableStore = function () {
|
|
1064
1064
|
validateNotDisposed();
|
|
@@ -1279,7 +1279,6 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1279
1279
|
// we don't need to prime metadata
|
|
1280
1280
|
() => { });
|
|
1281
1281
|
snapshotFromMemoryIngest = await ingestAndBroadcastFunc();
|
|
1282
|
-
await publishChangesToDurableStore();
|
|
1283
1282
|
})();
|
|
1284
1283
|
for (const key of keysToReviveAsArray) {
|
|
1285
1284
|
// we are overwriting the previous promise at this key, but that
|
|
@@ -1307,7 +1306,6 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1307
1306
|
// so all we have to do is ingest then write to L2
|
|
1308
1307
|
ingestStagingStore = buildIngestStagingStore(environment);
|
|
1309
1308
|
snapshotFromMemoryIngest = await ingestAndBroadcastFunc();
|
|
1310
|
-
await publishChangesToDurableStore();
|
|
1311
1309
|
}
|
|
1312
1310
|
if (snapshotFromMemoryIngest === undefined) {
|
|
1313
1311
|
return undefined;
|
|
@@ -1320,12 +1318,10 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1320
1318
|
const result = await reviveSnapshot(environment, durableStore, snapshotFromMemoryIngest, durableStoreErrorHandler, () => environment.storeLookup(select, environment.createSnapshot, refresh));
|
|
1321
1319
|
return result.snapshot;
|
|
1322
1320
|
};
|
|
1323
|
-
const handleErrorResponse = function (ingestAndBroadcastFunc) {
|
|
1321
|
+
const handleErrorResponse = async function (ingestAndBroadcastFunc) {
|
|
1324
1322
|
validateNotDisposed();
|
|
1325
|
-
|
|
1326
|
-
return
|
|
1327
|
-
return snapshotFromMemoryIngest;
|
|
1328
|
-
});
|
|
1323
|
+
ingestStagingStore = buildIngestStagingStore(environment);
|
|
1324
|
+
return ingestAndBroadcastFunc();
|
|
1329
1325
|
};
|
|
1330
1326
|
const getNotifyChangeStoreEntries = function (keys) {
|
|
1331
1327
|
validateNotDisposed();
|
|
@@ -4350,6 +4346,58 @@ function makeStoreEval(preconditioner, objectInfoService, userId, contextProvide
|
|
|
4350
4346
|
* For full license text, see the LICENSE.txt file
|
|
4351
4347
|
*/
|
|
4352
4348
|
|
|
4349
|
+
/* Ideally we would use AbortController but it does not exist in V8, if it is ever polyfilled we can swap for it */
|
|
4350
|
+
class LdsAbortController {
|
|
4351
|
+
constructor() {
|
|
4352
|
+
this.signal = new AbortSignal();
|
|
4353
|
+
}
|
|
4354
|
+
abort() {
|
|
4355
|
+
this.signal.abort();
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
class AbortSignal {
|
|
4359
|
+
constructor() {
|
|
4360
|
+
this._aborted = false;
|
|
4361
|
+
this.listeners = new Map();
|
|
4362
|
+
}
|
|
4363
|
+
get aborted() {
|
|
4364
|
+
return this._aborted;
|
|
4365
|
+
}
|
|
4366
|
+
addEventListener(type, listener) {
|
|
4367
|
+
let listeners = this.listeners.get(type);
|
|
4368
|
+
if (!listeners) {
|
|
4369
|
+
listeners = new Set();
|
|
4370
|
+
this.listeners.set(type, listeners);
|
|
4371
|
+
}
|
|
4372
|
+
listeners.add(listener);
|
|
4373
|
+
}
|
|
4374
|
+
removeEventListener(type, listener) {
|
|
4375
|
+
const listeners = this.listeners.get(type);
|
|
4376
|
+
if (listeners) {
|
|
4377
|
+
listeners.delete(listener);
|
|
4378
|
+
if (listeners.size === 0) {
|
|
4379
|
+
this.listeners.delete(type);
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
dispatchEvent(event) {
|
|
4384
|
+
const listeners = this.listeners.get(event.type);
|
|
4385
|
+
if (listeners) {
|
|
4386
|
+
for (const listener of listeners) {
|
|
4387
|
+
listener(this, event);
|
|
4388
|
+
}
|
|
4389
|
+
}
|
|
4390
|
+
return !event.defaultPrevented;
|
|
4391
|
+
}
|
|
4392
|
+
abort() {
|
|
4393
|
+
if (!this.aborted) {
|
|
4394
|
+
this._aborted = true;
|
|
4395
|
+
const abortEvent = new Event('abort');
|
|
4396
|
+
this.dispatchEvent(abortEvent);
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
|
|
4353
4401
|
class AsyncWorkerPool {
|
|
4354
4402
|
constructor(concurrency) {
|
|
4355
4403
|
this.queue = [];
|
|
@@ -4360,51 +4408,57 @@ class AsyncWorkerPool {
|
|
|
4360
4408
|
return new Promise((resolve, reject) => {
|
|
4361
4409
|
this.queue.push({
|
|
4362
4410
|
...work,
|
|
4363
|
-
workFn: () => work.workFn().then(resolve).catch(reject),
|
|
4411
|
+
workFn: (abortController) => work.workFn(abortController).then(resolve).catch(reject),
|
|
4364
4412
|
});
|
|
4365
4413
|
this.doWork();
|
|
4366
4414
|
});
|
|
4367
4415
|
}
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4416
|
+
/**
|
|
4417
|
+
* cancel all work in the queue and active work
|
|
4418
|
+
* @returns true if all work was cancelled, false if any work could not be cancelled
|
|
4419
|
+
*/
|
|
4420
|
+
cancel() {
|
|
4421
|
+
let success = true;
|
|
4422
|
+
for (const { cancelFn } of this.queue) {
|
|
4423
|
+
if (cancelFn) {
|
|
4424
|
+
try {
|
|
4425
|
+
cancelFn();
|
|
4426
|
+
}
|
|
4427
|
+
catch (_a) {
|
|
4428
|
+
success = false;
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
this.queue = [];
|
|
4433
|
+
for (const { abortController, cancelFn } of this.activeWork) {
|
|
4434
|
+
abortController.abort();
|
|
4376
4435
|
if (cancelFn) {
|
|
4377
|
-
|
|
4436
|
+
try {
|
|
4437
|
+
cancelFn();
|
|
4438
|
+
}
|
|
4439
|
+
catch (_b) {
|
|
4440
|
+
success = false;
|
|
4441
|
+
}
|
|
4378
4442
|
}
|
|
4379
|
-
}
|
|
4380
|
-
|
|
4443
|
+
}
|
|
4444
|
+
this.activeWork = [];
|
|
4445
|
+
return success;
|
|
4381
4446
|
}
|
|
4382
4447
|
doWork() {
|
|
4383
4448
|
while (this.queue.length > 0 && this.activeWork.length < this.concurrency) {
|
|
4384
4449
|
const work = this.queue.shift();
|
|
4385
4450
|
if (work) {
|
|
4386
|
-
|
|
4451
|
+
const abortController = new LdsAbortController();
|
|
4452
|
+
const newWork = { ...work, abortController };
|
|
4453
|
+
this.activeWork.push(newWork);
|
|
4387
4454
|
const { workFn } = work;
|
|
4388
|
-
workFn()
|
|
4389
|
-
.
|
|
4390
|
-
.finally(() => {
|
|
4391
|
-
this.activeWork = this.activeWork.filter((w) => w !== work);
|
|
4455
|
+
workFn(abortController).finally(() => {
|
|
4456
|
+
this.activeWork = this.activeWork.filter((w) => w !== newWork);
|
|
4392
4457
|
this.doWork();
|
|
4393
4458
|
});
|
|
4394
4459
|
}
|
|
4395
4460
|
}
|
|
4396
4461
|
}
|
|
4397
|
-
}
|
|
4398
|
-
function promiseAllSettled(promises) {
|
|
4399
|
-
return Promise.all(promises.map((promise) => promise
|
|
4400
|
-
.then((value) => ({
|
|
4401
|
-
status: 'fulfilled',
|
|
4402
|
-
value,
|
|
4403
|
-
}))
|
|
4404
|
-
.catch((reason) => ({
|
|
4405
|
-
status: 'rejected',
|
|
4406
|
-
reason,
|
|
4407
|
-
}))));
|
|
4408
4462
|
}
|
|
4409
4463
|
|
|
4410
4464
|
/**
|
|
@@ -5720,9 +5774,8 @@ class AbstractResourceRequestActionHandler {
|
|
|
5720
5774
|
const { response, synchronousIngest } = entry;
|
|
5721
5775
|
synchronousIngest(response, action);
|
|
5722
5776
|
}
|
|
5723
|
-
//
|
|
5724
|
-
|
|
5725
|
-
return Promise.resolve();
|
|
5777
|
+
// must call base broadcast
|
|
5778
|
+
return luvio.storeBroadcast();
|
|
5726
5779
|
},
|
|
5727
5780
|
// getTypeCacheKeysRecord uses the response, not the full path factory
|
|
5728
5781
|
// so 2nd parameter will be unused
|
|
@@ -14935,9 +14988,10 @@ const DEFAULT_BATCH_SIZE = 500;
|
|
|
14935
14988
|
const DEFAULT_CONCURRENCY = 6;
|
|
14936
14989
|
class PrimingSession extends EventEmitter {
|
|
14937
14990
|
constructor(config) {
|
|
14991
|
+
var _a, _b;
|
|
14938
14992
|
super();
|
|
14939
|
-
this.batchSize = config.batchSize
|
|
14940
|
-
this.concurrency = config.concurrency
|
|
14993
|
+
this.batchSize = (_a = config.batchSize) !== null && _a !== void 0 ? _a : DEFAULT_BATCH_SIZE;
|
|
14994
|
+
this.concurrency = (_b = config.concurrency) !== null && _b !== void 0 ? _b : DEFAULT_CONCURRENCY;
|
|
14941
14995
|
this.recordLoader = config.recordLoader;
|
|
14942
14996
|
this.recordIngestor = config.recordIngestor;
|
|
14943
14997
|
this.objectInfoLoader = config.objectInfoLoader;
|
|
@@ -14965,12 +15019,20 @@ class PrimingSession extends EventEmitter {
|
|
|
14965
15019
|
this.enqueueBatches(availableBatches);
|
|
14966
15020
|
}
|
|
14967
15021
|
}
|
|
15022
|
+
cancel() {
|
|
15023
|
+
this.networkWorkerPool.cancel();
|
|
15024
|
+
}
|
|
14968
15025
|
// parallelizes batches of priming work
|
|
14969
15026
|
enqueueBatches(batches) {
|
|
14970
15027
|
for (const batch of batches) {
|
|
14971
15028
|
this.networkWorkerPool.push({
|
|
14972
|
-
workFn: () => {
|
|
14973
|
-
return this.recordLoader
|
|
15029
|
+
workFn: (abortController) => {
|
|
15030
|
+
return this.recordLoader
|
|
15031
|
+
.fetchRecordData(batch, abortController)
|
|
15032
|
+
.then(async (result) => {
|
|
15033
|
+
if (abortController.signal.aborted) {
|
|
15034
|
+
return;
|
|
15035
|
+
}
|
|
14974
15036
|
if (result.ok === false) {
|
|
14975
15037
|
const { error } = result;
|
|
14976
15038
|
const primingError = error === 'network-error' ? 'service-unavailable' : 'unknown';
|
|
@@ -14994,6 +15056,9 @@ class PrimingSession extends EventEmitter {
|
|
|
14994
15056
|
this.recordIngestor
|
|
14995
15057
|
.insertRecords(records)
|
|
14996
15058
|
.then(({ written, conflicted }) => {
|
|
15059
|
+
if (abortController.signal.aborted) {
|
|
15060
|
+
return;
|
|
15061
|
+
}
|
|
14997
15062
|
// now that the records are persisted, emit the primed event
|
|
14998
15063
|
if (written.length > 0) {
|
|
14999
15064
|
this.emit('primed', Array.from(written));
|
|
@@ -15010,6 +15075,13 @@ class PrimingSession extends EventEmitter {
|
|
|
15010
15075
|
});
|
|
15011
15076
|
});
|
|
15012
15077
|
},
|
|
15078
|
+
cancelFn: () => {
|
|
15079
|
+
this.emit('error', {
|
|
15080
|
+
ids: batch.ids,
|
|
15081
|
+
code: 'canceled',
|
|
15082
|
+
message: `batch canceled`,
|
|
15083
|
+
});
|
|
15084
|
+
},
|
|
15013
15085
|
});
|
|
15014
15086
|
}
|
|
15015
15087
|
}
|
|
@@ -15035,8 +15107,6 @@ class PrimingSession extends EventEmitter {
|
|
|
15035
15107
|
}
|
|
15036
15108
|
|
|
15037
15109
|
const requiredPrefix = `required_`;
|
|
15038
|
-
// note this is automatically incremented by scripts/release/bump-api-version.js at each release
|
|
15039
|
-
const apiVersion = `v58.0`;
|
|
15040
15110
|
const requiredFieldMap = {
|
|
15041
15111
|
ApiName: 'ApiName',
|
|
15042
15112
|
Id: 'Id',
|
|
@@ -15050,10 +15120,10 @@ class RecordLoaderGraphQL {
|
|
|
15050
15120
|
constructor(networkAdapter) {
|
|
15051
15121
|
this.networkAdapter = networkAdapter;
|
|
15052
15122
|
}
|
|
15053
|
-
async fetchRecordData(batch) {
|
|
15123
|
+
async fetchRecordData(batch, abortController) {
|
|
15054
15124
|
let rep;
|
|
15055
15125
|
try {
|
|
15056
|
-
rep = await this.callGraphQL(batch);
|
|
15126
|
+
rep = await this.callGraphQL(batch, abortController);
|
|
15057
15127
|
}
|
|
15058
15128
|
catch (e) {
|
|
15059
15129
|
return {
|
|
@@ -15095,25 +15165,9 @@ class RecordLoaderGraphQL {
|
|
|
15095
15165
|
missingIds: Array.from(seenRecords),
|
|
15096
15166
|
};
|
|
15097
15167
|
}
|
|
15098
|
-
|
|
15168
|
+
callGraphQL(batch, abortController) {
|
|
15099
15169
|
const query = this.generateGraphQLQuery(batch.type, batch.fields);
|
|
15100
|
-
|
|
15101
|
-
baseUri: `/services/data/${apiVersion}`,
|
|
15102
|
-
basePath: '/graphql',
|
|
15103
|
-
method: 'POST',
|
|
15104
|
-
priority: 'background',
|
|
15105
|
-
body: {
|
|
15106
|
-
query,
|
|
15107
|
-
variables: {
|
|
15108
|
-
ids: batch.ids,
|
|
15109
|
-
first: batch.ids.length,
|
|
15110
|
-
},
|
|
15111
|
-
},
|
|
15112
|
-
queryParams: {},
|
|
15113
|
-
urlParams: {},
|
|
15114
|
-
headers: {},
|
|
15115
|
-
}, {});
|
|
15116
|
-
return response.body;
|
|
15170
|
+
return this.networkAdapter.postGraphQL(query, { ids: batch.ids, first: batch.ids.length }, abortController);
|
|
15117
15171
|
}
|
|
15118
15172
|
generateGraphQLQuery(type, fields) {
|
|
15119
15173
|
const fieldList = Object.keys(requiredFieldMap)
|
|
@@ -15249,8 +15303,57 @@ function instrumentPrimingSession(session) {
|
|
|
15249
15303
|
return session;
|
|
15250
15304
|
}
|
|
15251
15305
|
|
|
15306
|
+
// so eslint doesn't complain about nimbus
|
|
15307
|
+
/* global __nimbus */
|
|
15308
|
+
// note this is automatically incremented by scripts/release/bump-api-version.js at each release
|
|
15309
|
+
const apiVersion = `v58.0`;
|
|
15310
|
+
class NimbusPrimingNetworkAdapter {
|
|
15311
|
+
postGraphQL(query, variables, abortController) {
|
|
15312
|
+
return new Promise((resolve, reject) => {
|
|
15313
|
+
let listener;
|
|
15314
|
+
const unregisterListener = () => {
|
|
15315
|
+
if (listener) {
|
|
15316
|
+
abortController.signal.removeEventListener('abort', listener);
|
|
15317
|
+
}
|
|
15318
|
+
};
|
|
15319
|
+
__nimbus.plugins.LdsNetworkAdapter
|
|
15320
|
+
.sendRequest({
|
|
15321
|
+
method: 'POST',
|
|
15322
|
+
path: `/services/data/${apiVersion}/graphql`,
|
|
15323
|
+
body: JSON.stringify({
|
|
15324
|
+
query,
|
|
15325
|
+
variables,
|
|
15326
|
+
}),
|
|
15327
|
+
headers: {},
|
|
15328
|
+
queryParams: {},
|
|
15329
|
+
priority: 'background',
|
|
15330
|
+
observabilityContext: {},
|
|
15331
|
+
}, (response) => {
|
|
15332
|
+
unregisterListener();
|
|
15333
|
+
const { body } = response;
|
|
15334
|
+
if (body) {
|
|
15335
|
+
resolve(JSON.parse(body));
|
|
15336
|
+
}
|
|
15337
|
+
else {
|
|
15338
|
+
reject(new Error('No body returned from graphql endpoint'));
|
|
15339
|
+
}
|
|
15340
|
+
}, (error) => {
|
|
15341
|
+
unregisterListener();
|
|
15342
|
+
reject(error);
|
|
15343
|
+
})
|
|
15344
|
+
.then((cancellationToken) => {
|
|
15345
|
+
listener = () => {
|
|
15346
|
+
__nimbus.plugins.LdsNetworkAdapter.cancelRequest(cancellationToken);
|
|
15347
|
+
};
|
|
15348
|
+
abortController.signal.addEventListener('abort', listener);
|
|
15349
|
+
});
|
|
15350
|
+
});
|
|
15351
|
+
}
|
|
15352
|
+
}
|
|
15353
|
+
|
|
15252
15354
|
function primingSessionFactory(config) {
|
|
15253
|
-
const {
|
|
15355
|
+
const { store, objectInfoService, getLuvio } = config;
|
|
15356
|
+
const networkAdapter = new NimbusPrimingNetworkAdapter();
|
|
15254
15357
|
const recordLoader = new RecordLoaderGraphQL(networkAdapter);
|
|
15255
15358
|
const recordIngestor = new RecordIngestor(store, getLuvio);
|
|
15256
15359
|
const session = new PrimingSession({
|
|
@@ -15376,7 +15479,6 @@ function getRuntime() {
|
|
|
15376
15479
|
createPrimingSession: (config) => {
|
|
15377
15480
|
return primingSessionFactory({
|
|
15378
15481
|
store: lazyBaseDurableStore,
|
|
15379
|
-
networkAdapter: lazyNetworkAdapter,
|
|
15380
15482
|
objectInfoService: lazyObjectInfoService,
|
|
15381
15483
|
getLuvio: () => lazyLuvio,
|
|
15382
15484
|
concurrency: config.concurrency,
|
|
@@ -15399,4 +15501,4 @@ register({
|
|
|
15399
15501
|
});
|
|
15400
15502
|
|
|
15401
15503
|
export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
|
|
15402
|
-
// version: 1.
|
|
15504
|
+
// version: 1.111.0-f30e5e921
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PrimingNetworkAdapter } from '@salesforce/lds-priming';
|
|
2
|
+
import type { GraphQLRepresentation } from '@salesforce/lds-adapters-uiapi';
|
|
3
|
+
import type { LdsAbortController } from '@salesforce/lds-utils-adapters';
|
|
4
|
+
export declare class NimbusPrimingNetworkAdapter implements PrimingNetworkAdapter {
|
|
5
|
+
postGraphQL(query: string, variables: Record<string, any>, abortController: LdsAbortController): Promise<GraphQLRepresentation>;
|
|
6
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { PrimingSession } from '@salesforce/lds-priming';
|
|
2
|
-
import type { Luvio
|
|
2
|
+
import type { Luvio } from '@luvio/engine';
|
|
3
3
|
import type { NimbusSqliteStore } from '../durableStore/NimbusSqliteStore/NimbusSqliteStore';
|
|
4
4
|
import type { ObjectInfoService } from '../main';
|
|
5
5
|
export interface PrimingSessionFactoryConfig {
|
|
6
6
|
store: NimbusSqliteStore;
|
|
7
|
-
networkAdapter: NetworkAdapter;
|
|
8
7
|
objectInfoService: ObjectInfoService;
|
|
9
8
|
getLuvio: () => Luvio;
|
|
10
9
|
concurrency?: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/lds-runtime-mobile",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.111.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
5
|
"description": "LDS runtime for mobile/hybrid environments.",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -32,27 +32,27 @@
|
|
|
32
32
|
"release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-runtime-mobile"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@salesforce/lds-adapters-uiapi": "^1.
|
|
36
|
-
"@salesforce/lds-bindings": "^1.
|
|
37
|
-
"@salesforce/lds-instrumentation": "^1.
|
|
38
|
-
"@salesforce/lds-priming": "^1.
|
|
35
|
+
"@salesforce/lds-adapters-uiapi": "^1.111.0",
|
|
36
|
+
"@salesforce/lds-bindings": "^1.111.0",
|
|
37
|
+
"@salesforce/lds-instrumentation": "^1.111.0",
|
|
38
|
+
"@salesforce/lds-priming": "^1.111.0",
|
|
39
39
|
"@salesforce/user": "0.0.12",
|
|
40
40
|
"o11y": "244.0.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@luvio/engine": "0.
|
|
44
|
-
"@luvio/environments": "0.
|
|
45
|
-
"@luvio/graphql-parser": "0.
|
|
46
|
-
"@salesforce/lds-adapters-graphql": "^1.
|
|
47
|
-
"@salesforce/lds-drafts": "^1.
|
|
48
|
-
"@salesforce/lds-drafts-adapters-uiapi": "^1.
|
|
49
|
-
"@salesforce/lds-graphql-eval": "^1.
|
|
50
|
-
"@salesforce/lds-network-adapter": "^1.
|
|
51
|
-
"@salesforce/lds-network-nimbus": "^1.
|
|
52
|
-
"@salesforce/lds-store-binary": "^1.
|
|
53
|
-
"@salesforce/lds-store-sql": "^1.
|
|
54
|
-
"@salesforce/lds-utils-adapters": "^1.
|
|
55
|
-
"@salesforce/nimbus-plugin-lds": "^1.
|
|
43
|
+
"@luvio/engine": "0.136.5",
|
|
44
|
+
"@luvio/environments": "0.136.5",
|
|
45
|
+
"@luvio/graphql-parser": "0.136.5",
|
|
46
|
+
"@salesforce/lds-adapters-graphql": "^1.111.0",
|
|
47
|
+
"@salesforce/lds-drafts": "^1.111.0",
|
|
48
|
+
"@salesforce/lds-drafts-adapters-uiapi": "^1.111.0",
|
|
49
|
+
"@salesforce/lds-graphql-eval": "^1.111.0",
|
|
50
|
+
"@salesforce/lds-network-adapter": "^1.111.0",
|
|
51
|
+
"@salesforce/lds-network-nimbus": "^1.111.0",
|
|
52
|
+
"@salesforce/lds-store-binary": "^1.111.0",
|
|
53
|
+
"@salesforce/lds-store-sql": "^1.111.0",
|
|
54
|
+
"@salesforce/lds-utils-adapters": "^1.111.0",
|
|
55
|
+
"@salesforce/nimbus-plugin-lds": "^1.111.0",
|
|
56
56
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
57
57
|
"wait-for-expect": "^3.0.2"
|
|
58
58
|
},
|
package/sfdc/main.js
CHANGED
|
@@ -1055,10 +1055,10 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1055
1055
|
};
|
|
1056
1056
|
const storeBroadcast = function (_rebuildSnapshot, _snapshotDataAvailable) {
|
|
1057
1057
|
validateNotDisposed();
|
|
1058
|
-
//
|
|
1059
|
-
//
|
|
1060
|
-
//
|
|
1061
|
-
return
|
|
1058
|
+
// publishing to L2 is essentially "broadcasting" because the onChanged
|
|
1059
|
+
// handler will fire which will revive records to the main L1 store and
|
|
1060
|
+
// call the base storeBroadcast
|
|
1061
|
+
return publishChangesToDurableStore();
|
|
1062
1062
|
};
|
|
1063
1063
|
const publishChangesToDurableStore = function () {
|
|
1064
1064
|
validateNotDisposed();
|
|
@@ -1279,7 +1279,6 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1279
1279
|
// we don't need to prime metadata
|
|
1280
1280
|
() => { });
|
|
1281
1281
|
snapshotFromMemoryIngest = await ingestAndBroadcastFunc();
|
|
1282
|
-
await publishChangesToDurableStore();
|
|
1283
1282
|
})();
|
|
1284
1283
|
for (const key of keysToReviveAsArray) {
|
|
1285
1284
|
// we are overwriting the previous promise at this key, but that
|
|
@@ -1307,7 +1306,6 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1307
1306
|
// so all we have to do is ingest then write to L2
|
|
1308
1307
|
ingestStagingStore = buildIngestStagingStore(environment);
|
|
1309
1308
|
snapshotFromMemoryIngest = await ingestAndBroadcastFunc();
|
|
1310
|
-
await publishChangesToDurableStore();
|
|
1311
1309
|
}
|
|
1312
1310
|
if (snapshotFromMemoryIngest === undefined) {
|
|
1313
1311
|
return undefined;
|
|
@@ -1320,12 +1318,10 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
1320
1318
|
const result = await reviveSnapshot(environment, durableStore, snapshotFromMemoryIngest, durableStoreErrorHandler, () => environment.storeLookup(select, environment.createSnapshot, refresh));
|
|
1321
1319
|
return result.snapshot;
|
|
1322
1320
|
};
|
|
1323
|
-
const handleErrorResponse = function (ingestAndBroadcastFunc) {
|
|
1321
|
+
const handleErrorResponse = async function (ingestAndBroadcastFunc) {
|
|
1324
1322
|
validateNotDisposed();
|
|
1325
|
-
|
|
1326
|
-
return
|
|
1327
|
-
return snapshotFromMemoryIngest;
|
|
1328
|
-
});
|
|
1323
|
+
ingestStagingStore = buildIngestStagingStore(environment);
|
|
1324
|
+
return ingestAndBroadcastFunc();
|
|
1329
1325
|
};
|
|
1330
1326
|
const getNotifyChangeStoreEntries = function (keys) {
|
|
1331
1327
|
validateNotDisposed();
|
|
@@ -4350,6 +4346,58 @@ function makeStoreEval(preconditioner, objectInfoService, userId, contextProvide
|
|
|
4350
4346
|
* For full license text, see the LICENSE.txt file
|
|
4351
4347
|
*/
|
|
4352
4348
|
|
|
4349
|
+
/* Ideally we would use AbortController but it does not exist in V8, if it is ever polyfilled we can swap for it */
|
|
4350
|
+
class LdsAbortController {
|
|
4351
|
+
constructor() {
|
|
4352
|
+
this.signal = new AbortSignal();
|
|
4353
|
+
}
|
|
4354
|
+
abort() {
|
|
4355
|
+
this.signal.abort();
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
class AbortSignal {
|
|
4359
|
+
constructor() {
|
|
4360
|
+
this._aborted = false;
|
|
4361
|
+
this.listeners = new Map();
|
|
4362
|
+
}
|
|
4363
|
+
get aborted() {
|
|
4364
|
+
return this._aborted;
|
|
4365
|
+
}
|
|
4366
|
+
addEventListener(type, listener) {
|
|
4367
|
+
let listeners = this.listeners.get(type);
|
|
4368
|
+
if (!listeners) {
|
|
4369
|
+
listeners = new Set();
|
|
4370
|
+
this.listeners.set(type, listeners);
|
|
4371
|
+
}
|
|
4372
|
+
listeners.add(listener);
|
|
4373
|
+
}
|
|
4374
|
+
removeEventListener(type, listener) {
|
|
4375
|
+
const listeners = this.listeners.get(type);
|
|
4376
|
+
if (listeners) {
|
|
4377
|
+
listeners.delete(listener);
|
|
4378
|
+
if (listeners.size === 0) {
|
|
4379
|
+
this.listeners.delete(type);
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
dispatchEvent(event) {
|
|
4384
|
+
const listeners = this.listeners.get(event.type);
|
|
4385
|
+
if (listeners) {
|
|
4386
|
+
for (const listener of listeners) {
|
|
4387
|
+
listener(this, event);
|
|
4388
|
+
}
|
|
4389
|
+
}
|
|
4390
|
+
return !event.defaultPrevented;
|
|
4391
|
+
}
|
|
4392
|
+
abort() {
|
|
4393
|
+
if (!this.aborted) {
|
|
4394
|
+
this._aborted = true;
|
|
4395
|
+
const abortEvent = new Event('abort');
|
|
4396
|
+
this.dispatchEvent(abortEvent);
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
|
|
4353
4401
|
class AsyncWorkerPool {
|
|
4354
4402
|
constructor(concurrency) {
|
|
4355
4403
|
this.queue = [];
|
|
@@ -4360,51 +4408,57 @@ class AsyncWorkerPool {
|
|
|
4360
4408
|
return new Promise((resolve, reject) => {
|
|
4361
4409
|
this.queue.push({
|
|
4362
4410
|
...work,
|
|
4363
|
-
workFn: () => work.workFn().then(resolve).catch(reject),
|
|
4411
|
+
workFn: (abortController) => work.workFn(abortController).then(resolve).catch(reject),
|
|
4364
4412
|
});
|
|
4365
4413
|
this.doWork();
|
|
4366
4414
|
});
|
|
4367
4415
|
}
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4416
|
+
/**
|
|
4417
|
+
* cancel all work in the queue and active work
|
|
4418
|
+
* @returns true if all work was cancelled, false if any work could not be cancelled
|
|
4419
|
+
*/
|
|
4420
|
+
cancel() {
|
|
4421
|
+
let success = true;
|
|
4422
|
+
for (const { cancelFn } of this.queue) {
|
|
4423
|
+
if (cancelFn) {
|
|
4424
|
+
try {
|
|
4425
|
+
cancelFn();
|
|
4426
|
+
}
|
|
4427
|
+
catch (_a) {
|
|
4428
|
+
success = false;
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
this.queue = [];
|
|
4433
|
+
for (const { abortController, cancelFn } of this.activeWork) {
|
|
4434
|
+
abortController.abort();
|
|
4376
4435
|
if (cancelFn) {
|
|
4377
|
-
|
|
4436
|
+
try {
|
|
4437
|
+
cancelFn();
|
|
4438
|
+
}
|
|
4439
|
+
catch (_b) {
|
|
4440
|
+
success = false;
|
|
4441
|
+
}
|
|
4378
4442
|
}
|
|
4379
|
-
}
|
|
4380
|
-
|
|
4443
|
+
}
|
|
4444
|
+
this.activeWork = [];
|
|
4445
|
+
return success;
|
|
4381
4446
|
}
|
|
4382
4447
|
doWork() {
|
|
4383
4448
|
while (this.queue.length > 0 && this.activeWork.length < this.concurrency) {
|
|
4384
4449
|
const work = this.queue.shift();
|
|
4385
4450
|
if (work) {
|
|
4386
|
-
|
|
4451
|
+
const abortController = new LdsAbortController();
|
|
4452
|
+
const newWork = { ...work, abortController };
|
|
4453
|
+
this.activeWork.push(newWork);
|
|
4387
4454
|
const { workFn } = work;
|
|
4388
|
-
workFn()
|
|
4389
|
-
.
|
|
4390
|
-
.finally(() => {
|
|
4391
|
-
this.activeWork = this.activeWork.filter((w) => w !== work);
|
|
4455
|
+
workFn(abortController).finally(() => {
|
|
4456
|
+
this.activeWork = this.activeWork.filter((w) => w !== newWork);
|
|
4392
4457
|
this.doWork();
|
|
4393
4458
|
});
|
|
4394
4459
|
}
|
|
4395
4460
|
}
|
|
4396
4461
|
}
|
|
4397
|
-
}
|
|
4398
|
-
function promiseAllSettled(promises) {
|
|
4399
|
-
return Promise.all(promises.map((promise) => promise
|
|
4400
|
-
.then((value) => ({
|
|
4401
|
-
status: 'fulfilled',
|
|
4402
|
-
value,
|
|
4403
|
-
}))
|
|
4404
|
-
.catch((reason) => ({
|
|
4405
|
-
status: 'rejected',
|
|
4406
|
-
reason,
|
|
4407
|
-
}))));
|
|
4408
4462
|
}
|
|
4409
4463
|
|
|
4410
4464
|
/**
|
|
@@ -5720,9 +5774,8 @@ class AbstractResourceRequestActionHandler {
|
|
|
5720
5774
|
const { response, synchronousIngest } = entry;
|
|
5721
5775
|
synchronousIngest(response, action);
|
|
5722
5776
|
}
|
|
5723
|
-
//
|
|
5724
|
-
|
|
5725
|
-
return Promise.resolve();
|
|
5777
|
+
// must call base broadcast
|
|
5778
|
+
return luvio.storeBroadcast();
|
|
5726
5779
|
},
|
|
5727
5780
|
// getTypeCacheKeysRecord uses the response, not the full path factory
|
|
5728
5781
|
// so 2nd parameter will be unused
|
|
@@ -14935,9 +14988,10 @@ const DEFAULT_BATCH_SIZE = 500;
|
|
|
14935
14988
|
const DEFAULT_CONCURRENCY = 6;
|
|
14936
14989
|
class PrimingSession extends EventEmitter {
|
|
14937
14990
|
constructor(config) {
|
|
14991
|
+
var _a, _b;
|
|
14938
14992
|
super();
|
|
14939
|
-
this.batchSize = config.batchSize
|
|
14940
|
-
this.concurrency = config.concurrency
|
|
14993
|
+
this.batchSize = (_a = config.batchSize) !== null && _a !== void 0 ? _a : DEFAULT_BATCH_SIZE;
|
|
14994
|
+
this.concurrency = (_b = config.concurrency) !== null && _b !== void 0 ? _b : DEFAULT_CONCURRENCY;
|
|
14941
14995
|
this.recordLoader = config.recordLoader;
|
|
14942
14996
|
this.recordIngestor = config.recordIngestor;
|
|
14943
14997
|
this.objectInfoLoader = config.objectInfoLoader;
|
|
@@ -14965,12 +15019,20 @@ class PrimingSession extends EventEmitter {
|
|
|
14965
15019
|
this.enqueueBatches(availableBatches);
|
|
14966
15020
|
}
|
|
14967
15021
|
}
|
|
15022
|
+
cancel() {
|
|
15023
|
+
this.networkWorkerPool.cancel();
|
|
15024
|
+
}
|
|
14968
15025
|
// parallelizes batches of priming work
|
|
14969
15026
|
enqueueBatches(batches) {
|
|
14970
15027
|
for (const batch of batches) {
|
|
14971
15028
|
this.networkWorkerPool.push({
|
|
14972
|
-
workFn: () => {
|
|
14973
|
-
return this.recordLoader
|
|
15029
|
+
workFn: (abortController) => {
|
|
15030
|
+
return this.recordLoader
|
|
15031
|
+
.fetchRecordData(batch, abortController)
|
|
15032
|
+
.then(async (result) => {
|
|
15033
|
+
if (abortController.signal.aborted) {
|
|
15034
|
+
return;
|
|
15035
|
+
}
|
|
14974
15036
|
if (result.ok === false) {
|
|
14975
15037
|
const { error } = result;
|
|
14976
15038
|
const primingError = error === 'network-error' ? 'service-unavailable' : 'unknown';
|
|
@@ -14994,6 +15056,9 @@ class PrimingSession extends EventEmitter {
|
|
|
14994
15056
|
this.recordIngestor
|
|
14995
15057
|
.insertRecords(records)
|
|
14996
15058
|
.then(({ written, conflicted }) => {
|
|
15059
|
+
if (abortController.signal.aborted) {
|
|
15060
|
+
return;
|
|
15061
|
+
}
|
|
14997
15062
|
// now that the records are persisted, emit the primed event
|
|
14998
15063
|
if (written.length > 0) {
|
|
14999
15064
|
this.emit('primed', Array.from(written));
|
|
@@ -15010,6 +15075,13 @@ class PrimingSession extends EventEmitter {
|
|
|
15010
15075
|
});
|
|
15011
15076
|
});
|
|
15012
15077
|
},
|
|
15078
|
+
cancelFn: () => {
|
|
15079
|
+
this.emit('error', {
|
|
15080
|
+
ids: batch.ids,
|
|
15081
|
+
code: 'canceled',
|
|
15082
|
+
message: `batch canceled`,
|
|
15083
|
+
});
|
|
15084
|
+
},
|
|
15013
15085
|
});
|
|
15014
15086
|
}
|
|
15015
15087
|
}
|
|
@@ -15035,8 +15107,6 @@ class PrimingSession extends EventEmitter {
|
|
|
15035
15107
|
}
|
|
15036
15108
|
|
|
15037
15109
|
const requiredPrefix = `required_`;
|
|
15038
|
-
// note this is automatically incremented by scripts/release/bump-api-version.js at each release
|
|
15039
|
-
const apiVersion = `v58.0`;
|
|
15040
15110
|
const requiredFieldMap = {
|
|
15041
15111
|
ApiName: 'ApiName',
|
|
15042
15112
|
Id: 'Id',
|
|
@@ -15050,10 +15120,10 @@ class RecordLoaderGraphQL {
|
|
|
15050
15120
|
constructor(networkAdapter) {
|
|
15051
15121
|
this.networkAdapter = networkAdapter;
|
|
15052
15122
|
}
|
|
15053
|
-
async fetchRecordData(batch) {
|
|
15123
|
+
async fetchRecordData(batch, abortController) {
|
|
15054
15124
|
let rep;
|
|
15055
15125
|
try {
|
|
15056
|
-
rep = await this.callGraphQL(batch);
|
|
15126
|
+
rep = await this.callGraphQL(batch, abortController);
|
|
15057
15127
|
}
|
|
15058
15128
|
catch (e) {
|
|
15059
15129
|
return {
|
|
@@ -15095,25 +15165,9 @@ class RecordLoaderGraphQL {
|
|
|
15095
15165
|
missingIds: Array.from(seenRecords),
|
|
15096
15166
|
};
|
|
15097
15167
|
}
|
|
15098
|
-
|
|
15168
|
+
callGraphQL(batch, abortController) {
|
|
15099
15169
|
const query = this.generateGraphQLQuery(batch.type, batch.fields);
|
|
15100
|
-
|
|
15101
|
-
baseUri: `/services/data/${apiVersion}`,
|
|
15102
|
-
basePath: '/graphql',
|
|
15103
|
-
method: 'POST',
|
|
15104
|
-
priority: 'background',
|
|
15105
|
-
body: {
|
|
15106
|
-
query,
|
|
15107
|
-
variables: {
|
|
15108
|
-
ids: batch.ids,
|
|
15109
|
-
first: batch.ids.length,
|
|
15110
|
-
},
|
|
15111
|
-
},
|
|
15112
|
-
queryParams: {},
|
|
15113
|
-
urlParams: {},
|
|
15114
|
-
headers: {},
|
|
15115
|
-
}, {});
|
|
15116
|
-
return response.body;
|
|
15170
|
+
return this.networkAdapter.postGraphQL(query, { ids: batch.ids, first: batch.ids.length }, abortController);
|
|
15117
15171
|
}
|
|
15118
15172
|
generateGraphQLQuery(type, fields) {
|
|
15119
15173
|
const fieldList = Object.keys(requiredFieldMap)
|
|
@@ -15249,8 +15303,57 @@ function instrumentPrimingSession(session) {
|
|
|
15249
15303
|
return session;
|
|
15250
15304
|
}
|
|
15251
15305
|
|
|
15306
|
+
// so eslint doesn't complain about nimbus
|
|
15307
|
+
/* global __nimbus */
|
|
15308
|
+
// note this is automatically incremented by scripts/release/bump-api-version.js at each release
|
|
15309
|
+
const apiVersion = `v58.0`;
|
|
15310
|
+
class NimbusPrimingNetworkAdapter {
|
|
15311
|
+
postGraphQL(query, variables, abortController) {
|
|
15312
|
+
return new Promise((resolve, reject) => {
|
|
15313
|
+
let listener;
|
|
15314
|
+
const unregisterListener = () => {
|
|
15315
|
+
if (listener) {
|
|
15316
|
+
abortController.signal.removeEventListener('abort', listener);
|
|
15317
|
+
}
|
|
15318
|
+
};
|
|
15319
|
+
__nimbus.plugins.LdsNetworkAdapter
|
|
15320
|
+
.sendRequest({
|
|
15321
|
+
method: 'POST',
|
|
15322
|
+
path: `/services/data/${apiVersion}/graphql`,
|
|
15323
|
+
body: JSON.stringify({
|
|
15324
|
+
query,
|
|
15325
|
+
variables,
|
|
15326
|
+
}),
|
|
15327
|
+
headers: {},
|
|
15328
|
+
queryParams: {},
|
|
15329
|
+
priority: 'background',
|
|
15330
|
+
observabilityContext: {},
|
|
15331
|
+
}, (response) => {
|
|
15332
|
+
unregisterListener();
|
|
15333
|
+
const { body } = response;
|
|
15334
|
+
if (body) {
|
|
15335
|
+
resolve(JSON.parse(body));
|
|
15336
|
+
}
|
|
15337
|
+
else {
|
|
15338
|
+
reject(new Error('No body returned from graphql endpoint'));
|
|
15339
|
+
}
|
|
15340
|
+
}, (error) => {
|
|
15341
|
+
unregisterListener();
|
|
15342
|
+
reject(error);
|
|
15343
|
+
})
|
|
15344
|
+
.then((cancellationToken) => {
|
|
15345
|
+
listener = () => {
|
|
15346
|
+
__nimbus.plugins.LdsNetworkAdapter.cancelRequest(cancellationToken);
|
|
15347
|
+
};
|
|
15348
|
+
abortController.signal.addEventListener('abort', listener);
|
|
15349
|
+
});
|
|
15350
|
+
});
|
|
15351
|
+
}
|
|
15352
|
+
}
|
|
15353
|
+
|
|
15252
15354
|
function primingSessionFactory(config) {
|
|
15253
|
-
const {
|
|
15355
|
+
const { store, objectInfoService, getLuvio } = config;
|
|
15356
|
+
const networkAdapter = new NimbusPrimingNetworkAdapter();
|
|
15254
15357
|
const recordLoader = new RecordLoaderGraphQL(networkAdapter);
|
|
15255
15358
|
const recordIngestor = new RecordIngestor(store, getLuvio);
|
|
15256
15359
|
const session = new PrimingSession({
|
|
@@ -15376,7 +15479,6 @@ function getRuntime() {
|
|
|
15376
15479
|
createPrimingSession: (config) => {
|
|
15377
15480
|
return primingSessionFactory({
|
|
15378
15481
|
store: lazyBaseDurableStore,
|
|
15379
|
-
networkAdapter: lazyNetworkAdapter,
|
|
15380
15482
|
objectInfoService: lazyObjectInfoService,
|
|
15381
15483
|
getLuvio: () => lazyLuvio,
|
|
15382
15484
|
concurrency: config.concurrency,
|
|
@@ -15399,4 +15501,4 @@ register({
|
|
|
15399
15501
|
});
|
|
15400
15502
|
|
|
15401
15503
|
export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
|
|
15402
|
-
// version: 1.
|
|
15504
|
+
// version: 1.111.0-f30e5e921
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PrimingNetworkAdapter } from '@salesforce/lds-priming';
|
|
2
|
+
import type { GraphQLRepresentation } from '@salesforce/lds-adapters-uiapi';
|
|
3
|
+
import type { LdsAbortController } from '@salesforce/lds-utils-adapters';
|
|
4
|
+
export declare class NimbusPrimingNetworkAdapter implements PrimingNetworkAdapter {
|
|
5
|
+
postGraphQL(query: string, variables: Record<string, any>, abortController: LdsAbortController): Promise<GraphQLRepresentation>;
|
|
6
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { PrimingSession } from '@salesforce/lds-priming';
|
|
2
|
-
import type { Luvio
|
|
2
|
+
import type { Luvio } from '@luvio/engine';
|
|
3
3
|
import type { NimbusSqliteStore } from '../durableStore/NimbusSqliteStore/NimbusSqliteStore';
|
|
4
4
|
import type { ObjectInfoService } from '../main';
|
|
5
5
|
export interface PrimingSessionFactoryConfig {
|
|
6
6
|
store: NimbusSqliteStore;
|
|
7
|
-
networkAdapter: NetworkAdapter;
|
|
8
7
|
objectInfoService: ObjectInfoService;
|
|
9
8
|
getLuvio: () => Luvio;
|
|
10
9
|
concurrency?: number;
|