udp-stencil-component-library 26.8.0 → 26.9.0-beta.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.
Files changed (56) hide show
  1. package/dist/cjs/advanced-search_12.cjs.entry.js +3 -3
  2. package/dist/cjs/ag-grid-base_65.cjs.entry.js +4 -4
  3. package/dist/cjs/ambient-template-grid.cjs.entry.js +3 -3
  4. package/dist/cjs/api-method-instance-grid.cjs.entry.js +5 -5
  5. package/dist/cjs/{apiMethodInstance-Dl1OvqO3.js → apiMethodInstance-D65NIw8S.js} +1 -1
  6. package/dist/cjs/{apiUtils-DMOOqk3y.js → apiUtils-0pkNuvqf.js} +412 -18
  7. package/dist/cjs/{catalog-store-CrTx8FL-.js → catalog-store-B_YMkXRh.js} +1 -1
  8. package/dist/cjs/{configureUdpColumnMods-CongQl55.js → configureUdpColumnMods-BT7UbQPh.js} +1 -1
  9. package/dist/cjs/index.cjs.js +27 -6
  10. package/dist/cjs/{lookupHelper-DPnaYUT4.js → lookupHelper-ClpMWN_g.js} +1 -1
  11. package/dist/cjs/search-method-grid.cjs.entry.js +13 -7
  12. package/dist/collection/components/grid/new-grid/datasources/searchMethodDatasource.js +9 -3
  13. package/dist/collection/components/grid/new-grid/search-method-grid.js +5 -4
  14. package/dist/collection/index.js +1 -0
  15. package/dist/collection/store/execution-store.js +332 -0
  16. package/dist/collection/udp-utilities/api-udp/apiUtils.js +54 -16
  17. package/dist/components/ag-grid-base2.js +1 -1
  18. package/dist/components/ambient-template-grid.js +1 -1
  19. package/dist/components/apiUtils.js +1 -1
  20. package/dist/components/catalog-store.js +1 -1
  21. package/dist/components/configureUdpColumnMods.js +1 -1
  22. package/dist/components/index.js +1 -1
  23. package/dist/components/search-method-grid2.js +1 -1
  24. package/dist/components/udp-export-sheet2.js +1 -1
  25. package/dist/docs.json +5 -5
  26. package/dist/esm/advanced-search_12.entry.js +3 -3
  27. package/dist/esm/ag-grid-base_65.entry.js +4 -4
  28. package/dist/esm/ambient-template-grid.entry.js +3 -3
  29. package/dist/esm/api-method-instance-grid.entry.js +5 -5
  30. package/dist/esm/{apiMethodInstance-V3OfLZqE.js → apiMethodInstance-BunReWfq.js} +1 -1
  31. package/dist/esm/{apiUtils-5ytQ3Uwx.js → apiUtils-Cq-WuEqc.js} +390 -18
  32. package/dist/esm/{catalog-store-C3AM0WtT.js → catalog-store-CLsDGUEl.js} +1 -1
  33. package/dist/esm/{configureUdpColumnMods-Bob9zsKz.js → configureUdpColumnMods-UWccWlH6.js} +1 -1
  34. package/dist/esm/index.js +6 -6
  35. package/dist/esm/{lookupHelper-B7F-SThL.js → lookupHelper-CSo9DNLr.js} +1 -1
  36. package/dist/esm/search-method-grid.entry.js +13 -7
  37. package/dist/stencil-library/advanced-search_12.entry.js +1 -1
  38. package/dist/stencil-library/ag-grid-base_65.entry.js +1 -1
  39. package/dist/stencil-library/ambient-template-grid.entry.js +1 -1
  40. package/dist/stencil-library/api-method-instance-grid.entry.js +1 -1
  41. package/dist/stencil-library/{apiMethodInstance-V3OfLZqE.js → apiMethodInstance-BunReWfq.js} +1 -1
  42. package/dist/stencil-library/apiUtils-Cq-WuEqc.js +1 -0
  43. package/dist/stencil-library/{catalog-store-C3AM0WtT.js → catalog-store-CLsDGUEl.js} +1 -1
  44. package/dist/stencil-library/{configureUdpColumnMods-Bob9zsKz.js → configureUdpColumnMods-UWccWlH6.js} +1 -1
  45. package/dist/stencil-library/index.esm.js +1 -1
  46. package/dist/stencil-library/lookupHelper-CSo9DNLr.js +1 -0
  47. package/dist/stencil-library/search-method-grid.entry.js +1 -1
  48. package/dist/types/components/grid/new-grid/datasources/searchMethodDatasource.d.ts +1 -0
  49. package/dist/types/components/grid/new-grid/search-method-grid.d.ts +6 -0
  50. package/dist/types/components.d.ts +12 -0
  51. package/dist/types/index.d.ts +1 -0
  52. package/dist/types/store/execution-store.d.ts +181 -0
  53. package/dist/types/udp-utilities/api-udp/apiUtils.d.ts +8 -0
  54. package/package.json +1 -1
  55. package/dist/stencil-library/apiUtils-5ytQ3Uwx.js +0 -1
  56. package/dist/stencil-library/lookupHelper-B7F-SThL.js +0 -1
@@ -2,7 +2,7 @@
2
2
 
3
3
  var index = require('./index-CZB9dMeB.js');
4
4
  var conversionFunctions = require('./conversionFunctions-B_9y17KE.js');
