@salesforce/lds-runtime-mobile 1.110.2 → 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 +171 -68
- 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 +171 -68
- 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
|
/**
|
|
@@ -14934,9 +14988,10 @@ const DEFAULT_BATCH_SIZE = 500;
|
|
|
14934
14988
|
const DEFAULT_CONCURRENCY = 6;
|
|
14935
14989
|
class PrimingSession extends EventEmitter {
|
|
14936
14990
|
constructor(config) {
|
|
14991
|
+
var _a, _b;
|
|
14937
14992
|
super();
|
|
14938
|
-
this.batchSize = config.batchSize
|
|
14939
|
-
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;
|
|
14940
14995
|
this.recordLoader = config.recordLoader;
|
|
14941
14996
|
this.recordIngestor = config.recordIngestor;
|
|
14942
14997
|
this.objectInfoLoader = config.objectInfoLoader;
|
|
@@ -14964,12 +15019,20 @@ class PrimingSession extends EventEmitter {
|
|
|
14964
15019
|
this.enqueueBatches(availableBatches);
|
|
14965
15020
|
}
|
|
14966
15021
|
}
|
|
15022
|
+
cancel() {
|
|
15023
|
+
this.networkWorkerPool.cancel();
|
|
15024
|
+
}
|
|
14967
15025
|
// parallelizes batches of priming work
|
|
14968
15026
|
enqueueBatches(batches) {
|
|
14969
15027
|
for (const batch of batches) {
|
|
14970
15028
|
this.networkWorkerPool.push({
|
|
14971
|
-
workFn: () => {
|
|
14972
|
-
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
|
+
}
|
|
14973
15036
|
if (result.ok === false) {
|
|
14974
15037
|
const { error } = result;
|
|
14975
15038
|
const primingError = error === 'network-error' ? 'service-unavailable' : 'unknown';
|
|
@@ -14993,6 +15056,9 @@ class PrimingSession extends EventEmitter {
|
|
|
14993
15056
|
this.recordIngestor
|
|
14994
15057
|
.insertRecords(records)
|
|
14995
15058
|
.then(({ written, conflicted }) => {
|
|
15059
|
+
if (abortController.signal.aborted) {
|
|
15060
|
+
return;
|
|
15061
|
+
}
|
|
14996
15062
|
// now that the records are persisted, emit the primed event
|
|
14997
15063
|
if (written.length > 0) {
|
|
14998
15064
|
this.emit('primed', Array.from(written));
|
|
@@ -15009,6 +15075,13 @@ class PrimingSession extends EventEmitter {
|
|
|
15009
15075
|
});
|
|
15010
15076
|
});
|
|
15011
15077
|
},
|
|
15078
|
+
cancelFn: () => {
|
|
15079
|
+
this.emit('error', {
|
|
15080
|
+
ids: batch.ids,
|
|
15081
|
+
code: 'canceled',
|
|
15082
|
+
message: `batch canceled`,
|
|
15083
|
+
});
|
|
15084
|
+
},
|
|
15012
15085
|
});
|
|
15013
15086
|
}
|
|
15014
15087
|
}
|
|
@@ -15034,8 +15107,6 @@ class PrimingSession extends EventEmitter {
|
|
|
15034
15107
|
}
|
|
15035
15108
|
|
|
15036
15109
|
const requiredPrefix = `required_`;
|
|
15037
|
-
// note this is automatically incremented by scripts/release/bump-api-version.js at each release
|
|
15038
|
-
const apiVersion = `v58.0`;
|
|
15039
15110
|
const requiredFieldMap = {
|
|
15040
15111
|
ApiName: 'ApiName',
|
|
15041
15112
|
Id: 'Id',
|
|
@@ -15049,10 +15120,10 @@ class RecordLoaderGraphQL {
|
|
|
15049
15120
|
constructor(networkAdapter) {
|
|
15050
15121
|
this.networkAdapter = networkAdapter;
|
|
15051
15122
|
}
|
|
15052
|
-
async fetchRecordData(batch) {
|
|
15123
|
+
async fetchRecordData(batch, abortController) {
|
|
15053
15124
|
let rep;
|
|
15054
15125
|
try {
|
|
15055
|
-
rep = await this.callGraphQL(batch);
|
|
15126
|
+
rep = await this.callGraphQL(batch, abortController);
|
|
15056
15127
|
}
|
|
15057
15128
|
catch (e) {
|
|
15058
15129
|
return {
|
|
@@ -15094,25 +15165,9 @@ class RecordLoaderGraphQL {
|
|
|
15094
15165
|
missingIds: Array.from(seenRecords),
|
|
15095
15166
|
};
|
|
15096
15167
|
}
|
|
15097
|
-
|
|
15168
|
+
callGraphQL(batch, abortController) {
|
|
15098
15169
|
const query = this.generateGraphQLQuery(batch.type, batch.fields);
|
|
15099
|
-
|
|
15100
|
-
baseUri: `/services/data/${apiVersion}`,
|
|
15101
|
-
basePath: '/graphql',
|
|
15102
|
-
method: 'POST',
|
|
15103
|
-
priority: 'background',
|
|
15104
|
-
body: {
|
|
15105
|
-
query,
|
|
15106
|
-
variables: {
|
|
15107
|
-
ids: batch.ids,
|
|
15108
|
-
first: batch.ids.length,
|
|
15109
|
-
},
|
|
15110
|
-
},
|
|
15111
|
-
queryParams: {},
|
|
15112
|
-
urlParams: {},
|
|
15113
|
-
headers: {},
|
|
15114
|
-
}, {});
|
|
15115
|
-
return response.body;
|
|
15170
|
+
return this.networkAdapter.postGraphQL(query, { ids: batch.ids, first: batch.ids.length }, abortController);
|
|
15116
15171
|
}
|
|
15117
15172
|
generateGraphQLQuery(type, fields) {
|
|
15118
15173
|
const fieldList = Object.keys(requiredFieldMap)
|
|
@@ -15248,8 +15303,57 @@ function instrumentPrimingSession(session) {
|
|
|
15248
15303
|
return session;
|
|
15249
15304
|
}
|
|
15250
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
|
+
|
|
15251
15354
|
function primingSessionFactory(config) {
|
|
15252
|
-
const {
|
|
15355
|
+
const { store, objectInfoService, getLuvio } = config;
|
|
15356
|
+
const networkAdapter = new NimbusPrimingNetworkAdapter();
|
|
15253
15357
|
const recordLoader = new RecordLoaderGraphQL(networkAdapter);
|
|
15254
15358
|
const recordIngestor = new RecordIngestor(store, getLuvio);
|
|
15255
15359
|
const session = new PrimingSession({
|
|
@@ -15375,7 +15479,6 @@ function getRuntime() {
|
|
|
15375
15479
|
createPrimingSession: (config) => {
|
|
15376
15480
|
return primingSessionFactory({
|
|
15377
15481
|
store: lazyBaseDurableStore,
|
|
15378
|
-
networkAdapter: lazyNetworkAdapter,
|
|
15379
15482
|
objectInfoService: lazyObjectInfoService,
|
|
15380
15483
|
getLuvio: () => lazyLuvio,
|
|
15381
15484
|
concurrency: config.concurrency,
|
|
@@ -15398,4 +15501,4 @@ register({
|
|
|
15398
15501
|
});
|
|
15399
15502
|
|
|
15400
15503
|
export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
|
|
15401
|
-
// 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
|
/**
|
|
@@ -14934,9 +14988,10 @@ const DEFAULT_BATCH_SIZE = 500;
|
|
|
14934
14988
|
const DEFAULT_CONCURRENCY = 6;
|
|
14935
14989
|
class PrimingSession extends EventEmitter {
|
|
14936
14990
|
constructor(config) {
|
|
14991
|
+
var _a, _b;
|
|
14937
14992
|
super();
|
|
14938
|
-
this.batchSize = config.batchSize
|
|
14939
|
-
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;
|
|
14940
14995
|
this.recordLoader = config.recordLoader;
|
|
14941
14996
|
this.recordIngestor = config.recordIngestor;
|
|
14942
14997
|
this.objectInfoLoader = config.objectInfoLoader;
|
|
@@ -14964,12 +15019,20 @@ class PrimingSession extends EventEmitter {
|
|
|
14964
15019
|
this.enqueueBatches(availableBatches);
|
|
14965
15020
|
}
|
|
14966
15021
|
}
|
|
15022
|
+
cancel() {
|
|
15023
|
+
this.networkWorkerPool.cancel();
|
|
15024
|
+
}
|
|
14967
15025
|
// parallelizes batches of priming work
|
|
14968
15026
|
enqueueBatches(batches) {
|
|
14969
15027
|
for (const batch of batches) {
|
|
14970
15028
|
this.networkWorkerPool.push({
|
|
14971
|
-
workFn: () => {
|
|
14972
|
-
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
|
+
}
|
|
14973
15036
|
if (result.ok === false) {
|
|
14974
15037
|
const { error } = result;
|
|
14975
15038
|
const primingError = error === 'network-error' ? 'service-unavailable' : 'unknown';
|
|
@@ -14993,6 +15056,9 @@ class PrimingSession extends EventEmitter {
|
|
|
14993
15056
|
this.recordIngestor
|
|
14994
15057
|
.insertRecords(records)
|
|
14995
15058
|
.then(({ written, conflicted }) => {
|
|
15059
|
+
if (abortController.signal.aborted) {
|
|
15060
|
+
return;
|
|
15061
|
+
}
|
|
14996
15062
|
// now that the records are persisted, emit the primed event
|
|
14997
15063
|
if (written.length > 0) {
|
|
14998
15064
|
this.emit('primed', Array.from(written));
|
|
@@ -15009,6 +15075,13 @@ class PrimingSession extends EventEmitter {
|
|
|
15009
15075
|
});
|
|
15010
15076
|
});
|
|
15011
15077
|
},
|
|
15078
|
+
cancelFn: () => {
|
|
15079
|
+
this.emit('error', {
|
|
15080
|
+
ids: batch.ids,
|
|
15081
|
+
code: 'canceled',
|
|
15082
|
+
message: `batch canceled`,
|
|
15083
|
+
});
|
|
15084
|
+
},
|
|
15012
15085
|
});
|
|
15013
15086
|
}
|
|
15014
15087
|
}
|
|
@@ -15034,8 +15107,6 @@ class PrimingSession extends EventEmitter {
|
|
|
15034
15107
|
}
|
|
15035
15108
|
|
|
15036
15109
|
const requiredPrefix = `required_`;
|
|
15037
|
-
// note this is automatically incremented by scripts/release/bump-api-version.js at each release
|
|
15038
|
-
const apiVersion = `v58.0`;
|
|
15039
15110
|
const requiredFieldMap = {
|
|
15040
15111
|
ApiName: 'ApiName',
|
|
15041
15112
|
Id: 'Id',
|
|
@@ -15049,10 +15120,10 @@ class RecordLoaderGraphQL {
|
|
|
15049
15120
|
constructor(networkAdapter) {
|
|
15050
15121
|
this.networkAdapter = networkAdapter;
|
|
15051
15122
|
}
|
|
15052
|
-
async fetchRecordData(batch) {
|
|
15123
|
+
async fetchRecordData(batch, abortController) {
|
|
15053
15124
|
let rep;
|
|
15054
15125
|
try {
|
|
15055
|
-
rep = await this.callGraphQL(batch);
|
|
15126
|
+
rep = await this.callGraphQL(batch, abortController);
|
|
15056
15127
|
}
|
|
15057
15128
|
catch (e) {
|
|
15058
15129
|
return {
|
|
@@ -15094,25 +15165,9 @@ class RecordLoaderGraphQL {
|
|
|
15094
15165
|
missingIds: Array.from(seenRecords),
|
|
15095
15166
|
};
|
|
15096
15167
|
}
|
|
15097
|
-
|
|
15168
|
+
callGraphQL(batch, abortController) {
|
|
15098
15169
|
const query = this.generateGraphQLQuery(batch.type, batch.fields);
|
|
15099
|
-
|
|
15100
|
-
baseUri: `/services/data/${apiVersion}`,
|
|
15101
|
-
basePath: '/graphql',
|
|
15102
|
-
method: 'POST',
|
|
15103
|
-
priority: 'background',
|
|
15104
|
-
body: {
|
|
15105
|
-
query,
|
|
15106
|
-
variables: {
|
|
15107
|
-
ids: batch.ids,
|
|
15108
|
-
first: batch.ids.length,
|
|
15109
|
-
},
|
|
15110
|
-
},
|
|
15111
|
-
queryParams: {},
|
|
15112
|
-
urlParams: {},
|
|
15113
|
-
headers: {},
|
|
15114
|
-
}, {});
|
|
15115
|
-
return response.body;
|
|
15170
|
+
return this.networkAdapter.postGraphQL(query, { ids: batch.ids, first: batch.ids.length }, abortController);
|
|
15116
15171
|
}
|
|
15117
15172
|
generateGraphQLQuery(type, fields) {
|
|
15118
15173
|
const fieldList = Object.keys(requiredFieldMap)
|
|
@@ -15248,8 +15303,57 @@ function instrumentPrimingSession(session) {
|
|
|
15248
15303
|
return session;
|
|
15249
15304
|
}
|
|
15250
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
|
+
|
|
15251
15354
|
function primingSessionFactory(config) {
|
|
15252
|
-
const {
|
|
15355
|
+
const { store, objectInfoService, getLuvio } = config;
|
|
15356
|
+
const networkAdapter = new NimbusPrimingNetworkAdapter();
|
|
15253
15357
|
const recordLoader = new RecordLoaderGraphQL(networkAdapter);
|
|
15254
15358
|
const recordIngestor = new RecordIngestor(store, getLuvio);
|
|
15255
15359
|
const session = new PrimingSession({
|
|
@@ -15375,7 +15479,6 @@ function getRuntime() {
|
|
|
15375
15479
|
createPrimingSession: (config) => {
|
|
15376
15480
|
return primingSessionFactory({
|
|
15377
15481
|
store: lazyBaseDurableStore,
|
|
15378
|
-
networkAdapter: lazyNetworkAdapter,
|
|
15379
15482
|
objectInfoService: lazyObjectInfoService,
|
|
15380
15483
|
getLuvio: () => lazyLuvio,
|
|
15381
15484
|
concurrency: config.concurrency,
|
|
@@ -15398,4 +15501,4 @@ register({
|
|
|
15398
15501
|
});
|
|
15399
15502
|
|
|
15400
15503
|
export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
|
|
15401
|
-
// 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;
|