@cmdoss/suipay 0.1.0 → 0.1.1-dev.1
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 +4 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +204 -60
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -37,8 +37,10 @@ const quote = await client.quote(url, { body: JSON.stringify({ prompt: '...' })
|
|
|
37
37
|
const result = await client.pay(url, { quote });
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
Passing `quote` pins `payTo
|
|
41
|
-
|
|
40
|
+
Passing `quote` pins `payTo` and replays that quote's method, body, and
|
|
41
|
+
content type. A later offer cannot swap the recipient or the coin. `maxAmount`
|
|
42
|
+
can only tighten the quoted price, not raise it. A different body or content
|
|
43
|
+
type is refused before anything is signed.
|
|
42
44
|
|
|
43
45
|
## Which package?
|
|
44
46
|
|
package/dist/index.d.ts
CHANGED
|
@@ -16,12 +16,19 @@ interface Quote {
|
|
|
16
16
|
method: 'GET' | 'POST';
|
|
17
17
|
/** Exact POST bytes the probe sent. Absent for GET. */
|
|
18
18
|
body?: string;
|
|
19
|
+
/** Content type the probe sent. Null when the probe sent none. */
|
|
20
|
+
contentType: string | null;
|
|
19
21
|
}
|
|
20
22
|
interface QuoteRequest {
|
|
21
23
|
/** HTTP method the resource is sold at. Defaults to POST, same as the shared pay-flow. */
|
|
22
24
|
method?: 'GET' | 'POST';
|
|
23
25
|
/** POST probe body. Ignored for GET. Defaults to `{}`. */
|
|
24
26
|
body?: string;
|
|
27
|
+
/**
|
|
28
|
+
* POST content type. Undefined means `application/json`. Null means the
|
|
29
|
+
* probe sends no content type, which must match the later payment.
|
|
30
|
+
*/
|
|
31
|
+
contentType?: string | null;
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
interface ClientOptions {
|
|
@@ -47,8 +54,8 @@ interface PayRequest {
|
|
|
47
54
|
maxAmount?: string;
|
|
48
55
|
asset?: string;
|
|
49
56
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
57
|
+
* Omitted with no body is GET, including the price probe. A body makes it
|
|
58
|
+
* POST. A quote's method wins when this is omitted.
|
|
52
59
|
*/
|
|
53
60
|
method?: 'GET' | 'POST';
|
|
54
61
|
dialect?: Quote['dialect'];
|
package/dist/index.js
CHANGED
|
@@ -393,6 +393,32 @@ function createSpendAccountChain(options) {
|
|
|
393
393
|
kindBytes: toBase64(await tx.build({ client, onlyTransactionKind: true }))
|
|
394
394
|
};
|
|
395
395
|
}
|
|
396
|
+
function appendCreatePolicyGrant(tx, input) {
|
|
397
|
+
if (!input.onChainPolicyIds.length) {
|
|
398
|
+
throw new Error("create_grant requires at least one on-chain policy id");
|
|
399
|
+
}
|
|
400
|
+
if (!input.maxPerPayment || BigInt(input.maxPerPayment) <= 0n) {
|
|
401
|
+
throw new Error("create_grant requires a non-zero max_per_payment");
|
|
402
|
+
}
|
|
403
|
+
if (!input.sessionCap || BigInt(input.sessionCap) <= 0n) {
|
|
404
|
+
throw new Error("create_grant requires a non-zero session_cap");
|
|
405
|
+
}
|
|
406
|
+
const expires = input.expiresAtMs === void 0 || input.expiresAtMs === null ? 0n : BigInt(input.expiresAtMs);
|
|
407
|
+
tx.moveCall({
|
|
408
|
+
target: target("create_policy_grant"),
|
|
409
|
+
typeArguments: [input.coinType],
|
|
410
|
+
arguments: [
|
|
411
|
+
tx.object(input.poolObjectId),
|
|
412
|
+
tx.pure.address(input.delegate),
|
|
413
|
+
// The unified Grant<T> takes Option<u64> caps. This builder rejects
|
|
414
|
+
// absent or zero caps above, so both are always Some here.
|
|
415
|
+
tx.pure.option("u64", BigInt(input.sessionCap)),
|
|
416
|
+
tx.pure.option("u64", BigInt(input.maxPerPayment)),
|
|
417
|
+
tx.pure.u64(expires),
|
|
418
|
+
tx.pure.vector("u64", input.onChainPolicyIds.map((id) => BigInt(id)))
|
|
419
|
+
]
|
|
420
|
+
});
|
|
421
|
+
}
|
|
396
422
|
async function fundingCoin(tx, owner, coinType, amount) {
|
|
397
423
|
if (!isSuiCoinType(coinType)) {
|
|
398
424
|
return coinWithBalance({ type: coinType, balance: amount });
|
|
@@ -592,32 +618,23 @@ function createSpendAccountChain(options) {
|
|
|
592
618
|
return kindBytes(tx);
|
|
593
619
|
},
|
|
594
620
|
async buildCreateGrantKind(input) {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
621
|
+
const tx = new Transaction2();
|
|
622
|
+
tx.setSender(input.owner);
|
|
623
|
+
appendCreatePolicyGrant(tx, input);
|
|
624
|
+
return kindBytes(tx);
|
|
625
|
+
},
|
|
626
|
+
async buildCreateGrantBatchKind(inputs) {
|
|
627
|
+
if (!inputs.length) {
|
|
628
|
+
throw new Error("create_grant batch requires at least one grant");
|
|
600
629
|
}
|
|
601
|
-
|
|
602
|
-
|
|
630
|
+
const owner = inputs[0].owner;
|
|
631
|
+
if (inputs.some((input) => input.owner !== owner)) {
|
|
632
|
+
throw new Error("create_grant batch requires one owner");
|
|
603
633
|
}
|
|
604
634
|
const tx = new Transaction2();
|
|
605
|
-
tx.setSender(
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
target: target("create_policy_grant"),
|
|
609
|
-
typeArguments: [input.coinType],
|
|
610
|
-
arguments: [
|
|
611
|
-
tx.object(input.poolObjectId),
|
|
612
|
-
tx.pure.address(input.delegate),
|
|
613
|
-
// The unified Grant<T> takes Option<u64> caps. This builder rejects
|
|
614
|
-
// absent or zero caps above, so both are always Some here.
|
|
615
|
-
tx.pure.option("u64", BigInt(input.sessionCap)),
|
|
616
|
-
tx.pure.option("u64", BigInt(input.maxPerPayment)),
|
|
617
|
-
tx.pure.u64(expires),
|
|
618
|
-
tx.pure.vector("u64", input.onChainPolicyIds.map((id) => BigInt(id)))
|
|
619
|
-
]
|
|
620
|
-
});
|
|
635
|
+
tx.setSender(owner);
|
|
636
|
+
for (const input of inputs)
|
|
637
|
+
appendCreatePolicyGrant(tx, input);
|
|
621
638
|
return kindBytes(tx);
|
|
622
639
|
},
|
|
623
640
|
async buildCreateSpendGrantKind(input) {
|
|
@@ -6291,7 +6308,7 @@ var SECRET_KEY_SET = new Set(FORBIDDEN_SECRET_KEYS.map((k) => k.toLowerCase()));
|
|
|
6291
6308
|
|
|
6292
6309
|
// ../sdk/dist/agent-sdk/delegate-agent.js
|
|
6293
6310
|
function resolveExclusionDirectoryId(explicit, discovered) {
|
|
6294
|
-
return explicit
|
|
6311
|
+
return explicit?.trim() ? explicit : discovered;
|
|
6295
6312
|
}
|
|
6296
6313
|
function createExclusionRegistryResolver(client, exclusionDirectoryObjectId) {
|
|
6297
6314
|
if (!exclusionDirectoryObjectId || !exclusionDirectoryObjectId.trim())
|
|
@@ -6361,7 +6378,15 @@ async function createPayer(options) {
|
|
|
6361
6378
|
const { session, binding } = resolved.value;
|
|
6362
6379
|
const deployment = {
|
|
6363
6380
|
network: session.network,
|
|
6364
|
-
packageId: session.packageId
|
|
6381
|
+
packageId: session.packageId,
|
|
6382
|
+
// What the GATEWAY published, not what this payer settled on: a caller
|
|
6383
|
+
// override belongs to the payer's configuration, not to the deployment it
|
|
6384
|
+
// is describing. Dropping this left the field permanently undefined on the
|
|
6385
|
+
// one instance a consumer can reach, so anything asking the payer whether
|
|
6386
|
+
// guarded settles are available got "no" while it was doing them.
|
|
6387
|
+
...resolved.value.deployment.exclusionDirectoryObjectId ? {
|
|
6388
|
+
exclusionDirectoryObjectId: resolved.value.deployment.exclusionDirectoryObjectId
|
|
6389
|
+
} : {}
|
|
6365
6390
|
};
|
|
6366
6391
|
const exclusionDirectoryObjectId = resolveExclusionDirectoryId(options.exclusionDirectoryObjectId, resolved.value.deployment.exclusionDirectoryObjectId);
|
|
6367
6392
|
let network;
|
|
@@ -6478,18 +6503,25 @@ async function createPayer(options) {
|
|
|
6478
6503
|
}
|
|
6479
6504
|
|
|
6480
6505
|
// src/quote.ts
|
|
6481
|
-
function probeInit(method, body) {
|
|
6482
|
-
if (method === "GET") return { method: "GET" };
|
|
6506
|
+
function probeInit(method, body, contentType) {
|
|
6507
|
+
if (method === "GET") return { method: "GET", redirect: "manual" };
|
|
6508
|
+
const headers = {};
|
|
6509
|
+
if (contentType) headers["content-type"] = contentType;
|
|
6483
6510
|
return {
|
|
6484
6511
|
method: "POST",
|
|
6485
|
-
|
|
6512
|
+
redirect: "manual",
|
|
6513
|
+
headers,
|
|
6486
6514
|
body
|
|
6487
6515
|
};
|
|
6488
6516
|
}
|
|
6489
6517
|
async function quoteResource(url, fetchImpl = fetch, request = {}) {
|
|
6490
6518
|
const method = request.method === "GET" ? "GET" : "POST";
|
|
6491
|
-
const body = request.body ?? "{}";
|
|
6492
|
-
const
|
|
6519
|
+
const body = method === "POST" ? request.body ?? "{}" : "";
|
|
6520
|
+
const contentType = method === "GET" ? null : request.contentType === void 0 ? "application/json" : request.contentType;
|
|
6521
|
+
const response = await fetchImpl(url, probeInit(method, body, contentType));
|
|
6522
|
+
if (response.type === "opaqueredirect" || response.status >= 300 && response.status < 400) {
|
|
6523
|
+
throw new Error("quote refused a redirect");
|
|
6524
|
+
}
|
|
6493
6525
|
if (response.status !== 402) {
|
|
6494
6526
|
throw new Error(`quote expected HTTP 402, got ${response.status}`);
|
|
6495
6527
|
}
|
|
@@ -6509,7 +6541,8 @@ async function quoteResource(url, fetchImpl = fetch, request = {}) {
|
|
|
6509
6541
|
dialect: mppOffer ? "mpp" : "x402",
|
|
6510
6542
|
decimals: offer.decimals,
|
|
6511
6543
|
method,
|
|
6512
|
-
...method === "POST" ? { body } : {}
|
|
6544
|
+
...method === "POST" ? { body } : {},
|
|
6545
|
+
contentType
|
|
6513
6546
|
};
|
|
6514
6547
|
}
|
|
6515
6548
|
|
|
@@ -6545,18 +6578,86 @@ function contentTypeFrom(headers) {
|
|
|
6545
6578
|
}
|
|
6546
6579
|
return contentType;
|
|
6547
6580
|
}
|
|
6548
|
-
function
|
|
6549
|
-
|
|
6550
|
-
|
|
6581
|
+
function assertGatewayResource(resourceUrl, gatewayUrl) {
|
|
6582
|
+
let resource;
|
|
6583
|
+
let gateway;
|
|
6584
|
+
try {
|
|
6585
|
+
resource = new URL(resourceUrl);
|
|
6586
|
+
gateway = new URL(gatewayUrl);
|
|
6587
|
+
} catch {
|
|
6588
|
+
throw new Error("resource URL must be absolute http(s) on the gateway origin");
|
|
6551
6589
|
}
|
|
6552
|
-
|
|
6590
|
+
if (resource.protocol !== "http:" && resource.protocol !== "https:") {
|
|
6591
|
+
throw new Error("resource URL must be absolute http(s) on the gateway origin");
|
|
6592
|
+
}
|
|
6593
|
+
if (resource.origin !== gateway.origin) {
|
|
6594
|
+
throw new Error(
|
|
6595
|
+
`resource origin ${resource.origin} does not match gateway ${gateway.origin}`
|
|
6596
|
+
);
|
|
6597
|
+
}
|
|
6598
|
+
}
|
|
6599
|
+
function isPlainObject(value) {
|
|
6600
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
6601
|
+
const prototype = Object.getPrototypeOf(value);
|
|
6602
|
+
return prototype === Object.prototype || prototype === null;
|
|
6603
|
+
}
|
|
6604
|
+
function canonicalJson(value, seen = /* @__PURE__ */ new Set()) {
|
|
6605
|
+
if (value === null) return "null";
|
|
6606
|
+
const type = typeof value;
|
|
6607
|
+
if (type === "boolean") return value ? "true" : "false";
|
|
6608
|
+
if (type === "number") {
|
|
6609
|
+
if (!Number.isFinite(value)) {
|
|
6610
|
+
throw new Error("pay json must be finite; NaN and Infinity are not payable");
|
|
6611
|
+
}
|
|
6612
|
+
return JSON.stringify(value);
|
|
6613
|
+
}
|
|
6614
|
+
if (type === "string") return JSON.stringify(value);
|
|
6615
|
+
if (type === "bigint" || type === "undefined" || type === "function" || type === "symbol") {
|
|
6616
|
+
throw new Error(`pay json must not contain ${type}`);
|
|
6617
|
+
}
|
|
6618
|
+
const object = value;
|
|
6619
|
+
if (typeof object.toJSON === "function") {
|
|
6620
|
+
throw new Error("pay json must be a plain object; toJSON is not payable");
|
|
6621
|
+
}
|
|
6622
|
+
if (seen.has(object)) throw new Error("pay json must not be cyclic");
|
|
6623
|
+
seen.add(object);
|
|
6624
|
+
try {
|
|
6625
|
+
if (Array.isArray(object)) {
|
|
6626
|
+
return `[${object.map((item) => canonicalJson(item, seen)).join(",")}]`;
|
|
6627
|
+
}
|
|
6628
|
+
if (!isPlainObject(object)) throw new Error("pay json must be a plain object");
|
|
6629
|
+
const entries = Object.entries(object).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
6630
|
+
return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item, seen)}`).join(",")}}`;
|
|
6631
|
+
} finally {
|
|
6632
|
+
seen.delete(object);
|
|
6633
|
+
}
|
|
6634
|
+
}
|
|
6635
|
+
function jsonBody(value) {
|
|
6636
|
+
if (!isPlainObject(value)) throw new Error("pay json must be a plain object");
|
|
6637
|
+
return canonicalJson(value);
|
|
6553
6638
|
}
|
|
6554
6639
|
function hasBytes(body) {
|
|
6555
6640
|
if (body === void 0) return false;
|
|
6556
6641
|
if (typeof body === "string") return body.length > 0;
|
|
6557
6642
|
return body.byteLength > 0;
|
|
6558
6643
|
}
|
|
6559
|
-
function
|
|
6644
|
+
function sameBytes(left, right) {
|
|
6645
|
+
if (left.byteLength !== right.byteLength) return false;
|
|
6646
|
+
for (let i = 0; i < left.byteLength; i += 1) {
|
|
6647
|
+
if (left[i] !== right[i]) return false;
|
|
6648
|
+
}
|
|
6649
|
+
return true;
|
|
6650
|
+
}
|
|
6651
|
+
function asBytes(body) {
|
|
6652
|
+
return typeof body === "string" ? new TextEncoder().encode(body) : body;
|
|
6653
|
+
}
|
|
6654
|
+
function integerAmount(value, label) {
|
|
6655
|
+
if (!/^[0-9]+$/.test(value)) {
|
|
6656
|
+
throw new Error(`${label} must be a non-negative integer`);
|
|
6657
|
+
}
|
|
6658
|
+
return BigInt(value);
|
|
6659
|
+
}
|
|
6660
|
+
function freezePay(url, input) {
|
|
6560
6661
|
const quoted = input?.quote;
|
|
6561
6662
|
if (quoted && quoted.resource !== url) {
|
|
6562
6663
|
throw new Error("pay quote.resource must match the URL being paid");
|
|
@@ -6564,39 +6665,79 @@ function resolvePay(url, input) {
|
|
|
6564
6665
|
if (input?.json !== void 0 && input.body !== void 0) {
|
|
6565
6666
|
throw new Error("pay accepts json or body, not both");
|
|
6566
6667
|
}
|
|
6567
|
-
|
|
6668
|
+
const headerType = contentTypeFrom(input?.headers) ?? null;
|
|
6568
6669
|
let body;
|
|
6670
|
+
let contentType = headerType;
|
|
6569
6671
|
if (input?.json !== void 0) {
|
|
6570
6672
|
body = jsonBody(input.json);
|
|
6571
|
-
contentType =
|
|
6673
|
+
contentType = headerType ?? "application/json";
|
|
6674
|
+
} else if (typeof input?.body === "string") {
|
|
6675
|
+
body = input.body;
|
|
6676
|
+
contentType = headerType ?? "application/json";
|
|
6572
6677
|
} else if (input?.body !== void 0) {
|
|
6573
6678
|
body = input.body;
|
|
6574
6679
|
} else if (typeof quoted?.body === "string") {
|
|
6575
6680
|
body = quoted.body;
|
|
6576
|
-
|
|
6681
|
+
contentType = headerType ?? quoted.contentType;
|
|
6682
|
+
}
|
|
6683
|
+
const method = input?.method ?? quoted?.method ?? (body !== void 0 ? "POST" : "GET");
|
|
6684
|
+
if (quoted && input?.method && input.method !== quoted.method) {
|
|
6685
|
+
throw new Error("pay method must match the quote");
|
|
6577
6686
|
}
|
|
6578
|
-
const method = input?.method ?? quoted?.method ?? (body !== void 0 ? "POST" : void 0);
|
|
6579
6687
|
if (method === "GET" && hasBytes(body)) {
|
|
6580
6688
|
throw new Error('pay GET cannot carry a body; pass method: "POST"');
|
|
6581
6689
|
}
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
function toPayInput(url, input, resolved) {
|
|
6585
|
-
const quoted = resolved.quote;
|
|
6586
|
-
const maxAmount = input?.maxAmount?.trim() || quoted?.amount;
|
|
6587
|
-
const asset = input?.asset?.trim() || quoted?.asset;
|
|
6588
|
-
if (!maxAmount || !asset) {
|
|
6589
|
-
throw new Error("pay requires maxAmount and asset (or a quote that carries them)");
|
|
6690
|
+
if (method === "GET" && contentType) {
|
|
6691
|
+
throw new Error("pay GET cannot declare a content type");
|
|
6590
6692
|
}
|
|
6591
|
-
|
|
6592
|
-
|
|
6693
|
+
if (quoted) {
|
|
6694
|
+
if ((contentType ?? null) !== (quoted.contentType ?? null)) {
|
|
6695
|
+
throw new Error("pay content type must match the quote");
|
|
6696
|
+
}
|
|
6697
|
+
if (quoted.body !== void 0 || body !== void 0) {
|
|
6698
|
+
const quotedBytes = new TextEncoder().encode(quoted.body ?? "");
|
|
6699
|
+
const paidBytes = body === void 0 ? new Uint8Array() : asBytes(body);
|
|
6700
|
+
if (!sameBytes(quotedBytes, paidBytes)) {
|
|
6701
|
+
throw new Error("pay body must match the quoted bytes");
|
|
6702
|
+
}
|
|
6703
|
+
}
|
|
6704
|
+
}
|
|
6705
|
+
return { method, body, contentType, quote: quoted };
|
|
6706
|
+
}
|
|
6707
|
+
function spendCeiling(input, quote2) {
|
|
6708
|
+
if (!quote2) {
|
|
6709
|
+
const maxAmount2 = input?.maxAmount?.trim();
|
|
6710
|
+
const asset = input?.asset?.trim();
|
|
6711
|
+
if (!maxAmount2 || !asset) {
|
|
6712
|
+
throw new Error("pay requires maxAmount and asset (or a quote that carries them)");
|
|
6713
|
+
}
|
|
6714
|
+
integerAmount(maxAmount2, "maxAmount");
|
|
6715
|
+
return { maxAmount: maxAmount2, asset };
|
|
6716
|
+
}
|
|
6717
|
+
const callerAsset = input?.asset?.trim();
|
|
6718
|
+
if (callerAsset && callerAsset !== quote2.asset) {
|
|
6719
|
+
throw new Error("pay asset must match the quote");
|
|
6720
|
+
}
|
|
6721
|
+
const quoted = integerAmount(quote2.amount.trim(), "quote.amount");
|
|
6722
|
+
let maxAmount = quote2.amount.trim();
|
|
6723
|
+
const callerRaw = input?.maxAmount?.trim();
|
|
6724
|
+
if (callerRaw) {
|
|
6725
|
+
const caller = integerAmount(callerRaw, "maxAmount");
|
|
6726
|
+
if (caller < quoted) maxAmount = callerRaw;
|
|
6727
|
+
}
|
|
6728
|
+
return { maxAmount, asset: quote2.asset };
|
|
6729
|
+
}
|
|
6730
|
+
function toPayInput(resolved, quote2, input) {
|
|
6731
|
+
const { maxAmount, asset } = spendCeiling(input, quote2);
|
|
6732
|
+
const dialect = input?.dialect ?? quote2?.dialect;
|
|
6733
|
+
const recipient = quote2?.payTo;
|
|
6593
6734
|
return {
|
|
6594
6735
|
intent: {
|
|
6595
6736
|
maxAmount,
|
|
6596
6737
|
asset,
|
|
6597
6738
|
...recipient ? { recipient } : {}
|
|
6598
6739
|
},
|
|
6599
|
-
|
|
6740
|
+
method: resolved.method,
|
|
6600
6741
|
...dialect ? { dialect } : {},
|
|
6601
6742
|
...resolved.body !== void 0 ? { body: resolved.body } : {},
|
|
6602
6743
|
...resolved.contentType ? { contentType: resolved.contentType } : {}
|
|
@@ -6617,23 +6758,26 @@ async function createClient(options) {
|
|
|
6617
6758
|
const payer = created.value;
|
|
6618
6759
|
return {
|
|
6619
6760
|
quote(url, request) {
|
|
6761
|
+
assertGatewayResource(url, gatewayUrl);
|
|
6620
6762
|
return quoteResource(url, fetchImpl ?? fetch, request);
|
|
6621
6763
|
},
|
|
6622
6764
|
async pay(url, input) {
|
|
6623
|
-
|
|
6624
|
-
const
|
|
6765
|
+
assertGatewayResource(url, gatewayUrl);
|
|
6766
|
+
const frozen = freezePay(url, input);
|
|
6767
|
+
const priced = input?.maxAmount?.trim() || input?.asset?.trim() || frozen.quote;
|
|
6768
|
+
let quote2 = frozen.quote;
|
|
6625
6769
|
if (!priced) {
|
|
6626
|
-
if (
|
|
6770
|
+
if (frozen.body instanceof Uint8Array) {
|
|
6627
6771
|
throw new Error("pay requires maxAmount and asset when body is raw bytes");
|
|
6628
6772
|
}
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
...typeof
|
|
6773
|
+
quote2 = await quoteResource(url, fetchImpl ?? fetch, {
|
|
6774
|
+
method: frozen.method,
|
|
6775
|
+
...typeof frozen.body === "string" ? { body: frozen.body } : {},
|
|
6776
|
+
contentType: frozen.contentType
|
|
6632
6777
|
});
|
|
6633
|
-
resolved = resolvePay(url, { ...input, quote: quote2 });
|
|
6634
6778
|
}
|
|
6635
|
-
const paid = await payer.pay(url, toPayInput(
|
|
6636
|
-
return
|
|
6779
|
+
const paid = await payer.pay(url, toPayInput(frozen, quote2, input));
|
|
6780
|
+
return quote2 ? { ...paid, quote: quote2 } : paid;
|
|
6637
6781
|
}
|
|
6638
6782
|
};
|
|
6639
6783
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmdoss/suipay",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1-dev.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"description": "SuiPay embeddable client
|
|
6
|
+
"description": "SuiPay embeddable client — quote and pay a 402 from a spend-account grant.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=20"
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"README.md"
|
|
22
22
|
],
|
|
23
23
|
"publishConfig": {
|
|
24
|
-
"access": "public"
|
|
24
|
+
"access": "public",
|
|
25
|
+
"provenance": false
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
28
|
"@mysten/sui": "2.24.0"
|
|
@@ -30,11 +31,13 @@
|
|
|
30
31
|
"@types/node": "^26",
|
|
31
32
|
"tsup": "^8.0.0",
|
|
32
33
|
"typescript": "^6.0.3",
|
|
33
|
-
"vitest": "^4.1.10"
|
|
34
|
+
"vitest": "^4.1.10",
|
|
35
|
+
"@cmdoss/suipay-sdk": "0.1.0",
|
|
36
|
+
"@cmdoss/suipay-core": "0.1.0"
|
|
34
37
|
},
|
|
35
38
|
"scripts": {
|
|
36
39
|
"build": "tsup",
|
|
37
40
|
"test": "vitest run",
|
|
38
41
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
39
42
|
}
|
|
40
|
-
}
|
|
43
|
+
}
|