@vxil/cli 0.1.0 → 0.2.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.
@@ -1,18 +1,23 @@
1
1
  import { type Static, type TSchema } from '@sinclair/typebox';
2
2
  export * from './_vxil-feature-configs-hooks.js';
3
3
  export * from './readmodels.js';
4
+ export declare const RESERVED_CREDIT_TYPES: ReadonlySet<string>;
5
+ /** True when a credit_type is a vxil-COGS reserved type (grant/consume/config
6
+ * of which is restricted to internal platform machinery). */
7
+ export declare function isReservedCreditType(creditType: string): boolean;
4
8
  export declare const NotificationsConfigSchema: import("@sinclair/typebox").TObject<{
5
9
  enabled: import("@sinclair/typebox").TBoolean;
6
10
  fromEmail: import("@sinclair/typebox").TString;
7
11
  fromName: import("@sinclair/typebox").TString;
8
12
  replyTo: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
9
13
  resendApiKeyRef: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
14
+ webhookSecretRef: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
10
15
  provider: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"resend">, import("@sinclair/typebox").TLiteral<"mock">]>;
11
16
  defaultLocale: import("@sinclair/typebox").TString;
12
- retry: import("@sinclair/typebox").TObject<{
17
+ retry: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
13
18
  maxAttempts: import("@sinclair/typebox").TInteger;
14
19
  backoff: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"exponential">, import("@sinclair/typebox").TLiteral<"linear">]>;
15
- }>;
20
+ }>>;
16
21
  suppression: import("@sinclair/typebox").TObject<{
17
22
  softBounceThreshold: import("@sinclair/typebox").TInteger;
18
23
  }>;
@@ -25,8 +30,31 @@ export declare const NotificationsConfigSchema: import("@sinclair/typebox").TObj
25
30
  }>;
26
31
  /** in-app inbox channel (send with channel: 'inbox' | 'both') */
27
32
  inboxEnabled: import("@sinclair/typebox").TBoolean;
33
+ /** §11b.5 broadcast campaigns channel. Optional bag (= 1 leaf): absent means
34
+ * disabled; per-campaign quiet_hours / freq_cap overrides live on the
35
+ * notifications.campaigns ROW (tenant data), not here. Folded into the
36
+ * canonical schema 2026-07-18 (M21/#4 — Value.Clean previously STRIPPED the
37
+ * worker-local extension, so campaigns 403'd via the real config path). */
38
+ broadcast: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
39
+ enabled: import("@sinclair/typebox").TBoolean;
40
+ /** tenant-default per-recipient quiet window (defer-not-drop); a
41
+ * per-campaign quiet_hours wins over it. Mirrors the campaigns-row shape
42
+ * (workers/notifications-v1 CampaignBody.quiet_hours). start/end are
43
+ * pattern-pinned to what the worker's parseHhMm actually parses — a
44
+ * looser string ('10pm') would validate but FAIL OPEN at runtime
45
+ * (quiet window silently ignored). */
46
+ defaultQuietHours: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
47
+ tz: import("@sinclair/typebox").TString;
48
+ start: import("@sinclair/typebox").TString;
49
+ end: import("@sinclair/typebox").TString;
50
+ }>>;
51
+ /** default rolling per-user-per-day campaign-send cap across campaigns */
52
+ freqCapPerUserPerDay: import("@sinclair/typebox").TInteger;
53
+ }>>;
28
54
  }>;
29
55
  export type NotificationsConfig = Static<typeof NotificationsConfigSchema>;
