@cmdoss/suipay-mcp 0.2.2-dev.8 → 0.2.2-dev.9
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
CHANGED
|
@@ -5,13 +5,13 @@ buyer-funded spend account. The buyer owns the account. The agent holds the
|
|
|
5
5
|
delegate key and can spend only under the on-chain grant (recipient bind,
|
|
6
6
|
per-payment cap, budget).
|
|
7
7
|
|
|
8
|
-
Pin `@cmdoss/suipay-mcp@0.2.2` in MCP config. `1.0.1` remains on the
|
|
8
|
+
Pin `@cmdoss/suipay-mcp@0.2.2-dev.9` in MCP config. `1.0.1` remains on the
|
|
9
9
|
registry as a historical release; do not install it for new agents.
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
claude mcp add --scope user suipay -- npx -y @cmdoss/suipay-mcp@0.2.2
|
|
14
|
+
claude mcp add --scope user suipay -- npx -y @cmdoss/suipay-mcp@0.2.2-dev.9
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
No wallet secret belongs in this command or MCP config. There is no
|
|
@@ -112,10 +112,10 @@ Default is Railway **suipay-dev**. `--local` / `target: "local"` is laptop-only.
|
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
114
|
# Railway suipay-dev (default)
|
|
115
|
-
npx @cmdoss/suipay-mcp@0.2.2
|
|
115
|
+
npx @cmdoss/suipay-mcp@0.2.2-dev.9
|
|
116
116
|
|
|
117
117
|
# Laptop stack
|
|
118
|
-
npx @cmdoss/suipay-mcp@0.2.2 --local
|
|
118
|
+
npx @cmdoss/suipay-mcp@0.2.2-dev.9 --local
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
`SUIPAY_MCP_TARGET=local|dev` selects the same preset. Explicit
|
package/dist/bin/suipay.js
CHANGED
|
@@ -538,6 +538,32 @@ function createSpendAccountChain(options) {
|
|
|
538
538
|
kindBytes: toBase64(await tx.build({ client, onlyTransactionKind: true }))
|
|
539
539
|
};
|
|
540
540
|
}
|
|
541
|
+
function appendCreatePolicyGrant(tx, input) {
|
|
542
|
+
if (!input.onChainPolicyIds.length) {
|
|
543
|
+
throw new Error("create_grant requires at least one on-chain policy id");
|
|
544
|
+
}
|
|
545
|
+
if (!input.maxPerPayment || BigInt(input.maxPerPayment) <= 0n) {
|
|
546
|
+
throw new Error("create_grant requires a non-zero max_per_payment");
|
|
547
|
+
}
|
|
548
|
+
if (!input.sessionCap || BigInt(input.sessionCap) <= 0n) {
|
|
549
|
+
throw new Error("create_grant requires a non-zero session_cap");
|
|
550
|
+
}
|
|
551
|
+
const expires = input.expiresAtMs === void 0 || input.expiresAtMs === null ? 0n : BigInt(input.expiresAtMs);
|
|
552
|
+
tx.moveCall({
|
|
553
|
+
target: target("create_policy_grant"),
|
|
554
|
+
typeArguments: [input.coinType],
|
|
555
|
+
arguments: [
|
|
556
|
+
tx.object(input.poolObjectId),
|
|
557
|
+
tx.pure.address(input.delegate),
|
|
558
|
+
// The unified Grant<T> takes Option<u64> caps. This builder rejects
|
|
559
|
+
// absent or zero caps above, so both are always Some here.
|
|
560
|
+
tx.pure.option("u64", BigInt(input.sessionCap)),
|
|
561
|
+
tx.pure.option("u64", BigInt(input.maxPerPayment)),
|
|
562
|
+
tx.pure.u64(expires),
|
|
563
|
+
tx.pure.vector("u64", input.onChainPolicyIds.map((id) => BigInt(id)))
|
|
564
|
+
]
|
|
565
|
+
});
|
|
566
|
+
}
|
|
541
567
|
async function fundingCoin(tx, owner, coinType, amount) {
|
|
542
568
|
if (!isSuiCoinType(coinType)) {
|
|
543
569
|
return coinWithBalance({ type: coinType, balance: amount });
|
|
@@ -737,32 +763,23 @@ function createSpendAccountChain(options) {
|
|
|
737
763
|
return kindBytes(tx);
|
|
738
764
|
},
|
|
739
765
|
async buildCreateGrantKind(input) {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
766
|
+
const tx = new Transaction2();
|
|
767
|
+
tx.setSender(input.owner);
|
|
768
|
+
appendCreatePolicyGrant(tx, input);
|
|
769
|
+
return kindBytes(tx);
|
|
770
|
+
},
|
|
771
|
+
async buildCreateGrantBatchKind(inputs) {
|
|
772
|
+
if (!inputs.length) {
|
|
773
|
+
throw new Error("create_grant batch requires at least one grant");
|
|
745
774
|
}
|
|
746
|
-
|
|
747
|
-
|
|
775
|
+
const owner = inputs[0].owner;
|
|
776
|
+
if (inputs.some((input) => input.owner !== owner)) {
|
|
777
|
+
throw new Error("create_grant batch requires one owner");
|
|
748
778
|
}
|
|
749
779
|
const tx = new Transaction2();
|
|
750
|
-
tx.setSender(
|
|
751
|
-
const
|
|
752
|
-
|
|
753
|
-
target: target("create_policy_grant"),
|
|
754
|
-
typeArguments: [input.coinType],
|
|
755
|
-
arguments: [
|
|
756
|
-
tx.object(input.poolObjectId),
|
|
757
|
-
tx.pure.address(input.delegate),
|
|
758
|
-
// The unified Grant<T> takes Option<u64> caps. This builder rejects
|
|
759
|
-
// absent or zero caps above, so both are always Some here.
|
|
760
|
-
tx.pure.option("u64", BigInt(input.sessionCap)),
|
|
761
|
-
tx.pure.option("u64", BigInt(input.maxPerPayment)),
|
|
762
|
-
tx.pure.u64(expires),
|
|
763
|
-
tx.pure.vector("u64", input.onChainPolicyIds.map((id) => BigInt(id)))
|
|
764
|
-
]
|
|
765
|
-
});
|
|
780
|
+
tx.setSender(owner);
|
|
781
|
+
for (const input of inputs)
|
|
782
|
+
appendCreatePolicyGrant(tx, input);
|
|
766
783
|
return kindBytes(tx);
|
|
767
784
|
},
|
|
768
785
|
async buildCreateSpendGrantKind(input) {
|
|
@@ -5563,7 +5580,7 @@ var MCP_TARGET_PRESETS = {
|
|
|
5563
5580
|
gatewayUrl: "https://gateway-dev-ba84.up.railway.app"
|
|
5564
5581
|
},
|
|
5565
5582
|
local: {
|
|
5566
|
-
consoleUrl: "
|
|
5583
|
+
consoleUrl: "https://suipay-dev.up.railway.app",
|
|
5567
5584
|
gatewayUrl: "http://127.0.0.1:4340"
|
|
5568
5585
|
}
|
|
5569
5586
|
};
|
|
@@ -5996,9 +6013,29 @@ function recordFromKeypair(kp, opts = {}, existing, operatorSecret) {
|
|
|
5996
6013
|
};
|
|
5997
6014
|
}
|
|
5998
6015
|
var ENV_KEY_MISMATCH = "SUIPAY_MCP_KEY does not match the stored delegate key - refusing to overwrite";
|
|
6016
|
+
function signingMaterial(parsed) {
|
|
6017
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
6018
|
+
if (isLocalSigningKeyRecord(parsed)) return parsed;
|
|
6019
|
+
const c = parsed;
|
|
6020
|
+
if (typeof c.delegatePrivateKey !== "string" || !HEX64.test(c.delegatePrivateKey) || typeof c.delegatePublicKeyHex !== "string" || !HEX64.test(c.delegatePublicKeyHex) || typeof c.delegateAddress !== "string" || !ADDR.test(c.delegateAddress)) {
|
|
6021
|
+
return null;
|
|
6022
|
+
}
|
|
6023
|
+
const label = typeof c.label === "string" ? c.label.trim() : "";
|
|
6024
|
+
return {
|
|
6025
|
+
version: 2,
|
|
6026
|
+
delegatePrivateKey: c.delegatePrivateKey,
|
|
6027
|
+
delegatePublicKeyHex: c.delegatePublicKeyHex,
|
|
6028
|
+
delegateAddress: c.delegateAddress,
|
|
6029
|
+
createdAt: typeof c.createdAt === "string" && c.createdAt ? c.createdAt : (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
6030
|
+
...isHttpUrl(c.gatewayUrl) ? { gatewayUrl: c.gatewayUrl } : {},
|
|
6031
|
+
...label ? { label } : {}
|
|
6032
|
+
};
|
|
6033
|
+
}
|
|
5999
6034
|
function existingRecordForEnv(parsed) {
|
|
6000
6035
|
if (parsed === null) return null;
|
|
6001
|
-
if (
|
|
6036
|
+
if (isValid(parsed)) return parsed;
|
|
6037
|
+
const material = signingMaterial(parsed);
|
|
6038
|
+
if (material) return material;
|
|
6002
6039
|
throw new Error(
|
|
6003
6040
|
`credentials file at ${credsPath()} failed schema validation - refusing to continue`
|
|
6004
6041
|
);
|
|
@@ -6036,16 +6073,25 @@ async function ensureLocalSigningKey(opts = {}) {
|
|
|
6036
6073
|
}
|
|
6037
6074
|
const parsed = readCredentialsJson();
|
|
6038
6075
|
if (parsed !== null) {
|
|
6039
|
-
if (isLocalSigningKeyRecord(parsed)) {
|
|
6040
|
-
return identityFromStored(
|
|
6041
|
-
parsed.delegatePrivateKey,
|
|
6042
|
-
parsed.delegatePublicKeyHex,
|
|
6043
|
-
parsed.delegateAddress
|
|
6044
|
-
);
|
|
6045
|
-
}
|
|
6046
|
-
if (isValid(parsed)) {
|
|
6076
|
+
if (isValid(parsed) && !isLocalSigningKeyRecord(parsed)) {
|
|
6047
6077
|
return rewriteV1ToLocalSigningKey(parsed, opts);
|
|
6048
6078
|
}
|
|
6079
|
+
const material = signingMaterial(parsed);
|
|
6080
|
+
if (material) {
|
|
6081
|
+
const identity = identityFromStored(
|
|
6082
|
+
material.delegatePrivateKey,
|
|
6083
|
+
material.delegatePublicKeyHex,
|
|
6084
|
+
material.delegateAddress
|
|
6085
|
+
);
|
|
6086
|
+
if (!isLocalSigningKeyRecord(parsed)) {
|
|
6087
|
+
const label = opts.label?.trim() || material.label;
|
|
6088
|
+
writeCredentialsFile({
|
|
6089
|
+
...material,
|
|
6090
|
+
...label ? { label } : {}
|
|
6091
|
+
});
|
|
6092
|
+
}
|
|
6093
|
+
return identity;
|
|
6094
|
+
}
|
|
6049
6095
|
throw new Error(`credentials file at ${credsPath()} failed schema validation - refusing to continue`);
|
|
6050
6096
|
}
|
|
6051
6097
|
const kp = await generateKeypair();
|
|
@@ -6136,6 +6182,32 @@ function loadLocalKeypair() {
|
|
|
6136
6182
|
Uint8Array.from(Buffer.from(parsed.delegatePrivateKey, "hex"))
|
|
6137
6183
|
);
|
|
6138
6184
|
}
|
|
6185
|
+
function replaceLocalSigningKey(input) {
|
|
6186
|
+
identityFromStored(
|
|
6187
|
+
input.delegatePrivateKey,
|
|
6188
|
+
input.delegatePublicKeyHex,
|
|
6189
|
+
input.delegateAddress
|
|
6190
|
+
);
|
|
6191
|
+
const parsed = readCredentialsJson();
|
|
6192
|
+
let gatewayUrl;
|
|
6193
|
+
let label;
|
|
6194
|
+
if (parsed && typeof parsed === "object") {
|
|
6195
|
+
const record = parsed;
|
|
6196
|
+
if (isHttpUrl(record.gatewayUrl)) gatewayUrl = record.gatewayUrl;
|
|
6197
|
+
if (typeof record.label === "string" && record.label.trim()) {
|
|
6198
|
+
label = record.label.trim();
|
|
6199
|
+
}
|
|
6200
|
+
}
|
|
6201
|
+
writeCredentialsFile({
|
|
6202
|
+
version: 2,
|
|
6203
|
+
delegatePrivateKey: input.delegatePrivateKey,
|
|
6204
|
+
delegatePublicKeyHex: input.delegatePublicKeyHex,
|
|
6205
|
+
delegateAddress: input.delegateAddress,
|
|
6206
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6207
|
+
...gatewayUrl ? { gatewayUrl } : {},
|
|
6208
|
+
...label ? { label } : {}
|
|
6209
|
+
});
|
|
6210
|
+
}
|
|
6139
6211
|
function persistGatewayUrl(gatewayUrl) {
|
|
6140
6212
|
if (!isHttpUrl(gatewayUrl)) {
|
|
6141
6213
|
throw new Error("gatewayUrl must be an http(s) origin");
|
|
@@ -7146,7 +7218,7 @@ var SECRET_KEY_SET = new Set(FORBIDDEN_SECRET_KEYS.map((k) => k.toLowerCase()));
|
|
|
7146
7218
|
|
|
7147
7219
|
// ../sdk/dist/agent-sdk/delegate-agent.js
|
|
7148
7220
|
function resolveExclusionDirectoryId(explicit, discovered) {
|
|
7149
|
-
return explicit
|
|
7221
|
+
return explicit?.trim() ? explicit : discovered;
|
|
7150
7222
|
}
|
|
7151
7223
|
function createExclusionRegistryResolver(client, exclusionDirectoryObjectId) {
|
|
7152
7224
|
if (!exclusionDirectoryObjectId || !exclusionDirectoryObjectId.trim())
|
|
@@ -7216,7 +7288,15 @@ async function createPayer(options) {
|
|
|
7216
7288
|
const { session, binding } = resolved.value;
|
|
7217
7289
|
const deployment = {
|
|
7218
7290
|
network: session.network,
|
|
7219
|
-
packageId: session.packageId
|
|
7291
|
+
packageId: session.packageId,
|
|
7292
|
+
// What the GATEWAY published, not what this payer settled on: a caller
|
|
7293
|
+
// override belongs to the payer's configuration, not to the deployment it
|
|
7294
|
+
// is describing. Dropping this left the field permanently undefined on the
|
|
7295
|
+
// one instance a consumer can reach, so anything asking the payer whether
|
|
7296
|
+
// guarded settles are available got "no" while it was doing them.
|
|
7297
|
+
...resolved.value.deployment.exclusionDirectoryObjectId ? {
|
|
7298
|
+
exclusionDirectoryObjectId: resolved.value.deployment.exclusionDirectoryObjectId
|
|
7299
|
+
} : {}
|
|
7220
7300
|
};
|
|
7221
7301
|
const exclusionDirectoryObjectId = resolveExclusionDirectoryId(options.exclusionDirectoryObjectId, resolved.value.deployment.exclusionDirectoryObjectId);
|
|
7222
7302
|
let network;
|
|
@@ -7336,6 +7416,7 @@ async function createPayer(options) {
|
|
|
7336
7416
|
import { createServer } from "http";
|
|
7337
7417
|
import { randomBytes as randomBytes3, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
7338
7418
|
import open from "open";
|
|
7419
|
+
import { Ed25519Keypair as Ed25519Keypair3 } from "@mysten/sui/keypairs/ed25519";
|
|
7339
7420
|
var HEX642 = /^[0-9a-f]{64}$/;
|
|
7340
7421
|
var PUBHEX = /^[0-9a-fA-F]{64}$/;
|
|
7341
7422
|
function isPreflight(obj) {
|
|
@@ -7343,6 +7424,11 @@ function isPreflight(obj) {
|
|
|
7343
7424
|
const o = obj;
|
|
7344
7425
|
return typeof o.state === "string" && HEX642.test(o.state) && typeof o.publicKey === "string" && PUBHEX.test(o.publicKey) && typeof o.delegateAddress === "string" && /^0x[0-9a-fA-F]{64}$/.test(o.delegateAddress) && typeof o.gateway === "string" && o.gateway.length > 0;
|
|
7345
7426
|
}
|
|
7427
|
+
function isAdoptKey(obj) {
|
|
7428
|
+
if (!obj || typeof obj !== "object") return false;
|
|
7429
|
+
const o = obj;
|
|
7430
|
+
return typeof o.state === "string" && HEX642.test(o.state) && typeof o.delegatePrivateKey === "string" && HEX642.test(o.delegatePrivateKey) && typeof o.delegatePublicKeyHex === "string" && PUBHEX.test(o.delegatePublicKeyHex) && typeof o.delegateAddress === "string" && /^0x[0-9a-fA-F]{64}$/.test(o.delegateAddress);
|
|
7431
|
+
}
|
|
7346
7432
|
function isCallback(obj) {
|
|
7347
7433
|
if (!obj || typeof obj !== "object") return false;
|
|
7348
7434
|
const o = obj;
|
|
@@ -7467,7 +7553,7 @@ async function startStdioLogin(opts) {
|
|
|
7467
7553
|
res.writeHead(code, { "content-type": type, ...SECURITY_HEADERS, ...extra });
|
|
7468
7554
|
res.end(body);
|
|
7469
7555
|
};
|
|
7470
|
-
const okPath = url.pathname === "/preflight" || url.pathname === "/callback";
|
|
7556
|
+
const okPath = url.pathname === "/preflight" || url.pathname === "/callback" || url.pathname === "/key";
|
|
7471
7557
|
if (req.method === "OPTIONS") {
|
|
7472
7558
|
const extra = { ...cors };
|
|
7473
7559
|
if (okHost && okOrigin && okPath && req.headers["access-control-request-private-network"] === "true") {
|
|
@@ -7538,6 +7624,55 @@ async function startStdioLogin(opts) {
|
|
|
7538
7624
|
);
|
|
7539
7625
|
return;
|
|
7540
7626
|
}
|
|
7627
|
+
if (url.pathname === "/key") {
|
|
7628
|
+
if (!preflightVerified) {
|
|
7629
|
+
res.writeHead(428, {
|
|
7630
|
+
"content-type": "application/json",
|
|
7631
|
+
...cors,
|
|
7632
|
+
...SECURITY_HEADERS
|
|
7633
|
+
});
|
|
7634
|
+
res.end(JSON.stringify({ ok: false, error: "preflight required" }));
|
|
7635
|
+
return;
|
|
7636
|
+
}
|
|
7637
|
+
if (!isAdoptKey(parsed) || !stateEquals(parsed.state, connectState)) {
|
|
7638
|
+
res.writeHead(400, {
|
|
7639
|
+
"content-type": "application/json",
|
|
7640
|
+
...cors,
|
|
7641
|
+
...SECURITY_HEADERS
|
|
7642
|
+
});
|
|
7643
|
+
res.end(JSON.stringify({ ok: false, error: "invalid key payload" }));
|
|
7644
|
+
return;
|
|
7645
|
+
}
|
|
7646
|
+
try {
|
|
7647
|
+
const kp = Ed25519Keypair3.fromSecretKey(
|
|
7648
|
+
Uint8Array.from(Buffer.from(parsed.delegatePrivateKey, "hex"))
|
|
7649
|
+
);
|
|
7650
|
+
const derived = kp.getPublicKey().toSuiAddress();
|
|
7651
|
+
if (derived.toLowerCase() !== parsed.delegateAddress.toLowerCase()) {
|
|
7652
|
+
throw new Error("address mismatch");
|
|
7653
|
+
}
|
|
7654
|
+
replaceLocalSigningKey({
|
|
7655
|
+
delegatePrivateKey: parsed.delegatePrivateKey,
|
|
7656
|
+
delegatePublicKeyHex: parsed.delegatePublicKeyHex,
|
|
7657
|
+
delegateAddress: derived
|
|
7658
|
+
});
|
|
7659
|
+
} catch {
|
|
7660
|
+
res.writeHead(400, {
|
|
7661
|
+
"content-type": "application/json",
|
|
7662
|
+
...cors,
|
|
7663
|
+
...SECURITY_HEADERS
|
|
7664
|
+
});
|
|
7665
|
+
res.end(JSON.stringify({ ok: false, error: "key rejected" }));
|
|
7666
|
+
return;
|
|
7667
|
+
}
|
|
7668
|
+
res.writeHead(200, {
|
|
7669
|
+
"content-type": "application/json",
|
|
7670
|
+
...cors,
|
|
7671
|
+
...SECURITY_HEADERS
|
|
7672
|
+
});
|
|
7673
|
+
res.end(JSON.stringify({ ok: true }));
|
|
7674
|
+
return;
|
|
7675
|
+
}
|
|
7541
7676
|
if (!preflightVerified) {
|
|
7542
7677
|
res.writeHead(428, {
|
|
7543
7678
|
"content-type": "text/html",
|
|
@@ -9099,10 +9234,15 @@ async function suipayLogin(args, cfg, deps = {}) {
|
|
|
9099
9234
|
});
|
|
9100
9235
|
}
|
|
9101
9236
|
if (live.kind === "unknown") {
|
|
9102
|
-
return
|
|
9103
|
-
status: "
|
|
9237
|
+
return text({
|
|
9238
|
+
status: "ok",
|
|
9239
|
+
reused: true,
|
|
9240
|
+
grantStatus: "unknown",
|
|
9104
9241
|
code: "GRANT_STATUS_UNKNOWN",
|
|
9105
|
-
|
|
9242
|
+
target: target ?? cfg.target,
|
|
9243
|
+
delegateAddress: identity.delegateAddress,
|
|
9244
|
+
gatewayUrl: endpoints.gatewayUrl,
|
|
9245
|
+
message: "Credentials are already saved for this agent. The existing grant could not be checked just now, so no new sign-in was started and the key file was left unchanged. Retry suipay_login in a moment."
|
|
9106
9246
|
});
|
|
9107
9247
|
}
|
|
9108
9248
|
}
|
package/dist/http.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadBootProfile,
|
|
3
3
|
main
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-LQOZBRH6.js";
|
|
5
5
|
import {
|
|
6
6
|
MCP_TARGET_PRESETS,
|
|
7
7
|
PACKAGE_NAME,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
settlePreparedMcpPayment,
|
|
27
27
|
traceMcpHttpRequest,
|
|
28
28
|
verifySpendAccountPayReconstructs
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-NDJ7BFI4.js";
|
|
30
30
|
export {
|
|
31
31
|
MCP_TARGET_PRESETS,
|
|
32
32
|
PACKAGE_NAME,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmdoss/suipay-mcp",
|
|
3
|
-
"version": "0.2.2-dev.
|
|
3
|
+
"version": "0.2.2-dev.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SuiPay MCP — pay MPP-gated APIs from a spend-account grant with an agent-held delegate key.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"publishConfig": {
|
|
22
22
|
"access": "public",
|
|
23
|
-
"provenance":
|
|
23
|
+
"provenance": false
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
26
26
|
"node": ">=20"
|
|
@@ -36,7 +36,9 @@
|
|
|
36
36
|
"@types/node": "^26",
|
|
37
37
|
"tsup": "^8.0.0",
|
|
38
38
|
"typescript": "^6.0.3",
|
|
39
|
-
"vitest": "^4.1.10"
|
|
39
|
+
"vitest": "^4.1.10",
|
|
40
|
+
"@cmdoss/suipay-core": "0.1.0",
|
|
41
|
+
"@cmdoss/suipay-sdk": "0.1.0"
|
|
40
42
|
},
|
|
41
43
|
"scripts": {
|
|
42
44
|
"build": "tsup",
|