@vxil/cli 0.5.3 → 0.7.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.
@@ -0,0 +1,179 @@
1
+ import type { DeclaredRlPolicy, DeclaredWebhookSubscription } from './_vxil-feature-configs.js';
2
+ /** The target_url path markers of the platform's function-delivery lanes
3
+ * (control-plane fnCmsHooks.ts FN_CMSHOOK_PATH / FN_AUTHHOOK_PATH /
4
+ * FN_WEBHOOK_TRIGGER_PATH — mirrored here because this package is
5
+ * typebox-only). A subscription on one of them is derived from the functions
6
+ * manifest by the deploy reconciler: never declarable, never "undeclared". */
7
+ export declare const FN_TRIGGER_TARGET_MARKERS: readonly ["/v1/internal/fn/cms-hook/", "/v1/internal/fn/auth-hook/", "/v1/internal/fn/trigger/"];
8
+ export declare function isFnTriggerSubscriptionUrl(targetUrl: string): boolean;
9
+ export type ApiStateDatum = 'policies' | 'subscriptions' | 'templates';
10
+ /** feature → the declared-API-state datum its config block may carry. */
11
+ export declare const API_STATE_DATUMS: ReadonlyArray<{
12
+ feature: string;
13
+ datum: ApiStateDatum;
14
+ }>;
15
+ export declare function apiStateDatumOf(feature: string): ApiStateDatum | null;
16
+ /** The declared list a validated manifest carries for its feature's datum, or
17
+ * null when the feature has no datum / the block is absent. An absent block
18
+ * means "not managed by config" (nothing converges, nothing is reported) —
19
+ * distinct from an EMPTY array, which declares "there should be none". */
20
+ export declare function declaredApiState(feature: string, manifest: Record<string, unknown> | null | undefined): {
21
+ datum: ApiStateDatum;
22
+ declared: unknown[];
23
+ } | null;
24
+ /** ONE row of GET /v1/rate-limits/policies (rate-limits-v1 core.ts Policy). */
25
+ export interface LiveRlPolicy {
26
+ policy_id: string;
27
+ name: string;
28
+ key_template: string;
29
+ limit: number;
30
+ window_seconds: number;
31
+ behavior: string;
32
+ /** absent on a policy stored before the token-bucket pass → 'sliding_window' */
33
+ algorithm?: string;
34
+ }
35
+ /** The PUT /v1/rate-limits/policies/:id body the converge sends (core.ts
36
+ * UpdateBody minus `name`, which is the key). */
37
+ export interface RlPolicyPatch {
38
+ limit?: number;
39
+ window_seconds?: number;
40
+ behavior?: 'block' | 'shape';
41
+ algorithm?: 'sliding_window' | 'token_bucket';
42
+ }
43
+ export declare const RL_DEFAULT_BEHAVIOR: "block";
44
+ export declare const RL_DEFAULT_ALGORITHM: "sliding_window";
45
+ export interface RlPolicyPlan {
46
+ create: DeclaredRlPolicy[];
47
+ update: Array<{
48
+ policy_id: string;
49
+ name: string;
50
+ patch: RlPolicyPatch;
51
+ changed: string[];
52
+ }>;
53
+ /** `key_template` differs — the update route cannot change it, so the only
54
+ * fix is delete+recreate (a NEW policy_id): destructive-shaped. */
55
+ recreate: Array<{
56
+ policy_id: string;
57
+ name: string;
58
+ declared: DeclaredRlPolicy;
59
+ }>;
60
+ unchanged: string[];
61
+ /** live rows the config does not declare (left in place by default) */
62
+ undeclared: Array<{
63
+ policy_id: string;
64
+ name: string;
65
+ }>;
66
+ /** a declared name matched by MORE THAN ONE live row — names are not a
67
+ * unique key on the route, so the converge cannot pick; nothing is touched */
68
+ ambiguous: Array<{
69
+ name: string;
70
+ count: number;
71
+ }>;
72
+ }
73
+ export declare function planRlPolicies(declared: readonly DeclaredRlPolicy[], live: readonly LiveRlPolicy[]): RlPolicyPlan;
74
+ /** ONE row of GET /v1/webhooks/subscriptions (state 'deleted' never listed). */
75
+ export interface LiveWebhookSubscription {
76
+ sub_id: string;
77
+ target_url: string;
78
+ event_prefixes: string[];
79
+ state?: string;
80
+ }
81
+ export interface WebhookSubscriptionPlan {
82
+ create: DeclaredWebhookSubscription[];
83
+ /** the prefix SET differs — there is no update route, so delete+recreate (a
84
+ * NEW sub_id, and the watermark restarts at "now"): destructive-shaped. */
85
+ recreate: Array<{
86
+ sub_id: string;
87
+ target_url: string;
88
+ declared: DeclaredWebhookSubscription;
89
+ }>;
90
+ unchanged: string[];
91
+ /** live rows the config does not declare, EXCLUDING the function-delivery
92
+ * lanes (those derive from the functions manifest) — left in place by default */
93
+ undeclared: Array<{
94
+ sub_id: string;
95
+ target_url: string;
96
+ }>;
97
+ }
98
+ export declare function planWebhookSubscriptions(declared: readonly DeclaredWebhookSubscription[], live: readonly LiveWebhookSubscription[]): WebhookSubscriptionPlan;
99
+ /** ONE row of GET /v1/ai/templates. `content_sha256` is the canonical hash of
100
+ * the LATEST version's {system,user,schema} (@vxil/runtime
101
+ * aiTemplateContentSha256), stamped by ai-v1 since 2026-09-23; absent on an
102
+ * older server. */
103
+ export interface LiveAiTemplate {
104
+ name: string;
105
+ latest_version: number;
106
+ content_sha256?: string;
107
+ }
108
+ /** A declared template with its content hash pre-computed by the caller (the
109
+ * hash is async WebCrypto; this planner stays pure/sync). */
110
+ export interface HashedDeclaredAiTemplate {
111
+ template: string;
112
+ content_sha256: string;
113
+ }
114
+ export interface AiTemplatePlan {
115
+ create: string[];
116
+ /** content differs → POST a new version (monotonic per name) */
117
+ update: string[];
118
+ unchanged: string[];
119
+ /** stored names the config does not declare — there is NO delete route for
120
+ * templates, so these are only ever reported, never removed */
121
+ undeclared: string[];
122
+ /** live rows with no `content_sha256` (an older server): the content cannot
123
+ * be compared, so each is re-put as `update` and named here */
124
+ unknownContent: string[];
125
+ }
126
+ export declare function planAiTemplates(declared: readonly HashedDeclaredAiTemplate[], live: readonly LiveAiTemplate[]): AiTemplatePlan;
127
+ export interface ApiStateSummary {
128
+ datum: ApiStateDatum;
129
+ created: string[];
130
+ updated: string[];
131
+ /** destructive-shaped changes APPLIED under allow-destructive (delete+recreate) */
132
+ recreated: string[];
133
+ unchanged: string[];
134
+ /** live rows the config does not declare — left in place (or, under
135
+ * allow-destructive, listed in `deleted` instead) */
136
+ undeclared: string[];
137
+ /** undeclared rows DELETED under allow-destructive */
138
+ deleted: string[];
139
+ /** destructive-shaped changes NOT applied (need allow-destructive) */
140
+ pending_destructive: string[];
141
+ /** declared keys the converge could not resolve (duplicate live rows) */
142
+ ambiguous: string[];
143
+ /** rows a route refused (a 4xx) — the converge continues past them */
144
+ failed: Array<{
145
+ key: string;
146
+ error: string;
147
+ }>;
148
+ }
149
+ export declare function emptyApiStateSummary(datum: ApiStateDatum): ApiStateSummary;
150
+ /** The `api_state` object a config-write response carries (`PUT /v1/config/
151
+ * :feature` and its dashboard twin, dry-run included — control-plane
152
+ * handlers/apiState.ts apiStateResponseField) and the shape `vxil push` /
153
+ * `vxil plan` print. `ok:false` + `deferred:true` = not converged for an
154
+ * INDEFINITE reason — the feature worker has not seen the config yet, or a
155
+ * transient failure (a push asks again through POST /v1/apply after its
156
+ * wait); `ok:false` otherwise = a DEFINITE, named refusal (nothing to retry);
157
+ * `note` = converged nothing on purpose (a disabled feature). */
158
+ export interface ApiStateResponseField extends ApiStateSummary {
159
+ ok: boolean;
160
+ dry_run?: boolean;
161
+ deferred?: boolean;
162
+ error?: string;
163
+ note?: string;
164
+ }
165
+ /** The note every executor reports for a DISABLED feature whose block still
166
+ * declares rows: the declaration is kept in the manifest and nothing is
167
+ * converged (a parked feature is not a propagation window — review finding 2). */
168
+ export declare const API_STATE_DISABLED_NOTE = "feature disabled \u2014 declaration kept, not converged";
169
+ /** `GET /v1/rate-limits/policies` is a 100-row HARD cap with no cursor. A list
170
+ * AT the cap is not a complete live set, so planning creates against it would
171
+ * re-POST every declared name the cap hid (review finding 5). The server's
172
+ * converge and the CLI's read-only plan refuse with this message instead. */
173
+ export declare function rlPolicyListCapError(liveCount: number): string | null;
174
+ export declare const RL_POLICY_LIST_CAP = 100;
175
+ /** `+2 created · ~1 updated · =3 unchanged · 1 undeclared (left in place)` —
176
+ * the one-line summary `vxil push` prints and the apply journal notes. */
177
+ export declare function formatApiStateSummary(s: ApiStateSummary): string;
178
+ /** The multi-line detail under the summary: one line per named row. */
179
+ export declare function formatApiStateDetail(s: ApiStateSummary): string[];
@@ -0,0 +1,7 @@
1
+ /** JSON.stringify with object keys sorted at every depth (arrays keep their
2
+ * order; undefined-valued keys are dropped, as JSON.stringify drops them).
3
+ * Two values with equal output are equal in CONTENT. A stored manifest comes
4
+ * back from storage with its object keys re-ordered, so every declared-vs-
5
+ * stored config compare (the server's shallowDiff, the CLI's diffManifest)
6
+ * must go through this, never through plain JSON.stringify. */
7
+ export declare function canonicalJson(v: unknown): string | undefined;
@@ -0,0 +1,38 @@
1
+ export declare const READ_MODEL_LIMITS: {
2
+ readonly maxReadModels: 20;
3
+ readonly maxAggregates: 4;
4
+ readonly maxGroupBy: 2;
5
+ readonly maxWindowDays: 366;
6
+ readonly maxSpecBytes: 4096;
7
+ readonly maxCdcRules: 25;
8
+ };
9
+ /**
10
+ * Structural validation of a declared read-model `spec` — shared by the
11
+ * config-write gate here and re-exported for anyone needing the pure check.
12
+ * `kind` selects the §3.1 (aggregate) or §4.1 (rank) grammar.
13
+ */
14
+ export declare function validateReadModelSpecShape(where: string, kind: 'aggregate' | 'rank', spec: unknown): string[];
15
+ /** Shape of one declared read-model (mirrors the CmsConfigSchema Record). */
16
+ interface ReadModelDefLike {
17
+ collection?: string;
18
+ kind?: string;
19
+ spec?: unknown;
20
+ materialize?: {
21
+ cron?: string;
22
+ to?: string;
23
+ };
24
+ enabled?: boolean;
25
+ }
26
+ /** Cross-field rule for CmsConfig.readModels (called from validateFeatureConfig). */
27
+ export declare function validateReadModelsConfig(readModels: Record<string, ReadModelDefLike> | undefined): string[];
28
+ /** Shape of one CDC rule (mirrors the CmsConfigSchema Record). */
29
+ interface CdcRuleLike {
30
+ collection?: string;
31
+ channel?: string;
32
+ events?: unknown;
33
+ payload?: unknown;
34
+ enabled?: boolean;
35
+ }
36
+ /** Cross-field rule for CmsConfig.cdc (called from validateFeatureConfig). */
37
+ export declare function validateCdcConfig(cdc: Record<string, CdcRuleLike> | undefined): string[];
38
+ export {};
@@ -1,6 +1,8 @@
1
1
  import { type Static, type TSchema } from '@sinclair/typebox';
