@vxil/cli 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -64,6 +64,17 @@ export declare class HookEvalError extends Error {
64
64
  /** Thrown by a `validate` hook whose expression is falsy — maps to a clean 422. */
65
65
  export declare class HookRejection extends Error {
66
66
  }
67
+ /** A WRITE `validate` hook whose expression could not be evaluated (null
68
+ * arithmetic, a missing operand, a bad date …). Still a HookEvalError — the
69
+ * write is refused, never let through — but it carries the hook's id and its
70
+ * declared `message`, so the API can show the end user the tenant's own copy
71
+ * while keeping the engine detail for the developer. `message` stays the
72
+ * engine detail. */
73
+ export declare class HookValidateFault extends HookEvalError {
74
+ readonly hookId: string;
75
+ readonly tenantMessage: string | undefined;
76
+ constructor(hookId: string, tenantMessage: string | undefined, detail: string);
77
+ }
67
78
  /** Parse a hook expression into an AST. Throws HookParseError on any malformed input. */
68
79
  export declare function parseExpr(src: string): Node;
69
80
  /** Walk the AST and reject anything outside the allow-list, plus depth bounds.
@@ -157,6 +168,36 @@ export type InferredType = 'number' | 'string' | 'boolean' | 'null' | 'unknown';
157
168
  /** Best-effort static type of an expression's result (its output). 'unknown' for
158
169
  * member access / coalesce / mixed ternaries — never a false-positive mismatch. */
159
170
  export declare function inferType(nd: Node): InferredType;
171
+ /** One declared field, as the typing pass needs it (cms field type + required). */
172
+ export interface HookFieldInfo {
173
+ type: string;
174
+ required?: boolean;
175
+ }
176
+ /** collection → field → declared info. */
177
+ export type HookFieldTypes = Record<string, Record<string, HookFieldInfo>>;
178
+ /** Type one parsed expression against one collection's declared fields.
179
+ * `errors` are shapes that can never work (refuse); `warnings` are shapes
180
+ * that work only for some stored values (json vs a scalar, `+` on a text
181
+ * field) and arithmetic on an optional field with no coalesce() — it faults
182
+ * the hook whenever the field is missing. `present` lists fields a derive sets first. */
183
+ export declare function checkHookExprTypes(root: Node, fields: Record<string, HookFieldInfo> | undefined, opts: {
184
+ kind: HookDef['kind'];
185
+ event: HookDef['event'];
186
+ present?: ReadonlySet<string> | undefined;
187
+ }): {
188
+ errors: string[];
189
+ warnings: string[];
190
+ };
191
+ /** Project declared collections (`{ <name>: { fields: { <f>: { type, required? } } } }`
192
+ * — the vxil.config / apply-bundle shape) onto HookFieldTypes. Malformed
193
+ * entries are skipped: no declared field means no verdict. */
194
+ export declare function hookFieldTypesOf(collections: unknown): HookFieldTypes;
195
+ /** Type every hook whose collection the caller declares (see checkHookExprTypes).
196
+ * Unparseable expressions are skipped — validateHookDef already reports them. */
197
+ export declare function checkHookTypes(hooks: Record<string, HookDef> | undefined, fieldTypes: HookFieldTypes): {
198
+ errors: string[];
199
+ warnings: string[];
200
+ };
160
201
  export type HlKind = 'num' | 'str' | 'fn' | 'var' | 'kw' | 'op' | 'ident' | 'ws' | 'err';
161
202
  /** Token-level highlighter over the FULL source (whitespace + bad chars kept),
162
203
  * so a dashboard editor can render a colored overlay behind a textarea. */
@@ -78,9 +78,10 @@ export declare const NotificationsConfigSchema: import("@sinclair/typebox").TObj
78
78
  maxAttempts: import("@sinclair/typebox").TInteger;
79
79
  backoff: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"exponential">, import("@sinclair/typebox").TLiteral<"linear">]>;
80
80
  }>>;
81
- suppression: import("@sinclair/typebox").TObject<{
81
+ suppression: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
82
82
  softBounceThreshold: import("@sinclair/typebox").TInteger;
83
- }>;
83
+ testRecipients: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
84
+ }>>;
84
85
  rateLimit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
85
86
  perDay: import("@sinclair/typebox").TInteger;
86
87
  perTenantSec: import("@sinclair/typebox").TInteger;
@@ -832,6 +833,9 @@ export declare const TEST_RECIPIENT_EMAIL_RE: RegExp;
832
833
  export declare const TEST_RECIPIENT_GLOB_RE: RegExp;
833
834
  export declare const TEST_RECIPIENT_E164_RE: RegExp;
834
835
  export declare function isTestRecipientPattern(entry: string): boolean;
836
+ /** The MAIL subset of the grammar (notifications suppression.testRecipients):
837
+ * an exact email or an `*@domain` glob. */
838
+ export declare function isMailTestRecipientPattern(entry: string): boolean;
835
839
  /** True iff `identifier` (an email today) matches one configured entry:
836
840
  * exact (case-insensitive) or the `*@domain` glob. +E.164 entries never match
837
841
  * an email. */