@vxil/sdk 0.1.1 → 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/README.md +1 -1
- package/dist/index.d.ts +182 -12
- package/dist/index.js +88 -8
- package/package.json +4 -5
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ const items = await vx.from('tasks').list({ status: 'open' });
|
|
|
19
19
|
- Zero dependencies; works in Node ≥18, browsers, and edge runtimes.
|
|
20
20
|
- Defaults to `https://api.vxil.com`; pass `baseUrl` to target another environment.
|
|
21
21
|
- Every feature the tenant has enabled is available as a typed namespace; generate a
|
|
22
|
-
project-exact client with `npx vxil gen`.
|
|
22
|
+
project-exact client with `npx @vxil/cli gen`.
|
|
23
23
|
|
|
24
24
|
Docs: [vxil.com](https://vxil.com) · Dashboard: [vxil.com/dashboard](https://vxil.com/dashboard) · Terms: [vxil.com/terms](https://vxil.com/terms)
|
|
25
25
|
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type ApiVersion = 'v1';
|
|
|
8
8
|
* (`/v1/<namespace>/…`). Matches the segment `versionedPath` rewrites, so an
|
|
9
9
|
* override changes exactly that namespace's paths. Renamed client accessors map
|
|
10
10
|
* onto their real namespaces (`vx.search` → `search`, `vx.feeds` → `feeds`). */
|
|
11
|
-
export type FeatureKey = 'users' | 'notifications' | 'config' | 'features' | 'audit' | 'jobs' | 'auth' | 'rate-limits' | 'files' | 'cms' | 'comments' | 'dm' | 'feeds' | 'realtime' | 'orgs' | 'webhooks' | 'search' | 'ai' | 'rag' | 'payments' | 'fn' | 'copilot';
|
|
11
|
+
export type FeatureKey = 'users' | 'notifications' | 'config' | 'features' | 'audit' | 'usage' | 'jobs' | 'auth' | 'rate-limits' | 'files' | 'cms' | 'comments' | 'dm' | 'feeds' | 'realtime' | 'orgs' | 'webhooks' | 'search' | 'ai' | 'rag' | 'payments' | 'fn' | 'copilot';
|
|
12
12
|
export interface VxilOptions {
|
|
13
13
|
apiKey: string;
|
|
14
14
|
/** defaults to the production edge */
|
|
@@ -17,7 +17,7 @@ export interface VxilOptions {
|
|
|
17
17
|
/** An end-user's vxil-`auth` **session token** (the ES256 JWT `auth` mints).
|
|
18
18
|
* When set, every request additionally carries it as the `X-Vxil-End-User`
|
|
19
19
|
* header — the edge verifies it and threads a **verified `end_user_id`** into
|
|
20
|
-
* the
|
|
20
|
+
* the request, putting it in **end-user mode** (owner-scoped reads/
|
|
21
21
|
* writes on owned collections; default-safe). This is the thin-client shape:
|
|
22
22
|
* a mobile/SPA holds a public/thin-client key + the signed-in user's session
|
|
23
23
|
* token and calls the edge directly, safely scoped to that user. Absent ⇒
|
|
@@ -84,6 +84,80 @@ export interface FeatureConfig {
|
|
|
84
84
|
version: number;
|
|
85
85
|
manifest: Record<string, unknown>;
|
|
86
86
|
}
|
|
87
|
+
/** An advisory plan from the planner (POST /v1/plan) — a proposal, not applied. */
|
|
88
|
+
export interface VxilPlan {
|
|
89
|
+
app: {
|
|
90
|
+
name: string;
|
|
91
|
+
slug: string;
|
|
92
|
+
summary: string;
|
|
93
|
+
prompt: string;
|
|
94
|
+
};
|
|
95
|
+
/** features to enable, each with the capability that pulled it in. */
|
|
96
|
+
features: Array<{
|
|
97
|
+
feature: string;
|
|
98
|
+
why: string;
|
|
99
|
+
}>;
|
|
100
|
+
/** the raw features[] list for a quickstart body. */
|
|
101
|
+
enable: string[];
|
|
102
|
+
/** feature → materialized config manifest. */
|
|
103
|
+
config: Record<string, unknown>;
|
|
104
|
+
/** truly-unique server logic that needs a tenant function. */
|
|
105
|
+
functions: Array<{
|
|
106
|
+
why_unique: string;
|
|
107
|
+
}>;
|
|
108
|
+
/** cms collection drafts (AI tier; [] on the deterministic floor). */
|
|
109
|
+
collections: Array<{
|
|
110
|
+
name: string;
|
|
111
|
+
public?: boolean;
|
|
112
|
+
ownerField?: string;
|
|
113
|
+
fields: Array<{
|
|
114
|
+
name: string;
|
|
115
|
+
type: string;
|
|
116
|
+
required?: boolean;
|
|
117
|
+
unique?: boolean;
|
|
118
|
+
indexSlot?: string;
|
|
119
|
+
relationTo?: string;
|
|
120
|
+
onDelete?: string;
|
|
121
|
+
}>;
|
|
122
|
+
}>;
|
|
123
|
+
/** deny-clamped deploy-key scope union (informational). */
|
|
124
|
+
scopes: string[];
|
|
125
|
+
/** 1 = fully declarative; < 1 = some logic needs functions. */
|
|
126
|
+
thinness: number;
|
|
127
|
+
notes: string[];
|
|
128
|
+
/** a ready-to-review vxil.config.ts draft. */
|
|
129
|
+
config_draft: string;
|
|
130
|
+
rationale: string;
|
|
131
|
+
/** which brain produced the plan. */
|
|
132
|
+
source: 'ai' | 'deterministic';
|
|
133
|
+
}
|
|
134
|
+
/** Current-month usage projection (GET /v1/usage) — the same meter the
|
|
135
|
+
* platform bills and enforces request quotas from. */
|
|
136
|
+
export interface UsageCurrent {
|
|
137
|
+
/** the current UTC month, 'YYYY-MM'. */
|
|
138
|
+
period: string;
|
|
139
|
+
/** the plan tier the quota is derived from. */
|
|
140
|
+
tier: string;
|
|
141
|
+
requests: {
|
|
142
|
+
/** requests recorded this month (0 until the meter has rows). */
|
|
143
|
+
used: number;
|
|
144
|
+
/** the plan's included monthly requests; null = no fixed cap. */
|
|
145
|
+
quota: number | null;
|
|
146
|
+
/** max(quota − used, 0); null when quota is null. */
|
|
147
|
+
remaining: number | null;
|
|
148
|
+
/** the PLAN's hard-cap policy — true only on the free tier (which is cut
|
|
149
|
+
* off with 429 quota_exceeded when exhausted); paid tiers are never
|
|
150
|
+
* interrupted mid-month. Not a live "the next request will 429" signal. */
|
|
151
|
+
enforced: boolean;
|
|
152
|
+
};
|
|
153
|
+
/** month-to-date per-feature metered detail. Aggregated periodically — it
|
|
154
|
+
* may lag and may be empty. */
|
|
155
|
+
features: Array<{
|
|
156
|
+
feature: string;
|
|
157
|
+
metric: string;
|
|
158
|
+
quantity: number;
|
|
159
|
+
}>;
|
|
160
|
+
}
|
|
87
161
|
export interface DeadLetter {
|
|
88
162
|
delivery_id: string;
|
|
89
163
|
template_id: string;
|
|
@@ -164,7 +238,7 @@ export interface PaymentsWebhookEvent {
|
|
|
164
238
|
processed_at: string | null;
|
|
165
239
|
reprocess_count: number;
|
|
166
240
|
reprocessed_at: string | null;
|
|
167
|
-
/** detail-only: the verified provider payload (
|
|
241
|
+
/** detail-only: the verified provider payload (JSON; '{}' for failed rows). */
|
|
168
242
|
payload?: unknown;
|
|
169
243
|
/** detail-only: the raw body of a sig_failed/parse_failed delivery (≤64KB). */
|
|
170
244
|
raw_body?: string | null;
|
|
@@ -304,6 +378,12 @@ export interface AiGeneration {
|
|
|
304
378
|
usage: AiUsage;
|
|
305
379
|
finish: string;
|
|
306
380
|
tool_calls?: AiToolCall[];
|
|
381
|
+
/** the parsed JSON output — present when the request (or its template)
|
|
382
|
+
* carried a response schema; guaranteed to satisfy it (a 200 never violates
|
|
383
|
+
* the schema — final-invalid is a 422 output_schema_mismatch). */
|
|
384
|
+
output?: unknown;
|
|
385
|
+
/** true when the output only validated after the single repair pass. */
|
|
386
|
+
repaired?: boolean;
|
|
307
387
|
cached: boolean;
|
|
308
388
|
}
|
|
309
389
|
/** A streamed generation handle: open the realtime channel for token frames. */
|
|
@@ -315,7 +395,7 @@ export interface AiStreamHandle {
|
|
|
315
395
|
connect_path?: string;
|
|
316
396
|
resume_path: string;
|
|
317
397
|
}
|
|
318
|
-
/** Frames delivered over the ai
|
|
398
|
+
/** Frames delivered over the ai-<generation_id> realtime channel and the
|
|
319
399
|
* ?since= replay buffer (the WS envelope is { event, data } — `event` is the
|
|
320
400
|
* frame type; replayed frames carry it as `type`). `title` arrives early when
|
|
321
401
|
* the stream was requested with title/title_template; only the terminal usage
|
|
@@ -670,6 +750,53 @@ export interface DmConfigState {
|
|
|
670
750
|
version: number;
|
|
671
751
|
configured: boolean;
|
|
672
752
|
}
|
|
753
|
+
/** The safe query subset the keyless cms public lane admits (roadmap §4.4): the
|
|
754
|
+
* same bounded filter/sort/limit/cursor as the authored list, minus anything
|
|
755
|
+
* owner- or lifecycle-scoped (the lane FORCES status='published'). `filter` is a
|
|
756
|
+
* JSON object, serialized to the wire `filter=` param. */
|
|
757
|
+
export interface CmsPublicQuery {
|
|
758
|
+
filter?: Record<string, unknown>;
|
|
759
|
+
sort?: string;
|
|
760
|
+
/** capped at 100 by the public lane regardless of the value sent. */
|
|
761
|
+
limit?: number;
|
|
762
|
+
cursor?: string;
|
|
763
|
+
}
|
|
764
|
+
/** One row on the keyless public lane: the item id + its authored data + the
|
|
765
|
+
* public lifecycle timestamps. NO internal/system columns and NEVER the
|
|
766
|
+
* owner_field (stripped server-side). */
|
|
767
|
+
export interface CmsPublicRow {
|
|
768
|
+
item_id: string;
|
|
769
|
+
data: Record<string, unknown>;
|
|
770
|
+
created_at: string;
|
|
771
|
+
updated_at: string;
|
|
772
|
+
published_at: string | null;
|
|
773
|
+
}
|
|
774
|
+
/** Build the anonymous, KEYLESS public-delivery URL for a collection's PUBLISHED
|
|
775
|
+
* items (roadmap §4.4) — `{base}/v1/cms/public/:tenantId/:collection[?…]`. This is
|
|
776
|
+
* the reader path a public blog/storefront/docs site hits with NO api key: the
|
|
777
|
+
* edge mints a restricted read-only inner token bound to the URL tenant, forces
|
|
778
|
+
* `status='published'`, and strips the collection's owner_field. PURE (no
|
|
779
|
+
* network) — pass the result to `fetch`, an `<img>`/link, or `listCmsPublic`.
|
|
780
|
+
* `baseUrl` defaults to `VXIL_BASE_URL` (Node) or the production edge, exactly
|
|
781
|
+
* like the client constructor. */
|
|
782
|
+
export declare function cmsPublicUrl(tenantId: string, collection: string, query?: CmsPublicQuery, opts?: {
|
|
783
|
+
baseUrl?: string;
|
|
784
|
+
}): string;
|
|
785
|
+
/** Fetch a page of a collection's PUBLISHED items over the KEYLESS public lane
|
|
786
|
+
* (roadmap §4.4) — NO api key, no `Vxil` client, no auth of any kind. This is the
|
|
787
|
+
* anonymous reader path (a blog/storefront/docs front-end). Returns the same
|
|
788
|
+
* `{ items, next_cursor }` envelope the authed list does, but rows are stripped
|
|
789
|
+
* to the public surface (`CmsPublicRow`) — drafts and the owner_field are never
|
|
790
|
+
* present. A non-2xx throws `VxilError` carrying the envelope, as everywhere else.
|
|
791
|
+
* The collection must be marked public (`collections.setPublic(collection, true)`
|
|
792
|
+
* or `{ public: true }` on create) or the lane 404s (no not-public oracle). */
|
|
793
|
+
export declare function listCmsPublic(tenantId: string, collection: string, query?: CmsPublicQuery, opts?: {
|
|
794
|
+
baseUrl?: string;
|
|
795
|
+
fetch?: typeof fetch;
|
|
796
|
+
}): Promise<{
|
|
797
|
+
items: CmsPublicRow[];
|
|
798
|
+
next_cursor: string | null;
|
|
799
|
+
}>;
|
|
673
800
|
/** The structural shape a `vxil gen`-generated `VxilSchema` satisfies. The base
|
|
674
801
|
* `Vxil` class is generic over it (`new Vxil<VxilSchema>(...)`), exactly the
|
|
675
802
|
* `createClient<Database>()` move — types are layered on; the runtime is
|
|
@@ -1111,6 +1238,14 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1111
1238
|
};
|
|
1112
1239
|
}>;
|
|
1113
1240
|
};
|
|
1241
|
+
/** The planner (config-architect): describe an app in plain English and get an
|
|
1242
|
+
* ADVISORY vxil plan — which features to enable, a materialized `config_draft`,
|
|
1243
|
+
* and which truly-unique logic needs a tenant function. Deterministic + pure;
|
|
1244
|
+
* it PROPOSES a plan, it never applies anything (review it, then push the
|
|
1245
|
+
* config). Needs `features:read`. (POST /v1/plan; docs/planner-feature-design.md) */
|
|
1246
|
+
readonly planner: {
|
|
1247
|
+
create: (description: string, name?: string) => Promise<VxilPlan>;
|
|
1248
|
+
};
|
|
1114
1249
|
readonly audit: {
|
|
1115
1250
|
list: (q?: {
|
|
1116
1251
|
since?: string;
|
|
@@ -1147,6 +1282,13 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1147
1282
|
}>;
|
|
1148
1283
|
}>;
|
|
1149
1284
|
};
|
|
1285
|
+
/** Current-month usage: requests used vs the plan's included quota, plus
|
|
1286
|
+
* month-to-date per-feature metered detail. Read-only (needs `usage:read`
|
|
1287
|
+
* or `features:read`). Agents: call this before a bulk run to self-check
|
|
1288
|
+
* remaining quota. */
|
|
1289
|
+
readonly usage: {
|
|
1290
|
+
current: () => Promise<UsageCurrent>;
|
|
1291
|
+
};
|
|
1150
1292
|
readonly jobs: {
|
|
1151
1293
|
/** Enqueue a one-off job; Vxil POSTs a signed callback to target_url with
|
|
1152
1294
|
* retries. deliver_after (ISO) / delay_seconds (≤ 30 d, at most one of the
|
|
@@ -1400,7 +1542,7 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1400
1542
|
};
|
|
1401
1543
|
/** End-user administration (server/function surface, auth:write). */
|
|
1402
1544
|
users: {
|
|
1403
|
-
/** GDPR PII erasure: anonymize the end-user's auth +
|
|
1545
|
+
/** GDPR PII erasure: anonymize the end-user's auth + end-user identity record
|
|
1404
1546
|
* (email → tombstone, password/name/avatar cleared) and revoke every
|
|
1405
1547
|
* live session. Idempotent — a second call on an already-erased user is a
|
|
1406
1548
|
* no-op. Meant to be called from a "delete my account" server route or
|
|
@@ -1568,6 +1710,12 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1568
1710
|
* end-user principal (default-deny) in end-user mode; a no-op in
|
|
1569
1711
|
* server-caller mode. Omit for shared/reference collections. */
|
|
1570
1712
|
owner_field?: string;
|
|
1713
|
+
/** Public delivery (roadmap §4.4): when true, this collection's PUBLISHED
|
|
1714
|
+
* items become KEYLESS-readable through the anonymous public lane —
|
|
1715
|
+
* `GET {base}/v1/cms/public/:tenantId/:collection` with NO api key. Drafts
|
|
1716
|
+
* and the owner_field are never exposed. Optional; defaults false. Use the
|
|
1717
|
+
* top-level `cmsPublicUrl` / `listCmsPublic` helpers for the reader side. */
|
|
1718
|
+
public?: boolean;
|
|
1571
1719
|
fields?: Array<{
|
|
1572
1720
|
field: string;
|
|
1573
1721
|
type: "string" | "text" | "int" | "float" | "bool" | "datetime" | "json" | "relation" | "file";
|
|
@@ -1591,6 +1739,7 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1591
1739
|
collection: string;
|
|
1592
1740
|
fields: number;
|
|
1593
1741
|
owner_field?: string;
|
|
1742
|
+
public?: boolean;
|
|
1594
1743
|
}>;
|
|
1595
1744
|
list: () => Promise<Array<{
|
|
1596
1745
|
collection: string;
|
|
@@ -1602,6 +1751,12 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1602
1751
|
/** Set (or clear, with `null`) the collection's end-user owner-scope flag
|
|
1603
1752
|
* (design §5.1). Names an existing `string` field that holds the owner id. */
|
|
1604
1753
|
setOwnerField: (collection: string, ownerField: string | null) => Promise<void>;
|
|
1754
|
+
/** Toggle the collection's PUBLIC-delivery flag (roadmap §4.4). When `true`,
|
|
1755
|
+
* its PUBLISHED items become KEYLESS-readable via the anonymous public lane
|
|
1756
|
+
* (`GET {base}/v1/cms/public/:tenantId/:collection` — no api key); drafts and
|
|
1757
|
+
* the owner_field are never exposed. `false` closes the lane (and purges the
|
|
1758
|
+
* edge cache). Read the public side with `cmsPublicUrl` / `listCmsPublic`. */
|
|
1759
|
+
setPublic: (collection: string, isPublic: boolean) => Promise<void>;
|
|
1605
1760
|
};
|
|
1606
1761
|
items: {
|
|
1607
1762
|
/** `lock` serializes same-key writers (per-tenant advisory lock); `guard`
|
|
@@ -1621,11 +1776,11 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1621
1776
|
get: (collection: string, itemId: string) => Promise<Record<string, unknown>>;
|
|
1622
1777
|
/**
|
|
1623
1778
|
* The bounded query DSL. filter ops: $eq $ne $gt $gte $lt $lte $in
|
|
1624
|
-
* $contains $startsWith (LIKE-escaped;
|
|
1625
|
-
* fields) $arrayContains/$anyOf (json/relation array containment
|
|
1626
|
-
*
|
|
1779
|
+
* $contains $startsWith (LIKE-escaped; substring-searchable on s*-slotted
|
|
1780
|
+
* fields) $arrayContains/$anyOf (json/relation array containment, indexed);
|
|
1781
|
+
* range/sort needs slot-indexed fields. This is the
|
|
1627
1782
|
* DELIBERATELY-UNTYPED escape hatch: it accepts everything the server
|
|
1628
|
-
* admits, including unslotted range ops (served by unindexed
|
|
1783
|
+
* admits, including unslotted range ops (served by unindexed
|
|
1629
1784
|
* scans, bounded only by the statement timeout) that the generated
|
|
1630
1785
|
* per-field `Filterable` unions on `vx.from(...).query` exclude.
|
|
1631
1786
|
*/
|
|
@@ -2270,7 +2425,7 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2270
2425
|
settings?: Record<string, unknown>;
|
|
2271
2426
|
role?: string | null;
|
|
2272
2427
|
}>;
|
|
2273
|
-
/** Update a workspace's name / `settings`
|
|
2428
|
+
/** Update a workspace's name / `settings` JSON. */
|
|
2274
2429
|
update: (orgId: string, patch: {
|
|
2275
2430
|
name?: string;
|
|
2276
2431
|
settings?: Record<string, unknown>;
|
|
@@ -2521,7 +2676,7 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2521
2676
|
};
|
|
2522
2677
|
/**
|
|
2523
2678
|
* Managed hybrid search (the `vector-search` feature): store documents → chunk →
|
|
2524
|
-
* embed → index, then retrieve top-k via hybrid (
|
|
2679
|
+
* embed → index, then retrieve top-k via hybrid (keyword ∪ vector, RRF-fused),
|
|
2525
2680
|
* vector, or keyword. The embedder is config: 'mock' (deterministic default),
|
|
2526
2681
|
* 'byov' (you supply vectors), or a BYO-key provider (openai/cohere).
|
|
2527
2682
|
*/
|
|
@@ -2615,7 +2770,10 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2615
2770
|
readonly ai: {
|
|
2616
2771
|
templates: {
|
|
2617
2772
|
/** Store a tenant-authored prompt template; versions are monotonic per name.
|
|
2618
|
-
* `{{var}}` placeholders are filled from `generate`'s `input`.
|
|
2773
|
+
* `{{var}}` placeholders are filled from `generate`'s `input`.
|
|
2774
|
+
* `schema` (a JSON Schema) is now ENFORCED at generate time on sync/job
|
|
2775
|
+
* requests — the output is validated (with one repair pass) against it;
|
|
2776
|
+
* a per-request `response_schema` overrides it. Ignored on streams. */
|
|
2619
2777
|
put: (input: {
|
|
2620
2778
|
template: string;
|
|
2621
2779
|
user: string;
|
|
@@ -2657,6 +2815,13 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2657
2815
|
* role:'tool' results) — vxil relays; you execute the tools. */
|
|
2658
2816
|
messages?: AiChatMessage[];
|
|
2659
2817
|
json_mode?: boolean;
|
|
2818
|
+
/** JSON Schema the completion must satisfy (schema-guaranteed structured
|
|
2819
|
+
* output): enforced natively where the provider supports strict
|
|
2820
|
+
* structured output, else via one validate-and-repair pass; the parsed
|
|
2821
|
+
* object lands in `output` (+`repaired` when the repair pass fired). A
|
|
2822
|
+
* still-invalid result is a 422 `output_schema_mismatch` (billed). Wins
|
|
2823
|
+
* over the template's stored schema. */
|
|
2824
|
+
response_schema?: Record<string, unknown>;
|
|
2660
2825
|
images?: string[];
|
|
2661
2826
|
user_id?: string;
|
|
2662
2827
|
}) => Promise<AiGeneration>;
|
|
@@ -2708,6 +2873,11 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2708
2873
|
}>;
|
|
2709
2874
|
messages?: AiChatMessage[];
|
|
2710
2875
|
json_mode?: boolean;
|
|
2876
|
+
/** JSON Schema the completion must satisfy — same contract as
|
|
2877
|
+
* `generate`; the validated answer lands in the replay buffer (a
|
|
2878
|
+
* schema-mismatch delivers finish:'schema_mismatch' on the terminal
|
|
2879
|
+
* usage frame). */
|
|
2880
|
+
response_schema?: Record<string, unknown>;
|
|
2711
2881
|
images?: string[];
|
|
2712
2882
|
user_id?: string;
|
|
2713
2883
|
}) => Promise<AiJobHandle>;
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,57 @@ function resolveBase(explicit) {
|
|
|
43
43
|
const envBase = g.process?.env?.VXIL_BASE_URL;
|
|
44
44
|
return (explicit ?? envBase ?? DEFAULT_BASE).replace(/\/$/, '');
|
|
45
45
|
}
|
|
46
|
+
/** Build the anonymous, KEYLESS public-delivery URL for a collection's PUBLISHED
|
|
47
|
+
* items (roadmap §4.4) — `{base}/v1/cms/public/:tenantId/:collection[?…]`. This is
|
|
48
|
+
* the reader path a public blog/storefront/docs site hits with NO api key: the
|
|
49
|
+
* edge mints a restricted read-only inner token bound to the URL tenant, forces
|
|
50
|
+
* `status='published'`, and strips the collection's owner_field. PURE (no
|
|
51
|
+
* network) — pass the result to `fetch`, an `<img>`/link, or `listCmsPublic`.
|
|
52
|
+
* `baseUrl` defaults to `VXIL_BASE_URL` (Node) or the production edge, exactly
|
|
53
|
+
* like the client constructor. */
|
|
54
|
+
export function cmsPublicUrl(tenantId, collection, query, opts) {
|
|
55
|
+
const base = resolveBase(opts?.baseUrl);
|
|
56
|
+
const path = `/v1/cms/public/${encodeURIComponent(tenantId)}/${encodeURIComponent(collection)}`;
|
|
57
|
+
const qs = new URLSearchParams();
|
|
58
|
+
if (query?.filter)
|
|
59
|
+
qs.set('filter', JSON.stringify(query.filter));
|
|
60
|
+
if (query?.sort)
|
|
61
|
+
qs.set('sort', query.sort);
|
|
62
|
+
if (query?.limit !== undefined)
|
|
63
|
+
qs.set('limit', String(query.limit));
|
|
64
|
+
if (query?.cursor)
|
|
65
|
+
qs.set('cursor', query.cursor);
|
|
66
|
+
const s = qs.toString();
|
|
67
|
+
return `${base}${path}${s ? `?${s}` : ''}`;
|
|
68
|
+
}
|
|
69
|
+
/** Fetch a page of a collection's PUBLISHED items over the KEYLESS public lane
|
|
70
|
+
* (roadmap §4.4) — NO api key, no `Vxil` client, no auth of any kind. This is the
|
|
71
|
+
* anonymous reader path (a blog/storefront/docs front-end). Returns the same
|
|
72
|
+
* `{ items, next_cursor }` envelope the authed list does, but rows are stripped
|
|
73
|
+
* to the public surface (`CmsPublicRow`) — drafts and the owner_field are never
|
|
74
|
+
* present. A non-2xx throws `VxilError` carrying the envelope, as everywhere else.
|
|
75
|
+
* The collection must be marked public (`collections.setPublic(collection, true)`
|
|
76
|
+
* or `{ public: true }` on create) or the lane 404s (no not-public oracle). */
|
|
77
|
+
export async function listCmsPublic(tenantId, collection, query, opts) {
|
|
78
|
+
const url = cmsPublicUrl(tenantId, collection, query, opts);
|
|
79
|
+
const fetchImpl = opts?.fetch ?? fetch;
|
|
80
|
+
const res = await fetchImpl(url, { method: 'GET' });
|
|
81
|
+
const text = await res.text();
|
|
82
|
+
let parsed = {};
|
|
83
|
+
if (text.length > 0) {
|
|
84
|
+
try {
|
|
85
|
+
parsed = JSON.parse(text);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
throw new VxilError(res.status, `http_${res.status}`, text.slice(0, 200));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (!res.ok || parsed.error) {
|
|
92
|
+
const e = parsed.error ?? { code: `http_${res.status}`, message: text.slice(0, 200) };
|
|
93
|
+
throw new VxilError(res.status, e.code, e.message, e.hint, e.fixUrl, parsed.meta?.request_id);
|
|
94
|
+
}
|
|
95
|
+
return parsed.data ?? { items: [], next_cursor: null };
|
|
96
|
+
}
|
|
46
97
|
export class Vxil {
|
|
47
98
|
base;
|
|
48
99
|
key;
|
|
@@ -302,6 +353,17 @@ export class Vxil {
|
|
|
302
353
|
* stable flat-array shorthand. */
|
|
303
354
|
summary: async () => (await this.call('GET', '/v1/features')).data,
|
|
304
355
|
};
|
|
356
|
+
/** The planner (config-architect): describe an app in plain English and get an
|
|
357
|
+
* ADVISORY vxil plan — which features to enable, a materialized `config_draft`,
|
|
358
|
+
* and which truly-unique logic needs a tenant function. Deterministic + pure;
|
|
359
|
+
* it PROPOSES a plan, it never applies anything (review it, then push the
|
|
360
|
+
* config). Needs `features:read`. (POST /v1/plan; docs/planner-feature-design.md) */
|
|
361
|
+
planner = {
|
|
362
|
+
create: async (description, name) => (await this.call('POST', '/v1/plan', {
|
|
363
|
+
description,
|
|
364
|
+
...(name ? { name } : {}),
|
|
365
|
+
})).data,
|
|
366
|
+
};
|
|
305
367
|
audit = {
|
|
306
368
|
list: async (q) => {
|
|
307
369
|
const qs = new URLSearchParams();
|
|
@@ -367,6 +429,13 @@ export class Vxil {
|
|
|
367
429
|
};
|
|
368
430
|
},
|
|
369
431
|
};
|
|
432
|
+
/** Current-month usage: requests used vs the plan's included quota, plus
|
|
433
|
+
* month-to-date per-feature metered detail. Read-only (needs `usage:read`
|
|
434
|
+
* or `features:read`). Agents: call this before a bulk run to self-check
|
|
435
|
+
* remaining quota. */
|
|
436
|
+
usage = {
|
|
437
|
+
current: async () => (await this.call('GET', '/v1/usage')).data,
|
|
438
|
+
};
|
|
370
439
|
jobs = {
|
|
371
440
|
/** Enqueue a one-off job; Vxil POSTs a signed callback to target_url with
|
|
372
441
|
* retries. deliver_after (ISO) / delay_seconds (≤ 30 d, at most one of the
|
|
@@ -481,7 +550,7 @@ export class Vxil {
|
|
|
481
550
|
},
|
|
482
551
|
/** End-user administration (server/function surface, auth:write). */
|
|
483
552
|
users: {
|
|
484
|
-
/** GDPR PII erasure: anonymize the end-user's auth +
|
|
553
|
+
/** GDPR PII erasure: anonymize the end-user's auth + end-user identity record
|
|
485
554
|
* (email → tombstone, password/name/avatar cleared) and revoke every
|
|
486
555
|
* live session. Idempotent — a second call on an already-erased user is a
|
|
487
556
|
* no-op. Meant to be called from a "delete my account" server route or
|
|
@@ -574,6 +643,14 @@ export class Vxil {
|
|
|
574
643
|
setOwnerField: async (collection, ownerField) => {
|
|
575
644
|
await this.call('POST', `/v1/cms/collections/${encodeURIComponent(collection)}/fields`, { owner_field: ownerField });
|
|
576
645
|
},
|
|
646
|
+
/** Toggle the collection's PUBLIC-delivery flag (roadmap §4.4). When `true`,
|
|
647
|
+
* its PUBLISHED items become KEYLESS-readable via the anonymous public lane
|
|
648
|
+
* (`GET {base}/v1/cms/public/:tenantId/:collection` — no api key); drafts and
|
|
649
|
+
* the owner_field are never exposed. `false` closes the lane (and purges the
|
|
650
|
+
* edge cache). Read the public side with `cmsPublicUrl` / `listCmsPublic`. */
|
|
651
|
+
setPublic: async (collection, isPublic) => {
|
|
652
|
+
await this.call('POST', `/v1/cms/collections/${encodeURIComponent(collection)}/fields`, { public: isPublic });
|
|
653
|
+
},
|
|
577
654
|
},
|
|
578
655
|
items: {
|
|
579
656
|
/** `lock` serializes same-key writers (per-tenant advisory lock); `guard`
|
|
@@ -582,11 +659,11 @@ export class Vxil {
|
|
|
582
659
|
get: async (collection, itemId) => (await this.call('GET', `/v1/cms/items/${encodeURIComponent(collection)}/${encodeURIComponent(itemId)}`)).data,
|
|
583
660
|
/**
|
|
584
661
|
* The bounded query DSL. filter ops: $eq $ne $gt $gte $lt $lte $in
|
|
585
|
-
* $contains $startsWith (LIKE-escaped;
|
|
586
|
-
* fields) $arrayContains/$anyOf (json/relation array containment
|
|
587
|
-
*
|
|
662
|
+
* $contains $startsWith (LIKE-escaped; substring-searchable on s*-slotted
|
|
663
|
+
* fields) $arrayContains/$anyOf (json/relation array containment, indexed);
|
|
664
|
+
* range/sort needs slot-indexed fields. This is the
|
|
588
665
|
* DELIBERATELY-UNTYPED escape hatch: it accepts everything the server
|
|
589
|
-
* admits, including unslotted range ops (served by unindexed
|
|
666
|
+
* admits, including unslotted range ops (served by unindexed
|
|
590
667
|
* scans, bounded only by the statement timeout) that the generated
|
|
591
668
|
* per-field `Filterable` unions on `vx.from(...).query` exclude.
|
|
592
669
|
*/
|
|
@@ -937,7 +1014,7 @@ export class Vxil {
|
|
|
937
1014
|
sessionClaims: async (userId) => (await this.call('GET', `/v1/orgs/session-claims?user_id=${encodeURIComponent(userId)}`)).data,
|
|
938
1015
|
/** Read one workspace (incl. `settings`). */
|
|
939
1016
|
get: async (orgId) => (await this.call('GET', `/v1/orgs/${encodeURIComponent(orgId)}`)).data,
|
|
940
|
-
/** Update a workspace's name / `settings`
|
|
1017
|
+
/** Update a workspace's name / `settings` JSON. */
|
|
941
1018
|
update: async (orgId, patch) => (await this.call('PATCH', `/v1/orgs/${encodeURIComponent(orgId)}`, patch)).data,
|
|
942
1019
|
members: {
|
|
943
1020
|
add: async (orgId, userId, role) => {
|
|
@@ -1060,7 +1137,7 @@ export class Vxil {
|
|
|
1060
1137
|
};
|
|
1061
1138
|
/**
|
|
1062
1139
|
* Managed hybrid search (the `vector-search` feature): store documents → chunk →
|
|
1063
|
-
* embed → index, then retrieve top-k via hybrid (
|
|
1140
|
+
* embed → index, then retrieve top-k via hybrid (keyword ∪ vector, RRF-fused),
|
|
1064
1141
|
* vector, or keyword. The embedder is config: 'mock' (deterministic default),
|
|
1065
1142
|
* 'byov' (you supply vectors), or a BYO-key provider (openai/cohere).
|
|
1066
1143
|
*/
|
|
@@ -1120,7 +1197,10 @@ export class Vxil {
|
|
|
1120
1197
|
ai = {
|
|
1121
1198
|
templates: {
|
|
1122
1199
|
/** Store a tenant-authored prompt template; versions are monotonic per name.
|
|
1123
|
-
* `{{var}}` placeholders are filled from `generate`'s `input`.
|
|
1200
|
+
* `{{var}}` placeholders are filled from `generate`'s `input`.
|
|
1201
|
+
* `schema` (a JSON Schema) is now ENFORCED at generate time on sync/job
|
|
1202
|
+
* requests — the output is validated (with one repair pass) against it;
|
|
1203
|
+
* a per-request `response_schema` overrides it. Ignored on streams. */
|
|
1124
1204
|
put: async (input) => (await this.call('POST', '/v1/ai/templates', input)).data,
|
|
1125
1205
|
/** List stored templates (each name + its latest version). */
|
|
1126
1206
|
list: async () => (await this.call('GET', '/v1/ai/templates')).data.templates,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vxil/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Typed client for the Vxil REST API (notifications, auth, jobs, files, cms, comments, webhooks, realtime, orgs, rate-limits).",
|
|
@@ -28,11 +28,10 @@
|
|
|
28
28
|
"files": [
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
|
-
"scripts": {
|
|
32
|
-
"build": "tsc -p tsconfig.build.json",
|
|
33
|
-
"prepublishOnly": "pnpm run build"
|
|
34
|
-
},
|
|
35
31
|
"publishConfig": {
|
|
36
32
|
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.build.json"
|
|
37
36
|
}
|
|
38
37
|
}
|