2
2
  export * from './_vxil-feature-configs-hooks.js';
3
- export * from './readmodels.js';
3
+ export * from './_vxil-feature-configs-readmodels.js';
4
+ export * from './_vxil-feature-configs-apiState.js';
5
+ export * from './_vxil-feature-configs-canonicalJson.js';
4
6
  export declare const RESERVED_CREDIT_TYPES: ReadonlySet<string>;
5
7
  /** True when a credit_type is a vxil-COGS reserved type (grant/consume/config
6
8
  * of which is restricted to internal platform machinery). */
@@ -265,12 +267,35 @@ export type AuthSecurityConfig = NonNullable<Static<typeof AuthConfigSchema>['se
265
267
  /** The RB-2 generic OIDC / SSO issuer block (`providers.oidc`). */
266
268
  export type AuthOidcConfig = Static<typeof OidcProviderSchema>;
267
269
  export type AuthConfig = Static<typeof AuthConfigSchema>;
270
+ export declare const RL_POLICY_NAME_PATTERN = "^[a-zA-Z0-9_.:-]+$";
271
+ /** GET /v1/rate-limits/policies lists at most 100 with no cursor (core.ts
272
+ * listPolicies) — a declared set past that could never be reconciled. */
273
+ export declare const RL_MAX_DECLARED_POLICIES = 100;
274
+ /** rate-limits-v1 core.ts createPolicy: at most 8 distinct `{var}`s. */
275
+ export declare const RL_KEY_TEMPLATE_MAX_VARS = 8;
276
+ export declare const DeclaredRlPolicySchema: import("@sinclair/typebox").TObject<{
277
+ name: import("@sinclair/typebox").TString;
278
+ key_template: import("@sinclair/typebox").TString;
279
+ limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
280
+ window_seconds: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
281
+ behavior: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"block">, import("@sinclair/typebox").TLiteral<"shape">]>>;
282
+ algorithm: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"sliding_window">, import("@sinclair/typebox").TLiteral<"token_bucket">]>>;
283
+ }>;
284
+ export type DeclaredRlPolicy = Static<typeof DeclaredRlPolicySchema>;
268
285
  export declare const RateLimitsConfigSchema: import("@sinclair/typebox").TObject<{
269
286
  enabled: import("@sinclair/typebox").TBoolean;
270
287
  defaults: import("@sinclair/typebox").TObject<{
271
288
  perTenantSec: import("@sinclair/typebox").TInteger;
272
289
  burstSize: import("@sinclair/typebox").TInteger;
273
290
  }>;
291
+ policies: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
292
+ name: import("@sinclair/typebox").TString;
293
+ key_template: import("@sinclair/typebox").TString;
294
+ limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
295
+ window_seconds: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
296
+ behavior: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"block">, import("@sinclair/typebox").TLiteral<"shape">]>>;
297
+ algorithm: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"sliding_window">, import("@sinclair/typebox").TLiteral<"token_bucket">]>>;
298
+ }>>>;
274
299
  }>;
