@vxil/sdk 0.7.0 → 0.8.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 +93 -14
- package/dist/index.js +42 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -535,6 +535,33 @@ 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
|
+
}
|
|
538
565
|
export interface FileObject {
|
|
539
566
|
object_id: string;
|
|
540
567
|
filename: string;
|
|
@@ -1513,7 +1540,12 @@ export interface CmsReindexPage {
|
|
|
1513
1540
|
/** The result of a bounded filtered delete (cms.md §20). `matched` counts the
|
|
1514
1541
|
* rows this page selected (≤ `limit`); `deleted` counts the ones actually
|
|
1515
1542
|
* 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.
|
|
1543
|
+
* Loop while `deleted > 0` — the filter re-evaluates against live rows.
|
|
1544
|
+
* `complete` is false when the call stopped starting rows at its wall-clock
|
|
1545
|
+
* bound (8 s; the row in flight finishes) before every matched row was
|
|
1546
|
+
* processed — such a call always deleted at least one row, so the loop above
|
|
1547
|
+
* stays exact; `next_cursor` resumes that page if you prefer. Rows already
|
|
1548
|
+
* deleted stay deleted. */
|
|
1517
1549
|
export interface CmsBulkDeleteResult {
|
|
1518
1550
|
collection: string;
|
|
1519
1551
|
matched: number;
|
|
@@ -1521,6 +1553,8 @@ export interface CmsBulkDeleteResult {
|
|
|
1521
1553
|
cascaded: number;
|
|
1522
1554
|
set_null: number;
|
|
1523
1555
|
dry_run: boolean;
|
|
1556
|
+
/** every matched row was processed (always true for a dry run). */
|
|
1557
|
+
complete: boolean;
|
|
1524
1558
|
next_cursor: string | null;
|
|
1525
1559
|
}
|
|
1526
1560
|
/** A write guard (cms.md §10): "after this write, at most `max` live items
|
|
@@ -1959,6 +1993,24 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
1959
1993
|
delete: (id: string, opts?: {
|
|
1960
1994
|
erase?: boolean;
|
|
1961
1995
|
}) => Promise<void>;
|
|
1996
|
+
/**
|
|
1997
|
+
* Merge a REGISTRY-ONLY user (a row you created with upsert that never
|
|
1998
|
+
* signed in) INTO another user of the tenant: its attributes fill the
|
|
1999
|
+
* survivor's gaps (the survivor wins on conflicts), the merged id is
|
|
2000
|
+
* soft-deleted, its owner-scoped cms / files / payments rows move to the
|
|
2001
|
+
* survivor, and `auth.user.merged { from, into, method: 'registry_merge' }`
|
|
2002
|
+
* is audited. `rekeyed: false` means a re-key could not finish inside the
|
|
2003
|
+
* request — the event is the backstop (call the feature's re-key route
|
|
2004
|
+
* again; it is idempotent). 409 `has_auth_identity` when the id already
|
|
2005
|
+
* has a sign-in identity: merge that through the auth flows instead.
|
|
2006
|
+
* Server-only (403 in end-user mode). Scope users:write.
|
|
2007
|
+
*/
|
|
2008
|
+
merge: (id: string, into: string) => Promise<{
|
|
2009
|
+
from: string;
|
|
2010
|
+
into: string;
|
|
2011
|
+
merged: boolean;
|
|
2012
|
+
rekeyed: boolean;
|
|
2013
|
+
}>;
|
|
1962
2014
|
list: (q?: {
|
|
1963
2015
|
email?: string;
|
|
1964
2016
|
/** substring match on email + display name (server-side, trgm-indexed), 1-100 chars */
|
|
@@ -2086,6 +2138,8 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2086
2138
|
* `counts.total / sent` to 4 dp, or null when nothing was sent. `sent`
|
|
2087
2139
|
* counts deliveries the provider ACCEPTED, not inbox-delivered mail —
|
|
2088
2140
|
* this is a suppressions-per-accepted-send ratio, not an RFC bounce rate.
|
|
2141
|
+
* `sent` is counted up to 100 000: past that it is the cap and
|
|
2142
|
+
* `sent_capped` is true (the rate is then a lower bound).
|
|
2089
2143
|
* Operator surface: a verified end-user token gets 403. */
|
|
2090
2144
|
stats: (q?: {
|
|
2091
2145
|
days?: number;
|
|
@@ -2100,6 +2154,7 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
2100
2154
|
total: number;
|
|
2101
2155
|
};
|
|
2102
2156
|
sent: number;
|
|
2157
|
+
sent_capped?: boolean;
|
|
2103
2158
|
rate: number | null;
|
|
2104
2159
|
}>;
|
|
2105
2160
|
};
|
|
@@ -3132,7 +3187,10 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
3132
3187
|
* the SAME single-item delete path (restrict refusal, cascade budget,
|
|
3133
3188
|
* unique-claim freeing, CDC), so this is N deletes in one round trip, not
|
|
3134
3189
|
* a set-delete. `dryRun` reports `matched` and mutates nothing. Loop
|
|
3135
|
-
* while `deleted > 0`. A
|
|
3190
|
+
* while `deleted > 0`. A call stops STARTING rows after 8 s of wall
|
|
3191
|
+
* clock (the row in flight finishes; never before its first delete) and
|
|
3192
|
+
* answers `complete: false` + `next_cursor` (pass it as `cursor` to
|
|
3193
|
+
* resume the page). A refusal mid-sweep (409 referenced / 422
|
|
3136
3194
|
* cascade_too_large) stops the call — rows already deleted STAY deleted,
|
|
3137
3195
|
* and the error message names how many. Soft-deleted rows are hard-purged
|
|
3138
3196
|
* by the platform 30 days later (there is no per-tenant retention knob). */
|
|
@@ -3677,6 +3735,21 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
3677
3735
|
state: string;
|
|
3678
3736
|
}>>;
|
|
3679
3737
|
unsubscribe: (subId: string) => Promise<void>;
|
|
3738
|
+
/**
|
|
3739
|
+
* Change a subscription's event filter in place (2026-09-25). The sub_id
|
|
3740
|
+
* and the delivery cursor are kept — nothing is replayed, nothing is
|
|
3741
|
+
* skipped; the new prefixes apply from the next delivery pass. An empty
|
|
3742
|
+
* array subscribes to every event. `target_url` is the subscription's
|
|
3743
|
+
* identity and is not editable: a new target is a new subscription.
|
|
3744
|
+
*/
|
|
3745
|
+
update: (subId: string, input: {
|
|
3746
|
+
event_prefixes: string[];
|
|
3747
|
+
}) => Promise<{
|
|
3748
|
+
sub_id: string;
|
|
3749
|
+
target_url: string;
|
|
3750
|
+
event_prefixes: string[];
|
|
3751
|
+
state: string;
|
|
3752
|
+
}>;
|
|
3680
3753
|
/**
|
|
3681
3754
|
* Send a synthetic 'webhooks.test' event to the subscription's endpoint
|
|
3682
3755
|
* through the REAL signing+delivery pipeline and wait inline (≤ ~8 s).
|
|
@@ -4794,19 +4867,29 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
4794
4867
|
* entitlements + the tier's recurring credits apply; `until` null =
|
|
4795
4868
|
* open-ended, else access ends at `until`. Idempotent on
|
|
4796
4869
|
* `idempotency_key` (a replay returns the first grant, `replayed: true`).
|
|
4797
|
-
* 422 unknown_tier when the tier is not in ledger.tierMap.
|
|
4870
|
+
* 422 unknown_tier when the tier is not in ledger.tierMap.
|
|
4871
|
+
* `charge_id` (optional) links the grant to the vxil charge (`chg_…`, from
|
|
4872
|
+
* `listCharges` or the `payments.charge.succeeded` / `.completed` event)
|
|
4873
|
+
* it was bought with: a FULL refund or chargeback of that charge ends the
|
|
4874
|
+
* grant (`payments.subscription.revoked` with `via: 'refund' | 'chargeback'`).
|
|
4875
|
+
* 404 charge_not_found; 422 charge_user_mismatch (another user's charge) /
|
|
4876
|
+
* charge_refunded (the refund beat the grant — nothing to grant against).
|
|
4877
|
+
* 422 reserved_idempotency_key when `idempotency_key` starts with
|
|
4878
|
+
* `purchase:` (the namespace of purchase passes). */
|
|
4798
4879
|
grantSubscription: (input: {
|
|
4799
4880
|
user_id: string;
|
|
4800
4881
|
tier: string;
|
|
4801
4882
|
until?: string | null;
|
|
4802
4883
|
reason: string;
|
|
4803
4884
|
idempotency_key: string;
|
|
4885
|
+
charge_id?: string | null;
|
|
4804
4886
|
}) => Promise<{
|
|
4805
4887
|
subscription_id: string | null;
|
|
4806
4888
|
user_id: string;
|
|
4807
4889
|
tier: string;
|
|
4808
4890
|
status: string;
|
|
4809
4891
|
until: string | null;
|
|
4892
|
+
charge_id: string | null;
|
|
4810
4893
|
replayed: boolean;
|
|
4811
4894
|
}>;
|
|
4812
4895
|
/** SERVER-ONLY. Revoke a MANUAL grant now (409 not_manual for a provider
|
|
@@ -4884,22 +4967,18 @@ export declare class Vxil<S extends VxilSchemaShape = VxilSchemaShape> {
|
|
|
4884
4967
|
} | null;
|
|
4885
4968
|
}>;
|
|
4886
4969
|
/** List charges newest-first (the refund enabler — discover the charge_id).
|
|
4887
|
-
* Filters: user_id, status, limit (clamped 1..100, default 50).
|
|
4970
|
+
* Filters: user_id, status, limit (clamped 1..100, default 50).
|
|
4971
|
+
* Each row carries the provider's own charge id (`provider_charge_id`),
|
|
4972
|
+
* the provider's charge state (`provider_status`: `'paid'` — Paddle's
|
|
4973
|
+
* money-taken state — or `'completed'`; null on rows recorded before
|
|
4974
|
+
* 2026-09-25) and the one-off `product_id` it bought, so a function can
|
|
4975
|
+
* match a charge to a provider event without reading the delivery log. */
|
|
4888
4976
|
listCharges: (q?: {
|
|
4889
4977
|
user_id?: string;
|
|
4890
4978
|
status?: "succeeded" | "failed" | "refunded" | "partially_refunded" | "pending";
|
|
4891
4979
|
limit?: number;
|
|
4892
4980
|
}) => 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
|
-
}>;
|
|
4981
|
+
charges: PaymentsCharge[];
|
|
4903
4982
|
}>;
|
|
4904
4983
|
/** Provider webhook event log (payments.md §7 "Event log & replay"):
|
|
4905
4984
|
* 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 });
|
|
@@ -1170,7 +1185,10 @@ export class Vxil {
|
|
|
1170
1185
|
* the SAME single-item delete path (restrict refusal, cascade budget,
|
|
1171
1186
|
* unique-claim freeing, CDC), so this is N deletes in one round trip, not
|
|
1172
1187
|
* a set-delete. `dryRun` reports `matched` and mutates nothing. Loop
|
|
1173
|
-
* while `deleted > 0`. A
|
|
1188
|
+
* while `deleted > 0`. A call stops STARTING rows after 8 s of wall
|
|
1189
|
+
* clock (the row in flight finishes; never before its first delete) and
|
|
1190
|
+
* answers `complete: false` + `next_cursor` (pass it as `cursor` to
|
|
1191
|
+
* resume the page). A refusal mid-sweep (409 referenced / 422
|
|
1174
1192
|
* cascade_too_large) stops the call — rows already deleted STAY deleted,
|
|
1175
1193
|
* and the error message names how many. Soft-deleted rows are hard-purged
|
|
1176
1194
|
* by the platform 30 days later (there is no per-tenant retention knob). */
|
|
@@ -1439,6 +1457,14 @@ export class Vxil {
|
|
|
1439
1457
|
unsubscribe: async (subId) => {
|
|
1440
1458
|
await this.call('DELETE', `/v1/webhooks/subscriptions/${encodeURIComponent(subId)}`);
|
|
1441
1459
|
},
|
|
1460
|
+
/**
|
|
1461
|
+
* Change a subscription's event filter in place (2026-09-25). The sub_id
|
|
1462
|
+
* and the delivery cursor are kept — nothing is replayed, nothing is
|
|
1463
|
+
* skipped; the new prefixes apply from the next delivery pass. An empty
|
|
1464
|
+
* array subscribes to every event. `target_url` is the subscription's
|
|
1465
|
+
* identity and is not editable: a new target is a new subscription.
|
|
1466
|
+
*/
|
|
1467
|
+
update: async (subId, input) => (await this.call('PATCH', `/v1/webhooks/subscriptions/${encodeURIComponent(subId)}`, input)).data,
|
|
1442
1468
|
/**
|
|
1443
1469
|
* Send a synthetic 'webhooks.test' event to the subscription's endpoint
|
|
1444
1470
|
* through the REAL signing+delivery pipeline and wait inline (≤ ~8 s).
|
|
@@ -1988,7 +2014,15 @@ export class Vxil {
|
|
|
1988
2014
|
* entitlements + the tier's recurring credits apply; `until` null =
|
|
1989
2015
|
* open-ended, else access ends at `until`. Idempotent on
|
|
1990
2016
|
* `idempotency_key` (a replay returns the first grant, `replayed: true`).
|
|
1991
|
-
* 422 unknown_tier when the tier is not in ledger.tierMap.
|
|
2017
|
+
* 422 unknown_tier when the tier is not in ledger.tierMap.
|
|
2018
|
+
* `charge_id` (optional) links the grant to the vxil charge (`chg_…`, from
|
|
2019
|
+
* `listCharges` or the `payments.charge.succeeded` / `.completed` event)
|
|
2020
|
+
* it was bought with: a FULL refund or chargeback of that charge ends the
|
|
2021
|
+
* grant (`payments.subscription.revoked` with `via: 'refund' | 'chargeback'`).
|
|
2022
|
+
* 404 charge_not_found; 422 charge_user_mismatch (another user's charge) /
|
|
2023
|
+
* charge_refunded (the refund beat the grant — nothing to grant against).
|
|
2024
|
+
* 422 reserved_idempotency_key when `idempotency_key` starts with
|
|
2025
|
+
* `purchase:` (the namespace of purchase passes). */
|
|
1992
2026
|
grantSubscription: async (input) => (await this.call('POST', '/v1/payments/subscriptions/grant', input)).data,
|
|
1993
2027
|
/** SERVER-ONLY. Revoke a MANUAL grant now (409 not_manual for a provider
|
|
1994
2028
|
* subscription — use `cancel`). Never touches a provider. */
|
|
@@ -2022,7 +2056,12 @@ export class Vxil {
|
|
|
2022
2056
|
* 403 `server_only`; the sweep is a tenant-wide operator surface. */
|
|
2023
2057
|
reconcile: async () => (await this.call('GET', '/v1/payments/reconcile')).data,
|
|
2024
2058
|
/** List charges newest-first (the refund enabler — discover the charge_id).
|
|
2025
|
-
* Filters: user_id, status, limit (clamped 1..100, default 50).
|
|
2059
|
+
* Filters: user_id, status, limit (clamped 1..100, default 50).
|
|
2060
|
+
* Each row carries the provider's own charge id (`provider_charge_id`),
|
|
2061
|
+
* the provider's charge state (`provider_status`: `'paid'` — Paddle's
|
|
2062
|
+
* money-taken state — or `'completed'`; null on rows recorded before
|
|
2063
|
+
* 2026-09-25) and the one-off `product_id` it bought, so a function can
|
|
2064
|
+
* match a charge to a provider event without reading the delivery log. */
|
|
2026
2065
|
listCharges: async (q) => {
|
|
2027
2066
|
const suffix = qs({
|
|
2028
2067
|
user_id: q?.user_id || undefined,
|
package/package.json
CHANGED