@vxil/sdk 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +142 -20
- package/dist/index.js +57 -7
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -535,6 +535,57 @@ export interface PaymentsEntitlementView {
|
|
|
535
535
|
period_end: string | null;
|
|
536
536
|
};
|
|
537
537
|
}
|
|
538
|
+
/** The provider's own state of a charge, as a closed union (2026-09-25). Paddle
|
|
539
|
+
* delivers `paid` (money taken) and then `completed` (fulfilled) for ONE
|
|
540
|
+
* charge; every other provider has a single terminal state and lands
|
|
541
|
+
* `completed` at once. `payments.charge.succeeded` carries the state of the
|
|
542
|
+
* delivery that recorded the charge; `payments.charge.completed` fires at
|
|
543
|
+
* most once per charge, only when a recorded charge later TRANSITIONS to
|
|
544
|
+
* `completed` (Paddle paid → completed). Handle `succeeded` gated on
|
|
545
|
+
* `provider_status === 'completed'` plus `completed` to act once per charge. */
|
|
546
|
+
export type PaymentsProviderChargeStatus = 'paid' | 'completed';
|
|
547
|
+
/** A charge row as listed by GET /v1/payments/charges (payments.md §3). */
|
|
548
|
+
export interface PaymentsCharge {
|
|
549
|
+
/** the vxil charge id (`chg_…`) — what refunds and a charge-linked grant key on */
|
|
550
|
+
charge_id: string;
|
|
551
|
+
end_user_id: string;
|
|
552
|
+
provider: string;
|
|
553
|
+
/** the provider's own transaction / payment id */
|
|
554
|
+
provider_charge_id: string | null;
|
|
555
|
+
/** null on rows recorded before the provider-state column existed */
|
|
556
|
+
provider_status: PaymentsProviderChargeStatus | null;
|
|
557
|
+
/** the one-off product the charge bought (the `ledger.productMap` key), if any */
|
|
558
|
+
product_id: string | null;
|
|
559
|
+
amount_cents: number;
|
|
560
|
+
amount_refunded: number;
|
|
561
|
+
currency: string;
|
|
562
|
+
status: string;
|
|
563
|
+
created_at: string;
|
|
564
|
+
}
|
|
565
|
+
/** A subscription row as listed by GET /v1/payments/subscriptions (payments.md
|
|
566
|
+
* §3) — provider subscriptions, manual grants and purchase passes alike.
|
|
567
|
+
* `current_period_start` (2026-09-25) is the row's own window start: for a
|
|
568
|
+
* purchase pass (`provider_sub_id: 'purchase:<charge_id>'`) the day its access
|
|
569
|
+
* begins, which is in the FUTURE for a pass queued behind a live one; for a
|
|
570
|
+
* manual grant the time the grant was written. A `type` with an index
|
|
571
|
+
* signature (not an interface), so code that typed these rows as
|
|
572
|
+
* `Record<string, unknown>` keeps compiling. */
|
|
573
|
+
export type PaymentsSubscription = {
|
|
574
|
+
subscription_id: string;
|
|
575
|
+
end_user_id: string;
|
|
576
|
+
/** 'manual' for a support grant or a purchase pass; else the provider */
|
|
577
|
+
provider: string;
|
|
578
|
+
provider_sub_id: string;
|
|
579
|
+
tier: string | null;
|
|
580
|
+
/** trialing | active | past_due | cancelled | expired | lapsed */
|
|
581
|
+
status: string;
|
|
582
|
+
current_period_start: string | null;
|
|
583
|
+
current_period_end: string | null;
|
|
584
|
+
/** the vxil charge (`chg_…`) a pass or a charge-linked grant was bought with */
|
|
585
|
+
charge_id: string | null;
|
|
586
|
+
created_at: string;
|
|
587
|
+
[key: string]: unknown;
|
|
588
|
+
};
|
|
538
589
|
export interface FileObject {
|
|
539
590
|
object_id: string;
|
|
540
591
|
filename: string;
|
|
@@ -1513,7 +1564,12 @@ export interface CmsReindexPage {
|
|
|
1513
1564
|
/** The result of a bounded filtered delete (cms.md §20). `matched` counts the
|
|
1514
1565
|
* rows this page selected (≤ `limit`); `deleted` counts the ones actually
|
|
1515
1566
|
* removed (a row that vanished between the match and the delete is skipped).
|
|
1516
|
-
* Loop while `deleted > 0` — the filter re-evaluates against live rows.
|
|
1567
|
+
* Loop while `deleted > 0` — the filter re-evaluates against live rows.
|
|
1568
|
+
* `complete` is false when the call stopped starting rows at its wall-clock
|
|
1569
|
+
* bound (8 s; the row in flight finishes) before every matched row was
|
|
1570
|
+
* processed — such a call always deleted at least one row, so the loop above
|
|
1571
|
+
* stays exact; `next_cursor` resumes that page if you prefer. Rows already
|
|
1572
|
+
* deleted stay deleted. */
|
|
1517
1573
|
export interface CmsBulkDeleteResult {
|
|
1518
1574
|
collection: string;
|
|
1519
1575
|
matched: number;
|
|
@@ -1521,6 +1577,8 @@ export interface CmsBulkDeleteResult {
|
|
|
1521
1577
|
cascaded: number;
|
|
1522
1578
|
set_null: number;
|
|
1523
1579
|
dry_run: boolean;
|
|
1580
|
+
/** every matched row was processed (always true for a dry run). */
|
|
1581
|
+
complete: boolean;
|
|
1524
1582
|
next_cursor: string | null;
|
|
1525
1583
|
}
|
|
1526
1584
|
/** A write guard (cms.md §10): "after this write, at most `max` live items
|
|
@@ -1959,6 +2017,24 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1959
2017
|
delete: (id: string, opts?: {
|
|
1960
2018
|
erase?: boolean;
|
|
1961
2019
|
}) => Promise<void>;
|
|
2020
|
+
/**
|
|
2021
|
+
* Merge a REGISTRY-ONLY user (a row you created with upsert that never
|
|
2022
|
+
* signed in) INTO another user of the tenant: its attributes fill the
|
|
2023
|
+
* survivor's gaps (the survivor wins on conflicts), the merged id is
|
|
2024
|
+
* soft-deleted, its owner-scoped cms / files / payments rows move to the
|
|
2025
|
+
* survivor, and `auth.user.merged { from, into, method: 'registry_merge' }`
|
|
2026
|
+
* is audited. `rekeyed: false` means a re-key could not finish inside the
|
|
2027
|
+
* request — the event is the backstop (call the feature's re-key route
|
|
2028
|
+
* again; it is idempotent). 409 `has_auth_identity` when the id already
|
|
2029
|
+
* has a sign-in identity: merge that through the auth flows instead.
|
|
2030
|
+
* Server-only (403 in end-user mode). Scope users:write.
|
|
2031
|
+
*/
|
|
2032
|
+
merge: (id: string, into: string) => Promise<{
|
|
2033
|
+
from: string;
|
|
2034
|
+
into: string;
|
|
2035
|
+
merged: boolean;
|
|
2036
|
+
rekeyed: boolean;
|
|
2037
|
+
}>;
|
|
1962
2038
|
list: (q?: {
|
|
1963
2039
|
email?: string;
|
|
1964
2040
|
/** substring match on email + display name (server-side, trgm-indexed), 1-100 chars */
|
|
@@ -2086,6 +2162,8 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2086
2162
|
* `counts.total / sent` to 4 dp, or null when nothing was sent. `sent`
|
|
2087
2163
|
* counts deliveries the provider ACCEPTED, not inbox-delivered mail —
|
|
2088
2164
|
* this is a suppressions-per-accepted-send ratio, not an RFC bounce rate.
|
|
2165
|
+
* `sent` is counted up to 100 000: past that it is the cap and
|
|
2166
|
+
* `sent_capped` is true (the rate is then a lower bound).
|
|
2089
2167
|
* Operator surface: a verified end-user token gets 403. */
|
|
2090
2168
|
stats: (q?: {
|
|
2091
2169
|
days?: number;
|
|
@@ -2100,6 +2178,7 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2100
2178
|
total: number;
|
|
2101
2179
|
};
|
|
2102
2180
|
sent: number;
|
|
2181
|
+
sent_capped?: boolean;
|
|
2103
2182
|
rate: number | null;
|
|
2104
2183
|
}>;
|
|
2105
2184
|
};
|
|
@@ -2434,7 +2513,8 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2434
2513
|
run_id: string;
|
|
2435
2514
|
state: string;
|
|
2436
2515
|
}>;
|
|
2437
|
-
/** Clone a terminal run into a fresh queued run.
|
|
2516
|
+
/** Clone a terminal run into a fresh queued run. A generation run answers
|
|
2517
|
+
* `409 not_replayable` — submit the generation again instead. */
|
|
2438
2518
|
replay: (runId: string) => Promise<{
|
|
2439
2519
|
run_id: string;
|
|
2440
2520
|
replayed_from: string;
|
|
@@ -2749,8 +2829,11 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2749
2829
|
* refresh token in one process share ONE rotation, and for 30 s after it
|
|
2750
2830
|
* settles a call still carrying the OLD pair gets the new pair (no second
|
|
2751
2831
|
* request) while a call with the just-minted pair gets it back unchanged.
|
|
2752
|
-
* A refresh that fails
|
|
2753
|
-
*
|
|
2832
|
+
* A refresh that fails throws the `VxilError`. A `401 invalid_refresh`
|
|
2833
|
+
* can be a rotation another process (another server instance) just
|
|
2834
|
+
* made, so do not clear the session on the first one — keep the cookie
|
|
2835
|
+
* and treat only a repeat failure of the same pair after a short grace
|
|
2836
|
+
* as "sign in again"; see guide 09's refresh recipe.
|
|
2754
2837
|
*
|
|
2755
2838
|
* Call it on a client whose key carries `auth:signin` — normally the
|
|
2756
2839
|
* sign-in key, in server mode. An end-user-mode client sends its
|
|
@@ -2910,9 +2993,18 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2910
2993
|
* Consume budget. With behavior 'block' an exceeded check throws
|
|
2911
2994
|
* VxilError(429); 'shape' resolves with allowed=false instead.
|
|
2912
2995
|
* `override_id` is present when a per-identifier override was applied.
|
|
2996
|
+
* Name the policy by EXACTLY ONE of `policy_id` or `policy` (its name —
|
|
2997
|
+
* unique per project, and it survives a delete-and-recreate). An unknown
|
|
2998
|
+
* name is the same 404 `not_found` as an unknown id; a policy created
|
|
2999
|
+
* before 2026-09-23 is found by name once it has been saved or listed again.
|
|
2913
3000
|
*/
|
|
2914
|
-
check: (input: {
|
|
3001
|
+
check: (input: ({
|
|
2915
3002
|
policy_id: string;
|
|
3003
|
+
policy?: never;
|
|
3004
|
+
} | {
|
|
3005
|
+
policy: string;
|
|
3006
|
+
policy_id?: never;
|
|
3007
|
+
}) & {
|
|
2916
3008
|
key_values?: Record<string, string>;
|
|
2917
3009
|
cost?: number;
|
|
2918
3010
|
}) => Promise<{
|
|
@@ -3132,7 +3224,10 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
3132
3224
|
* the SAME single-item delete path (restrict refusal, cascade budget,
|
|
3133
3225
|
* unique-claim freeing, CDC), so this is N deletes in one round trip, not
|
|
3134
3226
|
* a set-delete. `dryRun` reports `matched` and mutates nothing. Loop
|
|
3135
|
-
* while `deleted > 0`. A
|
|
3227
|
+
* while `deleted > 0`. A call stops STARTING rows after 8 s of wall
|
|
3228
|
+
* clock (the row in flight finishes; never before its first delete) and
|
|
3229
|
+
* answers `complete: false` + `next_cursor` (pass it as `cursor` to
|
|
3230
|
+
* resume the page). A refusal mid-sweep (409 referenced / 422
|
|
3136
3231
|
* cascade_too_large) stops the call — rows already deleted STAY deleted,
|
|
3137
3232
|
* and the error message names how many. Soft-deleted rows are hard-purged
|
|
3138
3233
|
* by the platform 30 days later (there is no per-tenant retention knob). */
|
|
@@ -3677,6 +3772,21 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
3677
3772
|
state: string;
|
|
3678
3773
|
}>>;
|
|
3679
3774
|
unsubscribe: (subId: string) => Promise<void>;
|
|
3775
|
+
/**
|
|
3776
|
+
* Change a subscription's event filter in place (2026-09-25). The sub_id
|
|
3777
|
+
* and the delivery cursor are kept — nothing is replayed, nothing is
|
|
3778
|
+
* skipped; the new prefixes apply from the next delivery pass. An empty
|
|
3779
|
+
* array subscribes to every event. `target_url` is the subscription's
|
|
3780
|
+
* identity and is not editable: a new target is a new subscription.
|
|
3781
|
+
*/
|
|
3782
|
+
update: (subId: string, input: {
|
|
3783
|
+
event_prefixes: string[];
|
|
3784
|
+
}) => Promise<{
|
|
3785
|
+
sub_id: string;
|
|
3786
|
+
target_url: string;
|
|
3787
|
+
event_prefixes: string[];
|
|
3788
|
+
state: string;
|
|
3789
|
+
}>;
|
|
3680
3790
|
/**
|
|
3681
3791
|
* Send a synthetic 'webhooks.test' event to the subscription's endpoint
|
|
3682
3792
|
* through the REAL signing+delivery pipeline and wait inline (≤ ~8 s).
|
|
@@ -4716,11 +4826,14 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
4716
4826
|
cancel_at: string | null;
|
|
4717
4827
|
}>;
|
|
4718
4828
|
/** List subscriptions (the cancel enabler — discover the subscription_id);
|
|
4719
|
-
* optionally scoped to one user / status.
|
|
4829
|
+
* optionally scoped to one user / status. Each row carries its own
|
|
4830
|
+
* window: `current_period_start` … `current_period_end` (a queued pass
|
|
4831
|
+
* starts in the future). In end-user mode the list is always the signed-in
|
|
4832
|
+
* user's own rows, whatever `user_id` says. */
|
|
4720
4833
|
listSubscriptions: (q?: {
|
|
4721
4834
|
user_id?: string;
|
|
4722
4835
|
status?: string;
|
|
4723
|
-
}) => Promise<
|
|
4836
|
+
}) => Promise<PaymentsSubscription[]>;
|
|
4724
4837
|
/**
|
|
4725
4838
|
* Create a hosted-checkout session (payments.md §3). Redirect the buyer to
|
|
4726
4839
|
* the returned `url`; completion lands server-side via the provider webhook
|
|
@@ -4794,19 +4907,32 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
4794
4907
|
* entitlements + the tier's recurring credits apply; `until` null =
|
|
4795
4908
|
* open-ended, else access ends at `until`. Idempotent on
|
|
4796
4909
|
* `idempotency_key` (a replay returns the first grant, `replayed: true`).
|
|
4797
|
-
* 422 unknown_tier when the tier is not in ledger.tierMap.
|
|
4910
|
+
* 422 unknown_tier when the tier is not in ledger.tierMap.
|
|
4911
|
+
* `charge_id` (optional) links the grant to the vxil charge (`chg_…`, from
|
|
4912
|
+
* `listCharges` or the `payments.charge.succeeded` / `.completed` event)
|
|
4913
|
+
* it was bought with: a FULL refund or chargeback of that charge ends the
|
|
4914
|
+
* grant (`payments.subscription.revoked` with `via: 'refund' | 'chargeback'`).
|
|
4915
|
+
* 404 charge_not_found; 422 charge_user_mismatch (another user's charge) /
|
|
4916
|
+
* charge_refunded (the refund beat the grant — nothing to grant against).
|
|
4917
|
+
* 422 reserved_idempotency_key when `idempotency_key` starts with
|
|
4918
|
+
* `purchase:` (the namespace of purchase passes). */
|
|
4798
4919
|
grantSubscription: (input: {
|
|
4799
4920
|
user_id: string;
|
|
4800
4921
|
tier: string;
|
|
4801
4922
|
until?: string | null;
|
|
4802
4923
|
reason: string;
|
|
4803
4924
|
idempotency_key: string;
|
|
4925
|
+
charge_id?: string | null;
|
|
4804
4926
|
}) => Promise<{
|
|
4805
4927
|
subscription_id: string | null;
|
|
4806
4928
|
user_id: string;
|
|
4807
4929
|
tier: string;
|
|
4808
4930
|
status: string;
|
|
4931
|
+
/** (2026-09-25) the grant row's start — the time it was WRITTEN (a replay
|
|
4932
|
+
* answers the first grant's), never a window you computed */
|
|
4933
|
+
since?: string | null;
|
|
4809
4934
|
until: string | null;
|
|
4935
|
+
charge_id: string | null;
|
|
4810
4936
|
replayed: boolean;
|
|
4811
4937
|
}>;
|
|
4812
4938
|
/** SERVER-ONLY. Revoke a MANUAL grant now (409 not_manual for a provider
|
|
@@ -4884,22 +5010,18 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
4884
5010
|
} | null;
|
|
4885
5011
|
}>;
|
|
4886
5012
|
/** List charges newest-first (the refund enabler — discover the charge_id).
|
|
4887
|
-
* Filters: user_id, status, limit (clamped 1..100, default 50).
|
|
5013
|
+
* Filters: user_id, status, limit (clamped 1..100, default 50).
|
|
5014
|
+
* Each row carries the provider's own charge id (`provider_charge_id`),
|
|
5015
|
+
* the provider's charge state (`provider_status`: `'paid'` — Paddle's
|
|
5016
|
+
* money-taken state — or `'completed'`; null on rows recorded before
|
|
5017
|
+
* 2026-09-25) and the one-off `product_id` it bought, so a function can
|
|
5018
|
+
* match a charge to a provider event without reading the delivery log. */
|
|
4888
5019
|
listCharges: (q?: {
|
|
4889
5020
|
user_id?: string;
|
|
4890
5021
|
status?: "succeeded" | "failed" | "refunded" | "partially_refunded" | "pending";
|
|
4891
5022
|
limit?: number;
|
|
4892
5023
|
}) => Promise<{
|
|
4893
|
-
charges:
|
|
4894
|
-
charge_id: string;
|
|
4895
|
-
end_user_id: string;
|
|
4896
|
-
provider: string;
|
|
4897
|
-
amount_cents: number;
|
|
4898
|
-
amount_refunded: number;
|
|
4899
|
-
currency: string;
|
|
4900
|
-
status: string;
|
|
4901
|
-
created_at: string;
|
|
4902
|
-
}>;
|
|
5024
|
+
charges: PaymentsCharge[];
|
|
4903
5025
|
}>;
|
|
4904
5026
|
/** Provider webhook event log (payments.md §7 "Event log & replay"):
|
|
4905
5027
|
* operator visibility over every delivery — incl. persisted signature
|
package/dist/index.js
CHANGED
|
@@ -400,6 +400,19 @@ export class Vxil {
|
|
|
400
400
|
delete: async (id, opts) => {
|
|
401
401
|
await this.call('DELETE', `/v1/users/${encodeURIComponent(id)}${opts?.erase ? '?erase=true' : ''}`);
|
|
402
402
|
},
|
|
403
|
+
/**
|
|
404
|
+
* Merge a REGISTRY-ONLY user (a row you created with upsert that never
|
|
405
|
+
* signed in) INTO another user of the tenant: its attributes fill the
|
|
406
|
+
* survivor's gaps (the survivor wins on conflicts), the merged id is
|
|
407
|
+
* soft-deleted, its owner-scoped cms / files / payments rows move to the
|
|
408
|
+
* survivor, and `auth.user.merged { from, into, method: 'registry_merge' }`
|
|
409
|
+
* is audited. `rekeyed: false` means a re-key could not finish inside the
|
|
410
|
+
* request — the event is the backstop (call the feature's re-key route
|
|
411
|
+
* again; it is idempotent). 409 `has_auth_identity` when the id already
|
|
412
|
+
* has a sign-in identity: merge that through the auth flows instead.
|
|
413
|
+
* Server-only (403 in end-user mode). Scope users:write.
|
|
414
|
+
*/
|
|
415
|
+
merge: async (id, into) => (await this.call('POST', `/v1/users/${encodeURIComponent(id)}/merge`, { into })).data,
|
|
403
416
|
list: async (q) => {
|
|
404
417
|
const s = qs({
|
|
405
418
|
email: q?.email || undefined,
|
|
@@ -460,6 +473,8 @@ export class Vxil {
|
|
|
460
473
|
* `counts.total / sent` to 4 dp, or null when nothing was sent. `sent`
|
|
461
474
|
* counts deliveries the provider ACCEPTED, not inbox-delivered mail —
|
|
462
475
|
* this is a suppressions-per-accepted-send ratio, not an RFC bounce rate.
|
|
476
|
+
* `sent` is counted up to 100 000: past that it is the cap and
|
|
477
|
+
* `sent_capped` is true (the rate is then a lower bound).
|
|
463
478
|
* Operator surface: a verified end-user token gets 403. */
|
|
464
479
|
stats: async (q) => {
|
|
465
480
|
const s = qs({ days: q?.days || undefined });
|
|
@@ -684,7 +699,8 @@ export class Vxil {
|
|
|
684
699
|
* number to alarm on), in-flight runs per lane, dead letters in 24 h. */
|
|
685
700
|
queue: async () => (await this.call('GET', '/v1/jobs/queue')).data,
|
|
686
701
|
cancel: async (runId) => (await this.call('POST', `/v1/jobs/runs/${encodeURIComponent(runId)}/cancel`)).data,
|
|
687
|
-
/** Clone a terminal run into a fresh queued run.
|
|
702
|
+
/** Clone a terminal run into a fresh queued run. A generation run answers
|
|
703
|
+
* `409 not_replayable` — submit the generation again instead. */
|
|
688
704
|
replay: async (runId) => (await this.call('POST', `/v1/jobs/runs/${encodeURIComponent(runId)}/replay`)).data,
|
|
689
705
|
/**
|
|
690
706
|
* Suspend the RUNNING run until an event (call from the executing
|
|
@@ -864,8 +880,11 @@ export class Vxil {
|
|
|
864
880
|
* refresh token in one process share ONE rotation, and for 30 s after it
|
|
865
881
|
* settles a call still carrying the OLD pair gets the new pair (no second
|
|
866
882
|
* request) while a call with the just-minted pair gets it back unchanged.
|
|
867
|
-
* A refresh that fails
|
|
868
|
-
*
|
|
883
|
+
* A refresh that fails throws the `VxilError`. A `401 invalid_refresh`
|
|
884
|
+
* can be a rotation another process (another server instance) just
|
|
885
|
+
* made, so do not clear the session on the first one — keep the cookie
|
|
886
|
+
* and treat only a repeat failure of the same pair after a short grace
|
|
887
|
+
* as "sign in again"; see guide 09's refresh recipe.
|
|
869
888
|
*
|
|
870
889
|
* Call it on a client whose key carries `auth:signin` — normally the
|
|
871
890
|
* sign-in key, in server mode. An end-user-mode client sends its
|
|
@@ -1002,6 +1021,10 @@ export class Vxil {
|
|
|
1002
1021
|
* Consume budget. With behavior 'block' an exceeded check throws
|
|
1003
1022
|
* VxilError(429); 'shape' resolves with allowed=false instead.
|
|
1004
1023
|
* `override_id` is present when a per-identifier override was applied.
|
|
1024
|
+
* Name the policy by EXACTLY ONE of `policy_id` or `policy` (its name —
|
|
1025
|
+
* unique per project, and it survives a delete-and-recreate). An unknown
|
|
1026
|
+
* name is the same 404 `not_found` as an unknown id; a policy created
|
|
1027
|
+
* before 2026-09-23 is found by name once it has been saved or listed again.
|
|
1005
1028
|
*/
|
|
1006
1029
|
check: async (input) => (await this.call('POST', '/v1/rate-limits/check', input)).data,
|
|
1007
1030
|
/** Per-identifier overrides layered over a policy: `pattern` matches the
|
|
@@ -1170,7 +1193,10 @@ export class Vxil {
|
|
|
1170
1193
|
* the SAME single-item delete path (restrict refusal, cascade budget,
|
|
1171
1194
|
* unique-claim freeing, CDC), so this is N deletes in one round trip, not
|
|
1172
1195
|
* a set-delete. `dryRun` reports `matched` and mutates nothing. Loop
|
|
1173
|
-
* while `deleted > 0`. A
|
|
1196
|
+
* while `deleted > 0`. A call stops STARTING rows after 8 s of wall
|
|
1197
|
+
* clock (the row in flight finishes; never before its first delete) and
|
|
1198
|
+
* answers `complete: false` + `next_cursor` (pass it as `cursor` to
|
|
1199
|
+
* resume the page). A refusal mid-sweep (409 referenced / 422
|
|
1174
1200
|
* cascade_too_large) stops the call — rows already deleted STAY deleted,
|
|
1175
1201
|
* and the error message names how many. Soft-deleted rows are hard-purged
|
|
1176
1202
|
* by the platform 30 days later (there is no per-tenant retention knob). */
|
|
@@ -1439,6 +1465,14 @@ export class Vxil {
|
|
|
1439
1465
|
unsubscribe: async (subId) => {
|
|
1440
1466
|
await this.call('DELETE', `/v1/webhooks/subscriptions/${encodeURIComponent(subId)}`);
|
|
1441
1467
|
},
|
|
1468
|
+
/**
|
|
1469
|
+
* Change a subscription's event filter in place (2026-09-25). The sub_id
|
|
1470
|
+
* and the delivery cursor are kept — nothing is replayed, nothing is
|
|
1471
|
+
* skipped; the new prefixes apply from the next delivery pass. An empty
|
|
1472
|
+
* array subscribes to every event. `target_url` is the subscription's
|
|
1473
|
+
* identity and is not editable: a new target is a new subscription.
|
|
1474
|
+
*/
|
|
1475
|
+
update: async (subId, input) => (await this.call('PATCH', `/v1/webhooks/subscriptions/${encodeURIComponent(subId)}`, input)).data,
|
|
1442
1476
|
/**
|
|
1443
1477
|
* Send a synthetic 'webhooks.test' event to the subscription's endpoint
|
|
1444
1478
|
* through the REAL signing+delivery pipeline and wait inline (≤ ~8 s).
|
|
@@ -1941,7 +1975,10 @@ export class Vxil {
|
|
|
1941
1975
|
* period closes; false revokes immediately and re-folds entitlements. */
|
|
1942
1976
|
cancel: async (subscriptionId, opts) => (await this.call('DELETE', `/v1/payments/subscriptions/${encodeURIComponent(subscriptionId)}${opts?.atPeriodEnd ? '?at_period_end=true' : ''}`)).data,
|
|
1943
1977
|
/** List subscriptions (the cancel enabler — discover the subscription_id);
|
|
1944
|
-
* optionally scoped to one user / status.
|
|
1978
|
+
* optionally scoped to one user / status. Each row carries its own
|
|
1979
|
+
* window: `current_period_start` … `current_period_end` (a queued pass
|
|
1980
|
+
* starts in the future). In end-user mode the list is always the signed-in
|
|
1981
|
+
* user's own rows, whatever `user_id` says. */
|
|
1945
1982
|
listSubscriptions: async (q) => {
|
|
1946
1983
|
const s = qs({ user_id: q?.user_id || undefined, status: q?.status || undefined });
|
|
1947
1984
|
return (await this.call('GET', `/v1/payments/subscriptions${s}`)).data.subscriptions;
|
|
@@ -1988,7 +2025,15 @@ export class Vxil {
|
|
|
1988
2025
|
* entitlements + the tier's recurring credits apply; `until` null =
|
|
1989
2026
|
* open-ended, else access ends at `until`. Idempotent on
|
|
1990
2027
|
* `idempotency_key` (a replay returns the first grant, `replayed: true`).
|
|
1991
|
-
* 422 unknown_tier when the tier is not in ledger.tierMap.
|
|
2028
|
+
* 422 unknown_tier when the tier is not in ledger.tierMap.
|
|
2029
|
+
* `charge_id` (optional) links the grant to the vxil charge (`chg_…`, from
|
|
2030
|
+
* `listCharges` or the `payments.charge.succeeded` / `.completed` event)
|
|
2031
|
+
* it was bought with: a FULL refund or chargeback of that charge ends the
|
|
2032
|
+
* grant (`payments.subscription.revoked` with `via: 'refund' | 'chargeback'`).
|
|
2033
|
+
* 404 charge_not_found; 422 charge_user_mismatch (another user's charge) /
|
|
2034
|
+
* charge_refunded (the refund beat the grant — nothing to grant against).
|
|
2035
|
+
* 422 reserved_idempotency_key when `idempotency_key` starts with
|
|
2036
|
+
* `purchase:` (the namespace of purchase passes). */
|
|
1992
2037
|
grantSubscription: async (input) => (await this.call('POST', '/v1/payments/subscriptions/grant', input)).data,
|
|
1993
2038
|
/** SERVER-ONLY. Revoke a MANUAL grant now (409 not_manual for a provider
|
|
1994
2039
|
* subscription — use `cancel`). Never touches a provider. */
|
|
@@ -2022,7 +2067,12 @@ export class Vxil {
|
|
|
2022
2067
|
* 403 `server_only`; the sweep is a tenant-wide operator surface. */
|
|
2023
2068
|
reconcile: async () => (await this.call('GET', '/v1/payments/reconcile')).data,
|
|
2024
2069
|
/** List charges newest-first (the refund enabler — discover the charge_id).
|
|
2025
|
-
* Filters: user_id, status, limit (clamped 1..100, default 50).
|
|
2070
|
+
* Filters: user_id, status, limit (clamped 1..100, default 50).
|
|
2071
|
+
* Each row carries the provider's own charge id (`provider_charge_id`),
|
|
2072
|
+
* the provider's charge state (`provider_status`: `'paid'` — Paddle's
|
|
2073
|
+
* money-taken state — or `'completed'`; null on rows recorded before
|
|
2074
|
+
* 2026-09-25) and the one-off `product_id` it bought, so a function can
|
|
2075
|
+
* match a charge to a provider event without reading the delivery log. */
|
|
2026
2076
|
listCharges: async (q) => {
|
|
2027
2077
|
const suffix = qs({
|
|
2028
2078
|
user_id: q?.user_id || undefined,
|
package/package.json
CHANGED