275
300
  export type RateLimitsConfig = Static<typeof RateLimitsConfigSchema>;
276
301
  export declare const FilesConfigSchema: import("@sinclair/typebox").TObject<{
@@ -301,6 +326,11 @@ export declare const FilesConfigSchema: import("@sinclair/typebox").TObject<{
301
326
  }>>;
302
327
  }>;
303
328
  export type FilesConfig = Static<typeof FilesConfigSchema>;
329
+ export declare const DeclaredWebhookSubscriptionSchema: import("@sinclair/typebox").TObject<{
330
+ target_url: import("@sinclair/typebox").TString;
331
+ event_prefixes: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
332
+ }>;
333
+ export type DeclaredWebhookSubscription = Static<typeof DeclaredWebhookSubscriptionSchema>;
304
334
  export declare const WebhooksConfigSchema: import("@sinclair/typebox").TObject<{
305
335
  enabled: import("@sinclair/typebox").TBoolean;
306
336
  maxSubscriptions: import("@sinclair/typebox").TInteger;
@@ -310,6 +340,10 @@ export declare const WebhooksConfigSchema: import("@sinclair/typebox").TObject<{
310
340
  minLevel: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"warn">, import("@sinclair/typebox").TLiteral<"error">]>;
311
341
  digestMinutes: import("@sinclair/typebox").TInteger;
312
342
  }>>;
