@komaci/prefetch 242.1.9 → 242.2.1

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.
@@ -0,0 +1,8 @@
1
+ export const createRouter = jest.fn().mockImplementation((config) => {
2
+ return {
3
+ config,
4
+ subscribe: jest.fn(),
5
+ navigate: jest.fn(),
6
+ };
7
+ });
8
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1,8 @@
1
+ export const createRouter = jest.fn().mockImplementation((config) => {
2
+ return {
3
+ config,
4
+ subscribe: jest.fn(),
5
+ navigate: jest.fn(),
6
+ };
7
+ });
8
+ //# sourceMappingURL=router.js.map
@@ -1,3 +1,3 @@
1
- declare const _default: import("packages/@komaci/resolver/src/modules/komaci/resolverTypes/resolverTypes").AdgModuleHandle | undefined;
1
+ declare const _default: import("komaci/resolverTypes").AdgModuleHandle | undefined;
2
2
  export default _default;
3
3
  //# sourceMappingURL=mockAdgModule.d.ts.map
@@ -0,0 +1,11 @@
1
+ import registerAdgFunction from 'komaci/registerAdgFunction';
2
+ const emptyAdg = {
3
+ parentClass: undefined,
4
+ properties: {},
5
+ functions: [],
6
+ composition: () => [],
7
+ };
8
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
9
+ const adgFunction = (fct) => emptyAdg;
10
+ export default registerAdgFunction(adgFunction);
11
+ //# sourceMappingURL=mockAdgModule.js.map
@@ -0,0 +1,15 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ const mockInstrumentObj = {
3
+ log: jest.fn(),
4
+ error: jest.fn(),
5
+ trackValue: jest.fn(),
6
+ startActivity: jest.fn().mockImplementation((name) => ({
7
+ stop: jest.fn(),
8
+ error: jest.fn(),
9
+ })),
10
+ incrementCounter: jest.fn(),
11
+ };
12
+ export const getInstrumentation = jest
13
+ .fn()
14
+ .mockImplementation((name) => mockInstrumentObj);
15
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,6 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ export const wireContextSchema = {};
3
+ export const batchSchema = {};
4
+ export const bulkResolveSchema = {};
5
+ export const prefetchSchema = {};
6
+ //# sourceMappingURL=sf_komaci.js.map
@@ -4,51 +4,51 @@ import { createRouter } from 'lwr/router';
4
4
  // NOTE: Backward compatible prefetch until primer is updated to handle this.
5
5
  // TODO W-9690128 - Let's potentially remove this prefetch method and update lsdk code to call `getPrefetchState` directly.
6
6
  export function prefetch(routes = [], pageReferences = [], config) {
7
- if (!routes?.length || !pageReferences?.length) {
8
- return Promise.resolve([]);
9
- }
10
-
11
- const router = createRouter({
12
- routes
13
- });
14
- return new Promise((resolve, reject) => {
15
- let currentState;
16
- const addressesProcessed = [];
17
- const wrappedConfig = {
18
- maxConcurrent: config?.maxConcurrent,
19
- onAddressProcessed: status => {
20
- addressesProcessed.push(status);
21
- if (config && config.onAddressProcessed) config.onAddressProcessed(status);
22
- },
23
- onStateChanged: status => {
24
- const {
25
- state
26
- } = status;
27
-
28
- if (state === 'running') {
29
- if (!currentState) {
30
- currentState = state;
31
- } else {
32
- reject(new Error(`Unexpected state transition. ${currentState} -> ${state}`));
33
- }
34
- } else if (state === 'done') {
35
- if (addressesProcessed.length !== pageReferences.length) {
36
- reject(new Error(`Prefetch error, expected ${pageReferences.length} addresses processed, but only got ${addressesProcessed.length}`));
37
- }
38
-
39
- resolve(addressesProcessed);
40
- } else if (state === 'error') {
41
- reject(new Error(`Prefetch error: ${status.message}`));
42
- }
43
-
44
- if (config && config.onStateChanged) config.onStateChanged(status);
45
- },
46
- instrumentationContext: config?.instrumentationContext,
47
- downloadImage: config?.downloadImage
48
- };
49
- getPrefetchService(router, pageReferences, wrappedConfig);
50
- });
7
+ if (!(routes === null || routes === void 0 ? void 0 : routes.length) || !(pageReferences === null || pageReferences === void 0 ? void 0 : pageReferences.length)) {
8
+ return Promise.resolve([]);
9
+ }
10
+ const router = createRouter({
11
+ routes,
12
+ });
13
+ return new Promise((resolve, reject) => {
14
+ let currentState;
15
+ const addressesProcessed = [];
16
+ const wrappedConfig = {
17
+ maxConcurrent: config === null || config === void 0 ? void 0 : config.maxConcurrent,
18
+ onAddressProcessed: (status) => {
19
+ addressesProcessed.push(status);
20
+ if (config && config.onAddressProcessed)
21
+ config.onAddressProcessed(status);
22
+ },
23
+ onStateChanged: (status) => {
24
+ const { state } = status;
25
+ if (state === 'running') {
26
+ if (!currentState) {
27
+ currentState = state;
28
+ }
29
+ else {
30
+ reject(new Error(`Unexpected state transition. ${currentState} -> ${state}`));
31
+ }
32
+ }
33
+ else if (state === 'done') {
34
+ if (addressesProcessed.length !== pageReferences.length) {
35
+ reject(new Error(`Prefetch error, expected ${pageReferences.length} addresses processed, but only got ${addressesProcessed.length}`));
36
+ }
37
+ resolve(addressesProcessed);
38
+ }
39
+ else if (state === 'error') {
40
+ reject(new Error(`Prefetch error: ${status.message}`));
41
+ }
42
+ if (config && config.onStateChanged)
43
+ config.onStateChanged(status);
44
+ },
45
+ instrumentationContext: config === null || config === void 0 ? void 0 : config.instrumentationContext,
46
+ downloadImage: config === null || config === void 0 ? void 0 : config.downloadImage,
47
+ };
48
+ getPrefetchService(router, pageReferences, wrappedConfig);
49
+ });
51
50
  }
