@vxil/feature-configs 0.2.0 → 0.3.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.
- package/dist/index.d.ts +99 -33
- package/dist/index.js +336 -37
- package/package.json +1 -1
- package/src/index.test.ts +411 -26
- package/src/index.ts +411 -92
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,32 @@ export declare const RESERVED_CREDIT_TYPES: ReadonlySet<string>;
|
|
|
5
5
|
/** True when a credit_type is a vxil-COGS reserved type (grant/consume/config
|
|
6
6
|
* of which is restricted to internal platform machinery). */
|
|
7
7
|
export declare function isReservedCreditType(creditType: string): boolean;
|
|
8
|
+
export declare const NOTIFICATION_TEMPLATE_PLACEHOLDERS: Readonly<Record<string, readonly string[]>>;
|
|
9
|
+
/** Per-override caps (D4). Bodies are emails, not documents. */
|
|
10
|
+
export declare const NOTIF_OVERRIDE_SUBJECT_MAX = 500;
|
|
11
|
+
export declare const NOTIF_OVERRIDE_BODY_MAX = 20000;
|
|
12
|
+
/** Whole-map caps: keeps one manifest (and the KV row every send reads) small. */
|
|
13
|
+
export declare const NOTIF_OVERRIDE_MAX_LOCALES_PER_TEMPLATE = 20;
|
|
14
|
+
export declare const NOTIF_OVERRIDE_MAX_BYTES: number;
|
|
15
|
+
/**
|
|
16
|
+
* D4 — validate `templates.overrides` at CONFIG-WRITE time. Returns [] when the
|
|
17
|
+
* bag is absent or clean. Every rule fails LOUD rather than shipping something
|
|
18
|
+
* that silently renders wrong in a customer's inbox:
|
|
19
|
+
* • overrides present with `allowOverride:false` → rejected (never inert);
|
|
20
|
+
* • an unknown template id / locale tag → rejected;
|
|
21
|
+
* • an unknown `{{placeholder}}` in subject/html/text → rejected (the class of
|
|
22
|
+
* typo that renders as an empty string in a live email);
|
|
23
|
+
* • size caps (per-locale count, whole-map bytes) → rejected.
|
|
24
|
+
* Pure, so it is unit-tested without a control plane.
|
|
25
|
+
*/
|
|
26
|
+
export declare function validateNotificationOverrides(templates: {
|
|
27
|
+
allowOverride?: boolean;
|
|
28
|
+
overrides?: Record<string, Record<string, {
|
|
29
|
+
subject?: string;
|
|
30
|
+
html?: string;
|
|
31
|
+
text?: string;
|
|
32
|
+
}>>;
|
|
33
|
+
} | undefined): string[];
|
|
8
34
|
export declare const NotificationsConfigSchema: import("@sinclair/typebox").TObject<{
|
|
9
35
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
10
36
|
fromEmail: import("@sinclair/typebox").TString;
|
|
@@ -25,9 +51,14 @@ export declare const NotificationsConfigSchema: import("@sinclair/typebox").TObj
|
|
|
25
51
|
perDay: import("@sinclair/typebox").TInteger;
|
|
26
52
|
perTenantSec: import("@sinclair/typebox").TInteger;
|
|
27
53
|
}>;
|
|
28
|
-
templates: import("@sinclair/typebox").TObject<{
|
|
54
|
+
templates: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
29
55
|
allowOverride: import("@sinclair/typebox").TBoolean;
|
|
30
|
-
|
|
56
|
+
overrides: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TObject<{
|
|
57
|
+
subject: import("@sinclair/typebox").TString;
|
|
58
|
+
html: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
59
|
+
text: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
60
|
+
}>>>>;
|
|
61
|
+
}>>;
|
|
31
62
|
/** in-app inbox channel (send with channel: 'inbox' | 'both') */
|
|
32
63
|
inboxEnabled: import("@sinclair/typebox").TBoolean;
|
|
33
64
|
/** §11b.5 broadcast campaigns channel. Optional bag (= 1 leaf): absent means
|
|
@@ -100,16 +131,29 @@ export declare const JobsConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
100
131
|
}>;
|
|
101
132
|
}>;
|
|
102
133
|
export type JobsConfig = Static<typeof JobsConfigSchema>;
|
|
134
|
+
declare const OidcProviderSchema: import("@sinclair/typebox").TObject<{
|
|
135
|
+
issuer: import("@sinclair/typebox").TString;
|
|
136
|
+
clientId: import("@sinclair/typebox").TString;
|
|
137
|
+
clientSecretRef: import("@sinclair/typebox").TString;
|
|
138
|
+
scopes: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
139
|
+
claims: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
140
|
+
email: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
141
|
+
name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
142
|
+
roles: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
143
|
+
}>>;
|
|
144
|
+
allowedDomains: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
145
|
+
autoLink: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
146
|
+
}>;
|
|
103
147
|
export declare const AuthConfigSchema: import("@sinclair/typebox").TObject<{
|
|
104
148
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
105
|
-
methods: import("@sinclair/typebox").TObject<{
|
|
149
|
+
methods: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
106
150
|
emailPassword: import("@sinclair/typebox").TBoolean;
|
|
107
151
|
magicLink: import("@sinclair/typebox").TBoolean;
|
|
108
152
|
google: import("@sinclair/typebox").TBoolean;
|
|
109
153
|
github: import("@sinclair/typebox").TBoolean;
|
|
110
154
|
apple: import("@sinclair/typebox").TBoolean;
|
|
111
155
|
facebook: import("@sinclair/typebox").TBoolean;
|
|
112
|
-
}
|
|
156
|
+
}>>;
|
|
113
157
|
providers: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
114
158
|
google: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
115
159
|
clientIdRef: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -133,10 +177,24 @@ export declare const AuthConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
133
177
|
clientSecretRef: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
134
178
|
audRefs: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
135
179
|
}>>;
|
|
180
|
+
oidc: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
181
|
+
issuer: import("@sinclair/typebox").TString;
|
|
182
|
+
clientId: import("@sinclair/typebox").TString;
|
|
183
|
+
clientSecretRef: import("@sinclair/typebox").TString;
|
|
184
|
+
scopes: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
185
|
+
claims: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
186
|
+
email: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
187
|
+
name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
188
|
+
roles: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
189
|
+
}>>;
|
|
190
|
+
allowedDomains: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
191
|
+
autoLink: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
192
|
+
}>>;
|
|
136
193
|
}>>;
|
|
137
194
|
session: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
138
195
|
ttlMinutes: import("@sinclair/typebox").TInteger;
|
|
139
196
|
refreshTtlDays: import("@sinclair/typebox").TInteger;
|
|
197
|
+
maxConcurrent: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
140
198
|
}>>;
|
|
141
199
|
password: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
142
200
|
minLength: import("@sinclair/typebox").TInteger;
|
|
@@ -153,6 +211,7 @@ export declare const AuthConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
153
211
|
codeTtlMinutes: import("@sinclair/typebox").TInteger;
|
|
154
212
|
maxAttempts: import("@sinclair/typebox").TInteger;
|
|
155
213
|
resendCooldownSec: import("@sinclair/typebox").TInteger;
|
|
214
|
+
testRecipients: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
156
215
|
}>>;
|
|
157
216
|
anonymous: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
158
217
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
@@ -160,7 +219,21 @@ export declare const AuthConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
160
219
|
orgClaims: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
161
220
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
162
221
|
}>>;
|
|
222
|
+
security: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
223
|
+
lockout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
224
|
+
maxFailures: import("@sinclair/typebox").TInteger;
|
|
225
|
+
windowMinutes: import("@sinclair/typebox").TInteger;
|
|
226
|
+
lockMinutes: import("@sinclair/typebox").TInteger;
|
|
227
|
+
}>>;
|
|
228
|
+
breachedPasswords: import("@sinclair/typebox").TBoolean;
|
|
229
|
+
captchaSecretRef: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
230
|
+
allowedRedirectOrigins: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
231
|
+
}>>;
|
|
163
232
|
}>;
|
|
233
|
+
/** The security bag as persisted (present ⇒ leaf defaults applied). */
|
|
234
|
+
export type AuthSecurityConfig = NonNullable<Static<typeof AuthConfigSchema>['security']>;
|
|
235
|
+
/** The RB-2 generic OIDC / SSO issuer block (`providers.oidc`). */
|
|
236
|
+
export type AuthOidcConfig = Static<typeof OidcProviderSchema>;
|
|
164
237
|
export type AuthConfig = Static<typeof AuthConfigSchema>;
|
|
165
238
|
export declare const RateLimitsConfigSchema: import("@sinclair/typebox").TObject<{
|
|
166
239
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
@@ -172,7 +245,6 @@ export declare const RateLimitsConfigSchema: import("@sinclair/typebox").TObject
|
|
|
172
245
|
export type RateLimitsConfig = Static<typeof RateLimitsConfigSchema>;
|
|
173
246
|
export declare const FilesConfigSchema: import("@sinclair/typebox").TObject<{
|
|
174
247
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
175
|
-
bucketRef: import("@sinclair/typebox").TString;
|
|
176
248
|
uploadUrlTtl: import("@sinclair/typebox").TInteger;
|
|
177
249
|
downloadUrlTtl: import("@sinclair/typebox").TInteger;
|
|
178
250
|
quotas: import("@sinclair/typebox").TObject<{
|
|
@@ -181,10 +253,6 @@ export declare const FilesConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
181
253
|
maxObjectCount: import("@sinclair/typebox").TInteger;
|
|
182
254
|
}>;
|
|
183
255
|
allowedContentTypes: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
184
|
-
contentScan: import("@sinclair/typebox").TObject<{
|
|
185
|
-
enabled: import("@sinclair/typebox").TBoolean;
|
|
186
|
-
quarantineOnFail: import("@sinclair/typebox").TBoolean;
|
|
187
|
-
}>;
|
|
188
256
|
sharedLinks: import("@sinclair/typebox").TObject<{
|
|
189
257
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
190
258
|
maxTtl: import("@sinclair/typebox").TInteger;
|
|
@@ -268,9 +336,6 @@ export declare const McpConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
268
336
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
269
337
|
exposureLevel: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"all">, import("@sinclair/typebox").TLiteral<"read-only">, import("@sinclair/typebox").TLiteral<"custom">]>;
|
|
270
338
|
allowToolList: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
271
|
-
scopedKey: import("@sinclair/typebox").TObject<{
|
|
272
|
-
perAgentKeys: import("@sinclair/typebox").TBoolean;
|
|
273
|
-
}>;
|
|
274
339
|
rateLimits: import("@sinclair/typebox").TObject<{
|
|
275
340
|
toolCallsPerMin: import("@sinclair/typebox").TInteger;
|
|
276
341
|
}>;
|
|
@@ -328,9 +393,6 @@ export declare const ActivityFeedConfigSchema: import("@sinclair/typebox").TObje
|
|
|
328
393
|
copyLimit: import("@sinclair/typebox").TInteger;
|
|
329
394
|
maxFollowing: import("@sinclair/typebox").TInteger;
|
|
330
395
|
}>;
|
|
331
|
-
aggregation: import("@sinclair/typebox").TObject<{
|
|
332
|
-
maxGroupActivities: import("@sinclair/typebox").TInteger;
|
|
333
|
-
}>;
|
|
334
396
|
realtime: import("@sinclair/typebox").TObject<{
|
|
335
397
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
336
398
|
}>;
|
|
@@ -338,9 +400,6 @@ export declare const ActivityFeedConfigSchema: import("@sinclair/typebox").TObje
|
|
|
338
400
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
339
401
|
digestCadence: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"off">, import("@sinclair/typebox").TLiteral<"hourly">, import("@sinclair/typebox").TLiteral<"daily">]>;
|
|
340
402
|
}>;
|
|
341
|
-
rateLimit: import("@sinclair/typebox").TObject<{
|
|
342
|
-
addPerSec: import("@sinclair/typebox").TInteger;
|
|
343
|
-
}>;
|
|
344
403
|
}>;
|
|
345
404
|
export type ActivityFeedConfig = Static<typeof ActivityFeedConfigSchema>;
|
|
346
405
|
export declare const VectorSearchConfigSchema: import("@sinclair/typebox").TObject<{
|
|
@@ -458,6 +517,7 @@ export declare const PaymentsConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
458
517
|
publicSdkKey: import("@sinclair/typebox").TString;
|
|
459
518
|
secretApiKeyRef: import("@sinclair/typebox").TString;
|
|
460
519
|
webhookSecretRef: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
520
|
+
acceptSandbox: import("@sinclair/typebox").TBoolean;
|
|
461
521
|
}>>;
|
|
462
522
|
paypal: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
463
523
|
clientIdRef: import("@sinclair/typebox").TString;
|
|
@@ -466,9 +526,6 @@ export declare const PaymentsConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
466
526
|
sandbox: import("@sinclair/typebox").TBoolean;
|
|
467
527
|
}>>;
|
|
468
528
|
returnUrl: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
469
|
-
prices: import("@sinclair/typebox").TObject<{
|
|
470
|
-
catalogRef: import("@sinclair/typebox").TString;
|
|
471
|
-
}>;
|
|
472
529
|
defaults: import("@sinclair/typebox").TObject<{
|
|
473
530
|
currency: import("@sinclair/typebox").TString;
|
|
474
531
|
trialDays: import("@sinclair/typebox").TInteger;
|
|
@@ -491,19 +548,19 @@ export declare const PaymentsConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
491
548
|
}>>;
|
|
492
549
|
priceMap: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TString>>;
|
|
493
550
|
autoRefundOnJobFailure: import("@sinclair/typebox").TBoolean;
|
|
551
|
+
grace: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
552
|
+
pastDueDays: import("@sinclair/typebox").TInteger;
|
|
553
|
+
}>>;
|
|
554
|
+
enforcePeriodEnd: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
555
|
+
slackHours: import("@sinclair/typebox").TInteger;
|
|
556
|
+
}>>;
|
|
494
557
|
}>>;
|
|
495
|
-
webhooks: import("@sinclair/typebox").TObject<{
|
|
496
|
-
forwardToTenantUrl: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
497
|
-
}>;
|
|
498
558
|
}>;
|
|
499
559
|
export type PaymentsConfig = Static<typeof PaymentsConfigSchema>;
|
|
500
560
|
export declare const FunctionsConfigSchema: import("@sinclair/typebox").TObject<{
|
|
501
561
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
502
|
-
runtime: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"isolate">, import("@sinclair/typebox").TLiteral<"container">]>;
|
|
503
562
|
defaultLimits: import("@sinclair/typebox").TObject<{
|
|
504
563
|
cpuMs: import("@sinclair/typebox").TInteger;
|
|
505
|
-
timeoutMs: import("@sinclair/typebox").TInteger;
|
|
506
|
-
memoryMb: import("@sinclair/typebox").TInteger;
|
|
507
564
|
}>;
|
|
508
565
|
metering: import("@sinclair/typebox").TObject<{
|
|
509
566
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
@@ -567,14 +624,8 @@ export declare const CopilotConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
567
624
|
guestToolAllow: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
568
625
|
}>>;
|
|
569
626
|
}>>;
|
|
570
|
-
escalation: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
571
|
-
enabled: import("@sinclair/typebox").TBoolean;
|
|
572
|
-
handler: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"comments">, import("@sinclair/typebox").TLiteral<"notifications">]>;
|
|
573
|
-
notifyTemplate: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
574
|
-
}>>;
|
|
575
627
|
limits: import("@sinclair/typebox").TObject<{
|
|
576
628
|
consumeCredits: import("@sinclair/typebox").TBoolean;
|
|
577
|
-
tokensPerUserPerDay: import("@sinclair/typebox").TInteger;
|
|
578
629
|
}>;
|
|
579
630
|
widget: import("@sinclair/typebox").TObject<{
|
|
580
631
|
enabled: import("@sinclair/typebox").TBoolean;
|
|
@@ -590,6 +641,21 @@ export declare const CONFIG_FLAG_CAP = 15;
|
|
|
590
641
|
* Per features/auth.md §4: an OPTIONAL object (e.g. a provider credential
|
|
591
642
|
* block) counts as ONE flag — the tenant's decision is "configure it or
|
|
592
643
|
* not", not each inner ref. */
|
|
644
|
+
/** The auth lifecycle events an `authHook` binding may name (F4-30) — the
|
|
645
|
+
* closed union `packages/config` types as AuthHookEvent; the control-plane
|
|
646
|
+
* reconciler maps each to its `auth.<event>` audit-event prefix. */
|
|
647
|
+
export declare const AUTH_HOOK_EVENTS: readonly ["user.created", "session.created", "session.revoked", "signin.failure"];
|
|
648
|
+
export type AuthHookEvent = (typeof AUTH_HOOK_EVENTS)[number];
|
|
649
|
+
/** F4-29 test-recipient entry grammar (shared by the validator and auth-v1's
|
|
650
|
+
* matcher): an exact email, a `*@domain` glob, or a +E.164 phone number. */
|
|
651
|
+
export declare const TEST_RECIPIENT_EMAIL_RE: RegExp;
|
|
652
|
+
export declare const TEST_RECIPIENT_GLOB_RE: RegExp;
|
|
653
|
+
export declare const TEST_RECIPIENT_E164_RE: RegExp;
|
|
654
|
+
export declare function isTestRecipientPattern(entry: string): boolean;
|
|
655
|
+
/** True iff `identifier` (an email today) matches one configured entry:
|
|
656
|
+
* exact (case-insensitive) or the `*@domain` glob. +E.164 entries never match
|
|
657
|
+
* an email. */
|
|
658
|
+
export declare function matchesTestRecipient(identifier: string, entries: readonly string[] | undefined): boolean;
|
|
593
659
|
export declare function countLeaves(schema: TSchema): number;
|
|
594
660
|
export interface ConfigValidation {
|
|
595
661
|
ok: boolean;
|