@mysten-incubation/suipay 0.0.0-stage → 0.2.0-dev.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/README.md CHANGED
@@ -1,3 +1,104 @@
1
- # Temporary Holding Version
1
+ # @mysten-incubation/suipay
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Embeddable SuiPay client for app developers. Quote a 402 resource and pay it
4
+ from a spend-account grant. This package does **not** bake hosted gateway URLs
5
+ — pass `gatewayUrl` yourself.
6
+
7
+ ## 30-second quickstart
8
+
9
+ ```ts
10
+ import { createClient } from '@mysten-incubation/suipay';
11
+ import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
12
+
13
+ const keypair = Ed25519Keypair.fromSecretKey(/* 32-byte seed */);
14
+
15
+ const client = await createClient({
16
+ gatewayUrl: process.env.SUIPAY_GATEWAY_URL!,
17
+ keypair,
18
+ });
19
+
20
+ const url = 'https://gateway.example/v1/image/generate';
21
+ const result = await client.pay(url, {
22
+ json: { prompt: 'a small red circle' },
23
+ });
24
+ ```
25
+
26
+ `pay` quotes that POST, then pays the quoted price. You do not pass atomic
27
+ units. `result.quote` is the price it agreed to, and `result.paid` says whether
28
+ settlement finished.
29
+
30
+ `createClient` throws if `gatewayUrl` or `keypair` is missing. The key must
31
+ already have a live spend-account grant on that gateway. A body makes the
32
+ request POST; a GET resource is `pay(url, { method: 'GET' })`. To show the
33
+ price before spending, call `quote` first and pass it back:
34
+
35
+ ```ts
36
+ const quote = await client.quote(url, { body: JSON.stringify({ prompt: '...' }) });
37
+ const result = await client.pay(url, { quote });
38
+ ```
39
+
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.
44
+
45
+ ## Errors — branch on `code`
46
+
47
+ A caller mistake caught before anything is quoted or signed (a missing
48
+ `gatewayUrl`, a URL off the gateway origin, `json` and `body` together) is
49
+ **thrown** as a `SuiPayError`. A failed quote throws one too. Once a payment
50
+ is attempted, `pay` **returns** the result instead: a failed or ambiguous
51
+ `PayResult` carries `code`, `paymentState`, `retryable`, `nextAction`,
52
+ `detail`, and `txDigest` / `paymentId` / `challengeId` when known.
53
+
54
+ ```ts
55
+ import { SuiPayError, toErrorFields } from '@mysten-incubation/suipay';
56
+
57
+ try {
58
+ const result = await client.pay(url, { json: { prompt: 'a small red circle' } });
59
+ if (result.status !== 'ok') {
60
+ // Money first: `paymentState` always agrees with `paid`.
61
+ if (result.paymentState !== 'not_charged') {
62
+ console.log('do not pay again; reconcile', result.paymentId);
63
+ } else if (result.retryable) {
64
+ console.log('safe to retry');
65
+ } else {
66
+ console.log(result.code, result.nextAction); // branch on code, never on detail
67
+ }
68
+ }
69
+ } catch (err) {
70
+ const fields = err instanceof SuiPayError ? err : toErrorFields(err);
71
+ console.log(fields.code, fields.nextAction);
72
+ }
73
+ ```
74
+
75
+ `status` keeps its meaning: `failed` only when nothing was charged,
76
+ `ambiguous` when money moved or may have. `ErrorCode`, `PaymentState` and
77
+ `NextAction` are exported, so a `switch` over `ErrorCode` can be exhaustive.
78
+
79
+ ## Which package?
80
+
81
+ | Install | Use it when |
82
+ | --- | --- |
83
+ | `@mysten-incubation/suipay` | An app needs `quote` + `pay` against a 402. This barrel. |
84
+ | `@mysten-incubation/suipay-buyer` | You need the typed `/v1` control plane, connection manifests, or `createPayer` directly. |
85
+ | `@mysten-incubation/suipay-mcp` | An MCP host (Claude, Codex, …) should log in, discover, and pay. |
86
+
87
+ Sellers copy `apps/seller-template` (and `@suipay/seller-runtime` inside the
88
+ repo). There is **no** published seller SDK.
89
+
90
+ Do not publish or depend on `@cmdoss/suipay-core` or `@cmdoss/suipay-sdk`.
91
+ Those stay private; this tarball bundles what it needs.
92
+
93
+ ## Build (this repo)
94
+
95
+ ```bash
96
+ pnpm --filter @mysten-incubation/suipay test
97
+ pnpm --filter @mysten-incubation/suipay build
98
+ ```
99
+
100
+ Publishing is the `release-npm` workflow: merge to `dev` publishes
101
+ `@mysten-incubation/suipay@<version>-dev.N` with dist-tag `dev` (OIDC, pack gate,
102
+ provenance). `latest` is a gated dispatch from `main` (`dry_run` default
103
+ true). Do not `npm publish` from a laptop. See
104
+ [`docs/guide/npm-release.md`](../../docs/guide/npm-release.md).