56
+ /** The §11b.5 broadcast bag as persisted (present ⇒ leaf defaults applied). */
57
+ export type BroadcastConfig = NonNullable<NotificationsConfig['broadcast']>;
30
58
  export declare const JobsConfigSchema: import("@sinclair/typebox").TObject<{
31
59
  enabled: import("@sinclair/typebox").TBoolean;
32
60
  retry: import("@sinclair/typebox").TObject<{
@@ -585,3 +613,19 @@ export declare const MCP_MAX_PROMPTS = 32;
585
613
  * validation below and the control-plane deploy clamp. */
586
614
  export declare const DENY_FUNCTION_SCOPES: Set<string>;
587
615
  export declare function validateFeatureConfig(feature: string, raw: unknown): ConfigValidation;
616
+ 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"];
617
+ export type FeatureKey = (typeof FEATURE_KEYS)[number];
618
+ /** The hand-authored "when to use" intent a machine schema cannot convey.
619
+ * REQUIRED for every feature (Record key-closure): a feature added to
620
+ * FEATURE_KEYS without a hint is a compile error naming the missing key. */
621
+ export interface PlannerHint {
622
+ /** One or two sentences: when an app needs this feature. */
623
+ whenToUse: string;
624
+ /** Soft priors — words/needs that suggest the feature (NOT a matcher). */
625
+ signals: string[];
626
+ /** When NOT to pick it (disambiguation vs neighbors). */
627
+ notFor: string;
628
+ /** Features that must be enabled alongside (runtime substrate deps). */
629
+ dependsOn: FeatureKey[];
630
+ }
631
+ export declare const FEATURE_HINTS: Record<FeatureKey, PlannerHint>;
package/dist/config.d.ts CHANGED
@@ -14,7 +14,39 @@ export interface FieldDef {
14
14
  relationTo?: string;
15
15
  computed?: boolean;
16
16
  compute?: unknown;
17
+ /** Claims-table-enforced value uniqueness across live items (cms.md §9.3):
18
+ * a duplicate write is a clean 409 unique_violation. Scalar types only
19
+ * (string/int/float/datetime/relation/file). Carried on collection/field
20
+ * CREATE by `vxil push` and server apply; since 2026-07-17 `vxil push` also
21
+ * RECONCILES it on an existing same-type field (in-place alter via the REST
22
+ * field re-add — packages/cli/src/cms.ts FIELD_ATTRS); attributes push
23
+ * cannot reconcile surface as a visible plan warning, never a silent no-op. */
24
+ unique?: boolean;
25
+ /** Per-relation-field delete behavior (cms.md §11): bounded, atomic fan-out
26
+ * when the referenced item is deleted. Same carriage + reconcile behavior
27
+ * as `unique`. */
28
+ onDelete?: 'cascade' | 'set_null';
17
29
  }
30
+ /** The CANONICAL field-attribute name set (config-side spelling), DERIVED from
31
+ * `FieldDef` itself so it can never drift from the authoring type: it is every
32
+ * key of `FieldDef` except `type` (which is required, not an optional carried
33
+ * attribute). This is the compile-time source of truth for the config-carriage
34
+ * completeness ratchet (audit 2026-07-15e #2, roadmap §4.5 P3): the CLI carriage
35
+ * table (`packages/cli/src/cms.ts` FIELD_ATTRS) and the server one
36
+ * (`workers/control-plane/src/handlers/apply.ts` FIELD_ATTR_DELTA) each pin
37
+ * `keyof` coverage against a set that equals this — so a 9th attribute added to
38
+ * `FieldDef` WITHOUT threading it through BOTH push paths is a tsc error naming
39
+ * the uncovered key, not a silent half-carriage. */
40
+ export type FieldAttrName = Exclude<keyof FieldDef, 'type'>;
41
+ /** Compile-time exact-key closure helper: resolves to `Set` iff `Covered`
42
+ * covers EVERY member of `Required` (i.e. `Required` is assignable to
43
+ * `Covered`), else to the specific uncovered key literal(s) — so a `satisfies`
44
+ * against the covered literal union produces a tsc error naming the field the
45
+ * developer forgot to thread through the carriage table. Used by both push
46
+ * paths' carriage tables to gate additions to `FieldAttrName`. */
47
+ export type CoversFieldAttrs<Covered extends FieldAttrName> = [
48
+ FieldAttrName
49
+ ] extends [Covered] ? Covered : Exclude<FieldAttrName, Covered>;
18
50
  /** A CMS collection-as-code: collection slug → fields. */
19
51
  export interface CollectionDef {
20
52
  singular?: string;
@@ -23,9 +55,17 @@ export interface CollectionDef {
23
55
  * existing `string` field on this collection that holds the owner (end-user)
24
56
  * id. When set, the cms worker auto-scopes owned reads/writes to the VERIFIED
25
57
  * end-user principal in end-user mode (default-deny) — and is a no-op in
26
- * server-caller mode. NOT an RLS predicate; a single declarative flag the
27
- * typed worker consults. Omit for shared/reference collections. */
58
+ * server-caller mode. Not a hard-isolation predicate; a single declarative
59
+ * flag the typed worker consults. Omit for shared/reference collections. */
28
60
  ownerField?: string;
61
+ /** Public delivery (roadmap §4.4): when true, this collection's PUBLISHED items
62
+ * are servable through the keyless, edge-cached GET /v1/cms/public/:tenantId/
63
+ * :collection lane (no API key). Owner-UNSCOPED (public content, not per-user);
64
+ * the owner_field is stripped from every served row. Default false. Carried by
65
+ * BOTH push paths (the `vxil push` cms reconciler AND control-plane /v1/apply)
66
+ * with a regression test on each — an attribute read by no enforcing path ships
67
+ * inert (the validation.unique / owner_field precedent). */
68
+ public?: boolean;
29
69
  }
30
70
  /** A function trigger (the §7.3 crossing). cmsHook fires on a CMS write;
31
71
  * authHook is the post-signup hook (fires on `auth.user.created`,
@@ -77,7 +117,7 @@ export interface FunctionDef {
77
117
  }
78
118
  /** A secret REFERENCE (never a value). `vxil secrets set <name>` writes the value. */
79
119
  export interface SecretRef {
80
- /** which feature's KEK the value is envelope-encrypted under. */
120
+ /** which feature the value is encrypted at rest under. */
81
121
  feature: string;
82
122
  description?: string;
83
123
  }