@vxil/config 0.1.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 +158 -0
- package/dist/index.js +24 -0
- package/package.json +30 -0
- package/src/index.test.ts +28 -0
- package/src/index.ts +184 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { NotificationsConfig, JobsConfig, AuthConfig, RateLimitsConfig, FilesConfig, WebhooksConfig, CommentsConfig, CmsConfig, McpConfig, RealtimeConfig, PresenceConfig, OrgsConfig, ActivityFeedConfig, VectorSearchConfig, AiConfig, RagConfig, PaymentsConfig, FunctionsConfig, CopilotConfig } from '@vxil/feature-configs';
|
|
2
|
+
/** The 9 CMS field types (workers/cms-v1 core.ts FIELD_TYPES). */
|
|
3
|
+
export type FieldType = 'string' | 'text' | 'int' | 'float' | 'bool' | 'datetime' | 'json' | 'relation' | 'file';
|
|
4
|
+
/** The 8 fixed CMS index-slot columns (4 string · 2 numeric · 2 datetime). */
|
|
5
|
+
export type IndexSlot = 's1' | 's2' | 's3' | 's4' | 'n1' | 'n2' | 't1' | 't2';
|
|
6
|
+
/** A single CMS field declaration — mirrors the cms-v1 FieldInput wire shape. */
|
|
7
|
+
export interface FieldDef {
|
|
8
|
+
type: FieldType;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
validation?: Record<string, unknown>;
|
|
11
|
+
/** map to an index slot to make the field filterable-by-range / sortable. */
|
|
12
|
+
indexSlot?: IndexSlot;
|
|
13
|
+
/** required when type === 'relation' — the target collection slug. */
|
|
14
|
+
relationTo?: string;
|
|
15
|
+
computed?: boolean;
|
|
16
|
+
compute?: unknown;
|
|
17
|
+
}
|
|
18
|
+
/** A CMS collection-as-code: collection slug → fields. */
|
|
19
|
+
export interface CollectionDef {
|
|
20
|
+
singular?: string;
|
|
21
|
+
fields: Record<string, FieldDef>;
|
|
22
|
+
/** End-user owner-scoping (docs/end-user-principals-design.md §5.1): names an
|
|
23
|
+
* existing `string` field on this collection that holds the owner (end-user)
|
|
24
|
+
* id. When set, the cms worker auto-scopes owned reads/writes to the VERIFIED
|
|
25
|
+
* 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. */
|
|
28
|
+
ownerField?: string;
|
|
29
|
+
}
|
|
30
|
+
/** A function trigger (the §7.3 crossing). cmsHook fires on a CMS write;
|
|
31
|
+
* authHook is the post-signup hook (fires on `auth.user.created`,
|
|
32
|
+
* at-least-once, ~1min fanout latency). */
|
|
33
|
+
export type FunctionTrigger = {
|
|
34
|
+
kind: 'http';
|
|
35
|
+
path?: string;
|
|
36
|
+
} | {
|
|
37
|
+
kind: 'cron';
|
|
38
|
+
schedule: string;
|
|
39
|
+
} | {
|
|
40
|
+
kind: 'queue';
|
|
41
|
+
source: string;
|
|
42
|
+
} | {
|
|
43
|
+
kind: 'webhook';
|
|
44
|
+
source: string;
|
|
45
|
+
} | {
|
|
46
|
+
kind: 'cmsHook';
|
|
47
|
+
collection: string;
|
|
48
|
+
event: 'beforeCreate' | 'beforeUpdate' | 'beforeWrite';
|
|
49
|
+
} | {
|
|
50
|
+
kind: 'authHook';
|
|
51
|
+
event?: 'user.created';
|
|
52
|
+
};
|
|
53
|
+
/** A deployed tenant function — source in functions/, deployed on `vxil push`. */
|
|
54
|
+
export interface FunctionDef {
|
|
55
|
+
/** path to the ES-module entrypoint, e.g. ./functions/<name>.ts */
|
|
56
|
+
entry: string;
|
|
57
|
+
trigger?: FunctionTrigger;
|
|
58
|
+
/** clamped by DENY_FUNCTION_SCOPES at deploy (admin, wildcard, features:write,
|
|
59
|
+
* functions:write, secrets:write rejected; payments:write / notifications:send /
|
|
60
|
+
* users:* allowed as owner-granted business scopes). */
|
|
61
|
+
scopes?: string[];
|
|
62
|
+
/** tenant_secrets refs injected under KEK_FUNCTIONS (productization). */
|
|
63
|
+
secrets?: string[];
|
|
64
|
+
/** Outbound-Worker host allowlist (deny-by-default egress guard). */
|
|
65
|
+
egressAllow?: string[];
|
|
66
|
+
limits?: {
|
|
67
|
+
cpuMs?: number;
|
|
68
|
+
timeoutMs?: number;
|
|
69
|
+
memoryMb?: number;
|
|
70
|
+
};
|
|
71
|
+
enabled?: boolean;
|
|
72
|
+
/** optional typed contract surfaced by `vxil gen` (Level 1, §4.5). */
|
|
73
|
+
signature?: {
|
|
74
|
+
input?: unknown;
|
|
75
|
+
output?: unknown;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** A secret REFERENCE (never a value). `vxil secrets set <name>` writes the value. */
|
|
79
|
+
export interface SecretRef {
|
|
80
|
+
/** which feature's KEK the value is envelope-encrypted under. */
|
|
81
|
+
feature: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
}
|
|
84
|
+
/** Optional deterministic seed, applied via the per-feature import bundle. */
|
|
85
|
+
export interface SeedSpec {
|
|
86
|
+
cms?: {
|
|
87
|
+
collection: string;
|
|
88
|
+
items: Record<string, unknown>[];
|
|
89
|
+
}[];
|
|
90
|
+
users?: {
|
|
91
|
+
id: string;
|
|
92
|
+
email?: string;
|
|
93
|
+
}[];
|
|
94
|
+
}
|
|
95
|
+
/** The released API majors (docs/feature-versioning.md §3), a CLOSED union —
|
|
96
|
+
* `'v1'` is the only released major, so `apiVersion: 'v2'` is a COMPILE error
|
|
97
|
+
* until a v2 GAs. `defineConfig` also validates it at runtime against
|
|
98
|
+
* `RELEASED_API_VERSIONS`. */
|
|
99
|
+
export type ApiVersion = 'v1';
|
|
100
|
+
/** The released majors `defineConfig` validates `apiVersion` against. Widened
|
|
101
|
+
* only by a real v2. */
|
|
102
|
+
export declare const RELEASED_API_VERSIONS: readonly ApiVersion[];
|
|
103
|
+
/** The whole vxil backend, declared in one typed, version-controlled file. */
|
|
104
|
+
export interface VxilConfig {
|
|
105
|
+
/** target environment label; resolved to a baseUrl by `vxil link` / `--env`. */
|
|
106
|
+
env?: string;
|
|
107
|
+
/** Pin the API major the CLI targets (default `'v1'`, docs/feature-versioning.md).
|
|
108
|
+
* Path-major, per-platform: a breaking change ships as a new major on a new
|
|
109
|
+
* path with a ≥6-month deprecation window. `VXIL_API_VERSION` overrides this
|
|
110
|
+
* for a one-off invocation. */
|
|
111
|
+
apiVersion?: ApiVersion;
|
|
112
|
+
/** (a) PER-feature CONFIG — the same 15-leaf TypeBox manifests, validated by the
|
|
113
|
+
* same Value.Default/Clean pipeline the server uses. Keys match FEATURE_SCHEMAS
|
|
114
|
+
* exactly (note the hyphenated ids). */
|
|
115
|
+
features?: {
|
|
116
|
+
notifications?: Partial<NotificationsConfig>;
|
|
117
|
+
jobs?: Partial<JobsConfig>;
|
|
118
|
+
auth?: Partial<AuthConfig>;
|
|
119
|
+
'rate-limits'?: Partial<RateLimitsConfig>;
|
|
120
|
+
files?: Partial<FilesConfig>;
|
|
121
|
+
webhooks?: Partial<WebhooksConfig>;
|
|
122
|
+
comments?: Partial<CommentsConfig>;
|
|
123
|
+
cms?: Partial<CmsConfig>;
|
|
124
|
+
mcp?: Partial<McpConfig>;
|
|
125
|
+
realtime?: Partial<RealtimeConfig>;
|
|
126
|
+
presence?: Partial<PresenceConfig>;
|
|
127
|
+
orgs?: Partial<OrgsConfig>;
|
|
128
|
+
'activity-feed'?: Partial<ActivityFeedConfig>;
|
|
129
|
+
'vector-search'?: Partial<VectorSearchConfig>;
|
|
130
|
+
ai?: Partial<AiConfig>;
|
|
131
|
+
rag?: Partial<RagConfig>;
|
|
132
|
+
payments?: Partial<PaymentsConfig>;
|
|
133
|
+
functions?: Partial<FunctionsConfig>;
|
|
134
|
+
copilot?: Partial<CopilotConfig>;
|
|
135
|
+
};
|
|
136
|
+
/** (b) CMS SCHEMA-AS-CODE — collections + fields. `push` reconciles them
|
|
137
|
+
* additively against GET /v1/cms/collections (no destructive drops without
|
|
138
|
+
* --allow-destructive). Lane-A hooks stay in features.cms.hooks (config). */
|
|
139
|
+
cms?: {
|
|
140
|
+
collections?: Record<string, CollectionDef>;
|
|
141
|
+
};
|
|
142
|
+
/** (c) FUNCTIONS — name → trigger/scopes/egress/entry; sources in functions/. */
|
|
143
|
+
functions?: Record<string, FunctionDef>;
|
|
144
|
+
/** (d) SECRETS — REFERENCES ONLY, never values. */
|
|
145
|
+
secrets?: Record<string, SecretRef>;
|
|
146
|
+
/** (e) SEED DATA — optional. */
|
|
147
|
+
seed?: SeedSpec;
|
|
148
|
+
}
|
|
149
|
+
/** A typed identity function: returns its argument so the CLI can compile it.
|
|
150
|
+
* The one runtime check is `apiVersion` — a mistyped/unreleased pin (possible
|
|
151
|
+
* from JS callers with no compile gate, or a stale generated value) fails fast
|
|
152
|
+
* here rather than 404-ing every request against a nonexistent major. */
|
|
153
|
+
export declare function defineConfig(c: VxilConfig): VxilConfig;
|
|
154
|
+
/** Authoring helper for split-out cms/<name>.ts collection modules (§6a).
|
|
155
|
+
* `field('title', 'string', { required: true, indexSlot: 's1' })`. */
|
|
156
|
+
export declare function field(type: FieldType, opts?: Omit<FieldDef, 'type'>): FieldDef;
|
|
157
|
+
/** Authoring helper for a collection module: `export default collection({...})`. */
|
|
158
|
+
export declare function collection(def: CollectionDef): CollectionDef;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** The released majors `defineConfig` validates `apiVersion` against. Widened
|
|
2
|
+
* only by a real v2. */
|
|
3
|
+
export const RELEASED_API_VERSIONS = ['v1'];
|
|
4
|
+
/** A typed identity function: returns its argument so the CLI can compile it.
|
|
5
|
+
* The one runtime check is `apiVersion` — a mistyped/unreleased pin (possible
|
|
6
|
+
* from JS callers with no compile gate, or a stale generated value) fails fast
|
|
7
|
+
* here rather than 404-ing every request against a nonexistent major. */
|
|
8
|
+
export function defineConfig(c) {
|
|
9
|
+
if (c.apiVersion !== undefined && !RELEASED_API_VERSIONS.includes(c.apiVersion)) {
|
|
10
|
+
throw new Error(`vxil.config: apiVersion '${String(c.apiVersion)}' is not a released API major ` +
|
|
11
|
+
`(released: ${RELEASED_API_VERSIONS.map((v) => `'${v}'`).join(', ')}). ` +
|
|
12
|
+
'A new major ships as a new path with its own deprecation window — see docs/feature-versioning.md.');
|
|
13
|
+
}
|
|
14
|
+
return c;
|
|
15
|
+
}
|
|
16
|
+
/** Authoring helper for split-out cms/<name>.ts collection modules (§6a).
|
|
17
|
+
* `field('title', 'string', { required: true, indexSlot: 's1' })`. */
|
|
18
|
+
export function field(type, opts = {}) {
|
|
19
|
+
return { type, ...opts };
|
|
20
|
+
}
|
|
21
|
+
/** Authoring helper for a collection module: `export default collection({...})`. */
|
|
22
|
+
export function collection(def) {
|
|
23
|
+
return def;
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vxil/config",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "defineConfig() \u2014 one typed source of truth for a whole vxil backend (features + CMS schema + functions + secret refs + seed). INTERNAL workspace package: bundled into the published `vxil` package's `vxil/config` subpath, not published separately.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://vxil.com",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/techmakerdev/vxil.git",
|
|
10
|
+
"directory": "packages/config"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./src/index.ts"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.build.json",
|
|
22
|
+
"prepublishOnly": "pnpm run build"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@vxil/feature-configs": "workspace:*"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { defineConfig, RELEASED_API_VERSIONS } from './index.js';
|
|
3
|
+
|
|
4
|
+
describe('defineConfig', () => {
|
|
5
|
+
it('is an identity function (returns its argument verbatim)', () => {
|
|
6
|
+
const cfg = { features: { cms: {} } };
|
|
7
|
+
expect(defineConfig(cfg)).toBe(cfg);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('accepts the released apiVersion', () => {
|
|
11
|
+
const cfg = defineConfig({ apiVersion: 'v1', features: {} });
|
|
12
|
+
expect(cfg.apiVersion).toBe('v1');
|
|
13
|
+
expect(RELEASED_API_VERSIONS).toEqual(['v1']);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('accepts a config without apiVersion (optional; defaults to v1 at the CLI)', () => {
|
|
17
|
+
expect(() => defineConfig({ features: {} })).not.toThrow();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('throws on an unreleased apiVersion (fail-fast, actionable message)', () => {
|
|
21
|
+
// A JS caller (no compile gate) or a stale generated value must be rejected
|
|
22
|
+
// at load, not silently 404 every request.
|
|
23
|
+
expect(() => defineConfig({ apiVersion: 'v2' as 'v1', features: {} }))
|
|
24
|
+
.toThrow(/apiVersion 'v2' is not a released API major/);
|
|
25
|
+
expect(() => defineConfig({ apiVersion: 'latest' as 'v1' }))
|
|
26
|
+
.toThrow(/feature-versioning\.md/);
|
|
27
|
+
});
|
|
28
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// @vxil/config — the typed source of truth for a whole vxil backend.
|
|
2
|
+
//
|
|
3
|
+
// `defineConfig` is a TYPED IDENTITY FUNCTION: it returns its argument verbatim
|
|
4
|
+
// so `vxil push` can compile it to a JSON manifest. Type-checking happens in the
|
|
5
|
+
// tenant's editor (real autocomplete from the @vxil/feature-configs Static<>
|
|
6
|
+
// types); the control plane never executes this file. This keeps config-as-code
|
|
7
|
+
// §7.3-consistent — config is DATA; the only tenant CODE that crosses into vxil
|
|
8
|
+
// is (a) the Lane-A hook expressions (a closed sandbox) and (b) the functions/
|
|
9
|
+
// sources (the paid, opt-in, egress-guarded crossing). Everything here is
|
|
10
|
+
// declarative. See docs/vxil-cli-sdk-code-experience-design.md §3.
|
|
11
|
+
import type {
|
|
12
|
+
NotificationsConfig, JobsConfig, AuthConfig, RateLimitsConfig, FilesConfig,
|
|
13
|
+
WebhooksConfig, CommentsConfig, CmsConfig, McpConfig, RealtimeConfig,
|
|
14
|
+
PresenceConfig, OrgsConfig, ActivityFeedConfig, VectorSearchConfig, AiConfig,
|
|
15
|
+
RagConfig, PaymentsConfig, FunctionsConfig, CopilotConfig,
|
|
16
|
+
} from '@vxil/feature-configs';
|
|
17
|
+
|
|
18
|
+
/** The 9 CMS field types (workers/cms-v1 core.ts FIELD_TYPES). */
|
|
19
|
+
export type FieldType =
|
|
20
|
+
| 'string' | 'text' | 'int' | 'float' | 'bool' | 'datetime' | 'json' | 'relation' | 'file';
|
|
21
|
+
|
|
22
|
+
/** The 8 fixed CMS index-slot columns (4 string · 2 numeric · 2 datetime). */
|
|
23
|
+
export type IndexSlot = 's1' | 's2' | 's3' | 's4' | 'n1' | 'n2' | 't1' | 't2';
|
|
24
|
+
|
|
25
|
+
/** A single CMS field declaration — mirrors the cms-v1 FieldInput wire shape. */
|
|
26
|
+
export interface FieldDef {
|
|
27
|
+
type: FieldType;
|
|
28
|
+
required?: boolean;
|
|
29
|
+
validation?: Record<string, unknown>;
|
|
30
|
+
/** map to an index slot to make the field filterable-by-range / sortable. */
|
|
31
|
+
indexSlot?: IndexSlot;
|
|
32
|
+
/** required when type === 'relation' — the target collection slug. */
|
|
33
|
+
relationTo?: string;
|
|
34
|
+
computed?: boolean;
|
|
35
|
+
compute?: unknown;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A CMS collection-as-code: collection slug → fields. */
|
|
39
|
+
export interface CollectionDef {
|
|
40
|
+
singular?: string;
|
|
41
|
+
fields: Record<string, FieldDef>;
|
|
42
|
+
/** End-user owner-scoping (docs/end-user-principals-design.md §5.1): names an
|
|
43
|
+
* existing `string` field on this collection that holds the owner (end-user)
|
|
44
|
+
* id. When set, the cms worker auto-scopes owned reads/writes to the VERIFIED
|
|
45
|
+
* end-user principal in end-user mode (default-deny) — and is a no-op in
|
|
46
|
+
* server-caller mode. NOT an RLS predicate; a single declarative flag the
|
|
47
|
+
* typed worker consults. Omit for shared/reference collections. */
|
|
48
|
+
ownerField?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** A function trigger (the §7.3 crossing). cmsHook fires on a CMS write;
|
|
52
|
+
* authHook is the post-signup hook (fires on `auth.user.created`,
|
|
53
|
+
* at-least-once, ~1min fanout latency). */
|
|
54
|
+
export type FunctionTrigger =
|
|
55
|
+
| { kind: 'http'; path?: string }
|
|
56
|
+
| { kind: 'cron'; schedule: string }
|
|
57
|
+
| { kind: 'queue'; source: string }
|
|
58
|
+
| { kind: 'webhook'; source: string }
|
|
59
|
+
| { kind: 'cmsHook'; collection: string; event: 'beforeCreate' | 'beforeUpdate' | 'beforeWrite' }
|
|
60
|
+
| { kind: 'authHook'; event?: 'user.created' };
|
|
61
|
+
|
|
62
|
+
/** A deployed tenant function — source in functions/, deployed on `vxil push`. */
|
|
63
|
+
export interface FunctionDef {
|
|
64
|
+
/** path to the ES-module entrypoint, e.g. ./functions/<name>.ts */
|
|
65
|
+
entry: string;
|
|
66
|
+
trigger?: FunctionTrigger;
|
|
67
|
+
/** clamped by DENY_FUNCTION_SCOPES at deploy (admin, wildcard, features:write,
|
|
68
|
+
* functions:write, secrets:write rejected; payments:write / notifications:send /
|
|
69
|
+
* users:* allowed as owner-granted business scopes). */
|
|
70
|
+
scopes?: string[];
|
|
71
|
+
/** tenant_secrets refs injected under KEK_FUNCTIONS (productization). */
|
|
72
|
+
secrets?: string[];
|
|
73
|
+
/** Outbound-Worker host allowlist (deny-by-default egress guard). */
|
|
74
|
+
egressAllow?: string[];
|
|
75
|
+
limits?: { cpuMs?: number; timeoutMs?: number; memoryMb?: number };
|
|
76
|
+
enabled?: boolean;
|
|
77
|
+
/** optional typed contract surfaced by `vxil gen` (Level 1, §4.5). */
|
|
78
|
+
signature?: { input?: unknown; output?: unknown };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** A secret REFERENCE (never a value). `vxil secrets set <name>` writes the value. */
|
|
82
|
+
export interface SecretRef {
|
|
83
|
+
/** which feature's KEK the value is envelope-encrypted under. */
|
|
84
|
+
feature: string;
|
|
85
|
+
description?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Optional deterministic seed, applied via the per-feature import bundle. */
|
|
89
|
+
export interface SeedSpec {
|
|
90
|
+
cms?: { collection: string; items: Record<string, unknown>[] }[];
|
|
91
|
+
users?: { id: string; email?: string }[];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The released API majors (docs/feature-versioning.md §3), a CLOSED union —
|
|
95
|
+
* `'v1'` is the only released major, so `apiVersion: 'v2'` is a COMPILE error
|
|
96
|
+
* until a v2 GAs. `defineConfig` also validates it at runtime against
|
|
97
|
+
* `RELEASED_API_VERSIONS`. */
|
|
98
|
+
export type ApiVersion = 'v1';
|
|
99
|
+
|
|
100
|
+
/** The released majors `defineConfig` validates `apiVersion` against. Widened
|
|
101
|
+
* only by a real v2. */
|
|
102
|
+
export const RELEASED_API_VERSIONS: readonly ApiVersion[] = ['v1'];
|
|
103
|
+
|
|
104
|
+
/** The whole vxil backend, declared in one typed, version-controlled file. */
|
|
105
|
+
export interface VxilConfig {
|
|
106
|
+
/** target environment label; resolved to a baseUrl by `vxil link` / `--env`. */
|
|
107
|
+
env?: string;
|
|
108
|
+
|
|
109
|
+
/** Pin the API major the CLI targets (default `'v1'`, docs/feature-versioning.md).
|
|
110
|
+
* Path-major, per-platform: a breaking change ships as a new major on a new
|
|
111
|
+
* path with a ≥6-month deprecation window. `VXIL_API_VERSION` overrides this
|
|
112
|
+
* for a one-off invocation. */
|
|
113
|
+
apiVersion?: ApiVersion;
|
|
114
|
+
|
|
115
|
+
/** (a) PER-feature CONFIG — the same 15-leaf TypeBox manifests, validated by the
|
|
116
|
+
* same Value.Default/Clean pipeline the server uses. Keys match FEATURE_SCHEMAS
|
|
117
|
+
* exactly (note the hyphenated ids). */
|
|
118
|
+
features?: {
|
|
119
|
+
notifications?: Partial<NotificationsConfig>;
|
|
120
|
+
jobs?: Partial<JobsConfig>;
|
|
121
|
+
auth?: Partial<AuthConfig>;
|
|
122
|
+
'rate-limits'?: Partial<RateLimitsConfig>;
|
|
123
|
+
files?: Partial<FilesConfig>;
|
|
124
|
+
webhooks?: Partial<WebhooksConfig>;
|
|
125
|
+
comments?: Partial<CommentsConfig>;
|
|
126
|
+
cms?: Partial<CmsConfig>;
|
|
127
|
+
mcp?: Partial<McpConfig>;
|
|
128
|
+
realtime?: Partial<RealtimeConfig>;
|
|
129
|
+
presence?: Partial<PresenceConfig>;
|
|
130
|
+
orgs?: Partial<OrgsConfig>;
|
|
131
|
+
'activity-feed'?: Partial<ActivityFeedConfig>;
|
|
132
|
+
'vector-search'?: Partial<VectorSearchConfig>;
|
|
133
|
+
ai?: Partial<AiConfig>;
|
|
134
|
+
rag?: Partial<RagConfig>;
|
|
135
|
+
payments?: Partial<PaymentsConfig>;
|
|
136
|
+
functions?: Partial<FunctionsConfig>;
|
|
137
|
+
copilot?: Partial<CopilotConfig>;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/** (b) CMS SCHEMA-AS-CODE — collections + fields. `push` reconciles them
|
|
141
|
+
* additively against GET /v1/cms/collections (no destructive drops without
|
|
142
|
+
* --allow-destructive). Lane-A hooks stay in features.cms.hooks (config). */
|
|
143
|
+
cms?: {
|
|
144
|
+
collections?: Record<string, CollectionDef>;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/** (c) FUNCTIONS — name → trigger/scopes/egress/entry; sources in functions/. */
|
|
148
|
+
functions?: Record<string, FunctionDef>;
|
|
149
|
+
|
|
150
|
+
/** (d) SECRETS — REFERENCES ONLY, never values. */
|
|
151
|
+
secrets?: Record<string, SecretRef>;
|
|
152
|
+
|
|
153
|
+
/** (e) SEED DATA — optional. */
|
|
154
|
+
seed?: SeedSpec;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** A typed identity function: returns its argument so the CLI can compile it.
|
|
158
|
+
* The one runtime check is `apiVersion` — a mistyped/unreleased pin (possible
|
|
159
|
+
* from JS callers with no compile gate, or a stale generated value) fails fast
|
|
160
|
+
* here rather than 404-ing every request against a nonexistent major. */
|
|
161
|
+
export function defineConfig(c: VxilConfig): VxilConfig {
|
|
162
|
+
if (c.apiVersion !== undefined && !RELEASED_API_VERSIONS.includes(c.apiVersion)) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`vxil.config: apiVersion '${String(c.apiVersion)}' is not a released API major ` +
|
|
165
|
+
`(released: ${RELEASED_API_VERSIONS.map((v) => `'${v}'`).join(', ')}). ` +
|
|
166
|
+
'A new major ships as a new path with its own deprecation window — see docs/feature-versioning.md.',
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return c;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Authoring helper for split-out cms/<name>.ts collection modules (§6a).
|
|
173
|
+
* `field('title', 'string', { required: true, indexSlot: 's1' })`. */
|
|
174
|
+
export function field(
|
|
175
|
+
type: FieldType,
|
|
176
|
+
opts: Omit<FieldDef, 'type'> = {},
|
|
177
|
+
): FieldDef {
|
|
178
|
+
return { type, ...opts };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Authoring helper for a collection module: `export default collection({...})`. */
|
|
182
|
+
export function collection(def: CollectionDef): CollectionDef {
|
|
183
|
+
return def;
|
|
184
|
+
}
|