@praxisui/core 9.0.0-beta.73 → 9.0.0-beta.74
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/README.md +15 -0
- package/ai/component-registry.json +10 -4
- package/fesm2022/praxisui-core.mjs +1350 -496
- package/package.json +1 -1
- package/types/praxisui-core.d.ts +310 -12
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { Component, InjectionToken, Injectable, inject, Inject, Optional, makeEnvironmentProviders, APP_INITIALIZER, signal, computed, DestroyRef, ENVIRONMENT_INITIALIZER, ErrorHandler, EventEmitter, Output, Input, ChangeDetectionStrategy, Directive, SecurityContext, ViewContainerRef, SimpleChange, ContentChild, HostBinding, HostListener, ViewChildren, ViewChild, Injector, input, output, effect } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/common/http';
|
|
4
4
|
import { HttpHeaders, HttpClient, HttpParams, HttpResponse, HttpContextToken, HTTP_INTERCEPTORS, withInterceptors } from '@angular/common/http';
|
|
5
|
-
import { of, defer, throwError, from, EMPTY, BehaviorSubject, firstValueFrom, Subject, map as map$1, switchMap as switchMap$1 } from 'rxjs';
|
|
5
|
+
import { of, defer, throwError, from, EMPTY, BehaviorSubject, firstValueFrom, Subject, map as map$1, switchMap as switchMap$1, catchError as catchError$1 } from 'rxjs';
|
|
6
6
|
import { switchMap, take, map, catchError, concatMap, tap, shareReplay, takeUntil, toArray, finalize } from 'rxjs/operators';
|
|
7
7
|
import * as i1$2 from '@angular/common';
|
|
8
8
|
import { Location, DOCUMENT, CommonModule } from '@angular/common';
|
|
@@ -297,10 +297,10 @@ function buildSchemaId(params) {
|
|
|
297
297
|
const schemaType = (params.schemaType || 'response').toLowerCase();
|
|
298
298
|
const internal = params.includeInternalSchemas ? 'true' : 'false';
|
|
299
299
|
const parts = [path, operation, schemaType, `internal:${internal}`];
|
|
300
|
-
if (params.
|
|
301
|
-
parts.push(`
|
|
302
|
-
if (params.
|
|
303
|
-
parts.push(`
|
|
300
|
+
if (params.idField)
|
|
301
|
+
parts.push(`idField:${params.idField}`);
|
|
302
|
+
if (params.readOnly !== undefined)
|
|
303
|
+
parts.push(`readOnly:${params.readOnly}`);
|
|
304
304
|
if (params.apiOrigin)
|
|
305
305
|
parts.push(`origin:${params.apiOrigin}`);
|
|
306
306
|
return parts.join('|');
|
|
@@ -1722,6 +1722,17 @@ const OPTION_SOURCE_SEARCH_MODES = new Set([
|
|
|
1722
1722
|
'contains',
|
|
1723
1723
|
'exact',
|
|
1724
1724
|
]);
|
|
1725
|
+
const OPTION_SOURCE_SELECTED_RELOAD_POLICIES = new Set([
|
|
1726
|
+
'required',
|
|
1727
|
+
'supported',
|
|
1728
|
+
'unsupported-with-waiver',
|
|
1729
|
+
'not-applicable',
|
|
1730
|
+
]);
|
|
1731
|
+
const OPTION_SOURCE_INVALID_SORT_POLICIES = new Set([
|
|
1732
|
+
'reject',
|
|
1733
|
+
'ignore',
|
|
1734
|
+
'unsupported',
|
|
1735
|
+
]);
|
|
1725
1736
|
const LOOKUP_OPEN_DETAIL_MODES = new Set([
|
|
1726
1737
|
'samePage',
|
|
1727
1738
|
'newTab',
|
|
@@ -2481,6 +2492,18 @@ class SchemaNormalizerService {
|
|
|
2481
2492
|
if (value.includeIds !== undefined) {
|
|
2482
2493
|
optionSource.includeIds = this.parseBoolean(value.includeIds);
|
|
2483
2494
|
}
|
|
2495
|
+
if (value.selectedReloadPolicy !== undefined) {
|
|
2496
|
+
const selectedReloadPolicy = this.parseOptionSourceSelectedReloadPolicy(value.selectedReloadPolicy);
|
|
2497
|
+
if (selectedReloadPolicy) {
|
|
2498
|
+
optionSource.selectedReloadPolicy = selectedReloadPolicy;
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
if (value.invalidSortPolicy !== undefined) {
|
|
2502
|
+
const invalidSortPolicy = this.parseOptionSourceInvalidSortPolicy(value.invalidSortPolicy);
|
|
2503
|
+
if (invalidSortPolicy) {
|
|
2504
|
+
optionSource.invalidSortPolicy = invalidSortPolicy;
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2484
2507
|
return optionSource;
|
|
2485
2508
|
}
|
|
2486
2509
|
parseOptionSourceType(value) {
|
|
@@ -2491,6 +2514,14 @@ class SchemaNormalizerService {
|
|
|
2491
2514
|
const normalized = String(value ?? '').trim();
|
|
2492
2515
|
return OPTION_SOURCE_SEARCH_MODES.has(normalized) ? normalized : undefined;
|
|
2493
2516
|
}
|
|
2517
|
+
parseOptionSourceSelectedReloadPolicy(value) {
|
|
2518
|
+
const normalized = String(value ?? '').trim();
|
|
2519
|
+
return OPTION_SOURCE_SELECTED_RELOAD_POLICIES.has(normalized) ? normalized : undefined;
|
|
2520
|
+
}
|
|
2521
|
+
parseOptionSourceInvalidSortPolicy(value) {
|
|
2522
|
+
const normalized = String(value ?? '').trim();
|
|
2523
|
+
return OPTION_SOURCE_INVALID_SORT_POLICIES.has(normalized) ? normalized : undefined;
|
|
2524
|
+
}
|
|
2494
2525
|
parseLookupOpenDetailMode(value) {
|
|
2495
2526
|
const normalized = String(value ?? '').trim();
|
|
2496
2527
|
return LOOKUP_OPEN_DETAIL_MODES.has(normalized) ? normalized : undefined;
|
|
@@ -3418,12 +3449,12 @@ class ApiConfigStorage {
|
|
|
3418
3449
|
shouldLogSaveError(key, err) {
|
|
3419
3450
|
if (err?.status === 404)
|
|
3420
3451
|
return false;
|
|
3421
|
-
return this.shouldPropagateSaveError(key);
|
|
3452
|
+
return this.shouldPropagateSaveError(key, err);
|
|
3422
3453
|
}
|
|
3423
3454
|
shouldLogClearError(key, err) {
|
|
3424
3455
|
if (err?.status === 404)
|
|
3425
3456
|
return false;
|
|
3426
|
-
return this.shouldPropagateClearError(key);
|
|
3457
|
+
return this.shouldPropagateClearError(key, err);
|
|
3427
3458
|
}
|
|
3428
3459
|
loadConfig(key) {
|
|
3429
3460
|
const existingProbe = ApiConfigStorage.loadAvailabilityProbes.get(this.baseUrl);
|
|
@@ -3437,7 +3468,7 @@ class ApiConfigStorage {
|
|
|
3437
3468
|
const etag = cached?.etag;
|
|
3438
3469
|
const { type, id } = this.resolveKey(key);
|
|
3439
3470
|
const url = `${this.baseUrl}`;
|
|
3440
|
-
const params = this.buildParams(type, id);
|
|
3471
|
+
const params = this.buildParams(type, id, cached?.scope);
|
|
3441
3472
|
const headers = this.buildHeaders(etag ? { 'If-None-Match': this.formatEtag(etag) } : {});
|
|
3442
3473
|
let releaseProbe = null;
|
|
3443
3474
|
if (establishAvailability) {
|
|
@@ -3460,7 +3491,11 @@ class ApiConfigStorage {
|
|
|
3460
3491
|
const nextEtag = this.stripQuotes(resp.headers.get('ETag'));
|
|
3461
3492
|
const body = resp.body;
|
|
3462
3493
|
if (nextEtag) {
|
|
3463
|
-
this.cache.set(key, {
|
|
3494
|
+
this.cache.set(key, {
|
|
3495
|
+
etag: nextEtag,
|
|
3496
|
+
payload: body?.payload,
|
|
3497
|
+
scope: this.resolveResponseScope(body?.scope),
|
|
3498
|
+
});
|
|
3464
3499
|
}
|
|
3465
3500
|
releaseProbe?.();
|
|
3466
3501
|
return body?.payload ?? null;
|
|
@@ -3488,7 +3523,11 @@ class ApiConfigStorage {
|
|
|
3488
3523
|
const nextEtag = this.stripQuotes(resp.headers.get('ETag'));
|
|
3489
3524
|
const body = resp.body;
|
|
3490
3525
|
if (nextEtag) {
|
|
3491
|
-
this.cache.set(key, {
|
|
3526
|
+
this.cache.set(key, {
|
|
3527
|
+
etag: nextEtag,
|
|
3528
|
+
payload: body?.payload,
|
|
3529
|
+
scope: this.resolveResponseScope(body?.scope),
|
|
3530
|
+
});
|
|
3492
3531
|
}
|
|
3493
3532
|
return body?.payload ?? null;
|
|
3494
3533
|
}), catchError((err) => {
|
|
@@ -3510,36 +3549,47 @@ class ApiConfigStorage {
|
|
|
3510
3549
|
saveConfig(key, config) {
|
|
3511
3550
|
const { type, id } = this.resolveKey(key);
|
|
3512
3551
|
const url = `${this.baseUrl}`;
|
|
3513
|
-
const params = this.buildParams(type, id);
|
|
3514
3552
|
const cached = this.cache.get(key);
|
|
3553
|
+
const params = this.buildParams(type, id, cached?.scope);
|
|
3515
3554
|
const headers = this.buildHeaders(cached?.etag ? { 'If-Match': this.formatEtag(cached.etag) } : undefined);
|
|
3516
3555
|
return this.http
|
|
3517
3556
|
.put(url, { payload: config }, { observe: 'response', headers, params })
|
|
3518
3557
|
.pipe(map((resp) => {
|
|
3519
3558
|
const nextEtag = this.stripQuotes(resp.headers.get('ETag'));
|
|
3520
3559
|
const payload = resp.body?.payload ?? config;
|
|
3521
|
-
this.cache.set(key, {
|
|
3560
|
+
this.cache.set(key, {
|
|
3561
|
+
etag: nextEtag,
|
|
3562
|
+
payload,
|
|
3563
|
+
scope: this.resolveResponseScope(resp.body?.scope) ?? cached?.scope,
|
|
3564
|
+
});
|
|
3522
3565
|
}), catchError((err) => {
|
|
3523
3566
|
if (this.shouldLogSaveError(key, err)) {
|
|
3524
3567
|
console.warn('[ApiConfigStorage] save error', err);
|
|
3525
3568
|
}
|
|
3526
|
-
return this.shouldPropagateSaveError(key)
|
|
3569
|
+
return this.shouldPropagateSaveError(key, err)
|
|
3527
3570
|
? throwError(() => err)
|
|
3528
3571
|
// Soft-fail path: complete without next so runtime can treat as
|
|
3529
3572
|
// "not acknowledged" instead of a hard error.
|
|
3530
3573
|
: EMPTY;
|
|
3531
3574
|
}));
|
|
3532
3575
|
}
|
|
3533
|
-
shouldPropagateSaveError(key) {
|
|
3576
|
+
shouldPropagateSaveError(key, err) {
|
|
3577
|
+
if (this.isConcurrencyConflict(err))
|
|
3578
|
+
return true;
|
|
3534
3579
|
if (this.opts?.errorPolicy === 'fail')
|
|
3535
3580
|
return true;
|
|
3536
3581
|
return this.isCriticalPersistenceKey(key);
|
|
3537
3582
|
}
|
|
3538
|
-
shouldPropagateClearError(key) {
|
|
3583
|
+
shouldPropagateClearError(key, err) {
|
|
3584
|
+
if (this.isConcurrencyConflict(err))
|
|
3585
|
+
return true;
|
|
3539
3586
|
if (this.opts?.errorPolicy === 'fail')
|
|
3540
3587
|
return true;
|
|
3541
3588
|
return this.isCriticalPersistenceKey(key);
|
|
3542
3589
|
}
|
|
3590
|
+
isConcurrencyConflict(err) {
|
|
3591
|
+
return err?.status === 409 || err?.status === 412;
|
|
3592
|
+
}
|
|
3543
3593
|
shouldPropagateLoadError(key, _err) {
|
|
3544
3594
|
if (this.opts?.errorPolicy !== 'fail')
|
|
3545
3595
|
return false;
|
|
@@ -3552,8 +3602,8 @@ class ApiConfigStorage {
|
|
|
3552
3602
|
clearConfig(key) {
|
|
3553
3603
|
const { type, id } = this.resolveKey(key);
|
|
3554
3604
|
const url = `${this.baseUrl}`;
|
|
3555
|
-
const params = this.buildParams(type, id);
|
|
3556
3605
|
const cached = this.cache.get(key);
|
|
3606
|
+
const params = this.buildParams(type, id, cached?.scope);
|
|
3557
3607
|
const headers = this.buildHeaders(cached?.etag ? { 'If-Match': this.formatEtag(cached.etag) } : undefined);
|
|
3558
3608
|
return this.http
|
|
3559
3609
|
.delete(url, { observe: 'response', headers, params })
|
|
@@ -3563,7 +3613,7 @@ class ApiConfigStorage {
|
|
|
3563
3613
|
if (this.shouldLogClearError(key, err)) {
|
|
3564
3614
|
console.warn('[ApiConfigStorage] clear error', err);
|
|
3565
3615
|
}
|
|
3566
|
-
return this.shouldPropagateClearError(key)
|
|
3616
|
+
return this.shouldPropagateClearError(key, err)
|
|
3567
3617
|
? throwError(() => err)
|
|
3568
3618
|
// Soft-fail path: complete without next so runtime can treat as
|
|
3569
3619
|
// "clear not acknowledged" instead of a hard error.
|
|
@@ -3588,18 +3638,23 @@ class ApiConfigStorage {
|
|
|
3588
3638
|
}
|
|
3589
3639
|
return new HttpHeaders(merged);
|
|
3590
3640
|
}
|
|
3591
|
-
buildParams(componentType, componentId) {
|
|
3641
|
+
buildParams(componentType, componentId, resolvedScope) {
|
|
3592
3642
|
const params = {
|
|
3593
3643
|
componentType,
|
|
3594
3644
|
componentId,
|
|
3595
3645
|
};
|
|
3596
|
-
|
|
3597
|
-
|
|
3646
|
+
const effectiveScope = this.scope || resolvedScope;
|
|
3647
|
+
if (effectiveScope) {
|
|
3648
|
+
params['scope'] = effectiveScope;
|
|
3598
3649
|
}
|
|
3599
3650
|
return new HttpParams({
|
|
3600
3651
|
fromObject: params,
|
|
3601
3652
|
});
|
|
3602
3653
|
}
|
|
3654
|
+
resolveResponseScope(value) {
|
|
3655
|
+
const normalized = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
3656
|
+
return normalized === 'user' || normalized === 'tenant' ? normalized : undefined;
|
|
3657
|
+
}
|
|
3603
3658
|
resolveKey(key) {
|
|
3604
3659
|
const type = this.componentTypeResolver(key);
|
|
3605
3660
|
return { type, id: key };
|
|
@@ -4232,6 +4287,12 @@ class GenericCrudService {
|
|
|
4232
4287
|
.set('path', path)
|
|
4233
4288
|
.set('operation', operation)
|
|
4234
4289
|
.set('schemaType', schemaType);
|
|
4290
|
+
if (options?.idField) {
|
|
4291
|
+
httpParams = httpParams.set('idField', options.idField);
|
|
4292
|
+
}
|
|
4293
|
+
if (options?.readOnly !== undefined) {
|
|
4294
|
+
httpParams = httpParams.set('readOnly', String(options.readOnly));
|
|
4295
|
+
}
|
|
4235
4296
|
// Resolve schemas/filtered honoring relative base (dev proxy) when applicable
|
|
4236
4297
|
let filteredUrl = '/schemas/filtered';
|
|
4237
4298
|
let apiOrigin = '';
|
|
@@ -4243,7 +4304,17 @@ class GenericCrudService {
|
|
|
4243
4304
|
}
|
|
4244
4305
|
catch { }
|
|
4245
4306
|
// Build cache key including the API origin (not the app origin)
|
|
4246
|
-
const schemaId = buildSchemaId({
|
|
4307
|
+
const schemaId = buildSchemaId({
|
|
4308
|
+
path,
|
|
4309
|
+
operation,
|
|
4310
|
+
schemaType,
|
|
4311
|
+
includeInternalSchemas: false,
|
|
4312
|
+
idField: options?.idField,
|
|
4313
|
+
readOnly: options?.readOnly,
|
|
4314
|
+
tenant,
|
|
4315
|
+
locale,
|
|
4316
|
+
apiOrigin,
|
|
4317
|
+
});
|
|
4247
4318
|
const headersBase = composeHeadersWithVersion(entry);
|
|
4248
4319
|
const shouldUseDirectSchemaEndpoint = GenericCrudService.unavailableFilteredSchemaUrls.has(filteredUrl);
|
|
4249
4320
|
if (shouldUseDirectSchemaEndpoint) {
|
|
@@ -4258,7 +4329,13 @@ class GenericCrudService {
|
|
|
4258
4329
|
headers = headers.set('Accept-Language', locale);
|
|
4259
4330
|
if (tenant)
|
|
4260
4331
|
headers = headers.set('X-Tenant', tenant);
|
|
4261
|
-
debugCrudService('[CRUD:Service] getSchema (filtered fallback):request', {
|
|
4332
|
+
debugCrudService('[CRUD:Service] getSchema (filtered fallback):request', {
|
|
4333
|
+
filteredUrl,
|
|
4334
|
+
path,
|
|
4335
|
+
idField: options?.idField,
|
|
4336
|
+
readOnly: options?.readOnly,
|
|
4337
|
+
hasCached: !!cached,
|
|
4338
|
+
});
|
|
4262
4339
|
return this.http.get(filteredUrl, {
|
|
4263
4340
|
params: httpParams,
|
|
4264
4341
|
headers,
|
|
@@ -4602,6 +4679,12 @@ class GenericCrudService {
|
|
|
4602
4679
|
if (params.includeInternalSchemas !== undefined) {
|
|
4603
4680
|
httpParams = httpParams.set('includeInternalSchemas', String(params.includeInternalSchemas));
|
|
4604
4681
|
}
|
|
4682
|
+
if (params.idField) {
|
|
4683
|
+
httpParams = httpParams.set('idField', params.idField);
|
|
4684
|
+
}
|
|
4685
|
+
if (params.readOnly !== undefined) {
|
|
4686
|
+
httpParams = httpParams.set('readOnly', String(params.readOnly));
|
|
4687
|
+
}
|
|
4605
4688
|
const entry = this.resolveEndpointEntry(params.endpointKey);
|
|
4606
4689
|
let url = '/schemas/filtered';
|
|
4607
4690
|
let origin = '';
|
|
@@ -4617,7 +4700,7 @@ class GenericCrudService {
|
|
|
4617
4700
|
const includeInternal = !!params.includeInternalSchemas;
|
|
4618
4701
|
const tenant = this.globalConfig.getTenant();
|
|
4619
4702
|
const locale = (typeof navigator !== 'undefined' && navigator.language) ? navigator.language : undefined;
|
|
4620
|
-
const schemaId = buildSchemaId({ path, operation, schemaType: schemaTypeParam, includeInternalSchemas: includeInternal, tenant, locale, apiOrigin: origin });
|
|
4703
|
+
const schemaId = buildSchemaId({ path, operation, schemaType: schemaTypeParam, includeInternalSchemas: includeInternal, idField: params.idField, readOnly: params.readOnly, tenant, locale, apiOrigin: origin });
|
|
4621
4704
|
// Prepare headers with If-None-Match when cached
|
|
4622
4705
|
const headersBase = composeHeadersWithVersion(entry);
|
|
4623
4706
|
return from(this.ensureSchemaCacheReady()).pipe(concatMap(() => from(this._schemaCache.get(schemaId)).pipe(concatMap((cached) => {
|
|
@@ -4632,7 +4715,7 @@ class GenericCrudService {
|
|
|
4632
4715
|
headers = headers.set('Accept-Language', locale);
|
|
4633
4716
|
if (tenant)
|
|
4634
4717
|
headers = headers.set('X-Tenant', tenant);
|
|
4635
|
-
debugCrudService('[CRUD:Service] getFilteredSchema:request', { url, params: { path, operation, schemaType: schemaTypeParam, includeInternalSchemas: includeInternal }, hasCached: !!cached });
|
|
4718
|
+
debugCrudService('[CRUD:Service] getFilteredSchema:request', { url, params: { path, operation, schemaType: schemaTypeParam, includeInternalSchemas: includeInternal, idField: params.idField, readOnly: params.readOnly }, hasCached: !!cached });
|
|
4636
4719
|
return this.http.get(url, {
|
|
4637
4720
|
params: httpParams,
|
|
4638
4721
|
headers,
|
|
@@ -5222,9 +5305,7 @@ class GenericCrudService {
|
|
|
5222
5305
|
const includeInternal = !!options?.includeInternalSchemas;
|
|
5223
5306
|
const cacheEnabled = options?.cache !== false;
|
|
5224
5307
|
const endpointKey = options?.endpointKey ?? this.currentEndpointKey;
|
|
5225
|
-
const
|
|
5226
|
-
const locale = (typeof navigator !== 'undefined' && navigator.language) ? navigator.language : '-';
|
|
5227
|
-
const cacheKey = `${endpointKey}|${path}|post|request|${includeInternal ? '1' : '0'}|tenant:${tenant}|locale:${locale}`;
|
|
5308
|
+
const cacheKey = `${endpointKey}|${path}|post|request|${includeInternal ? '1' : '0'}`;
|
|
5228
5309
|
debugCrudService('[CRUD:Service] getFilterSchema:derived', {
|
|
5229
5310
|
path, includeInternal, cacheEnabled, cacheKey,
|
|
5230
5311
|
});
|
|
@@ -8774,10 +8855,16 @@ class PraxisJsonLogicService {
|
|
|
8774
8855
|
}
|
|
8775
8856
|
evaluate(expression, data, options) {
|
|
8776
8857
|
const context = this.createContext(data, options);
|
|
8777
|
-
|
|
8858
|
+
assertJsonLogicLimits(expression, context.limits ?? DEFAULT_JSON_LOGIC_LIMITS);
|
|
8859
|
+
const result = this.evaluateValue(expression, context);
|
|
8860
|
+
if (result !== undefined) {
|
|
8861
|
+
assertJsonLogicLimits(result, context.limits ?? DEFAULT_JSON_LOGIC_LIMITS, 'result');
|
|
8862
|
+
}
|
|
8863
|
+
return result;
|
|
8778
8864
|
}
|
|
8779
8865
|
evaluateResult(expression, data, options) {
|
|
8780
|
-
const
|
|
8866
|
+
const evaluated = this.evaluate(expression, data, options);
|
|
8867
|
+
const value = evaluated === undefined ? null : evaluated;
|
|
8781
8868
|
return {
|
|
8782
8869
|
value,
|
|
8783
8870
|
truthy: this.isTruthy(value),
|
|
@@ -8793,6 +8880,17 @@ class PraxisJsonLogicService {
|
|
|
8793
8880
|
validateResult(expression, options) {
|
|
8794
8881
|
const issues = [];
|
|
8795
8882
|
const context = this.createContext({}, options);
|
|
8883
|
+
try {
|
|
8884
|
+
assertJsonLogicLimits(expression, context.limits ?? DEFAULT_JSON_LOGIC_LIMITS);
|
|
8885
|
+
}
|
|
8886
|
+
catch (error) {
|
|
8887
|
+
issues.push({
|
|
8888
|
+
code: 'RULE_LIMIT_EXCEEDED',
|
|
8889
|
+
message: error instanceof Error ? error.message : 'JSON Logic expression exceeds configured limits.',
|
|
8890
|
+
path: '$',
|
|
8891
|
+
});
|
|
8892
|
+
return { valid: false, issues };
|
|
8893
|
+
}
|
|
8796
8894
|
if (options?.requireExpressionObject && !this.isTopLevelExpressionObject(expression)) {
|
|
8797
8895
|
issues.push({
|
|
8798
8896
|
code: 'RULE_SHAPE_INVALID',
|
|
@@ -8856,6 +8954,7 @@ class PraxisJsonLogicService {
|
|
|
8856
8954
|
allowImplicitRoot: options?.allowImplicitRoot,
|
|
8857
8955
|
nowUtc: options?.nowUtc,
|
|
8858
8956
|
userTimeZone: options?.userTimeZone,
|
|
8957
|
+
limits: { ...DEFAULT_JSON_LOGIC_LIMITS, ...options?.limits },
|
|
8859
8958
|
};
|
|
8860
8959
|
}
|
|
8861
8960
|
evaluateValue(value, context) {
|
|
@@ -9010,13 +9109,13 @@ class PraxisJsonLogicService {
|
|
|
9010
9109
|
const [left, right] = this.evaluateArgs(operator, rawArgs, context, 2, 2);
|
|
9011
9110
|
switch (operator) {
|
|
9012
9111
|
case '==':
|
|
9013
|
-
return left
|
|
9112
|
+
return canonicalLooseEquals(left, right);
|
|
9014
9113
|
case '===':
|
|
9015
|
-
return left
|
|
9114
|
+
return canonicalStrictEquals(left, right);
|
|
9016
9115
|
case '!=':
|
|
9017
|
-
return left
|
|
9116
|
+
return !canonicalLooseEquals(left, right);
|
|
9018
9117
|
case '!==':
|
|
9019
|
-
return left
|
|
9118
|
+
return !canonicalStrictEquals(left, right);
|
|
9020
9119
|
case '>':
|
|
9021
9120
|
this.assertComparable(operator, left, right);
|
|
9022
9121
|
return left > right;
|
|
@@ -9037,7 +9136,7 @@ class PraxisJsonLogicService {
|
|
|
9037
9136
|
return haystack.includes(needle);
|
|
9038
9137
|
}
|
|
9039
9138
|
if (Array.isArray(haystack)) {
|
|
9040
|
-
return haystack.some((item) => item
|
|
9139
|
+
return haystack.some((item) => canonicalStrictEquals(item, needle));
|
|
9041
9140
|
}
|
|
9042
9141
|
throw new PraxisJsonLogicError('RULE_ARGUMENT_TYPE_INVALID', '`in` requires a string haystack or an array haystack.');
|
|
9043
9142
|
}
|
|
@@ -9055,10 +9154,16 @@ class PraxisJsonLogicService {
|
|
|
9055
9154
|
return values.reduce((product, item) => product * item, 1);
|
|
9056
9155
|
case '/': {
|
|
9057
9156
|
this.requireArgs('/', values, 2);
|
|
9157
|
+
if (values.slice(1).some((item) => item === 0)) {
|
|
9158
|
+
throw new PraxisJsonLogicError('RULE_ARGUMENT_TYPE_INVALID', 'Operator / cannot divide by zero.');
|
|
9159
|
+
}
|
|
9058
9160
|
return values.slice(1).reduce((acc, item) => acc / item, values[0]);
|
|
9059
9161
|
}
|
|
9060
9162
|
case '%': {
|
|
9061
9163
|
this.requireArgs('%', values, 2, 2);
|
|
9164
|
+
if (values[1] === 0) {
|
|
9165
|
+
throw new PraxisJsonLogicError('RULE_ARGUMENT_TYPE_INVALID', 'Operator % cannot divide by zero.');
|
|
9166
|
+
}
|
|
9062
9167
|
return values[0] % values[1];
|
|
9063
9168
|
}
|
|
9064
9169
|
case 'min':
|
|
@@ -9069,7 +9174,12 @@ class PraxisJsonLogicService {
|
|
|
9069
9174
|
}
|
|
9070
9175
|
evaluateCat(rawArgs, context) {
|
|
9071
9176
|
const args = this.evaluateArgs('cat', rawArgs, context, 1);
|
|
9072
|
-
|
|
9177
|
+
const parts = args.map((value) => value == null ? '' : String(value));
|
|
9178
|
+
const length = parts.reduce((total, part) => total + part.length, 0);
|
|
9179
|
+
if (length > (context.limits ?? DEFAULT_JSON_LOGIC_LIMITS).maxStringLength) {
|
|
9180
|
+
throw new PraxisJsonLogicError('RULE_LIMIT_EXCEEDED', 'JSON Logic intermediate string exceeds the length limit.');
|
|
9181
|
+
}
|
|
9182
|
+
return parts.join('');
|
|
9073
9183
|
}
|
|
9074
9184
|
evaluateSubstr(rawArgs, context) {
|
|
9075
9185
|
const args = this.evaluateArgs('substr', rawArgs, context, 2, 3);
|
|
@@ -9088,7 +9198,12 @@ class PraxisJsonLogicService {
|
|
|
9088
9198
|
evaluateMerge(rawArgs, context) {
|
|
9089
9199
|
const args = this.toArgumentArray(rawArgs).map((arg) => this.evaluateValue(arg, context));
|
|
9090
9200
|
const result = [];
|
|
9201
|
+
const maxItems = (context.limits ?? DEFAULT_JSON_LOGIC_LIMITS).maxArrayItems;
|
|
9091
9202
|
for (const value of args) {
|
|
9203
|
+
const added = Array.isArray(value) ? value.length : 1;
|
|
9204
|
+
if (result.length + added > maxItems) {
|
|
9205
|
+
throw new PraxisJsonLogicError('RULE_LIMIT_EXCEEDED', 'JSON Logic intermediate array exceeds the item limit.');
|
|
9206
|
+
}
|
|
9092
9207
|
if (Array.isArray(value)) {
|
|
9093
9208
|
result.push(...value);
|
|
9094
9209
|
}
|
|
@@ -9102,12 +9217,14 @@ class PraxisJsonLogicService {
|
|
|
9102
9217
|
const [sourceExpression, mapExpression] = this.requireHigherOrderArgs('map', rawArgs, 2, 2);
|
|
9103
9218
|
const source = this.evaluateValue(sourceExpression, context);
|
|
9104
9219
|
this.assertArrayOperand('map', source);
|
|
9220
|
+
this.assertIntermediateArrayLimit(source, context);
|
|
9105
9221
|
return source.map((item) => this.evaluateValue(mapExpression, this.createChildContext(context, item)));
|
|
9106
9222
|
}
|
|
9107
9223
|
evaluateFilter(rawArgs, context) {
|
|
9108
9224
|
const [sourceExpression, predicateExpression] = this.requireHigherOrderArgs('filter', rawArgs, 2, 2);
|
|
9109
9225
|
const source = this.evaluateValue(sourceExpression, context);
|
|
9110
9226
|
this.assertArrayOperand('filter', source);
|
|
9227
|
+
this.assertIntermediateArrayLimit(source, context);
|
|
9111
9228
|
return source.filter((item) => this.isTruthy(this.evaluateValue(predicateExpression, this.createChildContext(context, item))));
|
|
9112
9229
|
}
|
|
9113
9230
|
evaluateReduce(rawArgs, context) {
|
|
@@ -9155,6 +9272,11 @@ class PraxisJsonLogicService {
|
|
|
9155
9272
|
throw new PraxisJsonLogicError('RULE_ARGUMENT_TYPE_INVALID', `Operator ${operator} requires an array as the first argument.`);
|
|
9156
9273
|
}
|
|
9157
9274
|
}
|
|
9275
|
+
assertIntermediateArrayLimit(value, context) {
|
|
9276
|
+
if (value.length > (context.limits ?? DEFAULT_JSON_LOGIC_LIMITS).maxArrayItems) {
|
|
9277
|
+
throw new PraxisJsonLogicError('RULE_LIMIT_EXCEEDED', 'JSON Logic intermediate array exceeds the item limit.');
|
|
9278
|
+
}
|
|
9279
|
+
}
|
|
9158
9280
|
createChildContext(context, data) {
|
|
9159
9281
|
return {
|
|
9160
9282
|
...context,
|
|
@@ -9274,6 +9396,19 @@ class PraxisJsonLogicService {
|
|
|
9274
9396
|
if (arity) {
|
|
9275
9397
|
this.validateArity(operator, args.length, arity.min, arity.max, path, issues);
|
|
9276
9398
|
}
|
|
9399
|
+
if (operator === 'matches' && typeof args[1] === 'string') {
|
|
9400
|
+
try {
|
|
9401
|
+
compileSafeRegex(args[1]);
|
|
9402
|
+
}
|
|
9403
|
+
catch (error) {
|
|
9404
|
+
issues.push({
|
|
9405
|
+
code: error instanceof PraxisJsonLogicError ? error.code : 'RULE_REGEX_INVALID',
|
|
9406
|
+
message: error instanceof Error ? error.message : 'Regular expression is invalid.',
|
|
9407
|
+
path,
|
|
9408
|
+
operator,
|
|
9409
|
+
});
|
|
9410
|
+
}
|
|
9411
|
+
}
|
|
9277
9412
|
args.forEach((arg, index) => this.validateValue(arg, context, `${path}.${operator}[${index}]`, issues));
|
|
9278
9413
|
}
|
|
9279
9414
|
validateVar(rawArgs, context, path, issues) {
|
|
@@ -9309,11 +9444,23 @@ class PraxisJsonLogicService {
|
|
|
9309
9444
|
if (!rawPath.length) {
|
|
9310
9445
|
return;
|
|
9311
9446
|
}
|
|
9447
|
+
let firstToken;
|
|
9448
|
+
try {
|
|
9449
|
+
firstToken = splitPath(rawPath)[0];
|
|
9450
|
+
}
|
|
9451
|
+
catch (error) {
|
|
9452
|
+
issues.push({
|
|
9453
|
+
code: error instanceof PraxisJsonLogicError ? error.code : 'RULE_PATH_INVALID',
|
|
9454
|
+
message: error instanceof Error ? error.message : `Invalid Praxis JSON Logic path: "${rawPath}".`,
|
|
9455
|
+
path,
|
|
9456
|
+
operator: 'var',
|
|
9457
|
+
});
|
|
9458
|
+
return;
|
|
9459
|
+
}
|
|
9312
9460
|
const availableRoots = context.availableRoots ?? [];
|
|
9313
9461
|
if (!availableRoots.length) {
|
|
9314
9462
|
return;
|
|
9315
9463
|
}
|
|
9316
|
-
const firstToken = splitPath(rawPath)[0];
|
|
9317
9464
|
if (!firstToken) {
|
|
9318
9465
|
return;
|
|
9319
9466
|
}
|
|
@@ -9358,61 +9505,12 @@ class PraxisJsonLogicService {
|
|
|
9358
9505
|
}
|
|
9359
9506
|
}
|
|
9360
9507
|
getOperatorArity(operator) {
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
return { min: 1 };
|
|
9365
|
-
case '!':
|
|
9366
|
-
case '!!':
|
|
9367
|
-
return { min: 1, max: 1 };
|
|
9368
|
-
case 'if':
|
|
9369
|
-
return { min: 2 };
|
|
9370
|
-
case 'in':
|
|
9371
|
-
case '==':
|
|
9372
|
-
case '===':
|
|
9373
|
-
case '!=':
|
|
9374
|
-
case '!==':
|
|
9375
|
-
case '>':
|
|
9376
|
-
case '>=':
|
|
9377
|
-
case '<':
|
|
9378
|
-
case '<=':
|
|
9379
|
-
return { min: 2, max: 2 };
|
|
9380
|
-
case 'cat':
|
|
9381
|
-
return { min: 1 };
|
|
9382
|
-
case 'substr':
|
|
9383
|
-
return { min: 2, max: 3 };
|
|
9384
|
-
case 'merge':
|
|
9385
|
-
return { min: 1 };
|
|
9386
|
-
case 'map':
|
|
9387
|
-
case 'filter':
|
|
9388
|
-
case 'all':
|
|
9389
|
-
case 'some':
|
|
9390
|
-
case 'none':
|
|
9391
|
-
return { min: 2, max: 2 };
|
|
9392
|
-
case 'reduce':
|
|
9393
|
-
return { min: 2, max: 3 };
|
|
9394
|
-
case '+':
|
|
9395
|
-
case '*':
|
|
9396
|
-
case 'min':
|
|
9397
|
-
case 'max':
|
|
9398
|
-
return { min: 1 };
|
|
9399
|
-
case '-':
|
|
9400
|
-
return { min: 1 };
|
|
9401
|
-
case '/':
|
|
9402
|
-
return { min: 2 };
|
|
9403
|
-
case '%':
|
|
9404
|
-
return { min: 2, max: 2 };
|
|
9405
|
-
default: {
|
|
9406
|
-
const custom = this.customOperators.get(operator);
|
|
9407
|
-
if (!custom) {
|
|
9408
|
-
return undefined;
|
|
9409
|
-
}
|
|
9410
|
-
return {
|
|
9411
|
-
min: custom.minArgs ?? 0,
|
|
9412
|
-
max: custom.maxArgs,
|
|
9413
|
-
};
|
|
9414
|
-
}
|
|
9508
|
+
const native = BUILTIN_JSON_LOGIC_OPERATOR_DESCRIPTORS.find((descriptor) => descriptor.operator === operator);
|
|
9509
|
+
if (native) {
|
|
9510
|
+
return { min: native.minArgs ?? 0, max: native.maxArgs };
|
|
9415
9511
|
}
|
|
9512
|
+
const custom = this.customOperators.get(operator);
|
|
9513
|
+
return custom ? { min: custom.minArgs ?? 0, max: custom.maxArgs } : undefined;
|
|
9416
9514
|
}
|
|
9417
9515
|
isSupportedOperator(operator) {
|
|
9418
9516
|
return BUILTIN_JSON_LOGIC_OPERATORS.includes(operator)
|
|
@@ -9450,7 +9548,7 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9450
9548
|
return container.includes(candidate);
|
|
9451
9549
|
}
|
|
9452
9550
|
if (Array.isArray(container)) {
|
|
9453
|
-
return container.some((item) => item
|
|
9551
|
+
return container.some((item) => canonicalStrictEquals(item, candidate));
|
|
9454
9552
|
}
|
|
9455
9553
|
throw new PraxisJsonLogicError('RULE_ARGUMENT_TYPE_INVALID', '`contains` requires a string or array as the first argument.');
|
|
9456
9554
|
},
|
|
@@ -9507,9 +9605,11 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9507
9605
|
throw new PraxisJsonLogicError('RULE_ARGUMENT_TYPE_INVALID', '`matches` requires string arguments.');
|
|
9508
9606
|
}
|
|
9509
9607
|
try {
|
|
9510
|
-
return
|
|
9608
|
+
return compileSafeRegex(pattern).test(value);
|
|
9511
9609
|
}
|
|
9512
|
-
catch {
|
|
9610
|
+
catch (error) {
|
|
9611
|
+
if (error instanceof PraxisJsonLogicError)
|
|
9612
|
+
throw error;
|
|
9513
9613
|
throw new PraxisJsonLogicError('RULE_ARGUMENT_TYPE_INVALID', '`matches` received an invalid regular expression.');
|
|
9514
9614
|
}
|
|
9515
9615
|
},
|
|
@@ -9642,7 +9742,7 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9642
9742
|
maxArgs: 0,
|
|
9643
9743
|
returnType: 'number',
|
|
9644
9744
|
purity: 'contextual',
|
|
9645
|
-
evaluate: () =>
|
|
9745
|
+
evaluate: (_args, context) => requiredNow(context).getTime(),
|
|
9646
9746
|
},
|
|
9647
9747
|
{
|
|
9648
9748
|
operator: 'date',
|
|
@@ -9653,10 +9753,7 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9653
9753
|
purity: 'pure',
|
|
9654
9754
|
evaluate: (args, _context, helpers) => {
|
|
9655
9755
|
const [value] = helpers.requireArgs('date', args, 1, 1);
|
|
9656
|
-
const parsed =
|
|
9657
|
-
if (!parsed) {
|
|
9658
|
-
return null;
|
|
9659
|
-
}
|
|
9756
|
+
const parsed = requireTemporalValue(value);
|
|
9660
9757
|
if (parsed.kind === 'date-only') {
|
|
9661
9758
|
return Date.parse(`${parsed.ymd}T00:00:00.000Z`);
|
|
9662
9759
|
}
|
|
@@ -9672,11 +9769,8 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9672
9769
|
purity: 'contextual',
|
|
9673
9770
|
evaluate: (args, context, helpers) => {
|
|
9674
9771
|
const [value] = helpers.requireArgs('yearsSince', args, 1, 1);
|
|
9675
|
-
const parsed =
|
|
9676
|
-
|
|
9677
|
-
return null;
|
|
9678
|
-
}
|
|
9679
|
-
const now = context.nowUtc ? new Date(context.nowUtc) : new Date();
|
|
9772
|
+
const parsed = requireTemporalValue(value);
|
|
9773
|
+
const now = requiredNow(context);
|
|
9680
9774
|
return Math.floor((now.getTime() - temporalValueToInstant(parsed).getTime()) / 31557600000);
|
|
9681
9775
|
},
|
|
9682
9776
|
},
|
|
@@ -9689,11 +9783,8 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9689
9783
|
purity: 'contextual',
|
|
9690
9784
|
evaluate: (args, context, helpers) => {
|
|
9691
9785
|
const [value] = helpers.requireArgs('monthsSince', args, 1, 1);
|
|
9692
|
-
const parsed =
|
|
9693
|
-
|
|
9694
|
-
return null;
|
|
9695
|
-
}
|
|
9696
|
-
const now = context.nowUtc ? new Date(context.nowUtc) : new Date();
|
|
9786
|
+
const parsed = requireTemporalValue(value);
|
|
9787
|
+
const now = requiredNow(context);
|
|
9697
9788
|
return Math.floor((now.getTime() - temporalValueToInstant(parsed).getTime()) / 2629800000);
|
|
9698
9789
|
},
|
|
9699
9790
|
},
|
|
@@ -9706,11 +9797,8 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9706
9797
|
purity: 'contextual',
|
|
9707
9798
|
evaluate: (args, context, helpers) => {
|
|
9708
9799
|
const [value] = helpers.requireArgs('daysSince', args, 1, 1);
|
|
9709
|
-
const parsed =
|
|
9710
|
-
|
|
9711
|
-
return null;
|
|
9712
|
-
}
|
|
9713
|
-
const now = context.nowUtc ? new Date(context.nowUtc) : new Date();
|
|
9800
|
+
const parsed = requireTemporalValue(value);
|
|
9801
|
+
const now = requiredNow(context);
|
|
9714
9802
|
return Math.floor((now.getTime() - temporalValueToInstant(parsed).getTime()) / 86400000);
|
|
9715
9803
|
},
|
|
9716
9804
|
},
|
|
@@ -9784,10 +9872,7 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9784
9872
|
purity: 'contextual',
|
|
9785
9873
|
evaluate: (args, context, helpers) => {
|
|
9786
9874
|
const [candidate] = helpers.requireArgs('isToday', args, 1, 1);
|
|
9787
|
-
const parsed =
|
|
9788
|
-
if (!parsed) {
|
|
9789
|
-
return false;
|
|
9790
|
-
}
|
|
9875
|
+
const parsed = requireTemporalValue(candidate);
|
|
9791
9876
|
return temporalValueToYmd(parsed, context) === currentYmd(context);
|
|
9792
9877
|
},
|
|
9793
9878
|
},
|
|
@@ -9800,11 +9885,11 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9800
9885
|
purity: 'contextual',
|
|
9801
9886
|
evaluate: (args, context, helpers) => {
|
|
9802
9887
|
const [candidate, rawAmount, rawUnit] = helpers.requireArgs('inLast', args, 3, 3);
|
|
9803
|
-
const parsed =
|
|
9888
|
+
const parsed = requireTemporalValue(candidate);
|
|
9804
9889
|
const amount = Math.abs(Number(rawAmount));
|
|
9805
9890
|
const unit = String(rawUnit || '').toLowerCase();
|
|
9806
|
-
if (!
|
|
9807
|
-
|
|
9891
|
+
if (!Number.isFinite(amount) || !/^(days?|weeks?|months?)$/.test(unit)) {
|
|
9892
|
+
throw temporalError('inLast requires a finite amount and one of days, weeks or months');
|
|
9808
9893
|
}
|
|
9809
9894
|
const today = currentYmd(context);
|
|
9810
9895
|
const floor = addYmdByUnit(today, -amount, unit);
|
|
@@ -9821,10 +9906,9 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
|
|
|
9821
9906
|
purity: 'contextual',
|
|
9822
9907
|
evaluate: (args, context, helpers) => {
|
|
9823
9908
|
const [candidate, rawDays] = helpers.requireArgs('weekdayIn', args, 2, 2);
|
|
9824
|
-
const parsed =
|
|
9825
|
-
if (!
|
|
9826
|
-
|
|
9827
|
-
}
|
|
9909
|
+
const parsed = requireTemporalValue(candidate);
|
|
9910
|
+
if (!Array.isArray(rawDays))
|
|
9911
|
+
throw new PraxisJsonLogicError('RULE_ARGUMENT_TYPE_INVALID', '`weekdayIn` requires an array of weekdays.');
|
|
9828
9912
|
const normalized = rawDays
|
|
9829
9913
|
.map((item) => Number(item))
|
|
9830
9914
|
.filter(Number.isFinite)
|
|
@@ -9848,39 +9932,6 @@ const ALL_RULE_CONTEXT_ROOTS = [
|
|
|
9848
9932
|
'state',
|
|
9849
9933
|
'context',
|
|
9850
9934
|
];
|
|
9851
|
-
const BUILTIN_JSON_LOGIC_OPERATORS = [
|
|
9852
|
-
'var',
|
|
9853
|
-
'==',
|
|
9854
|
-
'===',
|
|
9855
|
-
'!=',
|
|
9856
|
-
'!==',
|
|
9857
|
-
'>',
|
|
9858
|
-
'>=',
|
|
9859
|
-
'<',
|
|
9860
|
-
'<=',
|
|
9861
|
-
'!',
|
|
9862
|
-
'!!',
|
|
9863
|
-
'and',
|
|
9864
|
-
'or',
|
|
9865
|
-
'if',
|
|
9866
|
-
'in',
|
|
9867
|
-
'cat',
|
|
9868
|
-
'substr',
|
|
9869
|
-
'merge',
|
|
9870
|
-
'map',
|
|
9871
|
-
'filter',
|
|
9872
|
-
'reduce',
|
|
9873
|
-
'all',
|
|
9874
|
-
'some',
|
|
9875
|
-
'none',
|
|
9876
|
-
'+',
|
|
9877
|
-
'-',
|
|
9878
|
-
'*',
|
|
9879
|
-
'/',
|
|
9880
|
-
'%',
|
|
9881
|
-
'min',
|
|
9882
|
-
'max',
|
|
9883
|
-
];
|
|
9884
9935
|
const BUILTIN_JSON_LOGIC_OPERATOR_DESCRIPTORS = [
|
|
9885
9936
|
{ operator: 'var', source: 'native', minArgs: 1, maxArgs: 2, returnType: 'unknown', purity: 'pure' },
|
|
9886
9937
|
{ operator: '==', source: 'native', minArgs: 2, maxArgs: 2, returnType: 'boolean', purity: 'pure' },
|
|
@@ -9914,6 +9965,8 @@ const BUILTIN_JSON_LOGIC_OPERATOR_DESCRIPTORS = [
|
|
|
9914
9965
|
{ operator: 'min', source: 'native', minArgs: 1, returnType: 'number', purity: 'pure' },
|
|
9915
9966
|
{ operator: 'max', source: 'native', minArgs: 1, returnType: 'number', purity: 'pure' },
|
|
9916
9967
|
];
|
|
9968
|
+
const BUILTIN_JSON_LOGIC_OPERATORS = BUILTIN_JSON_LOGIC_OPERATOR_DESCRIPTORS
|
|
9969
|
+
.map((descriptor) => descriptor.operator);
|
|
9917
9970
|
function isComparisonOperator(operator) {
|
|
9918
9971
|
return ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(operator);
|
|
9919
9972
|
}
|
|
@@ -9935,6 +9988,8 @@ function parseTemporalValue(value) {
|
|
|
9935
9988
|
if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) {
|
|
9936
9989
|
return { kind: 'date-only', ymd: raw };
|
|
9937
9990
|
}
|
|
9991
|
+
if (!/(Z|[+-]\d{2}:\d{2})$/.test(raw))
|
|
9992
|
+
return null;
|
|
9938
9993
|
const date = new Date(raw);
|
|
9939
9994
|
return Number.isNaN(date.getTime()) ? null : { kind: 'instant', date };
|
|
9940
9995
|
}
|
|
@@ -9951,13 +10006,12 @@ function temporalValueToInstant(value) {
|
|
|
9951
10006
|
return new Date(`${value.ymd}T00:00:00.000Z`);
|
|
9952
10007
|
}
|
|
9953
10008
|
function currentYmd(context) {
|
|
9954
|
-
const now =
|
|
10009
|
+
const now = requiredNow(context);
|
|
9955
10010
|
return formatDateYmd(now, context.userTimeZone);
|
|
9956
10011
|
}
|
|
9957
10012
|
function formatDateYmd(date, timeZone) {
|
|
9958
|
-
if (!timeZone)
|
|
9959
|
-
|
|
9960
|
-
}
|
|
10013
|
+
if (!timeZone)
|
|
10014
|
+
throw temporalError('userTimeZone is required for contextual operators');
|
|
9961
10015
|
const formatter = new Intl.DateTimeFormat('en-CA', {
|
|
9962
10016
|
timeZone,
|
|
9963
10017
|
year: 'numeric',
|
|
@@ -9969,7 +10023,7 @@ function formatDateYmd(date, timeZone) {
|
|
|
9969
10023
|
function addYmdByUnit(ymd, amount, unit) {
|
|
9970
10024
|
const [year, month, day] = ymd.split('-').map((item) => Number(item));
|
|
9971
10025
|
const base = new Date(Date.UTC(year, month - 1, day));
|
|
9972
|
-
const normalized =
|
|
10026
|
+
const normalized = unit.toLowerCase();
|
|
9973
10027
|
if (normalized.startsWith('week')) {
|
|
9974
10028
|
base.setUTCDate(base.getUTCDate() + amount * 7);
|
|
9975
10029
|
return base.toISOString().slice(0, 10);
|
|
@@ -9979,8 +10033,56 @@ function addYmdByUnit(ymd, amount, unit) {
|
|
|
9979
10033
|
.toISOString()
|
|
9980
10034
|
.slice(0, 10);
|
|
9981
10035
|
}
|
|
9982
|
-
|
|
9983
|
-
|
|
10036
|
+
if (normalized.startsWith('day')) {
|
|
10037
|
+
base.setUTCDate(base.getUTCDate() + amount);
|
|
10038
|
+
return base.toISOString().slice(0, 10);
|
|
10039
|
+
}
|
|
10040
|
+
throw temporalError(`Unsupported temporal unit: ${unit}`);
|
|
10041
|
+
}
|
|
10042
|
+
const DEFAULT_JSON_LOGIC_LIMITS = {
|
|
10043
|
+
maxDepth: 64,
|
|
10044
|
+
maxNodes: 10_000,
|
|
10045
|
+
maxExpressionBytes: 256_000,
|
|
10046
|
+
maxArrayItems: 10_000,
|
|
10047
|
+
maxStringLength: 64_000,
|
|
10048
|
+
maxOperations: 50_000,
|
|
10049
|
+
maxRegexLength: 512,
|
|
10050
|
+
maxRegexComplexity: 64,
|
|
10051
|
+
};
|
|
10052
|
+
function assertJsonLogicLimits(value, limits, subject = 'expression') {
|
|
10053
|
+
const serialized = JSON.stringify(value);
|
|
10054
|
+
if (new TextEncoder().encode(serialized).length > limits.maxExpressionBytes) {
|
|
10055
|
+
throw new PraxisJsonLogicError('RULE_LIMIT_EXCEEDED', `JSON Logic ${subject} exceeds the byte limit.`);
|
|
10056
|
+
}
|
|
10057
|
+
let nodes = 0;
|
|
10058
|
+
let operations = 0;
|
|
10059
|
+
const visit = (candidate, depth) => {
|
|
10060
|
+
nodes += 1;
|
|
10061
|
+
if (nodes > limits.maxNodes || depth > limits.maxDepth) {
|
|
10062
|
+
throw new PraxisJsonLogicError('RULE_LIMIT_EXCEEDED', `JSON Logic ${subject} exceeds structural limits.`);
|
|
10063
|
+
}
|
|
10064
|
+
if (typeof candidate === 'string' && candidate.length > limits.maxStringLength) {
|
|
10065
|
+
throw new PraxisJsonLogicError('RULE_LIMIT_EXCEEDED', 'JSON Logic string exceeds the length limit.');
|
|
10066
|
+
}
|
|
10067
|
+
if (Array.isArray(candidate)) {
|
|
10068
|
+
if (candidate.length > limits.maxArrayItems) {
|
|
10069
|
+
throw new PraxisJsonLogicError('RULE_LIMIT_EXCEEDED', 'JSON Logic array exceeds the item limit.');
|
|
10070
|
+
}
|
|
10071
|
+
candidate.forEach((item) => visit(item, depth + 1));
|
|
10072
|
+
return;
|
|
10073
|
+
}
|
|
10074
|
+
if (candidate !== null && typeof candidate === 'object') {
|
|
10075
|
+
const entries = Object.entries(candidate);
|
|
10076
|
+
if (entries.length === 1) {
|
|
10077
|
+
operations += 1;
|
|
10078
|
+
if (operations > limits.maxOperations) {
|
|
10079
|
+
throw new PraxisJsonLogicError('RULE_LIMIT_EXCEEDED', 'JSON Logic expression exceeds the operation limit.');
|
|
10080
|
+
}
|
|
10081
|
+
}
|
|
10082
|
+
entries.forEach(([, child]) => visit(child, depth + 1));
|
|
10083
|
+
}
|
|
10084
|
+
};
|
|
10085
|
+
visit(value, 0);
|
|
9984
10086
|
}
|
|
9985
10087
|
function ymdToWeekday(ymd) {
|
|
9986
10088
|
const [year, month, day] = ymd.split('-').map((item) => Number(item));
|
|
@@ -9989,12 +10091,67 @@ function ymdToWeekday(ymd) {
|
|
|
9989
10091
|
return weekday === 0 ? 7 : weekday;
|
|
9990
10092
|
}
|
|
9991
10093
|
function splitPath(path) {
|
|
10094
|
+
if (!path || path === '$' || path.includes('..') || path.startsWith('.') || path.endsWith('.') || /\*|\?|\[\-|\[[^\d\"]|\[[^\]]*$/.test(path)) {
|
|
10095
|
+
throw new PraxisJsonLogicError('RULE_PATH_INVALID', `Invalid Praxis JSON Logic path: "${path}".`);
|
|
10096
|
+
}
|
|
9992
10097
|
const normalized = path.startsWith('$.') ? path.slice(2) : path;
|
|
9993
|
-
|
|
10098
|
+
const rewritten = normalized
|
|
9994
10099
|
.replace(/\["([^"]+)"\]/g, '.$1')
|
|
9995
|
-
.replace(/\[(\d+)\]/g, '.$1')
|
|
9996
|
-
|
|
9997
|
-
|
|
10100
|
+
.replace(/\[(\d+)\]/g, '.$1');
|
|
10101
|
+
if (rewritten.includes('[') || rewritten.includes(']'))
|
|
10102
|
+
throw new PraxisJsonLogicError('RULE_PATH_INVALID', `Invalid Praxis JSON Logic path: "${path}".`);
|
|
10103
|
+
return rewritten.split('.').filter(Boolean);
|
|
10104
|
+
}
|
|
10105
|
+
function canonicalStrictEquals(left, right) {
|
|
10106
|
+
if (typeof left === 'number' && typeof right === 'number')
|
|
10107
|
+
return Number.isFinite(left) && Number.isFinite(right) && left === right;
|
|
10108
|
+
if (Array.isArray(left) && Array.isArray(right))
|
|
10109
|
+
return left.length === right.length && left.every((value, index) => canonicalStrictEquals(value, right[index]));
|
|
10110
|
+
if (left && right && typeof left === 'object' && typeof right === 'object') {
|
|
10111
|
+
const a = Object.keys(left);
|
|
10112
|
+
const b = Object.keys(right);
|
|
10113
|
+
return a.length === b.length && a.every((key) => Object.prototype.hasOwnProperty.call(right, key) && canonicalStrictEquals(left[key], right[key]));
|
|
10114
|
+
}
|
|
10115
|
+
return left === right;
|
|
10116
|
+
}
|
|
10117
|
+
function canonicalLooseEquals(left, right) {
|
|
10118
|
+
if (left == null && right == null)
|
|
10119
|
+
return true;
|
|
10120
|
+
if (typeof left === 'number' && typeof right === 'string' && right.trim() !== '')
|
|
10121
|
+
return Number.isFinite(Number(right)) && left === Number(right);
|
|
10122
|
+
if (typeof right === 'number' && typeof left === 'string' && left.trim() !== '')
|
|
10123
|
+
return Number.isFinite(Number(left)) && right === Number(left);
|
|
10124
|
+
if (typeof left === 'boolean' && typeof right === 'number')
|
|
10125
|
+
return Number(left) === right;
|
|
10126
|
+
if (typeof right === 'boolean' && typeof left === 'number')
|
|
10127
|
+
return Number(right) === left;
|
|
10128
|
+
return canonicalStrictEquals(left, right);
|
|
10129
|
+
}
|
|
10130
|
+
function compileSafeRegex(pattern) {
|
|
10131
|
+
const complexity = (pattern.match(/[?{]/g) ?? []).length;
|
|
10132
|
+
const withoutBounds = pattern.replace(/\{\d+(?:,\d+)?\}/g, '');
|
|
10133
|
+
const oversizedBound = Array.from(pattern.matchAll(/\{(\d+)(?:,(\d+))?\}/g))
|
|
10134
|
+
.some((match) => Number(match[2] ?? match[1]) > 256);
|
|
10135
|
+
if (pattern.length > 512 || complexity > 64 || /[()*+|]/.test(pattern) || /\\[1-9]/.test(pattern) || /[{}]/.test(withoutBounds) || oversizedBound) {
|
|
10136
|
+
throw new PraxisJsonLogicError('RULE_REGEX_INVALID', 'Regular expression uses an unsupported or excessive construct.');
|
|
10137
|
+
}
|
|
10138
|
+
try {
|
|
10139
|
+
return new RegExp(pattern);
|
|
10140
|
+
}
|
|
10141
|
+
catch {
|
|
10142
|
+
throw new PraxisJsonLogicError('RULE_REGEX_INVALID', 'Regular expression is syntactically invalid.');
|
|
10143
|
+
}
|
|
10144
|
+
}
|
|
10145
|
+
function temporalError(message) { return new PraxisJsonLogicError('RULE_TEMPORAL_INPUT_INVALID', `${message}.`); }
|
|
10146
|
+
function requireTemporalValue(value) { const parsed = parseTemporalValue(value); if (!parsed)
|
|
10147
|
+
throw temporalError('Temporal input is invalid'); return parsed; }
|
|
10148
|
+
function requiredNow(context) {
|
|
10149
|
+
if (!context.nowUtc)
|
|
10150
|
+
throw temporalError('nowUtc is required for contextual operators');
|
|
10151
|
+
const now = new Date(context.nowUtc);
|
|
10152
|
+
if (Number.isNaN(now.getTime()))
|
|
10153
|
+
throw temporalError('nowUtc must be an ISO-8601 instant');
|
|
10154
|
+
return now;
|
|
9998
10155
|
}
|
|
9999
10156
|
function readPath(target, path) {
|
|
10000
10157
|
let current = target;
|
|
@@ -13198,6 +13355,12 @@ class ResourceDiscoveryService {
|
|
|
13198
13355
|
getCapabilities(source, options) {
|
|
13199
13356
|
return this.followLink(source, 'capabilities', options);
|
|
13200
13357
|
}
|
|
13358
|
+
getCapabilitiesByUrl(href, options) {
|
|
13359
|
+
return this.fetchJson(href, options);
|
|
13360
|
+
}
|
|
13361
|
+
getSchemaCatalog(query = {}, options) {
|
|
13362
|
+
return this.http.get(this.resolveHref('/schemas/catalog', options), { params: this.toSchemaCatalogParams(query) });
|
|
13363
|
+
}
|
|
13201
13364
|
fetchJson(href, options) {
|
|
13202
13365
|
return this.http.get(this.resolveHref(href, options));
|
|
13203
13366
|
}
|
|
@@ -13234,6 +13397,16 @@ class ResourceDiscoveryService {
|
|
|
13234
13397
|
}
|
|
13235
13398
|
return href;
|
|
13236
13399
|
}
|
|
13400
|
+
toSchemaCatalogParams(query) {
|
|
13401
|
+
let params = new HttpParams();
|
|
13402
|
+
for (const key of ['group', 'path', 'operation']) {
|
|
13403
|
+
const value = String(query[key] ?? '').trim();
|
|
13404
|
+
if (value) {
|
|
13405
|
+
params = params.set(key, value);
|
|
13406
|
+
}
|
|
13407
|
+
}
|
|
13408
|
+
return params;
|
|
13409
|
+
}
|
|
13237
13410
|
extractLinks(source) {
|
|
13238
13411
|
if (!source) {
|
|
13239
13412
|
return undefined;
|
|
@@ -13371,6 +13544,484 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
13371
13544
|
args: [{ providedIn: 'any' }]
|
|
13372
13545
|
}] });
|
|
13373
13546
|
|
|
13547
|
+
const SURFACE_OPEN_PRESETS = [
|
|
13548
|
+
{
|
|
13549
|
+
id: 'praxis-dynamic-form',
|
|
13550
|
+
label: 'Formulário',
|
|
13551
|
+
description: 'Abre um formulário dinâmico com resourcePath, formId e resourceId.',
|
|
13552
|
+
payload: {
|
|
13553
|
+
presentation: 'drawer',
|
|
13554
|
+
widget: {
|
|
13555
|
+
id: 'praxis-dynamic-form',
|
|
13556
|
+
bindingOrder: [
|
|
13557
|
+
'formId',
|
|
13558
|
+
'componentInstanceId',
|
|
13559
|
+
'resourcePath',
|
|
13560
|
+
'resourceId',
|
|
13561
|
+
'schemaUrl',
|
|
13562
|
+
'readUrl',
|
|
13563
|
+
'mode',
|
|
13564
|
+
'presentationModeGlobal',
|
|
13565
|
+
],
|
|
13566
|
+
inputs: {
|
|
13567
|
+
resourcePath: '',
|
|
13568
|
+
formId: '',
|
|
13569
|
+
mode: 'view',
|
|
13570
|
+
},
|
|
13571
|
+
},
|
|
13572
|
+
bindings: [],
|
|
13573
|
+
},
|
|
13574
|
+
},
|
|
13575
|
+
{
|
|
13576
|
+
id: 'praxis-table',
|
|
13577
|
+
label: 'Tabela',
|
|
13578
|
+
description: 'Abre uma tabela filtrável usando inputs declarativos e queryContext.',
|
|
13579
|
+
payload: {
|
|
13580
|
+
presentation: 'drawer',
|
|
13581
|
+
widget: {
|
|
13582
|
+
id: 'praxis-table',
|
|
13583
|
+
bindingOrder: ['resourcePath', 'tableId', 'queryContext'],
|
|
13584
|
+
inputs: {
|
|
13585
|
+
resourcePath: '',
|
|
13586
|
+
tableId: '',
|
|
13587
|
+
queryContext: {
|
|
13588
|
+
filters: {},
|
|
13589
|
+
},
|
|
13590
|
+
},
|
|
13591
|
+
},
|
|
13592
|
+
bindings: [],
|
|
13593
|
+
},
|
|
13594
|
+
},
|
|
13595
|
+
{
|
|
13596
|
+
id: 'praxis-list',
|
|
13597
|
+
label: 'Lista',
|
|
13598
|
+
description: 'Abre uma lista com config/listId e bindings configuráveis.',
|
|
13599
|
+
payload: {
|
|
13600
|
+
presentation: 'drawer',
|
|
13601
|
+
widget: {
|
|
13602
|
+
id: 'praxis-list',
|
|
13603
|
+
bindingOrder: ['listId', 'config'],
|
|
13604
|
+
inputs: {
|
|
13605
|
+
listId: '',
|
|
13606
|
+
config: {},
|
|
13607
|
+
},
|
|
13608
|
+
},
|
|
13609
|
+
bindings: [],
|
|
13610
|
+
},
|
|
13611
|
+
},
|
|
13612
|
+
{
|
|
13613
|
+
id: 'praxis-crud',
|
|
13614
|
+
label: 'CRUD',
|
|
13615
|
+
description: 'Abre a surface de CRUD com metadata/crudId e bindings configuráveis.',
|
|
13616
|
+
payload: {
|
|
13617
|
+
presentation: 'drawer',
|
|
13618
|
+
widget: {
|
|
13619
|
+
id: 'praxis-crud',
|
|
13620
|
+
bindingOrder: ['metadata', 'crudId', 'context'],
|
|
13621
|
+
inputs: {
|
|
13622
|
+
metadata: {
|
|
13623
|
+
component: 'praxis-crud',
|
|
13624
|
+
table: {
|
|
13625
|
+
columns: [],
|
|
13626
|
+
},
|
|
13627
|
+
data: [],
|
|
13628
|
+
},
|
|
13629
|
+
crudId: '',
|
|
13630
|
+
context: {},
|
|
13631
|
+
},
|
|
13632
|
+
},
|
|
13633
|
+
bindings: [],
|
|
13634
|
+
},
|
|
13635
|
+
},
|
|
13636
|
+
];
|
|
13637
|
+
|
|
13638
|
+
class ResourceSurfaceOpenAdapterService {
|
|
13639
|
+
discovery = inject(ResourceDiscoveryService);
|
|
13640
|
+
toPayload(surface, options) {
|
|
13641
|
+
const resourcePath = this.normalizeResourcePath(options.resourcePath);
|
|
13642
|
+
if (!resourcePath) {
|
|
13643
|
+
throw new Error('ResourceSurfaceOpenAdapterService requires resourcePath.');
|
|
13644
|
+
}
|
|
13645
|
+
const discoveryOptions = options.endpointKey || options.apiUrlEntry
|
|
13646
|
+
? {
|
|
13647
|
+
...(options.endpointKey ? { endpointKey: options.endpointKey } : {}),
|
|
13648
|
+
...(options.apiUrlEntry ? { apiUrlEntry: options.apiUrlEntry } : {}),
|
|
13649
|
+
}
|
|
13650
|
+
: undefined;
|
|
13651
|
+
const resolvedApiEntry = this.discovery.resolveApiEntry(discoveryOptions);
|
|
13652
|
+
const resolvedSchemaUrl = this.discovery.resolveHref(surface.schemaUrl, discoveryOptions);
|
|
13653
|
+
const resolvedSubmitUrl = this.isWritableFormSurface(surface.kind)
|
|
13654
|
+
? this.discovery.resolveHref(surface.path, discoveryOptions)
|
|
13655
|
+
: null;
|
|
13656
|
+
const resolvedReadUrl = this.resolveItemHydrationReadUrl(surface, resourcePath, discoveryOptions);
|
|
13657
|
+
const basePayload = this.buildBasePayload(surface);
|
|
13658
|
+
const payload = {
|
|
13659
|
+
...basePayload,
|
|
13660
|
+
presentation: options.presentation ?? basePayload.presentation,
|
|
13661
|
+
title: options.title ?? surface.title ?? basePayload.title,
|
|
13662
|
+
subtitle: options.subtitle ?? surface.description ?? basePayload.subtitle,
|
|
13663
|
+
icon: options.icon ?? basePayload.icon,
|
|
13664
|
+
context: {
|
|
13665
|
+
resource: {
|
|
13666
|
+
resourceKey: surface.resourceKey,
|
|
13667
|
+
resourcePath,
|
|
13668
|
+
resourceId: options.resourceId ?? null,
|
|
13669
|
+
group: options.group ?? null,
|
|
13670
|
+
},
|
|
13671
|
+
surface: {
|
|
13672
|
+
id: surface.id,
|
|
13673
|
+
resourceKey: surface.resourceKey,
|
|
13674
|
+
kind: surface.kind,
|
|
13675
|
+
scope: surface.scope,
|
|
13676
|
+
title: surface.title,
|
|
13677
|
+
description: surface.description ?? null,
|
|
13678
|
+
intent: surface.intent ?? null,
|
|
13679
|
+
operationId: surface.operationId,
|
|
13680
|
+
path: surface.path,
|
|
13681
|
+
method: surface.method,
|
|
13682
|
+
schemaId: surface.schemaId,
|
|
13683
|
+
schemaUrl: surface.schemaUrl,
|
|
13684
|
+
responseCardinality: surface.responseCardinality ?? null,
|
|
13685
|
+
availability: surface.availability,
|
|
13686
|
+
order: surface.order,
|
|
13687
|
+
tags: surface.tags,
|
|
13688
|
+
relatedResource: surface.relatedResource ?? null,
|
|
13689
|
+
},
|
|
13690
|
+
},
|
|
13691
|
+
};
|
|
13692
|
+
if (basePayload.widget.id === 'praxis-table') {
|
|
13693
|
+
payload.widget.inputs = {
|
|
13694
|
+
...(payload.widget.inputs || {}),
|
|
13695
|
+
resourcePath,
|
|
13696
|
+
tableId: this.buildStableInstanceId(surface),
|
|
13697
|
+
queryContext: options.queryContext ?? payload.widget.inputs?.['queryContext'] ?? { filters: {} },
|
|
13698
|
+
};
|
|
13699
|
+
return payload;
|
|
13700
|
+
}
|
|
13701
|
+
const mode = this.resolveFormMode(surface.kind, surface.scope);
|
|
13702
|
+
payload.widget.inputs = {
|
|
13703
|
+
...(payload.widget.inputs || {}),
|
|
13704
|
+
resourcePath,
|
|
13705
|
+
formId: this.buildStableInstanceId(surface),
|
|
13706
|
+
mode,
|
|
13707
|
+
schemaUrl: resolvedSchemaUrl,
|
|
13708
|
+
readUrl: resolvedReadUrl,
|
|
13709
|
+
apiEndpointKey: options.endpointKey ?? null,
|
|
13710
|
+
apiUrlEntry: options.apiUrlEntry ?? resolvedApiEntry,
|
|
13711
|
+
};
|
|
13712
|
+
if (surface.scope === 'ITEM' && resolvedReadUrl) {
|
|
13713
|
+
payload.widget.inputs['customEndpoints'] = {
|
|
13714
|
+
...(payload.widget.inputs['customEndpoints'] || {}),
|
|
13715
|
+
getById: resolvedReadUrl,
|
|
13716
|
+
};
|
|
13717
|
+
payload.widget.bindingOrder = this.withInputBefore(payload.widget.bindingOrder, 'customEndpoints', 'resourceId');
|
|
13718
|
+
}
|
|
13719
|
+
if (this.isWritableFormSurface(surface.kind)) {
|
|
13720
|
+
payload.widget.inputs['submitMethod'] = surface.method.toLowerCase();
|
|
13721
|
+
payload.widget.inputs['submitUrl'] = resolvedSubmitUrl;
|
|
13722
|
+
}
|
|
13723
|
+
if (this.isReadableItemSurface(surface)) {
|
|
13724
|
+
payload.widget.inputs['presentationModeGlobal'] = true;
|
|
13725
|
+
}
|
|
13726
|
+
if (surface.scope === 'ITEM') {
|
|
13727
|
+
if (options.resourceId != null) {
|
|
13728
|
+
payload.widget.inputs['resourceId'] = options.resourceId;
|
|
13729
|
+
}
|
|
13730
|
+
else if (options.idBindingPath) {
|
|
13731
|
+
payload.bindings = [
|
|
13732
|
+
...(payload.bindings || []),
|
|
13733
|
+
this.buildIdBinding(options.idBindingPath),
|
|
13734
|
+
];
|
|
13735
|
+
}
|
|
13736
|
+
else {
|
|
13737
|
+
throw new Error(`ResourceSurfaceOpenAdapterService requires resourceId or idBindingPath for item surface "${surface.id}".`);
|
|
13738
|
+
}
|
|
13739
|
+
}
|
|
13740
|
+
return payload;
|
|
13741
|
+
}
|
|
13742
|
+
buildBasePayload(surface) {
|
|
13743
|
+
const presetId = surface.scope === 'COLLECTION' && this.isCollectionView(surface.kind)
|
|
13744
|
+
? 'praxis-table'
|
|
13745
|
+
: 'praxis-dynamic-form';
|
|
13746
|
+
const preset = SURFACE_OPEN_PRESETS.find((candidate) => candidate.id === presetId);
|
|
13747
|
+
if (!preset) {
|
|
13748
|
+
throw new Error(`Missing canonical surface preset "${presetId}".`);
|
|
13749
|
+
}
|
|
13750
|
+
return this.clone(preset.payload);
|
|
13751
|
+
}
|
|
13752
|
+
buildStableInstanceId(surface) {
|
|
13753
|
+
return `${surface.resourceKey}.${surface.id}`.replace(/[^a-zA-Z0-9._-]+/g, '-');
|
|
13754
|
+
}
|
|
13755
|
+
withInputBefore(bindingOrder, input, beforeInput) {
|
|
13756
|
+
const next = (bindingOrder || []).filter((item) => item !== input);
|
|
13757
|
+
const targetIndex = next.indexOf(beforeInput);
|
|
13758
|
+
if (targetIndex >= 0) {
|
|
13759
|
+
next.splice(targetIndex, 0, input);
|
|
13760
|
+
return next;
|
|
13761
|
+
}
|
|
13762
|
+
return [...next, input];
|
|
13763
|
+
}
|
|
13764
|
+
normalizeResourcePath(resourcePath) {
|
|
13765
|
+
return String(resourcePath || '').trim().replace(/^\/+/, '').replace(/\/+$/, '');
|
|
13766
|
+
}
|
|
13767
|
+
resolveFormMode(kind, scope) {
|
|
13768
|
+
if (kind === 'VIEW' || kind === 'READ_PROJECTION') {
|
|
13769
|
+
return 'view';
|
|
13770
|
+
}
|
|
13771
|
+
if (scope === 'ITEM') {
|
|
13772
|
+
return 'edit';
|
|
13773
|
+
}
|
|
13774
|
+
return 'create';
|
|
13775
|
+
}
|
|
13776
|
+
isCollectionView(kind) {
|
|
13777
|
+
return kind === 'VIEW' || kind === 'READ_PROJECTION';
|
|
13778
|
+
}
|
|
13779
|
+
isWritableFormSurface(kind) {
|
|
13780
|
+
return kind === 'FORM' || kind === 'PARTIAL_FORM';
|
|
13781
|
+
}
|
|
13782
|
+
isReadableFormSurface(kind) {
|
|
13783
|
+
return kind === 'VIEW' || kind === 'READ_PROJECTION';
|
|
13784
|
+
}
|
|
13785
|
+
isReadableItemSurface(surface) {
|
|
13786
|
+
return (surface.scope === 'ITEM' &&
|
|
13787
|
+
surface.method.toUpperCase() === 'GET' &&
|
|
13788
|
+
(surface.kind === 'VIEW' || surface.kind === 'READ_PROJECTION'));
|
|
13789
|
+
}
|
|
13790
|
+
isItemFormHydrationSurface(surface) {
|
|
13791
|
+
return surface.scope === 'ITEM'
|
|
13792
|
+
&& (this.isReadableFormSurface(surface.kind) || this.isWritableFormSurface(surface.kind));
|
|
13793
|
+
}
|
|
13794
|
+
resolveItemHydrationReadUrl(surface, resourcePath, discoveryOptions) {
|
|
13795
|
+
if (!this.isItemFormHydrationSurface(surface)) {
|
|
13796
|
+
return null;
|
|
13797
|
+
}
|
|
13798
|
+
if (this.isReadableItemSurface(surface)) {
|
|
13799
|
+
return this.discovery.resolveHref(surface.path, discoveryOptions);
|
|
13800
|
+
}
|
|
13801
|
+
return this.discovery.resolveHref(this.buildCanonicalItemHref(resourcePath), discoveryOptions);
|
|
13802
|
+
}
|
|
13803
|
+
buildCanonicalItemHref(resourcePath) {
|
|
13804
|
+
const normalizedResourcePath = this.normalizeResourcePath(resourcePath);
|
|
13805
|
+
const itemHref = `${normalizedResourcePath}/{id}`;
|
|
13806
|
+
return normalizedResourcePath.startsWith('api/') ? `/${itemHref}` : itemHref;
|
|
13807
|
+
}
|
|
13808
|
+
buildIdBinding(idBindingPath) {
|
|
13809
|
+
return {
|
|
13810
|
+
from: idBindingPath,
|
|
13811
|
+
to: 'widget.inputs.resourceId',
|
|
13812
|
+
mode: 'path',
|
|
13813
|
+
};
|
|
13814
|
+
}
|
|
13815
|
+
clone(value) {
|
|
13816
|
+
return value == null ? value : JSON.parse(JSON.stringify(value));
|
|
13817
|
+
}
|
|
13818
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceSurfaceOpenAdapterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
13819
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceSurfaceOpenAdapterService, providedIn: 'any' });
|
|
13820
|
+
}
|
|
13821
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceSurfaceOpenAdapterService, decorators: [{
|
|
13822
|
+
type: Injectable,
|
|
13823
|
+
args: [{ providedIn: 'any' }]
|
|
13824
|
+
}] });
|
|
13825
|
+
|
|
13826
|
+
class ResourceRecordOpenError extends Error {
|
|
13827
|
+
code;
|
|
13828
|
+
detail;
|
|
13829
|
+
constructor(code, message, detail) {
|
|
13830
|
+
super(message);
|
|
13831
|
+
this.code = code;
|
|
13832
|
+
this.detail = detail;
|
|
13833
|
+
this.name = 'ResourceRecordOpenError';
|
|
13834
|
+
}
|
|
13835
|
+
}
|
|
13836
|
+
/**
|
|
13837
|
+
* Resolves a governed record-open reference into a contextual surface payload.
|
|
13838
|
+
*
|
|
13839
|
+
* The service deliberately re-queries discovery for the current principal. It
|
|
13840
|
+
* never treats the authoring-time catalog, the row label or a local URL template
|
|
13841
|
+
* as authorization to open the target surface.
|
|
13842
|
+
*/
|
|
13843
|
+
class ResourceRecordOpenService {
|
|
13844
|
+
discovery = inject(ResourceDiscoveryService);
|
|
13845
|
+
surfaceAdapter = inject(ResourceSurfaceOpenAdapterService);
|
|
13846
|
+
resolve(reference, record, options) {
|
|
13847
|
+
return defer(() => {
|
|
13848
|
+
const canonicalReference = this.requireReference(reference);
|
|
13849
|
+
const resourceId = this.requireResourceId(record, canonicalReference.sourceIdentityField);
|
|
13850
|
+
return this.discovery
|
|
13851
|
+
.fetchJson(this.surfaceCatalogHref(canonicalReference.target.resourceKey), options)
|
|
13852
|
+
.pipe(map$1((catalog) => this.requireCatalog(catalog, canonicalReference.target.resourceKey, 'RESOURCE_CATALOG_INVALID')), switchMap$1((resourceCatalog) => {
|
|
13853
|
+
this.requireCollectionTargetSurface(resourceCatalog, canonicalReference);
|
|
13854
|
+
return this.discovery
|
|
13855
|
+
.fetchJson(this.itemHref(resourceCatalog.resourcePath, resourceId), options)
|
|
13856
|
+
.pipe(switchMap$1((itemResponse) => this.discovery.getSurfaces(itemResponse, options)), map$1((contextualCatalog) => this.materializeContextualSurface(contextualCatalog, resourceCatalog, canonicalReference, resourceId, options)));
|
|
13857
|
+
}));
|
|
13858
|
+
}).pipe(catchError$1((error) => throwError(() => this.normalizeFailure(error))));
|
|
13859
|
+
}
|
|
13860
|
+
materializeContextualSurface(candidate, resourceCatalog, reference, resourceId, options) {
|
|
13861
|
+
const contextualCatalog = this.requireCatalog(candidate, reference.target.resourceKey, 'CONTEXTUAL_CATALOG_INVALID');
|
|
13862
|
+
if (contextualCatalog.resourcePath !== resourceCatalog.resourcePath) {
|
|
13863
|
+
throw new ResourceRecordOpenError('CONTEXTUAL_CATALOG_INVALID', 'Contextual surface discovery returned a different resource path.');
|
|
13864
|
+
}
|
|
13865
|
+
if (contextualCatalog.resourceId != null &&
|
|
13866
|
+
String(contextualCatalog.resourceId) !== String(resourceId)) {
|
|
13867
|
+
throw new ResourceRecordOpenError('CONTEXTUAL_CATALOG_INVALID', 'Contextual surface discovery returned a different resource identity.');
|
|
13868
|
+
}
|
|
13869
|
+
const surface = this.requireSurface(contextualCatalog, reference.target.surfaceId, reference.target.resourceKey, 'CONTEXTUAL_SURFACE_UNAVAILABLE');
|
|
13870
|
+
if (!surface.availability.allowed) {
|
|
13871
|
+
throw new ResourceRecordOpenError('CONTEXTUAL_SURFACE_UNAVAILABLE', `Surface "${reference.target.surfaceId}" is unavailable for the current record context.`, { reason: surface.availability.reason ?? null });
|
|
13872
|
+
}
|
|
13873
|
+
const payload = this.surfaceAdapter.toPayload(surface, {
|
|
13874
|
+
resourcePath: contextualCatalog.resourcePath,
|
|
13875
|
+
resourceId,
|
|
13876
|
+
endpointKey: options?.endpointKey,
|
|
13877
|
+
apiUrlEntry: options?.apiUrlEntry,
|
|
13878
|
+
group: contextualCatalog.group ?? resourceCatalog.group ?? null,
|
|
13879
|
+
presentation: options?.presentation,
|
|
13880
|
+
title: options?.title,
|
|
13881
|
+
subtitle: options?.subtitle,
|
|
13882
|
+
icon: options?.icon,
|
|
13883
|
+
queryContext: options?.queryContext,
|
|
13884
|
+
});
|
|
13885
|
+
return {
|
|
13886
|
+
resourceId,
|
|
13887
|
+
resourcePath: contextualCatalog.resourcePath,
|
|
13888
|
+
surface,
|
|
13889
|
+
payload,
|
|
13890
|
+
};
|
|
13891
|
+
}
|
|
13892
|
+
requireCollectionTargetSurface(catalog, reference) {
|
|
13893
|
+
const surface = this.requireSurface(catalog, reference.target.surfaceId, reference.target.resourceKey, 'TARGET_SURFACE_UNAVAILABLE');
|
|
13894
|
+
const availabilityReason = String(surface.availability.reason ?? '').trim();
|
|
13895
|
+
if (!surface.availability.allowed &&
|
|
13896
|
+
availabilityReason !== 'resource-context-required') {
|
|
13897
|
+
throw new ResourceRecordOpenError('TARGET_SURFACE_UNAVAILABLE', `Surface "${reference.target.surfaceId}" is unavailable for the current principal.`, { reason: availabilityReason || null });
|
|
13898
|
+
}
|
|
13899
|
+
}
|
|
13900
|
+
requireSurface(catalog, surfaceId, resourceKey, failureCode) {
|
|
13901
|
+
const candidate = catalog.surfaces.find((surface) => this.text(surface['id']) ===
|
|
13902
|
+
surfaceId);
|
|
13903
|
+
if (!candidate) {
|
|
13904
|
+
throw new ResourceRecordOpenError(failureCode, `Surface "${surfaceId}" is not declared for resource "${resourceKey}".`);
|
|
13905
|
+
}
|
|
13906
|
+
const surface = candidate;
|
|
13907
|
+
const availability = this.record(surface['availability']);
|
|
13908
|
+
const kind = this.text(surface['kind']);
|
|
13909
|
+
const supportedKinds = [
|
|
13910
|
+
'FORM',
|
|
13911
|
+
'PARTIAL_FORM',
|
|
13912
|
+
'VIEW',
|
|
13913
|
+
'READ_PROJECTION',
|
|
13914
|
+
];
|
|
13915
|
+
if (this.text(surface['resourceKey']) !== resourceKey ||
|
|
13916
|
+
this.text(surface['scope']) !== 'ITEM' ||
|
|
13917
|
+
!supportedKinds.includes(kind) ||
|
|
13918
|
+
!this.text(surface['operationId']) ||
|
|
13919
|
+
!this.text(surface['path']) ||
|
|
13920
|
+
!this.text(surface['method']) ||
|
|
13921
|
+
!this.text(surface['schemaUrl']) ||
|
|
13922
|
+
typeof availability?.['allowed'] !== 'boolean') {
|
|
13923
|
+
throw new ResourceRecordOpenError(failureCode, `Surface "${surfaceId}" does not satisfy the canonical item-surface contract.`);
|
|
13924
|
+
}
|
|
13925
|
+
return candidate;
|
|
13926
|
+
}
|
|
13927
|
+
requireCatalog(candidate, resourceKey, failureCode) {
|
|
13928
|
+
const catalog = this.record(candidate);
|
|
13929
|
+
const resourcePath = this.safeResourcePath(this.text(catalog?.['resourcePath']));
|
|
13930
|
+
if (!catalog ||
|
|
13931
|
+
this.text(catalog['resourceKey']) !== resourceKey ||
|
|
13932
|
+
!resourcePath ||
|
|
13933
|
+
!Array.isArray(catalog['surfaces'])) {
|
|
13934
|
+
throw new ResourceRecordOpenError(failureCode, `Surface catalog for resource "${resourceKey}" is invalid.`);
|
|
13935
|
+
}
|
|
13936
|
+
const resourceId = catalog['resourceId'];
|
|
13937
|
+
if (resourceId != null &&
|
|
13938
|
+
typeof resourceId !== 'string' &&
|
|
13939
|
+
typeof resourceId !== 'number') {
|
|
13940
|
+
throw new ResourceRecordOpenError(failureCode, `Surface catalog for resource "${resourceKey}" has an invalid resource identity.`);
|
|
13941
|
+
}
|
|
13942
|
+
return {
|
|
13943
|
+
resourceKey,
|
|
13944
|
+
resourcePath,
|
|
13945
|
+
group: this.nullableText(catalog['group']),
|
|
13946
|
+
resourceId: resourceId ?? null,
|
|
13947
|
+
surfaces: catalog['surfaces'],
|
|
13948
|
+
};
|
|
13949
|
+
}
|
|
13950
|
+
requireReference(candidate) {
|
|
13951
|
+
const reference = this.record(candidate);
|
|
13952
|
+
const target = this.record(reference?.['target']);
|
|
13953
|
+
const sourceIdentityField = this.text(reference?.['sourceIdentityField']);
|
|
13954
|
+
const resourceKey = this.text(target?.['resourceKey']);
|
|
13955
|
+
const surfaceId = this.text(target?.['surfaceId']);
|
|
13956
|
+
if (!sourceIdentityField ||
|
|
13957
|
+
sourceIdentityField.length > 200 ||
|
|
13958
|
+
!/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/.test(resourceKey) ||
|
|
13959
|
+
!surfaceId ||
|
|
13960
|
+
surfaceId.length > 200) {
|
|
13961
|
+
throw new ResourceRecordOpenError('INVALID_REFERENCE', 'Record-open reference must declare a source field and canonical target identity.');
|
|
13962
|
+
}
|
|
13963
|
+
return {
|
|
13964
|
+
sourceIdentityField,
|
|
13965
|
+
target: { resourceKey, surfaceId },
|
|
13966
|
+
};
|
|
13967
|
+
}
|
|
13968
|
+
requireResourceId(candidate, sourceIdentityField) {
|
|
13969
|
+
const record = this.record(candidate);
|
|
13970
|
+
if (!record ||
|
|
13971
|
+
!Object.prototype.hasOwnProperty.call(record, sourceIdentityField)) {
|
|
13972
|
+
throw new ResourceRecordOpenError('SOURCE_IDENTITY_MISSING', `Record does not publish source identity field "${sourceIdentityField}".`);
|
|
13973
|
+
}
|
|
13974
|
+
const value = record[sourceIdentityField];
|
|
13975
|
+
if (typeof value === 'string' && value.trim()) {
|
|
13976
|
+
return value.trim();
|
|
13977
|
+
}
|
|
13978
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
13979
|
+
return value;
|
|
13980
|
+
}
|
|
13981
|
+
throw new ResourceRecordOpenError('SOURCE_IDENTITY_INVALID', `Source identity field "${sourceIdentityField}" must contain a string or finite number.`);
|
|
13982
|
+
}
|
|
13983
|
+
surfaceCatalogHref(resourceKey) {
|
|
13984
|
+
return `/schemas/surfaces?resource=${encodeURIComponent(resourceKey)}`;
|
|
13985
|
+
}
|
|
13986
|
+
itemHref(resourcePath, resourceId) {
|
|
13987
|
+
return `${resourcePath}/${encodeURIComponent(String(resourceId))}`;
|
|
13988
|
+
}
|
|
13989
|
+
safeResourcePath(candidate) {
|
|
13990
|
+
const normalized = candidate.replace(/\/+$/u, '');
|
|
13991
|
+
if (!normalized.startsWith('/api/') ||
|
|
13992
|
+
normalized.includes('..') ||
|
|
13993
|
+
normalized.includes('?') ||
|
|
13994
|
+
normalized.includes('#') ||
|
|
13995
|
+
normalized.includes('://')) {
|
|
13996
|
+
return null;
|
|
13997
|
+
}
|
|
13998
|
+
return normalized;
|
|
13999
|
+
}
|
|
14000
|
+
normalizeFailure(error) {
|
|
14001
|
+
if (error instanceof ResourceRecordOpenError) {
|
|
14002
|
+
return error;
|
|
14003
|
+
}
|
|
14004
|
+
return new ResourceRecordOpenError('DISCOVERY_FAILED', 'Canonical record-open discovery failed.', error);
|
|
14005
|
+
}
|
|
14006
|
+
record(value) {
|
|
14007
|
+
return value != null && typeof value === 'object' && !Array.isArray(value)
|
|
14008
|
+
? value
|
|
14009
|
+
: null;
|
|
14010
|
+
}
|
|
14011
|
+
text(value) {
|
|
14012
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
14013
|
+
}
|
|
14014
|
+
nullableText(value) {
|
|
14015
|
+
return this.text(value) || null;
|
|
14016
|
+
}
|
|
14017
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceRecordOpenService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
14018
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceRecordOpenService, providedIn: 'any' });
|
|
14019
|
+
}
|
|
14020
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceRecordOpenService, decorators: [{
|
|
14021
|
+
type: Injectable,
|
|
14022
|
+
args: [{ providedIn: 'any' }]
|
|
14023
|
+
}] });
|
|
14024
|
+
|
|
13374
14025
|
const DEFAULT_SERVICE_KEY = 'praxis-service';
|
|
13375
14026
|
const DEFAULT_RELEASE_LIMIT = 50;
|
|
13376
14027
|
const DEFAULT_ITEM_LIMIT = 5;
|
|
@@ -13945,97 +14596,6 @@ function registerPraxisRuntimeComponentObservation(provider, options = {}) {
|
|
|
13945
14596
|
return registry.register(provider, { ...options, destroyRef });
|
|
13946
14597
|
}
|
|
13947
14598
|
|
|
13948
|
-
const SURFACE_OPEN_PRESETS = [
|
|
13949
|
-
{
|
|
13950
|
-
id: 'praxis-dynamic-form',
|
|
13951
|
-
label: 'Formulário',
|
|
13952
|
-
description: 'Abre um formulário dinâmico com resourcePath, formId e resourceId.',
|
|
13953
|
-
payload: {
|
|
13954
|
-
presentation: 'drawer',
|
|
13955
|
-
widget: {
|
|
13956
|
-
id: 'praxis-dynamic-form',
|
|
13957
|
-
bindingOrder: [
|
|
13958
|
-
'formId',
|
|
13959
|
-
'componentInstanceId',
|
|
13960
|
-
'resourcePath',
|
|
13961
|
-
'resourceId',
|
|
13962
|
-
'schemaUrl',
|
|
13963
|
-
'readUrl',
|
|
13964
|
-
'mode',
|
|
13965
|
-
'presentationModeGlobal',
|
|
13966
|
-
],
|
|
13967
|
-
inputs: {
|
|
13968
|
-
resourcePath: '',
|
|
13969
|
-
formId: '',
|
|
13970
|
-
mode: 'view',
|
|
13971
|
-
},
|
|
13972
|
-
},
|
|
13973
|
-
bindings: [],
|
|
13974
|
-
},
|
|
13975
|
-
},
|
|
13976
|
-
{
|
|
13977
|
-
id: 'praxis-table',
|
|
13978
|
-
label: 'Tabela',
|
|
13979
|
-
description: 'Abre uma tabela filtrável usando inputs declarativos e queryContext.',
|
|
13980
|
-
payload: {
|
|
13981
|
-
presentation: 'drawer',
|
|
13982
|
-
widget: {
|
|
13983
|
-
id: 'praxis-table',
|
|
13984
|
-
bindingOrder: ['resourcePath', 'tableId', 'queryContext'],
|
|
13985
|
-
inputs: {
|
|
13986
|
-
resourcePath: '',
|
|
13987
|
-
tableId: '',
|
|
13988
|
-
queryContext: {
|
|
13989
|
-
filters: {},
|
|
13990
|
-
},
|
|
13991
|
-
},
|
|
13992
|
-
},
|
|
13993
|
-
bindings: [],
|
|
13994
|
-
},
|
|
13995
|
-
},
|
|
13996
|
-
{
|
|
13997
|
-
id: 'praxis-list',
|
|
13998
|
-
label: 'Lista',
|
|
13999
|
-
description: 'Abre uma lista com config/listId e bindings configuráveis.',
|
|
14000
|
-
payload: {
|
|
14001
|
-
presentation: 'drawer',
|
|
14002
|
-
widget: {
|
|
14003
|
-
id: 'praxis-list',
|
|
14004
|
-
bindingOrder: ['listId', 'config'],
|
|
14005
|
-
inputs: {
|
|
14006
|
-
listId: '',
|
|
14007
|
-
config: {},
|
|
14008
|
-
},
|
|
14009
|
-
},
|
|
14010
|
-
bindings: [],
|
|
14011
|
-
},
|
|
14012
|
-
},
|
|
14013
|
-
{
|
|
14014
|
-
id: 'praxis-crud',
|
|
14015
|
-
label: 'CRUD',
|
|
14016
|
-
description: 'Abre a surface de CRUD com metadata/crudId e bindings configuráveis.',
|
|
14017
|
-
payload: {
|
|
14018
|
-
presentation: 'drawer',
|
|
14019
|
-
widget: {
|
|
14020
|
-
id: 'praxis-crud',
|
|
14021
|
-
bindingOrder: ['metadata', 'crudId', 'context'],
|
|
14022
|
-
inputs: {
|
|
14023
|
-
metadata: {
|
|
14024
|
-
component: 'praxis-crud',
|
|
14025
|
-
table: {
|
|
14026
|
-
columns: [],
|
|
14027
|
-
},
|
|
14028
|
-
data: [],
|
|
14029
|
-
},
|
|
14030
|
-
crudId: '',
|
|
14031
|
-
context: {},
|
|
14032
|
-
},
|
|
14033
|
-
},
|
|
14034
|
-
bindings: [],
|
|
14035
|
-
},
|
|
14036
|
-
},
|
|
14037
|
-
];
|
|
14038
|
-
|
|
14039
14599
|
class ResourceActionOpenAdapterService {
|
|
14040
14600
|
discovery = inject(ResourceDiscoveryService);
|
|
14041
14601
|
toPayload(action, options) {
|
|
@@ -14143,194 +14703,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
14143
14703
|
args: [{ providedIn: 'any' }]
|
|
14144
14704
|
}] });
|
|
14145
14705
|
|
|
14146
|
-
class ResourceSurfaceOpenAdapterService {
|
|
14147
|
-
discovery = inject(ResourceDiscoveryService);
|
|
14148
|
-
toPayload(surface, options) {
|
|
14149
|
-
const resourcePath = this.normalizeResourcePath(options.resourcePath);
|
|
14150
|
-
if (!resourcePath) {
|
|
14151
|
-
throw new Error('ResourceSurfaceOpenAdapterService requires resourcePath.');
|
|
14152
|
-
}
|
|
14153
|
-
const discoveryOptions = options.endpointKey || options.apiUrlEntry
|
|
14154
|
-
? {
|
|
14155
|
-
...(options.endpointKey ? { endpointKey: options.endpointKey } : {}),
|
|
14156
|
-
...(options.apiUrlEntry ? { apiUrlEntry: options.apiUrlEntry } : {}),
|
|
14157
|
-
}
|
|
14158
|
-
: undefined;
|
|
14159
|
-
const resolvedApiEntry = this.discovery.resolveApiEntry(discoveryOptions);
|
|
14160
|
-
const resolvedSchemaUrl = this.discovery.resolveHref(surface.schemaUrl, discoveryOptions);
|
|
14161
|
-
const resolvedSubmitUrl = this.isWritableFormSurface(surface.kind)
|
|
14162
|
-
? this.discovery.resolveHref(surface.path, discoveryOptions)
|
|
14163
|
-
: null;
|
|
14164
|
-
const resolvedReadUrl = this.resolveItemHydrationReadUrl(surface, resourcePath, discoveryOptions);
|
|
14165
|
-
const basePayload = this.buildBasePayload(surface);
|
|
14166
|
-
const payload = {
|
|
14167
|
-
...basePayload,
|
|
14168
|
-
presentation: options.presentation ?? basePayload.presentation,
|
|
14169
|
-
title: options.title ?? surface.title ?? basePayload.title,
|
|
14170
|
-
subtitle: options.subtitle ?? surface.description ?? basePayload.subtitle,
|
|
14171
|
-
icon: options.icon ?? basePayload.icon,
|
|
14172
|
-
context: {
|
|
14173
|
-
resource: {
|
|
14174
|
-
resourceKey: surface.resourceKey,
|
|
14175
|
-
resourcePath,
|
|
14176
|
-
resourceId: options.resourceId ?? null,
|
|
14177
|
-
group: options.group ?? null,
|
|
14178
|
-
},
|
|
14179
|
-
surface: {
|
|
14180
|
-
id: surface.id,
|
|
14181
|
-
resourceKey: surface.resourceKey,
|
|
14182
|
-
kind: surface.kind,
|
|
14183
|
-
scope: surface.scope,
|
|
14184
|
-
title: surface.title,
|
|
14185
|
-
description: surface.description ?? null,
|
|
14186
|
-
intent: surface.intent ?? null,
|
|
14187
|
-
operationId: surface.operationId,
|
|
14188
|
-
path: surface.path,
|
|
14189
|
-
method: surface.method,
|
|
14190
|
-
schemaId: surface.schemaId,
|
|
14191
|
-
schemaUrl: surface.schemaUrl,
|
|
14192
|
-
responseCardinality: surface.responseCardinality ?? null,
|
|
14193
|
-
availability: surface.availability,
|
|
14194
|
-
order: surface.order,
|
|
14195
|
-
tags: surface.tags,
|
|
14196
|
-
relatedResource: surface.relatedResource ?? null,
|
|
14197
|
-
},
|
|
14198
|
-
},
|
|
14199
|
-
};
|
|
14200
|
-
if (basePayload.widget.id === 'praxis-table') {
|
|
14201
|
-
payload.widget.inputs = {
|
|
14202
|
-
...(payload.widget.inputs || {}),
|
|
14203
|
-
resourcePath,
|
|
14204
|
-
tableId: this.buildStableInstanceId(surface),
|
|
14205
|
-
queryContext: options.queryContext ?? payload.widget.inputs?.['queryContext'] ?? { filters: {} },
|
|
14206
|
-
};
|
|
14207
|
-
return payload;
|
|
14208
|
-
}
|
|
14209
|
-
const mode = this.resolveFormMode(surface.kind, surface.scope);
|
|
14210
|
-
payload.widget.inputs = {
|
|
14211
|
-
...(payload.widget.inputs || {}),
|
|
14212
|
-
resourcePath,
|
|
14213
|
-
formId: this.buildStableInstanceId(surface),
|
|
14214
|
-
mode,
|
|
14215
|
-
schemaUrl: resolvedSchemaUrl,
|
|
14216
|
-
readUrl: resolvedReadUrl,
|
|
14217
|
-
apiEndpointKey: options.endpointKey ?? null,
|
|
14218
|
-
apiUrlEntry: options.apiUrlEntry ?? resolvedApiEntry,
|
|
14219
|
-
};
|
|
14220
|
-
if (surface.scope === 'ITEM' && resolvedReadUrl) {
|
|
14221
|
-
payload.widget.inputs['customEndpoints'] = {
|
|
14222
|
-
...(payload.widget.inputs['customEndpoints'] || {}),
|
|
14223
|
-
getById: resolvedReadUrl,
|
|
14224
|
-
};
|
|
14225
|
-
payload.widget.bindingOrder = this.withInputBefore(payload.widget.bindingOrder, 'customEndpoints', 'resourceId');
|
|
14226
|
-
}
|
|
14227
|
-
if (this.isWritableFormSurface(surface.kind)) {
|
|
14228
|
-
payload.widget.inputs['submitMethod'] = surface.method.toLowerCase();
|
|
14229
|
-
payload.widget.inputs['submitUrl'] = resolvedSubmitUrl;
|
|
14230
|
-
}
|
|
14231
|
-
if (this.isReadableItemSurface(surface)) {
|
|
14232
|
-
payload.widget.inputs['presentationModeGlobal'] = true;
|
|
14233
|
-
}
|
|
14234
|
-
if (surface.scope === 'ITEM') {
|
|
14235
|
-
if (options.resourceId != null) {
|
|
14236
|
-
payload.widget.inputs['resourceId'] = options.resourceId;
|
|
14237
|
-
}
|
|
14238
|
-
else if (options.idBindingPath) {
|
|
14239
|
-
payload.bindings = [
|
|
14240
|
-
...(payload.bindings || []),
|
|
14241
|
-
this.buildIdBinding(options.idBindingPath),
|
|
14242
|
-
];
|
|
14243
|
-
}
|
|
14244
|
-
else {
|
|
14245
|
-
throw new Error(`ResourceSurfaceOpenAdapterService requires resourceId or idBindingPath for item surface "${surface.id}".`);
|
|
14246
|
-
}
|
|
14247
|
-
}
|
|
14248
|
-
return payload;
|
|
14249
|
-
}
|
|
14250
|
-
buildBasePayload(surface) {
|
|
14251
|
-
const presetId = surface.scope === 'COLLECTION' && this.isCollectionView(surface.kind)
|
|
14252
|
-
? 'praxis-table'
|
|
14253
|
-
: 'praxis-dynamic-form';
|
|
14254
|
-
const preset = SURFACE_OPEN_PRESETS.find((candidate) => candidate.id === presetId);
|
|
14255
|
-
if (!preset) {
|
|
14256
|
-
throw new Error(`Missing canonical surface preset "${presetId}".`);
|
|
14257
|
-
}
|
|
14258
|
-
return this.clone(preset.payload);
|
|
14259
|
-
}
|
|
14260
|
-
buildStableInstanceId(surface) {
|
|
14261
|
-
return `${surface.resourceKey}.${surface.id}`.replace(/[^a-zA-Z0-9._-]+/g, '-');
|
|
14262
|
-
}
|
|
14263
|
-
withInputBefore(bindingOrder, input, beforeInput) {
|
|
14264
|
-
const next = (bindingOrder || []).filter((item) => item !== input);
|
|
14265
|
-
const targetIndex = next.indexOf(beforeInput);
|
|
14266
|
-
if (targetIndex >= 0) {
|
|
14267
|
-
next.splice(targetIndex, 0, input);
|
|
14268
|
-
return next;
|
|
14269
|
-
}
|
|
14270
|
-
return [...next, input];
|
|
14271
|
-
}
|
|
14272
|
-
normalizeResourcePath(resourcePath) {
|
|
14273
|
-
return String(resourcePath || '').trim().replace(/^\/+/, '').replace(/\/+$/, '');
|
|
14274
|
-
}
|
|
14275
|
-
resolveFormMode(kind, scope) {
|
|
14276
|
-
if (kind === 'VIEW' || kind === 'READ_PROJECTION') {
|
|
14277
|
-
return 'view';
|
|
14278
|
-
}
|
|
14279
|
-
if (scope === 'ITEM') {
|
|
14280
|
-
return 'edit';
|
|
14281
|
-
}
|
|
14282
|
-
return 'create';
|
|
14283
|
-
}
|
|
14284
|
-
isCollectionView(kind) {
|
|
14285
|
-
return kind === 'VIEW' || kind === 'READ_PROJECTION';
|
|
14286
|
-
}
|
|
14287
|
-
isWritableFormSurface(kind) {
|
|
14288
|
-
return kind === 'FORM' || kind === 'PARTIAL_FORM';
|
|
14289
|
-
}
|
|
14290
|
-
isReadableFormSurface(kind) {
|
|
14291
|
-
return kind === 'VIEW' || kind === 'READ_PROJECTION';
|
|
14292
|
-
}
|
|
14293
|
-
isReadableItemSurface(surface) {
|
|
14294
|
-
return (surface.scope === 'ITEM' &&
|
|
14295
|
-
surface.method.toUpperCase() === 'GET' &&
|
|
14296
|
-
(surface.kind === 'VIEW' || surface.kind === 'READ_PROJECTION'));
|
|
14297
|
-
}
|
|
14298
|
-
isItemFormHydrationSurface(surface) {
|
|
14299
|
-
return surface.scope === 'ITEM'
|
|
14300
|
-
&& (this.isReadableFormSurface(surface.kind) || this.isWritableFormSurface(surface.kind));
|
|
14301
|
-
}
|
|
14302
|
-
resolveItemHydrationReadUrl(surface, resourcePath, discoveryOptions) {
|
|
14303
|
-
if (!this.isItemFormHydrationSurface(surface)) {
|
|
14304
|
-
return null;
|
|
14305
|
-
}
|
|
14306
|
-
if (this.isReadableItemSurface(surface)) {
|
|
14307
|
-
return this.discovery.resolveHref(surface.path, discoveryOptions);
|
|
14308
|
-
}
|
|
14309
|
-
return this.discovery.resolveHref(this.buildCanonicalItemHref(resourcePath), discoveryOptions);
|
|
14310
|
-
}
|
|
14311
|
-
buildCanonicalItemHref(resourcePath) {
|
|
14312
|
-
const normalizedResourcePath = this.normalizeResourcePath(resourcePath);
|
|
14313
|
-
const itemHref = `${normalizedResourcePath}/{id}`;
|
|
14314
|
-
return normalizedResourcePath.startsWith('api/') ? `/${itemHref}` : itemHref;
|
|
14315
|
-
}
|
|
14316
|
-
buildIdBinding(idBindingPath) {
|
|
14317
|
-
return {
|
|
14318
|
-
from: idBindingPath,
|
|
14319
|
-
to: 'widget.inputs.resourceId',
|
|
14320
|
-
mode: 'path',
|
|
14321
|
-
};
|
|
14322
|
-
}
|
|
14323
|
-
clone(value) {
|
|
14324
|
-
return value == null ? value : JSON.parse(JSON.stringify(value));
|
|
14325
|
-
}
|
|
14326
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceSurfaceOpenAdapterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
14327
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceSurfaceOpenAdapterService, providedIn: 'any' });
|
|
14328
|
-
}
|
|
14329
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceSurfaceOpenAdapterService, decorators: [{
|
|
14330
|
-
type: Injectable,
|
|
14331
|
-
args: [{ providedIn: 'any' }]
|
|
14332
|
-
}] });
|
|
14333
|
-
|
|
14334
14706
|
class SurfaceOutletRegistryService {
|
|
14335
14707
|
registrations = new Map();
|
|
14336
14708
|
register(registration) {
|
|
@@ -15843,7 +16215,7 @@ const DEFAULT_FAMILIES = [
|
|
|
15843
16215
|
'kpi',
|
|
15844
16216
|
'summary-list',
|
|
15845
16217
|
];
|
|
15846
|
-
const ANALYTIC_TABLE_OPERATIONS = new Set(['group-by', 'timeseries', 'distribution']);
|
|
16218
|
+
const ANALYTIC_TABLE_OPERATIONS = new Set(['group-by', 'timeseries', 'distribution', 'comparison']);
|
|
15847
16219
|
class AnalyticsPresentationResolver {
|
|
15848
16220
|
resolve(analytics, options) {
|
|
15849
16221
|
const projections = analytics?.projections?.filter(Boolean) ?? [];
|
|
@@ -16061,6 +16433,12 @@ class SchemaMetadataClient {
|
|
|
16061
16433
|
u.searchParams.set('operation', (params.operation || 'get').toLowerCase());
|
|
16062
16434
|
u.searchParams.set('schemaType', (params.schemaType || 'response').toLowerCase());
|
|
16063
16435
|
u.searchParams.set('includeInternalSchemas', String(!!params.includeInternalSchemas));
|
|
16436
|
+
if (params.idField) {
|
|
16437
|
+
u.searchParams.set('idField', params.idField);
|
|
16438
|
+
}
|
|
16439
|
+
if (params.readOnly !== undefined) {
|
|
16440
|
+
u.searchParams.set('readOnly', String(params.readOnly));
|
|
16441
|
+
}
|
|
16064
16442
|
const key = schemaId;
|
|
16065
16443
|
if (this.inFlight.has(key))
|
|
16066
16444
|
return this.inFlight.get(key);
|
|
@@ -16169,6 +16547,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
16169
16547
|
args: [API_URL]
|
|
16170
16548
|
}] }] });
|
|
16171
16549
|
|
|
16550
|
+
const COMPARISON_METRIC_OPERATIONS = new Set([
|
|
16551
|
+
'COUNT',
|
|
16552
|
+
'DISTINCT_COUNT',
|
|
16553
|
+
'SUM',
|
|
16554
|
+
]);
|
|
16172
16555
|
class AnalyticsStatsRequestBuilderService {
|
|
16173
16556
|
buildExecutionPlan(projection) {
|
|
16174
16557
|
const dimension = projection.bindings.primaryDimension;
|
|
@@ -16232,6 +16615,26 @@ class AnalyticsStatsRequestBuilderService {
|
|
|
16232
16615
|
limit,
|
|
16233
16616
|
orderBy,
|
|
16234
16617
|
};
|
|
16618
|
+
case 'comparison': {
|
|
16619
|
+
const period = projection.bindings.comparisonPeriod;
|
|
16620
|
+
if (!period?.field || !period.timezone || !period.preset || !period.mode) {
|
|
16621
|
+
throw new Error(`AnalyticsStatsRequestBuilderService requires bindings.comparisonPeriod for comparison projection "${projection.id}".`);
|
|
16622
|
+
}
|
|
16623
|
+
this.assertComparisonMetrics(metrics, projection.id);
|
|
16624
|
+
return {
|
|
16625
|
+
filter: {},
|
|
16626
|
+
field,
|
|
16627
|
+
periodField: period.field,
|
|
16628
|
+
metrics,
|
|
16629
|
+
period: {
|
|
16630
|
+
preset: period.preset,
|
|
16631
|
+
timezone: period.timezone,
|
|
16632
|
+
mode: period.mode,
|
|
16633
|
+
},
|
|
16634
|
+
limit,
|
|
16635
|
+
orderBy,
|
|
16636
|
+
};
|
|
16637
|
+
}
|
|
16235
16638
|
default:
|
|
16236
16639
|
throw new Error(`Unsupported analytics stats operation "${projection.source.operation}".`);
|
|
16237
16640
|
}
|
|
@@ -16244,6 +16647,22 @@ class AnalyticsStatsRequestBuilderService {
|
|
|
16244
16647
|
alias: field,
|
|
16245
16648
|
};
|
|
16246
16649
|
}
|
|
16650
|
+
assertComparisonMetrics(metrics, projectionId) {
|
|
16651
|
+
const aliases = new Set();
|
|
16652
|
+
for (const metric of metrics) {
|
|
16653
|
+
if (!COMPARISON_METRIC_OPERATIONS.has(metric.operation)) {
|
|
16654
|
+
throw new Error(`Analytics comparison metric operation "${metric.operation}" is not supported for projection "${projectionId}".`);
|
|
16655
|
+
}
|
|
16656
|
+
const alias = metric.alias?.trim();
|
|
16657
|
+
if (!alias) {
|
|
16658
|
+
throw new Error(`Analytics comparison metrics require a non-empty alias for projection "${projectionId}".`);
|
|
16659
|
+
}
|
|
16660
|
+
if (aliases.has(alias)) {
|
|
16661
|
+
throw new Error(`Analytics comparison metric aliases must be unique for projection "${projectionId}": "${alias}".`);
|
|
16662
|
+
}
|
|
16663
|
+
aliases.add(alias);
|
|
16664
|
+
}
|
|
16665
|
+
}
|
|
16247
16666
|
mapAggregationToBackend(aggregation) {
|
|
16248
16667
|
switch ((aggregation ?? '').toLowerCase()) {
|
|
16249
16668
|
case 'avg':
|
|
@@ -22212,7 +22631,7 @@ const ValidationPattern = {
|
|
|
22212
22631
|
|
|
22213
22632
|
function materializeFormLayoutFromMetadata(fields, options = {}) {
|
|
22214
22633
|
const policy = normalizeLayoutPolicy(options.policy);
|
|
22215
|
-
const visibleFields = normalizeFields(fields, options.includeHidden === true);
|
|
22634
|
+
const visibleFields = normalizeFields(resolveRelationPresentationFields(fields, policy), options.includeHidden === true);
|
|
22216
22635
|
const layoutFields = fieldsForLayoutPolicy(visibleFields, policy);
|
|
22217
22636
|
const groupedFields = groupFields(layoutFields);
|
|
22218
22637
|
const sections = groupedFields.map(([groupKey, groupFields], sectionIndex) => createSection(groupKey, groupFields, sectionIndex, policy, options));
|
|
@@ -22231,9 +22650,65 @@ function materializeFormLayoutFromMetadata(fields, options = {}) {
|
|
|
22231
22650
|
},
|
|
22232
22651
|
});
|
|
22233
22652
|
}
|
|
22653
|
+
/**
|
|
22654
|
+
* Detail responses commonly carry both the persisted relationship identifier
|
|
22655
|
+
* (`cargoId`) and a read-only projection (`cargoNome`). A compact detail must
|
|
22656
|
+
* present the projection to people while preserving the identifier for command
|
|
22657
|
+
* schemas and every non-presentation use of the same metadata.
|
|
22658
|
+
*
|
|
22659
|
+
* This intentionally requires the established pair: a select/lookup field
|
|
22660
|
+
* ending in `Id` and its hidden `<base>Nome` projection. It does not infer a
|
|
22661
|
+
* relationship from labels or fabricate a display value when the resource did
|
|
22662
|
+
* not publish one.
|
|
22663
|
+
*/
|
|
22664
|
+
function resolveRelationPresentationFields(fields, policy) {
|
|
22665
|
+
if (policy.preset !== 'compactPresentation' || policy.intent === 'command') {
|
|
22666
|
+
return fields;
|
|
22667
|
+
}
|
|
22668
|
+
const byName = new Map(fields
|
|
22669
|
+
.filter((field) => !!field?.name)
|
|
22670
|
+
.map((field) => [field.name, field]));
|
|
22671
|
+
const relationIdsToHide = new Set();
|
|
22672
|
+
const projections = new Map();
|
|
22673
|
+
for (const field of fields) {
|
|
22674
|
+
const relationName = relationPresentationName(field);
|
|
22675
|
+
if (!relationName)
|
|
22676
|
+
continue;
|
|
22677
|
+
const projection = byName.get(relationName);
|
|
22678
|
+
if (!projection || !isFormHidden(projection))
|
|
22679
|
+
continue;
|
|
22680
|
+
relationIdsToHide.add(field.name);
|
|
22681
|
+
projections.set(relationName, {
|
|
22682
|
+
...projection,
|
|
22683
|
+
label: field.label ?? projection.label,
|
|
22684
|
+
group: field.group ?? projection.group,
|
|
22685
|
+
order: field.order ?? projection.order,
|
|
22686
|
+
width: field.width ?? projection.width,
|
|
22687
|
+
icon: field.icon ?? projection.icon,
|
|
22688
|
+
helpText: field.helpText ?? projection.helpText,
|
|
22689
|
+
formHidden: false,
|
|
22690
|
+
hidden: false,
|
|
22691
|
+
visible: true,
|
|
22692
|
+
});
|
|
22693
|
+
}
|
|
22694
|
+
if (!relationIdsToHide.size)
|
|
22695
|
+
return fields;
|
|
22696
|
+
return fields
|
|
22697
|
+
.filter((field) => !relationIdsToHide.has(field.name))
|
|
22698
|
+
.map((field) => projections.get(field.name) ?? field);
|
|
22699
|
+
}
|
|
22700
|
+
function relationPresentationName(field) {
|
|
22701
|
+
const name = String(field?.name || '').trim();
|
|
22702
|
+
if (!name.endsWith('Id') || !field.optionSource) {
|
|
22703
|
+
return null;
|
|
22704
|
+
}
|
|
22705
|
+
return `${name.slice(0, -2)}Nome`;
|
|
22706
|
+
}
|
|
22234
22707
|
function normalizeLayoutPolicy(policy) {
|
|
22235
|
-
const intent = policy?.intent ??
|
|
22236
|
-
|
|
22708
|
+
const intent = policy?.intent ??
|
|
22709
|
+
(policy?.preset === 'groupedCommand' ? 'command' : 'detail');
|
|
22710
|
+
const preset = policy?.preset ??
|
|
22711
|
+
(intent === 'command' ? 'groupedCommand' : 'compactPresentation');
|
|
22237
22712
|
return {
|
|
22238
22713
|
source: policy?.source ?? 'authored',
|
|
22239
22714
|
preset,
|
|
@@ -22254,7 +22729,9 @@ function normalizeFields(fields, includeHidden) {
|
|
|
22254
22729
|
}
|
|
22255
22730
|
function isFormHidden(field) {
|
|
22256
22731
|
const anyField = field;
|
|
22257
|
-
return anyField.formHidden === true ||
|
|
22732
|
+
return (anyField.formHidden === true ||
|
|
22733
|
+
anyField.hidden === true ||
|
|
22734
|
+
anyField.visible === false);
|
|
22258
22735
|
}
|
|
22259
22736
|
function groupFields(fields) {
|
|
22260
22737
|
const groups = new Map();
|
|
@@ -22316,7 +22793,13 @@ function createPresentationRows(fields, sectionId, policy) {
|
|
|
22316
22793
|
const column = {
|
|
22317
22794
|
id: `${sectionId}-col-${field.name}`,
|
|
22318
22795
|
fields: [field.name],
|
|
22319
|
-
items: [
|
|
22796
|
+
items: [
|
|
22797
|
+
{
|
|
22798
|
+
id: `${sectionId}-item-${field.name}`,
|
|
22799
|
+
kind: 'field',
|
|
22800
|
+
fieldName: field.name,
|
|
22801
|
+
},
|
|
22802
|
+
],
|
|
22320
22803
|
span,
|
|
22321
22804
|
};
|
|
22322
22805
|
if (packingSpan >= 12) {
|
|
@@ -22352,7 +22835,13 @@ function createCommandRows(fields, sectionId) {
|
|
|
22352
22835
|
const column = {
|
|
22353
22836
|
id: `${sectionId}-col-${field.name}`,
|
|
22354
22837
|
fields: [field.name],
|
|
22355
|
-
items: [
|
|
22838
|
+
items: [
|
|
22839
|
+
{
|
|
22840
|
+
id: `${sectionId}-item-${field.name}`,
|
|
22841
|
+
kind: 'field',
|
|
22842
|
+
fieldName: field.name,
|
|
22843
|
+
},
|
|
22844
|
+
],
|
|
22356
22845
|
span,
|
|
22357
22846
|
};
|
|
22358
22847
|
if (mdSpan >= 12) {
|
|
@@ -22404,7 +22893,9 @@ function resolveCommandSpan(field) {
|
|
|
22404
22893
|
return { xs: 12, sm: 12, md: 6, lg: 6, xl: 6 };
|
|
22405
22894
|
if (width === 'sm')
|
|
22406
22895
|
return { xs: 12, sm: 6, md: 4, lg: 4, xl: 4 };
|
|
22407
|
-
if (width === 'xs' ||
|
|
22896
|
+
if (width === 'xs' ||
|
|
22897
|
+
controlType.includes('checkbox') ||
|
|
22898
|
+
controlType.includes('toggle')) {
|
|
22408
22899
|
return { xs: 12, sm: 6, md: 3, lg: 3, xl: 3 };
|
|
22409
22900
|
}
|
|
22410
22901
|
return { xs: 12, sm: 12, md: 6, lg: 6, xl: 6 };
|
|
@@ -22422,7 +22913,9 @@ function resolvePresentationRowPackingSpan(span, policy) {
|
|
|
22422
22913
|
}
|
|
22423
22914
|
function hasExplicitWidth(field) {
|
|
22424
22915
|
const rawWidth = field.width;
|
|
22425
|
-
return rawWidth !== undefined &&
|
|
22916
|
+
return (rawWidth !== undefined &&
|
|
22917
|
+
rawWidth !== null &&
|
|
22918
|
+
String(rawWidth).trim() !== '');
|
|
22426
22919
|
}
|
|
22427
22920
|
function shouldUseSchemaWidth(field, policy, summarySpan) {
|
|
22428
22921
|
if (!hasExplicitWidth(field)) {
|
|
@@ -22560,7 +23053,8 @@ function resolveSummaryPriority(field, summary) {
|
|
|
22560
23053
|
const explicitFieldPriority = numberOrNull(summary.fieldPriority?.[field.name] ?? summary.fieldPriority?.[fieldName]);
|
|
22561
23054
|
if (explicitFieldPriority !== null)
|
|
22562
23055
|
return explicitFieldPriority;
|
|
22563
|
-
const explicitGroupPriority = numberOrNull(summary.groupPriority?.[String(field.group || '')] ??
|
|
23056
|
+
const explicitGroupPriority = numberOrNull(summary.groupPriority?.[String(field.group || '')] ??
|
|
23057
|
+
summary.groupPriority?.[groupName]);
|
|
22564
23058
|
if (explicitGroupPriority !== null)
|
|
22565
23059
|
return explicitGroupPriority;
|
|
22566
23060
|
const fieldPriority = numberOrNull(field.summaryPriority ??
|
|
@@ -22568,7 +23062,9 @@ function resolveSummaryPriority(field, summary) {
|
|
|
22568
23062
|
field.presentationPriority);
|
|
22569
23063
|
if (fieldPriority !== null)
|
|
22570
23064
|
return fieldPriority;
|
|
22571
|
-
return typeof field.order === 'number'
|
|
23065
|
+
return typeof field.order === 'number'
|
|
23066
|
+
? field.order
|
|
23067
|
+
: Number.MAX_SAFE_INTEGER;
|
|
22572
23068
|
}
|
|
22573
23069
|
function resolveFieldSummaryRoles(field) {
|
|
22574
23070
|
const raw = [
|
|
@@ -22605,7 +23101,9 @@ function numberOrNull(value) {
|
|
|
22605
23101
|
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
22606
23102
|
return value;
|
|
22607
23103
|
}
|
|
22608
|
-
if (typeof value === 'string' &&
|
|
23104
|
+
if (typeof value === 'string' &&
|
|
23105
|
+
value.trim() !== '' &&
|
|
23106
|
+
Number.isFinite(Number(value))) {
|
|
22609
23107
|
return Number(value);
|
|
22610
23108
|
}
|
|
22611
23109
|
return null;
|
|
@@ -22635,7 +23133,9 @@ function resolvePresentationRole(groupName, fields, map) {
|
|
|
22635
23133
|
return 'markers';
|
|
22636
23134
|
if (normalized.includes('regra') || normalized.includes('rule'))
|
|
22637
23135
|
return 'rules';
|
|
22638
|
-
if (fields.some((field) => String(field.controlType || '')
|
|
23136
|
+
if (fields.some((field) => String(field.controlType || '')
|
|
23137
|
+
.toLowerCase()
|
|
23138
|
+
.includes('checkbox'))) {
|
|
22639
23139
|
return 'markers';
|
|
22640
23140
|
}
|
|
22641
23141
|
return 'default';
|
|
@@ -28184,7 +28684,10 @@ class DynamicWidgetLoaderDirective {
|
|
|
28184
28684
|
this.tryRender();
|
|
28185
28685
|
}
|
|
28186
28686
|
ngOnChanges(changes) {
|
|
28187
|
-
if (changes['widget']
|
|
28687
|
+
if (changes['widget']
|
|
28688
|
+
|| changes['ownerWidgetKey']
|
|
28689
|
+
|| changes['context']
|
|
28690
|
+
|| changes['autoWireOutputs']) {
|
|
28188
28691
|
this.tryRender();
|
|
28189
28692
|
}
|
|
28190
28693
|
}
|
|
@@ -28234,7 +28737,7 @@ class DynamicWidgetLoaderDirective {
|
|
|
28234
28737
|
if (!def || !def.id)
|
|
28235
28738
|
return;
|
|
28236
28739
|
const meta = this.registry.get(def.id);
|
|
28237
|
-
const inputs = this.withInferredIdentityInputs(def.id, def.inputs || {}, def.childWidgetKey);
|
|
28740
|
+
const inputs = this.withInferredIdentityInputs(def.id, def.inputs || {}, def.childWidgetKey, this.ownerWidgetKey, meta || undefined);
|
|
28238
28741
|
this.normalizeMaterializedRuntimeInputs(def.id, inputs, meta || undefined);
|
|
28239
28742
|
const outputs = def.outputs || {};
|
|
28240
28743
|
try {
|
|
@@ -28380,7 +28883,8 @@ class DynamicWidgetLoaderDirective {
|
|
|
28380
28883
|
try {
|
|
28381
28884
|
const hadPreviousValue = Object.prototype.hasOwnProperty.call(this.boundInputValues, key);
|
|
28382
28885
|
const previousValue = this.boundInputValues[key];
|
|
28383
|
-
if (hadPreviousValue
|
|
28886
|
+
if (hadPreviousValue
|
|
28887
|
+
&& this.areInputValuesEquivalent(previousValue, value)) {
|
|
28384
28888
|
return;
|
|
28385
28889
|
}
|
|
28386
28890
|
if (this.isSignalInput(compRef.instance, key)) {
|
|
@@ -28471,7 +28975,7 @@ class DynamicWidgetLoaderDirective {
|
|
|
28471
28975
|
}
|
|
28472
28976
|
return value;
|
|
28473
28977
|
}
|
|
28474
|
-
withInferredIdentityInputs(id, inputs, childWidgetKey) {
|
|
28978
|
+
withInferredIdentityInputs(id, inputs, childWidgetKey, ownerWidgetKey, meta) {
|
|
28475
28979
|
const identityInputByComponent = {
|
|
28476
28980
|
'praxis-table': 'tableId',
|
|
28477
28981
|
'praxis-crud': 'crudId',
|
|
@@ -28483,16 +28987,96 @@ class DynamicWidgetLoaderDirective {
|
|
|
28483
28987
|
'praxis-files-upload': 'filesUploadId',
|
|
28484
28988
|
};
|
|
28485
28989
|
const identityInput = identityInputByComponent[id];
|
|
28486
|
-
const
|
|
28487
|
-
|
|
28990
|
+
const normalizedChildWidgetKey = String(childWidgetKey || '').trim();
|
|
28991
|
+
const normalizedOwnerWidgetKey = String(ownerWidgetKey || '').trim();
|
|
28992
|
+
const fallbackId = normalizedChildWidgetKey || normalizedOwnerWidgetKey;
|
|
28993
|
+
const declaredInputs = new Set((meta?.inputs || []).map((input) => input.name));
|
|
28994
|
+
if (!identityInput
|
|
28995
|
+
|| !fallbackId
|
|
28996
|
+
|| !declaredInputs.has(identityInput)) {
|
|
28488
28997
|
return { ...inputs };
|
|
28489
28998
|
}
|
|
28490
28999
|
return {
|
|
28491
29000
|
...inputs,
|
|
28492
29001
|
[identityInput]: inputs[identityInput] || fallbackId,
|
|
28493
|
-
|
|
29002
|
+
...(declaredInputs.has('componentInstanceId')
|
|
29003
|
+
? { componentInstanceId: inputs['componentInstanceId'] || fallbackId }
|
|
29004
|
+
: {}),
|
|
28494
29005
|
};
|
|
28495
29006
|
}
|
|
29007
|
+
areInputValuesEquivalent(previousValue, value) {
|
|
29008
|
+
if (Object.is(previousValue, value)) {
|
|
29009
|
+
return true;
|
|
29010
|
+
}
|
|
29011
|
+
return this.areJsonLikeInputsEqual(previousValue, value, new Set(), new Set());
|
|
29012
|
+
}
|
|
29013
|
+
areJsonLikeInputsEqual(previousValue, value, previousAncestors, valueAncestors) {
|
|
29014
|
+
const previousType = typeof previousValue;
|
|
29015
|
+
const valueType = typeof value;
|
|
29016
|
+
if (previousValue == null
|
|
29017
|
+
|| value == null
|
|
29018
|
+
|| previousType !== 'object'
|
|
29019
|
+
|| valueType !== 'object') {
|
|
29020
|
+
return Object.is(previousValue, value)
|
|
29021
|
+
&& previousType !== 'function'
|
|
29022
|
+
&& previousType !== 'symbol'
|
|
29023
|
+
&& previousType !== 'bigint'
|
|
29024
|
+
&& valueType !== 'function'
|
|
29025
|
+
&& valueType !== 'symbol'
|
|
29026
|
+
&& valueType !== 'bigint';
|
|
29027
|
+
}
|
|
29028
|
+
try {
|
|
29029
|
+
if (Object.getOwnPropertySymbols(previousValue).length > 0
|
|
29030
|
+
|| Object.getOwnPropertySymbols(value).length > 0) {
|
|
29031
|
+
return false;
|
|
29032
|
+
}
|
|
29033
|
+
const previousIsArray = Array.isArray(previousValue);
|
|
29034
|
+
const valueIsArray = Array.isArray(value);
|
|
29035
|
+
if (previousIsArray !== valueIsArray) {
|
|
29036
|
+
return false;
|
|
29037
|
+
}
|
|
29038
|
+
if (previousIsArray) {
|
|
29039
|
+
if (previousValue.length !== value.length) {
|
|
29040
|
+
return false;
|
|
29041
|
+
}
|
|
29042
|
+
}
|
|
29043
|
+
else {
|
|
29044
|
+
const previousPrototype = Object.getPrototypeOf(previousValue);
|
|
29045
|
+
const valuePrototype = Object.getPrototypeOf(value);
|
|
29046
|
+
if ((previousPrototype !== Object.prototype && previousPrototype !== null)
|
|
29047
|
+
|| (valuePrototype !== Object.prototype && valuePrototype !== null)) {
|
|
29048
|
+
return false;
|
|
29049
|
+
}
|
|
29050
|
+
}
|
|
29051
|
+
if (previousAncestors.has(previousValue)
|
|
29052
|
+
|| valueAncestors.has(value)) {
|
|
29053
|
+
return false;
|
|
29054
|
+
}
|
|
29055
|
+
const previousKeys = Object.keys(previousValue);
|
|
29056
|
+
const keys = Object.keys(value);
|
|
29057
|
+
if (previousKeys.length !== keys.length) {
|
|
29058
|
+
return false;
|
|
29059
|
+
}
|
|
29060
|
+
previousAncestors.add(previousValue);
|
|
29061
|
+
valueAncestors.add(value);
|
|
29062
|
+
try {
|
|
29063
|
+
for (const key of previousKeys) {
|
|
29064
|
+
if (!Object.prototype.hasOwnProperty.call(value, key)
|
|
29065
|
+
|| !this.areJsonLikeInputsEqual(previousValue[key], value[key], previousAncestors, valueAncestors)) {
|
|
29066
|
+
return false;
|
|
29067
|
+
}
|
|
29068
|
+
}
|
|
29069
|
+
return true;
|
|
29070
|
+
}
|
|
29071
|
+
finally {
|
|
29072
|
+
previousAncestors.delete(previousValue);
|
|
29073
|
+
valueAncestors.delete(value);
|
|
29074
|
+
}
|
|
29075
|
+
}
|
|
29076
|
+
catch {
|
|
29077
|
+
return false;
|
|
29078
|
+
}
|
|
29079
|
+
}
|
|
28496
29080
|
normalizeMaterializedRuntimeInputs(id, inputs, meta) {
|
|
28497
29081
|
const allowedInputs = new Set((meta?.inputs || []).map((input) => input.name));
|
|
28498
29082
|
const accepts = (key) => !allowedInputs.size || allowedInputs.has(key);
|
|
@@ -30720,6 +31304,16 @@ class CompositionValidatorService {
|
|
|
30720
31304
|
this.nestedPortCatalog = nestedPortCatalog;
|
|
30721
31305
|
this.jsonLogic = jsonLogic;
|
|
30722
31306
|
}
|
|
31307
|
+
validateLinks(links, context = {}) {
|
|
31308
|
+
const linkDiagnostics = links.flatMap((link) => this.validateLink(link, {
|
|
31309
|
+
...context,
|
|
31310
|
+
links,
|
|
31311
|
+
}));
|
|
31312
|
+
return [
|
|
31313
|
+
...linkDiagnostics,
|
|
31314
|
+
...this.validateFeedbackCycles(links),
|
|
31315
|
+
];
|
|
31316
|
+
}
|
|
30723
31317
|
validateLink(link, context = {}) {
|
|
30724
31318
|
const diagnostics = [];
|
|
30725
31319
|
this.validateEndpointDirections(link, diagnostics);
|
|
@@ -30998,6 +31592,100 @@ class CompositionValidatorService {
|
|
|
30998
31592
|
transformKinds: link.transform.steps.map((step) => step.kind),
|
|
30999
31593
|
}));
|
|
31000
31594
|
}
|
|
31595
|
+
validateFeedbackCycles(links) {
|
|
31596
|
+
const edges = links.map((link) => ({
|
|
31597
|
+
link,
|
|
31598
|
+
from: this.feedbackNodeKey(link.from),
|
|
31599
|
+
to: this.feedbackNodeKey(link.to),
|
|
31600
|
+
}));
|
|
31601
|
+
const adjacency = new Map();
|
|
31602
|
+
for (const edge of edges) {
|
|
31603
|
+
const current = adjacency.get(edge.from) ?? [];
|
|
31604
|
+
current.push(edge);
|
|
31605
|
+
adjacency.set(edge.from, current);
|
|
31606
|
+
}
|
|
31607
|
+
const diagnostics = [];
|
|
31608
|
+
const seenCycles = new Set();
|
|
31609
|
+
for (const edge of edges) {
|
|
31610
|
+
const path = this.findFeedbackPath(edge.to, edge.from, adjacency, [edge.link.id]);
|
|
31611
|
+
if (!path) {
|
|
31612
|
+
continue;
|
|
31613
|
+
}
|
|
31614
|
+
const cycleLinkIds = this.stableUniqueLinkIds(path);
|
|
31615
|
+
const cycleKey = cycleLinkIds.join('|');
|
|
31616
|
+
if (seenCycles.has(cycleKey)) {
|
|
31617
|
+
continue;
|
|
31618
|
+
}
|
|
31619
|
+
seenCycles.add(cycleKey);
|
|
31620
|
+
const cycleLinks = cycleLinkIds
|
|
31621
|
+
.map((id) => links.find((link) => link.id === id))
|
|
31622
|
+
.filter((link) => !!link);
|
|
31623
|
+
const guarded = cycleLinks.every((link) => this.isIntentionalGuardedFeedback(link));
|
|
31624
|
+
diagnostics.push(this.createFeedbackCycleDiagnostic(cycleLinks[0] ?? edge.link, cycleLinkIds, guarded));
|
|
31625
|
+
}
|
|
31626
|
+
return diagnostics;
|
|
31627
|
+
}
|
|
31628
|
+
findFeedbackPath(current, target, adjacency, path, visited = new Set()) {
|
|
31629
|
+
if (current === target) {
|
|
31630
|
+
return path;
|
|
31631
|
+
}
|
|
31632
|
+
if (visited.has(current)) {
|
|
31633
|
+
return null;
|
|
31634
|
+
}
|
|
31635
|
+
visited.add(current);
|
|
31636
|
+
for (const edge of adjacency.get(current) ?? []) {
|
|
31637
|
+
const next = this.findFeedbackPath(edge.to, target, adjacency, [...path, edge.link.id], new Set(visited));
|
|
31638
|
+
if (next) {
|
|
31639
|
+
return next;
|
|
31640
|
+
}
|
|
31641
|
+
}
|
|
31642
|
+
return null;
|
|
31643
|
+
}
|
|
31644
|
+
stableUniqueLinkIds(linkIds) {
|
|
31645
|
+
return Array.from(new Set(linkIds)).sort((left, right) => left.localeCompare(right));
|
|
31646
|
+
}
|
|
31647
|
+
feedbackNodeKey(endpoint) {
|
|
31648
|
+
if (endpoint.kind === 'state') {
|
|
31649
|
+
return `state:${endpoint.ref.layer ?? 'values'}:${endpoint.ref.path}`;
|
|
31650
|
+
}
|
|
31651
|
+
if (endpoint.kind === 'global-action') {
|
|
31652
|
+
return `global-action:${endpoint.ref.actionId}`;
|
|
31653
|
+
}
|
|
31654
|
+
const nested = endpoint.ref.nestedPath?.length
|
|
31655
|
+
? endpoint.ref.nestedPath.map((segment) => [
|
|
31656
|
+
segment.kind,
|
|
31657
|
+
segment.id,
|
|
31658
|
+
segment.key,
|
|
31659
|
+
segment.index,
|
|
31660
|
+
segment.componentType,
|
|
31661
|
+
].filter((part) => part !== undefined && part !== '').join(':')).join('/')
|
|
31662
|
+
: '';
|
|
31663
|
+
return `component:${endpoint.ref.widget}:${nested}`;
|
|
31664
|
+
}
|
|
31665
|
+
isIntentionalGuardedFeedback(link) {
|
|
31666
|
+
const tags = link.metadata?.tags ?? [];
|
|
31667
|
+
const declaresIntent = tags.includes('intentional-feedback');
|
|
31668
|
+
const hasGuard = !!link.condition
|
|
31669
|
+
|| !!link.policy?.distinct
|
|
31670
|
+
|| !!link.policy?.distinctBy
|
|
31671
|
+
|| typeof link.policy?.debounceMs === 'number';
|
|
31672
|
+
return declaresIntent && hasGuard;
|
|
31673
|
+
}
|
|
31674
|
+
createFeedbackCycleDiagnostic(link, cycleLinkIds, guarded) {
|
|
31675
|
+
const code = guarded
|
|
31676
|
+
? 'SEMANTIC_FEEDBACK_CYCLE_GUARDED'
|
|
31677
|
+
: 'SEMANTIC_FEEDBACK_CYCLE_UNGUARDED';
|
|
31678
|
+
const message = guarded
|
|
31679
|
+
? `O ciclo de feedback entre links ${cycleLinkIds.join(', ')} foi declarado como intencional e guardado.`
|
|
31680
|
+
: `A composicao contem ciclo de feedback nao guardado entre links ${cycleLinkIds.join(', ')}.`;
|
|
31681
|
+
return this.createDiagnostic(link, code, guarded ? 'warning' : 'error', message, {
|
|
31682
|
+
kind: 'link',
|
|
31683
|
+
linkId: cycleLinkIds[0],
|
|
31684
|
+
}, {
|
|
31685
|
+
cycleLinkIds,
|
|
31686
|
+
acceptancePath: 'Use metadata.tags com intentional-feedback e ao menos um guard canonico por link: condition, distinct, distinctBy ou debounceMs.',
|
|
31687
|
+
}, !guarded);
|
|
31688
|
+
}
|
|
31001
31689
|
endpointSemanticKind(endpoint) {
|
|
31002
31690
|
return endpoint.ref.semanticKind;
|
|
31003
31691
|
}
|
|
@@ -32239,6 +32927,8 @@ class CompositionRuntimeEngine {
|
|
|
32239
32927
|
const matchedLinkIds = matchedLinks.map((link) => link.id);
|
|
32240
32928
|
let workingState = cloneStateSnapshot(this.store.getSnapshot().state);
|
|
32241
32929
|
const runtimeDiagnostics = this.createNestedWidgetEventBridgeDiagnostics(event, matchedLinks, occurredAt);
|
|
32930
|
+
const blockedFeedbackDiagnostics = this.createFeedbackCycleBlockedDiagnostics(matchedLinks, occurredAt);
|
|
32931
|
+
runtimeDiagnostics.push(...blockedFeedbackDiagnostics.values());
|
|
32242
32932
|
const linkResults = new Map();
|
|
32243
32933
|
const trace = [];
|
|
32244
32934
|
const emittedDiagnosticIds = new Set();
|
|
@@ -32257,6 +32947,7 @@ class CompositionRuntimeEngine {
|
|
|
32257
32947
|
for (const link of matchedLinks) {
|
|
32258
32948
|
const previousLink = this.store.getSnapshot().links.find((item) => item.linkId === link.id);
|
|
32259
32949
|
const stateBefore = cloneStateSnapshot(workingState);
|
|
32950
|
+
const blockedFeedbackDiagnostic = blockedFeedbackDiagnostics.get(link.id);
|
|
32260
32951
|
trace.push(this.traceService.createEntry(event.eventId, sequence++, {
|
|
32261
32952
|
timestamp: occurredAt,
|
|
32262
32953
|
phase: 'source-resolved',
|
|
@@ -32275,6 +32966,29 @@ class CompositionRuntimeEngine {
|
|
|
32275
32966
|
...endpointTraceDetails('target', link.to),
|
|
32276
32967
|
},
|
|
32277
32968
|
}));
|
|
32969
|
+
if (blockedFeedbackDiagnostic) {
|
|
32970
|
+
trace.push(this.traceService.createEntry(event.eventId, sequence++, {
|
|
32971
|
+
timestamp: occurredAt,
|
|
32972
|
+
phase: 'delivery-skipped',
|
|
32973
|
+
linkId: link.id,
|
|
32974
|
+
subject: {
|
|
32975
|
+
kind: 'link',
|
|
32976
|
+
linkId: link.id,
|
|
32977
|
+
label: link.metadata?.label,
|
|
32978
|
+
},
|
|
32979
|
+
inputSnapshot: stateBefore,
|
|
32980
|
+
outputSnapshot: workingState,
|
|
32981
|
+
details: {
|
|
32982
|
+
status: 'skipped',
|
|
32983
|
+
skippedReason: 'feedback-cycle-blocked',
|
|
32984
|
+
...endpointTraceDetails('source', link.from),
|
|
32985
|
+
...endpointTraceDetails('target', link.to),
|
|
32986
|
+
},
|
|
32987
|
+
diagnostics: [blockedFeedbackDiagnostic.code],
|
|
32988
|
+
}));
|
|
32989
|
+
sequence = this.appendDiagnosticTraceEntries(trace, emittedDiagnosticIds, event.eventId, sequence, [blockedFeedbackDiagnostic], link.id);
|
|
32990
|
+
continue;
|
|
32991
|
+
}
|
|
32278
32992
|
if (link.transform) {
|
|
32279
32993
|
trace.push(this.traceService.createEntry(event.eventId, sequence++, {
|
|
32280
32994
|
timestamp: occurredAt,
|
|
@@ -32377,11 +33091,19 @@ class CompositionRuntimeEngine {
|
|
|
32377
33091
|
stateSnapshot: materializedState,
|
|
32378
33092
|
linkPatches: matchedLinks.map((link) => ({
|
|
32379
33093
|
linkId: link.id,
|
|
32380
|
-
status:
|
|
32381
|
-
|
|
32382
|
-
|
|
33094
|
+
status: blockedFeedbackDiagnostics.has(link.id)
|
|
33095
|
+
? 'skipped'
|
|
33096
|
+
: linkResults.get(link.id)?.status,
|
|
33097
|
+
lastEventAt: linkResults.has(link.id) || blockedFeedbackDiagnostics.has(link.id)
|
|
33098
|
+
? occurredAt
|
|
33099
|
+
: undefined,
|
|
33100
|
+
lastDispatchTraceId: linkResults.has(link.id) || blockedFeedbackDiagnostics.has(link.id)
|
|
33101
|
+
? event.eventId
|
|
33102
|
+
: undefined,
|
|
32383
33103
|
lastDeliveredValuePreview: linkResults.get(link.id)?.value,
|
|
32384
|
-
diagnostics:
|
|
33104
|
+
diagnostics: blockedFeedbackDiagnostics.has(link.id)
|
|
33105
|
+
? [blockedFeedbackDiagnostics.get(link.id)]
|
|
33106
|
+
: linkResults.get(link.id)?.diagnostics,
|
|
32385
33107
|
})),
|
|
32386
33108
|
diagnostics,
|
|
32387
33109
|
traceTail: trace,
|
|
@@ -32589,10 +33311,10 @@ class CompositionRuntimeEngine {
|
|
|
32589
33311
|
.filter((widget) => !!widget),
|
|
32590
33312
|
};
|
|
32591
33313
|
const links = definition.links;
|
|
32592
|
-
return
|
|
33314
|
+
return this.compositionValidator.validateLinks(links, {
|
|
32593
33315
|
page,
|
|
32594
33316
|
links,
|
|
32595
|
-
})
|
|
33317
|
+
});
|
|
32596
33318
|
}
|
|
32597
33319
|
createDerivedDiagnostic(definition, message, index) {
|
|
32598
33320
|
const nodeKey = this.extractDerivedNodeKey(message);
|
|
@@ -32706,6 +33428,42 @@ class CompositionRuntimeEngine {
|
|
|
32706
33428
|
createdAt: occurredAt,
|
|
32707
33429
|
}));
|
|
32708
33430
|
}
|
|
33431
|
+
createFeedbackCycleBlockedDiagnostics(matchedLinks, occurredAt) {
|
|
33432
|
+
const blocked = new Map();
|
|
33433
|
+
const semanticDiagnostics = this.store.getSnapshot().diagnostics.filter((diagnostic) => diagnostic.code === 'SEMANTIC_FEEDBACK_CYCLE_UNGUARDED');
|
|
33434
|
+
for (const diagnostic of semanticDiagnostics) {
|
|
33435
|
+
const cycleLinkIds = Array.isArray(diagnostic.details?.['cycleLinkIds'])
|
|
33436
|
+
? diagnostic.details?.['cycleLinkIds'].filter((id) => typeof id === 'string')
|
|
33437
|
+
: [];
|
|
33438
|
+
for (const link of matchedLinks) {
|
|
33439
|
+
if (!cycleLinkIds.includes(link.id) || blocked.has(link.id)) {
|
|
33440
|
+
continue;
|
|
33441
|
+
}
|
|
33442
|
+
blocked.set(link.id, {
|
|
33443
|
+
id: `${link.id}:RUNTIME_FEEDBACK_CYCLE_BLOCKED`,
|
|
33444
|
+
code: 'RUNTIME_FEEDBACK_CYCLE_BLOCKED',
|
|
33445
|
+
severity: 'error',
|
|
33446
|
+
phase: 'runtime-dispatch',
|
|
33447
|
+
message: `O link ${link.id} nao foi executado porque pertence a um ciclo de feedback nao guardado.`,
|
|
33448
|
+
summary: `Link ${link.id} bloqueado por ciclo de feedback.`,
|
|
33449
|
+
subject: {
|
|
33450
|
+
kind: 'link',
|
|
33451
|
+
linkId: link.id,
|
|
33452
|
+
label: link.metadata?.label,
|
|
33453
|
+
},
|
|
33454
|
+
details: {
|
|
33455
|
+
cycleLinkIds,
|
|
33456
|
+
semanticDiagnosticId: diagnostic.id,
|
|
33457
|
+
},
|
|
33458
|
+
source: 'runtime-engine',
|
|
33459
|
+
blocking: true,
|
|
33460
|
+
transient: true,
|
|
33461
|
+
createdAt: occurredAt,
|
|
33462
|
+
});
|
|
33463
|
+
}
|
|
33464
|
+
}
|
|
33465
|
+
return blocked;
|
|
33466
|
+
}
|
|
32709
33467
|
}
|
|
32710
33468
|
function isComponentPortEndpoint(endpoint) {
|
|
32711
33469
|
return endpoint.kind === 'component-port';
|
|
@@ -33674,6 +34432,8 @@ class DynamicWidgetPageComponent {
|
|
|
33674
34432
|
effectiveValues: {},
|
|
33675
34433
|
diagnostics: [],
|
|
33676
34434
|
};
|
|
34435
|
+
configEditorContextRequests = new Map();
|
|
34436
|
+
nextConfigEditorContextRequestId = 0;
|
|
33677
34437
|
layout;
|
|
33678
34438
|
canvas;
|
|
33679
34439
|
grouping = [];
|
|
@@ -33819,14 +34579,17 @@ class DynamicWidgetPageComponent {
|
|
|
33819
34579
|
let widgets = this.cloneWidgets(pageWithPatchedInputs.widgets || []);
|
|
33820
34580
|
const directDelivery = this.applyCompositionWidgetDeliveries(widgets, cycle);
|
|
33821
34581
|
widgets = directDelivery.widgets;
|
|
33822
|
-
const projectedWidgets = this.
|
|
33823
|
-
widgets,
|
|
33824
|
-
state: cycle.snapshot.state,
|
|
33825
|
-
now: cycle.snapshot.generatedAt,
|
|
33826
|
-
}).widgets;
|
|
34582
|
+
const projectedWidgets = this.projectPersistentCompositionStateInputs(widgets, cycle.snapshot.state, cycle.snapshot.generatedAt);
|
|
33827
34583
|
const stateProjectionChanged = !this.areStateValuesEqual(widgets, projectedWidgets);
|
|
33828
34584
|
widgets = projectedWidgets;
|
|
33829
34585
|
const nextRuntime = this.buildStateRuntime(state, pageWithPatchedInputs.context);
|
|
34586
|
+
if (this.isTransientOnlyCompositionCycle(cycle)
|
|
34587
|
+
&& !updatedPrimaryStatePaths.length
|
|
34588
|
+
&& !directDelivery.changed
|
|
34589
|
+
&& !widgetInputPatchResult.changed) {
|
|
34590
|
+
this.applyResponsivePresentation(pageWithPatchedInputs, widgets, nextRuntime);
|
|
34591
|
+
return;
|
|
34592
|
+
}
|
|
33830
34593
|
if (!updatedPrimaryStatePaths.length &&
|
|
33831
34594
|
!directDelivery.changed &&
|
|
33832
34595
|
!stateProjectionChanged &&
|
|
@@ -33835,6 +34598,17 @@ class DynamicWidgetPageComponent {
|
|
|
33835
34598
|
}
|
|
33836
34599
|
this.applyPageUpdate({ ...pageWithPatchedInputs, widgets, state }, true, nextRuntime, false);
|
|
33837
34600
|
}
|
|
34601
|
+
isTransientOnlyCompositionCycle(cycle) {
|
|
34602
|
+
if (!this.compositionDefinition || !cycle.matchedLinkIds.length) {
|
|
34603
|
+
return false;
|
|
34604
|
+
}
|
|
34605
|
+
const linksById = new Map(this.compositionDefinition.links.map((link) => [link.id, link]));
|
|
34606
|
+
return cycle.matchedLinkIds.every((linkId) => {
|
|
34607
|
+
const link = linksById.get(linkId);
|
|
34608
|
+
return link?.to.kind === 'state'
|
|
34609
|
+
&& (link.to.ref.layer ?? 'values') === 'transient';
|
|
34610
|
+
});
|
|
34611
|
+
}
|
|
33838
34612
|
applyWidgetInputPatchToPage(page, widgetKey, evt) {
|
|
33839
34613
|
const payload = evt?.payload;
|
|
33840
34614
|
let inputPatch = this.extractWidgetInputPatch(payload);
|
|
@@ -34483,11 +35257,7 @@ class DynamicWidgetPageComponent {
|
|
|
34483
35257
|
let widgets = this.cloneWidgets(page.widgets || []);
|
|
34484
35258
|
widgets = this.applyCompositionWidgetDeliveries(widgets, cycle).widgets;
|
|
34485
35259
|
if (this.compositionDefinition) {
|
|
34486
|
-
widgets = this.
|
|
34487
|
-
widgets,
|
|
34488
|
-
state: cycle.snapshot.state,
|
|
34489
|
-
now: cycle.snapshot.generatedAt,
|
|
34490
|
-
}).widgets;
|
|
35260
|
+
widgets = this.projectPersistentCompositionStateInputs(widgets, cycle.snapshot.state, cycle.snapshot.generatedAt);
|
|
34491
35261
|
}
|
|
34492
35262
|
const runtime = this.buildStateRuntime(state, page.context);
|
|
34493
35263
|
return {
|
|
@@ -34604,11 +35374,7 @@ class DynamicWidgetPageComponent {
|
|
|
34604
35374
|
const state = this.stateFromCompositionSnapshot(page.state, cycle.snapshot.state.primaryValues);
|
|
34605
35375
|
let widgets = this.cloneWidgets(page.widgets || []);
|
|
34606
35376
|
widgets = this.applyCompositionWidgetDeliveries(widgets, cycle).widgets;
|
|
34607
|
-
widgets = this.
|
|
34608
|
-
widgets,
|
|
34609
|
-
state: cycle.snapshot.state,
|
|
34610
|
-
now: cycle.snapshot.generatedAt,
|
|
34611
|
-
}).widgets;
|
|
35377
|
+
widgets = this.projectPersistentCompositionStateInputs(widgets, cycle.snapshot.state, cycle.snapshot.generatedAt);
|
|
34612
35378
|
const runtime = this.buildStateRuntime(state, page.context);
|
|
34613
35379
|
this.applyPageUpdate({ ...page, widgets, state }, true, runtime, false, true);
|
|
34614
35380
|
}
|
|
@@ -35308,20 +36074,28 @@ class DynamicWidgetPageComponent {
|
|
|
35308
36074
|
ref.applied$.subscribe((result) => this.applyWidgetShell(key, result, false));
|
|
35309
36075
|
ref.saved$.subscribe((result) => this.applyWidgetShell(key, result, true));
|
|
35310
36076
|
}
|
|
35311
|
-
openWidgetComponentSettings(key) {
|
|
35312
|
-
if (this.
|
|
36077
|
+
async openWidgetComponentSettings(key) {
|
|
36078
|
+
if (!this.settingsPanel) {
|
|
36079
|
+
this.dispatchWidgetComponentSettingsToRuntime(key);
|
|
35313
36080
|
return;
|
|
35314
36081
|
}
|
|
35315
|
-
if (!this.settingsPanel)
|
|
35316
|
-
return;
|
|
35317
36082
|
const page = this.materializeRuntimeInputsForWidget(this.ensurePageDefinition(), key);
|
|
35318
36083
|
const widget = page.widgets.find((w) => w.key === key);
|
|
35319
36084
|
if (!widget)
|
|
35320
36085
|
return;
|
|
35321
36086
|
const metadata = this.componentMetadata?.get(widget.definition?.id || '');
|
|
35322
36087
|
const editor = metadata?.configEditor?.component;
|
|
35323
|
-
if (!editor)
|
|
36088
|
+
if (!editor) {
|
|
36089
|
+
this.dispatchWidgetComponentSettingsToRuntime(key);
|
|
36090
|
+
return;
|
|
36091
|
+
}
|
|
36092
|
+
const persistedInputs = this.cloneStateValues(widget.definition.inputs || {});
|
|
36093
|
+
const requestId = ++this.nextConfigEditorContextRequestId;
|
|
36094
|
+
this.configEditorContextRequests.set(key, requestId);
|
|
36095
|
+
const contextResult = await this.resolveWidgetConfigEditorContext(metadata, page, widget, key, persistedInputs);
|
|
36096
|
+
if (this.configEditorContextRequests.get(key) !== requestId) {
|
|
35324
36097
|
return;
|
|
36098
|
+
}
|
|
35325
36099
|
const ref = this.settingsPanel.open({
|
|
35326
36100
|
id: `dynamic-page-component:${key}`,
|
|
35327
36101
|
title: metadata.configEditor?.title ||
|
|
@@ -35330,7 +36104,9 @@ class DynamicWidgetPageComponent {
|
|
|
35330
36104
|
content: {
|
|
35331
36105
|
component: editor,
|
|
35332
36106
|
inputs: {
|
|
35333
|
-
inputs:
|
|
36107
|
+
inputs: persistedInputs,
|
|
36108
|
+
context: contextResult.context ?? {},
|
|
36109
|
+
contextDiagnostics: contextResult.diagnostics ?? [],
|
|
35334
36110
|
widgetKey: key,
|
|
35335
36111
|
widgetType: widget.definition?.id,
|
|
35336
36112
|
},
|
|
@@ -35339,6 +36115,53 @@ class DynamicWidgetPageComponent {
|
|
|
35339
36115
|
ref.applied$.subscribe((result) => this.applyWidgetComponentInputs(key, result, false));
|
|
35340
36116
|
ref.saved$.subscribe((result) => this.applyWidgetComponentInputs(key, result, true));
|
|
35341
36117
|
}
|
|
36118
|
+
async resolveWidgetConfigEditorContext(metadata, page, widget, key, persistedInputs) {
|
|
36119
|
+
const resolver = metadata.configEditor?.contextResolver;
|
|
36120
|
+
if (!resolver) {
|
|
36121
|
+
return {};
|
|
36122
|
+
}
|
|
36123
|
+
try {
|
|
36124
|
+
const resolved = await resolver({
|
|
36125
|
+
componentId: metadata.id,
|
|
36126
|
+
widgetKey: key,
|
|
36127
|
+
widgetType: widget.definition?.id,
|
|
36128
|
+
persistedInputs: this.cloneStateValues(persistedInputs),
|
|
36129
|
+
page: this.cloneStateValues(page),
|
|
36130
|
+
widget: this.cloneStateValues(widget),
|
|
36131
|
+
metadata,
|
|
36132
|
+
});
|
|
36133
|
+
if (this.isConfigEditorContextResult(resolved)) {
|
|
36134
|
+
return {
|
|
36135
|
+
context: this.cloneStateValues(resolved.context ?? {}),
|
|
36136
|
+
diagnostics: Array.isArray(resolved.diagnostics)
|
|
36137
|
+
? resolved.diagnostics.map((diagnostic) => ({ ...diagnostic }))
|
|
36138
|
+
: [],
|
|
36139
|
+
};
|
|
36140
|
+
}
|
|
36141
|
+
return {
|
|
36142
|
+
context: this.cloneStateValues(resolved ?? {}),
|
|
36143
|
+
diagnostics: [],
|
|
36144
|
+
};
|
|
36145
|
+
}
|
|
36146
|
+
catch (error) {
|
|
36147
|
+
return {
|
|
36148
|
+
context: {},
|
|
36149
|
+
diagnostics: [
|
|
36150
|
+
{
|
|
36151
|
+
code: 'config-editor-context-resolution-failed',
|
|
36152
|
+
severity: 'error',
|
|
36153
|
+
message: error instanceof Error ? error.message : String(error),
|
|
36154
|
+
},
|
|
36155
|
+
],
|
|
36156
|
+
};
|
|
36157
|
+
}
|
|
36158
|
+
}
|
|
36159
|
+
isConfigEditorContextResult(value) {
|
|
36160
|
+
return !!value &&
|
|
36161
|
+
typeof value === 'object' &&
|
|
36162
|
+
!Array.isArray(value) &&
|
|
36163
|
+
('context' in value || 'diagnostics' in value);
|
|
36164
|
+
}
|
|
35342
36165
|
materializeRuntimeInputsForWidget(page, key) {
|
|
35343
36166
|
const normalizedKey = String(key || '').trim();
|
|
35344
36167
|
if (!normalizedKey) {
|
|
@@ -35887,7 +36710,8 @@ class DynamicWidgetPageComponent {
|
|
|
35887
36710
|
};
|
|
35888
36711
|
}
|
|
35889
36712
|
applyResponsivePresentation(pageDefinition, widgets, runtime) {
|
|
35890
|
-
const
|
|
36713
|
+
const runtimeWidgets = this.projectRuntimeCompositionStateInputs(widgets);
|
|
36714
|
+
const effective = this.resolveEffectivePresentation(pageDefinition, runtimeWidgets);
|
|
35891
36715
|
if (effective.canvas) {
|
|
35892
36716
|
this.applyCanvasLayout(effective.canvas, effective.layout, effective.grouping);
|
|
35893
36717
|
}
|
|
@@ -35904,6 +36728,36 @@ class DynamicWidgetPageComponent {
|
|
|
35904
36728
|
this.renderedGroups.set(effective.groups);
|
|
35905
36729
|
this.widgets.set(this.resolveShellTemplates(effective.widgets, runtime));
|
|
35906
36730
|
}
|
|
36731
|
+
projectPersistentCompositionStateInputs(widgets, state, now) {
|
|
36732
|
+
if (!this.compositionDefinition) {
|
|
36733
|
+
return this.cloneWidgets(widgets);
|
|
36734
|
+
}
|
|
36735
|
+
return this.compositionRuntime.projectStateWidgetInputs(this.compositionDefinition, {
|
|
36736
|
+
widgets,
|
|
36737
|
+
state: {
|
|
36738
|
+
primaryValues: this.cloneStateValues(state.primaryValues),
|
|
36739
|
+
derivedValues: this.cloneStateValues(state.derivedValues),
|
|
36740
|
+
transientValues: {},
|
|
36741
|
+
changedPaths: state.changedPaths ? [...state.changedPaths] : [],
|
|
36742
|
+
diagnostics: [...state.diagnostics],
|
|
36743
|
+
},
|
|
36744
|
+
now,
|
|
36745
|
+
}).widgets;
|
|
36746
|
+
}
|
|
36747
|
+
projectRuntimeCompositionStateInputs(widgets) {
|
|
36748
|
+
if (!this.compositionDefinition) {
|
|
36749
|
+
return widgets;
|
|
36750
|
+
}
|
|
36751
|
+
const snapshot = this.compositionRuntime.getSnapshot();
|
|
36752
|
+
if (!Object.keys(snapshot.state.transientValues || {}).length) {
|
|
36753
|
+
return widgets;
|
|
36754
|
+
}
|
|
36755
|
+
return this.compositionRuntime.projectStateWidgetInputs(this.compositionDefinition, {
|
|
36756
|
+
widgets,
|
|
36757
|
+
state: snapshot.state,
|
|
36758
|
+
now: snapshot.generatedAt,
|
|
36759
|
+
}).widgets;
|
|
36760
|
+
}
|
|
35907
36761
|
resolveEffectivePresentation(pageDefinition, widgets) {
|
|
35908
36762
|
const variant = this.resolveDeviceVariant(pageDefinition?.deviceLayouts);
|
|
35909
36763
|
const layout = this.mergeLayout(pageDefinition?.layout, variant?.layout);
|
|
@@ -40113,4 +40967,4 @@ function provideHookWhitelist(allowed) {
|
|
|
40113
40967
|
* Generated bundle index. Do not edit.
|
|
40114
40968
|
*/
|
|
40115
40969
|
|
|
40116
|
-
export { API_CONFIG_STORAGE_OPTIONS, API_URL, ASYNC_CONFIG_STORAGE, AllowedFileTypes, AnalyticsPresentationResolver, AnalyticsSchemaContractService, AnalyticsStatsRequestBuilderService, ApiConfigStorage, ApiEndpoint, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, BUILTIN_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentKeyService, ComponentMetadataRegistry, CompositionRuntimeFacade, ConsoleLoggerSink, CrudOperationResolutionService, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, DEFAULT_JSON_LOGIC_OPERATORS, DEFAULT_TABLE_CONFIG, DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK, DOMAIN_CATALOG_CONTEXT_HINT_SCHEMA_VERSION, DYNAMIC_PAGE_AI_CAPABILITIES, DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK, DYNAMIC_PAGE_CONFIG_EDITOR, DYNAMIC_PAGE_SHELL_EDITOR, DefaultLoadingRenderer, DeferredAsyncConfigStorage, DomainCatalogService, DomainKnowledgeService, DomainRuleService, DynamicFormService, DynamicWidgetLoaderDirective, DynamicWidgetPageComponent, EDITORIAL_ALLOWED_CONTENT_FORMATS, EDITORIAL_COMPLIANCE_PRESETS, EDITORIAL_EXTERNAL_LINK_REL, EDITORIAL_FORM_TEMPLATE_CATALOG, EDITORIAL_HTML_ENABLED, EDITORIAL_MARKDOWN_IMAGES_ENABLED, EDITORIAL_SOLUTION_CATALOG, EDITORIAL_SOLUTION_PRESETS, EDITORIAL_THEME_PRESETS, EDITORIAL_WIDGET_CONVENTION_INPUTS, EDITORIAL_WIDGET_TAG, EMPLOYEE_ONBOARDING_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE, EVENT_REGISTRATION_EDITORIAL_SOLUTION, EVENT_REGISTRATION_EDITORIAL_TEMPLATE, EmptyStateCardComponent, EnterpriseRuntimeContextService, ErrorMessageService, FIELD_METADATA_CAPABILITIES, FIELD_SELECTOR_REGISTRY_BASE, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, FIELD_SELECTOR_REGISTRY_OVERRIDES, FORM_HOOKS, FORM_HOOKS_PRESETS, FORM_HOOKS_WHITELIST, FORM_HOOK_RESOLVERS, FieldControlType, FieldDataType, FieldSelectorRegistry, FormHooksRegistry, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_HANDLERS, GLOBAL_ACTION_UI_SCHEMAS, GLOBAL_ANALYTICS_SERVICE, GLOBAL_API_CLIENT, GLOBAL_CONFIG, GLOBAL_DIALOG_SERVICE, GLOBAL_ROUTE_GUARD_RESOLVER, GLOBAL_SURFACE_SERVICE, GLOBAL_TOAST_SERVICE, GenericCrudService, GlobalActionService, GlobalConfigService, INLINE_FILTER_ALIAS_TOKENS, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_SET, INLINE_FILTER_CONTROL_TYPE_VALUES, INLINE_FILTER_TOKEN_TO_BASE_CONTROL_TYPE, INLINE_FILTER_TOKEN_TO_CONTROL_TYPE, IconPickerService, IconPosition, IconSize, LOGGER_LEVEL_BY_ENV, LOGGER_LEVEL_PRIORITY, LoadingOrchestrator, LocalConnectionStorage, LocalStorageAsyncAdapter, LocalStorageCacheAdapter, LocalStorageConfigService, LoggerService, LoggerThrottleTracker, LoggerWarnOnceTracker, MemoryCacheAdapter, NestedPortCatalogService, NestedWidgetConfigAccessor, NumericFormat, OVERLAY_DECIDER_DEBUG, OVERLAY_DECISION_MATRIX, ObservabilityDashboardService, OverlayDeciderService, PRAXIS_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY, PRAXIS_EXPORT_FORMULA_PREFIXES, PRAXIS_EXPORT_SECURITY_POLICY, PRAXIS_FOOTER_LINKS_METADATA, PRAXIS_GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_OPTIONS, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_READY, PRAXIS_GLOBAL_CONFIG_TENANT_RESOLVER, PRAXIS_HERO_BANNER_METADATA, PRAXIS_I18N_CONFIG, PRAXIS_I18N_TRANSLATOR, PRAXIS_JSON_LOGIC_OPERATORS, PRAXIS_LAYER_SCALE_DEFAULTS, PRAXIS_LAYER_SCALE_VARS, PRAXIS_LEGAL_NOTICE_METADATA, PRAXIS_LOADING_CTX, PRAXIS_LOADING_RENDERER, PRAXIS_LOGGER_CONFIG, PRAXIS_LOGGER_SINKS, PRAXIS_OBSERVABILITY_DASHBOARD_OPTIONS, PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, materializeFormLayoutFromMetadata, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, normalizeStart, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisEnterpriseRuntimeContext, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolveResourceAvailabilityReasonKey, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };
|
|
40970
|
+
export { API_CONFIG_STORAGE_OPTIONS, API_URL, ASYNC_CONFIG_STORAGE, AllowedFileTypes, AnalyticsPresentationResolver, AnalyticsSchemaContractService, AnalyticsStatsRequestBuilderService, ApiConfigStorage, ApiEndpoint, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, BUILTIN_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentKeyService, ComponentMetadataRegistry, CompositionRuntimeFacade, ConsoleLoggerSink, CrudOperationResolutionService, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, DEFAULT_JSON_LOGIC_OPERATORS, DEFAULT_TABLE_CONFIG, DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK, DOMAIN_CATALOG_CONTEXT_HINT_SCHEMA_VERSION, DYNAMIC_PAGE_AI_CAPABILITIES, DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK, DYNAMIC_PAGE_CONFIG_EDITOR, DYNAMIC_PAGE_SHELL_EDITOR, DefaultLoadingRenderer, DeferredAsyncConfigStorage, DomainCatalogService, DomainKnowledgeService, DomainRuleService, DynamicFormService, DynamicWidgetLoaderDirective, DynamicWidgetPageComponent, EDITORIAL_ALLOWED_CONTENT_FORMATS, EDITORIAL_COMPLIANCE_PRESETS, EDITORIAL_EXTERNAL_LINK_REL, EDITORIAL_FORM_TEMPLATE_CATALOG, EDITORIAL_HTML_ENABLED, EDITORIAL_MARKDOWN_IMAGES_ENABLED, EDITORIAL_SOLUTION_CATALOG, EDITORIAL_SOLUTION_PRESETS, EDITORIAL_THEME_PRESETS, EDITORIAL_WIDGET_CONVENTION_INPUTS, EDITORIAL_WIDGET_TAG, EMPLOYEE_ONBOARDING_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE, EVENT_REGISTRATION_EDITORIAL_SOLUTION, EVENT_REGISTRATION_EDITORIAL_TEMPLATE, EmptyStateCardComponent, EnterpriseRuntimeContextService, ErrorMessageService, FIELD_METADATA_CAPABILITIES, FIELD_SELECTOR_REGISTRY_BASE, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, FIELD_SELECTOR_REGISTRY_OVERRIDES, FORM_HOOKS, FORM_HOOKS_PRESETS, FORM_HOOKS_WHITELIST, FORM_HOOK_RESOLVERS, FieldControlType, FieldDataType, FieldSelectorRegistry, FormHooksRegistry, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_HANDLERS, GLOBAL_ACTION_UI_SCHEMAS, GLOBAL_ANALYTICS_SERVICE, GLOBAL_API_CLIENT, GLOBAL_CONFIG, GLOBAL_DIALOG_SERVICE, GLOBAL_ROUTE_GUARD_RESOLVER, GLOBAL_SURFACE_SERVICE, GLOBAL_TOAST_SERVICE, GenericCrudService, GlobalActionService, GlobalConfigService, INLINE_FILTER_ALIAS_TOKENS, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_SET, INLINE_FILTER_CONTROL_TYPE_VALUES, INLINE_FILTER_TOKEN_TO_BASE_CONTROL_TYPE, INLINE_FILTER_TOKEN_TO_CONTROL_TYPE, IconPickerService, IconPosition, IconSize, LOGGER_LEVEL_BY_ENV, LOGGER_LEVEL_PRIORITY, LoadingOrchestrator, LocalConnectionStorage, LocalStorageAsyncAdapter, LocalStorageCacheAdapter, LocalStorageConfigService, LoggerService, LoggerThrottleTracker, LoggerWarnOnceTracker, MemoryCacheAdapter, NestedPortCatalogService, NestedWidgetConfigAccessor, NumericFormat, OVERLAY_DECIDER_DEBUG, OVERLAY_DECISION_MATRIX, ObservabilityDashboardService, OverlayDeciderService, PRAXIS_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY, PRAXIS_EXPORT_FORMULA_PREFIXES, PRAXIS_EXPORT_SECURITY_POLICY, PRAXIS_FOOTER_LINKS_METADATA, PRAXIS_GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_OPTIONS, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_READY, PRAXIS_GLOBAL_CONFIG_TENANT_RESOLVER, PRAXIS_HERO_BANNER_METADATA, PRAXIS_I18N_CONFIG, PRAXIS_I18N_TRANSLATOR, PRAXIS_JSON_LOGIC_OPERATORS, PRAXIS_LAYER_SCALE_DEFAULTS, PRAXIS_LAYER_SCALE_VARS, PRAXIS_LEGAL_NOTICE_METADATA, PRAXIS_LOADING_CTX, PRAXIS_LOADING_RENDERER, PRAXIS_LOGGER_CONFIG, PRAXIS_LOGGER_SINKS, PRAXIS_OBSERVABILITY_DASHBOARD_OPTIONS, PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceRecordOpenError, ResourceRecordOpenService, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, materializeFormLayoutFromMetadata, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, normalizeStart, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisEnterpriseRuntimeContext, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolveResourceAvailabilityReasonKey, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };
|