343
+ subscriptions: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
344
+ target_url: import("@sinclair/typebox").TString;
345
+ event_prefixes: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
346
+ }>>>;
313
347
  }>;
314
348
  export type WebhooksConfig = Static<typeof WebhooksConfigSchema>;
315
349
  export declare const CommentsConfigSchema: import("@sinclair/typebox").TObject<{
@@ -476,6 +510,15 @@ export declare const VectorSearchConfigSchema: import("@sinclair/typebox").TObje
476
510
  }>>>;
477
511
  }>;
478
512
  export type VectorSearchConfig = Static<typeof VectorSearchConfigSchema>;
513
+ export declare const AI_TEMPLATE_NAME_PATTERN = "^[a-zA-Z0-9_.\\-]+$";
514
+ export declare const AI_MAX_DECLARED_TEMPLATES = 50;
515
+ export declare const DeclaredAiTemplateSchema: import("@sinclair/typebox").TObject<{
516
+ template: import("@sinclair/typebox").TString;
517
+ user: import("@sinclair/typebox").TString;
518
+ system: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
519
+ schema: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
520
+ }>;
521
+ export type DeclaredAiTemplate = Static<typeof DeclaredAiTemplateSchema>;
479
522
  export declare const AiConfigSchema: import("@sinclair/typebox").TObject<{
480
523
  enabled: import("@sinclair/typebox").TBoolean;
481
524
  defaultProvider: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"mock">, import("@sinclair/typebox").TLiteral<"openai">, import("@sinclair/typebox").TLiteral<"anthropic">, import("@sinclair/typebox").TLiteral<"gemini">, import("@sinclair/typebox").TLiteral<"azure">, import("@sinclair/typebox").TLiteral<"openrouter">]>;
