@ftptech/x402-canton-client 0.1.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.
@@ -0,0 +1,61 @@
1
+ /**
2
+ * ExactCantonScheme — payer-side x402 scheme client.
3
+ *
4
+ * Composes a `CantonSigner` (which knows how to create a
5
+ * TransferCommand on the agent's participant) with the x402 v2 wire
6
+ * format to produce the PaymentPayload the facilitator expects.
7
+ *
8
+ * Usage pattern (next-tick wrapFetchWithCantonPayment will inline
9
+ * this):
10
+ *
11
+ * const scheme = new ExactCantonScheme(signer);
12
+ * const payload = await scheme.createPaymentPayload(
13
+ * requirements,
14
+ * { url: "https://api.example.com/data" }
15
+ * );
16
+ * // POST the request again with
17
+ * // PAYMENT-SIGNATURE: <base64-encoded JSON payload>
18
+ */
19
+ import type { PaymentRequirements, X402ResourceInfo, CantonNetwork, CantonPaymentPayload } from "@ftptech/x402-canton-core";
20
+ import type { CantonSigner } from "./signer.js";
21
+ export interface CantonPaymentEnvelope {
22
+ x402Version: 2;
23
+ scheme: "exact-canton";
24
+ network: CantonNetwork;
25
+ resource: X402ResourceInfo;
26
+ accepted: PaymentRequirements;
27
+ payload: CantonPaymentPayload;
28
+ }
29
+ /**
30
+ * Thrown when the resource advertises a transferMethod this signer cannot
31
+ * service — e.g. a CIP-56-only wallet (the relay-backed agent wallet) facing a
32
+ * resource that only accepts `external-party-amulet-rules` (the v1 Splice
33
+ * TransferCommand path), or vice versa. Named + carrying both methods so the
34
+ * caller can branch (e.g. surface "fund a different wallet" vs a cryptic
35
+ * "signer does not implement ..."), instead of leaking a bare Error.
36
+ */
37
+ export declare class SchemeMethodMismatchError extends Error {
38
+ /** What the resource's 402 demanded. */
39
+ readonly required: string;
40
+ /** What this signer actually supports. */
41
+ readonly supported: string;
42
+ constructor(
43
+ /** What the resource's 402 demanded. */
44
+ required: string,
45
+ /** What this signer actually supports. */
46
+ supported: string);
47
+ }
48
+ export declare class ExactCantonScheme {
49
+ private readonly signer;
50
+ constructor(signer: CantonSigner);
51
+ /**
52
+ * Build the full PaymentPayload to send back in PAYMENT-SIGNATURE.
53
+ *
54
+ * Generates a fresh paymentId, stamps x402 metadata onto the
55
+ * on-ledger Transfer.meta, delegates to signer.signCip56Transfer to
56
+ * land the TransferFactory_Transfer, and wraps the result in the v2
57
+ * envelope. Throws if the signer can't service the cip56 path.
58
+ */
59
+ createPaymentPayload(requirements: PaymentRequirements, resource: X402ResourceInfo): Promise<CantonPaymentEnvelope>;
60
+ }
61
+ //# sourceMappingURL=scheme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheme.d.ts","sourceRoot":"","sources":["../src/scheme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,CAAC,CAAC;IACf,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,OAAO,EAAE,oBAAoB,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAEhD,wCAAwC;aACxB,QAAQ,EAAE,MAAM;IAChC,0CAA0C;aAC1B,SAAS,EAAE,MAAM;;IAHjC,wCAAwC;IACxB,QAAQ,EAAE,MAAM;IAChC,0CAA0C;IAC1B,SAAS,EAAE,MAAM;CAiBpC;AAED,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,YAAY;IAEjD;;;;;;;OAOG;IACG,oBAAoB,CACxB,YAAY,EAAE,mBAAmB,EACjC,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,qBAAqB,CAAC;CAkHlC"}
package/dist/scheme.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * ExactCantonScheme — payer-side x402 scheme client.
3
+ *
4
+ * Composes a `CantonSigner` (which knows how to create a
5
+ * TransferCommand on the agent's participant) with the x402 v2 wire
6
+ * format to produce the PaymentPayload the facilitator expects.
7
+ *
8
+ * Usage pattern (next-tick wrapFetchWithCantonPayment will inline
9
+ * this):
10
+ *
11
+ * const scheme = new ExactCantonScheme(signer);
12
+ * const payload = await scheme.createPaymentPayload(
13
+ * requirements,
14
+ * { url: "https://api.example.com/data" }
15
+ * );
16
+ * // POST the request again with
17
+ * // PAYMENT-SIGNATURE: <base64-encoded JSON payload>
18
+ */
19
+ import { randomUUID } from "node:crypto";
20
+ /**
21
+ * Thrown when the resource advertises a transferMethod this signer cannot
22
+ * service — e.g. a CIP-56-only wallet (the relay-backed agent wallet) facing a
23
+ * resource that only accepts `external-party-amulet-rules` (the v1 Splice
24
+ * TransferCommand path), or vice versa. Named + carrying both methods so the
25
+ * caller can branch (e.g. surface "fund a different wallet" vs a cryptic
26
+ * "signer does not implement ..."), instead of leaking a bare Error.
27
+ */
28
+ export class SchemeMethodMismatchError extends Error {
29
+ required;
30
+ supported;
31
+ constructor(
32
+ /** What the resource's 402 demanded. */
33
+ required,
34
+ /** What this signer actually supports. */
35
+ supported) {
36
+ const hint = supported === "cip56-transfer-factory"
37
+ ? " The agent-wallet relay signer is CIP-56-only " +
38
+ "(cip56-transfer-factory) and cannot create a v1 " +
39
+ "external-party-amulet-rules TransferCommand."
40
+ : supported === "(none)"
41
+ ? " This signer implements neither signCip56Transfer nor " +
42
+ "signTransferCommand."
43
+ : "";
44
+ super(`this wallet supports ${supported} only; the resource requires ` +
45
+ `${required}.${hint}`);
46
+ this.required = required;
47
+ this.supported = supported;
48
+ this.name = "SchemeMethodMismatchError";
49
+ }
50
+ }
51
+ export class ExactCantonScheme {
52
+ signer;
53
+ constructor(signer) {
54
+ this.signer = signer;
55
+ }
56
+ /**
57
+ * Build the full PaymentPayload to send back in PAYMENT-SIGNATURE.
58
+ *
59
+ * Generates a fresh paymentId, stamps x402 metadata onto the
60
+ * on-ledger Transfer.meta, delegates to signer.signCip56Transfer to
61
+ * land the TransferFactory_Transfer, and wraps the result in the v2
62
+ * envelope. Throws if the signer can't service the cip56 path.
63
+ */
64
+ async createPaymentPayload(requirements, resource) {
65
+ const extra = requirements.extra;
66
+ const paymentId = randomUUID();
67
+ if (extra.transferMethod === "external-party-amulet-rules") {
68
+ if (!this.signer.signTransferCommand) {
69
+ // The signer advertised no v1 capability — most commonly the
70
+ // CIP-56-only agent-wallet relay signer. Surface a named, branchable
71
+ // error instead of a cryptic "does not implement ..." (plan §4.3).
72
+ throw new SchemeMethodMismatchError("external-party-amulet-rules", this.signer.signCip56Transfer
73
+ ? "cip56-transfer-factory"
74
+ : "(none)");
75
+ }
76
+ const description = JSON.stringify({
77
+ paymentId,
78
+ resourceUrl: resource.url,
79
+ ...(extra.merchantContractCid !== undefined
80
+ ? { merchantContractCid: extra.merchantContractCid }
81
+ : {}),
82
+ x402Version: 2,
83
+ });
84
+ const signed = await this.signer.signTransferCommand({
85
+ receiver: requirements.payTo,
86
+ delegate: extra.facilitatorParty,
87
+ amount: requirements.amount,
88
+ synchronizerId: extra.synchronizerId,
89
+ description,
90
+ expiresAtMs: Date.now() + requirements.maxTimeoutSeconds * 1000,
91
+ });
92
+ return {
93
+ x402Version: 2,
94
+ scheme: "exact-canton",
95
+ network: requirements.network,
96
+ resource,
97
+ accepted: requirements,
98
+ payload: {
99
+ transferMethod: "external-party-amulet-rules",
100
+ transferCommandCid: signed.transferCommandCid,
101
+ payerParty: signed.payerParty,
102
+ nonce: signed.nonce,
103
+ ...(signed.createUpdateId !== undefined
104
+ ? { createUpdateId: signed.createUpdateId }
105
+ : {}),
106
+ },
107
+ };
108
+ }
109
+ if (extra.transferMethod === "cip56-transfer-factory") {
110
+ if (!this.signer.signCip56Transfer) {
111
+ throw new SchemeMethodMismatchError("cip56-transfer-factory", this.signer.signTransferCommand
112
+ ? "external-party-amulet-rules"
113
+ : "(none)");
114
+ }
115
+ // Stash x402 metadata on the on-ledger Transfer.meta so the
116
+ // facilitator's /verify can correlate even though there's no
117
+ // dedicated `description` field on TransferFactory_Transfer.
118
+ // `Map Text Text` encodes as a JSON object in Canton 3.4's
119
+ // JSON Ledger API v2.
120
+ // x402.facilitatorParty MUST be included in Transfer.meta so
121
+ // that CIP-56 factory/registry implementations can add the
122
+ // facilitator as an observer on the resulting TransferInstruction.
123
+ // Without this, the facilitator cannot call getTransactionById
124
+ // for the completed proof path (Canton only returns events the
125
+ // requesting party is a stakeholder in). See scheme spec
126
+ // §Facilitator Visibility for the full requirement.
127
+ const transferMeta = {
128
+ "x402.paymentId": paymentId,
129
+ "x402.resourceUrl": resource.url,
130
+ "x402.version": "2",
131
+ "x402.facilitatorParty": extra.facilitatorParty,
132
+ };
133
+ const signed = await this.signer.signCip56Transfer({
134
+ receiver: requirements.payTo,
135
+ transferFactoryCid: extra.transferFactoryCid,
136
+ transferFactoryTemplateId: extra.transferFactoryTemplateId,
137
+ factoryAdmin: extra.instrumentId.admin,
138
+ instrumentId: extra.instrumentId,
139
+ amount: requirements.amount,
140
+ synchronizerId: extra.synchronizerId,
141
+ facilitatorParty: extra.facilitatorParty,
142
+ transferMeta,
143
+ });
144
+ return {
145
+ x402Version: 2,
146
+ scheme: "exact-canton",
147
+ network: requirements.network,
148
+ resource,
149
+ accepted: requirements,
150
+ payload: {
151
+ transferMethod: "cip56-transfer-factory",
152
+ payerParty: signed.payerParty,
153
+ ...(signed.transferInstructionCid !== null
154
+ ? { transferInstructionCid: signed.transferInstructionCid }
155
+ : { updateId: signed.updateId }),
156
+ },
157
+ };
158
+ }
159
+ // Exhaustiveness — cip56-transfer-factory is the only variant.
160
+ const exhaustive = extra;
161
+ throw new Error(`unsupported transferMethod: ${exhaustive.transferMethod}`);
162
+ }
163
+ }
164
+ //# sourceMappingURL=scheme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheme.js","sourceRoot":"","sources":["../src/scheme.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * CantonSigner abstraction for the payer (agent) side.
3
+ *
4
+ * The signer lands the on-ledger artifact the facilitator later
5
+ * verifies, via `signCip56Transfer` — any CIP-56 token (incl. Canton
6
+ * Coin) through Splice's `TransferFactory_Transfer`. Settlement happens
7
+ * directly between sender and receiver; the facilitator's role is just
8
+ * verification (for a merchant with a TransferPreapproval the transfer
9
+ * completes atomically).
10
+ *
11
+ * Implementation: `Cip56KeyfileSigner` — production, Ed25519 PEM key,
12
+ * interactive-submission/prepare+execute. Test stubs use vi.fn().
13
+ */
14
+ export interface SignTransferCommandInput {
15
+ /** Merchant party id. Same as PaymentRequirements.payTo. */
16
+ receiver: string;
17
+ /** Facilitator party id. Same as extra.facilitatorParty. */
18
+ delegate: string;
19
+ /** Atomic units of the asset (e.g. canton-coin). JSON string. */
20
+ amount: string;
21
+ /** Global Synchronizer id. Same as extra.synchronizerId. */
22
+ synchronizerId: string;
23
+ /** JSON-encoded {paymentId, resourceUrl, merchantContractCid?, x402Version}. */
24
+ description: string;
25
+ /** Optional override for the TransferCommand expiry. Defaults to
26
+ * now + 60s per the maxTimeoutSeconds convention. */
27
+ expiresAtMs?: number;
28
+ }
29
+ export interface SignedTransferCommand {
30
+ /** ContractId of the TransferCommand just created on-ledger. */
31
+ transferCommandCid: string;
32
+ /** The agent's own party id (the TransferCommand.sender). */
33
+ payerParty: string;
34
+ /** Monotonic nonce assigned to this TransferCommand. */
35
+ nonce: number;
36
+ /** updateId of the TransferCommand_Create transaction. Set when the agent
37
+ * uses the relay path (submit/execute returns it); absent for direct
38
+ * KeyfileSigner flows where the create updateId is not surfaced. */
39
+ createUpdateId?: string;
40
+ }
41
+ export interface SignCip56TransferInput {
42
+ /** Merchant party id. Same as PaymentRequirements.payTo. */
43
+ receiver: string;
44
+ /** CIP-56 TransferFactory cid the merchant advertised in
45
+ * `extra.transferFactoryCid`. */
46
+ transferFactoryCid: string;
47
+ /** Hash-prefixed template id of the factory contract. The
48
+ * signer can read this off Scan or pass through what the
49
+ * merchant published. */
50
+ transferFactoryTemplateId: string;
51
+ /** The factory's admin party — clients should source from a
52
+ * trusted location (Scan or the merchant's own published
53
+ * metadata). Implementations check `expectedAdmin` matches the
54
+ * factory's own admin field as a bait-defense. */
55
+ factoryAdmin: string;
56
+ /** `{admin, id}` of the instrument the merchant advertised in
57
+ * `extra.instrumentId`. */
58
+ instrumentId: {
59
+ admin: string;
60
+ id: string;
61
+ };
62
+ /** Atomic units of the instrument. JSON string for precision. */
63
+ amount: string;
64
+ /** Global Synchronizer id. */
65
+ synchronizerId: string;
66
+ /** Optional override for the Transfer.executeBefore. Defaults
67
+ * to now + 60s. */
68
+ executeBeforeMs?: number;
69
+ /** Token-specific extra context to pass into the factory choice's
70
+ * `extraArgs`. For most CIP-56 tokens this is `{values: {}}` for
71
+ * both `context` and `meta`; some implementations want
72
+ * merchant-supplied factoryContext metadata. Canton 3.4 encodes
73
+ * `Map Text Text` as a JSON object (not an array of pairs). */
74
+ extraArgs?: {
75
+ context: {
76
+ values: Record<string, string>;
77
+ };
78
+ meta: {
79
+ values: Record<string, string>;
80
+ };
81
+ };
82
+ /** Facilitator party id from PaymentRequirements.extra.facilitatorParty.
83
+ * MUST be included in Transfer.meta.values["x402.facilitatorParty"]
84
+ * so that CIP-56 factories can add the facilitator as an observer
85
+ * on the resulting TransferInstruction. Without observer status the
86
+ * facilitator cannot verify or settle the payment. */
87
+ facilitatorParty: string;
88
+ /** Free-form metadata appended to the on-ledger Transfer.meta.
89
+ * Will include x402 paymentId, resourceUrl, version, and
90
+ * facilitatorParty (auto-added by ExactCantonScheme.sign). */
91
+ transferMeta?: Record<string, string>;
92
+ }
93
+ export interface SignedCip56Transfer {
94
+ payerParty: string;
95
+ /** Canton ledger updateId of the TransferFactory_Transfer
96
+ * submission. Always set; the client uses this as the
97
+ * Completed-case proof in the PaymentPayload. */
98
+ updateId: string;
99
+ /** ContractId of the TransferInstruction the registry created,
100
+ * IF the result was TransferInstructionResult_Pending. Null for
101
+ * Completed results. */
102
+ transferInstructionCid: string | null;
103
+ }
104
+ export interface CantonSigner {
105
+ /** Party this signer signs as. Same value the facilitator sees
106
+ * in `payload.payerParty`. */
107
+ readonly party: string;
108
+ /**
109
+ * Land a Splice TransferCommand on the agent's participant for the
110
+ * Canton-Coin v1 path. Implementations call
111
+ * /v2/interactive-submission/prepare -> sign the prepared-tx hash with
112
+ * the agent's key -> /execute. Optional: signers that only support
113
+ * CIP-56 may omit this method.
114
+ */
115
+ signTransferCommand?(input: SignTransferCommandInput): Promise<SignedTransferCommand>;
116
+ /**
117
+ * Exercise TransferFactory_Transfer on the agent's participant
118
+ * for the CIP-56 path. Implementations submit the exercise,
119
+ * extract the TransferInstructionResult from the resulting
120
+ * transaction events, and return the updateId plus (if
121
+ * applicable) the TransferInstruction cid. Optional: signers
122
+ * that only support TransferCommand may omit this method.
123
+ */
124
+ signCip56Transfer?(input: SignCip56TransferInput): Promise<SignedCip56Transfer>;
125
+ }
126
+ //# sourceMappingURL=signer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,wBAAwB;IACvC,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,cAAc,EAAE,MAAM,CAAC;IACvB,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAC;IACpB;0DACsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd;;yEAEqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB;sCACkC;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;8BAE0B;IAC1B,yBAAyB,EAAE,MAAM,CAAC;IAClC;;;uDAGmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB;gCAC4B;IAC5B,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB;wBACoB;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;oEAIgE;IAChE,SAAS,CAAC,EAAE;QACV,OAAO,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;SAAE,CAAC;QAC5C,IAAI,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;SAAE,CAAC;KAC1C,CAAC;IACF;;;;2DAIuD;IACvD,gBAAgB,EAAE,MAAM,CAAC;IACzB;;mEAE+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB;;sDAEkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB;;6BAEyB;IACzB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IAC3B;mCAC+B;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB;;;;;;OAMG;IACH,mBAAmB,CAAC,CAClB,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAElC;;;;;;;OAOG;IACH,iBAAiB,CAAC,CAChB,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACjC"}
package/dist/signer.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * CantonSigner abstraction for the payer (agent) side.
3
+ *
4
+ * The signer lands the on-ledger artifact the facilitator later
5
+ * verifies, via `signCip56Transfer` — any CIP-56 token (incl. Canton
6
+ * Coin) through Splice's `TransferFactory_Transfer`. Settlement happens
7
+ * directly between sender and receiver; the facilitator's role is just
8
+ * verification (for a merchant with a TransferPreapproval the transfer
9
+ * completes atomically).
10
+ *
11
+ * Implementation: `Cip56KeyfileSigner` — production, Ed25519 PEM key,
12
+ * interactive-submission/prepare+execute. Test stubs use vi.fn().
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=signer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer.js","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@ftptech/x402-canton-client",
3
+ "version": "0.1.0",
4
+ "description": "Canton x402 client SDK — payer side. ExactCantonScheme + signer abstractions for autonomous agents.",
5
+ "license": "Apache-2.0",
6
+ "author": "FTP team",
7
+ "homepage": "https://github.com/sunstrike228/canton-x402/tree/main/packages/client#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/sunstrike228/canton-x402.git",
11
+ "directory": "packages/client"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/sunstrike228/canton-x402/issues"
15
+ },
16
+ "keywords": [
17
+ "x402",
18
+ "canton",
19
+ "canton-network",
20
+ "client",
21
+ "payment",
22
+ "fetch",
23
+ "agent"
24
+ ],
25
+ "type": "module",
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ }
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "dependencies": {
40
+ "@ftptech/x402-canton-core": "^0.1.0",
41
+ "@ftptech/x402-canton-ledger": "^0.1.0"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -p tsconfig.json",
48
+ "typecheck": "tsc -p tsconfig.json --noEmit",
49
+ "test": "vitest run",
50
+ "lint": "eslint src --max-warnings 0"
51
+ }
52
+ }