5
- var catalogStore = require('./catalog-store-CrTx8FL-.js');
5
+ var catalogStore = require('./catalog-store-B_YMkXRh.js');
6
6
  var Close24 = require('@carbon/icons/es/close/24');
7
7
  var uuid = require('uuid');
8
8
  var Save16 = require('@carbon/icons/es/save/16');
@@ -14,8 +14,8 @@ var Star16 = require('@carbon/icons/es/star/16');
14
14
  var AdvancedQuery16 = require('@carbon/icons/es/ibm-watson--discovery/16');
15
15
  var DataEnrichment16 = require('@carbon/icons/es/idea/16');
16
16
  var Renew16 = require('@carbon/icons/es/renew/16');
17
- require('./apiUtils-DMOOqk3y.js');
18
- require('deep-equal');
17
+ require('./apiUtils-0pkNuvqf.js');
18
+ require('lodash-es/isEqual');
19
19
  require('./makeApiCall-CFfg9gI0.js');
20
20
  require('axios');
21
21
  require('./configService-N6ke1_s4.js');
@@ -2,13 +2,13 @@
2
2
 
3
3
  var index = require('./index-CZB9dMeB.js');
4
4
  var agGridEnterpriseV33 = require('ag-grid-enterprise-v33');
5
- var apiUtils = require('./apiUtils-DMOOqk3y.js');
6
- var lookupHelper = require('./lookupHelper-DPnaYUT4.js');
5
+ var apiUtils = require('./apiUtils-0pkNuvqf.js');
6
+ var lookupHelper = require('./lookupHelper-ClpMWN_g.js');
7
7
  var tenantUtils = require('./tenantUtils-BCKSE0vq.js');
8
8
  var searchObject = require('./searchObject-mbqgqdRh.js');
9
9
  var searchObjectHelper = require('./searchObjectHelper-DYpPEIzz.js');
10
10
  var statusRenderer = require('./status-renderer-9CQ-hhq8.js');
11
- var configureUdpColumnMods = require('./configureUdpColumnMods-CongQl55.js');
11
+ var configureUdpColumnMods = require('./configureUdpColumnMods-BT7UbQPh.js');
12
12
  var lodashEs = require('lodash-es');
13
13
  var makeApiCall = require('./makeApiCall-CFfg9gI0.js');
14
14
  var configService = require('./configService-N6ke1_s4.js');
@@ -58,7 +58,7 @@ require('@fluentui/web-components/textarea.js');
58
58
  require('@fluentui/web-components/tooltip.js');
59
59
  require('@fluentui/web-components/tree.js');
60
60
  require('@fluentui/web-components/tree-item.js');
61
- require('deep-equal');
61
+ require('lodash-es/isEqual');
62
62
  require('axios');
63
63
  require('./iconMapping-D932h4o2.js');
64
64
  require('@carbon/icons/es/add/16');
@@ -2,11 +2,11 @@
2
2
 
3
3
  var index = require('./index-CZB9dMeB.js');
4
4
  var immer = require('immer');
5
- var catalogStore = require('./catalog-store-CrTx8FL-.js');
5
+ var catalogStore = require('./catalog-store-B_YMkXRh.js');
6
6
  var ChooseItem16 = require('@carbon/icons/es/choose-item/16');
7
7
  var Star16 = require('@carbon/icons/es/star/16');
8
8
  var List16 = require('@carbon/icons/es/list/16');
9
- var apiUtils = require('./apiUtils-DMOOqk3y.js');
9
+ var apiUtils = require('./apiUtils-0pkNuvqf.js');
10
10
  var transformSearchData = require('./transformSearchData-B4bk4Aik.js');
11
11
  var conversionFunctions = require('./conversionFunctions-B_9y17KE.js');
12
12
  var localforage = require('localforage');
@@ -16,7 +16,7 @@ var fastTypescriptMemoize = require('fast-typescript-memoize');
16
16
  var lodashEs = require('lodash-es');
17
17
  var uuid = require('uuid');
18
18
  var tenantUtils = require('./tenantUtils-BCKSE0vq.js');
19
- require('deep-equal');
19
+ require('lodash-es/isEqual');
20
20
  require('./makeApiCall-CFfg9gI0.js');
21
21
  require('axios');
22
22
  require('./configService-N6ke1_s4.js');
@@ -4,14 +4,14 @@ var index = require('./index-CZB9dMeB.js');
4
4
  var makeApiCall = require('./makeApiCall-CFfg9gI0.js');
5
5
  var searchObjectHelper = require('./searchObjectHelper-DYpPEIzz.js');
6
6
  var lodashEs = require('lodash-es');
7
- var apiMethodInstance = require('./apiMethodInstance-Dl1OvqO3.js');
7
+ var apiMethodInstance = require('./apiMethodInstance-D65NIw8S.js');
8
8
  var configService = require('./configService-N6ke1_s4.js');
9
9
  require('axios');
10
10
  require('./searchObject-mbqgqdRh.js');
11
- require('./configureUdpColumnMods-CongQl55.js');
12
- require('./lookupHelper-DPnaYUT4.js');
13
- require('./apiUtils-DMOOqk3y.js');
14
- require('deep-equal');
11
+ require('./configureUdpColumnMods-BT7UbQPh.js');
12
+ require('./lookupHelper-ClpMWN_g.js');
13
+ require('./apiUtils-0pkNuvqf.js');
14
+ require('lodash-es/isEqual');
15
15
  require('./tenantUtils-BCKSE0vq.js');
