@t2000/sdk 10.36.1 → 10.37.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 +2 -0
- package/dist/index.cjs +546 -6
- package/dist/index.d.cts +296 -15
- package/dist/index.d.ts +296 -15
- package/dist/index.js +513 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -35,6 +35,8 @@ The SDK also ships the **escrow-job builders** for agent-to-agent deliverable wo
|
|
|
35
35
|
|
|
36
36
|
The **open board** reads are public: `listOpenJobs(base, { status, query, limit, offset })` returns ONE page — `{ total, returned, truncated, nextOffset?, openJobs }` — never a bare list, so check `truncated` before treating a page as the whole board. Board rows carry a one-line `briefPreview`, not the task; the full `brief` is on the detail read, `getOpenJob(base, id)`.
|
|
37
37
|
|
|
38
|
+
**Sell headlessly** — `CommerceClient` is the one write path for seller onboarding (the same one `t2 agent *` / `t2 service *` call): `register()` (sponsored, idempotent) · `updateProfile()` · `upsertService()` / `retireService()` · `createPackage({ name, tiers })` (three `{base}-basic|standard|premium` listings, same slug math as the console) · `listEndpoint()` (x402, live-probed) · `resolveRef('#16')`. Gasless; errors are `T2000Error` with the API's message. Walkthrough → **[docs.t2000.ai/how-to/sell-headlessly](https://docs.t2000.ai/how-to/sell-headlessly)**.
|
|
39
|
+
|
|
38
40
|
## Full reference
|
|
39
41
|
|
|
40
42
|
Factory methods, full API surface, supported assets, Cetus swap routing, x402 payments, error handling, architecture →
|
package/dist/index.cjs
CHANGED
|
@@ -3762,6 +3762,17 @@ function isCustomHireEnvelope(text) {
|
|
|
3762
3762
|
return false;
|
|
3763
3763
|
}
|
|
3764
3764
|
}
|
|
3765
|
+
|
|
3766
|
+
// src/sponsored-guard.ts
|
|
3767
|
+
var sponsoredTxGuard = null;
|
|
3768
|
+
function setSponsoredTxGuard(guard) {
|
|
3769
|
+
sponsoredTxGuard = guard;
|
|
3770
|
+
}
|
|
3771
|
+
function runSponsoredTxGuard(ctx) {
|
|
3772
|
+
sponsoredTxGuard?.(ctx);
|
|
3773
|
+
}
|
|
3774
|
+
|
|
3775
|
+
// src/open-jobs.ts
|
|
3765
3776
|
async function fetchJson(url, init) {
|
|
3766
3777
|
const res = await fetch(url, {
|
|
3767
3778
|
method: init?.method ?? "GET",
|
|
@@ -3776,10 +3787,6 @@ async function fetchJson(url, init) {
|
|
|
3776
3787
|
}
|
|
3777
3788
|
return json;
|
|
3778
3789
|
}
|
|
3779
|
-
var sponsoredTxGuard = null;
|
|
3780
|
-
function setSponsoredTxGuard(guard) {
|
|
3781
|
-
sponsoredTxGuard = guard;
|
|
3782
|
-
}
|
|
3783
3790
|
async function listOpenJobs(base, filter = {}) {
|
|
3784
3791
|
const params = new URLSearchParams();
|
|
3785
3792
|
if (filter.status) params.set("status", filter.status);
|
|
@@ -3811,7 +3818,7 @@ async function getOpenJob(base, id) {
|
|
|
3811
3818
|
}
|
|
3812
3819
|
async function sponsoredOpeningVerb(base, signer, action, params) {
|
|
3813
3820
|
const address = signer.getAddress();
|
|
3814
|
-
|
|
3821
|
+
runSponsoredTxGuard({ base, action });
|
|
3815
3822
|
const prep = await fetchJson(`${base}/job/prepare`, {
|
|
3816
3823
|
method: "POST",
|
|
3817
3824
|
body: { address, action, params }
|
|
@@ -3821,7 +3828,7 @@ async function sponsoredOpeningVerb(base, signer, action, params) {
|
|
|
3821
3828
|
if (!(nonce && txBytes)) {
|
|
3822
3829
|
throw new Error("Failed to prepare the transaction.");
|
|
3823
3830
|
}
|
|
3824
|
-
|
|
3831
|
+
runSponsoredTxGuard({ base, action, txBytes });
|
|
3825
3832
|
const { signature } = await signer.signTransaction(utils.fromBase64(txBytes));
|
|
3826
3833
|
const json = await fetchJson(`${base}/job/submit`, {
|
|
3827
3834
|
method: "POST",
|
|
@@ -3858,6 +3865,505 @@ function refundOpenJob(base, signer, openingId) {
|
|
|
3858
3865
|
});
|
|
3859
3866
|
}
|
|
3860
3867
|
|
|
3868
|
+
// src/commerce/endpoint.ts
|
|
3869
|
+
init_errors();
|
|
3870
|
+
|
|
3871
|
+
// src/commerce/http.ts
|
|
3872
|
+
init_errors();
|
|
3873
|
+
var DEFAULT_COMMERCE_API_BASE2 = "https://api.t2000.ai/v1";
|
|
3874
|
+
function codeForStatus(status) {
|
|
3875
|
+
if (status === 400 || status === 409 || status === 422) {
|
|
3876
|
+
return "INVALID_INPUT";
|
|
3877
|
+
}
|
|
3878
|
+
if (status === 429 || status >= 500) {
|
|
3879
|
+
return "RPC_ERROR";
|
|
3880
|
+
}
|
|
3881
|
+
return "UNKNOWN";
|
|
3882
|
+
}
|
|
3883
|
+
function apiErrorMessage(json, status) {
|
|
3884
|
+
const err = json.error;
|
|
3885
|
+
if (typeof err === "string") {
|
|
3886
|
+
return err;
|
|
3887
|
+
}
|
|
3888
|
+
const msg = err?.message;
|
|
3889
|
+
return typeof msg === "string" ? msg : `HTTP ${status}`;
|
|
3890
|
+
}
|
|
3891
|
+
async function apiRequest(url, init) {
|
|
3892
|
+
const res = await fetch(url, {
|
|
3893
|
+
method: init?.method ?? (init?.body === void 0 ? "GET" : "POST"),
|
|
3894
|
+
headers: {
|
|
3895
|
+
accept: "application/json",
|
|
3896
|
+
...init?.body === void 0 ? {} : { "Content-Type": "application/json" }
|
|
3897
|
+
},
|
|
3898
|
+
body: init?.body === void 0 ? void 0 : JSON.stringify(init.body)
|
|
3899
|
+
});
|
|
3900
|
+
const json = await res.json().catch(() => ({}));
|
|
3901
|
+
return { ok: res.ok, status: res.status, json };
|
|
3902
|
+
}
|
|
3903
|
+
async function apiJson(url, init) {
|
|
3904
|
+
const res = await apiRequest(url, init);
|
|
3905
|
+
if (!res.ok) {
|
|
3906
|
+
throw new exports.T2000Error(codeForStatus(res.status), apiErrorMessage(res.json, res.status), {
|
|
3907
|
+
status: res.status,
|
|
3908
|
+
...res.json.error && typeof res.json.error === "object" ? { api: res.json.error } : {}
|
|
3909
|
+
});
|
|
3910
|
+
}
|
|
3911
|
+
return res.json;
|
|
3912
|
+
}
|
|
3913
|
+
function invalidInput(message) {
|
|
3914
|
+
return new exports.T2000Error("INVALID_INPUT", message);
|
|
3915
|
+
}
|
|
3916
|
+
async function signPreparedTx(base, action, signer, txBytes) {
|
|
3917
|
+
runSponsoredTxGuard({ base, action, txBytes });
|
|
3918
|
+
const { signature } = await signer.signTransaction(utils.fromBase64(txBytes));
|
|
3919
|
+
return signature;
|
|
3920
|
+
}
|
|
3921
|
+
|
|
3922
|
+
// src/commerce/endpoint.ts
|
|
3923
|
+
function endpointIssueLines(prep) {
|
|
3924
|
+
const lines = (prep.probe?.issues ?? []).map(
|
|
3925
|
+
(i) => ` \u2717 ${i.message ?? i.code}`
|
|
3926
|
+
);
|
|
3927
|
+
for (const r of prep.routes ?? []) {
|
|
3928
|
+
if (r.probeOk === false) {
|
|
3929
|
+
lines.push(` \u2717 ${r.method ?? "POST"} ${r.path}`);
|
|
3930
|
+
for (const i of r.issues ?? []) {
|
|
3931
|
+
lines.push(` ${i.message ?? i.code}`);
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
}
|
|
3935
|
+
return lines;
|
|
3936
|
+
}
|
|
3937
|
+
async function setEndpoint(apiBase, signer, endpoint, primary) {
|
|
3938
|
+
const address = signer.getAddress();
|
|
3939
|
+
runSponsoredTxGuard({ base: apiBase, action: "update" });
|
|
3940
|
+
const res = await apiRequest(`${apiBase}/agent/endpoint/prepare`, {
|
|
3941
|
+
method: "POST",
|
|
3942
|
+
body: { address, endpoint, ...primary ? { primary } : {} }
|
|
3943
|
+
});
|
|
3944
|
+
const prep = res.json;
|
|
3945
|
+
if (!res.ok) {
|
|
3946
|
+
const msg = apiErrorMessage(prep, res.status);
|
|
3947
|
+
const detail = endpointIssueLines(prep).join("\n");
|
|
3948
|
+
throw new exports.T2000Error(
|
|
3949
|
+
"INVALID_INPUT",
|
|
3950
|
+
detail ? `${msg}
|
|
3951
|
+
${detail}` : msg,
|
|
3952
|
+
{ status: res.status, probe: prep.probe ?? null, routes: prep.routes ?? [] }
|
|
3953
|
+
);
|
|
3954
|
+
}
|
|
3955
|
+
if (!(typeof prep.nonce === "string" && typeof prep.txBytes === "string")) {
|
|
3956
|
+
throw invalidInput("Failed to prepare the listing.");
|
|
3957
|
+
}
|
|
3958
|
+
const signature = await signPreparedTx(apiBase, "update", signer, prep.txBytes);
|
|
3959
|
+
const sub = await apiJson(`${apiBase}/agent/endpoint/submit`, {
|
|
3960
|
+
method: "POST",
|
|
3961
|
+
body: { nonce: prep.nonce, address, signature }
|
|
3962
|
+
});
|
|
3963
|
+
const listed = endpoint !== "";
|
|
3964
|
+
return {
|
|
3965
|
+
address,
|
|
3966
|
+
endpoint: listed ? prep.primary?.url ?? endpoint : null,
|
|
3967
|
+
listed,
|
|
3968
|
+
probe: prep.probe ?? null,
|
|
3969
|
+
origin: prep.origin ?? null,
|
|
3970
|
+
primary: prep.primary ?? null,
|
|
3971
|
+
routes: prep.routes ?? [],
|
|
3972
|
+
...typeof sub.digest === "string" ? { digest: sub.digest } : {}
|
|
3973
|
+
};
|
|
3974
|
+
}
|
|
3975
|
+
function listEndpoint(apiBase, signer, endpoint, opts = {}) {
|
|
3976
|
+
const target = endpoint.trim();
|
|
3977
|
+
if (!target) {
|
|
3978
|
+
throw invalidInput("Provide your x402 endpoint URL.");
|
|
3979
|
+
}
|
|
3980
|
+
return setEndpoint(apiBase, signer, target, opts.primary);
|
|
3981
|
+
}
|
|
3982
|
+
function removeEndpoint(apiBase, signer) {
|
|
3983
|
+
return setEndpoint(apiBase, signer, "");
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3986
|
+
// src/commerce/types.ts
|
|
3987
|
+
var AGENT_CATEGORIES = [
|
|
3988
|
+
"ai-models",
|
|
3989
|
+
"data-feeds",
|
|
3990
|
+
"finance",
|
|
3991
|
+
"research",
|
|
3992
|
+
"dev-tools",
|
|
3993
|
+
"creative",
|
|
3994
|
+
"travel",
|
|
3995
|
+
"comms",
|
|
3996
|
+
"other"
|
|
3997
|
+
];
|
|
3998
|
+
var SERVICE_TIERS = ["basic", "standard", "premium"];
|
|
3999
|
+
|
|
4000
|
+
// src/commerce/package-slug.ts
|
|
4001
|
+
var SERVICE_SLUG_RE = /^[a-z0-9][a-z0-9-]{1,47}$/;
|
|
4002
|
+
function trimDashes(s) {
|
|
4003
|
+
let start = 0;
|
|
4004
|
+
let end = s.length;
|
|
4005
|
+
while (start < end && s.charCodeAt(start) === 45) start += 1;
|
|
4006
|
+
while (end > start && s.charCodeAt(end - 1) === 45) end -= 1;
|
|
4007
|
+
return s.slice(start, end);
|
|
4008
|
+
}
|
|
4009
|
+
var MAX_SLUG_LENGTH = 48;
|
|
4010
|
+
function slugifyUnbounded(name) {
|
|
4011
|
+
return trimDashes(name.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-"));
|
|
4012
|
+
}
|
|
4013
|
+
function slugifyLoner(name) {
|
|
4014
|
+
return slugifyUnbounded(name).slice(0, MAX_SLUG_LENGTH);
|
|
4015
|
+
}
|
|
4016
|
+
function slugify(name) {
|
|
4017
|
+
return slugifyLoner(name);
|
|
4018
|
+
}
|
|
4019
|
+
var TIER_SLUG_RE = /^(.+)-(basic|standard|premium)$/;
|
|
4020
|
+
var MAX_TIER_BASE_LENGTH = 48 - "-standard".length;
|
|
4021
|
+
function parseServiceTierSlug(slug) {
|
|
4022
|
+
const m = TIER_SLUG_RE.exec(slug);
|
|
4023
|
+
if (!m) {
|
|
4024
|
+
return null;
|
|
4025
|
+
}
|
|
4026
|
+
return { base: m[1], tier: m[2] };
|
|
4027
|
+
}
|
|
4028
|
+
function packageBaseSlug(slugified) {
|
|
4029
|
+
const cut = slugified.slice(0, MAX_TIER_BASE_LENGTH);
|
|
4030
|
+
let end = cut.length;
|
|
4031
|
+
while (end > 0 && cut.charCodeAt(end - 1) === 45) end -= 1;
|
|
4032
|
+
return cut.slice(0, end);
|
|
4033
|
+
}
|
|
4034
|
+
function packageBaseFromName(name) {
|
|
4035
|
+
return packageBaseSlug(slugifyUnbounded(name));
|
|
4036
|
+
}
|
|
4037
|
+
function packageTierSlugs(base) {
|
|
4038
|
+
return SERVICE_TIERS.map((tier) => ({ tier, slug: `${base}-${tier}` }));
|
|
4039
|
+
}
|
|
4040
|
+
|
|
4041
|
+
// src/commerce/challenge.ts
|
|
4042
|
+
async function sha256Hex2(content) {
|
|
4043
|
+
const digest = await crypto.subtle.digest(
|
|
4044
|
+
"SHA-256",
|
|
4045
|
+
new TextEncoder().encode(content)
|
|
4046
|
+
);
|
|
4047
|
+
return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
4048
|
+
}
|
|
4049
|
+
function servicePayloadSha256(payload) {
|
|
4050
|
+
return sha256Hex2(JSON.stringify(payload));
|
|
4051
|
+
}
|
|
4052
|
+
function profileChallengeMessage(nonce) {
|
|
4053
|
+
return `t2000-agent-profile:${nonce}`;
|
|
4054
|
+
}
|
|
4055
|
+
function serviceChallengeMessage(nonce, payloadHash) {
|
|
4056
|
+
return `t2000-agent-service:${nonce}:${payloadHash}`;
|
|
4057
|
+
}
|
|
4058
|
+
async function fetchChallengeNonce(apiBase, address) {
|
|
4059
|
+
const challenge = await apiJson(`${apiBase}/agent/challenge`, {
|
|
4060
|
+
method: "POST",
|
|
4061
|
+
body: { address }
|
|
4062
|
+
});
|
|
4063
|
+
const nonce = challenge.nonce;
|
|
4064
|
+
if (typeof nonce !== "string" || !nonce) {
|
|
4065
|
+
throw invalidInput("Failed to get a challenge nonce.");
|
|
4066
|
+
}
|
|
4067
|
+
return nonce;
|
|
4068
|
+
}
|
|
4069
|
+
async function signChallenge(apiBase, signer, message) {
|
|
4070
|
+
const nonce = await fetchChallengeNonce(apiBase, signer.getAddress());
|
|
4071
|
+
const text = await message(nonce);
|
|
4072
|
+
const { signature } = await signer.signPersonalMessage(
|
|
4073
|
+
new TextEncoder().encode(text)
|
|
4074
|
+
);
|
|
4075
|
+
return { nonce, signature };
|
|
4076
|
+
}
|
|
4077
|
+
|
|
4078
|
+
// src/commerce/service.ts
|
|
4079
|
+
function serviceUpsertPayload(input) {
|
|
4080
|
+
const slug = input.slug.trim().toLowerCase();
|
|
4081
|
+
if (!SERVICE_SLUG_RE.test(slug)) {
|
|
4082
|
+
throw invalidInput(
|
|
4083
|
+
"slug must be 2-48 chars of [a-z0-9-], starting alphanumeric."
|
|
4084
|
+
);
|
|
4085
|
+
}
|
|
4086
|
+
return {
|
|
4087
|
+
...input.mode ? { mode: input.mode } : {},
|
|
4088
|
+
slug,
|
|
4089
|
+
name: input.name.trim(),
|
|
4090
|
+
description: input.description.trim(),
|
|
4091
|
+
priceUsdc: input.priceUsdc,
|
|
4092
|
+
slaMinutes: input.slaMinutes,
|
|
4093
|
+
reviewWindowMinutes: input.reviewWindowMinutes ?? 1440,
|
|
4094
|
+
rejectSplitBps: input.rejectSplitBps ?? 8e3,
|
|
4095
|
+
requirements: input.requirements,
|
|
4096
|
+
deliverable: input.deliverable.trim(),
|
|
4097
|
+
...input.examples === void 0 ? {} : { examples: input.examples }
|
|
4098
|
+
};
|
|
4099
|
+
}
|
|
4100
|
+
async function signedServiceAction(apiBase, signer, action, payload) {
|
|
4101
|
+
const address = signer.getAddress();
|
|
4102
|
+
const { nonce, signature } = await signChallenge(
|
|
4103
|
+
apiBase,
|
|
4104
|
+
signer,
|
|
4105
|
+
async (n) => serviceChallengeMessage(n, await servicePayloadSha256(payload))
|
|
4106
|
+
);
|
|
4107
|
+
return apiJson(`${apiBase}/agent/service`, {
|
|
4108
|
+
method: "POST",
|
|
4109
|
+
body: { address, nonce, signature, action, payload }
|
|
4110
|
+
});
|
|
4111
|
+
}
|
|
4112
|
+
async function upsertService(apiBase, signer, input) {
|
|
4113
|
+
const payload = serviceUpsertPayload(input);
|
|
4114
|
+
const response = await signedServiceAction(apiBase, signer, "upsert", payload);
|
|
4115
|
+
return { address: signer.getAddress(), slug: payload.slug, response };
|
|
4116
|
+
}
|
|
4117
|
+
async function retireService(apiBase, signer, slug) {
|
|
4118
|
+
const clean = slug.trim().toLowerCase();
|
|
4119
|
+
if (!SERVICE_SLUG_RE.test(clean)) {
|
|
4120
|
+
throw invalidInput("slug must be 2-48 chars of [a-z0-9-], starting alphanumeric.");
|
|
4121
|
+
}
|
|
4122
|
+
const response = await signedServiceAction(apiBase, signer, "retire", {
|
|
4123
|
+
slug: clean
|
|
4124
|
+
});
|
|
4125
|
+
return { address: signer.getAddress(), slug: clean, response };
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
// src/commerce/package.ts
|
|
4129
|
+
function planPackage(input) {
|
|
4130
|
+
const name = input.name.trim();
|
|
4131
|
+
if (!name) {
|
|
4132
|
+
throw invalidInput("name is required.");
|
|
4133
|
+
}
|
|
4134
|
+
const base = input.baseSlug ? packageBaseSlug(input.baseSlug.trim().toLowerCase()) : packageBaseFromName(name);
|
|
4135
|
+
if (!base || !SERVICE_SLUG_RE.test(`${base}-basic`)) {
|
|
4136
|
+
throw invalidInput(
|
|
4137
|
+
"Could not derive a package slug from the name \u2014 pass baseSlug (a-z, 0-9, dashes)."
|
|
4138
|
+
);
|
|
4139
|
+
}
|
|
4140
|
+
const byTier = /* @__PURE__ */ new Map();
|
|
4141
|
+
for (const t of input.tiers) {
|
|
4142
|
+
if (!SERVICE_TIERS.includes(t.tier)) {
|
|
4143
|
+
throw invalidInput(`Unknown tier "${t.tier}" \u2014 use basic, standard, premium.`);
|
|
4144
|
+
}
|
|
4145
|
+
if (byTier.has(t.tier)) {
|
|
4146
|
+
throw invalidInput(`Tier "${t.tier}" given twice.`);
|
|
4147
|
+
}
|
|
4148
|
+
byTier.set(t.tier, t);
|
|
4149
|
+
}
|
|
4150
|
+
const missing = SERVICE_TIERS.filter((t) => !byTier.has(t));
|
|
4151
|
+
if (missing.length > 0) {
|
|
4152
|
+
throw invalidInput(
|
|
4153
|
+
`A package needs all three tiers \u2014 missing: ${missing.join(", ")}.`
|
|
4154
|
+
);
|
|
4155
|
+
}
|
|
4156
|
+
return {
|
|
4157
|
+
base,
|
|
4158
|
+
tiers: packageTierSlugs(base).map(({ tier, slug }) => {
|
|
4159
|
+
const t = byTier.get(tier);
|
|
4160
|
+
return {
|
|
4161
|
+
tier,
|
|
4162
|
+
slug,
|
|
4163
|
+
input: {
|
|
4164
|
+
mode: "create",
|
|
4165
|
+
slug,
|
|
4166
|
+
name,
|
|
4167
|
+
description: (t.description ?? input.description).trim(),
|
|
4168
|
+
priceUsdc: t.priceUsdc,
|
|
4169
|
+
slaMinutes: t.slaMinutes ?? input.slaMinutes,
|
|
4170
|
+
deliverable: t.deliverable,
|
|
4171
|
+
requirements: input.requirements,
|
|
4172
|
+
reviewWindowMinutes: t.reviewWindowMinutes ?? input.reviewWindowMinutes,
|
|
4173
|
+
rejectSplitBps: t.rejectSplitBps ?? input.rejectSplitBps
|
|
4174
|
+
}
|
|
4175
|
+
};
|
|
4176
|
+
})
|
|
4177
|
+
};
|
|
4178
|
+
}
|
|
4179
|
+
async function createPackage(apiBase, signer, input) {
|
|
4180
|
+
const plan = planPackage(input);
|
|
4181
|
+
const tiers = [];
|
|
4182
|
+
for (const t of plan.tiers) {
|
|
4183
|
+
await upsertService(apiBase, signer, t.input);
|
|
4184
|
+
tiers.push({ tier: t.tier, slug: t.slug, priceUsdc: t.input.priceUsdc });
|
|
4185
|
+
}
|
|
4186
|
+
return { address: signer.getAddress(), base: plan.base, tiers };
|
|
4187
|
+
}
|
|
4188
|
+
|
|
4189
|
+
// src/commerce/resolve.ts
|
|
4190
|
+
init_errors();
|
|
4191
|
+
var FALLBACK_MISS = "Use an Agent ID (#93), @handle, or full 0x\u2026 address.";
|
|
4192
|
+
function agentResolveUrl(q, apiBase = DEFAULT_COMMERCE_API_BASE2) {
|
|
4193
|
+
return `${apiBase}/agents/resolve?q=${encodeURIComponent(q.trim())}`;
|
|
4194
|
+
}
|
|
4195
|
+
async function resolveAgentRef(q, apiBase = DEFAULT_COMMERCE_API_BASE2) {
|
|
4196
|
+
const res = await apiRequest(agentResolveUrl(q, apiBase));
|
|
4197
|
+
const json = res.json;
|
|
4198
|
+
if (!(res.ok && typeof json.address === "string")) {
|
|
4199
|
+
throw new exports.T2000Error(
|
|
4200
|
+
"CONTACT_NOT_FOUND",
|
|
4201
|
+
typeof json.error === "string" ? json.error : FALLBACK_MISS,
|
|
4202
|
+
{ ref: q }
|
|
4203
|
+
);
|
|
4204
|
+
}
|
|
4205
|
+
return {
|
|
4206
|
+
address: json.address,
|
|
4207
|
+
...typeof json.numericId === "number" || json.numericId === null ? { numericId: json.numericId } : {},
|
|
4208
|
+
...typeof json.name === "string" ? { name: json.name } : {}
|
|
4209
|
+
};
|
|
4210
|
+
}
|
|
4211
|
+
async function getAgentProfile(address, apiBase = DEFAULT_COMMERCE_API_BASE2) {
|
|
4212
|
+
const res = await apiRequest(`${apiBase}/agents/${encodeURIComponent(address)}`);
|
|
4213
|
+
if (!res.ok) {
|
|
4214
|
+
return null;
|
|
4215
|
+
}
|
|
4216
|
+
return { ...res.json, address };
|
|
4217
|
+
}
|
|
4218
|
+
|
|
4219
|
+
// src/commerce/profile.ts
|
|
4220
|
+
function parseAgentCategory(raw) {
|
|
4221
|
+
const c = raw.trim().toLowerCase();
|
|
4222
|
+
if (!AGENT_CATEGORIES.includes(c)) {
|
|
4223
|
+
throw invalidInput(
|
|
4224
|
+
`category must be one of: ${AGENT_CATEGORIES.join(", ")} (got "${raw}").`
|
|
4225
|
+
);
|
|
4226
|
+
}
|
|
4227
|
+
return c;
|
|
4228
|
+
}
|
|
4229
|
+
async function updateProfile(apiBase, signer, input) {
|
|
4230
|
+
const hasField = input.name !== void 0 || input.imageUrl !== void 0 || input.description !== void 0 || input.category !== void 0 || input.website !== void 0 || input.twitter !== void 0 || input.github !== void 0;
|
|
4231
|
+
if (!hasField) {
|
|
4232
|
+
throw invalidInput(
|
|
4233
|
+
"Provide at least one of name, imageUrl, description, category, website, twitter, github."
|
|
4234
|
+
);
|
|
4235
|
+
}
|
|
4236
|
+
const category = input.category === void 0 ? void 0 : parseAgentCategory(input.category);
|
|
4237
|
+
const address = signer.getAddress();
|
|
4238
|
+
const { nonce, signature } = await signChallenge(
|
|
4239
|
+
apiBase,
|
|
4240
|
+
signer,
|
|
4241
|
+
profileChallengeMessage
|
|
4242
|
+
);
|
|
4243
|
+
await apiJson(`${apiBase}/agent/profile`, {
|
|
4244
|
+
method: "POST",
|
|
4245
|
+
body: {
|
|
4246
|
+
address,
|
|
4247
|
+
nonce,
|
|
4248
|
+
signature,
|
|
4249
|
+
displayName: input.name,
|
|
4250
|
+
imageUrl: input.imageUrl,
|
|
4251
|
+
description: input.description,
|
|
4252
|
+
category,
|
|
4253
|
+
website: input.website,
|
|
4254
|
+
twitter: input.twitter,
|
|
4255
|
+
github: input.github
|
|
4256
|
+
}
|
|
4257
|
+
});
|
|
4258
|
+
return { address };
|
|
4259
|
+
}
|
|
4260
|
+
async function ensureCategory(apiBase, signer, category) {
|
|
4261
|
+
if (category !== void 0) {
|
|
4262
|
+
const parsed = parseAgentCategory(category);
|
|
4263
|
+
await updateProfile(apiBase, signer, { category: parsed });
|
|
4264
|
+
return parsed;
|
|
4265
|
+
}
|
|
4266
|
+
const profile = await getAgentProfile(signer.getAddress(), apiBase).catch(
|
|
4267
|
+
() => null
|
|
4268
|
+
);
|
|
4269
|
+
const existing = typeof profile?.category === "string" && profile.category ? profile.category : null;
|
|
4270
|
+
if (!existing) {
|
|
4271
|
+
throw invalidInput(
|
|
4272
|
+
`Pick a directory category first \u2014 buyers browse listings by category. Set one of ${AGENT_CATEGORIES.join(" | ")} (updateProfile({ category }) / t2 agent profile --category).`
|
|
4273
|
+
);
|
|
4274
|
+
}
|
|
4275
|
+
return existing;
|
|
4276
|
+
}
|
|
4277
|
+
|
|
4278
|
+
// src/commerce/register.ts
|
|
4279
|
+
async function registerAgent(apiBase, signer) {
|
|
4280
|
+
const address = signer.getAddress();
|
|
4281
|
+
runSponsoredTxGuard({ base: apiBase, action: "register" });
|
|
4282
|
+
const prep = await apiJson(`${apiBase}/agent/register/prepare`, {
|
|
4283
|
+
method: "POST",
|
|
4284
|
+
body: { address }
|
|
4285
|
+
});
|
|
4286
|
+
if (prep.alreadyRegistered === true) {
|
|
4287
|
+
return { address, alreadyRegistered: true };
|
|
4288
|
+
}
|
|
4289
|
+
const regNonce = prep.regNonce;
|
|
4290
|
+
const txBytes = prep.txBytes;
|
|
4291
|
+
if (!(typeof regNonce === "string" && typeof txBytes === "string")) {
|
|
4292
|
+
throw invalidInput("Failed to prepare registration.");
|
|
4293
|
+
}
|
|
4294
|
+
const signature = await signPreparedTx(apiBase, "register", signer, txBytes);
|
|
4295
|
+
const res = await apiJson(`${apiBase}/agent/register/submit`, {
|
|
4296
|
+
method: "POST",
|
|
4297
|
+
body: { regNonce, address, agentSignature: signature }
|
|
4298
|
+
});
|
|
4299
|
+
return {
|
|
4300
|
+
address,
|
|
4301
|
+
alreadyRegistered: res.alreadyRegistered === true,
|
|
4302
|
+
...typeof res.digest === "string" ? { digest: res.digest } : {}
|
|
4303
|
+
};
|
|
4304
|
+
}
|
|
4305
|
+
|
|
4306
|
+
// src/commerce/client.ts
|
|
4307
|
+
var CommerceClient = class {
|
|
4308
|
+
signer;
|
|
4309
|
+
apiBase;
|
|
4310
|
+
constructor(options) {
|
|
4311
|
+
this.signer = options.signer;
|
|
4312
|
+
let base = options.apiBase ?? DEFAULT_COMMERCE_API_BASE2;
|
|
4313
|
+
while (base.endsWith("/")) base = base.slice(0, -1);
|
|
4314
|
+
this.apiBase = base;
|
|
4315
|
+
}
|
|
4316
|
+
/** This signer's wallet address. */
|
|
4317
|
+
get address() {
|
|
4318
|
+
return this.signer.getAddress();
|
|
4319
|
+
}
|
|
4320
|
+
/** Register the wallet as an on-chain Agent ID (sponsored; idempotent). */
|
|
4321
|
+
register() {
|
|
4322
|
+
return registerAgent(this.apiBase, this.signer);
|
|
4323
|
+
}
|
|
4324
|
+
/** Set public profile fields (signed, no gas). */
|
|
4325
|
+
updateProfile(input) {
|
|
4326
|
+
return updateProfile(this.apiBase, this.signer, input);
|
|
4327
|
+
}
|
|
4328
|
+
/** The sell gate — set `category` or confirm the live one; throws when
|
|
4329
|
+
* neither exists. Returns the category in force. */
|
|
4330
|
+
ensureCategory(category) {
|
|
4331
|
+
return ensureCategory(this.apiBase, this.signer, category);
|
|
4332
|
+
}
|
|
4333
|
+
/** This seller's public profile (null when unregistered). */
|
|
4334
|
+
profile() {
|
|
4335
|
+
return getAgentProfile(this.address, this.apiBase);
|
|
4336
|
+
}
|
|
4337
|
+
/** List (or fully re-write) one service — `mode: "create"` refuses a live slug. */
|
|
4338
|
+
upsertService(input) {
|
|
4339
|
+
return upsertService(this.apiBase, this.signer, input);
|
|
4340
|
+
}
|
|
4341
|
+
/** Take a service off the board (funded jobs keep settling on-chain). */
|
|
4342
|
+
retireService(input) {
|
|
4343
|
+
return retireService(
|
|
4344
|
+
this.apiBase,
|
|
4345
|
+
this.signer,
|
|
4346
|
+
typeof input === "string" ? input : input.slug
|
|
4347
|
+
);
|
|
4348
|
+
}
|
|
4349
|
+
/** Three tiers under one name — `{base}-basic|standard|premium`. */
|
|
4350
|
+
createPackage(input) {
|
|
4351
|
+
return createPackage(this.apiBase, this.signer, input);
|
|
4352
|
+
}
|
|
4353
|
+
/** Sell an x402 API (origin or one 402 URL) — live-probed, sponsored. */
|
|
4354
|
+
listEndpoint(endpoint, opts = {}) {
|
|
4355
|
+
return listEndpoint(this.apiBase, this.signer, endpoint, opts);
|
|
4356
|
+
}
|
|
4357
|
+
/** Clear the x402 listing. */
|
|
4358
|
+
removeEndpoint() {
|
|
4359
|
+
return removeEndpoint(this.apiBase, this.signer);
|
|
4360
|
+
}
|
|
4361
|
+
/** `#93` · `@handle` · `name.sui` · `0x…` → wallet (marketplace refs only). */
|
|
4362
|
+
resolveRef(q) {
|
|
4363
|
+
return resolveAgentRef(q, this.apiBase);
|
|
4364
|
+
}
|
|
4365
|
+
};
|
|
4366
|
+
|
|
3861
4367
|
// src/utils/resolve-created.ts
|
|
3862
4368
|
var OPENING_TYPE_MARKER = "::opening::Opening<";
|
|
3863
4369
|
var ESCROW_JOB_TYPE_MARKER = "::escrow::Job<";
|
|
@@ -4309,11 +4815,13 @@ exports.A2A_ESCROW_PACKAGE_V6_ID = A2A_ESCROW_PACKAGE_V6_ID;
|
|
|
4309
4815
|
exports.A2A_ESCROW_PACKAGE_V7_ID = A2A_ESCROW_PACKAGE_V7_ID;
|
|
4310
4816
|
exports.A2A_ESCROW_PACKAGE_V8_ID = A2A_ESCROW_PACKAGE_V8_ID;
|
|
4311
4817
|
exports.A2A_SCORE_BOARD_ID = A2A_SCORE_BOARD_ID;
|
|
4818
|
+
exports.AGENT_CATEGORIES = AGENT_CATEGORIES;
|
|
4312
4819
|
exports.AUDRIC_PARENT = AUDRIC_PARENT;
|
|
4313
4820
|
exports.AUDRIC_PARENT_NAME = AUDRIC_PARENT_NAME;
|
|
4314
4821
|
exports.AUDRIC_PARENT_NFT_ID = AUDRIC_PARENT_NFT_ID;
|
|
4315
4822
|
exports.CETUS_USDC_SUI_POOL = CETUS_USDC_SUI_POOL;
|
|
4316
4823
|
exports.CLOCK_ID = CLOCK_ID;
|
|
4824
|
+
exports.CommerceClient = CommerceClient;
|
|
4317
4825
|
exports.DEFAULT_ACTIVITY_REPORT_URL = DEFAULT_ACTIVITY_REPORT_URL;
|
|
4318
4826
|
exports.DEFAULT_API_BASE = DEFAULT_API_BASE;
|
|
4319
4827
|
exports.DEFAULT_COMMERCE_API_BASE = DEFAULT_COMMERCE_API_BASE;
|
|
@@ -4338,6 +4846,8 @@ exports.MAX_DELIVER_HORIZON_MS = MAX_DELIVER_HORIZON_MS;
|
|
|
4338
4846
|
exports.MAX_JOB_USDC = MAX_JOB_USDC;
|
|
4339
4847
|
exports.MAX_OPEN_WINDOW_MS = MAX_OPEN_WINDOW_MS;
|
|
4340
4848
|
exports.MAX_REVIEW_WINDOW_MS = MAX_REVIEW_WINDOW_MS;
|
|
4849
|
+
exports.MAX_SLUG_LENGTH = MAX_SLUG_LENGTH;
|
|
4850
|
+
exports.MAX_TIER_BASE_LENGTH = MAX_TIER_BASE_LENGTH;
|
|
4341
4851
|
exports.MIN_JOB_USDC = MIN_JOB_USDC;
|
|
4342
4852
|
exports.MIST_PER_SUI = MIST_PER_SUI;
|
|
4343
4853
|
exports.OPENING_CLAIM_POLICIES = OPENING_CLAIM_POLICIES;
|
|
@@ -4351,6 +4861,8 @@ exports.PROVEN_MIN_REVIEWS = PROVEN_MIN_REVIEWS;
|
|
|
4351
4861
|
exports.REVIEW_MAX_STARS = REVIEW_MAX_STARS;
|
|
4352
4862
|
exports.REVIEW_MIN_STARS = REVIEW_MIN_STARS;
|
|
4353
4863
|
exports.SENDABLE_ASSETS = SENDABLE_ASSETS;
|
|
4864
|
+
exports.SERVICE_SLUG_RE = SERVICE_SLUG_RE;
|
|
4865
|
+
exports.SERVICE_TIERS = SERVICE_TIERS;
|
|
4354
4866
|
exports.SPONSORED_PYTH_DEPENDENT_PROVIDERS = SPONSORED_PYTH_DEPENDENT_PROVIDERS;
|
|
4355
4867
|
exports.STABLE_ASSETS = STABLE_ASSETS;
|
|
4356
4868
|
exports.SUINS_NAME_REGEX = SUINS_NAME_REGEX;
|
|
@@ -4367,6 +4879,7 @@ exports.WRITE_APPENDER_REGISTRY = WRITE_APPENDER_REGISTRY;
|
|
|
4367
4879
|
exports.ZkLoginSigner = ZkLoginSigner;
|
|
4368
4880
|
exports.addSendToTx = addSendToTx;
|
|
4369
4881
|
exports.addSwapToTx = addSwapToTx;
|
|
4882
|
+
exports.agentResolveUrl = agentResolveUrl;
|
|
4370
4883
|
exports.approxUsdValue = approxUsdValue;
|
|
4371
4884
|
exports.assertAllowedAsset = assertAllowedAsset;
|
|
4372
4885
|
exports.assertBuyerRequirements = assertBuyerRequirements;
|
|
@@ -4403,12 +4916,15 @@ exports.classifySendAsset = classifySendAsset;
|
|
|
4403
4916
|
exports.classifyTransaction = classifyTransaction;
|
|
4404
4917
|
exports.clearLimits = clearLimits;
|
|
4405
4918
|
exports.composeTx = composeTx;
|
|
4919
|
+
exports.createPackage = createPackage;
|
|
4406
4920
|
exports.customHireEnvelope = customHireEnvelope;
|
|
4407
4921
|
exports.dailySpentToday = dailySpentToday;
|
|
4408
4922
|
exports.deriveAgentScoreId = deriveAgentScoreId;
|
|
4409
4923
|
exports.deriveAllowedAddressesFromPtb = deriveAllowedAddressesFromPtb;
|
|
4410
4924
|
exports.deserializeCetusRoute = deserializeCetusRoute;
|
|
4411
4925
|
exports.displayHandle = displayHandle;
|
|
4926
|
+
exports.endpointIssueLines = endpointIssueLines;
|
|
4927
|
+
exports.ensureCategory = ensureCategory;
|
|
4412
4928
|
exports.executeTx = executeTx;
|
|
4413
4929
|
exports.exportPrivateKey = exportPrivateKey;
|
|
4414
4930
|
exports.extractAllUserLegs = extractAllUserLegs;
|
|
@@ -4417,6 +4933,7 @@ exports.extractTxCommands = extractTxCommands;
|
|
|
4417
4933
|
exports.extractTxSender = extractTxSender;
|
|
4418
4934
|
exports.fallbackLabel = fallbackLabel;
|
|
4419
4935
|
exports.fetchAllCoins = fetchAllCoins;
|
|
4936
|
+
exports.fetchChallengeNonce = fetchChallengeNonce;
|
|
4420
4937
|
exports.fetchService = fetchService;
|
|
4421
4938
|
exports.findSwapRoute = findSwapRoute;
|
|
4422
4939
|
exports.formatAssetAmount = formatAssetAmount;
|
|
@@ -4425,6 +4942,7 @@ exports.formatUsd = formatUsd;
|
|
|
4425
4942
|
exports.fullHandle = fullHandle;
|
|
4426
4943
|
exports.generateKeypair = generateKeypair;
|
|
4427
4944
|
exports.getAddress = getAddress;
|
|
4945
|
+
exports.getAgentProfile = getAgentProfile;
|
|
4428
4946
|
exports.getAgentScore = getAgentScore;
|
|
4429
4947
|
exports.getCoinMeta = getCoinMeta;
|
|
4430
4948
|
exports.getDecimals = getDecimals;
|
|
@@ -4446,6 +4964,7 @@ exports.isCustomHireEnvelope = isCustomHireEnvelope;
|
|
|
4446
4964
|
exports.isInRegistry = isInRegistry;
|
|
4447
4965
|
exports.jobActionsFor = jobActionsFor;
|
|
4448
4966
|
exports.keypairFromPrivateKey = keypairFromPrivateKey;
|
|
4967
|
+
exports.listEndpoint = listEndpoint;
|
|
4449
4968
|
exports.listModels = listModels;
|
|
4450
4969
|
exports.listOpenJobs = listOpenJobs;
|
|
4451
4970
|
exports.listServices = listServices;
|
|
@@ -4458,8 +4977,14 @@ exports.mistToSui = mistToSui;
|
|
|
4458
4977
|
exports.normalizeAddressInput = normalizeAddressInput;
|
|
4459
4978
|
exports.normalizeAsset = normalizeAsset;
|
|
4460
4979
|
exports.normalizeCoinType = normalizeCoinType;
|
|
4980
|
+
exports.packageBaseFromName = packageBaseFromName;
|
|
4981
|
+
exports.packageBaseSlug = packageBaseSlug;
|
|
4982
|
+
exports.packageTierSlugs = packageTierSlugs;
|
|
4983
|
+
exports.parseAgentCategory = parseAgentCategory;
|
|
4984
|
+
exports.parseServiceTierSlug = parseServiceTierSlug;
|
|
4461
4985
|
exports.parseSuiRpcTx = parseSuiRpcTx;
|
|
4462
4986
|
exports.payWithX402 = payWithX402;
|
|
4987
|
+
exports.planPackage = planPackage;
|
|
4463
4988
|
exports.postOpenJob = postOpenJob;
|
|
4464
4989
|
exports.preflightCreateJob = preflightCreateJob;
|
|
4465
4990
|
exports.preflightCreateOpening = preflightCreateOpening;
|
|
@@ -4468,6 +4993,7 @@ exports.preflightPay = preflightPay;
|
|
|
4468
4993
|
exports.preflightSend = preflightSend;
|
|
4469
4994
|
exports.preflightSwap = preflightSwap;
|
|
4470
4995
|
exports.probeX402 = probeX402;
|
|
4996
|
+
exports.profileChallengeMessage = profileChallengeMessage;
|
|
4471
4997
|
exports.putJobSpec = putJobSpec;
|
|
4472
4998
|
exports.queryBalance = queryBalance;
|
|
4473
4999
|
exports.queryHistory = queryHistory;
|
|
@@ -4478,25 +5004,39 @@ exports.readLimitsFile = readLimitsFile;
|
|
|
4478
5004
|
exports.recordDailySpend = recordDailySpend;
|
|
4479
5005
|
exports.refineLendingLabel = refineLendingLabel;
|
|
4480
5006
|
exports.refundOpenJob = refundOpenJob;
|
|
5007
|
+
exports.registerAgent = registerAgent;
|
|
5008
|
+
exports.removeEndpoint = removeEndpoint;
|
|
4481
5009
|
exports.reportX402Activity = reportX402Activity;
|
|
4482
5010
|
exports.resolveAddressToSuinsViaRpc = resolveAddressToSuinsViaRpc;
|
|
5011
|
+
exports.resolveAgentRef = resolveAgentRef;
|
|
4483
5012
|
exports.resolveCreatedObjectId = resolveCreatedObjectId;
|
|
4484
5013
|
exports.resolveSuinsViaRpc = resolveSuinsViaRpc;
|
|
4485
5014
|
exports.resolveSymbol = resolveSymbol;
|
|
4486
5015
|
exports.resolveTokenType = resolveTokenType;
|
|
5016
|
+
exports.retireService = retireService;
|
|
4487
5017
|
exports.saveBech32 = saveBech32;
|
|
4488
5018
|
exports.saveKey = saveKey;
|
|
4489
5019
|
exports.selectAndSplitCoin = selectAndSplitCoin;
|
|
4490
5020
|
exports.selectSuiCoin = selectSuiCoin;
|
|
4491
5021
|
exports.serializeCetusRoute = serializeCetusRoute;
|
|
5022
|
+
exports.serviceChallengeMessage = serviceChallengeMessage;
|
|
5023
|
+
exports.servicePayloadSha256 = servicePayloadSha256;
|
|
5024
|
+
exports.serviceUpsertPayload = serviceUpsertPayload;
|
|
4492
5025
|
exports.setLimits = setLimits;
|
|
4493
5026
|
exports.setSponsoredTxGuard = setSponsoredTxGuard;
|
|
5027
|
+
exports.signChallenge = signChallenge;
|
|
4494
5028
|
exports.simulateTransaction = simulateTransaction;
|
|
5029
|
+
exports.slugify = slugify;
|
|
5030
|
+
exports.slugifyLoner = slugifyLoner;
|
|
5031
|
+
exports.slugifyUnbounded = slugifyUnbounded;
|
|
4495
5032
|
exports.stableToRaw = stableToRaw;
|
|
4496
5033
|
exports.submitJobReview = submitJobReview;
|
|
4497
5034
|
exports.suiToMist = suiToMist;
|
|
4498
5035
|
exports.throwIfSimulationFailed = throwIfSimulationFailed;
|
|
5036
|
+
exports.trimDashes = trimDashes;
|
|
4499
5037
|
exports.truncateAddress = truncateAddress;
|
|
5038
|
+
exports.updateProfile = updateProfile;
|
|
5039
|
+
exports.upsertService = upsertService;
|
|
4500
5040
|
exports.usdcToRaw = usdcToRaw;
|
|
4501
5041
|
exports.validateAddress = validateAddress;
|
|
4502
5042
|
exports.validateLabel = validateLabel;
|