@@ -500,11 +543,17 @@ export declare const AiConfigSchema: import("@sinclair/typebox").TObject<{
500
543
  tokensPerUserPerDay: import("@sinclair/typebox").TInteger;
501
544
  consumeCredits: import("@sinclair/typebox").TBoolean;
502
545
  }>;
503
- streaming: import("@sinclair/typebox").TObject<{
546
+ streaming: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
504
547
  enabled: import("@sinclair/typebox").TBoolean;
505
548
  replayBufferFrames: import("@sinclair/typebox").TInteger;
506
549
  flushMs: import("@sinclair/typebox").TInteger;
507
- }>;
550
+ }>>;
551
+ templates: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
552
+ template: import("@sinclair/typebox").TString;
553
+ user: import("@sinclair/typebox").TString;
554
+ system: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
555
+ schema: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
556
+ }>>>;
508
557
  }>;
509
558
  export type AiConfig = Static<typeof AiConfigSchema>;
510
559
  export declare const RagConfigSchema: import("@sinclair/typebox").TObject<{
@@ -713,6 +762,18 @@ export declare const MCP_MAX_PROMPTS = 32;
713
762
  * stays ALLOWED (fn→fn composition). Source of truth for both the config-write
714
763
  * validation below and the control-plane deploy clamp. */
715
764
  export declare const DENY_FUNCTION_SCOPES: Set<string>;
765
+ /** `{var}` names of a rate-limit key template (rate-limits-v1 core.ts
766
+ * templateVars parity). */
767
+ export declare function rlTemplateVars(template: string): string[];
768
+ export declare function validateDeclaredRlPolicies(policies: readonly DeclaredRlPolicy[] | undefined): string[];
769
+ export declare function validateDeclaredWebhookSubscriptions(subscriptions: readonly DeclaredWebhookSubscription[] | undefined, maxSubscriptions: number | undefined): string[];
770
+ /** The stored-template `schema` bounds — MIRRORED from @vxil/runtime
771
+ * (AI_TEMPLATE_SCHEMA_MAX_BYTES / AI_TEMPLATE_SCHEMA_MAX_DEPTH; this package is
772
+ * typebox-only). ai-v1 putTemplate refuses the same numbers at the route, so a
773
+ * declared entry that passes here is never a 422 at converge. */
774
+ export declare const AI_TEMPLATE_SCHEMA_MAX_BYTES = 32000;
775
+ export declare const AI_TEMPLATE_SCHEMA_MAX_DEPTH = 64;
776
+ export declare function validateDeclaredAiTemplates(templates: readonly DeclaredAiTemplate[] | undefined): string[];
716
777
  export declare function validateFeatureConfig(feature: string, raw: unknown): ConfigValidation;
717
778
  export declare const FEATURE_KEYS: readonly ["notifications", "jobs", "auth", "rate-limits", "files", "webhooks", "comments", "cms", "mcp", "realtime", "presence", "orgs", "activity-feed", "vector-search", "ai", "rag", "payments", "functions", "copilot"];
718
779
  export type FeatureKey = (typeof FEATURE_KEYS)[number];