16
16
 
17
17
  const ApiMethodInstanceGrid = class {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var configureUdpColumnMods = require('./configureUdpColumnMods-CongQl55.js');
3
+ var configureUdpColumnMods = require('./configureUdpColumnMods-BT7UbQPh.js');
4
4
 
5
5
  function mapDotNetTypeToAgGridType(type) {
6
6
  const normalized = type.replace(/\?$/, '').trim().toLowerCase();
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var deepEqual = require('deep-equal');
3
+ var isEqual = require('lodash-es/isEqual');
4
4
  var makeApiCall = require('./makeApiCall-CFfg9gI0.js');
5
5
  var configService = require('./configService-N6ke1_s4.js');
6
6
  var index = require('./index-CZB9dMeB.js');
@@ -8,7 +8,7 @@ var tenantUtils = require('./tenantUtils-BCKSE0vq.js');
8
8
 
9
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
10
 
11
- var deepEqual__default = /*#__PURE__*/_interopDefault(deepEqual);
11
+ var isEqual__default = /*#__PURE__*/_interopDefault(isEqual);
12
12
 
13
13
  const appendToMap = (map, propName, value) => {
14
14
  const items = map.get(propName);
@@ -238,15 +238,15 @@ const getBaseUrls = async () => {
238
238
  return baseUrls;
239
239
  };
240
240
 
241
- const { state, onChange } = createStore({
241
+ const { state: state$1, onChange } = createStore({
242
242
  lookupsDataMap: null,
243
243
  });
244
244
  function setLookupsDataMap(lookupsDataMap, replace = false) {
245
245
  if (replace) {
246
- state.lookupsDataMap = lookupsDataMap;
246
+ state$1.lookupsDataMap = lookupsDataMap;
247
247
  }
248
248
  else {
249
- state.lookupsDataMap = Object.assign(Object.assign({}, state.lookupsDataMap), lookupsDataMap);
249
+ state$1.lookupsDataMap = Object.assign(Object.assign({}, state$1.lookupsDataMap), lookupsDataMap);
250
250
  }
251
251
  }
252
252
 
@@ -254,9 +254,342 @@ var lookupsStore = /*#__PURE__*/Object.freeze({
254
254
  __proto__: null,
255
255
  onChange: onChange,
256
256
  setLookupsDataMap: setLookupsDataMap,
257
- state: state
257
+ state: state$1
258
258
  });
259
259
 
260
+ var _a, _b, _c, _d, _e, _f, _g;
261
+ /**
262
+ * BasicOperation type ids of the promoted base operations executable
263
+ * product-side — every operation the emitted UdpQuery runtime dispatches
264
+ * (UNT-6403): reads (Get=1, GetAll=5, Search=6, GetConfig=7, GetFull=8,
265
+ * Describe=9, GetData=10, Export=16, GetFileResult=18), writes (Create=2,
266
+ * Update=3, Delete=4, Import=15), and the virtual row operations
267
+ * (VirtualGet..VirtualDelete=11-14). BulkCreate=17 is dispatcher-ready but
268
+ * excluded until PromotedApiMethodView gains a BulkCreate slot the catalog can
269
+ * expose. The dispatcher independently rejects anything it does not support
270
+ * (501), so this list is a routing optimization, not a security boundary.
271
+ */
272
+ const DIRECT_ELIGIBLE_BASE_OPERATION_TYPE_IDS = [
273
+ '1',
274
+ '2',
275
+ '3',
276
+ '4',
277
+ '5',
278
+ '6',
279
+ '7',
280
+ '8',
281
+ '9',
282
+ '10',
283
+ '11',
284
+ '12',
285
+ '13',
286
+ '14',
287
+ '15',
288
+ '16',
289
+ '18',
290
+ ];
291
+ // The stencil dist ships several bundle flavors, and a page routinely loads two of
292
+ // them at once: utility imports through the package root resolve to dist/esm, while
293
+ // the React wrappers load the components (and everything they bundle, including this
294
+ // module) from dist/components. Module-scoped state therefore SPLITS — the enterprise
295
+ // library's writes land in the esm copy while the grid datasource reads the
296
+ // components copy. Backing the state with a namespaced global keeps every compiled
297
+ // copy reading and writing the same object. Reads are imperative (resolveExecutionTarget
298
+ // at request time), so no store reactivity is needed.
299
+ const EXECUTION_STATE_GLOBAL_KEY = '__udpQueryExecutionState__';
300
+ const globalScope = globalThis;
301
+ const state = ((_a = globalScope[EXECUTION_STATE_GLOBAL_KEY]) !== null && _a !== void 0 ? _a : (globalScope[EXECUTION_STATE_GLOBAL_KEY] = {
302
+ queryExecution: null,
303
+ directEligibleApiMethodIds: [],
304
+ integrationOnlyIds: [],
305
+ integrationFallbackStatuses: {},
306
+ descriptorKnown: false,
307
+ eligibilityKnown: false,
308
+ descriptorResolving: false,
309
+ descriptorWaiters: [],
310
+ }));
311
+ // A copy of this module compiled into an older bundle may have created the
312
+ // global without newer fields; heal the shape instead of trusting it.
313
+ (_b = state.integrationOnlyIds) !== null && _b !== void 0 ? _b : (state.integrationOnlyIds = []);
314
+ (_c = state.integrationFallbackStatuses) !== null && _c !== void 0 ? _c : (state.integrationFallbackStatuses = {});
315
+ (_d = state.descriptorKnown) !== null && _d !== void 0 ? _d : (state.descriptorKnown = false);
316
+ (_e = state.eligibilityKnown) !== null && _e !== void 0 ? _e : (state.eligibilityKnown = false);
317
+ (_f = state.descriptorResolving) !== null && _f !== void 0 ? _f : (state.descriptorResolving = false);
318
+ (_g = state.descriptorWaiters) !== null && _g !== void 0 ? _g : (state.descriptorWaiters = []);
319
+ /**
320
+ * Strips trailing '/' characters. A loop rather than `/\/+$/`, which
321
+ * backtracks quadratically on inputs with many embedded slashes.
322
+ */
323
+ const trimTrailingSlashes = (url) => {
324
+ let end = url.length;
325
+ while (end > 0 && url[end - 1] === '/')
326
+ end--;
327
+ return url.slice(0, end);
328
+ };
329
+ /**
330
+ * Ad hoc UdpQuery execution endpoint emitted into every generated product app —
331
+ * contract with the code generator's UdpQueryControllerGenerator.
332
+ */
333
+ const buildDirectAdhocRequestUrl = (productBaseUrl, apiMethodId) => `${trimTrailingSlashes(productBaseUrl)}/api/v1/UdpQuery/adhoc/${apiMethodId}`;
334
+ /**
335
+ * With-parameters UdpQuery execution endpoint emitted into every generated
336
+ * product app — the direct counterpart of Integration's
337
+ * `apimethod/executeQueryWithParameters/{apiMethodId}`. Same request body
338
+ * contract (a flat name→value map plus an optional `requestBody` entry).
339
+ */
340
+ const buildDirectExecuteWithParametersUrl = (productBaseUrl, apiMethodId) => `${trimTrailingSlashes(productBaseUrl)}/api/v1/UdpQuery/${apiMethodId}/executeWithParameters`;
341
+ /**
342
+ * Instance-mode UdpQuery execution endpoint (saved query instances, the only
343
+ * mode applying alias/lookup result mapping). Per-instance operation
344
+ * eligibility cannot be derived client-side — the promoted catalog keys by
345
+ * apiMethodId, not instance id — so instance callers route direct on the
346
+ * descriptor alone and rely on the dispatcher's 501 plus the fallback contract.
347
+ */
348
+ const buildDirectExecuteInstanceUrl = (productBaseUrl, apiMethodInstanceId) => `${trimTrailingSlashes(productBaseUrl)}/api/v1/UdpQuery/${apiMethodInstanceId}/execute`;
349
+ /**
350
+ * Response header the emitted UdpQuery controller stamps on every response it
351
+ * produces, success and error alike. Its absence on a 404 means the endpoint
352
+ * itself is missing (a build without the runtime); the product's CORS policy
353
+ * must expose it (Access-Control-Expose-Headers) for cross-origin callers.
354
+ */
355
+ const UDP_QUERY_RUNTIME_MARKER_HEADER = 'x-udpquery-runtime';
356
+ /**
357
+ * The migration-window fallback contract for a failed DIRECT execution: retry
358
+ * via Integration only on 501 (the runtime's "not supported / not configured
359
+ * here — execute on Integration" signal, which also covers product builds
360
+ * whose runtime predates an operation), on a 404 WITHOUT the runtime marker
361
+ * header (endpoint absent), and — for reads only — on 503. Never on
362
+ * marker-carrying 404s or any other status — a real query error must surface,
363
+ * not silently re-execute on the other path and mask a broken direct route.
364
+ */
365
+ const shouldFallBackToIntegration = (status, hasRuntimeMarker, options = {}) => status === 501 || (status === 503 && !options.mayWrite) || (status === 404 && !hasRuntimeMarker);
366
+ /**
367
+ * The one implementation of the migration-window fallback, shared by every
368
+ * executor seam (stencil apiUtils, the React library's methodUtils): run the
369
+ * direct call, and on a {@link shouldFallBackToIntegration} failure retry via
370
+ * Integration; rethrow everything else. 501 and markerless 404 describe the
371
+ * deployed build, so the id goes integration-only for the rest of the page
372
+ * load; 503 is transient, so only this call falls back.
373
+ */
374
+ const directCallWithIntegrationFallback = async (directCall, integrationCall, id, options = {}) => {
375
+ try {
376
+ const result = await directCall();
377
+ clearIntegrationFallbackStatus(id);
378
+ return result;
379
+ }
380
+ catch (error) {
381
+ const response = error === null || error === void 0 ? void 0 : error.response;
382
+ const status = response === null || response === void 0 ? void 0 : response.status;
383
+ const headers = response === null || response === void 0 ? void 0 : response.headers;
384
+ const hasMarker = !!(headers &&
385
+ (typeof headers.get === 'function'
386
+ ? headers.get(UDP_QUERY_RUNTIME_MARKER_HEADER)
387
+ : headers[UDP_QUERY_RUNTIME_MARKER_HEADER]));
388
+ if (shouldFallBackToIntegration(status, hasMarker, options)) {
389
+ console.warn(`Direct UdpQuery execution answered ${status}; falling back to Integration`, error);
390
+ if (status === 503) {
391
+ recordIntegrationFallbackStatus(id, status);
392
+ }
393
+ else {
394
+ // Skip the wasted direct attempt for this id for the rest of the page load.
395
+ markIntegrationOnly(id, status);
396
+ }
397
+ return integrationCall();
398
+ }
399
+ throw error;
400
+ }
401
+ };
402
+ /**
403
+ * Records that a direct execution for this id (apiMethodId or instance id)
404
+ * answered the fallback signal, so subsequent executions this page load skip
405
+ * the wasted direct attempt and go straight to Integration.
406
+ */
407
+ function markIntegrationOnly(id, status) {
408
+ if (id && !state.integrationOnlyIds.includes(id)) {
409
+ state.integrationOnlyIds = [...state.integrationOnlyIds, id];
410
+ if (typeof status === 'number') {
411
+ state.integrationFallbackStatuses = Object.assign(Object.assign({}, state.integrationFallbackStatuses), { [id]: status });
412
+ }
413
+ }
414
+ }
415
+ function recordIntegrationFallbackStatus(id, status) {
416
+ if (id) {
417
+ state.integrationFallbackStatuses = Object.assign(Object.assign({}, state.integrationFallbackStatuses), { [id]: status });
418
+ }
419
+ }
420
+ function clearIntegrationFallbackStatus(id) {
421
+ if (id && id in state.integrationFallbackStatuses) {
422
+ const rest = Object.assign({}, state.integrationFallbackStatuses);
423
+ delete rest[id];
424
+ state.integrationFallbackStatuses = rest;
425
+ }
426
+ }
427
+ /**
428
+ * The HTTP status this id's latest direct attempt fell back on (501, 503 or a
429
+ * markerless 404), or undefined when it has not fallen back or its latest
430
+ * direct attempt succeeded. 501/404 also make the id integration-only for the
431
+ * page load, so they stick; a 503 clears on the next direct success.
432
+ */
433
+ function getIntegrationFallbackStatus(id) {
434
+ return id ? state.integrationFallbackStatuses[id] : undefined;
435
+ }
436
+ function isIntegrationOnly(id) {
437
+ return !!id && state.integrationOnlyIds.includes(id);
438
+ }
439
+ /**
440
+ * Announces an in-flight descriptor fetch, arming the boot barrier: from this
441
+ * call until the routing answer settles (see isExecutionRoutingSettled),
442
+ * whenExecutionRoutingSettled parks executors instead of letting their first
443
+ * query silently fail open to Integration. Idempotent; called by the provider
444
+ * that owns the tenant x product descriptor fetch as soon as it mounts.
445
+ * Whoever calls this MUST guarantee a descriptor write follows (success or
446
+ * failure), and — when that write says direct — a bulk eligibility write too,
447
+ * or parked executors never run.
448
+ */
449
+ function markQueryExecutionResolving() {
450
+ if (!isExecutionRoutingSettled()) {
451
+ state.descriptorResolving = true;
452
+ }
453
+ }
454
+ /**
455
+ * The routing question is settled once the descriptor is known and, when it
456
+ * says direct, the bulk eligibility registration has landed as well — before
457
+ * that, every per-id eligibility check would miss and route Integration.
458
+ * An integration (or absent) descriptor settles alone: eligibility is
459
+ * irrelevant on that path.
460
+ */
461
+ function isExecutionRoutingSettled() {
462
+ var _a;
463
+ return state.descriptorKnown && (((_a = state.queryExecution) === null || _a === void 0 ? void 0 : _a.mode) !== 'direct' || state.eligibilityKnown);
464
+ }
465
+ function releaseBarrierIfSettled() {
466
+ if (isExecutionRoutingSettled()) {
467
+ releaseQueryExecutionResolving();
468
+ }
469
+ }
470
+ /**
471
+ * How long a parked executor waits for the routing answer before failing open
472
+ * to Integration.
473
+ */
474
+ const EXECUTION_ROUTING_SETTLE_TIMEOUT_MS = 10000;
475
+ /**
476
+ * Disarms the boot barrier and releases every parked executor onto whatever
477
+ * routing is known (Integration until a descriptor lands). For a provider that
478
+ * unmounts mid-fetch, and the barrier's own timeout. A descriptor or
479
+ * eligibility write arriving later still takes effect for subsequent queries.
480
+ */
481
+ function releaseQueryExecutionResolving() {
482
+ state.descriptorResolving = false;
483
+ const waiters = state.descriptorWaiters;
484
+ state.descriptorWaiters = [];
485
+ waiters.forEach((release) => release());
486
+ }
487
+ /**
488
+ * Starts routing over for a new scope (tenant switch): forgets the descriptor
489
+ * and every per-id Integration fallback, and re-arms the boot barrier so
490
+ * executors park until the new scope's descriptor lands instead of running on
491
+ * the previous one's. The eligible set is kept — it is keyed by the api
492
+ * catalog, and the provider replaces it whenever the catalog changes. Same
493
+ * contract as markQueryExecutionResolving: a descriptor write MUST follow.
494
+ */
495
+ function resetQueryExecutionRouting() {
496
+ state.queryExecution = null;
497
+ state.descriptorKnown = false;
498
+ state.integrationOnlyIds = [];
499
+ state.integrationFallbackStatuses = {};
500
+ state.descriptorResolving = true;
501
+ }
502
+ /**
503
+ * The boot barrier: resolves once the routing question is settled for this
504
+ * page load. Immediate when it already is — or when no provider has announced
505
+ * a descriptor fetch, preserving the fail-open-to-Integration behavior for
506
+ * surfaces mounted without one. Never hangs: after
507
+ * EXECUTION_ROUTING_SETTLE_TIMEOUT_MS the barrier disarms and every parked
508
+ * executor fails open.
509
+ */
510
+ function whenExecutionRoutingSettled(timeoutMs = EXECUTION_ROUTING_SETTLE_TIMEOUT_MS) {
511
+ if (isExecutionRoutingSettled() || !state.descriptorResolving) {
512
+ return Promise.resolve();
513
+ }
514
+ return new Promise((resolve) => {
515
+ const timer = setTimeout(() => {
516
+ console.warn(`Query execution routing did not settle within ${timeoutMs}ms; executing via Integration`);
517
+ releaseQueryExecutionResolving();
518
+ }, timeoutMs);
519
+ state.descriptorWaiters.push(() => {
520
+ clearTimeout(timer);
521
+ resolve();
522
+ });
523
+ });
524
+ }
525
+ /**
526
+ * Deliberately not persisted (session/local storage): ForceIntegration's
527
+ * kill-switch semantics rely on a fresh descriptor fetch per page load.
528
+ * Also advances the boot barrier — a null or integration write settles it
529
+ * outright (eligibility is irrelevant on that path); a direct write settles it
530
+ * once the bulk eligibility registration has landed too.
531
+ */
532
+ function setQueryExecutionDescriptor(descriptor) {
533
+ state.queryExecution = descriptor !== null && descriptor !== void 0 ? descriptor : null;
534
+ state.descriptorKnown = true;
535
+ releaseBarrierIfSettled();
536
+ }
537
+ function getQueryExecutionDescriptor() {
538
+ return state.queryExecution;
539
+ }
540
+ /**
541
+ * apiMethodIds of the catalog's direct-eligible promoted base operations — the
542
+ * per-query half of the routing rule. Populated by the enterprise library from
543
+ * the promoted-method catalog it already fetches at startup. This bulk write
544
+ * (an empty list on a failed catalog fetch included) is the boot barrier's
545
+ * eligibility-known signal; the additive per-entity writes below are not — they
546
+ * cover one entity, so releasing every parked query on them would wrongly send
547
+ * the others to Integration.
548
+ */
549
+ function setDirectEligibleApiMethodIds(apiMethodIds) {
550
+ state.directEligibleApiMethodIds = (apiMethodIds !== null && apiMethodIds !== void 0 ? apiMethodIds : []).filter((id) => !!id);
551
+ state.eligibilityKnown = true;
552
+ releaseBarrierIfSettled();
553
+ }
554
+ function getDirectEligibleApiMethodIds() {
555
+ return state.directEligibleApiMethodIds;
556
+ }
557
+ /**
558
+ * Additively merges apiMethodIds into the eligible set. Used by the per-entity
559
+ * promoted-method fetches so a page's own entity is registered by the same
560
+ * response that arms its grid — closing the startup race against the bulk
561
+ * catalog fetch (which still replaces the full list when it lands).
562
+ */
563
+ function addDirectEligibleApiMethodIds(apiMethodIds) {
564
+ const incoming = (apiMethodIds !== null && apiMethodIds !== void 0 ? apiMethodIds : []).filter((id) => !!id);
565
+ if (!incoming.length) {
566
+ return;
567
+ }
568
+ state.directEligibleApiMethodIds = Array.from(new Set([...state.directEligibleApiMethodIds, ...incoming]));
569
+ }
570
+ /**
571
+ * The one place the whole routing rule lives: direct only when the descriptor
572
+ * says direct, carries a product URL, and the query's apiMethodId maps to a
573
+ * direct-eligible promoted base operation. Anything else — including an unset
574
+ * descriptor from a backend that predates the field — resolves to the
575
+ * Integration path. On direct failure the executor seams apply the narrow
576
+ * {@link shouldFallBackToIntegration} contract (501/503, markerless 404); every
577
+ * other failure surfaces, and ForceIntegration on the product version remains
578
+ * the operational recovery path.
579
+ */
580
+ function resolveExecutionTarget(apiMethodId) {
581
+ const descriptor = state.queryExecution;
582
+ if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.mode) === 'direct' &&
583
+ descriptor.url &&
584
+ apiMethodId &&
585
+ !isIntegrationOnly(apiMethodId) &&
586
+ state.directEligibleApiMethodIds.includes(apiMethodId)) {
587
+ const url = trimTrailingSlashes(descriptor.url);
588
+ return { mode: 'direct', url, requestUrl: buildDirectAdhocRequestUrl(url, apiMethodId) };
589
+ }
590
+ return { mode: 'integration' };
591
+ }
592
+
260
593
  // Function for the first API call
261
594
  const getApiCatalogAndProduct = async () => {
262
595
  const { baseURL } = await getBaseUrls();
@@ -276,7 +609,7 @@ let prefetchedQueryAdHoc;
276
609
  const executeQueryAdHoc = (data, apiMethodId, apiBase, prefetch = false) => {
277
610
  const args = [data, apiMethodId, tenantUtils.getCurrentTenantId(), apiBase != 'hotlist'];
278
611
  if (!prefetch && prefetchedQueryAdHoc) {
279
- if (deepEqual__default.default(prefetchedQueryAdHoc.args, args)) {
612
+ if (isEqual__default.default(prefetchedQueryAdHoc.args, args)) {
280
613
  const { response } = prefetchedQueryAdHoc;
281
614
  console.info(`Using prefetch for /apimethod/executeQueryAdHoc/${apiMethodId} prefetch`, prefetchedQueryAdHoc.args, args);
282
615
  prefetchedQueryAdHoc = undefined;
@@ -287,11 +620,25 @@ const executeQueryAdHoc = (data, apiMethodId, apiBase, prefetch = false) => {
287
620
  prefetchedQueryAdHoc = undefined;
288
621
  }
289
622
  }
290
- const response = getBaseUrls().then(({ baseURL, baseURLHost }) => {
291
- const url = apiBase != 'hotlist'
292
- ? `${baseURL}/apimethod/executeQueryAdHoc/${apiMethodId}`
293
- : `${baseURLHost}/UdpHotList/containingRecord`;
294
- return makeApiCall.makeApiCall('POST', url, data);
623
+ const response = getBaseUrls().then(async ({ baseURL, baseURLHost }) => {
624
+ // Direct-if-eligible routing (UNT-6403): when the tenant x product execution
625
+ // descriptor says "direct" and this apiMethodId maps to a direct-eligible
626
+ // promoted base operation, the ad hoc query executes against the product's
627
+ // UdpQuery endpoint, with the narrow Integration fallback for builds whose
628
+ // runtime predates the operation. The boot barrier holds a page's first
629
+ // queries until the provider's descriptor fetch settles, so a reload does
630
+ // not silently route them to Integration.
631
+ if (apiBase != 'hotlist') {
632
+ await whenExecutionRoutingSettled();
633
+ }
634
+ const target = apiBase != 'hotlist' ? resolveExecutionTarget(apiMethodId) : { mode: 'integration' };
635
+ const integrationUrl = apiBase == 'hotlist'
636
+ ? `${baseURLHost}/UdpHotList/containingRecord`
637
+ : `${baseURL}/apimethod/executeQueryAdHoc/${apiMethodId}`;
638
+ if (target.mode === 'direct') {
639
+ return directCallWithIntegrationFallback(() => makeApiCall.makeApiCall('POST', target.requestUrl, data), () => makeApiCall.makeApiCall('POST', integrationUrl, data), apiMethodId);
640
+ }
641
+ return makeApiCall.makeApiCall('POST', integrationUrl, data);
295
642
  });
296
643
  if (prefetch) {
297
644
  console.info(`Prefetching /apimethod/executeQueryAdHoc/${apiMethodId}`);
@@ -311,10 +658,31 @@ const getApiCatalogById = async (apiCatalogId) => {
311
658
  const executeQueryWithParameters = async (data, apiMethodId) => {
312
659
  console.log('executeQueryWithParameters called', apiMethodId);
313
660
  const { baseURL } = await getBaseUrls();
314
- console.log('baseURL from External config:', baseURL);
315
- const url = `${baseURL}/apimethod/executeQueryWithParameters/${apiMethodId}`;
316
- const response = await makeApiCall.makeApiCall('POST', url, data);
317
- return response; // return the response data
661
+ const integrationUrl = `${baseURL}/apimethod/executeQueryWithParameters/${apiMethodId}`;
662
+ // Direct-if-eligible routing (UNT-6403): the request body contract is identical
663
+ // on both paths (a flat name→value map plus an optional requestBody entry).
664
+ // Boot barrier: see executeQueryAdHoc.
665
+ await whenExecutionRoutingSettled();
666
+ const target = resolveExecutionTarget(apiMethodId);
667
+ if (target.mode === 'direct') {
668
+ return directCallWithIntegrationFallback(() => makeApiCall.makeApiCall('POST', buildDirectExecuteWithParametersUrl(target.url, apiMethodId), data), () => makeApiCall.makeApiCall('POST', integrationUrl, data), apiMethodId, { mayWrite: true });
669
+ }
670
+ return makeApiCall.makeApiCall('POST', integrationUrl, data);
671
+ };
672
+ /**
673
+ * Ad hoc execution against a caller-resolved direct UdpQuery URL, for callers
674
+ * that route outside the hosting product's execution store (e.g. Data Builder,
675
+ * which builds queries against any product). Applies the same migration-window
676
+ * fallback contract as executeQueryAdHoc, with Integration's ad hoc endpoint
677
+ * for this apiMethodId as the fallback target.
678
+ */
679
+ const executeDirectQueryAdHoc = async (data, apiMethodId, directRequestUrl) => {
680
+ const { baseURL } = await getBaseUrls();
681
+ const integrationUrl = `${baseURL}/apimethod/executeQueryAdHoc/${apiMethodId}`;
682
+ if (isIntegrationOnly(apiMethodId)) {
683
+ return makeApiCall.makeApiCall('POST', integrationUrl, data);
684
+ }
685
+ return directCallWithIntegrationFallback(() => makeApiCall.makeApiCall('POST', directRequestUrl, data), () => makeApiCall.makeApiCall('POST', integrationUrl, data), apiMethodId);
318
686
  };
319
687
  class QueryResult {
320
688
  constructor() {
@@ -370,7 +738,9 @@ function getCleanData(data, lookupsMap) {
370
738
  const keys = (_a = lookup.udpLookupUdpLookupKey) !== null && _a !== void 0 ? _a : (lookup.keyName ? [{ name: lookup.keyName }] : []);
371
739
  let temp = (_b = lookup === null || lookup === void 0 ? void 0 : lookup.data) === null || _b === void 0 ? void 0 : _b.find(item => item[lookup.valueName] === currentValue);
372
740
  if (temp != null)
373
- keys.forEach(k => { cleanData[index][k.name] = temp[k.name]; });
741
+ keys.forEach(k => {
742
+ cleanData[index][k.name] = temp[k.name];
743
+ });
374
744
  });
375
745
  }
376
746
  else if (cleanData[attribute]) {
@@ -379,7 +749,9 @@ function getCleanData(data, lookupsMap) {
379
749
  const keys = (_a = lookup.udpLookupUdpLookupKey) !== null && _a !== void 0 ? _a : (lookup.keyName ? [{ name: lookup.keyName }] : []);
380
750
  let temp = lookup.data.find(item => item[lookup.valueName] === currentValue);
381
751
  if (temp != null)
382
- keys.forEach(k => { cleanData[k.name] = temp[k.name]; });
752
+ keys.forEach(k => {
753
+ cleanData[k.name] = temp[k.name];
754
+ });
383
755
  /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */
384
756
  }
385
757
  });
@@ -627,11 +999,20 @@ const removeRecordFromHotlist = async (hotlistID) => {
627
999
  return makeApiCall.makeApiCall('DELETE', url, null, true);
628
1000
  };
629
1001
 
1002
+ exports.DIRECT_ELIGIBLE_BASE_OPERATION_TYPE_IDS = DIRECT_ELIGIBLE_BASE_OPERATION_TYPE_IDS;
1003
+ exports.EXECUTION_ROUTING_SETTLE_TIMEOUT_MS = EXECUTION_ROUTING_SETTLE_TIMEOUT_MS;
1004
+ exports.UDP_QUERY_RUNTIME_MARKER_HEADER = UDP_QUERY_RUNTIME_MARKER_HEADER;
1005
+ exports.addDirectEligibleApiMethodIds = addDirectEligibleApiMethodIds;
630
1006
  exports.addRecordToAHotlist = addRecordToAHotlist;
1007
+ exports.buildDirectAdhocRequestUrl = buildDirectAdhocRequestUrl;
1008
+ exports.buildDirectExecuteInstanceUrl = buildDirectExecuteInstanceUrl;
1009
+ exports.buildDirectExecuteWithParametersUrl = buildDirectExecuteWithParametersUrl;
631
1010
  exports.createAHotlist = createAHotlist;
632
1011
  exports.createStore = createStore;
633
1012
  exports.deleteAHotlist = deleteAHotlist;
634
1013
  exports.deleteSelectedView = deleteSelectedView;
1014
+ exports.directCallWithIntegrationFallback = directCallWithIntegrationFallback;
1015
+ exports.executeDirectQueryAdHoc = executeDirectQueryAdHoc;
635
1016
  exports.executeQueryAdHoc = executeQueryAdHoc;
636
1017
  exports.executeQueryAdHocAndMapLookups = executeQueryAdHocAndMapLookups;
637
1018
  exports.executeQueryWithParameters = executeQueryWithParameters;
@@ -643,12 +1024,25 @@ exports.getApiMethodInstance = getApiMethodInstance;
643
1024
  exports.getAvailableGridActions = getAvailableGridActions;
644
1025
  exports.getAvailableViews = getAvailableViews;
645
1026
  exports.getCleanData = getCleanData;
1027
+ exports.getDirectEligibleApiMethodIds = getDirectEligibleApiMethodIds;
646
1028
  exports.getGridViewsWithConfigurations = getGridViewsWithConfigurations;
1029
+ exports.getIntegrationFallbackStatus = getIntegrationFallbackStatus;
647
1030
  exports.getPromotedLookupMethod = getPromotedLookupMethod;
648
1031
  exports.getPromotedMethodEntities = getPromotedMethodEntities;
1032
+ exports.getQueryExecutionDescriptor = getQueryExecutionDescriptor;
649
1033
  exports.getSelectedView = getSelectedView;
1034
+ exports.isIntegrationOnly = isIntegrationOnly;
650
1035
  exports.loadAHotlist = loadAHotlist;
1036
+ exports.markIntegrationOnly = markIntegrationOnly;
1037
+ exports.markQueryExecutionResolving = markQueryExecutionResolving;
1038
+ exports.releaseQueryExecutionResolving = releaseQueryExecutionResolving;
651
1039
  exports.removeRecordFromHotlist = removeRecordFromHotlist;
1040
+ exports.resetQueryExecutionRouting = resetQueryExecutionRouting;
1041
+ exports.resolveExecutionTarget = resolveExecutionTarget;
652
1042
  exports.saveView = saveView;
1043
+ exports.setDirectEligibleApiMethodIds = setDirectEligibleApiMethodIds;
1044
+ exports.setQueryExecutionDescriptor = setQueryExecutionDescriptor;
1045
+ exports.shouldFallBackToIntegration = shouldFallBackToIntegration;
653
1046
  exports.updateView = updateView;
654
1047
  exports.updateViewAndConfigurations = updateViewAndConfigurations;
1048
+ exports.whenExecutionRoutingSettled = whenExecutionRoutingSettled;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var apiUtils = require('./apiUtils-DMOOqk3y.js');
3
+ var apiUtils = require('./apiUtils-0pkNuvqf.js');
4
4
 
5
5
  // src/global/state.ts
6
6
  const { state, onChange } = apiUtils.createStore({
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var lookupHelper = require('./lookupHelper-DPnaYUT4.js');
3
+ var lookupHelper = require('./lookupHelper-ClpMWN_g.js');
4
4
 
5
5
  /**
6
6
  * Finds an existing 'actions' column in an array of ColDefs and applies