52
51
  export function getPrefetchService(router, addresses, config) {
53
- return new PrefetchService(router, addresses, config);
54
- }
52
+ return new PrefetchService(router, addresses, config);
53
+ }
54
+ //# sourceMappingURL=prefetch.js.map
@@ -1,509 +1,443 @@
1
- import { ERROR_PREFIX, PrefetchStatusStates as STATE } from 'komaci/prefetchTypes';
1
+ import { ERROR_PREFIX, PrefetchStatusStates as STATE, } from 'komaci/prefetchTypes';
2
2
  import { getInstrumentation } from 'o11y/client';
3
3
  import { getBulkAdgResolver } from 'komaci/resolver';
4
4
  import { InstrumentedAction } from 'komaci/instrumentedAction';
5
- import { bulkResolveSchema, prefetchSchema, prefetchServiceSchema, totalRoutingSchema } from 'o11y_schema/sf_komaci';
5
+ import { bulkResolveSchema, prefetchSchema, prefetchServiceSchema, totalRoutingSchema, } from 'o11y_schema/sf_komaci';
6
6
  const NO_ADG_MODULE_FOUND = 'No ADG module found for given address.';
7
7
  const ValidStatusTransitions = {
8
- [STATE.init]: [STATE.running, STATE.stopped, STATE.error],
9
- [STATE.running]: [STATE.done, STATE.error, STATE.stopped],
10
- [STATE.error]: [STATE.stopped, STATE.done],
11
- [STATE.done]: [STATE.stopped],
12
- [STATE.stopped]: [],
13
-
14
- isValid(oldState, newState) {
15
- return this[oldState].includes(newState);
16
- }
17
-
8
+ [STATE.init]: [STATE.running, STATE.stopped, STATE.error],
9
+ [STATE.running]: [STATE.done, STATE.error, STATE.stopped],
10
+ [STATE.error]: [STATE.stopped, STATE.done],
11
+ [STATE.done]: [STATE.stopped],
12
+ [STATE.stopped]: [],
13
+ isValid(oldState, newState) {
14
+ return this[oldState].includes(newState);
15
+ },
18
16
  };
