@vxil/sdk 0.2.0 → 0.4.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 +83 -6
- package/dist/index.d.ts +810 -60
- package/dist/index.js +413 -268
- package/dist/qs.d.ts +15 -0
- package/dist/qs.js +48 -0
- package/dist/retry.d.ts +47 -0
- package/dist/retry.js +156 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,77 @@
|
|
|
1
|
-
/** The released API majors, as a CLOSED union — one per released major (docs/
|
|
2
|
-
* feature-versioning.md §3). `'v1'` is the only released major, so pinning
|
|
3
|
-
* anything else (`apiVersion: 'v2'`) is a COMPILE error until a v2 GAs and
|
|
4
|
-
* widens this union. Every path the SDK builds is major-versioned; the default
|
|
5
|
-
* is the compile-time constant `'v1'` (never a floating `latest` alias). */
|
|
6
1
|
export type ApiVersion = 'v1';
|
|
7
2
|
/** A per-feature API-version override key: the URL namespace that leads a path
|
|
8
3
|
* (`/v1/<namespace>/…`). Matches the segment `versionedPath` rewrites, so an
|
|
9
4
|
* override changes exactly that namespace's paths. Renamed client accessors map
|
|
10
5
|
* 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';
|
|
6
|
+
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';
|
|
7
|
+
/** Retry policy for the client (DEFAULT OFF: `attempts` is `0`). Only
|
|
8
|
+
* idempotent requests are ever retried — GET/HEAD/PUT/DELETE, and a POST only
|
|
9
|
+
* when the call carries an `Idempotency-Key` header (`{ idempotencyKey }` on
|
|
10
|
+
* the money routes) — so a retry can never double-apply a write. */
|
|
11
|
+
export interface VxilRetryOptions {
|
|
12
|
+
/** How many RETRIES to make after the first attempt (`2` ⇒ up to 3 requests).
|
|
13
|
+
* Default `0` = retries off. */
|
|
14
|
+
attempts?: number;
|
|
15
|
+
/** Response statuses that trigger a retry. Default `[429, 502, 503, 504]`. */
|
|
16
|
+
retryOn?: number[];
|
|
17
|
+
/** Base delay before the first retry; doubles each retry (with jitter in
|
|
18
|
+
* `[½, 1]` of the computed delay). Default `250`. */
|
|
19
|
+
backoffMs?: number;
|
|
20
|
+
/** The longest the client will ever wait between attempts. Also the cap on
|
|
21
|
+
* an honoured `Retry-After`: when the server asks for MORE than this the
|
|
22
|
+
* client does not retry and surfaces the error (its `retryAfter` tells you
|
|
23
|
+
* how long the server asked for). Default `10_000`. */
|
|
24
|
+
maxBackoffMs?: number;
|
|
25
|
+
/** Use the response's `Retry-After` header (seconds or an HTTP-date) as the
|
|
26
|
+
* delay instead of the backoff schedule when present. Default `true`. */
|
|
27
|
+
respectRetryAfter?: boolean;
|
|
28
|
+
/** Also retry when `fetch` itself fails (DNS, connection reset, a
|
|
29
|
+
* `timeoutMs` timeout) — again only for idempotent requests. Default `true`
|
|
30
|
+
* (inert while `attempts` is `0`). */
|
|
31
|
+
retryOnNetworkError?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** What a hook sees of a request: a FROZEN descriptor. Credential headers
|
|
34
|
+
* (`authorization`, `x-vxil-end-user`) are never included. */
|
|
35
|
+
export interface VxilRequestInfo {
|
|
36
|
+
readonly method: string;
|
|
37
|
+
readonly url: string;
|
|
38
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
39
|
+
/** 1 for the first attempt, 2 for the first retry, … */
|
|
40
|
+
readonly attempt: number;
|
|
41
|
+
}
|
|
42
|
+
/** Request lifecycle hooks. Each may be async; a thrown error propagates to
|
|
43
|
+
* the caller (the request is not sent / the response is not returned). */
|
|
44
|
+
export interface VxilHooks {
|
|
45
|
+
/** Runs before EVERY attempt (so a retry can carry a fresh trace id). May
|
|
46
|
+
* return extra headers to add for that attempt — a correlation id, a
|
|
47
|
+
* tracing header. The credential headers cannot be set from a hook (they
|
|
48
|
+
* are dropped); rotate an end-user session with `vx.asEndUser(token)`. */
|
|
49
|
+
beforeRequest?: (request: VxilRequestInfo) => void | Record<string, string> | Promise<void | Record<string, string>>;
|
|
50
|
+
/** Runs after every response that arrives (2xx or not, retried or final),
|
|
51
|
+
* before the retry decision. The body has already been read into the
|
|
52
|
+
* client — inspect `response.status` / `response.headers`, not the body. */
|
|
53
|
+
afterResponse?: (info: {
|
|
54
|
+
request: VxilRequestInfo;
|
|
55
|
+
response: Response;
|
|
56
|
+
durationMs: number;
|
|
57
|
+
}) => void | Promise<void>;
|
|
58
|
+
/** Runs right before the client sleeps for a retry. `status` is set for a
|
|
59
|
+
* retryable response, `error` for a network failure / timeout. */
|
|
60
|
+
onRetry?: (info: {
|
|
61
|
+
request: VxilRequestInfo;
|
|
62
|
+
delayMs: number;
|
|
63
|
+
status?: number;
|
|
64
|
+
error?: unknown;
|
|
65
|
+
}) => void | Promise<void>;
|
|
66
|
+
}
|
|
12
67
|
export interface VxilOptions {
|
|
68
|
+
/** The tenant API key (`vxil_live_…` / `vxil_test_…`).
|
|
69
|
+
*
|
|
70
|
+
* A key may optionally be minted with an **IP allowlist** (`allowed_cidrs`,
|
|
71
|
+
* set in the dashboard at mint time). When it is, a call from an address
|
|
72
|
+
* outside that list is refused at the edge with `403 ip_not_allowed` —
|
|
73
|
+
* before it reaches any feature — and the key is otherwise unchanged. Keys
|
|
74
|
+
* minted without one (the default) are not IP-restricted. */
|
|
13
75
|
apiKey: string;
|
|
14
76
|
/** defaults to the production edge */
|
|
15
77
|
baseUrl?: string;
|
|
@@ -33,6 +95,19 @@ export interface VxilOptions {
|
|
|
33
95
|
* over `apiVersion` for that namespace only. Optional; the compiled default
|
|
34
96
|
* is `'v1'` for every feature. */
|
|
35
97
|
apiVersions?: Partial<Record<FeatureKey, ApiVersion>>;
|
|
98
|
+
/** Retry policy — DEFAULT OFF (`attempts: 0`). Only idempotent requests are
|
|
99
|
+
* ever retried (GET/HEAD/PUT/DELETE, and a POST only when it carries an
|
|
100
|
+
* `Idempotency-Key`), so a retry can never double-apply a write. See
|
|
101
|
+
* `VxilRetryOptions` for the schedule and `Retry-After` handling. */
|
|
102
|
+
retry?: VxilRetryOptions;
|
|
103
|
+
/** Per-attempt timeout in milliseconds (default: none). On expiry the
|
|
104
|
+
* request — body read included — is aborted and a `VxilError`
|
|
105
|
+
* `{ status: 0, code: 'request_timeout' }` is thrown. A timeout counts as a
|
|
106
|
+
* network error for `retry`. */
|
|
107
|
+
timeoutMs?: number;
|
|
108
|
+
/** Request lifecycle hooks — correlation ids, logging, metrics, a retry
|
|
109
|
+
* audit. Nothing runs unless set. See `VxilHooks`. */
|
|
110
|
+
hooks?: VxilHooks;
|
|
36
111
|
}
|
|
37
112
|
/** Rewrite a built `/v1/<ns>/…` path onto the version configured for its
|
|
38
113
|
* namespace: the per-namespace override wins, else the global default. PURE and
|
|
@@ -44,13 +119,24 @@ export interface Meta {
|
|
|
44
119
|
request_id: string;
|
|
45
120
|
tenant_id?: string;
|
|
46
121
|
}
|
|
122
|
+
/** Every non-2xx answer is thrown as this class, carrying the structured error
|
|
123
|
+
* envelope. `status` is the HTTP status — or `0` when no response arrived
|
|
124
|
+
* (a `timeoutMs` timeout, `code: 'request_timeout'`). */
|
|
47
125
|
export declare class VxilError extends Error {
|
|
48
126
|
readonly status: number;
|
|
49
127
|
readonly code: string;
|
|
50
128
|
readonly hint?: string | undefined;
|
|
51
129
|
readonly fixUrl?: string | undefined;
|
|
52
130
|
readonly requestId?: string | undefined;
|
|
53
|
-
|
|
131
|
+
/** Seconds the server asked the caller to wait — parsed from `Retry-After`
|
|
132
|
+
* (delta-seconds or an HTTP-date) when the answer carried it (a rate
|
|
133
|
+
* limit, a busy upstream); otherwise undefined. */
|
|
134
|
+
readonly retryAfter?: number | undefined;
|
|
135
|
+
constructor(status: number, code: string, message: string, hint?: string | undefined, fixUrl?: string | undefined, requestId?: string | undefined,
|
|
136
|
+
/** Seconds the server asked the caller to wait — parsed from `Retry-After`
|
|
137
|
+
* (delta-seconds or an HTTP-date) when the answer carried it (a rate
|
|
138
|
+
* limit, a busy upstream); otherwise undefined. */
|
|
139
|
+
retryAfter?: number | undefined);
|
|
54
140
|
}
|
|
55
141
|
export interface VxilUser {
|
|
56
142
|
id: string;
|
|
@@ -78,6 +164,44 @@ export interface Delivery {
|
|
|
78
164
|
queued_at: string;
|
|
79
165
|
sent_at: string | null;
|
|
80
166
|
failed_at: string | null;
|
|
167
|
+
/** Engagement stamps from the signed provider webhook (first-wins). `null`
|
|
168
|
+
* means "no such event received", NOT "did not happen". */
|
|
169
|
+
delivered_at?: string | null;
|
|
170
|
+
opened_at?: string | null;
|
|
171
|
+
clicked_at?: string | null;
|
|
172
|
+
}
|
|
173
|
+
/** An ADDITIVE, non-fatal note on a 202 send — today only `mock_provider`
|
|
174
|
+
* (the send is recorded but no email leaves vxil). */
|
|
175
|
+
export interface NotificationWarning {
|
|
176
|
+
code: string;
|
|
177
|
+
message: string;
|
|
178
|
+
hint?: string;
|
|
179
|
+
}
|
|
180
|
+
export interface NotificationSendResult {
|
|
181
|
+
delivery_id?: string;
|
|
182
|
+
inbox_message_id?: string;
|
|
183
|
+
status: string;
|
|
184
|
+
/** present only for a scheduled send (`send_at` / `delay_seconds`) */
|
|
185
|
+
scheduled_for?: string;
|
|
186
|
+
warnings?: NotificationWarning[];
|
|
187
|
+
}
|
|
188
|
+
export interface Campaign {
|
|
189
|
+
campaign_id: string;
|
|
190
|
+
name: string;
|
|
191
|
+
channel: string;
|
|
192
|
+
template_id: string;
|
|
193
|
+
audience_ref: string;
|
|
194
|
+
schedule_cron: string | null;
|
|
195
|
+
status: 'draft' | 'scheduled' | 'running' | 'done' | 'paused' | 'cancelled';
|
|
196
|
+
created_at: string;
|
|
197
|
+
/** the jobs schedule row this campaign owns; null = no cron registered */
|
|
198
|
+
schedule_id?: string | null;
|
|
199
|
+
last_run_at?: string | null;
|
|
200
|
+
}
|
|
201
|
+
export interface CampaignState {
|
|
202
|
+
campaign_id: string;
|
|
203
|
+
status: string;
|
|
204
|
+
schedule_id: string | null;
|
|
81
205
|
}
|
|
82
206
|
export interface FeatureConfig {
|
|
83
207
|
feature: string;
|
|
@@ -131,6 +255,33 @@ export interface VxilPlan {
|
|
|
131
255
|
/** which brain produced the plan. */
|
|
132
256
|
source: 'ai' | 'deterministic';
|
|
133
257
|
}
|
|
258
|
+
/** Current-month usage projection (GET /v1/usage) — the same meter the
|
|
259
|
+
* platform bills and enforces request quotas from. */
|
|
260
|
+
export interface UsageCurrent {
|
|
261
|
+
/** the current UTC month, 'YYYY-MM'. */
|
|
262
|
+
period: string;
|
|
263
|
+
/** the plan tier the quota is derived from. */
|
|
264
|
+
tier: string;
|
|
265
|
+
requests: {
|
|
266
|
+
/** requests recorded this month (0 until the meter has rows). */
|
|
267
|
+
used: number;
|
|
268
|
+
/** the plan's included monthly requests; null = no fixed cap. */
|
|
269
|
+
quota: number | null;
|
|
270
|
+
/** max(quota − used, 0); null when quota is null. */
|
|
271
|
+
remaining: number | null;
|
|
272
|
+
/** the PLAN's hard-cap policy — true only on the free tier (which is cut
|
|
273
|
+
* off with 429 quota_exceeded when exhausted); paid tiers are never
|
|
274
|
+
* interrupted mid-month. Not a live "the next request will 429" signal. */
|
|
275
|
+
enforced: boolean;
|
|
276
|
+
};
|
|
277
|
+
/** month-to-date per-feature metered detail. Aggregated periodically — it
|
|
278
|
+
* may lag and may be empty. */
|
|
279
|
+
features: Array<{
|
|
280
|
+
feature: string;
|
|
281
|
+
metric: string;
|
|
282
|
+
quantity: number;
|
|
283
|
+
}>;
|
|
284
|
+
}
|
|
134
285
|
export interface DeadLetter {
|
|
135
286
|
delivery_id: string;
|
|
136
287
|
template_id: string;
|
|
@@ -203,8 +354,14 @@ export interface PaymentsWebhookEvent {
|
|
|
203
354
|
provider: string;
|
|
204
355
|
provider_evt_id: string;
|
|
205
356
|
event_type: string;
|
|
206
|
-
/** received | processed | error | sig_failed | parse_failed | reprocessed
|
|
357
|
+
/** received | processed | error | sig_failed | parse_failed | reprocessed |
|
|
358
|
+
* ignored (a well-formed provider type we deliberately do not fold) |
|
|
359
|
+
* unowned (no end user resolvable) | rejected_environment (a sandbox event
|
|
360
|
+
* the tenant did not opt into) — the last three are 200-acked, never folded. */
|
|
207
361
|
outcome: string | null;
|
|
362
|
+
/** the PROVIDER-reported environment of the delivery ('production' |
|
|
363
|
+
* 'sandbox') — a separate axis from the API key's live/test label. */
|
|
364
|
+
environment?: 'production' | 'sandbox';
|
|
208
365
|
signature_ok: boolean;
|
|
209
366
|
error: string | null;
|
|
210
367
|
received_at: string | null;
|
|
@@ -217,6 +374,70 @@ export interface PaymentsWebhookEvent {
|
|
|
217
374
|
raw_body?: string | null;
|
|
218
375
|
provider_event_ts?: string | null;
|
|
219
376
|
}
|
|
377
|
+
/** The outcome of a provider re-sync / Restore Purchases (payments.md §7d). */
|
|
378
|
+
export interface PaymentsSyncOutcome {
|
|
379
|
+
provider: string;
|
|
380
|
+
synced: number;
|
|
381
|
+
changed: number;
|
|
382
|
+
unchanged: number;
|
|
383
|
+
errors: string[];
|
|
384
|
+
changes: Array<{
|
|
385
|
+
provider_sub_id: string;
|
|
386
|
+
status: string;
|
|
387
|
+
tier: string | null;
|
|
388
|
+
until: string | null;
|
|
389
|
+
}>;
|
|
390
|
+
dry_run?: boolean;
|
|
391
|
+
}
|
|
392
|
+
/** A lifecycle simulation run (payments.md §7d; mock/dev tenants only). */
|
|
393
|
+
export interface PaymentsSimulationResult {
|
|
394
|
+
scenario: string;
|
|
395
|
+
run_id: string;
|
|
396
|
+
user_id: string;
|
|
397
|
+
tier: string;
|
|
398
|
+
tenant_kind: 'standard' | 'dev' | 'unknown';
|
|
399
|
+
note: string;
|
|
400
|
+
steps: Array<{
|
|
401
|
+
event_type: string;
|
|
402
|
+
status: number;
|
|
403
|
+
outcome: string;
|
|
404
|
+
}>;
|
|
405
|
+
oracle: {
|
|
406
|
+
expected: Record<string, 'premium' | 'free'>;
|
|
407
|
+
observed: Record<string, {
|
|
408
|
+
tier: string;
|
|
409
|
+
until: string | null;
|
|
410
|
+
}>;
|
|
411
|
+
pass: boolean;
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
/** The ONE complete entitlement read (GET /v1/payments/entitlements; payments.md
|
|
415
|
+
* §3a). `until` is the winning subscription's current_period_end (+ the
|
|
416
|
+
* configured grace window when it is past_due); null on the free baseline. */
|
|
417
|
+
export interface PaymentsEntitlementView {
|
|
418
|
+
user_id: string;
|
|
419
|
+
tier: string;
|
|
420
|
+
entitlements: string[];
|
|
421
|
+
quotas: Record<string, number>;
|
|
422
|
+
source_sub_id: string | null;
|
|
423
|
+
since: string | null;
|
|
424
|
+
until: string | null;
|
|
425
|
+
as_of: string;
|
|
426
|
+
environment: 'production' | 'sandbox';
|
|
427
|
+
/** present only when `?quota=` was asked for */
|
|
428
|
+
quota?: {
|
|
429
|
+
name: string;
|
|
430
|
+
value: number | null;
|
|
431
|
+
};
|
|
432
|
+
/** present only when `?credit_type=` was asked for */
|
|
433
|
+
credits?: {
|
|
434
|
+
credit_type: string;
|
|
435
|
+
balance: number;
|
|
436
|
+
held: number;
|
|
437
|
+
available: number;
|
|
438
|
+
period_end: string | null;
|
|
439
|
+
};
|
|
440
|
+
}
|
|
220
441
|
export interface FileObject {
|
|
221
442
|
object_id: string;
|
|
222
443
|
filename: string;
|
|
@@ -225,6 +446,26 @@ export interface FileObject {
|
|
|
225
446
|
status: 'pending' | 'available' | 'deleted';
|
|
226
447
|
created_at: string;
|
|
227
448
|
}
|
|
449
|
+
/** A live shared link as listed by GET /v1/files/{id}/shared-links (files.md
|
|
450
|
+
* §6). `downloads` is the burn-on-read counter; `max_downloads` null =
|
|
451
|
+
* unlimited (1 = a one-time link). A link that hit its cap, expired, or was
|
|
452
|
+
* revoked no longer lists. */
|
|
453
|
+
export interface FileSharedLink {
|
|
454
|
+
link_id: string;
|
|
455
|
+
created_at: string;
|
|
456
|
+
expires_at: string;
|
|
457
|
+
downloads: number;
|
|
458
|
+
max_downloads: number | null;
|
|
459
|
+
}
|
|
460
|
+
/** Options for POST /v1/files/{id}/shared-links. `expires_at` (ISO 8601) takes
|
|
461
|
+
* precedence over `ttl_seconds`; both are clamped to the tenant's
|
|
462
|
+
* `sharedLinks.maxTtl`. `max_downloads` ≥ 1 caps successful public
|
|
463
|
+
* resolutions (1 = one-time link); omit for unlimited. */
|
|
464
|
+
export interface CreateSharedLinkOptions {
|
|
465
|
+
ttl_seconds?: number;
|
|
466
|
+
expires_at?: string;
|
|
467
|
+
max_downloads?: number | null;
|
|
468
|
+
}
|
|
228
469
|
/** One recognized OCR text block (files.md §1.1). bbox is [x, y, w, h] in the
|
|
229
470
|
* provider's unit space; page is 1-based. confidence is 0..1 normalized per
|
|
230
471
|
* provider (Textract native 0..100 divided by 100; mock pins 0.95); absent
|
|
@@ -351,6 +592,12 @@ export interface AiGeneration {
|
|
|
351
592
|
usage: AiUsage;
|
|
352
593
|
finish: string;
|
|
353
594
|
tool_calls?: AiToolCall[];
|
|
595
|
+
/** the parsed JSON output — present when the request (or its template)
|
|
596
|
+
* carried a response schema; guaranteed to satisfy it (a 200 never violates
|
|
597
|
+
* the schema — final-invalid is a 422 output_schema_mismatch). */
|
|
598
|
+
output?: unknown;
|
|
599
|
+
/** true when the output only validated after the single repair pass. */
|
|
600
|
+
repaired?: boolean;
|
|
354
601
|
cached: boolean;
|
|
355
602
|
}
|
|
356
603
|
/** A streamed generation handle: open the realtime channel for token frames. */
|
|
@@ -415,6 +662,57 @@ export interface AiEmbedResult {
|
|
|
415
662
|
usage: AiUsage;
|
|
416
663
|
generation_id: string;
|
|
417
664
|
}
|
|
665
|
+
/** The per-request knobs every verdict route shares (POST /v1/ai/classify and
|
|
666
|
+
* /v1/ai/judge): a stored template may author the whole prompt (rendered with
|
|
667
|
+
* the verdict vars — `{{input}}`, `{{labels}}`, `{{rubric}}`, `{{examples}}` /
|
|
668
|
+
* `{{candidate}}`, `{{candidates}}`, `{{criteria}}`, `{{scale_min}}`,
|
|
669
|
+
* `{{scale_max}}` — plus your own `vars`); provider/model override the tenant
|
|
670
|
+
* defaults; `max_tokens` defaults to min(config maxTokens, 512) and
|
|
671
|
+
* `temperature` to 0. Verdicts are sync-only (no stream / job mode). */
|
|
672
|
+
export interface AiVerdictOptions {
|
|
673
|
+
template?: string;
|
|
674
|
+
template_version?: number;
|
|
675
|
+
vars?: Record<string, unknown>;
|
|
676
|
+
provider?: string;
|
|
677
|
+
model?: string;
|
|
678
|
+
max_tokens?: number;
|
|
679
|
+
temperature?: number;
|
|
680
|
+
user_id?: string;
|
|
681
|
+
}
|
|
682
|
+
/** A classify verdict (POST /v1/ai/classify). `label` (single) or `labels`
|
|
683
|
+
* (multi:true — every applicable label, possibly empty) is guaranteed to be
|
|
684
|
+
* drawn from the request's `labels`: the allowed set is forced through the
|
|
685
|
+
* structured-output schema, so a 200 can never carry an off-list label. */
|
|
686
|
+
export interface AiClassifyResult {
|
|
687
|
+
generation_id: string;
|
|
688
|
+
label?: string;
|
|
689
|
+
labels?: string[];
|
|
690
|
+
/** 0..1 */
|
|
691
|
+
confidence: number;
|
|
692
|
+
rationale?: string;
|
|
693
|
+
usage: AiUsage;
|
|
694
|
+
/** true when the verdict only validated after the one repair pass. */
|
|
695
|
+
repaired?: boolean;
|
|
696
|
+
cached: boolean;
|
|
697
|
+
}
|
|
698
|
+
/** A judge verdict (POST /v1/ai/judge). One `candidate` → `score` (an integer
|
|
699
|
+
* inside `scale`, default 0..10) + `verdict: 'pass' | 'fail'`; several
|
|
700
|
+
* `candidates` → `scores` (one per candidate, in order) + `best` (the index of
|
|
701
|
+
* the top score) + `verdict: 'tie'` when the top score is shared. Sending
|
|
702
|
+
* `candidates` ALWAYS yields `scores` + `best` — a one-element list keeps the
|
|
703
|
+
* richer `score`/`pass|fail` fields too, so the shape never flips out from
|
|
704
|
+
* under a variable-length array. */
|
|
705
|
+
export interface AiJudgeResult {
|
|
706
|
+
generation_id: string;
|
|
707
|
+
score?: number;
|
|
708
|
+
scores?: number[];
|
|
709
|
+
verdict?: 'pass' | 'fail' | 'tie';
|
|
710
|
+
best?: number;
|
|
711
|
+
rationale?: string;
|
|
712
|
+
usage: AiUsage;
|
|
713
|
+
repaired?: boolean;
|
|
714
|
+
cached: boolean;
|
|
715
|
+
}
|
|
418
716
|
/** Per-user token rollups (GET /v1/ai/usage). */
|
|
419
717
|
export interface AiUsageReport {
|
|
420
718
|
input_tokens: number;
|
|
@@ -817,6 +1115,35 @@ type DisabledFeatures<S extends VxilSchemaShape> = {
|
|
|
817
1115
|
export type EnabledVxil<S extends VxilSchemaShape> = Omit<Vxil<S>, DisabledFeatures<S>> & {
|
|
818
1116
|
[P in DisabledFeatures<S>]: DisabledFeature<FeatureMap[P] & string>;
|
|
819
1117
|
};
|
|
1118
|
+
/** One config-declared per-record ACTION (cms.md §17): a button on a record row
|
|
1119
|
+
* that invokes the deployed tenant function `fn` ONCE with `{ collection,
|
|
1120
|
+
* item_id, action, actor, item }`. Exactly one human-initiated step — no
|
|
1121
|
+
* conditions, no chaining, no scheduling. ≤8 per collection. */
|
|
1122
|
+
export interface CmsActionDef {
|
|
1123
|
+
/** /^[a-z][a-z0-9_]{0,31}$/ — the URL key of `items.runAction` */
|
|
1124
|
+
key: string;
|
|
1125
|
+
/** the button label (1–64 chars) */
|
|
1126
|
+
label: string;
|
|
1127
|
+
/** the deployed function name (/^[a-z][a-z0-9-]{0,47}$/) */
|
|
1128
|
+
fn: string;
|
|
1129
|
+
}
|
|
1130
|
+
/** One live item referencing another through a relation field (cms.md §11.1). */
|
|
1131
|
+
export interface CmsBacklink {
|
|
1132
|
+
collection: string;
|
|
1133
|
+
field: string;
|
|
1134
|
+
item_id: string;
|
|
1135
|
+
status: string;
|
|
1136
|
+
}
|
|
1137
|
+
/** The bounded reverse read (`items.backlinks`): `count` = rows in THIS page
|
|
1138
|
+
* (≤ `limit`), never a total; `has_more` = the cap was hit. */
|
|
1139
|
+
export interface CmsBacklinksPage {
|
|
1140
|
+
collection: string;
|
|
1141
|
+
item_id: string;
|
|
1142
|
+
backlinks: CmsBacklink[];
|
|
1143
|
+
count: number;
|
|
1144
|
+
has_more: boolean;
|
|
1145
|
+
limit: number;
|
|
1146
|
+
}
|
|
820
1147
|
/** A write guard (cms.md §10): "after this write, at most `max` live items
|
|
821
1148
|
* match `filter`". Requires `lock` — an unlocked guard is racy by construction. */
|
|
822
1149
|
export interface CmsGuard {
|
|
@@ -1002,6 +1329,12 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1002
1329
|
/** The end-user session token threaded as `X-Vxil-End-User` when set (end-user
|
|
1003
1330
|
* mode). Undefined ⇒ no header ⇒ server-caller mode (unchanged). */
|
|
1004
1331
|
private readonly endUserToken;
|
|
1332
|
+
/** The ONE path every request takes: retry + timeout + hooks around
|
|
1333
|
+
* `fetchImpl`. With none of the three configured it is a single fetch. */
|
|
1334
|
+
private readonly transport;
|
|
1335
|
+
private readonly retryOpts;
|
|
1336
|
+
private readonly timeoutMs;
|
|
1337
|
+
private readonly hooks;
|
|
1005
1338
|
constructor(opts: VxilOptions);
|
|
1006
1339
|
/** The header bag every request layers on top of `authorization`: the
|
|
1007
1340
|
* `X-Vxil-End-User` session token in end-user mode, nothing in server mode.
|
|
@@ -1010,8 +1343,8 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1010
1343
|
/** Return a client that sends `X-Vxil-End-User: <token>` on every request —
|
|
1011
1344
|
* a per-call/scoped override of end-user mode over an otherwise server-mode
|
|
1012
1345
|
* client, mirroring how the edge threads the verified principal. The base
|
|
1013
|
-
* URL, api key, fetch impl
|
|
1014
|
-
* end-user token is (re)set. Pass a falsy token to get back a server-mode
|
|
1346
|
+
* URL, api key, fetch impl, version pins and the retry/timeout/hooks options
|
|
1347
|
+
* are inherited unchanged; only the end-user token is (re)set. Pass a falsy token to get back a server-mode
|
|
1015
1348
|
* client (drops the header). See docs/end-user-principals-design.md §4.1. */
|
|
1016
1349
|
asEndUser(endUserToken: string | undefined): Vxil<S>;
|
|
1017
1350
|
/** Build the versioned request path — the ONE place a wire path is finalized.
|
|
@@ -1084,15 +1417,72 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1084
1417
|
user_id: string;
|
|
1085
1418
|
template: "magic-link" | "welcome" | "transactional";
|
|
1086
1419
|
data: Record<string, unknown>;
|
|
1420
|
+
/** Explicit wins; otherwise the recipient's stored `locale` attribute
|
|
1421
|
+
* (set it via `users.upsert({ attributes: { locale } })`), then
|
|
1422
|
+
* `config.defaultLocale`. */
|
|
1087
1423
|
locale?: string;
|
|
1088
1424
|
/** 'inbox'/'both' require config inboxEnabled */
|
|
1089
1425
|
channel?: "email" | "inbox" | "both";
|
|
1426
|
+
/** hold the send until this ISO instant (≤ 30 d out) */
|
|
1427
|
+
send_at?: string;
|
|
1428
|
+
/** …or this many seconds from now (≤ 30 d). At most one of the two. */
|
|
1429
|
+
delay_seconds?: number;
|
|
1090
1430
|
}, opts?: {
|
|
1091
1431
|
idempotencyKey?: string;
|
|
1432
|
+
}) => Promise<NotificationSendResult>;
|
|
1433
|
+
/** Up to 100 sends in one call. Each item is INDEPENDENTLY atomic (recorded
|
|
1434
|
+
* + enqueued, or neither) and `results` is index-aligned with `items`. */
|
|
1435
|
+
sendBatch: (items: Array<{
|
|
1436
|
+
user_id: string;
|
|
1437
|
+
template: "magic-link" | "welcome" | "transactional";
|
|
1438
|
+
data: Record<string, unknown>;
|
|
1439
|
+
locale?: string;
|
|
1440
|
+
channel?: "email" | "inbox" | "both";
|
|
1441
|
+
send_at?: string;
|
|
1442
|
+
delay_seconds?: number;
|
|
1443
|
+
/** per-item 24 h idempotency key (the header equivalent for one item) */
|
|
1444
|
+
idempotency_key?: string;
|
|
1445
|
+
}>) => Promise<{
|
|
1446
|
+
results: Array<{
|
|
1447
|
+
index: number;
|
|
1448
|
+
delivery_id?: string;
|
|
1449
|
+
inbox_message_id?: string;
|
|
1450
|
+
status?: string;
|
|
1451
|
+
scheduled_for?: string;
|
|
1452
|
+
error?: {
|
|
1453
|
+
code: string;
|
|
1454
|
+
message: string;
|
|
1455
|
+
hint?: string;
|
|
1456
|
+
};
|
|
1457
|
+
}>;
|
|
1458
|
+
count: number;
|
|
1459
|
+
accepted: number;
|
|
1460
|
+
failed: number;
|
|
1461
|
+
warnings?: NotificationWarning[];
|
|
1462
|
+
}>;
|
|
1463
|
+
/** Render a template exactly as a send would, WITHOUT sending. `missing`
|
|
1464
|
+
* lists the required data keys you left out. Needs `notifications:read`. */
|
|
1465
|
+
preview: (templateId: string, input?: {
|
|
1466
|
+
data?: Record<string, unknown>;
|
|
1467
|
+
locale?: string;
|
|
1092
1468
|
}) => Promise<{
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1469
|
+
template_id: string;
|
|
1470
|
+
locale: string;
|
|
1471
|
+
overridden: boolean;
|
|
1472
|
+
subject: string;
|
|
1473
|
+
html: string;
|
|
1474
|
+
text: string;
|
|
1475
|
+
missing: string[];
|
|
1476
|
+
}>;
|
|
1477
|
+
/** Read-only deliverability probe: is `config.fromEmail`'s domain verified
|
|
1478
|
+
* at the provider? FAIL-SOFT — `verified: 'unknown'` whenever it cannot be
|
|
1479
|
+
* determined (mock provider, no key, provider unreachable). */
|
|
1480
|
+
senderDomain: () => Promise<{
|
|
1481
|
+
domain: string | null;
|
|
1482
|
+
verified: boolean | "unknown";
|
|
1483
|
+
provider: string;
|
|
1484
|
+
checked_at: string;
|
|
1485
|
+
reason?: string;
|
|
1096
1486
|
}>;
|
|
1097
1487
|
inbox: {
|
|
1098
1488
|
list: (q: {
|
|
@@ -1120,6 +1510,8 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1120
1510
|
user_id?: string;
|
|
1121
1511
|
status?: string;
|
|
1122
1512
|
limit?: number;
|
|
1513
|
+
/** A7: only deliveries that reached this engagement state */
|
|
1514
|
+
engagement?: "delivered" | "opened" | "clicked";
|
|
1123
1515
|
}) => Promise<Delivery[]>;
|
|
1124
1516
|
suppressions: {
|
|
1125
1517
|
list: () => Promise<Array<{
|
|
@@ -1161,17 +1553,36 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1161
1553
|
}) => Promise<{
|
|
1162
1554
|
campaign_id: string;
|
|
1163
1555
|
status: string;
|
|
1556
|
+
schedule_id: string | null;
|
|
1164
1557
|
}>;
|
|
1165
|
-
list: () => Promise<
|
|
1558
|
+
list: () => Promise<Campaign[]>;
|
|
1559
|
+
/** Stop a scheduled campaign from firing (the jobs cron is torn down). */
|
|
1560
|
+
pause: (campaignId: string) => Promise<CampaignState>;
|
|
1561
|
+
/** Re-register the cron (back to `scheduled`, or `draft` with no cron). */
|
|
1562
|
+
resume: (campaignId: string) => Promise<CampaignState>;
|
|
1563
|
+
/** Terminal stop — the cron is removed and the campaign cannot resume. */
|
|
1564
|
+
cancel: (campaignId: string) => Promise<CampaignState>;
|
|
1565
|
+
/** Soft-delete: hidden from the list, cron removed; the dedupe ledger
|
|
1566
|
+
* survives so a re-created campaign cannot re-send to a served user. */
|
|
1567
|
+
remove: (campaignId: string) => Promise<CampaignState & {
|
|
1568
|
+
deleted?: boolean;
|
|
1569
|
+
}>;
|
|
1570
|
+
/** Push ONE audience page (≤ 1000 rows) into a campaign run — the shape a
|
|
1571
|
+
* tenant audience callback uses. Omit `audience` for a campaign whose
|
|
1572
|
+
* `audience_ref` is the built-in `users:all` selector. */
|
|
1573
|
+
run: (campaignId: string, audience?: Array<{
|
|
1574
|
+
end_user_id: string;
|
|
1575
|
+
locale?: string | null;
|
|
1576
|
+
}>) => Promise<{
|
|
1166
1577
|
campaign_id: string;
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1578
|
+
audience_source: "supplied" | "builtin" | "external";
|
|
1579
|
+
audience_size: number;
|
|
1580
|
+
sent: number;
|
|
1581
|
+
deferred: number;
|
|
1582
|
+
skipped_freq_cap: number;
|
|
1583
|
+
skipped_no_email: number;
|
|
1584
|
+
already_sent: number;
|
|
1585
|
+
}>;
|
|
1175
1586
|
};
|
|
1176
1587
|
};
|
|
1177
1588
|
readonly config: {
|
|
@@ -1249,6 +1660,13 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1249
1660
|
}>;
|
|
1250
1661
|
}>;
|
|
1251
1662
|
};
|
|
1663
|
+
/** Current-month usage: requests used vs the plan's included quota, plus
|
|
1664
|
+
* month-to-date per-feature metered detail. Read-only (needs `usage:read`
|
|
1665
|
+
* or `features:read`). Agents: call this before a bulk run to self-check
|
|
1666
|
+
* remaining quota. */
|
|
1667
|
+
readonly usage: {
|
|
1668
|
+
current: () => Promise<UsageCurrent>;
|
|
1669
|
+
};
|
|
1252
1670
|
readonly jobs: {
|
|
1253
1671
|
/** Enqueue a one-off job; Vxil POSTs a signed callback to target_url with
|
|
1254
1672
|
* retries. deliver_after (ISO) / delay_seconds (≤ 30 d, at most one of the
|
|
@@ -1414,6 +1832,16 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1414
1832
|
delete: (ruleId: string) => Promise<void>;
|
|
1415
1833
|
};
|
|
1416
1834
|
};
|
|
1835
|
+
/** vxil-auth. SCOPES (docs/features/auth.md §7.6): every flow here that
|
|
1836
|
+
* obtains, renews, verifies or ends the caller's OWN session (signUp/signIn,
|
|
1837
|
+
* magicLink, otp, anonymous, stepUp, oauth, sessions.refresh/revoke/verify,
|
|
1838
|
+
* password reset) accepts the narrow `auth:signin` — the ONLY auth scope a
|
|
1839
|
+
* key baked into a browser/mobile bundle should carry. `sessions.list` needs
|
|
1840
|
+
* `auth:read`; `sessions.revokeById` and `users.erase` need `auth:write`
|
|
1841
|
+
* (administrative — server keys only). In end-user mode (`endUserToken` /
|
|
1842
|
+
* `asEndUser`) the administrative calls bind to the signed-in user: own
|
|
1843
|
+
* sessions only, own devices only, erase self only. `auth:write` still
|
|
1844
|
+
* satisfies every call. */
|
|
1417
1845
|
readonly auth: {
|
|
1418
1846
|
signUp: (input: {
|
|
1419
1847
|
email: string;
|
|
@@ -1446,9 +1874,18 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1446
1874
|
* Server-side guessing budget (config otp.maxAttempts), single active code,
|
|
1447
1875
|
* resend cooldown (429 otp_rate_limited). */
|
|
1448
1876
|
otp: {
|
|
1877
|
+
/** `test_code` is present ONLY when the address matches auth config
|
|
1878
|
+
* `otp.testRecipients` (store-review / CI accounts): no mail is sent and
|
|
1879
|
+
* the code comes back instead. `captcha_token` is required when the
|
|
1880
|
+
* tenant configured `security.captchaSecretRef`. */
|
|
1449
1881
|
request: (input: {
|
|
1450
1882
|
email: string;
|
|
1451
|
-
|
|
1883
|
+
locale?: string;
|
|
1884
|
+
captcha_token?: string;
|
|
1885
|
+
}) => Promise<{
|
|
1886
|
+
sent: true;
|
|
1887
|
+
test_code?: string;
|
|
1888
|
+
}>;
|
|
1452
1889
|
verify: (input: {
|
|
1453
1890
|
email: string;
|
|
1454
1891
|
code: string;
|
|
@@ -1470,7 +1907,16 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1470
1907
|
request: (input: {
|
|
1471
1908
|
token: string;
|
|
1472
1909
|
email: string;
|
|
1473
|
-
|
|
1910
|
+
locale?: string;
|
|
1911
|
+
}) => Promise<{
|
|
1912
|
+
sent: true;
|
|
1913
|
+
test_code?: string;
|
|
1914
|
+
}>;
|
|
1915
|
+
/** On success the guest keeps its user id (`user_id` unchanged).
|
|
1916
|
+
* If the claimed email ALREADY has an account, the guest is MERGED
|
|
1917
|
+
* into it: `user_id` is the existing account, `merged: true`, and a
|
|
1918
|
+
* fresh `session.token` (same session, re-signed for the merged
|
|
1919
|
+
* identity — swap it client-side; other guest sessions are revoked). */
|
|
1474
1920
|
verify: (input: {
|
|
1475
1921
|
token: string;
|
|
1476
1922
|
email: string;
|
|
@@ -1479,6 +1925,11 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1479
1925
|
user_id: string;
|
|
1480
1926
|
email: string;
|
|
1481
1927
|
verified: boolean;
|
|
1928
|
+
merged?: true;
|
|
1929
|
+
session?: {
|
|
1930
|
+
token: string;
|
|
1931
|
+
expires_at: string;
|
|
1932
|
+
};
|
|
1482
1933
|
}>;
|
|
1483
1934
|
};
|
|
1484
1935
|
};
|
|
@@ -1488,7 +1939,11 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1488
1939
|
stepUp: {
|
|
1489
1940
|
request: (input: {
|
|
1490
1941
|
token: string;
|
|
1491
|
-
|
|
1942
|
+
locale?: string;
|
|
1943
|
+
}) => Promise<{
|
|
1944
|
+
sent: true;
|
|
1945
|
+
test_code?: string;
|
|
1946
|
+
}>;
|
|
1492
1947
|
verify: (input: {
|
|
1493
1948
|
token: string;
|
|
1494
1949
|
code: string;
|
|
@@ -1506,11 +1961,22 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1506
1961
|
* (email → tombstone, password/name/avatar cleared) and revoke every
|
|
1507
1962
|
* live session. Idempotent — a second call on an already-erased user is a
|
|
1508
1963
|
* no-op. Meant to be called from a "delete my account" server route or
|
|
1509
|
-
* vxil function (which declares `auth:write`).
|
|
1964
|
+
* vxil function (which declares `auth:write`). In END-USER mode the call
|
|
1965
|
+
* is SELF-only: `userId` must be the signed-in user, any other id throws
|
|
1966
|
+
* 403 `server_only` (a thin client can never erase someone else). */
|
|
1510
1967
|
erase: (userId: string) => Promise<{
|
|
1511
1968
|
user_id: string;
|
|
1512
1969
|
erased: boolean;
|
|
1513
1970
|
}>;
|
|
1971
|
+
/** END-USER MODE ONLY (`endUserToken` / `asEndUser`): the signed-in user
|
|
1972
|
+
* deep-merges a bounded `attributes` object into its OWN shared identity
|
|
1973
|
+
* row (null deletes a key; ≤8 KB, ≤64 top-level keys, depth ≤8). Profile
|
|
1974
|
+
* fields are not patchable here. In server mode the call throws 422
|
|
1975
|
+
* `end_user_mode_required` — use `users.patch(id, …)` instead. */
|
|
1976
|
+
patchMe: (attributes: Record<string, unknown>) => Promise<{
|
|
1977
|
+
user_id: string;
|
|
1978
|
+
attributes: Record<string, unknown>;
|
|
1979
|
+
}>;
|
|
1514
1980
|
};
|
|
1515
1981
|
sessions: {
|
|
1516
1982
|
verify: (token: string) => Promise<{
|
|
@@ -1528,11 +1994,26 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1528
1994
|
session: AuthSession;
|
|
1529
1995
|
}>;
|
|
1530
1996
|
revoke: (token: string) => Promise<void>;
|
|
1997
|
+
/** "Sign out everywhere": revoke EVERY live session of a user in one call
|
|
1998
|
+
* (one statement, one batched edge-cache write; each session's
|
|
1999
|
+
* revoked_reason = 'revoke_all'). SERVER mode names the user (`userId`,
|
|
2000
|
+
* scope `auth:write`); in END-USER mode the signed-in user's own sessions
|
|
2001
|
+
* go and `userId` is ignored (scope `auth:signin` suffices). Idempotent:
|
|
2002
|
+
* a user with no live sessions returns `revoked: 0`. */
|
|
2003
|
+
revokeAll: (userId?: string) => Promise<{
|
|
2004
|
+
user_id: string;
|
|
2005
|
+
revoked: number;
|
|
2006
|
+
session_ids: string[];
|
|
2007
|
+
}>;
|
|
1531
2008
|
/** Force-revoke a SPECIFIC session by its `session_id` (from `list`) — the
|
|
1532
2009
|
* server-forced device-lockout path beyond the client-cooperative
|
|
1533
|
-
* by-token `revoke`. Throws 404 when the id is unknown or already revoked
|
|
2010
|
+
* by-token `revoke`. Throws 404 when the id is unknown or already revoked
|
|
2011
|
+
* — or, in end-user mode, when it belongs to another user (a signed-in
|
|
2012
|
+
* user can kick only their OWN devices). Scope `auth:write`. */
|
|
1534
2013
|
revokeById: (sessionId: string) => Promise<void>;
|
|
1535
|
-
/** List a user's active sessions (the account "signed-in devices" surface).
|
|
2014
|
+
/** List a user's active sessions (the account "signed-in devices" surface).
|
|
2015
|
+
* Scope `auth:read`. In end-user mode the list is bound to the signed-in
|
|
2016
|
+
* user regardless of `userId` (the verified principal wins). */
|
|
1536
2017
|
list: (userId: string) => Promise<Array<{
|
|
1537
2018
|
session_id: string;
|
|
1538
2019
|
created_at: string;
|
|
@@ -1551,21 +2032,48 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1551
2032
|
password: string;
|
|
1552
2033
|
}) => Promise<void>;
|
|
1553
2034
|
};
|
|
2035
|
+
/** Email verification (the flow behind auth config `emailVerification.required`,
|
|
2036
|
+
* which makes password sign-in answer 403 `email_not_verified` until the
|
|
2037
|
+
* address is confirmed). `request` always resolves (anti-enumeration —
|
|
2038
|
+
* a link is mailed only to an existing, unverified user; `redirect_url`
|
|
2039
|
+
* is your page that reads `?token=` and calls `confirm`). `confirm` is
|
|
2040
|
+
* single-use and expires after 24h. */
|
|
2041
|
+
emailVerification: {
|
|
2042
|
+
request: (input: {
|
|
2043
|
+
email: string;
|
|
2044
|
+
redirect_url: string;
|
|
2045
|
+
locale?: string;
|
|
2046
|
+
captcha_token?: string;
|
|
2047
|
+
}) => Promise<void>;
|
|
2048
|
+
confirm: (token: string) => Promise<{
|
|
2049
|
+
user_id: string;
|
|
2050
|
+
verified: true;
|
|
2051
|
+
}>;
|
|
2052
|
+
};
|
|
1554
2053
|
/** Social sign-in. The web `start`/`callback` flows are browser redirects
|
|
1555
|
-
* (not JSON calls)
|
|
2054
|
+
* (not JSON calls): send the browser to
|
|
2055
|
+
* `GET /v1/auth/oauth/{provider}/start?redirect_uri=…` (server-side, with
|
|
2056
|
+
* your key) and hand the returned `code`+`state` to `…/callback`; `native`
|
|
2057
|
+
* is the mobile / broker token-exchange the SDK wraps. `oidc` is the
|
|
2058
|
+
* tenant's generic OIDC / SSO issuer (auth config `providers.oidc` —
|
|
2059
|
+
* Okta / Entra / Auth0 / any OpenID Connect IdP, or a SAML broker that
|
|
2060
|
+
* speaks OIDC); it rides the same three routes. */
|
|
1556
2061
|
oauth: {
|
|
1557
2062
|
/** Native social sign-in: exchange a provider `id_token`/`access_token`
|
|
1558
2063
|
* for a vxil session (`linked` marks whether the user was created or
|
|
1559
2064
|
* matched to an existing identity). */
|
|
1560
|
-
native: (provider: "google" | "apple" | "github" | "facebook" | "mock", input: {
|
|
2065
|
+
native: (provider: "google" | "apple" | "github" | "facebook" | "mock" | "oidc", input: {
|
|
1561
2066
|
id_token?: string;
|
|
1562
2067
|
access_token?: string;
|
|
1563
2068
|
nonce?: string;
|
|
2069
|
+
anonymous_token?: string;
|
|
1564
2070
|
}) => Promise<{
|
|
1565
2071
|
user_id: string;
|
|
1566
2072
|
session: AuthSession;
|
|
1567
2073
|
verified: boolean;
|
|
1568
|
-
linked: "created" | "existing";
|
|
2074
|
+
linked: "created" | "existing" | "promoted" | "merged";
|
|
2075
|
+
/** sessions taken over by auth config session.maxConcurrent (present once opted in) */
|
|
2076
|
+
took_over?: string[];
|
|
1569
2077
|
}>;
|
|
1570
2078
|
};
|
|
1571
2079
|
};
|
|
@@ -1573,8 +2081,10 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1573
2081
|
createPolicy: (input: {
|
|
1574
2082
|
name: string;
|
|
1575
2083
|
key_template: string;
|
|
1576
|
-
|
|
1577
|
-
|
|
2084
|
+
/** omitted ⇒ seeded from the tenant's rate-limits config `defaults` (F8-54) */
|
|
2085
|
+
limit?: number;
|
|
2086
|
+
/** omitted ⇒ seeded from the tenant's rate-limits config `defaults` (F8-54) */
|
|
2087
|
+
window_seconds?: number;
|
|
1578
2088
|
behavior?: "block" | "shape";
|
|
1579
2089
|
}) => Promise<RateLimitPolicy>;
|
|
1580
2090
|
listPolicies: () => Promise<RateLimitPolicy[]>;
|
|
@@ -1692,14 +2202,31 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1692
2202
|
* scalar-valued types only. Concurrent duplicates → 409 unique_violation. */
|
|
1693
2203
|
unique?: boolean;
|
|
1694
2204
|
/** relation fields only: what a delete of the referenced item does to
|
|
1695
|
-
* this one (bounded fan-out, cms.md §11)
|
|
1696
|
-
|
|
2205
|
+
* this one — cascade / set_null (bounded fan-out, cms.md §11) or
|
|
2206
|
+
* `restrict` (§11.1: the delete is refused with 409 `referenced`
|
|
2207
|
+
* while a live reference exists). */
|
|
2208
|
+
on_delete?: "cascade" | "set_null" | "restrict";
|
|
2209
|
+
/** FIELD-LEVEL read security (cms.md §18): the end-user ORG ROLE slugs
|
|
2210
|
+
* allowed to READ this field. Omitted/`[]` = ungated. A non-empty list
|
|
2211
|
+
* is FAIL-SAFE — in verified end-user mode the field is OMITTED from
|
|
2212
|
+
* every read (get / list / query / `$expand` / the write-response echo)
|
|
2213
|
+
* unless the session's verified roles intersect it, it is UNQUERYABLE
|
|
2214
|
+
* (filter/sort/group-by on it is a 422), and it is NEVER served on the
|
|
2215
|
+
* anonymous public lane. A SERVER caller (an API key with no end-user
|
|
2216
|
+
* session) still sees every field. Writes are unaffected. ≤16 entries,
|
|
2217
|
+
* each `^[a-z0-9][a-z0-9_-]{0,31}$` (the `orgs` role alphabet). */
|
|
2218
|
+
read_roles?: string[];
|
|
1697
2219
|
}>;
|
|
2220
|
+
/** Per-record action buttons (cms.md §17): `[{ key, label, fn }]` —
|
|
2221
|
+
* exactly ONE human-initiated step each; `fn` names a deployed tenant
|
|
2222
|
+
* function invoked by `items.runAction`. ≤8 per collection. */
|
|
2223
|
+
actions?: CmsActionDef[];
|
|
1698
2224
|
}) => Promise<{
|
|
1699
2225
|
collection: string;
|
|
1700
2226
|
fields: number;
|
|
1701
2227
|
owner_field?: string;
|
|
1702
2228
|
public?: boolean;
|
|
2229
|
+
actions?: CmsActionDef[];
|
|
1703
2230
|
}>;
|
|
1704
2231
|
list: () => Promise<Array<{
|
|
1705
2232
|
collection: string;
|
|
@@ -1708,6 +2235,14 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1708
2235
|
owner_field?: string | null;
|
|
1709
2236
|
}>>;
|
|
1710
2237
|
addField: (collection: string, field: Record<string, unknown>) => Promise<void>;
|
|
2238
|
+
/** Set (or clear, with `null`/`[]`) a field's READ-ROLE gate (cms.md §18) —
|
|
2239
|
+
* the same-type in-place alter on the fields route. Re-sends the field's
|
|
2240
|
+
* `type` (required by the alter path); every OTHER attribute the field
|
|
2241
|
+
* carries is re-sent from `rest`, because the alter overwrites the whole
|
|
2242
|
+
* definition. In verified end-user mode a gated field is omitted from every
|
|
2243
|
+
* read unless the session's verified roles intersect `roles`; server-caller
|
|
2244
|
+
* reads and ALL writes are unaffected. */
|
|
2245
|
+
setFieldReadRoles: (collection: string, field: string, type: "string" | "text" | "int" | "float" | "bool" | "datetime" | "json" | "relation" | "file", roles: string[] | null, rest?: Record<string, unknown>) => Promise<void>;
|
|
1711
2246
|
/** Set (or clear, with `null`) the collection's end-user owner-scope flag
|
|
1712
2247
|
* (design §5.1). Names an existing `string` field that holds the owner id. */
|
|
1713
2248
|
setOwnerField: (collection: string, ownerField: string | null) => Promise<void>;
|
|
@@ -1717,6 +2252,11 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1717
2252
|
* the owner_field are never exposed. `false` closes the lane (and purges the
|
|
1718
2253
|
* edge cache). Read the public side with `cmsPublicUrl` / `listCmsPublic`. */
|
|
1719
2254
|
setPublic: (collection: string, isPublic: boolean) => Promise<void>;
|
|
2255
|
+
/** Replace the collection's per-record ACTION list (cms.md §17) — the
|
|
2256
|
+
* `{ actions }` fields-route meta-op; `[]` clears. Each action is ONE
|
|
2257
|
+
* human-initiated step: the dashboard renders it as a button per record,
|
|
2258
|
+
* and `items.runAction` invokes its deployed function. */
|
|
2259
|
+
setActions: (collection: string, actions: CmsActionDef[]) => Promise<void>;
|
|
1720
2260
|
};
|
|
1721
2261
|
items: {
|
|
1722
2262
|
/** `lock` serializes same-key writers (per-tenant advisory lock); `guard`
|
|
@@ -1774,6 +2314,27 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1774
2314
|
set_null: number;
|
|
1775
2315
|
}>;
|
|
1776
2316
|
publish: (collection: string, itemId: string) => Promise<Record<string, unknown>>;
|
|
2317
|
+
/** P1-12 (cms.md §11.1): the BOUNDED reverse read — which live items
|
|
2318
|
+
* reference this one, through which relation field. Owner-scoped in
|
|
2319
|
+
* end-user mode like `get`. `count` is the page returned (≤ limit, max
|
|
2320
|
+
* 100), never a total; `has_more` says the cap was hit. A DELETE refused
|
|
2321
|
+
* with 409 `referenced` (an `on_delete: 'restrict'` edge) names the same
|
|
2322
|
+
* refs in its `referencing` field. */
|
|
2323
|
+
backlinks: (collection: string, itemId: string, opts?: {
|
|
2324
|
+
limit?: number;
|
|
2325
|
+
}) => Promise<CmsBacklinksPage>;
|
|
2326
|
+
/** P1-7 (cms.md §17): run ONE declared per-record action — invokes the
|
|
2327
|
+
* action's deployed function with `{ collection, item_id, action, actor,
|
|
2328
|
+
* item }` and returns its result. 404 when the key is not declared;
|
|
2329
|
+
* 502 `action_failed` (with `upstream.code` = the function's error
|
|
2330
|
+
* class) when the function fails. Requires cms:write. */
|
|
2331
|
+
runAction: (collection: string, itemId: string, key: string) => Promise<{
|
|
2332
|
+
collection: string;
|
|
2333
|
+
item_id: string;
|
|
2334
|
+
action: string;
|
|
2335
|
+
fn: string;
|
|
2336
|
+
result: unknown;
|
|
2337
|
+
}>;
|
|
1777
2338
|
/** cms-rel B2 (cms.md §12): bounded group-by aggregate. fns count|sum|
|
|
1778
2339
|
* min|max|avg over index-slot-bound fields; groupBy ≤2 slot-bound
|
|
1779
2340
|
* fields; filter = the full query DSL incl. ONE-hop dotted join terms
|
|
@@ -2335,6 +2896,24 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2335
2896
|
}>;
|
|
2336
2897
|
}>;
|
|
2337
2898
|
};
|
|
2899
|
+
/** Every audit event the platform can emit, with the subscribable prefixes
|
|
2900
|
+
* and their counts — the discovery surface for `subscribe({ event_prefixes })`.
|
|
2901
|
+
* Static reference data (CI-generated from the emitters), identical for every
|
|
2902
|
+
* tenant. `level` is the event CLASS ('lifecycle' | 'failure'), not the
|
|
2903
|
+
* payload's 'info'|'warn'|'error' severity key. */
|
|
2904
|
+
eventCatalog: () => Promise<{
|
|
2905
|
+
count: number;
|
|
2906
|
+
events: Array<{
|
|
2907
|
+
name: string;
|
|
2908
|
+
feature: string;
|
|
2909
|
+
level: "lifecycle" | "failure";
|
|
2910
|
+
payload_keys?: string[];
|
|
2911
|
+
}>;
|
|
2912
|
+
prefixes: Array<{
|
|
2913
|
+
prefix: string;
|
|
2914
|
+
count: number;
|
|
2915
|
+
}>;
|
|
2916
|
+
}>;
|
|
2338
2917
|
};
|
|
2339
2918
|
readonly orgs: {
|
|
2340
2919
|
create: (input: {
|
|
@@ -2617,20 +3196,20 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2617
3196
|
expires_at: string | null;
|
|
2618
3197
|
}>;
|
|
2619
3198
|
sharedLinks: {
|
|
2620
|
-
/** Public (unauthenticated) URL for the object; revocable.
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
3199
|
+
/** Public (unauthenticated) URL for the object; revocable. Optional
|
|
3200
|
+
* `max_downloads` (1 = one-time link) and an absolute `expires_at`; the
|
|
3201
|
+
* public resolver answers 410 `link_exhausted` / `link_expired` past
|
|
3202
|
+
* either bound. */
|
|
3203
|
+
create: (objectId: string, opts?: CreateSharedLinkOptions) => Promise<{
|
|
2624
3204
|
link_id: string;
|
|
2625
3205
|
url: string;
|
|
2626
|
-
|
|
3206
|
+
expires_in: number;
|
|
3207
|
+
expires_at: string;
|
|
3208
|
+
max_downloads: number | null;
|
|
3209
|
+
downloads: number;
|
|
2627
3210
|
}>;
|
|
2628
|
-
/** List an object's active (unrevoked, unexpired) shared links. */
|
|
2629
|
-
list: (objectId: string) => Promise<
|
|
2630
|
-
link_id: string;
|
|
2631
|
-
created_at: string;
|
|
2632
|
-
expires_at: string | null;
|
|
2633
|
-
}>>;
|
|
3211
|
+
/** List an object's active (unrevoked, unexpired, unexhausted) shared links. */
|
|
3212
|
+
list: (objectId: string) => Promise<FileSharedLink[]>;
|
|
2634
3213
|
revoke: (linkId: string) => Promise<void>;
|
|
2635
3214
|
};
|
|
2636
3215
|
};
|
|
@@ -2730,7 +3309,10 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2730
3309
|
readonly ai: {
|
|
2731
3310
|
templates: {
|
|
2732
3311
|
/** Store a tenant-authored prompt template; versions are monotonic per name.
|
|
2733
|
-
* `{{var}}` placeholders are filled from `generate`'s `input`.
|
|
3312
|
+
* `{{var}}` placeholders are filled from `generate`'s `input`.
|
|
3313
|
+
* `schema` (a JSON Schema) is now ENFORCED at generate time on sync/job
|
|
3314
|
+
* requests — the output is validated (with one repair pass) against it;
|
|
3315
|
+
* a per-request `response_schema` overrides it. Ignored on streams. */
|
|
2734
3316
|
put: (input: {
|
|
2735
3317
|
template: string;
|
|
2736
3318
|
user: string;
|
|
@@ -2772,6 +3354,13 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2772
3354
|
* role:'tool' results) — vxil relays; you execute the tools. */
|
|
2773
3355
|
messages?: AiChatMessage[];
|
|
2774
3356
|
json_mode?: boolean;
|
|
3357
|
+
/** JSON Schema the completion must satisfy (schema-guaranteed structured
|
|
3358
|
+
* output): enforced natively where the provider supports strict
|
|
3359
|
+
* structured output, else via one validate-and-repair pass; the parsed
|
|
3360
|
+
* object lands in `output` (+`repaired` when the repair pass fired). A
|
|
3361
|
+
* still-invalid result is a 422 `output_schema_mismatch` (billed). Wins
|
|
3362
|
+
* over the template's stored schema. */
|
|
3363
|
+
response_schema?: Record<string, unknown>;
|
|
2775
3364
|
images?: string[];
|
|
2776
3365
|
user_id?: string;
|
|
2777
3366
|
}) => Promise<AiGeneration>;
|
|
@@ -2823,6 +3412,11 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2823
3412
|
}>;
|
|
2824
3413
|
messages?: AiChatMessage[];
|
|
2825
3414
|
json_mode?: boolean;
|
|
3415
|
+
/** JSON Schema the completion must satisfy — same contract as
|
|
3416
|
+
* `generate`; the validated answer lands in the replay buffer (a
|
|
3417
|
+
* schema-mismatch delivers finish:'schema_mismatch' on the terminal
|
|
3418
|
+
* usage frame). */
|
|
3419
|
+
response_schema?: Record<string, unknown>;
|
|
2826
3420
|
images?: string[];
|
|
2827
3421
|
user_id?: string;
|
|
2828
3422
|
}) => Promise<AiJobHandle>;
|
|
@@ -2841,6 +3435,47 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2841
3435
|
done: boolean;
|
|
2842
3436
|
max_seq: number;
|
|
2843
3437
|
}>;
|
|
3438
|
+
/** Classify an input into one of YOUR labels (or, with `multi:true`, every
|
|
3439
|
+
* label that applies) — a schema-forced verdict over the generate path:
|
|
3440
|
+
* the allowed labels ride the structured-output schema as an enum, so the
|
|
3441
|
+
* model cannot answer off-list; the reply is `{ label | labels,
|
|
3442
|
+
* confidence, rationale }`. Same metering/cache/provider rules as
|
|
3443
|
+
* `generate` (a still-invalid verdict is a billed 422
|
|
3444
|
+
* output_schema_mismatch). Caps: 2–64 labels (≤64 chars, unique), input
|
|
3445
|
+
* ≤32k chars (a string or ordered `{ text }` parts joined into ONE
|
|
3446
|
+
* input), rubric ≤4k, ≤16 examples. */
|
|
3447
|
+
classify: (input: AiVerdictOptions & {
|
|
3448
|
+
input: string | Array<{
|
|
3449
|
+
text: string;
|
|
3450
|
+
}>;
|
|
3451
|
+
labels: string[];
|
|
3452
|
+
multi?: boolean;
|
|
3453
|
+
rubric?: string;
|
|
3454
|
+
examples?: Array<{
|
|
3455
|
+
input: string;
|
|
3456
|
+
label: string;
|
|
3457
|
+
}>;
|
|
3458
|
+
}) => Promise<AiClassifyResult>;
|
|
3459
|
+
/** Grade a candidate response (or rank up to 8) against YOUR criteria —
|
|
3460
|
+
* a schema-forced integer score inside `scale` (default 0..10) plus
|
|
3461
|
+
* `pass|fail` for one candidate, or `scores[]` + `best` (+ `verdict:'tie'`)
|
|
3462
|
+
* for several — `candidates` always yields `scores`/`best`, even at
|
|
3463
|
+
* length 1. Same metering/cache/provider rules as `generate`. Caps:
|
|
3464
|
+
* input ≤16k chars, candidates ≤8 × 4k chars, criteria ≤16 items / 4k
|
|
3465
|
+
* chars, scale span ≤100. */
|
|
3466
|
+
judge: (input: AiVerdictOptions & {
|
|
3467
|
+
input: string;
|
|
3468
|
+
candidate?: string;
|
|
3469
|
+
candidates?: string[];
|
|
3470
|
+
criteria: string | Array<{
|
|
3471
|
+
name: string;
|
|
3472
|
+
weight?: number;
|
|
3473
|
+
}>;
|
|
3474
|
+
scale?: {
|
|
3475
|
+
min: number;
|
|
3476
|
+
max: number;
|
|
3477
|
+
};
|
|
3478
|
+
}) => Promise<AiJudgeResult>;
|
|
2844
3479
|
/** Embed a batch of strings (1–256). */
|
|
2845
3480
|
embed: (input: {
|
|
2846
3481
|
input: string[];
|
|
@@ -2990,27 +3625,43 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2990
3625
|
*/
|
|
2991
3626
|
readonly payments: {
|
|
2992
3627
|
/** Provider + ledger capability surface (+ the `missing` set an agent can act
|
|
2993
|
-
* on to recommend a provider).
|
|
3628
|
+
* on to recommend a provider). `client` is the RevenueCat tenant's PUBLIC
|
|
3629
|
+
* SDK handout (project id + public SDK key — never the secret key); null
|
|
3630
|
+
* for every other provider. */
|
|
2994
3631
|
capabilities: () => Promise<{
|
|
2995
3632
|
provider: string;
|
|
2996
3633
|
capabilities: string[];
|
|
2997
3634
|
ledger_capabilities: string[];
|
|
2998
3635
|
missing: string[];
|
|
3636
|
+
client: {
|
|
3637
|
+
revenuecat: {
|
|
3638
|
+
project_id: string;
|
|
3639
|
+
public_sdk_key: string;
|
|
3640
|
+
};
|
|
3641
|
+
} | null;
|
|
2999
3642
|
}>;
|
|
3000
3643
|
/** The user's effective entitlement snapshot (the multi-sub tier fold):
|
|
3001
|
-
* tier + boolean entitlements + numeric quotas
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3644
|
+
* tier + boolean entitlements + numeric quotas — plus the access window
|
|
3645
|
+
* (`since` / `until` = the winning subscription's period end, or end +
|
|
3646
|
+
* grace when it is past_due), `as_of` (server time), the `environment`
|
|
3647
|
+
* the winning subscription was written from, and OPTIONAL inline reads:
|
|
3648
|
+
* `quota` inlines one quota, `creditType` inlines the same owner-bound
|
|
3649
|
+
* balance `getBalance` returns — ONE call for a thin client's paywall.
|
|
3650
|
+
* A non-2xx answer means UNKNOWN: render the last cached answer, never
|
|
3651
|
+
* free (payments.md §3a). */
|
|
3652
|
+
getEntitlements: (userId: string, opts?: {
|
|
3653
|
+
quota?: string;
|
|
3654
|
+
creditType?: string;
|
|
3655
|
+
}) => Promise<PaymentsEntitlementView>;
|
|
3008
3656
|
/** Boolean gate: does the user hold `entitlement`? Returns granted + its
|
|
3009
|
-
* source (subscription/tier) + the resolved tier
|
|
3657
|
+
* source (subscription/tier) + the resolved tier, plus `until` (how long
|
|
3658
|
+
* the answer is good for) and `as_of`. Non-2xx = unknown, never free. */
|
|
3010
3659
|
hasEntitlement: (userId: string, entitlement: string) => Promise<{
|
|
3011
3660
|
granted: boolean;
|
|
3012
3661
|
source: string | null;
|
|
3013
3662
|
tier: string;
|
|
3663
|
+
until: string | null;
|
|
3664
|
+
as_of: string;
|
|
3014
3665
|
}>;
|
|
3015
3666
|
/** A single numeric quota for the user (e.g. `seats`, `api_calls`); null when
|
|
3016
3667
|
* the resolved tier declares no such quota. Convenience over getEntitlements. */
|
|
@@ -3161,10 +3812,107 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
3161
3812
|
status: "pending" | "succeeded" | "failed";
|
|
3162
3813
|
amount_cents: number;
|
|
3163
3814
|
}>;
|
|
3164
|
-
/**
|
|
3165
|
-
*
|
|
3815
|
+
/** Where the user MANAGES their subscription, resolved by FUNDING SOURCE
|
|
3816
|
+
* (the provider of their live subscription, not the tenant's primary):
|
|
3817
|
+
* `kind: 'portal'` = a provider-minted portal session URL (Stripe, Paddle
|
|
3818
|
+
* via the captured customer id, mock); `'store'` = the App Store / Play
|
|
3819
|
+
* Store manage-subscriptions page for a RevenueCat row that recorded its
|
|
3820
|
+
* store; `'none'` (url null) = nothing to link (PayPal, a manual grant, no
|
|
3821
|
+
* live subscription on a portal-less primary). */
|
|
3166
3822
|
getCustomerPortalUrl: (userId: string) => Promise<{
|
|
3167
|
-
url: string;
|
|
3823
|
+
url: string | null;
|
|
3824
|
+
kind: "portal" | "store" | "none";
|
|
3825
|
+
provider: string | null;
|
|
3826
|
+
}>;
|
|
3827
|
+
/** SERVER-ONLY. A support / promotional / migration grant: a `manual`
|
|
3828
|
+
* subscription row (no provider behind it) folded like a webhook —
|
|
3829
|
+
* entitlements + the tier's recurring credits apply; `until` null =
|
|
3830
|
+
* open-ended, else access ends at `until`. Idempotent on
|
|
3831
|
+
* `idempotency_key` (a replay returns the first grant, `replayed: true`).
|
|
3832
|
+
* 422 unknown_tier when the tier is not in ledger.tierMap. */
|
|
3833
|
+
grantSubscription: (input: {
|
|
3834
|
+
user_id: string;
|
|
3835
|
+
tier: string;
|
|
3836
|
+
until?: string | null;
|
|
3837
|
+
reason: string;
|
|
3838
|
+
idempotency_key: string;
|
|
3839
|
+
}) => Promise<{
|
|
3840
|
+
subscription_id: string | null;
|
|
3841
|
+
user_id: string;
|
|
3842
|
+
tier: string;
|
|
3843
|
+
status: string;
|
|
3844
|
+
until: string | null;
|
|
3845
|
+
replayed: boolean;
|
|
3846
|
+
}>;
|
|
3847
|
+
/** SERVER-ONLY. Revoke a MANUAL grant now (409 not_manual for a provider
|
|
3848
|
+
* subscription — use `cancel`). Never touches a provider. */
|
|
3849
|
+
revokeSubscription: (subscriptionId: string) => Promise<{
|
|
3850
|
+
subscription_id: string;
|
|
3851
|
+
status: string;
|
|
3852
|
+
cancel_at: string | null;
|
|
3853
|
+
revoked_at: string | null;
|
|
3854
|
+
}>;
|
|
3855
|
+
/** SERVER-ONLY. Re-read a customer's subscriptions FROM the provider and
|
|
3856
|
+
* fold them through the same conditional upsert a webhook uses (never a
|
|
3857
|
+
* second write path). `dry_run` diffs without writing. Capped 30/min per
|
|
3858
|
+
* project (429 rate_limited). The migration backfill (`vxil migrate
|
|
3859
|
+
* payments --from-provider …`) drives this per customer. */
|
|
3860
|
+
syncSubscriptions: (input: {
|
|
3861
|
+
user_id?: string;
|
|
3862
|
+
customer_ref?: string;
|
|
3863
|
+
provider?: "mock" | "stripe" | "paddle" | "revenuecat" | "paypal";
|
|
3864
|
+
dry_run?: boolean;
|
|
3865
|
+
}) => Promise<PaymentsSyncOutcome>;
|
|
3866
|
+
/** The server leg of "Restore Purchases": in end-user mode the verified
|
|
3867
|
+
* principal's OWN provider state is re-read (no user id needed); in server
|
|
3868
|
+
* mode pass `user_id`. 3 per hour per user (429). Returns the sync outcome
|
|
3869
|
+
* plus the fresh entitlement view in one answer. */
|
|
3870
|
+
restoreSubscriptions: (input?: {
|
|
3871
|
+
user_id?: string;
|
|
3872
|
+
provider?: "mock" | "stripe" | "paddle" | "revenuecat" | "paypal";
|
|
3873
|
+
}) => Promise<PaymentsSyncOutcome & {
|
|
3874
|
+
entitlements: PaymentsEntitlementView;
|
|
3875
|
+
}>;
|
|
3876
|
+
/** SERVER-ONLY. Account merge: move EVERY provider's subscriptions,
|
|
3877
|
+
* customer links and available credit balances of `from_user_id` onto
|
|
3878
|
+
* `into_user_id` — at-most-once per pair. The consumer of the
|
|
3879
|
+
* `auth.user.merged { from, into }` audit event. */
|
|
3880
|
+
reKeySubscriptions: (input: {
|
|
3881
|
+
from_user_id: string;
|
|
3882
|
+
into_user_id: string;
|
|
3883
|
+
}) => Promise<{
|
|
3884
|
+
from_user_id: string;
|
|
3885
|
+
into_user_id: string;
|
|
3886
|
+
moved: number;
|
|
3887
|
+
credits_moved: number;
|
|
3888
|
+
}>;
|
|
3889
|
+
/** SERVER-ONLY, mock/dev tenants ONLY (403 simulation_not_allowed
|
|
3890
|
+
* elsewhere). Drive a scripted lifecycle (renewal, expiry, refund-pair,
|
|
3891
|
+
* past-due-grace, cross-platform-unlock, transfer) through the mock
|
|
3892
|
+
* webhook path and judge it with the conformance oracle. */
|
|
3893
|
+
simulate: (input: {
|
|
3894
|
+
scenario: "refund-pair" | "cross-platform-unlock" | "renewal" | "expiry" | "past-due-grace" | "transfer";
|
|
3895
|
+
user_id: string;
|
|
3896
|
+
tier?: string;
|
|
3897
|
+
}) => Promise<PaymentsSimulationResult>;
|
|
3898
|
+
/** The last report-only reconciliation sweep result for this project
|
|
3899
|
+
* (`run: null` before the first daily tick). */
|
|
3900
|
+
reconcile: () => Promise<{
|
|
3901
|
+
run: {
|
|
3902
|
+
run_id: string;
|
|
3903
|
+
ran_at: string | null;
|
|
3904
|
+
clean: boolean;
|
|
3905
|
+
discrepancy_count: number;
|
|
3906
|
+
lapsed_count: number;
|
|
3907
|
+
findings: Array<{
|
|
3908
|
+
kind: string;
|
|
3909
|
+
count: number;
|
|
3910
|
+
ids: string[];
|
|
3911
|
+
}>;
|
|
3912
|
+
} | null;
|
|
3913
|
+
enforce_period_end: {
|
|
3914
|
+
slack_hours: number;
|
|
3915
|
+
} | null;
|
|
3168
3916
|
}>;
|
|
3169
3917
|
/** List charges newest-first (the refund enabler — discover the charge_id).
|
|
3170
3918
|
* Filters: user_id, status, limit (clamped 1..100, default 50). */
|
|
@@ -3194,7 +3942,9 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
3194
3942
|
list: (q?: {
|
|
3195
3943
|
provider?: "mock" | "stripe" | "paddle" | "revenuecat" | "paypal";
|
|
3196
3944
|
event_type?: string;
|
|
3197
|
-
outcome?: "received" | "processed" | "error" | "sig_failed" | "parse_failed" | "reprocessed";
|
|
3945
|
+
outcome?: "received" | "processed" | "error" | "sig_failed" | "parse_failed" | "reprocessed" | "ignored" | "unowned" | "rejected_environment";
|
|
3946
|
+
/** the provider-reported environment axis (not the API key's label) */
|
|
3947
|
+
environment?: "production" | "sandbox";
|
|
3198
3948
|
since?: string;
|
|
3199
3949
|
cursor?: string;
|
|
3200
3950
|
limit?: number;
|