@stndrds/schema 1.0.0-alpha.276 → 1.0.0-alpha.277
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{all-D5zeUllO.d.mts → all-D-E8v5yo.d.mts} +1 -1
- package/dist/{all--B2_3ksI.d.ts → all-D5SkjRst.d.ts} +1 -1
- package/dist/{chunk-EDOEX3O7.js → chunk-F32XOFSP.js} +156 -54
- package/dist/{chunk-RAF6K6VG.js → chunk-FMLZHHWB.js} +19 -5
- package/dist/{chunk-QLU5QR7M.mjs → chunk-K4UER3DU.mjs} +2 -6
- package/dist/{chunk-T7BST4JS.js → chunk-KKR6I3YV.js} +3 -3
- package/dist/{chunk-RBG2YMF2.mjs → chunk-PSCSTHUB.mjs} +16 -3
- package/dist/{chunk-F3YPU2N6.js → chunk-RYAQOR7M.js} +2 -6
- package/dist/{chunk-U7QUIEFF.mjs → chunk-VVYIFBFQ.mjs} +1 -1
- package/dist/{chunk-4USPA67J.mjs → chunk-XQEDMB6B.mjs} +118 -25
- package/dist/exceptions.d.mts +1 -6
- package/dist/exceptions.d.ts +1 -6
- package/dist/exceptions.js +39 -39
- package/dist/exceptions.mjs +1 -1
- package/dist/{index-Bq1KrQkR.d.ts → index-AJeEKoy6.d.ts} +24 -234
- package/dist/{index-DtxtOBYT.d.mts → index-ApHE8c1J.d.mts} +24 -234
- package/dist/index.d.mts +404 -10
- package/dist/index.d.ts +404 -10
- package/dist/index.js +257 -248
- package/dist/index.mjs +63 -90
- package/dist/validation/all.d.mts +2 -2
- package/dist/validation/all.d.ts +2 -2
- package/dist/validation/all.js +29 -29
- package/dist/validation/all.mjs +4 -4
- package/dist/validation/config/index.d.mts +1 -1
- package/dist/validation/config/index.d.ts +1 -1
- package/dist/validation/config/index.js +11 -11
- package/dist/validation/config/index.mjs +2 -2
- package/dist/validation/object/index.js +14 -14
- package/dist/validation/object/index.mjs +2 -2
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './types-DNz3ITS-.mjs';
|
|
2
2
|
import './validation/core/index.mjs';
|
|
3
|
-
import { D as DetailViewConfig, L as ListViewConfig, V as ViewType, a as ViewConfig } from './index-
|
|
3
|
+
import { D as DetailViewConfig, L as ListViewConfig, V as ViewType, a as ViewConfig } from './index-ApHE8c1J.mjs';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import './helpers-C1VVEAOO.mjs';
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './types-DqLi1tx1.js';
|
|
2
2
|
import './validation/core/index.js';
|
|
3
|
-
import { D as DetailViewConfig, L as ListViewConfig, V as ViewType, a as ViewConfig } from './index-
|
|
3
|
+
import { D as DetailViewConfig, L as ListViewConfig, V as ViewType, a as ViewConfig } from './index-AJeEKoy6.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import './helpers-vQ6kp8ET.js';
|
|
6
6
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkKKR6I3YV_js = require('./chunk-KKR6I3YV.js');
|
|
4
|
+
var chunkRYAQOR7M_js = require('./chunk-RYAQOR7M.js');
|
|
5
5
|
var zod = require('zod');
|
|
6
6
|
|
|
7
7
|
// src/types/system-attributes.ts
|
|
@@ -313,19 +313,19 @@ function isAttributeGroupable(attribute) {
|
|
|
313
313
|
function isAttributeKanbanGroupable(attribute) {
|
|
314
314
|
return getAttributeCapabilities(attribute).query.kanbanGroupable;
|
|
315
315
|
}
|
|
316
|
-
function
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (targetType && hasFilterOperatorEntry(targetType)) {
|
|
324
|
-
return ATTRIBUTE_FILTER_OPERATORS[targetType];
|
|
325
|
-
}
|
|
326
|
-
return ATTRIBUTE_FILTER_OPERATORS.number;
|
|
316
|
+
function resolveEffectiveFilterType(attribute) {
|
|
317
|
+
if (attribute.type !== "rollup") return attribute.type;
|
|
318
|
+
const rollup = attribute;
|
|
319
|
+
if (rollup.function === "earliest" || rollup.function === "latest") return "date";
|
|
320
|
+
if (rollup.function === "original") {
|
|
321
|
+
const targetType = rollup.targetAttributeType;
|
|
322
|
+
if (targetType && hasFilterOperatorEntry(targetType)) return targetType;
|
|
327
323
|
}
|
|
328
|
-
return
|
|
324
|
+
return "number";
|
|
325
|
+
}
|
|
326
|
+
function getRollupFilterOperators(attr) {
|
|
327
|
+
const effectiveType = resolveEffectiveFilterType(attr);
|
|
328
|
+
return hasFilterOperatorEntry(effectiveType) ? ATTRIBUTE_FILTER_OPERATORS[effectiveType] : ATTRIBUTE_FILTER_OPERATORS.number;
|
|
329
329
|
}
|
|
330
330
|
function getRawFilterOperators(attribute) {
|
|
331
331
|
if (attribute.type === "rollup") {
|
|
@@ -424,6 +424,90 @@ function now() {
|
|
|
424
424
|
return { dynamic: "date", anchor: "now" };
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
+
// src/filters/extract-filter-value.ts
|
|
428
|
+
function toAmount(value) {
|
|
429
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
430
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
431
|
+
const parsed = Number(value);
|
|
432
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
function extractCurrencyFilterValue(value) {
|
|
437
|
+
if (value !== null && typeof value === "object") {
|
|
438
|
+
return "value" in value ? toAmount(value.value) : null;
|
|
439
|
+
}
|
|
440
|
+
return toAmount(value);
|
|
441
|
+
}
|
|
442
|
+
function extractFilterValue(value) {
|
|
443
|
+
if (value === null || value === void 0) return null;
|
|
444
|
+
if (typeof value === "object" && "value" in value) {
|
|
445
|
+
return value.value ?? null;
|
|
446
|
+
}
|
|
447
|
+
return value;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// src/filters/polarity.ts
|
|
451
|
+
var NEGATIVE_OPERATORS = /* @__PURE__ */ new Set([
|
|
452
|
+
"is_not",
|
|
453
|
+
"not_contains",
|
|
454
|
+
"none_of",
|
|
455
|
+
"is_empty"
|
|
456
|
+
]);
|
|
457
|
+
var NEGATIVE_TO_POSITIVE = {
|
|
458
|
+
is_not: "is",
|
|
459
|
+
not_contains: "contains",
|
|
460
|
+
none_of: "any_of",
|
|
461
|
+
is_empty: "is_not_empty"
|
|
462
|
+
};
|
|
463
|
+
function getOperatorPolarity(op) {
|
|
464
|
+
return NEGATIVE_OPERATORS.has(op) ? "none" : "any";
|
|
465
|
+
}
|
|
466
|
+
function normalizeForEdgeRpc(op) {
|
|
467
|
+
return NEGATIVE_TO_POSITIVE[op] ?? op;
|
|
468
|
+
}
|
|
469
|
+
var SINGLE_TO_MULTI = {
|
|
470
|
+
is: "any_of",
|
|
471
|
+
is_not: "none_of"
|
|
472
|
+
};
|
|
473
|
+
function toMultiValueOperator(op) {
|
|
474
|
+
return SINGLE_TO_MULTI[op] ?? op;
|
|
475
|
+
}
|
|
476
|
+
var SET_MEMBERSHIP_OPERATORS = new Set(
|
|
477
|
+
Object.values(SINGLE_TO_MULTI).filter((op) => op !== void 0)
|
|
478
|
+
);
|
|
479
|
+
function isSetMembershipOperator(op) {
|
|
480
|
+
return SET_MEMBERSHIP_OPERATORS.has(op);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/filters/canonicalize-value.ts
|
|
484
|
+
function canonicalizeFilterValue(rule, effectiveType) {
|
|
485
|
+
const value = rule.value;
|
|
486
|
+
if (isNoValueOperator(rule.operator)) return;
|
|
487
|
+
if (value === null || value === void 0) return;
|
|
488
|
+
if (isDynamicValue(value)) return;
|
|
489
|
+
if (isSetMembershipOperator(rule.operator)) {
|
|
490
|
+
if (!Array.isArray(value)) rule.value = [value];
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (effectiveType !== "currency") return;
|
|
494
|
+
const amount = extractCurrencyFilterValue(value);
|
|
495
|
+
if (amount !== null) {
|
|
496
|
+
rule.value = amount;
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (!hasCurrencyAmount(value)) return;
|
|
500
|
+
const message = `Filter on a currency attribute expected a numeric amount, received ${JSON.stringify(
|
|
501
|
+
value
|
|
502
|
+
)}`;
|
|
503
|
+
throw new chunkRYAQOR7M_js.ValidationError(message, [{ path: ["value"], message }]);
|
|
504
|
+
}
|
|
505
|
+
function hasCurrencyAmount(value) {
|
|
506
|
+
if (typeof value !== "object") return true;
|
|
507
|
+
if (!("value" in value)) return false;
|
|
508
|
+
return value.value != null;
|
|
509
|
+
}
|
|
510
|
+
|
|
427
511
|
// src/filters/normalize-operator.ts
|
|
428
512
|
var SYNONYM_ALIASES = {
|
|
429
513
|
// equality
|
|
@@ -507,6 +591,12 @@ function resolveIsWithinBounds(value, now2 = /* @__PURE__ */ new Date()) {
|
|
|
507
591
|
if (!(Number.isFinite(bounds.startMs) && Number.isFinite(bounds.endMs))) return null;
|
|
508
592
|
return bounds;
|
|
509
593
|
}
|
|
594
|
+
function resolveUtcDayBounds(ms) {
|
|
595
|
+
if (!Number.isFinite(ms)) return null;
|
|
596
|
+
const startMs = utcDayStart(new Date(ms));
|
|
597
|
+
if (!Number.isFinite(startMs)) return null;
|
|
598
|
+
return { startMs, endMs: startMs + MS_PER_DAY };
|
|
599
|
+
}
|
|
510
600
|
function toUtcDayString(ms) {
|
|
511
601
|
return new Date(ms).toISOString().slice(0, 10);
|
|
512
602
|
}
|
|
@@ -571,13 +661,13 @@ function resolveCanonicalOperator(rawOperator, effectiveType) {
|
|
|
571
661
|
const replacement = REMOVED_OPERATOR_REPLACEMENTS[rawOperator];
|
|
572
662
|
if (replacement) {
|
|
573
663
|
const m = `Unknown filter operator "${rawOperator}" \u2014 use ${replacement}`;
|
|
574
|
-
throw new
|
|
664
|
+
throw new chunkRYAQOR7M_js.ValidationError(m, [{ path: ["operator"], message: m }]);
|
|
575
665
|
}
|
|
576
666
|
const normalized = normalizeOperator(rawOperator);
|
|
577
667
|
const membership = SUBSTRING_TO_MEMBERSHIP[normalized];
|
|
578
668
|
if (membership && SET_MEMBERSHIP_TYPES.has(effectiveType)) {
|
|
579
669
|
const m = `Operator "${normalized}" is not valid for type "${effectiveType}" \u2014 use "${membership}"`;
|
|
580
|
-
throw new
|
|
670
|
+
throw new chunkRYAQOR7M_js.ValidationError(m, [{ path: ["operator"], message: m }]);
|
|
581
671
|
}
|
|
582
672
|
return normalized;
|
|
583
673
|
}
|
|
@@ -587,7 +677,7 @@ function assertOperatorForType(operator, type, context) {
|
|
|
587
677
|
if (!ops?.includes(normalized)) {
|
|
588
678
|
const validList = ops?.length ? ops.join(", ") : "(no operators registered for this type)";
|
|
589
679
|
const summary = `Operator "${operator}" is not valid for ${context} type "${type}". Valid operators: ${validList}.`;
|
|
590
|
-
throw new
|
|
680
|
+
throw new chunkRYAQOR7M_js.ValidationError(summary, [
|
|
591
681
|
{
|
|
592
682
|
path: ["operator"],
|
|
593
683
|
message: summary
|
|
@@ -600,19 +690,24 @@ function assertRelativeDateValue(rule) {
|
|
|
600
690
|
if (rule.operator !== "is_within") return;
|
|
601
691
|
if (!isRelativeDateValue(rule.value)) {
|
|
602
692
|
const m = `Operator "is_within" requires a relative-date value { amount: positive number, unit: days|weeks|months|years, direction: past|future }`;
|
|
603
|
-
throw new
|
|
693
|
+
throw new chunkRYAQOR7M_js.ValidationError(m, [{ path: ["value"], message: m }]);
|
|
604
694
|
}
|
|
605
695
|
}
|
|
696
|
+
function applyCanonicalForm(rule, operator, effectiveType) {
|
|
697
|
+
rule.operator = operator;
|
|
698
|
+
canonicalizeFilterValue(rule, effectiveType);
|
|
699
|
+
assertRelativeDateValue(rule);
|
|
700
|
+
}
|
|
606
701
|
function assertDynamicValueForAttribute(rule, attrType) {
|
|
607
702
|
if (!isDynamicValue(rule.value)) return;
|
|
608
703
|
const v = rule.value;
|
|
609
704
|
if (v.dynamic === "actor" && attrType !== "user") {
|
|
610
705
|
const m = `actor token (@me) is only valid on user attributes, not "${attrType}"`;
|
|
611
|
-
throw new
|
|
706
|
+
throw new chunkRYAQOR7M_js.ValidationError(m, [{ path: ["value"], message: m }]);
|
|
612
707
|
}
|
|
613
708
|
if (v.dynamic === "date" && attrType !== "date") {
|
|
614
709
|
const m = `date token (@today/@now) is only valid on date attributes, not "${attrType}"`;
|
|
615
|
-
throw new
|
|
710
|
+
throw new chunkRYAQOR7M_js.ValidationError(m, [{ path: ["value"], message: m }]);
|
|
616
711
|
}
|
|
617
712
|
}
|
|
618
713
|
function collectQualifiedRuleIssues(rule, context) {
|
|
@@ -620,7 +715,7 @@ function collectQualifiedRuleIssues(rule, context) {
|
|
|
620
715
|
validateQualifiedRule({ ...rule }, context);
|
|
621
716
|
return [];
|
|
622
717
|
} catch (error) {
|
|
623
|
-
if (!(error instanceof
|
|
718
|
+
if (!(error instanceof chunkRYAQOR7M_js.ValidationError)) throw error;
|
|
624
719
|
return error.errors.map((issue) => ({ ...issue, path: [...issue.path] }));
|
|
625
720
|
}
|
|
626
721
|
}
|
|
@@ -628,63 +723,61 @@ function validateQualifiedRule(rule, context) {
|
|
|
628
723
|
const rootAttr = context.attributes.find((a) => a.name === rule.attribute);
|
|
629
724
|
const systemOps = SYSTEM_FILTER_OPERATORS[rule.attribute];
|
|
630
725
|
if (!(rootAttr || systemOps)) {
|
|
631
|
-
throw new
|
|
726
|
+
throw new chunkRYAQOR7M_js.ValidationError(`Unknown attribute: ${rule.attribute}`, [
|
|
632
727
|
{ path: ["attribute"], message: `Unknown attribute: ${rule.attribute}` }
|
|
633
728
|
]);
|
|
634
729
|
}
|
|
635
730
|
if (rule.quantifier !== void 0 && !rule.property) {
|
|
636
731
|
const m = `quantifier is only valid on qualified edge rules (set "property")`;
|
|
637
|
-
throw new
|
|
732
|
+
throw new chunkRYAQOR7M_js.ValidationError(m, [{ path: ["quantifier"], message: m }]);
|
|
638
733
|
}
|
|
639
734
|
if (!rootAttr) {
|
|
640
735
|
if (rule.property) {
|
|
641
|
-
throw new
|
|
736
|
+
throw new chunkRYAQOR7M_js.ValidationError(`Cannot qualify system attribute "${rule.attribute}"`, [
|
|
642
737
|
{ path: ["property"], message: `"${rule.attribute}" is a system column, not a reference` }
|
|
643
738
|
]);
|
|
644
739
|
}
|
|
645
740
|
const effectiveType = SYSTEM_FILTER_ATTRIBUTE_TYPES[rule.attribute] ?? "text";
|
|
646
|
-
const
|
|
647
|
-
if (!systemOps.includes(
|
|
741
|
+
const normalizedOperator2 = resolveCanonicalOperator(rule.operator, effectiveType);
|
|
742
|
+
if (!systemOps.includes(normalizedOperator2)) {
|
|
648
743
|
const summary = `Operator "${rule.operator}" is not valid for system attribute "${rule.attribute}". Valid operators: ${systemOps.join(", ")}.`;
|
|
649
|
-
throw new
|
|
744
|
+
throw new chunkRYAQOR7M_js.ValidationError(summary, [{ path: ["operator"], message: summary }]);
|
|
650
745
|
}
|
|
651
|
-
rule
|
|
652
|
-
assertRelativeDateValue(rule);
|
|
746
|
+
applyCanonicalForm(rule, normalizedOperator2, effectiveType);
|
|
653
747
|
return;
|
|
654
748
|
}
|
|
655
749
|
if (!rule.property) {
|
|
656
750
|
assertDynamicValueForAttribute(rule, rootAttr.type);
|
|
657
751
|
const ops = getAttributeFilterOperators(rootAttr);
|
|
658
|
-
const
|
|
659
|
-
if (!ops.includes(
|
|
752
|
+
const normalizedOperator2 = resolveCanonicalOperator(rule.operator, rootAttr.type);
|
|
753
|
+
if (!ops.includes(normalizedOperator2)) {
|
|
660
754
|
const validList = ops.length ? ops.join(", ") : "(not filterable)";
|
|
661
755
|
const summary = `Operator "${rule.operator}" is not valid for attribute "${rootAttr.name}". Valid operators: ${validList}.`;
|
|
662
|
-
throw new
|
|
756
|
+
throw new chunkRYAQOR7M_js.ValidationError(summary, [{ path: ["operator"], message: summary }]);
|
|
663
757
|
}
|
|
664
|
-
rule
|
|
665
|
-
assertRelativeDateValue(rule);
|
|
758
|
+
applyCanonicalForm(rule, normalizedOperator2, resolveEffectiveFilterType(rootAttr));
|
|
666
759
|
return;
|
|
667
760
|
}
|
|
668
761
|
if (!REFERENCE_TYPES.has(rootAttr.type)) {
|
|
669
|
-
throw new
|
|
762
|
+
throw new chunkRYAQOR7M_js.ValidationError(`Cannot qualify ${rootAttr.type} attribute "${rule.attribute}"`, [
|
|
670
763
|
{ path: ["property"], message: `Attribute "${rule.attribute}" is not a reference type` }
|
|
671
764
|
]);
|
|
672
765
|
}
|
|
673
766
|
const propSchema = rootAttr.properties;
|
|
674
767
|
if (!propSchema) {
|
|
675
|
-
throw new
|
|
768
|
+
throw new chunkRYAQOR7M_js.ValidationError(`Attribute "${rule.attribute}" has no qualifyWith schema`, [
|
|
676
769
|
{ path: ["property"], message: `"${rule.attribute}" has no qualifyWith` }
|
|
677
770
|
]);
|
|
678
771
|
}
|
|
679
772
|
const propDef = propSchema.definitions.find((p) => p.name === rule.property);
|
|
680
773
|
if (!propDef) {
|
|
681
|
-
throw new
|
|
774
|
+
throw new chunkRYAQOR7M_js.ValidationError(
|
|
682
775
|
`Property "${rule.property}" not defined on "${rule.attribute}".qualifyWith()`,
|
|
683
776
|
[{ path: ["property"], message: `Unknown property: ${rule.property}` }]
|
|
684
777
|
);
|
|
685
778
|
}
|
|
686
|
-
|
|
687
|
-
|
|
779
|
+
const normalizedOperator = assertOperatorForType(rule.operator, propDef.type, "property");
|
|
780
|
+
applyCanonicalForm(rule, normalizedOperator, propDef.type);
|
|
688
781
|
}
|
|
689
782
|
|
|
690
783
|
// src/types/objects.ts
|
|
@@ -719,12 +812,12 @@ var RESERVED_OBJECT_NAMES = ["skill"];
|
|
|
719
812
|
// src/validators/view-config.schema.ts
|
|
720
813
|
var createModeSchema = zod.z.enum(["redirect", "inline", "peek"]);
|
|
721
814
|
var nonEmptyStringArraySchema = zod.z.array(zod.z.string()).min(1);
|
|
722
|
-
var columnsSchema = zod.z.array(zod.z.string()).max(
|
|
815
|
+
var columnsSchema = zod.z.array(zod.z.string()).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.columnsPerTab);
|
|
723
816
|
var sortRuleSchema = zod.z.object({
|
|
724
817
|
attribute: zod.z.string(),
|
|
725
818
|
direction: zod.z.enum(["asc", "desc"])
|
|
726
819
|
}).strict();
|
|
727
|
-
var sortsSchema = zod.z.array(sortRuleSchema).max(
|
|
820
|
+
var sortsSchema = zod.z.array(sortRuleSchema).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.sortsPerTab);
|
|
728
821
|
var relativeDateValueSchema = zod.z.object({
|
|
729
822
|
amount: zod.z.number(),
|
|
730
823
|
unit: zod.z.enum(["days", "weeks", "months", "years"]),
|
|
@@ -793,7 +886,7 @@ var filterRuleSchema = zod.z.object({
|
|
|
793
886
|
operator: filterOperatorSchema,
|
|
794
887
|
value: filterValueSchema
|
|
795
888
|
}).strict();
|
|
796
|
-
var filterRulesSchema = zod.z.array(filterRuleSchema).max(
|
|
889
|
+
var filterRulesSchema = zod.z.array(filterRuleSchema).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.filterRulesPerTab);
|
|
797
890
|
var filterStateSchema = zod.z.object({
|
|
798
891
|
combinator: zod.z.enum(["and", "or"]),
|
|
799
892
|
rules: filterRulesSchema
|
|
@@ -877,13 +970,13 @@ var baseGroupShape = {
|
|
|
877
970
|
var fieldGroupWriteSchema = zod.z.object({
|
|
878
971
|
...baseGroupShape,
|
|
879
972
|
type: zod.z.literal("fields"),
|
|
880
|
-
fields: zod.z.array(fieldSchema).max(
|
|
973
|
+
fields: zod.z.array(fieldSchema).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.fieldsPerGroup)
|
|
881
974
|
}).strict();
|
|
882
975
|
var relationGroupSchema = zod.z.object({
|
|
883
976
|
...baseGroupShape,
|
|
884
977
|
type: zod.z.literal("relation"),
|
|
885
978
|
attribute: zod.z.string(),
|
|
886
|
-
columns: zod.z.array(zod.z.string()).max(
|
|
979
|
+
columns: zod.z.array(zod.z.string()).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.columnsPerTab).optional(),
|
|
887
980
|
readOnly: zod.z.boolean().optional(),
|
|
888
981
|
allowCreate: zod.z.boolean().optional()
|
|
889
982
|
}).strict();
|
|
@@ -892,13 +985,13 @@ var baseTabShape = {
|
|
|
892
985
|
id: zod.z.string(),
|
|
893
986
|
name: zod.z.string(),
|
|
894
987
|
label: zod.z.string(),
|
|
895
|
-
icon:
|
|
988
|
+
icon: chunkKKR6I3YV_js.iconNameSchema.optional(),
|
|
896
989
|
order: zod.z.number().optional()
|
|
897
990
|
};
|
|
898
991
|
var formTabWriteSchema = zod.z.object({
|
|
899
992
|
...baseTabShape,
|
|
900
993
|
type: zod.z.literal("form"),
|
|
901
|
-
groups: zod.z.array(groupWriteSchema).min(1).max(
|
|
994
|
+
groups: zod.z.array(groupWriteSchema).min(1).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.groupsPerFormTab),
|
|
902
995
|
formColumns: zod.z.union([zod.z.literal(1), zod.z.literal(2), zod.z.literal(3)]).optional(),
|
|
903
996
|
density: zod.z.enum(["compact", "comfortable", "spacious"]).optional()
|
|
904
997
|
}).strict().superRefine((tab, ctx) => {
|
|
@@ -907,13 +1000,13 @@ var formTabWriteSchema = zod.z.object({
|
|
|
907
1000
|
(count, group) => count + (group.type === "fields" ? group.fields.length : 0),
|
|
908
1001
|
0
|
|
909
1002
|
);
|
|
910
|
-
if (totalFields >
|
|
1003
|
+
if (totalFields > chunkKKR6I3YV_js.SCHEMA_LIMITS.fieldsPerFormTab) {
|
|
911
1004
|
ctx.addIssue({
|
|
912
1005
|
code: "too_big",
|
|
913
1006
|
origin: "array",
|
|
914
|
-
maximum:
|
|
1007
|
+
maximum: chunkKKR6I3YV_js.SCHEMA_LIMITS.fieldsPerFormTab,
|
|
915
1008
|
inclusive: true,
|
|
916
|
-
message: `A form tab can contain at most ${
|
|
1009
|
+
message: `A form tab can contain at most ${chunkKKR6I3YV_js.SCHEMA_LIMITS.fieldsPerFormTab} fields`,
|
|
917
1010
|
path: ["groups"]
|
|
918
1011
|
});
|
|
919
1012
|
}
|
|
@@ -1115,7 +1208,7 @@ var formsTabSchema = zod.z.object({
|
|
|
1115
1208
|
var emailsTabSchema = zod.z.object({
|
|
1116
1209
|
...baseTabShape,
|
|
1117
1210
|
type: zod.z.literal("emails"),
|
|
1118
|
-
emailAttributeIds: zod.z.array(zod.z.string()).max(
|
|
1211
|
+
emailAttributeIds: zod.z.array(zod.z.string()).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.emailAttributesPerTab)
|
|
1119
1212
|
}).strict();
|
|
1120
1213
|
var detailTabSchema = zod.z.discriminatedUnion("type", [
|
|
1121
1214
|
formTabWriteSchema,
|
|
@@ -1130,7 +1223,7 @@ var detailTabSchema = zod.z.discriminatedUnion("type", [
|
|
|
1130
1223
|
var listTabCommonShape = {
|
|
1131
1224
|
id: zod.z.string(),
|
|
1132
1225
|
label: zod.z.string(),
|
|
1133
|
-
icon:
|
|
1226
|
+
icon: chunkKKR6I3YV_js.iconNameSchema.optional(),
|
|
1134
1227
|
default: zod.z.boolean().optional(),
|
|
1135
1228
|
// Which records the tab scopes to. `"all"` is the default and means "impose
|
|
1136
1229
|
// no scope" — the mandatory viewer predicate alone decides, so the tab shows
|
|
@@ -1164,7 +1257,7 @@ var listViewTabSchema = zod.z.discriminatedUnion("layout", [
|
|
|
1164
1257
|
]);
|
|
1165
1258
|
var _listViewConfigSchema = zod.z.object({
|
|
1166
1259
|
defaultFilters: filterGroupSchema.optional(),
|
|
1167
|
-
tabs: zod.z.array(listViewTabSchema).min(1).max(
|
|
1260
|
+
tabs: zod.z.array(listViewTabSchema).min(1).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.tabsPerView)
|
|
1168
1261
|
}).strict().superRefine((config, ctx) => {
|
|
1169
1262
|
addDuplicateIdIssues(config.tabs, ctx, ["tabs"]);
|
|
1170
1263
|
let hasDefault = false;
|
|
@@ -1181,9 +1274,9 @@ var _listViewConfigSchema = zod.z.object({
|
|
|
1181
1274
|
});
|
|
1182
1275
|
});
|
|
1183
1276
|
var _detailViewConfigSchema = zod.z.object({
|
|
1184
|
-
tabs: zod.z.array(detailTabSchema).min(1).max(
|
|
1277
|
+
tabs: zod.z.array(detailTabSchema).min(1).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.tabsPerView),
|
|
1185
1278
|
sidePanel: zod.z.object({
|
|
1186
|
-
attributes: zod.z.array(zod.z.string()).max(
|
|
1279
|
+
attributes: zod.z.array(zod.z.string()).max(chunkKKR6I3YV_js.SCHEMA_LIMITS.sidePanelAttributes),
|
|
1187
1280
|
width: zod.z.number().optional()
|
|
1188
1281
|
}).strict().optional()
|
|
1189
1282
|
}).strict().superRefine((config, ctx) => {
|
|
@@ -1227,12 +1320,16 @@ exports.SYSTEM_ATTRIBUTES = SYSTEM_ATTRIBUTES;
|
|
|
1227
1320
|
exports.SYSTEM_ATTRIBUTE_I18N_KEYS = SYSTEM_ATTRIBUTE_I18N_KEYS;
|
|
1228
1321
|
exports.SYSTEM_FIELD_NAMES = SYSTEM_FIELD_NAMES;
|
|
1229
1322
|
exports.SYSTEM_FILTER_ATTRIBUTE_TYPES = SYSTEM_FILTER_ATTRIBUTE_TYPES;
|
|
1323
|
+
exports.canonicalizeFilterValue = canonicalizeFilterValue;
|
|
1230
1324
|
exports.collectQualifiedRuleIssues = collectQualifiedRuleIssues;
|
|
1231
1325
|
exports.currentActor = currentActor;
|
|
1232
1326
|
exports.detailTabSchema = detailTabSchema;
|
|
1233
1327
|
exports.detailViewConfigSchema = detailViewConfigSchema;
|
|
1328
|
+
exports.extractCurrencyFilterValue = extractCurrencyFilterValue;
|
|
1329
|
+
exports.extractFilterValue = extractFilterValue;
|
|
1234
1330
|
exports.getAttributeCapabilities = getAttributeCapabilities;
|
|
1235
1331
|
exports.getAttributeFilterOperators = getAttributeFilterOperators;
|
|
1332
|
+
exports.getOperatorPolarity = getOperatorPolarity;
|
|
1236
1333
|
exports.getRollupFilterOperators = getRollupFilterOperators2;
|
|
1237
1334
|
exports.getSystemAttributeI18nKey = getSystemAttributeI18nKey;
|
|
1238
1335
|
exports.getSystemAttributeList = getSystemAttributeList;
|
|
@@ -1246,15 +1343,20 @@ exports.isDynamicValue = isDynamicValue;
|
|
|
1246
1343
|
exports.isManagedSystemAttribute = isManagedSystemAttribute;
|
|
1247
1344
|
exports.isNoValueOperator = isNoValueOperator;
|
|
1248
1345
|
exports.isRelativeDateValue = isRelativeDateValue;
|
|
1346
|
+
exports.isSetMembershipOperator = isSetMembershipOperator;
|
|
1249
1347
|
exports.listViewConfigSchema = listViewConfigSchema;
|
|
1250
1348
|
exports.listViewTabSchema = listViewTabSchema;
|
|
1251
1349
|
exports.normalizeFilterRule = normalizeFilterRule;
|
|
1350
|
+
exports.normalizeForEdgeRpc = normalizeForEdgeRpc;
|
|
1252
1351
|
exports.normalizeOperator = normalizeOperator;
|
|
1253
1352
|
exports.now = now;
|
|
1254
1353
|
exports.parseViewConfig = parseViewConfig;
|
|
1255
1354
|
exports.relationSourceSchema = relationSourceSchema;
|
|
1355
|
+
exports.resolveEffectiveFilterType = resolveEffectiveFilterType;
|
|
1256
1356
|
exports.resolveIsWithinBounds = resolveIsWithinBounds;
|
|
1357
|
+
exports.resolveUtcDayBounds = resolveUtcDayBounds;
|
|
1257
1358
|
exports.tableSourceSchema = tableSourceSchema;
|
|
1359
|
+
exports.toMultiValueOperator = toMultiValueOperator;
|
|
1258
1360
|
exports.toUtcDayString = toUtcDayString;
|
|
1259
1361
|
exports.today = today;
|
|
1260
1362
|
exports.validateQualifiedRule = validateQualifiedRule;
|
|
@@ -9,7 +9,7 @@ var chunk5WATIVCA_js = require('./chunk-5WATIVCA.js');
|
|
|
9
9
|
var chunkSI34M4IC_js = require('./chunk-SI34M4IC.js');
|
|
10
10
|
var chunkYIP5FJ5H_js = require('./chunk-YIP5FJ5H.js');
|
|
11
11
|
var chunkZPFOKBIN_js = require('./chunk-ZPFOKBIN.js');
|
|
12
|
-
var
|
|
12
|
+
var chunkRYAQOR7M_js = require('./chunk-RYAQOR7M.js');
|
|
13
13
|
var chunkACKMC6FL_js = require('./chunk-ACKMC6FL.js');
|
|
14
14
|
var chunkE6JUYGJX_js = require('./chunk-E6JUYGJX.js');
|
|
15
15
|
var chunkQ4SZAMJT_js = require('./chunk-Q4SZAMJT.js');
|
|
@@ -76,6 +76,13 @@ function createFormAttributeValidator(attr, messages = chunkYKWSHBT5_js.DEFAULT_
|
|
|
76
76
|
}
|
|
77
77
|
return validator;
|
|
78
78
|
}
|
|
79
|
+
|
|
80
|
+
// src/lib/empty.ts
|
|
81
|
+
function isNullishOrEmptyString(value) {
|
|
82
|
+
return value === null || value === void 0 || value === "";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/validation/object/object-validator.ts
|
|
79
86
|
var objectValidatorCache = /* @__PURE__ */ new WeakMap();
|
|
80
87
|
var draftValidatorCache = /* @__PURE__ */ new WeakMap();
|
|
81
88
|
function createObjectValidator(objectDef) {
|
|
@@ -84,7 +91,13 @@ function createObjectValidator(objectDef) {
|
|
|
84
91
|
const shape = {};
|
|
85
92
|
for (const attr of objectDef.attributes) {
|
|
86
93
|
const validator = createAttributeValidator(attr);
|
|
87
|
-
|
|
94
|
+
if (attr.required && attr.type === "text") {
|
|
95
|
+
shape[attr.name] = validator.refine((value) => !isNullishOrEmptyString(value), {
|
|
96
|
+
message: chunkYKWSHBT5_js.DEFAULT_VALIDATION_MESSAGES.required(attr)
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
shape[attr.name] = attr.required ? validator : withEmptyToNull(validator);
|
|
100
|
+
}
|
|
88
101
|
}
|
|
89
102
|
const schema = zod.z.object(shape).passthrough();
|
|
90
103
|
objectValidatorCache.set(objectDef, schema);
|
|
@@ -143,7 +156,7 @@ function validateObjectOrThrow(objectDef, data) {
|
|
|
143
156
|
if (!result.success) {
|
|
144
157
|
const errors = result.errors ?? [];
|
|
145
158
|
const detail = errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("\n") || "Unknown validation error";
|
|
146
|
-
throw new
|
|
159
|
+
throw new chunkRYAQOR7M_js.ValidationError(
|
|
147
160
|
`Validation failed for ${objectDef.label}:
|
|
148
161
|
${detail}`,
|
|
149
162
|
errors.map((err) => ({ path: err.path, message: err.message }))
|
|
@@ -170,7 +183,7 @@ function validateDraftOrThrow(objectDef, data) {
|
|
|
170
183
|
if (!result.success) {
|
|
171
184
|
const errors = result.errors ?? [];
|
|
172
185
|
const detail = errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("\n") || "Unknown validation error";
|
|
173
|
-
throw new
|
|
186
|
+
throw new chunkRYAQOR7M_js.ValidationError(
|
|
174
187
|
`Draft validation failed for ${objectDef.label}:
|
|
175
188
|
${detail}`,
|
|
176
189
|
errors.map((err) => ({ path: err.path, message: err.message }))
|
|
@@ -182,7 +195,7 @@ function rejectUnknownAttributesOrThrow(objectDef, data) {
|
|
|
182
195
|
const knownNames = new Set(objectDef.attributes.map((a) => a.name));
|
|
183
196
|
const unknownKeys = Object.keys(data).filter((key) => !knownNames.has(key));
|
|
184
197
|
if (unknownKeys.length > 0) {
|
|
185
|
-
throw new
|
|
198
|
+
throw new chunkRYAQOR7M_js.ValidationError(
|
|
186
199
|
`Unknown attribute${unknownKeys.length > 1 ? "s" : ""} for ${objectDef.label}: ${unknownKeys.join(", ")}`,
|
|
187
200
|
unknownKeys.map((key) => ({ path: [key], message: "Unknown attribute" }))
|
|
188
201
|
);
|
|
@@ -220,6 +233,7 @@ exports.createDraftValidator = createDraftValidator;
|
|
|
220
233
|
exports.createFormAttributeValidator = createFormAttributeValidator;
|
|
221
234
|
exports.createObjectValidator = createObjectValidator;
|
|
222
235
|
exports.getMissingRequiredAttributes = getMissingRequiredAttributes;
|
|
236
|
+
exports.isNullishOrEmptyString = isNullishOrEmptyString;
|
|
223
237
|
exports.isRecordComplete = isRecordComplete;
|
|
224
238
|
exports.rejectUnknownAttributesOrThrow = rejectUnknownAttributesOrThrow;
|
|
225
239
|
exports.validateAttribute = validateAttribute;
|
|
@@ -67,6 +67,8 @@ var SchemaErrorCode = {
|
|
|
67
67
|
// Configuration / wiring — a required runtime dependency is not configured
|
|
68
68
|
CONFIGURATION_REQUIRED: "CONFIGURATION_REQUIRED",
|
|
69
69
|
SEARCH_ADAPTER_REQUIRED: "SEARCH_ADAPTER_REQUIRED",
|
|
70
|
+
// Background jobs — one or more cron schedules could not be armed at boot
|
|
71
|
+
CRON_REGISTRATION_FAILED: "CRON_REGISTRATION_FAILED",
|
|
70
72
|
// Search backend — a search read call failed at the transport level
|
|
71
73
|
// (non-API transport error: JSON.parse on a non-JSON body, network failure)
|
|
72
74
|
SEARCH_BACKEND_FAILED: "SEARCH_BACKEND_FAILED",
|
|
@@ -115,12 +117,6 @@ var SchemaErrorCode = {
|
|
|
115
117
|
DOCUMENT_FOLDER_SERVICE_UNAVAILABLE: "DOCUMENT_FOLDER_SERVICE_UNAVAILABLE",
|
|
116
118
|
DOCUMENT_FOLDER_PATH_NOT_FOUND: "DOCUMENT_FOLDER_PATH_NOT_FOUND",
|
|
117
119
|
// Email image proxy — token/fetch failures surfaced through the proxy route
|
|
118
|
-
EMAIL_IMAGE_PROXY_INVALID_TOKEN: "EMAIL_IMAGE_PROXY_INVALID_TOKEN",
|
|
119
|
-
EMAIL_IMAGE_PROXY_EXPIRED_TOKEN: "EMAIL_IMAGE_PROXY_EXPIRED_TOKEN",
|
|
120
|
-
EMAIL_IMAGE_PROXY_TOO_LARGE: "EMAIL_IMAGE_PROXY_TOO_LARGE",
|
|
121
|
-
EMAIL_IMAGE_PROXY_UNSUPPORTED_CONTENT_TYPE: "EMAIL_IMAGE_PROXY_UNSUPPORTED_CONTENT_TYPE",
|
|
122
|
-
EMAIL_IMAGE_PROXY_UNSAFE_URL: "EMAIL_IMAGE_PROXY_UNSAFE_URL",
|
|
123
|
-
EMAIL_IMAGE_PROXY_UPSTREAM_FAILED: "EMAIL_IMAGE_PROXY_UPSTREAM_FAILED",
|
|
124
120
|
// Email provider sync — transport failures from Gmail / Microsoft Graph
|
|
125
121
|
EMAIL_PROVIDER_API_FAILED: "EMAIL_PROVIDER_API_FAILED",
|
|
126
122
|
EMAIL_BATCH_ITEM_FAILED: "EMAIL_BATCH_ITEM_FAILED",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkRYAQOR7M_js = require('./chunk-RYAQOR7M.js');
|
|
4
4
|
var zod = require('zod');
|
|
5
5
|
var constants = require('@stndrds/constants');
|
|
6
6
|
|
|
@@ -571,7 +571,7 @@ function getAttributeConfigWriteSchema(type) {
|
|
|
571
571
|
}
|
|
572
572
|
}
|
|
573
573
|
function validationErrorFromIssues(issues) {
|
|
574
|
-
return
|
|
574
|
+
return chunkRYAQOR7M_js.ValidationError.fromZodErrors(
|
|
575
575
|
issues.map((issue) => ({
|
|
576
576
|
path: issue.path.map((segment) => typeof segment === "symbol" ? String(segment) : segment),
|
|
577
577
|
message: issue.message
|
|
@@ -594,7 +594,7 @@ function validatePatchedIcon(patch) {
|
|
|
594
594
|
}
|
|
595
595
|
const result = iconNameSchema.optional().safeParse(patch.icon);
|
|
596
596
|
if (!result.success) {
|
|
597
|
-
throw
|
|
597
|
+
throw chunkRYAQOR7M_js.ValidationError.fromZodErrors(
|
|
598
598
|
result.error.issues.map((issue) => ({
|
|
599
599
|
path: [
|
|
600
600
|
"icon",
|
|
@@ -7,7 +7,7 @@ import { createCheckboxValidator } from './chunk-OSSGN43B.mjs';
|
|
|
7
7
|
import { createDateValidator } from './chunk-Q44QKLN4.mjs';
|
|
8
8
|
import { createNumberValidator } from './chunk-UANQJ2GH.mjs';
|
|
9
9
|
import { createTextValidator } from './chunk-O73ROMWQ.mjs';
|
|
10
|
-
import { ValidationError } from './chunk-
|
|
10
|
+
import { ValidationError } from './chunk-K4UER3DU.mjs';
|
|
11
11
|
import { createCurrencyValidator } from './chunk-AYVHMVKQ.mjs';
|
|
12
12
|
import { createLocationValidator } from './chunk-YUFTHPOE.mjs';
|
|
13
13
|
import { createPhoneValidator } from './chunk-R5LAJCBU.mjs';
|
|
@@ -74,6 +74,13 @@ function createFormAttributeValidator(attr, messages = DEFAULT_VALIDATION_MESSAG
|
|
|
74
74
|
}
|
|
75
75
|
return validator;
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
// src/lib/empty.ts
|
|
79
|
+
function isNullishOrEmptyString(value) {
|
|
80
|
+
return value === null || value === void 0 || value === "";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/validation/object/object-validator.ts
|
|
77
84
|
var objectValidatorCache = /* @__PURE__ */ new WeakMap();
|
|
78
85
|
var draftValidatorCache = /* @__PURE__ */ new WeakMap();
|
|
79
86
|
function createObjectValidator(objectDef) {
|
|
@@ -82,7 +89,13 @@ function createObjectValidator(objectDef) {
|
|
|
82
89
|
const shape = {};
|
|
83
90
|
for (const attr of objectDef.attributes) {
|
|
84
91
|
const validator = createAttributeValidator(attr);
|
|
85
|
-
|
|
92
|
+
if (attr.required && attr.type === "text") {
|
|
93
|
+
shape[attr.name] = validator.refine((value) => !isNullishOrEmptyString(value), {
|
|
94
|
+
message: DEFAULT_VALIDATION_MESSAGES.required(attr)
|
|
95
|
+
});
|
|
96
|
+
} else {
|
|
97
|
+
shape[attr.name] = attr.required ? validator : withEmptyToNull(validator);
|
|
98
|
+
}
|
|
86
99
|
}
|
|
87
100
|
const schema = z.object(shape).passthrough();
|
|
88
101
|
objectValidatorCache.set(objectDef, schema);
|
|
@@ -213,4 +226,4 @@ function isRecordComplete(objectDef, data) {
|
|
|
213
226
|
return validation.success;
|
|
214
227
|
}
|
|
215
228
|
|
|
216
|
-
export { createAttributeValidator, createDraftValidator, createFormAttributeValidator, createObjectValidator, getMissingRequiredAttributes, isRecordComplete, rejectUnknownAttributesOrThrow, validateAttribute, validateDraft, validateDraftOrThrow, validateObject, validateObjectOrThrow };
|
|
229
|
+
export { createAttributeValidator, createDraftValidator, createFormAttributeValidator, createObjectValidator, getMissingRequiredAttributes, isNullishOrEmptyString, isRecordComplete, rejectUnknownAttributesOrThrow, validateAttribute, validateDraft, validateDraftOrThrow, validateObject, validateObjectOrThrow };
|
|
@@ -69,6 +69,8 @@ var SchemaErrorCode = {
|
|
|
69
69
|
// Configuration / wiring — a required runtime dependency is not configured
|
|
70
70
|
CONFIGURATION_REQUIRED: "CONFIGURATION_REQUIRED",
|
|
71
71
|
SEARCH_ADAPTER_REQUIRED: "SEARCH_ADAPTER_REQUIRED",
|
|
72
|
+
// Background jobs — one or more cron schedules could not be armed at boot
|
|
73
|
+
CRON_REGISTRATION_FAILED: "CRON_REGISTRATION_FAILED",
|
|
72
74
|
// Search backend — a search read call failed at the transport level
|
|
73
75
|
// (non-API transport error: JSON.parse on a non-JSON body, network failure)
|
|
74
76
|
SEARCH_BACKEND_FAILED: "SEARCH_BACKEND_FAILED",
|
|
@@ -117,12 +119,6 @@ var SchemaErrorCode = {
|
|
|
117
119
|
DOCUMENT_FOLDER_SERVICE_UNAVAILABLE: "DOCUMENT_FOLDER_SERVICE_UNAVAILABLE",
|
|
118
120
|
DOCUMENT_FOLDER_PATH_NOT_FOUND: "DOCUMENT_FOLDER_PATH_NOT_FOUND",
|
|
119
121
|
// Email image proxy — token/fetch failures surfaced through the proxy route
|
|
120
|
-
EMAIL_IMAGE_PROXY_INVALID_TOKEN: "EMAIL_IMAGE_PROXY_INVALID_TOKEN",
|
|
121
|
-
EMAIL_IMAGE_PROXY_EXPIRED_TOKEN: "EMAIL_IMAGE_PROXY_EXPIRED_TOKEN",
|
|
122
|
-
EMAIL_IMAGE_PROXY_TOO_LARGE: "EMAIL_IMAGE_PROXY_TOO_LARGE",
|
|
123
|
-
EMAIL_IMAGE_PROXY_UNSUPPORTED_CONTENT_TYPE: "EMAIL_IMAGE_PROXY_UNSUPPORTED_CONTENT_TYPE",
|
|
124
|
-
EMAIL_IMAGE_PROXY_UNSAFE_URL: "EMAIL_IMAGE_PROXY_UNSAFE_URL",
|
|
125
|
-
EMAIL_IMAGE_PROXY_UPSTREAM_FAILED: "EMAIL_IMAGE_PROXY_UPSTREAM_FAILED",
|
|
126
122
|
// Email provider sync — transport failures from Gmail / Microsoft Graph
|
|
127
123
|
EMAIL_PROVIDER_API_FAILED: "EMAIL_PROVIDER_API_FAILED",
|
|
128
124
|
EMAIL_BATCH_ITEM_FAILED: "EMAIL_BATCH_ITEM_FAILED",
|