19
17
  export class PrefetchService {
20
- config = {};
21
- state = STATE.init;
22
- apiOptions = {};
23
-
24
- constructor(router, addresses, config = {}) {
25
- if (!router) {
26
- throw new TypeError(`${ERROR_PREFIX} Must provide Router.`);
18
+ constructor(router, addresses, config = {}) {
19
+ this.config = {};
20
+ this.state = STATE.init;
21
+ this.apiOptions = {};
22
+ if (!router) {
23
+ throw new TypeError(`${ERROR_PREFIX} Must provide Router.`);
24
+ }
25
+ this.config = config;
26
+ this.apiOptions.instrumentationContext = this.config.instrumentationContext
27
+ ? this.config.instrumentationContext
28
+ : undefined;
29
+ this.router = router;
30
+ this.adgMap = new Map();
31
+ this.resolutionGroups = [];
32
+ this._instrumentation = getInstrumentation('komaci');
33
+ this._activity = this._instrumentation.startActivity('prefetch', this.apiOptions);
34
+ this._size = addresses.length;
35
+ //FIXME: to use o11y.startActivity() when o11y available
36
+ this._startTime = Date.now();
37
+ this.prefetch(addresses);
27
38
  }
28
-
29
- this.config = config;
30
- this.apiOptions.instrumentationContext = this.config.instrumentationContext ? this.config.instrumentationContext : undefined;
31
- this.router = router;
32
- this.adgMap = new Map();
33
- this.resolutionGroups = [];
34
- this._instrumentation = getInstrumentation('komaci');
35
- this._activity = this._instrumentation.startActivity('prefetch', this.apiOptions);
36
- this._size = addresses.length; //FIXME: to use o11y.startActivity() when o11y available
37
-
38
- this._startTime = Date.now();
39
- this.prefetch(addresses);
40
- }
41
- /**
42
- * Processes the given address through the router, retrieving the AdgFunction if
43
- * available.
44
- * @param address to process
45
- * @returns AdgRoutingResult encapsulating the status, original address, and adgFn
46
- */
47
-
48
-
49
- processAddress(address) {
50
- const userSchemaData = {
51
- page: JSON.stringify(address)
52
- };
53
- let resolveViewResult;
54
-
55
- try {
56
- resolveViewResult = this.router.resolveView(address);
57
- } catch (err) {
58
- this._instrumentation.error(err, prefetchSchema, userSchemaData, this.apiOptions);
59
-
60
- return Promise.resolve(this.getErrorAddress(address, 'Unexpected exception during routing: ' + err?.message));
39
+ /**
40
+ * Processes the given address through the router, retrieving the AdgFunction if
41
+ * available.
42
+ * @param address to process
43
+ * @returns AdgRoutingResult encapsulating the status, original address, and adgFn
44
+ */
45
+ processAddress(address) {
46
+ const userSchemaData = { page: JSON.stringify(address) };
47
+ let resolveViewResult;
48
+ try {
49
+ resolveViewResult = this.router.resolveView(address);
50
+ }
51
+ catch (err) {
52
+ this._instrumentation.error(err, prefetchSchema, userSchemaData, this.apiOptions);
53
+ return Promise.resolve(this.getErrorAddress(address, 'Unexpected exception during routing: ' + (err === null || err === void 0 ? void 0 : err.message)));
54
+ }
55
+ return resolveViewResult
56
+ .then((destination) => {
57
+ return this.onRoutingResult(address, destination);
58
+ })
59
+ .then((value) => {
60
+ this._instrumentation.log(prefetchSchema, userSchemaData, this.apiOptions);
61
+ return value;
62
+ })
63
+ .catch((err) => {
64
+ this._instrumentation.error(err, prefetchSchema, userSchemaData, this.apiOptions);
65
+ return this.getErrorAddress(address, (err === null || err === void 0 ? void 0 : err.message)
66
+ ? 'Unexpected exception processing routing result: ' +
67
+ (err === null || err === void 0 ? void 0 : err.message)
68
+ : 'Unknown exception processing routing result.');
69
+ });
61
70
  }
62
-
63
- return resolveViewResult.then(destination => {
64
- return this.onRoutingResult(address, destination);
65
- }).then(value => {
66
- this._instrumentation.log(prefetchSchema, userSchemaData, this.apiOptions);
67
-
68
- return value;
69
- }).catch(err => {
70
- this._instrumentation.error(err, prefetchSchema, userSchemaData, this.apiOptions);
71
-
72
- return this.getErrorAddress(address, err?.message ? 'Unexpected exception processing routing result: ' + err?.message : 'Unknown exception processing routing result.');
73
- });
74
- }
75
-
76
- getErrorAddress(address, reason) {
77
- return {
78
- address,
79
- success: false,
80
- reason: reason
81
- };
82
- }
83
- /**
84
- * Determine if the router has an adg for the given address. For each result
85
- * with an adg, group the address with other addresses that resolve to the same
86
- * adg.
87
- *
88
- * @param address that resolves to this routingResult
89
- * @param routingResult provided by the router for this address
90
- * @returns adgRoutingResult
91
- */
92
-
93
-
94
- async onRoutingResult(address, routingResult) {
95
- const adg = 'komaci';
96
- const {
97
- viewset = {}
98
- } = routingResult;
99
- let adgModuleImporter; // if routing handler only provides komaci view, use komaci module importer
100
-
101
- if (viewset[adg]) {
102
- adgModuleImporter = viewset[adg];
103
- } else if (viewset['default']) {
104
- // calculate komaci specifier using generic default viewset
105
- const viewInfo = viewset['default'];
106
-
107
- if (viewInfo) {
108
- if (viewInfo.specifier) {
109
- const komaciSpecifier = '@salesforce/komaci/' + viewInfo.specifier.replace('/', '__'); // create adgModuleImporter using komaciSpecifier
110
-
111
- adgModuleImporter = () => import(komaciSpecifier);
71
+ getErrorAddress(address, reason) {
72
+ return {
73
+ address,
74
+ success: false,
75
+ reason: reason,
76
+ };
77
+ }
78
+ /**
79
+ * Determine if the router has an adg for the given address. For each result
80
+ * with an adg, group the address with other addresses that resolve to the same
81
+ * adg.
82
+ *
83
+ * @param address that resolves to this routingResult
84
+ * @param routingResult provided by the router for this address
85
+ * @returns adgRoutingResult
86
+ */
87
+ async onRoutingResult(address, routingResult) {
88
+ const adg = 'komaci';
89
+ const { viewset = {} } = routingResult;
90
+ let adgModuleImporter;
91
+ // if routing handler only provides komaci view, use komaci module importer
92
+ if (viewset[adg]) {
93
+ adgModuleImporter = viewset[adg];
94
+ }
95
+ else if (viewset['default']) {
96
+ // calculate komaci specifier using generic default viewset
97
+ const viewInfo = viewset['default'];
98
+ if (viewInfo) {
99
+ if (viewInfo.specifier) {
100
+ const komaciSpecifier = '@salesforce/komaci/' + viewInfo.specifier.replace('/', '__');
101
+ // create adgModuleImporter using komaciSpecifier
102
+ adgModuleImporter = () => import(komaciSpecifier);
103
+ }
104
+ }
105
+ }
106
+ const adgModuleImport = await (adgModuleImporter === null || adgModuleImporter === void 0 ? void 0 : adgModuleImporter());
107
+ const adgRoutingResult = {
108
+ address,
109
+ success: false, // assume the worst
110
+ };
111
+ if (adgModuleImport === null || adgModuleImport === void 0 ? void 0 : adgModuleImport.default) {
112
+ const adgModule = adgModuleImport.default;
113
+ adgRoutingResult.success = true;
114
+ adgRoutingResult.adgModule = adgModule;
115
+ this.updateAdgMap(adgModule, address);
112
116
  }
113
- }
117
+ else {
118
+ adgRoutingResult.reason = NO_ADG_MODULE_FOUND;
119
+ }
120
+ return adgRoutingResult;
114
121
  }
115
-
116
- const adgModuleImport = await adgModuleImporter?.();
117
- const adgRoutingResult = {
118
- address,
119
- success: false // assume the worst
120
-
121
- };
122
-
123
- if (adgModuleImport?.default) {
124
- const adgModule = adgModuleImport.default;
125
- adgRoutingResult.success = true;
126
- adgRoutingResult.adgModule = adgModule;
127
- this.updateAdgMap(adgModule, address);
128
- } else {
129
- adgRoutingResult.reason = NO_ADG_MODULE_FOUND;
122
+ /**
123
+ * Updates the adgMap with the given adgFn, creating the entry if needed
124
+ * and updating the pageReference array for the given address.
125
+ *
126
+ * @param adgModule adgModule that will act as a key in the map
127
+ * @param address address associated with this adgFn
128
+ */
129
+ updateAdgMap(adgModule, address) {
130
+ const addresses = this.adgMap.get(adgModule);
131
+ // check to see if adg has already been added, and append address to the list
132
+ if (addresses) {
133
+ // if highVolumePriming is enabled, we only wish to resolve each unique module once, so don't add additional addresses to the list for resolution
134
+ if (!this.config.highVolumePriming) {
135
+ addresses.push(address);
136
+ }
137
+ }
138
+ else {
139
+ // adg hasn't been added, create entry.
140
+ this.adgMap.set(adgModule, [address]);
141
+ }
130
142
  }
131
-
132
- return adgRoutingResult;
133
- }
134
- /**
135
- * Updates the adgMap with the given adgFn, creating the entry if needed
136
- * and updating the pageReference array for the given address.
137
- *
138
- * @param adgModule adgModule that will act as a key in the map
139
- * @param address address associated with this adgFn
140
- */
141
-
142
-
143
- updateAdgMap(adgModule, address) {
144
- const addresses = this.adgMap.get(adgModule); // check to see if adg has already been added, and append address to the list
145
-
146
- if (addresses) {
147
- // if highVolumePriming is enabled, we only wish to resolve each unique module once, so don't add additional addresses to the list for resolution
148
- if (!this.config.highVolumePriming) {
149
- addresses.push(address);
150
- }
151
- } else {
152
- // adg hasn't been added, create entry.
153
- this.adgMap.set(adgModule, [address]);
143
+ /**
144
+ * Initiates the prefetch process for the given array of addresses.
145
+ * - Addresses are ran through the router to resolve their associated AdgModule, if any
146
+ * - Addresses that resolve to AdgModule are grouped together in order to be resolved in a batch
147
+ * - Addresses that do no resolve to an AdgModule are rejected
148
+ *
149
+ * @param addresses
150
+ */
151
+ prefetch(addresses) {
152
+ this.updateState(STATE.running);
153
+ this.processAllAddresses(addresses).then((adgRoutingResults) => {
154
+ const rejected = adgRoutingResults.filter(({ success }) => !success);
155
+ rejected.forEach(({ address: rejectedAddress, reason }) => {
156
+ const message = reason ||
157
+ `${ERROR_PREFIX} Unknown exception processing routing result.`;
158
+ this.onAddressDone(rejectedAddress, 'rejected', [message]);
159
+ });
160
+ // if prefetch exclusively consists of unprocessable addresses, update state to done
161
+ if (rejected.length === adgRoutingResults.length) {
162
+ this.updateState(STATE.done, 'no processable addresses, do not bulkResolve and set state to "done"');
163
+ }
164
+ this.bulkResolveGuard();
165
+ });
154
166
  }
155
- }
156
- /**
157
- * Initiates the prefetch process for the given array of addresses.
158
- * - Addresses are ran through the router to resolve their associated AdgModule, if any
159
- * - Addresses that resolve to AdgModule are grouped together in order to be resolved in a batch
160
- * - Addresses that do no resolve to an AdgModule are rejected
161
- *
162
- * @param addresses
163
- */
164
-
165
-
166
- prefetch(addresses) {
167
- this.updateState(STATE.running);
168
- this.processAllAddresses(addresses).then(adgRoutingResults => {
169
- const rejected = adgRoutingResults.filter(({
170
- success
171
- }) => !success);
172
- rejected.forEach(({
173
- address: rejectedAddress,
174
- reason
175
- }) => {
176
- const message = reason || `${ERROR_PREFIX} Unknown exception processing routing result.`;
177
- this.onAddressDone(rejectedAddress, 'rejected', [message]);
178
- }); // if prefetch exclusively consists of unprocessable addresses, update state to done
179
-
180
- if (rejected.length === adgRoutingResults.length) {
181
- this.updateState(STATE.done, 'no processable addresses, do not bulkResolve and set state to "done"');
182
- }
183
-
184
- this.bulkResolveGuard();
185
- });
186
- }
187
- /**
188
- * Processes a list of addresses through the router in series
189
- * @param addresses to process
190
- * @returns { AdgRoutingResult[] } a list of AdgRoutingResult
191
- */
192
-
193
-
194
- async processAllAddresses(addresses) {
195
- // add instrumentation to get total duration to process all addresses
196
- const action = InstrumentedAction.startAction('komaci.router', totalRoutingSchema, {
197
- instrumentWithoutLog: false,
198
- postTimeInLog: true,
199
- apiOptions: this.apiOptions
200
- });
201
- const results = [];
202
- const maxConcurrent = this.config.maxConcurrent || Number.MAX_SAFE_INTEGER;
203
-
204
- for (let i = 0; i < addresses.length; i += maxConcurrent) {
205
- const processList = addresses.slice(i, Math.min(addresses.length, i + maxConcurrent));
206
- results.push(...(await Promise.all(processList.map(address => this.processAddress(address)))));
167
+ /**
168
+ * Processes a list of addresses through the router in series
169
+ * @param addresses to process
170
+ * @returns { AdgRoutingResult[] } a list of AdgRoutingResult
171
+ */
172
+ async processAllAddresses(addresses) {
173
+ // add instrumentation to get total duration to process all addresses
174
+ const action = InstrumentedAction.startAction('komaci.router', totalRoutingSchema, {
175
+ instrumentWithoutLog: false,
176
+ postTimeInLog: true,
177
+ apiOptions: this.apiOptions,
178
+ });
179
+ const results = [];
180
+ const maxConcurrent = this.config.maxConcurrent || Number.MAX_SAFE_INTEGER;
181
+ for (let i = 0; i < addresses.length; i += maxConcurrent) {
182
+ const processList = addresses.slice(i, Math.min(addresses.length, i + maxConcurrent));
183
+ results.push(...(await Promise.all(processList.map((address) => this.processAddress(address)))));
184
+ }
185
+ action.finishAction(false, {});
186
+ return results;
207
187
  }
208
-
209
- action.finishAction(false, {});
210
- return results;
211
- }
212
- /**
213
- * Split all the addresses based on the maxConcurrent configuration
214
- * bulkResolve them in iterations
215
- */
216
-
217
-
218
- bulkResolveGuard() {
219
- const maxConcurrent = this.config.maxConcurrent || Number.MAX_SAFE_INTEGER; // rest capacity when there are addresses being processed
220
-
221
- let capacity = maxConcurrent;
222
- const adgs = this.adgMap.keys();
223
-
224
- for (const adgFn of adgs) {
225
- const addresses = this.adgMap.get(adgFn);
226
-
227
- if (addresses && addresses.length > 0) {
228
- if (addresses.length > capacity) {
229
- if (addresses.length < maxConcurrent) {
230
- /* to benefits from batching,
231
- we dont want to split addresses for same adg if they can be in same iteration
232
- example: having maxConcurrent: 10
233
- adg1: 6 addresses
234
- adg2: 8 addresses
235
- ideal way is two iterations for both adg1 and adg2 instead of iter1: 6 adg1 + 4 adg2, iter2: 4 adg2
236
- in addition to the example, if there is another adg3: 4 addresses, will do
237
- iter1: 6 adg1 + 4 adg3
238
- iter2: 8 adg2
239
- */
240
- continue;
241
- } // if the length of address have exceed the maxConcurrent,
242
- // split/resolve and update the rest to adgMap
243
-
244
-
245
- const currentIteration = addresses.slice(0, capacity);
246
- this.adgMap.set(adgFn, addresses.slice(capacity));
247
- this.bulkResolve(adgFn, currentIteration);
248
- break;
249
- } else {
250
- // if the length of address can fit in the capacity,
251
- // resolve them all and remove the entry from adgMap
252
- capacity = capacity - addresses.length;
253
- this.adgMap.delete(adgFn);
254
- this.bulkResolve(adgFn, addresses);
188
+ /**
189
+ * Split all the addresses based on the maxConcurrent configuration
190
+ * bulkResolve them in iterations
191
+ */
192
+ bulkResolveGuard() {
193
+ const maxConcurrent = this.config.maxConcurrent || Number.MAX_SAFE_INTEGER;
194
+ // rest capacity when there are addresses being processed
195
+ let capacity = maxConcurrent;
196
+ const adgs = this.adgMap.keys();
197
+ for (const adgFn of adgs) {
198
+ const addresses = this.adgMap.get(adgFn);
199
+ if (addresses && addresses.length > 0) {
200
+ if (addresses.length > capacity) {
201
+ if (addresses.length < maxConcurrent) {
202
+ /* to benefits from batching,
203
+ we dont want to split addresses for same adg if they can be in same iteration
204
+ example: having maxConcurrent: 10
205
+ adg1: 6 addresses
206
+ adg2: 8 addresses
207
+ ideal way is two iterations for both adg1 and adg2 instead of iter1: 6 adg1 + 4 adg2, iter2: 4 adg2
208
+
209
+ in addition to the example, if there is another adg3: 4 addresses, will do
210
+ iter1: 6 adg1 + 4 adg3
211
+ iter2: 8 adg2
212
+ */
213
+ continue;
214
+ }
215
+ // if the length of address have exceed the maxConcurrent,
216
+ // split/resolve and update the rest to adgMap
217
+ const currentIteration = addresses.slice(0, capacity);
218
+ this.adgMap.set(adgFn, addresses.slice(capacity));
219
+ this.bulkResolve(adgFn, currentIteration);
220
+ break;
221
+ }
222
+ else {
223
+ // if the length of address can fit in the capacity,
224
+ // resolve them all and remove the entry from adgMap
225
+ capacity = capacity - addresses.length;
226
+ this.adgMap.delete(adgFn);
227
+ this.bulkResolve(adgFn, addresses);
228
+ }
229
+ }
230
+ else {
231
+ // in case of empty address list
232
+ this.adgMap.delete(adgFn);
233
+ }
255
234
  }
256
- } else {
257
- // in case of empty address list
258
- this.adgMap.delete(adgFn);
259
- }
260
235
  }
261
- }
262
- /**
263
- * Resolves the given adgFunction with the given resolutionGroup
264
- * @param adgFn to resolve for the inputs provided in the resolutionContext
265
- * @param addresses the list of addresses to be placed into a new BulkResolver
266
- */
267
-
268
-
269
- bulkResolve(adgFn, addresses) {
270
- if (this.state == STATE.stopped) {
271
- return;
236
+ /**
237
+ * Resolves the given adgFunction with the given resolutionGroup
238
+ * @param adgFn to resolve for the inputs provided in the resolutionContext
239
+ * @param addresses the list of addresses to be placed into a new BulkResolver
240
+ */
241
+ bulkResolve(adgFn, addresses) {
242
+ if (this.state == STATE.stopped) {
243
+ return;
244
+ }
245
+ const action = InstrumentedAction.startAction('komaci', bulkResolveSchema, {
246
+ instrumentWithoutLog: false,
247
+ postTimeInLog: true,
248
+ apiOptions: this.apiOptions,
249
+ });
250
+ const adgInputs = addresses.map((address) => {
251
+ return {
252
+ properties: {},
253
+ context: {
254
+ CurrentPageReference: address,
255
+ },
256
+ };
257
+ });
258
+ const resolverInputStatus = addresses.map(() => STATE.running);
259
+ const bulkResolutionGroup = {
260
+ addresses,
261
+ resolverInputStatus,
262
+ };
263
+ bulkResolutionGroup.adgInputs = adgInputs;
264
+ const bulkResolutionStatusCbs = {
265
+ bulkResolutionStatusCb: this.onBulkResolutionStatus.bind(this, bulkResolutionGroup, action),
266
+ overallBulkResolutionStatusCb: undefined,
267
+ };
268
+ const environmentCfg = {
269
+ instrumentationCtx: this.apiOptions.instrumentationContext,
270
+ downloadImageFunc: this.config.downloadImage,
271
+ MaxResolutionDepth: 512,
272
+ WireTimeout: 180 * 1000,
273
+ WireSlowRunningTimeout: 30 * 1000,
274
+ };
275
+ bulkResolutionGroup.bulkResolver = getBulkAdgResolver(adgFn, adgInputs, bulkResolutionStatusCbs, environmentCfg);
276
+ this.resolutionGroups.push(bulkResolutionGroup);
277
+ bulkResolutionGroup.bulkResolver.start();
272
278
  }
273
-
274
- const action = InstrumentedAction.startAction('komaci', bulkResolveSchema, {
275
- instrumentWithoutLog: false,
276
- postTimeInLog: true,
277
- apiOptions: this.apiOptions
278
- });
279
- const adgInputs = addresses.map(address => {
280
- return {
281
- properties: {},
282
- context: {
283
- CurrentPageReference: address
279
+ /**
280
+ * StatusCallback to BulkResolver, invoked when resolver emits a new status.
281
+ * Updates the prefetchService's status if applicable.
282
+ * @param bulkResolutionGroup
283
+ * @param action InstrumentationContext
284
+ * @param status
285
+ */
286
+ onBulkResolutionStatus(bulkResolutionGroup, action, status) {
287
+ var _a;
288
+ const state = status.status.getState();
289
+ const index = status.index;
290
+ const { addresses } = bulkResolutionGroup;
291
+ if (index >= 0 && index < addresses.length) {
292
+ bulkResolutionGroup.resolverInputStatus[index] = state;
293
+ }
294
+ else {
295
+ this.onUnexpectedCondition(`Invalid index provided by resolver: ${index}`);
296
+ return;
297
+ }
298
+ if ((_a = bulkResolutionGroup.bulkResolver) === null || _a === void 0 ? void 0 : _a.areAllResolversDone()) {
299
+ action.finishAction(false, {
300
+ userSchemaData: {
301
+ keyCount: addresses.length,
302
+ },
303
+ });
304
+ }
305
+ switch (state) {
306
+ case STATE.done:
307
+ this.onResolutionDone(status, bulkResolutionGroup);
308
+ break;
309
+ case STATE.stopped:
310
+ // NOTE: Prefetch initiates stop, so this is a noop
311
+ break;
312
+ case STATE.running:
313
+ break;
314
+ default:
315
+ this.onUnexpectedCondition(`Unexpected resolution status: ${JSON.stringify(status)}`);
284
316
  }
285
- };
286
- });
287
- const resolverInputStatus = addresses.map(() => STATE.running);
288
- const bulkResolutionGroup = {
289
- addresses,
290
- resolverInputStatus
291
- };
292
- bulkResolutionGroup.adgInputs = adgInputs;
293
- const bulkResolutionStatusCbs = {
294
- bulkResolutionStatusCb: this.onBulkResolutionStatus.bind(this, bulkResolutionGroup, action),
295
- overallBulkResolutionStatusCb: undefined
296
- };
297
- const environmentCfg = {
298
- instrumentationCtx: this.apiOptions.instrumentationContext,
299
- downloadImageFunc: this.config.downloadImage,
300
- MaxResolutionDepth: 512,
301
- WireTimeout: 180 * 1000,
302
- WireSlowRunningTimeout: 30 * 1000
303
- };
304
- bulkResolutionGroup.bulkResolver = getBulkAdgResolver(adgFn, adgInputs, bulkResolutionStatusCbs, environmentCfg);
305
- this.resolutionGroups.push(bulkResolutionGroup);
306
- bulkResolutionGroup.bulkResolver.start();
307
- }
308
- /**
309
- * StatusCallback to BulkResolver, invoked when resolver emits a new status.
310
- * Updates the prefetchService's status if applicable.
311
- * @param bulkResolutionGroup
312
- * @param action InstrumentationContext
313
- * @param status
314
- */
315
-
316
-
317
- onBulkResolutionStatus(bulkResolutionGroup, action, status) {
318
- const state = status.status.getState();
319
- const index = status.index;
320
- const {
321
- addresses
322
- } = bulkResolutionGroup;
323
-
324
- if (index >= 0 && index < addresses.length) {
325
- bulkResolutionGroup.resolverInputStatus[index] = state;
326
- } else {
327
- this.onUnexpectedCondition(`Invalid index provided by resolver: ${index}`);
328
- return;
329
317
  }
330
-
331
- if (bulkResolutionGroup.bulkResolver?.areAllResolversDone()) {
332
- action.finishAction(false, {
333
- userSchemaData: {
334
- keyCount: addresses.length
318
+ /**
319
+ * Stops all bulkResolvers
320
+ */
321
+ stop() {
322
+ if (this.state == STATE.stopped) {
323
+ return;
335
324
  }
336
- });
325
+ this.resolutionGroups.forEach((bulkResolutionContext) => {
326
+ const { bulkResolver } = bulkResolutionContext;
327
+ if (bulkResolver) {
328
+ bulkResolver.stop();
329
+ }
330
+ });
331
+ this.updateState(STATE.stopped);
337
332
  }
338
-
339
- switch (state) {
340
- case STATE.done:
341
- this.onResolutionDone(status, bulkResolutionGroup);
342
- break;
343
-
344
- case STATE.stopped:
345
- // NOTE: Prefetch initiates stop, so this is a noop
346
- break;
347
-
348
- case STATE.running:
349
- break;
350
-
351
- default:
352
- this.onUnexpectedCondition(`Unexpected resolution status: ${JSON.stringify(status)}`);
333
+ /**
334
+ * Called upon unexpected conditions that may indicate to the consumer that
335
+ * the prefetchService or its associated resolver is in an invalid state
336
+ * @param message
337
+ */
338
+ onUnexpectedCondition(message) {
339
+ // eslint-disable-next-line no-console
340
+ console.log(`Komaci/prefetch - error, message: ${message}`);
341
+ this._activity.error(message);
342
+ this.updateState(STATE.error, message);
353
343
  }
354
- }
355
- /**
356
- * Stops all bulkResolvers
357
- */
358
-
359
-
360
- stop() {
361
- if (this.state == STATE.stopped) {
362
- return;
344
+ /**
345
+ * Called when resolution for a given address has completed, or was otherwise
346
+ * rejected.
347
+ * @param address that is done
348
+ * @param state completed when resolved, or rejected when either no ADG exists, or resolver emitted an error with the given address
349
+ * @param reasons reasons for rejected status, if any
350
+ */
351
+ onAddressDone(address, state, reasons) {
352
+ const { onAddressProcessed } = this.config;
353
+ const status = {
354
+ state: state,
355
+ address,
356
+ reasons: reasons,
357
+ };
358
+ try {
359
+ onAddressProcessed === null || onAddressProcessed === void 0 ? void 0 : onAddressProcessed(status);
360
+ }
361
+ catch (error) {
362
+ this.onUnexpectedCondition(error === null || error === void 0 ? void 0 : error.message);
363
+ }
363
364
  }
364
-
365
- this.resolutionGroups.forEach(bulkResolutionContext => {
366
- const {
367
- bulkResolver
368
- } = bulkResolutionContext;
369
-
370
- if (bulkResolver) {
371
- bulkResolver.stop();
372
- }
373
- });
374
- this.updateState(STATE.stopped);
375
- }
376
- /**
377
- * Called upon unexpected conditions that may indicate to the consumer that
378
- * the prefetchService or its associated resolver is in an invalid state
379
- * @param message
380
- */
381
-
382
-
383
- onUnexpectedCondition(message) {
384
- // eslint-disable-next-line no-console
385
- console.log(`Komaci/prefetch - error, message: ${message}`);
386
-
387
- this._activity.error(message);
388
-
389
- this.updateState(STATE.error, message);
390
- }
391
- /**
392
- * Called when resolution for a given address has completed, or was otherwise
393
- * rejected.
394
- * @param address that is done
395
- * @param state completed when resolved, or rejected when either no ADG exists, or resolver emitted an error with the given address
396
- * @param reasons reasons for rejected status, if any
397
- */
398
-
399
-
400
- onAddressDone(address, state, reasons) {
401
- const {
402
- onAddressProcessed
403
- } = this.config;
404
- const status = {
405
- state: state,
406
- address,
407
- reasons: reasons
408
- };
409
-
410
- try {
411
- onAddressProcessed?.(status);
412
- } catch (error) {
413
- this.onUnexpectedCondition(error?.message);
365
+ /**
366
+ * Updates the current PrefetchState to done if every bulkResolver has emitted
367
+ * a non-running status for all inputs.
368
+ */
369
+ updateStateIfAllDone(bulkResolutionContext, status) {
370
+ const bulkContexts = this.resolutionGroups.values();
371
+ let allDone = true;
372
+ for (const context of bulkContexts) {
373
+ if (context.bulkResolver && !context.bulkResolver.areAllResolversDone()) {
374
+ allDone = false;
375
+ break;
376
+ }
377
+ }
378
+ if (allDone) {
379
+ if (this.adgMap.size > 0) {
380
+ // if all current runs are all done but with addresses left in the adgMap
381
+ // go process them
382
+ this.bulkResolveGuard();
383
+ }
384
+ else {
385
+ // prefetch is done when allIdel and nothing left in adgMap
386
+ // eslint-disable-next-line no-console
387
+ console.log(`Komaci/prefetch - duration: ${Date.now() - this._startTime}, size: ${this._size}.`);
388
+ this._activity.stop(prefetchServiceSchema, {
389
+ addressCount: this._size,
390
+ startTime: this._startTime,
391
+ });
392
+ this.updateState(STATE.done, status.status.getErrorMessages().join('\n'));
393
+ bulkResolutionContext.bulkResolver = undefined;
394
+ }
395
+ }
414
396
  }
415
- }
416
- /**
417
- * Updates the current PrefetchState to done if every bulkResolver has emitted
418
- * a non-running status for all inputs.
419
- */
420
-
421
-
422
- updateStateIfAllDone(bulkResolutionContext, status) {
423
- const bulkContexts = this.resolutionGroups.values();
424
- let allDone = true;
425
-
426
- for (const context of bulkContexts) {
427
- if (context.bulkResolver && !context.bulkResolver.areAllResolversDone()) {
428
- allDone = false;
429
- break;
430
- }
397
+ /**
398
+ * Called when resolver emits a "sink" state for an address or all addresses
399
+ * @param status
400
+ * @param bulkResolutionContext
401
+ */
402
+ onResolutionDone(status, bulkResolutionContext) {
403
+ const index = status.index;
404
+ const { addresses } = bulkResolutionContext;
405
+ const addressState = status.status.getErrorMessages().length !== 0 ? 'rejected' : 'completed';
406
+ const impactedAddress = addresses[index];
407
+ this.onAddressDone(impactedAddress, addressState, status.status.getErrorMessages());
408
+ this.updateStateIfAllDone(bulkResolutionContext, status);
431
409
  }
432
-
433
- if (allDone) {
434
- if (this.adgMap.size > 0) {
435
- // if all current runs are all done but with addresses left in the adgMap
436
- // go process them
437
- this.bulkResolveGuard();
438
- } else {
439
- // prefetch is done when allIdel and nothing left in adgMap
440
- // eslint-disable-next-line no-console
441
- console.log(`Komaci/prefetch - duration: ${Date.now() - this._startTime}, size: ${this._size}.`);
442
-
443
- this._activity.stop(prefetchServiceSchema, {
444
- addressCount: this._size,
445
- startTime: this._startTime
446
- });
447
-
448
- this.updateState(STATE.done, status.status.getErrorMessages().join('\n'));
449
- bulkResolutionContext.bulkResolver = undefined;
450
- }
410
+ /**
411
+ * Updates PrefetchState and notifies consumer via config.onStateChanged callback
412
+ * @param newState the new state
413
+ * @param [message] state message, if any
414
+ */
415
+ updateState(newState, message) {
416
+ const { onStateChanged } = this.config;
417
+ const abandoned = []; // TODO: Abandoned Not yet implemented
418
+ if (ValidStatusTransitions.isValid(this.state, newState)) {
419
+ this.state = newState;
420
+ try {
421
+ onStateChanged === null || onStateChanged === void 0 ? void 0 : onStateChanged({
422
+ state: newState,
423
+ abandoned,
424
+ message,
425
+ });
426
+ }
427
+ catch (error) {
428
+ // eslint-disable-next-line no-console
429
+ console.log(error === null || error === void 0 ? void 0 : error.message);
430
+ }
431
+ }
432
+ else {
433
+ const errorMessage = `Komaci/prefetch - Invalid state transition from resovler. Resolver emitted state: ${newState} while prefetch is in ${this.state}`;
434
+ // eslint-disable-next-line no-console
435
+ console.log(errorMessage);
436
+ this._activity.error(errorMessage, 'invalid-prefetch-state-transition');
437
+ }
451
438
  }
452
- }
453
- /**
454
- * Called when resolver emits a "sink" state for an address or all addresses
455
- * @param status
456
- * @param bulkResolutionContext
457
- */
458
-
459
-
460
- onResolutionDone(status, bulkResolutionContext) {
461
- const index = status.index;
462
- const {
463
- addresses
464
- } = bulkResolutionContext;
465
- const addressState = status.status.getErrorMessages().length !== 0 ? 'rejected' : 'completed';
466
- const impactedAddress = addresses[index];
467
- this.onAddressDone(impactedAddress, addressState, status.status.getErrorMessages());
468
- this.updateStateIfAllDone(bulkResolutionContext, status);
469
- }
470
- /**
471
- * Updates PrefetchState and notifies consumer via config.onStateChanged callback
472
- * @param newState the new state
473
- * @param [message] state message, if any
474
- */
475
-
476
-
477
- updateState(newState, message) {
478
- const {
479
- onStateChanged
480
- } = this.config;
481
- const abandoned = []; // TODO: Abandoned Not yet implemented
482
-
483
- if (ValidStatusTransitions.isValid(this.state, newState)) {
484
- this.state = newState;
485
-
486
- try {
487
- onStateChanged?.({
488
- state: newState,
489
- abandoned,
490
- message
491
- });
492
- } catch (error) {
493
- // eslint-disable-next-line no-console
494
- console.log(error?.message);
495
- }
496
- } else {
497
- const errorMessage = `Komaci/prefetch - Invalid state transition from resovler. Resolver emitted state: ${newState} while prefetch is in ${this.state}`; // eslint-disable-next-line no-console
498
-
499
- console.log(errorMessage);
500
-
501
- this._activity.error(errorMessage, 'invalid-prefetch-state-transition');
439
+ getState() {
440
+ return this.state;
502
441
  }
503
- }
504
-
505
- getState() {
506
- return this.state;
507
- }
508
-
509
- }
442
+ }
443
+ //# sourceMappingURL=prefetchService.js.map
@@ -1,30 +1,22 @@
1
1
  export const ERROR_PREFIX = '[komaci prefetch]';
2
- /**
3
- * Routing result for each address
4
- */
5
-
6
- export let ResolutionStatusState;
7
-
2
+ export var ResolutionStatusState;
8
3
  (function (ResolutionStatusState) {
9
- ResolutionStatusState["running"] = "running";
10
- ResolutionStatusState["done"] = "done";
11
- ResolutionStatusState["error"] = "error";
12
- ResolutionStatusState["stopped"] = "stopped";
4
+ ResolutionStatusState["running"] = "running";
5
+ ResolutionStatusState["done"] = "done";
6
+ ResolutionStatusState["error"] = "error";
7
+ ResolutionStatusState["stopped"] = "stopped";
13
8
  })(ResolutionStatusState || (ResolutionStatusState = {}));
14
-
15
- export let PrefetchStatusStates;
16
-
9
+ export var PrefetchStatusStates;
17
10
  (function (PrefetchStatusStates) {
18
- PrefetchStatusStates["init"] = "init";
19
- PrefetchStatusStates["done"] = "done";
20
- PrefetchStatusStates["running"] = "running";
21
- PrefetchStatusStates["stopped"] = "stopped";
22
- PrefetchStatusStates["error"] = "error";
11
+ PrefetchStatusStates["init"] = "init";
12
+ PrefetchStatusStates["done"] = "done";
13
+ PrefetchStatusStates["running"] = "running";
14
+ PrefetchStatusStates["stopped"] = "stopped";
15
+ PrefetchStatusStates["error"] = "error";
23
16
  })(PrefetchStatusStates || (PrefetchStatusStates = {}));
24
-
25
- export let AddressStatusStates;
26
-
17
+ export var AddressStatusStates;
27
18
  (function (AddressStatusStates) {
28
- AddressStatusStates["completed"] = "completed";
29
- AddressStatusStates["rejected"] = "rejected";
30
- })(AddressStatusStates || (AddressStatusStates = {}));
19
+ AddressStatusStates["completed"] = "completed";
20
+ AddressStatusStates["rejected"] = "rejected";
21
+ })(AddressStatusStates || (AddressStatusStates = {}));
22
+ //# sourceMappingURL=prefetchTypes.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@komaci/prefetch",
3
- "version": "242.1.9",
3
+ "version": "242.2.1",
4
4
  "description": "Komaci prefetch service.",
5
5
  "homepage": "https://komaci.dev/",
6
6
  "repository": {
@@ -19,21 +19,21 @@
19
19
  "types": "build/modules/komaci/prefetchTypes/prefetchTypes.d.ts",
20
20
  "main": "build/index.js",
21
21
  "scripts": {
22
- "build": "node ../../../bin/pack-ts --dir src/modules build/modules && tsc -b ./tsconfig.json"
22
+ "build": "tsc -b"
23
23
  },
24
24
  "files": [
25
25
  "build/**/*.js",
26
26
  "build/**/*.d.ts"
27
27
  ],
28
28
  "dependencies": {
29
- "@komaci/module-shared": "242.1.9",
30
- "@komaci/resolver": "242.1.9",
29
+ "@komaci/module-shared": "242.2.1",
30
+ "@komaci/resolver": "242.2.1",
31
31
  "@lwrjs/router": "0.6.0-alpha.15",
32
32
  "o11y": "^240.7.0",
33
33
  "o11y_schema": "^240.11.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@komaci/types": "242.1.9",
36
+ "@komaci/types": "242.2.1",
37
37
  "wait-for-expect": "^3.0.2"
38
38
  }
39
39
  }